kernel: b53: add Register Access Bridge Registers (SRAB) interface
[openwrt/svn-archive/archive.git] / target / linux / generic / files / drivers / net / phy / b53 / b53_srab.c
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/platform_device.h>
22 #include <linux/platform_data/b53.h>
23
24 #include "b53_priv.h"
25
26 /* command and status register of the SRAB */
27 #define B53_SRAB_CMDSTAT 0x2c
28 #define B53_SRAB_CMDSTAT_RST BIT(2)
29 #define B53_SRAB_CMDSTAT_WRITE BIT(1)
30 #define B53_SRAB_CMDSTAT_GORDYN BIT(0)
31 #define B53_SRAB_CMDSTAT_PAGE 24
32 #define B53_SRAB_CMDSTAT_REG 16
33
34 /* high order word of write data to switch registe */
35 #define B53_SRAB_WD_H 0x30
36
37 /* low order word of write data to switch registe */
38 #define B53_SRAB_WD_L 0x34
39
40 /* high order word of read data from switch register */
41 #define B53_SRAB_RD_H 0x38
42
43 /* low order word of read data from switch register */
44 #define B53_SRAB_RD_L 0x3c
45
46 /* command and status register of the SRAB */
47 #define B53_SRAB_CTRLS 0x40
48 #define B53_SRAB_CTRLS_RCAREQ BIT(3)
49 #define B53_SRAB_CTRLS_RCAGNT BIT(4)
50 #define B53_SRAB_CTRLS_SW_INIT_DONE BIT(6)
51
52 /* the register captures interrupt pulses from the switch */
53 #define B53_SRAB_INTR 0x44
54
55 static int b53_srab_request_grant(struct b53_device *dev)
56 {
57 u8 __iomem *regs = dev->priv;
58 u32 ctrls;
59 int i;
60
61 ctrls = readl(regs + B53_SRAB_CTRLS);
62 ctrls |= B53_SRAB_CTRLS_RCAREQ;
63 writel(ctrls, regs + B53_SRAB_CTRLS);
64
65 for (i = 0; i < 20; i++) {
66 ctrls = readl(regs + B53_SRAB_CTRLS);
67 if (ctrls & B53_SRAB_CTRLS_RCAGNT)
68 break;
69 usleep_range(10, 100);
70 }
71 if (WARN_ON(i == 5))
72 return -EIO;
73
74 return 0;
75 }
76
77 static void b53_srab_release_grant(struct b53_device *dev)
78 {
79 u8 __iomem *regs = dev->priv;
80 u32 ctrls;
81
82 ctrls = readl(regs + B53_SRAB_CTRLS);
83 ctrls &= ~B53_SRAB_CTRLS_RCAREQ;
84 writel(ctrls, regs + B53_SRAB_CTRLS);
85 }
86
87 static int b53_srab_op(struct b53_device *dev, u8 page, u8 reg, u32 op)
88 {
89 int i;
90 u32 cmdstat;
91 u8 __iomem *regs = dev->priv;
92
93 /* set register address */
94 cmdstat = (page << B53_SRAB_CMDSTAT_PAGE) |
95 (reg << B53_SRAB_CMDSTAT_REG) |
96 B53_SRAB_CMDSTAT_GORDYN |
97 op;
98 writel(cmdstat, regs + B53_SRAB_CMDSTAT);
99
100 /* check if operation completed */
101 for (i = 0; i < 5; ++i) {
102 cmdstat = readl(regs + B53_SRAB_CMDSTAT);
103 if (!(cmdstat & B53_SRAB_CMDSTAT_GORDYN))
104 break;
105 usleep_range(10, 100);
106 }
107
108 if (WARN_ON(i == 5))
109 return -EIO;
110
111 return 0;
112 }
113
114 static int b53_srab_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
115 {
116 u8 __iomem *regs = dev->priv;
117 int ret = 0;
118
119 ret = b53_srab_request_grant(dev);
120 if (ret)
121 goto err;
122
123 ret = b53_srab_op(dev, page, reg, 0);
124 if (ret)
125 goto err;
126
127 *val = readl(regs + B53_SRAB_RD_L) & 0xff;
128
129 err:
130 b53_srab_release_grant(dev);
131
132 return ret;
133 }
134
135 static int b53_srab_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
136 {
137 u8 __iomem *regs = dev->priv;
138 int ret = 0;
139
140 ret = b53_srab_request_grant(dev);
141 if (ret)
142 goto err;
143
144 ret = b53_srab_op(dev, page, reg, 0);
145 if (ret)
146 goto err;
147
148 *val = readl(regs + B53_SRAB_RD_L) & 0xffff;
149
150 err:
151 b53_srab_release_grant(dev);
152
153 return ret;
154 }
155
156 static int b53_srab_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
157 {
158 u8 __iomem *regs = dev->priv;
159 int ret = 0;
160
161 ret = b53_srab_request_grant(dev);
162 if (ret)
163 goto err;
164
165 ret = b53_srab_op(dev, page, reg, 0);
166 if (ret)
167 goto err;
168
169 *val = readl(regs + B53_SRAB_RD_L);
170
171 err:
172 b53_srab_release_grant(dev);
173
174 return ret;
175 }
176
177 static int b53_srab_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
178 {
179 u8 __iomem *regs = dev->priv;
180 int ret = 0;
181
182 ret = b53_srab_request_grant(dev);
183 if (ret)
184 goto err;
185
186 ret = b53_srab_op(dev, page, reg, 0);
187 if (ret)
188 goto err;
189
190 *val = readl(regs + B53_SRAB_RD_L);
191 *val += ((u64)readl(regs + B53_SRAB_RD_H) & 0xffff) << 32;
192
193 err:
194 b53_srab_release_grant(dev);
195
196 return ret;
197 }
198
199 static int b53_srab_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
200 {
201 u8 __iomem *regs = dev->priv;
202 int ret = 0;
203
204 ret = b53_srab_request_grant(dev);
205 if (ret)
206 goto err;
207
208 ret = b53_srab_op(dev, page, reg, 0);
209 if (ret)
210 goto err;
211
212 *val = readl(regs + B53_SRAB_RD_L);
213 *val += (u64)readl(regs + B53_SRAB_RD_H) << 32;
214
215 err:
216 b53_srab_release_grant(dev);
217
218 return ret;
219 }
220
221 static int b53_srab_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
222 {
223 u8 __iomem *regs = dev->priv;
224 int ret = 0;
225
226 ret = b53_srab_request_grant(dev);
227 if (ret)
228 goto err;
229
230 writel(value, regs + B53_SRAB_WD_L);
231
232 ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
233
234 err:
235 b53_srab_release_grant(dev);
236
237 return ret;
238 }
239
240 static int b53_srab_write16(struct b53_device *dev, u8 page, u8 reg,
241 u16 value)
242 {
243 u8 __iomem *regs = dev->priv;
244 int ret = 0;
245
246 ret = b53_srab_request_grant(dev);
247 if (ret)
248 goto err;
249
250 writel(value, regs + B53_SRAB_WD_L);
251
252 ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
253
254 err:
255 b53_srab_release_grant(dev);
256
257 return ret;
258 }
259
260 static int b53_srab_write32(struct b53_device *dev, u8 page, u8 reg,
261 u32 value)
262 {
263 u8 __iomem *regs = dev->priv;
264 int ret = 0;
265
266 ret = b53_srab_request_grant(dev);
267 if (ret)
268 goto err;
269
270 writel(value, regs + B53_SRAB_WD_L);
271
272 ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
273
274 err:
275 b53_srab_release_grant(dev);
276
277 return ret;
278
279 }
280
281 static int b53_srab_write48(struct b53_device *dev, u8 page, u8 reg,
282 u64 value)
283 {
284 u8 __iomem *regs = dev->priv;
285 int ret = 0;
286
287 ret = b53_srab_request_grant(dev);
288 if (ret)
289 goto err;
290
291 writel((u32)value, regs + B53_SRAB_WD_L);
292 writel((u16)(value >> 32), regs + B53_SRAB_WD_H);
293
294 ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
295
296 err:
297 b53_srab_release_grant(dev);
298
299 return ret;
300
301 }
302
303 static int b53_srab_write64(struct b53_device *dev, u8 page, u8 reg,
304 u64 value)
305 {
306 u8 __iomem *regs = dev->priv;
307 int ret = 0;
308
309 ret = b53_srab_request_grant(dev);
310 if (ret)
311 goto err;
312
313 writel((u32)value, regs + B53_SRAB_WD_L);
314 writel((u32)(value >> 32), regs + B53_SRAB_WD_H);
315
316 ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
317
318 err:
319 b53_srab_release_grant(dev);
320
321 return ret;
322 }
323
324 static struct b53_io_ops b53_srab_ops = {
325 .read8 = b53_srab_read8,
326 .read16 = b53_srab_read16,
327 .read32 = b53_srab_read32,
328 .read48 = b53_srab_read48,
329 .read64 = b53_srab_read64,
330 .write8 = b53_srab_write8,
331 .write16 = b53_srab_write16,
332 .write32 = b53_srab_write32,
333 .write48 = b53_srab_write48,
334 .write64 = b53_srab_write64,
335 };
336
337 static int b53_srab_probe(struct platform_device *pdev)
338 {
339 struct b53_platform_data *pdata = pdev->dev.platform_data;
340 struct b53_device *dev;
341
342 if (!pdata)
343 return -EINVAL;
344
345 dev = b53_switch_alloc(&pdev->dev, &b53_srab_ops, pdata->regs);
346 if (!dev)
347 return -ENOMEM;
348
349 if (pdata)
350 dev->pdata = pdata;
351
352 pdev->dev.platform_data = dev;
353
354 return b53_switch_register(dev);
355 }
356
357 static int b53_srab_remove(struct platform_device *pdev)
358 {
359 struct b53_device *dev = pdev->dev.platform_data;
360
361 if (dev) {
362 pdev->dev.platform_data = dev->pdata;
363 b53_switch_remove(dev);
364 }
365
366 return 0;
367 }
368
369 static struct platform_driver b53_srab_driver = {
370 .probe = b53_srab_probe,
371 .remove = b53_srab_remove,
372 .driver = {
373 .name = "b53-srab-switch",
374 },
375 };
376
377 module_platform_driver(b53_srab_driver);
378 MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
379 MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver");
380 MODULE_LICENSE("Dual BSD/GPL");