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 }; 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 gpio_mdio_probe(struct platform_device *ofdev) 220 { 221 struct device *dev = &ofdev->dev; 222 struct device_node *np = ofdev->dev.of_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 prop = of_get_property(np, "mdc-pin", NULL); 248 priv->mdc_pin = *prop; 249 250 prop = of_get_property(np, "mdio-pin", NULL); 251 priv->mdio_pin = *prop; 252 253 new_bus->parent = dev; 254 dev_set_drvdata(dev, new_bus); 255 256 err = of_mdiobus_register(new_bus, np); 257 258 if (err != 0) { 259 printk(KERN_ERR "%s: Cannot register as MDIO bus, err %d\n", 260 new_bus->name, err); 261 goto out_free_irq; 262 } 263 264 return 0; 265 266 out_free_irq: 267 kfree(new_bus); 268 out_free_priv: 269 kfree(priv); 270 out: 271 return err; 272 } 273 274 275 static int gpio_mdio_remove(struct platform_device *dev) 276 { 277 struct mii_bus *bus = dev_get_drvdata(&dev->dev); 278 279 mdiobus_unregister(bus); 280 281 dev_set_drvdata(&dev->dev, NULL); 282 283 kfree(bus->priv); 284 bus->priv = NULL; 285 mdiobus_free(bus); 286 287 return 0; 288 } 289 290 static const struct of_device_id gpio_mdio_match[] = 291 { 292 { 293 .compatible = "gpio-mdio", 294 }, 295 {}, 296 }; 297 MODULE_DEVICE_TABLE(of, gpio_mdio_match); 298 299 static struct platform_driver gpio_mdio_driver = 300 { 301 .probe = gpio_mdio_probe, 302 .remove = gpio_mdio_remove, 303 .driver = { 304 .name = "gpio-mdio-bitbang", 305 .of_match_table = gpio_mdio_match, 306 }, 307 }; 308 309 int gpio_mdio_init(void) 310 { 311 struct device_node *np; 312 313 np = of_find_compatible_node(NULL, NULL, "1682m-gpio"); 314 if (!np) 315 np = of_find_compatible_node(NULL, NULL, 316 "pasemi,pwrficient-gpio"); 317 if (!np) 318 return -ENODEV; 319 gpio_regs = of_iomap(np, 0); 320 of_node_put(np); 321 322 if (!gpio_regs) 323 return -ENODEV; 324 325 return platform_driver_register(&gpio_mdio_driver); 326 } 327 module_init(gpio_mdio_init); 328 329 void gpio_mdio_exit(void) 330 { 331 platform_driver_unregister(&gpio_mdio_driver); 332 if (gpio_regs) 333 iounmap(gpio_regs); 334 } 335 module_exit(gpio_mdio_exit); 336 337 MODULE_LICENSE("GPL"); 338 MODULE_AUTHOR("Olof Johansson <olof@lixom.net>"); 339 MODULE_DESCRIPTION("Driver for MDIO over GPIO on PA Semi PWRficient-based boards"); 340