aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/phy
diff options
context:
space:
mode:
authorDavid Daney <david.daney@cavium.com>2012-05-02 11:16:39 -0400
committerDavid S. Miller <davem@davemloft.net>2012-05-07 22:58:09 -0400
commit416912a129349788372e6ac27ab86bd9b18c8cc0 (patch)
tree239766992fc6878f89cce3037f65f757fc880dae /drivers/net/phy
parent0ca2997d145268e6b4ef000692061849cdab8348 (diff)
netdev/of/phy: Add MDIO bus multiplexer driven by GPIO lines.
The GPIO pins select which sub bus is connected to the master. Initially tested with an sn74cbtlv3253 switch device wired into the MDIO bus. Signed-off-by: David Daney <david.daney@cavium.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/phy')
-rw-r--r--drivers/net/phy/Kconfig10
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/mdio-mux-gpio.c142
3 files changed, 153 insertions, 0 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 99c0674a5935..944cdfb80fe4 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -144,6 +144,16 @@ config MDIO_BUS_MUX
144 to a parent bus. Switching between child busses is done by 144 to a parent bus. Switching between child busses is done by
145 device specific drivers. 145 device specific drivers.
146 146
147config MDIO_BUS_MUX_GPIO
148 tristate "Support for GPIO controlled MDIO bus multiplexers"
149 depends on OF_GPIO && OF_MDIO
150 select MDIO_BUS_MUX
151 help
152 This module provides a driver for MDIO bus multiplexers that
153 are controlled via GPIO lines. The multiplexer connects one of
154 several child MDIO busses to a parent bus. Child bus
155 selection is under the control of GPIO lines.
156
147endif # PHYLIB 157endif # PHYLIB
148 158
149config MICREL_KS8995MA 159config MICREL_KS8995MA
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index a6b50e7715d0..f51af688ef8b 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -26,3 +26,4 @@ obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
26obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o 26obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o
27obj-$(CONFIG_AMD_PHY) += amd.o 27obj-$(CONFIG_AMD_PHY) += amd.o
28obj-$(CONFIG_MDIO_BUS_MUX) += mdio-mux.o 28obj-$(CONFIG_MDIO_BUS_MUX) += mdio-mux.o
29obj-$(CONFIG_MDIO_BUS_MUX_GPIO) += mdio-mux-gpio.o
diff --git a/drivers/net/phy/mdio-mux-gpio.c b/drivers/net/phy/mdio-mux-gpio.c
new file mode 100644
index 000000000000..e0cc4ef33dee
--- /dev/null
+++ b/drivers/net/phy/mdio-mux-gpio.c
@@ -0,0 +1,142 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2011, 2012 Cavium, Inc.
7 */
8
9#include <linux/platform_device.h>
10#include <linux/device.h>
11#include <linux/of_mdio.h>
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/phy.h>
15#include <linux/mdio-mux.h>
16#include <linux/of_gpio.h>
17
18#define DRV_VERSION "1.0"
19#define DRV_DESCRIPTION "GPIO controlled MDIO bus multiplexer driver"
20
21#define MDIO_MUX_GPIO_MAX_BITS 8
22
23struct mdio_mux_gpio_state {
24 int gpio[MDIO_MUX_GPIO_MAX_BITS];
25 unsigned int num_gpios;
26 void *mux_handle;
27};
28
29static int mdio_mux_gpio_switch_fn(int current_child, int desired_child,
30 void *data)
31{
32 int change;
33 unsigned int n;
34 struct mdio_mux_gpio_state *s = data;
35
36 if (current_child == desired_child)
37 return 0;
38
39 change = current_child == -1 ? -1 : current_child ^ desired_child;
40
41 for (n = 0; n < s->num_gpios; n++) {
42 if (change & 1)
43 gpio_set_value_cansleep(s->gpio[n],
44 (desired_child & 1) != 0);
45 change >>= 1;
46 desired_child >>= 1;
47 }
48
49 return 0;
50}
51
52static int __devinit mdio_mux_gpio_probe(struct platform_device *pdev)
53{
54 enum of_gpio_flags f;
55 struct mdio_mux_gpio_state *s;
56 unsigned int num_gpios;
57 unsigned int n;
58 int r;
59
60 if (!pdev->dev.of_node)
61 return -ENODEV;
62
63 num_gpios = of_gpio_count(pdev->dev.of_node);
64 if (num_gpios == 0 || num_gpios > MDIO_MUX_GPIO_MAX_BITS)
65 return -ENODEV;
66
67 s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
68 if (!s)
69 return -ENOMEM;
70
71 s->num_gpios = num_gpios;
72
73 for (n = 0; n < num_gpios; ) {
74 int gpio = of_get_gpio_flags(pdev->dev.of_node, n, &f);
75 if (gpio < 0) {
76 r = (gpio == -ENODEV) ? -EPROBE_DEFER : gpio;
77 goto err;
78 }
79 s->gpio[n] = gpio;
80
81 n++;
82
83 r = gpio_request(gpio, "mdio_mux_gpio");
84 if (r)
85 goto err;
86
87 r = gpio_direction_output(gpio, 0);
88 if (r)
89 goto err;
90 }
91
92 r = mdio_mux_init(&pdev->dev,
93 mdio_mux_gpio_switch_fn, &s->mux_handle, s);
94
95 if (r == 0) {
96 pdev->dev.platform_data = s;
97 return 0;
98 }
99err:
100 while (n) {
101 n--;
102 gpio_free(s->gpio[n]);
103 }
104 devm_kfree(&pdev->dev, s);
105 return r;
106}
107
108static int __devexit mdio_mux_gpio_remove(struct platform_device *pdev)
109{
110 struct mdio_mux_gpio_state *s = pdev->dev.platform_data;
111 mdio_mux_uninit(s->mux_handle);
112 return 0;
113}
114
115static struct of_device_id mdio_mux_gpio_match[] = {
116 {
117 .compatible = "mdio-mux-gpio",
118 },
119 {
120 /* Legacy compatible property. */
121 .compatible = "cavium,mdio-mux-sn74cbtlv3253",
122 },
123 {},
124};
125MODULE_DEVICE_TABLE(of, mdio_mux_gpio_match);
126
127static struct platform_driver mdio_mux_gpio_driver = {
128 .driver = {
129 .name = "mdio-mux-gpio",
130 .owner = THIS_MODULE,
131 .of_match_table = mdio_mux_gpio_match,
132 },
133 .probe = mdio_mux_gpio_probe,
134 .remove = __devexit_p(mdio_mux_gpio_remove),
135};
136
137module_platform_driver(mdio_mux_gpio_driver);
138
139MODULE_DESCRIPTION(DRV_DESCRIPTION);
140MODULE_VERSION(DRV_VERSION);
141MODULE_AUTHOR("David Daney");
142MODULE_LICENSE("GPL");