0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/io.h>
0013 #include <linux/module.h>
0014 #include <linux/types.h>
0015 #include <linux/slab.h>
0016 #include <linux/sched.h>
0017 #include <linux/errno.h>
0018 #include <linux/ioport.h>
0019 #include <linux/interrupt.h>
0020 #include <linux/phy.h>
0021 #include <linux/of_address.h>
0022 #include <linux/of_mdio.h>
0023 #include <linux/of_platform.h>
0024
0025 #define DELAY 1
0026
0027 static void __iomem *gpio_regs;
0028
0029 struct gpio_priv {
0030 int mdc_pin;
0031 int mdio_pin;
0032 };
0033
0034 #define MDC_PIN(bus) (((struct gpio_priv *)bus->priv)->mdc_pin)
0035 #define MDIO_PIN(bus) (((struct gpio_priv *)bus->priv)->mdio_pin)
0036
0037 static inline void mdio_lo(struct mii_bus *bus)
0038 {
0039 out_le32(gpio_regs+0x10, 1 << MDIO_PIN(bus));
0040 }
0041
0042 static inline void mdio_hi(struct mii_bus *bus)
0043 {
0044 out_le32(gpio_regs, 1 << MDIO_PIN(bus));
0045 }
0046
0047 static inline void mdc_lo(struct mii_bus *bus)
0048 {
0049 out_le32(gpio_regs+0x10, 1 << MDC_PIN(bus));
0050 }
0051
0052 static inline void mdc_hi(struct mii_bus *bus)
0053 {
0054 out_le32(gpio_regs, 1 << MDC_PIN(bus));
0055 }
0056
0057 static inline void mdio_active(struct mii_bus *bus)
0058 {
0059 out_le32(gpio_regs+0x20, (1 << MDC_PIN(bus)) | (1 << MDIO_PIN(bus)));
0060 }
0061
0062 static inline void mdio_tristate(struct mii_bus *bus)
0063 {
0064 out_le32(gpio_regs+0x30, (1 << MDIO_PIN(bus)));
0065 }
0066
0067 static inline int mdio_read(struct mii_bus *bus)
0068 {
0069 return !!(in_le32(gpio_regs+0x40) & (1 << MDIO_PIN(bus)));
0070 }
0071
0072 static void clock_out(struct mii_bus *bus, int bit)
0073 {
0074 if (bit)
0075 mdio_hi(bus);
0076 else
0077 mdio_lo(bus);
0078 udelay(DELAY);
0079 mdc_hi(bus);
0080 udelay(DELAY);
0081 mdc_lo(bus);
0082 }
0083
0084
0085 static void bitbang_pre(struct mii_bus *bus, int read, u8 addr, u8 reg)
0086 {
0087 int i;
0088
0089
0090 mdio_active(bus);
0091 for (i = 0; i < 40; i++) {
0092 clock_out(bus, 1);
0093 }
0094
0095
0096 clock_out(bus, 0);
0097 clock_out(bus, 1);
0098
0099 clock_out(bus, read);
0100 clock_out(bus, !read);
0101
0102
0103 for (i = 0; i < 5; i++) {
0104 clock_out(bus, (addr & 0x10) != 0);
0105 addr <<= 1;
0106 }
0107
0108
0109 for (i = 0; i < 5; i++) {
0110 clock_out(bus, (reg & 0x10) != 0);
0111 reg <<= 1;
0112 }
0113 }
0114
0115 static int gpio_mdio_read(struct mii_bus *bus, int phy_id, int location)
0116 {
0117 u16 rdreg;
0118 int ret, i;
0119 u8 addr = phy_id & 0xff;
0120 u8 reg = location & 0xff;
0121
0122 bitbang_pre(bus, 1, addr, reg);
0123
0124
0125 mdio_tristate(bus);
0126 udelay(DELAY);
0127 mdc_hi(bus);
0128 udelay(DELAY);
0129 mdc_lo(bus);
0130
0131
0132 rdreg = 0;
0133 for (i = 0; i < 16; i++) {
0134 mdc_lo(bus);
0135 udelay(DELAY);
0136 mdc_hi(bus);
0137 udelay(DELAY);
0138 mdc_lo(bus);
0139 udelay(DELAY);
0140 rdreg <<= 1;
0141 rdreg |= mdio_read(bus);
0142 }
0143
0144 mdc_hi(bus);
0145 udelay(DELAY);
0146 mdc_lo(bus);
0147 udelay(DELAY);
0148
0149 ret = rdreg;
0150
0151 return ret;
0152 }
0153
0154 static int gpio_mdio_write(struct mii_bus *bus, int phy_id, int location, u16 val)
0155 {
0156 int i;
0157
0158 u8 addr = phy_id & 0xff;
0159 u8 reg = location & 0xff;
0160 u16 value = val & 0xffff;
0161
0162 bitbang_pre(bus, 0, addr, reg);
0163
0164
0165 mdc_lo(bus);
0166 mdio_hi(bus);
0167 udelay(DELAY);
0168 mdc_hi(bus);
0169 udelay(DELAY);
0170 mdc_lo(bus);
0171 mdio_lo(bus);
0172 udelay(DELAY);
0173 mdc_hi(bus);
0174 udelay(DELAY);
0175
0176
0177 for (i = 0; i < 16; i++) {
0178 mdc_lo(bus);
0179 if (value & 0x8000)
0180 mdio_hi(bus);
0181 else
0182 mdio_lo(bus);
0183 udelay(DELAY);
0184 mdc_hi(bus);
0185 udelay(DELAY);
0186 value <<= 1;
0187 }
0188
0189
0190
0191
0192 mdio_tristate(bus);
0193 mdc_lo(bus);
0194 udelay(DELAY);
0195 mdc_hi(bus);
0196 udelay(DELAY);
0197 return 0;
0198 }
0199
0200 static int gpio_mdio_reset(struct mii_bus *bus)
0201 {
0202
0203 return 0;
0204 }
0205
0206
0207 static int gpio_mdio_probe(struct platform_device *ofdev)
0208 {
0209 struct device *dev = &ofdev->dev;
0210 struct device_node *np = ofdev->dev.of_node;
0211 struct mii_bus *new_bus;
0212 struct gpio_priv *priv;
0213 const unsigned int *prop;
0214 int err;
0215
0216 err = -ENOMEM;
0217 priv = kzalloc(sizeof(struct gpio_priv), GFP_KERNEL);
0218 if (!priv)
0219 goto out;
0220
0221 new_bus = mdiobus_alloc();
0222
0223 if (!new_bus)
0224 goto out_free_priv;
0225
0226 new_bus->name = "pasemi gpio mdio bus";
0227 new_bus->read = &gpio_mdio_read;
0228 new_bus->write = &gpio_mdio_write;
0229 new_bus->reset = &gpio_mdio_reset;
0230
0231 prop = of_get_property(np, "reg", NULL);
0232 snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", *prop);
0233 new_bus->priv = priv;
0234
0235 prop = of_get_property(np, "mdc-pin", NULL);
0236 priv->mdc_pin = *prop;
0237
0238 prop = of_get_property(np, "mdio-pin", NULL);
0239 priv->mdio_pin = *prop;
0240
0241 new_bus->parent = dev;
0242 dev_set_drvdata(dev, new_bus);
0243
0244 err = of_mdiobus_register(new_bus, np);
0245
0246 if (err != 0) {
0247 pr_err("%s: Cannot register as MDIO bus, err %d\n",
0248 new_bus->name, err);
0249 goto out_free_irq;
0250 }
0251
0252 return 0;
0253
0254 out_free_irq:
0255 kfree(new_bus);
0256 out_free_priv:
0257 kfree(priv);
0258 out:
0259 return err;
0260 }
0261
0262
0263 static int gpio_mdio_remove(struct platform_device *dev)
0264 {
0265 struct mii_bus *bus = dev_get_drvdata(&dev->dev);
0266
0267 mdiobus_unregister(bus);
0268
0269 dev_set_drvdata(&dev->dev, NULL);
0270
0271 kfree(bus->priv);
0272 bus->priv = NULL;
0273 mdiobus_free(bus);
0274
0275 return 0;
0276 }
0277
0278 static const struct of_device_id gpio_mdio_match[] =
0279 {
0280 {
0281 .compatible = "gpio-mdio",
0282 },
0283 {},
0284 };
0285 MODULE_DEVICE_TABLE(of, gpio_mdio_match);
0286
0287 static struct platform_driver gpio_mdio_driver =
0288 {
0289 .probe = gpio_mdio_probe,
0290 .remove = gpio_mdio_remove,
0291 .driver = {
0292 .name = "gpio-mdio-bitbang",
0293 .of_match_table = gpio_mdio_match,
0294 },
0295 };
0296
0297 static int gpio_mdio_init(void)
0298 {
0299 struct device_node *np;
0300
0301 np = of_find_compatible_node(NULL, NULL, "1682m-gpio");
0302 if (!np)
0303 np = of_find_compatible_node(NULL, NULL,
0304 "pasemi,pwrficient-gpio");
0305 if (!np)
0306 return -ENODEV;
0307 gpio_regs = of_iomap(np, 0);
0308 of_node_put(np);
0309
0310 if (!gpio_regs)
0311 return -ENODEV;
0312
0313 return platform_driver_register(&gpio_mdio_driver);
0314 }
0315 module_init(gpio_mdio_init);
0316
0317 static void gpio_mdio_exit(void)
0318 {
0319 platform_driver_unregister(&gpio_mdio_driver);
0320 if (gpio_regs)
0321 iounmap(gpio_regs);
0322 }
0323 module_exit(gpio_mdio_exit);
0324
0325 MODULE_LICENSE("GPL");
0326 MODULE_AUTHOR("Olof Johansson <olof@lixom.net>");
0327 MODULE_DESCRIPTION("Driver for MDIO over GPIO on PA Semi PWRficient-based boards");