diff options
Diffstat (limited to 'drivers/usb/renesas_usbhs/mod.c')
| -rw-r--r-- | drivers/usb/renesas_usbhs/mod.c | 121 |
1 files changed, 90 insertions, 31 deletions
diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c index a577f8f4064..6a030b931a3 100644 --- a/drivers/usb/renesas_usbhs/mod.c +++ b/drivers/usb/renesas_usbhs/mod.c @@ -16,8 +16,8 @@ */ #include <linux/interrupt.h> -#include "./common.h" -#include "./mod.h" +#include "common.h" +#include "mod.h" #define usbhs_priv_to_modinfo(priv) (&priv->mod_info) #define usbhs_mod_info_call(priv, func, param...) \ @@ -50,7 +50,9 @@ static int usbhsm_autonomy_irq_vbus(struct usbhs_priv *priv, { struct platform_device *pdev = usbhs_priv_to_pdev(priv); - return usbhsc_drvcllbck_notify_hotplug(pdev); + renesas_usbhs_call_notify_hotplug(pdev); + + return 0; } void usbhs_mod_autonomy_mode(struct usbhs_priv *priv) @@ -58,7 +60,7 @@ 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; + priv->pfunc.get_vbus = usbhsm_autonomy_get_vbus; usbhs_irq_callback_update(priv, NULL); } @@ -93,8 +95,9 @@ struct usbhs_mod *usbhs_mod_get(struct usbhs_priv *priv, int id) return ret; } -int usbhs_mod_is_host(struct usbhs_priv *priv, struct usbhs_mod *mod) +int usbhs_mod_is_host(struct usbhs_priv *priv) { + struct usbhs_mod *mod = usbhs_mod_get_current(priv); struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); if (!mod) @@ -139,13 +142,17 @@ int usbhs_mod_probe(struct usbhs_priv *priv) /* * install host/gadget driver */ - ret = usbhs_mod_gadget_probe(priv); + ret = usbhs_mod_host_probe(priv); if (ret < 0) return ret; + ret = usbhs_mod_gadget_probe(priv); + if (ret < 0) + goto mod_init_host_err; + /* irq settings */ - ret = request_irq(priv->irq, usbhs_interrupt, - IRQF_DISABLED, dev_name(dev), priv); + ret = devm_request_irq(dev, priv->irq, usbhs_interrupt, + priv->irqflags, dev_name(dev), priv); if (ret) { dev_err(dev, "irq request err\n"); goto mod_init_gadget_err; @@ -155,33 +162,21 @@ int usbhs_mod_probe(struct usbhs_priv *priv) mod_init_gadget_err: usbhs_mod_gadget_remove(priv); +mod_init_host_err: + usbhs_mod_host_remove(priv); return ret; } void usbhs_mod_remove(struct usbhs_priv *priv) { + usbhs_mod_host_remove(priv); usbhs_mod_gadget_remove(priv); - free_irq(priv->irq, priv); } /* * status functions */ -int usbhs_status_get_usb_speed(struct usbhs_irq_state *irq_state) -{ - switch (irq_state->dvstctr & RHST) { - case RHST_LOW_SPEED: - return USB_SPEED_LOW; - case RHST_FULL_SPEED: - return USB_SPEED_FULL; - case RHST_HIGH_SPEED: - return USB_SPEED_HIGH; - } - - return USB_SPEED_UNKNOWN; -} - int usbhs_status_get_device_state(struct usbhs_irq_state *irq_state) { int state = irq_state->intsts0 & DVSQ_MASK; @@ -213,15 +208,17 @@ int usbhs_status_get_ctrl_stage(struct usbhs_irq_state *irq_state) return (int)irq_state->intsts0 & CTSQ_MASK; } -static void usbhs_status_get_each_irq(struct usbhs_priv *priv, - struct usbhs_irq_state *state) +static int usbhs_status_get_each_irq(struct usbhs_priv *priv, + struct usbhs_irq_state *state) { struct usbhs_mod *mod = usbhs_mod_get_current(priv); + u16 intenb0, intenb1; state->intsts0 = usbhs_read(priv, INTSTS0); state->intsts1 = usbhs_read(priv, INTSTS1); - state->dvstctr = usbhs_read(priv, DVSTCTR); + intenb0 = usbhs_read(priv, INTENB0); + intenb1 = usbhs_read(priv, INTENB1); /* mask */ if (mod) { @@ -232,6 +229,20 @@ static void usbhs_status_get_each_irq(struct usbhs_priv *priv, state->bempsts &= mod->irq_bempsts; state->brdysts &= mod->irq_brdysts; } + + /* + * Check whether the irq enable registers and the irq status are set + * when IRQF_SHARED is set. + */ + if (priv->irqflags & IRQF_SHARED) { + if (!(intenb0 & state->intsts0) && + !(intenb1 & state->intsts1) && + !(state->bempsts) && + !(state->brdysts)) + return -EIO; + } + + return 0; } /* @@ -244,7 +255,8 @@ static irqreturn_t usbhs_interrupt(int irq, void *data) struct usbhs_priv *priv = data; struct usbhs_irq_state irq_state; - usbhs_status_get_each_irq(priv, &irq_state); + if (usbhs_status_get_each_irq(priv, &irq_state) < 0) + return IRQ_NONE; /* * clear interrupt @@ -260,15 +272,17 @@ static irqreturn_t usbhs_interrupt(int irq, void *data) usbhs_write(priv, INTSTS0, ~irq_state.intsts0 & INTSTS0_MAGIC); usbhs_write(priv, INTSTS1, ~irq_state.intsts1 & INTSTS1_MAGIC); - usbhs_write(priv, BRDYSTS, 0); - usbhs_write(priv, NRDYSTS, 0); - usbhs_write(priv, BEMPSTS, 0); + usbhs_write(priv, BRDYSTS, ~irq_state.brdysts); + usbhs_write(priv, NRDYSTS, ~irq_state.nrdysts); + usbhs_write(priv, BEMPSTS, ~irq_state.bempsts); /* * call irq callback functions * see also * usbhs_irq_setting_update */ + + /* INTSTS0 */ if (irq_state.intsts0 & VBINT) usbhs_mod_info_call(priv, irq_vbus, priv, &irq_state); @@ -284,15 +298,38 @@ static irqreturn_t usbhs_interrupt(int irq, void *data) if (irq_state.intsts0 & BRDY) usbhs_mod_call(priv, irq_ready, priv, &irq_state); + /* INTSTS1 */ + if (irq_state.intsts1 & ATTCH) + usbhs_mod_call(priv, irq_attch, priv, &irq_state); + + if (irq_state.intsts1 & DTCH) + usbhs_mod_call(priv, irq_dtch, priv, &irq_state); + + if (irq_state.intsts1 & SIGN) + usbhs_mod_call(priv, irq_sign, priv, &irq_state); + + if (irq_state.intsts1 & SACK) + usbhs_mod_call(priv, irq_sack, priv, &irq_state); + return IRQ_HANDLED; } void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod) { u16 intenb0 = 0; + u16 intenb1 = 0; struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); + /* + * BEMPENB/BRDYENB are picky. + * below method is required + * + * - clear INTSTS0 + * - update BEMPENB/BRDYENB + * - update INTSTS0 + */ usbhs_write(priv, INTENB0, 0); + usbhs_write(priv, INTENB1, 0); usbhs_write(priv, BEMPENB, 0); usbhs_write(priv, BRDYENB, 0); @@ -310,6 +347,9 @@ void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod) intenb0 |= VBSE; if (mod) { + /* + * INTSTS0 + */ if (mod->irq_ctrl_stage) intenb0 |= CTRE; @@ -322,7 +362,26 @@ void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod) usbhs_write(priv, BRDYENB, mod->irq_brdysts); intenb0 |= BRDYE; } + + /* + * INTSTS1 + */ + if (mod->irq_attch) + intenb1 |= ATTCHE; + + if (mod->irq_dtch) + intenb1 |= DTCHE; + + if (mod->irq_sign) + intenb1 |= SIGNE; + + if (mod->irq_sack) + intenb1 |= SACKE; } - usbhs_write(priv, INTENB0, intenb0); + if (intenb0) + usbhs_write(priv, INTENB0, intenb0); + + if (intenb1) + usbhs_write(priv, INTENB1, intenb1); } |
