]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/net/ethernet/marvell/mvmdio.c
Merge remote-tracking branch 'regulator/topic/max8997' into regulator-next
[karo-tx-linux.git] / drivers / net / ethernet / marvell / mvmdio.c
1 /*
2  * Driver for the MDIO interface of Marvell network interfaces.
3  *
4  * Since the MDIO interface of Marvell network interfaces is shared
5  * between all network interfaces, having a single driver allows to
6  * handle concurrent accesses properly (you may have four Ethernet
7  * ports, but they in fact share the same SMI interface to access the
8  * MDIO bus). Moreover, this MDIO interface code is similar between
9  * the mv643xx_eth driver and the mvneta driver. For now, it is only
10  * used by the mvneta driver, but it could later be used by the
11  * mv643xx_eth driver as well.
12  *
13  * Copyright (C) 2012 Marvell
14  *
15  * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
16  *
17  * This file is licensed under the terms of the GNU General Public
18  * License version 2. This program is licensed "as is" without any
19  * warranty of any kind, whether express or implied.
20  */
21
22 #include <linux/init.h>
23 #include <linux/kernel.h>
24 #include <linux/module.h>
25 #include <linux/mutex.h>
26 #include <linux/phy.h>
27 #include <linux/of_address.h>
28 #include <linux/of_mdio.h>
29 #include <linux/platform_device.h>
30 #include <linux/delay.h>
31
32 #define MVMDIO_SMI_DATA_SHIFT              0
33 #define MVMDIO_SMI_PHY_ADDR_SHIFT          16
34 #define MVMDIO_SMI_PHY_REG_SHIFT           21
35 #define MVMDIO_SMI_READ_OPERATION          BIT(26)
36 #define MVMDIO_SMI_WRITE_OPERATION         0
37 #define MVMDIO_SMI_READ_VALID              BIT(27)
38 #define MVMDIO_SMI_BUSY                    BIT(28)
39
40 struct orion_mdio_dev {
41         struct mutex lock;
42         void __iomem *smireg;
43 };
44
45 /* Wait for the SMI unit to be ready for another operation
46  */
47 static int orion_mdio_wait_ready(struct mii_bus *bus)
48 {
49         struct orion_mdio_dev *dev = bus->priv;
50         int count;
51         u32 val;
52
53         count = 0;
54         while (1) {
55                 val = readl(dev->smireg);
56                 if (!(val & MVMDIO_SMI_BUSY))
57                         break;
58
59                 if (count > 100) {
60                         dev_err(bus->parent, "Timeout: SMI busy for too long\n");
61                         return -ETIMEDOUT;
62                 }
63
64                 udelay(10);
65                 count++;
66         }
67
68         return 0;
69 }
70
71 static int orion_mdio_read(struct mii_bus *bus, int mii_id,
72                            int regnum)
73 {
74         struct orion_mdio_dev *dev = bus->priv;
75         int count;
76         u32 val;
77         int ret;
78
79         mutex_lock(&dev->lock);
80
81         ret = orion_mdio_wait_ready(bus);
82         if (ret < 0) {
83                 mutex_unlock(&dev->lock);
84                 return ret;
85         }
86
87         writel(((mii_id << MVMDIO_SMI_PHY_ADDR_SHIFT) |
88                 (regnum << MVMDIO_SMI_PHY_REG_SHIFT)  |
89                 MVMDIO_SMI_READ_OPERATION),
90                dev->smireg);
91
92         /* Wait for the value to become available */
93         count = 0;
94         while (1) {
95                 val = readl(dev->smireg);
96                 if (val & MVMDIO_SMI_READ_VALID)
97                         break;
98
99                 if (count > 100) {
100                         dev_err(bus->parent, "Timeout when reading PHY\n");
101                         mutex_unlock(&dev->lock);
102                         return -ETIMEDOUT;
103                 }
104
105                 udelay(10);
106                 count++;
107         }
108
109         mutex_unlock(&dev->lock);
110
111         return val & 0xFFFF;
112 }
113
114 static int orion_mdio_write(struct mii_bus *bus, int mii_id,
115                             int regnum, u16 value)
116 {
117         struct orion_mdio_dev *dev = bus->priv;
118         int ret;
119
120         mutex_lock(&dev->lock);
121
122         ret = orion_mdio_wait_ready(bus);
123         if (ret < 0) {
124                 mutex_unlock(&dev->lock);
125                 return ret;
126         }
127
128         writel(((mii_id << MVMDIO_SMI_PHY_ADDR_SHIFT) |
129                 (regnum << MVMDIO_SMI_PHY_REG_SHIFT)  |
130                 MVMDIO_SMI_WRITE_OPERATION            |
131                 (value << MVMDIO_SMI_DATA_SHIFT)),
132                dev->smireg);
133
134         mutex_unlock(&dev->lock);
135
136         return 0;
137 }
138
139 static int orion_mdio_reset(struct mii_bus *bus)
140 {
141         return 0;
142 }
143
144 static int orion_mdio_probe(struct platform_device *pdev)
145 {
146         struct device_node *np = pdev->dev.of_node;
147         struct mii_bus *bus;
148         struct orion_mdio_dev *dev;
149         int i, ret;
150
151         bus = mdiobus_alloc_size(sizeof(struct orion_mdio_dev));
152         if (!bus) {
153                 dev_err(&pdev->dev, "Cannot allocate MDIO bus\n");
154                 return -ENOMEM;
155         }
156
157         bus->name = "orion_mdio_bus";
158         bus->read = orion_mdio_read;
159         bus->write = orion_mdio_write;
160         bus->reset = orion_mdio_reset;
161         snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii",
162                  dev_name(&pdev->dev));
163         bus->parent = &pdev->dev;
164
165         bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
166         if (!bus->irq) {
167                 dev_err(&pdev->dev, "Cannot allocate PHY IRQ array\n");
168                 mdiobus_free(bus);
169                 return -ENOMEM;
170         }
171
172         for (i = 0; i < PHY_MAX_ADDR; i++)
173                 bus->irq[i] = PHY_POLL;
174
175         dev = bus->priv;
176         dev->smireg = of_iomap(pdev->dev.of_node, 0);
177         if (!dev->smireg) {
178                 dev_err(&pdev->dev, "No SMI register address given in DT\n");
179                 kfree(bus->irq);
180                 mdiobus_free(bus);
181                 return -ENODEV;
182         }
183
184         mutex_init(&dev->lock);
185
186         ret = of_mdiobus_register(bus, np);
187         if (ret < 0) {
188                 dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret);
189                 iounmap(dev->smireg);
190                 kfree(bus->irq);
191                 mdiobus_free(bus);
192                 return ret;
193         }
194
195         platform_set_drvdata(pdev, bus);
196
197         return 0;
198 }
199
200 static int orion_mdio_remove(struct platform_device *pdev)
201 {
202         struct mii_bus *bus = platform_get_drvdata(pdev);
203         mdiobus_unregister(bus);
204         kfree(bus->irq);
205         mdiobus_free(bus);
206         return 0;
207 }
208
209 static const struct of_device_id orion_mdio_match[] = {
210         { .compatible = "marvell,orion-mdio" },
211         { }
212 };
213 MODULE_DEVICE_TABLE(of, orion_mdio_match);
214
215 static struct platform_driver orion_mdio_driver = {
216         .probe = orion_mdio_probe,
217         .remove = orion_mdio_remove,
218         .driver = {
219                 .name = "orion-mdio",
220                 .of_match_table = orion_mdio_match,
221         },
222 };
223
224 module_platform_driver(orion_mdio_driver);
225
226 MODULE_DESCRIPTION("Marvell MDIO interface driver");
227 MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
228 MODULE_LICENSE("GPL");