diff options
author | Vitaly Bordug <vbordug@ru.mvista.com> | 2006-08-15 02:00:30 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-08-19 17:44:31 -0400 |
commit | 5b4b8454344a0391bb0f69fda0f4ec8e1f0d2fed (patch) | |
tree | a5e662cdc03d319e56a277281dcde754150276f4 /drivers/net/fs_enet/mii-bitbang.c | |
parent | 11b0bacd717c285c94dbb56505a28434b34f0639 (diff) |
[PATCH] FS_ENET: use PAL for mii management
This patch should update the fs_enet infrastructure to utilize Phy Abstraction
Layer subsystem. Along with the above, there are apparent bugfixes, overhaul
and improvements.
Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/fs_enet/mii-bitbang.c')
-rw-r--r-- | drivers/net/fs_enet/mii-bitbang.c | 448 |
1 files changed, 226 insertions, 222 deletions
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index 48f9cf83ab6f..0b9b8b5c847c 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/mii.h> | 33 | #include <linux/mii.h> |
34 | #include <linux/ethtool.h> | 34 | #include <linux/ethtool.h> |
35 | #include <linux/bitops.h> | 35 | #include <linux/bitops.h> |
36 | #include <linux/platform_device.h> | ||
36 | 37 | ||
37 | #include <asm/pgtable.h> | 38 | #include <asm/pgtable.h> |
38 | #include <asm/irq.h> | 39 | #include <asm/irq.h> |
@@ -40,129 +41,25 @@ | |||
40 | 41 | ||
41 | #include "fs_enet.h" | 42 | #include "fs_enet.h" |
42 | 43 | ||
43 | #ifdef CONFIG_8xx | 44 | static int bitbang_prep_bit(u8 **datp, u8 *mskp, |
44 | static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit) | 45 | struct fs_mii_bit *mii_bit) |
45 | { | 46 | { |
46 | immap_t *im = (immap_t *)fs_enet_immap; | 47 | void *dat; |
47 | void *dir, *dat, *ppar; | ||
48 | int adv; | 48 | int adv; |
49 | u8 msk; | 49 | u8 msk; |
50 | 50 | ||
51 | switch (port) { | 51 | dat = (void*) mii_bit->offset; |
52 | case fsiop_porta: | ||
53 | dir = &im->im_ioport.iop_padir; | ||
54 | dat = &im->im_ioport.iop_padat; | ||
55 | ppar = &im->im_ioport.iop_papar; | ||
56 | break; | ||
57 | |||
58 | case fsiop_portb: | ||
59 | dir = &im->im_cpm.cp_pbdir; | ||
60 | dat = &im->im_cpm.cp_pbdat; | ||
61 | ppar = &im->im_cpm.cp_pbpar; | ||
62 | break; | ||
63 | |||
64 | case fsiop_portc: | ||
65 | dir = &im->im_ioport.iop_pcdir; | ||
66 | dat = &im->im_ioport.iop_pcdat; | ||
67 | ppar = &im->im_ioport.iop_pcpar; | ||
68 | break; | ||
69 | |||
70 | case fsiop_portd: | ||
71 | dir = &im->im_ioport.iop_pddir; | ||
72 | dat = &im->im_ioport.iop_pddat; | ||
73 | ppar = &im->im_ioport.iop_pdpar; | ||
74 | break; | ||
75 | |||
76 | case fsiop_porte: | ||
77 | dir = &im->im_cpm.cp_pedir; | ||
78 | dat = &im->im_cpm.cp_pedat; | ||
79 | ppar = &im->im_cpm.cp_pepar; | ||
80 | break; | ||
81 | |||
82 | default: | ||
83 | printk(KERN_ERR DRV_MODULE_NAME | ||
84 | "Illegal port value %d!\n", port); | ||
85 | return -EINVAL; | ||
86 | } | ||
87 | |||
88 | adv = bit >> 3; | ||
89 | dir = (char *)dir + adv; | ||
90 | dat = (char *)dat + adv; | ||
91 | ppar = (char *)ppar + adv; | ||
92 | |||
93 | msk = 1 << (7 - (bit & 7)); | ||
94 | if ((in_8(ppar) & msk) != 0) { | ||
95 | printk(KERN_ERR DRV_MODULE_NAME | ||
96 | "pin %d on port %d is not general purpose!\n", bit, port); | ||
97 | return -EINVAL; | ||
98 | } | ||
99 | |||
100 | *dirp = dir; | ||
101 | *datp = dat; | ||
102 | *mskp = msk; | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | #endif | ||
107 | |||
108 | #ifdef CONFIG_8260 | ||
109 | static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit) | ||
110 | { | ||
111 | iop_cpm2_t *io = &((cpm2_map_t *)fs_enet_immap)->im_ioport; | ||
112 | void *dir, *dat, *ppar; | ||
113 | int adv; | ||
114 | u8 msk; | ||
115 | |||
116 | switch (port) { | ||
117 | case fsiop_porta: | ||
118 | dir = &io->iop_pdira; | ||
119 | dat = &io->iop_pdata; | ||
120 | ppar = &io->iop_ppara; | ||
121 | break; | ||
122 | |||
123 | case fsiop_portb: | ||
124 | dir = &io->iop_pdirb; | ||
125 | dat = &io->iop_pdatb; | ||
126 | ppar = &io->iop_pparb; | ||
127 | break; | ||
128 | |||
129 | case fsiop_portc: | ||
130 | dir = &io->iop_pdirc; | ||
131 | dat = &io->iop_pdatc; | ||
132 | ppar = &io->iop_pparc; | ||
133 | break; | ||
134 | |||
135 | case fsiop_portd: | ||
136 | dir = &io->iop_pdird; | ||
137 | dat = &io->iop_pdatd; | ||
138 | ppar = &io->iop_ppard; | ||
139 | break; | ||
140 | |||
141 | default: | ||
142 | printk(KERN_ERR DRV_MODULE_NAME | ||
143 | "Illegal port value %d!\n", port); | ||
144 | return -EINVAL; | ||
145 | } | ||
146 | 52 | ||
147 | adv = bit >> 3; | 53 | adv = mii_bit->bit >> 3; |
148 | dir = (char *)dir + adv; | ||
149 | dat = (char *)dat + adv; | 54 | dat = (char *)dat + adv; |
150 | ppar = (char *)ppar + adv; | ||
151 | 55 | ||
152 | msk = 1 << (7 - (bit & 7)); | 56 | msk = 1 << (7 - (mii_bit->bit & 7)); |
153 | if ((in_8(ppar) & msk) != 0) { | ||
154 | printk(KERN_ERR DRV_MODULE_NAME | ||
155 | "pin %d on port %d is not general purpose!\n", bit, port); | ||
156 | return -EINVAL; | ||
157 | } | ||
158 | 57 | ||
159 | *dirp = dir; | ||
160 | *datp = dat; | 58 | *datp = dat; |
161 | *mskp = msk; | 59 | *mskp = msk; |
162 | 60 | ||
163 | return 0; | 61 | return 0; |
164 | } | 62 | } |
165 | #endif | ||
166 | 63 | ||
167 | static inline void bb_set(u8 *p, u8 m) | 64 | static inline void bb_set(u8 *p, u8 m) |
168 | { | 65 | { |
@@ -179,44 +76,44 @@ static inline int bb_read(u8 *p, u8 m) | |||
179 | return (in_8(p) & m) != 0; | 76 | return (in_8(p) & m) != 0; |
180 | } | 77 | } |
181 | 78 | ||
182 | static inline void mdio_active(struct fs_enet_mii_bus *bus) | 79 | static inline void mdio_active(struct bb_info *bitbang) |
183 | { | 80 | { |
184 | bb_set(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk); | 81 | bb_set(bitbang->mdio_dir, bitbang->mdio_dir_msk); |
185 | } | 82 | } |
186 | 83 | ||
187 | static inline void mdio_tristate(struct fs_enet_mii_bus *bus) | 84 | static inline void mdio_tristate(struct bb_info *bitbang ) |
188 | { | 85 | { |
189 | bb_clr(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk); | 86 | bb_clr(bitbang->mdio_dir, bitbang->mdio_dir_msk); |
190 | } | 87 | } |
191 | 88 | ||
192 | static inline int mdio_read(struct fs_enet_mii_bus *bus) | 89 | static inline int mdio_read(struct bb_info *bitbang ) |
193 | { | 90 | { |
194 | return bb_read(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); | 91 | return bb_read(bitbang->mdio_dat, bitbang->mdio_dat_msk); |
195 | } | 92 | } |
196 | 93 | ||
197 | static inline void mdio(struct fs_enet_mii_bus *bus, int what) | 94 | static inline void mdio(struct bb_info *bitbang , int what) |
198 | { | 95 | { |
199 | if (what) | 96 | if (what) |
200 | bb_set(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); | 97 | bb_set(bitbang->mdio_dat, bitbang->mdio_dat_msk); |
201 | else | 98 | else |
202 | bb_clr(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); | 99 | bb_clr(bitbang->mdio_dat, bitbang->mdio_dat_msk); |
203 | } | 100 | } |
204 | 101 | ||
205 | static inline void mdc(struct fs_enet_mii_bus *bus, int what) | 102 | static inline void mdc(struct bb_info *bitbang , int what) |
206 | { | 103 | { |
207 | if (what) | 104 | if (what) |
208 | bb_set(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk); | 105 | bb_set(bitbang->mdc_dat, bitbang->mdc_msk); |
209 | else | 106 | else |
210 | bb_clr(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk); | 107 | bb_clr(bitbang->mdc_dat, bitbang->mdc_msk); |
211 | } | 108 | } |
212 | 109 | ||
213 | static inline void mii_delay(struct fs_enet_mii_bus *bus) | 110 | static inline void mii_delay(struct bb_info *bitbang ) |
214 | { | 111 | { |
215 | udelay(bus->bus_info->i.bitbang.delay); | 112 | udelay(bitbang->delay); |
216 | } | 113 | } |
217 | 114 | ||
218 | /* Utility to send the preamble, address, and register (common to read and write). */ | 115 | /* Utility to send the preamble, address, and register (common to read and write). */ |
219 | static void bitbang_pre(struct fs_enet_mii_bus *bus, int read, u8 addr, u8 reg) | 116 | static void bitbang_pre(struct bb_info *bitbang , int read, u8 addr, u8 reg) |
220 | { | 117 | { |
221 | int j; | 118 | int j; |
222 | 119 | ||
@@ -228,177 +125,284 @@ static void bitbang_pre(struct fs_enet_mii_bus *bus, int read, u8 addr, u8 reg) | |||
228 | * but it is safer and will be much more robust. | 125 | * but it is safer and will be much more robust. |
229 | */ | 126 | */ |
230 | 127 | ||
231 | mdio_active(bus); | 128 | mdio_active(bitbang); |
232 | mdio(bus, 1); | 129 | mdio(bitbang, 1); |
233 | for (j = 0; j < 32; j++) { | 130 | for (j = 0; j < 32; j++) { |
234 | mdc(bus, 0); | 131 | mdc(bitbang, 0); |
235 | mii_delay(bus); | 132 | mii_delay(bitbang); |
236 | mdc(bus, 1); | 133 | mdc(bitbang, 1); |
237 | mii_delay(bus); | 134 | mii_delay(bitbang); |
238 | } | 135 | } |
239 | 136 | ||
240 | /* send the start bit (01) and the read opcode (10) or write (10) */ | 137 | /* send the start bit (01) and the read opcode (10) or write (10) */ |
241 | mdc(bus, 0); | 138 | mdc(bitbang, 0); |
242 | mdio(bus, 0); | 139 | mdio(bitbang, 0); |
243 | mii_delay(bus); | 140 | mii_delay(bitbang); |
244 | mdc(bus, 1); | 141 | mdc(bitbang, 1); |
245 | mii_delay(bus); | 142 | mii_delay(bitbang); |
246 | mdc(bus, 0); | 143 | mdc(bitbang, 0); |
247 | mdio(bus, 1); | 144 | mdio(bitbang, 1); |
248 | mii_delay(bus); | 145 | mii_delay(bitbang); |
249 | mdc(bus, 1); | 146 | mdc(bitbang, 1); |
250 | mii_delay(bus); | 147 | mii_delay(bitbang); |
251 | mdc(bus, 0); | 148 | mdc(bitbang, 0); |
252 | mdio(bus, read); | 149 | mdio(bitbang, read); |
253 | mii_delay(bus); | 150 | mii_delay(bitbang); |
254 | mdc(bus, 1); | 151 | mdc(bitbang, 1); |
255 | mii_delay(bus); | 152 | mii_delay(bitbang); |
256 | mdc(bus, 0); | 153 | mdc(bitbang, 0); |
257 | mdio(bus, !read); | 154 | mdio(bitbang, !read); |
258 | mii_delay(bus); | 155 | mii_delay(bitbang); |
259 | mdc(bus, 1); | 156 | mdc(bitbang, 1); |
260 | mii_delay(bus); | 157 | mii_delay(bitbang); |
261 | 158 | ||
262 | /* send the PHY address */ | 159 | /* send the PHY address */ |
263 | for (j = 0; j < 5; j++) { | 160 | for (j = 0; j < 5; j++) { |
264 | mdc(bus, 0); | 161 | mdc(bitbang, 0); |
265 | mdio(bus, (addr & 0x10) != 0); | 162 | mdio(bitbang, (addr & 0x10) != 0); |
266 | mii_delay(bus); | 163 | mii_delay(bitbang); |
267 | mdc(bus, 1); | 164 | mdc(bitbang, 1); |
268 | mii_delay(bus); | 165 | mii_delay(bitbang); |
269 | addr <<= 1; | 166 | addr <<= 1; |
270 | } | 167 | } |
271 | 168 | ||
272 | /* send the register address */ | 169 | /* send the register address */ |
273 | for (j = 0; j < 5; j++) { | 170 | for (j = 0; j < 5; j++) { |
274 | mdc(bus, 0); | 171 | mdc(bitbang, 0); |
275 | mdio(bus, (reg & 0x10) != 0); | 172 | mdio(bitbang, (reg & 0x10) != 0); |
276 | mii_delay(bus); | 173 | mii_delay(bitbang); |
277 | mdc(bus, 1); | 174 | mdc(bitbang, 1); |
278 | mii_delay(bus); | 175 | mii_delay(bitbang); |
279 | reg <<= 1; | 176 | reg <<= 1; |
280 | } | 177 | } |
281 | } | 178 | } |
282 | 179 | ||
283 | static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location) | 180 | static int fs_enet_mii_bb_read(struct mii_bus *bus , int phy_id, int location) |
284 | { | 181 | { |
285 | u16 rdreg; | 182 | u16 rdreg; |
286 | int ret, j; | 183 | int ret, j; |
287 | u8 addr = phy_id & 0xff; | 184 | u8 addr = phy_id & 0xff; |
288 | u8 reg = location & 0xff; | 185 | u8 reg = location & 0xff; |
186 | struct bb_info* bitbang = bus->priv; | ||
289 | 187 | ||
290 | bitbang_pre(bus, 1, addr, reg); | 188 | bitbang_pre(bitbang, 1, addr, reg); |
291 | 189 | ||
292 | /* tri-state our MDIO I/O pin so we can read */ | 190 | /* tri-state our MDIO I/O pin so we can read */ |
293 | mdc(bus, 0); | 191 | mdc(bitbang, 0); |
294 | mdio_tristate(bus); | 192 | mdio_tristate(bitbang); |
295 | mii_delay(bus); | 193 | mii_delay(bitbang); |
296 | mdc(bus, 1); | 194 | mdc(bitbang, 1); |
297 | mii_delay(bus); | 195 | mii_delay(bitbang); |
298 | 196 | ||
299 | /* check the turnaround bit: the PHY should be driving it to zero */ | 197 | /* check the turnaround bit: the PHY should be driving it to zero */ |
300 | if (mdio_read(bus) != 0) { | 198 | if (mdio_read(bitbang) != 0) { |
301 | /* PHY didn't drive TA low */ | 199 | /* PHY didn't drive TA low */ |
302 | for (j = 0; j < 32; j++) { | 200 | for (j = 0; j < 32; j++) { |
303 | mdc(bus, 0); | 201 | mdc(bitbang, 0); |
304 | mii_delay(bus); | 202 | mii_delay(bitbang); |
305 | mdc(bus, 1); | 203 | mdc(bitbang, 1); |
306 | mii_delay(bus); | 204 | mii_delay(bitbang); |
307 | } | 205 | } |
308 | ret = -1; | 206 | ret = -1; |
309 | goto out; | 207 | goto out; |
310 | } | 208 | } |
311 | 209 | ||
312 | mdc(bus, 0); | 210 | mdc(bitbang, 0); |
313 | mii_delay(bus); | 211 | mii_delay(bitbang); |
314 | 212 | ||
315 | /* read 16 bits of register data, MSB first */ | 213 | /* read 16 bits of register data, MSB first */ |
316 | rdreg = 0; | 214 | rdreg = 0; |
317 | for (j = 0; j < 16; j++) { | 215 | for (j = 0; j < 16; j++) { |
318 | mdc(bus, 1); | 216 | mdc(bitbang, 1); |
319 | mii_delay(bus); | 217 | mii_delay(bitbang); |
320 | rdreg <<= 1; | 218 | rdreg <<= 1; |
321 | rdreg |= mdio_read(bus); | 219 | rdreg |= mdio_read(bitbang); |
322 | mdc(bus, 0); | 220 | mdc(bitbang, 0); |
323 | mii_delay(bus); | 221 | mii_delay(bitbang); |
324 | } | 222 | } |
325 | 223 | ||
326 | mdc(bus, 1); | 224 | mdc(bitbang, 1); |
327 | mii_delay(bus); | 225 | mii_delay(bitbang); |
328 | mdc(bus, 0); | 226 | mdc(bitbang, 0); |
329 | mii_delay(bus); | 227 | mii_delay(bitbang); |
330 | mdc(bus, 1); | 228 | mdc(bitbang, 1); |
331 | mii_delay(bus); | 229 | mii_delay(bitbang); |
332 | 230 | ||
333 | ret = rdreg; | 231 | ret = rdreg; |
334 | out: | 232 | out: |
335 | return ret; | 233 | return ret; |
336 | } | 234 | } |
337 | 235 | ||
338 | static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val) | 236 | static int fs_enet_mii_bb_write(struct mii_bus *bus, int phy_id, int location, u16 val) |
339 | { | 237 | { |
340 | int j; | 238 | int j; |
239 | struct bb_info* bitbang = bus->priv; | ||
240 | |||
341 | u8 addr = phy_id & 0xff; | 241 | u8 addr = phy_id & 0xff; |
342 | u8 reg = location & 0xff; | 242 | u8 reg = location & 0xff; |
343 | u16 value = val & 0xffff; | 243 | u16 value = val & 0xffff; |
344 | 244 | ||
345 | bitbang_pre(bus, 0, addr, reg); | 245 | bitbang_pre(bitbang, 0, addr, reg); |
346 | 246 | ||
347 | /* send the turnaround (10) */ | 247 | /* send the turnaround (10) */ |
348 | mdc(bus, 0); | 248 | mdc(bitbang, 0); |
349 | mdio(bus, 1); | 249 | mdio(bitbang, 1); |
350 | mii_delay(bus); | 250 | mii_delay(bitbang); |
351 | mdc(bus, 1); | 251 | mdc(bitbang, 1); |
352 | mii_delay(bus); | 252 | mii_delay(bitbang); |
353 | mdc(bus, 0); | 253 | mdc(bitbang, 0); |
354 | mdio(bus, 0); | 254 | mdio(bitbang, 0); |
355 | mii_delay(bus); | 255 | mii_delay(bitbang); |
356 | mdc(bus, 1); | 256 | mdc(bitbang, 1); |
357 | mii_delay(bus); | 257 | mii_delay(bitbang); |
358 | 258 | ||
359 | /* write 16 bits of register data, MSB first */ | 259 | /* write 16 bits of register data, MSB first */ |
360 | for (j = 0; j < 16; j++) { | 260 | for (j = 0; j < 16; j++) { |
361 | mdc(bus, 0); | 261 | mdc(bitbang, 0); |
362 | mdio(bus, (value & 0x8000) != 0); | 262 | mdio(bitbang, (value & 0x8000) != 0); |
363 | mii_delay(bus); | 263 | mii_delay(bitbang); |
364 | mdc(bus, 1); | 264 | mdc(bitbang, 1); |
365 | mii_delay(bus); | 265 | mii_delay(bitbang); |
366 | value <<= 1; | 266 | value <<= 1; |
367 | } | 267 | } |
368 | 268 | ||
369 | /* | 269 | /* |
370 | * Tri-state the MDIO line. | 270 | * Tri-state the MDIO line. |
371 | */ | 271 | */ |
372 | mdio_tristate(bus); | 272 | mdio_tristate(bitbang); |
373 | mdc(bus, 0); | 273 | mdc(bitbang, 0); |
374 | mii_delay(bus); | 274 | mii_delay(bitbang); |
375 | mdc(bus, 1); | 275 | mdc(bitbang, 1); |
376 | mii_delay(bus); | 276 | mii_delay(bitbang); |
277 | return 0; | ||
377 | } | 278 | } |
378 | 279 | ||
379 | int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus) | 280 | static int fs_enet_mii_bb_reset(struct mii_bus *bus) |
281 | { | ||
282 | /*nothing here - dunno how to reset it*/ | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static int fs_mii_bitbang_init(struct bb_info *bitbang, struct fs_mii_bb_platform_info* fmpi) | ||
380 | { | 287 | { |
381 | const struct fs_mii_bus_info *bi = bus->bus_info; | ||
382 | int r; | 288 | int r; |
383 | 289 | ||
384 | r = bitbang_prep_bit(&bus->bitbang.mdio_dir, | 290 | bitbang->delay = fmpi->delay; |
385 | &bus->bitbang.mdio_dat, | 291 | |
386 | &bus->bitbang.mdio_msk, | 292 | r = bitbang_prep_bit(&bitbang->mdio_dir, |
387 | bi->i.bitbang.mdio_port, | 293 | &bitbang->mdio_dir_msk, |
388 | bi->i.bitbang.mdio_bit); | 294 | &fmpi->mdio_dir); |
389 | if (r != 0) | 295 | if (r != 0) |
390 | return r; | 296 | return r; |
391 | 297 | ||
392 | r = bitbang_prep_bit(&bus->bitbang.mdc_dir, | 298 | r = bitbang_prep_bit(&bitbang->mdio_dat, |
393 | &bus->bitbang.mdc_dat, | 299 | &bitbang->mdio_dat_msk, |
394 | &bus->bitbang.mdc_msk, | 300 | &fmpi->mdio_dat); |
395 | bi->i.bitbang.mdc_port, | ||
396 | bi->i.bitbang.mdc_bit); | ||
397 | if (r != 0) | 301 | if (r != 0) |
398 | return r; | 302 | return r; |
399 | 303 | ||
400 | bus->mii_read = mii_read; | 304 | r = bitbang_prep_bit(&bitbang->mdc_dat, |
401 | bus->mii_write = mii_write; | 305 | &bitbang->mdc_msk, |
306 | &fmpi->mdc_dat); | ||
307 | if (r != 0) | ||
308 | return r; | ||
402 | 309 | ||
403 | return 0; | 310 | return 0; |
404 | } | 311 | } |
312 | |||
313 | |||
314 | static int __devinit fs_enet_mdio_probe(struct device *dev) | ||
315 | { | ||
316 | struct platform_device *pdev = to_platform_device(dev); | ||
317 | struct fs_mii_bb_platform_info *pdata; | ||
318 | struct mii_bus *new_bus; | ||
319 | struct bb_info *bitbang; | ||
320 | int err = 0; | ||
321 | |||
322 | if (NULL == dev) | ||
323 | return -EINVAL; | ||
324 | |||
325 | new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); | ||
326 | |||
327 | if (NULL == new_bus) | ||
328 | return -ENOMEM; | ||
329 | |||
330 | bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL); | ||
331 | |||
332 | if (NULL == bitbang) | ||
333 | return -ENOMEM; | ||
334 | |||
335 | new_bus->name = "BB MII Bus", | ||
336 | new_bus->read = &fs_enet_mii_bb_read, | ||
337 | new_bus->write = &fs_enet_mii_bb_write, | ||
338 | new_bus->reset = &fs_enet_mii_bb_reset, | ||
339 | new_bus->id = pdev->id; | ||
340 | |||
341 | new_bus->phy_mask = ~0x9; | ||
342 | pdata = (struct fs_mii_bb_platform_info *)pdev->dev.platform_data; | ||
343 | |||
344 | if (NULL == pdata) { | ||
345 | printk(KERN_ERR "gfar mdio %d: Missing platform data!\n", pdev->id); | ||
346 | return -ENODEV; | ||
347 | } | ||
348 | |||
349 | /*set up workspace*/ | ||
350 | fs_mii_bitbang_init(bitbang, pdata); | ||
351 | |||
352 | new_bus->priv = bitbang; | ||
353 | |||
354 | new_bus->irq = pdata->irq; | ||
355 | |||
356 | new_bus->dev = dev; | ||
357 | dev_set_drvdata(dev, new_bus); | ||
358 | |||
359 | err = mdiobus_register(new_bus); | ||
360 | |||
361 | if (0 != err) { | ||
362 | printk (KERN_ERR "%s: Cannot register as MDIO bus\n", | ||
363 | new_bus->name); | ||
364 | goto bus_register_fail; | ||
365 | } | ||
366 | |||
367 | return 0; | ||
368 | |||
369 | bus_register_fail: | ||
370 | kfree(bitbang); | ||
371 | kfree(new_bus); | ||
372 | |||
373 | return err; | ||
374 | } | ||
375 | |||
376 | |||
377 | static int fs_enet_mdio_remove(struct device *dev) | ||
378 | { | ||
379 | struct mii_bus *bus = dev_get_drvdata(dev); | ||
380 | |||
381 | mdiobus_unregister(bus); | ||
382 | |||
383 | dev_set_drvdata(dev, NULL); | ||
384 | |||
385 | iounmap((void *) (&bus->priv)); | ||
386 | bus->priv = NULL; | ||
387 | kfree(bus); | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | static struct device_driver fs_enet_bb_mdio_driver = { | ||
393 | .name = "fsl-bb-mdio", | ||
394 | .bus = &platform_bus_type, | ||
395 | .probe = fs_enet_mdio_probe, | ||
396 | .remove = fs_enet_mdio_remove, | ||
397 | }; | ||
398 | |||
399 | int fs_enet_mdio_bb_init(void) | ||
400 | { | ||
401 | return driver_register(&fs_enet_bb_mdio_driver); | ||
402 | } | ||
403 | |||
404 | void fs_enet_mdio_bb_exit(void) | ||
405 | { | ||
406 | driver_unregister(&fs_enet_bb_mdio_driver); | ||
407 | } | ||
408 | |||