aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Pinchart <laurentp@cse-semaphore.com>2008-05-26 05:53:21 -0400
committerJeff Garzik <jgarzik@redhat.com>2008-05-30 22:18:25 -0400
commita5edeccb1a8432ae5d9fb9bccea5a4b64c565017 (patch)
treed55dfa3802a65d3a3372f3487fb42b8495f96f2c
parent62c78329581e76347e1078b8ea996b603be3efec (diff)
net: OpenFirmware GPIO based MDIO bitbang driver
This patch adds an MDIO bitbang driver that uses the GPIO library and its OF bindings to access the bus I/Os. Signed-off-by: Laurent Pinchart <laurentp@cse-semaphore.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
-rw-r--r--Documentation/powerpc/booting-without-of.txt21
-rw-r--r--drivers/net/phy/Kconfig6
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/mdio-ofgpio.c205
4 files changed, 233 insertions, 0 deletions
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index 1d2a772506cf..46a9dba11f2f 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -58,6 +58,7 @@ Table of Contents
58 o) Xilinx IP cores 58 o) Xilinx IP cores
59 p) Freescale Synchronous Serial Interface 59 p) Freescale Synchronous Serial Interface
60 q) USB EHCI controllers 60 q) USB EHCI controllers
61 r) MDIO on GPIOs
61 62
62 VII - Marvell Discovery mv64[345]6x System Controller chips 63 VII - Marvell Discovery mv64[345]6x System Controller chips
63 1) The /system-controller node 64 1) The /system-controller node
@@ -2870,6 +2871,26 @@ platforms are moved over to use the flattened-device-tree model.
2870 reg = <0xe8000000 32>; 2871 reg = <0xe8000000 32>;
2871 }; 2872 };
2872 2873
2874 r) MDIO on GPIOs
2875
2876 Currently defined compatibles:
2877 - virtual,gpio-mdio
2878
2879 MDC and MDIO lines connected to GPIO controllers are listed in the
2880 gpios property as described in section VIII.1 in the following order:
2881
2882 MDC, MDIO.
2883
2884 Example:
2885
2886 mdio {
2887 compatible = "virtual,mdio-gpio";
2888 #address-cells = <1>;
2889 #size-cells = <0>;
2890 gpios = <&qe_pio_a 11
2891 &qe_pio_c 6>;
2892 };
2893
2873VII - Marvell Discovery mv64[345]6x System Controller chips 2894VII - Marvell Discovery mv64[345]6x System Controller chips
2874=========================================================== 2895===========================================================
2875 2896
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 284217c12839..d55932acd887 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -84,4 +84,10 @@ config MDIO_BITBANG
84 84
85 If in doubt, say N. 85 If in doubt, say N.
86 86
87config MDIO_OF_GPIO
88 tristate "Support for GPIO lib-based bitbanged MDIO buses"
89 depends on MDIO_BITBANG && OF_GPIO
90 ---help---
91 Supports GPIO lib-based MDIO busses.
92
87endif # PHYLIB 93endif # PHYLIB
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 5997d6ef702b..eee329fa6f53 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -15,3 +15,4 @@ obj-$(CONFIG_ICPLUS_PHY) += icplus.o
15obj-$(CONFIG_REALTEK_PHY) += realtek.o 15obj-$(CONFIG_REALTEK_PHY) += realtek.o
16obj-$(CONFIG_FIXED_PHY) += fixed.o 16obj-$(CONFIG_FIXED_PHY) += fixed.o
17obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o 17obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
18obj-$(CONFIG_MDIO_OF_GPIO) += mdio-ofgpio.o
diff --git a/drivers/net/phy/mdio-ofgpio.c b/drivers/net/phy/mdio-ofgpio.c
new file mode 100644
index 000000000000..7edfc0c34835
--- /dev/null
+++ b/drivers/net/phy/mdio-ofgpio.c
@@ -0,0 +1,205 @@
1/*
2 * OpenFirmware GPIO based MDIO bitbang driver.
3 *
4 * Copyright (c) 2008 CSE Semaphore Belgium.
5 * by Laurent Pinchart <laurentp@cse-semaphore.com>
6 *
7 * Based on earlier work by
8 *
9 * Copyright (c) 2003 Intracom S.A.
10 * by Pantelis Antoniou <panto@intracom.gr>
11 *
12 * 2005 (c) MontaVista Software, Inc.
13 * Vitaly Bordug <vbordug@ru.mvista.com>
14 *
15 * This file is licensed under the terms of the GNU General Public License
16 * version 2. This program is licensed "as is" without any warranty of any
17 * kind, whether express or implied.
18 */
19
20#include <linux/module.h>
21#include <linux/slab.h>
22#include <linux/init.h>
23#include <linux/interrupt.h>
24#include <linux/mdio-bitbang.h>
25#include <linux/of_gpio.h>
26#include <linux/of_platform.h>
27
28struct mdio_gpio_info {
29 struct mdiobb_ctrl ctrl;
30 int mdc, mdio;
31};
32
33static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
34{
35 struct mdio_gpio_info *bitbang =
36 container_of(ctrl, struct mdio_gpio_info, ctrl);
37
38 if (dir)
39 gpio_direction_output(bitbang->mdio, 1);
40 else
41 gpio_direction_input(bitbang->mdio);
42}
43
44static int mdio_read(struct mdiobb_ctrl *ctrl)
45{
46 struct mdio_gpio_info *bitbang =
47 container_of(ctrl, struct mdio_gpio_info, ctrl);
48
49 return gpio_get_value(bitbang->mdio);
50}
51
52static void mdio(struct mdiobb_ctrl *ctrl, int what)
53{
54 struct mdio_gpio_info *bitbang =
55 container_of(ctrl, struct mdio_gpio_info, ctrl);
56
57 gpio_set_value(bitbang->mdio, what);
58}
59
60static void mdc(struct mdiobb_ctrl *ctrl, int what)
61{
62 struct mdio_gpio_info *bitbang =
63 container_of(ctrl, struct mdio_gpio_info, ctrl);
64
65 gpio_set_value(bitbang->mdc, what);
66}
67
68static struct mdiobb_ops mdio_gpio_ops = {
69 .owner = THIS_MODULE,
70 .set_mdc = mdc,
71 .set_mdio_dir = mdio_dir,
72 .set_mdio_data = mdio,
73 .get_mdio_data = mdio_read,
74};
75
76static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus,
77 struct device_node *np)
78{
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{
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;
113 struct mdio_gpio_info *bitbang;
114 int ret = -ENOMEM;
115 int i;
116
117 bitbang = kzalloc(sizeof(struct mdio_gpio_info), GFP_KERNEL);
118 if (!bitbang)
119 goto out;
120
121 bitbang->ctrl.ops = &mdio_gpio_ops;
122
123 new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
124 if (!new_bus)
125 goto out_free_priv;
126
127 new_bus->name = "GPIO Bitbanged MII",
128
129 ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node);
130 if (ret)
131 goto out_free_bus;
132
133 new_bus->phy_mask = ~0;
134 new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
135 if (!new_bus->irq)
136 goto out_free_bus;
137
138 for (i = 0; i < PHY_MAX_ADDR; i++)
139 new_bus->irq[i] = -1;
140
141 while ((np = of_get_next_child(ofdev->node, np)))
142 if (!strcmp(np->type, "ethernet-phy"))
143 add_phy(new_bus, np);
144
145 new_bus->dev = &ofdev->dev;
146 dev_set_drvdata(&ofdev->dev, new_bus);
147
148 ret = mdiobus_register(new_bus);
149 if (ret)
150 goto out_free_irqs;
151
152 return 0;
153
154out_free_irqs:
155 dev_set_drvdata(&ofdev->dev, NULL);
156 kfree(new_bus->irq);
157out_free_bus:
158 kfree(new_bus);
159out_free_priv:
160 free_mdio_bitbang(new_bus);
161out:
162 return ret;
163}
164
165static int mdio_ofgpio_remove(struct of_device *ofdev)
166{
167 struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
168 struct mdio_gpio_info *bitbang = bus->priv;
169
170 mdiobus_unregister(bus);
171 free_mdio_bitbang(bus);
172 dev_set_drvdata(&ofdev->dev, NULL);
173 kfree(bus->irq);
174 kfree(bitbang);
175 kfree(bus);
176
177 return 0;
178}
179
180static struct of_device_id mdio_ofgpio_match[] = {
181 {
182 .compatible = "virtual,mdio-gpio",
183 },
184 {},
185};
186
187static struct of_platform_driver mdio_ofgpio_driver = {
188 .name = "mdio-gpio",
189 .match_table = mdio_ofgpio_match,
190 .probe = mdio_ofgpio_probe,
191 .remove = mdio_ofgpio_remove,
192};
193
194static int mdio_ofgpio_init(void)
195{
196 return of_register_platform_driver(&mdio_ofgpio_driver);
197}
198
199static void mdio_ofgpio_exit(void)
200{
201 of_unregister_platform_driver(&mdio_ofgpio_driver);
202}
203
204module_init(mdio_ofgpio_init);
205module_exit(mdio_ofgpio_exit);