diff options
author | Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 2011-04-28 09:41:20 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-04-30 02:24:35 +0200 |
commit | b002ff6e268b6024d6927a1ce330a14ca162b6ab (patch) | |
tree | 83bd5dde6f872396cd42762b59f96cf9c024d30a /drivers/usb/renesas_usbhs/mod.c | |
parent | usb: renesas_usbhs: use delayed_work instead of work_struct (diff) | |
download | linux-b002ff6e268b6024d6927a1ce330a14ca162b6ab.tar.xz linux-b002ff6e268b6024d6927a1ce330a14ca162b6ab.zip |
usb: renesas_usbhs: add autonomy mode
Current renesas_usbhs was designed to save power when USB is not connected.
And it assumed platform uses callback to notify connection/disconnection
by external interrupt.
But some SuperH / platform board doesn't have such feature.
This patch adds autonomy mode which detect USB connection/disconnection
by internal interrupt.
But power will be always ON when autonomy mode is selected.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/renesas_usbhs/mod.c')
-rw-r--r-- | drivers/usb/renesas_usbhs/mod.c | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c index d0f5f67e0749..a577f8f4064c 100644 --- a/drivers/usb/renesas_usbhs/mod.c +++ b/drivers/usb/renesas_usbhs/mod.c @@ -20,6 +20,48 @@ #include "./mod.h" #define usbhs_priv_to_modinfo(priv) (&priv->mod_info) +#define usbhs_mod_info_call(priv, func, param...) \ +({ \ + struct usbhs_mod_info *info; \ + info = usbhs_priv_to_modinfo(priv); \ + !info->func ? 0 : \ + info->func(param); \ +}) + +/* + * autonomy + * + * these functions are used if platform doesn't have external phy. + * -> there is no "notify_hotplug" callback from platform + * -> call "notify_hotplug" by itself + * -> use own interrupt to connect/disconnect + * -> it mean module clock is always ON + * ~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +static int usbhsm_autonomy_get_vbus(struct platform_device *pdev) +{ + struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); + + return VBSTS & usbhs_read(priv, INTSTS0); +} + +static int usbhsm_autonomy_irq_vbus(struct usbhs_priv *priv, + struct usbhs_irq_state *irq_state) +{ + struct platform_device *pdev = usbhs_priv_to_pdev(priv); + + return usbhsc_drvcllbck_notify_hotplug(pdev); +} + +void usbhs_mod_autonomy_mode(struct usbhs_priv *priv) +{ + struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); + + info->irq_vbus = usbhsm_autonomy_irq_vbus; + priv->pfunc->get_vbus = usbhsm_autonomy_get_vbus; + + usbhs_irq_callback_update(priv, NULL); +} /* * host / gadget functions @@ -227,6 +269,9 @@ static irqreturn_t usbhs_interrupt(int irq, void *data) * see also * usbhs_irq_setting_update */ + if (irq_state.intsts0 & VBINT) + usbhs_mod_info_call(priv, irq_vbus, priv, &irq_state); + if (irq_state.intsts0 & DVST) usbhs_mod_call(priv, irq_dev_state, priv, &irq_state); @@ -245,6 +290,7 @@ static irqreturn_t usbhs_interrupt(int irq, void *data) void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod) { u16 intenb0 = 0; + struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); usbhs_write(priv, INTENB0, 0); @@ -260,6 +306,8 @@ void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod) * it don't enable DVSE (intenb0) here * but "mod->irq_dev_state" will be called. */ + if (info->irq_vbus) + intenb0 |= VBSE; if (mod) { if (mod->irq_ctrl_stage) |