diff mbox series

[1/6] usb: chipidea: Add dynamic pinctrl selection

Message ID 1534859756-6955-1-git-send-email-loic.poulain@linaro.org (mailing list archive)
State New, archived
Headers show
Series [1/6] usb: chipidea: Add dynamic pinctrl selection | expand

Commit Message

Loic Poulain Aug. 21, 2018, 1:55 p.m. UTC
Some hardware implementations require to configure pins differently
according to the USB role (host/device), this can be an update of the
pins routing or a simple GPIO value change.

This patch introduces new optional "host" and "device" pinctrls.
If these pinctrls are defined by the device, they are respectively
selected on host/device role start.

If a default pinctrl exist, it is restored on host/device role stop.

Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
---
 drivers/usb/chipidea/core.c  | 19 +++++++++++++++++++
 drivers/usb/chipidea/host.c  |  9 +++++++++
 drivers/usb/chipidea/udc.c   |  9 +++++++++
 include/linux/usb/chipidea.h |  6 ++++++
 4 files changed, 43 insertions(+)

Comments

Andy Shevchenko Aug. 23, 2018, 10:11 a.m. UTC | #1
On Tue, Aug 21, 2018 at 4:57 PM Loic Poulain <loic.poulain@linaro.org> wrote:
>
> Some hardware implementations require to configure pins differently
> according to the USB role (host/device), this can be an update of the
> pins routing or a simple GPIO value change.
>
> This patch introduces new optional "host" and "device" pinctrls.
> If these pinctrls are defined by the device, they are respectively
> selected on host/device role start.
>
> If a default pinctrl exist, it is restored on host/device role stop.

>  #include <linux/extcon.h>
>  #include <linux/phy/phy.h>
>  #include <linux/platform_device.h>
> +#include <linux/pinctrl/consumer.h>

A nit: Even in this context it would be nice to keep *some* order.

>  #include <linux/module.h>
>  #include <linux/idr.h>
>  #include <linux/interrupt.h>

> +               p = pinctrl_lookup_state(platdata->pctl, "default");
> +               p = pinctrl_lookup_state(platdata->pctl, "host");
> +               p = pinctrl_lookup_state(platdata->pctl, "device");

I'm wondering if we have any rules applied to these names.

>  #include <linux/usb/hcd.h>
>  #include <linux/usb/chipidea.h>
>  #include <linux/regulator/consumer.h>
> +#include <linux/pinctrl/consumer.h>

Ditto about ordering.

> +       if (ci->platdata->pins_host)
> +               pinctrl_select_state(ci->platdata->pctl,
> +                                    ci->platdata->pins_host);

Hmm... Do we need to have a condition above?

> +       if (ci->platdata->pins_host && ci->platdata->pins_default)
> +               pinctrl_select_state(ci->platdata->pctl,
> +                                    ci->platdata->pins_default);

Ditto about conditional.

>  #include <linux/usb/gadget.h>
>  #include <linux/usb/otg-fsm.h>
>  #include <linux/usb/chipidea.h>
> +#include <linux/pinctrl/consumer.h>

Ditto about ordering.

> +       if (ci->platdata->pins_device)
> +               pinctrl_select_state(ci->platdata->pctl,
> +                                    ci->platdata->pins_device);


> +       if (ci->platdata->pins_device && ci->platdata->pins_default)
> +               pinctrl_select_state(ci->platdata->pctl,
> +                                    ci->platdata->pins_default);

Ditto about conditional.
Bjorn Andersson Aug. 23, 2018, 2:53 p.m. UTC | #2
On Tue 21 Aug 06:55 PDT 2018, Loic Poulain wrote:

> Some hardware implementations require to configure pins differently
> according to the USB role (host/device), this can be an update of the
> pins routing or a simple GPIO value change.
> 
> This patch introduces new optional "host" and "device" pinctrls.
> If these pinctrls are defined by the device, they are respectively
> selected on host/device role start.
> 
> If a default pinctrl exist, it is restored on host/device role stop.
> 

The implementation looks reasonable, but we're actually just toggling a
gpio using pinctrl states. Do you see any reason not to control this mux
through the gpio api?

Regards,
Bjorn

> Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
> ---
>  drivers/usb/chipidea/core.c  | 19 +++++++++++++++++++
>  drivers/usb/chipidea/host.c  |  9 +++++++++
>  drivers/usb/chipidea/udc.c   |  9 +++++++++
>  include/linux/usb/chipidea.h |  6 ++++++
>  4 files changed, 43 insertions(+)
> 
> diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
> index 85fc6db..03e52fc 100644
> --- a/drivers/usb/chipidea/core.c
> +++ b/drivers/usb/chipidea/core.c
> @@ -46,6 +46,7 @@
>  #include <linux/extcon.h>
>  #include <linux/phy/phy.h>
>  #include <linux/platform_device.h>
> +#include <linux/pinctrl/consumer.h>
>  #include <linux/module.h>
>  #include <linux/idr.h>
>  #include <linux/interrupt.h>
> @@ -723,6 +724,24 @@ static int ci_get_platdata(struct device *dev,
>  		else
>  			cable->connected = false;
>  	}
> +
> +	platdata->pctl = devm_pinctrl_get(dev);
> +	if (!IS_ERR(platdata->pctl)) {
> +		struct pinctrl_state *p;
> +
> +		p = pinctrl_lookup_state(platdata->pctl, "default");
> +		if (!IS_ERR(p))
> +			platdata->pins_default = p;
> +
> +		p = pinctrl_lookup_state(platdata->pctl, "host");
> +		if (!IS_ERR(p))
> +			platdata->pins_host = p;
> +
> +		p = pinctrl_lookup_state(platdata->pctl, "device");
> +		if (!IS_ERR(p))
> +			platdata->pins_device = p;
> +	}
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
> index af45aa32..55dbd49 100644
> --- a/drivers/usb/chipidea/host.c
> +++ b/drivers/usb/chipidea/host.c
> @@ -13,6 +13,7 @@
>  #include <linux/usb/hcd.h>
>  #include <linux/usb/chipidea.h>
>  #include <linux/regulator/consumer.h>
> +#include <linux/pinctrl/consumer.h>
>  
>  #include "../host/ehci.h"
>  
> @@ -150,6 +151,10 @@ static int host_start(struct ci_hdrc *ci)
>  		}
>  	}
>  
> +	if (ci->platdata->pins_host)
> +		pinctrl_select_state(ci->platdata->pctl,
> +				     ci->platdata->pins_host);
> +
>  	ret = usb_add_hcd(hcd, 0, 0);
>  	if (ret) {
>  		goto disable_reg;
> @@ -194,6 +199,10 @@ static void host_stop(struct ci_hdrc *ci)
>  	}
>  	ci->hcd = NULL;
>  	ci->otg.host = NULL;
> +
> +	if (ci->platdata->pins_host && ci->platdata->pins_default)
> +		pinctrl_select_state(ci->platdata->pctl,
> +				     ci->platdata->pins_default);
>  }
>  
>  
> diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
> index 9852ec5..c04384e 100644
> --- a/drivers/usb/chipidea/udc.c
> +++ b/drivers/usb/chipidea/udc.c
> @@ -19,6 +19,7 @@
>  #include <linux/usb/gadget.h>
>  #include <linux/usb/otg-fsm.h>
>  #include <linux/usb/chipidea.h>
> +#include <linux/pinctrl/consumer.h>
>  
>  #include "ci.h"
>  #include "udc.h"
> @@ -1965,6 +1966,10 @@ void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)
>  
>  static int udc_id_switch_for_device(struct ci_hdrc *ci)
>  {
> +	if (ci->platdata->pins_device)
> +		pinctrl_select_state(ci->platdata->pctl,
> +				     ci->platdata->pins_device);
> +
>  	if (ci->is_otg)
>  		/* Clear and enable BSV irq */
>  		hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE,
> @@ -1983,6 +1988,10 @@ static void udc_id_switch_for_host(struct ci_hdrc *ci)
>  		hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS);
>  
>  	ci->vbus_active = 0;
> +
> +	if (ci->platdata->pins_device && ci->platdata->pins_default)
> +		pinctrl_select_state(ci->platdata->pctl,
> +				     ci->platdata->pins_default);
>  }
>  
>  /**
> diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h
> index 07f9936..63758c3 100644
> --- a/include/linux/usb/chipidea.h
> +++ b/include/linux/usb/chipidea.h
> @@ -77,6 +77,12 @@ struct ci_hdrc_platform_data {
>  	struct ci_hdrc_cable		vbus_extcon;
>  	struct ci_hdrc_cable		id_extcon;
>  	u32			phy_clkgate_delay_us;
> +
> +	/* pins */
> +	struct pinctrl *pctl;
> +	struct pinctrl_state *pins_default;
> +	struct pinctrl_state *pins_host;
> +	struct pinctrl_state *pins_device;
>  };
>  
>  /* Default offset of capability registers */
> -- 
> 2.7.4
>
Loic Poulain Aug. 23, 2018, 3:44 p.m. UTC | #3
Hi Bjorn,

On 23 August 2018 at 16:53, Bjorn Andersson <bjorn.andersson@linaro.org> wrote:
> On Tue 21 Aug 06:55 PDT 2018, Loic Poulain wrote:
>
>> Some hardware implementations require to configure pins differently
>> according to the USB role (host/device), this can be an update of the
>> pins routing or a simple GPIO value change.
>>
>> This patch introduces new optional "host" and "device" pinctrls.
>> If these pinctrls are defined by the device, they are respectively
>> selected on host/device role start.
>>
>> If a default pinctrl exist, it is restored on host/device role stop.
>>
>
> The implementation looks reasonable, but we're actually just toggling a
> gpio using pinctrl states. Do you see any reason not to control this mux
> through the gpio api?
>

Actually, two gpios (including hub reset one), but you're right.
Point is that these gpios are very specific to the Dragonboard layout and
not related to USB controller itself (external mux), so I'm not sure it makes
sense to control a 'mux' GPIO from the chipidea driver. That's why I used
pinctrl which is more generic and hides the underlying operations (a simple
GPIO toggling in our case).

But let me know if there is a better way.


Regards,
Loic
Loic Poulain Aug. 24, 2018, 9:40 a.m. UTC | #4
On 23 August 2018 at 12:11, Andy Shevchenko <andy.shevchenko@gmail.com> wrote:
> On Tue, Aug 21, 2018 at 4:57 PM Loic Poulain <loic.poulain@linaro.org> wrote:
>>
>> Some hardware implementations require to configure pins differently
>> according to the USB role (host/device), this can be an update of the
>> pins routing or a simple GPIO value change.
>>
>> This patch introduces new optional "host" and "device" pinctrls.
>> If these pinctrls are defined by the device, they are respectively
>> selected on host/device role start.
>>
>> If a default pinctrl exist, it is restored on host/device role stop.
>
>>  #include <linux/extcon.h>
>>  #include <linux/phy/phy.h>
>>  #include <linux/platform_device.h>
>> +#include <linux/pinctrl/consumer.h>
>
> A nit: Even in this context it would be nice to keep *some* order.
>

Ok.

>>  #include <linux/module.h>
>>  #include <linux/idr.h>
>>  #include <linux/interrupt.h>
>
>> +               p = pinctrl_lookup_state(platdata->pctl, "default");
>> +               p = pinctrl_lookup_state(platdata->pctl, "host");
>> +               p = pinctrl_lookup_state(platdata->pctl, "device");
>
> I'm wondering if we have any rules applied to these names.

I suppose i have document this in the chipidea DT binding doc.

>
>>  #include <linux/usb/hcd.h>
>>  #include <linux/usb/chipidea.h>
>>  #include <linux/regulator/consumer.h>
>> +#include <linux/pinctrl/consumer.h>
>
> Ditto about ordering.
>
>> +       if (ci->platdata->pins_host)
>> +               pinctrl_select_state(ci->platdata->pctl,
>> +                                    ci->platdata->pins_host);
>
> Hmm... Do we need to have a condition above?
>

Yes, since these pinctrls are optional and can be null.

>> +       if (ci->platdata->pins_host && ci->platdata->pins_default)
>> +               pinctrl_select_state(ci->platdata->pctl,
>> +                                    ci->platdata->pins_default);
>
> Ditto about conditional.
>
>>  #include <linux/usb/gadget.h>
>>  #include <linux/usb/otg-fsm.h>
>>  #include <linux/usb/chipidea.h>
>> +#include <linux/pinctrl/consumer.h>
>
> Ditto about ordering.
>
>> +       if (ci->platdata->pins_device)
>> +               pinctrl_select_state(ci->platdata->pctl,
>> +                                    ci->platdata->pins_device);
>
>
>> +       if (ci->platdata->pins_device && ci->platdata->pins_default)
>> +               pinctrl_select_state(ci->platdata->pctl,
>> +                                    ci->platdata->pins_default);
>
> Ditto about conditional.
>
> --
> With Best Regards,
> Andy Shevchenko

Regards,
Loic
diff mbox series

Patch

diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 85fc6db..03e52fc 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -46,6 +46,7 @@ 
 #include <linux/extcon.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/module.h>
 #include <linux/idr.h>
 #include <linux/interrupt.h>
@@ -723,6 +724,24 @@  static int ci_get_platdata(struct device *dev,
 		else
 			cable->connected = false;
 	}
+
+	platdata->pctl = devm_pinctrl_get(dev);
+	if (!IS_ERR(platdata->pctl)) {
+		struct pinctrl_state *p;
+
+		p = pinctrl_lookup_state(platdata->pctl, "default");
+		if (!IS_ERR(p))
+			platdata->pins_default = p;
+
+		p = pinctrl_lookup_state(platdata->pctl, "host");
+		if (!IS_ERR(p))
+			platdata->pins_host = p;
+
+		p = pinctrl_lookup_state(platdata->pctl, "device");
+		if (!IS_ERR(p))
+			platdata->pins_device = p;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
index af45aa32..55dbd49 100644
--- a/drivers/usb/chipidea/host.c
+++ b/drivers/usb/chipidea/host.c
@@ -13,6 +13,7 @@ 
 #include <linux/usb/hcd.h>
 #include <linux/usb/chipidea.h>
 #include <linux/regulator/consumer.h>
+#include <linux/pinctrl/consumer.h>
 
 #include "../host/ehci.h"
 
@@ -150,6 +151,10 @@  static int host_start(struct ci_hdrc *ci)
 		}
 	}
 
+	if (ci->platdata->pins_host)
+		pinctrl_select_state(ci->platdata->pctl,
+				     ci->platdata->pins_host);
+
 	ret = usb_add_hcd(hcd, 0, 0);
 	if (ret) {
 		goto disable_reg;
@@ -194,6 +199,10 @@  static void host_stop(struct ci_hdrc *ci)
 	}
 	ci->hcd = NULL;
 	ci->otg.host = NULL;
+
+	if (ci->platdata->pins_host && ci->platdata->pins_default)
+		pinctrl_select_state(ci->platdata->pctl,
+				     ci->platdata->pins_default);
 }
 
 
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 9852ec5..c04384e 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -19,6 +19,7 @@ 
 #include <linux/usb/gadget.h>
 #include <linux/usb/otg-fsm.h>
 #include <linux/usb/chipidea.h>
+#include <linux/pinctrl/consumer.h>
 
 #include "ci.h"
 #include "udc.h"
@@ -1965,6 +1966,10 @@  void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)
 
 static int udc_id_switch_for_device(struct ci_hdrc *ci)
 {
+	if (ci->platdata->pins_device)
+		pinctrl_select_state(ci->platdata->pctl,
+				     ci->platdata->pins_device);
+
 	if (ci->is_otg)
 		/* Clear and enable BSV irq */
 		hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE,
@@ -1983,6 +1988,10 @@  static void udc_id_switch_for_host(struct ci_hdrc *ci)
 		hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS);
 
 	ci->vbus_active = 0;
+
+	if (ci->platdata->pins_device && ci->platdata->pins_default)
+		pinctrl_select_state(ci->platdata->pctl,
+				     ci->platdata->pins_default);
 }
 
 /**
diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h
index 07f9936..63758c3 100644
--- a/include/linux/usb/chipidea.h
+++ b/include/linux/usb/chipidea.h
@@ -77,6 +77,12 @@  struct ci_hdrc_platform_data {
 	struct ci_hdrc_cable		vbus_extcon;
 	struct ci_hdrc_cable		id_extcon;
 	u32			phy_clkgate_delay_us;
+
+	/* pins */
+	struct pinctrl *pctl;
+	struct pinctrl_state *pins_default;
+	struct pinctrl_state *pins_host;
+	struct pinctrl_state *pins_device;
 };
 
 /* Default offset of capability registers */