Re: [PATCH 2/2] usb: dwc2: add support for STM32MP15 SoCs USB OTG HS and FS

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

On 11/25/2019 2:26 PM, Amelie Delaunay wrote:
> This patch introduces a new parameter to activate external ID pin and valid
> vbus level detection, required on STM32MP15 SoC to support dual role,
> either in HS or FS.
> The STM32MP15 SoC uses the GGPIO register to enable the level detection.
> The level detector requires to be powered.
> Also adds the params structures for STM32MP15 OTG HS and STM32MP1 OTG FS.
> 
> Signed-off-by: Amelie Delaunay <amelie.delaunay@xxxxxx>

Acked-by: Minas Harutyunyan <hminas@xxxxxxxxxxxx>

> ---
>   drivers/usb/dwc2/core.h     |  8 ++++
>   drivers/usb/dwc2/hw.h       |  8 ++++
>   drivers/usb/dwc2/params.c   | 33 +++++++++++++
>   drivers/usb/dwc2/platform.c | 94 ++++++++++++++++++++++++++++++++++++-
>   4 files changed, 141 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
> index d08d070a0fb6..687fefcd5706 100644
> --- a/drivers/usb/dwc2/core.h
> +++ b/drivers/usb/dwc2/core.h
> @@ -411,6 +411,10 @@ enum dwc2_ep0_state {
>    *			register.
>    *			0 - Deactivate the transceiver (default)
>    *			1 - Activate the transceiver
> + * @activate_stm_id_vb_detection: Activate external ID pin and Vbus level
> + *			detection using GGPIO register.
> + *			0 - Deactivate the external level detection (default)
> + *			1 - Activate the external level detection
>    * @g_dma:              Enables gadget dma usage (default: autodetect).
>    * @g_dma_desc:         Enables gadget descriptor DMA (default: autodetect).
>    * @g_rx_fifo_size:	The periodic rx fifo size for the device, in
> @@ -481,6 +485,7 @@ struct dwc2_core_params {
>   	bool service_interval;
>   	u8 hird_threshold;
>   	bool activate_stm_fs_transceiver;
> +	bool activate_stm_id_vb_detection;
>   	bool ipg_isoc_en;
>   	u16 max_packet_count;
>   	u32 max_transfer_size;
> @@ -874,6 +879,8 @@ struct dwc2_hregs_backup {
>    *                      removed once all SoCs support usb transceiver.
>    * @supplies:           Definition of USB power supplies
>    * @vbus_supply:        Regulator supplying vbus.
> + * @usb33d:		Optional 3.3v regulator used on some stm32 devices to
> + *			supply ID and VBUS detection hardware.
>    * @lock:		Spinlock that protects all the driver data structures
>    * @priv:		Stores a pointer to the struct usb_hcd
>    * @queuing_high_bandwidth: True if multiple packets of a high-bandwidth
> @@ -1061,6 +1068,7 @@ struct dwc2_hsotg {
>   	struct dwc2_hsotg_plat *plat;
>   	struct regulator_bulk_data supplies[DWC2_NUM_SUPPLIES];
>   	struct regulator *vbus_supply;
> +	struct regulator *usb33d;
>   
>   	spinlock_t lock;
>   	void *priv;
> diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h
> index 510e87ec0be8..c4027bbcedec 100644
> --- a/drivers/usb/dwc2/hw.h
> +++ b/drivers/usb/dwc2/hw.h
> @@ -54,6 +54,12 @@
>   #define GOTGCTL_HSTSETHNPEN		BIT(10)
>   #define GOTGCTL_HNPREQ			BIT(9)
>   #define GOTGCTL_HSTNEGSCS		BIT(8)
> +#define GOTGCTL_BVALOVAL		BIT(7)
> +#define GOTGCTL_BVALOEN			BIT(6)
> +#define GOTGCTL_AVALOVAL		BIT(5)
> +#define GOTGCTL_AVALOEN			BIT(4)
> +#define GOTGCTL_VBVALOVAL		BIT(3)
> +#define GOTGCTL_VBVALOEN		BIT(2)
>   #define GOTGCTL_SESREQ			BIT(1)
>   #define GOTGCTL_SESREQSCS		BIT(0)
>   
> @@ -227,6 +233,8 @@
>   #define GPVNDCTL			HSOTG_REG(0x0034)
>   #define GGPIO				HSOTG_REG(0x0038)
>   #define GGPIO_STM32_OTG_GCCFG_PWRDWN	BIT(16)
> +#define GGPIO_STM32_OTG_GCCFG_VBDEN	BIT(21)
> +#define GGPIO_STM32_OTG_GCCFG_IDEN	BIT(22)
>   
>   #define GUID				HSOTG_REG(0x003c)
>   #define GSNPSID				HSOTG_REG(0x0040)
> diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
> index 31e090ac9f1e..8ccc83f7eb3f 100644
> --- a/drivers/usb/dwc2/params.c
> +++ b/drivers/usb/dwc2/params.c
> @@ -163,6 +163,35 @@ static void dwc2_set_stm32f7_hsotg_params(struct dwc2_hsotg *hsotg)
>   	p->host_perio_tx_fifo_size = 256;
>   }
>   
> +static void dwc2_set_stm32mp15_fsotg_params(struct dwc2_hsotg *hsotg)
> +{
> +	struct dwc2_core_params *p = &hsotg->params;
> +
> +	p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
> +	p->speed = DWC2_SPEED_PARAM_FULL;
> +	p->host_rx_fifo_size = 128;
> +	p->host_nperio_tx_fifo_size = 96;
> +	p->host_perio_tx_fifo_size = 96;
> +	p->max_packet_count = 256;
> +	p->phy_type = DWC2_PHY_TYPE_PARAM_FS;
> +	p->i2c_enable = false;
> +	p->activate_stm_fs_transceiver = true;
> +	p->activate_stm_id_vb_detection = true;
> +	p->power_down = DWC2_POWER_DOWN_PARAM_NONE;
> +}
> +
> +static void dwc2_set_stm32mp15_hsotg_params(struct dwc2_hsotg *hsotg)
> +{
> +	struct dwc2_core_params *p = &hsotg->params;
> +
> +	p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
> +	p->activate_stm_id_vb_detection = true;
> +	p->host_rx_fifo_size = 440;
> +	p->host_nperio_tx_fifo_size = 256;
> +	p->host_perio_tx_fifo_size = 256;
> +	p->power_down = DWC2_POWER_DOWN_PARAM_NONE;
> +}
> +
>   const struct of_device_id dwc2_of_match_table[] = {
>   	{ .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params },
>   	{ .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params  },
> @@ -186,6 +215,10 @@ const struct of_device_id dwc2_of_match_table[] = {
>   	{ .compatible = "st,stm32f4x9-hsotg" },
>   	{ .compatible = "st,stm32f7-hsotg",
>   	  .data = dwc2_set_stm32f7_hsotg_params },
> +	{ .compatible = "st,stm32mp15-fsotg",
> +	  .data = dwc2_set_stm32mp15_fsotg_params },
> +	{ .compatible = "st,stm32mp15-hsotg",
> +	  .data = dwc2_set_stm32mp15_hsotg_params },
>   	{},
>   };
>   MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
> diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
> index 3c6ce09a6db5..8368d6d66d64 100644
> --- a/drivers/usb/dwc2/platform.c
> +++ b/drivers/usb/dwc2/platform.c
> @@ -312,6 +312,9 @@ static int dwc2_driver_remove(struct platform_device *dev)
>   	if (hsotg->gadget_enabled)
>   		dwc2_hsotg_remove(hsotg);
>   
> +	if (hsotg->params.activate_stm_id_vb_detection)
> +		regulator_disable(hsotg->usb33d);
> +
>   	if (hsotg->ll_hw_enabled)
>   		dwc2_lowlevel_hw_disable(hsotg);
>   
> @@ -464,10 +467,35 @@ static int dwc2_driver_probe(struct platform_device *dev)
>   	if (retval)
>   		goto error;
>   
> +	if (hsotg->params.activate_stm_id_vb_detection) {
> +		u32 ggpio;
> +
> +		hsotg->usb33d = devm_regulator_get(hsotg->dev, "usb33d");
> +		if (IS_ERR(hsotg->usb33d)) {
> +			retval = PTR_ERR(hsotg->usb33d);
> +			if (retval != -EPROBE_DEFER)
> +				dev_err(hsotg->dev,
> +					"failed to request usb33d supply: %d\n",
> +					retval);
> +			goto error;
> +		}
> +		retval = regulator_enable(hsotg->usb33d);
> +		if (retval) {
> +			dev_err(hsotg->dev,
> +				"failed to enable usb33d supply: %d\n", retval);
> +			goto error;
> +		}
> +
> +		ggpio = dwc2_readl(hsotg, GGPIO);
> +		ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN;
> +		ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN;
> +		dwc2_writel(hsotg, ggpio, GGPIO);
> +	}
> +
>   	if (hsotg->dr_mode != USB_DR_MODE_HOST) {
>   		retval = dwc2_gadget_init(hsotg);
>   		if (retval)
> -			goto error;
> +			goto error_init;
>   		hsotg->gadget_enabled = 1;
>   	}
>   
> @@ -493,7 +521,7 @@ static int dwc2_driver_probe(struct platform_device *dev)
>   		if (retval) {
>   			if (hsotg->gadget_enabled)
>   				dwc2_hsotg_remove(hsotg);
> -			goto error;
> +			goto error_init;
>   		}
>   		hsotg->hcd_enabled = 1;
>   	}
> @@ -509,6 +537,9 @@ static int dwc2_driver_probe(struct platform_device *dev)
>   
>   	return 0;
>   
> +error_init:
> +	if (hsotg->params.activate_stm_id_vb_detection)
> +		regulator_disable(hsotg->usb33d);
>   error:
>   	dwc2_lowlevel_hw_disable(hsotg);
>   	return retval;
> @@ -523,6 +554,37 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
>   	if (is_device_mode)
>   		dwc2_hsotg_suspend(dwc2);
>   
> +	if (dwc2->params.activate_stm_id_vb_detection) {
> +		unsigned long flags;
> +		u32 ggpio, gotgctl;
> +
> +		/*
> +		 * Need to force the mode to the current mode to avoid Mode
> +		 * Mismatch Interrupt when ID detection will be disabled.
> +		 */
> +		dwc2_force_mode(dwc2, !is_device_mode);
> +
> +		spin_lock_irqsave(&dwc2->lock, flags);
> +		gotgctl = dwc2_readl(dwc2, GOTGCTL);
> +		/* bypass debounce filter, enable overrides */
> +		gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS;
> +		gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN;
> +		/* Force A / B session if needed */
> +		if (gotgctl & GOTGCTL_ASESVLD)
> +			gotgctl |= GOTGCTL_AVALOVAL;
> +		if (gotgctl & GOTGCTL_BSESVLD)
> +			gotgctl |= GOTGCTL_BVALOVAL;
> +		dwc2_writel(dwc2, gotgctl, GOTGCTL);
> +		spin_unlock_irqrestore(&dwc2->lock, flags);
> +
> +		ggpio = dwc2_readl(dwc2, GGPIO);
> +		ggpio &= ~GGPIO_STM32_OTG_GCCFG_IDEN;
> +		ggpio &= ~GGPIO_STM32_OTG_GCCFG_VBDEN;
> +		dwc2_writel(dwc2, ggpio, GGPIO);
> +
> +		regulator_disable(dwc2->usb33d);
> +	}
> +
>   	if (dwc2->ll_hw_enabled &&
>   	    (is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) {
>   		ret = __dwc2_lowlevel_hw_disable(dwc2);
> @@ -544,6 +606,34 @@ static int __maybe_unused dwc2_resume(struct device *dev)
>   	}
>   	dwc2->phy_off_for_suspend = false;
>   
> +	if (dwc2->params.activate_stm_id_vb_detection) {
> +		unsigned long flags;
> +		u32 ggpio, gotgctl;
> +
> +		ret = regulator_enable(dwc2->usb33d);
> +		if (ret)
> +			return ret;
> +
> +		ggpio = dwc2_readl(dwc2, GGPIO);
> +		ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN;
> +		ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN;
> +		dwc2_writel(dwc2, ggpio, GGPIO);
> +
> +		/* ID/VBUS detection startup time */
> +		usleep_range(5000, 7000);
> +
> +		spin_lock_irqsave(&dwc2->lock, flags);
> +		gotgctl = dwc2_readl(dwc2, GOTGCTL);
> +		gotgctl &= ~GOTGCTL_DBNCE_FLTR_BYPASS;
> +		gotgctl &= ~(GOTGCTL_BVALOEN | GOTGCTL_AVALOEN |
> +			     GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL);
> +		dwc2_writel(dwc2, gotgctl, GOTGCTL);
> +		spin_unlock_irqrestore(&dwc2->lock, flags);
> +	}
> +
> +	/* Need to restore FORCEDEVMODE/FORCEHOSTMODE */
> +	dwc2_force_dr_mode(dwc2);
> +
>   	if (dwc2_is_device_mode(dwc2))
>   		ret = dwc2_hsotg_resume(dwc2);
>   
> 




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux