Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1/*
  2 * B53 register access through Switch Register Access Bridge Registers
  3 *
  4 * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
  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 <linux/kernel.h>
 20#include <linux/module.h>
 21#include <linux/delay.h>
 22#include <linux/platform_device.h>
 23#include <linux/platform_data/b53.h>
 24#include <linux/of.h>
 25
 26#include "b53_priv.h"
 27
 28/* command and status register of the SRAB */
 29#define B53_SRAB_CMDSTAT		0x2c
 30#define  B53_SRAB_CMDSTAT_RST		BIT(2)
 31#define  B53_SRAB_CMDSTAT_WRITE		BIT(1)
 32#define  B53_SRAB_CMDSTAT_GORDYN	BIT(0)
 33#define  B53_SRAB_CMDSTAT_PAGE		24
 34#define  B53_SRAB_CMDSTAT_REG		16
 35
 36/* high order word of write data to switch registe */
 37#define B53_SRAB_WD_H			0x30
 38
 39/* low order word of write data to switch registe */
 40#define B53_SRAB_WD_L			0x34
 41
 42/* high order word of read data from switch register */
 43#define B53_SRAB_RD_H			0x38
 44
 45/* low order word of read data from switch register */
 46#define B53_SRAB_RD_L			0x3c
 47
 48/* command and status register of the SRAB */
 49#define B53_SRAB_CTRLS			0x40
 50#define  B53_SRAB_CTRLS_RCAREQ		BIT(3)
 51#define  B53_SRAB_CTRLS_RCAGNT		BIT(4)
 52#define  B53_SRAB_CTRLS_SW_INIT_DONE	BIT(6)
 53
 54/* the register captures interrupt pulses from the switch */
 55#define B53_SRAB_INTR			0x44
 56#define  B53_SRAB_INTR_P(x)		BIT(x)
 57#define  B53_SRAB_SWITCH_PHY		BIT(8)
 58#define  B53_SRAB_1588_SYNC		BIT(9)
 59#define  B53_SRAB_IMP1_SLEEP_TIMER	BIT(10)
 60#define  B53_SRAB_P7_SLEEP_TIMER	BIT(11)
 61#define  B53_SRAB_IMP0_SLEEP_TIMER	BIT(12)
 62
 63struct b53_srab_priv {
 64	void __iomem *regs;
 65};
 66
 67static int b53_srab_request_grant(struct b53_device *dev)
 68{
 69	struct b53_srab_priv *priv = dev->priv;
 70	u8 __iomem *regs = priv->regs;
 71	u32 ctrls;
 72	int i;
 73
 74	ctrls = readl(regs + B53_SRAB_CTRLS);
 75	ctrls |= B53_SRAB_CTRLS_RCAREQ;
 76	writel(ctrls, regs + B53_SRAB_CTRLS);
 77
 78	for (i = 0; i < 20; i++) {
 79		ctrls = readl(regs + B53_SRAB_CTRLS);
 80		if (ctrls & B53_SRAB_CTRLS_RCAGNT)
 81			break;
 82		usleep_range(10, 100);
 83	}
 84	if (WARN_ON(i == 5))
 85		return -EIO;
 86
 87	return 0;
 88}
 89
 90static void b53_srab_release_grant(struct b53_device *dev)
 91{
 92	struct b53_srab_priv *priv = dev->priv;
 93	u8 __iomem *regs = priv->regs;
 94	u32 ctrls;
 95
 96	ctrls = readl(regs + B53_SRAB_CTRLS);
 97	ctrls &= ~B53_SRAB_CTRLS_RCAREQ;
 98	writel(ctrls, regs + B53_SRAB_CTRLS);
 99}
100
101static int b53_srab_op(struct b53_device *dev, u8 page, u8 reg, u32 op)
102{
103	struct b53_srab_priv *priv = dev->priv;
104	u8 __iomem *regs = priv->regs;
105	int i;
106	u32 cmdstat;
107
108	/* set register address */
109	cmdstat = (page << B53_SRAB_CMDSTAT_PAGE) |
110		  (reg << B53_SRAB_CMDSTAT_REG) |
111		  B53_SRAB_CMDSTAT_GORDYN |
112		  op;
113	writel(cmdstat, regs + B53_SRAB_CMDSTAT);
114
115	/* check if operation completed */
116	for (i = 0; i < 5; ++i) {
117		cmdstat = readl(regs + B53_SRAB_CMDSTAT);
118		if (!(cmdstat & B53_SRAB_CMDSTAT_GORDYN))
119			break;
120		usleep_range(10, 100);
121	}
122
123	if (WARN_ON(i == 5))
124		return -EIO;
125
126	return 0;
127}
128
129static int b53_srab_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
130{
131	struct b53_srab_priv *priv = dev->priv;
132	u8 __iomem *regs = priv->regs;
133	int ret = 0;
134
135	ret = b53_srab_request_grant(dev);
136	if (ret)
137		goto err;
138
139	ret = b53_srab_op(dev, page, reg, 0);
140	if (ret)
141		goto err;
142
143	*val = readl(regs + B53_SRAB_RD_L) & 0xff;
144
145err:
146	b53_srab_release_grant(dev);
147
148	return ret;
149}
150
151static int b53_srab_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
152{
153	struct b53_srab_priv *priv = dev->priv;
154	u8 __iomem *regs = priv->regs;
155	int ret = 0;
156
157	ret = b53_srab_request_grant(dev);
158	if (ret)
159		goto err;
160
161	ret = b53_srab_op(dev, page, reg, 0);
162	if (ret)
163		goto err;
164
165	*val = readl(regs + B53_SRAB_RD_L) & 0xffff;
166
167err:
168	b53_srab_release_grant(dev);
169
170	return ret;
171}
172
173static int b53_srab_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
174{
175	struct b53_srab_priv *priv = dev->priv;
176	u8 __iomem *regs = priv->regs;
177	int ret = 0;
178
179	ret = b53_srab_request_grant(dev);
180	if (ret)
181		goto err;
182
183	ret = b53_srab_op(dev, page, reg, 0);
184	if (ret)
185		goto err;
186
187	*val = readl(regs + B53_SRAB_RD_L);
188
189err:
190	b53_srab_release_grant(dev);
191
192	return ret;
193}
194
195static int b53_srab_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
196{
197	struct b53_srab_priv *priv = dev->priv;
198	u8 __iomem *regs = priv->regs;
199	int ret = 0;
200
201	ret = b53_srab_request_grant(dev);
202	if (ret)
203		goto err;
204
205	ret = b53_srab_op(dev, page, reg, 0);
206	if (ret)
207		goto err;
208
209	*val = readl(regs + B53_SRAB_RD_L);
210	*val += ((u64)readl(regs + B53_SRAB_RD_H) & 0xffff) << 32;
211
212err:
213	b53_srab_release_grant(dev);
214
215	return ret;
216}
217
218static int b53_srab_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
219{
220	struct b53_srab_priv *priv = dev->priv;
221	u8 __iomem *regs = priv->regs;
222	int ret = 0;
223
224	ret = b53_srab_request_grant(dev);
225	if (ret)
226		goto err;
227
228	ret = b53_srab_op(dev, page, reg, 0);
229	if (ret)
230		goto err;
231
232	*val = readl(regs + B53_SRAB_RD_L);
233	*val += (u64)readl(regs + B53_SRAB_RD_H) << 32;
234
235err:
236	b53_srab_release_grant(dev);
237
238	return ret;
239}
240
241static int b53_srab_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
242{
243	struct b53_srab_priv *priv = dev->priv;
244	u8 __iomem *regs = priv->regs;
245	int ret = 0;
246
247	ret = b53_srab_request_grant(dev);
248	if (ret)
249		goto err;
250
251	writel(value, regs + B53_SRAB_WD_L);
252
253	ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
254
255err:
256	b53_srab_release_grant(dev);
257
258	return ret;
259}
260
261static int b53_srab_write16(struct b53_device *dev, u8 page, u8 reg,
262			    u16 value)
263{
264	struct b53_srab_priv *priv = dev->priv;
265	u8 __iomem *regs = priv->regs;
266	int ret = 0;
267
268	ret = b53_srab_request_grant(dev);
269	if (ret)
270		goto err;
271
272	writel(value, regs + B53_SRAB_WD_L);
273
274	ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
275
276err:
277	b53_srab_release_grant(dev);
278
279	return ret;
280}
281
282static int b53_srab_write32(struct b53_device *dev, u8 page, u8 reg,
283			    u32 value)
284{
285	struct b53_srab_priv *priv = dev->priv;
286	u8 __iomem *regs = priv->regs;
287	int ret = 0;
288
289	ret = b53_srab_request_grant(dev);
290	if (ret)
291		goto err;
292
293	writel(value, regs + B53_SRAB_WD_L);
294
295	ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
296
297err:
298	b53_srab_release_grant(dev);
299
300	return ret;
301}
302
303static int b53_srab_write48(struct b53_device *dev, u8 page, u8 reg,
304			    u64 value)
305{
306	struct b53_srab_priv *priv = dev->priv;
307	u8 __iomem *regs = priv->regs;
308	int ret = 0;
309
310	ret = b53_srab_request_grant(dev);
311	if (ret)
312		goto err;
313
314	writel((u32)value, regs + B53_SRAB_WD_L);
315	writel((u16)(value >> 32), regs + B53_SRAB_WD_H);
316
317	ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
318
319err:
320	b53_srab_release_grant(dev);
321
322	return ret;
323}
324
325static int b53_srab_write64(struct b53_device *dev, u8 page, u8 reg,
326			    u64 value)
327{
328	struct b53_srab_priv *priv = dev->priv;
329	u8 __iomem *regs = priv->regs;
330	int ret = 0;
331
332	ret = b53_srab_request_grant(dev);
333	if (ret)
334		goto err;
335
336	writel((u32)value, regs + B53_SRAB_WD_L);
337	writel((u32)(value >> 32), regs + B53_SRAB_WD_H);
338
339	ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
340
341err:
342	b53_srab_release_grant(dev);
343
344	return ret;
345}
346
347static const struct b53_io_ops b53_srab_ops = {
348	.read8 = b53_srab_read8,
349	.read16 = b53_srab_read16,
350	.read32 = b53_srab_read32,
351	.read48 = b53_srab_read48,
352	.read64 = b53_srab_read64,
353	.write8 = b53_srab_write8,
354	.write16 = b53_srab_write16,
355	.write32 = b53_srab_write32,
356	.write48 = b53_srab_write48,
357	.write64 = b53_srab_write64,
358};
359
360static const struct of_device_id b53_srab_of_match[] = {
361	{ .compatible = "brcm,bcm53010-srab" },
362	{ .compatible = "brcm,bcm53011-srab" },
363	{ .compatible = "brcm,bcm53012-srab" },
364	{ .compatible = "brcm,bcm53018-srab" },
365	{ .compatible = "brcm,bcm53019-srab" },
366	{ .compatible = "brcm,bcm5301x-srab" },
367	{ .compatible = "brcm,bcm58522-srab", .data = (void *)BCM58XX_DEVICE_ID },
368	{ .compatible = "brcm,bcm58525-srab", .data = (void *)BCM58XX_DEVICE_ID },
369	{ .compatible = "brcm,bcm58535-srab", .data = (void *)BCM58XX_DEVICE_ID },
370	{ .compatible = "brcm,bcm58622-srab", .data = (void *)BCM58XX_DEVICE_ID },
371	{ .compatible = "brcm,bcm58623-srab", .data = (void *)BCM58XX_DEVICE_ID },
372	{ .compatible = "brcm,bcm58625-srab", .data = (void *)BCM58XX_DEVICE_ID },
373	{ .compatible = "brcm,bcm88312-srab", .data = (void *)BCM58XX_DEVICE_ID },
374	{ .compatible = "brcm,nsp-srab", .data = (void *)BCM58XX_DEVICE_ID },
375	{ /* sentinel */ },
376};
377MODULE_DEVICE_TABLE(of, b53_srab_of_match);
378
379static int b53_srab_probe(struct platform_device *pdev)
380{
381	struct b53_platform_data *pdata = pdev->dev.platform_data;
382	struct device_node *dn = pdev->dev.of_node;
383	const struct of_device_id *of_id = NULL;
384	struct b53_srab_priv *priv;
385	struct b53_device *dev;
386	struct resource *r;
387
388	if (dn)
389		of_id = of_match_node(b53_srab_of_match, dn);
390
391	if (of_id) {
392		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
393		if (!pdata)
394			return -ENOMEM;
395
396		pdata->chip_id = (u32)(unsigned long)of_id->data;
397	}
398
399	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
400	if (!priv)
401		return -ENOMEM;
402
403	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
404	priv->regs = devm_ioremap_resource(&pdev->dev, r);
405	if (IS_ERR(priv->regs))
406		return -ENOMEM;
407
408	dev = b53_switch_alloc(&pdev->dev, &b53_srab_ops, priv);
409	if (!dev)
410		return -ENOMEM;
411
412	if (pdata)
413		dev->pdata = pdata;
414
415	platform_set_drvdata(pdev, dev);
416
417	return b53_switch_register(dev);
418}
419
420static int b53_srab_remove(struct platform_device *pdev)
421{
422	struct b53_device *dev = platform_get_drvdata(pdev);
423
424	if (dev)
425		b53_switch_remove(dev);
426
427	return 0;
428}
429
430static struct platform_driver b53_srab_driver = {
431	.probe = b53_srab_probe,
432	.remove = b53_srab_remove,
433	.driver = {
434		.name = "b53-srab-switch",
435		.of_match_table = b53_srab_of_match,
436	},
437};
438
439module_platform_driver(b53_srab_driver);
440MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
441MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver");
442MODULE_LICENSE("Dual BSD/GPL");