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