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

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>

authored by

Paulius Zaleckas and committed by
David S. Miller
f004f3ea 72af187f

+196 -76
+4 -1
drivers/net/phy/Kconfig
··· 86 86 87 87 config MDIO_GPIO 88 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 90 ---help--- 91 91 Supports GPIO lib-based MDIO busses. 92 + 93 + To compile this driver as a module, choose M here: the module 94 + will be called mdio-gpio. 92 95 93 96 endif # PHYLIB
+167 -75
drivers/net/phy/mdio-gpio.c
··· 1 1 /* 2 - * OpenFirmware GPIO based MDIO bitbang driver. 2 + * GPIO based MDIO bitbang driver. 3 + * Supports OpenFirmware. 3 4 * 4 5 * Copyright (c) 2008 CSE Semaphore Belgium. 5 6 * by Laurent Pinchart <laurentp@cse-semaphore.com> 7 + * 8 + * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt> 6 9 * 7 10 * Based on earlier work by 8 11 * ··· 24 21 #include <linux/slab.h> 25 22 #include <linux/init.h> 26 23 #include <linux/interrupt.h> 27 - #include <linux/mdio-bitbang.h> 24 + #include <linux/platform_device.h> 25 + #include <linux/gpio.h> 26 + #include <linux/mdio-gpio.h> 27 + 28 + #ifdef CONFIG_OF_GPIO 28 29 #include <linux/of_gpio.h> 29 30 #include <linux/of_platform.h> 31 + #endif 30 32 31 33 struct mdio_gpio_info { 32 34 struct mdiobb_ctrl ctrl; ··· 49 41 gpio_direction_input(bitbang->mdio); 50 42 } 51 43 52 - static int mdio_read(struct mdiobb_ctrl *ctrl) 44 + static int mdio_get(struct mdiobb_ctrl *ctrl) 53 45 { 54 46 struct mdio_gpio_info *bitbang = 55 47 container_of(ctrl, struct mdio_gpio_info, ctrl); ··· 57 49 return gpio_get_value(bitbang->mdio); 58 50 } 59 51 60 - static void mdio(struct mdiobb_ctrl *ctrl, int what) 52 + static void mdio_set(struct mdiobb_ctrl *ctrl, int what) 61 53 { 62 54 struct mdio_gpio_info *bitbang = 63 55 container_of(ctrl, struct mdio_gpio_info, ctrl); ··· 65 57 gpio_set_value(bitbang->mdio, what); 66 58 } 67 59 68 - static void mdc(struct mdiobb_ctrl *ctrl, int what) 60 + static void mdc_set(struct mdiobb_ctrl *ctrl, int what) 69 61 { 70 62 struct mdio_gpio_info *bitbang = 71 63 container_of(ctrl, struct mdio_gpio_info, ctrl); ··· 75 67 76 68 static struct mdiobb_ops mdio_gpio_ops = { 77 69 .owner = THIS_MODULE, 78 - .set_mdc = mdc, 70 + .set_mdc = mdc_set, 79 71 .set_mdio_dir = mdio_dir, 80 - .set_mdio_data = mdio, 81 - .get_mdio_data = mdio_read, 72 + .set_mdio_data = mdio_set, 73 + .get_mdio_data = mdio_get, 82 74 }; 83 75 84 - static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus, 85 - struct device_node *np) 76 + static int __devinit mdio_gpio_bus_init(struct device *dev, 77 + struct mdio_gpio_platform_data *pdata, 78 + int bus_id) 86 79 { 80 + struct mii_bus *new_bus; 81 + struct mdio_gpio_info *bitbang; 82 + int ret = -ENOMEM; 83 + int i; 84 + 85 + bitbang = kzalloc(sizeof(*bitbang), GFP_KERNEL); 86 + if (!bitbang) 87 + goto out; 88 + 89 + bitbang->ctrl.ops = &mdio_gpio_ops; 90 + bitbang->mdc = pdata->mdc; 91 + bitbang->mdio = pdata->mdio; 92 + 93 + new_bus = alloc_mdio_bitbang(&bitbang->ctrl); 94 + if (!new_bus) 95 + goto out_free_bitbang; 96 + 97 + new_bus->name = "GPIO Bitbanged MDIO", 98 + 99 + ret = -ENODEV; 100 + 101 + new_bus->phy_mask = pdata->phy_mask; 102 + new_bus->irq = pdata->irqs; 103 + new_bus->parent = dev; 104 + 105 + if (new_bus->phy_mask == ~0) 106 + goto out_free_bus; 107 + 108 + for (i = 0; i < PHY_MAX_ADDR; i++) 109 + if (!new_bus->irq[i]) 110 + new_bus->irq[i] = PHY_POLL; 111 + 112 + snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", bus_id); 113 + 114 + if (gpio_request(bitbang->mdc, "mdc")) 115 + goto out_free_bus; 116 + 117 + if (gpio_request(bitbang->mdio, "mdio")) 118 + goto out_free_mdc; 119 + 120 + dev_set_drvdata(dev, new_bus); 121 + 122 + ret = mdiobus_register(new_bus); 123 + if (ret) 124 + goto out_free_all; 125 + 126 + return 0; 127 + 128 + out_free_all: 129 + dev_set_drvdata(dev, NULL); 130 + gpio_free(bitbang->mdio); 131 + out_free_mdc: 132 + gpio_free(bitbang->mdc); 133 + out_free_bus: 134 + free_mdio_bitbang(new_bus); 135 + out_free_bitbang: 136 + kfree(bitbang); 137 + out: 138 + return ret; 139 + } 140 + 141 + static void __devexit mdio_gpio_bus_destroy(struct device *dev) 142 + { 143 + struct mii_bus *bus = dev_get_drvdata(dev); 87 144 struct mdio_gpio_info *bitbang = bus->priv; 88 145 89 - bitbang->mdc = of_get_gpio(np, 0); 90 - bitbang->mdio = of_get_gpio(np, 1); 146 + mdiobus_unregister(bus); 147 + free_mdio_bitbang(bus); 148 + dev_set_drvdata(dev, NULL); 149 + gpio_free(bitbang->mdc); 150 + gpio_free(bitbang->mdio); 151 + kfree(bitbang); 152 + } 91 153 92 - if (bitbang->mdc < 0 || bitbang->mdio < 0) 154 + static int __devinit mdio_gpio_probe(struct platform_device *pdev) 155 + { 156 + struct mdio_gpio_platform_data *pdata = pdev->dev.platform_data; 157 + 158 + if (!pdata) 93 159 return -ENODEV; 94 160 95 - snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc); 161 + return mdio_gpio_bus_init(&pdev->dev, pdata, pdev->id); 162 + } 163 + 164 + static int __devexit mdio_gpio_remove(struct platform_device *pdev) 165 + { 166 + mdio_gpio_bus_destroy(&pdev->dev); 167 + 96 168 return 0; 97 169 } 98 170 99 - static void __devinit add_phy(struct mii_bus *bus, struct device_node *np) 171 + #ifdef CONFIG_OF_GPIO 172 + static void __devinit add_phy(struct mdio_gpio_platform_data *pdata, 173 + struct device_node *np) 100 174 { 101 175 const u32 *data; 102 176 int len, id, irq; ··· 188 98 return; 189 99 190 100 id = *data; 191 - bus->phy_mask &= ~(1 << id); 101 + pdata->phy_mask &= ~(1 << id); 192 102 193 103 irq = of_irq_to_resource(np, 0, NULL); 194 - if (irq != NO_IRQ) 195 - bus->irq[id] = irq; 104 + if (irq) 105 + pdata->irqs[id] = irq; 196 106 } 197 107 198 108 static int __devinit mdio_ofgpio_probe(struct of_device *ofdev, 199 109 const struct of_device_id *match) 200 110 { 201 111 struct device_node *np = NULL; 202 - struct mii_bus *new_bus; 203 - struct mdio_gpio_info *bitbang; 204 - int ret = -ENOMEM; 205 - int i; 112 + struct mdio_gpio_platform_data *pdata; 206 113 207 - bitbang = kzalloc(sizeof(struct mdio_gpio_info), GFP_KERNEL); 208 - if (!bitbang) 209 - goto out; 114 + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); 115 + if (!pdata) 116 + return -ENOMEM; 210 117 211 - bitbang->ctrl.ops = &mdio_gpio_ops; 118 + pdata->mdc = of_get_gpio(ofdev->node, 0); 119 + pdata->mdio = of_get_gpio(ofdev->node, 1); 212 120 213 - new_bus = alloc_mdio_bitbang(&bitbang->ctrl); 214 - if (!new_bus) 215 - goto out_free_bitbang; 216 - 217 - new_bus->name = "GPIO Bitbanged MII", 218 - 219 - ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node); 220 - if (ret) 221 - goto out_free_bus; 222 - 223 - new_bus->phy_mask = ~0; 224 - new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); 225 - if (!new_bus->irq) 226 - goto out_free_bus; 227 - 228 - for (i = 0; i < PHY_MAX_ADDR; i++) 229 - new_bus->irq[i] = -1; 121 + if (pdata->mdc < 0 || pdata->mdio < 0) 122 + goto out_free; 230 123 231 124 while ((np = of_get_next_child(ofdev->node, np))) 232 125 if (!strcmp(np->type, "ethernet-phy")) 233 - add_phy(new_bus, np); 126 + add_phy(pdata, np); 234 127 235 - new_bus->parent = &ofdev->dev; 236 - dev_set_drvdata(&ofdev->dev, new_bus); 128 + return mdio_gpio_bus_init(&ofdev->dev, pdata, pdata->mdc); 237 129 238 - ret = mdiobus_register(new_bus); 239 - if (ret) 240 - goto out_free_irqs; 241 - 242 - return 0; 243 - 244 - out_free_irqs: 245 - dev_set_drvdata(&ofdev->dev, NULL); 246 - kfree(new_bus->irq); 247 - out_free_bus: 248 - free_mdio_bitbang(new_bus); 249 - out_free_bitbang: 250 - kfree(bitbang); 251 - out: 252 - return ret; 130 + out_free: 131 + kfree(pdata); 132 + return -ENODEV; 253 133 } 254 134 255 - static int mdio_ofgpio_remove(struct of_device *ofdev) 135 + static int __devexit mdio_ofgpio_remove(struct of_device *ofdev) 256 136 { 257 - struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); 258 - struct mdio_gpio_info *bitbang = bus->priv; 259 - 260 - mdiobus_unregister(bus); 261 - kfree(bus->irq); 262 - free_mdio_bitbang(bus); 263 - dev_set_drvdata(&ofdev->dev, NULL); 264 - kfree(bitbang); 137 + mdio_gpio_bus_destroy(&ofdev->dev); 138 + kfree(ofdev->dev.platform_data); 265 139 266 140 return 0; 267 141 } ··· 241 187 .name = "mdio-gpio", 242 188 .match_table = mdio_ofgpio_match, 243 189 .probe = mdio_ofgpio_probe, 244 - .remove = mdio_ofgpio_remove, 190 + .remove = __devexit_p(mdio_ofgpio_remove), 245 191 }; 246 192 247 - static int mdio_ofgpio_init(void) 193 + static inline int __init mdio_ofgpio_init(void) 248 194 { 249 195 return of_register_platform_driver(&mdio_ofgpio_driver); 250 196 } 251 197 252 - static void mdio_ofgpio_exit(void) 198 + static inline void __exit mdio_ofgpio_exit(void) 253 199 { 254 200 of_unregister_platform_driver(&mdio_ofgpio_driver); 255 201 } 202 + #else 203 + static inline int __init mdio_ofgpio_init(void) { return 0; } 204 + static inline void __exit mdio_ofgpio_exit(void) { } 205 + #endif /* CONFIG_OF_GPIO */ 256 206 257 - module_init(mdio_ofgpio_init); 258 - module_exit(mdio_ofgpio_exit); 207 + static struct platform_driver mdio_gpio_driver = { 208 + .probe = mdio_gpio_probe, 209 + .remove = __devexit_p(mdio_gpio_remove), 210 + .driver = { 211 + .name = "mdio-gpio", 212 + .owner = THIS_MODULE, 213 + }, 214 + }; 215 + 216 + static int __init mdio_gpio_init(void) 217 + { 218 + int ret; 219 + 220 + ret = mdio_ofgpio_init(); 221 + if (ret) 222 + return ret; 223 + 224 + ret = platform_driver_register(&mdio_gpio_driver); 225 + if (ret) 226 + mdio_ofgpio_exit(); 227 + 228 + return ret; 229 + } 230 + module_init(mdio_gpio_init); 231 + 232 + static void __exit mdio_gpio_exit(void) 233 + { 234 + platform_driver_unregister(&mdio_gpio_driver); 235 + mdio_ofgpio_exit(); 236 + } 237 + module_exit(mdio_gpio_exit); 238 + 239 + MODULE_ALIAS("platform:mdio-gpio"); 240 + MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas"); 241 + MODULE_LICENSE("GPL"); 242 + MODULE_DESCRIPTION("Generic driver for MDIO bus emulation using GPIO");
+25
include/linux/mdio-gpio.h
··· 1 + /* 2 + * MDIO-GPIO bus platform data structures 3 + * 4 + * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt> 5 + * 6 + * This file is licensed under the terms of the GNU General Public License 7 + * version 2. This program is licensed "as is" without any warranty of any 8 + * kind, whether express or implied. 9 + */ 10 + 11 + #ifndef __LINUX_MDIO_GPIO_H 12 + #define __LINUX_MDIO_GPIO_H 13 + 14 + #include <linux/mdio-bitbang.h> 15 + 16 + struct mdio_gpio_platform_data { 17 + /* GPIO numbers for bus pins */ 18 + unsigned int mdc; 19 + unsigned int mdio; 20 + 21 + unsigned int phy_mask; 22 + int irqs[PHY_MAX_ADDR]; 23 + }; 24 + 25 + #endif /* __LINUX_MDIO_GPIO_H */