OpenWrt – Blame information for rev 4
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
4 | office | 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 | platform_set_drvdata(pdev, 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 = platform_get_drvdata(pdev); |
||
360 | |||
361 | if (dev) |
||
362 | b53_switch_remove(dev); |
||
363 | |||
364 | return 0; |
||
365 | } |
||
366 | |||
367 | static struct platform_driver b53_srab_driver = { |
||
368 | .probe = b53_srab_probe, |
||
369 | .remove = b53_srab_remove, |
||
370 | .driver = { |
||
371 | .name = "b53-srab-switch", |
||
372 | }, |
||
373 | }; |
||
374 | |||
375 | module_platform_driver(b53_srab_driver); |
||
376 | MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>"); |
||
377 | MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver"); |
||
378 | MODULE_LICENSE("Dual BSD/GPL"); |