2 * B53 register access through Switch Register Access Bridge Registers
4 * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
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.
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.
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>
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
36 /* high order word of write data to switch registe */
37 #define B53_SRAB_WD_H 0x30
39 /* low order word of write data to switch registe */
40 #define B53_SRAB_WD_L 0x34
42 /* high order word of read data from switch register */
43 #define B53_SRAB_RD_H 0x38
45 /* low order word of read data from switch register */
46 #define B53_SRAB_RD_L 0x3c
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)
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)
63 struct b53_srab_priv
{
67 static int b53_srab_request_grant(struct b53_device
*dev
)
69 struct b53_srab_priv
*priv
= dev
->priv
;
70 u8 __iomem
*regs
= priv
->regs
;
74 ctrls
= readl(regs
+ B53_SRAB_CTRLS
);
75 ctrls
|= B53_SRAB_CTRLS_RCAREQ
;
76 writel(ctrls
, regs
+ B53_SRAB_CTRLS
);
78 for (i
= 0; i
< 20; i
++) {
79 ctrls
= readl(regs
+ B53_SRAB_CTRLS
);
80 if (ctrls
& B53_SRAB_CTRLS_RCAGNT
)
82 usleep_range(10, 100);
90 static void b53_srab_release_grant(struct b53_device
*dev
)
92 struct b53_srab_priv
*priv
= dev
->priv
;
93 u8 __iomem
*regs
= priv
->regs
;
96 ctrls
= readl(regs
+ B53_SRAB_CTRLS
);
97 ctrls
&= ~B53_SRAB_CTRLS_RCAREQ
;
98 writel(ctrls
, regs
+ B53_SRAB_CTRLS
);
101 static int b53_srab_op(struct b53_device
*dev
, u8 page
, u8 reg
, u32 op
)
103 struct b53_srab_priv
*priv
= dev
->priv
;
104 u8 __iomem
*regs
= priv
->regs
;
108 /* set register address */
109 cmdstat
= (page
<< B53_SRAB_CMDSTAT_PAGE
) |
110 (reg
<< B53_SRAB_CMDSTAT_REG
) |
111 B53_SRAB_CMDSTAT_GORDYN
|
113 writel(cmdstat
, regs
+ B53_SRAB_CMDSTAT
);
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
))
120 usleep_range(10, 100);
129 static int b53_srab_read8(struct b53_device
*dev
, u8 page
, u8 reg
, u8
*val
)
131 struct b53_srab_priv
*priv
= dev
->priv
;
132 u8 __iomem
*regs
= priv
->regs
;
135 ret
= b53_srab_request_grant(dev
);
139 ret
= b53_srab_op(dev
, page
, reg
, 0);
143 *val
= readl(regs
+ B53_SRAB_RD_L
) & 0xff;
146 b53_srab_release_grant(dev
);
151 static int b53_srab_read16(struct b53_device
*dev
, u8 page
, u8 reg
, u16
*val
)
153 struct b53_srab_priv
*priv
= dev
->priv
;
154 u8 __iomem
*regs
= priv
->regs
;
157 ret
= b53_srab_request_grant(dev
);
161 ret
= b53_srab_op(dev
, page
, reg
, 0);
165 *val
= readl(regs
+ B53_SRAB_RD_L
) & 0xffff;
168 b53_srab_release_grant(dev
);
173 static int b53_srab_read32(struct b53_device
*dev
, u8 page
, u8 reg
, u32
*val
)
175 struct b53_srab_priv
*priv
= dev
->priv
;
176 u8 __iomem
*regs
= priv
->regs
;
179 ret
= b53_srab_request_grant(dev
);
183 ret
= b53_srab_op(dev
, page
, reg
, 0);
187 *val
= readl(regs
+ B53_SRAB_RD_L
);
190 b53_srab_release_grant(dev
);
195 static int b53_srab_read48(struct b53_device
*dev
, u8 page
, u8 reg
, u64
*val
)
197 struct b53_srab_priv
*priv
= dev
->priv
;
198 u8 __iomem
*regs
= priv
->regs
;
201 ret
= b53_srab_request_grant(dev
);
205 ret
= b53_srab_op(dev
, page
, reg
, 0);
209 *val
= readl(regs
+ B53_SRAB_RD_L
);
210 *val
+= ((u64
)readl(regs
+ B53_SRAB_RD_H
) & 0xffff) << 32;
213 b53_srab_release_grant(dev
);
218 static int b53_srab_read64(struct b53_device
*dev
, u8 page
, u8 reg
, u64
*val
)
220 struct b53_srab_priv
*priv
= dev
->priv
;
221 u8 __iomem
*regs
= priv
->regs
;
224 ret
= b53_srab_request_grant(dev
);
228 ret
= b53_srab_op(dev
, page
, reg
, 0);
232 *val
= readl(regs
+ B53_SRAB_RD_L
);
233 *val
+= (u64
)readl(regs
+ B53_SRAB_RD_H
) << 32;
236 b53_srab_release_grant(dev
);
241 static int b53_srab_write8(struct b53_device
*dev
, u8 page
, u8 reg
, u8 value
)
243 struct b53_srab_priv
*priv
= dev
->priv
;
244 u8 __iomem
*regs
= priv
->regs
;
247 ret
= b53_srab_request_grant(dev
);
251 writel(value
, regs
+ B53_SRAB_WD_L
);
253 ret
= b53_srab_op(dev
, page
, reg
, B53_SRAB_CMDSTAT_WRITE
);
256 b53_srab_release_grant(dev
);
261 static int b53_srab_write16(struct b53_device
*dev
, u8 page
, u8 reg
,
264 struct b53_srab_priv
*priv
= dev
->priv
;
265 u8 __iomem
*regs
= priv
->regs
;
268 ret
= b53_srab_request_grant(dev
);
272 writel(value
, regs
+ B53_SRAB_WD_L
);
274 ret
= b53_srab_op(dev
, page
, reg
, B53_SRAB_CMDSTAT_WRITE
);
277 b53_srab_release_grant(dev
);
282 static int b53_srab_write32(struct b53_device
*dev
, u8 page
, u8 reg
,
285 struct b53_srab_priv
*priv
= dev
->priv
;
286 u8 __iomem
*regs
= priv
->regs
;
289 ret
= b53_srab_request_grant(dev
);
293 writel(value
, regs
+ B53_SRAB_WD_L
);
295 ret
= b53_srab_op(dev
, page
, reg
, B53_SRAB_CMDSTAT_WRITE
);
298 b53_srab_release_grant(dev
);
303 static int b53_srab_write48(struct b53_device
*dev
, u8 page
, u8 reg
,
306 struct b53_srab_priv
*priv
= dev
->priv
;
307 u8 __iomem
*regs
= priv
->regs
;
310 ret
= b53_srab_request_grant(dev
);
314 writel((u32
)value
, regs
+ B53_SRAB_WD_L
);
315 writel((u16
)(value
>> 32), regs
+ B53_SRAB_WD_H
);
317 ret
= b53_srab_op(dev
, page
, reg
, B53_SRAB_CMDSTAT_WRITE
);
320 b53_srab_release_grant(dev
);
325 static int b53_srab_write64(struct b53_device
*dev
, u8 page
, u8 reg
,
328 struct b53_srab_priv
*priv
= dev
->priv
;
329 u8 __iomem
*regs
= priv
->regs
;
332 ret
= b53_srab_request_grant(dev
);
336 writel((u32
)value
, regs
+ B53_SRAB_WD_L
);
337 writel((u32
)(value
>> 32), regs
+ B53_SRAB_WD_H
);
339 ret
= b53_srab_op(dev
, page
, reg
, B53_SRAB_CMDSTAT_WRITE
);
342 b53_srab_release_grant(dev
);
347 static 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
,
360 static 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,bcm11360-srab", .data
= (void *)BCM583XX_DEVICE_ID
},
368 { .compatible
= "brcm,bcm58522-srab", .data
= (void *)BCM58XX_DEVICE_ID
},
369 { .compatible
= "brcm,bcm58525-srab", .data
= (void *)BCM58XX_DEVICE_ID
},
370 { .compatible
= "brcm,bcm58535-srab", .data
= (void *)BCM58XX_DEVICE_ID
},
371 { .compatible
= "brcm,bcm58622-srab", .data
= (void *)BCM58XX_DEVICE_ID
},
372 { .compatible
= "brcm,bcm58623-srab", .data
= (void *)BCM58XX_DEVICE_ID
},
373 { .compatible
= "brcm,bcm58625-srab", .data
= (void *)BCM58XX_DEVICE_ID
},
374 { .compatible
= "brcm,bcm88312-srab", .data
= (void *)BCM58XX_DEVICE_ID
},
375 { .compatible
= "brcm,cygnus-srab", .data
= (void *)BCM583XX_DEVICE_ID
},
376 { .compatible
= "brcm,nsp-srab", .data
= (void *)BCM58XX_DEVICE_ID
},
377 { .compatible
= "brcm,omega-srab", .data
= (void *)BCM583XX_DEVICE_ID
},
380 MODULE_DEVICE_TABLE(of
, b53_srab_of_match
);
382 static int b53_srab_probe(struct platform_device
*pdev
)
384 struct b53_platform_data
*pdata
= pdev
->dev
.platform_data
;
385 struct device_node
*dn
= pdev
->dev
.of_node
;
386 const struct of_device_id
*of_id
= NULL
;
387 struct b53_srab_priv
*priv
;
388 struct b53_device
*dev
;
392 of_id
= of_match_node(b53_srab_of_match
, dn
);
395 pdata
= devm_kzalloc(&pdev
->dev
, sizeof(*pdata
), GFP_KERNEL
);
399 pdata
->chip_id
= (u32
)(unsigned long)of_id
->data
;
402 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
406 r
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
407 priv
->regs
= devm_ioremap_resource(&pdev
->dev
, r
);
408 if (IS_ERR(priv
->regs
))
411 dev
= b53_switch_alloc(&pdev
->dev
, &b53_srab_ops
, priv
);
418 platform_set_drvdata(pdev
, dev
);
420 return b53_switch_register(dev
);
423 static int b53_srab_remove(struct platform_device
*pdev
)
425 struct b53_device
*dev
= platform_get_drvdata(pdev
);
428 b53_switch_remove(dev
);
433 static struct platform_driver b53_srab_driver
= {
434 .probe
= b53_srab_probe
,
435 .remove
= b53_srab_remove
,
437 .name
= "b53-srab-switch",
438 .of_match_table
= b53_srab_of_match
,
442 module_platform_driver(b53_srab_driver
);
443 MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
444 MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver");
445 MODULE_LICENSE("Dual BSD/GPL");