Merge tag 'usb-for-v5.7' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next

Felipe writes:

USB: changes for v5.7 merge window

Lots of changes on dwc3 this time, most of them from Thinh fixing a
bunch of really old mishaps on the driver.

DWC2 got support for STM32MP15 and a couple RockChip SoCs while DWC3
learned about Amlogic A1 family.

Apart from these, we have a few spelling fixes and other minor
non-critical fixes all over the place.

Signed-off-by: Felipe Balbi <balbi@kernel.org>

* tag 'usb-for-v5.7' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb: (41 commits)
  dt-bindings: usb: add documentation for aspeed usb-vhub
  ARM: dts: aspeed-g4: add vhub port and endpoint properties
  ARM: dts: aspeed-g5: add vhub port and endpoint properties
  ARM: dts: aspeed-g6: add usb functions
  usb: gadget: aspeed: add ast2600 vhub support
  usb: gadget: aspeed: read vhub properties from device tree
  usb: gadget: aspeed: support per-vhub usb descriptors
  usb: gadget: f_phonet: Replace zero-length array with flexible-array member
  usb: gadget: composite: Inform controller driver of self-powered
  usb: gadget: amd5536udc: fix spelling mistake "reserverd" -> "reserved"
  udc: s3c-hsudc: Silence warning about supplies during deferred probe
  usb: dwc2: Silence warning about supplies during deferred probe
  dt-bindings: usb: dwc2: add compatible property for rk3368 usb
  dt-bindings: usb: dwc2: add compatible property for rk3328 usb
  usb: gadget: add raw-gadget interface
  usb: dwc2: Implement set_selfpowered()
  usb: dwc3: qcom: Replace <linux/clk-provider.h> by <linux/of_clk.h>
  usb: dwc3: core: don't do suspend for device mode if already suspended
  usb: dwc3: Rework resets initialization to be more flexible
  usb: dwc3: Rework clock initialization to be more flexible
  ...
This commit is contained in:
Greg Kroah-Hartman
2020-03-16 08:22:49 +01:00
40 changed files with 3532 additions and 219 deletions
@@ -22,10 +22,14 @@ description: |
The DWC3 Glue controls the PHY routing and power, an interrupt line is
connected to the Glue to serve as OTG ID change detection.
The Amlogic A1 embeds a DWC3 USB IP Core configured for USB2 in
host-only mode.
properties:
compatible:
enum:
- amlogic,meson-g12a-usb-ctrl
- amlogic,meson-a1-usb-ctrl
ranges: true
@@ -84,6 +88,25 @@ required:
- phys
- dr_mode
allOf:
- if:
properties:
compatible:
enum:
- amlogic,meson-a1-usb-ctrl
then:
properties:
clocks:
minItems: 3
clock-names:
items:
- const: usb_ctrl
- const: usb_bus
- const: xtal_usb_ctrl
required:
- clock-names
examples:
- |
usb: usb@ffe09000 {
@@ -0,0 +1,77 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (c) 2020 Facebook Inc.
%YAML 1.2
---
$id: http://devicetree.org/schemas/usb/aspeed,usb-vhub.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ASPEED USB 2.0 Virtual Hub Controller
maintainers:
- Benjamin Herrenschmidt <benh@kernel.crashing.org>
description: |+
The ASPEED USB 2.0 Virtual Hub Controller implements 1 set of USB Hub
register and several sets of Device and Endpoint registers to support
the Virtual Hub's downstream USB devices.
Supported number of devices and endpoints vary depending on hardware
revisions. AST2400 and AST2500 Virtual Hub supports 5 downstream devices
and 15 generic endpoints, while AST2600 Virtual Hub supports 7 downstream
devices and 21 generic endpoints.
properties:
compatible:
enum:
- aspeed,ast2400-usb-vhub
- aspeed,ast2500-usb-vhub
- aspeed,ast2600-usb-vhub
reg:
maxItems: 1
clocks:
maxItems: 1
interrupts:
maxItems: 1
aspeed,vhub-downstream-ports:
description: Number of downstream ports supported by the Virtual Hub
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- default: 5
minimum: 1
maximum: 7
aspeed,vhub-generic-endpoints:
description: Number of generic endpoints supported by the Virtual Hub
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- default: 15
minimum: 1
maximum: 21
required:
- compatible
- reg
- clocks
- interrupts
- aspeed,vhub-downstream-ports
- aspeed,vhub-generic-endpoints
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/aspeed-clock.h>
vhub: usb-vhub@1e6a0000 {
compatible = "aspeed,ast2500-usb-vhub";
reg = <0x1e6a0000 0x300>;
interrupts = <5>;
clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>;
aspeed,vhub-downstream-ports = <5>;
aspeed,vhub-generic-endpoints = <15>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb2ad_default>;
};
@@ -18,27 +18,15 @@ properties:
- const: rockchip,rk3066-usb
- const: snps,dwc2
- items:
- const: rockchip,px30-usb
- const: rockchip,rk3066-usb
- const: snps,dwc2
- items:
- const: rockchip,rk3036-usb
- const: rockchip,rk3066-usb
- const: snps,dwc2
- items:
- const: rockchip,rv1108-usb
- const: rockchip,rk3066-usb
- const: snps,dwc2
- items:
- const: rockchip,rk3188-usb
- const: rockchip,rk3066-usb
- const: snps,dwc2
- items:
- const: rockchip,rk3228-usb
- const: rockchip,rk3066-usb
- const: snps,dwc2
- items:
- const: rockchip,rk3288-usb
- enum:
- rockchip,px30-usb
- rockchip,rk3036-usb
- rockchip,rk3188-usb
- rockchip,rk3228-usb
- rockchip,rk3288-usb
- rockchip,rk3328-usb
- rockchip,rk3368-usb
- rockchip,rv1108-usb
- const: rockchip,rk3066-usb
- const: snps,dwc2
- const: lantiq,arx100-usb
@@ -7,7 +7,8 @@ Required properties:
- compatible: must be "snps,dwc3"
- reg : Address and length of the register set for the device
- interrupts: Interrupts used by the dwc3 controller.
- clock-names: should contain "ref", "bus_early", "suspend"
- clock-names: list of clock names. Ideally should be "ref",
"bus_early", "suspend" but may be less or more.
- clocks: list of phandle and clock specifier pairs corresponding to
entries in the clock-names property.
@@ -36,7 +37,7 @@ Optional properties:
- phys: from the *Generic PHY* bindings
- phy-names: from the *Generic PHY* bindings; supported names are "usb2-phy"
or "usb3-phy".
- resets: a single pair of phandle and reset specifier
- resets: set of phandle and reset specifier pairs
- snps,usb2-lpm-disable: indicate if we don't want to enable USB2 HW LPM
- snps,usb3_lpm_capable: determines if platform is USB3 LPM capable
- snps,dis-start-transfer-quirk: when set, disable isoc START TRANSFER command
@@ -75,6 +76,8 @@ Optional properties:
from P0 to P1/P2/P3 without delay.
- snps,dis-tx-ipgap-linecheck-quirk: when set, disable u2mac linestate check
during HS transmit.
- snps,parkmode-disable-ss-quirk: when set, all SuperSpeed bus instances in
park mode are disabled.
- snps,dis_metastability_quirk: when set, disable metastability workaround.
CAUTION: use only if you are absolutely sure of it.
- snps,is-utmi-l1-suspend: true when DWC3 asserts output signal
@@ -35,6 +35,12 @@ Optional properties:
the USB data role (USB host or USB device) for a given
USB connector, such as Type-C, Type-B(micro).
see connector/usb-connector.txt.
- role-switch-default-mode: indicating if usb-role-switch is enabled, the
device default operation mode of controller while usb
role is USB_ROLE_NONE. Valid arguments are "host" and
"peripheral". Defaults to "peripheral" if not
specified.
This is an attribute to a USB controller such as:
@@ -0,0 +1,69 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/usb/maxim,max3420-udc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MAXIM MAX3420/1 USB Peripheral Controller
maintainers:
- Jassi Brar <jaswinder.singh@linaro.org>
description: |
The controller provices USB2.0 compliant FullSpeed peripheral
implementation over the SPI interface.
Specifications about the part can be found at:
http://datasheets.maximintegrated.com/en/ds/MAX3420E.pdf
properties:
compatible:
enum:
- maxim,max3420-udc
- maxim,max3421-udc
reg:
maxItems: 1
interrupts:
items:
- description: usb irq from max3420
- description: vbus detection irq
minItems: 1
maxItems: 2
interrupt-names:
items:
- const: udc
- const: vbus
minItems: 1
maxItems: 2
spi-max-frequency:
maximum: 26000000
required:
- compatible
- reg
- interrupts
- interrupt-names
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi0 {
#address-cells = <1>;
#size-cells = <0>;
udc@0 {
compatible = "maxim,max3420-udc";
reg = <0>;
interrupt-parent = <&gpio>;
interrupts = <0 IRQ_TYPE_EDGE_FALLING>, <10 IRQ_TYPE_EDGE_BOTH>;
interrupt-names = "udc", "vbus";
spi-max-frequency = <12500000>;
};
};
+1
View File
@@ -22,6 +22,7 @@ USB support
misc_usbsevseg
mtouchusb
ohci
raw-gadget
usbip_protocol
usbmon
usb-serial
+61
View File
@@ -0,0 +1,61 @@
==============
USB Raw Gadget
==============
USB Raw Gadget is a kernel module that provides a userspace interface for
the USB Gadget subsystem. Essentially it allows to emulate USB devices
from userspace. Enabled with CONFIG_USB_RAW_GADGET. Raw Gadget is
currently a strictly debugging feature and shouldn't be used in
production, use GadgetFS instead.
Comparison to GadgetFS
~~~~~~~~~~~~~~~~~~~~~~
Raw Gadget is similar to GadgetFS, but provides a more low-level and
direct access to the USB Gadget layer for the userspace. The key
differences are:
1. Every USB request is passed to the userspace to get a response, while
GadgetFS responds to some USB requests internally based on the provided
descriptors. However note, that the UDC driver might respond to some
requests on its own and never forward them to the Gadget layer.
2. GadgetFS performs some sanity checks on the provided USB descriptors,
while Raw Gadget allows you to provide arbitrary data as responses to
USB requests.
3. Raw Gadget provides a way to select a UDC device/driver to bind to,
while GadgetFS currently binds to the first available UDC.
4. Raw Gadget uses predictable endpoint names (handles) across different
UDCs (as long as UDCs have enough endpoints of each required transfer
type).
5. Raw Gadget has ioctl-based interface instead of a filesystem-based one.
Userspace interface
~~~~~~~~~~~~~~~~~~~
To create a Raw Gadget instance open /dev/raw-gadget. Multiple raw-gadget
instances (bound to different UDCs) can be used at the same time. The
interaction with the opened file happens through the ioctl() calls, see
comments in include/uapi/linux/usb/raw_gadget.h for details.
The typical usage of Raw Gadget looks like:
1. Open Raw Gadget instance via /dev/raw-gadget.
2. Initialize the instance via USB_RAW_IOCTL_INIT.
3. Launch the instance with USB_RAW_IOCTL_RUN.
4. In a loop issue USB_RAW_IOCTL_EVENT_FETCH calls to receive events from
Raw Gadget and react to those depending on what kind of USB device
needs to be emulated.
Potential future improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Implement ioctl's for setting/clearing halt status on endpoints.
- Reporting more events (suspend, resume, etc.) through
USB_RAW_IOCTL_EVENT_FETCH.
- Support O_NONBLOCK I/O.
+2
View File
@@ -164,6 +164,8 @@
reg = <0x1e6a0000 0x300>;
interrupts = <5>;
clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>;
aspeed,vhub-downstream-ports = <5>;
aspeed,vhub-generic-endpoints = <15>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb2d_default>;
status = "disabled";
+2
View File
@@ -195,6 +195,8 @@
reg = <0x1e6a0000 0x300>;
interrupts = <5>;
clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>;
aspeed,vhub-downstream-ports = <5>;
aspeed,vhub-generic-endpoints = <15>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb2ad_default>;
status = "disabled";
+25
View File
@@ -1112,6 +1112,31 @@
groups = "UART9";
};
pinctrl_usb2ah_default: usb2ah_default {
function = "USB2AH";
groups = "USBA";
};
pinctrl_usb2ad_default: usb2ad_default {
function = "USB2AD";
groups = "USBA";
};
pinctrl_usb2bh_default: usb2bh_default {
function = "USB2BH";
groups = "USBB";
};
pinctrl_usb2bd_default: usb2bd_default {
function = "USB2BD";
groups = "USBB";
};
pinctrl_usb11bhid_default: usb11bhid_default {
function = "USB11BHID";
groups = "USBB";
};
pinctrl_vb_default: vb_default {
function = "VB";
groups = "VB";
+45
View File
@@ -245,6 +245,51 @@
status = "disabled";
};
ehci0: usb@1e6a1000 {
compatible = "aspeed,ast2600-ehci", "generic-ehci";
reg = <0x1e6a1000 0x100>;
interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb2ah_default>;
status = "disabled";
};
ehci1: usb@1e6a3000 {
compatible = "aspeed,ast2600-ehci", "generic-ehci";
reg = <0x1e6a3000 0x100>;
interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&syscon ASPEED_CLK_GATE_USBPORT2CLK>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb2bh_default>;
status = "disabled";
};
uhci: usb@1e6b0000 {
compatible = "aspeed,ast2600-uhci", "generic-uhci";
reg = <0x1e6b0000 0x100>;
interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
#ports = <2>;
clocks = <&syscon ASPEED_CLK_GATE_USBUHCICLK>;
status = "disabled";
/*
* No default pinmux, it will follow EHCI, use an
* explicit pinmux override if EHCI is not enabled.
*/
};
vhub: usb-vhub@1e6a0000 {
compatible = "aspeed,ast2600-usb-vhub";
reg = <0x1e6a0000 0x350>;
interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>;
aspeed,vhub-downstream-ports = <7>;
aspeed,vhub-generic-endpoints = <21>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb2ad_default>;
status = "disabled";
};
apb {
compatible = "simple-bus";
#address-cells = <1>;
+8
View File
@@ -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;
+23 -1
View File
@@ -1646,7 +1646,8 @@ static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg,
switch (ctrl->bRequestType & USB_RECIP_MASK) {
case USB_RECIP_DEVICE:
status = 1 << USB_DEVICE_SELF_POWERED;
status = hsotg->gadget.is_selfpowered <<
USB_DEVICE_SELF_POWERED;
status |= hsotg->remote_wakeup_allowed <<
USB_DEVICE_REMOTE_WAKEUP;
reply = cpu_to_le16(status);
@@ -4527,6 +4528,26 @@ static int dwc2_hsotg_gadget_getframe(struct usb_gadget *gadget)
return dwc2_hsotg_read_frameno(to_hsotg(gadget));
}
/**
* dwc2_hsotg_set_selfpowered - set if device is self/bus powered
* @gadget: The usb gadget state
* @is_selfpowered: Whether the device is self-powered
*
* Set if the device is self or bus powered.
*/
static int dwc2_hsotg_set_selfpowered(struct usb_gadget *gadget,
int is_selfpowered)
{
struct dwc2_hsotg *hsotg = to_hsotg(gadget);
unsigned long flags;
spin_lock_irqsave(&hsotg->lock, flags);
gadget->is_selfpowered = !!is_selfpowered;
spin_unlock_irqrestore(&hsotg->lock, flags);
return 0;
}
/**
* dwc2_hsotg_pullup - connect/disconnect the USB PHY
* @gadget: The usb gadget state
@@ -4618,6 +4639,7 @@ static int dwc2_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned int mA)
static const struct usb_gadget_ops dwc2_hsotg_gadget_ops = {
.get_frame = dwc2_hsotg_gadget_getframe,
.set_selfpowered = dwc2_hsotg_set_selfpowered,
.udc_start = dwc2_hsotg_udc_start,
.udc_stop = dwc2_hsotg_udc_stop,
.pullup = dwc2_hsotg_pullup,
+8
View File
@@ -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)
+33
View File
@@ -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);
+95 -3
View File
@@ -285,7 +285,9 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
ret = devm_regulator_bulk_get(hsotg->dev, ARRAY_SIZE(hsotg->supplies),
hsotg->supplies);
if (ret) {
dev_err(hsotg->dev, "failed to request supplies: %d\n", ret);
if (ret != -EPROBE_DEFER)
dev_err(hsotg->dev, "failed to request supplies: %d\n",
ret);
return ret;
}
return 0;
@@ -312,6 +314,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 +469,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 +523,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 +539,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 +556,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 +608,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);
+13 -16
View File
@@ -289,12 +289,6 @@ done:
return 0;
}
static const struct clk_bulk_data dwc3_core_clks[] = {
{ .id = "ref" },
{ .id = "bus_early" },
{ .id = "suspend" },
};
/*
* dwc3_frame_length_adjustment - Adjusts frame length if required
* @dwc3: Pointer to our controller context structure
@@ -1029,6 +1023,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
if (dwc->dis_tx_ipgap_linecheck_quirk)
reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS;
if (dwc->parkmode_disable_ss_quirk)
reg |= DWC3_GUCTL1_PARKMODE_DISABLE_SS;
dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
}
@@ -1342,6 +1339,8 @@ static void dwc3_get_properties(struct dwc3 *dwc)
"snps,dis-del-phy-power-chg-quirk");
dwc->dis_tx_ipgap_linecheck_quirk = device_property_read_bool(dev,
"snps,dis-tx-ipgap-linecheck-quirk");
dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev,
"snps,parkmode-disable-ss-quirk");
dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
"snps,tx_de_emphasis_quirk");
@@ -1441,11 +1440,6 @@ static int dwc3_probe(struct platform_device *pdev)
if (!dwc)
return -ENOMEM;
dwc->clks = devm_kmemdup(dev, dwc3_core_clks, sizeof(dwc3_core_clks),
GFP_KERNEL);
if (!dwc->clks)
return -ENOMEM;
dwc->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1476,22 +1470,23 @@ static int dwc3_probe(struct platform_device *pdev)
dwc3_get_properties(dwc);
dwc->reset = devm_reset_control_get_optional_shared(dev, NULL);
dwc->reset = devm_reset_control_array_get(dev, true, true);
if (IS_ERR(dwc->reset))
return PTR_ERR(dwc->reset);
if (dev->of_node) {
dwc->num_clks = ARRAY_SIZE(dwc3_core_clks);
ret = devm_clk_bulk_get(dev, dwc->num_clks, dwc->clks);
ret = devm_clk_bulk_get_all(dev, &dwc->clks);
if (ret == -EPROBE_DEFER)
return ret;
/*
* Clocks are optional, but new DT platforms should support all
* clocks as required by the DT-binding.
*/
if (ret)
if (ret < 0)
dwc->num_clks = 0;
else
dwc->num_clks = ret;
}
ret = reset_control_deassert(dwc->reset);
@@ -1637,6 +1632,8 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
if (pm_runtime_suspended(dwc->dev))
break;
spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_suspend(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
+10
View File
@@ -25,6 +25,7 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/usb/role.h>
#include <linux/ulpi/interface.h>
#include <linux/phy/phy.h>
@@ -249,6 +250,7 @@
#define DWC3_GUCTL_HSTINAUTORETRY BIT(14)
/* Global User Control 1 Register */
#define DWC3_GUCTL1_PARKMODE_DISABLE_SS BIT(17)
#define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS BIT(28)
#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24)
@@ -953,6 +955,9 @@ struct dwc3_scratchpad_array {
* @hsphy_mode: UTMI phy mode, one of following:
* - USBPHY_INTERFACE_MODE_UTMI
* - USBPHY_INTERFACE_MODE_UTMIW
* @role_sw: usb_role_switch handle
* @role_switch_default_mode: default operation mode of controller while
* usb role is USB_ROLE_NONE.
* @usb2_phy: pointer to USB2 PHY
* @usb3_phy: pointer to USB3 PHY
* @usb2_generic_phy: pointer to USB2 PHY
@@ -1024,6 +1029,8 @@ struct dwc3_scratchpad_array {
* change quirk.
* @dis_tx_ipgap_linecheck_quirk: set if we disable u2mac linestate
* check during HS transmit.
* @parkmode_disable_ss_quirk: set if we need to disable all SuperSpeed
* instances in park mode.
* @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
* @tx_de_emphasis: Tx de-emphasis value
* 0 - -6dB de-emphasis
@@ -1086,6 +1093,8 @@ struct dwc3 {
struct extcon_dev *edev;
struct notifier_block edev_nb;
enum usb_phy_interface hsphy_mode;
struct usb_role_switch *role_sw;
enum usb_dr_mode role_switch_default_mode;
u32 fladj;
u32 irq_gadget;
@@ -1215,6 +1224,7 @@ struct dwc3 {
unsigned dis_u2_freeclk_exists_quirk:1;
unsigned dis_del_phy_power_chg_quirk:1;
unsigned dis_tx_ipgap_linecheck_quirk:1;
unsigned parkmode_disable_ss_quirk:1;
unsigned tx_de_emphasis_quirk:1;
unsigned tx_de_emphasis:2;
+95 -1
View File
@@ -476,6 +476,92 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
return edev;
}
#if IS_ENABLED(CONFIG_USB_ROLE_SWITCH)
#define ROLE_SWITCH 1
static int dwc3_usb_role_switch_set(struct device *dev, enum usb_role role)
{
struct dwc3 *dwc = dev_get_drvdata(dev);
u32 mode;
switch (role) {
case USB_ROLE_HOST:
mode = DWC3_GCTL_PRTCAP_HOST;
break;
case USB_ROLE_DEVICE:
mode = DWC3_GCTL_PRTCAP_DEVICE;
break;
default:
if (dwc->role_switch_default_mode == USB_DR_MODE_HOST)
mode = DWC3_GCTL_PRTCAP_HOST;
else
mode = DWC3_GCTL_PRTCAP_DEVICE;
break;
}
dwc3_set_mode(dwc, mode);
return 0;
}
static enum usb_role dwc3_usb_role_switch_get(struct device *dev)
{
struct dwc3 *dwc = dev_get_drvdata(dev);
unsigned long flags;
enum usb_role role;
spin_lock_irqsave(&dwc->lock, flags);
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_HOST:
role = USB_ROLE_HOST;
break;
case DWC3_GCTL_PRTCAP_DEVICE:
role = USB_ROLE_DEVICE;
break;
case DWC3_GCTL_PRTCAP_OTG:
role = dwc->current_otg_role;
break;
default:
if (dwc->role_switch_default_mode == USB_DR_MODE_HOST)
role = USB_ROLE_HOST;
else
role = USB_ROLE_DEVICE;
break;
}
spin_unlock_irqrestore(&dwc->lock, flags);
return role;
}
static int dwc3_setup_role_switch(struct dwc3 *dwc)
{
struct usb_role_switch_desc dwc3_role_switch = {NULL};
const char *str;
u32 mode;
int ret;
ret = device_property_read_string(dwc->dev, "role-switch-default-mode",
&str);
if (ret >= 0 && !strncmp(str, "host", strlen("host"))) {
dwc->role_switch_default_mode = USB_DR_MODE_HOST;
mode = DWC3_GCTL_PRTCAP_HOST;
} else {
dwc->role_switch_default_mode = USB_DR_MODE_PERIPHERAL;
mode = DWC3_GCTL_PRTCAP_DEVICE;
}
dwc3_role_switch.fwnode = dev_fwnode(dwc->dev);
dwc3_role_switch.set = dwc3_usb_role_switch_set;
dwc3_role_switch.get = dwc3_usb_role_switch_get;
dwc->role_sw = usb_role_switch_register(dwc->dev, &dwc3_role_switch);
if (IS_ERR(dwc->role_sw))
return PTR_ERR(dwc->role_sw);
dwc3_set_mode(dwc, mode);
return 0;
}
#else
#define ROLE_SWITCH 0
#define dwc3_setup_role_switch(x) 0
#endif
int dwc3_drd_init(struct dwc3 *dwc)
{
int ret, irq;
@@ -484,7 +570,12 @@ int dwc3_drd_init(struct dwc3 *dwc)
if (IS_ERR(dwc->edev))
return PTR_ERR(dwc->edev);
if (dwc->edev) {
if (ROLE_SWITCH &&
device_property_read_bool(dwc->dev, "usb-role-switch")) {
ret = dwc3_setup_role_switch(dwc);
if (ret < 0)
return ret;
} else if (dwc->edev) {
dwc->edev_nb.notifier_call = dwc3_drd_notifier;
ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
&dwc->edev_nb);
@@ -531,6 +622,9 @@ void dwc3_drd_exit(struct dwc3 *dwc)
{
unsigned long flags;
if (dwc->role_sw)
usb_role_switch_unregister(dwc->role_sw);
if (dwc->edev)
extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST,
&dwc->edev_nb);

Some files were not shown because too many files have changed in this diff Show More