From patchwork Fri Oct 31 16:49:34 2008 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paulius Zaleckas X-Patchwork-Id: 6720 X-Patchwork-Delegate: jgarzik@pobox.com Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by ozlabs.org (Postfix) with ESMTP id 0EAF7DDE19 for ; Sat, 1 Nov 2008 03:49:43 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751686AbYJaQtl (ORCPT ); Fri, 31 Oct 2008 12:49:41 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1751689AbYJaQtj (ORCPT ); Fri, 31 Oct 2008 12:49:39 -0400 Received: from 81-7-68-229.static.zebra.lt ([81.7.68.229]:43066 "EHLO teltonika.lt" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751675AbYJaQth (ORCPT ); Fri, 31 Oct 2008 12:49:37 -0400 Received: (qmail 24952 invoked by uid 118); 31 Oct 2008 16:48:10 -0000 Received: from 82.135.208.232 by mailserver (envelope-from , uid 112) with qmail-scanner-1.25st (clamdscan: 0.90.1/8546. spamassassin: 3.1.7-deb. perlscan: 1.25st. Clear:RC:1(82.135.208.232):. Processed in 0.116393 secs); 31 Oct 2008 16:48:10 -0000 Received: from 82-135-208-232.static.zebra.lt (HELO Programuotojas.82-135-208-232.ip.zebra.lt) (paulius.zaleckas@[82.135.208.232]) (envelope-sender ) by teltonika.lt (qmail-ldap-1.03) with SMTP for ; 31 Oct 2008 16:48:10 -0000 From: Paulius Zaleckas Subject: [PATCH 2/2] phylib: make mdio-gpio work without OF To: netdev@vger.kernel.org Cc: linux-arm-kernel@lists.arm.linux.org.uk, linux-embedded@vger.kernel.org, Paulius Zaleckas , Laurent Pinchart , Grant Likely , Mike Frysinger Date: Fri, 31 Oct 2008 18:49:34 +0200 Message-ID: <20081031164934.20490.67539.stgit@Programuotojas.82-135-208-232.ip.zebra.lt> In-Reply-To: <20081031164132.20490.27608.stgit@Programuotojas.82-135-208-232.ip.zebra.lt> References: <20081031164132.20490.27608.stgit@Programuotojas.82-135-208-232.ip.zebra.lt> User-Agent: StGIT/0.14.1 MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org 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 - if NO_IRQ is not defined define it to 0 - 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) Laurent, please test this driver under OF. Signed-off-by: Paulius Zaleckas Cc: Laurent Pinchart Cc: Grant Likely Cc: Mike Frysinger --- drivers/net/phy/Kconfig | 5 + drivers/net/phy/mdio-gpio.c | 188 +++++++++++++++++++++++++++++++++---------- include/linux/mdio-gpio.h | 30 +++++++ 3 files changed, 180 insertions(+), 43 deletions(-) create mode 100644 include/linux/mdio-gpio.h -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 0318077..c4c5a2f 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -86,8 +86,11 @@ config MDIO_BITBANG config MDIO_GPIO tristate "Support for GPIO lib-based bitbanged MDIO buses" - depends on MDIO_BITBANG && OF_GPIO + depends on MDIO_BITBANG && GENERIC_GPIO ---help--- Supports GPIO lib-based MDIO busses. + To compile this driver as a module, choose M here: the module + will be called mdio-gpio. + endif # PHYLIB diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index 2ff9775..a7b94ac 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -1,9 +1,12 @@ /* - * OpenFirmware GPIO based MDIO bitbang driver. + * GPIO based MDIO bitbang driver. + * Supports OpenFirmware. * * Copyright (c) 2008 CSE Semaphore Belgium. * by Laurent Pinchart * + * Copyright (C) 2008, Paulius Zaleckas + * * Based on earlier work by * * Copyright (c) 2003 Intracom S.A. @@ -22,12 +25,23 @@ #include #include #include -#include -#include +#ifdef CONFIG_OF_GPIO +# include +# include +#else +# include +# include +# include +#endif + +#ifndef NO_IRQ +#define NO_IRQ 0 +#endif struct mdio_gpio_info { struct mdiobb_ctrl ctrl; int mdc, mdio; + int irq[PHY_MAX_ADDR]; }; static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) @@ -41,7 +55,7 @@ static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) gpio_direction_input(bitbang->mdio); } -static int mdio_read(struct mdiobb_ctrl *ctrl) +static int mdio_get(struct mdiobb_ctrl *ctrl) { struct mdio_gpio_info *bitbang = container_of(ctrl, struct mdio_gpio_info, ctrl); @@ -49,7 +63,7 @@ static int mdio_read(struct mdiobb_ctrl *ctrl) return gpio_get_value(bitbang->mdio); } -static void mdio(struct mdiobb_ctrl *ctrl, int what) +static void mdio_set(struct mdiobb_ctrl *ctrl, int what) { struct mdio_gpio_info *bitbang = container_of(ctrl, struct mdio_gpio_info, ctrl); @@ -57,7 +71,7 @@ static void mdio(struct mdiobb_ctrl *ctrl, int what) gpio_set_value(bitbang->mdio, what); } -static void mdc(struct mdiobb_ctrl *ctrl, int what) +static void mdc_set(struct mdiobb_ctrl *ctrl, int what) { struct mdio_gpio_info *bitbang = container_of(ctrl, struct mdio_gpio_info, ctrl); @@ -67,12 +81,13 @@ static void mdc(struct mdiobb_ctrl *ctrl, int what) static struct mdiobb_ops mdio_gpio_ops = { .owner = THIS_MODULE, - .set_mdc = mdc, + .set_mdc = mdc_set, .set_mdio_dir = mdio_dir, - .set_mdio_data = mdio, - .get_mdio_data = mdio_read, + .set_mdio_data = mdio_set, + .get_mdio_data = mdio_get, }; +#ifdef CONFIG_OF_GPIO static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus, struct device_node *np) { @@ -87,34 +102,60 @@ static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus, snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc); return 0; } - -static void __devinit add_phy(struct mii_bus *bus, struct device_node *np) +#else +static void __devinit mdio_gpio_bitbang_init(struct mii_bus *bus, + struct mdio_gpio_platform_data *pdata, + int bus_id) { - const u32 *data; - int len, id, irq; + struct mdio_gpio_info *bitbang = bus->priv; + + bitbang->mdc = pdata->mdc; + bitbang->mdio = pdata->mdio; + + snprintf(bus->id, MII_BUS_ID_SIZE, "phy%i", bus_id); +} +#endif - data = of_get_property(np, "reg", &len); - if (!data || len != 4) +static void __devinit add_phy(struct mii_bus *bus, unsigned int phy_addr, + int phy_irq) +{ + if (phy_addr >= PHY_MAX_ADDR) { + dev_err(bus->parent, + "Failed to add phy with invalid address: 0x%x", + phy_addr); return; + } - id = *data; - bus->phy_mask &= ~(1 << id); + bus->phy_mask &= ~(1 << phy_addr); - irq = of_irq_to_resource(np, 0, NULL); - if (irq != NO_IRQ) - bus->irq[id] = irq; + if (phy_irq != NO_IRQ) + bus->irq[phy_addr] = phy_irq; } +#ifdef CONFIG_OF_GPIO static int __devinit mdio_ofgpio_probe(struct of_device *ofdev, const struct of_device_id *match) { struct device_node *np = NULL; + struct device *dev = &ofdev->dev; +#else +static int __devinit mdio_gpio_probe(struct platform_device *pdev) +{ + struct mdio_gpio_platform_data *pdata; + struct device *dev = &pdev->dev; +#endif struct mii_bus *new_bus; struct mdio_gpio_info *bitbang; int ret = -ENOMEM; int i; - bitbang = kzalloc(sizeof(struct mdio_gpio_info), GFP_KERNEL); +#ifndef CONFIG_OF_GPIO + pdata = dev->platform_data; + if (pdata == NULL) + goto out; +#endif + + bitbang = kzalloc(sizeof(*bitbang), GFP_KERNEL); if (!bitbang) goto out; @@ -124,36 +165,66 @@ static int __devinit mdio_ofgpio_probe(struct of_device *ofdev, if (!new_bus) goto out_free_bitbang; - new_bus->name = "GPIO Bitbanged MII", + new_bus->name = "GPIO Bitbanged MDIO", +#ifdef CONFIG_OF_GPIO ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node); if (ret) goto out_free_bus; +#else + mdio_gpio_bitbang_init(new_bus, pdata, pdev->id); +#endif - new_bus->phy_mask = ~0; - new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); - if (!new_bus->irq) + ret = -ENODEV; + + if (gpio_request(bitbang->mdc, "mdc")) goto out_free_bus; + if (gpio_request(bitbang->mdio, "mdio")) + goto out_free_mdc; + + new_bus->phy_mask = ~0; + new_bus->irq = bitbang->irq; + new_bus->parent = dev; + for (i = 0; i < PHY_MAX_ADDR; i++) - new_bus->irq[i] = -1; + new_bus->irq[i] = PHY_POLL; +#ifdef CONFIG_OF_GPIO while ((np = of_get_next_child(ofdev->node, np))) - if (!strcmp(np->type, "ethernet-phy")) - add_phy(new_bus, np); + if (!strcmp(np->type, "ethernet-phy")) { + const u32 *data; + int len; + + data = of_get_property(np, "reg", &len); + if (!data || len != 4) + continue; + + add_phy(new_bus, *data, + of_irq_to_resource(np, 0, NULL)); + } +#else + for (i = 0; i < pdata->nr_phys; i++) + add_phy(new_bus, pdata->phys[i].addr, pdata->phys[i].irq); +#endif - new_bus->parent = &ofdev->dev; - dev_set_drvdata(&ofdev->dev, new_bus); + if (new_bus->phy_mask == ~0) + goto out_free_gpio; + + dev_set_drvdata(dev, new_bus); ret = mdiobus_register(new_bus); if (ret) - goto out_free_irqs; + goto out_free_all; return 0; -out_free_irqs: - dev_set_drvdata(&ofdev->dev, NULL); - kfree(new_bus->irq); +out_free_all: + dev_set_drvdata(dev, NULL); +out_free_gpio: + gpio_free(bitbang->mdio); +out_free_mdc: + gpio_free(bitbang->mdc); out_free_bus: free_mdio_bitbang(new_bus); out_free_bitbang: @@ -162,20 +233,29 @@ out: return ret; } +#ifdef CONFIG_OF_GPIO static int mdio_ofgpio_remove(struct of_device *ofdev) { - struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); + struct device *dev = &ofdev->dev; +#else +static int __devexit mdio_gpio_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; +#endif + struct mii_bus *bus = dev_get_drvdata(dev); struct mdio_gpio_info *bitbang = bus->priv; mdiobus_unregister(bus); - kfree(bus->irq); free_mdio_bitbang(bus); - dev_set_drvdata(&ofdev->dev, NULL); + dev_set_drvdata(dev, NULL); + gpio_free(bitbang->mdc); + gpio_free(bitbang->mdio); kfree(bitbang); return 0; } +#ifdef CONFIG_OF_GPIO static struct of_device_id mdio_ofgpio_match[] = { { .compatible = "virtual,mdio-gpio", @@ -189,16 +269,40 @@ static struct of_platform_driver mdio_ofgpio_driver = { .probe = mdio_ofgpio_probe, .remove = mdio_ofgpio_remove, }; +#else +static struct platform_driver mdio_gpio_driver = { + .probe = mdio_gpio_probe, + .remove = __devexit_p(mdio_gpio_remove), + .driver = { + .name = "mdio-gpio", + .owner = THIS_MODULE, + }, +}; +#endif -static int mdio_ofgpio_init(void) +static int __init mdio_gpio_init(void) { +#ifdef CONFIG_OF_GPIO return of_register_platform_driver(&mdio_ofgpio_driver); +#else + return platform_driver_register(&mdio_gpio_driver); +#endif } +module_init(mdio_gpio_init); -static void mdio_ofgpio_exit(void) +static void __exit mdio_gpio_exit(void) { +#ifdef CONFIG_OF_GPIO of_unregister_platform_driver(&mdio_ofgpio_driver); +#else + platform_driver_unregister(&mdio_gpio_driver); +#endif } - -module_init(mdio_ofgpio_init); -module_exit(mdio_ofgpio_exit); +module_exit(mdio_gpio_exit); + +#ifndef CONFIG_OF_GPIO +MODULE_ALIAS("platform:mdio-gpio"); +#endif +MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Generic driver for MDIO bus emulation using GPIO"); diff --git a/include/linux/mdio-gpio.h b/include/linux/mdio-gpio.h new file mode 100644 index 0000000..5ca24ed --- /dev/null +++ b/include/linux/mdio-gpio.h @@ -0,0 +1,30 @@ +/* + * MDIO-GPIO bus platform data structures + * + * Copyright (C) 2008, Paulius Zaleckas + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef __LINUX_MDIO_GPIO_H +#define __LINUX_MDIO_GPIO_H + +struct mdio_gpio_phy { + /* PHY address on MDIO bus */ + unsigned int addr; + /* preconfigured irq connected to PHY or -1 if no irq */ + int irq; +}; + +struct mdio_gpio_platform_data { + /* GPIO numbers for bus pins */ + unsigned int mdc; + unsigned int mdio; + + unsigned int nr_phys; + struct mdio_gpio_phy *phys; +}; + +#endif /* __LINUX_MDIO_GPIO_H */