aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/mediatek/patches-4.14/0108-usb-mtu3-use-FORCE-RG_IDDIG-to-implement-manual-DRD-.patch
diff options
context:
space:
mode:
authorJohn Crispin <john@phrozen.org>2018-05-07 12:07:32 +0200
committerJohn Crispin <john@phrozen.org>2018-05-24 22:11:55 +0200
commit050da2107a7eb2a571a8a3d0cee21cc6a44b72b8 (patch)
tree147c3b85ccae12e4b1659acd86ac93b13ecfa15d /target/linux/mediatek/patches-4.14/0108-usb-mtu3-use-FORCE-RG_IDDIG-to-implement-manual-DRD-.patch
parent4f67c1522d92bc4512c3ecf58c38ff9886530b48 (diff)
downloadupstream-050da2107a7eb2a571a8a3d0cee21cc6a44b72b8.tar.gz
upstream-050da2107a7eb2a571a8a3d0cee21cc6a44b72b8.tar.bz2
upstream-050da2107a7eb2a571a8a3d0cee21cc6a44b72b8.zip
mediatek: backport upstream mediatek patches
Signed-off-by: John Crispin <john@phrozen.org>
Diffstat (limited to 'target/linux/mediatek/patches-4.14/0108-usb-mtu3-use-FORCE-RG_IDDIG-to-implement-manual-DRD-.patch')
-rw-r--r--target/linux/mediatek/patches-4.14/0108-usb-mtu3-use-FORCE-RG_IDDIG-to-implement-manual-DRD-.patch290
1 files changed, 290 insertions, 0 deletions
diff --git a/target/linux/mediatek/patches-4.14/0108-usb-mtu3-use-FORCE-RG_IDDIG-to-implement-manual-DRD-.patch b/target/linux/mediatek/patches-4.14/0108-usb-mtu3-use-FORCE-RG_IDDIG-to-implement-manual-DRD-.patch
new file mode 100644
index 0000000000..ce454feb23
--- /dev/null
+++ b/target/linux/mediatek/patches-4.14/0108-usb-mtu3-use-FORCE-RG_IDDIG-to-implement-manual-DRD-.patch
@@ -0,0 +1,290 @@
+From 6c4995c9a8ba8841ba640201636954c84f494587 Mon Sep 17 00:00:00 2001
+From: Chunfeng Yun <chunfeng.yun@mediatek.com>
+Date: Fri, 13 Oct 2017 17:10:42 +0800
+Subject: [PATCH 108/224] 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>
+---
+ drivers/usb/mtu3/mtu3.h | 18 ++++++++----
+ drivers/usb/mtu3/mtu3_dr.c | 61 ++++++++++++++++++++++++++++++-----------
+ drivers/usb/mtu3/mtu3_dr.h | 6 ++++
+ drivers/usb/mtu3/mtu3_host.c | 5 ++++
+ drivers/usb/mtu3/mtu3_hw_regs.h | 2 ++
+ drivers/usb/mtu3/mtu3_plat.c | 38 ++-----------------------
+ 6 files changed, 74 insertions(+), 56 deletions(-)
+
+diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h
+index ef2dc92a2109..b0c2b5dca045 100644
+--- a/drivers/usb/mtu3/mtu3.h
++++ b/drivers/usb/mtu3/mtu3.h
+@@ -115,6 +115,19 @@ enum mtu3_g_ep0_state {
+ };
+
+ /**
++ * MTU3_DR_FORCE_NONE: automatically switch host and periperal mode
++ * by IDPIN signal.
++ * MTU3_DR_FORCE_HOST: force to enter host mode and override OTG
++ * IDPIN signal.
++ * MTU3_DR_FORCE_DEVICE: force to enter peripheral mode.
++ */
++enum mtu3_dr_force_mode {
++ MTU3_DR_FORCE_NONE = 0,
++ MTU3_DR_FORCE_HOST,
++ MTU3_DR_FORCE_DEVICE,
++};
++
++/**
+ * @base: the base address of fifo
+ * @limit: the bitmap size in bits
+ * @bitmap: fifo bitmap in unit of @MTU3_EP_FIFO_UNIT
+@@ -196,7 +209,6 @@ struct mtu3_gpd_ring {
+ * xHCI driver initialization, it's necessary for system bootup
+ * as device.
+ * @is_u3_drd: whether port0 supports usb3.0 dual-role device or not
+-* @id_*: used to maually switch between host and device modes by idpin
+ * @manual_drd_enabled: it's true when supports dual-role device by debugfs
+ * to switch host/device modes depending on user input.
+ */
+@@ -207,10 +219,6 @@ struct otg_switch_mtk {
+ struct notifier_block id_nb;
+ struct delayed_work extcon_reg_dwork;
+ bool is_u3_drd;
+- /* dual-role switch by debugfs */
+- struct pinctrl *id_pinctrl;
+- struct pinctrl_state *id_float;
+- struct pinctrl_state *id_ground;
+ bool manual_drd_enabled;
+ };
+
+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);
+ }
+diff --git a/drivers/usb/mtu3/mtu3_dr.h b/drivers/usb/mtu3/mtu3_dr.h
+index 9b228b5811b0..0f0cbac00192 100644
+--- a/drivers/usb/mtu3/mtu3_dr.h
++++ b/drivers/usb/mtu3/mtu3_dr.h
+@@ -87,6 +87,8 @@ static inline void ssusb_gadget_exit(struct ssusb_mtk *ssusb)
+ int ssusb_otg_switch_init(struct ssusb_mtk *ssusb);
+ void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb);
+ int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on);
++void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
++ enum mtu3_dr_force_mode mode);
+
+ #else
+
+@@ -103,6 +105,10 @@ static inline int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on)
+ return 0;
+ }
+
++static inline void
++ssusb_set_force_mode(struct ssusb_mtk *ssusb, enum mtu3_dr_force_mode mode)
++{}
++
+ #endif
+
+ #endif /* _MTU3_DR_H_ */
+diff --git a/drivers/usb/mtu3/mtu3_host.c b/drivers/usb/mtu3/mtu3_host.c
+index edcc59148171..ec76b86dd887 100644
+--- a/drivers/usb/mtu3/mtu3_host.c
++++ b/drivers/usb/mtu3/mtu3_host.c
+@@ -189,6 +189,8 @@ int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend)
+
+ static void ssusb_host_setup(struct ssusb_mtk *ssusb)
+ {
++ struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
++
+ host_ports_num_get(ssusb);
+
+ /*
+@@ -197,6 +199,9 @@ static void ssusb_host_setup(struct ssusb_mtk *ssusb)
+ */
+ ssusb_host_enable(ssusb);
+
++ if (otg_sx->manual_drd_enabled)
++ ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
++
+ /* if port0 supports dual-role, works as host mode by default */
+ ssusb_set_vbus(&ssusb->otg_switch, 1);
+ }
+diff --git a/drivers/usb/mtu3/mtu3_hw_regs.h b/drivers/usb/mtu3/mtu3_hw_regs.h
+index b6059752dc12..a7e35f6ad90a 100644
+--- a/drivers/usb/mtu3/mtu3_hw_regs.h
++++ b/drivers/usb/mtu3/mtu3_hw_regs.h
+@@ -472,6 +472,8 @@
+ #define SSUSB_U3_PORT_DIS BIT(0)
+
+ /* U3D_SSUSB_U2_CTRL_0P */
++#define SSUSB_U2_PORT_RG_IDDIG BIT(12)
++#define SSUSB_U2_PORT_FORCE_IDDIG BIT(11)
+ #define SSUSB_U2_PORT_VBUSVALID BIT(9)
+ #define SSUSB_U2_PORT_OTG_SEL BIT(7)
+ #define SSUSB_U2_PORT_HOST BIT(2)
+diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c
+index fb8992011bde..1e473b068650 100644
+--- a/drivers/usb/mtu3/mtu3_plat.c
++++ b/drivers/usb/mtu3/mtu3_plat.c
+@@ -21,7 +21,6 @@
+ #include <linux/module.h>
+ #include <linux/of_address.h>
+ #include <linux/of_irq.h>
+-#include <linux/pinctrl/consumer.h>
+ #include <linux/platform_device.h>
+
+ #include "mtu3.h"
+@@ -212,33 +211,6 @@ static void ssusb_ip_sw_reset(struct ssusb_mtk *ssusb)
+ mtu3_clrbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST);
+ }
+
+-static int get_iddig_pinctrl(struct ssusb_mtk *ssusb)
+-{
+- struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
+-
+- otg_sx->id_pinctrl = devm_pinctrl_get(ssusb->dev);
+- if (IS_ERR(otg_sx->id_pinctrl)) {
+- dev_err(ssusb->dev, "Cannot find id pinctrl!\n");
+- return PTR_ERR(otg_sx->id_pinctrl);
+- }
+-
+- otg_sx->id_float =
+- pinctrl_lookup_state(otg_sx->id_pinctrl, "id_float");
+- if (IS_ERR(otg_sx->id_float)) {
+- dev_err(ssusb->dev, "Cannot find pinctrl id_float!\n");
+- return PTR_ERR(otg_sx->id_float);
+- }
+-
+- otg_sx->id_ground =
+- pinctrl_lookup_state(otg_sx->id_pinctrl, "id_ground");
+- if (IS_ERR(otg_sx->id_ground)) {
+- dev_err(ssusb->dev, "Cannot find pinctrl id_ground!\n");
+- return PTR_ERR(otg_sx->id_ground);
+- }
+-
+- return 0;
+-}
+-
+ /* ignore the error if the clock does not exist */
+ static struct clk *get_optional_clk(struct device *dev, const char *id)
+ {
+@@ -349,15 +321,11 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
+ dev_err(ssusb->dev, "couldn't get extcon device\n");
+ return -EPROBE_DEFER;
+ }
+- if (otg_sx->manual_drd_enabled) {
+- ret = get_iddig_pinctrl(ssusb);
+- if (ret)
+- return ret;
+- }
+ }
+
+- dev_info(dev, "dr_mode: %d, is_u3_dr: %d, u3p_dis_msk:%x\n",
+- ssusb->dr_mode, otg_sx->is_u3_drd, ssusb->u3p_dis_msk);
++ dev_info(dev, "dr_mode: %d, is_u3_dr: %d, u3p_dis_msk: %x, drd: %s\n",
++ ssusb->dr_mode, otg_sx->is_u3_drd, ssusb->u3p_dis_msk,
++ otg_sx->manual_drd_enabled ? "manual" : "auto");
+
+ return 0;
+ }
+--
+2.11.0
+