mirror of
				https://github.com/Ysurac/openmptcprouter.git
				synced 2025-03-09 15:40:20 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			274 lines
		
	
	
	
		
			8.3 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			274 lines
		
	
	
	
		
			8.3 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| 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(-)
 | |
| 
 | |
| --- 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;
 | |
|  };
 | |
|  
 | |
| --- a/drivers/usb/mtu3/mtu3_dr.c
 | |
| +++ b/drivers/usb/mtu3/mtu3_dr.c
 | |
| @@ -261,21 +261,22 @@ static void extcon_register_dwork(struct
 | |
|   * 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 ss
 | |
|  	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);
 | |
| +	} 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);
 | |
| +		/*
 | |
| +		 * 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_
 | |
|  {
 | |
|  	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);
 | |
|  }
 | |
| --- a/drivers/usb/mtu3/mtu3_dr.h
 | |
| +++ b/drivers/usb/mtu3/mtu3_dr.h
 | |
| @@ -87,6 +87,8 @@ static inline void ssusb_gadget_exit(str
 | |
|  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
 | |
|  	return 0;
 | |
|  }
 | |
|  
 | |
| +static inline void
 | |
| +ssusb_set_force_mode(struct ssusb_mtk *ssusb, enum mtu3_dr_force_mode mode)
 | |
| +{}
 | |
| +
 | |
|  #endif
 | |
|  
 | |
|  #endif		/* _MTU3_DR_H_ */
 | |
| --- 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
 | |
|  
 | |
|  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 ssus
 | |
|  	 */
 | |
|  	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);
 | |
|  }
 | |
| --- 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)
 | |
| --- 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 ssu
 | |
|  	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 platfor
 | |
|  			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;
 | |
|  }
 |