2 * B53 register access through memory mapped registers
4 * Copyright (C) 2012-2013 Jonas Gorski <jogo@openwrt.org>
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/bits.h>
20 #include <linux/kernel.h>
21 #include <linux/module.h>
24 #include <linux/platform_device.h>
25 #include <linux/platform_data/b53.h>
29 struct b53_mmap_priv
{
33 static int b53_mmap_read8(struct b53_device
*dev
, u8 page
, u8 reg
, u8
*val
)
35 struct b53_mmap_priv
*priv
= dev
->priv
;
36 void __iomem
*regs
= priv
->regs
;
38 *val
= readb(regs
+ (page
<< 8) + reg
);
43 static int b53_mmap_read16(struct b53_device
*dev
, u8 page
, u8 reg
, u16
*val
)
45 struct b53_mmap_priv
*priv
= dev
->priv
;
46 void __iomem
*regs
= priv
->regs
;
51 if (dev
->pdata
&& dev
->pdata
->big_endian
)
52 *val
= ioread16be(regs
+ (page
<< 8) + reg
);
54 *val
= readw(regs
+ (page
<< 8) + reg
);
59 static int b53_mmap_read32(struct b53_device
*dev
, u8 page
, u8 reg
, u32
*val
)
61 struct b53_mmap_priv
*priv
= dev
->priv
;
62 void __iomem
*regs
= priv
->regs
;
67 if (dev
->pdata
&& dev
->pdata
->big_endian
)
68 *val
= ioread32be(regs
+ (page
<< 8) + reg
);
70 *val
= readl(regs
+ (page
<< 8) + reg
);
75 static int b53_mmap_read48(struct b53_device
*dev
, u8 page
, u8 reg
, u64
*val
)
77 struct b53_mmap_priv
*priv
= dev
->priv
;
78 void __iomem
*regs
= priv
->regs
;
87 if (dev
->pdata
&& dev
->pdata
->big_endian
) {
88 lo
= ioread16be(regs
+ (page
<< 8) + reg
);
89 hi
= ioread32be(regs
+ (page
<< 8) + reg
+ 2);
91 lo
= readw(regs
+ (page
<< 8) + reg
);
92 hi
= readl(regs
+ (page
<< 8) + reg
+ 2);
95 *val
= ((u64
)hi
<< 16) | lo
;
100 if (dev
->pdata
&& dev
->pdata
->big_endian
) {
101 lo
= ioread32be(regs
+ (page
<< 8) + reg
);
102 hi
= ioread16be(regs
+ (page
<< 8) + reg
+ 4);
104 lo
= readl(regs
+ (page
<< 8) + reg
);
105 hi
= readw(regs
+ (page
<< 8) + reg
+ 4);
108 *val
= ((u64
)hi
<< 32) | lo
;
114 static int b53_mmap_read64(struct b53_device
*dev
, u8 page
, u8 reg
, u64
*val
)
116 struct b53_mmap_priv
*priv
= dev
->priv
;
117 void __iomem
*regs
= priv
->regs
;
120 if (WARN_ON(reg
% 4))
123 if (dev
->pdata
&& dev
->pdata
->big_endian
) {
124 lo
= ioread32be(regs
+ (page
<< 8) + reg
);
125 hi
= ioread32be(regs
+ (page
<< 8) + reg
+ 4);
127 lo
= readl(regs
+ (page
<< 8) + reg
);
128 hi
= readl(regs
+ (page
<< 8) + reg
+ 4);
131 *val
= ((u64
)hi
<< 32) | lo
;
136 static int b53_mmap_write8(struct b53_device
*dev
, u8 page
, u8 reg
, u8 value
)
138 struct b53_mmap_priv
*priv
= dev
->priv
;
139 void __iomem
*regs
= priv
->regs
;
141 writeb(value
, regs
+ (page
<< 8) + reg
);
146 static int b53_mmap_write16(struct b53_device
*dev
, u8 page
, u8 reg
,
149 struct b53_mmap_priv
*priv
= dev
->priv
;
150 void __iomem
*regs
= priv
->regs
;
152 if (WARN_ON(reg
% 2))
155 if (dev
->pdata
&& dev
->pdata
->big_endian
)
156 iowrite16be(value
, regs
+ (page
<< 8) + reg
);
158 writew(value
, regs
+ (page
<< 8) + reg
);
163 static int b53_mmap_write32(struct b53_device
*dev
, u8 page
, u8 reg
,
166 struct b53_mmap_priv
*priv
= dev
->priv
;
167 void __iomem
*regs
= priv
->regs
;
169 if (WARN_ON(reg
% 4))
172 if (dev
->pdata
&& dev
->pdata
->big_endian
)
173 iowrite32be(value
, regs
+ (page
<< 8) + reg
);
175 writel(value
, regs
+ (page
<< 8) + reg
);
180 static int b53_mmap_write48(struct b53_device
*dev
, u8 page
, u8 reg
,
183 if (WARN_ON(reg
% 2))
187 u32 hi
= (u32
)(value
>> 16);
190 b53_mmap_write16(dev
, page
, reg
, lo
);
191 b53_mmap_write32(dev
, page
, reg
+ 2, hi
);
193 u16 hi
= (u16
)(value
>> 32);
196 b53_mmap_write32(dev
, page
, reg
, lo
);
197 b53_mmap_write16(dev
, page
, reg
+ 4, hi
);
203 static int b53_mmap_write64(struct b53_device
*dev
, u8 page
, u8 reg
,
208 hi
= upper_32_bits(value
);
209 lo
= lower_32_bits(value
);
211 if (WARN_ON(reg
% 4))
214 b53_mmap_write32(dev
, page
, reg
, lo
);
215 b53_mmap_write32(dev
, page
, reg
+ 4, hi
);
220 static int b53_mmap_phy_read16(struct b53_device
*dev
, int addr
, int reg
,
226 static int b53_mmap_phy_write16(struct b53_device
*dev
, int addr
, int reg
,
232 static const struct b53_io_ops b53_mmap_ops
= {
233 .read8
= b53_mmap_read8
,
234 .read16
= b53_mmap_read16
,
235 .read32
= b53_mmap_read32
,
236 .read48
= b53_mmap_read48
,
237 .read64
= b53_mmap_read64
,
238 .write8
= b53_mmap_write8
,
239 .write16
= b53_mmap_write16
,
240 .write32
= b53_mmap_write32
,
241 .write48
= b53_mmap_write48
,
242 .write64
= b53_mmap_write64
,
243 .phy_read16
= b53_mmap_phy_read16
,
244 .phy_write16
= b53_mmap_phy_write16
,
247 static int b53_mmap_probe_of(struct platform_device
*pdev
,
248 struct b53_platform_data
**ppdata
)
250 struct device_node
*np
= pdev
->dev
.of_node
;
251 struct device_node
*of_ports
, *of_port
;
252 struct device
*dev
= &pdev
->dev
;
253 struct b53_platform_data
*pdata
;
256 mem
= devm_platform_ioremap_resource(pdev
, 0);
260 pdata
= devm_kzalloc(dev
, sizeof(struct b53_platform_data
),
266 pdata
->chip_id
= (u32
)(unsigned long)device_get_match_data(dev
);
267 pdata
->big_endian
= of_property_read_bool(np
, "big-endian");
269 of_ports
= of_get_child_by_name(np
, "ports");
271 dev_err(dev
, "no ports child node found\n");
275 for_each_available_child_of_node(of_ports
, of_port
) {
278 if (of_property_read_u32(of_port
, "reg", ®
))
281 if (reg
< B53_N_PORTS
)
282 pdata
->enabled_ports
|= BIT(reg
);
285 of_node_put(of_ports
);
291 static int b53_mmap_probe(struct platform_device
*pdev
)
293 struct device_node
*np
= pdev
->dev
.of_node
;
294 struct b53_platform_data
*pdata
= pdev
->dev
.platform_data
;
295 struct b53_mmap_priv
*priv
;
296 struct b53_device
*dev
;
300 ret
= b53_mmap_probe_of(pdev
, &pdata
);
302 dev_err(&pdev
->dev
, "OF probe error\n");
310 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
314 priv
->regs
= pdata
->regs
;
316 dev
= b53_switch_alloc(&pdev
->dev
, &b53_mmap_ops
, priv
);
322 platform_set_drvdata(pdev
, dev
);
324 return b53_switch_register(dev
);
327 static void b53_mmap_remove(struct platform_device
*pdev
)
329 struct b53_device
*dev
= platform_get_drvdata(pdev
);
332 b53_switch_remove(dev
);
335 static void b53_mmap_shutdown(struct platform_device
*pdev
)
337 struct b53_device
*dev
= platform_get_drvdata(pdev
);
340 b53_switch_shutdown(dev
);
342 platform_set_drvdata(pdev
, NULL
);
345 static const struct of_device_id b53_mmap_of_table
[] = {
347 .compatible
= "brcm,bcm3384-switch",
348 .data
= (void *)BCM63XX_DEVICE_ID
,
350 .compatible
= "brcm,bcm6318-switch",
351 .data
= (void *)BCM63268_DEVICE_ID
,
353 .compatible
= "brcm,bcm6328-switch",
354 .data
= (void *)BCM63XX_DEVICE_ID
,
356 .compatible
= "brcm,bcm6362-switch",
357 .data
= (void *)BCM63XX_DEVICE_ID
,
359 .compatible
= "brcm,bcm6368-switch",
360 .data
= (void *)BCM63XX_DEVICE_ID
,
362 .compatible
= "brcm,bcm63268-switch",
363 .data
= (void *)BCM63268_DEVICE_ID
,
365 .compatible
= "brcm,bcm63xx-switch",
366 .data
= (void *)BCM63XX_DEVICE_ID
,
367 }, { /* sentinel */ }
369 MODULE_DEVICE_TABLE(of
, b53_mmap_of_table
);
371 static struct platform_driver b53_mmap_driver
= {
372 .probe
= b53_mmap_probe
,
373 .remove
= b53_mmap_remove
,
374 .shutdown
= b53_mmap_shutdown
,
376 .name
= "b53-switch",
377 .of_match_table
= b53_mmap_of_table
,
381 module_platform_driver(b53_mmap_driver
);
382 MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
383 MODULE_DESCRIPTION("B53 MMAP access driver");
384 MODULE_LICENSE("Dual BSD/GPL");