aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/phy
diff options
context:
space:
mode:
authorPaulius Zaleckas <paulius.zaleckas@teltonika.lt>2008-11-13 19:24:34 -0500
committerDavid S. Miller <davem@davemloft.net>2008-11-16 21:59:45 -0500
commitf004f3ea34209d8b836426b26ade3dc502631b18 (patch)
treebf58002618bc3dd98db2416bb20cbeb016ecdd23 /drivers/net/phy
parent72af187f216ed83c77ca3e6f22dfc9caf72e9347 (diff)
phylib: make mdio-gpio work without OF (v4)
make mdio-gpio work with non OpenFirmware gpio implementation. Aditional changes to mdio-gpio: - use gpio_request() and gpio_free() - place irq[] array in struct mdio_gpio_info - add module description, author and license - add note about compiling this driver as module - rename mdc and mdio function (were ugly names) - change MII to MDIO in bus name - add __init __exit to module (un)loading functions - probe fails if no phys added to the bus - kzalloc bitbang with sizeof(*bitbang) Changes since v3: - keep bus naming "%x" to be compatible with existing drivers. Changes since v2: - more #ifdefs reduction - platform driver will be registered on OF platforms also - unified platform and OF bus_id to phy%i Changes since v1: - removed NO_IRQ - reduced #idefs Laurent, please test this driver under OF. Signed-off-by: Paulius Zaleckas <paulius.zaleckas@teltonika.lt> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/phy')
-rw-r--r--drivers/net/phy/Kconfig5
-rw-r--r--drivers/net/phy/mdio-gpio.c232
2 files changed, 166 insertions, 71 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 031807751991..c4c5a2f8ec74 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -86,8 +86,11 @@ config MDIO_BITBANG
86 86
87config MDIO_GPIO 87config MDIO_GPIO
88 tristate "Support for GPIO lib-based bitbanged MDIO buses" 88 tristate "Support for GPIO lib-based bitbanged MDIO buses"
89 depends on MDIO_BITBANG && OF_GPIO 89 depends on MDIO_BITBANG && GENERIC_GPIO
90 ---help--- 90 ---help---
91 Supports GPIO lib-based MDIO busses. 91 Supports GPIO lib-based MDIO busses.
92 92
93 To compile this driver as a module, choose M here: the module
94 will be called mdio-gpio.
95
93endif # PHYLIB 96endif # PHYLIB
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
index 2ff97754e574..a439ebeb4319 100644
--- a/drivers/net/phy/mdio-gpio.c
+++ b/drivers/net/phy/mdio-gpio.c
@@ -1,9 +1,12 @@
1/* 1/*
2 * OpenFirmware GPIO based MDIO bitbang driver. 2 * GPIO based MDIO bitbang driver.
3 * Supports OpenFirmware.
3 * 4 *
4 * Copyright (c) 2008 CSE Semaphore Belgium. 5 * Copyright (c) 2008 CSE Semaphore Belgium.
5 * by Laurent Pinchart <laurentp@cse-semaphore.com> 6 * by Laurent Pinchart <laurentp@cse-semaphore.com>
6 * 7 *
8 * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
9 *
7 * Based on earlier work by 10 * Based on earlier work by
8 * 11 *
9 * Copyright (c) 2003 Intracom S.A. 12 * Copyright (c) 2003 Intracom S.A.
@@ -21,9 +24,14 @@
21#include <linux/slab.h> 24#include <linux/slab.h>
22#include <linux/init.h> 25#include <linux/init.h>
23#include <linux/interrupt.h> 26#include <linux/interrupt.h>
24#include <linux/mdio-bitbang.h> 27#include <linux/platform_device.h>
28#include <linux/gpio.h>
29#include <linux/mdio-gpio.h>
30
31#ifdef CONFIG_OF_GPIO
25#include <linux/of_gpio.h> 32#include <linux/of_gpio.h>
26#include <linux/of_platform.h> 33#include <linux/of_platform.h>
34#endif
27 35
28struct mdio_gpio_info { 36struct mdio_gpio_info {
29 struct mdiobb_ctrl ctrl; 37 struct mdiobb_ctrl ctrl;
@@ -41,7 +49,7 @@ static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
41 gpio_direction_input(bitbang->mdio); 49 gpio_direction_input(bitbang->mdio);
42} 50}
43 51
44static int mdio_read(struct mdiobb_ctrl *ctrl) 52static int mdio_get(struct mdiobb_ctrl *ctrl)
45{ 53{
46 struct mdio_gpio_info *bitbang = 54 struct mdio_gpio_info *bitbang =
47 container_of(ctrl, struct mdio_gpio_info, ctrl); 55 container_of(ctrl, struct mdio_gpio_info, ctrl);
@@ -49,7 +57,7 @@ static int mdio_read(struct mdiobb_ctrl *ctrl)
49 return gpio_get_value(bitbang->mdio); 57 return gpio_get_value(bitbang->mdio);
50} 58}
51 59
52static void mdio(struct mdiobb_ctrl *ctrl, int what) 60static void mdio_set(struct mdiobb_ctrl *ctrl, int what)
53{ 61{
54 struct mdio_gpio_info *bitbang = 62 struct mdio_gpio_info *bitbang =
55 container_of(ctrl, struct mdio_gpio_info, ctrl); 63 container_of(ctrl, struct mdio_gpio_info, ctrl);
@@ -57,7 +65,7 @@ static void mdio(struct mdiobb_ctrl *ctrl, int what)
57 gpio_set_value(bitbang->mdio, what); 65 gpio_set_value(bitbang->mdio, what);
58} 66}
59 67
60static void mdc(struct mdiobb_ctrl *ctrl, int what) 68static void mdc_set(struct mdiobb_ctrl *ctrl, int what)
61{ 69{
62 struct mdio_gpio_info *bitbang = 70 struct mdio_gpio_info *bitbang =
63 container_of(ctrl, struct mdio_gpio_info, ctrl); 71 container_of(ctrl, struct mdio_gpio_info, ctrl);
@@ -67,93 +75,69 @@ static void mdc(struct mdiobb_ctrl *ctrl, int what)
67 75
68static struct mdiobb_ops mdio_gpio_ops = { 76static struct mdiobb_ops mdio_gpio_ops = {
69 .owner = THIS_MODULE, 77 .owner = THIS_MODULE,
70 .set_mdc = mdc, 78 .set_mdc = mdc_set,
71 .set_mdio_dir = mdio_dir, 79 .set_mdio_dir = mdio_dir,
72 .set_mdio_data = mdio, 80 .set_mdio_data = mdio_set,
73 .get_mdio_data = mdio_read, 81 .get_mdio_data = mdio_get,
74}; 82};
75 83
76static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus, 84static int __devinit mdio_gpio_bus_init(struct device *dev,
77 struct device_node *np) 85 struct mdio_gpio_platform_data *pdata,
78{ 86 int bus_id)
79 struct mdio_gpio_info *bitbang = bus->priv;
80
81 bitbang->mdc = of_get_gpio(np, 0);
82 bitbang->mdio = of_get_gpio(np, 1);
83
84 if (bitbang->mdc < 0 || bitbang->mdio < 0)
85 return -ENODEV;
86
87 snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc);
88 return 0;
89}
90
91static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
92{ 87{
93 const u32 *data;
94 int len, id, irq;
95
96 data = of_get_property(np, "reg", &len);
97 if (!data || len != 4)
98 return;
99
100 id = *data;
101 bus->phy_mask &= ~(1 << id);
102
103 irq = of_irq_to_resource(np, 0, NULL);
104 if (irq != NO_IRQ)
105 bus->irq[id] = irq;
106}
107
108static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
109 const struct of_device_id *match)
110{
111 struct device_node *np = NULL;
112 struct mii_bus *new_bus; 88 struct mii_bus *new_bus;
113 struct mdio_gpio_info *bitbang; 89 struct mdio_gpio_info *bitbang;
114 int ret = -ENOMEM; 90 int ret = -ENOMEM;
115 int i; 91 int i;
116 92
117 bitbang = kzalloc(sizeof(struct mdio_gpio_info), GFP_KERNEL); 93 bitbang = kzalloc(sizeof(*bitbang), GFP_KERNEL);
118 if (!bitbang) 94 if (!bitbang)
119 goto out; 95 goto out;
120 96
121 bitbang->ctrl.ops = &mdio_gpio_ops; 97 bitbang->ctrl.ops = &mdio_gpio_ops;
98 bitbang->mdc = pdata->mdc;
99 bitbang->mdio = pdata->mdio;
122 100
123 new_bus = alloc_mdio_bitbang(&bitbang->ctrl); 101 new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
124 if (!new_bus) 102 if (!new_bus)
125 goto out_free_bitbang; 103 goto out_free_bitbang;
126 104
127 new_bus->name = "GPIO Bitbanged MII", 105 new_bus->name = "GPIO Bitbanged MDIO",
128 106
129 ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node); 107 ret = -ENODEV;
130 if (ret)
131 goto out_free_bus;
132 108
133 new_bus->phy_mask = ~0; 109 new_bus->phy_mask = pdata->phy_mask;
134 new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); 110 new_bus->irq = pdata->irqs;
135 if (!new_bus->irq) 111 new_bus->parent = dev;
112
113 if (new_bus->phy_mask == ~0)
136 goto out_free_bus; 114 goto out_free_bus;
137 115
138 for (i = 0; i < PHY_MAX_ADDR; i++) 116 for (i = 0; i < PHY_MAX_ADDR; i++)
139 new_bus->irq[i] = -1; 117 if (!new_bus->irq[i])
118 new_bus->irq[i] = PHY_POLL;
140 119
141 while ((np = of_get_next_child(ofdev->node, np))) 120 snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", bus_id);
142 if (!strcmp(np->type, "ethernet-phy")) 121
143 add_phy(new_bus, np); 122 if (gpio_request(bitbang->mdc, "mdc"))
123 goto out_free_bus;
144 124
145 new_bus->parent = &ofdev->dev; 125 if (gpio_request(bitbang->mdio, "mdio"))
146 dev_set_drvdata(&ofdev->dev, new_bus); 126 goto out_free_mdc;
127
128 dev_set_drvdata(dev, new_bus);
147 129
148 ret = mdiobus_register(new_bus); 130 ret = mdiobus_register(new_bus);
149 if (ret) 131 if (ret)
150 goto out_free_irqs; 132 goto out_free_all;
151 133
152 return 0; 134 return 0;
153 135
154out_free_irqs: 136out_free_all:
155 dev_set_drvdata(&ofdev->dev, NULL); 137 dev_set_drvdata(dev, NULL);
156 kfree(new_bus->irq); 138 gpio_free(bitbang->mdio);
139out_free_mdc:
140 gpio_free(bitbang->mdc);
157out_free_bus: 141out_free_bus:
158 free_mdio_bitbang(new_bus); 142 free_mdio_bitbang(new_bus);
159out_free_bitbang: 143out_free_bitbang:
@@ -162,16 +146,86 @@ out:
162 return ret; 146 return ret;
163} 147}
164 148
165static int mdio_ofgpio_remove(struct of_device *ofdev) 149static void __devexit mdio_gpio_bus_destroy(struct device *dev)
166{ 150{
167 struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); 151 struct mii_bus *bus = dev_get_drvdata(dev);
168 struct mdio_gpio_info *bitbang = bus->priv; 152 struct mdio_gpio_info *bitbang = bus->priv;
169 153
170 mdiobus_unregister(bus); 154 mdiobus_unregister(bus);
171 kfree(bus->irq);
172 free_mdio_bitbang(bus); 155 free_mdio_bitbang(bus);
173 dev_set_drvdata(&ofdev->dev, NULL); 156 dev_set_drvdata(dev, NULL);
157 gpio_free(bitbang->mdc);
158 gpio_free(bitbang->mdio);
174 kfree(bitbang); 159 kfree(bitbang);
160}
161
162static int __devinit mdio_gpio_probe(struct platform_device *pdev)
163{
164 struct mdio_gpio_platform_data *pdata = pdev->dev.platform_data;
165
166 if (!pdata)
167 return -ENODEV;
168
169 return mdio_gpio_bus_init(&pdev->dev, pdata, pdev->id);
170}
171
172static int __devexit mdio_gpio_remove(struct platform_device *pdev)
173{
174 mdio_gpio_bus_destroy(&pdev->dev);
175
176 return 0;
177}
178
179#ifdef CONFIG_OF_GPIO
180static void __devinit add_phy(struct mdio_gpio_platform_data *pdata,
181 struct device_node *np)
182{
183 const u32 *data;
184 int len, id, irq;
185
186 data = of_get_property(np, "reg", &len);
187 if (!data || len != 4)
188 return;
189
190 id = *data;
191 pdata->phy_mask &= ~(1 << id);
192
193 irq = of_irq_to_resource(np, 0, NULL);
194 if (irq)
195 pdata->irqs[id] = irq;
196}
197
198static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
199 const struct of_device_id *match)
200{
201 struct device_node *np = NULL;
202 struct mdio_gpio_platform_data *pdata;
203
204 pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
205 if (!pdata)
206 return -ENOMEM;
207
208 pdata->mdc = of_get_gpio(ofdev->node, 0);
209 pdata->mdio = of_get_gpio(ofdev->node, 1);
210
211 if (pdata->mdc < 0 || pdata->mdio < 0)
212 goto out_free;
213
214 while ((np = of_get_next_child(ofdev->node, np)))
215 if (!strcmp(np->type, "ethernet-phy"))
216 add_phy(pdata, np);
217
218 return mdio_gpio_bus_init(&ofdev->dev, pdata, pdata->mdc);
219
220out_free:
221 kfree(pdata);
222 return -ENODEV;
223}
224
225static int __devexit mdio_ofgpio_remove(struct of_device *ofdev)
226{
227 mdio_gpio_bus_destroy(&ofdev->dev);
228 kfree(ofdev->dev.platform_data);
175 229
176 return 0; 230 return 0;
177} 231}
@@ -187,18 +241,56 @@ static struct of_platform_driver mdio_ofgpio_driver = {
187 .name = "mdio-gpio", 241 .name = "mdio-gpio",
188 .match_table = mdio_ofgpio_match, 242 .match_table = mdio_ofgpio_match,
189 .probe = mdio_ofgpio_probe, 243 .probe = mdio_ofgpio_probe,
190 .remove = mdio_ofgpio_remove, 244 .remove = __devexit_p(mdio_ofgpio_remove),
191}; 245};
192 246
193static int mdio_ofgpio_init(void) 247static inline int __init mdio_ofgpio_init(void)
194{ 248{
195 return of_register_platform_driver(&mdio_ofgpio_driver); 249 return of_register_platform_driver(&mdio_ofgpio_driver);
196} 250}
197 251
198static void mdio_ofgpio_exit(void) 252static inline void __exit mdio_ofgpio_exit(void)
199{ 253{
200 of_unregister_platform_driver(&mdio_ofgpio_driver); 254 of_unregister_platform_driver(&mdio_ofgpio_driver);
201} 255}
256#else
257static inline int __init mdio_ofgpio_init(void) { return 0; }
258static inline void __exit mdio_ofgpio_exit(void) { }
259#endif /* CONFIG_OF_GPIO */
260
261static struct platform_driver mdio_gpio_driver = {
262 .probe = mdio_gpio_probe,
263 .remove = __devexit_p(mdio_gpio_remove),
264 .driver = {
265 .name = "mdio-gpio",
266 .owner = THIS_MODULE,
267 },
268};
269
270static int __init mdio_gpio_init(void)
271{
272 int ret;
273
274 ret = mdio_ofgpio_init();
275 if (ret)
276 return ret;
277
278 ret = platform_driver_register(&mdio_gpio_driver);
279 if (ret)
280 mdio_ofgpio_exit();
281
282 return ret;
283}
284module_init(mdio_gpio_init);
285
286static void __exit mdio_gpio_exit(void)
287{
288 platform_driver_unregister(&mdio_gpio_driver);
289 mdio_ofgpio_exit();
290}
291module_exit(mdio_gpio_exit);
202 292
203module_init(mdio_ofgpio_init); 293MODULE_ALIAS("platform:mdio-gpio");
204module_exit(mdio_ofgpio_exit); 294MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas");
295MODULE_LICENSE("GPL");
296MODULE_DESCRIPTION("Generic driver for MDIO bus emulation using GPIO");