diff options
Diffstat (limited to 'drivers/net/phy/mdio-gpio.c')
| -rw-r--r-- | drivers/net/phy/mdio-gpio.c | 73 | 
1 files changed, 51 insertions, 22 deletions
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index 8004acbef2c..5f1a2250018 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -22,7 +22,6 @@  #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> @@ -33,29 +32,39 @@  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(np, 0); +	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(np, 1); +	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;  } @@ -65,8 +74,19 @@ 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);  } @@ -76,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) @@ -84,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) @@ -92,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 = { @@ -111,18 +134,22 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev,  	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", @@ -139,11 +166,18 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev,  	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 (devm_gpio_request(dev, bitbang->mdio, "mdio"))  		goto out_free_bus; -	if (gpio_request(bitbang->mdio, "mdio")) -		goto out_free_mdc; +	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); @@ -151,12 +185,8 @@ static struct mii_bus *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;  } @@ -164,13 +194,8 @@ 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 mdio_gpio_bus_destroy(struct device *dev) @@ -190,6 +215,10 @@ static int mdio_gpio_probe(struct platform_device *pdev)  	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;  | 
