Version:  2.0.40 2.2.26 2.4.37 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16

Linux/arch/powerpc/platforms/pasemi/gpio_mdio.c

  1 /*
  2  * Copyright (C) 2006-2007 PA Semi, Inc
  3  *
  4  * Author: Olof Johansson, PA Semi
  5  *
  6  * Maintained by: Olof Johansson <olof@lixom.net>
  7  *
  8  * Based on drivers/net/fs_enet/mii-bitbang.c.
  9  *
 10  * This program is free software; you can redistribute it and/or modify
 11  * it under the terms of the GNU General Public License version 2 as
 12  * published by the Free Software Foundation.
 13  *
 14  * This program is distributed in the hope that it will be useful,
 15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 17  * GNU General Public License for more details.
 18  *
 19  * You should have received a copy of the GNU General Public License
 20  * along with this program; if not, write to the Free Software
 21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 22  */
 23 
 24 #include <linux/io.h>
 25 #include <linux/module.h>
 26 #include <linux/types.h>
 27 #include <linux/slab.h>
 28 #include <linux/sched.h>
 29 #include <linux/errno.h>
 30 #include <linux/ioport.h>
 31 #include <linux/interrupt.h>
 32 #include <linux/phy.h>
 33 #include <linux/of_address.h>
 34 #include <linux/of_mdio.h>
 35 #include <linux/of_platform.h>
 36 
 37 #define DELAY 1
 38 
 39 static void __iomem *gpio_regs;
 40 
 41 struct gpio_priv {
 42         int mdc_pin;
 43         int mdio_pin;
 44         int mdio_irqs[PHY_MAX_ADDR];
 45 };
 46 
 47 #define MDC_PIN(bus)    (((struct gpio_priv *)bus->priv)->mdc_pin)
 48 #define MDIO_PIN(bus)   (((struct gpio_priv *)bus->priv)->mdio_pin)
 49 
 50 static inline void mdio_lo(struct mii_bus *bus)
 51 {
 52         out_le32(gpio_regs+0x10, 1 << MDIO_PIN(bus));
 53 }
 54 
 55 static inline void mdio_hi(struct mii_bus *bus)
 56 {
 57         out_le32(gpio_regs, 1 << MDIO_PIN(bus));
 58 }
 59 
 60 static inline void mdc_lo(struct mii_bus *bus)
 61 {
 62         out_le32(gpio_regs+0x10, 1 << MDC_PIN(bus));
 63 }
 64 
 65 static inline void mdc_hi(struct mii_bus *bus)
 66 {
 67         out_le32(gpio_regs, 1 << MDC_PIN(bus));
 68 }
 69 
 70 static inline void mdio_active(struct mii_bus *bus)
 71 {
 72         out_le32(gpio_regs+0x20, (1 << MDC_PIN(bus)) | (1 << MDIO_PIN(bus)));
 73 }
 74 
 75 static inline void mdio_tristate(struct mii_bus *bus)
 76 {
 77         out_le32(gpio_regs+0x30, (1 << MDIO_PIN(bus)));
 78 }
 79 
 80 static inline int mdio_read(struct mii_bus *bus)
 81 {
 82         return !!(in_le32(gpio_regs+0x40) & (1 << MDIO_PIN(bus)));
 83 }
 84 
 85 static void clock_out(struct mii_bus *bus, int bit)
 86 {
 87         if (bit)
 88                 mdio_hi(bus);
 89         else
 90                 mdio_lo(bus);
 91         udelay(DELAY);
 92         mdc_hi(bus);
 93         udelay(DELAY);
 94         mdc_lo(bus);
 95 }
 96 
 97 /* Utility to send the preamble, address, and register (common to read and write). */
 98 static void bitbang_pre(struct mii_bus *bus, int read, u8 addr, u8 reg)
 99 {
100         int i;
101 
102         /* CFE uses a really long preamble (40 bits). We'll do the same. */
103         mdio_active(bus);
104         for (i = 0; i < 40; i++) {
105                 clock_out(bus, 1);
106         }
107 
108         /* send the start bit (01) and the read opcode (10) or write (10) */
109         clock_out(bus, 0);
110         clock_out(bus, 1);
111 
112         clock_out(bus, read);
113         clock_out(bus, !read);
114 
115         /* send the PHY address */
116         for (i = 0; i < 5; i++) {
117                 clock_out(bus, (addr & 0x10) != 0);
118                 addr <<= 1;
119         }
120 
121         /* send the register address */
122         for (i = 0; i < 5; i++) {
123                 clock_out(bus, (reg & 0x10) != 0);
124                 reg <<= 1;
125         }
126 }
127 
128 static int gpio_mdio_read(struct mii_bus *bus, int phy_id, int location)
129 {
130         u16 rdreg;
131         int ret, i;
132         u8 addr = phy_id & 0xff;
133         u8 reg = location & 0xff;
134 
135         bitbang_pre(bus, 1, addr, reg);
136 
137         /* tri-state our MDIO I/O pin so we can read */
138         mdio_tristate(bus);
139         udelay(DELAY);
140         mdc_hi(bus);
141         udelay(DELAY);
142         mdc_lo(bus);
143 
144         /* read 16 bits of register data, MSB first */
145         rdreg = 0;
146         for (i = 0; i < 16; i++) {
147                 mdc_lo(bus);
148                 udelay(DELAY);
149                 mdc_hi(bus);
150                 udelay(DELAY);
151                 mdc_lo(bus);
152                 udelay(DELAY);
153                 rdreg <<= 1;
154                 rdreg |= mdio_read(bus);
155         }
156 
157         mdc_hi(bus);
158         udelay(DELAY);
159         mdc_lo(bus);
160         udelay(DELAY);
161 
162         ret = rdreg;
163 
164         return ret;
165 }
166 
167 static int gpio_mdio_write(struct mii_bus *bus, int phy_id, int location, u16 val)
168 {
169         int i;
170 
171         u8 addr = phy_id & 0xff;
172         u8 reg = location & 0xff;
173         u16 value = val & 0xffff;
174 
175         bitbang_pre(bus, 0, addr, reg);
176 
177         /* send the turnaround (10) */
178         mdc_lo(bus);
179         mdio_hi(bus);
180         udelay(DELAY);
181         mdc_hi(bus);
182         udelay(DELAY);
183         mdc_lo(bus);
184         mdio_lo(bus);
185         udelay(DELAY);
186         mdc_hi(bus);
187         udelay(DELAY);
188 
189         /* write 16 bits of register data, MSB first */
190         for (i = 0; i < 16; i++) {
191                 mdc_lo(bus);
192                 if (value & 0x8000)
193                         mdio_hi(bus);
194                 else
195                         mdio_lo(bus);
196                 udelay(DELAY);
197                 mdc_hi(bus);
198                 udelay(DELAY);
199                 value <<= 1;
200         }
201 
202         /*
203          * Tri-state the MDIO line.
204          */
205         mdio_tristate(bus);
206         mdc_lo(bus);
207         udelay(DELAY);
208         mdc_hi(bus);
209         udelay(DELAY);
210         return 0;
211 }
212 
213 static int gpio_mdio_reset(struct mii_bus *bus)
214 {
215         /*nothing here - dunno how to reset it*/
216         return 0;
217 }
218 
219 
220 static int gpio_mdio_probe(struct platform_device *ofdev)
221 {
222         struct device *dev = &ofdev->dev;
223         struct device_node *np = ofdev->dev.of_node;
224         struct mii_bus *new_bus;
225         struct gpio_priv *priv;
226         const unsigned int *prop;
227         int err;
228 
229         err = -ENOMEM;
230         priv = kzalloc(sizeof(struct gpio_priv), GFP_KERNEL);
231         if (!priv)
232                 goto out;
233 
234         new_bus = mdiobus_alloc();
235 
236         if (!new_bus)
237                 goto out_free_priv;
238 
239         new_bus->name = "pasemi gpio mdio bus";
240         new_bus->read = &gpio_mdio_read;
241         new_bus->write = &gpio_mdio_write;
242         new_bus->reset = &gpio_mdio_reset;
243 
244         prop = of_get_property(np, "reg", NULL);
245         snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", *prop);
246         new_bus->priv = priv;
247 
248         new_bus->irq = priv->mdio_irqs;
249 
250         prop = of_get_property(np, "mdc-pin", NULL);
251         priv->mdc_pin = *prop;
252 
253         prop = of_get_property(np, "mdio-pin", NULL);
254         priv->mdio_pin = *prop;
255 
256         new_bus->parent = dev;
257         dev_set_drvdata(dev, new_bus);
258 
259         err = of_mdiobus_register(new_bus, np);
260 
261         if (err != 0) {
262                 printk(KERN_ERR "%s: Cannot register as MDIO bus, err %d\n",
263                                 new_bus->name, err);
264                 goto out_free_irq;
265         }
266 
267         return 0;
268 
269 out_free_irq:
270         kfree(new_bus);
271 out_free_priv:
272         kfree(priv);
273 out:
274         return err;
275 }
276 
277 
278 static int gpio_mdio_remove(struct platform_device *dev)
279 {
280         struct mii_bus *bus = dev_get_drvdata(&dev->dev);
281 
282         mdiobus_unregister(bus);
283 
284         dev_set_drvdata(&dev->dev, NULL);
285 
286         kfree(bus->priv);
287         bus->priv = NULL;
288         mdiobus_free(bus);
289 
290         return 0;
291 }
292 
293 static struct of_device_id gpio_mdio_match[] =
294 {
295         {
296                 .compatible      = "gpio-mdio",
297         },
298         {},
299 };
300 MODULE_DEVICE_TABLE(of, gpio_mdio_match);
301 
302 static struct platform_driver gpio_mdio_driver =
303 {
304         .probe          = gpio_mdio_probe,
305         .remove         = gpio_mdio_remove,
306         .driver = {
307                 .name = "gpio-mdio-bitbang",
308                 .owner = THIS_MODULE,
309                 .of_match_table = gpio_mdio_match,
310         },
311 };
312 
313 int gpio_mdio_init(void)
314 {
315         struct device_node *np;
316 
317         np = of_find_compatible_node(NULL, NULL, "1682m-gpio");
318         if (!np)
319                 np = of_find_compatible_node(NULL, NULL,
320                                              "pasemi,pwrficient-gpio");
321         if (!np)
322                 return -ENODEV;
323         gpio_regs = of_iomap(np, 0);
324         of_node_put(np);
325 
326         if (!gpio_regs)
327                 return -ENODEV;
328 
329         return platform_driver_register(&gpio_mdio_driver);
330 }
331 module_init(gpio_mdio_init);
332 
333 void gpio_mdio_exit(void)
334 {
335         platform_driver_unregister(&gpio_mdio_driver);
336         if (gpio_regs)
337                 iounmap(gpio_regs);
338 }
339 module_exit(gpio_mdio_exit);
340 
341 MODULE_LICENSE("GPL");
342 MODULE_AUTHOR("Olof Johansson <olof@lixom.net>");
343 MODULE_DESCRIPTION("Driver for MDIO over GPIO on PA Semi PWRficient-based boards");
344 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us