Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * B53 register access through SPI
  3 *
  4 * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
  5 *
  6 * Permission to use, copy, modify, and/or distribute this software for any
  7 * purpose with or without fee is hereby granted, provided that the above
  8 * copyright notice and this permission notice appear in all copies.
  9 *
 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 17 */
 18
 19#include <asm/unaligned.h>
 20
 21#include <linux/delay.h>
 22#include <linux/kernel.h>
 23#include <linux/module.h>
 24#include <linux/spi/spi.h>
 25#include <linux/platform_data/b53.h>
 26
 27#include "b53_priv.h"
 28
 29#define B53_SPI_DATA		0xf0
 30
 31#define B53_SPI_STATUS		0xfe
 32#define B53_SPI_CMD_SPIF	BIT(7)
 33#define B53_SPI_CMD_RACK	BIT(5)
 34
 35#define B53_SPI_CMD_READ	0x00
 36#define B53_SPI_CMD_WRITE	0x01
 37#define B53_SPI_CMD_NORMAL	0x60
 38#define B53_SPI_CMD_FAST	0x10
 39
 40#define B53_SPI_PAGE_SELECT	0xff
 41
 42static inline int b53_spi_read_reg(struct spi_device *spi, u8 reg, u8 *val,
 43				   unsigned int len)
 44{
 45	u8 txbuf[2];
 46
 47	txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_READ;
 48	txbuf[1] = reg;
 49
 50	return spi_write_then_read(spi, txbuf, 2, val, len);
 51}
 52
 53static inline int b53_spi_clear_status(struct spi_device *spi)
 54{
 55	unsigned int i;
 56	u8 rxbuf;
 57	int ret;
 58
 59	for (i = 0; i < 10; i++) {
 60		ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1);
 61		if (ret)
 62			return ret;
 63
 64		if (!(rxbuf & B53_SPI_CMD_SPIF))
 65			break;
 66
 67		mdelay(1);
 68	}
 69
 70	if (i == 10)
 71		return -EIO;
 72
 73	return 0;
 74}
 75
 76static inline int b53_spi_set_page(struct spi_device *spi, u8 page)
 77{
 78	u8 txbuf[3];
 79
 80	txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
 81	txbuf[1] = B53_SPI_PAGE_SELECT;
 82	txbuf[2] = page;
 83
 84	return spi_write(spi, txbuf, sizeof(txbuf));
 85}
 86
 87static inline int b53_prepare_reg_access(struct spi_device *spi, u8 page)
 88{
 89	int ret = b53_spi_clear_status(spi);
 90
 91	if (ret)
 92		return ret;
 93
 94	return b53_spi_set_page(spi, page);
 95}
 96
 97static int b53_spi_prepare_reg_read(struct spi_device *spi, u8 reg)
 98{
 99	u8 rxbuf;
100	int retry_count;
101	int ret;
102
103	ret = b53_spi_read_reg(spi, reg, &rxbuf, 1);
104	if (ret)
105		return ret;
106
107	for (retry_count = 0; retry_count < 10; retry_count++) {
108		ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1);
109		if (ret)
110			return ret;
111
112		if (rxbuf & B53_SPI_CMD_RACK)
113			break;
114
115		mdelay(1);
116	}
117
118	if (retry_count == 10)
119		return -EIO;
120
121	return 0;
122}
123
124static int b53_spi_read(struct b53_device *dev, u8 page, u8 reg, u8 *data,
125			unsigned int len)
126{
127	struct spi_device *spi = dev->priv;
128	int ret;
129
130	ret = b53_prepare_reg_access(spi, page);
131	if (ret)
132		return ret;
133
134	ret = b53_spi_prepare_reg_read(spi, reg);
135	if (ret)
136		return ret;
137
138	return b53_spi_read_reg(spi, B53_SPI_DATA, data, len);
139}
140
141static int b53_spi_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
142{
143	return b53_spi_read(dev, page, reg, val, 1);
144}
145
146static int b53_spi_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
147{
148	int ret = b53_spi_read(dev, page, reg, (u8 *)val, 2);
149
150	if (!ret)
151		*val = le16_to_cpu(*val);
152
153	return ret;
154}
155
156static int b53_spi_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
157{
158	int ret = b53_spi_read(dev, page, reg, (u8 *)val, 4);
159
160	if (!ret)
161		*val = le32_to_cpu(*val);
162
163	return ret;
164}
165
166static int b53_spi_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
167{
168	int ret;
169
170	*val = 0;
171	ret = b53_spi_read(dev, page, reg, (u8 *)val, 6);
172	if (!ret)
173		*val = le64_to_cpu(*val);
174
175	return ret;
176}
177
178static int b53_spi_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
179{
180	int ret = b53_spi_read(dev, page, reg, (u8 *)val, 8);
181
182	if (!ret)
183		*val = le64_to_cpu(*val);
184
185	return ret;
186}
187
188static int b53_spi_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
189{
190	struct spi_device *spi = dev->priv;
191	int ret;
192	u8 txbuf[3];
193
194	ret = b53_prepare_reg_access(spi, page);
195	if (ret)
196		return ret;
197
198	txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
199	txbuf[1] = reg;
200	txbuf[2] = value;
201
202	return spi_write(spi, txbuf, sizeof(txbuf));
203}
204
205static int b53_spi_write16(struct b53_device *dev, u8 page, u8 reg, u16 value)
206{
207	struct spi_device *spi = dev->priv;
208	int ret;
209	u8 txbuf[4];
210
211	ret = b53_prepare_reg_access(spi, page);
212	if (ret)
213		return ret;
214
215	txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
216	txbuf[1] = reg;
217	put_unaligned_le16(value, &txbuf[2]);
218
219	return spi_write(spi, txbuf, sizeof(txbuf));
220}
221
222static int b53_spi_write32(struct b53_device *dev, u8 page, u8 reg, u32 value)
223{
224	struct spi_device *spi = dev->priv;
225	int ret;
226	u8 txbuf[6];
227
228	ret = b53_prepare_reg_access(spi, page);
229	if (ret)
230		return ret;
231
232	txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
233	txbuf[1] = reg;
234	put_unaligned_le32(value, &txbuf[2]);
235
236	return spi_write(spi, txbuf, sizeof(txbuf));
237}
238
239static int b53_spi_write48(struct b53_device *dev, u8 page, u8 reg, u64 value)
240{
241	struct spi_device *spi = dev->priv;
242	int ret;
243	u8 txbuf[10];
244
245	ret = b53_prepare_reg_access(spi, page);
246	if (ret)
247		return ret;
248
249	txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
250	txbuf[1] = reg;
251	put_unaligned_le64(value, &txbuf[2]);
252
253	return spi_write(spi, txbuf, sizeof(txbuf) - 2);
254}
255
256static int b53_spi_write64(struct b53_device *dev, u8 page, u8 reg, u64 value)
257{
258	struct spi_device *spi = dev->priv;
259	int ret;
260	u8 txbuf[10];
261
262	ret = b53_prepare_reg_access(spi, page);
263	if (ret)
264		return ret;
265
266	txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
267	txbuf[1] = reg;
268	put_unaligned_le64(value, &txbuf[2]);
269
270	return spi_write(spi, txbuf, sizeof(txbuf));
271}
272
273static const struct b53_io_ops b53_spi_ops = {
274	.read8 = b53_spi_read8,
275	.read16 = b53_spi_read16,
276	.read32 = b53_spi_read32,
277	.read48 = b53_spi_read48,
278	.read64 = b53_spi_read64,
279	.write8 = b53_spi_write8,
280	.write16 = b53_spi_write16,
281	.write32 = b53_spi_write32,
282	.write48 = b53_spi_write48,
283	.write64 = b53_spi_write64,
284};
285
286static int b53_spi_probe(struct spi_device *spi)
287{
288	struct b53_device *dev;
289	int ret;
290
291	dev = b53_switch_alloc(&spi->dev, &b53_spi_ops, spi);
292	if (!dev)
293		return -ENOMEM;
294
295	if (spi->dev.platform_data)
296		dev->pdata = spi->dev.platform_data;
297
298	ret = b53_switch_register(dev);
299	if (ret)
300		return ret;
301
302	spi_set_drvdata(spi, dev);
303
304	return 0;
305}
306
307static int b53_spi_remove(struct spi_device *spi)
308{
309	struct b53_device *dev = spi_get_drvdata(spi);
310
311	if (dev)
312		b53_switch_remove(dev);
313
314	return 0;
315}
316
317static struct spi_driver b53_spi_driver = {
318	.driver = {
319		.name	= "b53-switch",
320	},
321	.probe	= b53_spi_probe,
322	.remove	= b53_spi_remove,
323};
324
325module_spi_driver(b53_spi_driver);
326
327MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
328MODULE_DESCRIPTION("B53 SPI access driver");
329MODULE_LICENSE("Dual BSD/GPL");