|
@@ -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);
|
|
|
}
|