USB/Thunderbolt driver changes for 6.2-rc1

Here is the large set of USB and Thunderbolt driver changes for 6.2-rc1.
 Overall, thanks to the removal of a driver, more lines were removed than
 added, a nice change.  Highlights include:
   - removal of the sisusbvga driver that was not used by anyone anymore
   - minor thunderbolt driver changes and tweaks
   - chipidea driver updates
   - usual set of typec driver features and hardware support added
   - musb minor driver fixes
   - fotg210 driver fixes, bringing that hardware back from the "dead"
   - minor dwc3 driver updates
   - addition, and then removal, of a list.h helper function for many USB
     and other subsystem drivers, that ended up breaking the build.  That
     will come back for 6.3-rc1, it missed this merge window.
   - usual xhci updates and enhancements
   - usb-serial driver updates and support for new devices
   - other minor USB driver updates
 
 All of these have been in linux-next for a while with no reported
 problems.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCY5wvYg8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+yl5DACgssl/ag4zDePHpfoiG5zEGEzH8XsAoMFrzvzu
 d43hsH3qsfDGSZRkJJMu
 =ORDd
 -----END PGP SIGNATURE-----

Merge tag 'usb-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB and Thunderbolt driver updates from Greg KH:
 "Here is the large set of USB and Thunderbolt driver changes for
  6.2-rc1. Overall, thanks to the removal of a driver, more lines were
  removed than added, a nice change. Highlights include:

   - removal of the sisusbvga driver that was not used by anyone anymore

   - minor thunderbolt driver changes and tweaks

   - chipidea driver updates

   - usual set of typec driver features and hardware support added

   - musb minor driver fixes

   - fotg210 driver fixes, bringing that hardware back from the "dead"

   - minor dwc3 driver updates

   - addition, and then removal, of a list.h helper function for many
     USB and other subsystem drivers, that ended up breaking the build.
     That will come back for 6.3-rc1, it missed this merge window.

   - usual xhci updates and enhancements

   - usb-serial driver updates and support for new devices

   - other minor USB driver updates

  All of these have been in linux-next for a while with no reported
  problems"

* tag 'usb-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (153 commits)
  usb: gadget: uvc: Rename bmInterfaceFlags -> bmInterlaceFlags
  usb: dwc2: power on/off phy for peripheral mode in dual-role mode
  usb: dwc2: disable lpm feature on Rockchip SoCs
  dt-bindings: usb: mtk-xhci: add support for mt7986
  usb: dwc3: core: defer probe on ulpi_read_id timeout
  usb: ulpi: defer ulpi_register on ulpi_read_id timeout
  usb: misc: onboard_usb_hub: add Genesys Logic GL850G hub support
  dt-bindings: usb: Add binding for Genesys Logic GL850G hub controller
  dt-bindings: vendor-prefixes: add Genesys Logic
  usb: fotg210-udc: fix potential memory leak in fotg210_udc_probe()
  usb: typec: tipd: Set mode of operation for USB Type-C connector
  usb: gadget: udc: drop obsolete dependencies on COMPILE_TEST
  usb: musb: remove extra check in musb_gadget_vbus_draw
  usb: gadget: uvc: Prevent buffer overflow in setup handler
  usb: dwc3: qcom: Fix memory leak in dwc3_qcom_interconnect_init
  usb: typec: wusb3801: fix fwnode refcount leak in wusb3801_probe()
  usb: storage: Add check for kcalloc
  USB: sisusbvga: use module_usb_driver()
  USB: sisusbvga: rename sisusb.c to sisusbvga.c
  USB: sisusbvga: remove console support
  ...
This commit is contained in:
Linus Torvalds 2022-12-16 03:22:53 -08:00
commit 58bcac11fd
163 changed files with 2084 additions and 7054 deletions

View File

@ -197,7 +197,7 @@ Description: Specific MJPEG format descriptors
read-only
bmaControls this format's data for bmaControls in
the streaming header
bmInterfaceFlags specifies interlace information,
bmInterlaceFlags specifies interlace information,
read-only
bAspectRatioY the X dimension of the picture aspect
ratio, read-only
@ -253,7 +253,7 @@ Description: Specific uncompressed format descriptors
read-only
bmaControls this format's data for bmaControls in
the streaming header
bmInterfaceFlags specifies interlace information,
bmInterlaceFlags specifies interlace information,
read-only
bAspectRatioY the X dimension of the picture aspect
ratio, read-only

View File

@ -264,6 +264,17 @@ Description:
attached to the port will not be detected, initialized,
or enumerated.
What: /sys/bus/usb/devices/.../<hub_interface>/port<X>/early_stop
Date: Sep 2022
Contact: Ray Chi <raychi@google.com>
Description:
Some USB hosts have some watchdog mechanisms so that the device
may enter ramdump if it takes a long time during port initialization.
This attribute allows each port just has two attempts so that the
port initialization will be failed quickly. In addition, if a port
which is marked with early_stop has failed to initialize, it will ignore
all future connections until this attribute is clear.
What: /sys/bus/usb/devices/.../power/usb2_lpm_l1_timeout
Date: May 2013
Contact: Mathias Nyman <mathias.nyman@linux.intel.com>

View File

@ -28,6 +28,9 @@ properties:
items:
- const: phy
power-domains:
maxItems: 1
vbus-supply:
description:
A phandle to the regulator for USB VBUS.

View File

@ -43,7 +43,10 @@ properties:
- const: rockchip,rk3066-usb
- const: snps,dwc2
- const: lantiq,arx100-usb
- const: lantiq,ase-usb
- const: lantiq,danube-usb
- const: lantiq,xrx200-usb
- const: lantiq,xrx300-usb
- items:
- enum:
- amlogic,meson8-usb

View File

@ -0,0 +1,48 @@
# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/usb/genesys,gl850g.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Genesys Logic GL850G USB 2.0 hub controller
maintainers:
- Icenowy Zheng <uwu@icenowy.me>
allOf:
- $ref: usb-device.yaml#
properties:
compatible:
enum:
- usb5e3,608
reg: true
reset-gpios:
description: GPIO controlling the RESET# pin.
vdd-supply:
description:
the regulator that provides 3.3V core power to the hub.
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
usb {
dr_mode = "host";
#address-cells = <1>;
#size-cells = <0>;
hub: hub@1 {
compatible = "usb5e3,608";
reg = <1>;
reset-gpios = <&pio 7 2 GPIO_ACTIVE_LOW>;
};
};

View File

@ -28,6 +28,7 @@ properties:
- mediatek,mt7622-xhci
- mediatek,mt7623-xhci
- mediatek,mt7629-xhci
- mediatek,mt7986-xhci
- mediatek,mt8173-xhci
- mediatek,mt8183-xhci
- mediatek,mt8186-xhci

View File

@ -24,6 +24,7 @@ properties:
- mediatek,mt2712-mtu3
- mediatek,mt8173-mtu3
- mediatek,mt8183-mtu3
- mediatek,mt8186-mtu3
- mediatek,mt8188-mtu3
- mediatek,mt8192-mtu3
- mediatek,mt8195-mtu3

View File

@ -39,6 +39,7 @@ properties:
- qcom,sm8250-dwc3
- qcom,sm8350-dwc3
- qcom,sm8450-dwc3
- qcom,sm8550-dwc3
- const: qcom,dwc3
reg:
@ -301,6 +302,7 @@ allOf:
- qcom,sm8150-dwc3
- qcom,sm8250-dwc3
- qcom,sm8450-dwc3
- qcom,sm8550-dwc3
then:
properties:
clocks:
@ -358,6 +360,7 @@ allOf:
- qcom,sm8250-dwc3
- qcom,sm8350-dwc3
- qcom,sm8450-dwc3
- qcom,sm8550-dwc3
then:
properties:
interrupts:

View File

@ -27,6 +27,7 @@ properties:
should default to OTG.
$ref: /schemas/types.yaml#/definitions/string
enum: [host, peripheral, otg]
default: otg
hnp-disable:
description:

View File

@ -39,6 +39,11 @@ properties:
the VBus line.
$ref: /schemas/types.yaml#/definitions/phandle
wakeup-source:
description:
Specify if the USB phy can detect the remote wakeup signal
while the system sleep.
required:
- compatible
- '#phy-cells'

View File

@ -1,89 +0,0 @@
Microchip USB 2.0 Hi-Speed Hub Controller
The device node for the configuration of a Microchip USB251x/xBi USB 2.0
Hi-Speed Controller.
Required properties :
- compatible : Should be "microchip,usb251xb" or one of the specific types:
"microchip,usb2512b", "microchip,usb2512bi", "microchip,usb2513b",
"microchip,usb2513bi", "microchip,usb2514b", "microchip,usb2514bi",
"microchip,usb2517", "microchip,usb2517i", "microchip,usb2422"
- reg : I2C address on the selected bus (default is <0x2C>)
Optional properties :
- reset-gpios : Should specify the gpio for hub reset
- vdd-supply : Should specify the phandle to the regulator supplying vdd
- skip-config : Skip Hub configuration, but only send the USB-Attach command
- vendor-id : Set USB Vendor ID of the hub (16 bit, default is 0x0424)
- product-id : Set USB Product ID of the hub (16 bit, default depends on type)
- device-id : Set USB Device ID of the hub (16 bit, default is 0x0bb3)
- language-id : Set USB Language ID (16 bit, default is 0x0000)
- manufacturer : Set USB Manufacturer string (max 31 characters long)
- product : Set USB Product string (max 31 characters long)
- serial : Set USB Serial string (max 31 characters long)
- {bus,self}-powered : selects between self- and bus-powered operation
(boolean, default is self-powered)
- disable-hi-speed : disable USB Hi-Speed support (boolean)
- {multi,single}-tt : selects between multi- and single-transaction-translator
(boolean, default is multi-tt)
- disable-eop : disable End of Packet generation in full-speed mode (boolean)
- {ganged,individual}-sensing : select over-current sense type in self-powered
mode (boolean, default is individual)
- {ganged,individual}-port-switching : select port power switching mode
(boolean, default is individual)
- dynamic-power-switching : enable auto-switching from self- to bus-powered
operation if the local power source is removed or unavailable (boolean)
- oc-delay-us : Delay time (in microseconds) for filtering the over-current
sense inputs. Valid values are 100, 4000, 8000 (default) and 16000. If
an invalid value is given, the default is used instead.
- compound-device : indicate the hub is part of a compound device (boolean)
- port-mapping-mode : enable port mapping mode (boolean)
- led-{usb,speed}-mode : led usb/speed indication mode selection
(boolean, default is speed mode)
- string-support : enable string descriptor support (required for manufacturer,
product and serial string configuration)
- non-removable-ports : Should specify the ports which have a non-removable
device connected.
- sp-disabled-ports : Specifies the ports which will be self-power disabled
- bp-disabled-ports : Specifies the ports which will be bus-power disabled
- sp-max-total-current-microamp: Specifies max current consumed by the hub
from VBUS when operating in self-powered hub. It includes the hub
silicon along with all associated circuitry including a permanently
attached peripheral (range: 0 - 100000 uA, default 1000 uA)
- bp-max-total-current-microamp: Specifies max current consumed by the hub
from VBUS when operating in self-powered hub. It includes the hub
silicon along with all associated circuitry including a permanently
attached peripheral (range: 0 - 510000 uA, default 100000 uA)
- sp-max-removable-current-microamp: Specifies max current consumed by the hub
from VBUS when operating in self-powered hub. It includes the hub
silicon along with all associated circuitry excluding a permanently
attached peripheral (range: 0 - 100000 uA, default 1000 uA)
- bp-max-removable-current-microamp: Specifies max current consumed by the hub
from VBUS when operating in self-powered hub. It includes the hub
silicon along with all associated circuitry excluding a permanently
attached peripheral (range: 0 - 510000 uA, default 100000 uA)
- power-on-time-ms : Specifies the time it takes from the time the host
initiates the power-on sequence to a port until the port has adequate
power. The value is given in ms in a 0 - 510 range (default is 100ms).
- swap-dx-lanes : Specifies the ports which will swap the differential-pair
(D+/D-), default is not-swapped.
Examples:
usb2512b@2c {
compatible = "microchip,usb2512b";
reg = <0x2c>;
reset-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
};
usb2514b@2c {
compatible = "microchip,usb2514b";
reg = <0x2c>;
vendor-id = /bits/ 16 <0x0000>;
product-id = /bits/ 16 <0x0000>;
string-support;
manufacturer = "Foo";
product = "Foo-Bar";
serial = "1234567890A";
/* correct misplaced usb connectors on port 1,2 */
swap-dx-lanes = <1 2>;
};

View File

@ -0,0 +1,271 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/usb/usb251xb.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Microchip USB 2.0 Hi-Speed Hub Controller
maintainers:
- Richard Leitner <richard.leitner@skidata.com>
properties:
compatible:
enum:
- microchip,usb2422
- microchip,usb2512b
- microchip,usb2512bi
- microchip,usb2513b
- microchip,usb2513bi
- microchip,usb2514b
- microchip,usb2514bi
- microchip,usb2517
- microchip,usb2517i
- microchip,usb251xb
reg:
maxItems: 1
reset-gpios:
description: |
Should specify the gpio for hub reset
vdd-supply:
description: |
Should specify the phandle to the regulator supplying vdd
skip-config:
$ref: /schemas/types.yaml#/definitions/flag
description: |
Skip Hub configuration, but only send the USB-Attach command
vendor-id:
$ref: /schemas/types.yaml#/definitions/uint16
default: 0x0424
description: |
Set USB Vendor ID of the hub
product-id:
$ref: /schemas/types.yaml#/definitions/uint16
description: |
Set USB Product ID of the hub
device-id:
$ref: /schemas/types.yaml#/definitions/uint16
default: 0x0bb3
description: |
Set USB Device ID of the hub
language-id:
$ref: /schemas/types.yaml#/definitions/uint16
default: 0x0000
description: |
Set USB Language ID
manufacturer:
$ref: /schemas/types.yaml#/definitions/string
description: |
Set USB Manufacturer string (max 31 characters long)
product:
$ref: /schemas/types.yaml#/definitions/string
description: |
Set USB Product string (max 31 characters long)
serial:
$ref: /schemas/types.yaml#/definitions/string
description: |
Set USB Serial string (max 31 characters long)
bus-powered:
$ref: /schemas/types.yaml#/definitions/flag
description: |
selects between self- and bus-powered operation
(boolean, default is self-powered)
self-powered:
$ref: /schemas/types.yaml#/definitions/flag
description: |
selects between self- and bus-powered operation
(boolean, default is self-powered)
disable-hi-speed:
$ref: /schemas/types.yaml#/definitions/flag
description: |
disable USB Hi-Speed support (boolean)
multi-tt:
$ref: /schemas/types.yaml#/definitions/flag
description: |
selects between multi- and single-transaction-translator
(boolean, default is multi-tt)
single-tt:
$ref: /schemas/types.yaml#/definitions/flag
description: |
selects between multi- and single-transaction-translator
(boolean, default is multi-tt)
disable-eop:
$ref: /schemas/types.yaml#/definitions/flag
description: |
disable End of Packet generation in full-speed mode (boolean)
ganged-sensing:
$ref: /schemas/types.yaml#/definitions/flag
description: |
select over-current sense type in self-powered mode
(boolean, default is individual)
individual-sensing:
$ref: /schemas/types.yaml#/definitions/flag
description: |
select over-current sense type in self-powered mode
(boolean, default is individual)
ganged-port-switching:
$ref: /schemas/types.yaml#/definitions/flag
description: |
select port power switching mode (boolean, default is individual)
individual-port-switching:
$ref: /schemas/types.yaml#/definitions/flag
description: |
select port power switching mode (boolean, default is individual)
dynamic-power-switching:
$ref: /schemas/types.yaml#/definitions/flag
description: |
enable auto-switching from self- to bus-powered operation if the
local power source is removed or unavailable (boolean)
oc-delay-us:
enum: [100, 4000, 8000, 16000]
default: 8000
description: |
Delay time (in microseconds) for filtering the over-current sense
inputs. If an invalid value is given, the default is used instead.
compound-device:
$ref: /schemas/types.yaml#/definitions/flag
description: |
indicate the hub is part of a compound device (boolean)
port-mapping-mode:
$ref: /schemas/types.yaml#/definitions/flag
description: |
enable port mapping mode (boolean)
led-usb-mode:
$ref: /schemas/types.yaml#/definitions/flag
description: |
led usb/speed indication mode selection (boolean, default is speed mode)
led-speed-mode:
$ref: /schemas/types.yaml#/definitions/flag
description: |
led usb/speed indication mode selection (boolean, default is speed mode)
string-support:
$ref: /schemas/types.yaml#/definitions/flag
description: |
enable string descriptor support (required for manufacturer, product
and serial string configuration)
non-removable-ports:
$ref: /schemas/types.yaml#/definitions/uint8-array
description: |
Should specify the ports which have a non-removable device connected.
sp-disabled-ports:
$ref: /schemas/types.yaml#/definitions/uint8-array
description: |
Specifies the ports which will be self-power disabled
bp-disabled-ports:
$ref: /schemas/types.yaml#/definitions/uint8-array
description: |
Specifies the ports which will be bus-power disabled
sp-max-total-current-microamp:
maximum: 100000
default: 1000
description: |
Specifies max current consumed by the hub from VBUS when
operating in self-powered hub. It includes the hub silicon
along with all associated circuitry including a permanently
attached peripheral.
bp-max-total-current-microamp:
maximum: 510000
default: 100000
description: |
Specifies max current consumed by the hub from VBUS when
operating in self-powered hub. It includes the hub silicon
along with all associated circuitry including a permanently
attached peripheral.
sp-max-removable-current-microamp:
maximum: 100000
default: 1000
description: |
Specifies max current consumed by the hub from VBUS when
operating in self-powered hub. It includes the hub silicon
along with all associated circuitry excluding a permanently
attached peripheral.
bp-max-removable-current-microamp:
maximum: 510000
default: 100000
description: |
Specifies max current consumed by the hub from VBUS when
operating in self-powered hub. It includes the hub silicon
along with all associated circuitry excluding a permanently
attached peripheral.
power-on-time-ms:
maximum: 510
default: 100
description: |
Specifies the time it takes from the time the host initiates the
power-on sequence to a port until the port has adequate power.
swap-dx-lanes:
$ref: /schemas/types.yaml#/definitions/uint8-array
description: |
Specifies the ports which will swap the differential-pair (D+/D-),
default is not-swapped.
additionalProperties: false
required:
- compatible
- reg
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
usb-hub@2c {
compatible = "microchip,usb2512b";
reg = <0x2c>;
reset-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
};
usb-hub@2d {
compatible = "microchip,usb2514b";
reg = <0x2d>;
vendor-id = /bits/ 16 <0x0000>;
product-id = /bits/ 16 <0x0000>;
string-support;
manufacturer = "Foo";
product = "Foo-Bar";
serial = "1234567890A";
/* correct misplaced usb connectors on port 1,2 */
swap-dx-lanes = <1 2>;
};
};

View File

@ -494,6 +494,8 @@ patternProperties:
description: GE Fanuc Intelligent Platforms Embedded Systems, Inc.
"^gemei,.*":
description: Gemei Digital Technology Co., Ltd.
"^genesys,.*":
description: Genesys Logic, Inc.
"^geniatech,.*":
description: Geniatech, Inc.
"^giantec,.*":

View File

@ -395,6 +395,8 @@ PCI
PHY
devm_usb_get_phy()
devm_usb_get_phy_by_node()
devm_usb_get_phy_by_phandle()
devm_usb_put_phy()
PINCTRL

View File

@ -7935,6 +7935,12 @@ F: fs/notify/fanotify/
F: include/linux/fanotify.h
F: include/uapi/linux/fanotify.h
FARADAY FOTG210 USB2 DUAL-ROLE CONTROLLER
M: Linus Walleij <linus.walleij@linaro.org>
L: linux-usb@vger.kernel.org
S: Maintained
F: drivers/usb/fotg210/
FARSYNC SYNCHRONOUS DRIVER
M: Kevin Curtis <kevin.curtis@farsite.co.uk>
S: Supported
@ -13795,7 +13801,7 @@ MICROCHIP USB251XB DRIVER
M: Richard Leitner <richard.leitner@skidata.com>
L: linux-usb@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/usb/usb251xb.txt
F: Documentation/devicetree/bindings/usb/usb251xb.yaml
F: drivers/usb/misc/usb251xb.c
MICROCHIP USBA UDC DRIVER

View File

@ -911,7 +911,6 @@ CONFIG_USB_IDMOUSE=m
CONFIG_USB_FTDI_ELAN=m
CONFIG_USB_APPLEDISPLAY=m
CONFIG_USB_SISUSBVGA=m
CONFIG_USB_SISUSBVGA_CON=y
CONFIG_USB_LD=m
CONFIG_USB_TRANCEVIBRATOR=m
CONFIG_USB_IOWARRIOR=m

View File

@ -92,7 +92,6 @@ CONFIG_USB_SERIAL_PL2303=m
CONFIG_USB_EMI62=m
CONFIG_USB_EMI26=m
CONFIG_USB_SISUSBVGA=m
CONFIG_USB_SISUSBVGA_CON=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set

View File

@ -313,9 +313,9 @@ static void tusb320_typec_irq_handler(struct tusb320_priv *priv, u8 reg9)
typec_set_pwr_opmode(port, TYPEC_PWR_MODE_USB);
}
static irqreturn_t tusb320_irq_handler(int irq, void *dev_id)
static irqreturn_t tusb320_state_update_handler(struct tusb320_priv *priv,
bool force_update)
{
struct tusb320_priv *priv = dev_id;
unsigned int reg;
if (regmap_read(priv->regmap, TUSB320_REG9, &reg)) {
@ -323,7 +323,7 @@ static irqreturn_t tusb320_irq_handler(int irq, void *dev_id)
return IRQ_NONE;
}
if (!(reg & TUSB320_REG9_INTERRUPT_STATUS))
if (!force_update && !(reg & TUSB320_REG9_INTERRUPT_STATUS))
return IRQ_NONE;
tusb320_extcon_irq_handler(priv, reg);
@ -340,6 +340,13 @@ static irqreturn_t tusb320_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
static irqreturn_t tusb320_irq_handler(int irq, void *dev_id)
{
struct tusb320_priv *priv = dev_id;
return tusb320_state_update_handler(priv, false);
}
static const struct regmap_config tusb320_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@ -466,7 +473,7 @@ static int tusb320_probe(struct i2c_client *client,
return ret;
/* update initial state */
tusb320_irq_handler(client->irq, priv);
tusb320_state_update_handler(priv, true);
/* Reset chip to its default state */
ret = tusb320_reset(priv);
@ -477,7 +484,7 @@ static int tusb320_probe(struct i2c_client *client,
* State and polarity might change after a reset, so update
* them again and make sure the interrupt status bit is cleared.
*/
tusb320_irq_handler(client->irq, priv);
tusb320_state_update_handler(priv, true);
ret = devm_request_threaded_irq(priv->dev, client->irq, NULL,
tusb320_irq_handler,

View File

@ -971,7 +971,7 @@ static void cros_typec_register_partner_pdos(struct cros_typec_data *typec,
if (!resp->source_cap_count && !resp->sink_cap_count)
return;
port->partner_pd = usb_power_delivery_register(NULL, &desc);
port->partner_pd = typec_partner_usb_power_delivery_register(port->partner, &desc);
if (IS_ERR(port->partner_pd)) {
dev_warn(typec->dev, "Failed to register partner PD device, port: %d\n", port_num);
return;

View File

@ -15,24 +15,20 @@ static acpi_status tb_acpi_add_link(acpi_handle handle, u32 level, void *data,
void **return_value)
{
struct acpi_device *adev = acpi_fetch_acpi_dev(handle);
struct fwnode_reference_args args;
struct fwnode_handle *fwnode;
struct tb_nhi *nhi = data;
struct pci_dev *pdev;
struct device *dev;
int ret;
if (!adev)
return AE_OK;
fwnode = acpi_fwnode_handle(adev);
ret = fwnode_property_get_reference_args(fwnode, "usb4-host-interface",
NULL, 0, 0, &args);
if (ret)
fwnode = fwnode_find_reference(acpi_fwnode_handle(adev), "usb4-host-interface", 0);
if (IS_ERR(fwnode))
return AE_OK;
/* It needs to reference this NHI */
if (dev_fwnode(&nhi->pdev->dev) != args.fwnode)
if (dev_fwnode(&nhi->pdev->dev) != fwnode)
goto out_put;
/*
@ -100,7 +96,7 @@ static acpi_status tb_acpi_add_link(acpi_handle handle, u32 level, void *data,
}
out_put:
fwnode_handle_put(args.fwnode);
fwnode_handle_put(fwnode);
return AE_OK;
}

View File

@ -8,12 +8,13 @@
#include <linux/delay.h>
#include <linux/idr.h>
#include <linux/module.h>
#include <linux/nvmem-provider.h>
#include <linux/pm_runtime.h>
#include <linux/sched/signal.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/string_helpers.h>
#include "tb.h"
@ -644,7 +645,7 @@ static int __tb_port_enable(struct tb_port *port, bool enable)
if (ret)
return ret;
tb_port_dbg(port, "lane %sabled\n", enable ? "en" : "dis");
tb_port_dbg(port, "lane %s\n", str_enabled_disabled(enable));
return 0;
}

View File

@ -361,6 +361,8 @@ struct tb_regs_port_header {
#define PORT_CS_18_BE BIT(8)
#define PORT_CS_18_TCM BIT(9)
#define PORT_CS_18_CPS BIT(10)
#define PORT_CS_18_WOCS BIT(16)
#define PORT_CS_18_WODS BIT(17)
#define PORT_CS_18_WOU4S BIT(18)
#define PORT_CS_19 0x13
#define PORT_CS_19_PC BIT(3)

View File

@ -155,6 +155,8 @@ static inline int usb4_switch_op_data(struct tb_switch *sw, u16 opcode,
static void usb4_switch_check_wakes(struct tb_switch *sw)
{
bool wakeup_usb4 = false;
struct usb4_port *usb4;
struct tb_port *port;
bool wakeup = false;
u32 val;
@ -173,20 +175,31 @@ static void usb4_switch_check_wakes(struct tb_switch *sw)
wakeup = val & (ROUTER_CS_6_WOPS | ROUTER_CS_6_WOUS);
}
/* Check for any connected downstream ports for USB4 wake */
/*
* Check for any downstream ports for USB4 wake,
* connection wake and disconnection wake.
*/
tb_switch_for_each_port(sw, port) {
if (!tb_port_has_remote(port))
if (!port->cap_usb4)
continue;
if (tb_port_read(port, &val, TB_CFG_PORT,
port->cap_usb4 + PORT_CS_18, 1))
break;
tb_port_dbg(port, "USB4 wake: %s\n",
(val & PORT_CS_18_WOU4S) ? "yes" : "no");
tb_port_dbg(port, "USB4 wake: %s, connection wake: %s, disconnection wake: %s\n",
(val & PORT_CS_18_WOU4S) ? "yes" : "no",
(val & PORT_CS_18_WOCS) ? "yes" : "no",
(val & PORT_CS_18_WODS) ? "yes" : "no");
if (val & PORT_CS_18_WOU4S)
wakeup = true;
wakeup_usb4 = val & (PORT_CS_18_WOU4S | PORT_CS_18_WOCS |
PORT_CS_18_WODS);
usb4 = port->usb4;
if (device_may_wakeup(&usb4->dev) && wakeup_usb4)
pm_wakeup_event(&usb4->dev, 0);
wakeup |= wakeup_usb4;
}
if (wakeup)
@ -366,6 +379,7 @@ bool usb4_switch_lane_bonding_possible(struct tb_switch *sw)
*/
int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags)
{
struct usb4_port *usb4;
struct tb_port *port;
u64 route = tb_route(sw);
u32 val;
@ -395,10 +409,13 @@ int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags)
val |= PORT_CS_19_WOU4;
} else {
bool configured = val & PORT_CS_19_PC;
usb4 = port->usb4;
if ((flags & TB_WAKE_ON_CONNECT) && !configured)
if (((flags & TB_WAKE_ON_CONNECT) |
device_may_wakeup(&usb4->dev)) && !configured)
val |= PORT_CS_19_WOC;
if ((flags & TB_WAKE_ON_DISCONNECT) && configured)
if (((flags & TB_WAKE_ON_DISCONNECT) |
device_may_wakeup(&usb4->dev)) && configured)
val |= PORT_CS_19_WOD;
if ((flags & TB_WAKE_ON_USB4) && configured)
val |= PORT_CS_19_WOU4;

View File

@ -284,6 +284,9 @@ struct usb4_port *usb4_port_device_add(struct tb_port *port)
}
}
if (!tb_is_upstream_port(port))
device_set_wakeup_capable(&usb4->dev, true);
pm_runtime_no_callbacks(&usb4->dev);
pm_runtime_set_active(&usb4->dev);
pm_runtime_enable(&usb4->dev);

View File

@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/prandom.h>
#include <linux/string_helpers.h>
#include <linux/utsname.h>
#include <linux/uuid.h>
#include <linux/workqueue.h>
@ -341,7 +342,6 @@ static int tb_xdp_properties_request(struct tb_ctl *ctl, u64 route,
memcpy(&req.src_uuid, src_uuid, sizeof(*src_uuid));
memcpy(&req.dst_uuid, dst_uuid, sizeof(*dst_uuid));
len = 0;
data_len = 0;
do {
@ -1344,7 +1344,7 @@ static int tb_xdomain_bond_lanes_uuid_high(struct tb_xdomain *xd)
tb_port_update_credits(port);
tb_xdomain_update_link_attributes(xd);
dev_dbg(&xd->dev, "lane bonding %sabled\n", width == 2 ? "en" : "dis");
dev_dbg(&xd->dev, "lane bonding %s\n", str_enabled_disabled(width == 2));
return 0;
}

View File

@ -111,8 +111,12 @@ source "drivers/usb/usbip/Kconfig"
endif
comment "USB dual-mode controller drivers"
source "drivers/usb/cdns3/Kconfig"
source "drivers/usb/fotg210/Kconfig"
source "drivers/usb/mtu3/Kconfig"
source "drivers/usb/musb/Kconfig"

View File

@ -17,6 +17,8 @@ obj-$(CONFIG_USB_CDNS_SUPPORT) += cdns3/
obj-$(CONFIG_USB_CDNS3) += cdns3/
obj-$(CONFIG_USB_CDNSP_PCI) += cdns3/
obj-$(CONFIG_USB_FOTG210) += fotg210/
obj-$(CONFIG_USB_MON) += mon/
obj-$(CONFIG_USB_MTU3) += mtu3/

View File

@ -192,14 +192,12 @@ static void cdnsp_pci_remove(struct pci_dev *pdev)
if (pci_dev_run_wake(pdev))
pm_runtime_get_noresume(&pdev->dev);
if (!pci_is_enabled(func)) {
if (pci_is_enabled(func)) {
cdns_remove(cdnsp);
} else {
kfree(cdnsp);
goto pci_put;
}
cdns_remove(cdnsp);
pci_put:
pci_dev_put(func);
}

View File

@ -2006,10 +2006,11 @@ int cdnsp_queue_bulk_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq)
int cdnsp_queue_ctrl_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq)
{
u32 field, length_field, remainder;
u32 field, length_field, zlp = 0;
struct cdnsp_ep *pep = preq->pep;
struct cdnsp_ring *ep_ring;
int num_trbs;
u32 maxp;
int ret;
ep_ring = cdnsp_request_to_transfer_ring(pdev, preq);
@ -2019,26 +2020,33 @@ int cdnsp_queue_ctrl_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq)
/* 1 TRB for data, 1 for status */
num_trbs = (pdev->three_stage_setup) ? 2 : 1;
maxp = usb_endpoint_maxp(pep->endpoint.desc);
if (preq->request.zero && preq->request.length &&
(preq->request.length % maxp == 0)) {
num_trbs++;
zlp = 1;
}
ret = cdnsp_prepare_transfer(pdev, preq, num_trbs);
if (ret)
return ret;
/* If there's data, queue data TRBs */
if (pdev->ep0_expect_in)
field = TRB_TYPE(TRB_DATA) | TRB_IOC;
else
field = TRB_ISP | TRB_TYPE(TRB_DATA) | TRB_IOC;
if (preq->request.length > 0) {
remainder = cdnsp_td_remainder(pdev, 0, preq->request.length,
preq->request.length, preq, 1, 0);
field = TRB_TYPE(TRB_DATA);
length_field = TRB_LEN(preq->request.length) |
TRB_TD_SIZE(remainder) | TRB_INTR_TARGET(0);
if (zlp)
field |= TRB_CHAIN;
else
field |= TRB_IOC | (pdev->ep0_expect_in ? 0 : TRB_ISP);
if (pdev->ep0_expect_in)
field |= TRB_DIR_IN;
length_field = TRB_LEN(preq->request.length) |
TRB_TD_SIZE(zlp) | TRB_INTR_TARGET(0);
cdnsp_queue_trb(pdev, ep_ring, true,
lower_32_bits(preq->request.dma),
upper_32_bits(preq->request.dma), length_field,
@ -2046,6 +2054,20 @@ int cdnsp_queue_ctrl_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq)
TRB_SETUPID(pdev->setup_id) |
pdev->setup_speed);
if (zlp) {
field = TRB_TYPE(TRB_NORMAL) | TRB_IOC;
if (!pdev->ep0_expect_in)
field = TRB_ISP;
cdnsp_queue_trb(pdev, ep_ring, true,
lower_32_bits(preq->request.dma),
upper_32_bits(preq->request.dma), 0,
field | ep_ring->cycle_state |
TRB_SETUPID(pdev->setup_id) |
pdev->setup_speed);
}
pdev->ep0_stage = CDNSP_DATA_STAGE;
}

View File

@ -127,12 +127,16 @@ enum ci_revision {
* struct ci_role_driver - host/gadget role driver
* @start: start this role
* @stop: stop this role
* @suspend: system suspend handler for this role
* @resume: system resume handler for this role
* @irq: irq handler for this role
* @name: role name string (host/gadget)
*/
struct ci_role_driver {
int (*start)(struct ci_hdrc *);
void (*stop)(struct ci_hdrc *);
void (*suspend)(struct ci_hdrc *ci);
void (*resume)(struct ci_hdrc *ci, bool power_lost);
irqreturn_t (*irq)(struct ci_hdrc *);
const char *name;
};

View File

@ -355,7 +355,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
data->hsic_pad_regulator =
devm_regulator_get_optional(dev, "hsic");
if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) {
/* no pad regualator is needed */
/* no pad regulator is needed */
data->hsic_pad_regulator = NULL;
} else if (IS_ERR(data->hsic_pad_regulator))
return dev_err_probe(dev, PTR_ERR(data->hsic_pad_regulator),
@ -527,16 +527,19 @@ static void ci_hdrc_imx_shutdown(struct platform_device *pdev)
ci_hdrc_imx_remove(pdev);
}
static int __maybe_unused imx_controller_suspend(struct device *dev)
static int __maybe_unused imx_controller_suspend(struct device *dev,
pm_message_t msg)
{
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
int ret = 0;
dev_dbg(dev, "at %s\n", __func__);
ret = imx_usbmisc_hsic_set_clk(data->usbmisc_data, false);
ret = imx_usbmisc_suspend(data->usbmisc_data,
PMSG_IS_AUTO(msg) || device_may_wakeup(dev));
if (ret) {
dev_err(dev, "usbmisc hsic_set_clk failed, ret=%d\n", ret);
dev_err(dev,
"usbmisc suspend failed, ret=%d\n", ret);
return ret;
}
@ -549,7 +552,8 @@ static int __maybe_unused imx_controller_suspend(struct device *dev)
return 0;
}
static int __maybe_unused imx_controller_resume(struct device *dev)
static int __maybe_unused imx_controller_resume(struct device *dev,
pm_message_t msg)
{
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
int ret = 0;
@ -570,22 +574,15 @@ static int __maybe_unused imx_controller_resume(struct device *dev)
data->in_lpm = false;
ret = imx_usbmisc_set_wakeup(data->usbmisc_data, false);
ret = imx_usbmisc_resume(data->usbmisc_data,
PMSG_IS_AUTO(msg) || device_may_wakeup(dev));
if (ret) {
dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret);
dev_err(dev, "usbmisc resume failed, ret=%d\n", ret);
goto clk_disable;
}
ret = imx_usbmisc_hsic_set_clk(data->usbmisc_data, true);
if (ret) {
dev_err(dev, "usbmisc hsic_set_clk failed, ret=%d\n", ret);
goto hsic_set_clk_fail;
}
return 0;
hsic_set_clk_fail:
imx_usbmisc_set_wakeup(data->usbmisc_data, true);
clk_disable:
imx_disable_unprepare_clks(dev);
return ret;
@ -601,16 +598,7 @@ static int __maybe_unused ci_hdrc_imx_suspend(struct device *dev)
/* The core's suspend doesn't run */
return 0;
if (device_may_wakeup(dev)) {
ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true);
if (ret) {
dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n",
ret);
return ret;
}
}
ret = imx_controller_suspend(dev);
ret = imx_controller_suspend(dev, PMSG_SUSPEND);
if (ret)
return ret;
@ -624,7 +612,7 @@ static int __maybe_unused ci_hdrc_imx_resume(struct device *dev)
int ret;
pinctrl_pm_select_default_state(dev);
ret = imx_controller_resume(dev);
ret = imx_controller_resume(dev, PMSG_RESUME);
if (!ret && data->supports_runtime_pm) {
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
@ -637,25 +625,18 @@ static int __maybe_unused ci_hdrc_imx_resume(struct device *dev)
static int __maybe_unused ci_hdrc_imx_runtime_suspend(struct device *dev)
{
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
int ret;
if (data->in_lpm) {
WARN_ON(1);
return 0;
}
ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true);
if (ret) {
dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret);
return ret;
}
return imx_controller_suspend(dev);
return imx_controller_suspend(dev, PMSG_AUTO_SUSPEND);
}
static int __maybe_unused ci_hdrc_imx_runtime_resume(struct device *dev)
{
return imx_controller_resume(dev);
return imx_controller_resume(dev, PMSG_AUTO_RESUME);
}
static const struct dev_pm_ops ci_hdrc_imx_pm_ops = {

View File

@ -32,9 +32,9 @@ struct imx_usbmisc_data {
int imx_usbmisc_init(struct imx_usbmisc_data *data);
int imx_usbmisc_init_post(struct imx_usbmisc_data *data);
int imx_usbmisc_set_wakeup(struct imx_usbmisc_data *data, bool enabled);
int imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *data);
int imx_usbmisc_hsic_set_clk(struct imx_usbmisc_data *data, bool on);
int imx_usbmisc_charger_detection(struct imx_usbmisc_data *data, bool connect);
int imx_usbmisc_suspend(struct imx_usbmisc_data *data, bool wakeup);
int imx_usbmisc_resume(struct imx_usbmisc_data *data, bool wakeup);
#endif /* __DRIVER_USB_CHIPIDEA_CI_HDRC_IMX_H */

View File

@ -608,52 +608,59 @@ static int ci_usb_role_switch_set(struct usb_role_switch *sw,
enum usb_role role)
{
struct ci_hdrc *ci = usb_role_switch_get_drvdata(sw);
struct ci_hdrc_cable *cable = NULL;
enum usb_role current_role = ci_role_to_usb_role(ci);
enum ci_role ci_role = usb_role_to_ci_role(role);
unsigned long flags;
struct ci_hdrc_cable *cable;
if ((ci_role != CI_ROLE_END && !ci->roles[ci_role]) ||
(current_role == role))
return 0;
pm_runtime_get_sync(ci->dev);
/* Stop current role */
spin_lock_irqsave(&ci->lock, flags);
if (current_role == USB_ROLE_DEVICE)
cable = &ci->platdata->vbus_extcon;
else if (current_role == USB_ROLE_HOST)
if (role == USB_ROLE_HOST) {
cable = &ci->platdata->id_extcon;
if (cable) {
cable->changed = true;
cable->connected = false;
ci_irq(ci);
spin_unlock_irqrestore(&ci->lock, flags);
if (ci->wq && role != USB_ROLE_NONE)
flush_workqueue(ci->wq);
spin_lock_irqsave(&ci->lock, flags);
}
cable = NULL;
/* Start target role */
if (role == USB_ROLE_DEVICE)
cable = &ci->platdata->vbus_extcon;
else if (role == USB_ROLE_HOST)
cable = &ci->platdata->id_extcon;
if (cable) {
cable->changed = true;
cable->connected = true;
ci_irq(ci);
cable = &ci->platdata->vbus_extcon;
cable->changed = true;
cable->connected = false;
} else if (role == USB_ROLE_DEVICE) {
cable = &ci->platdata->id_extcon;
cable->changed = true;
cable->connected = false;
cable = &ci->platdata->vbus_extcon;
cable->changed = true;
cable->connected = true;
} else {
cable = &ci->platdata->id_extcon;
cable->changed = true;
cable->connected = false;
cable = &ci->platdata->vbus_extcon;
cable->changed = true;
cable->connected = false;
}
spin_unlock_irqrestore(&ci->lock, flags);
pm_runtime_put_sync(ci->dev);
ci_irq(ci);
return 0;
}
static enum ci_role ci_get_role(struct ci_hdrc *ci)
{
enum ci_role role;
if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) {
if (ci->is_otg) {
role = ci_otg_role(ci);
hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE);
} else {
/*
* If the controller is not OTG capable, but support
* role switch, the defalt role is gadget, and the
* user can switch it through debugfs.
*/
role = CI_ROLE_GADGET;
}
} else {
role = ci->roles[CI_ROLE_HOST] ? CI_ROLE_HOST
: CI_ROLE_GADGET;
}
return role;
}
static struct usb_role_switch_desc ci_role_switch = {
.set = ci_usb_role_switch_set,
.get = ci_usb_role_switch_get,
@ -1151,25 +1158,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
}
}
if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) {
if (ci->is_otg) {
ci->role = ci_otg_role(ci);
/* Enable ID change irq */
hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE);
} else {
/*
* If the controller is not OTG capable, but support
* role switch, the defalt role is gadget, and the
* user can switch it through debugfs.
*/
ci->role = CI_ROLE_GADGET;
}
} else {
ci->role = ci->roles[CI_ROLE_HOST]
? CI_ROLE_HOST
: CI_ROLE_GADGET;
}
ci->role = ci_get_role(ci);
if (!ci_otg_is_fsm_mode(ci)) {
/* only update vbus status for peripheral */
if (ci->role == CI_ROLE_GADGET) {
@ -1305,11 +1294,13 @@ static void ci_extcon_wakeup_int(struct ci_hdrc *ci)
cable_id = &ci->platdata->id_extcon;
cable_vbus = &ci->platdata->vbus_extcon;
if (!IS_ERR(cable_id->edev) && ci->is_otg &&
if ((!IS_ERR(cable_id->edev) || !IS_ERR(ci->role_switch))
&& ci->is_otg &&
(otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS))
ci_irq(ci);
if (!IS_ERR(cable_vbus->edev) && ci->is_otg &&
if ((!IS_ERR(cable_vbus->edev) || !IS_ERR(ci->role_switch))
&& ci->is_otg &&
(otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS))
ci_irq(ci);
}
@ -1373,6 +1364,10 @@ static int ci_suspend(struct device *dev)
return 0;
}
/* Extra routine per role before system suspend */
if (ci->role != CI_ROLE_END && ci_role(ci)->suspend)
ci_role(ci)->suspend(ci);
if (device_may_wakeup(dev)) {
if (ci_otg_is_fsm_mode(ci))
ci_otg_fsm_suspend_for_srp(ci);
@ -1386,11 +1381,38 @@ static int ci_suspend(struct device *dev)
return 0;
}
static void ci_handle_power_lost(struct ci_hdrc *ci)
{
enum ci_role role;
disable_irq_nosync(ci->irq);
if (!ci_otg_is_fsm_mode(ci)) {
role = ci_get_role(ci);
if (ci->role != role) {
ci_handle_id_switch(ci);
} else if (role == CI_ROLE_GADGET) {
if (ci->is_otg && hw_read_otgsc(ci, OTGSC_BSV))
usb_gadget_vbus_connect(&ci->gadget);
}
}
enable_irq(ci->irq);
}
static int ci_resume(struct device *dev)
{
struct ci_hdrc *ci = dev_get_drvdata(dev);
bool power_lost;
int ret;
/* Since ASYNCLISTADDR (host mode) and ENDPTLISTADDR (device
* mode) share the same register address. We can check if
* controller resume from power lost based on this address
* due to this register will be reset after power lost.
*/
power_lost = !hw_read(ci, OP_ENDPTLISTADDR, ~0);
if (device_may_wakeup(dev))
disable_irq_wake(ci->irq);
@ -1398,6 +1420,19 @@ static int ci_resume(struct device *dev)
if (ret)
return ret;
if (power_lost) {
/* shutdown and re-init for phy */
ci_usb_phy_exit(ci);
ci_usb_phy_init(ci);
}
/* Extra routine per role after system resume */
if (ci->role != CI_ROLE_END && ci_role(ci)->resume)
ci_role(ci)->resume(ci, power_lost);
if (power_lost)
ci_handle_power_lost(ci);
if (ci->supports_runtime_pm) {
pm_runtime_disable(dev);
pm_runtime_set_active(dev);

View File

@ -459,6 +459,18 @@ static void ci_hdrc_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
ci_hdrc_free_dma_aligned_buffer(urb);
}
#ifdef CONFIG_PM_SLEEP
static void ci_hdrc_host_suspend(struct ci_hdrc *ci)
{
ehci_suspend(ci->hcd, device_may_wakeup(ci->dev));
}
static void ci_hdrc_host_resume(struct ci_hdrc *ci, bool power_lost)
{
ehci_resume(ci->hcd, power_lost);
}
#endif
int ci_hdrc_host_init(struct ci_hdrc *ci)
{
struct ci_role_driver *rdrv;
@ -472,6 +484,10 @@ int ci_hdrc_host_init(struct ci_hdrc *ci)
rdrv->start = host_start;
rdrv->stop = host_stop;
#ifdef CONFIG_PM_SLEEP
rdrv->suspend = ci_hdrc_host_suspend;
rdrv->resume = ci_hdrc_host_resume;
#endif
rdrv->irq = host_irq;
rdrv->name = "host";
ci->roles[CI_ROLE_HOST] = rdrv;

View File

@ -165,7 +165,7 @@ static int hw_wait_vbus_lower_bsv(struct ci_hdrc *ci)
return 0;
}
static void ci_handle_id_switch(struct ci_hdrc *ci)
void ci_handle_id_switch(struct ci_hdrc *ci)
{
enum ci_role role = ci_otg_role(ci);

View File

@ -14,6 +14,7 @@ int ci_hdrc_otg_init(struct ci_hdrc *ci);
void ci_hdrc_otg_destroy(struct ci_hdrc *ci);
enum ci_role ci_otg_role(struct ci_hdrc *ci);
void ci_handle_vbus_change(struct ci_hdrc *ci);
void ci_handle_id_switch(struct ci_hdrc *ci);
static inline void ci_otg_queue_work(struct ci_hdrc *ci)
{
disable_irq_nosync(ci->irq);

View File

@ -2181,6 +2181,34 @@ static void udc_id_switch_for_host(struct ci_hdrc *ci)
ci->platdata->pins_default);
}
#ifdef CONFIG_PM_SLEEP
static void udc_suspend(struct ci_hdrc *ci)
{
/*
* Set OP_ENDPTLISTADDR to be non-zero for
* checking if controller resume from power lost
* in non-host mode.
*/
if (hw_read(ci, OP_ENDPTLISTADDR, ~0) == 0)
hw_write(ci, OP_ENDPTLISTADDR, ~0, ~0);
}
static void udc_resume(struct ci_hdrc *ci, bool power_lost)
{
if (power_lost) {
if (ci->is_otg)
hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE,
OTGSC_BSVIS | OTGSC_BSVIE);
if (ci->vbus_active)
usb_gadget_vbus_disconnect(&ci->gadget);
}
/* Restore value 0 if it was set for power lost check */
if (hw_read(ci, OP_ENDPTLISTADDR, ~0) == 0xFFFFFFFF)
hw_write(ci, OP_ENDPTLISTADDR, ~0, 0);
}
#endif
/**
* ci_hdrc_gadget_init - initialize device related bits
* @ci: the controller
@ -2201,6 +2229,10 @@ int ci_hdrc_gadget_init(struct ci_hdrc *ci)
rdrv->start = udc_id_switch_for_device;
rdrv->stop = udc_id_switch_for_host;
#ifdef CONFIG_PM_SLEEP
rdrv->suspend = udc_suspend;
rdrv->resume = udc_resume;
#endif
rdrv->irq = udc_irq;
rdrv->name = "gadget";

View File

@ -150,6 +150,8 @@ struct usbmisc_ops {
int (*hsic_set_clk)(struct imx_usbmisc_data *data, bool enabled);
/* usb charger detection */
int (*charger_detection)(struct imx_usbmisc_data *data);
/* It's called when system resume from usb power lost */
int (*power_lost_check)(struct imx_usbmisc_data *data);
};
struct imx_usbmisc {
@ -937,6 +939,44 @@ static int usbmisc_imx7ulp_init(struct imx_usbmisc_data *data)
return 0;
}
static int usbmisc_imx7d_power_lost_check(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
unsigned long flags;
u32 val;
spin_lock_irqsave(&usbmisc->lock, flags);
val = readl(usbmisc->base);
spin_unlock_irqrestore(&usbmisc->lock, flags);
/*
* Here use a power on reset value to judge
* if the controller experienced a power lost
*/
if (val == 0x30001000)
return 1;
else
return 0;
}
static int usbmisc_imx6sx_power_lost_check(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
unsigned long flags;
u32 val;
spin_lock_irqsave(&usbmisc->lock, flags);
val = readl(usbmisc->base + data->index * 4);
spin_unlock_irqrestore(&usbmisc->lock, flags);
/*
* Here use a power on reset value to judge
* if the controller experienced a power lost
*/
if (val == 0x30001000)
return 1;
else
return 0;
}
static const struct usbmisc_ops imx25_usbmisc_ops = {
.init = usbmisc_imx25_init,
.post = usbmisc_imx25_post,
@ -970,12 +1010,14 @@ static const struct usbmisc_ops imx6sx_usbmisc_ops = {
.init = usbmisc_imx6sx_init,
.hsic_set_connect = usbmisc_imx6_hsic_set_connect,
.hsic_set_clk = usbmisc_imx6_hsic_set_clk,
.power_lost_check = usbmisc_imx6sx_power_lost_check,
};
static const struct usbmisc_ops imx7d_usbmisc_ops = {
.init = usbmisc_imx7d_init,
.set_wakeup = usbmisc_imx7d_set_wakeup,
.charger_detection = imx7d_charger_detection,
.power_lost_check = usbmisc_imx7d_power_lost_check,
};
static const struct usbmisc_ops imx7ulp_usbmisc_ops = {
@ -983,6 +1025,7 @@ static const struct usbmisc_ops imx7ulp_usbmisc_ops = {
.set_wakeup = usbmisc_imx7d_set_wakeup,
.hsic_set_connect = usbmisc_imx6_hsic_set_connect,
.hsic_set_clk = usbmisc_imx6_hsic_set_clk,
.power_lost_check = usbmisc_imx7d_power_lost_check,
};
static inline bool is_imx53_usbmisc(struct imx_usbmisc_data *data)
@ -1009,31 +1052,30 @@ EXPORT_SYMBOL_GPL(imx_usbmisc_init);
int imx_usbmisc_init_post(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc;
int ret = 0;
if (!data)
return 0;
usbmisc = dev_get_drvdata(data->dev);
if (!usbmisc->ops->post)
return 0;
return usbmisc->ops->post(data);
if (usbmisc->ops->post)
ret = usbmisc->ops->post(data);
if (ret) {
dev_err(data->dev, "post init failed, ret=%d\n", ret);
return ret;
}
if (usbmisc->ops->set_wakeup)
ret = usbmisc->ops->set_wakeup(data, false);
if (ret) {
dev_err(data->dev, "set_wakeup failed, ret=%d\n", ret);
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(imx_usbmisc_init_post);
int imx_usbmisc_set_wakeup(struct imx_usbmisc_data *data, bool enabled)
{
struct imx_usbmisc *usbmisc;
if (!data)
return 0;
usbmisc = dev_get_drvdata(data->dev);
if (!usbmisc->ops->set_wakeup)
return 0;
return usbmisc->ops->set_wakeup(data, enabled);
}
EXPORT_SYMBOL_GPL(imx_usbmisc_set_wakeup);
int imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc;
@ -1048,20 +1090,6 @@ int imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *data)
}
EXPORT_SYMBOL_GPL(imx_usbmisc_hsic_set_connect);
int imx_usbmisc_hsic_set_clk(struct imx_usbmisc_data *data, bool on)
{
struct imx_usbmisc *usbmisc;
if (!data)
return 0;
usbmisc = dev_get_drvdata(data->dev);
if (!usbmisc->ops->hsic_set_clk || !data->hsic)
return 0;
return usbmisc->ops->hsic_set_clk(data, on);
}
EXPORT_SYMBOL_GPL(imx_usbmisc_hsic_set_clk);
int imx_usbmisc_charger_detection(struct imx_usbmisc_data *data, bool connect)
{
struct imx_usbmisc *usbmisc;
@ -1094,6 +1122,78 @@ int imx_usbmisc_charger_detection(struct imx_usbmisc_data *data, bool connect)
}
EXPORT_SYMBOL_GPL(imx_usbmisc_charger_detection);
int imx_usbmisc_suspend(struct imx_usbmisc_data *data, bool wakeup)
{
struct imx_usbmisc *usbmisc;
int ret = 0;
if (!data)
return 0;
usbmisc = dev_get_drvdata(data->dev);
if (wakeup && usbmisc->ops->set_wakeup)
ret = usbmisc->ops->set_wakeup(data, true);
if (ret) {
dev_err(data->dev, "set_wakeup failed, ret=%d\n", ret);
return ret;
}
if (usbmisc->ops->hsic_set_clk && data->hsic)
ret = usbmisc->ops->hsic_set_clk(data, false);
if (ret) {
dev_err(data->dev, "set_wakeup failed, ret=%d\n", ret);
return ret;
}
return ret;
}
EXPORT_SYMBOL_GPL(imx_usbmisc_suspend);
int imx_usbmisc_resume(struct imx_usbmisc_data *data, bool wakeup)
{
struct imx_usbmisc *usbmisc;
int ret = 0;
if (!data)
return 0;
usbmisc = dev_get_drvdata(data->dev);
if (usbmisc->ops->power_lost_check)
ret = usbmisc->ops->power_lost_check(data);
if (ret > 0) {
/* re-init if resume from power lost */
ret = imx_usbmisc_init(data);
if (ret) {
dev_err(data->dev, "re-init failed, ret=%d\n", ret);
return ret;
}
}
if (wakeup && usbmisc->ops->set_wakeup)
ret = usbmisc->ops->set_wakeup(data, false);
if (ret) {
dev_err(data->dev, "set_wakeup failed, ret=%d\n", ret);
return ret;
}
if (usbmisc->ops->hsic_set_clk && data->hsic)
ret = usbmisc->ops->hsic_set_clk(data, true);
if (ret) {
dev_err(data->dev, "set_wakeup failed, ret=%d\n", ret);
goto hsic_set_clk_fail;
}
return 0;
hsic_set_clk_fail:
if (wakeup && usbmisc->ops->set_wakeup)
usbmisc->ops->set_wakeup(data, true);
return ret;
}
EXPORT_SYMBOL_GPL(imx_usbmisc_resume);
static const struct of_device_id usbmisc_imx_dt_ids[] = {
{
.compatible = "fsl,imx25-usbmisc",

View File

@ -207,7 +207,7 @@ static int ulpi_read_id(struct ulpi *ulpi)
/* Test the interface */
ret = ulpi_write(ulpi, ULPI_SCRATCH, 0xaa);
if (ret < 0)
goto err;
return ret;
ret = ulpi_read(ulpi, ULPI_SCRATCH);
if (ret < 0)

View File

@ -61,7 +61,7 @@ static void usb_parse_ssp_isoc_endpoint_companion(struct device *ddev,
desc = (struct usb_ssp_isoc_ep_comp_descriptor *) buffer;
if (desc->bDescriptorType != USB_DT_SSP_ISOC_ENDPOINT_COMP ||
size < USB_DT_SSP_ISOC_EP_COMP_SIZE) {
dev_warn(ddev, "Invalid SuperSpeedPlus isoc endpoint companion"
dev_notice(ddev, "Invalid SuperSpeedPlus isoc endpoint companion"
"for config %d interface %d altsetting %d ep %d.\n",
cfgno, inum, asnum, ep->desc.bEndpointAddress);
return;
@ -83,7 +83,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP ||
size < USB_DT_SS_EP_COMP_SIZE) {
dev_warn(ddev, "No SuperSpeed endpoint companion for config %d "
dev_notice(ddev, "No SuperSpeed endpoint companion for config %d "
" interface %d altsetting %d ep %d: "
"using minimum values\n",
cfgno, inum, asnum, ep->desc.bEndpointAddress);
@ -109,13 +109,13 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
/* Check the various values */
if (usb_endpoint_xfer_control(&ep->desc) && desc->bMaxBurst != 0) {
dev_warn(ddev, "Control endpoint with bMaxBurst = %d in "
dev_notice(ddev, "Control endpoint with bMaxBurst = %d in "
"config %d interface %d altsetting %d ep %d: "
"setting to zero\n", desc->bMaxBurst,
cfgno, inum, asnum, ep->desc.bEndpointAddress);
ep->ss_ep_comp.bMaxBurst = 0;
} else if (desc->bMaxBurst > 15) {
dev_warn(ddev, "Endpoint with bMaxBurst = %d in "
dev_notice(ddev, "Endpoint with bMaxBurst = %d in "
"config %d interface %d altsetting %d ep %d: "
"setting to 15\n", desc->bMaxBurst,
cfgno, inum, asnum, ep->desc.bEndpointAddress);
@ -125,7 +125,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
if ((usb_endpoint_xfer_control(&ep->desc) ||
usb_endpoint_xfer_int(&ep->desc)) &&
desc->bmAttributes != 0) {
dev_warn(ddev, "%s endpoint with bmAttributes = %d in "
dev_notice(ddev, "%s endpoint with bmAttributes = %d in "
"config %d interface %d altsetting %d ep %d: "
"setting to zero\n",
usb_endpoint_xfer_control(&ep->desc) ? "Control" : "Bulk",
@ -134,7 +134,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
ep->ss_ep_comp.bmAttributes = 0;
} else if (usb_endpoint_xfer_bulk(&ep->desc) &&
desc->bmAttributes > 16) {
dev_warn(ddev, "Bulk endpoint with more than 65536 streams in "
dev_notice(ddev, "Bulk endpoint with more than 65536 streams in "
"config %d interface %d altsetting %d ep %d: "
"setting to max\n",
cfgno, inum, asnum, ep->desc.bEndpointAddress);
@ -142,7 +142,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
} else if (usb_endpoint_xfer_isoc(&ep->desc) &&
!USB_SS_SSP_ISOC_COMP(desc->bmAttributes) &&
USB_SS_MULT(desc->bmAttributes) > 3) {
dev_warn(ddev, "Isoc endpoint has Mult of %d in "
dev_notice(ddev, "Isoc endpoint has Mult of %d in "
"config %d interface %d altsetting %d ep %d: "
"setting to 3\n",
USB_SS_MULT(desc->bmAttributes),
@ -160,7 +160,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
else
max_tx = 999999;
if (le16_to_cpu(desc->wBytesPerInterval) > max_tx) {
dev_warn(ddev, "%s endpoint with wBytesPerInterval of %d in "
dev_notice(ddev, "%s endpoint with wBytesPerInterval of %d in "
"config %d interface %d altsetting %d ep %d: "
"setting to %d\n",
usb_endpoint_xfer_isoc(&ep->desc) ? "Isoc" : "Int",
@ -273,7 +273,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
else if (d->bLength >= USB_DT_ENDPOINT_SIZE)
n = USB_DT_ENDPOINT_SIZE;
else {
dev_warn(ddev, "config %d interface %d altsetting %d has an "
dev_notice(ddev, "config %d interface %d altsetting %d has an "
"invalid endpoint descriptor of length %d, skipping\n",
cfgno, inum, asnum, d->bLength);
goto skip_to_next_endpoint_or_interface_descriptor;
@ -281,7 +281,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
i = d->bEndpointAddress & ~USB_ENDPOINT_DIR_MASK;
if (i >= 16 || i == 0) {
dev_warn(ddev, "config %d interface %d altsetting %d has an "
dev_notice(ddev, "config %d interface %d altsetting %d has an "
"invalid endpoint with address 0x%X, skipping\n",
cfgno, inum, asnum, d->bEndpointAddress);
goto skip_to_next_endpoint_or_interface_descriptor;
@ -293,7 +293,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
/* Check for duplicate endpoint addresses */
if (config_endpoint_is_duplicate(config, inum, asnum, d)) {
dev_warn(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n",
dev_notice(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n",
cfgno, inum, asnum, d->bEndpointAddress);
goto skip_to_next_endpoint_or_interface_descriptor;
}
@ -301,7 +301,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
/* Ignore some endpoints */
if (udev->quirks & USB_QUIRK_ENDPOINT_IGNORE) {
if (usb_endpoint_is_ignored(udev, ifp, d)) {
dev_warn(ddev, "config %d interface %d altsetting %d has an ignored endpoint with address 0x%X, skipping\n",
dev_notice(ddev, "config %d interface %d altsetting %d has an ignored endpoint with address 0x%X, skipping\n",
cfgno, inum, asnum,
d->bEndpointAddress);
goto skip_to_next_endpoint_or_interface_descriptor;
@ -378,7 +378,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
}
}
if (d->bInterval < i || d->bInterval > j) {
dev_warn(ddev, "config %d interface %d altsetting %d "
dev_notice(ddev, "config %d interface %d altsetting %d "
"endpoint 0x%X has an invalid bInterval %d, "
"changing to %d\n",
cfgno, inum, asnum,
@ -391,7 +391,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
* them usable, we will try treating them as Interrupt endpoints.
*/
if (udev->speed == USB_SPEED_LOW && usb_endpoint_xfer_bulk(d)) {
dev_warn(ddev, "config %d interface %d altsetting %d "
dev_notice(ddev, "config %d interface %d altsetting %d "
"endpoint 0x%X is Bulk; changing to Interrupt\n",
cfgno, inum, asnum, d->bEndpointAddress);
endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT;
@ -408,7 +408,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
*/
maxp = le16_to_cpu(endpoint->desc.wMaxPacketSize);
if (maxp == 0 && !(usb_endpoint_xfer_isoc(d) && asnum == 0)) {
dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid wMaxPacketSize 0\n",
dev_notice(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid wMaxPacketSize 0\n",
cfgno, inum, asnum, d->bEndpointAddress);
}
@ -439,7 +439,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
j = maxpacket_maxes[usb_endpoint_type(&endpoint->desc)];
if (maxp > j) {
dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid maxpacket %d, setting to %d\n",
dev_notice(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid maxpacket %d, setting to %d\n",
cfgno, inum, asnum, d->bEndpointAddress, maxp, j);
maxp = j;
endpoint->desc.wMaxPacketSize = cpu_to_le16(i | maxp);
@ -452,7 +452,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
*/
if (udev->speed == USB_SPEED_HIGH && usb_endpoint_xfer_bulk(d)) {
if (maxp != 512)
dev_warn(ddev, "config %d interface %d altsetting %d "
dev_notice(ddev, "config %d interface %d altsetting %d "
"bulk endpoint 0x%X has invalid maxpacket %d\n",
cfgno, inum, asnum, d->bEndpointAddress,
maxp);
@ -533,7 +533,7 @@ static int usb_parse_interface(struct device *ddev, int cfgno,
i < intfc->num_altsetting;
(++i, ++alt)) {
if (alt->desc.bAlternateSetting == asnum) {
dev_warn(ddev, "Duplicate descriptor for config %d "
dev_notice(ddev, "Duplicate descriptor for config %d "
"interface %d altsetting %d, skipping\n",
cfgno, inum, asnum);
goto skip_to_next_interface_descriptor;
@ -559,7 +559,7 @@ static int usb_parse_interface(struct device *ddev, int cfgno,
num_ep = num_ep_orig = alt->desc.bNumEndpoints;
alt->desc.bNumEndpoints = 0; /* Use as a counter */
if (num_ep > USB_MAXENDPOINTS) {
dev_warn(ddev, "too many endpoints for config %d interface %d "
dev_notice(ddev, "too many endpoints for config %d interface %d "
"altsetting %d: %d, using maximum allowed: %d\n",
cfgno, inum, asnum, num_ep, USB_MAXENDPOINTS);
num_ep = USB_MAXENDPOINTS;
@ -590,7 +590,7 @@ static int usb_parse_interface(struct device *ddev, int cfgno,
}
if (n != num_ep_orig)
dev_warn(ddev, "config %d interface %d altsetting %d has %d "
dev_notice(ddev, "config %d interface %d altsetting %d has %d "
"endpoint descriptor%s, different from the interface "
"descriptor's value: %d\n",
cfgno, inum, asnum, n, plural(n), num_ep_orig);
@ -625,7 +625,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
if (config->desc.bDescriptorType != USB_DT_CONFIG ||
config->desc.bLength < USB_DT_CONFIG_SIZE ||
config->desc.bLength > size) {
dev_err(ddev, "invalid descriptor for config index %d: "
dev_notice(ddev, "invalid descriptor for config index %d: "
"type = 0x%X, length = %d\n", cfgidx,
config->desc.bDescriptorType, config->desc.bLength);
return -EINVAL;
@ -636,7 +636,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
size -= config->desc.bLength;
if (nintf > USB_MAXINTERFACES) {
dev_warn(ddev, "config %d has too many interfaces: %d, "
dev_notice(ddev, "config %d has too many interfaces: %d, "
"using maximum allowed: %d\n",
cfgno, nintf, USB_MAXINTERFACES);
nintf = USB_MAXINTERFACES;
@ -650,7 +650,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
(buffer2 += header->bLength, size2 -= header->bLength)) {
if (size2 < sizeof(struct usb_descriptor_header)) {
dev_warn(ddev, "config %d descriptor has %d excess "
dev_notice(ddev, "config %d descriptor has %d excess "
"byte%s, ignoring\n",
cfgno, size2, plural(size2));
break;
@ -658,7 +658,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
header = (struct usb_descriptor_header *) buffer2;
if ((header->bLength > size2) || (header->bLength < 2)) {
dev_warn(ddev, "config %d has an invalid descriptor "
dev_notice(ddev, "config %d has an invalid descriptor "
"of length %d, skipping remainder of the config\n",
cfgno, header->bLength);
break;
@ -670,7 +670,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
d = (struct usb_interface_descriptor *) header;
if (d->bLength < USB_DT_INTERFACE_SIZE) {
dev_warn(ddev, "config %d has an invalid "
dev_notice(ddev, "config %d has an invalid "
"interface descriptor of length %d, "
"skipping\n", cfgno, d->bLength);
continue;
@ -680,7 +680,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
if ((dev->quirks & USB_QUIRK_HONOR_BNUMINTERFACES) &&
n >= nintf_orig) {
dev_warn(ddev, "config %d has more interface "
dev_notice(ddev, "config %d has more interface "
"descriptors, than it declares in "
"bNumInterfaces, ignoring interface "
"number: %d\n", cfgno, inum);
@ -688,7 +688,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
}
if (inum >= nintf_orig)
dev_warn(ddev, "config %d has an invalid "
dev_notice(ddev, "config %d has an invalid "
"interface number: %d but max is %d\n",
cfgno, inum, nintf_orig - 1);
@ -713,14 +713,14 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
d = (struct usb_interface_assoc_descriptor *)header;
if (d->bLength < USB_DT_INTERFACE_ASSOCIATION_SIZE) {
dev_warn(ddev,
dev_notice(ddev,
"config %d has an invalid interface association descriptor of length %d, skipping\n",
cfgno, d->bLength);
continue;
}
if (iad_num == USB_MAXIADS) {
dev_warn(ddev, "found more Interface "
dev_notice(ddev, "found more Interface "
"Association Descriptors "
"than allocated for in "
"configuration %d\n", cfgno);
@ -731,7 +731,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
} else if (header->bDescriptorType == USB_DT_DEVICE ||
header->bDescriptorType == USB_DT_CONFIG)
dev_warn(ddev, "config %d contains an unexpected "
dev_notice(ddev, "config %d contains an unexpected "
"descriptor of type 0x%X, skipping\n",
cfgno, header->bDescriptorType);
@ -740,11 +740,11 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
config->desc.wTotalLength = cpu_to_le16(buffer2 - buffer0);
if (n != nintf)
dev_warn(ddev, "config %d has %d interface%s, different from "
dev_notice(ddev, "config %d has %d interface%s, different from "
"the descriptor's value: %d\n",
cfgno, n, plural(n), nintf_orig);
else if (n == 0)
dev_warn(ddev, "config %d has no interfaces?\n", cfgno);
dev_notice(ddev, "config %d has no interfaces?\n", cfgno);
config->desc.bNumInterfaces = nintf = n;
/* Check for missing interface numbers */
@ -754,7 +754,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
break;
}
if (j >= nintf)
dev_warn(ddev, "config %d has no interface number "
dev_notice(ddev, "config %d has no interface number "
"%d\n", cfgno, i);
}
@ -762,7 +762,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
for (i = 0; i < nintf; ++i) {
j = nalts[i];
if (j > USB_MAXALTSETTING) {
dev_warn(ddev, "too many alternate settings for "
dev_notice(ddev, "too many alternate settings for "
"config %d interface %d: %d, "
"using maximum allowed: %d\n",
cfgno, inums[i], j, USB_MAXALTSETTING);
@ -811,7 +811,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
break;
}
if (n >= intfc->num_altsetting)
dev_warn(ddev, "config %d interface %d has no "
dev_notice(ddev, "config %d interface %d has no "
"altsetting %d\n", cfgno, inums[i], j);
}
}
@ -868,7 +868,7 @@ int usb_get_configuration(struct usb_device *dev)
int result;
if (ncfg > USB_MAXCONFIG) {
dev_warn(ddev, "too many configurations: %d, "
dev_notice(ddev, "too many configurations: %d, "
"using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG;
}
@ -902,7 +902,7 @@ int usb_get_configuration(struct usb_device *dev)
"descriptor/%s: %d\n", cfgno, "start", result);
if (result != -EPIPE)
goto err;
dev_err(ddev, "chopping to %d config(s)\n", cfgno);
dev_notice(ddev, "chopping to %d config(s)\n", cfgno);
dev->descriptor.bNumConfigurations = cfgno;
break;
} else if (result < 4) {
@ -934,7 +934,7 @@ int usb_get_configuration(struct usb_device *dev)
goto err;
}
if (result < length) {
dev_warn(ddev, "config index %d descriptor too short "
dev_notice(ddev, "config index %d descriptor too short "
"(expected %i, got %i)\n", cfgno, length, result);
length = result;
}
@ -993,7 +993,7 @@ int usb_get_bos_descriptor(struct usb_device *dev)
/* Get BOS descriptor */
ret = usb_get_descriptor(dev, USB_DT_BOS, 0, bos, USB_DT_BOS_SIZE);
if (ret < USB_DT_BOS_SIZE || bos->bLength < USB_DT_BOS_SIZE) {
dev_err(ddev, "unable to get BOS descriptor or descriptor too short\n");
dev_notice(ddev, "unable to get BOS descriptor or descriptor too short\n");
if (ret >= 0)
ret = -ENOMSG;
kfree(bos);
@ -1021,7 +1021,7 @@ int usb_get_bos_descriptor(struct usb_device *dev)
ret = usb_get_descriptor(dev, USB_DT_BOS, 0, buffer, total_len);
if (ret < total_len) {
dev_err(ddev, "unable to get BOS descriptor set\n");
dev_notice(ddev, "unable to get BOS descriptor set\n");
if (ret >= 0)
ret = -ENOMSG;
goto err;
@ -1046,7 +1046,7 @@ int usb_get_bos_descriptor(struct usb_device *dev)
}
if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) {
dev_warn(ddev, "descriptor type invalid, skip\n");
dev_notice(ddev, "descriptor type invalid, skip\n");
continue;
}

View File

@ -558,6 +558,17 @@ static int hcd_pci_suspend_noirq(struct device *dev)
return retval;
}
static int hcd_pci_poweroff_late(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
if (hcd->driver->pci_poweroff_late && !HCD_DEAD(hcd))
return hcd->driver->pci_poweroff_late(hcd, device_may_wakeup(dev));
return 0;
}
static int hcd_pci_resume_noirq(struct device *dev)
{
powermac_set_asic(to_pci_dev(dev), 1);
@ -578,6 +589,7 @@ static int hcd_pci_restore(struct device *dev)
#define hcd_pci_suspend NULL
#define hcd_pci_suspend_noirq NULL
#define hcd_pci_poweroff_late NULL
#define hcd_pci_resume_noirq NULL
#define hcd_pci_resume NULL
#define hcd_pci_restore NULL
@ -615,6 +627,7 @@ const struct dev_pm_ops usb_hcd_pci_pm_ops = {
.thaw_noirq = NULL,
.thaw = hcd_pci_resume,
.poweroff = hcd_pci_suspend,
.poweroff_late = hcd_pci_poweroff_late,
.poweroff_noirq = hcd_pci_suspend_noirq,
.restore_noirq = hcd_pci_resume_noirq,
.restore = hcd_pci_restore,

View File

@ -3133,8 +3133,12 @@ int usb_hcd_setup_local_mem(struct usb_hcd *hcd, phys_addr_t phys_addr,
GFP_KERNEL,
DMA_ATTR_WRITE_COMBINE);
if (IS_ERR(local_mem))
if (IS_ERR_OR_NULL(local_mem)) {
if (!local_mem)
return -ENOMEM;
return PTR_ERR(local_mem);
}
/*
* Here we pass a dma_addr_t but the arg type is a phys_addr_t.

View File

@ -3081,6 +3081,48 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
return status;
}
/*
* hub_port_stop_enumerate - stop USB enumeration or ignore port events
* @hub: target hub
* @port1: port num of the port
* @retries: port retries number of hub_port_init()
*
* Return:
* true: ignore port actions/events or give up connection attempts.
* false: keep original behavior.
*
* This function will be based on retries to check whether the port which is
* marked with early_stop attribute would stop enumeration or ignore events.
*
* Note:
* This function didn't change anything if early_stop is not set, and it will
* prevent all connection attempts when early_stop is set and the attempts of
* the port are more than 1.
*/
static bool hub_port_stop_enumerate(struct usb_hub *hub, int port1, int retries)
{
struct usb_port *port_dev = hub->ports[port1 - 1];
if (port_dev->early_stop) {
if (port_dev->ignore_event)
return true;
/*
* We want unsuccessful attempts to fail quickly.
* Since some devices may need one failure during
* port initialization, we allow two tries but no
* more.
*/
if (retries < 2)
return false;
port_dev->ignore_event = 1;
} else
port_dev->ignore_event = 0;
return port_dev->ignore_event;
}
/* Check if a port is power on */
int usb_port_is_power_on(struct usb_hub *hub, unsigned int portstatus)
{
@ -4796,6 +4838,11 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
do_new_scheme = use_new_scheme(udev, retry_counter, port_dev);
for (retries = 0; retries < GET_DESCRIPTOR_TRIES; (++retries, msleep(100))) {
if (hub_port_stop_enumerate(hub, port1, retries)) {
retval = -ENODEV;
break;
}
if (do_new_scheme) {
struct usb_device_descriptor *buf;
int r = 0;
@ -5246,6 +5293,11 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
status = 0;
for (i = 0; i < PORT_INIT_TRIES; i++) {
if (hub_port_stop_enumerate(hub, port1, i)) {
status = -ENODEV;
break;
}
usb_lock_port(port_dev);
mutex_lock(hcd->address0_mutex);
retry_locked = true;
@ -5614,6 +5666,10 @@ static void port_event(struct usb_hub *hub, int port1)
if (!pm_runtime_active(&port_dev->dev))
return;
/* skip port actions if ignore_event and early_stop are true */
if (port_dev->ignore_event && port_dev->early_stop)
return;
if (hub_handle_remote_wakeup(hub, port1, portstatus, portchange))
connect_change = 1;
@ -5927,6 +5983,10 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
mutex_lock(hcd->address0_mutex);
for (i = 0; i < PORT_INIT_TRIES; ++i) {
if (hub_port_stop_enumerate(parent_hub, port1, i)) {
ret = -ENODEV;
break;
}
/* ep0 maxpacket size may change; let the HCD know about it.
* Other endpoints will be handled by re-enumeration. */

View File

@ -90,6 +90,8 @@ struct usb_hub {
* @is_superspeed cache super-speed status
* @usb3_lpm_u1_permit: whether USB3 U1 LPM is permitted.
* @usb3_lpm_u2_permit: whether USB3 U2 LPM is permitted.
* @early_stop: whether port initialization will be stopped earlier.
* @ignore_event: whether events of the port are ignored.
*/
struct usb_port {
struct usb_device *child;
@ -103,6 +105,8 @@ struct usb_port {
u32 over_current_count;
u8 portnum;
u32 quirks;
unsigned int early_stop:1;
unsigned int ignore_event:1;
unsigned int is_superspeed:1;
unsigned int usb3_lpm_u1_permit:1;
unsigned int usb3_lpm_u2_permit:1;

View File

@ -7,6 +7,7 @@
* Author: Lan Tianyu <tianyu.lan@intel.com>
*/
#include <linux/kstrtox.h>
#include <linux/slab.h>
#include <linux/pm_qos.h>
#include <linux/component.h>
@ -17,6 +18,32 @@ static int usb_port_block_power_off;
static const struct attribute_group *port_dev_group[];
static ssize_t early_stop_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_port *port_dev = to_usb_port(dev);
return sysfs_emit(buf, "%s\n", port_dev->early_stop ? "yes" : "no");
}
static ssize_t early_stop_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct usb_port *port_dev = to_usb_port(dev);
bool value;
if (kstrtobool(buf, &value))
return -EINVAL;
if (value)
port_dev->early_stop = 1;
else
port_dev->early_stop = 0;
return count;
}
static DEVICE_ATTR_RW(early_stop);
static ssize_t disable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@ -63,7 +90,7 @@ static ssize_t disable_store(struct device *dev, struct device_attribute *attr,
bool disabled;
int rc;
rc = strtobool(buf, &disabled);
rc = kstrtobool(buf, &disabled);
if (rc)
return rc;
@ -236,6 +263,7 @@ static struct attribute *port_dev_attrs[] = {
&dev_attr_quirks.attr,
&dev_attr_over_current_count.attr,
&dev_attr_disable.attr,
&dev_attr_early_stop.attr,
NULL,
};

View File

@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/kstrtox.h>
#include <linux/string.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
@ -505,7 +506,7 @@ static ssize_t usb2_hardware_lpm_store(struct device *dev,
if (ret < 0)
return -EINTR;
ret = strtobool(buf, &value);
ret = kstrtobool(buf, &value);
if (!ret) {
udev->usb2_hw_lpm_allowed = value;
@ -975,7 +976,7 @@ static ssize_t interface_authorized_default_store(struct device *dev,
int rc = count;
bool val;
if (strtobool(buf, &val) != 0)
if (kstrtobool(buf, &val) != 0)
return -EINVAL;
if (val)
@ -1176,7 +1177,7 @@ static ssize_t interface_authorized_store(struct device *dev,
struct usb_interface *intf = to_usb_interface(dev);
bool val;
if (strtobool(buf, &val) != 0)
if (kstrtobool(buf, &val) != 0)
return -EINVAL;
if (val)

View File

@ -4549,7 +4549,8 @@ static int dwc2_hsotg_udc_start(struct usb_gadget *gadget,
hsotg->gadget.dev.of_node = hsotg->dev->of_node;
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) {
if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL ||
(hsotg->dr_mode == USB_DR_MODE_OTG && dwc2_is_device_mode(hsotg))) {
ret = dwc2_lowlevel_hw_enable(hsotg);
if (ret)
goto err;
@ -4611,7 +4612,8 @@ static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget)
if (!IS_ERR_OR_NULL(hsotg->uphy))
otg_set_peripheral(hsotg->uphy->otg, NULL);
if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL ||
(hsotg->dr_mode == USB_DR_MODE_OTG && dwc2_is_device_mode(hsotg)))
dwc2_lowlevel_hw_disable(hsotg);
return 0;

View File

@ -113,6 +113,10 @@ static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg)
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 <<
GAHBCFG_HBSTLEN_SHIFT;
p->power_down = DWC2_POWER_DOWN_PARAM_NONE;
p->lpm = false;
p->lpm_clock_gating = false;
p->besl = false;
p->hird_threshold_en = false;
}
static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg)

View File

@ -321,7 +321,7 @@ static int dwc2_driver_remove(struct platform_device *dev)
reset_control_assert(hsotg->reset);
reset_control_assert(hsotg->reset_ecc);
return ret;
return 0;
}
/**
@ -576,7 +576,8 @@ static int dwc2_driver_probe(struct platform_device *dev)
dwc2_debugfs_init(hsotg);
/* Gadget code manages lowlevel hw on its own */
if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL ||
(hsotg->dr_mode == USB_DR_MODE_OTG && dwc2_is_device_mode(hsotg)))
dwc2_lowlevel_hw_disable(hsotg);
#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \

View File

@ -152,11 +152,11 @@ config USB_DWC3_IMX8MP
config USB_DWC3_XILINX
tristate "Xilinx Platforms"
depends on (ARCH_ZYNQMP || ARCH_VERSAL) && OF
depends on (ARCH_ZYNQMP || COMPILE_TEST) && OF
default USB_DWC3
help
Support Xilinx SoCs with DesignWare Core USB3 IP.
This driver handles both ZynqMP and Versal SoC operations.
This driver handles ZynqMP SoC operations.
Say 'Y' or 'M' if you have one such device.
config USB_DWC3_AM62

View File

@ -122,21 +122,25 @@ static void __dwc3_set_mode(struct work_struct *work)
unsigned long flags;
int ret;
u32 reg;
u32 desired_dr_role;
mutex_lock(&dwc->mutex);
spin_lock_irqsave(&dwc->lock, flags);
desired_dr_role = dwc->desired_dr_role;
spin_unlock_irqrestore(&dwc->lock, flags);
pm_runtime_get_sync(dwc->dev);
if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_OTG)
dwc3_otg_update(dwc, 0);
if (!dwc->desired_dr_role)
if (!desired_dr_role)
goto out;
if (dwc->desired_dr_role == dwc->current_dr_role)
if (desired_dr_role == dwc->current_dr_role)
goto out;
if (dwc->desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev)
if (desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev)
goto out;
switch (dwc->current_dr_role) {
@ -164,7 +168,7 @@ static void __dwc3_set_mode(struct work_struct *work)
*/
if (dwc->current_dr_role && ((DWC3_IP_IS(DWC3) ||
DWC3_VER_IS_PRIOR(DWC31, 190A)) &&
dwc->desired_dr_role != DWC3_GCTL_PRTCAP_OTG)) {
desired_dr_role != DWC3_GCTL_PRTCAP_OTG)) {
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg |= DWC3_GCTL_CORESOFTRESET;
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
@ -184,11 +188,11 @@ static void __dwc3_set_mode(struct work_struct *work)
spin_lock_irqsave(&dwc->lock, flags);
dwc3_set_prtcap(dwc, dwc->desired_dr_role);
dwc3_set_prtcap(dwc, desired_dr_role);
spin_unlock_irqrestore(&dwc->lock, flags);
switch (dwc->desired_dr_role) {
switch (desired_dr_role) {
case DWC3_GCTL_PRTCAP_HOST:
ret = dwc3_host_init(dwc);
if (ret) {
@ -1096,8 +1100,13 @@ static int dwc3_core_init(struct dwc3 *dwc)
if (!dwc->ulpi_ready) {
ret = dwc3_core_ulpi_init(dwc);
if (ret)
if (ret) {
if (ret == -ETIMEDOUT) {
dwc3_core_soft_reset(dwc);
ret = -EPROBE_DEFER;
}
goto err0;
}
dwc->ulpi_ready = true;
}

View File

@ -45,7 +45,7 @@
#define PCI_DEVICE_ID_INTEL_ADLN 0x465e
#define PCI_DEVICE_ID_INTEL_ADLN_PCH 0x54ee
#define PCI_DEVICE_ID_INTEL_ADLS 0x7ae1
#define PCI_DEVICE_ID_INTEL_RPL 0x460e
#define PCI_DEVICE_ID_INTEL_RPL 0xa70e
#define PCI_DEVICE_ID_INTEL_RPLS 0x7a61
#define PCI_DEVICE_ID_INTEL_MTLP 0x7ec1
#define PCI_DEVICE_ID_INTEL_MTL 0x7e7e

View File

@ -261,7 +261,8 @@ static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom)
if (IS_ERR(qcom->icc_path_apps)) {
dev_err(dev, "failed to get apps-usb path: %ld\n",
PTR_ERR(qcom->icc_path_apps));
return PTR_ERR(qcom->icc_path_apps);
ret = PTR_ERR(qcom->icc_path_apps);
goto put_path_ddr;
}
max_speed = usb_get_maximum_speed(&qcom->dwc3->dev);
@ -274,16 +275,22 @@ static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom)
}
if (ret) {
dev_err(dev, "failed to set bandwidth for usb-ddr path: %d\n", ret);
return ret;
goto put_path_apps;
}
ret = icc_set_bw(qcom->icc_path_apps, APPS_USB_AVG_BW, APPS_USB_PEAK_BW);
if (ret) {
dev_err(dev, "failed to set bandwidth for apps-usb path: %d\n", ret);
return ret;
goto put_path_apps;
}
return 0;
put_path_apps:
icc_put(qcom->icc_path_apps);
put_path_ddr:
icc_put(qcom->icc_path_ddr);
return ret;
}
/**

View File

@ -1464,8 +1464,18 @@ static int dwc3_prepare_trbs_sg(struct dwc3_ep *dep,
*/
if (num_trbs_left == 1 || (needs_extra_trb &&
num_trbs_left <= 2 &&
sg_dma_len(sg_next(s)) >= length))
must_interrupt = true;
sg_dma_len(sg_next(s)) >= length)) {
struct dwc3_request *r;
/* Check if previous requests already set IOC */
list_for_each_entry(r, &dep->started_list, list) {
if (r != req && !r->request.no_interrupt)
break;
if (r == req)
must_interrupt = true;
}
}
dwc3_prepare_one_trb(dep, req, trb_length, 1, i, false,
must_interrupt);

View File

@ -0,0 +1,38 @@
# SPDX-License-Identifier: GPL-2.0
config USB_FOTG210
tristate "Faraday FOTG210 USB2 Dual Role controller"
depends on USB || USB_GADGET
depends on HAS_DMA && HAS_IOMEM
depends on ARCH_GEMINI || COMPILE_TEST
default ARCH_GEMINI
select MFD_SYSCON
help
Faraday FOTG210 is a dual-mode USB controller that can act
in both host controller and peripheral controller mode.
if USB_FOTG210
config USB_FOTG210_HCD
bool "Faraday FOTG210 USB Host Controller support"
depends on USB=y || USB=USB_FOTG210
help
Faraday FOTG210 is an OTG controller which can be configured as
an USB2.0 host. It is designed to meet USB2.0 EHCI specification
with minor modification.
To compile this driver as a module, choose M here: the
module will be called fotg210-hcd.
config USB_FOTG210_UDC
depends on USB_GADGET=y || USB_GADGET=USB_FOTG210
bool "Faraday FOTG210 USB Peripheral Controller support"
help
Faraday USB2.0 OTG controller which can be configured as
high speed or full speed USB device. This driver suppports
Bulk Transfer so far.
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "fotg210-udc".
endif

View File

@ -0,0 +1,10 @@
# SPDX-License-Identifier: GPL-2.0
# This setup links the different object files into one single
# module so we don't have to EXPORT() a lot of internal symbols
# or create unnecessary submodules.
fotg210-objs-y += fotg210-core.o
fotg210-objs-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o
fotg210-objs-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o
fotg210-objs := $(fotg210-objs-y)
obj-$(CONFIG_USB_FOTG210) += fotg210.o

View File

@ -0,0 +1,166 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Central probing code for the FOTG210 dual role driver
* We register one driver for the hardware and then we decide
* whether to proceed with probing the host or the peripheral
* driver.
*/
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/usb.h>
#include <linux/usb/otg.h>
#include "fotg210.h"
/*
* Gemini-specific initialization function, only executed on the
* Gemini SoC using the global misc control register.
*
* The gemini USB blocks are connected to either Mini-A (host mode) or
* Mini-B (peripheral mode) plugs. There is no role switch support on the
* Gemini SoC, just either-or.
*/
#define GEMINI_GLOBAL_MISC_CTRL 0x30
#define GEMINI_MISC_USB0_WAKEUP BIT(14)
#define GEMINI_MISC_USB1_WAKEUP BIT(15)
#define GEMINI_MISC_USB0_VBUS_ON BIT(22)
#define GEMINI_MISC_USB1_VBUS_ON BIT(23)
#define GEMINI_MISC_USB0_MINI_B BIT(29)
#define GEMINI_MISC_USB1_MINI_B BIT(30)
static int fotg210_gemini_init(struct device *dev, struct resource *res,
enum usb_dr_mode mode)
{
struct device_node *np = dev->of_node;
struct regmap *map;
bool wakeup;
u32 mask, val;
int ret;
map = syscon_regmap_lookup_by_phandle(np, "syscon");
if (IS_ERR(map)) {
dev_err(dev, "no syscon\n");
return PTR_ERR(map);
}
wakeup = of_property_read_bool(np, "wakeup-source");
/*
* Figure out if this is USB0 or USB1 by simply checking the
* physical base address.
*/
mask = 0;
if (res->start == 0x69000000) {
mask = GEMINI_MISC_USB1_VBUS_ON | GEMINI_MISC_USB1_MINI_B |
GEMINI_MISC_USB1_WAKEUP;
if (mode == USB_DR_MODE_HOST)
val = GEMINI_MISC_USB1_VBUS_ON;
else
val = GEMINI_MISC_USB1_MINI_B;
if (wakeup)
val |= GEMINI_MISC_USB1_WAKEUP;
} else {
mask = GEMINI_MISC_USB0_VBUS_ON | GEMINI_MISC_USB0_MINI_B |
GEMINI_MISC_USB0_WAKEUP;
if (mode == USB_DR_MODE_HOST)
val = GEMINI_MISC_USB0_VBUS_ON;
else
val = GEMINI_MISC_USB0_MINI_B;
if (wakeup)
val |= GEMINI_MISC_USB0_WAKEUP;
}
ret = regmap_update_bits(map, GEMINI_GLOBAL_MISC_CTRL, mask, val);
if (ret) {
dev_err(dev, "failed to initialize Gemini PHY\n");
return ret;
}
dev_info(dev, "initialized Gemini PHY in %s mode\n",
(mode == USB_DR_MODE_HOST) ? "host" : "gadget");
return 0;
}
static int fotg210_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
enum usb_dr_mode mode;
int ret;
mode = usb_get_dr_mode(dev);
if (of_device_is_compatible(dev->of_node, "cortina,gemini-usb")) {
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ret = fotg210_gemini_init(dev, res, mode);
if (ret)
return ret;
}
if (mode == USB_DR_MODE_PERIPHERAL)
ret = fotg210_udc_probe(pdev);
else
ret = fotg210_hcd_probe(pdev);
return ret;
}
static int fotg210_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
enum usb_dr_mode mode;
mode = usb_get_dr_mode(dev);
if (mode == USB_DR_MODE_PERIPHERAL)
fotg210_udc_remove(pdev);
else
fotg210_hcd_remove(pdev);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id fotg210_of_match[] = {
{ .compatible = "faraday,fotg210" },
{},
};
MODULE_DEVICE_TABLE(of, fotg210_of_match);
#endif
static struct platform_driver fotg210_driver = {
.driver = {
.name = "fotg210",
.of_match_table = of_match_ptr(fotg210_of_match),
},
.probe = fotg210_probe,
.remove = fotg210_remove,
};
static int __init fotg210_init(void)
{
if (usb_disabled())
return -ENODEV;
if (IS_ENABLED(CONFIG_USB_FOTG210_HCD))
fotg210_hcd_init();
return platform_driver_register(&fotg210_driver);
}
module_init(fotg210_init);
static void __exit fotg210_cleanup(void)
{
platform_driver_unregister(&fotg210_driver);
if (IS_ENABLED(CONFIG_USB_FOTG210_HCD))
fotg210_hcd_cleanup();
}
module_exit(fotg210_cleanup);
MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("FOTG210 Dual Role Controller Driver");

View File

@ -39,8 +39,8 @@
#include <asm/irq.h>
#include <asm/unaligned.h>
#define DRIVER_AUTHOR "Yuan-Hsin Chen"
#define DRIVER_DESC "FOTG210 Host Controller (EHCI) Driver"
#include "fotg210.h"
static const char hcd_name[] = "fotg210_hcd";
#undef FOTG210_URB_TRACE
@ -77,7 +77,7 @@ MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us");
#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
#include "fotg210.h"
#include "fotg210-hcd.h"
#define fotg210_dbg(fotg210, fmt, args...) \
dev_dbg(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args)
@ -5490,9 +5490,6 @@ static int fotg210_get_frame(struct usb_hcd *hcd)
* functions and in order to facilitate role switching we cannot
* give the fotg210 driver exclusive access to those.
*/
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_LICENSE("GPL");
static const struct hc_driver fotg210_fotg210_hc_driver = {
.description = hcd_name,
@ -5560,7 +5557,7 @@ static void fotg210_init(struct fotg210_hcd *fotg210)
* then invokes the start() method for the HCD associated with it
* through the hotplug entry's driver_data.
*/
static int fotg210_hcd_probe(struct platform_device *pdev)
int fotg210_hcd_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct usb_hcd *hcd;
@ -5652,7 +5649,7 @@ static int fotg210_hcd_probe(struct platform_device *pdev)
* @dev: USB Host Controller being removed
*
*/
static int fotg210_hcd_remove(struct platform_device *pdev)
int fotg210_hcd_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
@ -5668,27 +5665,8 @@ static int fotg210_hcd_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id fotg210_of_match[] = {
{ .compatible = "faraday,fotg210" },
{},
};
MODULE_DEVICE_TABLE(of, fotg210_of_match);
#endif
static struct platform_driver fotg210_hcd_driver = {
.driver = {
.name = "fotg210-hcd",
.of_match_table = of_match_ptr(fotg210_of_match),
},
.probe = fotg210_hcd_probe,
.remove = fotg210_hcd_remove,
};
static int __init fotg210_hcd_init(void)
int __init fotg210_hcd_init(void)
{
int retval = 0;
if (usb_disabled())
return -ENODEV;
@ -5704,24 +5682,11 @@ static int __init fotg210_hcd_init(void)
fotg210_debug_root = debugfs_create_dir("fotg210", usb_debug_root);
retval = platform_driver_register(&fotg210_hcd_driver);
if (retval < 0)
goto clean;
return retval;
clean:
debugfs_remove(fotg210_debug_root);
fotg210_debug_root = NULL;
clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
return retval;
return 0;
}
module_init(fotg210_hcd_init);
static void __exit fotg210_hcd_cleanup(void)
void __exit fotg210_hcd_cleanup(void)
{
platform_driver_unregister(&fotg210_hcd_driver);
debugfs_remove(fotg210_debug_root);
clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
}
module_exit(fotg210_hcd_cleanup);

View File

@ -15,8 +15,12 @@
#include <linux/platform_device.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/clk.h>
#include <linux/usb/otg.h>
#include <linux/usb/phy.h>
#include "fotg210.h"
#include "fotg210-udc.h"
#define DRIVER_DESC "FOTG210 USB Device Controller Driver"
#define DRIVER_VERSION "30-April-2013"
@ -629,10 +633,10 @@ static void fotg210_request_error(struct fotg210_udc *fotg210)
static void fotg210_set_address(struct fotg210_udc *fotg210,
struct usb_ctrlrequest *ctrl)
{
if (ctrl->wValue >= 0x0100) {
if (le16_to_cpu(ctrl->wValue) >= 0x0100) {
fotg210_request_error(fotg210);
} else {
fotg210_set_dev_addr(fotg210, ctrl->wValue);
fotg210_set_dev_addr(fotg210, le16_to_cpu(ctrl->wValue));
fotg210_set_cxdone(fotg210);
}
}
@ -713,17 +717,17 @@ static void fotg210_get_status(struct fotg210_udc *fotg210,
switch (ctrl->bRequestType & USB_RECIP_MASK) {
case USB_RECIP_DEVICE:
fotg210->ep0_data = 1 << USB_DEVICE_SELF_POWERED;
fotg210->ep0_data = cpu_to_le16(1 << USB_DEVICE_SELF_POWERED);
break;
case USB_RECIP_INTERFACE:
fotg210->ep0_data = 0;
fotg210->ep0_data = cpu_to_le16(0);
break;
case USB_RECIP_ENDPOINT:
epnum = ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK;
if (epnum)
fotg210->ep0_data =
fotg210_is_epnstall(fotg210->ep[epnum])
<< USB_ENDPOINT_HALT;
cpu_to_le16(fotg210_is_epnstall(fotg210->ep[epnum])
<< USB_ENDPOINT_HALT);
else
fotg210_request_error(fotg210);
break;
@ -1007,11 +1011,19 @@ static int fotg210_udc_start(struct usb_gadget *g,
{
struct fotg210_udc *fotg210 = gadget_to_fotg210(g);
u32 value;
int ret;
/* hook up the driver */
driver->driver.bus = NULL;
fotg210->driver = driver;
if (!IS_ERR_OR_NULL(fotg210->phy)) {
ret = otg_set_peripheral(fotg210->phy->otg,
&fotg210->gadget);
if (ret)
dev_err(fotg210->dev, "can't bind to phy\n");
}
/* enable device global interrupt */
value = ioread32(fotg210->reg + FOTG210_DMCR);
value |= DMCR_GLINT_EN;
@ -1053,6 +1065,9 @@ static int fotg210_udc_stop(struct usb_gadget *g)
struct fotg210_udc *fotg210 = gadget_to_fotg210(g);
unsigned long flags;
if (!IS_ERR_OR_NULL(fotg210->phy))
return otg_set_peripheral(fotg210->phy->otg, NULL);
spin_lock_irqsave(&fotg210->lock, flags);
fotg210_init(fotg210);
@ -1068,28 +1083,71 @@ static const struct usb_gadget_ops fotg210_gadget_ops = {
.udc_stop = fotg210_udc_stop,
};
static int fotg210_udc_remove(struct platform_device *pdev)
/**
* fotg210_phy_event - Called by phy upon VBus event
* @nb: notifier block
* @action: phy action, is vbus connect or disconnect
* @data: the usb_gadget structure in fotg210
*
* Called by the USB Phy when a cable connect or disconnect is sensed.
*
* Returns NOTIFY_OK or NOTIFY_DONE
*/
static int fotg210_phy_event(struct notifier_block *nb, unsigned long action,
void *data)
{
struct usb_gadget *gadget = data;
if (!gadget)
return NOTIFY_DONE;
switch (action) {
case USB_EVENT_VBUS:
usb_gadget_vbus_connect(gadget);
return NOTIFY_OK;
case USB_EVENT_NONE:
usb_gadget_vbus_disconnect(gadget);
return NOTIFY_OK;
default:
return NOTIFY_DONE;
}
}
static struct notifier_block fotg210_phy_notifier = {
.notifier_call = fotg210_phy_event,
};
int fotg210_udc_remove(struct platform_device *pdev)
{
struct fotg210_udc *fotg210 = platform_get_drvdata(pdev);
int i;
usb_del_gadget_udc(&fotg210->gadget);
if (!IS_ERR_OR_NULL(fotg210->phy)) {
usb_unregister_notifier(fotg210->phy, &fotg210_phy_notifier);
usb_put_phy(fotg210->phy);
}
iounmap(fotg210->reg);
free_irq(platform_get_irq(pdev, 0), fotg210);
fotg210_ep_free_request(&fotg210->ep[0]->ep, fotg210->ep0_req);
for (i = 0; i < FOTG210_MAX_NUM_EP; i++)
kfree(fotg210->ep[i]);
if (!IS_ERR(fotg210->pclk))
clk_disable_unprepare(fotg210->pclk);
kfree(fotg210);
return 0;
}
static int fotg210_udc_probe(struct platform_device *pdev)
int fotg210_udc_probe(struct platform_device *pdev)
{
struct resource *res, *ires;
struct resource *res;
struct fotg210_udc *fotg210 = NULL;
struct fotg210_ep *_ep[FOTG210_MAX_NUM_EP];
struct device *dev = &pdev->dev;
int irq;
int ret = 0;
int i;
@ -1099,29 +1157,59 @@ static int fotg210_udc_probe(struct platform_device *pdev)
return -ENODEV;
}
ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!ires) {
pr_err("platform_get_resource IORESOURCE_IRQ error.\n");
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
pr_err("could not get irq\n");
return -ENODEV;
}
ret = -ENOMEM;
/* initialize udc */
fotg210 = kzalloc(sizeof(struct fotg210_udc), GFP_KERNEL);
if (fotg210 == NULL)
return -ENOMEM;
fotg210->dev = dev;
/* It's OK not to supply this clock */
fotg210->pclk = devm_clk_get(dev, "PCLK");
if (!IS_ERR(fotg210->pclk)) {
ret = clk_prepare_enable(fotg210->pclk);
if (ret) {
dev_err(dev, "failed to enable PCLK\n");
goto err;
}
} else if (PTR_ERR(fotg210->pclk) == -EPROBE_DEFER) {
/*
* Percolate deferrals, for anything else,
* just live without the clocking.
*/
ret = -EPROBE_DEFER;
goto err;
}
fotg210->phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
if (IS_ERR(fotg210->phy)) {
ret = PTR_ERR(fotg210->phy);
if (ret == -EPROBE_DEFER)
goto err_pclk;
dev_info(dev, "no PHY found\n");
fotg210->phy = NULL;
} else {
ret = usb_phy_init(fotg210->phy);
if (ret)
goto err_pclk;
dev_info(dev, "found and initialized PHY\n");
}
for (i = 0; i < FOTG210_MAX_NUM_EP; i++) {
_ep[i] = kzalloc(sizeof(struct fotg210_ep), GFP_KERNEL);
if (_ep[i] == NULL)
fotg210->ep[i] = kzalloc(sizeof(struct fotg210_ep), GFP_KERNEL);
if (!fotg210->ep[i])
goto err_alloc;
fotg210->ep[i] = _ep[i];
}
fotg210->reg = ioremap(res->start, resource_size(res));
if (fotg210->reg == NULL) {
pr_err("ioremap error.\n");
dev_err(dev, "ioremap error\n");
goto err_alloc;
}
@ -1132,8 +1220,8 @@ static int fotg210_udc_probe(struct platform_device *pdev)
fotg210->gadget.ops = &fotg210_gadget_ops;
fotg210->gadget.max_speed = USB_SPEED_HIGH;
fotg210->gadget.dev.parent = &pdev->dev;
fotg210->gadget.dev.dma_mask = pdev->dev.dma_mask;
fotg210->gadget.dev.parent = dev;
fotg210->gadget.dev.dma_mask = dev->dma_mask;
fotg210->gadget.name = udc_name;
INIT_LIST_HEAD(&fotg210->gadget.ep_list);
@ -1176,23 +1264,28 @@ static int fotg210_udc_probe(struct platform_device *pdev)
fotg210_disable_unplug(fotg210);
ret = request_irq(ires->start, fotg210_irq, IRQF_SHARED,
ret = request_irq(irq, fotg210_irq, IRQF_SHARED,
udc_name, fotg210);
if (ret < 0) {
pr_err("request_irq error (%d)\n", ret);
dev_err(dev, "request_irq error (%d)\n", ret);
goto err_req;
}
ret = usb_add_gadget_udc(&pdev->dev, &fotg210->gadget);
if (!IS_ERR_OR_NULL(fotg210->phy))
usb_register_notifier(fotg210->phy, &fotg210_phy_notifier);
ret = usb_add_gadget_udc(dev, &fotg210->gadget);
if (ret)
goto err_add_udc;
dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
dev_info(dev, "version %s\n", DRIVER_VERSION);
return 0;
err_add_udc:
free_irq(ires->start, fotg210);
if (!IS_ERR_OR_NULL(fotg210->phy))
usb_unregister_notifier(fotg210->phy, &fotg210_phy_notifier);
free_irq(irq, fotg210);
err_req:
fotg210_ep_free_request(&fotg210->ep[0]->ep, fotg210->ep0_req);
@ -1203,22 +1296,11 @@ static int fotg210_udc_probe(struct platform_device *pdev)
err_alloc:
for (i = 0; i < FOTG210_MAX_NUM_EP; i++)
kfree(fotg210->ep[i]);
kfree(fotg210);
err_pclk:
if (!IS_ERR(fotg210->pclk))
clk_disable_unprepare(fotg210->pclk);
err:
kfree(fotg210);
return ret;
}
static struct platform_driver fotg210_driver = {
.driver = {
.name = udc_name,
},
.probe = fotg210_udc_probe,
.remove = fotg210_udc_remove,
};
module_platform_driver(fotg210_driver);
MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang <john453@faraday-tech.com>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION(DRIVER_DESC);

View File

@ -231,9 +231,12 @@ struct fotg210_ep {
struct fotg210_udc {
spinlock_t lock; /* protect the struct */
void __iomem *reg;
struct clk *pclk;
unsigned long irq_trigger;
struct device *dev;
struct usb_phy *phy;
struct usb_gadget gadget;
struct usb_gadget_driver *driver;

View File

@ -0,0 +1,42 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __FOTG210_H
#define __FOTG210_H
#ifdef CONFIG_USB_FOTG210_HCD
int fotg210_hcd_probe(struct platform_device *pdev);
int fotg210_hcd_remove(struct platform_device *pdev);
int fotg210_hcd_init(void);
void fotg210_hcd_cleanup(void);
#else
static inline int fotg210_hcd_probe(struct platform_device *pdev)
{
return 0;
}
static inline int fotg210_hcd_remove(struct platform_device *pdev)
{
return 0;
}
static inline int fotg210_hcd_init(void)
{
return 0;
}
static inline void fotg210_hcd_cleanup(void)
{
}
#endif
#ifdef CONFIG_USB_FOTG210_UDC
int fotg210_udc_probe(struct platform_device *pdev);
int fotg210_udc_remove(struct platform_device *pdev);
#else
static inline int fotg210_udc_probe(struct platform_device *pdev)
{
return 0;
}
static inline int fotg210_udc_remove(struct platform_device *pdev)
{
return 0;
}
#endif
#endif /* __FOTG210_H */

View File

@ -3,6 +3,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/kstrtox.h>
#include <linux/nls.h>
#include <linux/usb/composite.h>
#include <linux/usb/gadget_configfs.h>
@ -800,7 +801,7 @@ static ssize_t os_desc_use_store(struct config_item *item, const char *page,
bool use;
mutex_lock(&gi->lock);
ret = strtobool(page, &use);
ret = kstrtobool(page, &use);
if (!ret) {
gi->use_os_desc = use;
ret = len;

View File

@ -685,7 +685,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
struct usb_composite_dev *cdev = c->cdev;
struct f_ecm *ecm = func_to_ecm(f);
struct usb_string *us;
int status;
int status = 0;
struct usb_ep *ep;
struct f_ecm_opts *ecm_opts;
@ -695,23 +695,19 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
ecm_opts = container_of(f->fi, struct f_ecm_opts, func_inst);
/*
* in drivers/usb/gadget/configfs.c:configfs_composite_bind()
* configurations are bound in sequence with list_for_each_entry,
* in each configuration its functions are bound in sequence
* with list_for_each_entry, so we assume no race condition
* with regard to ecm_opts->bound access
*/
mutex_lock(&ecm_opts->lock);
gether_set_gadget(ecm_opts->net, cdev->gadget);
if (!ecm_opts->bound) {
mutex_lock(&ecm_opts->lock);
gether_set_gadget(ecm_opts->net, cdev->gadget);
status = gether_register_netdev(ecm_opts->net);
mutex_unlock(&ecm_opts->lock);
if (status)
return status;
ecm_opts->bound = true;
}
mutex_unlock(&ecm_opts->lock);
if (status)
return status;
ecm_string_defs[1].s = ecm->ethaddr;
us = usb_gstrings_attach(cdev, ecm_strings,

View File

@ -71,7 +71,7 @@ struct f_hidg {
wait_queue_head_t write_queue;
struct usb_request *req;
int minor;
struct device dev;
struct cdev cdev;
struct usb_function func;
@ -84,6 +84,14 @@ static inline struct f_hidg *func_to_hidg(struct usb_function *f)
return container_of(f, struct f_hidg, func);
}
static void hidg_release(struct device *dev)
{
struct f_hidg *hidg = container_of(dev, struct f_hidg, dev);
kfree(hidg->set_report_buf);
kfree(hidg);
}
/*-------------------------------------------------------------------------*/
/* Static descriptors */
@ -904,9 +912,7 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
struct usb_ep *ep;
struct f_hidg *hidg = func_to_hidg(f);
struct usb_string *us;
struct device *device;
int status;
dev_t dev;
/* maybe allocate device-global string IDs, and patch descriptors */
us = usb_gstrings_attach(c->cdev, ct_func_strings,
@ -999,21 +1005,11 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
/* create char device */
cdev_init(&hidg->cdev, &f_hidg_fops);
dev = MKDEV(major, hidg->minor);
status = cdev_add(&hidg->cdev, dev, 1);
status = cdev_device_add(&hidg->cdev, &hidg->dev);
if (status)
goto fail_free_descs;
device = device_create(hidg_class, NULL, dev, NULL,
"%s%d", "hidg", hidg->minor);
if (IS_ERR(device)) {
status = PTR_ERR(device);
goto del;
}
return 0;
del:
cdev_del(&hidg->cdev);
fail_free_descs:
usb_free_all_descriptors(f);
fail:
@ -1244,9 +1240,7 @@ static void hidg_free(struct usb_function *f)
hidg = func_to_hidg(f);
opts = container_of(f->fi, struct f_hid_opts, func_inst);
kfree(hidg->report_desc);
kfree(hidg->set_report_buf);
kfree(hidg);
put_device(&hidg->dev);
mutex_lock(&opts->lock);
--opts->refcnt;
mutex_unlock(&opts->lock);
@ -1256,8 +1250,7 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_hidg *hidg = func_to_hidg(f);
device_destroy(hidg_class, MKDEV(major, hidg->minor));
cdev_del(&hidg->cdev);
cdev_device_del(&hidg->cdev, &hidg->dev);
usb_free_all_descriptors(f);
}
@ -1266,6 +1259,7 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi)
{
struct f_hidg *hidg;
struct f_hid_opts *opts;
int ret;
/* allocate and initialize one new instance */
hidg = kzalloc(sizeof(*hidg), GFP_KERNEL);
@ -1275,25 +1269,31 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi)
opts = container_of(fi, struct f_hid_opts, func_inst);
mutex_lock(&opts->lock);
++opts->refcnt;
hidg->minor = opts->minor;
device_initialize(&hidg->dev);
hidg->dev.release = hidg_release;
hidg->dev.class = hidg_class;
hidg->dev.devt = MKDEV(major, opts->minor);
ret = dev_set_name(&hidg->dev, "hidg%d", opts->minor);
if (ret)
goto err_unlock;
hidg->bInterfaceSubClass = opts->subclass;
hidg->bInterfaceProtocol = opts->protocol;
hidg->report_length = opts->report_length;
hidg->report_desc_length = opts->report_desc_length;
if (opts->report_desc) {
hidg->report_desc = kmemdup(opts->report_desc,
opts->report_desc_length,
GFP_KERNEL);
hidg->report_desc = devm_kmemdup(&hidg->dev, opts->report_desc,
opts->report_desc_length,
GFP_KERNEL);
if (!hidg->report_desc) {
kfree(hidg);
mutex_unlock(&opts->lock);
return ERR_PTR(-ENOMEM);
ret = -ENOMEM;
goto err_put_device;
}
}
hidg->use_out_ep = !opts->no_out_endpoint;
++opts->refcnt;
mutex_unlock(&opts->lock);
hidg->func.name = "hid";
@ -1308,6 +1308,12 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi)
hidg->qlen = 4;
return &hidg->func;
err_put_device:
put_device(&hidg->dev);
err_unlock:
mutex_unlock(&opts->lock);
return ERR_PTR(ret);
}
DECLARE_USB_FUNCTION_INIT(hid, hidg_alloc_inst, hidg_alloc);

View File

@ -176,6 +176,7 @@
#include <linux/fcntl.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/kstrtox.h>
#include <linux/kthread.h>
#include <linux/sched/signal.h>
#include <linux/limits.h>
@ -3387,7 +3388,7 @@ static ssize_t fsg_opts_stall_store(struct config_item *item, const char *page,
return -EBUSY;
}
ret = strtobool(page, &stall);
ret = kstrtobool(page, &stall);
if (!ret) {
opts->common->can_stall = stall;
ret = len;

View File

@ -364,7 +364,7 @@ printer_open(struct inode *inode, struct file *fd)
spin_unlock_irqrestore(&dev->lock, flags);
kref_get(&dev->kref);
DBG(dev, "printer_open returned %x\n", ret);
return ret;
}
@ -382,7 +382,6 @@ printer_close(struct inode *inode, struct file *fd)
spin_unlock_irqrestore(&dev->lock, flags);
kref_put(&dev->kref, printer_dev_free);
DBG(dev, "printer_close\n");
return 0;
}
@ -848,8 +847,6 @@ static void printer_reset_interface(struct printer_dev *dev)
if (dev->interface < 0)
return;
DBG(dev, "%s\n", __func__);
if (dev->in_ep->desc)
usb_ep_disable(dev->in_ep);
@ -887,8 +884,6 @@ static void printer_soft_reset(struct printer_dev *dev)
{
struct usb_request *req;
INFO(dev, "Received Printer Reset Request\n");
if (usb_ep_disable(dev->in_ep))
DBG(dev, "Failed to disable USB in_ep\n");
if (usb_ep_disable(dev->out_ep))
@ -1185,8 +1180,6 @@ static void printer_func_disable(struct usb_function *f)
{
struct printer_dev *dev = func_to_printer(f);
DBG(dev, "%s\n", __func__);
printer_reset_interface(dev);
}

View File

@ -39,9 +39,6 @@ MODULE_PARM_DESC(trace, "Trace level bitmask");
/* string IDs are assigned dynamically */
#define UVC_STRING_CONTROL_IDX 0
#define UVC_STRING_STREAMING_IDX 1
static struct usb_string uvc_en_us_strings[] = {
/* [UVC_STRING_CONTROL_IDX].s = DYNAMIC, */
[UVC_STRING_STREAMING_IDX].s = "Video Streaming",
@ -216,8 +213,9 @@ uvc_function_ep0_complete(struct usb_ep *ep, struct usb_request *req)
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_DATA;
uvc_event->data.length = req->actual;
memcpy(&uvc_event->data.data, req->buf, req->actual);
uvc_event->data.length = min_t(unsigned int, req->actual,
sizeof(uvc_event->data.data));
memcpy(&uvc_event->data.data, req->buf, uvc_event->data.length);
v4l2_event_queue(&uvc->vdev, &v4l2_event);
}
}
@ -228,6 +226,8 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
struct uvc_device *uvc = to_uvc(f);
struct v4l2_event v4l2_event;
struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
unsigned int interface = le16_to_cpu(ctrl->wIndex) & 0xff;
struct usb_ctrlrequest *mctrl;
if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS) {
uvcg_info(f, "invalid request type\n");
@ -248,6 +248,16 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_SETUP;
memcpy(&uvc_event->req, ctrl, sizeof(uvc_event->req));
/* check for the interface number, fixup the interface number in
* the ctrl request so the userspace doesn't have to bother with
* offset and configfs parsing
*/
mctrl = &uvc_event->req;
mctrl->wIndex &= ~cpu_to_le16(0xff);
if (interface == uvc->streaming_intf)
mctrl->wIndex = cpu_to_le16(UVC_STRING_STREAMING_IDX);
v4l2_event_queue(&uvc->vdev, &v4l2_event);
return 0;

View File

@ -23,6 +23,7 @@
#include <linux/blkdev.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/kstrtox.h>
#include <linux/usb/composite.h>
#include "storage_common.h"
@ -396,7 +397,7 @@ ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem,
ssize_t rc;
bool ro;
rc = strtobool(buf, &ro);
rc = kstrtobool(buf, &ro);
if (rc)
return rc;
@ -419,7 +420,7 @@ ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count)
bool nofua;
int ret;
ret = strtobool(buf, &nofua);
ret = kstrtobool(buf, &nofua);
if (ret)
return ret;
@ -470,7 +471,7 @@ ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem,
bool cdrom;
int ret;
ret = strtobool(buf, &cdrom);
ret = kstrtobool(buf, &cdrom);
if (ret)
return ret;
@ -493,7 +494,7 @@ ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf,
bool removable;
int ret;
ret = strtobool(buf, &removable);
ret = kstrtobool(buf, &removable);
if (ret)
return ret;

View File

@ -798,7 +798,6 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g,
net->max_mtu = GETHER_MAX_MTU_SIZE;
dev->gadget = g;
SET_NETDEV_DEV(net, &g->dev);
SET_NETDEV_DEVTYPE(net, &gadget_type);
status = register_netdev(net);
@ -873,8 +872,6 @@ int gether_register_netdev(struct net_device *net)
struct usb_gadget *g;
int status;
if (!net->dev.parent)
return -EINVAL;
dev = netdev_priv(net);
g = dev->gadget;
@ -905,7 +902,6 @@ void gether_set_gadget(struct net_device *net, struct usb_gadget *g)
dev = netdev_priv(net);
dev->gadget = g;
SET_NETDEV_DEV(net, &g->dev);
}
EXPORT_SYMBOL_GPL(gether_set_gadget);

View File

@ -24,6 +24,7 @@
#include <linux/export.h>
#include <linux/module.h>
#include <linux/console.h>
#include <linux/kstrtox.h>
#include <linux/kthread.h>
#include <linux/workqueue.h>
#include <linux/kfifo.h>
@ -1070,7 +1071,7 @@ ssize_t gserial_set_console(unsigned char port_num, const char *page, size_t cou
bool enable;
int ret;
ret = strtobool(page, &enable);
ret = kstrtobool(page, &enable);
if (ret)
return ret;

View File

@ -1512,7 +1512,7 @@ UVCG_UNCOMPRESSED_ATTR(b_bits_per_pixel, bBitsPerPixel, 8);
UVCG_UNCOMPRESSED_ATTR(b_default_frame_index, bDefaultFrameIndex, 8);
UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, 8);
UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, 8);
UVCG_UNCOMPRESSED_ATTR_RO(bm_interface_flags, bmInterfaceFlags, 8);
UVCG_UNCOMPRESSED_ATTR_RO(bm_interlace_flags, bmInterlaceFlags, 8);
#undef UVCG_UNCOMPRESSED_ATTR
#undef UVCG_UNCOMPRESSED_ATTR_RO
@ -1541,7 +1541,7 @@ static struct configfs_attribute *uvcg_uncompressed_attrs[] = {
&uvcg_uncompressed_attr_b_default_frame_index,
&uvcg_uncompressed_attr_b_aspect_ratio_x,
&uvcg_uncompressed_attr_b_aspect_ratio_y,
&uvcg_uncompressed_attr_bm_interface_flags,
&uvcg_uncompressed_attr_bm_interlace_flags,
&uvcg_uncompressed_attr_bma_controls,
NULL,
};
@ -1574,7 +1574,7 @@ static struct config_group *uvcg_uncompressed_make(struct config_group *group,
h->desc.bDefaultFrameIndex = 1;
h->desc.bAspectRatioX = 0;
h->desc.bAspectRatioY = 0;
h->desc.bmInterfaceFlags = 0;
h->desc.bmInterlaceFlags = 0;
h->desc.bCopyProtect = 0;
INIT_LIST_HEAD(&h->fmt.frames);
@ -1700,7 +1700,7 @@ UVCG_MJPEG_ATTR(b_default_frame_index, bDefaultFrameIndex, 8);
UVCG_MJPEG_ATTR_RO(bm_flags, bmFlags, 8);
UVCG_MJPEG_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, 8);
UVCG_MJPEG_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, 8);
UVCG_MJPEG_ATTR_RO(bm_interface_flags, bmInterfaceFlags, 8);
UVCG_MJPEG_ATTR_RO(bm_interlace_flags, bmInterlaceFlags, 8);
#undef UVCG_MJPEG_ATTR
#undef UVCG_MJPEG_ATTR_RO
@ -1728,7 +1728,7 @@ static struct configfs_attribute *uvcg_mjpeg_attrs[] = {
&uvcg_mjpeg_attr_bm_flags,
&uvcg_mjpeg_attr_b_aspect_ratio_x,
&uvcg_mjpeg_attr_b_aspect_ratio_y,
&uvcg_mjpeg_attr_bm_interface_flags,
&uvcg_mjpeg_attr_bm_interlace_flags,
&uvcg_mjpeg_attr_bma_controls,
NULL,
};
@ -1755,7 +1755,7 @@ static struct config_group *uvcg_mjpeg_make(struct config_group *group,
h->desc.bDefaultFrameIndex = 1;
h->desc.bAspectRatioX = 0;
h->desc.bAspectRatioY = 0;
h->desc.bmInterfaceFlags = 0;
h->desc.bmInterlaceFlags = 0;
h->desc.bCopyProtect = 0;
INIT_LIST_HEAD(&h->fmt.frames);

View File

@ -9,6 +9,7 @@
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
@ -109,7 +110,7 @@ static int enable_set(const char *s, const struct kernel_param *kp)
if (!s) /* called for no-arg enable == default */
return 0;
ret = strtobool(s, &do_enable);
ret = kstrtobool(s, &do_enable);
if (ret || enable == do_enable)
return ret;

View File

@ -171,7 +171,7 @@ static const struct uvc_format_uncompressed uvc_format_yuv = {
.bDefaultFrameIndex = 1,
.bAspectRatioX = 0,
.bAspectRatioY = 0,
.bmInterfaceFlags = 0,
.bmInterlaceFlags = 0,
.bCopyProtect = 0,
};
@ -222,7 +222,7 @@ static const struct uvc_format_mjpeg uvc_format_mjpg = {
.bDefaultFrameIndex = 1,
.bAspectRatioX = 0,
.bAspectRatioY = 0,
.bmInterfaceFlags = 0,
.bmInterlaceFlags = 0,
.bCopyProtect = 0,
};

View File

@ -33,7 +33,7 @@ menu "USB Peripheral Controller"
config USB_AT91
tristate "Atmel AT91 USB Device Port"
depends on ARCH_AT91
depends on OF || COMPILE_TEST
depends on OF
help
Many Atmel AT91 processors (such as the AT91RM2000) have a
full speed USB Device Port with support for five configurable
@ -108,17 +108,6 @@ config USB_FUSB300
help
Faraday usb device controller FUSB300 driver
config USB_FOTG210_UDC
depends on HAS_DMA
tristate "Faraday FOTG210 USB Peripheral Controller"
help
Faraday USB2.0 OTG controller which can be configured as
high speed or full speed USB device. This driver supppors
Bulk Transfer so far.
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "fotg210_udc".
config USB_GR_UDC
tristate "Aeroflex Gaisler GRUSBDC USB Peripheral Controller Driver"
depends on HAS_DMA
@ -430,7 +419,7 @@ config USB_EG20T
config USB_GADGET_XILINX
tristate "Xilinx USB Driver"
depends on HAS_DMA
depends on OF || COMPILE_TEST
depends on OF
help
USB peripheral controller driver for Xilinx USB2 device.
Xilinx USB2 device is a soft IP which supports both full

View File

@ -34,7 +34,6 @@ obj-$(CONFIG_USB_EG20T) += pch_udc.o
obj-$(CONFIG_USB_MV_UDC) += mv_udc.o
mv_udc-y := mv_udc_core.o
obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
obj-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o
obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o
obj-$(CONFIG_USB_GR_UDC) += gr_udc.o
obj-$(CONFIG_USB_GADGET_XILINX) += udc-xilinx.o

View File

@ -37,7 +37,7 @@ void ast_vhub_done(struct ast_vhub_ep *ep, struct ast_vhub_req *req,
list_del_init(&req->queue);
if (req->req.status == -EINPROGRESS)
if ((req->req.status == -EINPROGRESS) || (status == -EOVERFLOW))
req->req.status = status;
if (req->req.dma) {

View File

@ -84,6 +84,7 @@ static void ast_vhub_epn_handle_ack(struct ast_vhub_ep *ep)
{
struct ast_vhub_req *req;
unsigned int len;
int status = 0;
u32 stat;
/* Read EP status */
@ -119,9 +120,15 @@ static void ast_vhub_epn_handle_ack(struct ast_vhub_ep *ep)
len = VHUB_EP_DMA_TX_SIZE(stat);
/* If not using DMA, copy data out if needed */
if (!req->req.dma && !ep->epn.is_in && len)
memcpy(req->req.buf + req->req.actual, ep->buf, len);
if (!req->req.dma && !ep->epn.is_in && len) {
if (req->req.actual + len > req->req.length) {
req->last_desc = 1;
status = -EOVERFLOW;
goto done;
} else {
memcpy(req->req.buf + req->req.actual, ep->buf, len);
}
}
/* Adjust size */
req->req.actual += len;
@ -129,9 +136,10 @@ static void ast_vhub_epn_handle_ack(struct ast_vhub_ep *ep)
if (len < ep->ep.maxpacket)
req->last_desc = 1;
done:
/* That's it ? complete the request and pick a new one */
if (req->last_desc >= 0) {
ast_vhub_done(ep, req, 0);
ast_vhub_done(ep, req, status);
req = list_first_entry_or_null(&ep->queue, struct ast_vhub_req,
queue);

View File

@ -1628,10 +1628,7 @@ static int at91rm9200_udc_init(struct at91_udc *udc)
static void at91rm9200_udc_pullup(struct at91_udc *udc, int is_on)
{
if (is_on)
gpiod_set_value(udc->board.pullup_pin, 1);
else
gpiod_set_value(udc->board.pullup_pin, 0);
gpiod_set_value(udc->board.pullup_pin, is_on);
}
static const struct at91_udc_caps at91rm9200_udc_caps = {

View File

@ -734,13 +734,13 @@ int usb_gadget_disconnect(struct usb_gadget *gadget)
}
ret = gadget->ops->pullup(gadget, 0);
if (!ret) {
if (!ret)
gadget->connected = 0;
mutex_lock(&udc_lock);
if (gadget->udc->driver)
gadget->udc->driver->disconnect(gadget);
mutex_unlock(&udc_lock);
}
mutex_lock(&udc_lock);
if (gadget->udc->driver)
gadget->udc->driver->disconnect(gadget);
mutex_unlock(&udc_lock);
out:
trace_usb_gadget_disconnect(gadget, ret);

View File

@ -47,7 +47,7 @@ config USB_XHCI_PCI_RENESAS
tristate "Support for additional Renesas xHCI controller with firmware"
help
Say 'Y' to enable the support for the Renesas xHCI controller with
firmware. Make sure you have the firwmare for the device and
firmware. Make sure you have the firmware for the device and
installed on your system for this device to work.
If unsure, say 'N'.
@ -389,17 +389,6 @@ config USB_ISP1362_HCD
To compile this driver as a module, choose M here: the
module will be called isp1362-hcd.
config USB_FOTG210_HCD
tristate "FOTG210 HCD support"
depends on USB && HAS_DMA && HAS_IOMEM
help
Faraday FOTG210 is an OTG controller which can be configured as
an USB2.0 host. It is designed to meet USB2.0 EHCI specification
with minor modification.
To compile this driver as a module, choose M here: the
module will be called fotg210-hcd.
config USB_MAX3421_HCD
tristate "MAX3421 HCD (USB-over-SPI) support"
depends on USB && SPI

View File

@ -84,6 +84,5 @@ obj-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
obj-$(CONFIG_USB_EHCI_MV) += ehci-mv.o
obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o
obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o
obj-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o
obj-$(CONFIG_USB_MAX3421_HCD) += max3421-hcd.o
obj-$(CONFIG_USB_XEN_HCD) += xen-hcd.o

View File

@ -99,7 +99,7 @@ static int ehci_hcd_grlib_probe(struct platform_device *op)
hcd->rsrc_len = resource_size(&res);
irq = irq_of_parse_and_map(dn, 0);
if (irq == NO_IRQ) {
if (!irq) {
dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n",
__FILE__);
rv = -EBUSY;

View File

@ -411,11 +411,12 @@ static struct pci_driver ehci_pci_driver = {
.remove = ehci_pci_remove,
.shutdown = usb_hcd_pci_shutdown,
#ifdef CONFIG_PM
.driver = {
.pm = &usb_hcd_pci_pm_ops
},
#ifdef CONFIG_PM
.pm = &usb_hcd_pci_pm_ops,
#endif
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
};
static int __init ehci_pci_init(void)

View File

@ -119,7 +119,7 @@ static int ehci_hcd_ppc_of_probe(struct platform_device *op)
hcd->rsrc_len = resource_size(&res);
irq = irq_of_parse_and_map(dn, 0);
if (irq == NO_IRQ) {
if (!irq) {
dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n",
__FILE__);
rv = -EBUSY;

View File

@ -471,7 +471,7 @@ struct ehci_iso_sched {
* acts like a qh would, if EHCI had them for ISO.
*/
struct ehci_iso_stream {
/* first field matches ehci_hq, but is NULL */
/* first field matches ehci_qh, but is NULL */
struct ehci_qh_hw *hw;
u8 bEndpointAddress;

View File

@ -676,7 +676,7 @@ static int of_fhci_probe(struct platform_device *ofdev)
/* USB Host interrupt. */
usb_irq = irq_of_parse_and_map(node, 0);
if (usb_irq == NO_IRQ) {
if (!usb_irq) {
dev_err(dev, "could not get usb irq\n");
ret = -EINVAL;
goto err_usb_irq;

View File

@ -120,7 +120,7 @@ static int ohci_hcd_ppc_of_probe(struct platform_device *op)
}
irq = irq_of_parse_and_map(dn, 0);
if (irq == NO_IRQ) {
if (!irq) {
dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n",
__FILE__);
rv = -EBUSY;

View File

@ -116,7 +116,7 @@ static int uhci_hcd_grlib_probe(struct platform_device *op)
hcd->rsrc_len = resource_size(&res);
irq = irq_of_parse_and_map(dn, 0);
if (irq == NO_IRQ) {
if (!irq) {
printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
rv = -EBUSY;
goto err_usb;

View File

@ -426,24 +426,37 @@ static unsigned int xhci_port_speed(unsigned int port_status)
*/
#define XHCI_PORT_RZ ((1<<2) | (1<<24) | (0xf<<28))
/*
/**
* xhci_port_state_to_neutral() - Clean up read portsc value back into writeable
* @state: u32 port value read from portsc register to be cleanup up
*
* Given a port state, this function returns a value that would result in the
* port being in the same state, if the value was written to the port status
* control register.
* Save Read Only (RO) bits and save read/write bits where
* writing a 0 clears the bit and writing a 1 sets the bit (RWS).
* For all other types (RW1S, RW1CS, RW, and RZ), writing a '0' has no effect.
*
* Return: u32 value that can be written back to portsc register without
* changing port state.
*/
u32 xhci_port_state_to_neutral(u32 state)
{
/* Save read-only status and port state */
return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS);
}
EXPORT_SYMBOL_GPL(xhci_port_state_to_neutral);
/*
* find slot id based on port number.
* @port: The one-based port number from one of the two split roothubs.
/**
* xhci_find_slot_id_by_port() - Find slot id of a usb device on a roothub port
* @hcd: pointer to hcd of the roothub
* @xhci: pointer to xhci structure
* @port: one-based port number of the port in this roothub.
*
* Return: Slot id of the usb device connected to the root port, 0 if not found
*/
int xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
u16 port)
{
@ -465,6 +478,7 @@ int xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
return slot_id;
}
EXPORT_SYMBOL_GPL(xhci_find_slot_id_by_port);
/*
* Stop device

View File

@ -485,6 +485,7 @@ static int xhci_mtk_probe(struct platform_device *pdev)
const struct hc_driver *driver;
struct xhci_hcd *xhci;
struct resource *res;
struct usb_hcd *usb3_hcd;
struct usb_hcd *hcd;
int ret = -ENODEV;
int wakeup_irq;
@ -593,6 +594,7 @@ static int xhci_mtk_probe(struct platform_device *pdev)
xhci = hcd_to_xhci(hcd);
xhci->main_hcd = hcd;
xhci->allow_single_roothub = 1;
/*
* imod_interval is the interrupt moderation value in nanoseconds.
@ -602,24 +604,29 @@ static int xhci_mtk_probe(struct platform_device *pdev)
xhci->imod_interval = 5000;
device_property_read_u32(dev, "imod-interval-ns", &xhci->imod_interval);
xhci->shared_hcd = usb_create_shared_hcd(driver, dev,
dev_name(dev), hcd);
if (!xhci->shared_hcd) {
ret = -ENOMEM;
goto disable_device_wakeup;
}
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret)
goto put_usb3_hcd;
goto disable_device_wakeup;
if (HCC_MAX_PSA(xhci->hcc_params) >= 4 &&
if (!xhci_has_one_roothub(xhci)) {
xhci->shared_hcd = usb_create_shared_hcd(driver, dev,
dev_name(dev), hcd);
if (!xhci->shared_hcd) {
ret = -ENOMEM;
goto dealloc_usb2_hcd;
}
}
usb3_hcd = xhci_get_usb3_hcd(xhci);
if (usb3_hcd && HCC_MAX_PSA(xhci->hcc_params) >= 4 &&
!(xhci->quirks & XHCI_BROKEN_STREAMS))
xhci->shared_hcd->can_do_streams = 1;
usb3_hcd->can_do_streams = 1;
ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
if (ret)
goto dealloc_usb2_hcd;
if (xhci->shared_hcd) {
ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
if (ret)
goto put_usb3_hcd;
}
if (wakeup_irq > 0) {
ret = dev_pm_set_dedicated_wake_irq_reverse(dev, wakeup_irq);
@ -639,15 +646,14 @@ static int xhci_mtk_probe(struct platform_device *pdev)
dealloc_usb3_hcd:
usb_remove_hcd(xhci->shared_hcd);
xhci->shared_hcd = NULL;
dealloc_usb2_hcd:
usb_remove_hcd(hcd);
put_usb3_hcd:
xhci_mtk_sch_exit(mtk);
usb_put_hcd(xhci->shared_hcd);
dealloc_usb2_hcd:
xhci_mtk_sch_exit(mtk);
usb_remove_hcd(hcd);
disable_device_wakeup:
device_init_wakeup(dev, false);
@ -679,10 +685,15 @@ static int xhci_mtk_remove(struct platform_device *pdev)
dev_pm_clear_wake_irq(dev);
device_init_wakeup(dev, false);
usb_remove_hcd(shared_hcd);
xhci->shared_hcd = NULL;
if (shared_hcd) {
usb_remove_hcd(shared_hcd);
xhci->shared_hcd = NULL;
}
usb_remove_hcd(hcd);
usb_put_hcd(shared_hcd);
if (shared_hcd)
usb_put_hcd(shared_hcd);
usb_put_hcd(hcd);
xhci_mtk_sch_exit(mtk);
clk_bulk_disable_unprepare(BULK_CLKS_NUM, mtk->clks);
@ -700,13 +711,16 @@ static int __maybe_unused xhci_mtk_suspend(struct device *dev)
struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
struct usb_hcd *hcd = mtk->hcd;
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct usb_hcd *shared_hcd = xhci->shared_hcd;
int ret;
xhci_dbg(xhci, "%s: stop port polling\n", __func__);
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
del_timer_sync(&hcd->rh_timer);
clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
del_timer_sync(&xhci->shared_hcd->rh_timer);
if (shared_hcd) {
clear_bit(HCD_FLAG_POLL_RH, &shared_hcd->flags);
del_timer_sync(&shared_hcd->rh_timer);
}
ret = xhci_mtk_host_disable(mtk);
if (ret)
@ -718,8 +732,10 @@ static int __maybe_unused xhci_mtk_suspend(struct device *dev)
restart_poll_rh:
xhci_dbg(xhci, "%s: restart port polling\n", __func__);
set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
usb_hcd_poll_rh_status(xhci->shared_hcd);
if (shared_hcd) {
set_bit(HCD_FLAG_POLL_RH, &shared_hcd->flags);
usb_hcd_poll_rh_status(shared_hcd);
}
set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
usb_hcd_poll_rh_status(hcd);
return ret;
@ -730,6 +746,7 @@ static int __maybe_unused xhci_mtk_resume(struct device *dev)
struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
struct usb_hcd *hcd = mtk->hcd;
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct usb_hcd *shared_hcd = xhci->shared_hcd;
int ret;
usb_wakeup_set(mtk, false);
@ -742,8 +759,10 @@ static int __maybe_unused xhci_mtk_resume(struct device *dev)
goto disable_clks;
xhci_dbg(xhci, "%s: restart port polling\n", __func__);
set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
usb_hcd_poll_rh_status(xhci->shared_hcd);
if (shared_hcd) {
set_bit(HCD_FLAG_POLL_RH, &shared_hcd->flags);
usb_hcd_poll_rh_status(shared_hcd);
}
set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
usb_hcd_poll_rh_status(hcd);
return 0;

View File

@ -59,6 +59,7 @@
#define PCI_DEVICE_ID_INTEL_TIGER_LAKE_XHCI 0x9a13
#define PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_XHCI 0x1138
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI 0x51ed
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_N_PCH_XHCI 0x54ed
#define PCI_DEVICE_ID_AMD_RENOIR_XHCI 0x1639
#define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9
@ -246,7 +247,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
xhci->quirks |= XHCI_MISSING_CAS;
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
pdev->device == PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI)
(pdev->device == PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_ALDER_LAKE_N_PCH_XHCI))
xhci->quirks |= XHCI_RESET_TO_DEFAULT;
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
@ -620,6 +622,57 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
return retval;
}
static int xhci_pci_poweroff_late(struct usb_hcd *hcd, bool do_wakeup)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct xhci_port *port;
struct usb_device *udev;
unsigned int slot_id;
u32 portsc;
int i;
/*
* Systems with XHCI_RESET_TO_DEFAULT quirk have boot firmware that
* cause significant boot delay if usb ports are in suspended U3 state
* during boot. Some USB devices survive in U3 state over S4 hibernate
*
* Disable ports that are in U3 if remote wake is not enabled for either
* host controller or connected device
*/
if (!(xhci->quirks & XHCI_RESET_TO_DEFAULT))
return 0;
for (i = 0; i < HCS_MAX_PORTS(xhci->hcs_params1); i++) {
port = &xhci->hw_ports[i];
portsc = readl(port->addr);
if ((portsc & PORT_PLS_MASK) != XDEV_U3)
continue;
slot_id = xhci_find_slot_id_by_port(port->rhub->hcd, xhci,
port->hcd_portnum + 1);
if (!slot_id || !xhci->devs[slot_id]) {
xhci_err(xhci, "No dev for slot_id %d for port %d-%d in U3\n",
slot_id, port->rhub->hcd->self.busnum, port->hcd_portnum + 1);
continue;
}
udev = xhci->devs[slot_id]->udev;
/* if wakeup is enabled then don't disable the port */
if (udev->do_remote_wakeup && do_wakeup)
continue;
xhci_dbg(xhci, "port %d-%d in U3 without wakeup, disable it\n",
port->rhub->hcd->self.busnum, port->hcd_portnum + 1);
portsc = xhci_port_state_to_neutral(portsc);
writel(portsc | PORT_PE, port->addr);
}
return 0;
}
static void xhci_pci_shutdown(struct usb_hcd *hcd)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
@ -673,11 +726,12 @@ static struct pci_driver xhci_pci_driver = {
/* suspend and resume implemented later */
.shutdown = usb_hcd_pci_shutdown,
#ifdef CONFIG_PM
.driver = {
.pm = &usb_hcd_pci_pm_ops
},
#ifdef CONFIG_PM
.pm = &usb_hcd_pci_pm_ops,
#endif
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
};
static int __init xhci_pci_init(void)
@ -686,6 +740,7 @@ static int __init xhci_pci_init(void)
#ifdef CONFIG_PM
xhci_pci_hc_driver.pci_suspend = xhci_pci_suspend;
xhci_pci_hc_driver.pci_resume = xhci_pci_resume;
xhci_pci_hc_driver.pci_poweroff_late = xhci_pci_poweroff_late;
xhci_pci_hc_driver.shutdown = xhci_pci_shutdown;
#endif
return pci_register_driver(&xhci_pci_driver);

View File

@ -896,7 +896,7 @@ static int xhci_reset_halted_ep(struct xhci_hcd *xhci, unsigned int slot_id,
}
static int xhci_handle_halted_endpoint(struct xhci_hcd *xhci,
struct xhci_virt_ep *ep, unsigned int stream_id,
struct xhci_virt_ep *ep,
struct xhci_td *td,
enum xhci_ep_reset_type reset_type)
{
@ -1110,8 +1110,7 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,
td->status = -EPROTO;
}
/* reset ep, reset handler cleans up cancelled tds */
err = xhci_handle_halted_endpoint(xhci, ep, 0, td,
reset_type);
err = xhci_handle_halted_endpoint(xhci, ep, td, reset_type);
if (err)
break;
ep->ep_state &= ~EP_STOP_CMD_PENDING;
@ -2183,8 +2182,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
}
/* Almost same procedure as for STALL_ERROR below */
xhci_clear_hub_tt_buffer(xhci, td, ep);
xhci_handle_halted_endpoint(xhci, ep, ep_ring->stream_id, td,
EP_HARD_RESET);
xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET);
return 0;
case COMP_STALL_ERROR:
/*
@ -2200,8 +2198,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
if (ep->ep_index != 0)
xhci_clear_hub_tt_buffer(xhci, td, ep);
xhci_handle_halted_endpoint(xhci, ep, ep_ring->stream_id, td,
EP_HARD_RESET);
xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET);
return 0; /* xhci_handle_halted_endpoint marked td cancelled */
default:
@ -2458,7 +2455,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
switch (trb_comp_code) {
case COMP_SUCCESS:
ep_ring->err_count = 0;
ep->err_count = 0;
/* handle success with untransferred data as short packet */
if (ep_trb != td->last_trb || remaining) {
xhci_warn(xhci, "WARN Successful completion on short TX\n");
@ -2484,14 +2481,13 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
break;
case COMP_USB_TRANSACTION_ERROR:
if (xhci->quirks & XHCI_NO_SOFT_RETRY ||
(ep_ring->err_count++ > MAX_SOFT_RETRY) ||
(ep->err_count++ > MAX_SOFT_RETRY) ||
le32_to_cpu(slot_ctx->tt_info) & TT_SLOT)
break;
td->status = 0;
xhci_handle_halted_endpoint(xhci, ep, ep_ring->stream_id, td,
EP_SOFT_RESET);
xhci_handle_halted_endpoint(xhci, ep, td, EP_SOFT_RESET);
return 0;
default:
/* do nothing */
@ -2565,8 +2561,14 @@ static int handle_tx_event(struct xhci_hcd *xhci,
case COMP_USB_TRANSACTION_ERROR:
case COMP_INVALID_STREAM_TYPE_ERROR:
case COMP_INVALID_STREAM_ID_ERROR:
xhci_handle_halted_endpoint(xhci, ep, 0, NULL,
EP_SOFT_RESET);
xhci_dbg(xhci, "Stream transaction error ep %u no id\n",
ep_index);
if (ep->err_count++ > MAX_SOFT_RETRY)
xhci_handle_halted_endpoint(xhci, ep, NULL,
EP_HARD_RESET);
else
xhci_handle_halted_endpoint(xhci, ep, NULL,
EP_SOFT_RESET);
goto cleanup;
case COMP_RING_UNDERRUN:
case COMP_RING_OVERRUN:
@ -2749,9 +2751,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
if (trb_comp_code == COMP_STALL_ERROR ||
xhci_requires_manual_halt_cleanup(xhci, ep_ctx,
trb_comp_code)) {
xhci_handle_halted_endpoint(xhci, ep,
ep_ring->stream_id,
NULL,
xhci_handle_halted_endpoint(xhci, ep, NULL,
EP_HARD_RESET);
}
goto cleanup;
@ -2844,9 +2844,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
if (trb_comp_code == COMP_STALL_ERROR ||
xhci_requires_manual_halt_cleanup(xhci, ep_ctx,
trb_comp_code))
xhci_handle_halted_endpoint(xhci, ep,
ep_ring->stream_id,
td, EP_HARD_RESET);
xhci_handle_halted_endpoint(xhci, ep, td,
EP_HARD_RESET);
goto cleanup;
}
@ -3031,6 +3030,11 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
if (!(status & STS_EINT))
goto out;
if (status & STS_HCE) {
xhci_warn(xhci, "WARNING: Host Controller Error\n");
goto out;
}
if (status & STS_FATAL) {
xhci_warn(xhci, "WARNING: Host System Error\n");
xhci_halt(xhci);

View File

@ -933,6 +933,7 @@ struct xhci_virt_ep {
* have to restore the device state to the previous state
*/
struct xhci_ring *new_ring;
unsigned int err_count;
unsigned int ep_state;
#define SET_DEQ_PENDING (1 << 0)
#define EP_HALTED (1 << 1) /* For stall handling */
@ -1627,7 +1628,6 @@ struct xhci_ring {
* if we own the TRB (if we are the consumer). See section 4.9.1.
*/
u32 cycle_state;
unsigned int err_count;
unsigned int stream_id;
unsigned int num_segs;
unsigned int num_trbs_free;

View File

@ -298,7 +298,7 @@ config BRCM_USB_PINMAP
config USB_ONBOARD_HUB
tristate "Onboard USB hub support"
depends on OF || COMPILE_TEST
depends on OF
help
Say Y here if you want to support discrete onboard USB hubs that
don't require an additional control bus for initialization, but

View File

@ -1624,7 +1624,6 @@ wait:if (ftdi->disconnected > 0) {
char data[30 *3 + 4];
char *d = data;
int m = (sizeof(data) - 1) / 3 - 1;
int l = 0;
struct u132_target *target = &ftdi->target[ed];
struct u132_command *command = &ftdi->command[
COMMAND_MASK & ftdi->command_next];
@ -1647,7 +1646,6 @@ wait:if (ftdi->disconnected > 0) {
} else if (i++ < m) {
int w = sprintf(d, " %02X", *b++);
d += w;
l += w;
} else
d += sprintf(d, " ..");
}
@ -1956,7 +1954,6 @@ static int ftdi_elan_synchronize(struct usb_ftdi *ftdi)
int long_stop = 10;
int retry_on_timeout = 5;
int retry_on_empty = 10;
int err_count = 0;
retval = ftdi_elan_flush_input_fifo(ftdi);
if (retval)
return retval;
@ -2051,7 +2048,6 @@ static int ftdi_elan_synchronize(struct usb_ftdi *ftdi)
continue;
}
} else {
err_count += 1;
dev_err(&ftdi->udev->dev, "error = %d\n",
retval);
if (read_stop-- > 0) {

View File

@ -331,6 +331,7 @@ static struct platform_driver onboard_hub_driver = {
/************************** USB driver **************************/
#define VENDOR_ID_GENESYS 0x05e3
#define VENDOR_ID_MICROCHIP 0x0424
#define VENDOR_ID_REALTEK 0x0bda
#define VENDOR_ID_TI 0x0451
@ -407,6 +408,7 @@ static void onboard_hub_usbdev_disconnect(struct usb_device *udev)
}
static const struct usb_device_id onboard_hub_id_table[] = {
{ USB_DEVICE(VENDOR_ID_GENESYS, 0x0608) }, /* Genesys Logic GL850G USB 2.0 */
{ USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2514) }, /* USB2514B USB 2.0 */
{ USB_DEVICE(VENDOR_ID_REALTEK, 0x0411) }, /* RTS5411 USB 3.1 */
{ USB_DEVICE(VENDOR_ID_REALTEK, 0x5411) }, /* RTS5411 USB 2.1 */

View File

@ -22,10 +22,15 @@ static const struct onboard_hub_pdata ti_tusb8041_data = {
.reset_us = 3000,
};
static const struct onboard_hub_pdata genesys_gl850g_data = {
.reset_us = 3,
};
static const struct of_device_id onboard_hub_match[] = {
{ .compatible = "usb424,2514", .data = &microchip_usb424_data, },
{ .compatible = "usb451,8140", .data = &ti_tusb8041_data, },
{ .compatible = "usb451,8142", .data = &ti_tusb8041_data, },
{ .compatible = "usb5e3,608", .data = &genesys_gl850g_data, },
{ .compatible = "usbbda,411", .data = &realtek_rts5411_data, },
{ .compatible = "usbbda,5411", .data = &realtek_rts5411_data, },
{ .compatible = "usbbda,414", .data = &realtek_rts5411_data, },

View File

@ -3,7 +3,6 @@
config USB_SISUSBVGA
tristate "USB 2.0 SVGA dongle support (Net2280/SiS315)"
depends on (USB_MUSB_HDRC || USB_EHCI_HCD)
select FONT_SUPPORT if USB_SISUSBVGA_CON
help
Say Y here if you intend to attach a USB2VGA dongle based on a
Net2280 and a SiS315 chip.
@ -13,36 +12,3 @@ config USB_SISUSBVGA
To compile this driver as a module, choose M here; the module will be
called sisusbvga. If unsure, say N.
config USB_SISUSBVGA_CON
bool "Text console and mode switching support" if USB_SISUSBVGA
depends on VT && BROKEN
select FONT_8x16
help
Say Y here if you want a VGA text console via the USB dongle or
want to support userland applications that utilize the driver's
display mode switching capabilities.
Note that this console supports VGA/EGA text mode only.
By default, the console part of the driver will not kick in when
the driver is initialized. If you want the driver to take over
one or more of the consoles, you need to specify the number of
the first and last consoles (starting at 1) as driver parameters.
For example, if the driver is compiled as a module:
modprobe sisusbvga first=1 last=5
If you use hotplug, add this to your modutils config files with
the "options" keyword, such as eg.
options sisusbvga first=1 last=5
If the driver is compiled into the kernel image, the parameters
must be given in the kernel command like, such as
sisusbvga.first=1 sisusbvga.last=5

View File

@ -4,6 +4,3 @@
#
obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga.o
sisusbvga-y := sisusb.o
sisusbvga-$(CONFIG_USB_SISUSBVGA_CON) += sisusb_con.o sisusb_init.o

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