From fe83f501d12d0b201cc0d2006e0db08300b99ff8 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Tue, 5 May 2020 17:11:53 +0100 Subject: usb: chipidea: Add delay time for pinctrl switch over On some hardware when we switch from one pin state to another it is desirable to have a delay time to allow for peripheral chips to take action based on the pin-state we have set. This patch adds support for a delay time to be specified when doing that switch. The switch and delay is a pattern then that is functionally decomposed into ci_platform_set_pin_state(). If no delay time is specified the pin-switch happens as before with zero delay. If a delay time is specified the pin-state is applied and then the specified delay delay is applied. Cc: Loic Poulain Cc: Peter Chen Signed-off-by: Bryan O'Donoghue --- drivers/usb/chipidea/ci.h | 3 +++ drivers/usb/chipidea/core.c | 19 +++++++++++++++++++ drivers/usb/chipidea/host.c | 7 +++---- drivers/usb/chipidea/udc.c | 6 ++---- 4 files changed, 27 insertions(+), 8 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index a4a3be049910..d34096dbfbca 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -467,4 +467,7 @@ void ci_platform_configure(struct ci_hdrc *ci); void dbg_create_files(struct ci_hdrc *ci); void dbg_remove_files(struct ci_hdrc *ci); + +void ci_platform_set_pin_state(struct ci_hdrc *ci, struct pinctrl_state *pins); + #endif /* __DRIVERS_USB_CHIPIDEA_CI_H */ diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 6330fa911792..d21e937954d1 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -185,6 +185,22 @@ u8 hw_port_test_get(struct ci_hdrc *ci) return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> __ffs(PORTSC_PTC); } +/** + * ci_platform_set_pin_state: set target pinctrl state with optional delay + * + * @ci: the controller + * @pins: the target pin-state + * + * This function returns nothing + */ +void ci_platform_set_pin_state(struct ci_hdrc *ci, struct pinctrl_state *pins) +{ + pinctrl_select_state(ci->platdata->pctl, pins); + if (ci->platdata->pin_switch_delay_us) + usleep_range(ci->platdata->pin_switch_delay_us, + ci->platdata->pin_switch_delay_us + 50); +} + static void hw_wait_phy_stable(void) { /* @@ -809,6 +825,9 @@ static int ci_get_platdata(struct device *dev, if (!platdata->enter_lpm) platdata->enter_lpm = ci_hdrc_enter_lpm_common; + of_property_read_u32(dev->of_node, "pin-switch-delay-us", + &platdata->pin_switch_delay_us); + return 0; } diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index bc3634a54c6b..d44eb544b1a5 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -170,8 +170,7 @@ static int host_start(struct ci_hdrc *ci) } if (ci->platdata->pins_host) - pinctrl_select_state(ci->platdata->pctl, - ci->platdata->pins_host); + ci_platform_set_pin_state(ci, ci->platdata->pins_host); ci->hcd = hcd; @@ -225,8 +224,8 @@ static void host_stop(struct ci_hdrc *ci) ci->otg.host = NULL; if (ci->platdata->pins_host && ci->platdata->pins_default) - pinctrl_select_state(ci->platdata->pctl, - ci->platdata->pins_default); + ci_platform_set_pin_state(ci, ci->platdata->pins_default); + } diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 8c3e3a635ac2..8e47626621de 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -2154,8 +2154,7 @@ 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); + ci_platform_set_pin_state(ci, ci->platdata->pins_device); if (ci->is_otg) /* Clear and enable BSV irq */ @@ -2177,8 +2176,7 @@ static void udc_id_switch_for_host(struct ci_hdrc *ci) ci->vbus_active = 0; if (ci->platdata->pins_device && ci->platdata->pins_default) - pinctrl_select_state(ci->platdata->pctl, - ci->platdata->pins_default); + ci_platform_set_pin_state(ci, ci->platdata->pins_default); } /** -- cgit v1.2.3