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 const 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 .of_match_table = gpio_mdio_match, 309 }, 310 }; 311 312 int gpio_mdio_init(void) 313 { 314 struct device_node *np; 315 316 np = of_find_compatible_node(NULL, NULL, "1682m-gpio"); 317 if (!np) 318 np = of_find_compatible_node(NULL, NULL, 319 "pasemi,pwrficient-gpio"); 320 if (!np) 321 return -ENODEV; 322 gpio_regs = of_iomap(np, 0); 323 of_node_put(np); 324 325 if (!gpio_regs) 326 return -ENODEV; 327 328 return platform_driver_register(&gpio_mdio_driver); 329 } 330 module_init(gpio_mdio_init); 331 332 void gpio_mdio_exit(void) 333 { 334 platform_driver_unregister(&gpio_mdio_driver); 335 if (gpio_regs) 336 iounmap(gpio_regs); 337 } 338 module_exit(gpio_mdio_exit); 339 340 MODULE_LICENSE("GPL"); 341 MODULE_AUTHOR("Olof Johansson <olof@lixom.net>"); 342 MODULE_DESCRIPTION("Driver for MDIO over GPIO on PA Semi PWRficient-based boards"); 343