summaryrefslogtreecommitdiff
path: root/drivers/usb/mtu3/mtu3_dr.c
diff options
context:
space:
mode:
authorChunfeng Yun <chunfeng.yun@mediatek.com>2017-10-13 17:10:42 +0800
committerFelipe Balbi <felipe.balbi@linux.intel.com>2017-10-19 10:38:11 +0300
commitc776f2c3e81308977e95a228b0665e3d5c63dff3 (patch)
tree2e0daefc114ea8a8e6ab388b72264749d4157d81 /drivers/usb/mtu3/mtu3_dr.c
parent1a46dfea0841d5ebc08fafe7b3f60d33581f8e27 (diff)
usb: mtu3: use FORCE/RG_IDDIG to implement manual DRD switch
In order to keep manual DRD switch independent on IDDIG interrupt, make use of FORCE/RG_IDDIG instead of IDDIG EINT interrupt to implement manual DRD switch function. Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Diffstat (limited to 'drivers/usb/mtu3/mtu3_dr.c')
-rw-r--r--drivers/usb/mtu3/mtu3_dr.c61
1 files changed, 45 insertions, 16 deletions
diff --git a/drivers/usb/mtu3/mtu3_dr.c b/drivers/usb/mtu3/mtu3_dr.c
index 560256115b23..ec442cd5a1ad 100644
--- a/drivers/usb/mtu3/mtu3_dr.c
+++ b/drivers/usb/mtu3/mtu3_dr.c
@@ -261,21 +261,22 @@ static void extcon_register_dwork(struct work_struct *work)
* depending on user input.
* This is useful in special cases, such as uses TYPE-A receptacle but also
* wants to support dual-role mode.
- * It generates cable state changes by pulling up/down IDPIN and
- * notifies driver to switch mode by "extcon-usb-gpio".
- * NOTE: when use MICRO receptacle, should not enable this interface.
*/
static void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host)
{
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
- if (to_host)
- pinctrl_select_state(otg_sx->id_pinctrl, otg_sx->id_ground);
- else
- pinctrl_select_state(otg_sx->id_pinctrl, otg_sx->id_float);
+ if (to_host) {
+ ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
+ ssusb_set_mailbox(otg_sx, MTU3_VBUS_OFF);
+ ssusb_set_mailbox(otg_sx, MTU3_ID_GROUND);
+ } else {
+ ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_DEVICE);
+ ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
+ ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
+ }
}
-
static int ssusb_mode_show(struct seq_file *sf, void *unused)
{
struct ssusb_mtk *ssusb = sf->private;
@@ -388,17 +389,45 @@ static void ssusb_debugfs_exit(struct ssusb_mtk *ssusb)
debugfs_remove_recursive(ssusb->dbgfs_root);
}
+void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
+ enum mtu3_dr_force_mode mode)
+{
+ u32 value;
+
+ value = mtu3_readl(ssusb->ippc_base, SSUSB_U2_CTRL(0));
+ switch (mode) {
+ case MTU3_DR_FORCE_DEVICE:
+ value |= SSUSB_U2_PORT_FORCE_IDDIG | SSUSB_U2_PORT_RG_IDDIG;
+ break;
+ case MTU3_DR_FORCE_HOST:
+ value |= SSUSB_U2_PORT_FORCE_IDDIG;
+ value &= ~SSUSB_U2_PORT_RG_IDDIG;
+ break;
+ case MTU3_DR_FORCE_NONE:
+ value &= ~(SSUSB_U2_PORT_FORCE_IDDIG | SSUSB_U2_PORT_RG_IDDIG);
+ break;
+ default:
+ return;
+ }
+ mtu3_writel(ssusb->ippc_base, SSUSB_U2_CTRL(0), value);
+}
+
int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
{
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
- INIT_DELAYED_WORK(&otg_sx->extcon_reg_dwork, extcon_register_dwork);
-
- if (otg_sx->manual_drd_enabled)
+ if (otg_sx->manual_drd_enabled) {
ssusb_debugfs_init(ssusb);
-
- /* It is enough to delay 1s for waiting for host initialization */
- schedule_delayed_work(&otg_sx->extcon_reg_dwork, HZ);
+ } else {
+ INIT_DELAYED_WORK(&otg_sx->extcon_reg_dwork,
+ extcon_register_dwork);
+
+ /*
+ * It is enough to delay 1s for waiting for
+ * host initialization
+ */
+ schedule_delayed_work(&otg_sx->extcon_reg_dwork, HZ);
+ }
return 0;
}
@@ -407,8 +436,8 @@ void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
{
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
- cancel_delayed_work(&otg_sx->extcon_reg_dwork);
-
if (otg_sx->manual_drd_enabled)
ssusb_debugfs_exit(ssusb);
+ else
+ cancel_delayed_work(&otg_sx->extcon_reg_dwork);
}