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