Felipe writes: USB: changes for v5.7 merge window Lots of changes on dwc3 this time, most of them from Thinh fixing a bunch of really old mishaps on the driver. DWC2 got support for STM32MP15 and a couple RockChip SoCs while DWC3 learned about Amlogic A1 family. Apart from these, we have a few spelling fixes and other minor non-critical fixes all over the place. Signed-off-by: Felipe Balbi <balbi@kernel.org> * tag 'usb-for-v5.7' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb: (41 commits) dt-bindings: usb: add documentation for aspeed usb-vhub ARM: dts: aspeed-g4: add vhub port and endpoint properties ARM: dts: aspeed-g5: add vhub port and endpoint properties ARM: dts: aspeed-g6: add usb functions usb: gadget: aspeed: add ast2600 vhub support usb: gadget: aspeed: read vhub properties from device tree usb: gadget: aspeed: support per-vhub usb descriptors usb: gadget: f_phonet: Replace zero-length array with flexible-array member usb: gadget: composite: Inform controller driver of self-powered usb: gadget: amd5536udc: fix spelling mistake "reserverd" -> "reserved" udc: s3c-hsudc: Silence warning about supplies during deferred probe usb: dwc2: Silence warning about supplies during deferred probe dt-bindings: usb: dwc2: add compatible property for rk3368 usb dt-bindings: usb: dwc2: add compatible property for rk3328 usb usb: gadget: add raw-gadget interface usb: dwc2: Implement set_selfpowered() usb: dwc3: qcom: Replace <linux/clk-provider.h> by <linux/of_clk.h> usb: dwc3: core: don't do suspend for device mode if already suspended usb: dwc3: Rework resets initialization to be more flexible usb: dwc3: Rework clock initialization to be more flexible ...
Unified · Split
| @@ -22,10 +22,14 @@ description: | · 21 unmodified lines | |||
| 22 | The DWC3 Glue controls the PHY routing and power, an interrupt line is | 22 | The DWC3 Glue controls the PHY routing and power, an interrupt line is |
| 23 | connected to the Glue to serve as OTG ID change detection. | 23 | connected to the Glue to serve as OTG ID change detection. |
| 24 | 24 | ||
| 25 | The Amlogic A1 embeds a DWC3 USB IP Core configured for USB2 in | ||
| 26 | host-only mode. | ||
| 27 | |||
| 25 | properties: | 28 | properties: |
| 26 | compatible: | 29 | compatible: |
| 27 | enum: | 30 | enum: |
| 28 | - amlogic,meson-g12a-usb-ctrl | 31 | - amlogic,meson-g12a-usb-ctrl |
| 32 | - amlogic,meson-a1-usb-ctrl | ||
| 29 | 33 | ||
| 30 | ranges: true | 34 | ranges: true |
| 31 | 35 | ||
| @@ -84,6 +88,25 @@ required: · 52 unmodified lines | |||
| 84 | - phys | 88 | - phys |
| 85 | - dr_mode | 89 | - dr_mode |
| 86 | 90 | ||
| 91 | allOf: | ||
| 92 | - if: | ||
| 93 | properties: | ||
| 94 | compatible: | ||
| 95 | enum: | ||
| 96 | - amlogic,meson-a1-usb-ctrl | ||
| 97 | |||
| 98 | then: | ||
| 99 | properties: | ||
| 100 | clocks: | ||
| 101 | minItems: 3 | ||
| 102 | clock-names: | ||
| 103 | items: | ||
| 104 | - const: usb_ctrl | ||
| 105 | - const: usb_bus | ||
| 106 | - const: xtal_usb_ctrl | ||
| 107 | required: | ||
| 108 | - clock-names | ||
| 109 | |||
| 87 | examples: | 110 | examples: |
| 88 | - | | 111 | - | |
| 89 | usb: usb@ffe09000 { | 112 | usb: usb@ffe09000 { |
| @@ -0,0 +1,77 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | # Copyright (c) 2020 Facebook Inc. | ||
| 3 | %YAML 1.2 | ||
| 4 | --- | ||
| 5 | $id: http://devicetree.org/schemas/usb/aspeed,usb-vhub.yaml# | ||
| 6 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 7 | |||
| 8 | title: ASPEED USB 2.0 Virtual Hub Controller | ||
| 9 | |||
| 10 | maintainers: | ||
| 11 | - Benjamin Herrenschmidt <benh@kernel.crashing.org> | ||
| 12 | |||
| 13 | description: |+ | ||
| 14 | The ASPEED USB 2.0 Virtual Hub Controller implements 1 set of USB Hub | ||
| 15 | register and several sets of Device and Endpoint registers to support | ||
| 16 | the Virtual Hub's downstream USB devices. | ||
| 17 | |||
| 18 | Supported number of devices and endpoints vary depending on hardware | ||
| 19 | revisions. AST2400 and AST2500 Virtual Hub supports 5 downstream devices | ||
| 20 | and 15 generic endpoints, while AST2600 Virtual Hub supports 7 downstream | ||
| 21 | devices and 21 generic endpoints. | ||
| 22 | |||
| 23 | properties: | ||
| 24 | compatible: | ||
| 25 | enum: | ||
| 26 | - aspeed,ast2400-usb-vhub | ||
| 27 | - aspeed,ast2500-usb-vhub | ||
| 28 | - aspeed,ast2600-usb-vhub | ||
| 29 | |||
| 30 | reg: | ||
| 31 | maxItems: 1 | ||
| 32 | |||
| 33 | clocks: | ||
| 34 | maxItems: 1 | ||
| 35 | |||
| 36 | interrupts: | ||
| 37 | maxItems: 1 | ||
| 38 | |||
| 39 | aspeed,vhub-downstream-ports: | ||
| 40 | description: Number of downstream ports supported by the Virtual Hub | ||
| 41 | allOf: | ||
| 42 | - $ref: /schemas/types.yaml#/definitions/uint32 | ||
| 43 | - default: 5 | ||
| 44 | minimum: 1 | ||
| 45 | maximum: 7 | ||
| 46 | |||
| 47 | aspeed,vhub-generic-endpoints: | ||
| 48 | description: Number of generic endpoints supported by the Virtual Hub | ||
| 49 | allOf: | ||
| 50 | - $ref: /schemas/types.yaml#/definitions/uint32 | ||
| 51 | - default: 15 | ||
| 52 | minimum: 1 | ||
| 53 | maximum: 21 | ||
| 54 | |||
| 55 | required: | ||
| 56 | - compatible | ||
| 57 | - reg | ||
| 58 | - clocks | ||
| 59 | - interrupts | ||
| 60 | - aspeed,vhub-downstream-ports | ||
| 61 | - aspeed,vhub-generic-endpoints | ||
| 62 | |||
| 63 | additionalProperties: false | ||
| 64 | |||
| 65 | examples: | ||
| 66 | - | | ||
| 67 | #include <dt-bindings/clock/aspeed-clock.h> | ||
| 68 | vhub: usb-vhub@1e6a0000 { | ||
| 69 | compatible = "aspeed,ast2500-usb-vhub"; | ||
| 70 | reg = <0x1e6a0000 0x300>; | ||
| 71 | interrupts = <5>; | ||
| 72 | clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>; | ||
| 73 | aspeed,vhub-downstream-ports = <5>; | ||
| 74 | aspeed,vhub-generic-endpoints = <15>; | ||
| 75 | pinctrl-names = "default"; | ||
| 76 | pinctrl-0 = <&pinctrl_usb2ad_default>; | ||
| 77 | }; | ||
| @@ -18,27 +18,15 @@ properties: · 17 unmodified lines | |||
| 18 | - const: rockchip,rk3066-usb | 18 | - const: rockchip,rk3066-usb |
| 19 | - const: snps,dwc2 | 19 | - const: snps,dwc2 |
| 20 | - items: | 20 | - items: |
| 21 | - const: rockchip,px30-usb | 21 | - enum: |
| 22 | - const: rockchip,rk3066-usb | 22 | - rockchip,px30-usb |
| 23 | - const: snps,dwc2 | 23 | - rockchip,rk3036-usb |
| 24 | - items: | 24 | - rockchip,rk3188-usb |
| 25 | - const: rockchip,rk3036-usb | 25 | - rockchip,rk3228-usb |
| 26 | - const: rockchip,rk3066-usb | 26 | - rockchip,rk3288-usb |
| 27 | - const: snps,dwc2 | 27 | - rockchip,rk3328-usb |
| 28 | - items: | 28 | - rockchip,rk3368-usb |
| 29 | - const: rockchip,rv1108-usb | 29 | - rockchip,rv1108-usb |
| 30 | - const: rockchip,rk3066-usb | ||
| 31 | - const: snps,dwc2 | ||
| 32 | - items: | ||
| 33 | - const: rockchip,rk3188-usb | ||
| 34 | - const: rockchip,rk3066-usb | ||
| 35 | - const: snps,dwc2 | ||
| 36 | - items: | ||
| 37 | - const: rockchip,rk3228-usb | ||
| 38 | - const: rockchip,rk3066-usb | ||
| 39 | - const: snps,dwc2 | ||
| 40 | - items: | ||
| 41 | - const: rockchip,rk3288-usb | ||
| 42 | - const: rockchip,rk3066-usb | 30 | - const: rockchip,rk3066-usb |
| 43 | - const: snps,dwc2 | 31 | - const: snps,dwc2 |
| 44 | - const: lantiq,arx100-usb | 32 | - const: lantiq,arx100-usb |
| @@ -7,7 +7,8 @@ Required properties: · 6 unmodified lines | |||
| 7 | - compatible: must be "snps,dwc3" | 7 | - compatible: must be "snps,dwc3" |
| 8 | - reg : Address and length of the register set for the device | 8 | - reg : Address and length of the register set for the device |
| 9 | - interrupts: Interrupts used by the dwc3 controller. | 9 | - interrupts: Interrupts used by the dwc3 controller. |
| 10 | - clock-names: should contain "ref", "bus_early", "suspend" | 10 | - clock-names: list of clock names. Ideally should be "ref", |
| 11 | "bus_early", "suspend" but may be less or more. | ||
| 11 | - clocks: list of phandle and clock specifier pairs corresponding to | 12 | - clocks: list of phandle and clock specifier pairs corresponding to |
| 12 | entries in the clock-names property. | 13 | entries in the clock-names property. |
| 13 | 14 | ||
| @@ -36,7 +37,7 @@ Optional properties: · 22 unmodified lines | |||
| 36 | - phys: from the *Generic PHY* bindings | 37 | - phys: from the *Generic PHY* bindings |
| 37 | - phy-names: from the *Generic PHY* bindings; supported names are "usb2-phy" | 38 | - phy-names: from the *Generic PHY* bindings; supported names are "usb2-phy" |
| 38 | or "usb3-phy". | 39 | or "usb3-phy". |
| 39 | - resets: a single pair of phandle and reset specifier | 40 | - resets: set of phandle and reset specifier pairs |
| 40 | - snps,usb2-lpm-disable: indicate if we don't want to enable USB2 HW LPM | 41 | - snps,usb2-lpm-disable: indicate if we don't want to enable USB2 HW LPM |
| 41 | - snps,usb3_lpm_capable: determines if platform is USB3 LPM capable | 42 | - snps,usb3_lpm_capable: determines if platform is USB3 LPM capable |
| 42 | - snps,dis-start-transfer-quirk: when set, disable isoc START TRANSFER command | 43 | - snps,dis-start-transfer-quirk: when set, disable isoc START TRANSFER command |
| @@ -75,6 +76,8 @@ Optional properties: · 32 unmodified lines | |||
| 75 | from P0 to P1/P2/P3 without delay. | 76 | from P0 to P1/P2/P3 without delay. |
| 76 | - snps,dis-tx-ipgap-linecheck-quirk: when set, disable u2mac linestate check | 77 | - snps,dis-tx-ipgap-linecheck-quirk: when set, disable u2mac linestate check |
| 77 | during HS transmit. | 78 | during HS transmit. |
| 79 | - snps,parkmode-disable-ss-quirk: when set, all SuperSpeed bus instances in | ||
| 80 | park mode are disabled. | ||
| 78 | - snps,dis_metastability_quirk: when set, disable metastability workaround. | 81 | - snps,dis_metastability_quirk: when set, disable metastability workaround. |
| 79 | CAUTION: use only if you are absolutely sure of it. | 82 | CAUTION: use only if you are absolutely sure of it. |
| 80 | - snps,is-utmi-l1-suspend: true when DWC3 asserts output signal | 83 | - snps,is-utmi-l1-suspend: true when DWC3 asserts output signal |
| @@ -35,6 +35,12 @@ Optional properties: · 34 unmodified lines | |||
| 35 | the USB data role (USB host or USB device) for a given | 35 | the USB data role (USB host or USB device) for a given |
| 36 | USB connector, such as Type-C, Type-B(micro). | 36 | USB connector, such as Type-C, Type-B(micro). |
| 37 | see connector/usb-connector.txt. | 37 | see connector/usb-connector.txt. |
| 38 | - role-switch-default-mode: indicating if usb-role-switch is enabled, the | ||
| 39 | device default operation mode of controller while usb | ||
| 40 | role is USB_ROLE_NONE. Valid arguments are "host" and | ||
| 41 | "peripheral". Defaults to "peripheral" if not | ||
| 42 | specified. | ||
| 43 | |||
| 38 | 44 | ||
| 39 | This is an attribute to a USB controller such as: | 45 | This is an attribute to a USB controller such as: |
| 40 | 46 | ||
| @@ -0,0 +1,69 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/usb/maxim,max3420-udc.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: MAXIM MAX3420/1 USB Peripheral Controller | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Jassi Brar <jaswinder.singh@linaro.org> | ||
| 11 | |||
| 12 | description: | | ||
| 13 | The controller provices USB2.0 compliant FullSpeed peripheral | ||
| 14 | implementation over the SPI interface. | ||
| 15 | |||
| 16 | Specifications about the part can be found at: | ||
| 17 | http://datasheets.maximintegrated.com/en/ds/MAX3420E.pdf | ||
| 18 | |||
| 19 | properties: | ||
| 20 | compatible: | ||
| 21 | enum: | ||
| 22 | - maxim,max3420-udc | ||
| 23 | - maxim,max3421-udc | ||
| 24 | |||
| 25 | reg: | ||
| 26 | maxItems: 1 | ||
| 27 | |||
| 28 | interrupts: | ||
| 29 | items: | ||
| 30 | - description: usb irq from max3420 | ||
| 31 | - description: vbus detection irq | ||
| 32 | minItems: 1 | ||
| 33 | maxItems: 2 | ||
| 34 | |||
| 35 | interrupt-names: | ||
| 36 | items: | ||
| 37 | - const: udc | ||
| 38 | - const: vbus | ||
| 39 | minItems: 1 | ||
| 40 | maxItems: 2 | ||
| 41 | |||
| 42 | spi-max-frequency: | ||
| 43 | maximum: 26000000 | ||
| 44 | |||
| 45 | required: | ||
| 46 | - compatible | ||
| 47 | - reg | ||
| 48 | - interrupts | ||
| 49 | - interrupt-names | ||
| 50 | |||
| 51 | additionalProperties: false | ||
| 52 | |||
| 53 | examples: | ||
| 54 | - | | ||
| 55 | #include <dt-bindings/gpio/gpio.h> | ||
| 56 | #include <dt-bindings/interrupt-controller/irq.h> | ||
| 57 | spi0 { | ||
| 58 | #address-cells = <1>; | ||
| 59 | #size-cells = <0>; | ||
| 60 | |||
| 61 | udc@0 { | ||
| 62 | compatible = "maxim,max3420-udc"; | ||
| 63 | reg = <0>; | ||
| 64 | interrupt-parent = <&gpio>; | ||
| 65 | interrupts = <0 IRQ_TYPE_EDGE_FALLING>, <10 IRQ_TYPE_EDGE_BOTH>; | ||
| 66 | interrupt-names = "udc", "vbus"; | ||
| 67 | spi-max-frequency = <12500000>; | ||
| 68 | }; | ||
| 69 | }; | ||
| @@ -22,6 +22,7 @@ USB support · 21 unmodified lines | |||
| 22 | misc_usbsevseg | 22 | misc_usbsevseg |
| 23 | mtouchusb | 23 | mtouchusb |
| 24 | ohci | 24 | ohci |
| 25 | raw-gadget | ||
| 25 | usbip_protocol | 26 | usbip_protocol |
| 26 | usbmon | 27 | usbmon |
| 27 | usb-serial | 28 | usb-serial |
| @@ -0,0 +1,61 @@ | |||
| 1 | ============== | ||
| 2 | USB Raw Gadget | ||
| 3 | ============== | ||
| 4 | |||
| 5 | USB Raw Gadget is a kernel module that provides a userspace interface for | ||
| 6 | the USB Gadget subsystem. Essentially it allows to emulate USB devices | ||
| 7 | from userspace. Enabled with CONFIG_USB_RAW_GADGET. Raw Gadget is | ||
| 8 | currently a strictly debugging feature and shouldn't be used in | ||
| 9 | production, use GadgetFS instead. | ||
| 10 | |||
| 11 | Comparison to GadgetFS | ||
| 12 | ~~~~~~~~~~~~~~~~~~~~~~ | ||
| 13 | |||
| 14 | Raw Gadget is similar to GadgetFS, but provides a more low-level and | ||
| 15 | direct access to the USB Gadget layer for the userspace. The key | ||
| 16 | differences are: | ||
| 17 | |||
| 18 | 1. Every USB request is passed to the userspace to get a response, while | ||
| 19 | GadgetFS responds to some USB requests internally based on the provided | ||
| 20 | descriptors. However note, that the UDC driver might respond to some | ||
| 21 | requests on its own and never forward them to the Gadget layer. | ||
| 22 | |||
| 23 | 2. GadgetFS performs some sanity checks on the provided USB descriptors, | ||
| 24 | while Raw Gadget allows you to provide arbitrary data as responses to | ||
| 25 | USB requests. | ||
| 26 | |||
| 27 | 3. Raw Gadget provides a way to select a UDC device/driver to bind to, | ||
| 28 | while GadgetFS currently binds to the first available UDC. | ||
| 29 | |||
| 30 | 4. Raw Gadget uses predictable endpoint names (handles) across different | ||
| 31 | UDCs (as long as UDCs have enough endpoints of each required transfer | ||
| 32 | type). | ||
| 33 | |||
| 34 | 5. Raw Gadget has ioctl-based interface instead of a filesystem-based one. | ||
| 35 | |||
| 36 | Userspace interface | ||
| 37 | ~~~~~~~~~~~~~~~~~~~ | ||
| 38 | |||
| 39 | To create a Raw Gadget instance open /dev/raw-gadget. Multiple raw-gadget | ||
| 40 | instances (bound to different UDCs) can be used at the same time. The | ||
| 41 | interaction with the opened file happens through the ioctl() calls, see | ||
| 42 | comments in include/uapi/linux/usb/raw_gadget.h for details. | ||
| 43 | |||
| 44 | The typical usage of Raw Gadget looks like: | ||
| 45 | |||
| 46 | 1. Open Raw Gadget instance via /dev/raw-gadget. | ||
| 47 | 2. Initialize the instance via USB_RAW_IOCTL_INIT. | ||
| 48 | 3. Launch the instance with USB_RAW_IOCTL_RUN. | ||
| 49 | 4. In a loop issue USB_RAW_IOCTL_EVENT_FETCH calls to receive events from | ||
| 50 | Raw Gadget and react to those depending on what kind of USB device | ||
| 51 | needs to be emulated. | ||
| 52 | |||
| 53 | Potential future improvements | ||
| 54 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 55 | |||
| 56 | - Implement ioctl's for setting/clearing halt status on endpoints. | ||
| 57 | |||
| 58 | - Reporting more events (suspend, resume, etc.) through | ||
| 59 | USB_RAW_IOCTL_EVENT_FETCH. | ||
| 60 | |||
| 61 | - Support O_NONBLOCK I/O. | ||
| @@ -164,6 +164,8 @@ · 163 unmodified lines | |||
| 164 | reg = <0x1e6a0000 0x300>; | 164 | reg = <0x1e6a0000 0x300>; |
| 165 | interrupts = <5>; | 165 | interrupts = <5>; |
| 166 | clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>; | 166 | clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>; |
| 167 | aspeed,vhub-downstream-ports = <5>; | ||
| 168 | aspeed,vhub-generic-endpoints = <15>; | ||
| 167 | pinctrl-names = "default"; | 169 | pinctrl-names = "default"; |
| 168 | pinctrl-0 = <&pinctrl_usb2d_default>; | 170 | pinctrl-0 = <&pinctrl_usb2d_default>; |
| 169 | status = "disabled"; | 171 | status = "disabled"; |
| @@ -195,6 +195,8 @@ · 194 unmodified lines | |||
| 195 | reg = <0x1e6a0000 0x300>; | 195 | reg = <0x1e6a0000 0x300>; |
| 196 | interrupts = <5>; | 196 | interrupts = <5>; |
| 197 | clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>; | 197 | clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>; |
| 198 | aspeed,vhub-downstream-ports = <5>; | ||
| 199 | aspeed,vhub-generic-endpoints = <15>; | ||
| 198 | pinctrl-names = "default"; | 200 | pinctrl-names = "default"; |
| 199 | pinctrl-0 = <&pinctrl_usb2ad_default>; | 201 | pinctrl-0 = <&pinctrl_usb2ad_default>; |
| 200 | status = "disabled"; | 202 | status = "disabled"; |
| @@ -1112,6 +1112,31 @@ · 1111 unmodified lines | |||
| 1112 | groups = "UART9"; | 1112 | groups = "UART9"; |
| 1113 | }; | 1113 | }; |
| 1114 | 1114 | ||
| 1115 | pinctrl_usb2ah_default: usb2ah_default { | ||
| 1116 | function = "USB2AH"; | ||
| 1117 | groups = "USBA"; | ||
| 1118 | }; | ||
| 1119 | |||
| 1120 | pinctrl_usb2ad_default: usb2ad_default { | ||
| 1121 | function = "USB2AD"; | ||
| 1122 | groups = "USBA"; | ||
| 1123 | }; | ||
| 1124 | |||
| 1125 | pinctrl_usb2bh_default: usb2bh_default { | ||
| 1126 | function = "USB2BH"; | ||
| 1127 | groups = "USBB"; | ||
| 1128 | }; | ||
| 1129 | |||
| 1130 | pinctrl_usb2bd_default: usb2bd_default { | ||
| 1131 | function = "USB2BD"; | ||
| 1132 | groups = "USBB"; | ||
| 1133 | }; | ||
| 1134 | |||
| 1135 | pinctrl_usb11bhid_default: usb11bhid_default { | ||
| 1136 | function = "USB11BHID"; | ||
| 1137 | groups = "USBB"; | ||
| 1138 | }; | ||
| 1139 | |||
| 1115 | pinctrl_vb_default: vb_default { | 1140 | pinctrl_vb_default: vb_default { |
| 1116 | function = "VB"; | 1141 | function = "VB"; |
| 1117 | groups = "VB"; | 1142 | groups = "VB"; |
| @@ -245,6 +245,51 @@ · 244 unmodified lines | |||
| 245 | status = "disabled"; | 245 | status = "disabled"; |
| 246 | }; | 246 | }; |
| 247 | 247 | ||
| 248 | ehci0: usb@1e6a1000 { | ||
| 249 | compatible = "aspeed,ast2600-ehci", "generic-ehci"; | ||
| 250 | reg = <0x1e6a1000 0x100>; | ||
| 251 | interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>; | ||
| 252 | clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>; | ||
| 253 | pinctrl-names = "default"; | ||
| 254 | pinctrl-0 = <&pinctrl_usb2ah_default>; | ||
| 255 | status = "disabled"; | ||
| 256 | }; | ||
| 257 | |||
| 258 | ehci1: usb@1e6a3000 { | ||
| 259 | compatible = "aspeed,ast2600-ehci", "generic-ehci"; | ||
| 260 | reg = <0x1e6a3000 0x100>; | ||
| 261 | interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>; | ||
| 262 | clocks = <&syscon ASPEED_CLK_GATE_USBPORT2CLK>; | ||
| 263 | pinctrl-names = "default"; | ||
| 264 | pinctrl-0 = <&pinctrl_usb2bh_default>; | ||
| 265 | status = "disabled"; | ||
| 266 | }; | ||
| 267 | |||
| 268 | uhci: usb@1e6b0000 { | ||
| 269 | compatible = "aspeed,ast2600-uhci", "generic-uhci"; | ||
| 270 | reg = <0x1e6b0000 0x100>; | ||
| 271 | interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>; | ||
| 272 | #ports = <2>; | ||
| 273 | clocks = <&syscon ASPEED_CLK_GATE_USBUHCICLK>; | ||
| 274 | status = "disabled"; | ||
| 275 | /* | ||
| 276 | * No default pinmux, it will follow EHCI, use an | ||
| 277 | * explicit pinmux override if EHCI is not enabled. | ||
| 278 | */ | ||
| 279 | }; | ||
| 280 | |||
| 281 | vhub: usb-vhub@1e6a0000 { | ||
| 282 | compatible = "aspeed,ast2600-usb-vhub"; | ||
| 283 | reg = <0x1e6a0000 0x350>; | ||
| 284 | interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>; | ||
| 285 | clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>; | ||
| 286 | aspeed,vhub-downstream-ports = <7>; | ||
| 287 | aspeed,vhub-generic-endpoints = <21>; | ||
| 288 | pinctrl-names = "default"; | ||
| 289 | pinctrl-0 = <&pinctrl_usb2ad_default>; | ||
| 290 | status = "disabled"; | ||
| 291 | }; | ||
| 292 | |||
| 248 | apb { | 293 | apb { |
| 249 | compatible = "simple-bus"; | 294 | compatible = "simple-bus"; |
| 250 | #address-cells = <1>; | 295 | #address-cells = <1>; |
| @@ -411,6 +411,10 @@ enum dwc2_ep0_state { · 410 unmodified lines | |||
| 411 | * register. | 411 | * register. |
| 412 | * 0 - Deactivate the transceiver (default) | 412 | * 0 - Deactivate the transceiver (default) |
| 413 | * 1 - Activate the transceiver | 413 | * 1 - Activate the transceiver |
| 414 | * @activate_stm_id_vb_detection: Activate external ID pin and Vbus level | ||
| 415 | * detection using GGPIO register. | ||
| 416 | * 0 - Deactivate the external level detection (default) | ||
| 417 | * 1 - Activate the external level detection | ||
| 414 | * @g_dma: Enables gadget dma usage (default: autodetect). | 418 | * @g_dma: Enables gadget dma usage (default: autodetect). |
| 415 | * @g_dma_desc: Enables gadget descriptor DMA (default: autodetect). | 419 | * @g_dma_desc: Enables gadget descriptor DMA (default: autodetect). |
| 416 | * @g_rx_fifo_size: The periodic rx fifo size for the device, in | 420 | * @g_rx_fifo_size: The periodic rx fifo size for the device, in |
| @@ -481,6 +485,7 @@ struct dwc2_core_params { · 64 unmodified lines | |||
| 481 | bool service_interval; | 485 | bool service_interval; |
| 482 | u8 hird_threshold; | 486 | u8 hird_threshold; |
| 483 | bool activate_stm_fs_transceiver; | 487 | bool activate_stm_fs_transceiver; |
| 488 | bool activate_stm_id_vb_detection; | ||
| 484 | bool ipg_isoc_en; | 489 | bool ipg_isoc_en; |
| 485 | u16 max_packet_count; | 490 | u16 max_packet_count; |
| 486 | u32 max_transfer_size; | 491 | u32 max_transfer_size; |
| @@ -874,6 +879,8 @@ struct dwc2_hregs_backup { · 387 unmodified lines | |||
| 874 | * removed once all SoCs support usb transceiver. | 879 | * removed once all SoCs support usb transceiver. |
| 875 | * @supplies: Definition of USB power supplies | 880 | * @supplies: Definition of USB power supplies |
| 876 | * @vbus_supply: Regulator supplying vbus. | 881 | * @vbus_supply: Regulator supplying vbus. |
| 882 | * @usb33d: Optional 3.3v regulator used on some stm32 devices to | ||
| 883 | * supply ID and VBUS detection hardware. | ||
| 877 | * @lock: Spinlock that protects all the driver data structures | 884 | * @lock: Spinlock that protects all the driver data structures |
| 878 | * @priv: Stores a pointer to the struct usb_hcd | 885 | * @priv: Stores a pointer to the struct usb_hcd |
| 879 | * @queuing_high_bandwidth: True if multiple packets of a high-bandwidth | 886 | * @queuing_high_bandwidth: True if multiple packets of a high-bandwidth |
| @@ -1061,6 +1068,7 @@ struct dwc2_hsotg { · 181 unmodified lines | |||
| 1061 | struct dwc2_hsotg_plat *plat; | 1068 | struct dwc2_hsotg_plat *plat; |
| 1062 | struct regulator_bulk_data supplies[DWC2_NUM_SUPPLIES]; | 1069 | struct regulator_bulk_data supplies[DWC2_NUM_SUPPLIES]; |
| 1063 | struct regulator *vbus_supply; | 1070 | struct regulator *vbus_supply; |
| 1071 | struct regulator *usb33d; | ||
| 1064 | 1072 | ||
| 1065 | spinlock_t lock; | 1073 | spinlock_t lock; |
| 1066 | void *priv; | 1074 | void *priv; |
| @@ -1646,7 +1646,8 @@ static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg, · 1645 unmodified lines | |||
| 1646 | 1646 | ||
| 1647 | switch (ctrl->bRequestType & USB_RECIP_MASK) { | 1647 | switch (ctrl->bRequestType & USB_RECIP_MASK) { |
| 1648 | case USB_RECIP_DEVICE: | 1648 | case USB_RECIP_DEVICE: |
| 1649 | status = 1 << USB_DEVICE_SELF_POWERED; | 1649 | status = hsotg->gadget.is_selfpowered << |
| 1650 | USB_DEVICE_SELF_POWERED; | ||
| 1650 | status |= hsotg->remote_wakeup_allowed << | 1651 | status |= hsotg->remote_wakeup_allowed << |
| 1651 | USB_DEVICE_REMOTE_WAKEUP; | 1652 | USB_DEVICE_REMOTE_WAKEUP; |
| 1652 | reply = cpu_to_le16(status); | 1653 | reply = cpu_to_le16(status); |
| @@ -4527,6 +4528,26 @@ static int dwc2_hsotg_gadget_getframe(struct usb_gadget *gadget) · 2874 unmodified lines | |||
| 4527 | return dwc2_hsotg_read_frameno(to_hsotg(gadget)); | 4528 | return dwc2_hsotg_read_frameno(to_hsotg(gadget)); |
| 4528 | } | 4529 | } |
| 4529 | 4530 | ||
| 4531 | /** | ||
| 4532 | * dwc2_hsotg_set_selfpowered - set if device is self/bus powered | ||
| 4533 | * @gadget: The usb gadget state | ||
| 4534 | * @is_selfpowered: Whether the device is self-powered | ||
| 4535 | * | ||
| 4536 | * Set if the device is self or bus powered. | ||
| 4537 | */ | ||
| 4538 | static int dwc2_hsotg_set_selfpowered(struct usb_gadget *gadget, | ||
| 4539 | int is_selfpowered) | ||
| 4540 | { | ||
| 4541 | struct dwc2_hsotg *hsotg = to_hsotg(gadget); | ||
| 4542 | unsigned long flags; | ||
| 4543 | |||
| 4544 | spin_lock_irqsave(&hsotg->lock, flags); | ||
| 4545 | gadget->is_selfpowered = !!is_selfpowered; | ||
| 4546 | spin_unlock_irqrestore(&hsotg->lock, flags); | ||
| 4547 | |||
| 4548 | return 0; | ||
| 4549 | } | ||
| 4550 | |||
| 4530 | /** | 4551 | /** |
| 4531 | * dwc2_hsotg_pullup - connect/disconnect the USB PHY | 4552 | * dwc2_hsotg_pullup - connect/disconnect the USB PHY |
| 4532 | * @gadget: The usb gadget state | 4553 | * @gadget: The usb gadget state |
| @@ -4618,6 +4639,7 @@ static int dwc2_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned int mA) · 85 unmodified lines | |||
| 4618 | 4639 | ||
| 4619 | static const struct usb_gadget_ops dwc2_hsotg_gadget_ops = { | 4640 | static const struct usb_gadget_ops dwc2_hsotg_gadget_ops = { |
| 4620 | .get_frame = dwc2_hsotg_gadget_getframe, | 4641 | .get_frame = dwc2_hsotg_gadget_getframe, |
| 4642 | .set_selfpowered = dwc2_hsotg_set_selfpowered, | ||
| 4621 | .udc_start = dwc2_hsotg_udc_start, | 4643 | .udc_start = dwc2_hsotg_udc_start, |
| 4622 | .udc_stop = dwc2_hsotg_udc_stop, | 4644 | .udc_stop = dwc2_hsotg_udc_stop, |
| 4623 | .pullup = dwc2_hsotg_pullup, | 4645 | .pullup = dwc2_hsotg_pullup, |
| @@ -54,6 +54,12 @@ · 53 unmodified lines | |||
| 54 | #define GOTGCTL_HSTSETHNPEN BIT(10) | 54 | #define GOTGCTL_HSTSETHNPEN BIT(10) |
| 55 | #define GOTGCTL_HNPREQ BIT(9) | 55 | #define GOTGCTL_HNPREQ BIT(9) |
| 56 | #define GOTGCTL_HSTNEGSCS BIT(8) | 56 | #define GOTGCTL_HSTNEGSCS BIT(8) |
| 57 | #define GOTGCTL_BVALOVAL BIT(7) | ||
| 58 | #define GOTGCTL_BVALOEN BIT(6) | ||
| 59 | #define GOTGCTL_AVALOVAL BIT(5) | ||
| 60 | #define GOTGCTL_AVALOEN BIT(4) | ||
| 61 | #define GOTGCTL_VBVALOVAL BIT(3) | ||
| 62 | #define GOTGCTL_VBVALOEN BIT(2) | ||
| 57 | #define GOTGCTL_SESREQ BIT(1) | 63 | #define GOTGCTL_SESREQ BIT(1) |
| 58 | #define GOTGCTL_SESREQSCS BIT(0) | 64 | #define GOTGCTL_SESREQSCS BIT(0) |
| 59 | 65 | ||
| @@ -227,6 +233,8 @@ · 167 unmodified lines | |||
| 227 | #define GPVNDCTL HSOTG_REG(0x0034) | 233 | #define GPVNDCTL HSOTG_REG(0x0034) |
| 228 | #define GGPIO HSOTG_REG(0x0038) | 234 | #define GGPIO HSOTG_REG(0x0038) |
| 229 | #define GGPIO_STM32_OTG_GCCFG_PWRDWN BIT(16) | 235 | #define GGPIO_STM32_OTG_GCCFG_PWRDWN BIT(16) |
| 236 | #define GGPIO_STM32_OTG_GCCFG_VBDEN BIT(21) | ||
| 237 | #define GGPIO_STM32_OTG_GCCFG_IDEN BIT(22) | ||
| 230 | 238 | ||
| 231 | #define GUID HSOTG_REG(0x003c) | 239 | #define GUID HSOTG_REG(0x003c) |
| 232 | #define GSNPSID HSOTG_REG(0x0040) | 240 | #define GSNPSID HSOTG_REG(0x0040) |
| @@ -163,6 +163,35 @@ static void dwc2_set_stm32f7_hsotg_params(struct dwc2_hsotg *hsotg) · 162 unmodified lines | |||
| 163 | p->host_perio_tx_fifo_size = 256; | 163 | p->host_perio_tx_fifo_size = 256; |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | static void dwc2_set_stm32mp15_fsotg_params(struct dwc2_hsotg *hsotg) | ||
| 167 | { | ||
| 168 | struct dwc2_core_params *p = &hsotg->params; | ||
| 169 | |||
| 170 | p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; | ||
| 171 | p->speed = DWC2_SPEED_PARAM_FULL; | ||
| 172 | p->host_rx_fifo_size = 128; | ||
| 173 | p->host_nperio_tx_fifo_size = 96; | ||
| 174 | p->host_perio_tx_fifo_size = 96; | ||
| 175 | p->max_packet_count = 256; | ||
| 176 | p->phy_type = DWC2_PHY_TYPE_PARAM_FS; | ||
| 177 | p->i2c_enable = false; | ||
| 178 | p->activate_stm_fs_transceiver = true; | ||
| 179 | p->activate_stm_id_vb_detection = true; | ||
| 180 | p->power_down = DWC2_POWER_DOWN_PARAM_NONE; | ||
| 181 | } | ||
| 182 | |||
| 183 | static void dwc2_set_stm32mp15_hsotg_params(struct dwc2_hsotg *hsotg) | ||
| 184 | { | ||
| 185 | struct dwc2_core_params *p = &hsotg->params; | ||
| 186 | |||
| 187 | p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; | ||
| 188 | p->activate_stm_id_vb_detection = true; | ||
| 189 | p->host_rx_fifo_size = 440; | ||
| 190 | p->host_nperio_tx_fifo_size = 256; | ||
| 191 | p->host_perio_tx_fifo_size = 256; | ||
| 192 | p->power_down = DWC2_POWER_DOWN_PARAM_NONE; | ||
| 193 | } | ||
| 194 | |||
| 166 | const struct of_device_id dwc2_of_match_table[] = { | 195 | const struct of_device_id dwc2_of_match_table[] = { |
| 167 | { .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params }, | 196 | { .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params }, |
| 168 | { .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params }, | 197 | { .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params }, |
| @@ -186,6 +215,10 @@ const struct of_device_id dwc2_of_match_table[] = { · 17 unmodified lines | |||
| 186 | { .compatible = "st,stm32f4x9-hsotg" }, | 215 | { .compatible = "st,stm32f4x9-hsotg" }, |
| 187 | { .compatible = "st,stm32f7-hsotg", | 216 | { .compatible = "st,stm32f7-hsotg", |
| 188 | .data = dwc2_set_stm32f7_hsotg_params }, | 217 | .data = dwc2_set_stm32f7_hsotg_params }, |
| 218 | { .compatible = "st,stm32mp15-fsotg", | ||
| 219 | .data = dwc2_set_stm32mp15_fsotg_params }, | ||
| 220 | { .compatible = "st,stm32mp15-hsotg", | ||
| 221 | .data = dwc2_set_stm32mp15_hsotg_params }, | ||
| 189 | {}, | 222 | {}, |
| 190 | }; | 223 | }; |
| 191 | MODULE_DEVICE_TABLE(of, dwc2_of_match_table); | 224 | MODULE_DEVICE_TABLE(of, dwc2_of_match_table); |
| @@ -285,7 +285,9 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) · 284 unmodified lines | |||
| 285 | ret = devm_regulator_bulk_get(hsotg->dev, ARRAY_SIZE(hsotg->supplies), | 285 | ret = devm_regulator_bulk_get(hsotg->dev, ARRAY_SIZE(hsotg->supplies), |
| 286 | hsotg->supplies); | 286 | hsotg->supplies); |
| 287 | if (ret) { | 287 | if (ret) { |
| 288 | dev_err(hsotg->dev, "failed to request supplies: %d\n", ret); | 288 | if (ret != -EPROBE_DEFER) |
| 289 | dev_err(hsotg->dev, "failed to request supplies: %d\n", | ||
| 290 | ret); | ||
| 289 | return ret; | 291 | return ret; |
| 290 | } | 292 | } |
| 291 | return 0; | 293 | return 0; |
| @@ -312,6 +314,9 @@ static int dwc2_driver_remove(struct platform_device *dev) · 20 unmodified lines | |||
| 312 | if (hsotg->gadget_enabled) | 314 | if (hsotg->gadget_enabled) |
| 313 | dwc2_hsotg_remove(hsotg); | 315 | dwc2_hsotg_remove(hsotg); |
| 314 | 316 | ||
| 317 | if (hsotg->params.activate_stm_id_vb_detection) | ||
| 318 | regulator_disable(hsotg->usb33d); | ||
| 319 | |||
| 315 | if (hsotg->ll_hw_enabled) | 320 | if (hsotg->ll_hw_enabled) |
| 316 | dwc2_lowlevel_hw_disable(hsotg); | 321 | dwc2_lowlevel_hw_disable(hsotg); |
| 317 | 322 | ||
| @@ -464,10 +469,35 @@ static int dwc2_driver_probe(struct platform_device *dev) · 146 unmodified lines | |||
| 464 | if (retval) | 469 | if (retval) |
| 465 | goto error; | 470 | goto error; |
| 466 | 471 | ||
| 472 | if (hsotg->params.activate_stm_id_vb_detection) { | ||
| 473 | u32 ggpio; | ||
| 474 | |||
| 475 | hsotg->usb33d = devm_regulator_get(hsotg->dev, "usb33d"); | ||
| 476 | if (IS_ERR(hsotg->usb33d)) { | ||
| 477 | retval = PTR_ERR(hsotg->usb33d); | ||
| 478 | if (retval != -EPROBE_DEFER) | ||
| 479 | dev_err(hsotg->dev, | ||
| 480 | "failed to request usb33d supply: %d\n", | ||
| 481 | retval); | ||
| 482 | goto error; | ||
| 483 | } | ||
| 484 | retval = regulator_enable(hsotg->usb33d); | ||
| 485 | if (retval) { | ||
| 486 | dev_err(hsotg->dev, | ||
| 487 | "failed to enable usb33d supply: %d\n", retval); | ||
| 488 | goto error; | ||
| 489 | } | ||
| 490 | |||
| 491 | ggpio = dwc2_readl(hsotg, GGPIO); | ||
| 492 | ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN; | ||
| 493 | ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN; | ||
| 494 | dwc2_writel(hsotg, ggpio, GGPIO); | ||
| 495 | } | ||
| 496 | |||
| 467 | if (hsotg->dr_mode != USB_DR_MODE_HOST) { | 497 | if (hsotg->dr_mode != USB_DR_MODE_HOST) { |
| 468 | retval = dwc2_gadget_init(hsotg); | 498 | retval = dwc2_gadget_init(hsotg); |
| 469 | if (retval) | 499 | if (retval) |
| 470 | goto error; | 500 | goto error_init; |
| 471 | hsotg->gadget_enabled = 1; | 501 | hsotg->gadget_enabled = 1; |
| 472 | } | 502 | } |
| 473 | 503 | ||
| @@ -493,7 +523,7 @@ static int dwc2_driver_probe(struct platform_device *dev) · 19 unmodified lines | |||
| 493 | if (retval) { | 523 | if (retval) { |
| 494 | if (hsotg->gadget_enabled) | 524 | if (hsotg->gadget_enabled) |
| 495 | dwc2_hsotg_remove(hsotg); | 525 | dwc2_hsotg_remove(hsotg); |
| 496 | goto error; | 526 | goto error_init; |
| 497 | } | 527 | } |
| 498 | hsotg->hcd_enabled = 1; | 528 | hsotg->hcd_enabled = 1; |
| 499 | } | 529 | } |
| @@ -509,6 +539,9 @@ static int dwc2_driver_probe(struct platform_device *dev) · 9 unmodified lines | |||
| 509 | 539 | ||
| 510 | return 0; | 540 | return 0; |
| 511 | 541 | ||
| 542 | error_init: | ||
| 543 | if (hsotg->params.activate_stm_id_vb_detection) | ||
| 544 | regulator_disable(hsotg->usb33d); | ||
| 512 | error: | 545 | error: |
| 513 | dwc2_lowlevel_hw_disable(hsotg); | 546 | dwc2_lowlevel_hw_disable(hsotg); |
| 514 | return retval; | 547 | return retval; |
| @@ -523,6 +556,37 @@ static int __maybe_unused dwc2_suspend(struct device *dev) · 8 unmodified lines | |||
| 523 | if (is_device_mode) | 556 | if (is_device_mode) |
| 524 | dwc2_hsotg_suspend(dwc2); | 557 | dwc2_hsotg_suspend(dwc2); |
| 525 | 558 | ||
| 559 | if (dwc2->params.activate_stm_id_vb_detection) { | ||
| 560 | unsigned long flags; | ||
| 561 | u32 ggpio, gotgctl; | ||
| 562 | |||
| 563 | /* | ||
| 564 | * Need to force the mode to the current mode to avoid Mode | ||
| 565 | * Mismatch Interrupt when ID detection will be disabled. | ||
| 566 | */ | ||
| 567 | dwc2_force_mode(dwc2, !is_device_mode); | ||
| 568 | |||
| 569 | spin_lock_irqsave(&dwc2->lock, flags); | ||
| 570 | gotgctl = dwc2_readl(dwc2, GOTGCTL); | ||
| 571 | /* bypass debounce filter, enable overrides */ | ||
| 572 | gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS; | ||
| 573 | gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN; | ||
| 574 | /* Force A / B session if needed */ | ||
| 575 | if (gotgctl & GOTGCTL_ASESVLD) | ||
| 576 | gotgctl |= GOTGCTL_AVALOVAL; | ||
| 577 | if (gotgctl & GOTGCTL_BSESVLD) | ||
| 578 | gotgctl |= GOTGCTL_BVALOVAL; | ||
| 579 | dwc2_writel(dwc2, gotgctl, GOTGCTL); | ||
| 580 | spin_unlock_irqrestore(&dwc2->lock, flags); | ||
| 581 | |||
| 582 | ggpio = dwc2_readl(dwc2, GGPIO); | ||
| 583 | ggpio &= ~GGPIO_STM32_OTG_GCCFG_IDEN; | ||
| 584 | ggpio &= ~GGPIO_STM32_OTG_GCCFG_VBDEN; | ||
| 585 | dwc2_writel(dwc2, ggpio, GGPIO); | ||
| 586 | |||
| 587 | regulator_disable(dwc2->usb33d); | ||
| 588 | } | ||
| 589 | |||
| 526 | if (dwc2->ll_hw_enabled && | 590 | if (dwc2->ll_hw_enabled && |
| 527 | (is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) { | 591 | (is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) { |
| 528 | ret = __dwc2_lowlevel_hw_disable(dwc2); | 592 | ret = __dwc2_lowlevel_hw_disable(dwc2); |
| @@ -544,6 +608,34 @@ static int __maybe_unused dwc2_resume(struct device *dev) · 15 unmodified lines | |||
| 544 | } | 608 | } |
| 545 | dwc2->phy_off_for_suspend = false; | 609 | dwc2->phy_off_for_suspend = false; |
| 546 | 610 | ||
| 611 | if (dwc2->params.activate_stm_id_vb_detection) { | ||
| 612 | unsigned long flags; | ||
| 613 | u32 ggpio, gotgctl; | ||
| 614 | |||
| 615 | ret = regulator_enable(dwc2->usb33d); | ||
| 616 | if (ret) | ||
| 617 | return ret; | ||
| 618 | |||
| 619 | ggpio = dwc2_readl(dwc2, GGPIO); | ||
| 620 | ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN; | ||
| 621 | ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN; | ||
| 622 | dwc2_writel(dwc2, ggpio, GGPIO); | ||
| 623 | |||
| 624 | /* ID/VBUS detection startup time */ | ||
| 625 | usleep_range(5000, 7000); | ||
| 626 | |||
| 627 | spin_lock_irqsave(&dwc2->lock, flags); | ||
| 628 | gotgctl = dwc2_readl(dwc2, GOTGCTL); | ||
| 629 | gotgctl &= ~GOTGCTL_DBNCE_FLTR_BYPASS; | ||
| 630 | gotgctl &= ~(GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | | ||
| 631 | GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL); | ||
| 632 | dwc2_writel(dwc2, gotgctl, GOTGCTL); | ||
| 633 | spin_unlock_irqrestore(&dwc2->lock, flags); | ||
| 634 | } | ||
| 635 | |||
| 636 | /* Need to restore FORCEDEVMODE/FORCEHOSTMODE */ | ||
| 637 | dwc2_force_dr_mode(dwc2); | ||
| 638 | |||
| 547 | if (dwc2_is_device_mode(dwc2)) | 639 | if (dwc2_is_device_mode(dwc2)) |
| 548 | ret = dwc2_hsotg_resume(dwc2); | 640 | ret = dwc2_hsotg_resume(dwc2); |
| 549 | 641 | ||
| @@ -289,12 +289,6 @@ done: · 288 unmodified lines | |||
| 289 | return 0; | 289 | return 0; |
| 290 | } | 290 | } |
| 291 | 291 | ||
| 292 | static const struct clk_bulk_data dwc3_core_clks[] = { | ||
| 293 | { .id = "ref" }, | ||
| 294 | { .id = "bus_early" }, | ||
| 295 | { .id = "suspend" }, | ||
| 296 | }; | ||
| 297 | |||
| 298 | /* | 292 | /* |
| 299 | * dwc3_frame_length_adjustment - Adjusts frame length if required | 293 | * dwc3_frame_length_adjustment - Adjusts frame length if required |
| 300 | * @dwc3: Pointer to our controller context structure | 294 | * @dwc3: Pointer to our controller context structure |
| @@ -1029,6 +1023,9 @@ static int dwc3_core_init(struct dwc3 *dwc) · 728 unmodified lines | |||
| 1029 | if (dwc->dis_tx_ipgap_linecheck_quirk) | 1023 | if (dwc->dis_tx_ipgap_linecheck_quirk) |
| 1030 | reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS; | 1024 | reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS; |
| 1031 | 1025 | ||
| 1026 | if (dwc->parkmode_disable_ss_quirk) | ||
| 1027 | reg |= DWC3_GUCTL1_PARKMODE_DISABLE_SS; | ||
| 1028 | |||
| 1032 | dwc3_writel(dwc->regs, DWC3_GUCTL1, reg); | 1029 | dwc3_writel(dwc->regs, DWC3_GUCTL1, reg); |
| 1033 | } | 1030 | } |
| 1034 | 1031 | ||
| @@ -1342,6 +1339,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) · 307 unmodified lines | |||
| 1342 | "snps,dis-del-phy-power-chg-quirk"); | 1339 | "snps,dis-del-phy-power-chg-quirk"); |
| 1343 | dwc->dis_tx_ipgap_linecheck_quirk = device_property_read_bool(dev, | 1340 | dwc->dis_tx_ipgap_linecheck_quirk = device_property_read_bool(dev, |
| 1344 | "snps,dis-tx-ipgap-linecheck-quirk"); | 1341 | "snps,dis-tx-ipgap-linecheck-quirk"); |
| 1342 | dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev, | ||
| 1343 | "snps,parkmode-disable-ss-quirk"); | ||
| 1345 | 1344 | ||
| 1346 | dwc->tx_de_emphasis_quirk = device_property_read_bool(dev, | 1345 | dwc->tx_de_emphasis_quirk = device_property_read_bool(dev, |
| 1347 | "snps,tx_de_emphasis_quirk"); | 1346 | "snps,tx_de_emphasis_quirk"); |
| @@ -1441,11 +1440,6 @@ static int dwc3_probe(struct platform_device *pdev) · 93 unmodified lines | |||
| 1441 | if (!dwc) | 1440 | if (!dwc) |
| 1442 | return -ENOMEM; | 1441 | return -ENOMEM; |
| 1443 | 1442 | ||
| 1444 | dwc->clks = devm_kmemdup(dev, dwc3_core_clks, sizeof(dwc3_core_clks), | ||
| 1445 | GFP_KERNEL); | ||
| 1446 | if (!dwc->clks) | ||
| 1447 | return -ENOMEM; | ||
| 1448 | |||
| 1449 | dwc->dev = dev; | 1443 | dwc->dev = dev; |
| 1450 | 1444 | ||
| 1451 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1445 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| @@ -1476,22 +1470,23 @@ static int dwc3_probe(struct platform_device *pdev) · 24 unmodified lines | |||
| 1476 | 1470 | ||
| 1477 | dwc3_get_properties(dwc); | 1471 | dwc3_get_properties(dwc); |
| 1478 | 1472 | ||
| 1479 | dwc->reset = devm_reset_control_get_optional_shared(dev, NULL); | 1473 | dwc->reset = devm_reset_control_array_get(dev, true, true); |
| 1480 | if (IS_ERR(dwc->reset)) | 1474 | if (IS_ERR(dwc->reset)) |
| 1481 | return PTR_ERR(dwc->reset); | 1475 | return PTR_ERR(dwc->reset); |
| 1482 | 1476 | ||
| 1483 | if (dev->of_node) { | 1477 | if (dev->of_node) { |
| 1484 | dwc->num_clks = ARRAY_SIZE(dwc3_core_clks); | 1478 | ret = devm_clk_bulk_get_all(dev, &dwc->clks); |
| 1485 | |||
| 1486 | ret = devm_clk_bulk_get(dev, dwc->num_clks, dwc->clks); | ||
| 1487 | if (ret == -EPROBE_DEFER) | 1479 | if (ret == -EPROBE_DEFER) |
| 1488 | return ret; | 1480 | return ret; |
| 1489 | /* | 1481 | /* |
| 1490 | * Clocks are optional, but new DT platforms should support all | 1482 | * Clocks are optional, but new DT platforms should support all |
| 1491 | * clocks as required by the DT-binding. | 1483 | * clocks as required by the DT-binding. |
| 1492 | */ | 1484 | */ |
| 1493 | if (ret) | 1485 | if (ret < 0) |
| 1494 | dwc->num_clks = 0; | 1486 | dwc->num_clks = 0; |
| 1487 | else | ||
| 1488 | dwc->num_clks = ret; | ||
| 1489 | |||
| 1495 | } | 1490 | } |
| 1496 | 1491 | ||
| 1497 | ret = reset_control_deassert(dwc->reset); | 1492 | ret = reset_control_deassert(dwc->reset); |
| @@ -1637,6 +1632,8 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) · 139 unmodified lines | |||
| 1637 | 1632 | ||
| 1638 | switch (dwc->current_dr_role) { | 1633 | switch (dwc->current_dr_role) { |
| 1639 | case DWC3_GCTL_PRTCAP_DEVICE: | 1634 | case DWC3_GCTL_PRTCAP_DEVICE: |
| 1635 | if (pm_runtime_suspended(dwc->dev)) | ||
| 1636 | break; | ||
| 1640 | spin_lock_irqsave(&dwc->lock, flags); | 1637 | spin_lock_irqsave(&dwc->lock, flags); |
| 1641 | dwc3_gadget_suspend(dwc); | 1638 | dwc3_gadget_suspend(dwc); |
| 1642 | spin_unlock_irqrestore(&dwc->lock, flags); | 1639 | spin_unlock_irqrestore(&dwc->lock, flags); |
| @@ -25,6 +25,7 @@ · 24 unmodified lines | |||
| 25 | #include <linux/usb/ch9.h> | 25 | #include <linux/usb/ch9.h> |
| 26 | #include <linux/usb/gadget.h> | 26 | #include <linux/usb/gadget.h> |
| 27 | #include <linux/usb/otg.h> | 27 | #include <linux/usb/otg.h> |
| 28 | #include <linux/usb/role.h> | ||
| 28 | #include <linux/ulpi/interface.h> | 29 | #include <linux/ulpi/interface.h> |
| 29 | 30 | ||
| 30 | #include <linux/phy/phy.h> | 31 | #include <linux/phy/phy.h> |
| @@ -249,6 +250,7 @@ · 218 unmodified lines | |||
| 249 | #define DWC3_GUCTL_HSTINAUTORETRY BIT(14) | 250 | #define DWC3_GUCTL_HSTINAUTORETRY BIT(14) |
| 250 | 251 | ||
| 251 | /* Global User Control 1 Register */ | 252 | /* Global User Control 1 Register */ |
| 253 | #define DWC3_GUCTL1_PARKMODE_DISABLE_SS BIT(17) | ||
| 252 | #define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS BIT(28) | 254 | #define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS BIT(28) |
| 253 | #define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24) | 255 | #define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24) |
| 254 | 256 | ||
| @@ -953,6 +955,9 @@ struct dwc3_scratchpad_array { · 698 unmodified lines | |||
| 953 | * @hsphy_mode: UTMI phy mode, one of following: | 955 | * @hsphy_mode: UTMI phy mode, one of following: |
| 954 | * - USBPHY_INTERFACE_MODE_UTMI | 956 | * - USBPHY_INTERFACE_MODE_UTMI |
| 955 | * - USBPHY_INTERFACE_MODE_UTMIW | 957 | * - USBPHY_INTERFACE_MODE_UTMIW |
| 958 | * @role_sw: usb_role_switch handle | ||
| 959 | * @role_switch_default_mode: default operation mode of controller while | ||
| 960 | * usb role is USB_ROLE_NONE. | ||
| 956 | * @usb2_phy: pointer to USB2 PHY | 961 | * @usb2_phy: pointer to USB2 PHY |
| 957 | * @usb3_phy: pointer to USB3 PHY | 962 | * @usb3_phy: pointer to USB3 PHY |
| 958 | * @usb2_generic_phy: pointer to USB2 PHY | 963 | * @usb2_generic_phy: pointer to USB2 PHY |
| @@ -1024,6 +1029,8 @@ struct dwc3_scratchpad_array { · 65 unmodified lines | |||
| 1024 | * change quirk. | 1029 | * change quirk. |
| 1025 | * @dis_tx_ipgap_linecheck_quirk: set if we disable u2mac linestate | 1030 | * @dis_tx_ipgap_linecheck_quirk: set if we disable u2mac linestate |
| 1026 | * check during HS transmit. | 1031 | * check during HS transmit. |
| 1032 | * @parkmode_disable_ss_quirk: set if we need to disable all SuperSpeed | ||
| 1033 | * instances in park mode. | ||
| 1027 | * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk | 1034 | * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk |
| 1028 | * @tx_de_emphasis: Tx de-emphasis value | 1035 | * @tx_de_emphasis: Tx de-emphasis value |
| 1029 | * 0 - -6dB de-emphasis | 1036 | * 0 - -6dB de-emphasis |
| @@ -1086,6 +1093,8 @@ struct dwc3 { · 56 unmodified lines | |||
| 1086 | struct extcon_dev *edev; | 1093 | struct extcon_dev *edev; |
| 1087 | struct notifier_block edev_nb; | 1094 | struct notifier_block edev_nb; |
| 1088 | enum usb_phy_interface hsphy_mode; | 1095 | enum usb_phy_interface hsphy_mode; |
| 1096 | struct usb_role_switch *role_sw; | ||
| 1097 | enum usb_dr_mode role_switch_default_mode; | ||
| 1089 | 1098 | ||
| 1090 | u32 fladj; | 1099 | u32 fladj; |
| 1091 | u32 irq_gadget; | 1100 | u32 irq_gadget; |
| @@ -1215,6 +1224,7 @@ struct dwc3 { · 123 unmodified lines | |||
| 1215 | unsigned dis_u2_freeclk_exists_quirk:1; | 1224 | unsigned dis_u2_freeclk_exists_quirk:1; |
| 1216 | unsigned dis_del_phy_power_chg_quirk:1; | 1225 | unsigned dis_del_phy_power_chg_quirk:1; |
| 1217 | unsigned dis_tx_ipgap_linecheck_quirk:1; | 1226 | unsigned dis_tx_ipgap_linecheck_quirk:1; |
| 1227 | unsigned parkmode_disable_ss_quirk:1; | ||
| 1218 | 1228 | ||
| 1219 | unsigned tx_de_emphasis_quirk:1; | 1229 | unsigned tx_de_emphasis_quirk:1; |
| 1220 | unsigned tx_de_emphasis:2; | 1230 | unsigned tx_de_emphasis:2; |
| @@ -476,6 +476,92 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc) · 475 unmodified lines | |||
| 476 | return edev; | 476 | return edev; |
| 477 | } | 477 | } |
| 478 | 478 | ||
| 479 | #if IS_ENABLED(CONFIG_USB_ROLE_SWITCH) | ||
| 480 | #define ROLE_SWITCH 1 | ||
| 481 | static int dwc3_usb_role_switch_set(struct device *dev, enum usb_role role) | ||
| 482 | { | ||
| 483 | struct dwc3 *dwc = dev_get_drvdata(dev); | ||
| 484 | u32 mode; | ||
| 485 | |||
| 486 | switch (role) { | ||
| 487 | case USB_ROLE_HOST: | ||
| 488 | mode = DWC3_GCTL_PRTCAP_HOST; | ||
| 489 | break; | ||
| 490 | case USB_ROLE_DEVICE: | ||
| 491 | mode = DWC3_GCTL_PRTCAP_DEVICE; | ||
| 492 | break; | ||
| 493 | default: | ||
| 494 | if (dwc->role_switch_default_mode == USB_DR_MODE_HOST) | ||
| 495 | mode = DWC3_GCTL_PRTCAP_HOST; | ||
| 496 | else | ||
| 497 | mode = DWC3_GCTL_PRTCAP_DEVICE; | ||
| 498 | break; | ||
| 499 | } | ||
| 500 | |||
| 501 | dwc3_set_mode(dwc, mode); | ||
| 502 | return 0; | ||
| 503 | } | ||
| 504 | |||
| 505 | static enum usb_role dwc3_usb_role_switch_get(struct device *dev) | ||
| 506 | { | ||
| 507 | struct dwc3 *dwc = dev_get_drvdata(dev); | ||
| 508 | unsigned long flags; | ||
| 509 | enum usb_role role; | ||
| 510 | |||
| 511 | spin_lock_irqsave(&dwc->lock, flags); | ||
| 512 | switch (dwc->current_dr_role) { | ||
| 513 | case DWC3_GCTL_PRTCAP_HOST: | ||
| 514 | role = USB_ROLE_HOST; | ||
| 515 | break; | ||
| 516 | case DWC3_GCTL_PRTCAP_DEVICE: | ||
| 517 | role = USB_ROLE_DEVICE; | ||
| 518 | break; | ||
| 519 | case DWC3_GCTL_PRTCAP_OTG: | ||
| 520 | role = dwc->current_otg_role; | ||
| 521 | break; | ||
| 522 | default: | ||
| 523 | if (dwc->role_switch_default_mode == USB_DR_MODE_HOST) | ||
| 524 | role = USB_ROLE_HOST; | ||
| 525 | else | ||
| 526 | role = USB_ROLE_DEVICE; | ||
| 527 | break; | ||
| 528 | } | ||
| 529 | spin_unlock_irqrestore(&dwc->lock, flags); | ||
| 530 | return role; | ||
| 531 | } | ||
| 532 | |||
| 533 | static int dwc3_setup_role_switch(struct dwc3 *dwc) | ||
| 534 | { | ||
| 535 | struct usb_role_switch_desc dwc3_role_switch = {NULL}; | ||
| 536 | const char *str; | ||
| 537 | u32 mode; | ||
| 538 | int ret; | ||
| 539 | |||
| 540 | ret = device_property_read_string(dwc->dev, "role-switch-default-mode", | ||
| 541 | &str); | ||
| 542 | if (ret >= 0 && !strncmp(str, "host", strlen("host"))) { | ||
| 543 | dwc->role_switch_default_mode = USB_DR_MODE_HOST; | ||
| 544 | mode = DWC3_GCTL_PRTCAP_HOST; | ||
| 545 | } else { | ||
| 546 | dwc->role_switch_default_mode = USB_DR_MODE_PERIPHERAL; | ||
| 547 | mode = DWC3_GCTL_PRTCAP_DEVICE; | ||
| 548 | } | ||
| 549 | |||
| 550 | dwc3_role_switch.fwnode = dev_fwnode(dwc->dev); | ||
| 551 | dwc3_role_switch.set = dwc3_usb_role_switch_set; | ||
| 552 | dwc3_role_switch.get = dwc3_usb_role_switch_get; | ||
| 553 | dwc->role_sw = usb_role_switch_register(dwc->dev, &dwc3_role_switch); | ||
| 554 | if (IS_ERR(dwc->role_sw)) | ||
| 555 | return PTR_ERR(dwc->role_sw); | ||
| 556 | |||
| 557 | dwc3_set_mode(dwc, mode); | ||
| 558 | return 0; | ||
| 559 | } | ||
| 560 | #else | ||
| 561 | #define ROLE_SWITCH 0 | ||
| 562 | #define dwc3_setup_role_switch(x) 0 | ||
| 563 | #endif | ||
| 564 | |||
| 479 | int dwc3_drd_init(struct dwc3 *dwc) | 565 | int dwc3_drd_init(struct dwc3 *dwc) |
| 480 | { | 566 | { |
| 481 | int ret, irq; | 567 | int ret, irq; |
| @@ -484,7 +570,12 @@ int dwc3_drd_init(struct dwc3 *dwc) · 2 unmodified lines | |||
| 484 | if (IS_ERR(dwc->edev)) | 570 | if (IS_ERR(dwc->edev)) |
| 485 | return PTR_ERR(dwc->edev); | 571 | return PTR_ERR(dwc->edev); |
| 486 | 572 | ||
| 487 | if (dwc->edev) { | 573 | if (ROLE_SWITCH && |
| 574 | device_property_read_bool(dwc->dev, "usb-role-switch")) { | ||
| 575 | ret = dwc3_setup_role_switch(dwc); | ||
| 576 | if (ret < 0) | ||
| 577 | return ret; | ||
| 578 | } else if (dwc->edev) { | ||
| 488 | dwc->edev_nb.notifier_call = dwc3_drd_notifier; | 579 | dwc->edev_nb.notifier_call = dwc3_drd_notifier; |
| 489 | ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST, | 580 | ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST, |
| 490 | &dwc->edev_nb); | 581 | &dwc->edev_nb); |
| @@ -531,6 +622,9 @@ void dwc3_drd_exit(struct dwc3 *dwc) · 40 unmodified lines | |||
| 531 | { | 622 | { |
| 532 | unsigned long flags; | 623 | unsigned long flags; |
| 533 | 624 | ||
| 625 | if (dwc->role_sw) | ||
| 626 | usb_role_switch_unregister(dwc->role_sw); | ||
| 627 | |||
| 534 | if (dwc->edev) | 628 | if (dwc->edev) |
| 535 | extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST, | 629 | extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST, |
| 536 | &dwc->edev_nb); | 630 | &dwc->edev_nb); |
| @@ -162,6 +162,12 @@ static const struct dwc3_exynos_driverdata exynos5250_drvdata = { · 161 unmodified lines | |||
| 162 | .suspend_clk_idx = -1, | 162 | .suspend_clk_idx = -1, |
| 163 | }; | 163 | }; |
| 164 | 164 | ||
| 165 | static const struct dwc3_exynos_driverdata exynos5420_drvdata = { | ||
| 166 | .clk_names = { "usbdrd30", "usbdrd30_susp_clk"}, | ||
| 167 | .num_clks = 2, | ||
| 168 | .suspend_clk_idx = 1, | ||
| 169 | }; | ||
| 170 | |||
| 165 | static const struct dwc3_exynos_driverdata exynos5433_drvdata = { | 171 | static const struct dwc3_exynos_driverdata exynos5433_drvdata = { |
| 166 | .clk_names = { "aclk", "susp_clk", "pipe_pclk", "phyclk" }, | 172 | .clk_names = { "aclk", "susp_clk", "pipe_pclk", "phyclk" }, |
| 167 | .num_clks = 4, | 173 | .num_clks = 4, |
| @@ -178,6 +184,9 @@ static const struct of_device_id exynos_dwc3_match[] = { · 10 unmodified lines | |||
| 178 | { | 184 | { |
| 179 | .compatible = "samsung,exynos5250-dwusb3", | 185 | .compatible = "samsung,exynos5250-dwusb3", |
| 180 | .data = &exynos5250_drvdata, | 186 | .data = &exynos5250_drvdata, |
| 187 | }, { | ||
| 188 | .compatible = "samsung,exynos5420-dwusb3", | ||
| 189 | .data = &exynos5420_drvdata, | ||
| 181 | }, { | 190 | }, { |
| 182 | .compatible = "samsung,exynos5433-dwusb3", | 191 | .compatible = "samsung,exynos5433-dwusb3", |
| 183 | .data = &exynos5433_drvdata, | 192 | .data = &exynos5433_drvdata, |
| @@ -107,10 +107,37 @@ static const char *phy_names[PHY_COUNT] = { · 106 unmodified lines | |||
| 107 | "usb2-phy0", "usb2-phy1", "usb3-phy0", | 107 | "usb2-phy0", "usb2-phy1", "usb3-phy0", |
| 108 | }; | 108 | }; |
| 109 | 109 | ||
| 110 | static struct clk_bulk_data meson_g12a_clocks[] = { | ||
| 111 | { .id = NULL }, | ||
| 112 | }; | ||
| 113 | |||
| 114 | static struct clk_bulk_data meson_a1_clocks[] = { | ||
| 115 | { .id = "usb_ctrl" }, | ||
| 116 | { .id = "usb_bus" }, | ||
| 117 | { .id = "xtal_usb_ctrl" }, | ||
| 118 | }; | ||
| 119 | |||
| 120 | struct dwc3_meson_g12a_drvdata { | ||
| 121 | bool otg_switch_supported; | ||
| 122 | struct clk_bulk_data *clks; | ||
| 123 | int num_clks; | ||
| 124 | }; | ||
| 125 | |||
| 126 | static struct dwc3_meson_g12a_drvdata g12a_drvdata = { | ||
| 127 | .otg_switch_supported = true, | ||
| 128 | .clks = meson_g12a_clocks, | ||
| 129 | .num_clks = ARRAY_SIZE(meson_g12a_clocks), | ||
| 130 | }; | ||
| 131 | |||
| 132 | static struct dwc3_meson_g12a_drvdata a1_drvdata = { | ||
| 133 | .otg_switch_supported = false, | ||
| 134 | .clks = meson_a1_clocks, | ||
| 135 | .num_clks = ARRAY_SIZE(meson_a1_clocks), | ||
| 136 | }; | ||
| 137 | |||
| 110 | struct dwc3_meson_g12a { | 138 | struct dwc3_meson_g12a { |
| 111 | struct device *dev; | 139 | struct device *dev; |
| 112 | struct regmap *regmap; | 140 | struct regmap *regmap; |
| 113 | struct clk *clk; | ||
| 114 | struct reset_control *reset; | 141 | struct reset_control *reset; |
| 115 | struct phy *phys[PHY_COUNT]; | 142 | struct phy *phys[PHY_COUNT]; |
| 116 | enum usb_dr_mode otg_mode; | 143 | enum usb_dr_mode otg_mode; |
| @@ -120,6 +147,7 @@ struct dwc3_meson_g12a { · 3 unmodified lines | |||
| 120 | struct regulator *vbus; | 147 | struct regulator *vbus; |
| 121 | struct usb_role_switch_desc switch_desc; | 148 | struct usb_role_switch_desc switch_desc; |
| 122 | struct usb_role_switch *role_switch; | 149 | struct usb_role_switch *role_switch; |
| 150 | const struct dwc3_meson_g12a_drvdata *drvdata; | ||
| 123 | }; | 151 | }; |
| 124 | 152 | ||
| 125 | static void dwc3_meson_g12a_usb2_set_mode(struct dwc3_meson_g12a *priv, | 153 | static void dwc3_meson_g12a_usb2_set_mode(struct dwc3_meson_g12a *priv, |
| @@ -151,7 +179,7 @@ static int dwc3_meson_g12a_usb2_init(struct dwc3_meson_g12a *priv) · 25 unmodified lines | |||
| 151 | U2P_R0_POWER_ON_RESET, | 179 | U2P_R0_POWER_ON_RESET, |
| 152 | U2P_R0_POWER_ON_RESET); | 180 | U2P_R0_POWER_ON_RESET); |
| 153 | 181 | ||
| 154 | if (i == USB2_OTG_PHY) { | 182 | if (priv->drvdata->otg_switch_supported && i == USB2_OTG_PHY) { |
| 155 | regmap_update_bits(priv->regmap, | 183 | regmap_update_bits(priv->regmap, |
| 156 | U2P_R0 + (U2P_REG_SIZE * i), | 184 | U2P_R0 + (U2P_REG_SIZE * i), |
| 157 | U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS, | 185 | U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS, |
| @@ -295,7 +323,7 @@ static int dwc3_meson_g12a_otg_mode_set(struct dwc3_meson_g12a *priv, · 137 unmodified lines | |||
| 295 | { | 323 | { |
| 296 | int ret; | 324 | int ret; |
| 297 | 325 | ||
| 298 | if (!priv->phys[USB2_OTG_PHY]) | 326 | if (!priv->drvdata->otg_switch_supported || !priv->phys[USB2_OTG_PHY]) |
| 299 | return -EINVAL; | 327 | return -EINVAL; |
| 300 | 328 | ||
| 301 | if (mode == PHY_MODE_USB_HOST) | 329 | if (mode == PHY_MODE_USB_HOST) |
| @@ -381,14 +409,61 @@ static struct device *dwc3_meson_g12_find_child(struct device *dev, · 79 unmodified lines | |||
| 381 | return &pdev->dev; | 409 | return &pdev->dev; |
| 382 | } | 410 | } |
| 383 | 411 | ||
| 412 | static int dwc3_meson_g12a_otg_init(struct platform_device *pdev, | ||
| 413 | struct dwc3_meson_g12a *priv) | ||
| 414 | { | ||
| 415 | enum phy_mode otg_id; | ||
| 416 | int ret, irq; | ||
| 417 | struct device *dev = &pdev->dev; | ||
| 418 | |||
| 419 | if (!priv->drvdata->otg_switch_supported) | ||
| 420 | return 0; | ||
| 421 | |||
| 422 | if (priv->otg_mode == USB_DR_MODE_OTG) { | ||
| 423 | /* Ack irq before registering */ | ||
| 424 | regmap_update_bits(priv->regmap, USB_R5, | ||
| 425 | USB_R5_ID_DIG_IRQ, 0); | ||
| 426 | |||
| 427 | irq = platform_get_irq(pdev, 0); | ||
| 428 | ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, | ||
| 429 | dwc3_meson_g12a_irq_thread, | ||
| 430 | IRQF_ONESHOT, pdev->name, priv); | ||
| 431 | if (ret) | ||
| 432 | return ret; | ||
| 433 | } | ||
| 434 | |||
| 435 | /* Setup OTG mode corresponding to the ID pin */ | ||
| 436 | if (priv->otg_mode == USB_DR_MODE_OTG) { | ||
| 437 | otg_id = dwc3_meson_g12a_get_id(priv); | ||
| 438 | if (otg_id != priv->otg_phy_mode) { | ||
| 439 | if (dwc3_meson_g12a_otg_mode_set(priv, otg_id)) | ||
| 440 | dev_warn(dev, "Failed to switch OTG mode\n"); | ||
| 441 | } | ||
| 442 | } | ||
| 443 | |||
| 444 | /* Setup role switcher */ | ||
| 445 | priv->switch_desc.usb2_port = dwc3_meson_g12_find_child(dev, | ||
| 446 | "snps,dwc3"); | ||
| 447 | priv->switch_desc.udc = dwc3_meson_g12_find_child(dev, "snps,dwc2"); | ||
| 448 | priv->switch_desc.allow_userspace_control = true; | ||
| 449 | priv->switch_desc.set = dwc3_meson_g12a_role_set; | ||
| 450 | priv->switch_desc.get = dwc3_meson_g12a_role_get; | ||
| 451 | priv->switch_desc.driver_data = priv; | ||
| 452 | |||
| 453 | priv->role_switch = usb_role_switch_register(dev, &priv->switch_desc); | ||
| 454 | if (IS_ERR(priv->role_switch)) | ||
| 455 | dev_warn(dev, "Unable to register Role Switch\n"); | ||
| 456 | |||
| 457 | return 0; | ||
| 458 | } | ||
| 459 | |||
| 384 | static int dwc3_meson_g12a_probe(struct platform_device *pdev) | 460 | static int dwc3_meson_g12a_probe(struct platform_device *pdev) |
| 385 | { | 461 | { |
| 386 | struct dwc3_meson_g12a *priv; | 462 | struct dwc3_meson_g12a *priv; |
| 387 | struct device *dev = &pdev->dev; | 463 | struct device *dev = &pdev->dev; |
| 388 | struct device_node *np = dev->of_node; | 464 | struct device_node *np = dev->of_node; |
| 389 | void __iomem *base; | 465 | void __iomem *base; |
| 390 | enum phy_mode otg_id; | 466 | int ret, i; |
| 391 | int ret, i, irq; | ||
| 392 | 467 | ||
| 393 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | 468 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
| 394 | if (!priv) | 469 | if (!priv) |
| @@ -410,17 +485,18 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev) · 15 unmodified lines | |||
| 410 | priv->vbus = NULL; | 485 | priv->vbus = NULL; |
| 411 | } | 486 | } |
| 412 | 487 | ||
| 413 | priv->clk = devm_clk_get(dev, NULL); | 488 | priv->drvdata = of_device_get_match_data(&pdev->dev); |
| 414 | if (IS_ERR(priv->clk)) | ||
| 415 | return PTR_ERR(priv->clk); | ||
| 416 | 489 | ||
| 417 | ret = clk_prepare_enable(priv->clk); | 490 | ret = devm_clk_bulk_get(dev, |
| 491 | priv->drvdata->num_clks, | ||
| 492 | priv->drvdata->clks); | ||
| 418 | if (ret) | 493 | if (ret) |
| 419 | return ret; | 494 | return ret; |
| 420 | 495 | ||
| 421 | devm_add_action_or_reset(dev, | 496 | ret = clk_bulk_prepare_enable(priv->drvdata->num_clks, |
| 422 | (void(*)(void *))clk_disable_unprepare, | 497 | priv->drvdata->clks); |
| 423 | priv->clk); | 498 | if (ret) |
| 499 | return ret; | ||
| 424 | 500 | ||
| 425 | platform_set_drvdata(pdev, priv); | 501 | platform_set_drvdata(pdev, priv); |
| 426 | priv->dev = dev; | 502 | priv->dev = dev; |
| @@ -434,41 +510,28 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev) · 7 unmodified lines | |||
| 434 | 510 | ||
| 435 | ret = reset_control_reset(priv->reset); | 511 | ret = reset_control_reset(priv->reset); |
| 436 | if (ret) | 512 | if (ret) |
| 437 | return ret; | 513 | goto err_disable_clks; |
| 438 | 514 | ||
| 439 | ret = dwc3_meson_g12a_get_phys(priv); | 515 | ret = dwc3_meson_g12a_get_phys(priv); |
| 440 | if (ret) | 516 | if (ret) |
| 441 | return ret; | 517 | goto err_disable_clks; |
| 442 | 518 | ||
| 443 | if (priv->vbus) { | 519 | if (priv->vbus) { |
| 444 | ret = regulator_enable(priv->vbus); | 520 | ret = regulator_enable(priv->vbus); |
| 445 | if (ret) | 521 | if (ret) |
| 446 | return ret; | 522 | goto err_disable_clks; |
| 447 | } | 523 | } |
| 448 | 524 | ||
| 449 | /* Get dr_mode */ | 525 | /* Get dr_mode */ |
| 450 | priv->otg_mode = usb_get_dr_mode(dev); | 526 | priv->otg_mode = usb_get_dr_mode(dev); |
| 451 | 527 | ||
| 452 | if (priv->otg_mode == USB_DR_MODE_OTG) { | ||
| 453 | /* Ack irq before registering */ | ||
| 454 | regmap_update_bits(priv->regmap, USB_R5, | ||
| 455 | USB_R5_ID_DIG_IRQ, 0); | ||
| 456 | |||
| 457 | irq = platform_get_irq(pdev, 0); | ||
| 458 | ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, | ||
| 459 | dwc3_meson_g12a_irq_thread, | ||
| 460 | IRQF_ONESHOT, pdev->name, priv); | ||
| 461 | if (ret) | ||
| 462 | return ret; | ||
| 463 | } | ||
| 464 | |||
| 465 | dwc3_meson_g12a_usb_init(priv); | 528 | dwc3_meson_g12a_usb_init(priv); |
| 466 | 529 | ||
| 467 | /* Init PHYs */ | 530 | /* Init PHYs */ |
| 468 | for (i = 0 ; i < PHY_COUNT ; ++i) { | 531 | for (i = 0 ; i < PHY_COUNT ; ++i) { |
| 469 | ret = phy_init(priv->phys[i]); | 532 | ret = phy_init(priv->phys[i]); |
| 470 | if (ret) | 533 | if (ret) |
| 471 | return ret; | 534 | goto err_disable_clks; |
| 472 | } | 535 | } |
| 473 | 536 | ||
| 474 | /* Set PHY Power */ | 537 | /* Set PHY Power */ |
| @@ -479,32 +542,12 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev) · 4 unmodified lines | |||
| 479 | } | 542 | } |
| 480 | 543 | ||
| 481 | ret = of_platform_populate(np, NULL, NULL, dev); | 544 | ret = of_platform_populate(np, NULL, NULL, dev); |
| 482 | if (ret) { | 545 | if (ret) |
| 483 | clk_disable_unprepare(priv->clk); | ||
| 484 | goto err_phys_power; | 546 | goto err_phys_power; |
| 485 | } | ||
| 486 | 547 | ||
| 487 | /* Setup OTG mode corresponding to the ID pin */ | 548 | ret = dwc3_meson_g12a_otg_init(pdev, priv); |
| 488 | if (priv->otg_mode == USB_DR_MODE_OTG) { | 549 | if (ret) |
| 489 | otg_id = dwc3_meson_g12a_get_id(priv); | 550 | goto err_phys_power; |
| 490 | if (otg_id != priv->otg_phy_mode) { | ||
| 491 | if (dwc3_meson_g12a_otg_mode_set(priv, otg_id)) | ||
| 492 | dev_warn(dev, "Failed to switch OTG mode\n"); | ||
| 493 | } | ||
| 494 | } | ||
| 495 | |||
| 496 | /* Setup role switcher */ | ||
| 497 | priv->switch_desc.usb2_port = dwc3_meson_g12_find_child(dev, | ||
| 498 | "snps,dwc3"); | ||
| 499 | priv->switch_desc.udc = dwc3_meson_g12_find_child(dev, "snps,dwc2"); | ||
| 500 | priv->switch_desc.allow_userspace_control = true; | ||
| 501 | priv->switch_desc.set = dwc3_meson_g12a_role_set; | ||
| 502 | priv->switch_desc.get = dwc3_meson_g12a_role_get; | ||
| 503 | priv->switch_desc.driver_data = priv; | ||
| 504 | |||
| 505 | priv->role_switch = usb_role_switch_register(dev, &priv->switch_desc); | ||
| 506 | if (IS_ERR(priv->role_switch)) | ||
| 507 | dev_warn(dev, "Unable to register Role Switch\n"); | ||
| 508 | 551 | ||
| 509 | pm_runtime_set_active(dev); | 552 | pm_runtime_set_active(dev); |
| 510 | pm_runtime_enable(dev); | 553 | pm_runtime_enable(dev); |
| @@ -520,6 +563,10 @@ err_phys_exit: · 9 unmodified lines | |||
| 520 | for (i = 0 ; i < PHY_COUNT ; ++i) | 563 | for (i = 0 ; i < PHY_COUNT ; ++i) |
| 521 | phy_exit(priv->phys[i]); | 564 | phy_exit(priv->phys[i]); |
| 522 | 565 | ||
| 566 | err_disable_clks: | ||
| 567 | clk_bulk_disable_unprepare(priv->drvdata->num_clks, | ||
| 568 | priv->drvdata->clks); | ||
| 569 | |||
| 523 | return ret; | 570 | return ret; |
| 524 | } | 571 | } |
| 525 | 572 | ||
| @@ -529,7 +576,8 @@ static int dwc3_meson_g12a_remove(struct platform_device *pdev) · 3 unmodified lines | |||
| 529 | struct device *dev = &pdev->dev; | 576 | struct device *dev = &pdev->dev; |
| 530 | int i; | 577 | int i; |
| 531 | 578 | ||
| 532 | usb_role_switch_unregister(priv->role_switch); | 579 | if (priv->drvdata->otg_switch_supported) |
| 580 | usb_role_switch_unregister(priv->role_switch); | ||
| 533 | 581 | ||
| 534 | of_platform_depopulate(dev); | 582 | of_platform_depopulate(dev); |
| 535 | 583 | ||
| @@ -542,6 +590,9 @@ static int dwc3_meson_g12a_remove(struct platform_device *pdev) · 6 unmodified lines | |||
| 542 | pm_runtime_put_noidle(dev); | 590 | pm_runtime_put_noidle(dev); |
| 543 | pm_runtime_set_suspended(dev); | 591 | pm_runtime_set_suspended(dev); |
| 544 | 592 | ||
| 593 | clk_bulk_disable_unprepare(priv->drvdata->num_clks, | ||
| 594 | priv->drvdata->clks); | ||
| 595 | |||
| 545 | return 0; | 596 | return 0; |
| 546 | } | 597 | } |
| 547 | 598 | ||
| @@ -549,7 +600,8 @@ static int __maybe_unused dwc3_meson_g12a_runtime_suspend(struct device *dev) · 1 unmodified line | |||
| 549 | { | 600 | { |
| 550 | struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); | 601 | struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); |
| 551 | 602 | ||
| 552 | clk_disable(priv->clk); | 603 | clk_bulk_disable_unprepare(priv->drvdata->num_clks, |
| 604 | priv->drvdata->clks); | ||
| 553 | 605 | ||
| 554 | return 0; | 606 | return 0; |
| 555 | } | 607 | } |
| @@ -558,7 +610,8 @@ static int __maybe_unused dwc3_meson_g12a_runtime_resume(struct device *dev) · 2 unmodified lines | |||
| 558 | { | 610 | { |
| 559 | struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); | 611 | struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); |
| 560 | 612 | ||
| 561 | return clk_enable(priv->clk); | 613 | return clk_bulk_prepare_enable(priv->drvdata->num_clks, |
| 614 | priv->drvdata->clks); | ||
| 562 | } | 615 | } |
| 563 | 616 | ||
| 564 | static int __maybe_unused dwc3_meson_g12a_suspend(struct device *dev) | 617 | static int __maybe_unused dwc3_meson_g12a_suspend(struct device *dev) |
| @@ -621,7 +674,14 @@ static const struct dev_pm_ops dwc3_meson_g12a_dev_pm_ops = { · 56 unmodified lines | |||
| 621 | }; | 674 | }; |
| 622 | 675 | ||
| 623 | static const struct of_device_id dwc3_meson_g12a_match[] = { | 676 | static const struct of_device_id dwc3_meson_g12a_match[] = { |
| 624 | { .compatible = "amlogic,meson-g12a-usb-ctrl" }, | 677 | { |
| 678 | .compatible = "amlogic,meson-g12a-usb-ctrl", | ||
| 679 | .data = &g12a_drvdata, | ||
| 680 | }, | ||
| 681 | { | ||
| 682 | .compatible = "amlogic,meson-a1-usb-ctrl", | ||
| 683 | .data = &a1_drvdata, | ||
| 684 | }, | ||
| 625 | { /* Sentinel */ } | 685 | { /* Sentinel */ } |
| 626 | }; | 686 | }; |
| 627 | MODULE_DEVICE_TABLE(of, dwc3_meson_g12a_match); | 687 | MODULE_DEVICE_TABLE(of, dwc3_meson_g12a_match); |
| @@ -1521,7 +1521,7 @@ static void dwc3_gadget_ep_skip_trbs(struct dwc3_ep *dep, struct dwc3_request *r · 1520 unmodified lines | |||
| 1521 | for (i = 0; i < req->num_trbs; i++) { | 1521 | for (i = 0; i < req->num_trbs; i++) { |
| 1522 | struct dwc3_trb *trb; | 1522 | struct dwc3_trb *trb; |
| 1523 | 1523 | ||
| 1524 | trb = req->trb + i; | 1524 | trb = &dep->trb_pool[dep->trb_dequeue]; |
| 1525 | trb->ctrl &= ~DWC3_TRB_CTRL_HWO; | 1525 | trb->ctrl &= ~DWC3_TRB_CTRL_HWO; |
| 1526 | dwc3_ep_inc_deq(dep); | 1526 | dwc3_ep_inc_deq(dep); |
| 1527 | } | 1527 | } |
| @@ -2570,10 +2570,8 @@ static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep, · 1042 unmodified lines | |||
| 2570 | 2570 | ||
| 2571 | dwc3_gadget_ep_cleanup_completed_requests(dep, event, status); | 2571 | dwc3_gadget_ep_cleanup_completed_requests(dep, event, status); |
| 2572 | 2572 | ||
| 2573 | if (stop) { | 2573 | if (stop) |
| 2574 | dwc3_stop_active_transfer(dep, true, true); | 2574 | dwc3_stop_active_transfer(dep, true, true); |
| 2575 | dep->flags = DWC3_EP_ENABLED; | ||
| 2576 | } | ||
| 2577 | 2575 | ||
| 2578 | /* | 2576 | /* |
| 2579 | * WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround. | 2577 | * WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround. |
| @@ -1,5 +1,5 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | /** | 2 | /* |
| 3 | * host.c - DesignWare USB3 DRD Controller Host Glue | 3 | * host.c - DesignWare USB3 DRD Controller Host Glue |
| 4 | * | 4 | * |
| 5 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com | 5 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com |
| @@ -7,6 +7,7 @@ · 1 unmodified line | |||
| 7 | * Authors: Felipe Balbi <balbi@ti.com>, | 7 | * Authors: Felipe Balbi <balbi@ti.com>, |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/acpi.h> | ||
| 10 | #include <linux/platform_device.h> | 11 | #include <linux/platform_device.h> |
| 11 | 12 | ||
| 12 | #include "core.h" | 13 | #include "core.h" |
| @@ -75,6 +76,7 @@ int dwc3_host_init(struct dwc3 *dwc) · 62 unmodified lines | |||
| 75 | } | 76 | } |
| 76 | 77 | ||
| 77 | xhci->dev.parent = dwc->dev; | 78 | xhci->dev.parent = dwc->dev; |
| 79 | ACPI_COMPANION_SET(&xhci->dev, ACPI_COMPANION(dwc->dev)); | ||
| 78 | 80 | ||
| 79 | dwc->xhci = xhci; | 81 | dwc->xhci = xhci; |
| 80 | 82 | ||
| @@ -227,6 +227,8 @@ DECLARE_EVENT_CLASS(dwc3_log_trb, · 226 unmodified lines | |||
| 227 | __field(u32, size) | 227 | __field(u32, size) |
| 228 | __field(u32, ctrl) | 228 | __field(u32, ctrl) |
| 229 | __field(u32, type) | 229 | __field(u32, type) |
| 230 | __field(u32, enqueue) | ||
| 231 | __field(u32, dequeue) | ||
| 230 | ), | 232 | ), |
| 231 | TP_fast_assign( | 233 | TP_fast_assign( |
| 232 | __assign_str(name, dep->name); | 234 | __assign_str(name, dep->name); |
| @@ -236,9 +238,12 @@ DECLARE_EVENT_CLASS(dwc3_log_trb, · 3 unmodified lines | |||
| 236 | __entry->size = trb->size; | 238 | __entry->size = trb->size; |
| 237 | __entry->ctrl = trb->ctrl; | 239 | __entry->ctrl = trb->ctrl; |
| 238 | __entry->type = usb_endpoint_type(dep->endpoint.desc); | 240 | __entry->type = usb_endpoint_type(dep->endpoint.desc); |
| 241 | __entry->enqueue = dep->trb_enqueue; | ||
| 242 | __entry->dequeue = dep->trb_dequeue; | ||
| 239 | ), | 243 | ), |
| 240 | TP_printk("%s: trb %p buf %08x%08x size %s%d ctrl %08x (%c%c%c%c:%c%c:%s)", | 244 | TP_printk("%s: trb %p (E%d:D%d) buf %08x%08x size %s%d ctrl %08x (%c%c%c%c:%c%c:%s)", |
| 241 | __get_str(name), __entry->trb, __entry->bph, __entry->bpl, | 245 | __get_str(name), __entry->trb, __entry->enqueue, |
| 246 | __entry->dequeue, __entry->bph, __entry->bpl, | ||
| 242 | ({char *s; | 247 | ({char *s; |
| 243 | int pcm = ((__entry->size >> 24) & 3) + 1; | 248 | int pcm = ((__entry->size >> 24) & 3) + 1; |
| 244 | switch (__entry->type) { | 249 | switch (__entry->type) { |
| @@ -861,6 +861,11 @@ static int set_config(struct usb_composite_dev *cdev, · 860 unmodified lines | |||
| 861 | else | 861 | else |
| 862 | power = min(power, 900U); | 862 | power = min(power, 900U); |
| 863 | done: | 863 | done: |
| 864 | if (power <= USB_SELF_POWER_VBUS_MAX_DRAW) | ||
| 865 | usb_gadget_set_selfpowered(gadget); | ||
| 866 | else | ||
| 867 | usb_gadget_clear_selfpowered(gadget); | ||
| 868 | |||
| 864 | usb_gadget_vbus_draw(gadget, power); | 869 | usb_gadget_vbus_draw(gadget, power); |
| 865 | if (result >= 0 && cdev->delayed_status) | 870 | if (result >= 0 && cdev->delayed_status) |
| 866 | result = USB_GADGET_DELAYED_STATUS; | 871 | result = USB_GADGET_DELAYED_STATUS; |
| @@ -2279,6 +2284,7 @@ void composite_suspend(struct usb_gadget *gadget) · 1412 unmodified lines | |||
| 2279 | 2284 | ||
| 2280 | cdev->suspended = 1; | 2285 | cdev->suspended = 1; |
| 2281 | 2286 | ||
| 2287 | usb_gadget_set_selfpowered(gadget); | ||
| 2282 | usb_gadget_vbus_draw(gadget, 2); | 2288 | usb_gadget_vbus_draw(gadget, 2); |
| 2283 | } | 2289 | } |
| 2284 | 2290 | ||
| @@ -2307,6 +2313,9 @@ void composite_resume(struct usb_gadget *gadget) · 22 unmodified lines | |||
| 2307 | else | 2313 | else |
| 2308 | maxpower = min(maxpower, 900U); | 2314 | maxpower = min(maxpower, 900U); |
| 2309 | 2315 | ||
| 2316 | if (maxpower > USB_SELF_POWER_VBUS_MAX_DRAW) | ||
| 2317 | usb_gadget_clear_selfpowered(gadget); | ||
| 2318 | |||
| 2310 | usb_gadget_vbus_draw(gadget, maxpower); | 2319 | usb_gadget_vbus_draw(gadget, maxpower); |
| 2311 | } | 2320 | } |
| 2312 | 2321 | ||
| @@ -516,4 +516,15 @@ config USB_G_WEBCAM · 515 unmodified lines | |||
| 516 | Say "y" to link the driver statically, or "m" to build a | 516 | Say "y" to link the driver statically, or "m" to build a |
| 517 | dynamically linked module called "g_webcam". | 517 | dynamically linked module called "g_webcam". |
| 518 | 518 | ||
| 519 | config USB_RAW_GADGET | ||
| 520 | tristate "USB Raw Gadget" | ||
| 521 | help | ||
| 522 | USB Raw Gadget is a kernel module that provides a userspace interface | ||
| 523 | for the USB Gadget subsystem. Essentially it allows to emulate USB | ||
| 524 | devices from userspace. See Documentation/usb/raw-gadget.rst for | ||
| 525 | details. | ||
| 526 | |||
| 527 | Say "y" to link the driver statically, or "m" to build a | ||
| 528 | dynamically linked module called "raw_gadget". | ||
| 529 | |||
| 519 | endchoice | 530 | endchoice |
| @@ -43,3 +43,4 @@ obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o · 42 unmodified lines | |||
| 43 | obj-$(CONFIG_USB_G_NCM) += g_ncm.o | 43 | obj-$(CONFIG_USB_G_NCM) += g_ncm.o |
| 44 | obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o | 44 | obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o |
| 45 | obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o | 45 | obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o |
| 46 | obj-$(CONFIG_USB_RAW_GADGET) += raw_gadget.o | ||
| @@ -0,0 +1,1078 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * USB Raw Gadget driver. | ||
| 4 | * See Documentation/usb/raw-gadget.rst for more details. | ||
| 5 | * | ||
| 6 | * Andrey Konovalov <andreyknvl@gmail.com> | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/compiler.h> | ||
| 10 | #include <linux/debugfs.h> | ||
| 11 | #include <linux/delay.h> | ||
| 12 | #include <linux/kref.h> | ||
| 13 | #include <linux/miscdevice.h> | ||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/semaphore.h> | ||
| 16 | #include <linux/sched.h> | ||
| 17 | #include <linux/slab.h> | ||
| 18 | #include <linux/uaccess.h> | ||
| 19 | #include <linux/wait.h> | ||
| 20 | |||
| 21 | #include <linux/usb.h> | ||
| 22 | #include <linux/usb/ch9.h> | ||
| 23 | #include <linux/usb/ch11.h> | ||
| 24 | #include <linux/usb/gadget.h> | ||
| 25 | |||
| 26 | #include <uapi/linux/usb/raw_gadget.h> | ||
| 27 | |||
| 28 | #define DRIVER_DESC "USB Raw Gadget" | ||
| 29 | #define DRIVER_NAME "raw-gadget" | ||
| 30 | |||
| 31 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 32 | MODULE_AUTHOR("Andrey Konovalov"); | ||
| 33 | MODULE_LICENSE("GPL"); | ||
| 34 | |||
| 35 | /*----------------------------------------------------------------------*/ | ||
| 36 | |||
| 37 | #define RAW_EVENT_QUEUE_SIZE 16 | ||
| 38 | |||
| 39 | struct raw_event_queue { | ||
| 40 | /* See the comment in raw_event_queue_fetch() for locking details. */ | ||
| 41 | spinlock_t lock; | ||
| 42 | struct semaphore sema; | ||
| 43 | struct usb_raw_event *events[RAW_EVENT_QUEUE_SIZE]; | ||
| 44 | int size; | ||
| 45 | }; | ||
| 46 | |||
| 47 | static void raw_event_queue_init(struct raw_event_queue *queue) | ||
| 48 | { | ||
| 49 | spin_lock_init(&queue->lock); | ||
| 50 | sema_init(&queue->sema, 0); | ||
| 51 | queue->size = 0; | ||
| 52 | } | ||
| 53 | |||
| 54 | static int raw_event_queue_add(struct raw_event_queue *queue, | ||
| 55 | enum usb_raw_event_type type, size_t length, const void *data) | ||
| 56 | { | ||
| 57 | unsigned long flags; | ||
| 58 | struct usb_raw_event *event; | ||
| 59 | |||
| 60 | spin_lock_irqsave(&queue->lock, flags); | ||
| 61 | if (WARN_ON(queue->size >= RAW_EVENT_QUEUE_SIZE)) { | ||
| 62 | spin_unlock_irqrestore(&queue->lock, flags); | ||
| 63 | return -ENOMEM; | ||
| 64 | } | ||
| 65 | event = kmalloc(sizeof(*event) + length, GFP_ATOMIC); | ||
| 66 | if (!event) { | ||
| 67 | spin_unlock_irqrestore(&queue->lock, flags); | ||
| 68 | return -ENOMEM; | ||
| 69 | } | ||
| 70 | event->type = type; | ||
| 71 | event->length = length; | ||
| 72 | if (event->length) | ||
| 73 | memcpy(&event->data[0], data, length); | ||
| 74 | queue->events[queue->size] = event; | ||
| 75 | queue->size++; | ||
| 76 | up(&queue->sema); | ||
| 77 | spin_unlock_irqrestore(&queue->lock, flags); | ||
| 78 | return 0; | ||
| 79 | } | ||
| 80 | |||
| 81 | static struct usb_raw_event *raw_event_queue_fetch( | ||
| 82 | struct raw_event_queue *queue) | ||
| 83 | { | ||
| 84 | unsigned long flags; | ||
| 85 | struct usb_raw_event *event; | ||
| 86 | |||
| 87 | /* | ||
| 88 | * This function can be called concurrently. We first check that | ||
| 89 | * there's at least one event queued by decrementing the semaphore, | ||
| 90 | * and then take the lock to protect queue struct fields. | ||
| 91 | */ | ||
| 92 | if (down_interruptible(&queue->sema)) | ||
| 93 | return NULL; | ||
| 94 | spin_lock_irqsave(&queue->lock, flags); | ||
| 95 | if (WARN_ON(!queue->size)) | ||
| 96 | return NULL; | ||
| 97 | event = queue->events[0]; | ||
| 98 | queue->size--; | ||
| 99 | memmove(&queue->events[0], &queue->events[1], | ||
| 100 | queue->size * sizeof(queue->events[0])); | ||
| 101 | spin_unlock_irqrestore(&queue->lock, flags); | ||
| 102 | return event; | ||
| 103 | } | ||
| 104 | |||
| 105 | static void raw_event_queue_destroy(struct raw_event_queue *queue) | ||
| 106 | { | ||
| 107 | int i; | ||
| 108 | |||
| 109 | for (i = 0; i < queue->size; i++) | ||
| 110 | kfree(queue->events[i]); | ||
| 111 | queue->size = 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | /*----------------------------------------------------------------------*/ | ||
| 115 | |||
| 116 | struct raw_dev; | ||
| 117 | |||
| 118 | #define USB_RAW_MAX_ENDPOINTS 32 | ||
| 119 | |||
| 120 | enum ep_state { | ||
| 121 | STATE_EP_DISABLED, | ||
| 122 | STATE_EP_ENABLED, | ||
| 123 | }; | ||
| 124 | |||
| 125 | struct raw_ep { | ||
| 126 | struct raw_dev *dev; | ||
| 127 | enum ep_state state; | ||
| 128 | struct usb_ep *ep; | ||
| 129 | struct usb_request *req; | ||
| 130 | bool urb_queued; | ||
| 131 | bool disabling; | ||
| 132 | ssize_t status; | ||
| 133 | }; | ||
| 134 | |||
| 135 | enum dev_state { | ||
| 136 | STATE_DEV_INVALID = 0, | ||
| 137 | STATE_DEV_OPENED, | ||
| 138 | STATE_DEV_INITIALIZED, | ||
| 139 | STATE_DEV_RUNNING, | ||
| 140 | STATE_DEV_CLOSED, | ||
| 141 | STATE_DEV_FAILED | ||
| 142 | }; | ||
| 143 | |||
| 144 | struct raw_dev { | ||
| 145 | struct kref count; | ||
| 146 | spinlock_t lock; | ||
| 147 | |||
| 148 | const char *udc_name; | ||
| 149 | struct usb_gadget_driver driver; | ||
| 150 | |||
| 151 | /* Reference to misc device: */ | ||
| 152 | struct device *dev; | ||
| 153 | |||
| 154 | /* Protected by lock: */ | ||
| 155 | enum dev_state state; | ||
| 156 | bool gadget_registered; | ||
| 157 | struct usb_gadget *gadget; | ||
| 158 | struct usb_request *req; | ||
| 159 | bool ep0_in_pending; | ||
| 160 | bool ep0_out_pending; | ||
| 161 | bool ep0_urb_queued; | ||
| 162 | ssize_t ep0_status; | ||
| 163 | struct raw_ep eps[USB_RAW_MAX_ENDPOINTS]; | ||
| 164 | |||
| 165 | struct completion ep0_done; | ||
| 166 | struct raw_event_queue queue; | ||
| 167 | }; | ||
| 168 | |||
| 169 | static struct raw_dev *dev_new(void) | ||
| 170 | { | ||
| 171 | struct raw_dev *dev; | ||
| 172 | |||
| 173 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
| 174 | if (!dev) | ||
| 175 | return NULL; | ||
| 176 | /* Matches kref_put() in raw_release(). */ | ||
| 177 | kref_init(&dev->count); | ||
| 178 | spin_lock_init(&dev->lock); | ||
| 179 | init_completion(&dev->ep0_done); | ||
| 180 | raw_event_queue_init(&dev->queue); | ||
| 181 | return dev; | ||
| 182 | } | ||
| 183 | |||
| 184 | static void dev_free(struct kref *kref) | ||
| 185 | { | ||
| 186 | struct raw_dev *dev = container_of(kref, struct raw_dev, count); | ||
| 187 | int i; | ||
| 188 | |||
| 189 | kfree(dev->udc_name); | ||
| 190 | kfree(dev->driver.udc_name); | ||
| 191 | if (dev->req) { | ||
| 192 | if (dev->ep0_urb_queued) | ||
| 193 | usb_ep_dequeue(dev->gadget->ep0, dev->req); | ||
| 194 | usb_ep_free_request(dev->gadget->ep0, dev->req); | ||
| 195 | } | ||
| 196 | raw_event_queue_destroy(&dev->queue); | ||
| 197 | for (i = 0; i < USB_RAW_MAX_ENDPOINTS; i++) { | ||
| 198 | if (dev->eps[i].state != STATE_EP_ENABLED) | ||
| 199 | continue; | ||
| 200 | usb_ep_disable(dev->eps[i].ep); | ||
| 201 | usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req); | ||
| 202 | kfree(dev->eps[i].ep->desc); | ||
| 203 | dev->eps[i].state = STATE_EP_DISABLED; | ||
| 204 | } | ||
| 205 | kfree(dev); | ||
| 206 | } | ||
| 207 | |||
| 208 | /*----------------------------------------------------------------------*/ | ||
| 209 | |||
| 210 | static int raw_queue_event(struct raw_dev *dev, | ||
| 211 | enum usb_raw_event_type type, size_t length, const void *data) | ||
| 212 | { | ||
| 213 | int ret = 0; | ||
| 214 | unsigned long flags; | ||
| 215 | |||
| 216 | ret = raw_event_queue_add(&dev->queue, type, length, data); | ||
| 217 | if (ret < 0) { | ||
| 218 | spin_lock_irqsave(&dev->lock, flags); | ||
| 219 | dev->state = STATE_DEV_FAILED; | ||
| 220 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 221 | } | ||
| 222 | return ret; | ||
| 223 | } | ||
| 224 | |||
| 225 | static void gadget_ep0_complete(struct usb_ep *ep, struct usb_request *req) | ||
| 226 | { | ||
| 227 | struct raw_dev *dev = req->context; | ||
| 228 | unsigned long flags; | ||
| 229 | |||
| 230 | spin_lock_irqsave(&dev->lock, flags); | ||
| 231 | if (req->status) | ||
| 232 | dev->ep0_status = req->status; | ||
| 233 | else | ||
| 234 | dev->ep0_status = req->actual; | ||
| 235 | if (dev->ep0_in_pending) | ||
| 236 | dev->ep0_in_pending = false; | ||
| 237 | else | ||
| 238 | dev->ep0_out_pending = false; | ||
| 239 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 240 | |||
| 241 | complete(&dev->ep0_done); | ||
| 242 | } | ||
| 243 | |||
| 244 | static int gadget_bind(struct usb_gadget *gadget, | ||
| 245 | struct usb_gadget_driver *driver) | ||
| 246 | { | ||
| 247 | int ret = 0; | ||
| 248 | struct raw_dev *dev = container_of(driver, struct raw_dev, driver); | ||
| 249 | struct usb_request *req; | ||
| 250 | unsigned long flags; | ||
| 251 | |||
| 252 | if (strcmp(gadget->name, dev->udc_name) != 0) | ||
| 253 | return -ENODEV; | ||
| 254 | |||
| 255 | set_gadget_data(gadget, dev); | ||
| 256 | req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); | ||
| 257 | if (!req) { | ||
| 258 | dev_err(&gadget->dev, "usb_ep_alloc_request failed\n"); | ||
| 259 | set_gadget_data(gadget, NULL); | ||
| 260 | return -ENOMEM; | ||
| 261 | } | ||
| 262 | |||
| 263 | spin_lock_irqsave(&dev->lock, flags); | ||
| 264 | dev->req = req; | ||
| 265 | dev->req->context = dev; | ||
| 266 | dev->req->complete = gadget_ep0_complete; | ||
| 267 | dev->gadget = gadget; | ||
| 268 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 269 | |||
| 270 | /* Matches kref_put() in gadget_unbind(). */ | ||
| 271 | kref_get(&dev->count); | ||
| 272 | |||
| 273 | ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL); | ||
| 274 | if (ret < 0) | ||
| 275 | dev_err(&gadget->dev, "failed to queue event\n"); | ||
| 276 | |||
| 277 | return ret; | ||
| 278 | } | ||
| 279 | |||
| 280 | static void gadget_unbind(struct usb_gadget *gadget) | ||
| 281 | { | ||
| 282 | struct raw_dev *dev = get_gadget_data(gadget); | ||
| 283 | |||
| 284 | set_gadget_data(gadget, NULL); | ||
| 285 | /* Matches kref_get() in gadget_bind(). */ | ||
| 286 | kref_put(&dev->count, dev_free); | ||
| 287 | } | ||
| 288 | |||
| 289 | static int gadget_setup(struct usb_gadget *gadget, | ||
| 290 | const struct usb_ctrlrequest *ctrl) | ||
| 291 | { | ||
| 292 | int ret = 0; | ||
| 293 | struct raw_dev *dev = get_gadget_data(gadget); | ||
| 294 | unsigned long flags; | ||
| 295 | |||
| 296 | spin_lock_irqsave(&dev->lock, flags); | ||
| 297 | if (dev->state != STATE_DEV_RUNNING) { | ||
| 298 | dev_err(&gadget->dev, "ignoring, device is not running\n"); | ||
| 299 | ret = -ENODEV; | ||
| 300 | goto out_unlock; | ||
| 301 | } | ||
| 302 | if (dev->ep0_in_pending || dev->ep0_out_pending) { | ||
| 303 | dev_dbg(&gadget->dev, "stalling, request already pending\n"); | ||
| 304 | ret = -EBUSY; | ||
| 305 | goto out_unlock; | ||
| 306 | } | ||
| 307 | if ((ctrl->bRequestType & USB_DIR_IN) && ctrl->wLength) | ||
| 308 | dev->ep0_in_pending = true; | ||
| 309 | else | ||
| 310 | dev->ep0_out_pending = true; | ||
| 311 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 312 | |||
| 313 | ret = raw_queue_event(dev, USB_RAW_EVENT_CONTROL, sizeof(*ctrl), ctrl); | ||
| 314 | if (ret < 0) | ||
| 315 | dev_err(&gadget->dev, "failed to queue event\n"); | ||
| 316 | goto out; | ||
| 317 | |||
| 318 | out_unlock: | ||
| 319 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 320 | out: | ||
| 321 | return ret; | ||
| 322 | } | ||
| 323 | |||
| 324 | /* These are currently unused but present in case UDC driver requires them. */ | ||
| 325 | static void gadget_disconnect(struct usb_gadget *gadget) { } | ||
| 326 | static void gadget_suspend(struct usb_gadget *gadget) { } | ||
| 327 | static void gadget_resume(struct usb_gadget *gadget) { } | ||
| 328 | static void gadget_reset(struct usb_gadget *gadget) { } | ||
| 329 | |||
| 330 | /*----------------------------------------------------------------------*/ | ||
| 331 | |||
| 332 | static struct miscdevice raw_misc_device; | ||
| 333 | |||
| 334 | static int raw_open(struct inode *inode, struct file *fd) | ||
| 335 | { | ||
| 336 | struct raw_dev *dev; | ||
| 337 | |||
| 338 | /* Nonblocking I/O is not supported yet. */ | ||
| 339 | if (fd->f_flags & O_NONBLOCK) | ||
| 340 | return -EINVAL; | ||
| 341 | |||
| 342 | dev = dev_new(); | ||
| 343 | if (!dev) | ||
| 344 | return -ENOMEM; | ||
| 345 | fd->private_data = dev; | ||
| 346 | dev->state = STATE_DEV_OPENED; | ||
| 347 | dev->dev = raw_misc_device.this_device; | ||
| 348 | return 0; | ||
| 349 | } | ||
| 350 | |||
| 351 | static int raw_release(struct inode *inode, struct file *fd) | ||
| 352 | { | ||
| 353 | int ret = 0; | ||
| 354 | struct raw_dev *dev = fd->private_data; | ||
| 355 | unsigned long flags; | ||
| 356 | bool unregister = false; | ||
| 357 | |||
| 358 | spin_lock_irqsave(&dev->lock, flags); | ||
| 359 | dev->state = STATE_DEV_CLOSED; | ||
| 360 | if (!dev->gadget) { | ||
| 361 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 362 | goto out_put; | ||
| 363 | } | ||
| 364 | if (dev->gadget_registered) | ||
| 365 | unregister = true; | ||
| 366 | dev->gadget_registered = false; | ||
| 367 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 368 | |||
| 369 | if (unregister) { | ||
| 370 | ret = usb_gadget_unregister_driver(&dev->driver); | ||
| 371 | if (ret != 0) | ||
| 372 | dev_err(dev->dev, | ||
| 373 | "usb_gadget_unregister_driver() failed with %d\n", | ||
| 374 | ret); | ||
| 375 | /* Matches kref_get() in raw_ioctl_run(). */ | ||
| 376 | kref_put(&dev->count, dev_free); | ||
| 377 | } | ||
| 378 | |||
| 379 | out_put: | ||
| 380 | /* Matches dev_new() in raw_open(). */ | ||
| 381 | kref_put(&dev->count, dev_free); | ||
| 382 | return ret; | ||
| 383 | } | ||
| 384 | |||
| 385 | /*----------------------------------------------------------------------*/ | ||
| 386 | |||
| 387 | static int raw_ioctl_init(struct raw_dev *dev, unsigned long value) | ||
| 388 | { | ||
| 389 | int ret = 0; | ||
| 390 | struct usb_raw_init arg; | ||
| 391 | char *udc_driver_name; | ||
| 392 | char *udc_device_name; | ||
| 393 | unsigned long flags; | ||
| 394 | |||
| 395 | ret = copy_from_user(&arg, (void __user *)value, sizeof(arg)); | ||
| 396 | if (ret) | ||
| 397 | return ret; | ||
| 398 | |||
| 399 | switch (arg.speed) { | ||
| 400 | case USB_SPEED_UNKNOWN: | ||
| 401 | arg.speed = USB_SPEED_HIGH; | ||
| 402 | break; | ||
| 403 | case USB_SPEED_LOW: | ||
| 404 | case USB_SPEED_FULL: | ||
| 405 | case USB_SPEED_HIGH: | ||
| 406 | case USB_SPEED_SUPER: | ||
| 407 | break; | ||
| 408 | default: | ||
| 409 | return -EINVAL; | ||
| 410 | } | ||
| 411 | |||
| 412 | udc_driver_name = kmalloc(UDC_NAME_LENGTH_MAX, GFP_KERNEL); | ||
| 413 | if (!udc_driver_name) | ||
| 414 | return -ENOMEM; | ||
| 415 | ret = strscpy(udc_driver_name, &arg.driver_name[0], | ||
| 416 | UDC_NAME_LENGTH_MAX); | ||
| 417 | if (ret < 0) { | ||
| 418 | kfree(udc_driver_name); | ||
| 419 | return ret; | ||
| 420 | } | ||
| 421 | ret = 0; | ||
| 422 | |||
| 423 | udc_device_name = kmalloc(UDC_NAME_LENGTH_MAX, GFP_KERNEL); | ||
| 424 | if (!udc_device_name) { | ||
| 425 | kfree(udc_driver_name); | ||
| 426 | return -ENOMEM; | ||
| 427 | } | ||
| 428 | ret = strscpy(udc_device_name, &arg.device_name[0], | ||
| 429 | UDC_NAME_LENGTH_MAX); | ||
| 430 | if (ret < 0) { | ||
| 431 | kfree(udc_driver_name); | ||
| 432 | kfree(udc_device_name); | ||
| 433 | return ret; | ||
| 434 | } | ||
| 435 | ret = 0; | ||
| 436 | |||
| 437 | spin_lock_irqsave(&dev->lock, flags); | ||
| 438 | if (dev->state != STATE_DEV_OPENED) { | ||
| 439 | dev_dbg(dev->dev, "fail, device is not opened\n"); | ||
| 440 | kfree(udc_driver_name); | ||
| 441 | kfree(udc_device_name); | ||
| 442 | ret = -EINVAL; | ||
| 443 | goto out_unlock; | ||
| 444 | } | ||
| 445 | dev->udc_name = udc_driver_name; | ||
| 446 | |||
| 447 | dev->driver.function = DRIVER_DESC; | ||
| 448 | dev->driver.max_speed = arg.speed; | ||
| 449 | dev->driver.setup = gadget_setup; | ||
| 450 | dev->driver.disconnect = gadget_disconnect; | ||
| 451 | dev->driver.bind = gadget_bind; | ||
| 452 | dev->driver.unbind = gadget_unbind; | ||
| 453 | dev->driver.suspend = gadget_suspend; | ||
| 454 | dev->driver.resume = gadget_resume; | ||
| 455 | dev->driver.reset = gadget_reset; | ||
| 456 | dev->driver.driver.name = DRIVER_NAME; | ||
| 457 | dev->driver.udc_name = udc_device_name; | ||
| 458 | dev->driver.match_existing_only = 1; | ||
| 459 | |||
| 460 | dev->state = STATE_DEV_INITIALIZED; | ||
| 461 | |||
| 462 | out_unlock: | ||
| 463 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 464 | return ret; | ||
| 465 | } | ||
| 466 | |||
| 467 | static int raw_ioctl_run(struct raw_dev *dev, unsigned long value) | ||
| 468 | { | ||
| 469 | int ret = 0; | ||
| 470 | unsigned long flags; | ||
| 471 | |||
| 472 | if (value) | ||
| 473 | return -EINVAL; | ||
| 474 | |||
| 475 | spin_lock_irqsave(&dev->lock, flags); | ||
| 476 | if (dev->state != STATE_DEV_INITIALIZED) { | ||
| 477 | dev_dbg(dev->dev, "fail, device is not initialized\n"); | ||
| 478 | ret = -EINVAL; | ||
| 479 | goto out_unlock; | ||
| 480 | } | ||
| 481 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 482 | |||
| 483 | ret = usb_gadget_probe_driver(&dev->driver); | ||
| 484 | |||
| 485 | spin_lock_irqsave(&dev->lock, flags); | ||
| 486 | if (ret) { | ||
| 487 | dev_err(dev->dev, | ||
| 488 | "fail, usb_gadget_probe_driver returned %d\n", ret); | ||
| 489 | dev->state = STATE_DEV_FAILED; | ||
| 490 | goto out_unlock; | ||
| 491 | } | ||
| 492 | dev->gadget_registered = true; | ||
| 493 | dev->state = STATE_DEV_RUNNING; | ||
| 494 | /* Matches kref_put() in raw_release(). */ | ||
| 495 | kref_get(&dev->count); | ||
| 496 | |||
| 497 | out_unlock: | ||
| 498 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 499 | return ret; | ||
| 500 | } | ||
| 501 | |||
| 502 | static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value) | ||
| 503 | { | ||
| 504 | int ret = 0; | ||
| 505 | struct usb_raw_event arg; | ||
| 506 | unsigned long flags; | ||
| 507 | struct usb_raw_event *event; | ||
| 508 | uint32_t length; | ||
| 509 | |||
| 510 | ret = copy_from_user(&arg, (void __user *)value, sizeof(arg)); | ||
| 511 | if (ret) | ||
| 512 | return ret; | ||
| 513 | |||
| 514 | spin_lock_irqsave(&dev->lock, flags); | ||
| 515 | if (dev->state != STATE_DEV_RUNNING) { | ||
| 516 | dev_dbg(dev->dev, "fail, device is not running\n"); | ||
| 517 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 518 | return -EINVAL; | ||
| 519 | } | ||
| 520 | if (!dev->gadget) { | ||
| 521 | dev_dbg(dev->dev, "fail, gadget is not bound\n"); | ||
| 522 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 523 | return -EBUSY; | ||
| 524 | } | ||
| 525 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 526 | |||
| 527 | event = raw_event_queue_fetch(&dev->queue); | ||
| 528 | if (!event) { | ||
| 529 | dev_dbg(&dev->gadget->dev, "event fetching interrupted\n"); | ||
| 530 | return -EINTR; | ||
| 531 | } | ||
| 532 | length = min(arg.length, event->length); | ||
| 533 | ret = copy_to_user((void __user *)value, event, | ||
| 534 | sizeof(*event) + length); | ||
| 535 | return ret; | ||
| 536 | } | ||
| 537 | |||
| 538 | static void *raw_alloc_io_data(struct usb_raw_ep_io *io, void __user *ptr, | ||
| 539 | bool get_from_user) | ||
| 540 | { | ||
| 541 | int ret; | ||
| 542 | void *data; | ||
| 543 | |||
| 544 | ret = copy_from_user(io, ptr, sizeof(*io)); | ||
| 545 | if (ret) | ||
| 546 | return ERR_PTR(ret); | ||
| 547 | if (io->ep >= USB_RAW_MAX_ENDPOINTS) | ||
| 548 | return ERR_PTR(-EINVAL); | ||
| 549 | if (!usb_raw_io_flags_valid(io->flags)) | ||
| 550 | return ERR_PTR(-EINVAL); | ||
| 551 | if (io->length > PAGE_SIZE) | ||
| 552 | return ERR_PTR(-EINVAL); | ||
| 553 | if (get_from_user) | ||
| 554 | data = memdup_user(ptr + sizeof(*io), io->length); | ||
| 555 | else { | ||
| 556 | data = kmalloc(io->length, GFP_KERNEL); | ||
| 557 | if (!data) | ||
| 558 | data = ERR_PTR(-ENOMEM); | ||
| 559 | } | ||
| 560 | return data; | ||
| 561 | } | ||
| 562 | |||
| 563 | static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io, | ||
| 564 | void *data, bool in) | ||
| 565 | { | ||
| 566 | int ret = 0; | ||
| 567 | unsigned long flags; | ||
| 568 | |||
| 569 | spin_lock_irqsave(&dev->lock, flags); | ||
| 570 | if (dev->state != STATE_DEV_RUNNING) { | ||
| 571 | dev_dbg(dev->dev, "fail, device is not running\n"); | ||
| 572 | ret = -EINVAL; | ||
| 573 | goto out_unlock; | ||
| 574 | } | ||
| 575 | if (!dev->gadget) { | ||
| 576 | dev_dbg(dev->dev, "fail, gadget is not bound\n"); | ||
| 577 | ret = -EBUSY; | ||
| 578 | goto out_unlock; | ||
| 579 | } | ||
| 580 | if (dev->ep0_urb_queued) { | ||
| 581 | dev_dbg(&dev->gadget->dev, "fail, urb already queued\n"); | ||
| 582 | ret = -EBUSY; | ||
| 583 | goto out_unlock; | ||
| 584 | } | ||
| 585 | if ((in && !dev->ep0_in_pending) || | ||
| 586 | (!in && !dev->ep0_out_pending)) { | ||
| 587 | dev_dbg(&dev->gadget->dev, "fail, wrong direction\n"); | ||
| 588 | ret = -EBUSY; | ||
| 589 | goto out_unlock; | ||
| 590 | } | ||
| 591 | if (WARN_ON(in && dev->ep0_out_pending)) { | ||
| 592 | ret = -ENODEV; | ||
| 593 | dev->state = STATE_DEV_FAILED; | ||
| 594 | goto out_done; | ||
| 595 | } | ||
| 596 | if (WARN_ON(!in && dev->ep0_in_pending)) { | ||
| 597 | ret = -ENODEV; | ||
| 598 | dev->state = STATE_DEV_FAILED; | ||
| 599 | goto out_done; | ||
| 600 | } | ||
| 601 | |||
| 602 | dev->req->buf = data; | ||
| 603 | dev->req->length = io->length; | ||
| 604 | dev->req->zero = usb_raw_io_flags_zero(io->flags); | ||
| 605 | dev->ep0_urb_queued = true; | ||
| 606 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 607 | |||
| 608 | ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL); | ||
| 609 | if (ret) { | ||
| 610 | dev_err(&dev->gadget->dev, | ||
| 611 | "fail, usb_ep_queue returned %d\n", ret); | ||
| 612 | spin_lock_irqsave(&dev->lock, flags); | ||
| 613 | dev->state = STATE_DEV_FAILED; | ||
| 614 | goto out_done; | ||
| 615 | } | ||
| 616 | |||
| 617 | ret = wait_for_completion_interruptible(&dev->ep0_done); | ||
| 618 | if (ret) { | ||
| 619 | dev_dbg(&dev->gadget->dev, "wait interrupted\n"); | ||
| 620 | usb_ep_dequeue(dev->gadget->ep0, dev->req); | ||
| 621 | wait_for_completion(&dev->ep0_done); | ||
| 622 | spin_lock_irqsave(&dev->lock, flags); | ||
| 623 | goto out_done; | ||
| 624 | } | ||
| 625 | |||
| 626 | spin_lock_irqsave(&dev->lock, flags); | ||
| 627 | ret = dev->ep0_status; | ||
| 628 | |||
| 629 | out_done: | ||
| 630 | dev->ep0_urb_queued = false; | ||
| 631 | out_unlock: | ||
| 632 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 633 | return ret; | ||
| 634 | } | ||
| 635 | |||
| 636 | static int raw_ioctl_ep0_write(struct raw_dev *dev, unsigned long value) | ||
| 637 | { | ||
| 638 | int ret = 0; | ||
| 639 | void *data; | ||
| 640 | struct usb_raw_ep_io io; | ||
| 641 | |||
| 642 | data = raw_alloc_io_data(&io, (void __user *)value, true); | ||
| 643 | if (IS_ERR(data)) | ||
| 644 | return PTR_ERR(data); | ||
| 645 | ret = raw_process_ep0_io(dev, &io, data, true); | ||
| 646 | kfree(data); | ||
| 647 | return ret; | ||
| 648 | } | ||
| 649 | |||
| 650 | static int raw_ioctl_ep0_read(struct raw_dev *dev, unsigned long value) | ||
| 651 | { | ||
| 652 | int ret = 0; | ||
| 653 | void *data; | ||
| 654 | struct usb_raw_ep_io io; | ||
| 655 | unsigned int length; | ||
| 656 | |||
| 657 | data = raw_alloc_io_data(&io, (void __user *)value, false); | ||
| 658 | if (IS_ERR(data)) | ||
| 659 | return PTR_ERR(data); | ||
| 660 | ret = raw_process_ep0_io(dev, &io, data, false); | ||
| 661 | if (ret < 0) { | ||
| 662 | kfree(data); | ||
| 663 | return ret; | ||
| 664 | } | ||
| 665 | length = min(io.length, (unsigned int)ret); | ||
| 666 | ret = copy_to_user((void __user *)(value + sizeof(io)), data, length); | ||
| 667 | kfree(data); | ||
| 668 | return ret; | ||
| 669 | } | ||
| 670 | |||
| 671 | static bool check_ep_caps(struct usb_ep *ep, | ||
| 672 | struct usb_endpoint_descriptor *desc) | ||
| 673 | { | ||
| 674 | switch (usb_endpoint_type(desc)) { | ||
| 675 | case USB_ENDPOINT_XFER_ISOC: | ||
| 676 | if (!ep->caps.type_iso) | ||
| 677 | return false; | ||
| 678 | break; | ||
| 679 | case USB_ENDPOINT_XFER_BULK: | ||
| 680 | if (!ep->caps.type_bulk) | ||
| 681 | return false; | ||
| 682 | break; | ||
| 683 | case USB_ENDPOINT_XFER_INT: | ||
| 684 | if (!ep->caps.type_int) | ||
| 685 | return false; | ||
| 686 | break; | ||
| 687 | default: | ||
| 688 | return false; | ||
| 689 | } | ||
| 690 | |||
| 691 | if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in) | ||
| 692 | return false; | ||
| 693 | if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out) | ||
| 694 | return false; | ||
| 695 | |||
| 696 | return true; | ||
| 697 | } | ||
| 698 | |||
| 699 | static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value) | ||
| 700 | { | ||
| 701 | int ret = 0, i; | ||
| 702 | unsigned long flags; | ||
| 703 | struct usb_endpoint_descriptor *desc; | ||
| 704 | struct usb_ep *ep = NULL; | ||
| 705 | |||
| 706 | desc = memdup_user((void __user *)value, sizeof(*desc)); | ||
| 707 | if (IS_ERR(desc)) | ||
| 708 | return PTR_ERR(desc); | ||
| 709 | |||
| 710 | /* | ||
| 711 | * Endpoints with a maxpacket length of 0 can cause crashes in UDC | ||
| 712 | * drivers. | ||
| 713 | */ | ||
| 714 | if (usb_endpoint_maxp(desc) == 0) { | ||
| 715 | dev_dbg(dev->dev, "fail, bad endpoint maxpacket\n"); | ||
| 716 | kfree(desc); | ||
| 717 | return -EINVAL; | ||
| 718 | } | ||
| 719 | |||
| 720 | spin_lock_irqsave(&dev->lock, flags); | ||
| 721 | if (dev->state != STATE_DEV_RUNNING) { | ||
| 722 | dev_dbg(dev->dev, "fail, device is not running\n"); | ||
| 723 | ret = -EINVAL; | ||
| 724 | goto out_free; | ||
| 725 | } | ||
| 726 | if (!dev->gadget) { | ||
| 727 | dev_dbg(dev->dev, "fail, gadget is not bound\n"); | ||
| 728 | ret = -EBUSY; | ||
| 729 | goto out_free; | ||
| 730 | } | ||
| 731 | |||
| 732 | for (i = 0; i < USB_RAW_MAX_ENDPOINTS; i++) { | ||
| 733 | if (dev->eps[i].state == STATE_EP_ENABLED) | ||
| 734 | continue; | ||
| 735 | break; | ||
| 736 | } | ||
| 737 | if (i == USB_RAW_MAX_ENDPOINTS) { | ||
| 738 | dev_dbg(&dev->gadget->dev, | ||
| 739 | "fail, no device endpoints available\n"); | ||
| 740 | ret = -EBUSY; | ||
| 741 | goto out_free; | ||
| 742 | } | ||
| 743 | |||
| 744 | gadget_for_each_ep(ep, dev->gadget) { | ||
| 745 | if (ep->enabled) | ||
| 746 | continue; | ||
| 747 | if (!check_ep_caps(ep, desc)) | ||
| 748 | continue; | ||
| 749 | ep->desc = desc; | ||
| 750 | ret = usb_ep_enable(ep); | ||
| 751 | if (ret < 0) { | ||
| 752 | dev_err(&dev->gadget->dev, | ||
| 753 | "fail, usb_ep_enable returned %d\n", ret); | ||
| 754 | goto out_free; | ||
| 755 | } | ||
| 756 | dev->eps[i].req = usb_ep_alloc_request(ep, GFP_ATOMIC); | ||
| 757 | if (!dev->eps[i].req) { | ||
| 758 | dev_err(&dev->gadget->dev, | ||
| 759 | "fail, usb_ep_alloc_request failed\n"); | ||
| 760 | usb_ep_disable(ep); | ||
| 761 | ret = -ENOMEM; | ||
| 762 | goto out_free; | ||
| 763 | } | ||
| 764 | dev->eps[i].ep = ep; | ||
| 765 | dev->eps[i].state = STATE_EP_ENABLED; | ||
| 766 | ep->driver_data = &dev->eps[i]; | ||
| 767 | ret = i; | ||
| 768 | goto out_unlock; | ||
| 769 | } | ||
| 770 | |||
| 771 | dev_dbg(&dev->gadget->dev, "fail, no gadget endpoints available\n"); | ||
| 772 | ret = -EBUSY; | ||
| 773 | |||
| 774 | out_free: | ||
| 775 | kfree(desc); | ||
| 776 | out_unlock: | ||
| 777 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 778 | return ret; | ||
| 779 | } | ||
| 780 | |||
| 781 | static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value) | ||
| 782 | { | ||
| 783 | int ret = 0, i = value; | ||
| 784 | unsigned long flags; | ||
| 785 | const void *desc; | ||
| 786 | |||
| 787 | if (i < 0 || i >= USB_RAW_MAX_ENDPOINTS) | ||
| 788 | return -EINVAL; | ||
| 789 | |||
| 790 | spin_lock_irqsave(&dev->lock, flags); | ||
| 791 | if (dev->state != STATE_DEV_RUNNING) { | ||
| 792 | dev_dbg(dev->dev, "fail, device is not running\n"); | ||
| 793 | ret = -EINVAL; | ||
| 794 | goto out_unlock; | ||
| 795 | } | ||
| 796 | if (!dev->gadget) { | ||
| 797 | dev_dbg(dev->dev, "fail, gadget is not bound\n"); | ||
| 798 | ret = -EBUSY; | ||
| 799 | goto out_unlock; | ||
| 800 | } | ||
| 801 | if (dev->eps[i].state != STATE_EP_ENABLED) { | ||
| 802 | dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n"); | ||
| 803 | ret = -EINVAL; | ||
| 804 | goto out_unlock; | ||
| 805 | } | ||
| 806 | if (dev->eps[i].disabling) { | ||
| 807 | dev_dbg(&dev->gadget->dev, | ||
| 808 | "fail, disable already in progress\n"); | ||
| 809 | ret = -EINVAL; | ||
| 810 | goto out_unlock; | ||
| 811 | } | ||
| 812 | if (dev->eps[i].urb_queued) { | ||
| 813 | dev_dbg(&dev->gadget->dev, | ||
| 814 | "fail, waiting for urb completion\n"); | ||
| 815 | ret = -EINVAL; | ||
| 816 | goto out_unlock; | ||
| 817 | } | ||
| 818 | dev->eps[i].disabling = true; | ||
| 819 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 820 | |||
| 821 | usb_ep_disable(dev->eps[i].ep); | ||
| 822 | |||
| 823 | spin_lock_irqsave(&dev->lock, flags); | ||
| 824 | usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req); | ||
| 825 | desc = dev->eps[i].ep->desc; | ||
| 826 | dev->eps[i].ep = NULL; | ||
| 827 | dev->eps[i].state = STATE_EP_DISABLED; | ||
| 828 | kfree(desc); | ||
| 829 | dev->eps[i].disabling = false; | ||
| 830 | |||
| 831 | out_unlock: | ||
| 832 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 833 | return ret; | ||
| 834 | } | ||
| 835 | |||
| 836 | static void gadget_ep_complete(struct usb_ep *ep, struct usb_request *req) | ||
| 837 | { | ||
| 838 | struct raw_ep *r_ep = (struct raw_ep *)ep->driver_data; | ||
| 839 | struct raw_dev *dev = r_ep->dev; | ||
| 840 | unsigned long flags; | ||
| 841 | |||
| 842 | spin_lock_irqsave(&dev->lock, flags); | ||
| 843 | if (req->status) | ||
| 844 | r_ep->status = req->status; | ||
| 845 | else | ||
| 846 | r_ep->status = req->actual; | ||
| 847 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 848 | |||
| 849 | complete((struct completion *)req->context); | ||
| 850 | } | ||
| 851 | |||
| 852 | static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io, | ||
| 853 | void *data, bool in) | ||
| 854 | { | ||
| 855 | int ret = 0; | ||
| 856 | unsigned long flags; | ||
| 857 | struct raw_ep *ep = &dev->eps[io->ep]; | ||
| 858 | DECLARE_COMPLETION_ONSTACK(done); | ||
| 859 | |||
| 860 | spin_lock_irqsave(&dev->lock, flags); | ||
| 861 | if (dev->state != STATE_DEV_RUNNING) { | ||
| 862 | dev_dbg(dev->dev, "fail, device is not running\n"); | ||
| 863 | ret = -EINVAL; | ||
| 864 | goto out_unlock; | ||
| 865 | } | ||
| 866 | if (!dev->gadget) { | ||
| 867 | dev_dbg(dev->dev, "fail, gadget is not bound\n"); | ||
| 868 | ret = -EBUSY; | ||
| 869 | goto out_unlock; | ||
| 870 | } | ||
| 871 | if (ep->state != STATE_EP_ENABLED) { | ||
| 872 | dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n"); | ||
| 873 | ret = -EBUSY; | ||
| 874 | goto out_unlock; | ||
| 875 | } | ||
| 876 | if (ep->disabling) { | ||
| 877 | dev_dbg(&dev->gadget->dev, | ||
| 878 | "fail, endpoint is already being disabled\n"); | ||
| 879 | ret = -EBUSY; | ||
| 880 | goto out_unlock; | ||
| 881 | } | ||
| 882 | if (ep->urb_queued) { | ||
| 883 | dev_dbg(&dev->gadget->dev, "fail, urb already queued\n"); | ||
| 884 | ret = -EBUSY; | ||
| 885 | goto out_unlock; | ||
| 886 | } | ||
| 887 | if ((in && !ep->ep->caps.dir_in) || (!in && ep->ep->caps.dir_in)) { | ||
| 888 | dev_dbg(&dev->gadget->dev, "fail, wrong direction\n"); | ||
| 889 | ret = -EINVAL; | ||
| 890 | goto out_unlock; | ||
| 891 | } | ||
| 892 | |||
| 893 | ep->dev = dev; | ||
| 894 | ep->req->context = &done; | ||
| 895 | ep->req->complete = gadget_ep_complete; | ||
| 896 | ep->req->buf = data; | ||
| 897 | ep->req->length = io->length; | ||
| 898 | ep->req->zero = usb_raw_io_flags_zero(io->flags); | ||
| 899 | ep->urb_queued = true; | ||
| 900 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 901 | |||
| 902 | ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL); | ||
| 903 | if (ret) { | ||
| 904 | dev_err(&dev->gadget->dev, | ||
| 905 | "fail, usb_ep_queue returned %d\n", ret); | ||
| 906 | spin_lock_irqsave(&dev->lock, flags); | ||
| 907 | dev->state = STATE_DEV_FAILED; | ||
| 908 | goto out_done; | ||
| 909 | } | ||
| 910 | |||
| 911 | ret = wait_for_completion_interruptible(&done); | ||
| 912 | if (ret) { | ||
| 913 | dev_dbg(&dev->gadget->dev, "wait interrupted\n"); | ||
| 914 | usb_ep_dequeue(ep->ep, ep->req); | ||
| 915 | wait_for_completion(&done); | ||
| 916 | spin_lock_irqsave(&dev->lock, flags); | ||
| 917 | goto out_done; | ||
| 918 | } | ||
| 919 | |||
| 920 | spin_lock_irqsave(&dev->lock, flags); | ||
| 921 | ret = ep->status; | ||
| 922 | |||
| 923 | out_done: | ||
| 924 | ep->urb_queued = false; | ||
| 925 | out_unlock: | ||
| 926 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 927 | return ret; | ||
| 928 | } | ||
| 929 | |||
| 930 | static int raw_ioctl_ep_write(struct raw_dev *dev, unsigned long value) | ||
| 931 | { | ||
| 932 | int ret = 0; | ||
| 933 | char *data; | ||
| 934 | struct usb_raw_ep_io io; | ||
| 935 | |||
| 936 | data = raw_alloc_io_data(&io, (void __user *)value, true); | ||
| 937 | if (IS_ERR(data)) | ||
| 938 | return PTR_ERR(data); | ||
| 939 | ret = raw_process_ep_io(dev, &io, data, true); | ||
| 940 | kfree(data); | ||
| 941 | return ret; | ||
| 942 | } | ||
| 943 | |||
| 944 | static int raw_ioctl_ep_read(struct raw_dev *dev, unsigned long value) | ||
| 945 | { | ||
| 946 | int ret = 0; | ||
| 947 | char *data; | ||
| 948 | struct usb_raw_ep_io io; | ||
| 949 | unsigned int length; | ||
| 950 | |||
| 951 | data = raw_alloc_io_data(&io, (void __user *)value, false); | ||
| 952 | if (IS_ERR(data)) | ||
| 953 | return PTR_ERR(data); | ||
| 954 | ret = raw_process_ep_io(dev, &io, data, false); | ||
| 955 | if (ret < 0) { | ||
| 956 | kfree(data); | ||
| 957 | return ret; | ||
| 958 | } | ||
| 959 | length = min(io.length, (unsigned int)ret); | ||
| 960 | ret = copy_to_user((void __user *)(value + sizeof(io)), data, length); | ||
| 961 | kfree(data); | ||
| 962 | return ret; | ||
| 963 | } | ||
| 964 | |||
| 965 | static int raw_ioctl_configure(struct raw_dev *dev, unsigned long value) | ||
| 966 | { | ||
| 967 | int ret = 0; | ||
| 968 | unsigned long flags; | ||
| 969 | |||
| 970 | if (value) | ||
| 971 | return -EINVAL; | ||
| 972 | spin_lock_irqsave(&dev->lock, flags); | ||
| 973 | if (dev->state != STATE_DEV_RUNNING) { | ||
| 974 | dev_dbg(dev->dev, "fail, device is not running\n"); | ||
| 975 | ret = -EINVAL; | ||
| 976 | goto out_unlock; | ||
| 977 | } | ||
| 978 | if (!dev->gadget) { | ||
| 979 | dev_dbg(dev->dev, "fail, gadget is not bound\n"); | ||
| 980 | ret = -EBUSY; | ||
| 981 | goto out_unlock; | ||
| 982 | } | ||
| 983 | usb_gadget_set_state(dev->gadget, USB_STATE_CONFIGURED); | ||
| 984 | |||
| 985 | out_unlock: | ||
| 986 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 987 | return ret; | ||
| 988 | } | ||
| 989 | |||
| 990 | static int raw_ioctl_vbus_draw(struct raw_dev *dev, unsigned long value) | ||
| 991 | { | ||
| 992 | int ret = 0; | ||
| 993 | unsigned long flags; | ||
| 994 | |||
| 995 | spin_lock_irqsave(&dev->lock, flags); | ||
| 996 | if (dev->state != STATE_DEV_RUNNING) { | ||
| 997 | dev_dbg(dev->dev, "fail, device is not running\n"); | ||
| 998 | ret = -EINVAL; | ||
| 999 | goto out_unlock; | ||
| 1000 | } | ||
| 1001 | if (!dev->gadget) { | ||
| 1002 | dev_dbg(dev->dev, "fail, gadget is not bound\n"); | ||
| 1003 | ret = -EBUSY; | ||
| 1004 | goto out_unlock; | ||
| 1005 | } | ||
| 1006 | usb_gadget_vbus_draw(dev->gadget, 2 * value); | ||
| 1007 | |||
| 1008 | out_unlock: | ||
| 1009 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 1010 | return ret; | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | static long raw_ioctl(struct file *fd, unsigned int cmd, unsigned long value) | ||
| 1014 | { | ||
| 1015 | struct raw_dev *dev = fd->private_data; | ||
| 1016 | int ret = 0; | ||
| 1017 | |||
| 1018 | if (!dev) | ||
| 1019 | return -EBUSY; | ||
| 1020 | |||
| 1021 | switch (cmd) { | ||
| 1022 | case USB_RAW_IOCTL_INIT: | ||
| 1023 | ret = raw_ioctl_init(dev, value); | ||
| 1024 | break; | ||
| 1025 | case USB_RAW_IOCTL_RUN: | ||
| 1026 | ret = raw_ioctl_run(dev, value); | ||
| 1027 | break; | ||
| 1028 | case USB_RAW_IOCTL_EVENT_FETCH: | ||
| 1029 | ret = raw_ioctl_event_fetch(dev, value); | ||
| 1030 | break; | ||
| 1031 | case USB_RAW_IOCTL_EP0_WRITE: | ||
| 1032 | ret = raw_ioctl_ep0_write(dev, value); | ||
| 1033 | break; | ||
| 1034 | case USB_RAW_IOCTL_EP0_READ: | ||
| 1035 | ret = raw_ioctl_ep0_read(dev, value); | ||
| 1036 | break; | ||
| 1037 | case USB_RAW_IOCTL_EP_ENABLE: | ||
| 1038 | ret = raw_ioctl_ep_enable(dev, value); | ||
| 1039 | break; | ||
| 1040 | case USB_RAW_IOCTL_EP_DISABLE: | ||
| 1041 | ret = raw_ioctl_ep_disable(dev, value); | ||
| 1042 | break; | ||
| 1043 | case USB_RAW_IOCTL_EP_WRITE: | ||
| 1044 | ret = raw_ioctl_ep_write(dev, value); | ||
| 1045 | break; | ||
| 1046 | case USB_RAW_IOCTL_EP_READ: | ||
| 1047 | ret = raw_ioctl_ep_read(dev, value); | ||
| 1048 | break; | ||
| 1049 | case USB_RAW_IOCTL_CONFIGURE: | ||
| 1050 | ret = raw_ioctl_configure(dev, value); | ||
| 1051 | break; | ||
| 1052 | case USB_RAW_IOCTL_VBUS_DRAW: | ||
| 1053 | ret = raw_ioctl_vbus_draw(dev, value); | ||
| 1054 | break; | ||
| 1055 | default: | ||
| 1056 | ret = -EINVAL; | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | return ret; | ||
| 1060 | } | ||
| 1061 | |||
| 1062 | /*----------------------------------------------------------------------*/ | ||
| 1063 | |||
| 1064 | static const struct file_operations raw_fops = { | ||
| 1065 | .open = raw_open, | ||
| 1066 | .unlocked_ioctl = raw_ioctl, | ||
| 1067 | .compat_ioctl = raw_ioctl, | ||
| 1068 | .release = raw_release, | ||
| 1069 | .llseek = no_llseek, | ||
| 1070 | }; | ||
| 1071 | |||
| 1072 | static struct miscdevice raw_misc_device = { | ||
| 1073 | .minor = MISC_DYNAMIC_MINOR, | ||
| 1074 | .name = DRIVER_NAME, | ||
| 1075 | .fops = &raw_fops, | ||
| 1076 | }; | ||
| 1077 | |||
| 1078 | module_misc_device(raw_misc_device); | ||
| @@ -441,6 +441,16 @@ config USB_GADGET_XILINX · 440 unmodified lines | |||
| 441 | dynamically linked module called "udc-xilinx" and force all | 441 | dynamically linked module called "udc-xilinx" and force all |
| 442 | gadget drivers to also be dynamically linked. | 442 | gadget drivers to also be dynamically linked. |
| 443 | 443 | ||
| 444 | config USB_MAX3420_UDC | ||
| 445 | tristate "MAX3420 (USB-over-SPI) support" | ||
| 446 | depends on SPI | ||
| 447 | help | ||
| 448 | The Maxim MAX3420 chip supports USB2.0 full-speed peripheral mode. | ||
| 449 | The MAX3420 is run by SPI interface, and hence the dependency. | ||
| 450 | |||
| 451 | To compile this driver as a module, choose M here: the module will | ||
| 452 | be called max3420_udc | ||
| 453 | |||
| 444 | config USB_TEGRA_XUDC | 454 | config USB_TEGRA_XUDC |
| 445 | tristate "NVIDIA Tegra Superspeed USB 3.0 Device Controller" | 455 | tristate "NVIDIA Tegra Superspeed USB 3.0 Device Controller" |
| 446 | depends on ARCH_TEGRA || COMPILE_TEST | 456 | depends on ARCH_TEGRA || COMPILE_TEST |
| @@ -42,3 +42,4 @@ obj-$(CONFIG_USB_GADGET_XILINX) += udc-xilinx.o · 41 unmodified lines | |||
| 42 | obj-$(CONFIG_USB_SNP_UDC_PLAT) += snps_udc_plat.o | 42 | obj-$(CONFIG_USB_SNP_UDC_PLAT) += snps_udc_plat.o |
| 43 | obj-$(CONFIG_USB_ASPEED_VHUB) += aspeed-vhub/ | 43 | obj-$(CONFIG_USB_ASPEED_VHUB) += aspeed-vhub/ |
| 44 | obj-$(CONFIG_USB_BDC_UDC) += bdc/ | 44 | obj-$(CONFIG_USB_BDC_UDC) += bdc/ |
| 45 | obj-$(CONFIG_USB_MAX3420_UDC) += max3420_udc.o | ||
| @@ -4,5 +4,5 @@ config USB_ASPEED_VHUB · 3 unmodified lines | |||
| 4 | depends on ARCH_ASPEED || COMPILE_TEST | 4 | depends on ARCH_ASPEED || COMPILE_TEST |
| 5 | depends on USB_LIBCOMPOSITE | 5 | depends on USB_LIBCOMPOSITE |
| 6 | help | 6 | help |
| 7 | USB peripheral controller for the Aspeed AST2500 family | 7 | USB peripheral controller for the Aspeed AST2400, AST2500 and |
| 8 | SoCs supporting the "vHub" functionality and USB2.0 | 8 | AST2600 family SoCs supporting the "vHub" functionality and USB2.0 |
| @@ -99,7 +99,7 @@ static irqreturn_t ast_vhub_irq(int irq, void *data) · 98 unmodified lines | |||
| 99 | { | 99 | { |
| 100 | struct ast_vhub *vhub = data; | 100 | struct ast_vhub *vhub = data; |
| 101 | irqreturn_t iret = IRQ_NONE; | 101 | irqreturn_t iret = IRQ_NONE; |
| 102 | u32 istat; | 102 | u32 i, istat; |
| 103 | 103 | ||
| 104 | /* Stale interrupt while tearing down */ | 104 | /* Stale interrupt while tearing down */ |
| 105 | if (!vhub->ep0_bufs) | 105 | if (!vhub->ep0_bufs) |
| @@ -121,10 +121,10 @@ static irqreturn_t ast_vhub_irq(int irq, void *data) · 15 unmodified lines | |||
| 121 | 121 | ||
| 122 | /* Handle generic EPs first */ | 122 | /* Handle generic EPs first */ |
| 123 | if (istat & VHUB_IRQ_EP_POOL_ACK_STALL) { | 123 | if (istat & VHUB_IRQ_EP_POOL_ACK_STALL) { |
| 124 | u32 i, ep_acks = readl(vhub->regs + AST_VHUB_EP_ACK_ISR); | 124 | u32 ep_acks = readl(vhub->regs + AST_VHUB_EP_ACK_ISR); |
| 125 | writel(ep_acks, vhub->regs + AST_VHUB_EP_ACK_ISR); | 125 | writel(ep_acks, vhub->regs + AST_VHUB_EP_ACK_ISR); |
| 126 | 126 | ||
| 127 | for (i = 0; ep_acks && i < AST_VHUB_NUM_GEN_EPs; i++) { | 127 | for (i = 0; ep_acks && i < vhub->max_epns; i++) { |
| 128 | u32 mask = VHUB_EP_IRQ(i); | 128 | u32 mask = VHUB_EP_IRQ(i); |
| 129 | if (ep_acks & mask) { | 129 | if (ep_acks & mask) { |
| 130 | ast_vhub_epn_ack_irq(&vhub->epns[i]); | 130 | ast_vhub_epn_ack_irq(&vhub->epns[i]); |
| @@ -134,21 +134,11 @@ static irqreturn_t ast_vhub_irq(int irq, void *data) · 3 unmodified lines | |||
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | /* Handle device interrupts */ | 136 | /* Handle device interrupts */ |
| 137 | if (istat & (VHUB_IRQ_DEVICE1 | | 137 | for (i = 0; i < vhub->max_ports; i++) { |
| 138 | VHUB_IRQ_DEVICE2 | | 138 | u32 dev_mask = VHUB_IRQ_DEVICE1 << i; |
| 139 | VHUB_IRQ_DEVICE3 | | 139 | |
| 140 | VHUB_IRQ_DEVICE4 | | 140 | if (istat & dev_mask) |
| 141 | VHUB_IRQ_DEVICE5)) { | 141 | ast_vhub_dev_irq(&vhub->ports[i].dev); |
| 142 | if (istat & VHUB_IRQ_DEVICE1) | ||
| 143 | ast_vhub_dev_irq(&vhub->ports[0].dev); | ||
| 144 | if (istat & VHUB_IRQ_DEVICE2) | ||
| 145 | ast_vhub_dev_irq(&vhub->ports[1].dev); | ||
| 146 | if (istat & VHUB_IRQ_DEVICE3) | ||
| 147 | ast_vhub_dev_irq(&vhub->ports[2].dev); | ||
| 148 | if (istat & VHUB_IRQ_DEVICE4) | ||
| 149 | ast_vhub_dev_irq(&vhub->ports[3].dev); | ||
| 150 | if (istat & VHUB_IRQ_DEVICE5) | ||
| 151 | ast_vhub_dev_irq(&vhub->ports[4].dev); | ||
| 152 | } | 142 | } |
| 153 | 143 | ||
| 154 | /* Handle top-level vHub EP0 interrupts */ | 144 | /* Handle top-level vHub EP0 interrupts */ |
| @@ -182,7 +172,7 @@ static irqreturn_t ast_vhub_irq(int irq, void *data) · 27 unmodified lines | |||
| 182 | 172 | ||
| 183 | void ast_vhub_init_hw(struct ast_vhub *vhub) | 173 | void ast_vhub_init_hw(struct ast_vhub *vhub) |
| 184 | { | 174 | { |
| 185 | u32 ctrl; | 175 | u32 ctrl, port_mask, epn_mask; |
| 186 | 176 | ||
| 187 | UDCDBG(vhub,"(Re)Starting HW ...\n"); | 177 | UDCDBG(vhub,"(Re)Starting HW ...\n"); |
| 188 | 178 | ||
| @@ -222,15 +212,20 @@ void ast_vhub_init_hw(struct ast_vhub *vhub) · 33 unmodified lines | |||
| 222 | } | 212 | } |
| 223 | 213 | ||
| 224 | /* Reset all devices */ | 214 | /* Reset all devices */ |
| 225 | writel(VHUB_SW_RESET_ALL, vhub->regs + AST_VHUB_SW_RESET); | 215 | port_mask = GENMASK(vhub->max_ports, 1); |
| 216 | writel(VHUB_SW_RESET_ROOT_HUB | | ||
| 217 | VHUB_SW_RESET_DMA_CONTROLLER | | ||
| 218 | VHUB_SW_RESET_EP_POOL | | ||
| 219 | port_mask, vhub->regs + AST_VHUB_SW_RESET); | ||
| 226 | udelay(1); | 220 | udelay(1); |
| 227 | writel(0, vhub->regs + AST_VHUB_SW_RESET); | 221 | writel(0, vhub->regs + AST_VHUB_SW_RESET); |
| 228 | 222 | ||
| 229 | /* Disable and cleanup EP ACK/NACK interrupts */ | 223 | /* Disable and cleanup EP ACK/NACK interrupts */ |
| 224 | epn_mask = GENMASK(vhub->max_epns - 1, 0); | ||
| 230 | writel(0, vhub->regs + AST_VHUB_EP_ACK_IER); | 225 | writel(0, vhub->regs + AST_VHUB_EP_ACK_IER); |
| 231 | writel(0, vhub->regs + AST_VHUB_EP_NACK_IER); | 226 | writel(0, vhub->regs + AST_VHUB_EP_NACK_IER); |
| 232 | writel(VHUB_EP_IRQ_ALL, vhub->regs + AST_VHUB_EP_ACK_ISR); | 227 | writel(epn_mask, vhub->regs + AST_VHUB_EP_ACK_ISR); |
| 233 | writel(VHUB_EP_IRQ_ALL, vhub->regs + AST_VHUB_EP_NACK_ISR); | 228 | writel(epn_mask, vhub->regs + AST_VHUB_EP_NACK_ISR); |
| 234 | 229 | ||
| 235 | /* Default settings for EP0, enable HW hub EP1 */ | 230 | /* Default settings for EP0, enable HW hub EP1 */ |
| 236 | writel(0, vhub->regs + AST_VHUB_EP0_CTRL); | 231 | writel(0, vhub->regs + AST_VHUB_EP0_CTRL); |
| @@ -273,7 +268,7 @@ static int ast_vhub_remove(struct platform_device *pdev) · 36 unmodified lines | |||
| 273 | return 0; | 268 | return 0; |
| 274 | 269 | ||
| 275 | /* Remove devices */ | 270 | /* Remove devices */ |
| 276 | for (i = 0; i < AST_VHUB_NUM_PORTS; i++) | 271 | for (i = 0; i < vhub->max_ports; i++) |
| 277 | ast_vhub_del_dev(&vhub->ports[i].dev); | 272 | ast_vhub_del_dev(&vhub->ports[i].dev); |
| 278 | 273 | ||
| 279 | spin_lock_irqsave(&vhub->lock, flags); | 274 | spin_lock_irqsave(&vhub->lock, flags); |
| @@ -295,7 +290,7 @@ static int ast_vhub_remove(struct platform_device *pdev) · 15 unmodified lines | |||
| 295 | if (vhub->ep0_bufs) | 290 | if (vhub->ep0_bufs) |
| 296 | dma_free_coherent(&pdev->dev, | 291 | dma_free_coherent(&pdev->dev, |
| 297 | AST_VHUB_EP0_MAX_PACKET * | 292 | AST_VHUB_EP0_MAX_PACKET * |
| 298 | (AST_VHUB_NUM_PORTS + 1), | 293 | (vhub->max_ports + 1), |
| 299 | vhub->ep0_bufs, | 294 | vhub->ep0_bufs, |
| 300 | vhub->ep0_bufs_dma); | 295 | vhub->ep0_bufs_dma); |
| 301 | vhub->ep0_bufs = NULL; | 296 | vhub->ep0_bufs = NULL; |
| @@ -309,11 +304,32 @@ static int ast_vhub_probe(struct platform_device *pdev) · 7 unmodified lines | |||
| 309 | struct ast_vhub *vhub; | 304 | struct ast_vhub *vhub; |
| 310 | struct resource *res; | 305 | struct resource *res; |
| 311 | int i, rc = 0; | 306 | int i, rc = 0; |
| 307 | const struct device_node *np = pdev->dev.of_node; | ||
| 312 | 308 | ||
| 313 | vhub = devm_kzalloc(&pdev->dev, sizeof(*vhub), GFP_KERNEL); | 309 | vhub = devm_kzalloc(&pdev->dev, sizeof(*vhub), GFP_KERNEL); |
| 314 | if (!vhub) | 310 | if (!vhub) |
| 315 | return -ENOMEM; | 311 | return -ENOMEM; |
| 316 | 312 | ||
| 313 | rc = of_property_read_u32(np, "aspeed,vhub-downstream-ports", | ||
| 314 | &vhub->max_ports); | ||
| 315 | if (rc < 0) | ||
| 316 | vhub->max_ports = AST_VHUB_NUM_PORTS; | ||
| 317 | |||
| 318 | vhub->ports = devm_kcalloc(&pdev->dev, vhub->max_ports, | ||
| 319 | sizeof(*vhub->ports), GFP_KERNEL); | ||
| 320 | if (!vhub->ports) | ||
| 321 | return -ENOMEM; | ||
| 322 | |||
| 323 | rc = of_property_read_u32(np, "aspeed,vhub-generic-endpoints", | ||
| 324 | &vhub->max_epns); | ||
| 325 | if (rc < 0) | ||
| 326 | vhub->max_epns = AST_VHUB_NUM_GEN_EPs; | ||
| 327 | |||
| 328 | vhub->epns = devm_kcalloc(&pdev->dev, vhub->max_epns, | ||
| 329 | sizeof(*vhub->epns), GFP_KERNEL); | ||
| 330 | if (!vhub->epns) | ||
| 331 | return -ENOMEM; | ||
| 332 | |||
| 317 | spin_lock_init(&vhub->lock); | 333 | spin_lock_init(&vhub->lock); |
| 318 | vhub->pdev = pdev; | 334 | vhub->pdev = pdev; |
| 319 | 335 | ||
| @@ -366,7 +382,7 @@ static int ast_vhub_probe(struct platform_device *pdev) · 46 unmodified lines | |||
| 366 | */ | 382 | */ |
| 367 | vhub->ep0_bufs = dma_alloc_coherent(&pdev->dev, | 383 | vhub->ep0_bufs = dma_alloc_coherent(&pdev->dev, |
| 368 | AST_VHUB_EP0_MAX_PACKET * | 384 | AST_VHUB_EP0_MAX_PACKET * |
| 369 | (AST_VHUB_NUM_PORTS + 1), | 385 | (vhub->max_ports + 1), |
| 370 | &vhub->ep0_bufs_dma, GFP_KERNEL); | 386 | &vhub->ep0_bufs_dma, GFP_KERNEL); |
| 371 | if (!vhub->ep0_bufs) { | 387 | if (!vhub->ep0_bufs) { |
| 372 | dev_err(&pdev->dev, "Failed to allocate EP0 DMA buffers\n"); | 388 | dev_err(&pdev->dev, "Failed to allocate EP0 DMA buffers\n"); |
| @@ -380,7 +396,7 @@ static int ast_vhub_probe(struct platform_device *pdev) · 7 unmodified lines | |||
| 380 | ast_vhub_init_ep0(vhub, &vhub->ep0, NULL); | 396 | ast_vhub_init_ep0(vhub, &vhub->ep0, NULL); |
| 381 | 397 | ||
| 382 | /* Init devices */ | 398 | /* Init devices */ |
| 383 | for (i = 0; i < AST_VHUB_NUM_PORTS && rc == 0; i++) | 399 | for (i = 0; i < vhub->max_ports && rc == 0; i++) |
| 384 | rc = ast_vhub_init_dev(vhub, i); | 400 | rc = ast_vhub_init_dev(vhub, i); |
| 385 | if (rc) | 401 | if (rc) |
| 386 | goto err; | 402 | goto err; |
| @@ -407,6 +423,9 @@ static const struct of_device_id ast_vhub_dt_ids[] = { · 20 unmodified lines | |||
| 407 | { | 423 | { |
| 408 | .compatible = "aspeed,ast2500-usb-vhub", | 424 | .compatible = "aspeed,ast2500-usb-vhub", |
| 409 | }, | 425 | }, |
| 426 | { | ||
| 427 | .compatible = "aspeed,ast2600-usb-vhub", | ||
| 428 | }, | ||
| 410 | { } | 429 | { } |
| 411 | }; | 430 | }; |
| 412 | MODULE_DEVICE_TABLE(of, ast_vhub_dt_ids); | 431 | MODULE_DEVICE_TABLE(of, ast_vhub_dt_ids); |
| @@ -77,7 +77,7 @@ static void ast_vhub_dev_enable(struct ast_vhub_dev *d) · 76 unmodified lines | |||
| 77 | writel(d->ep0.buf_dma, d->regs + AST_VHUB_DEV_EP0_DATA); | 77 | writel(d->ep0.buf_dma, d->regs + AST_VHUB_DEV_EP0_DATA); |
| 78 | 78 | ||
| 79 | /* Clear stall on all EPs */ | 79 | /* Clear stall on all EPs */ |
| 80 | for (i = 0; i < AST_VHUB_NUM_GEN_EPs; i++) { | 80 | for (i = 0; i < d->max_epns; i++) { |
| 81 | struct ast_vhub_ep *ep = d->epns[i]; | 81 | struct ast_vhub_ep *ep = d->epns[i]; |
| 82 | 82 | ||
| 83 | if (ep && (ep->epn.stalled || ep->epn.wedged)) { | 83 | if (ep && (ep->epn.stalled || ep->epn.wedged)) { |
| @@ -137,7 +137,7 @@ static int ast_vhub_ep_feature(struct ast_vhub_dev *d, · 53 unmodified lines | |||
| 137 | is_set ? "SET" : "CLEAR", ep_num, wValue); | 137 | is_set ? "SET" : "CLEAR", ep_num, wValue); |
| 138 | if (ep_num == 0) | 138 | if (ep_num == 0) |
| 139 | return std_req_complete; | 139 | return std_req_complete; |
| 140 | if (ep_num >= AST_VHUB_NUM_GEN_EPs || !d->epns[ep_num - 1]) | 140 | if (ep_num >= d->max_epns || !d->epns[ep_num - 1]) |
| 141 | return std_req_stall; | 141 | return std_req_stall; |
| 142 | if (wValue != USB_ENDPOINT_HALT) | 142 | if (wValue != USB_ENDPOINT_HALT) |
| 143 | return std_req_driver; | 143 | return std_req_driver; |
| @@ -181,7 +181,7 @@ static int ast_vhub_ep_status(struct ast_vhub_dev *d, · 37 unmodified lines | |||
| 181 | 181 | ||
| 182 | DDBG(d, "GET_STATUS(ep%d)\n", ep_num); | 182 | DDBG(d, "GET_STATUS(ep%d)\n", ep_num); |
| 183 | 183 | ||
| 184 | if (ep_num >= AST_VHUB_NUM_GEN_EPs) | 184 | if (ep_num >= d->max_epns) |
| 185 | return std_req_stall; | 185 | return std_req_stall; |
| 186 | if (ep_num != 0) { | 186 | if (ep_num != 0) { |
| 187 | ep = d->epns[ep_num - 1]; | 187 | ep = d->epns[ep_num - 1]; |
| @@ -299,7 +299,7 @@ static void ast_vhub_dev_nuke(struct ast_vhub_dev *d) · 111 unmodified lines | |||
| 299 | { | 299 | { |
| 300 | unsigned int i; | 300 | unsigned int i; |
| 301 | 301 | ||
| 302 | for (i = 0; i < AST_VHUB_NUM_GEN_EPs; i++) { | 302 | for (i = 0; i < d->max_epns; i++) { |
| 303 | if (!d->epns[i]) | 303 | if (!d->epns[i]) |
| 304 | continue; | 304 | continue; |
| 305 | ast_vhub_nuke(d->epns[i], -ESHUTDOWN); | 305 | ast_vhub_nuke(d->epns[i], -ESHUTDOWN); |
| @@ -416,10 +416,10 @@ static struct usb_ep *ast_vhub_udc_match_ep(struct usb_gadget *gadget, · 110 unmodified lines | |||
| 416 | * that will allow the generic code to use our | 416 | * that will allow the generic code to use our |
| 417 | * assigned address. | 417 | * assigned address. |
| 418 | */ | 418 | */ |
| 419 | for (i = 0; i < AST_VHUB_NUM_GEN_EPs; i++) | 419 | for (i = 0; i < d->max_epns; i++) |
| 420 | if (d->epns[i] == NULL) | 420 | if (d->epns[i] == NULL) |
| 421 | break; | 421 | break; |
| 422 | if (i >= AST_VHUB_NUM_GEN_EPs) | 422 | if (i >= d->max_epns) |
| 423 | return NULL; | 423 | return NULL; |
| 424 | addr = i + 1; | 424 | addr = i + 1; |
| 425 | 425 | ||
| @@ -526,6 +526,7 @@ void ast_vhub_del_dev(struct ast_vhub_dev *d) · 100 unmodified lines | |||
| 526 | 526 | ||
| 527 | usb_del_gadget_udc(&d->gadget); | 527 | usb_del_gadget_udc(&d->gadget); |
| 528 | device_unregister(d->port_dev); | 528 | device_unregister(d->port_dev); |
| 529 | kfree(d->epns); | ||
| 529 | } | 530 | } |
| 530 | 531 | ||
| 531 | static void ast_vhub_dev_release(struct device *dev) | 532 | static void ast_vhub_dev_release(struct device *dev) |
| @@ -546,14 +547,25 @@ int ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx) · 14 unmodified lines | |||
| 546 | 547 | ||
| 547 | ast_vhub_init_ep0(vhub, &d->ep0, d); | 548 | ast_vhub_init_ep0(vhub, &d->ep0, d); |
| 548 | 549 | ||
| 550 | /* | ||
| 551 | * A USB device can have up to 30 endpoints besides control | ||
| 552 | * endpoint 0. | ||
| 553 | */ | ||
| 554 | d->max_epns = min_t(u32, vhub->max_epns, 30); | ||
| 555 | d->epns = kcalloc(d->max_epns, sizeof(*d->epns), GFP_KERNEL); | ||
| 556 | if (!d->epns) | ||
| 557 | return -ENOMEM; | ||
| 558 | |||
| 549 | /* | 559 | /* |
| 550 | * The UDC core really needs us to have separate and uniquely | 560 | * The UDC core really needs us to have separate and uniquely |
| 551 | * named "parent" devices for each port so we create a sub device | 561 | * named "parent" devices for each port so we create a sub device |
| 552 | * here for that purpose | 562 | * here for that purpose |
| 553 | */ | 563 | */ |
| 554 | d->port_dev = kzalloc(sizeof(struct device), GFP_KERNEL); | 564 | d->port_dev = kzalloc(sizeof(struct device), GFP_KERNEL); |
| 555 | if (!d->port_dev) | 565 | if (!d->port_dev) { |
| 556 | return -ENOMEM; | 566 | rc = -ENOMEM; |
| 567 | goto fail_alloc; | ||
| 568 | } | ||
| 557 | device_initialize(d->port_dev); | 569 | device_initialize(d->port_dev); |
| 558 | d->port_dev->release = ast_vhub_dev_release; | 570 | d->port_dev->release = ast_vhub_dev_release; |
| 559 | d->port_dev->parent = parent; | 571 | d->port_dev->parent = parent; |
| @@ -584,6 +596,8 @@ int ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx) · 24 unmodified lines | |||
| 584 | device_del(d->port_dev); | 596 | device_del(d->port_dev); |
| 585 | fail_add: | 597 | fail_add: |
| 586 | put_device(d->port_dev); | 598 | put_device(d->port_dev); |
| 599 | fail_alloc: | ||
| 600 | kfree(d->epns); | ||
| 587 | 601 | ||
| 588 | return rc; | 602 | return rc; |
| 589 | } | 603 | } |
| @@ -800,10 +800,10 @@ struct ast_vhub_ep *ast_vhub_alloc_epn(struct ast_vhub_dev *d, u8 addr) · 799 unmodified lines | |||
| 800 | 800 | ||
| 801 | /* Find a free one (no device) */ | 801 | /* Find a free one (no device) */ |
| 802 | spin_lock_irqsave(&vhub->lock, flags); | 802 | spin_lock_irqsave(&vhub->lock, flags); |
| 803 | for (i = 0; i < AST_VHUB_NUM_GEN_EPs; i++) | 803 | for (i = 0; i < vhub->max_epns; i++) |
| 804 | if (vhub->epns[i].dev == NULL) | 804 | if (vhub->epns[i].dev == NULL) |
| 805 | break; | 805 | break; |
| 806 | if (i >= AST_VHUB_NUM_GEN_EPs) { | 806 | if (i >= vhub->max_epns) { |
| 807 | spin_unlock_irqrestore(&vhub->lock, flags); | 807 | spin_unlock_irqrestore(&vhub->lock, flags); |
| 808 | return NULL; | 808 | return NULL; |
| 809 | } | 809 | } |
| @@ -93,11 +93,7 @@ static void ast_vhub_patch_dev_desc_usb1(struct usb_device_descriptor *desc) · 92 unmodified lines | |||
| 93 | USB_DT_INTERFACE_SIZE + \ | 93 | USB_DT_INTERFACE_SIZE + \ |
| 94 | USB_DT_ENDPOINT_SIZE) | 94 | USB_DT_ENDPOINT_SIZE) |
| 95 | 95 | ||
| 96 | static const struct ast_vhub_full_cdesc { | 96 | static const struct ast_vhub_full_cdesc ast_vhub_conf_desc = { |
| 97 | struct usb_config_descriptor cfg; | ||
| 98 | struct usb_interface_descriptor intf; | ||
| 99 | struct usb_endpoint_descriptor ep; | ||
| 100 | } __attribute__ ((packed)) ast_vhub_conf_desc = { | ||
| 101 | .cfg = { | 97 | .cfg = { |
| 102 | .bLength = USB_DT_CONFIG_SIZE, | 98 | .bLength = USB_DT_CONFIG_SIZE, |
| 103 | .bDescriptorType = USB_DT_CONFIG, | 99 | .bDescriptorType = USB_DT_CONFIG, |
| @@ -266,6 +262,7 @@ static int ast_vhub_rep_desc(struct ast_vhub_ep *ep, · 162 unmodified lines | |||
| 266 | u8 desc_type, u16 len) | 262 | u8 desc_type, u16 len) |
| 267 | { | 263 | { |
| 268 | size_t dsize; | 264 | size_t dsize; |
| 265 | struct ast_vhub *vhub = ep->vhub; | ||
| 269 | 266 | ||
| 270 | EPDBG(ep, "GET_DESCRIPTOR(type:%d)\n", desc_type); | 267 | EPDBG(ep, "GET_DESCRIPTOR(type:%d)\n", desc_type); |
| 271 | 268 | ||
| @@ -281,20 +278,20 @@ static int ast_vhub_rep_desc(struct ast_vhub_ep *ep, · 9 unmodified lines | |||
| 281 | switch(desc_type) { | 278 | switch(desc_type) { |
| 282 | case USB_DT_DEVICE: | 279 | case USB_DT_DEVICE: |
| 283 | dsize = USB_DT_DEVICE_SIZE; | 280 | dsize = USB_DT_DEVICE_SIZE; |
| 284 | memcpy(ep->buf, &ast_vhub_dev_desc, dsize); | 281 | memcpy(ep->buf, &vhub->vhub_dev_desc, dsize); |
| 285 | BUILD_BUG_ON(dsize > sizeof(ast_vhub_dev_desc)); | 282 | BUILD_BUG_ON(dsize > sizeof(vhub->vhub_dev_desc)); |
| 286 | BUILD_BUG_ON(USB_DT_DEVICE_SIZE >= AST_VHUB_EP0_MAX_PACKET); | 283 | BUILD_BUG_ON(USB_DT_DEVICE_SIZE >= AST_VHUB_EP0_MAX_PACKET); |
| 287 | break; | 284 | break; |
| 288 | case USB_DT_CONFIG: | 285 | case USB_DT_CONFIG: |
| 289 | dsize = AST_VHUB_CONF_DESC_SIZE; | 286 | dsize = AST_VHUB_CONF_DESC_SIZE; |
| 290 | memcpy(ep->buf, &ast_vhub_conf_desc, dsize); | 287 | memcpy(ep->buf, &vhub->vhub_conf_desc, dsize); |
| 291 | BUILD_BUG_ON(dsize > sizeof(ast_vhub_conf_desc)); | 288 | BUILD_BUG_ON(dsize > sizeof(vhub->vhub_conf_desc)); |
| 292 | BUILD_BUG_ON(AST_VHUB_CONF_DESC_SIZE >= AST_VHUB_EP0_MAX_PACKET); | 289 | BUILD_BUG_ON(AST_VHUB_CONF_DESC_SIZE >= AST_VHUB_EP0_MAX_PACKET); |
| 293 | break; | 290 | break; |
| 294 | case USB_DT_HUB: | 291 | case USB_DT_HUB: |
| 295 | dsize = AST_VHUB_HUB_DESC_SIZE; | 292 | dsize = AST_VHUB_HUB_DESC_SIZE; |
| 296 | memcpy(ep->buf, &ast_vhub_hub_desc, dsize); | 293 | memcpy(ep->buf, &vhub->vhub_hub_desc, dsize); |
| 297 | BUILD_BUG_ON(dsize > sizeof(ast_vhub_hub_desc)); | 294 | BUILD_BUG_ON(dsize > sizeof(vhub->vhub_hub_desc)); |
| 298 | BUILD_BUG_ON(AST_VHUB_HUB_DESC_SIZE >= AST_VHUB_EP0_MAX_PACKET); | 295 | BUILD_BUG_ON(AST_VHUB_HUB_DESC_SIZE >= AST_VHUB_EP0_MAX_PACKET); |
| 299 | break; | 296 | break; |
| 300 | default: | 297 | default: |
| @@ -317,7 +314,8 @@ static int ast_vhub_rep_string(struct ast_vhub_ep *ep, · 16 unmodified lines | |||
| 317 | u8 string_id, u16 lang_id, | 314 | u8 string_id, u16 lang_id, |
| 318 | u16 len) | 315 | u16 len) |
| 319 | { | 316 | { |
| 320 | int rc = usb_gadget_get_string (&ast_vhub_strings, string_id, ep->buf); | 317 | int rc = usb_gadget_get_string(&ep->vhub->vhub_str_desc, |
| 318 | string_id, ep->buf); | ||
| 321 | 319 | ||
| 322 | /* | 320 | /* |
| 323 | * This should never happen unless we put too big strings in | 321 | * This should never happen unless we put too big strings in |
| @@ -504,7 +502,7 @@ static void ast_vhub_wake_work(struct work_struct *work) · 180 unmodified lines | |||
| 504 | * we let the normal host wake path deal with it later. | 502 | * we let the normal host wake path deal with it later. |
| 505 | */ | 503 | */ |
| 506 | spin_lock_irqsave(&vhub->lock, flags); | 504 | spin_lock_irqsave(&vhub->lock, flags); |
| 507 | for (i = 0; i < AST_VHUB_NUM_PORTS; i++) { | 505 | for (i = 0; i < vhub->max_ports; i++) { |
| 508 | struct ast_vhub_port *p = &vhub->ports[i]; | 506 | struct ast_vhub_port *p = &vhub->ports[i]; |
| 509 | 507 | ||
| 510 | if (!(p->status & USB_PORT_STAT_SUSPEND)) | 508 | if (!(p->status & USB_PORT_STAT_SUSPEND)) |
| @@ -587,7 +585,7 @@ static enum std_req_rc ast_vhub_set_port_feature(struct ast_vhub_ep *ep, · 76 unmodified lines | |||
| 587 | struct ast_vhub *vhub = ep->vhub; | 585 | struct ast_vhub *vhub = ep->vhub; |
| 588 | struct ast_vhub_port *p; | 586 | struct ast_vhub_port *p; |
| 589 | 587 | ||
| 590 | if (port == 0 || port > AST_VHUB_NUM_PORTS) | 588 | if (port == 0 || port > vhub->max_ports) |
| 591 | return std_req_stall; | 589 | return std_req_stall; |
| 592 | port--; | 590 | port--; |
| 593 | p = &vhub->ports[port]; | 591 | p = &vhub->ports[port]; |
| @@ -630,7 +628,7 @@ static enum std_req_rc ast_vhub_clr_port_feature(struct ast_vhub_ep *ep, · 36 unmodified lines | |||
| 630 | struct ast_vhub *vhub = ep->vhub; | 628 | struct ast_vhub *vhub = ep->vhub; |
| 631 | struct ast_vhub_port *p; | 629 | struct ast_vhub_port *p; |
| 632 | 630 | ||
| 633 | if (port == 0 || port > AST_VHUB_NUM_PORTS) | 631 | if (port == 0 || port > vhub->max_ports) |
| 634 | return std_req_stall; | 632 | return std_req_stall; |
| 635 | port--; | 633 | port--; |
| 636 | p = &vhub->ports[port]; | 634 | p = &vhub->ports[port]; |
| @@ -676,7 +674,7 @@ static enum std_req_rc ast_vhub_get_port_stat(struct ast_vhub_ep *ep, · 39 unmodified lines | |||
| 676 | struct ast_vhub *vhub = ep->vhub; | 674 | struct ast_vhub *vhub = ep->vhub; |
| 677 | u16 stat, chg; | 675 | u16 stat, chg; |
| 678 | 676 | ||
| 679 | if (port == 0 || port > AST_VHUB_NUM_PORTS) | 677 | if (port == 0 || port > vhub->max_ports) |
| 680 | return std_req_stall; | 678 | return std_req_stall; |
| 681 | port--; | 679 | port--; |
| 682 | 680 | ||
| @@ -757,7 +755,7 @@ void ast_vhub_hub_suspend(struct ast_vhub *vhub) · 74 unmodified lines | |||
| 757 | * Forward to unsuspended ports without changing | 755 | * Forward to unsuspended ports without changing |
| 758 | * their connection status. | 756 | * their connection status. |
| 759 | */ | 757 | */ |
| 760 | for (i = 0; i < AST_VHUB_NUM_PORTS; i++) { | 758 | for (i = 0; i < vhub->max_ports; i++) { |
| 761 | struct ast_vhub_port *p = &vhub->ports[i]; | 759 | struct ast_vhub_port *p = &vhub->ports[i]; |
| 762 | 760 | ||
| 763 | if (!(p->status & USB_PORT_STAT_SUSPEND)) | 761 | if (!(p->status & USB_PORT_STAT_SUSPEND)) |
| @@ -780,7 +778,7 @@ void ast_vhub_hub_resume(struct ast_vhub *vhub) · 16 unmodified lines | |||
| 780 | * Forward to unsuspended ports without changing | 778 | * Forward to unsuspended ports without changing |
| 781 | * their connection status. | 779 | * their connection status. |
| 782 | */ | 780 | */ |
| 783 | for (i = 0; i < AST_VHUB_NUM_PORTS; i++) { | 781 | for (i = 0; i < vhub->max_ports; i++) { |
| 784 | struct ast_vhub_port *p = &vhub->ports[i]; | 782 | struct ast_vhub_port *p = &vhub->ports[i]; |
| 785 | 783 | ||
| 786 | if (!(p->status & USB_PORT_STAT_SUSPEND)) | 784 | if (!(p->status & USB_PORT_STAT_SUSPEND)) |
| @@ -814,7 +812,7 @@ void ast_vhub_hub_reset(struct ast_vhub *vhub) · 27 unmodified lines | |||
| 814 | * Clear all port status, disable gadgets and "suspend" | 812 | * Clear all port status, disable gadgets and "suspend" |
| 815 | * them. They will be woken up by a port reset. | 813 | * them. They will be woken up by a port reset. |
| 816 | */ | 814 | */ |
| 817 | for (i = 0; i < AST_VHUB_NUM_PORTS; i++) { | 815 | for (i = 0; i < vhub->max_ports; i++) { |
| 818 | struct ast_vhub_port *p = &vhub->ports[i]; | 816 | struct ast_vhub_port *p = &vhub->ports[i]; |
| 819 | 817 | ||
| 820 | /* Only keep the connected flag */ | 818 | /* Only keep the connected flag */ |
| @@ -834,9 +832,31 @@ void ast_vhub_hub_reset(struct ast_vhub *vhub) · 13 unmodified lines | |||
| 834 | writel(0, vhub->regs + AST_VHUB_EP1_STS_CHG); | 832 | writel(0, vhub->regs + AST_VHUB_EP1_STS_CHG); |
| 835 | } | 833 | } |
| 836 | 834 | ||
| 835 | static void ast_vhub_init_desc(struct ast_vhub *vhub) | ||
| 836 | { | ||
| 837 | /* Initialize vhub Device Descriptor. */ | ||
| 838 | memcpy(&vhub->vhub_dev_desc, &ast_vhub_dev_desc, | ||
| 839 | sizeof(vhub->vhub_dev_desc)); | ||
| 840 | |||
| 841 | /* Initialize vhub Configuration Descriptor. */ | ||
| 842 | memcpy(&vhub->vhub_conf_desc, &ast_vhub_conf_desc, | ||
| 843 | sizeof(vhub->vhub_conf_desc)); | ||
| 844 | |||
| 845 | /* Initialize vhub Hub Descriptor. */ | ||
| 846 | memcpy(&vhub->vhub_hub_desc, &ast_vhub_hub_desc, | ||
| 847 | sizeof(vhub->vhub_hub_desc)); | ||
| 848 | vhub->vhub_hub_desc.bNbrPorts = vhub->max_ports; | ||
| 849 | |||
| 850 | /* Initialize vhub String Descriptors. */ | ||
| 851 | memcpy(&vhub->vhub_str_desc, &ast_vhub_strings, | ||
| 852 | sizeof(vhub->vhub_str_desc)); | ||
| 853 | } | ||
| 854 | |||
| 837 | void ast_vhub_init_hub(struct ast_vhub *vhub) | 855 | void ast_vhub_init_hub(struct ast_vhub *vhub) |
| 838 | { | 856 | { |
| 839 | vhub->speed = USB_SPEED_UNKNOWN; | 857 | vhub->speed = USB_SPEED_UNKNOWN; |
| 840 | INIT_WORK(&vhub->wake_work, ast_vhub_wake_work); | 858 | INIT_WORK(&vhub->wake_work, ast_vhub_wake_work); |
| 859 | |||
| 860 | ast_vhub_init_desc(vhub); | ||
| 841 | } | 861 | } |
| 842 | 862 | ||
| @@ -2,6 +2,9 @@ · 1 unmodified line | |||
| 2 | #ifndef __ASPEED_VHUB_H | 2 | #ifndef __ASPEED_VHUB_H |
| 3 | #define __ASPEED_VHUB_H | 3 | #define __ASPEED_VHUB_H |
| 4 | 4 | ||
| 5 | #include <linux/usb.h> | ||
| 6 | #include <linux/usb/ch11.h> | ||
| 7 | |||
| 5 | /***************************** | 8 | /***************************** |
| 6 | * * | 9 | * * |
| 7 | * VHUB register definitions * | 10 | * VHUB register definitions * |
| @@ -76,17 +79,9 @@ · 68 unmodified lines | |||
| 76 | #define VHUB_SW_RESET_DEVICE2 (1 << 2) | 79 | #define VHUB_SW_RESET_DEVICE2 (1 << 2) |
| 77 | #define VHUB_SW_RESET_DEVICE1 (1 << 1) | 80 | #define VHUB_SW_RESET_DEVICE1 (1 << 1) |
| 78 | #define VHUB_SW_RESET_ROOT_HUB (1 << 0) | 81 | #define VHUB_SW_RESET_ROOT_HUB (1 << 0) |
| 79 | #define VHUB_SW_RESET_ALL (VHUB_SW_RESET_EP_POOL | \ | 82 | |
| 80 | VHUB_SW_RESET_DMA_CONTROLLER | \ | ||
| 81 | VHUB_SW_RESET_DEVICE5 | \ | ||
| 82 | VHUB_SW_RESET_DEVICE4 | \ | ||
| 83 | VHUB_SW_RESET_DEVICE3 | \ | ||
| 84 | VHUB_SW_RESET_DEVICE2 | \ | ||
| 85 | VHUB_SW_RESET_DEVICE1 | \ | ||
| 86 | VHUB_SW_RESET_ROOT_HUB) | ||
| 87 | /* EP ACK/NACK IRQ masks */ | 83 | /* EP ACK/NACK IRQ masks */ |
| 88 | #define VHUB_EP_IRQ(n) (1 << (n)) | 84 | #define VHUB_EP_IRQ(n) (1 << (n)) |
| 89 | #define VHUB_EP_IRQ_ALL 0x7fff /* 15 EPs */ | ||
| 90 | 85 | ||
| 91 | /* USB status reg */ | 86 | /* USB status reg */ |
| 92 | #define VHUB_USBSTS_HISPEED (1 << 27) | 87 | #define VHUB_USBSTS_HISPEED (1 << 27) |
| @@ -210,6 +205,11 @@ · 117 unmodified lines | |||
| 210 | * * | 205 | * * |
| 211 | ****************************************/ | 206 | ****************************************/ |
| 212 | 207 | ||
| 208 | /* | ||
| 209 | * AST_VHUB_NUM_GEN_EPs and AST_VHUB_NUM_PORTS are kept to avoid breaking | ||
| 210 | * existing AST2400/AST2500 platforms. AST2600 and future vhub revisions | ||
| 211 | * should define number of downstream ports and endpoints in device tree. | ||
| 212 | */ | ||
| 213 | #define AST_VHUB_NUM_GEN_EPs 15 /* Generic non-0 EPs */ | 213 | #define AST_VHUB_NUM_GEN_EPs 15 /* Generic non-0 EPs */ |
| 214 | #define AST_VHUB_NUM_PORTS 5 /* vHub ports */ | 214 | #define AST_VHUB_NUM_PORTS 5 /* vHub ports */ |
| 215 | #define AST_VHUB_EP0_MAX_PACKET 64 /* EP0's max packet size */ | 215 | #define AST_VHUB_EP0_MAX_PACKET 64 /* EP0's max packet size */ |
| @@ -312,7 +312,7 @@ struct ast_vhub_ep { · 96 unmodified lines | |||
| 312 | /* Registers */ | 312 | /* Registers */ |
| 313 | void __iomem *regs; | 313 | void __iomem *regs; |
| 314 | 314 | ||
| 315 | /* Index in global pool (0..14) */ | 315 | /* Index in global pool (zero-based) */ |
| 316 | unsigned int g_idx; | 316 | unsigned int g_idx; |
| 317 | 317 | ||
| 318 | /* DMA Descriptors */ | 318 | /* DMA Descriptors */ |
| @@ -342,7 +342,7 @@ struct ast_vhub_dev { · 23 unmodified lines | |||
| 342 | struct ast_vhub *vhub; | 342 | struct ast_vhub *vhub; |
| 343 | void __iomem *regs; | 343 | void __iomem *regs; |
| 344 | 344 | ||
| 345 | /* Device index (0...4) and name string */ | 345 | /* Device index (zero-based) and name string */ |
| 346 | unsigned int index; | 346 | unsigned int index; |
| 347 | const char *name; | 347 | const char *name; |
| 348 | 348 | ||
| @@ -358,7 +358,8 @@ struct ast_vhub_dev { · 9 unmodified lines | |||
| 358 | 358 | ||
| 359 | /* Endpoint structures */ | 359 | /* Endpoint structures */ |
| 360 | struct ast_vhub_ep ep0; | 360 | struct ast_vhub_ep ep0; |
| 361 | struct ast_vhub_ep *epns[AST_VHUB_NUM_GEN_EPs]; | 361 | struct ast_vhub_ep **epns; |
| 362 | u32 max_epns; | ||
| 362 | 363 | ||
| 363 | }; | 364 | }; |
| 364 | #define to_ast_dev(__g) container_of(__g, struct ast_vhub_dev, gadget) | 365 | #define to_ast_dev(__g) container_of(__g, struct ast_vhub_dev, gadget) |
| @@ -373,6 +374,12 @@ struct ast_vhub_port { · 8 unmodified lines | |||
| 373 | struct ast_vhub_dev dev; | 374 | struct ast_vhub_dev dev; |
| 374 | }; | 375 | }; |
| 375 | 376 | ||
| 377 | struct ast_vhub_full_cdesc { | ||
| 378 | struct usb_config_descriptor cfg; | ||
| 379 | struct usb_interface_descriptor intf; | ||
| 380 | struct usb_endpoint_descriptor ep; | ||
| 381 | } __packed; | ||
| 382 | |||
| 376 | /* Global vhub structure */ | 383 | /* Global vhub structure */ |
| 377 | struct ast_vhub { | 384 | struct ast_vhub { |
| 378 | struct platform_device *pdev; | 385 | struct platform_device *pdev; |
| @@ -393,10 +400,12 @@ struct ast_vhub { · 14 unmodified lines | |||
| 393 | bool ep1_stalled : 1; | 400 | bool ep1_stalled : 1; |
| 394 | 401 | ||
| 395 | /* Per-port info */ | 402 | /* Per-port info */ |
| 396 | struct ast_vhub_port ports[AST_VHUB_NUM_PORTS]; | 403 | struct ast_vhub_port *ports; |
| 404 | u32 max_ports; | ||
| 397 | 405 | ||
| 398 | /* Generic EP data structures */ | 406 | /* Generic EP data structures */ |
| 399 | struct ast_vhub_ep epns[AST_VHUB_NUM_GEN_EPs]; | 407 | struct ast_vhub_ep *epns; |
| 408 | u32 max_epns; | ||
| 400 | 409 | ||
| 401 | /* Upstream bus is suspended ? */ | 410 | /* Upstream bus is suspended ? */ |
| 402 | bool suspended : 1; | 411 | bool suspended : 1; |
| @@ -409,6 +418,12 @@ struct ast_vhub { · 6 unmodified lines | |||
| 409 | 418 | ||
| 410 | /* Upstream bus speed captured at bus reset */ | 419 | /* Upstream bus speed captured at bus reset */ |
| 411 | unsigned int speed; | 420 | unsigned int speed; |
| 421 | |||
| 422 | /* Standard USB Descriptors of the vhub. */ | ||
| 423 | struct usb_device_descriptor vhub_dev_desc; | ||
| 424 | struct ast_vhub_full_cdesc vhub_conf_desc; | ||
| 425 | struct usb_hub_descriptor vhub_hub_desc; | ||
| 426 | struct usb_gadget_strings vhub_str_desc; | ||
| 412 | }; | 427 | }; |
| 413 | 428 | ||
| 414 | /* Standard request handlers result codes */ | 429 | /* Standard request handlers result codes */ |
| @@ -0,0 +1,1331 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0+ | ||
| 2 | /* | ||
| 3 | * MAX3420 Device Controller driver for USB. | ||
| 4 | * | ||
| 5 | * Author: Jaswinder Singh Brar <jaswinder.singh@linaro.org> | ||
| 6 | * (C) Copyright 2019-2020 Linaro Ltd | ||
| 7 | * | ||
| 8 | * Based on: | ||
| 9 | * o MAX3420E datasheet | ||
| 10 | * http://datasheets.maximintegrated.com/en/ds/MAX3420E.pdf | ||
| 11 | * o MAX342{0,1}E Programming Guides | ||
| 12 | * https://pdfserv.maximintegrated.com/en/an/AN3598.pdf | ||
| 13 | * https://pdfserv.maximintegrated.com/en/an/AN3785.pdf | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/delay.h> | ||
| 17 | #include <linux/device.h> | ||
| 18 | #include <linux/interrupt.h> | ||
| 19 | #include <linux/io.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/bitfield.h> | ||
| 22 | #include <linux/of_address.h> | ||
| 23 | #include <linux/of_device.h> | ||
| 24 | #include <linux/of_platform.h> | ||
| 25 | #include <linux/of_irq.h> | ||
| 26 | #include <linux/prefetch.h> | ||
| 27 | #include <linux/usb/ch9.h> | ||
| 28 | #include <linux/usb/gadget.h> | ||
| 29 | #include <linux/spi/spi.h> | ||
| 30 | #include <linux/gpio/consumer.h> | ||
| 31 | |||
| 32 | #define MAX3420_MAX_EPS 4 | ||
| 33 | #define MAX3420_EP_MAX_PACKET 64 /* Same for all Endpoints */ | ||
| 34 | #define MAX3420_EPNAME_SIZE 16 /* Buffer size for endpoint name */ | ||
| 35 | |||
| 36 | #define MAX3420_ACKSTAT BIT(0) | ||
| 37 | |||
| 38 | #define MAX3420_SPI_DIR_RD 0 /* read register from MAX3420 */ | ||
| 39 | #define MAX3420_SPI_DIR_WR 1 /* write register to MAX3420 */ | ||
| 40 | |||
| 41 | /* SPI commands: */ | ||
| 42 | #define MAX3420_SPI_DIR_SHIFT 1 | ||
| 43 | #define MAX3420_SPI_REG_SHIFT 3 | ||
| 44 | |||
| 45 | #define MAX3420_REG_EP0FIFO 0 | ||
| 46 | #define MAX3420_REG_EP1FIFO 1 | ||
| 47 | #define MAX3420_REG_EP2FIFO 2 | ||
| 48 | #define MAX3420_REG_EP3FIFO 3 | ||
| 49 | #define MAX3420_REG_SUDFIFO 4 | ||
| 50 | #define MAX3420_REG_EP0BC 5 | ||
| 51 | #define MAX3420_REG_EP1BC 6 | ||
| 52 | #define MAX3420_REG_EP2BC 7 | ||
| 53 | #define MAX3420_REG_EP3BC 8 | ||
| 54 | |||
| 55 | #define MAX3420_REG_EPSTALLS 9 | ||
| 56 | #define ACKSTAT BIT(6) | ||
| 57 | #define STLSTAT BIT(5) | ||
| 58 | #define STLEP3IN BIT(4) | ||
| 59 | #define STLEP2IN BIT(3) | ||
| 60 | #define STLEP1OUT BIT(2) | ||
| 61 | #define STLEP0OUT BIT(1) | ||
| 62 | #define STLEP0IN BIT(0) | ||
| 63 | |||
| 64 | #define MAX3420_REG_CLRTOGS 10 | ||
| 65 | #define EP3DISAB BIT(7) | ||
| 66 | #define EP2DISAB BIT(6) | ||
| 67 | #define EP1DISAB BIT(5) | ||
| 68 | #define CTGEP3IN BIT(4) | ||
| 69 | #define CTGEP2IN BIT(3) | ||
| 70 | #define CTGEP1OUT BIT(2) | ||
| 71 | |||
| 72 | #define MAX3420_REG_EPIRQ 11 | ||
| 73 | #define MAX3420_REG_EPIEN 12 | ||
| 74 | #define SUDAVIRQ BIT(5) | ||
| 75 | #define IN3BAVIRQ BIT(4) | ||
| 76 | #define IN2BAVIRQ BIT(3) | ||
| 77 | #define OUT1DAVIRQ BIT(2) | ||
| 78 | #define OUT0DAVIRQ BIT(1) | ||
| 79 | #define IN0BAVIRQ BIT(0) | ||
| 80 | |||
| 81 | #define MAX3420_REG_USBIRQ 13 | ||
| 82 | #define MAX3420_REG_USBIEN 14 | ||
| 83 | #define OSCOKIRQ BIT(0) | ||
| 84 | #define RWUDNIRQ BIT(1) | ||
| 85 | #define BUSACTIRQ BIT(2) | ||
| 86 | #define URESIRQ BIT(3) | ||
| 87 | #define SUSPIRQ BIT(4) | ||
| 88 | #define NOVBUSIRQ BIT(5) | ||
| 89 | #define VBUSIRQ BIT(6) | ||
| 90 | #define URESDNIRQ BIT(7) | ||
| 91 | |||
| 92 | #define MAX3420_REG_USBCTL 15 | ||
| 93 | #define HOSCSTEN BIT(7) | ||
| 94 | #define VBGATE BIT(6) | ||
| 95 | #define CHIPRES BIT(5) | ||
| 96 | #define PWRDOWN BIT(4) | ||
| 97 | #define CONNECT BIT(3) | ||
| 98 | #define SIGRWU BIT(2) | ||
| 99 | |||
| 100 | #define MAX3420_REG_CPUCTL 16 | ||
| 101 | #define IE BIT(0) | ||
| 102 | |||
| 103 | #define MAX3420_REG_PINCTL 17 | ||
| 104 | #define EP3INAK BIT(7) | ||
| 105 | #define EP2INAK BIT(6) | ||
| 106 | #define EP0INAK BIT(5) | ||
| 107 | #define FDUPSPI BIT(4) | ||
| 108 | #define INTLEVEL BIT(3) | ||
| 109 | #define POSINT BIT(2) | ||
| 110 | #define GPXB BIT(1) | ||
| 111 | #define GPXA BIT(0) | ||
| 112 | |||
| 113 | #define MAX3420_REG_REVISION 18 | ||
| 114 | |||
| 115 | #define MAX3420_REG_FNADDR 19 | ||
| 116 | #define FNADDR_MASK 0x7f | ||
| 117 | |||
| 118 | #define MAX3420_REG_IOPINS 20 | ||
| 119 | #define MAX3420_REG_IOPINS2 21 | ||
| 120 | #define MAX3420_REG_GPINIRQ 22 | ||
| 121 | #define MAX3420_REG_GPINIEN 23 | ||
| 122 | #define MAX3420_REG_GPINPOL 24 | ||
| 123 | #define MAX3420_REG_HIRQ 25 | ||
| 124 | #define MAX3420_REG_HIEN 26 | ||
| 125 | #define MAX3420_REG_MODE 27 | ||
| 126 | #define MAX3420_REG_PERADDR 28 | ||
| 127 | #define MAX3420_REG_HCTL 29 | ||
| 128 | #define MAX3420_REG_HXFR 30 | ||
| 129 | #define MAX3420_REG_HRSL 31 | ||
| 130 | |||
| 131 | #define ENABLE_IRQ BIT(0) | ||
| 132 | #define IOPIN_UPDATE BIT(1) | ||
| 133 | #define REMOTE_WAKEUP BIT(2) | ||
| 134 | #define CONNECT_HOST GENMASK(4, 3) | ||
| 135 | #define HCONNECT (1 << 3) | ||
| 136 | #define HDISCONNECT (3 << 3) | ||
| 137 | #define UDC_START GENMASK(6, 5) | ||
| 138 | #define START (1 << 5) | ||
| 139 | #define STOP (3 << 5) | ||
| 140 | #define ENABLE_EP GENMASK(8, 7) | ||
| 141 | #define ENABLE (1 << 7) | ||
| 142 | #define DISABLE (3 << 7) | ||
| 143 | #define STALL_EP GENMASK(10, 9) | ||
| 144 | #define STALL (1 << 9) | ||
| 145 | #define UNSTALL (3 << 9) | ||
| 146 | |||
| 147 | #define MAX3420_CMD(c) FIELD_PREP(GENMASK(7, 3), c) | ||
| 148 | #define MAX3420_SPI_CMD_RD(c) (MAX3420_CMD(c) | (0 << 1)) | ||
| 149 | #define MAX3420_SPI_CMD_WR(c) (MAX3420_CMD(c) | (1 << 1)) | ||
| 150 | |||
| 151 | struct max3420_req { | ||
| 152 | struct usb_request usb_req; | ||
| 153 | struct list_head queue; | ||
| 154 | struct max3420_ep *ep; | ||
| 155 | }; | ||
| 156 | |||
| 157 | struct max3420_ep { | ||
| 158 | struct usb_ep ep_usb; | ||
| 159 | struct max3420_udc *udc; | ||
| 160 | struct list_head queue; | ||
| 161 | char name[MAX3420_EPNAME_SIZE]; | ||
| 162 | unsigned int maxpacket; | ||
| 163 | spinlock_t lock; | ||
| 164 | int halted; | ||
| 165 | u32 todo; | ||
| 166 | int id; | ||
| 167 | }; | ||
| 168 | |||
| 169 | struct max3420_udc { | ||
| 170 | struct usb_gadget gadget; | ||
| 171 | struct max3420_ep ep[MAX3420_MAX_EPS]; | ||
| 172 | struct usb_gadget_driver *driver; | ||
| 173 | struct task_struct *thread_task; | ||
| 174 | int remote_wkp, is_selfpowered; | ||
| 175 | bool vbus_active, softconnect; | ||
| 176 | struct usb_ctrlrequest setup; | ||
| 177 | struct mutex spi_bus_mutex; | ||
| 178 | struct max3420_req ep0req; | ||
| 179 | struct spi_device *spi; | ||
| 180 | struct device *dev; | ||
| 181 | spinlock_t lock; | ||
| 182 | bool suspended; | ||
| 183 | u8 ep0buf[64]; | ||
| 184 | u32 todo; | ||
| 185 | }; | ||
| 186 | |||
| 187 | #define to_max3420_req(r) container_of((r), struct max3420_req, usb_req) | ||
| 188 | #define to_max3420_ep(e) container_of((e), struct max3420_ep, ep_usb) | ||
| 189 | #define to_udc(g) container_of((g), struct max3420_udc, gadget) | ||
| 190 | |||
| 191 | #define DRIVER_DESC "MAX3420 USB Device-Mode Driver" | ||
| 192 | static const char driver_name[] = "max3420-udc"; | ||
| 193 | |||
| 194 | /* Control endpoint configuration.*/ | ||
| 195 | static const struct usb_endpoint_descriptor ep0_desc = { | ||
| 196 | .bEndpointAddress = USB_DIR_OUT, | ||
| 197 | .bmAttributes = USB_ENDPOINT_XFER_CONTROL, | ||
| 198 | .wMaxPacketSize = cpu_to_le16(MAX3420_EP_MAX_PACKET), | ||
| 199 | }; | ||
| 200 | |||
| 201 | static void spi_ack_ctrl(struct max3420_udc *udc) | ||
| 202 | { | ||
| 203 | struct spi_device *spi = udc->spi; | ||
| 204 | struct spi_transfer transfer; | ||
| 205 | struct spi_message msg; | ||
| 206 | u8 txdata[1]; | ||
| 207 | |||
| 208 | memset(&transfer, 0, sizeof(transfer)); | ||
| 209 | |||
| 210 | spi_message_init(&msg); | ||
| 211 | |||
| 212 | txdata[0] = MAX3420_ACKSTAT; | ||
| 213 | transfer.tx_buf = txdata; | ||
| 214 | transfer.len = 1; | ||
| 215 | |||
| 216 | spi_message_add_tail(&transfer, &msg); | ||
| 217 | spi_sync(spi, &msg); | ||
| 218 | } | ||
| 219 | |||
| 220 | static u8 spi_rd8_ack(struct max3420_udc *udc, u8 reg, int actstat) | ||
| 221 | { | ||
| 222 | struct spi_device *spi = udc->spi; | ||
| 223 | struct spi_transfer transfer; | ||
| 224 | struct spi_message msg; | ||
| 225 | u8 txdata[2], rxdata[2]; | ||
| 226 | |||
| 227 | memset(&transfer, 0, sizeof(transfer)); | ||
| 228 | |||
| 229 | spi_message_init(&msg); | ||
| 230 | |||
| 231 | txdata[0] = MAX3420_SPI_CMD_RD(reg) | (actstat ? MAX3420_ACKSTAT : 0); | ||
| 232 | transfer.tx_buf = txdata; | ||
| 233 | transfer.rx_buf = rxdata; | ||
| 234 | transfer.len = 2; | ||
| 235 | |||
| 236 | spi_message_add_tail(&transfer, &msg); | ||
| 237 | spi_sync(spi, &msg); | ||
| 238 | |||
| 239 | return rxdata[1]; | ||
| 240 | } | ||
| 241 | |||
| 242 | static u8 spi_rd8(struct max3420_udc *udc, u8 reg) | ||
| 243 | { | ||
| 244 | return spi_rd8_ack(udc, reg, 0); | ||
| 245 | } | ||
| 246 | |||
| 247 | static void spi_wr8_ack(struct max3420_udc *udc, u8 reg, u8 val, int actstat) | ||
| 248 | { | ||
| 249 | struct spi_device *spi = udc->spi; | ||
| 250 | struct spi_transfer transfer; | ||
| 251 | struct spi_message msg; | ||
| 252 | u8 txdata[2]; | ||
| 253 | |||
| 254 | memset(&transfer, 0, sizeof(transfer)); | ||
| 255 | |||
| 256 | spi_message_init(&msg); | ||
| 257 | |||
| 258 | txdata[0] = MAX3420_SPI_CMD_WR(reg) | (actstat ? MAX3420_ACKSTAT : 0); | ||
| 259 | txdata[1] = val; | ||
| 260 | |||
| 261 | transfer.tx_buf = txdata; | ||
| 262 | transfer.len = 2; | ||
| 263 | |||
| 264 | spi_message_add_tail(&transfer, &msg); | ||
| 265 | spi_sync(spi, &msg); | ||
| 266 | } | ||
| 267 | |||
| 268 | static void spi_wr8(struct max3420_udc *udc, u8 reg, u8 val) | ||
| 269 | { | ||
| 270 | spi_wr8_ack(udc, reg, val, 0); | ||
| 271 | } | ||
| 272 | |||
| 273 | static void spi_rd_buf(struct max3420_udc *udc, u8 reg, void *buf, u8 len) | ||
| 274 | { | ||
| 275 | struct spi_device *spi = udc->spi; | ||
| 276 | struct spi_transfer transfer; | ||
| 277 | struct spi_message msg; | ||
| 278 | u8 local_buf[MAX3420_EP_MAX_PACKET + 1] = {}; | ||
| 279 | |||
| 280 | memset(&transfer, 0, sizeof(transfer)); | ||
| 281 | |||
| 282 | spi_message_init(&msg); | ||
| 283 | |||
| 284 | local_buf[0] = MAX3420_SPI_CMD_RD(reg); | ||
| 285 | transfer.tx_buf = &local_buf[0]; | ||
| 286 | transfer.rx_buf = &local_buf[0]; | ||
| 287 | transfer.len = len + 1; | ||
| 288 | |||
| 289 | spi_message_add_tail(&transfer, &msg); | ||
| 290 | spi_sync(spi, &msg); | ||
| 291 | |||
| 292 | memcpy(buf, &local_buf[1], len); | ||
| 293 | } | ||
| 294 | |||
| 295 | static void spi_wr_buf(struct max3420_udc *udc, u8 reg, void *buf, u8 len) | ||
| 296 | { | ||
| 297 | struct spi_device *spi = udc->spi; | ||
| 298 | struct spi_transfer transfer; | ||
| 299 | struct spi_message msg; | ||
| 300 | u8 local_buf[MAX3420_EP_MAX_PACKET + 1] = {}; | ||
| 301 | |||
| 302 | memset(&transfer, 0, sizeof(transfer)); | ||
| 303 | |||
| 304 | spi_message_init(&msg); | ||
| 305 | |||
| 306 | local_buf[0] = MAX3420_SPI_CMD_WR(reg); | ||
| 307 | memcpy(&local_buf[1], buf, len); | ||
| 308 | |||
| 309 | transfer.tx_buf = local_buf; | ||
| 310 | transfer.len = len + 1; | ||
| 311 | |||
| 312 | spi_message_add_tail(&transfer, &msg); | ||
| 313 | spi_sync(spi, &msg); | ||
| 314 | } | ||
| 315 | |||
| 316 | static int spi_max3420_enable(struct max3420_ep *ep) | ||
| 317 | { | ||
| 318 | struct max3420_udc *udc = ep->udc; | ||
| 319 | unsigned long flags; | ||
| 320 | u8 epdis, epien; | ||
| 321 | int todo; | ||
| 322 | |||
| 323 | spin_lock_irqsave(&ep->lock, flags); | ||
| 324 | todo = ep->todo & ENABLE_EP; | ||
| 325 | ep->todo &= ~ENABLE_EP; | ||
| 326 | spin_unlock_irqrestore(&ep->lock, flags); | ||
| 327 | |||
| 328 | if (!todo || ep->id == 0) | ||
| 329 | return false; | ||
| 330 | |||
| 331 | epien = spi_rd8(udc, MAX3420_REG_EPIEN); | ||
| 332 | epdis = spi_rd8(udc, MAX3420_REG_CLRTOGS); | ||
| 333 | |||
| 334 | if (todo == ENABLE) { | ||
| 335 | epdis &= ~BIT(ep->id + 4); | ||
| 336 | epien |= BIT(ep->id + 1); | ||
| 337 | } else { | ||
| 338 | epdis |= BIT(ep->id + 4); | ||
| 339 | epien &= ~BIT(ep->id + 1); | ||
| 340 | } | ||
| 341 | |||
| 342 | spi_wr8(udc, MAX3420_REG_CLRTOGS, epdis); | ||
| 343 | spi_wr8(udc, MAX3420_REG_EPIEN, epien); | ||
| 344 | |||
| 345 | return true; | ||
| 346 | } | ||
| 347 | |||
| 348 | static int spi_max3420_stall(struct max3420_ep *ep) | ||
| 349 | { | ||
| 350 | struct max3420_udc *udc = ep->udc; | ||
| 351 | unsigned long flags; | ||
| 352 | u8 epstalls; | ||
| 353 | int todo; | ||
| 354 | |||
| 355 | spin_lock_irqsave(&ep->lock, flags); | ||
| 356 | todo = ep->todo & STALL_EP; | ||
| 357 | ep->todo &= ~STALL_EP; | ||
| 358 | spin_unlock_irqrestore(&ep->lock, flags); | ||
| 359 | |||
| 360 | if (!todo || ep->id == 0) | ||
| 361 | return false; | ||
| 362 | |||
| 363 | epstalls = spi_rd8(udc, MAX3420_REG_EPSTALLS); | ||
| 364 | if (todo == STALL) { | ||
| 365 | ep->halted = 1; | ||
| 366 | epstalls |= BIT(ep->id + 1); | ||
| 367 | } else { | ||
| 368 | u8 clrtogs; | ||
| 369 | |||
| 370 | ep->halted = 0; | ||
| 371 | epstalls &= ~BIT(ep->id + 1); | ||
| 372 | clrtogs = spi_rd8(udc, MAX3420_REG_CLRTOGS); | ||
| 373 | clrtogs |= BIT(ep->id + 1); | ||
| 374 | spi_wr8(udc, MAX3420_REG_CLRTOGS, clrtogs); | ||
| 375 | } | ||
| 376 | spi_wr8(udc, MAX3420_REG_EPSTALLS, epstalls | ACKSTAT); | ||
| 377 | |||
| 378 | return true; | ||
| 379 | } | ||
| 380 | |||
| 381 | static int spi_max3420_rwkup(struct max3420_udc *udc) | ||
| 382 | { | ||
| 383 | unsigned long flags; | ||
| 384 | int wake_remote; | ||
| 385 | u8 usbctl; | ||
| 386 | |||
| 387 | spin_lock_irqsave(&udc->lock, flags); | ||
| 388 | wake_remote = udc->todo & REMOTE_WAKEUP; | ||
| 389 | udc->todo &= ~REMOTE_WAKEUP; | ||
| 390 | spin_unlock_irqrestore(&udc->lock, flags); | ||
| 391 | |||
| 392 | if (!wake_remote || !udc->suspended) | ||
| 393 | return false; | ||
| 394 | |||
| 395 | /* Set Remote-WkUp Signal*/ | ||
| 396 | usbctl = spi_rd8(udc, MAX3420_REG_USBCTL); | ||
| 397 | usbctl |= SIGRWU; | ||
| 398 | spi_wr8(udc, MAX3420_REG_USBCTL, usbctl); | ||
| 399 | |||
| 400 | msleep_interruptible(5); | ||
| 401 | |||
| 402 | /* Clear Remote-WkUp Signal*/ | ||
| 403 | usbctl = spi_rd8(udc, MAX3420_REG_USBCTL); | ||
| 404 | usbctl &= ~SIGRWU; | ||
| 405 | spi_wr8(udc, MAX3420_REG_USBCTL, usbctl); | ||
| 406 | |||
| 407 | udc->suspended = false; | ||
| 408 | |||
| 409 | return true; | ||
| 410 | } | ||
| 411 | |||
| 412 | static void max3420_nuke(struct max3420_ep *ep, int status); | ||
| 413 | static void __max3420_stop(struct max3420_udc *udc) | ||
| 414 | { | ||
| 415 | u8 val; | ||
| 416 | int i; | ||
| 417 | |||
| 418 | /* clear all pending requests */ | ||
| 419 | for (i = 1; i < MAX3420_MAX_EPS; i++) | ||
| 420 | max3420_nuke(&udc->ep[i], -ECONNRESET); | ||
| 421 | |||
| 422 | /* Disable IRQ to CPU */ | ||
| 423 | spi_wr8(udc, MAX3420_REG_CPUCTL, 0); | ||
| 424 | |||
| 425 | val = spi_rd8(udc, MAX3420_REG_USBCTL); | ||
| 426 | val |= PWRDOWN; | ||
| 427 | if (udc->is_selfpowered) | ||
| 428 | val &= ~HOSCSTEN; | ||
| 429 | else | ||
| 430 | val |= HOSCSTEN; | ||
| 431 | spi_wr8(udc, MAX3420_REG_USBCTL, val); | ||
| 432 | } | ||
| 433 | |||
| 434 | static void __max3420_start(struct max3420_udc *udc) | ||
| 435 | { | ||
| 436 | u8 val; | ||
| 437 | |||
| 438 | /* Need this delay if bus-powered, | ||
| 439 | * but even for self-powered it helps stability | ||
| 440 | */ | ||
| 441 | msleep_interruptible(250); | ||
| 442 | |||
| 443 | /* configure SPI */ | ||
| 444 | spi_wr8(udc, MAX3420_REG_PINCTL, FDUPSPI); | ||
| 445 | |||
| 446 | /* Chip Reset */ | ||
| 447 | spi_wr8(udc, MAX3420_REG_USBCTL, CHIPRES); | ||
| 448 | msleep_interruptible(5); | ||
| 449 | spi_wr8(udc, MAX3420_REG_USBCTL, 0); | ||
| 450 | |||
| 451 | /* Poll for OSC to stabilize */ | ||
| 452 | while (1) { | ||
| 453 | val = spi_rd8(udc, MAX3420_REG_USBIRQ); | ||
| 454 | if (val & OSCOKIRQ) | ||
| 455 | break; | ||
| 456 | cond_resched(); | ||
| 457 | } | ||
| 458 | |||
| 459 | /* Enable PULL-UP only when Vbus detected */ | ||
| 460 | val = spi_rd8(udc, MAX3420_REG_USBCTL); | ||
| 461 | val |= VBGATE | CONNECT; | ||
| 462 | spi_wr8(udc, MAX3420_REG_USBCTL, val); | ||
| 463 | |||
| 464 | val = URESDNIRQ | URESIRQ; | ||
| 465 | if (udc->is_selfpowered) | ||
| 466 | val |= NOVBUSIRQ; | ||
| 467 | spi_wr8(udc, MAX3420_REG_USBIEN, val); | ||
| 468 | |||
| 469 | /* Enable only EP0 interrupts */ | ||
| 470 | val = IN0BAVIRQ | OUT0DAVIRQ | SUDAVIRQ; | ||
| 471 | spi_wr8(udc, MAX3420_REG_EPIEN, val); | ||
| 472 | |||
| 473 | /* Enable IRQ to CPU */ | ||
| 474 | spi_wr8(udc, MAX3420_REG_CPUCTL, IE); | ||
| 475 | } | ||
| 476 | |||
| 477 | static int max3420_start(struct max3420_udc *udc) | ||
| 478 | { | ||
| 479 | unsigned long flags; | ||
| 480 | int todo; | ||
| 481 | |||
| 482 | spin_lock_irqsave(&udc->lock, flags); | ||
| 483 | todo = udc->todo & UDC_START; | ||
| 484 | udc->todo &= ~UDC_START; | ||
| 485 | spin_unlock_irqrestore(&udc->lock, flags); | ||
| 486 | |||
| 487 | if (!todo) | ||
| 488 | return false; | ||
| 489 | |||
| 490 | if (udc->vbus_active && udc->softconnect) | ||
| 491 | __max3420_start(udc); | ||
| 492 | else | ||
| 493 | __max3420_stop(udc); | ||
| 494 | |||
| 495 | return true; | ||
| 496 | } | ||
| 497 | |||
| 498 | static irqreturn_t max3420_vbus_handler(int irq, void *dev_id) | ||
| 499 | { | ||
| 500 | struct max3420_udc *udc = dev_id; | ||
| 501 | unsigned long flags; | ||
| 502 | |||
| 503 | spin_lock_irqsave(&udc->lock, flags); | ||
| 504 | /* its a vbus change interrupt */ | ||
| 505 | udc->vbus_active = !udc->vbus_active; | ||
| 506 | udc->todo |= UDC_START; | ||
| 507 | usb_udc_vbus_handler(&udc->gadget, udc->vbus_active); | ||
| 508 | usb_gadget_set_state(&udc->gadget, udc->vbus_active | ||
| 509 | ? USB_STATE_POWERED : USB_STATE_NOTATTACHED); | ||
| 510 | spin_unlock_irqrestore(&udc->lock, flags); | ||
| 511 | |||
| 512 | if (udc->thread_task && | ||
| 513 | udc->thread_task->state != TASK_RUNNING) | ||
| 514 | wake_up_process(udc->thread_task); | ||
| 515 | |||
| 516 | return IRQ_HANDLED; | ||
| 517 | } | ||
| 518 | |||
| 519 | static irqreturn_t max3420_irq_handler(int irq, void *dev_id) | ||
| 520 | { | ||
| 521 | struct max3420_udc *udc = dev_id; | ||
| 522 | struct spi_device *spi = udc->spi; | ||
| 523 | unsigned long flags; | ||
| 524 | |||
| 525 | spin_lock_irqsave(&udc->lock, flags); | ||
| 526 | if ((udc->todo & ENABLE_IRQ) == 0) { | ||
| 527 | disable_irq_nosync(spi->irq); | ||
| 528 | udc->todo |= ENABLE_IRQ; | ||
| 529 | } | ||
| 530 | spin_unlock_irqrestore(&udc->lock, flags); | ||
| 531 | |||
| 532 | if (udc->thread_task && | ||
| 533 | udc->thread_task->state != TASK_RUNNING) | ||
| 534 | wake_up_process(udc->thread_task); | ||
| 535 | |||
| 536 | return IRQ_HANDLED; | ||
| 537 | } | ||
| 538 | |||
| 539 | static void max3420_getstatus(struct max3420_udc *udc) | ||
| 540 | { | ||
| 541 | struct max3420_ep *ep; | ||
| 542 | u16 status = 0; | ||
| 543 | |||
| 544 | switch (udc->setup.bRequestType & USB_RECIP_MASK) { | ||
| 545 | case USB_RECIP_DEVICE: | ||
| 546 | /* Get device status */ | ||
| 547 | status = udc->gadget.is_selfpowered << USB_DEVICE_SELF_POWERED; | ||
| 548 | status |= (udc->remote_wkp << USB_DEVICE_REMOTE_WAKEUP); | ||
| 549 | break; | ||
| 550 | case USB_RECIP_INTERFACE: | ||
| 551 | if (udc->driver->setup(&udc->gadget, &udc->setup) < 0) | ||
| 552 | goto stall; | ||
| 553 | break; | ||
| 554 | case USB_RECIP_ENDPOINT: | ||
| 555 | ep = &udc->ep[udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK]; | ||
| 556 | if (udc->setup.wIndex & USB_DIR_IN) { | ||
| 557 | if (!ep->ep_usb.caps.dir_in) | ||
| 558 | goto stall; | ||
| 559 | } else { | ||
| 560 | if (!ep->ep_usb.caps.dir_out) | ||
| 561 | goto stall; | ||
| 562 | } | ||
| 563 | if (ep->halted) | ||
| 564 | status = 1 << USB_ENDPOINT_HALT; | ||
| 565 | break; | ||
| 566 | default: | ||
| 567 | goto stall; | ||
| 568 | } | ||
| 569 | |||
| 570 | status = cpu_to_le16(status); | ||
| 571 | spi_wr_buf(udc, MAX3420_REG_EP0FIFO, &status, 2); | ||
| 572 | spi_wr8_ack(udc, MAX3420_REG_EP0BC, 2, 1); | ||
| 573 | return; | ||
| 574 | stall: | ||
| 575 | dev_err(udc->dev, "Can't respond to getstatus request\n"); | ||
| 576 | spi_wr8(udc, MAX3420_REG_EPSTALLS, STLEP0IN | STLEP0OUT | STLSTAT); | ||
| 577 | } | ||
| 578 | |||
| 579 | static void max3420_set_clear_feature(struct max3420_udc *udc) | ||
| 580 | { | ||
| 581 | struct max3420_ep *ep; | ||
| 582 | int set = udc->setup.bRequest == USB_REQ_SET_FEATURE; | ||
| 583 | unsigned long flags; | ||
| 584 | int id; | ||
| 585 | |||
| 586 | switch (udc->setup.bRequestType) { | ||
| 587 | case USB_RECIP_DEVICE: | ||
| 588 | if (udc->setup.wValue != USB_DEVICE_REMOTE_WAKEUP) | ||
| 589 | break; | ||
| 590 | |||
| 591 | if (udc->setup.bRequest == USB_REQ_SET_FEATURE) | ||
| 592 | udc->remote_wkp = 1; | ||
| 593 | else | ||
| 594 | udc->remote_wkp = 0; | ||
| 595 | |||
| 596 | return spi_ack_ctrl(udc); | ||
| 597 | |||
| 598 | case USB_RECIP_ENDPOINT: | ||
| 599 | if (udc->setup.wValue != USB_ENDPOINT_HALT) | ||
| 600 | break; | ||
| 601 | |||
| 602 | id = udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK; | ||
| 603 | ep = &udc->ep[id]; | ||
| 604 | |||
| 605 | spin_lock_irqsave(&ep->lock, flags); | ||
| 606 | ep->todo &= ~STALL_EP; | ||
| 607 | if (set) | ||
| 608 | ep->todo |= STALL; | ||
| 609 | else | ||
| 610 | ep->todo |= UNSTALL; | ||
| 611 | spin_unlock_irqrestore(&ep->lock, flags); | ||
| 612 | |||
| 613 | spi_max3420_stall(ep); | ||
| 614 | return; | ||
| 615 | default: | ||
| 616 | break; | ||
| 617 | } | ||
| 618 | |||
| 619 | dev_err(udc->dev, "Can't respond to SET/CLEAR FEATURE\n"); | ||
| 620 | spi_wr8(udc, MAX3420_REG_EPSTALLS, STLEP0IN | STLEP0OUT | STLSTAT); | ||
| 621 | } | ||
| 622 | |||
| 623 | static void max3420_handle_setup(struct max3420_udc *udc) | ||
| 624 | { | ||
| 625 | struct usb_ctrlrequest setup; | ||
| 626 | u8 addr; | ||
| 627 | |||
| 628 | spi_rd_buf(udc, MAX3420_REG_SUDFIFO, (void *)&setup, 8); | ||
| 629 | |||
| 630 | udc->setup = setup; | ||
| 631 | udc->setup.wValue = cpu_to_le16(setup.wValue); | ||
| 632 | udc->setup.wIndex = cpu_to_le16(setup.wIndex); | ||
| 633 | udc->setup.wLength = cpu_to_le16(setup.wLength); | ||
| 634 | |||
| 635 | switch (udc->setup.bRequest) { | ||
| 636 | case USB_REQ_GET_STATUS: | ||
| 637 | /* Data+Status phase form udc */ | ||
| 638 | if ((udc->setup.bRequestType & | ||
| 639 | (USB_DIR_IN | USB_TYPE_MASK)) != | ||
| 640 | (USB_DIR_IN | USB_TYPE_STANDARD)) { | ||
| 641 | break; | ||
| 642 | } | ||
| 643 | return max3420_getstatus(udc); | ||
| 644 | case USB_REQ_SET_ADDRESS: | ||
| 645 | /* Status phase from udc */ | ||
| 646 | if (udc->setup.bRequestType != (USB_DIR_OUT | | ||
| 647 | USB_TYPE_STANDARD | USB_RECIP_DEVICE)) { | ||
| 648 | break; | ||
| 649 | } | ||
| 650 | addr = spi_rd8_ack(udc, MAX3420_REG_FNADDR, 1); | ||
| 651 | dev_dbg(udc->dev, "Assigned Address=%d\n", udc->setup.wValue); | ||
| 652 | return; | ||
| 653 | case USB_REQ_CLEAR_FEATURE: | ||
| 654 | case USB_REQ_SET_FEATURE: | ||
| 655 | /* Requests with no data phase, status phase from udc */ | ||
| 656 | if ((udc->setup.bRequestType & USB_TYPE_MASK) | ||
| 657 | != USB_TYPE_STANDARD) | ||
| 658 | break; | ||
| 659 | return max3420_set_clear_feature(udc); | ||
| 660 | default: | ||
| 661 | break; | ||
| 662 | } | ||
| 663 | |||
| 664 | if (udc->driver->setup(&udc->gadget, &setup) < 0) { | ||
| 665 | /* Stall EP0 */ | ||
| 666 | spi_wr8(udc, MAX3420_REG_EPSTALLS, | ||
| 667 | STLEP0IN | STLEP0OUT | STLSTAT); | ||
| 668 | } | ||
| 669 | } | ||
| 670 | |||
| 671 | static void max3420_req_done(struct max3420_req *req, int status) | ||
| 672 | { | ||
| 673 | struct max3420_ep *ep = req->ep; | ||
| 674 | struct max3420_udc *udc = ep->udc; | ||
| 675 | |||
| 676 | if (req->usb_req.status == -EINPROGRESS) | ||
| 677 | req->usb_req.status = status; | ||
| 678 | else | ||
| 679 | status = req->usb_req.status; | ||
| 680 | |||
| 681 | if (status && status != -ESHUTDOWN) | ||
| 682 | dev_err(udc->dev, "%s done %p, status %d\n", | ||
| 683 | ep->ep_usb.name, req, status); | ||
| 684 | |||
| 685 | if (req->usb_req.complete) | ||
| 686 | req->usb_req.complete(&ep->ep_usb, &req->usb_req); | ||
| 687 | } | ||
| 688 | |||
| 689 | static int max3420_do_data(struct max3420_udc *udc, int ep_id, int in) | ||
| 690 | { | ||
| 691 | struct max3420_ep *ep = &udc->ep[ep_id]; | ||
| 692 | struct max3420_req *req; | ||
| 693 | int done, length, psz; | ||
| 694 | void *buf; | ||
| 695 | |||
| 696 | if (list_empty(&ep->queue)) | ||
| 697 | return false; | ||
| 698 | |||
| 699 | req = list_first_entry(&ep->queue, struct max3420_req, queue); | ||
| 700 | buf = req->usb_req.buf + req->usb_req.actual; | ||
| 701 | |||
| 702 | psz = ep->ep_usb.maxpacket; | ||
| 703 | length = req->usb_req.length - req->usb_req.actual; | ||
| 704 | length = min(length, psz); | ||
| 705 | |||
| 706 | if (length == 0) { | ||
| 707 | done = 1; | ||
| 708 | goto xfer_done; | ||
| 709 | } | ||
| 710 | |||
| 711 | done = 0; | ||
| 712 | if (in) { | ||
| 713 | prefetch(buf); | ||
| 714 | spi_wr_buf(udc, MAX3420_REG_EP0FIFO + ep_id, buf, length); | ||
| 715 | spi_wr8(udc, MAX3420_REG_EP0BC + ep_id, length); | ||
| 716 | if (length < psz) | ||
| 717 | done = 1; | ||
| 718 | } else { | ||
| 719 | psz = spi_rd8(udc, MAX3420_REG_EP0BC + ep_id); | ||
| 720 | length = min(length, psz); | ||
| 721 | prefetchw(buf); | ||
| 722 | spi_rd_buf(udc, MAX3420_REG_EP0FIFO + ep_id, buf, length); | ||
| 723 | if (length < ep->ep_usb.maxpacket) | ||
| 724 | done = 1; | ||
| 725 | } | ||
| 726 | |||
| 727 | req->usb_req.actual += length; | ||
| 728 | |||
| 729 | if (req->usb_req.actual == req->usb_req.length) | ||
| 730 | done = 1; | ||
| 731 | |||
| 732 | xfer_done: | ||
| 733 | if (done) { | ||
| 734 | unsigned long flags; | ||
| 735 | |||
| 736 | spin_lock_irqsave(&ep->lock, flags); | ||
| 737 | list_del_init(&req->queue); | ||
| 738 | spin_unlock_irqrestore(&ep->lock, flags); | ||
| 739 | |||
| 740 | if (ep_id == 0) | ||
| 741 | spi_ack_ctrl(udc); | ||
| 742 | |||
| 743 | max3420_req_done(req, 0); | ||
| 744 | } | ||
| 745 | |||
| 746 | return true; | ||
| 747 | } | ||
| 748 | |||
| 749 | static int max3420_handle_irqs(struct max3420_udc *udc) | ||
| 750 | { | ||
| 751 | u8 epien, epirq, usbirq, usbien, reg[4]; | ||
| 752 | bool ret = false; | ||
| 753 | |||
| 754 | spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 4); | ||
| 755 | epirq = reg[0]; | ||
| 756 | epien = reg[1]; | ||
| 757 | usbirq = reg[2]; | ||
| 758 | usbien = reg[3]; | ||
| 759 | |||
| 760 | usbirq &= usbien; | ||
| 761 | epirq &= epien; | ||
| 762 | |||
| 763 | if (epirq & SUDAVIRQ) { | ||
| 764 | spi_wr8(udc, MAX3420_REG_EPIRQ, SUDAVIRQ); | ||
| 765 | max3420_handle_setup(udc); | ||
| 766 | return true; | ||
| 767 | } | ||
| 768 | |||
| 769 | if (usbirq & VBUSIRQ) { | ||
| 770 | spi_wr8(udc, MAX3420_REG_USBIRQ, VBUSIRQ); | ||
| 771 | dev_dbg(udc->dev, "Cable plugged in\n"); | ||
| 772 | return true; | ||
| 773 | } | ||
| 774 | |||
| 775 | if (usbirq & NOVBUSIRQ) { | ||
| 776 | spi_wr8(udc, MAX3420_REG_USBIRQ, NOVBUSIRQ); | ||
| 777 | dev_dbg(udc->dev, "Cable pulled out\n"); | ||
| 778 | return true; | ||
| 779 | } | ||
| 780 | |||
| 781 | if (usbirq & URESIRQ) { | ||
| 782 | spi_wr8(udc, MAX3420_REG_USBIRQ, URESIRQ); | ||
| 783 | dev_dbg(udc->dev, "USB Reset - Start\n"); | ||
| 784 | return true; | ||
| 785 | } | ||
| 786 | |||
| 787 | if (usbirq & URESDNIRQ) { | ||
| 788 | spi_wr8(udc, MAX3420_REG_USBIRQ, URESDNIRQ); | ||
| 789 | dev_dbg(udc->dev, "USB Reset - END\n"); | ||
| 790 | spi_wr8(udc, MAX3420_REG_USBIEN, URESDNIRQ | URESIRQ); | ||
| 791 | spi_wr8(udc, MAX3420_REG_EPIEN, SUDAVIRQ | IN0BAVIRQ | ||
| 792 | | OUT0DAVIRQ); | ||
| 793 | return true; | ||
| 794 | } | ||
| 795 | |||
| 796 | if (usbirq & SUSPIRQ) { | ||
| 797 | spi_wr8(udc, MAX3420_REG_USBIRQ, SUSPIRQ); | ||
| 798 | dev_dbg(udc->dev, "USB Suspend - Enter\n"); | ||
| 799 | udc->suspended = true; | ||
| 800 | return true; | ||
| 801 | } | ||
| 802 | |||
| 803 | if (usbirq & BUSACTIRQ) { | ||
| 804 | spi_wr8(udc, MAX3420_REG_USBIRQ, BUSACTIRQ); | ||
| 805 | dev_dbg(udc->dev, "USB Suspend - Exit\n"); | ||
| 806 | udc->suspended = false; | ||
| 807 | return true; | ||
| 808 | } | ||
| 809 | |||
| 810 | if (usbirq & RWUDNIRQ) { | ||
| 811 | spi_wr8(udc, MAX3420_REG_USBIRQ, RWUDNIRQ); | ||
| 812 | dev_dbg(udc->dev, "Asked Host to wakeup\n"); | ||
| 813 | return true; | ||
| 814 | } | ||
| 815 | |||
| 816 | if (usbirq & OSCOKIRQ) { | ||
| 817 | spi_wr8(udc, MAX3420_REG_USBIRQ, OSCOKIRQ); | ||
| 818 | dev_dbg(udc->dev, "Osc stabilized, start work\n"); | ||
| 819 | return true; | ||
| 820 | } | ||
| 821 | |||
| 822 | if (epirq & OUT0DAVIRQ && max3420_do_data(udc, 0, 0)) { | ||
| 823 | spi_wr8_ack(udc, MAX3420_REG_EPIRQ, OUT0DAVIRQ, 1); | ||
| 824 | ret = true; | ||
| 825 | } | ||
| 826 | |||
| 827 | if (epirq & IN0BAVIRQ && max3420_do_data(udc, 0, 1)) | ||
| 828 | ret = true; | ||
| 829 | |||
| 830 | if (epirq & OUT1DAVIRQ && max3420_do_data(udc, 1, 0)) { | ||
| 831 | spi_wr8_ack(udc, MAX3420_REG_EPIRQ, OUT1DAVIRQ, 1); | ||
| 832 | ret = true; | ||
| 833 | } | ||
| 834 | |||
| 835 | if (epirq & IN2BAVIRQ && max3420_do_data(udc, 2, 1)) | ||
| 836 | ret = true; | ||
| 837 | |||
| 838 | if (epirq & IN3BAVIRQ && max3420_do_data(udc, 3, 1)) | ||
| 839 | ret = true; | ||
| 840 | |||
| 841 | return ret; | ||
| 842 | } | ||
| 843 | |||
| 844 | static int max3420_thread(void *dev_id) | ||
| 845 | { | ||
| 846 | struct max3420_udc *udc = dev_id; | ||
| 847 | struct spi_device *spi = udc->spi; | ||
| 848 | int i, loop_again = 1; | ||
| 849 | unsigned long flags; | ||
| 850 | |||
| 851 | while (!kthread_should_stop()) { | ||
| 852 | if (!loop_again) { | ||
| 853 | ktime_t kt = ns_to_ktime(1000 * 1000 * 250); /* 250ms */ | ||
| 854 | |||
| 855 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 856 | |||
| 857 | spin_lock_irqsave(&udc->lock, flags); | ||
| 858 | if (udc->todo & ENABLE_IRQ) { | ||
| 859 | enable_irq(spi->irq); | ||
| 860 | udc->todo &= ~ENABLE_IRQ; | ||
| 861 | } | ||
| 862 | spin_unlock_irqrestore(&udc->lock, flags); | ||
| 863 | |||
| 864 | schedule_hrtimeout(&kt, HRTIMER_MODE_REL); | ||
| 865 | } | ||
| 866 | loop_again = 0; | ||
| 867 | |||
| 868 | mutex_lock(&udc->spi_bus_mutex); | ||
| 869 | |||
| 870 | /* If bus-vbus_active and disconnected */ | ||
| 871 | if (!udc->vbus_active || !udc->softconnect) | ||
| 872 | goto loop; | ||
| 873 | |||
| 874 | if (max3420_start(udc)) { | ||
| 875 | loop_again = 1; | ||
| 876 | goto loop; | ||
| 877 | } | ||
| 878 | |||
| 879 | if (max3420_handle_irqs(udc)) { | ||
| 880 | loop_again = 1; | ||
| 881 | goto loop; | ||
| 882 | } | ||
| 883 | |||
| 884 | if (spi_max3420_rwkup(udc)) { | ||
| 885 | loop_again = 1; | ||
| 886 | goto loop; | ||
| 887 | } | ||
| 888 | |||
| 889 | max3420_do_data(udc, 0, 1); /* get done with the EP0 ZLP */ | ||
| 890 | |||
| 891 | for (i = 1; i < MAX3420_MAX_EPS; i++) { | ||
| 892 | struct max3420_ep *ep = &udc->ep[i]; | ||
| 893 | |||
| 894 | if (spi_max3420_enable(ep)) | ||
| 895 | loop_again = 1; | ||
| 896 | if (spi_max3420_stall(ep)) | ||
| 897 | loop_again = 1; | ||
| 898 | } | ||
| 899 | loop: | ||
| 900 | mutex_unlock(&udc->spi_bus_mutex); | ||
| 901 | } | ||
| 902 | |||
| 903 | set_current_state(TASK_RUNNING); | ||
| 904 | dev_info(udc->dev, "SPI thread exiting"); | ||
| 905 | return 0; | ||
| 906 | } | ||
| 907 | |||
| 908 | static int max3420_ep_set_halt(struct usb_ep *_ep, int stall) | ||
| 909 | { | ||
| 910 | struct max3420_ep *ep = to_max3420_ep(_ep); | ||
| 911 | struct max3420_udc *udc = ep->udc; | ||
| 912 | unsigned long flags; | ||
| 913 | |||
| 914 | spin_lock_irqsave(&ep->lock, flags); | ||
| 915 | |||
| 916 | ep->todo &= ~STALL_EP; | ||
| 917 | if (stall) | ||
| 918 | ep->todo |= STALL; | ||
| 919 | else | ||
| 920 | ep->todo |= UNSTALL; | ||
| 921 | |||
| 922 | spin_unlock_irqrestore(&ep->lock, flags); | ||
| 923 | |||
| 924 | wake_up_process(udc->thread_task); | ||
| 925 | |||
| 926 | dev_dbg(udc->dev, "%sStall %s\n", stall ? "" : "Un", ep->name); | ||
| 927 | return 0; | ||
| 928 | } | ||
| 929 | |||
| 930 | static int __max3420_ep_enable(struct max3420_ep *ep, | ||
| 931 | const struct usb_endpoint_descriptor *desc) | ||
| 932 | { | ||
| 933 | unsigned int maxp = usb_endpoint_maxp(desc); | ||
| 934 | unsigned long flags; | ||
| 935 | |||
| 936 | spin_lock_irqsave(&ep->lock, flags); | ||
| 937 | ep->ep_usb.desc = desc; | ||
| 938 | ep->ep_usb.maxpacket = maxp; | ||
| 939 | |||
| 940 | ep->todo &= ~ENABLE_EP; | ||
| 941 | ep->todo |= ENABLE; | ||
| 942 | spin_unlock_irqrestore(&ep->lock, flags); | ||
| 943 | |||
| 944 | return 0; | ||
| 945 | } | ||
| 946 | |||
| 947 | static int max3420_ep_enable(struct usb_ep *_ep, | ||
| 948 | const struct usb_endpoint_descriptor *desc) | ||
| 949 | { | ||
| 950 | struct max3420_ep *ep = to_max3420_ep(_ep); | ||
| 951 | struct max3420_udc *udc = ep->udc; | ||
| 952 | |||
| 953 | __max3420_ep_enable(ep, desc); | ||
| 954 | |||
| 955 | wake_up_process(udc->thread_task); | ||
| 956 | |||
| 957 | return 0; | ||
| 958 | } | ||
| 959 | |||
| 960 | static void max3420_nuke(struct max3420_ep *ep, int status) | ||
| 961 | { | ||
| 962 | struct max3420_req *req, *r; | ||
| 963 | unsigned long flags; | ||
| 964 | |||
| 965 | spin_lock_irqsave(&ep->lock, flags); | ||
| 966 | |||
| 967 | list_for_each_entry_safe(req, r, &ep->queue, queue) { | ||
| 968 | list_del_init(&req->queue); | ||
| 969 | |||
| 970 | spin_unlock_irqrestore(&ep->lock, flags); | ||
| 971 | max3420_req_done(req, status); | ||
| 972 | spin_lock_irqsave(&ep->lock, flags); | ||
| 973 | } | ||
| 974 | |||
| 975 | spin_unlock_irqrestore(&ep->lock, flags); | ||
| 976 | } | ||
| 977 | |||
| 978 | static void __max3420_ep_disable(struct max3420_ep *ep) | ||
| 979 | { | ||
| 980 | struct max3420_udc *udc = ep->udc; | ||
| 981 | unsigned long flags; | ||
| 982 | |||
| 983 | spin_lock_irqsave(&ep->lock, flags); | ||
| 984 | |||
| 985 | ep->ep_usb.desc = NULL; | ||
| 986 | |||
| 987 | ep->todo &= ~ENABLE_EP; | ||
| 988 | ep->todo |= DISABLE; | ||
| 989 | |||
| 990 | spin_unlock_irqrestore(&ep->lock, flags); | ||
| 991 | |||
| 992 | dev_dbg(udc->dev, "Disabled %s\n", ep->name); | ||
| 993 | } | ||
| 994 | |||
| 995 | static int max3420_ep_disable(struct usb_ep *_ep) | ||
| 996 | { | ||
| 997 | struct max3420_ep *ep = to_max3420_ep(_ep); | ||
| 998 | struct max3420_udc *udc = ep->udc; | ||
| 999 | |||
| 1000 | max3420_nuke(ep, -ESHUTDOWN); | ||
| 1001 | |||
| 1002 | __max3420_ep_disable(ep); | ||
| 1003 | |||
| 1004 | wake_up_process(udc->thread_task); | ||
| 1005 | |||
| 1006 | return 0; | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | static struct usb_request *max3420_alloc_request(struct usb_ep *_ep, | ||
| 1010 | gfp_t gfp_flags) | ||
| 1011 | { | ||
| 1012 | struct max3420_ep *ep = to_max3420_ep(_ep); | ||
| 1013 | struct max3420_req *req; | ||
| 1014 | |||
| 1015 | req = kzalloc(sizeof(*req), gfp_flags); | ||
| 1016 | if (!req) | ||
| 1017 | return NULL; | ||
| 1018 | |||
| 1019 | req->ep = ep; | ||
| 1020 | |||
| 1021 | return &req->usb_req; | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | static void max3420_free_request(struct usb_ep *_ep, struct usb_request *_req) | ||
| 1025 | { | ||
| 1026 | kfree(to_max3420_req(_req)); | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | static int max3420_ep_queue(struct usb_ep *_ep, struct usb_request *_req, | ||
| 1030 | gfp_t ignored) | ||
| 1031 | { | ||
| 1032 | struct max3420_req *req = to_max3420_req(_req); | ||
| 1033 | struct max3420_ep *ep = to_max3420_ep(_ep); | ||
| 1034 | struct max3420_udc *udc = ep->udc; | ||
| 1035 | unsigned long flags; | ||
| 1036 | |||
| 1037 | _req->status = -EINPROGRESS; | ||
| 1038 | _req->actual = 0; | ||
| 1039 | |||
| 1040 | spin_lock_irqsave(&ep->lock, flags); | ||
| 1041 | list_add_tail(&req->queue, &ep->queue); | ||
| 1042 | spin_unlock_irqrestore(&ep->lock, flags); | ||
| 1043 | |||
| 1044 | wake_up_process(udc->thread_task); | ||
| 1045 | return 0; | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | static int max3420_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) | ||
| 1049 | { | ||
| 1050 | struct max3420_req *t, *req = to_max3420_req(_req); | ||
| 1051 | struct max3420_ep *ep = to_max3420_ep(_ep); | ||
| 1052 | unsigned long flags; | ||
| 1053 | |||
| 1054 | spin_lock_irqsave(&ep->lock, flags); | ||
| 1055 | |||
| 1056 | /* Pluck the descriptor from queue */ | ||
| 1057 | list_for_each_entry(t, &ep->queue, queue) | ||
| 1058 | if (t == req) { | ||
| 1059 | list_del_init(&req->queue); | ||
| 1060 | break; | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | spin_unlock_irqrestore(&ep->lock, flags); | ||
| 1064 | |||
| 1065 | if (t == req) | ||
| 1066 | max3420_req_done(req, -ECONNRESET); | ||
| 1067 | |||
| 1068 | return 0; | ||
| 1069 | } | ||
| 1070 | |||
| 1071 | static const struct usb_ep_ops max3420_ep_ops = { | ||
| 1072 | .enable = max3420_ep_enable, | ||
| 1073 | .disable = max3420_ep_disable, | ||
| 1074 | .alloc_request = max3420_alloc_request, | ||
| 1075 | .free_request = max3420_free_request, | ||
| 1076 | .queue = max3420_ep_queue, | ||
| 1077 | .dequeue = max3420_ep_dequeue, | ||
| 1078 | .set_halt = max3420_ep_set_halt, | ||
| 1079 | }; | ||
| 1080 | |||
| 1081 | static int max3420_wakeup(struct usb_gadget *gadget) | ||
| 1082 | { | ||
| 1083 | struct max3420_udc *udc = to_udc(gadget); | ||
| 1084 | unsigned long flags; | ||
| 1085 | int ret = -EINVAL; | ||
| 1086 | |||
| 1087 | spin_lock_irqsave(&udc->lock, flags); | ||
| 1088 | |||
| 1089 | /* Only if wakeup allowed by host */ | ||
| 1090 | if (udc->remote_wkp) { | ||
| 1091 | udc->todo |= REMOTE_WAKEUP; | ||
| 1092 | ret = 0; | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | spin_unlock_irqrestore(&udc->lock, flags); | ||
| 1096 | |||
| 1097 | if (udc->thread_task && | ||
| 1098 | udc->thread_task->state != TASK_RUNNING) | ||
| 1099 | wake_up_process(udc->thread_task); | ||
| 1100 | return ret; | ||
| 1101 | } | ||
| 1102 | |||
| 1103 | static int max3420_udc_start(struct usb_gadget *gadget, | ||
| 1104 | struct usb_gadget_driver *driver) | ||
| 1105 | { | ||
| 1106 | struct max3420_udc *udc = to_udc(gadget); | ||
| 1107 | unsigned long flags; | ||
| 1108 | |||
| 1109 | spin_lock_irqsave(&udc->lock, flags); | ||
| 1110 | /* hook up the driver */ | ||
| 1111 | driver->driver.bus = NULL; | ||
| 1112 | udc->driver = driver; | ||
| 1113 | udc->gadget.speed = USB_SPEED_FULL; | ||
| 1114 | |||
| 1115 | udc->gadget.is_selfpowered = udc->is_selfpowered; | ||
| 1116 | udc->remote_wkp = 0; | ||
| 1117 | udc->softconnect = true; | ||
| 1118 | udc->todo |= UDC_START; | ||
| 1119 | spin_unlock_irqrestore(&udc->lock, flags); | ||
| 1120 | |||
| 1121 | if (udc->thread_task && | ||
| 1122 | udc->thread_task->state != TASK_RUNNING) | ||
| 1123 | wake_up_process(udc->thread_task); | ||
| 1124 | |||
| 1125 | return 0; | ||
| 1126 | } | ||
| 1127 | |||
| 1128 | static int max3420_udc_stop(struct usb_gadget *gadget) | ||
| 1129 | { | ||
| 1130 | struct max3420_udc *udc = to_udc(gadget); | ||
| 1131 | unsigned long flags; | ||
| 1132 | |||
| 1133 | spin_lock_irqsave(&udc->lock, flags); | ||
| 1134 | udc->is_selfpowered = udc->gadget.is_selfpowered; | ||
| 1135 | udc->gadget.speed = USB_SPEED_UNKNOWN; | ||
| 1136 | udc->driver = NULL; | ||
| 1137 | udc->softconnect = false; | ||
| 1138 | udc->todo |= UDC_START; | ||
| 1139 | spin_unlock_irqrestore(&udc->lock, flags); | ||
| 1140 | |||
| 1141 | if (udc->thread_task && | ||
| 1142 | udc->thread_task->state != TASK_RUNNING) | ||
| 1143 | wake_up_process(udc->thread_task); | ||
| 1144 | |||
| 1145 | return 0; | ||
| 1146 | } | ||
| 1147 | |||
| 1148 | static const struct usb_gadget_ops max3420_udc_ops = { | ||
| 1149 | .udc_start = max3420_udc_start, | ||
| 1150 | .udc_stop = max3420_udc_stop, | ||
| 1151 | .wakeup = max3420_wakeup, | ||
| 1152 | }; | ||
| 1153 | |||
| 1154 | static void max3420_eps_init(struct max3420_udc *udc) | ||
| 1155 | { | ||
| 1156 | int idx; | ||
| 1157 | |||
| 1158 | INIT_LIST_HEAD(&udc->gadget.ep_list); | ||
| 1159 | |||
| 1160 | for (idx = 0; idx < MAX3420_MAX_EPS; idx++) { | ||
| 1161 | struct max3420_ep *ep = &udc->ep[idx]; | ||
| 1162 | |||
| 1163 | spin_lock_init(&ep->lock); | ||
| 1164 | INIT_LIST_HEAD(&ep->queue); | ||
| 1165 | |||
| 1166 | ep->udc = udc; | ||
| 1167 | ep->id = idx; | ||
| 1168 | ep->halted = 0; | ||
| 1169 | ep->maxpacket = 0; | ||
| 1170 | ep->ep_usb.name = ep->name; | ||
| 1171 | ep->ep_usb.ops = &max3420_ep_ops; | ||
| 1172 | usb_ep_set_maxpacket_limit(&ep->ep_usb, MAX3420_EP_MAX_PACKET); | ||
| 1173 | |||
| 1174 | if (idx == 0) { /* For EP0 */ | ||
| 1175 | ep->ep_usb.desc = &ep0_desc; | ||
| 1176 | ep->ep_usb.maxpacket = usb_endpoint_maxp(&ep0_desc); | ||
| 1177 | ep->ep_usb.caps.type_control = true; | ||
| 1178 | ep->ep_usb.caps.dir_in = true; | ||
| 1179 | ep->ep_usb.caps.dir_out = true; | ||
| 1180 | snprintf(ep->name, MAX3420_EPNAME_SIZE, "ep0"); | ||
| 1181 | continue; | ||
| 1182 | } | ||
| 1183 | |||
| 1184 | if (idx == 1) { /* EP1 is OUT */ | ||
| 1185 | ep->ep_usb.caps.dir_in = false; | ||
| 1186 | ep->ep_usb.caps.dir_out = true; | ||
| 1187 | snprintf(ep->name, MAX3420_EPNAME_SIZE, "ep1-bulk-out"); | ||
| 1188 | } else { /* EP2 & EP3 are IN */ | ||
| 1189 | ep->ep_usb.caps.dir_in = true; | ||
| 1190 | ep->ep_usb.caps.dir_out = false; | ||
| 1191 | snprintf(ep->name, MAX3420_EPNAME_SIZE, | ||
| 1192 | "ep%d-bulk-in", idx); | ||
| 1193 | } | ||
| 1194 | ep->ep_usb.caps.type_iso = false; | ||
| 1195 | ep->ep_usb.caps.type_int = false; | ||
| 1196 | ep->ep_usb.caps.type_bulk = true; | ||
| 1197 | |||
| 1198 | list_add_tail(&ep->ep_usb.ep_list, | ||
| 1199 | &udc->gadget.ep_list); | ||
| 1200 | } | ||
| 1201 | } | ||
| 1202 | |||
| 1203 | static int max3420_probe(struct spi_device *spi) | ||
| 1204 | { | ||
| 1205 | struct max3420_udc *udc; | ||
| 1206 | int err, irq; | ||
| 1207 | u8 reg[8]; | ||
| 1208 | |||
| 1209 | if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) { | ||
| 1210 | dev_err(&spi->dev, "UDC needs full duplex to work\n"); | ||
| 1211 | return -EINVAL; | ||
| 1212 | } | ||
| 1213 | |||
| 1214 | spi->mode = SPI_MODE_3; | ||
| 1215 | spi->bits_per_word = 8; | ||
| 1216 | |||
| 1217 | err = spi_setup(spi); | ||
| 1218 | if (err) { | ||
| 1219 | dev_err(&spi->dev, "Unable to setup SPI bus\n"); | ||
| 1220 | return -EFAULT; | ||
| 1221 | } | ||
| 1222 | |||
| 1223 | udc = devm_kzalloc(&spi->dev, sizeof(*udc), GFP_KERNEL); | ||
| 1224 | if (!udc) | ||
| 1225 | return -ENOMEM; | ||
| 1226 | |||
| 1227 | udc->spi = spi; | ||
| 1228 | |||
| 1229 | udc->remote_wkp = 0; | ||
| 1230 | |||
| 1231 | /* Setup gadget structure */ | ||
| 1232 | udc->gadget.ops = &max3420_udc_ops; | ||
| 1233 | udc->gadget.max_speed = USB_SPEED_FULL; | ||
| 1234 | udc->gadget.speed = USB_SPEED_UNKNOWN; | ||
| 1235 | udc->gadget.ep0 = &udc->ep[0].ep_usb; | ||
| 1236 | udc->gadget.name = driver_name; | ||
| 1237 | |||
| 1238 | spin_lock_init(&udc->lock); | ||
| 1239 | mutex_init(&udc->spi_bus_mutex); | ||
| 1240 | |||
| 1241 | udc->ep0req.ep = &udc->ep[0]; | ||
| 1242 | udc->ep0req.usb_req.buf = udc->ep0buf; | ||
| 1243 | INIT_LIST_HEAD(&udc->ep0req.queue); | ||
| 1244 | |||
| 1245 | /* setup Endpoints */ | ||
| 1246 | max3420_eps_init(udc); | ||
| 1247 | |||
| 1248 | /* configure SPI */ | ||
| 1249 | spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 8); | ||
| 1250 | spi_wr8(udc, MAX3420_REG_PINCTL, FDUPSPI); | ||
| 1251 | |||
| 1252 | err = usb_add_gadget_udc(&spi->dev, &udc->gadget); | ||
| 1253 | if (err) | ||
| 1254 | return err; | ||
| 1255 | |||
| 1256 | udc->dev = &udc->gadget.dev; | ||
| 1257 | |||
| 1258 | spi_set_drvdata(spi, udc); | ||
| 1259 | |||
| 1260 | irq = of_irq_get_byname(spi->dev.of_node, "udc"); | ||
| 1261 | err = devm_request_irq(&spi->dev, irq, max3420_irq_handler, 0, | ||
| 1262 | "max3420", udc); | ||
| 1263 | if (err < 0) | ||
| 1264 | return err; | ||
| 1265 | |||
| 1266 | udc->thread_task = kthread_create(max3420_thread, udc, | ||
| 1267 | "max3420-thread"); | ||
| 1268 | if (IS_ERR(udc->thread_task)) | ||
| 1269 | return PTR_ERR(udc->thread_task); | ||
| 1270 | |||
| 1271 | irq = of_irq_get_byname(spi->dev.of_node, "vbus"); | ||
| 1272 | if (irq <= 0) { /* no vbus irq implies self-powered design */ | ||
| 1273 | udc->is_selfpowered = 1; | ||
| 1274 | udc->vbus_active = true; | ||
| 1275 | udc->todo |= UDC_START; | ||
| 1276 | usb_udc_vbus_handler(&udc->gadget, udc->vbus_active); | ||
| 1277 | usb_gadget_set_state(&udc->gadget, USB_STATE_POWERED); | ||
| 1278 | max3420_start(udc); | ||
| 1279 | } else { | ||
| 1280 | udc->is_selfpowered = 0; | ||
| 1281 | /* Detect current vbus status */ | ||
| 1282 | spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 8); | ||
| 1283 | if (reg[7] != 0xff) | ||
| 1284 | udc->vbus_active = true; | ||
| 1285 | |||
| 1286 | err = devm_request_irq(&spi->dev, irq, | ||
| 1287 | max3420_vbus_handler, 0, "vbus", udc); | ||
| 1288 | if (err < 0) | ||
| 1289 | return err; | ||
| 1290 | } | ||
| 1291 | |||
| 1292 | return 0; | ||
| 1293 | } | ||
| 1294 | |||
| 1295 | static int max3420_remove(struct spi_device *spi) | ||
| 1296 | { | ||
| 1297 | struct max3420_udc *udc = spi_get_drvdata(spi); | ||
| 1298 | unsigned long flags; | ||
| 1299 | |||
| 1300 | usb_del_gadget_udc(&udc->gadget); | ||
| 1301 | |||
| 1302 | spin_lock_irqsave(&udc->lock, flags); | ||
| 1303 | |||
| 1304 | kthread_stop(udc->thread_task); | ||
| 1305 | |||
| 1306 | spin_unlock_irqrestore(&udc->lock, flags); | ||
| 1307 | |||
| 1308 | return 0; | ||
| 1309 | } | ||
| 1310 | |||
| 1311 | static const struct of_device_id max3420_udc_of_match[] = { | ||
| 1312 | { .compatible = "maxim,max3420-udc"}, | ||
| 1313 | { .compatible = "maxim,max3421-udc"}, | ||
| 1314 | {}, | ||
| 1315 | }; | ||
| 1316 | MODULE_DEVICE_TABLE(of, max3420_udc_of_match); | ||
| 1317 | |||
| 1318 | static struct spi_driver max3420_driver = { | ||
| 1319 | .driver = { | ||
| 1320 | .name = "max3420-udc", | ||
| 1321 | .of_match_table = of_match_ptr(max3420_udc_of_match), | ||
| 1322 | }, | ||
| 1323 | .probe = max3420_probe, | ||
| 1324 | .remove = max3420_remove, | ||
| 1325 | }; | ||
| 1326 | |||
| 1327 | module_spi_driver(max3420_driver); | ||
| 1328 | |||
| 1329 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 1330 | MODULE_AUTHOR("Jassi Brar <jaswinder.singh@linaro.org>"); | ||
| 1331 | MODULE_LICENSE("GPL"); | ||
| @@ -3493,11 +3493,8 @@ static int tegra_xudc_probe(struct platform_device *pdev) · 3492 unmodified lines | |||
| 3493 | } | 3493 | } |
| 3494 | 3494 | ||
| 3495 | xudc->irq = platform_get_irq(pdev, 0); | 3495 | xudc->irq = platform_get_irq(pdev, 0); |
| 3496 | if (xudc->irq < 0) { | 3496 | if (xudc->irq < 0) |
| 3497 | dev_err(xudc->dev, "failed to get IRQ: %d\n", | ||
| 3498 | xudc->irq); | ||
| 3499 | return xudc->irq; | 3497 | return xudc->irq; |
| 3500 | } | ||
| 3501 | 3498 | ||
| 3502 | err = devm_request_irq(&pdev->dev, xudc->irq, tegra_xudc_irq, 0, | 3499 | err = devm_request_irq(&pdev->dev, xudc->irq, tegra_xudc_irq, 0, |
| 3503 | dev_name(&pdev->dev), xudc); | 3500 | dev_name(&pdev->dev), xudc); |
| @@ -0,0 +1,167 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ | ||
| 2 | /* | ||
| 3 | * USB Raw Gadget driver. | ||
| 4 | * | ||
| 5 | * See Documentation/usb/raw-gadget.rst for more details. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef _UAPI__LINUX_USB_RAW_GADGET_H | ||
| 9 | #define _UAPI__LINUX_USB_RAW_GADGET_H | ||
| 10 | |||
| 11 | #include <asm/ioctl.h> | ||
| 12 | #include <linux/types.h> | ||
| 13 | #include <linux/usb/ch9.h> | ||
| 14 | |||
| 15 | /* Maximum length of driver_name/device_name in the usb_raw_init struct. */ | ||
| 16 | #define UDC_NAME_LENGTH_MAX 128 | ||
| 17 | |||
| 18 | /* | ||
| 19 | * struct usb_raw_init - argument for USB_RAW_IOCTL_INIT ioctl. | ||
| 20 | * @speed: The speed of the emulated USB device, takes the same values as | ||
| 21 | * the usb_device_speed enum: USB_SPEED_FULL, USB_SPEED_HIGH, etc. | ||
| 22 | * @driver_name: The name of the UDC driver. | ||
| 23 | * @device_name: The name of a UDC instance. | ||
| 24 | * | ||
| 25 | * The last two fields identify a UDC the gadget driver should bind to. | ||
| 26 | * For example, Dummy UDC has "dummy_udc" as its driver_name and "dummy_udc.N" | ||
| 27 | * as its device_name, where N in the index of the Dummy UDC instance. | ||
| 28 | * At the same time the dwc2 driver that is used on Raspberry Pi Zero, has | ||
| 29 | * "20980000.usb" as both driver_name and device_name. | ||
| 30 | */ | ||
| 31 | struct usb_raw_init { | ||
| 32 | __u8 driver_name[UDC_NAME_LENGTH_MAX]; | ||
| 33 | __u8 device_name[UDC_NAME_LENGTH_MAX]; | ||
| 34 | __u8 speed; | ||
| 35 | }; | ||
| 36 | |||
| 37 | /* The type of event fetched with the USB_RAW_IOCTL_EVENT_FETCH ioctl. */ | ||
| 38 | enum usb_raw_event_type { | ||
| 39 | USB_RAW_EVENT_INVALID = 0, | ||
| 40 | |||
| 41 | /* This event is queued when the driver has bound to a UDC. */ | ||
| 42 | USB_RAW_EVENT_CONNECT = 1, | ||
| 43 | |||
| 44 | /* This event is queued when a new control request arrived to ep0. */ | ||
| 45 | USB_RAW_EVENT_CONTROL = 2, | ||
| 46 | |||
| 47 | /* The list might grow in the future. */ | ||
| 48 | }; | ||
| 49 | |||
| 50 | /* | ||
| 51 | * struct usb_raw_event - argument for USB_RAW_IOCTL_EVENT_FETCH ioctl. | ||
| 52 | * @type: The type of the fetched event. | ||
| 53 | * @length: Length of the data buffer. Updated by the driver and set to the | ||
| 54 | * actual length of the fetched event data. | ||
| 55 | * @data: A buffer to store the fetched event data. | ||
| 56 | * | ||
| 57 | * Currently the fetched data buffer is empty for USB_RAW_EVENT_CONNECT, | ||
| 58 | * and contains struct usb_ctrlrequest for USB_RAW_EVENT_CONTROL. | ||
| 59 | */ | ||
| 60 | struct usb_raw_event { | ||
| 61 | __u32 type; | ||
| 62 | __u32 length; | ||
| 63 | __u8 data[0]; | ||
| 64 | }; | ||
| 65 | |||
| 66 | #define USB_RAW_IO_FLAGS_ZERO 0x0001 | ||
| 67 | #define USB_RAW_IO_FLAGS_MASK 0x0001 | ||
| 68 | |||
| 69 | static int usb_raw_io_flags_valid(__u16 flags) | ||
| 70 | { | ||
| 71 | return (flags & ~USB_RAW_IO_FLAGS_MASK) == 0; | ||
| 72 | } | ||
| 73 | |||
| 74 | static int usb_raw_io_flags_zero(__u16 flags) | ||
| 75 | { | ||
| 76 | return (flags & USB_RAW_IO_FLAGS_ZERO); | ||
| 77 | } | ||
| 78 | |||
| 79 | /* | ||
| 80 | * struct usb_raw_ep_io - argument for USB_RAW_IOCTL_EP0/EP_WRITE/READ ioctls. | ||
| 81 | * @ep: Endpoint handle as returned by USB_RAW_IOCTL_EP_ENABLE for | ||
| 82 | * USB_RAW_IOCTL_EP_WRITE/READ. Ignored for USB_RAW_IOCTL_EP0_WRITE/READ. | ||
| 83 | * @flags: When USB_RAW_IO_FLAGS_ZERO is specified, the zero flag is set on | ||
| 84 | * the submitted USB request, see include/linux/usb/gadget.h for details. | ||
| 85 | * @length: Length of data. | ||
| 86 | * @data: Data to send for USB_RAW_IOCTL_EP0/EP_WRITE. Buffer to store received | ||
| 87 | * data for USB_RAW_IOCTL_EP0/EP_READ. | ||
| 88 | */ | ||
| 89 | struct usb_raw_ep_io { | ||
| 90 | __u16 ep; | ||
| 91 | __u16 flags; | ||
| 92 | __u32 length; | ||
| 93 | __u8 data[0]; | ||
| 94 | }; | ||
| 95 | |||
| 96 | /* | ||
| 97 | * Initializes a Raw Gadget instance. | ||
| 98 | * Accepts a pointer to the usb_raw_init struct as an argument. | ||
| 99 | * Returns 0 on success or negative error code on failure. | ||
| 100 | */ | ||
| 101 | #define USB_RAW_IOCTL_INIT _IOW('U', 0, struct usb_raw_init) | ||
| 102 | |||
| 103 | /* | ||
| 104 | * Instructs Raw Gadget to bind to a UDC and start emulating a USB device. | ||
| 105 | * Returns 0 on success or negative error code on failure. | ||
| 106 | */ | ||
| 107 | #define USB_RAW_IOCTL_RUN _IO('U', 1) | ||
| 108 | |||
| 109 | /* | ||
| 110 | * A blocking ioctl that waits for an event and returns fetched event data to | ||
| 111 | * the user. | ||
| 112 | * Accepts a pointer to the usb_raw_event struct. | ||
| 113 | * Returns 0 on success or negative error code on failure. | ||
| 114 | */ | ||
| 115 | #define USB_RAW_IOCTL_EVENT_FETCH _IOR('U', 2, struct usb_raw_event) | ||
| 116 | |||
| 117 | /* | ||
| 118 | * Queues an IN (OUT for READ) urb as a response to the last control request | ||
| 119 | * received on endpoint 0, provided that was an IN (OUT for READ) request and | ||
| 120 | * waits until the urb is completed. Copies received data to user for READ. | ||
| 121 | * Accepts a pointer to the usb_raw_ep_io struct as an argument. | ||
| 122 | * Returns length of trasferred data on success or negative error code on | ||
| 123 | * failure. | ||
| 124 | */ | ||
| 125 | #define USB_RAW_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_raw_ep_io) | ||
| 126 | #define USB_RAW_IOCTL_EP0_READ _IOWR('U', 4, struct usb_raw_ep_io) | ||
| 127 | |||
| 128 | /* | ||
| 129 | * Finds an endpoint that supports the transfer type specified in the | ||
| 130 | * descriptor and enables it. | ||
| 131 | * Accepts a pointer to the usb_endpoint_descriptor struct as an argument. | ||
| 132 | * Returns enabled endpoint handle on success or negative error code on failure. | ||
| 133 | */ | ||
| 134 | #define USB_RAW_IOCTL_EP_ENABLE _IOW('U', 5, struct usb_endpoint_descriptor) | ||
| 135 | |||
| 136 | /* Disables specified endpoint. | ||
| 137 | * Accepts endpoint handle as an argument. | ||
| 138 | * Returns 0 on success or negative error code on failure. | ||
| 139 | */ | ||
| 140 | #define USB_RAW_IOCTL_EP_DISABLE _IOW('U', 6, __u32) | ||
| 141 | |||
| 142 | /* | ||
| 143 | * Queues an IN (OUT for READ) urb as a response to the last control request | ||
| 144 | * received on endpoint usb_raw_ep_io.ep, provided that was an IN (OUT for READ) | ||
| 145 | * request and waits until the urb is completed. Copies received data to user | ||
| 146 | * for READ. | ||
| 147 | * Accepts a pointer to the usb_raw_ep_io struct as an argument. | ||
| 148 | * Returns length of trasferred data on success or negative error code on | ||
| 149 | * failure. | ||
| 150 | */ | ||
| 151 | #define USB_RAW_IOCTL_EP_WRITE _IOW('U', 7, struct usb_raw_ep_io) | ||
| 152 | #define USB_RAW_IOCTL_EP_READ _IOWR('U', 8, struct usb_raw_ep_io) | ||
| 153 | |||
| 154 | /* | ||
| 155 | * Switches the gadget into the configured state. | ||
| 156 | * Returns 0 on success or negative error code on failure. | ||
| 157 | */ | ||
| 158 | #define USB_RAW_IOCTL_CONFIGURE _IO('U', 9) | ||
| 159 | |||
| 160 | /* | ||
| 161 | * Constrains UDC VBUS power usage. | ||
| 162 | * Accepts current limit in 2 mA units as an argument. | ||
| 163 | * Returns 0 on success or negative error code on failure. | ||
| 164 | */ | ||
| 165 | #define USB_RAW_IOCTL_VBUS_DRAW _IOW('U', 10, __u32) | ||
| 166 | |||
| 167 | #endif /* _UAPI__LINUX_USB_RAW_GADGET_H */ | ||