xref: /linux/drivers/net/dsa/b53/b53_mmap.c (revision 0d240e7811c4ec1965760ee4643b5bbc9cfacbb3)
1 /*
2  * B53 register access through memory mapped registers
3  *
4  * Copyright (C) 2012-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 <linux/kernel.h>
20 #include <linux/kconfig.h>
21 #include <linux/module.h>
22 #include <linux/io.h>
23 #include <linux/platform_device.h>
24 #include <linux/platform_data/b53.h>
25 
26 #include "b53_priv.h"
27 
28 struct b53_mmap_priv {
29 	void __iomem *regs;
30 };
31 
32 static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
33 {
34 	u8 __iomem *regs = dev->priv;
35 
36 	*val = readb(regs + (page << 8) + reg);
37 
38 	return 0;
39 }
40 
41 static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
42 {
43 	u8 __iomem *regs = dev->priv;
44 
45 	if (WARN_ON(reg % 2))
46 		return -EINVAL;
47 
48 	if (dev->pdata && dev->pdata->big_endian)
49 		*val = ioread16be(regs + (page << 8) + reg);
50 	else
51 		*val = readw(regs + (page << 8) + reg);
52 
53 	return 0;
54 }
55 
56 static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
57 {
58 	u8 __iomem *regs = dev->priv;
59 
60 	if (WARN_ON(reg % 4))
61 		return -EINVAL;
62 
63 	if (dev->pdata && dev->pdata->big_endian)
64 		*val = ioread32be(regs + (page << 8) + reg);
65 	else
66 		*val = readl(regs + (page << 8) + reg);
67 
68 	return 0;
69 }
70 
71 static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
72 {
73 	if (WARN_ON(reg % 2))
74 		return -EINVAL;
75 
76 	if (reg % 4) {
77 		u16 lo;
78 		u32 hi;
79 
80 		b53_mmap_read16(dev, page, reg, &lo);
81 		b53_mmap_read32(dev, page, reg + 2, &hi);
82 
83 		*val = ((u64)hi << 16) | lo;
84 	} else {
85 		u32 lo;
86 		u16 hi;
87 
88 		b53_mmap_read32(dev, page, reg, &lo);
89 		b53_mmap_read16(dev, page, reg + 4, &hi);
90 
91 		*val = ((u64)hi << 32) | lo;
92 	}
93 
94 	return 0;
95 }
96 
97 static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
98 {
99 	u32 hi, lo;
100 
101 	if (WARN_ON(reg % 4))
102 		return -EINVAL;
103 
104 	b53_mmap_read32(dev, page, reg, &lo);
105 	b53_mmap_read32(dev, page, reg + 4, &hi);
106 
107 	*val = ((u64)hi << 32) | lo;
108 
109 	return 0;
110 }
111 
112 static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
113 {
114 	u8 __iomem *regs = dev->priv;
115 
116 	writeb(value, regs + (page << 8) + reg);
117 
118 	return 0;
119 }
120 
121 static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg,
122 			    u16 value)
123 {
124 	u8 __iomem *regs = dev->priv;
125 
126 	if (WARN_ON(reg % 2))
127 		return -EINVAL;
128 
129 	if (dev->pdata && dev->pdata->big_endian)
130 		iowrite16be(value, regs + (page << 8) + reg);
131 	else
132 		writew(value, regs + (page << 8) + reg);
133 
134 	return 0;
135 }
136 
137 static int b53_mmap_write32(struct b53_device *dev, u8 page, u8 reg,
138 			    u32 value)
139 {
140 	u8 __iomem *regs = dev->priv;
141 
142 	if (WARN_ON(reg % 4))
143 		return -EINVAL;
144 
145 	if (dev->pdata && dev->pdata->big_endian)
146 		iowrite32be(value, regs + (page << 8) + reg);
147 	else
148 		writel(value, regs + (page << 8) + reg);
149 
150 	return 0;
151 }
152 
153 static int b53_mmap_write48(struct b53_device *dev, u8 page, u8 reg,
154 			    u64 value)
155 {
156 	if (WARN_ON(reg % 2))
157 		return -EINVAL;
158 
159 	if (reg % 4) {
160 		u32 hi = (u32)(value >> 16);
161 		u16 lo = (u16)value;
162 
163 		b53_mmap_write16(dev, page, reg, lo);
164 		b53_mmap_write32(dev, page, reg + 2, hi);
165 	} else {
166 		u16 hi = (u16)(value >> 32);
167 		u32 lo = (u32)value;
168 
169 		b53_mmap_write32(dev, page, reg, lo);
170 		b53_mmap_write16(dev, page, reg + 4, hi);
171 	}
172 
173 	return 0;
174 }
175 
176 static int b53_mmap_write64(struct b53_device *dev, u8 page, u8 reg,
177 			    u64 value)
178 {
179 	u32 hi, lo;
180 
181 	hi = upper_32_bits(value);
182 	lo = lower_32_bits(value);
183 
184 	if (WARN_ON(reg % 4))
185 		return -EINVAL;
186 
187 	b53_mmap_write32(dev, page, reg, lo);
188 	b53_mmap_write32(dev, page, reg + 4, hi);
189 
190 	return 0;
191 }
192 
193 static struct b53_io_ops b53_mmap_ops = {
194 	.read8 = b53_mmap_read8,
195 	.read16 = b53_mmap_read16,
196 	.read32 = b53_mmap_read32,
197 	.read48 = b53_mmap_read48,
198 	.read64 = b53_mmap_read64,
199 	.write8 = b53_mmap_write8,
200 	.write16 = b53_mmap_write16,
201 	.write32 = b53_mmap_write32,
202 	.write48 = b53_mmap_write48,
203 	.write64 = b53_mmap_write64,
204 };
205 
206 static int b53_mmap_probe(struct platform_device *pdev)
207 {
208 	struct b53_platform_data *pdata = pdev->dev.platform_data;
209 	struct b53_device *dev;
210 
211 	if (!pdata)
212 		return -EINVAL;
213 
214 	dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, pdata->regs);
215 	if (!dev)
216 		return -ENOMEM;
217 
218 	if (pdata)
219 		dev->pdata = pdata;
220 
221 	platform_set_drvdata(pdev, dev);
222 
223 	return b53_switch_register(dev);
224 }
225 
226 static int b53_mmap_remove(struct platform_device *pdev)
227 {
228 	struct b53_device *dev = platform_get_drvdata(pdev);
229 
230 	if (dev)
231 		b53_switch_remove(dev);
232 
233 	return 0;
234 }
235 
236 static const struct of_device_id b53_mmap_of_table[] = {
237 	{ .compatible = "brcm,bcm3384-switch" },
238 	{ .compatible = "brcm,bcm6328-switch" },
239 	{ .compatible = "brcm,bcm6368-switch" },
240 	{ .compatible = "brcm,bcm63xx-switch" },
241 	{ /* sentinel */ },
242 };
243 
244 static struct platform_driver b53_mmap_driver = {
245 	.probe = b53_mmap_probe,
246 	.remove = b53_mmap_remove,
247 	.driver = {
248 		.name = "b53-switch",
249 		.of_match_table = b53_mmap_of_table,
250 	},
251 };
252 
253 module_platform_driver(b53_mmap_driver);
254 MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
255 MODULE_DESCRIPTION("B53 MMAP access driver");
256 MODULE_LICENSE("Dual BSD/GPL");
257