diff options
Diffstat (limited to 'drivers/net/phy/mdio-gpio.c')
| -rw-r--r-- | drivers/net/phy/mdio-gpio.c | 236 | 
1 files changed, 103 insertions, 133 deletions
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index f62c7b717bc..5f1a2250018 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -22,30 +22,71 @@  #include <linux/module.h>  #include <linux/slab.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/platform_device.h>  #include <linux/gpio.h>  #include <linux/mdio-gpio.h> -#ifdef CONFIG_OF_GPIO  #include <linux/of_gpio.h>  #include <linux/of_mdio.h> -#include <linux/of_platform.h> -#endif  struct mdio_gpio_info {  	struct mdiobb_ctrl ctrl; -	int mdc, mdio; +	int mdc, mdio, mdo; +	int mdc_active_low, mdio_active_low, mdo_active_low;  }; +static void *mdio_gpio_of_get_data(struct platform_device *pdev) +{ +	struct device_node *np = pdev->dev.of_node; +	struct mdio_gpio_platform_data *pdata; +	enum of_gpio_flags flags; +	int ret; + +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); +	if (!pdata) +		return NULL; + +	ret = of_get_gpio_flags(np, 0, &flags); +	if (ret < 0) +		return NULL; + +	pdata->mdc = ret; +	pdata->mdc_active_low = flags & OF_GPIO_ACTIVE_LOW; + +	ret = of_get_gpio_flags(np, 1, &flags); +	if (ret < 0) +		return NULL; +	pdata->mdio = ret; +	pdata->mdio_active_low = flags & OF_GPIO_ACTIVE_LOW; + +	ret = of_get_gpio_flags(np, 2, &flags); +	if (ret > 0) { +		pdata->mdo = ret; +		pdata->mdo_active_low = flags & OF_GPIO_ACTIVE_LOW; +	} + +	return pdata; +} +  static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)  {  	struct mdio_gpio_info *bitbang =  		container_of(ctrl, struct mdio_gpio_info, ctrl); +	if (bitbang->mdo) { +		/* Separate output pin. Always set its value to high +		 * when changing direction. If direction is input, +		 * assume the pin serves as pull-up. If direction is +		 * output, the default value is high. +		 */ +		gpio_set_value(bitbang->mdo, 1 ^ bitbang->mdo_active_low); +		return; +	} +  	if (dir) -		gpio_direction_output(bitbang->mdio, 1); +		gpio_direction_output(bitbang->mdio, +				      1 ^ bitbang->mdio_active_low);  	else  		gpio_direction_input(bitbang->mdio);  } @@ -55,7 +96,7 @@ static int mdio_get(struct mdiobb_ctrl *ctrl)  	struct mdio_gpio_info *bitbang =  		container_of(ctrl, struct mdio_gpio_info, ctrl); -	return gpio_get_value(bitbang->mdio); +	return gpio_get_value(bitbang->mdio) ^ bitbang->mdio_active_low;  }  static void mdio_set(struct mdiobb_ctrl *ctrl, int what) @@ -63,7 +104,10 @@ static void mdio_set(struct mdiobb_ctrl *ctrl, int what)  	struct mdio_gpio_info *bitbang =  		container_of(ctrl, struct mdio_gpio_info, ctrl); -	gpio_set_value(bitbang->mdio, what); +	if (bitbang->mdo) +		gpio_set_value(bitbang->mdo, what ^ bitbang->mdo_active_low); +	else +		gpio_set_value(bitbang->mdio, what ^ bitbang->mdio_active_low);  }  static void mdc_set(struct mdiobb_ctrl *ctrl, int what) @@ -71,7 +115,7 @@ static void mdc_set(struct mdiobb_ctrl *ctrl, int what)  	struct mdio_gpio_info *bitbang =  		container_of(ctrl, struct mdio_gpio_info, ctrl); -	gpio_set_value(bitbang->mdc, what); +	gpio_set_value(bitbang->mdc, what ^ bitbang->mdc_active_low);  }  static struct mdiobb_ops mdio_gpio_ops = { @@ -82,25 +126,30 @@ static struct mdiobb_ops mdio_gpio_ops = {  	.get_mdio_data = mdio_get,  }; -static struct mii_bus * __devinit mdio_gpio_bus_init(struct device *dev, -					struct mdio_gpio_platform_data *pdata, -					int bus_id) +static struct mii_bus *mdio_gpio_bus_init(struct device *dev, +					  struct mdio_gpio_platform_data *pdata, +					  int bus_id)  {  	struct mii_bus *new_bus;  	struct mdio_gpio_info *bitbang;  	int i; -	bitbang = kzalloc(sizeof(*bitbang), GFP_KERNEL); +	bitbang = devm_kzalloc(dev, sizeof(*bitbang), GFP_KERNEL);  	if (!bitbang)  		goto out;  	bitbang->ctrl.ops = &mdio_gpio_ops; +	bitbang->ctrl.reset = pdata->reset;  	bitbang->mdc = pdata->mdc; +	bitbang->mdc_active_low = pdata->mdc_active_low;  	bitbang->mdio = pdata->mdio; +	bitbang->mdio_active_low = pdata->mdio_active_low; +	bitbang->mdo = pdata->mdo; +	bitbang->mdo_active_low = pdata->mdo_active_low;  	new_bus = alloc_mdio_bitbang(&bitbang->ctrl);  	if (!new_bus) -		goto out_free_bitbang; +		goto out;  	new_bus->name = "GPIO Bitbanged MDIO", @@ -115,13 +164,20 @@ static struct mii_bus * __devinit mdio_gpio_bus_init(struct device *dev,  		if (!new_bus->irq[i])  			new_bus->irq[i] = PHY_POLL; -	snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", bus_id); +	snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id); -	if (gpio_request(bitbang->mdc, "mdc")) +	if (devm_gpio_request(dev, bitbang->mdc, "mdc"))  		goto out_free_bus; -	if (gpio_request(bitbang->mdio, "mdio")) -		goto out_free_mdc; +	if (devm_gpio_request(dev, bitbang->mdio, "mdio")) +		goto out_free_bus; + +	if (bitbang->mdo) { +		if (devm_gpio_request(dev, bitbang->mdo, "mdo")) +			goto out_free_bus; +		gpio_direction_output(bitbang->mdo, 1); +		gpio_direction_input(bitbang->mdio); +	}  	gpio_direction_output(bitbang->mdc, 0); @@ -129,12 +185,8 @@ static struct mii_bus * __devinit mdio_gpio_bus_init(struct device *dev,  	return new_bus; -out_free_mdc: -	gpio_free(bitbang->mdc);  out_free_bus:  	free_mdio_bitbang(new_bus); -out_free_bitbang: -	kfree(bitbang);  out:  	return NULL;  } @@ -142,16 +194,11 @@ out:  static void mdio_gpio_bus_deinit(struct device *dev)  {  	struct mii_bus *bus = dev_get_drvdata(dev); -	struct mdio_gpio_info *bitbang = bus->priv; -	dev_set_drvdata(dev, NULL); -	gpio_free(bitbang->mdio); -	gpio_free(bitbang->mdc);  	free_mdio_bitbang(bus); -	kfree(bitbang);  } -static void __devexit mdio_gpio_bus_destroy(struct device *dev) +static void mdio_gpio_bus_destroy(struct device *dev)  {  	struct mii_bus *bus = dev_get_drvdata(dev); @@ -159,142 +206,65 @@ static void __devexit mdio_gpio_bus_destroy(struct device *dev)  	mdio_gpio_bus_deinit(dev);  } -static int __devinit mdio_gpio_probe(struct platform_device *pdev) +static int mdio_gpio_probe(struct platform_device *pdev)  { -	struct mdio_gpio_platform_data *pdata = pdev->dev.platform_data; +	struct mdio_gpio_platform_data *pdata;  	struct mii_bus *new_bus; -	int ret; +	int ret, bus_id; + +	if (pdev->dev.of_node) { +		pdata = mdio_gpio_of_get_data(pdev); +		bus_id = of_alias_get_id(pdev->dev.of_node, "mdio-gpio"); +		if (bus_id < 0) { +			dev_warn(&pdev->dev, "failed to get alias id\n"); +			bus_id = 0; +		} +	} else { +		pdata = dev_get_platdata(&pdev->dev); +		bus_id = pdev->id; +	}  	if (!pdata)  		return -ENODEV; -	new_bus = mdio_gpio_bus_init(&pdev->dev, pdata, pdev->id); +	new_bus = mdio_gpio_bus_init(&pdev->dev, pdata, bus_id);  	if (!new_bus)  		return -ENODEV; -	ret = mdiobus_register(new_bus); +	if (pdev->dev.of_node) +		ret = of_mdiobus_register(new_bus, pdev->dev.of_node); +	else +		ret = mdiobus_register(new_bus); +  	if (ret)  		mdio_gpio_bus_deinit(&pdev->dev);  	return ret;  } -static int __devexit mdio_gpio_remove(struct platform_device *pdev) +static int mdio_gpio_remove(struct platform_device *pdev)  {  	mdio_gpio_bus_destroy(&pdev->dev);  	return 0;  } -#ifdef CONFIG_OF_GPIO - -static int __devinit mdio_ofgpio_probe(struct platform_device *ofdev, -                                        const struct of_device_id *match) -{ -	struct mdio_gpio_platform_data *pdata; -	struct mii_bus *new_bus; -	int ret; - -	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); -	if (!pdata) -		return -ENOMEM; - -	ret = of_get_gpio(ofdev->dev.of_node, 0); -	if (ret < 0) -		goto out_free; -	pdata->mdc = ret; - -	ret = of_get_gpio(ofdev->dev.of_node, 1); -	if (ret < 0) -		goto out_free; -	pdata->mdio = ret; - -	new_bus = mdio_gpio_bus_init(&ofdev->dev, pdata, pdata->mdc); -	if (!new_bus) -		goto out_free; - -	ret = of_mdiobus_register(new_bus, ofdev->dev.of_node); -	if (ret) -		mdio_gpio_bus_deinit(&ofdev->dev); - -	return ret; - -out_free: -	kfree(pdata); -	return -ENODEV; -} - -static int __devexit mdio_ofgpio_remove(struct platform_device *ofdev) -{ -	mdio_gpio_bus_destroy(&ofdev->dev); -	kfree(ofdev->dev.platform_data); - -	return 0; -} - -static struct of_device_id mdio_ofgpio_match[] = { -	{ -		.compatible = "virtual,mdio-gpio", -	}, -	{}, -}; -MODULE_DEVICE_TABLE(of, mdio_ofgpio_match); - -static struct of_platform_driver mdio_ofgpio_driver = { -	.driver = { -		.name = "mdio-gpio", -		.owner = THIS_MODULE, -		.of_match_table = mdio_ofgpio_match, -	}, -	.probe = mdio_ofgpio_probe, -	.remove = __devexit_p(mdio_ofgpio_remove), +static struct of_device_id mdio_gpio_of_match[] = { +	{ .compatible = "virtual,mdio-gpio", }, +	{ /* sentinel */ }  }; -static inline int __init mdio_ofgpio_init(void) -{ -	return of_register_platform_driver(&mdio_ofgpio_driver); -} - -static inline void __exit mdio_ofgpio_exit(void) -{ -	of_unregister_platform_driver(&mdio_ofgpio_driver); -} -#else -static inline int __init mdio_ofgpio_init(void) { return 0; } -static inline void __exit mdio_ofgpio_exit(void) { } -#endif /* CONFIG_OF_GPIO */ -  static struct platform_driver mdio_gpio_driver = {  	.probe = mdio_gpio_probe, -	.remove = __devexit_p(mdio_gpio_remove), +	.remove = mdio_gpio_remove,  	.driver		= {  		.name	= "mdio-gpio",  		.owner	= THIS_MODULE, +		.of_match_table = mdio_gpio_of_match,  	},  }; -static int __init mdio_gpio_init(void) -{ -	int ret; - -	ret = mdio_ofgpio_init(); -	if (ret) -		return ret; - -	ret = platform_driver_register(&mdio_gpio_driver); -	if (ret) -		mdio_ofgpio_exit(); - -	return ret; -} -module_init(mdio_gpio_init); - -static void __exit mdio_gpio_exit(void) -{ -	platform_driver_unregister(&mdio_gpio_driver); -	mdio_ofgpio_exit(); -} -module_exit(mdio_gpio_exit); +module_platform_driver(mdio_gpio_driver);  MODULE_ALIAS("platform:mdio-gpio");  MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas");  | 
