[PATCH v12 10/13] usb: chipidea: add wait vbus lower than OTGSC_BSV before role starts

Marc Kleine-Budde
2013-07-11T07:24:56Z

On 07/11/2013 08:27 AM, Peter Chen wrote:
> When the gadget role starts, we need to make sure the vbus is lower
> than OTGSC_BSV, or there will be an vbus interrupt since we use
> B_SESSION_VALID as vbus interrupt to indicate connect and disconnect.
> When the host role starts, it may not be useful to wait vbus to lower
> than OTGSC_BSV, but it can indicate some hardware problems like the
> vbus is still higher than OTGSC_BSV after we disconnect to host some
> time later (500 jiffies currently), which is obvious not correct.

Jiffies ist not constant. I think you have to specify the timeout in
fractions of HZ. The system ticks with HZ jiffies per second. So a
timeout of 500ms is "HZ / 2".

Marc

>
> Signed-off-by: Peter Chen <peter.chen@freescale.com>
> ---
> drivers/usb/chipidea/ci.h | 3 +++
> drivers/usb/chipidea/core.c | 32 ++++++++++++++++++++++++++++++++
> drivers/usb/chipidea/otg.c | 4 ++++
> 3 files changed, 39 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
> index 3160363..df27696 100644
> --- a/drivers/usb/chipidea/ci.h
> +++ b/drivers/usb/chipidea/ci.h
> @@ -308,4 +308,7 @@ int hw_port_test_set(struct ci_hdrc *ci, u8 mode);
>
> u8 hw_port_test_get(struct ci_hdrc *ci);
>
> +int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask,
> + u32 value, unsigned long timeout);
> +
> #endif /* __DRIVERS_USB_CHIPIDEA_CI_H */
> diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
> index 7a07300..1c39541 100644
> --- a/drivers/usb/chipidea/core.c
> +++ b/drivers/usb/chipidea/core.c
> @@ -295,6 +295,38 @@ int hw_device_reset(struct ci_hdrc *ci, u32 mode)
> return 0;
> }
>
> +/**
> + * hw_wait_reg: wait the register value
> + *
> + * Sometimes, it needs to wait register value before going on.
> + * Eg, when switch to device mode, the vbus value should be lower
> + * than OTGSC_BSV before connects to host.
> + *
> + * @ci: the controller
> + * @reg: register index
> + * @mask: mast bit
> + * @value: the bit value to wait
> + * @timeout: timeout to indicate an error
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Better: timeout in jiffies

> + *
> + * This function returns an error code if timeout
> + */
> +int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask,
> + u32 value, unsigned long timeout)
> +{
> + unsigned long elapse = jiffies + timeout;
> +
> + while (hw_read(ci, reg, mask) != value) {
> + if (time_after(jiffies, elapse)) {
> + dev_err(ci->dev, "timeout waiting for %08x in %d\n",
> + mask, reg);
> + return -ETIMEDOUT;
> + }
> + msleep(20);
> + }
> +
> + return 0;
> +}
> +
> static irqreturn_t ci_irq(int irq, void *data)
> {
> struct ci_hdrc *ci = data;
> diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c
> index c74194d..8aa0241 100644
> --- a/drivers/usb/chipidea/otg.c
> +++ b/drivers/usb/chipidea/otg.c
> @@ -67,6 +67,7 @@ void ci_handle_vbus_change(struct ci_hdrc *ci)
> usb_gadget_vbus_disconnect(&ci->gadget);
> }
>
> +#define CI_VBUS_STABLE_TIMEOUT 500
> static void ci_handle_id_switch(struct ci_hdrc *ci)
> {
> enum ci_role role = ci_otg_role(ci);
> @@ -76,6 +77,9 @@ static void ci_handle_id_switch(struct ci_hdrc *ci)
> ci_role(ci)->name, ci->roles[role]->name);
>
> ci_role_stop(ci);
> + /* wait vbus lower than OTGSC_BSV */
> + hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0,
> + CI_VBUS_STABLE_TIMEOUT);
> ci_role_start(ci, role);
> }
> }
>

--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 259 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130711/cb139f86/attachment.sig>