linux/arch/powerpc/platforms/pasemi/gpio_mdio.c
<<
>>
Prefs
   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
  37static void __iomem *gpio_regs;
  38
  39struct 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
  48static inline void mdio_lo(struct mii_bus *bus)
  49{
  50        out_le32(gpio_regs+0x10, 1 << MDIO_PIN(bus));
  51}
  52
  53static inline void mdio_hi(struct mii_bus *bus)
  54{
  55        out_le32(gpio_regs, 1 << MDIO_PIN(bus));
  56}
  57
  58static inline void mdc_lo(struct mii_bus *bus)
  59{
  60        out_le32(gpio_regs+0x10, 1 << MDC_PIN(bus));
  61}
  62
  63static inline void mdc_hi(struct mii_bus *bus)
  64{
  65        out_le32(gpio_regs, 1 << MDC_PIN(bus));
  66}
  67
  68static 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
  73static inline void mdio_tristate(struct mii_bus *bus)
  74{
  75        out_le32(gpio_regs+0x30, (1 << MDIO_PIN(bus)));
  76}
  77
  78static inline int mdio_read(struct mii_bus *bus)
  79{
  80        return !!(in_le32(gpio_regs+0x40) & (1 << MDIO_PIN(bus)));
  81}
  82
  83static 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). */
  96static 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
 126static 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
 165static 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
 211static int gpio_mdio_reset(struct mii_bus *bus)
 212{
 213        /*nothing here - dunno how to reset it*/
 214        return 0;
 215}
 216
 217
 218static 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
 268out_free_irq:
 269        kfree(new_bus);
 270out_free_priv:
 271        kfree(priv);
 272out:
 273        return err;
 274}
 275
 276
 277static 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
 292static struct of_device_id gpio_mdio_match[] =
 293{
 294        {
 295                .compatible      = "gpio-mdio",
 296        },
 297        {},
 298};
 299MODULE_DEVICE_TABLE(of, gpio_mdio_match);
 300
 301static 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
 311int 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}
 329module_init(gpio_mdio_init);
 330
 331void gpio_mdio_exit(void)
 332{
 333        of_unregister_platform_driver(&gpio_mdio_driver);
 334        if (gpio_regs)
 335                iounmap(gpio_regs);
 336}
 337module_exit(gpio_mdio_exit);
 338
 339MODULE_LICENSE("GPL");
 340MODULE_AUTHOR("Olof Johansson <olof@lixom.net>");
 341MODULE_DESCRIPTION("Driver for MDIO over GPIO on PA Semi PWRficient-based boards");
 342