diff options
author | John Crispin <john@phrozen.org> | 2018-05-07 12:07:32 +0200 |
---|---|---|
committer | John Crispin <john@phrozen.org> | 2018-05-24 22:11:55 +0200 |
commit | 050da2107a7eb2a571a8a3d0cee21cc6a44b72b8 (patch) | |
tree | 147c3b85ccae12e4b1659acd86ac93b13ecfa15d /target/linux/mediatek/patches-4.14/0108-usb-mtu3-use-FORCE-RG_IDDIG-to-implement-manual-DRD-.patch | |
parent | 4f67c1522d92bc4512c3ecf58c38ff9886530b48 (diff) | |
download | upstream-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-.patch | 290 |
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 + |