phy_sun4i_usb: set_mode: Allow using set_mode to force end the current session
Subsystems (4)
PATCH v3 1/3 phy_sun4i_usb: set_mode: Allow using set_mode to force end the current session
The sunxi musb has a bug where sometimes it will generate a babble error on device disconnect instead of a disconnect irq. When this happens the musb-controller switches from host mode to device mode (it clears MUSB_DEVCTL_SESSION and sets MUSB_DEVCTL_BDEVICE) and gets stuck in this state.
Clearing this requires reporting Vbus low for 200 or more ms, but on some devices Vbus is simply always high (host-only mode, no Vbus control).
This commit modifies sun4i_usb_phy_set_mode so that it will force end the current session when called with the current mode, before this commit calling set_mode with the current mode was a nop since id_det would stay the same resulting in the detect_work not doing anything.
This allows the sunxi-musb glue to use sun4i_usb_phy_set_mode to force end the current session without changing the mode, to fixup the stuck state after a babble error.
---
Changes in v2:
-New patch in v2 of this series replacing the
"phy-sun4i-usb: Add sun4i_usb_phy_force_session_end() function" from v1
Changes in v3:
-Fix dev_info so that it prints the new-mode instead of the old one
--- drivers/phy/phy-sun4i-usb.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
drivers/phy/phy-sun4i-usb.c +10 -4
@@ -437,25 +437,31 @@ static int sun4i_usb_phy_set_mode(struct phy *_phy, enum phy_mode mode) {struct sun4i_usb_phy *phy =phy_get_drvdata (_phy);struct sun4i_usb_phy_data *data =to_sun4i_usb_phy_data (phy); +int new_mode;if (phy->index !=0 )return -EINVAL ;switch (mode) {case PHY_MODE_USB_HOST : - data->dr_mode =USB_DR_MODE_HOST ; + new_mode =USB_DR_MODE_HOST ;break ;case PHY_MODE_USB_DEVICE : - data->dr_mode =USB_DR_MODE_PERIPHERAL ; + new_mode =USB_DR_MODE_PERIPHERAL ;break ;case PHY_MODE_USB_OTG : - data->dr_mode =USB_DR_MODE_OTG ; + new_mode =USB_DR_MODE_OTG ;break ;default :return -EINVAL ; } -dev_info (&_phy->dev,"Changing dr_mode to %d\n" , (int )data->dr_mode); +if (new_mode != data->dr_mode) { +dev_info (&_phy->dev,"Changing dr_mode to %d\n" , new_mode); + data->dr_mode = new_mode; + } + + data->id_det =-1 ;/* Force reprocessing of id */ data->force_session_end = true;queue_delayed_work (system_wq, &data->detect,0 );
Signature · 1 line
2.9.3
PATCH v3 2/3 musb: sunxi: Remove custom babble handling
The musb core already handles babble interrupts, so the sunxi glue having its own custom handling is redundant.
---
Changes in v2:
-This is a new patch in v2 of this patch series
Changes in v3:
-Improve commit msg
--- drivers/usb/musb/sunxi.c | 10 ---------- 1 file changed, 10 deletions(-)
drivers/usb/musb/sunxi.c +0 -10
@@ -186,16 +186,6 @@ static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci)if (musb->int_usb)writeb (musb->int_usb, musb->mregs +SUNXI_MUSB_INTRUSB ); -/* -* sunxi musb often signals babble on low / full speed device -* disconnect, without ever raising MUSB_INTR_DISCONNECT, since -* normally babble never happens treat it as disconnect. -*/ -if ((musb->int_usb &MUSB_INTR_BABBLE ) &&is_host_active (musb)) { - musb->int_usb &= ~MUSB_INTR_BABBLE ; - musb->int_usb |=MUSB_INTR_DISCONNECT ; - } -if ((musb->int_usb &MUSB_INTR_RESET ) && !is_host_active (musb)) {/* ep0 FADDR must be 0 when (re)entering peripheral mode */ musb_ep_select (musb->mregs,0 );
Signature · 1 line
2.9.3
PATCH v3 2/3 musb: sunxi: Remove custom babble handling
Quoted 4 lines · Hans de Goede
The musb core already handles babble interrupts, so the sunxi glue having its own custom handling is redundant.
Signed-off-by Hans de Goede <[email protected]>
Applied. Thanks.
-Bin.
Quoted 33 lines
---
Changes in v2:
-This is a new patch in v2 of this patch series
Changes in v3:(quoted diff) +0
-2-Improve commit msg --- drivers/usb/musb/sunxi.c | 10 ---------- 1 file changed, 10 deletions(-)drivers/usb/musb/sunxi.c +0
-10@@ -186,16 +186,6 @@ static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci)if (musb->int_usb)writeb (musb->int_usb, musb->mregs +SUNXI_MUSB_INTRUSB ); -/* -* sunxi musb often signals babble on low / full speed device -* disconnect, without ever raising MUSB_INTR_DISCONNECT, since -* normally babble never happens treat it as disconnect. -*/ -if ((musb->int_usb &MUSB_INTR_BABBLE ) &&is_host_active (musb)) { - musb->int_usb &= ~MUSB_INTR_BABBLE ; - musb->int_usb |=MUSB_INTR_DISCONNECT ; - } -if ((musb->int_usb &MUSB_INTR_RESET ) && !is_host_active (musb)) {/* ep0 FADDR must be 0 when (re)entering peripheral mode */ musb_ep_select (musb->mregs,0 );Signature · 1 line
2.9.3
PATCH v3 3/3 musb: sunxi: Force session end on babble errors in host-mode
In reply to Hans de GoedeThe sunxi musb has a bug where sometimes it will generate a babble error on device disconnect instead of a disconnect irq. When this happens the musb-controller switches from host mode to device mode (it clears MUSB_DEVCTL_SESSION and sets MUSB_DEVCTL_BDEVICE) and gets stuck in this state.
Clearing this requires reporting Vbus low for 200 or more ms, but on some devices Vbus is simply always high (host-only mode, no Vbus control).
This commit adds a sunxi_musb_recover() callback which makes sunxi_musb_work call phy_set_mode with the current mode, which will force end the current session.
This fixes the musb controller getting stuck in this state on systems without Vbus control; and also fixes the need to unplug the usb-b -> usb-a cable to get out of this state on systems with Vbus control.
---
Changes in v2:
-Use musb_platform_recover callback instead of using DYI code in the
interrupt handler
-Call phy_set_mode with the current mode instead of adding a new custom
sunxi phy callback
--- drivers/usb/musb/sunxi.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
drivers/usb/musb/sunxi.c +15 -0
@@ -380,6 +380,20 @@ static int sunxi_musb_set_mode(struct musb *musb, u8 mode)return 0 ; } +static int sunxi_musb_recover (struct musb *musb) +{ +struct sunxi_glue *glue =dev_get_drvdata (musb->controller->parent); + +/* +* Schedule a phy_set_mode with the current glue->phy_mode value, +* this will force end the current session. +*/ +set_bit (SUNXI_MUSB_FL_PHY_MODE_PEND , &glue->flags); +schedule_work (&glue->work); + +return 0 ; +} +/* * sunxi musb register layout * 0x00 - 0x17 fifo regs, 1 long per fifo
@@ -608,6 +622,7 @@ static const struct musb_platform_ops sunxi_musb_ops = { .dma_init = sunxi_musb_dma_controller_create, .dma_exit = sunxi_musb_dma_controller_destroy, .set_mode = sunxi_musb_set_mode, + .recover = sunxi_musb_recover, .set_vbus = sunxi_musb_set_vbus, .pre_root_reset_end = sunxi_musb_pre_root_reset_end, .post_root_reset_end = sunxi_musb_post_root_reset_end,
Signature · 1 line
2.9.3
PATCH v3 3/3 musb: sunxi: Force session end on babble errors in host-mode
Quoted 14 lines · Hans de Goede
The sunxi musb has a bug where sometimes it will generate a babble error on device disconnect instead of a disconnect irq. When this happens the musb-controller switches from host mode to device mode (it clears
MUSB_DEVCTL_SESSIONand setsMUSB_DEVCTL_BDEVICE) and gets stuck in this state.Clearing this requires reporting Vbus low for 200 or more ms, but on some devices Vbus is simply always high (host-only mode, no Vbus control).
This commit adds a
sunxi_musb_recover()callback which makessunxi_musb_workcallphy_set_modewith the current mode, which will force end the current session.
Quoted 5 lines
This fixes the musb controller getting stuck in this state on systems without Vbus control; and also fixes the need to unplug the usb-b -> usb-a cable to get out of this state on systems with Vbus control.
Signed-off-by Hans de Goede <[email protected]>
Applied. Thanks.
-Bin.
Quoted 46 lines
---
Changes in v2:(quoted diff) +0
-3-Use musb_platform_recover callback instead of using DYI code in the interrupt handler -Call phy_set_mode with the current mode instead of adding a new custom sunxi phy callback --- drivers/usb/musb/sunxi.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)drivers/usb/musb/sunxi.c +15
-0@@ -380,6 +380,20 @@ static int sunxi_musb_set_mode(struct musb *musb, u8 mode)return 0 ; } +static int sunxi_musb_recover (struct musb *musb) +{ +struct sunxi_glue *glue =dev_get_drvdata (musb->controller->parent); + +/* +* Schedule a phy_set_mode with the current glue->phy_mode value, +* this will force end the current session. +*/ +set_bit (SUNXI_MUSB_FL_PHY_MODE_PEND , &glue->flags); +schedule_work (&glue->work); + +return 0 ; +} +/* * sunxi musb register layout * 0x00 - 0x17 fifo regs, 1 long per fifo @@ -608,6 +622,7 @@ static const struct musb_platform_ops sunxi_musb_ops = { .dma_init = sunxi_musb_dma_controller_create, .dma_exit = sunxi_musb_dma_controller_destroy, .set_mode = sunxi_musb_set_mode, + .recover = sunxi_musb_recover, .set_vbus = sunxi_musb_set_vbus, .pre_root_reset_end = sunxi_musb_pre_root_reset_end, .post_root_reset_end = sunxi_musb_post_root_reset_end,Signature · 1 line
2.9.3
Kishon Vijay Abraham I
AppliedPATCH v3 1/3 phy_sun4i_usb: set_mode: Allow using set_mode to force end the current session
In reply to Hans de GoedeQuoted 15 lines · Hans de Goede
The sunxi musb has a bug where sometimes it will generate a babble error on device disconnect instead of a disconnect irq. When this happens the musb-controller switches from host mode to device mode (it clears
MUSB_DEVCTL_SESSIONand setsMUSB_DEVCTL_BDEVICE) and gets stuck in this state.Clearing this requires reporting Vbus low for 200 or more ms, but on some devices Vbus is simply always high (host-only mode, no Vbus control).
This commit modifies
sun4i_usb_phy_set_modeso that it will force end the current session when called with the current mode, before this commit callingset_modewith the current mode was a nop sinceid_detwould stay the same resulting in thedetect_worknot doing anything.
Quoted 5 lines
This allows the sunxi-musb glue to use
sun4i_usb_phy_set_modeto force end the current session without changing the mode, to fixup the stuck state after a babble error.Signed-off-by Hans de Goede <[email protected]>
merged, thanks.
-Kishon
Quoted 52 lines
---
Changes in v2:
-New patch in v2 of this series replacing the
"phy-sun4i-usb: Addsun4i_usb_phy_force_session_end()function" from v1
Changes in v3:(quoted diff) +0
-2-Fix dev_info so that it prints the new-mode instead of the old one --- drivers/phy/phy-sun4i-usb.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)drivers/phy/phy-sun4i-usb.c +10
-4@@ -437,25 +437,31 @@ static int sun4i_usb_phy_set_mode(struct phy *_phy, enum phy_mode mode) {struct sun4i_usb_phy *phy =phy_get_drvdata (_phy);struct sun4i_usb_phy_data *data =to_sun4i_usb_phy_data (phy); +int new_mode;if (phy->index !=0 )return -EINVAL ;switch (mode) {case PHY_MODE_USB_HOST : - data->dr_mode =USB_DR_MODE_HOST ; + new_mode =USB_DR_MODE_HOST ;break ;case PHY_MODE_USB_DEVICE : - data->dr_mode =USB_DR_MODE_PERIPHERAL ; + new_mode =USB_DR_MODE_PERIPHERAL ;break ;case PHY_MODE_USB_OTG : - data->dr_mode =USB_DR_MODE_OTG ; + new_mode =USB_DR_MODE_OTG ;break ;default :return -EINVAL ; } -dev_info (&_phy->dev,"Changing dr_mode to %d\n" , (int )data->dr_mode); +if (new_mode != data->dr_mode) { +dev_info (&_phy->dev,"Changing dr_mode to %d\n" , new_mode); + data->dr_mode = new_mode; + } + + data->id_det =-1 ;/* Force reprocessing of id */ data->force_session_end = true;queue_delayed_work (system_wq, &data->detect,0 );