diff options
Diffstat (limited to 'drivers/usb/phy/phy-generic.c')
| -rw-r--r-- | drivers/usb/phy/phy-generic.c | 108 | 
1 files changed, 59 insertions, 49 deletions
diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index efe59f3f7fd..fce3a9e9bb5 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -35,6 +35,9 @@  #include <linux/clk.h>  #include <linux/regulator/consumer.h>  #include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/gpio.h> +#include <linux/delay.h>  #include "phy-generic.h" @@ -64,6 +67,23 @@ static int nop_set_suspend(struct usb_phy *x, int suspend)  	return 0;  } +static void nop_reset_set(struct usb_phy_gen_xceiv *nop, int asserted) +{ +	int value; + +	if (!gpio_is_valid(nop->gpio_reset)) +		return; + +	value = asserted; +	if (nop->reset_active_low) +		value = !value; + +	gpio_set_value_cansleep(nop->gpio_reset, value); + +	if (!asserted) +		usleep_range(10000, 20000); +} +  int usb_gen_phy_init(struct usb_phy *phy)  {  	struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); @@ -74,13 +94,10 @@ int usb_gen_phy_init(struct usb_phy *phy)  	}  	if (!IS_ERR(nop->clk)) -		clk_enable(nop->clk); +		clk_prepare_enable(nop->clk); -	if (!IS_ERR(nop->reset)) { -		/* De-assert RESET */ -		if (regulator_enable(nop->reset)) -			dev_err(phy->dev, "Failed to de-assert reset\n"); -	} +	/* De-assert RESET */ +	nop_reset_set(nop, 0);  	return 0;  } @@ -90,14 +107,11 @@ void usb_gen_phy_shutdown(struct usb_phy *phy)  {  	struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); -	if (!IS_ERR(nop->reset)) { -		/* Assert RESET */ -		if (regulator_disable(nop->reset)) -			dev_err(phy->dev, "Failed to assert reset\n"); -	} +	/* Assert RESET */ +	nop_reset_set(nop, 1);  	if (!IS_ERR(nop->clk)) -		clk_disable(nop->clk); +		clk_disable_unprepare(nop->clk);  	if (!IS_ERR(nop->vcc)) {  		if (regulator_disable(nop->vcc)) @@ -136,8 +150,7 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)  }  int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, -		enum usb_phy_type type, u32 clk_rate, bool needs_vcc, -		bool needs_reset) +		enum usb_phy_type type, u32 clk_rate, bool needs_vcc)  {  	int err; @@ -160,14 +173,6 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,  		}  	} -	if (!IS_ERR(nop->clk)) { -		err = clk_prepare(nop->clk); -		if (err) { -			dev_err(dev, "Error preparing clock\n"); -			return err; -		} -	} -  	nop->vcc = devm_regulator_get(dev, "vcc");  	if (IS_ERR(nop->vcc)) {  		dev_dbg(dev, "Error getting vcc regulator: %ld\n", @@ -176,12 +181,22 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,  			return -EPROBE_DEFER;  	} -	nop->reset = devm_regulator_get(dev, "reset"); -	if (IS_ERR(nop->reset)) { -		dev_dbg(dev, "Error getting reset regulator: %ld\n", -					PTR_ERR(nop->reset)); -		if (needs_reset) -			return -EPROBE_DEFER; +	if (gpio_is_valid(nop->gpio_reset)) { +		unsigned long gpio_flags; + +		/* Assert RESET */ +		if (nop->reset_active_low) +			gpio_flags = GPIOF_OUT_INIT_LOW; +		else +			gpio_flags = GPIOF_OUT_INIT_HIGH; + +		err = devm_gpio_request_one(dev, nop->gpio_reset, +						gpio_flags, dev_name(dev)); +		if (err) { +			dev_err(dev, "Error requesting RESET GPIO %d\n", +					nop->gpio_reset); +			return err; +		}  	}  	nop->dev		= dev; @@ -200,13 +215,6 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,  }  EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy); -void usb_phy_gen_cleanup_phy(struct usb_phy_gen_xceiv *nop) -{ -	if (!IS_ERR(nop->clk)) -		clk_unprepare(nop->clk); -} -EXPORT_SYMBOL_GPL(usb_phy_gen_cleanup_phy); -  static int usb_phy_gen_xceiv_probe(struct platform_device *pdev)  {  	struct device *dev = &pdev->dev; @@ -217,31 +225,36 @@ static int usb_phy_gen_xceiv_probe(struct platform_device *pdev)  	int err;  	u32 clk_rate = 0;  	bool needs_vcc = false; -	bool needs_reset = false; + +	nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL); +	if (!nop) +		return -ENOMEM; + +	nop->reset_active_low = true;	/* default behaviour */  	if (dev->of_node) {  		struct device_node *node = dev->of_node; +		enum of_gpio_flags flags;  		if (of_property_read_u32(node, "clock-frequency", &clk_rate))  			clk_rate = 0;  		needs_vcc = of_property_read_bool(node, "vcc-supply"); -		needs_reset = of_property_read_bool(node, "reset-supply"); +		nop->gpio_reset = of_get_named_gpio_flags(node, "reset-gpios", +								0, &flags); +		if (nop->gpio_reset == -EPROBE_DEFER) +			return -EPROBE_DEFER; + +		nop->reset_active_low = flags & OF_GPIO_ACTIVE_LOW;  	} else if (pdata) {  		type = pdata->type;  		clk_rate = pdata->clk_rate;  		needs_vcc = pdata->needs_vcc; -		needs_reset = pdata->needs_reset; +		nop->gpio_reset = pdata->gpio_reset;  	} -	nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL); -	if (!nop) -		return -ENOMEM; - - -	err = usb_phy_gen_create_phy(dev, nop, type, clk_rate, needs_vcc, -			needs_reset); +	err = usb_phy_gen_create_phy(dev, nop, type, clk_rate, needs_vcc);  	if (err)  		return err; @@ -252,15 +265,13 @@ static int usb_phy_gen_xceiv_probe(struct platform_device *pdev)  	if (err) {  		dev_err(&pdev->dev, "can't register transceiver, err: %d\n",  			err); -		goto err_add; +		return err;  	}  	platform_set_drvdata(pdev, nop);  	return 0; -err_add: -	usb_phy_gen_cleanup_phy(nop);  	return err;  } @@ -268,7 +279,6 @@ static int usb_phy_gen_xceiv_remove(struct platform_device *pdev)  {  	struct usb_phy_gen_xceiv *nop = platform_get_drvdata(pdev); -	usb_phy_gen_cleanup_phy(nop);  	usb_remove_phy(&nop->phy);  	return 0;  | 
