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

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mdio_lo
  2. mdio_hi
  3. mdc_lo
  4. mdc_hi
  5. mdio_active
  6. mdio_tristate
  7. mdio_read
  8. clock_out
  9. bitbang_pre
  10. gpio_mdio_read
  11. gpio_mdio_write
  12. gpio_mdio_reset
  13. gpio_mdio_probe
  14. gpio_mdio_remove
  15. gpio_mdio_init
  16. gpio_mdio_exit

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

/* [<][>][^][v][top][bottom][index][help] */