Version:  2.0.40 2.2.26 2.4.37 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16

Linux/drivers/net/phy/mdio-moxart.c

  1 /* MOXA ART Ethernet (RTL8201CP) MDIO interface driver
  2  *
  3  * Copyright (C) 2013 Jonas Jensen <jonas.jensen@gmail.com>
  4  *
  5  * This file is licensed under the terms of the GNU General Public
  6  * License version 2.  This program is licensed "as is" without any
  7  * warranty of any kind, whether express or implied.
  8  */
  9 
 10 #include <linux/delay.h>
 11 #include <linux/kernel.h>
 12 #include <linux/module.h>
 13 #include <linux/mutex.h>
 14 #include <linux/of_address.h>
 15 #include <linux/of_mdio.h>
 16 #include <linux/phy.h>
 17 #include <linux/platform_device.h>
 18 #include <linux/regulator/consumer.h>
 19 
 20 #define REG_PHY_CTRL            0
 21 #define REG_PHY_WRITE_DATA      4
 22 
 23 /* REG_PHY_CTRL */
 24 #define MIIWR                   BIT(27) /* init write sequence (auto cleared)*/
 25 #define MIIRD                   BIT(26)
 26 #define REGAD_MASK              0x3e00000
 27 #define PHYAD_MASK              0x1f0000
 28 #define MIIRDATA_MASK           0xffff
 29 
 30 /* REG_PHY_WRITE_DATA */
 31 #define MIIWDATA_MASK           0xffff
 32 
 33 struct moxart_mdio_data {
 34         void __iomem            *base;
 35 };
 36 
 37 static int moxart_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
 38 {
 39         struct moxart_mdio_data *data = bus->priv;
 40         u32 ctrl = 0;
 41         unsigned int count = 5;
 42 
 43         dev_dbg(&bus->dev, "%s\n", __func__);
 44 
 45         ctrl |= MIIRD | ((mii_id << 16) & PHYAD_MASK) |
 46                 ((regnum << 21) & REGAD_MASK);
 47 
 48         writel(ctrl, data->base + REG_PHY_CTRL);
 49 
 50         do {
 51                 ctrl = readl(data->base + REG_PHY_CTRL);
 52 
 53                 if (!(ctrl & MIIRD))
 54                         return ctrl & MIIRDATA_MASK;
 55 
 56                 mdelay(10);
 57                 count--;
 58         } while (count > 0);
 59 
 60         dev_dbg(&bus->dev, "%s timed out\n", __func__);
 61 
 62         return -ETIMEDOUT;
 63 }
 64 
 65 static int moxart_mdio_write(struct mii_bus *bus, int mii_id,
 66                              int regnum, u16 value)
 67 {
 68         struct moxart_mdio_data *data = bus->priv;
 69         u32 ctrl = 0;
 70         unsigned int count = 5;
 71 
 72         dev_dbg(&bus->dev, "%s\n", __func__);
 73 
 74         ctrl |= MIIWR | ((mii_id << 16) & PHYAD_MASK) |
 75                 ((regnum << 21) & REGAD_MASK);
 76 
 77         value &= MIIWDATA_MASK;
 78 
 79         writel(value, data->base + REG_PHY_WRITE_DATA);
 80         writel(ctrl, data->base + REG_PHY_CTRL);
 81 
 82         do {
 83                 ctrl = readl(data->base + REG_PHY_CTRL);
 84 
 85                 if (!(ctrl & MIIWR))
 86                         return 0;
 87 
 88                 mdelay(10);
 89                 count--;
 90         } while (count > 0);
 91 
 92         dev_dbg(&bus->dev, "%s timed out\n", __func__);
 93 
 94         return -ETIMEDOUT;
 95 }
 96 
 97 static int moxart_mdio_reset(struct mii_bus *bus)
 98 {
 99         int data, i;
100 
101         for (i = 0; i < PHY_MAX_ADDR; i++) {
102                 data = moxart_mdio_read(bus, i, MII_BMCR);
103                 if (data < 0)
104                         continue;
105 
106                 data |= BMCR_RESET;
107                 if (moxart_mdio_write(bus, i, MII_BMCR, data) < 0)
108                         continue;
109         }
110 
111         return 0;
112 }
113 
114 static int moxart_mdio_probe(struct platform_device *pdev)
115 {
116         struct device_node *np = pdev->dev.of_node;
117         struct mii_bus *bus;
118         struct moxart_mdio_data *data;
119         struct resource *res;
120         int ret, i;
121 
122         bus = mdiobus_alloc_size(sizeof(*data));
123         if (!bus)
124                 return -ENOMEM;
125 
126         bus->name = "MOXA ART Ethernet MII";
127         bus->read = &moxart_mdio_read;
128         bus->write = &moxart_mdio_write;
129         bus->reset = &moxart_mdio_reset;
130         snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d-mii", pdev->name, pdev->id);
131         bus->parent = &pdev->dev;
132 
133         bus->irq = devm_kzalloc(&pdev->dev, sizeof(int) * PHY_MAX_ADDR,
134                         GFP_KERNEL);
135         if (!bus->irq) {
136                 ret = -ENOMEM;
137                 goto err_out_free_mdiobus;
138         }
139 
140         /* Setting PHY_IGNORE_INTERRUPT here even if it has no effect,
141          * of_mdiobus_register() sets these PHY_POLL.
142          * Ideally, the interrupt from MAC controller could be used to
143          * detect link state changes, not polling, i.e. if there was
144          * a way phy_driver could set PHY_HAS_INTERRUPT but have that
145          * interrupt handled in ethernet drivercode.
146          */
147         for (i = 0; i < PHY_MAX_ADDR; i++)
148                 bus->irq[i] = PHY_IGNORE_INTERRUPT;
149 
150         data = bus->priv;
151         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
152         data->base = devm_ioremap_resource(&pdev->dev, res);
153         if (IS_ERR(data->base)) {
154                 ret = PTR_ERR(data->base);
155                 goto err_out_free_mdiobus;
156         }
157 
158         ret = of_mdiobus_register(bus, np);
159         if (ret < 0)
160                 goto err_out_free_mdiobus;
161 
162         platform_set_drvdata(pdev, bus);
163 
164         return 0;
165 
166 err_out_free_mdiobus:
167         mdiobus_free(bus);
168         return ret;
169 }
170 
171 static int moxart_mdio_remove(struct platform_device *pdev)
172 {
173         struct mii_bus *bus = platform_get_drvdata(pdev);
174 
175         mdiobus_unregister(bus);
176         mdiobus_free(bus);
177 
178         return 0;
179 }
180 
181 static const struct of_device_id moxart_mdio_dt_ids[] = {
182         { .compatible = "moxa,moxart-mdio" },
183         { }
184 };
185 MODULE_DEVICE_TABLE(of, moxart_mdio_dt_ids);
186 
187 static struct platform_driver moxart_mdio_driver = {
188         .probe = moxart_mdio_probe,
189         .remove = moxart_mdio_remove,
190         .driver = {
191                 .name = "moxart-mdio",
192                 .of_match_table = moxart_mdio_dt_ids,
193         },
194 };
195 
196 module_platform_driver(moxart_mdio_driver);
197 
198 MODULE_DESCRIPTION("MOXA ART MDIO interface driver");
199 MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>");
200 MODULE_LICENSE("GPL");
201 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us