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