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_mdio.h> 34 #include <linux/of_platform.h> 35 36 #define DELAY 1 37 38 static void __iomem *gpio_regs; 39 40 struct gpio_priv { 41 int mdc_pin; 42 int mdio_pin; 43 int mdio_irqs[PHY_MAX_ADDR]; 44 }; 45 46 #define MDC_PIN(bus) (((struct gpio_priv *)bus->priv)->mdc_pin) 47 #define MDIO_PIN(bus) (((struct gpio_priv *)bus->priv)->mdio_pin) 48 49 static inline void mdio_lo(struct mii_bus *bus) 50 { 51 out_le32(gpio_regs+0x10, 1 << MDIO_PIN(bus)); 52 } 53 54 static inline void mdio_hi(struct mii_bus *bus) 55 { 56 out_le32(gpio_regs, 1 << MDIO_PIN(bus)); 57 } 58 59 static inline void mdc_lo(struct mii_bus *bus) 60 { 61 out_le32(gpio_regs+0x10, 1 << MDC_PIN(bus)); 62 } 63 64 static inline void mdc_hi(struct mii_bus *bus) 65 { 66 out_le32(gpio_regs, 1 << MDC_PIN(bus)); 67 } 68 69 static inline void mdio_active(struct mii_bus *bus) 70 { 71 out_le32(gpio_regs+0x20, (1 << MDC_PIN(bus)) | (1 << MDIO_PIN(bus))); 72 } 73 74 static inline void mdio_tristate(struct mii_bus *bus) 75 { 76 out_le32(gpio_regs+0x30, (1 << MDIO_PIN(bus))); 77 } 78 79 static inline int mdio_read(struct mii_bus *bus) 80 { 81 return !!(in_le32(gpio_regs+0x40) & (1 << MDIO_PIN(bus))); 82 } 83 84 static void clock_out(struct mii_bus *bus, int bit) 85 { 86 if (bit) 87 mdio_hi(bus); 88 else 89 mdio_lo(bus); 90 udelay(DELAY); 91 mdc_hi(bus); 92 udelay(DELAY); 93 mdc_lo(bus); 94 } 95 96 /* Utility to send the preamble, address, and register (common to read and write). */ 97 static void bitbang_pre(struct mii_bus *bus, int read, u8 addr, u8 reg) 98 { 99 int i; 100 101 /* CFE uses a really long preamble (40 bits). We'll do the same. */ 102 mdio_active(bus); 103 for (i = 0; i < 40; i++) { 104 clock_out(bus, 1); 105 } 106 107 /* send the start bit (01) and the read opcode (10) or write (10) */ 108 clock_out(bus, 0); 109 clock_out(bus, 1); 110 111 clock_out(bus, read); 112 clock_out(bus, !read); 113 114 /* send the PHY address */ 115 for (i = 0; i < 5; i++) { 116 clock_out(bus, (addr & 0x10) != 0); 117 addr <<= 1; 118 } 119 120 /* send the register address */ 121 for (i = 0; i < 5; i++) { 122 clock_out(bus, (reg & 0x10) != 0); 123 reg <<= 1; 124 } 125 } 126 127 static int gpio_mdio_read(struct mii_bus *bus, int phy_id, int location) 128 { 129 u16 rdreg; 130 int ret, i; 131 u8 addr = phy_id & 0xff; 132 u8 reg = location & 0xff; 133 134 bitbang_pre(bus, 1, addr, reg); 135 136 /* tri-state our MDIO I/O pin so we can read */ 137 mdio_tristate(bus); 138 udelay(DELAY); 139 mdc_hi(bus); 140 udelay(DELAY); 141 mdc_lo(bus); 142 143 /* read 16 bits of register data, MSB first */ 144 rdreg = 0; 145 for (i = 0; i < 16; i++) { 146 mdc_lo(bus); 147 udelay(DELAY); 148 mdc_hi(bus); 149 udelay(DELAY); 150 mdc_lo(bus); 151 udelay(DELAY); 152 rdreg <<= 1; 153 rdreg |= mdio_read(bus); 154 } 155 156 mdc_hi(bus); 157 udelay(DELAY); 158 mdc_lo(bus); 159 udelay(DELAY); 160 161 ret = rdreg; 162 163 return ret; 164 } 165 166 static int gpio_mdio_write(struct mii_bus *bus, int phy_id, int location, u16 val) 167 { 168 int i; 169 170 u8 addr = phy_id & 0xff; 171 u8 reg = location & 0xff; 172 u16 value = val & 0xffff; 173 174 bitbang_pre(bus, 0, addr, reg); 175 176 /* send the turnaround (10) */ 177 mdc_lo(bus); 178 mdio_hi(bus); 179 udelay(DELAY); 180 mdc_hi(bus); 181 udelay(DELAY); 182 mdc_lo(bus); 183 mdio_lo(bus); 184 udelay(DELAY); 185 mdc_hi(bus); 186 udelay(DELAY); 187 188 /* write 16 bits of register data, MSB first */ 189 for (i = 0; i < 16; i++) { 190 mdc_lo(bus); 191 if (value & 0x8000) 192 mdio_hi(bus); 193 else 194 mdio_lo(bus); 195 udelay(DELAY); 196 mdc_hi(bus); 197 udelay(DELAY); 198 value <<= 1; 199 } 200 201 /* 202 * Tri-state the MDIO line. 203 */ 204 mdio_tristate(bus); 205 mdc_lo(bus); 206 udelay(DELAY); 207 mdc_hi(bus); 208 udelay(DELAY); 209 return 0; 210 } 211 212 static int gpio_mdio_reset(struct mii_bus *bus) 213 { 214 /*nothing here - dunno how to reset it*/ 215 return 0; 216 } 217 218 219 static int __devinit gpio_mdio_probe(struct platform_device *ofdev, 220 const struct of_device_id *match) 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 of_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 of_register_platform_driver(&gpio_mdio_driver); 330 } 331 module_init(gpio_mdio_init); 332 333 void gpio_mdio_exit(void) 334 { 335 of_unregister_platform_driver(&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