Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Laurent Pinchart and committed by
Jeff Garzik
a5edeccb 62c78329

+233
+21
Documentation/powerpc/booting-without-of.txt
··· 58 58 o) Xilinx IP cores 59 59 p) Freescale Synchronous Serial Interface 60 60 q) USB EHCI controllers 61 + r) MDIO on GPIOs 61 62 62 63 VII - Marvell Discovery mv64[345]6x System Controller chips 63 64 1) The /system-controller node ··· 2869 2868 board-control@e8000000 { 2870 2869 compatible = "fsl,fpga-pixis"; 2871 2870 reg = <0xe8000000 32>; 2871 + }; 2872 + 2873 + r) MDIO on GPIOs 2874 + 2875 + Currently defined compatibles: 2876 + - virtual,gpio-mdio 2877 + 2878 + MDC and MDIO lines connected to GPIO controllers are listed in the 2879 + gpios property as described in section VIII.1 in the following order: 2880 + 2881 + MDC, MDIO. 2882 + 2883 + Example: 2884 + 2885 + mdio { 2886 + compatible = "virtual,mdio-gpio"; 2887 + #address-cells = <1>; 2888 + #size-cells = <0>; 2889 + gpios = <&qe_pio_a 11 2890 + &qe_pio_c 6>; 2872 2891 }; 2873 2892 2874 2893 VII - Marvell Discovery mv64[345]6x System Controller chips
+6
drivers/net/phy/Kconfig
··· 84 84 85 85 If in doubt, say N. 86 86 87 + config 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 + 87 93 endif # PHYLIB
+1
drivers/net/phy/Makefile
··· 15 15 obj-$(CONFIG_REALTEK_PHY) += realtek.o 16 16 obj-$(CONFIG_FIXED_PHY) += fixed.o 17 17 obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o 18 + obj-$(CONFIG_MDIO_OF_GPIO) += mdio-ofgpio.o
+205
drivers/net/phy/mdio-ofgpio.c
··· 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 + 28 + struct mdio_gpio_info { 29 + struct mdiobb_ctrl ctrl; 30 + int mdc, mdio; 31 + }; 32 + 33 + static 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 + 44 + static 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 + 52 + static 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 + 60 + static 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 + 68 + static 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 + 76 + static 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 + 91 + static 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 + 108 + static 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 + 154 + out_free_irqs: 155 + dev_set_drvdata(&ofdev->dev, NULL); 156 + kfree(new_bus->irq); 157 + out_free_bus: 158 + kfree(new_bus); 159 + out_free_priv: 160 + free_mdio_bitbang(new_bus); 161 + out: 162 + return ret; 163 + } 164 + 165 + static 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 + 180 + static struct of_device_id mdio_ofgpio_match[] = { 181 + { 182 + .compatible = "virtual,mdio-gpio", 183 + }, 184 + {}, 185 + }; 186 + 187 + static 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 + 194 + static int mdio_ofgpio_init(void) 195 + { 196 + return of_register_platform_driver(&mdio_ofgpio_driver); 197 + } 198 + 199 + static void mdio_ofgpio_exit(void) 200 + { 201 + of_unregister_platform_driver(&mdio_ofgpio_driver); 202 + } 203 + 204 + module_init(mdio_ofgpio_init); 205 + module_exit(mdio_ofgpio_exit);