diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-10-26 11:14:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-10-26 11:14:13 -0400 |
commit | 9703fc8caf36ac65dca1538b23dd137de0b53233 (patch) | |
tree | 4e92539741cdce08f3c0095fefe76232a686f576 | |
parent | da19a102ce87bf3e0a7fe277a659d1fc35330d6d (diff) | |
parent | b8d9ee24493d862fbfeb3d209c032647f6073d5d (diff) |
Merge tag 'usb-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB/PHY updates from Greg KH:
"Here is the big USB/PHY driver patches for 4.20-rc1
Lots of USB changes in here, primarily in these areas:
- typec updates and new drivers
- new PHY drivers
- dwc2 driver updates and additions (this old core keeps getting
added to new devices.)
- usbtmc major update based on the industry group coming together and
working to add new features and performance to the driver.
- USB gadget additions for new features
- USB gadget configfs updates
- chipidea driver updates
- other USB gadget updates
- USB serial driver updates
- renesas driver updates
- xhci driver updates
- other tiny USB driver updates
All of these have been in linux-next for a while with no reported
issues"
* tag 'usb-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (229 commits)
usb: phy: ab8500: silence some uninitialized variable warnings
usb: xhci: tegra: Add genpd support
usb: xhci: tegra: Power-off power-domains on removal
usbip:vudc: BUG kmalloc-2048 (Not tainted): Poison overwritten
usbip: tools: fix atoi() on non-null terminated string
USB: misc: appledisplay: fix backlight update_status return code
phy: phy-pxa-usb: add a new driver
usb: host: add DT bindings for faraday fotg2
usb: host: ohci-at91: fix request of irq for optional gpio
usb/early: remove set but not used variable 'remain_length'
usb: typec: Fix copy/paste on typec_set_vconn_role() kerneldoc
usb: typec: tcpm: Report back negotiated PPS voltage and current
USB: core: remove set but not used variable 'udev'
usb: core: fix memory leak on port_dev_path allocation
USB: net2280: Remove ->disconnect() callback from net2280_pullup()
usb: dwc2: disable power_down on rockchip devices
usb: gadget: udc: renesas_usb3: add support for r8a77990
dt-bindings: usb: renesas_usb3: add bindings for r8a77990
usb: gadget: udc: renesas_usb3: Add r8a774a1 support
USB: serial: cypress_m8: remove set but not used variable 'iflag'
...
181 files changed, 8787 insertions, 2189 deletions
diff --git a/Documentation/ABI/stable/sysfs-driver-usb-usbtmc b/Documentation/ABI/stable/sysfs-driver-usb-usbtmc index e960cd027e1e..a9e123ba32cd 100644 --- a/Documentation/ABI/stable/sysfs-driver-usb-usbtmc +++ b/Documentation/ABI/stable/sysfs-driver-usb-usbtmc | |||
@@ -25,38 +25,3 @@ Description: | |||
25 | 4.2.2. | 25 | 4.2.2. |
26 | 26 | ||
27 | The files are read only. | 27 | The files are read only. |
28 | |||
29 | |||
30 | What: /sys/bus/usb/drivers/usbtmc/*/TermChar | ||
31 | Date: August 2008 | ||
32 | Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | ||
33 | Description: | ||
34 | This file is the TermChar value to be sent to the USB TMC | ||
35 | device as described by the document, "Universal Serial Bus Test | ||
36 | and Measurement Class Specification | ||
37 | (USBTMC) Revision 1.0" as published by the USB-IF. | ||
38 | |||
39 | Note that the TermCharEnabled file determines if this value is | ||
40 | sent to the device or not. | ||
41 | |||
42 | |||
43 | What: /sys/bus/usb/drivers/usbtmc/*/TermCharEnabled | ||
44 | Date: August 2008 | ||
45 | Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | ||
46 | Description: | ||
47 | This file determines if the TermChar is to be sent to the | ||
48 | device on every transaction or not. For more details about | ||
49 | this, please see the document, "Universal Serial Bus Test and | ||
50 | Measurement Class Specification (USBTMC) Revision 1.0" as | ||
51 | published by the USB-IF. | ||
52 | |||
53 | |||
54 | What: /sys/bus/usb/drivers/usbtmc/*/auto_abort | ||
55 | Date: August 2008 | ||
56 | Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | ||
57 | Description: | ||
58 | This file determines if the transaction of the USB TMC | ||
59 | device is to be automatically aborted if there is any error. | ||
60 | For more details about this, please see the document, | ||
61 | "Universal Serial Bus Test and Measurement Class Specification | ||
62 | (USBTMC) Revision 1.0" as published by the USB-IF. | ||
diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uvc b/Documentation/ABI/testing/configfs-usb-gadget-uvc index 9281e2aa38df..809765bd9573 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-uvc +++ b/Documentation/ABI/testing/configfs-usb-gadget-uvc | |||
@@ -12,6 +12,10 @@ Date: Dec 2014 | |||
12 | KernelVersion: 4.0 | 12 | KernelVersion: 4.0 |
13 | Description: Control descriptors | 13 | Description: Control descriptors |
14 | 14 | ||
15 | All attributes read only: | ||
16 | bInterfaceNumber - USB interface number for this | ||
17 | streaming interface | ||
18 | |||
15 | What: /config/usb-gadget/gadget/functions/uvc.name/control/class | 19 | What: /config/usb-gadget/gadget/functions/uvc.name/control/class |
16 | Date: Dec 2014 | 20 | Date: Dec 2014 |
17 | KernelVersion: 4.0 | 21 | KernelVersion: 4.0 |
@@ -109,6 +113,10 @@ Date: Dec 2014 | |||
109 | KernelVersion: 4.0 | 113 | KernelVersion: 4.0 |
110 | Description: Streaming descriptors | 114 | Description: Streaming descriptors |
111 | 115 | ||
116 | All attributes read only: | ||
117 | bInterfaceNumber - USB interface number for this | ||
118 | streaming interface | ||
119 | |||
112 | What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class | 120 | What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class |
113 | Date: Dec 2014 | 121 | Date: Dec 2014 |
114 | KernelVersion: 4.0 | 122 | KernelVersion: 4.0 |
@@ -160,6 +168,10 @@ Description: Specific MJPEG format descriptors | |||
160 | 168 | ||
161 | All attributes read only, | 169 | All attributes read only, |
162 | except bmaControls and bDefaultFrameIndex: | 170 | except bmaControls and bDefaultFrameIndex: |
171 | bFormatIndex - unique id for this format descriptor; | ||
172 | only defined after parent header is | ||
173 | linked into the streaming class; | ||
174 | read-only | ||
163 | bmaControls - this format's data for bmaControls in | 175 | bmaControls - this format's data for bmaControls in |
164 | the streaming header | 176 | the streaming header |
165 | bmInterfaceFlags - specifies interlace information, | 177 | bmInterfaceFlags - specifies interlace information, |
@@ -177,6 +189,10 @@ Date: Dec 2014 | |||
177 | KernelVersion: 4.0 | 189 | KernelVersion: 4.0 |
178 | Description: Specific MJPEG frame descriptors | 190 | Description: Specific MJPEG frame descriptors |
179 | 191 | ||
192 | bFrameIndex - unique id for this framedescriptor; | ||
193 | only defined after parent format is | ||
194 | linked into the streaming header; | ||
195 | read-only | ||
180 | dwFrameInterval - indicates how frame interval can be | 196 | dwFrameInterval - indicates how frame interval can be |
181 | programmed; a number of values | 197 | programmed; a number of values |
182 | separated by newline can be specified | 198 | separated by newline can be specified |
@@ -204,6 +220,10 @@ Date: Dec 2014 | |||
204 | KernelVersion: 4.0 | 220 | KernelVersion: 4.0 |
205 | Description: Specific uncompressed format descriptors | 221 | Description: Specific uncompressed format descriptors |
206 | 222 | ||
223 | bFormatIndex - unique id for this format descriptor; | ||
224 | only defined after parent header is | ||
225 | linked into the streaming class; | ||
226 | read-only | ||
207 | bmaControls - this format's data for bmaControls in | 227 | bmaControls - this format's data for bmaControls in |
208 | the streaming header | 228 | the streaming header |
209 | bmInterfaceFlags - specifies interlace information, | 229 | bmInterfaceFlags - specifies interlace information, |
@@ -224,6 +244,10 @@ Date: Dec 2014 | |||
224 | KernelVersion: 4.0 | 244 | KernelVersion: 4.0 |
225 | Description: Specific uncompressed frame descriptors | 245 | Description: Specific uncompressed frame descriptors |
226 | 246 | ||
247 | bFrameIndex - unique id for this framedescriptor; | ||
248 | only defined after parent format is | ||
249 | linked into the streaming header; | ||
250 | read-only | ||
227 | dwFrameInterval - indicates how frame interval can be | 251 | dwFrameInterval - indicates how frame interval can be |
228 | programmed; a number of values | 252 | programmed; a number of values |
229 | separated by newline can be specified | 253 | separated by newline can be specified |
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index 08d456e07b53..559baa5c418c 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb | |||
@@ -189,6 +189,16 @@ Description: | |||
189 | The file will read "hotplug", "wired" and "not used" if the | 189 | The file will read "hotplug", "wired" and "not used" if the |
190 | information is available, and "unknown" otherwise. | 190 | information is available, and "unknown" otherwise. |
191 | 191 | ||
192 | What: /sys/bus/usb/devices/.../(hub interface)/portX/location | ||
193 | Date: October 2018 | ||
194 | Contact: Bjørn Mork <bjorn@mork.no> | ||
195 | Description: | ||
196 | Some platforms provide usb port physical location through | ||
197 | firmware. This is used by the kernel to pair up logical ports | ||
198 | mapping to the same physical connector. The attribute exposes the | ||
199 | raw location value as a hex integer. | ||
200 | |||
201 | |||
192 | What: /sys/bus/usb/devices/.../(hub interface)/portX/quirks | 202 | What: /sys/bus/usb/devices/.../(hub interface)/portX/quirks |
193 | Date: May 2018 | 203 | Date: May 2018 |
194 | Contact: Nicolas Boichat <drinkcat@chromium.org> | 204 | Contact: Nicolas Boichat <drinkcat@chromium.org> |
@@ -219,7 +229,14 @@ Description: | |||
219 | ports and report them to the kernel. This attribute is to expose | 229 | ports and report them to the kernel. This attribute is to expose |
220 | the number of over-current situation occurred on a specific port | 230 | the number of over-current situation occurred on a specific port |
221 | to user space. This file will contain an unsigned 32 bit value | 231 | to user space. This file will contain an unsigned 32 bit value |
222 | which wraps to 0 after its maximum is reached. | 232 | which wraps to 0 after its maximum is reached. This file supports |
233 | poll() for monitoring changes to this value in user space. | ||
234 | |||
235 | Any time this value changes the corresponding hub device will send a | ||
236 | udev event with the following attributes: | ||
237 | |||
238 | OVER_CURRENT_PORT=/sys/bus/usb/devices/.../(hub interface)/portX | ||
239 | OVER_CURRENT_COUNT=[current value of this sysfs attribute] | ||
223 | 240 | ||
224 | What: /sys/bus/usb/devices/.../(hub interface)/portX/usb3_lpm_permit | 241 | What: /sys/bus/usb/devices/.../(hub interface)/portX/usb3_lpm_permit |
225 | Date: November 2015 | 242 | Date: November 2015 |
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index e129cd8a6dcc..8022d902e770 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt | |||
@@ -4623,7 +4623,8 @@ | |||
4623 | 4623 | ||
4624 | usbcore.old_scheme_first= | 4624 | usbcore.old_scheme_first= |
4625 | [USB] Start with the old device initialization | 4625 | [USB] Start with the old device initialization |
4626 | scheme (default 0 = off). | 4626 | scheme, applies only to low and full-speed devices |
4627 | (default 0 = off). | ||
4627 | 4628 | ||
4628 | usbcore.usbfs_memory_mb= | 4629 | usbcore.usbfs_memory_mb= |
4629 | [USB] Memory limit (in MB) for buffers allocated by | 4630 | [USB] Memory limit (in MB) for buffers allocated by |
diff --git a/Documentation/devicetree/bindings/connector/usb-connector.txt b/Documentation/devicetree/bindings/connector/usb-connector.txt index 8855bfcfd778..d90e17e2428b 100644 --- a/Documentation/devicetree/bindings/connector/usb-connector.txt +++ b/Documentation/devicetree/bindings/connector/usb-connector.txt | |||
@@ -29,15 +29,15 @@ Required properties for usb-c-connector with power delivery support: | |||
29 | in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.2 | 29 | in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.2 |
30 | Source_Capabilities Message, the order of each entry(PDO) should follow | 30 | Source_Capabilities Message, the order of each entry(PDO) should follow |
31 | the PD spec chapter 6.4.1. Required for power source and power dual role. | 31 | the PD spec chapter 6.4.1. Required for power source and power dual role. |
32 | User can specify the source PDO array via PDO_FIXED/BATT/VAR() defined in | 32 | User can specify the source PDO array via PDO_FIXED/BATT/VAR/PPS_APDO() |
33 | dt-bindings/usb/pd.h. | 33 | defined in dt-bindings/usb/pd.h. |
34 | - sink-pdos: An array of u32 with each entry providing supported power | 34 | - sink-pdos: An array of u32 with each entry providing supported power |
35 | sink data object(PDO), the detailed bit definitions of PDO can be found | 35 | sink data object(PDO), the detailed bit definitions of PDO can be found |
36 | in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.3 | 36 | in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.3 |
37 | Sink Capabilities Message, the order of each entry(PDO) should follow | 37 | Sink Capabilities Message, the order of each entry(PDO) should follow |
38 | the PD spec chapter 6.4.1. Required for power sink and power dual role. | 38 | the PD spec chapter 6.4.1. Required for power sink and power dual role. |
39 | User can specify the sink PDO array via PDO_FIXED/BATT/VAR() defined in | 39 | User can specify the sink PDO array via PDO_FIXED/BATT/VAR/PPS_APDO() defined |
40 | dt-bindings/usb/pd.h. | 40 | in dt-bindings/usb/pd.h. |
41 | - op-sink-microwatt: Sink required operating power in microwatt, if source | 41 | - op-sink-microwatt: Sink required operating power in microwatt, if source |
42 | can't offer the power, Capability Mismatch is set. Required for power | 42 | can't offer the power, Capability Mismatch is set. Required for power |
43 | sink and power dual role. | 43 | sink and power dual role. |
diff --git a/Documentation/devicetree/bindings/phy/brcm-sata-phy.txt b/Documentation/devicetree/bindings/phy/brcm-sata-phy.txt index 0aced97d8092..b640845fec67 100644 --- a/Documentation/devicetree/bindings/phy/brcm-sata-phy.txt +++ b/Documentation/devicetree/bindings/phy/brcm-sata-phy.txt | |||
@@ -8,6 +8,7 @@ Required properties: | |||
8 | "brcm,iproc-nsp-sata-phy" | 8 | "brcm,iproc-nsp-sata-phy" |
9 | "brcm,phy-sata3" | 9 | "brcm,phy-sata3" |
10 | "brcm,iproc-sr-sata-phy" | 10 | "brcm,iproc-sr-sata-phy" |
11 | "brcm,bcm63138-sata-phy" | ||
11 | - address-cells: should be 1 | 12 | - address-cells: should be 1 |
12 | - size-cells: should be 0 | 13 | - size-cells: should be 0 |
13 | - reg: register ranges for the PHY PCB interface | 14 | - reg: register ranges for the PHY PCB interface |
diff --git a/Documentation/devicetree/bindings/phy/phy-cadence-dp.txt b/Documentation/devicetree/bindings/phy/phy-cadence-dp.txt new file mode 100644 index 000000000000..7f49fd54ebc1 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-cadence-dp.txt | |||
@@ -0,0 +1,30 @@ | |||
1 | Cadence MHDP DisplayPort SD0801 PHY binding | ||
2 | =========================================== | ||
3 | |||
4 | This binding describes the Cadence SD0801 PHY hardware included with | ||
5 | the Cadence MHDP DisplayPort controller. | ||
6 | |||
7 | ------------------------------------------------------------------------------- | ||
8 | Required properties (controller (parent) node): | ||
9 | - compatible : Should be "cdns,dp-phy" | ||
10 | - reg : Defines the following sets of registers in the parent | ||
11 | mhdp device: | ||
12 | - Offset of the DPTX PHY configuration registers | ||
13 | - Offset of the SD0801 PHY configuration registers | ||
14 | - #phy-cells : from the generic PHY bindings, must be 0. | ||
15 | |||
16 | Optional properties: | ||
17 | - num_lanes : Number of DisplayPort lanes to use (1, 2 or 4) | ||
18 | - max_bit_rate : Maximum DisplayPort link bit rate to use, in Mbps (2160, | ||
19 | 2430, 2700, 3240, 4320, 5400 or 8100) | ||
20 | ------------------------------------------------------------------------------- | ||
21 | |||
22 | Example: | ||
23 | dp_phy: phy@f0fb030a00 { | ||
24 | compatible = "cdns,dp-phy"; | ||
25 | reg = <0xf0 0xfb030a00 0x0 0x00000040>, | ||
26 | <0xf0 0xfb500000 0x0 0x00100000>; | ||
27 | num_lanes = <4>; | ||
28 | max_bit_rate = <8100>; | ||
29 | #phy-cells = <0>; | ||
30 | }; | ||
diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-hdmi.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-hdmi.txt new file mode 100644 index 000000000000..710cccd5ee56 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-hdmi.txt | |||
@@ -0,0 +1,43 @@ | |||
1 | ROCKCHIP HDMI PHY WITH INNO IP BLOCK | ||
2 | |||
3 | Required properties: | ||
4 | - compatible : should be one of the listed compatibles: | ||
5 | * "rockchip,rk3228-hdmi-phy", | ||
6 | * "rockchip,rk3328-hdmi-phy"; | ||
7 | - reg : Address and length of the hdmi phy control register set | ||
8 | - clocks : phandle + clock specifier for the phy clocks | ||
9 | - clock-names : string, clock name, must contain "sysclk" for system | ||
10 | control and register configuration, "refoclk" for crystal- | ||
11 | oscillator reference PLL clock input and "refpclk" for pclk- | ||
12 | based refeference PLL clock input. | ||
13 | - #clock-cells: should be 0. | ||
14 | - clock-output-names : shall be the name for the output clock. | ||
15 | - interrupts : phandle + interrupt specified for the hdmiphy interrupt | ||
16 | - #phy-cells : must be 0. See ./phy-bindings.txt for details. | ||
17 | |||
18 | Optional properties for rk3328-hdmi-phy: | ||
19 | - nvmem-cells = phandle + nvmem specifier for the cpu-version efuse | ||
20 | - nvmem-cell-names : "cpu-version" to read the chip version, required | ||
21 | for adjustment to some frequency settings | ||
22 | |||
23 | Example: | ||
24 | hdmi_phy: hdmi-phy@12030000 { | ||
25 | compatible = "rockchip,rk3228-hdmi-phy"; | ||
26 | reg = <0x12030000 0x10000>; | ||
27 | #phy-cells = <0>; | ||
28 | clocks = <&cru PCLK_HDMI_PHY>, <&xin24m>, <&cru DCLK_HDMIPHY>; | ||
29 | clock-names = "sysclk", "refoclk", "refpclk"; | ||
30 | #clock-cells = <0>; | ||
31 | clock-output-names = "hdmi_phy"; | ||
32 | status = "disabled"; | ||
33 | }; | ||
34 | |||
35 | Then the PHY can be used in other nodes such as: | ||
36 | |||
37 | hdmi: hdmi@200a0000 { | ||
38 | compatible = "rockchip,rk3228-dw-hdmi"; | ||
39 | ... | ||
40 | phys = <&hdmi_phy>; | ||
41 | phy-names = "hdmi"; | ||
42 | ... | ||
43 | }; | ||
diff --git a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt index 0c7629e88bf3..adf20b2bdf71 100644 --- a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt +++ b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt | |||
@@ -10,16 +10,20 @@ Required properties: | |||
10 | "qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996, | 10 | "qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996, |
11 | "qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996, | 11 | "qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996, |
12 | "qcom,sdm845-qmp-usb3-phy" for USB3 QMP V3 phy on sdm845, | 12 | "qcom,sdm845-qmp-usb3-phy" for USB3 QMP V3 phy on sdm845, |
13 | "qcom,sdm845-qmp-usb3-uni-phy" for USB3 QMP V3 UNI phy on sdm845. | 13 | "qcom,sdm845-qmp-usb3-uni-phy" for USB3 QMP V3 UNI phy on sdm845, |
14 | "qcom,sdm845-qmp-ufs-phy" for UFS QMP phy on sdm845. | ||
14 | 15 | ||
15 | - reg: | 16 | - reg: |
16 | - For "qcom,sdm845-qmp-usb3-phy": | 17 | - index 0: address and length of register set for PHY's common |
17 | - index 0: address and length of register set for PHY's common serdes | 18 | serdes block. |
18 | block. | 19 | - index 1: address and length of the DP_COM control block (for |
19 | - named register "dp_com" (using reg-names): address and length of the | 20 | "qcom,sdm845-qmp-usb3-phy" only). |
20 | DP_COM control block. | 21 | |
21 | - For all others: | 22 | - reg-names: |
22 | - offset and length of register set for PHY's common serdes block. | 23 | - For "qcom,sdm845-qmp-usb3-phy": |
24 | - Should be: "reg-base", "dp_com" | ||
25 | - For all others: | ||
26 | - The reg-names property shouldn't be defined. | ||
23 | 27 | ||
24 | - #clock-cells: must be 1 | 28 | - #clock-cells: must be 1 |
25 | - Phy pll outputs a bunch of clocks for Tx, Rx and Pipe | 29 | - Phy pll outputs a bunch of clocks for Tx, Rx and Pipe |
@@ -35,6 +39,7 @@ Required properties: | |||
35 | "aux" for phy aux clock, | 39 | "aux" for phy aux clock, |
36 | "ref" for 19.2 MHz ref clk, | 40 | "ref" for 19.2 MHz ref clk, |
37 | "com_aux" for phy common block aux clock, | 41 | "com_aux" for phy common block aux clock, |
42 | "ref_aux" for phy reference aux clock, | ||
38 | For "qcom,msm8996-qmp-pcie-phy" must contain: | 43 | For "qcom,msm8996-qmp-pcie-phy" must contain: |
39 | "aux", "cfg_ahb", "ref". | 44 | "aux", "cfg_ahb", "ref". |
40 | For "qcom,msm8996-qmp-usb3-phy" must contain: | 45 | For "qcom,msm8996-qmp-usb3-phy" must contain: |
diff --git a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt index fb4a204da2bf..de7b5393c163 100644 --- a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt +++ b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt | |||
@@ -1,10 +1,12 @@ | |||
1 | * Renesas R-Car generation 3 USB 2.0 PHY | 1 | * Renesas R-Car generation 3 USB 2.0 PHY |
2 | 2 | ||
3 | This file provides information on what the device node for the R-Car generation | 3 | This file provides information on what the device node for the R-Car generation |
4 | 3 USB 2.0 PHY contains. | 4 | 3 and RZ/G2 USB 2.0 PHY contain. |
5 | 5 | ||
6 | Required properties: | 6 | Required properties: |
7 | - compatible: "renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795 | 7 | - compatible: "renesas,usb2-phy-r8a774a1" if the device is a part of an R8A774A1 |
8 | SoC. | ||
9 | "renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795 | ||
8 | SoC. | 10 | SoC. |
9 | "renesas,usb2-phy-r8a7796" if the device is a part of an R8A7796 | 11 | "renesas,usb2-phy-r8a7796" if the device is a part of an R8A7796 |
10 | SoC. | 12 | SoC. |
@@ -14,7 +16,8 @@ Required properties: | |||
14 | R8A77990 SoC. | 16 | R8A77990 SoC. |
15 | "renesas,usb2-phy-r8a77995" if the device is a part of an | 17 | "renesas,usb2-phy-r8a77995" if the device is a part of an |
16 | R8A77995 SoC. | 18 | R8A77995 SoC. |
17 | "renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 compatible device. | 19 | "renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 or RZ/G2 |
20 | compatible device. | ||
18 | 21 | ||
19 | When compatible with the generic version, nodes must list the | 22 | When compatible with the generic version, nodes must list the |
20 | SoC-specific version corresponding to the platform first | 23 | SoC-specific version corresponding to the platform first |
@@ -31,6 +34,8 @@ channel as USB OTG: | |||
31 | - interrupts: interrupt specifier for the PHY. | 34 | - interrupts: interrupt specifier for the PHY. |
32 | - vbus-supply: Phandle to a regulator that provides power to the VBUS. This | 35 | - vbus-supply: Phandle to a regulator that provides power to the VBUS. This |
33 | regulator will be managed during the PHY power on/off sequence. | 36 | regulator will be managed during the PHY power on/off sequence. |
37 | - renesas,no-otg-pins: boolean, specify when a board does not provide proper | ||
38 | otg pins. | ||
34 | 39 | ||
35 | Example (R-Car H3): | 40 | Example (R-Car H3): |
36 | 41 | ||
diff --git a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb3.txt b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb3.txt index 47dd296ecead..9d9826609c2f 100644 --- a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb3.txt +++ b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb3.txt | |||
@@ -1,20 +1,22 @@ | |||
1 | * Renesas R-Car generation 3 USB 3.0 PHY | 1 | * Renesas R-Car generation 3 USB 3.0 PHY |
2 | 2 | ||
3 | This file provides information on what the device node for the R-Car generation | 3 | This file provides information on what the device node for the R-Car generation |
4 | 3 USB 3.0 PHY contains. | 4 | 3 and RZ/G2 USB 3.0 PHY contain. |
5 | If you want to enable spread spectrum clock (ssc), you should use USB_EXTAL | 5 | If you want to enable spread spectrum clock (ssc), you should use USB_EXTAL |
6 | instead of USB3_CLK. However, if you don't want to these features, you don't | 6 | instead of USB3_CLK. However, if you don't want to these features, you don't |
7 | need this driver. | 7 | need this driver. |
8 | 8 | ||
9 | Required properties: | 9 | Required properties: |
10 | - compatible: "renesas,r8a7795-usb3-phy" if the device is a part of an R8A7795 | 10 | - compatible: "renesas,r8a774a1-usb3-phy" if the device is a part of an R8A774A1 |
11 | SoC. | ||
12 | "renesas,r8a7795-usb3-phy" if the device is a part of an R8A7795 | ||
11 | SoC. | 13 | SoC. |
12 | "renesas,r8a7796-usb3-phy" if the device is a part of an R8A7796 | 14 | "renesas,r8a7796-usb3-phy" if the device is a part of an R8A7796 |
13 | SoC. | 15 | SoC. |
14 | "renesas,r8a77965-usb3-phy" if the device is a part of an | 16 | "renesas,r8a77965-usb3-phy" if the device is a part of an |
15 | R8A77965 SoC. | 17 | R8A77965 SoC. |
16 | "renesas,rcar-gen3-usb3-phy" for a generic R-Car Gen3 compatible | 18 | "renesas,rcar-gen3-usb3-phy" for a generic R-Car Gen3 or RZ/G2 |
17 | device. | 19 | compatible device. |
18 | 20 | ||
19 | When compatible with the generic version, nodes must list the | 21 | When compatible with the generic version, nodes must list the |
20 | SoC-specific version corresponding to the platform first | 22 | SoC-specific version corresponding to the platform first |
diff --git a/Documentation/devicetree/bindings/phy/uniphier-pcie-phy.txt b/Documentation/devicetree/bindings/phy/uniphier-pcie-phy.txt new file mode 100644 index 000000000000..1889d3b89d68 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/uniphier-pcie-phy.txt | |||
@@ -0,0 +1,31 @@ | |||
1 | Socionext UniPhier PCIe PHY bindings | ||
2 | |||
3 | This describes the devicetree bindings for PHY interface built into | ||
4 | PCIe controller implemented on Socionext UniPhier SoCs. | ||
5 | |||
6 | Required properties: | ||
7 | - compatible: Should contain one of the following: | ||
8 | "socionext,uniphier-ld20-pcie-phy" - for LD20 PHY | ||
9 | "socionext,uniphier-pxs3-pcie-phy" - for PXs3 PHY | ||
10 | - reg: Specifies offset and length of the register set for the device. | ||
11 | - #phy-cells: Must be zero. | ||
12 | - clocks: A phandle to the clock gate for PCIe glue layer including | ||
13 | this phy. | ||
14 | - resets: A phandle to the reset line for PCIe glue layer including | ||
15 | this phy. | ||
16 | |||
17 | Optional properties: | ||
18 | - socionext,syscon: A phandle to system control to set configurations | ||
19 | for phy. | ||
20 | |||
21 | Refer to phy/phy-bindings.txt for the generic PHY binding properties. | ||
22 | |||
23 | Example: | ||
24 | pcie_phy: phy@66038000 { | ||
25 | compatible = "socionext,uniphier-ld20-pcie-phy"; | ||
26 | reg = <0x66038000 0x4000>; | ||
27 | #phy-cells = <0>; | ||
28 | clocks = <&sys_clk 24>; | ||
29 | resets = <&sys_rst 24>; | ||
30 | socionext,syscon = <&soc_glue>; | ||
31 | }; | ||
diff --git a/Documentation/devicetree/bindings/phy/uniphier-usb2-phy.txt b/Documentation/devicetree/bindings/phy/uniphier-usb2-phy.txt new file mode 100644 index 000000000000..b43b28250cc0 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/uniphier-usb2-phy.txt | |||
@@ -0,0 +1,45 @@ | |||
1 | Socionext UniPhier USB2 PHY | ||
2 | |||
3 | This describes the devicetree bindings for PHY interface built into | ||
4 | USB2 controller implemented on Socionext UniPhier SoCs. | ||
5 | |||
6 | Pro4 SoC has both USB2 and USB3 host controllers, however, this USB3 | ||
7 | controller doesn't include its own High-Speed PHY. This needs to specify | ||
8 | USB2 PHY instead of USB3 HS-PHY. | ||
9 | |||
10 | Required properties: | ||
11 | - compatible: Should contain one of the following: | ||
12 | "socionext,uniphier-pro4-usb2-phy" - for Pro4 SoC | ||
13 | "socionext,uniphier-ld11-usb2-phy" - for LD11 SoC | ||
14 | |||
15 | Sub-nodes: | ||
16 | Each PHY should be represented as a sub-node. | ||
17 | |||
18 | Sub-nodes required properties: | ||
19 | - #phy-cells: Should be 0. | ||
20 | - reg: The number of the PHY. | ||
21 | |||
22 | Sub-nodes optional properties: | ||
23 | - vbus-supply: A phandle to the regulator for USB VBUS. | ||
24 | |||
25 | Refer to phy/phy-bindings.txt for the generic PHY binding properties. | ||
26 | |||
27 | Example: | ||
28 | soc-glue@5f800000 { | ||
29 | ... | ||
30 | usb-phy { | ||
31 | compatible = "socionext,uniphier-ld11-usb2-phy"; | ||
32 | usb_phy0: phy@0 { | ||
33 | reg = <0>; | ||
34 | #phy-cells = <0>; | ||
35 | }; | ||
36 | ... | ||
37 | }; | ||
38 | }; | ||
39 | |||
40 | usb@5a800100 { | ||
41 | compatible = "socionext,uniphier-ehci", "generic-ehci"; | ||
42 | ... | ||
43 | phy-names = "usb"; | ||
44 | phys = <&usb_phy0>; | ||
45 | }; | ||
diff --git a/Documentation/devicetree/bindings/phy/uniphier-usb3-hsphy.txt b/Documentation/devicetree/bindings/phy/uniphier-usb3-hsphy.txt new file mode 100644 index 000000000000..e8d8086a7ae9 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/uniphier-usb3-hsphy.txt | |||
@@ -0,0 +1,69 @@ | |||
1 | Socionext UniPhier USB3 High-Speed (HS) PHY | ||
2 | |||
3 | This describes the devicetree bindings for PHY interfaces built into | ||
4 | USB3 controller implemented on Socionext UniPhier SoCs. | ||
5 | Although the controller includes High-Speed PHY and Super-Speed PHY, | ||
6 | this describes about High-Speed PHY. | ||
7 | |||
8 | Required properties: | ||
9 | - compatible: Should contain one of the following: | ||
10 | "socionext,uniphier-pro4-usb3-hsphy" - for Pro4 SoC | ||
11 | "socionext,uniphier-pxs2-usb3-hsphy" - for PXs2 SoC | ||
12 | "socionext,uniphier-ld20-usb3-hsphy" - for LD20 SoC | ||
13 | "socionext,uniphier-pxs3-usb3-hsphy" - for PXs3 SoC | ||
14 | - reg: Specifies offset and length of the register set for the device. | ||
15 | - #phy-cells: Should be 0. | ||
16 | - clocks: A list of phandles to the clock gate for USB3 glue layer. | ||
17 | According to the clock-names, appropriate clocks are required. | ||
18 | - clock-names: Should contain the following: | ||
19 | "gio", "link" - for Pro4 SoC | ||
20 | "phy", "phy-ext", "link" - for PXs3 SoC, "phy-ext" is optional. | ||
21 | "phy", "link" - for others | ||
22 | - resets: A list of phandles to the reset control for USB3 glue layer. | ||
23 | According to the reset-names, appropriate resets are required. | ||
24 | - reset-names: Should contain the following: | ||
25 | "gio", "link" - for Pro4 SoC | ||
26 | "phy", "link" - for others | ||
27 | |||
28 | Optional properties: | ||
29 | - vbus-supply: A phandle to the regulator for USB VBUS. | ||
30 | - nvmem-cells: Phandles to nvmem cell that contains the trimming data. | ||
31 | Available only for HS-PHY implemented on LD20 and PXs3, and | ||
32 | if unspecified, default value is used. | ||
33 | - nvmem-cell-names: Should be the following names, which correspond to | ||
34 | each nvmem-cells. | ||
35 | All of the 3 parameters associated with the following names are | ||
36 | required for each port, if any one is omitted, the trimming data | ||
37 | of the port will not be set at all. | ||
38 | "rterm", "sel_t", "hs_i" - Each cell name for phy parameters | ||
39 | |||
40 | Refer to phy/phy-bindings.txt for the generic PHY binding properties. | ||
41 | |||
42 | Example: | ||
43 | |||
44 | usb-glue@65b00000 { | ||
45 | compatible = "socionext,uniphier-ld20-dwc3-glue", | ||
46 | "simple-mfd"; | ||
47 | #address-cells = <1>; | ||
48 | #size-cells = <1>; | ||
49 | ranges = <0 0x65b00000 0x400>; | ||
50 | |||
51 | usb_vbus0: regulator { | ||
52 | ... | ||
53 | }; | ||
54 | |||
55 | usb_hsphy0: hs-phy@200 { | ||
56 | compatible = "socionext,uniphier-ld20-usb3-hsphy"; | ||
57 | reg = <0x200 0x10>; | ||
58 | #phy-cells = <0>; | ||
59 | clock-names = "link", "phy"; | ||
60 | clocks = <&sys_clk 14>, <&sys_clk 16>; | ||
61 | reset-names = "link", "phy"; | ||
62 | resets = <&sys_rst 14>, <&sys_rst 16>; | ||
63 | vbus-supply = <&usb_vbus0>; | ||
64 | nvmem-cell-names = "rterm", "sel_t", "hs_i"; | ||
65 | nvmem-cells = <&usb_rterm0>, <&usb_sel_t0>, | ||
66 | <&usb_hs_i0>; | ||
67 | }; | ||
68 | ... | ||
69 | }; | ||
diff --git a/Documentation/devicetree/bindings/phy/uniphier-usb3-ssphy.txt b/Documentation/devicetree/bindings/phy/uniphier-usb3-ssphy.txt new file mode 100644 index 000000000000..490b815445e8 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/uniphier-usb3-ssphy.txt | |||
@@ -0,0 +1,57 @@ | |||
1 | Socionext UniPhier USB3 Super-Speed (SS) PHY | ||
2 | |||
3 | This describes the devicetree bindings for PHY interfaces built into | ||
4 | USB3 controller implemented on Socionext UniPhier SoCs. | ||
5 | Although the controller includes High-Speed PHY and Super-Speed PHY, | ||
6 | this describes about Super-Speed PHY. | ||
7 | |||
8 | Required properties: | ||
9 | - compatible: Should contain one of the following: | ||
10 | "socionext,uniphier-pro4-usb3-ssphy" - for Pro4 SoC | ||
11 | "socionext,uniphier-pxs2-usb3-ssphy" - for PXs2 SoC | ||
12 | "socionext,uniphier-ld20-usb3-ssphy" - for LD20 SoC | ||
13 | "socionext,uniphier-pxs3-usb3-ssphy" - for PXs3 SoC | ||
14 | - reg: Specifies offset and length of the register set for the device. | ||
15 | - #phy-cells: Should be 0. | ||
16 | - clocks: A list of phandles to the clock gate for USB3 glue layer. | ||
17 | According to the clock-names, appropriate clocks are required. | ||
18 | - clock-names: | ||
19 | "gio", "link" - for Pro4 SoC | ||
20 | "phy", "phy-ext", "link" - for PXs3 SoC, "phy-ext" is optional. | ||
21 | "phy", "link" - for others | ||
22 | - resets: A list of phandles to the reset control for USB3 glue layer. | ||
23 | According to the reset-names, appropriate resets are required. | ||
24 | - reset-names: | ||
25 | "gio", "link" - for Pro4 SoC | ||
26 | "phy", "link" - for others | ||
27 | |||
28 | Optional properties: | ||
29 | - vbus-supply: A phandle to the regulator for USB VBUS. | ||
30 | |||
31 | Refer to phy/phy-bindings.txt for the generic PHY binding properties. | ||
32 | |||
33 | Example: | ||
34 | |||
35 | usb-glue@65b00000 { | ||
36 | compatible = "socionext,uniphier-ld20-dwc3-glue", | ||
37 | "simple-mfd"; | ||
38 | #address-cells = <1>; | ||
39 | #size-cells = <1>; | ||
40 | ranges = <0 0x65b00000 0x400>; | ||
41 | |||
42 | usb_vbus0: regulator { | ||
43 | ... | ||
44 | }; | ||
45 | |||
46 | usb_ssphy0: ss-phy@300 { | ||
47 | compatible = "socionext,uniphier-ld20-usb3-ssphy"; | ||
48 | reg = <0x300 0x10>; | ||
49 | #phy-cells = <0>; | ||
50 | clock-names = "link", "phy"; | ||
51 | clocks = <&sys_clk 14>, <&sys_clk 16>; | ||
52 | reset-names = "link", "phy"; | ||
53 | resets = <&sys_rst 14>, <&sys_rst 16>; | ||
54 | vbus-supply = <&usb_vbus0>; | ||
55 | }; | ||
56 | ... | ||
57 | }; | ||
diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt index 2e9318151df7..529e51879fb2 100644 --- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt | |||
@@ -80,6 +80,8 @@ Optional properties: | |||
80 | controller. It's expected that a mux state of 0 indicates device mode and a | 80 | controller. It's expected that a mux state of 0 indicates device mode and a |
81 | mux state of 1 indicates host mode. | 81 | mux state of 1 indicates host mode. |
82 | - mux-control-names: Shall be "usb_switch" if mux-controls is specified. | 82 | - mux-control-names: Shall be "usb_switch" if mux-controls is specified. |
83 | - pinctrl-names: Names for optional pin modes in "default", "host", "device" | ||
84 | - pinctrl-n: alternate pin modes | ||
83 | 85 | ||
84 | i.mx specific properties | 86 | i.mx specific properties |
85 | - fsl,usbmisc: phandler of non-core register device, with one | 87 | - fsl,usbmisc: phandler of non-core register device, with one |
diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 3e4c38b806ac..636630fb92d7 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt | |||
@@ -19,6 +19,7 @@ Exception for clocks: | |||
19 | "cavium,octeon-7130-usb-uctl" | 19 | "cavium,octeon-7130-usb-uctl" |
20 | "qcom,dwc3" | 20 | "qcom,dwc3" |
21 | "samsung,exynos5250-dwusb3" | 21 | "samsung,exynos5250-dwusb3" |
22 | "samsung,exynos5433-dwusb3" | ||
22 | "samsung,exynos7-dwusb3" | 23 | "samsung,exynos7-dwusb3" |
23 | "sprd,sc9860-dwc3" | 24 | "sprd,sc9860-dwc3" |
24 | "st,stih407-dwc3" | 25 | "st,stih407-dwc3" |
diff --git a/Documentation/devicetree/bindings/usb/ehci-mv.txt b/Documentation/devicetree/bindings/usb/ehci-mv.txt new file mode 100644 index 000000000000..335589895763 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/ehci-mv.txt | |||
@@ -0,0 +1,23 @@ | |||
1 | * Marvell PXA/MMP EHCI controller. | ||
2 | |||
3 | Required properties: | ||
4 | |||
5 | - compatible: must be "marvell,pxau2o-ehci" | ||
6 | - reg: physical base addresses of the controller and length of memory mapped region | ||
7 | - interrupts: one EHCI controller interrupt should be described here | ||
8 | - clocks: phandle list of usb clocks | ||
9 | - clock-names: should be "USBCLK" | ||
10 | - phys: phandle for the PHY device | ||
11 | - phy-names: should be "usb" | ||
12 | |||
13 | Example: | ||
14 | |||
15 | ehci0: usb-ehci@d4208000 { | ||
16 | compatible = "marvell,pxau2o-ehci"; | ||
17 | reg = <0xd4208000 0x200>; | ||
18 | interrupts = <44>; | ||
19 | clocks = <&soc_clocks MMP2_CLK_USB>; | ||
20 | clock-names = "USBCLK"; | ||
21 | phys = <&usb_otg_phy>; | ||
22 | phy-names = "usb"; | ||
23 | }; | ||
diff --git a/Documentation/devicetree/bindings/usb/exynos-usb.txt b/Documentation/devicetree/bindings/usb/exynos-usb.txt index c97374315049..b7111f43fa59 100644 --- a/Documentation/devicetree/bindings/usb/exynos-usb.txt +++ b/Documentation/devicetree/bindings/usb/exynos-usb.txt | |||
@@ -83,6 +83,8 @@ Required properties: | |||
83 | - compatible: should be one of the following - | 83 | - compatible: should be one of the following - |
84 | "samsung,exynos5250-dwusb3": for USB 3.0 DWC3 controller on | 84 | "samsung,exynos5250-dwusb3": for USB 3.0 DWC3 controller on |
85 | Exynos5250/5420. | 85 | Exynos5250/5420. |
86 | "samsung,exynos5433-dwusb3": for USB 3.0 DWC3 controller on | ||
87 | Exynos5433. | ||
86 | "samsung,exynos7-dwusb3": for USB 3.0 DWC3 controller on Exynos7. | 88 | "samsung,exynos7-dwusb3": for USB 3.0 DWC3 controller on Exynos7. |
87 | - #address-cells, #size-cells : should be '1' if the device has sub-nodes | 89 | - #address-cells, #size-cells : should be '1' if the device has sub-nodes |
88 | with 'reg' property. | 90 | with 'reg' property. |
diff --git a/Documentation/devicetree/bindings/usb/faraday,fotg210.txt b/Documentation/devicetree/bindings/usb/faraday,fotg210.txt new file mode 100644 index 000000000000..06a2286e2054 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/faraday,fotg210.txt | |||
@@ -0,0 +1,35 @@ | |||
1 | Faraday FOTG Host controller | ||
2 | |||
3 | This OTG-capable USB host controller is found in Cortina Systems | ||
4 | Gemini and other SoC products. | ||
5 | |||
6 | Required properties: | ||
7 | - compatible: should be one of: | ||
8 | "faraday,fotg210" | ||
9 | "cortina,gemini-usb", "faraday,fotg210" | ||
10 | - reg: should contain one register range i.e. start and length | ||
11 | - interrupts: description of the interrupt line | ||
12 | |||
13 | Optional properties: | ||
14 | - clocks: should contain the IP block clock | ||
15 | - clock-names: should be "PCLK" for the IP block clock | ||
16 | |||
17 | Required properties for "cortina,gemini-usb" compatible: | ||
18 | - syscon: a phandle to the system controller to access PHY registers | ||
19 | |||
20 | Optional properties for "cortina,gemini-usb" compatible: | ||
21 | - cortina,gemini-mini-b: boolean property that indicates that a Mini-B | ||
22 | OTG connector is in use | ||
23 | - wakeup-source: see power/wakeup-source.txt | ||
24 | |||
25 | Example for Gemini: | ||
26 | |||
27 | usb@68000000 { | ||
28 | compatible = "cortina,gemini-usb", "faraday,fotg210"; | ||
29 | reg = <0x68000000 0x1000>; | ||
30 | interrupts = <10 IRQ_TYPE_LEVEL_HIGH>; | ||
31 | clocks = <&cc 12>; | ||
32 | clock-names = "PCLK"; | ||
33 | syscon = <&syscon>; | ||
34 | wakeup-source; | ||
35 | }; | ||
diff --git a/Documentation/devicetree/bindings/usb/fcs,fusb302.txt b/Documentation/devicetree/bindings/usb/fcs,fusb302.txt index 6087dc7f209e..a5d011d2efc8 100644 --- a/Documentation/devicetree/bindings/usb/fcs,fusb302.txt +++ b/Documentation/devicetree/bindings/usb/fcs,fusb302.txt | |||
@@ -5,10 +5,19 @@ Required properties : | |||
5 | - reg : I2C slave address | 5 | - reg : I2C slave address |
6 | - interrupts : Interrupt specifier | 6 | - interrupts : Interrupt specifier |
7 | 7 | ||
8 | Optional properties : | 8 | Required sub-node: |
9 | - fcs,operating-sink-microwatt : | 9 | - connector : The "usb-c-connector" attached to the FUSB302 IC. The bindings |
10 | Minimum amount of power accepted from a sink | 10 | of the connector node are specified in: |
11 | when negotiating | 11 | |
12 | Documentation/devicetree/bindings/connector/usb-connector.txt | ||
13 | |||
14 | Deprecated properties : | ||
15 | - fcs,max-sink-microvolt : Maximum sink voltage accepted by port controller | ||
16 | - fcs,max-sink-microamp : Maximum sink current accepted by port controller | ||
17 | - fcs,max-sink-microwatt : Maximum sink power accepted by port controller | ||
18 | - fcs,operating-sink-microwatt : Minimum amount of power accepted from a sink | ||
19 | when negotiating | ||
20 | |||
12 | 21 | ||
13 | Example: | 22 | Example: |
14 | 23 | ||
@@ -17,7 +26,16 @@ fusb302: typec-portc@54 { | |||
17 | reg = <0x54>; | 26 | reg = <0x54>; |
18 | interrupt-parent = <&nmi_intc>; | 27 | interrupt-parent = <&nmi_intc>; |
19 | interrupts = <0 IRQ_TYPE_LEVEL_LOW>; | 28 | interrupts = <0 IRQ_TYPE_LEVEL_LOW>; |
20 | fcs,max-sink-microvolt = <12000000>; | 29 | |
21 | fcs,max-sink-microamp = <3000000>; | 30 | usb_con: connector { |
22 | fcs,max-sink-microwatt = <36000000>; | 31 | compatible = "usb-c-connector"; |
32 | label = "USB-C"; | ||
33 | power-role = "dual"; | ||
34 | try-power-role = "sink"; | ||
35 | source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>; | ||
36 | sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM) | ||
37 | PDO_VAR(3000, 12000, 3000) | ||
38 | PDO_PPS_APDO(3000, 11000, 3000)>; | ||
39 | op-sink-microwatt = <10000000>; | ||
40 | }; | ||
23 | }; | 41 | }; |
diff --git a/Documentation/devicetree/bindings/usb/renesas_usb3.txt b/Documentation/devicetree/bindings/usb/renesas_usb3.txt index 2c071bb5801e..d366555166d0 100644 --- a/Documentation/devicetree/bindings/usb/renesas_usb3.txt +++ b/Documentation/devicetree/bindings/usb/renesas_usb3.txt | |||
@@ -2,11 +2,13 @@ Renesas Electronics USB3.0 Peripheral driver | |||
2 | 2 | ||
3 | Required properties: | 3 | Required properties: |
4 | - compatible: Must contain one of the following: | 4 | - compatible: Must contain one of the following: |
5 | - "renesas,r8a774a1-usb3-peri" | ||
5 | - "renesas,r8a7795-usb3-peri" | 6 | - "renesas,r8a7795-usb3-peri" |
6 | - "renesas,r8a7796-usb3-peri" | 7 | - "renesas,r8a7796-usb3-peri" |
7 | - "renesas,r8a77965-usb3-peri" | 8 | - "renesas,r8a77965-usb3-peri" |
8 | - "renesas,rcar-gen3-usb3-peri" for a generic R-Car Gen3 compatible | 9 | - "renesas,r8a77990-usb3-peri" |
9 | device | 10 | - "renesas,rcar-gen3-usb3-peri" for a generic R-Car Gen3 or RZ/G2 |
11 | compatible device | ||
10 | 12 | ||
11 | When compatible with the generic version, nodes must list the | 13 | When compatible with the generic version, nodes must list the |
12 | SoC-specific version corresponding to the platform first | 14 | SoC-specific version corresponding to the platform first |
diff --git a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt index 43960faf5a88..90719f501852 100644 --- a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt +++ b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt | |||
@@ -4,7 +4,9 @@ Required properties: | |||
4 | - compatible: Must contain one or more of the following: | 4 | - compatible: Must contain one or more of the following: |
5 | 5 | ||
6 | - "renesas,usbhs-r8a7743" for r8a7743 (RZ/G1M) compatible device | 6 | - "renesas,usbhs-r8a7743" for r8a7743 (RZ/G1M) compatible device |
7 | - "renesas,usbhs-r8a7744" for r8a7744 (RZ/G1N) compatible device | ||
7 | - "renesas,usbhs-r8a7745" for r8a7745 (RZ/G1E) compatible device | 8 | - "renesas,usbhs-r8a7745" for r8a7745 (RZ/G1E) compatible device |
9 | - "renesas,usbhs-r8a774a1" for r8a774a1 (RZ/G2M) compatible device | ||
8 | - "renesas,usbhs-r8a7790" for r8a7790 (R-Car H2) compatible device | 10 | - "renesas,usbhs-r8a7790" for r8a7790 (R-Car H2) compatible device |
9 | - "renesas,usbhs-r8a7791" for r8a7791 (R-Car M2-W) compatible device | 11 | - "renesas,usbhs-r8a7791" for r8a7791 (R-Car M2-W) compatible device |
10 | - "renesas,usbhs-r8a7792" for r8a7792 (R-Car V2H) compatible device | 12 | - "renesas,usbhs-r8a7792" for r8a7792 (R-Car V2H) compatible device |
@@ -13,10 +15,11 @@ Required properties: | |||
13 | - "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device | 15 | - "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device |
14 | - "renesas,usbhs-r8a7796" for r8a7796 (R-Car M3-W) compatible device | 16 | - "renesas,usbhs-r8a7796" for r8a7796 (R-Car M3-W) compatible device |
15 | - "renesas,usbhs-r8a77965" for r8a77965 (R-Car M3-N) compatible device | 17 | - "renesas,usbhs-r8a77965" for r8a77965 (R-Car M3-N) compatible device |
18 | - "renesas,usbhs-r8a77990" for r8a77990 (R-Car E3) compatible device | ||
16 | - "renesas,usbhs-r8a77995" for r8a77995 (R-Car D3) compatible device | 19 | - "renesas,usbhs-r8a77995" for r8a77995 (R-Car D3) compatible device |
17 | - "renesas,usbhs-r7s72100" for r7s72100 (RZ/A1) compatible device | 20 | - "renesas,usbhs-r7s72100" for r7s72100 (RZ/A1) compatible device |
18 | - "renesas,rcar-gen2-usbhs" for R-Car Gen2 or RZ/G1 compatible devices | 21 | - "renesas,rcar-gen2-usbhs" for R-Car Gen2 or RZ/G1 compatible devices |
19 | - "renesas,rcar-gen3-usbhs" for R-Car Gen3 compatible device | 22 | - "renesas,rcar-gen3-usbhs" for R-Car Gen3 or RZ/G2 compatible devices |
20 | - "renesas,rza1-usbhs" for RZ/A1 compatible device | 23 | - "renesas,rza1-usbhs" for RZ/A1 compatible device |
21 | 24 | ||
22 | When compatible with the generic version, nodes must list the | 25 | When compatible with the generic version, nodes must list the |
@@ -25,7 +28,11 @@ Required properties: | |||
25 | 28 | ||
26 | - reg: Base address and length of the register for the USBHS | 29 | - reg: Base address and length of the register for the USBHS |
27 | - interrupts: Interrupt specifier for the USBHS | 30 | - interrupts: Interrupt specifier for the USBHS |
28 | - clocks: A list of phandle + clock specifier pairs | 31 | - clocks: A list of phandle + clock specifier pairs. |
32 | - In case of "renesas,rcar-gen3-usbhs", two clocks are required. | ||
33 | First clock should be peripheral and second one should be host. | ||
34 | - In case of except above, one clock is required. First clock | ||
35 | should be peripheral. | ||
29 | 36 | ||
30 | Optional properties: | 37 | Optional properties: |
31 | - renesas,buswait: Integer to use BUSWAIT register | 38 | - renesas,buswait: Integer to use BUSWAIT register |
diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt index 0f1b75386207..406252d14c6b 100644 --- a/Documentation/devicetree/bindings/usb/usb-ehci.txt +++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt | |||
@@ -15,7 +15,11 @@ Optional properties: | |||
15 | - needs-reset-on-resume : boolean, set this to force EHCI reset after resume | 15 | - needs-reset-on-resume : boolean, set this to force EHCI reset after resume |
16 | - has-transaction-translator : boolean, set this if EHCI have a Transaction | 16 | - has-transaction-translator : boolean, set this if EHCI have a Transaction |
17 | Translator built into the root hub. | 17 | Translator built into the root hub. |
18 | - clocks : a list of phandle + clock specifier pairs | 18 | - clocks : a list of phandle + clock specifier pairs. In case of Renesas |
19 | R-Car Gen3 SoCs: | ||
20 | - if a host only channel: first clock should be host. | ||
21 | - if a USB DRD channel: first clock should be host and second one | ||
22 | should be peripheral. | ||
19 | - phys : see usb-hcd.txt in the current directory | 23 | - phys : see usb-hcd.txt in the current directory |
20 | - resets : phandle + reset specifier pair | 24 | - resets : phandle + reset specifier pair |
21 | 25 | ||
diff --git a/Documentation/devicetree/bindings/usb/usb-ohci.txt b/Documentation/devicetree/bindings/usb/usb-ohci.txt index a8d2103d1f3d..aaaa5255c972 100644 --- a/Documentation/devicetree/bindings/usb/usb-ohci.txt +++ b/Documentation/devicetree/bindings/usb/usb-ohci.txt | |||
@@ -12,7 +12,11 @@ Optional properties: | |||
12 | - no-big-frame-no : boolean, set if frame_no lives in bits [15:0] of HCCA | 12 | - no-big-frame-no : boolean, set if frame_no lives in bits [15:0] of HCCA |
13 | - remote-wakeup-connected: remote wakeup is wired on the platform | 13 | - remote-wakeup-connected: remote wakeup is wired on the platform |
14 | - num-ports : u32, to override the detected port count | 14 | - num-ports : u32, to override the detected port count |
15 | - clocks : a list of phandle + clock specifier pairs | 15 | - clocks : a list of phandle + clock specifier pairs. In case of Renesas |
16 | R-Car Gen3 SoCs: | ||
17 | - if a host only channel: first clock should be host. | ||
18 | - if a USB DRD channel: first clock should be host and second one | ||
19 | should be peripheral. | ||
16 | - phys : see usb-hcd.txt in the current directory | 20 | - phys : see usb-hcd.txt in the current directory |
17 | - resets : a list of phandle + reset specifier pairs | 21 | - resets : a list of phandle + reset specifier pairs |
18 | 22 | ||
diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt index ac4cd0d6195a..fea8b1545751 100644 --- a/Documentation/devicetree/bindings/usb/usb-xhci.txt +++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt | |||
@@ -8,6 +8,8 @@ Required properties: | |||
8 | - "marvell,armada-375-xhci" for Armada 375 SoCs | 8 | - "marvell,armada-375-xhci" for Armada 375 SoCs |
9 | - "marvell,armada-380-xhci" for Armada 38x SoCs | 9 | - "marvell,armada-380-xhci" for Armada 38x SoCs |
10 | - "renesas,xhci-r8a7743" for r8a7743 SoC | 10 | - "renesas,xhci-r8a7743" for r8a7743 SoC |
11 | - "renesas,xhci-r8a7744" for r8a7744 SoC | ||
12 | - "renesas,xhci-r8a774a1" for r8a774a1 SoC | ||
11 | - "renesas,xhci-r8a7790" for r8a7790 SoC | 13 | - "renesas,xhci-r8a7790" for r8a7790 SoC |
12 | - "renesas,xhci-r8a7791" for r8a7791 SoC | 14 | - "renesas,xhci-r8a7791" for r8a7791 SoC |
13 | - "renesas,xhci-r8a7793" for r8a7793 SoC | 15 | - "renesas,xhci-r8a7793" for r8a7793 SoC |
@@ -17,7 +19,8 @@ Required properties: | |||
17 | - "renesas,xhci-r8a77990" for r8a77990 SoC | 19 | - "renesas,xhci-r8a77990" for r8a77990 SoC |
18 | - "renesas,rcar-gen2-xhci" for a generic R-Car Gen2 or RZ/G1 compatible | 20 | - "renesas,rcar-gen2-xhci" for a generic R-Car Gen2 or RZ/G1 compatible |
19 | device | 21 | device |
20 | - "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 compatible device | 22 | - "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 or RZ/G2 compatible |
23 | device | ||
21 | - "xhci-platform" (deprecated) | 24 | - "xhci-platform" (deprecated) |
22 | 25 | ||
23 | When compatible with the generic version, nodes must list the | 26 | When compatible with the generic version, nodes must list the |
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 13a7c999c04a..d05d93761653 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt | |||
@@ -201,7 +201,7 @@ Code Seq#(hex) Include File Comments | |||
201 | 'X' 01 linux/pktcdvd.h conflict! | 201 | 'X' 01 linux/pktcdvd.h conflict! |
202 | 'Y' all linux/cyclades.h | 202 | 'Y' all linux/cyclades.h |
203 | 'Z' 14-15 drivers/message/fusion/mptctl.h | 203 | 'Z' 14-15 drivers/message/fusion/mptctl.h |
204 | '[' 00-07 linux/usb/tmc.h USB Test and Measurement Devices | 204 | '[' 00-3F linux/usb/tmc.h USB Test and Measurement Devices |
205 | <mailto:gregkh@linuxfoundation.org> | 205 | <mailto:gregkh@linuxfoundation.org> |
206 | 'a' all linux/atm*.h, linux/sonet.h ATM on linux | 206 | 'a' all linux/atm*.h, linux/sonet.h ATM on linux |
207 | <http://lrcwww.epfl.ch/> | 207 | <http://lrcwww.epfl.ch/> |
diff --git a/MAINTAINERS b/MAINTAINERS index bd702ad56c7f..554941e05171 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -15443,6 +15443,12 @@ F: Documentation/driver-api/usb/typec_bus.rst | |||
15443 | F: drivers/usb/typec/altmodes/ | 15443 | F: drivers/usb/typec/altmodes/ |
15444 | F: include/linux/usb/typec_altmode.h | 15444 | F: include/linux/usb/typec_altmode.h |
15445 | 15445 | ||
15446 | USB TYPEC PORT CONTROLLER DRIVERS | ||
15447 | M: Guenter Roeck <linux@roeck-us.net> | ||
15448 | L: linux-usb@vger.kernel.org | ||
15449 | S: Maintained | ||
15450 | F: drivers/usb/typec/tcpm/ | ||
15451 | |||
15446 | USB UHCI DRIVER | 15452 | USB UHCI DRIVER |
15447 | M: Alan Stern <stern@rowland.harvard.edu> | 15453 | M: Alan Stern <stern@rowland.harvard.edu> |
15448 | L: linux-usb@vger.kernel.org | 15454 | L: linux-usb@vger.kernel.org |
diff --git a/arch/arm/mach-mmp/devices.c b/arch/arm/mach-mmp/devices.c index 671c7a09ab3d..0fca63c80e1a 100644 --- a/arch/arm/mach-mmp/devices.c +++ b/arch/arm/mach-mmp/devices.c | |||
@@ -277,21 +277,12 @@ struct platform_device pxa168_device_u2o = { | |||
277 | 277 | ||
278 | #if IS_ENABLED(CONFIG_USB_EHCI_MV_U2O) | 278 | #if IS_ENABLED(CONFIG_USB_EHCI_MV_U2O) |
279 | struct resource pxa168_u2oehci_resources[] = { | 279 | struct resource pxa168_u2oehci_resources[] = { |
280 | /* regbase */ | ||
281 | [0] = { | 280 | [0] = { |
282 | .start = PXA168_U2O_REGBASE + U2x_CAPREGS_OFFSET, | 281 | .start = PXA168_U2O_REGBASE, |
283 | .end = PXA168_U2O_REGBASE + USB_REG_RANGE, | 282 | .end = PXA168_U2O_REGBASE + USB_REG_RANGE, |
284 | .flags = IORESOURCE_MEM, | 283 | .flags = IORESOURCE_MEM, |
285 | .name = "capregs", | ||
286 | }, | 284 | }, |
287 | /* phybase */ | ||
288 | [1] = { | 285 | [1] = { |
289 | .start = PXA168_U2O_PHYBASE, | ||
290 | .end = PXA168_U2O_PHYBASE + USB_PHY_RANGE, | ||
291 | .flags = IORESOURCE_MEM, | ||
292 | .name = "phyregs", | ||
293 | }, | ||
294 | [2] = { | ||
295 | .start = IRQ_PXA168_USB1, | 286 | .start = IRQ_PXA168_USB1, |
296 | .end = IRQ_PXA168_USB1, | 287 | .end = IRQ_PXA168_USB1, |
297 | .flags = IORESOURCE_IRQ, | 288 | .flags = IORESOURCE_IRQ, |
diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 8e799ae1df69..67481fc82445 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c | |||
@@ -116,6 +116,7 @@ static void em28xx_audio_isocirq(struct urb *urb) | |||
116 | stride = runtime->frame_bits >> 3; | 116 | stride = runtime->frame_bits >> 3; |
117 | 117 | ||
118 | for (i = 0; i < urb->number_of_packets; i++) { | 118 | for (i = 0; i < urb->number_of_packets; i++) { |
119 | unsigned long flags; | ||
119 | int length = | 120 | int length = |
120 | urb->iso_frame_desc[i].actual_length / stride; | 121 | urb->iso_frame_desc[i].actual_length / stride; |
121 | cp = (unsigned char *)urb->transfer_buffer + | 122 | cp = (unsigned char *)urb->transfer_buffer + |
@@ -137,7 +138,7 @@ static void em28xx_audio_isocirq(struct urb *urb) | |||
137 | length * stride); | 138 | length * stride); |
138 | } | 139 | } |
139 | 140 | ||
140 | snd_pcm_stream_lock(substream); | 141 | snd_pcm_stream_lock_irqsave(substream, flags); |
141 | 142 | ||
142 | dev->adev.hwptr_done_capture += length; | 143 | dev->adev.hwptr_done_capture += length; |
143 | if (dev->adev.hwptr_done_capture >= | 144 | if (dev->adev.hwptr_done_capture >= |
@@ -153,7 +154,7 @@ static void em28xx_audio_isocirq(struct urb *urb) | |||
153 | period_elapsed = 1; | 154 | period_elapsed = 1; |
154 | } | 155 | } |
155 | 156 | ||
156 | snd_pcm_stream_unlock(substream); | 157 | snd_pcm_stream_unlock_irqrestore(substream, flags); |
157 | } | 158 | } |
158 | if (period_elapsed) | 159 | if (period_elapsed) |
159 | snd_pcm_period_elapsed(substream); | 160 | snd_pcm_period_elapsed(substream); |
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 5657f8710ca6..2b8c84a5c9a8 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c | |||
@@ -777,6 +777,7 @@ EXPORT_SYMBOL_GPL(em28xx_set_mode); | |||
777 | static void em28xx_irq_callback(struct urb *urb) | 777 | static void em28xx_irq_callback(struct urb *urb) |
778 | { | 778 | { |
779 | struct em28xx *dev = urb->context; | 779 | struct em28xx *dev = urb->context; |
780 | unsigned long flags; | ||
780 | int i; | 781 | int i; |
781 | 782 | ||
782 | switch (urb->status) { | 783 | switch (urb->status) { |
@@ -793,9 +794,9 @@ static void em28xx_irq_callback(struct urb *urb) | |||
793 | } | 794 | } |
794 | 795 | ||
795 | /* Copy data from URB */ | 796 | /* Copy data from URB */ |
796 | spin_lock(&dev->slock); | 797 | spin_lock_irqsave(&dev->slock, flags); |
797 | dev->usb_ctl.urb_data_copy(dev, urb); | 798 | dev->usb_ctl.urb_data_copy(dev, urb); |
798 | spin_unlock(&dev->slock); | 799 | spin_unlock_irqrestore(&dev->slock, flags); |
799 | 800 | ||
800 | /* Reset urb buffers */ | 801 | /* Reset urb buffers */ |
801 | for (i = 0; i < urb->number_of_packets; i++) { | 802 | for (i = 0; i < urb->number_of_packets; i++) { |
diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index 96055de6e8ce..7d268f2404e1 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c | |||
@@ -419,6 +419,7 @@ static void tm6000_irq_callback(struct urb *urb) | |||
419 | { | 419 | { |
420 | struct tm6000_dmaqueue *dma_q = urb->context; | 420 | struct tm6000_dmaqueue *dma_q = urb->context; |
421 | struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); | 421 | struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); |
422 | unsigned long flags; | ||
422 | int i; | 423 | int i; |
423 | 424 | ||
424 | switch (urb->status) { | 425 | switch (urb->status) { |
@@ -436,9 +437,9 @@ static void tm6000_irq_callback(struct urb *urb) | |||
436 | break; | 437 | break; |
437 | } | 438 | } |
438 | 439 | ||
439 | spin_lock(&dev->slock); | 440 | spin_lock_irqsave(&dev->slock, flags); |
440 | tm6000_isoc_copy(urb); | 441 | tm6000_isoc_copy(urb); |
441 | spin_unlock(&dev->slock); | 442 | spin_unlock_irqrestore(&dev->slock, flags); |
442 | 443 | ||
443 | /* Reset urb buffers */ | 444 | /* Reset urb buffers */ |
444 | for (i = 0; i < urb->number_of_packets; i++) { | 445 | for (i = 0; i < urb->number_of_packets; i++) { |
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index c89d3effd99d..60f949e2a684 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig | |||
@@ -43,6 +43,7 @@ config PHY_XGENE | |||
43 | source "drivers/phy/allwinner/Kconfig" | 43 | source "drivers/phy/allwinner/Kconfig" |
44 | source "drivers/phy/amlogic/Kconfig" | 44 | source "drivers/phy/amlogic/Kconfig" |
45 | source "drivers/phy/broadcom/Kconfig" | 45 | source "drivers/phy/broadcom/Kconfig" |
46 | source "drivers/phy/cadence/Kconfig" | ||
46 | source "drivers/phy/hisilicon/Kconfig" | 47 | source "drivers/phy/hisilicon/Kconfig" |
47 | source "drivers/phy/lantiq/Kconfig" | 48 | source "drivers/phy/lantiq/Kconfig" |
48 | source "drivers/phy/marvell/Kconfig" | 49 | source "drivers/phy/marvell/Kconfig" |
@@ -54,6 +55,7 @@ source "drivers/phy/ralink/Kconfig" | |||
54 | source "drivers/phy/renesas/Kconfig" | 55 | source "drivers/phy/renesas/Kconfig" |
55 | source "drivers/phy/rockchip/Kconfig" | 56 | source "drivers/phy/rockchip/Kconfig" |
56 | source "drivers/phy/samsung/Kconfig" | 57 | source "drivers/phy/samsung/Kconfig" |
58 | source "drivers/phy/socionext/Kconfig" | ||
57 | source "drivers/phy/st/Kconfig" | 59 | source "drivers/phy/st/Kconfig" |
58 | source "drivers/phy/tegra/Kconfig" | 60 | source "drivers/phy/tegra/Kconfig" |
59 | source "drivers/phy/ti/Kconfig" | 61 | source "drivers/phy/ti/Kconfig" |
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index ce8339ff0022..0301e25d07c1 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile | |||
@@ -15,6 +15,7 @@ obj-$(CONFIG_ARCH_RENESAS) += renesas/ | |||
15 | obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ | 15 | obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ |
16 | obj-$(CONFIG_ARCH_TEGRA) += tegra/ | 16 | obj-$(CONFIG_ARCH_TEGRA) += tegra/ |
17 | obj-y += broadcom/ \ | 17 | obj-y += broadcom/ \ |
18 | cadence/ \ | ||
18 | hisilicon/ \ | 19 | hisilicon/ \ |
19 | marvell/ \ | 20 | marvell/ \ |
20 | motorola/ \ | 21 | motorola/ \ |
@@ -22,5 +23,6 @@ obj-y += broadcom/ \ | |||
22 | qualcomm/ \ | 23 | qualcomm/ \ |
23 | ralink/ \ | 24 | ralink/ \ |
24 | samsung/ \ | 25 | samsung/ \ |
26 | socionext/ \ | ||
25 | st/ \ | 27 | st/ \ |
26 | ti/ | 28 | ti/ |
diff --git a/drivers/phy/broadcom/Kconfig b/drivers/phy/broadcom/Kconfig index 8786a9674471..aa917a61071d 100644 --- a/drivers/phy/broadcom/Kconfig +++ b/drivers/phy/broadcom/Kconfig | |||
@@ -60,7 +60,8 @@ config PHY_NS2_USB_DRD | |||
60 | 60 | ||
61 | config PHY_BRCM_SATA | 61 | config PHY_BRCM_SATA |
62 | tristate "Broadcom SATA PHY driver" | 62 | tristate "Broadcom SATA PHY driver" |
63 | depends on ARCH_BRCMSTB || ARCH_BCM_IPROC || BMIPS_GENERIC || COMPILE_TEST | 63 | depends on ARCH_BRCMSTB || ARCH_BCM_IPROC || BMIPS_GENERIC || \ |
64 | ARCH_BCM_63XX || COMPILE_TEST | ||
64 | depends on OF | 65 | depends on OF |
65 | select GENERIC_PHY | 66 | select GENERIC_PHY |
66 | default ARCH_BCM_IPROC | 67 | default ARCH_BCM_IPROC |
diff --git a/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c b/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c index 0f4ac5d63cff..b074682d9dd8 100644 --- a/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c +++ b/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c | |||
@@ -153,8 +153,8 @@ static int cygnus_pcie_phy_probe(struct platform_device *pdev) | |||
153 | struct cygnus_pcie_phy *p; | 153 | struct cygnus_pcie_phy *p; |
154 | 154 | ||
155 | if (of_property_read_u32(child, "reg", &id)) { | 155 | if (of_property_read_u32(child, "reg", &id)) { |
156 | dev_err(dev, "missing reg property for %s\n", | 156 | dev_err(dev, "missing reg property for %pOFn\n", |
157 | child->name); | 157 | child); |
158 | ret = -EINVAL; | 158 | ret = -EINVAL; |
159 | goto put_child; | 159 | goto put_child; |
160 | } | 160 | } |
diff --git a/drivers/phy/broadcom/phy-brcm-sata.c b/drivers/phy/broadcom/phy-brcm-sata.c index 8708ea3b4d6d..0f4a06ff7fd3 100644 --- a/drivers/phy/broadcom/phy-brcm-sata.c +++ b/drivers/phy/broadcom/phy-brcm-sata.c | |||
@@ -47,6 +47,7 @@ enum brcm_sata_phy_version { | |||
47 | BRCM_SATA_PHY_IPROC_NS2, | 47 | BRCM_SATA_PHY_IPROC_NS2, |
48 | BRCM_SATA_PHY_IPROC_NSP, | 48 | BRCM_SATA_PHY_IPROC_NSP, |
49 | BRCM_SATA_PHY_IPROC_SR, | 49 | BRCM_SATA_PHY_IPROC_SR, |
50 | BRCM_SATA_PHY_DSL_28NM, | ||
50 | }; | 51 | }; |
51 | 52 | ||
52 | enum brcm_sata_phy_rxaeq_mode { | 53 | enum brcm_sata_phy_rxaeq_mode { |
@@ -96,7 +97,10 @@ enum sata_phy_regs { | |||
96 | PLLCONTROL_0_FREQ_DET_RESTART = BIT(13), | 97 | PLLCONTROL_0_FREQ_DET_RESTART = BIT(13), |
97 | PLLCONTROL_0_FREQ_MONITOR = BIT(12), | 98 | PLLCONTROL_0_FREQ_MONITOR = BIT(12), |
98 | PLLCONTROL_0_SEQ_START = BIT(15), | 99 | PLLCONTROL_0_SEQ_START = BIT(15), |
100 | PLL_CAP_CHARGE_TIME = 0x83, | ||
101 | PLL_VCO_CAL_THRESH = 0x84, | ||
99 | PLL_CAP_CONTROL = 0x85, | 102 | PLL_CAP_CONTROL = 0x85, |
103 | PLL_FREQ_DET_TIME = 0x86, | ||
100 | PLL_ACTRL2 = 0x8b, | 104 | PLL_ACTRL2 = 0x8b, |
101 | PLL_ACTRL2_SELDIV_MASK = 0x1f, | 105 | PLL_ACTRL2_SELDIV_MASK = 0x1f, |
102 | PLL_ACTRL2_SELDIV_SHIFT = 9, | 106 | PLL_ACTRL2_SELDIV_SHIFT = 9, |
@@ -106,6 +110,9 @@ enum sata_phy_regs { | |||
106 | PLL1_ACTRL2 = 0x82, | 110 | PLL1_ACTRL2 = 0x82, |
107 | PLL1_ACTRL3 = 0x83, | 111 | PLL1_ACTRL3 = 0x83, |
108 | PLL1_ACTRL4 = 0x84, | 112 | PLL1_ACTRL4 = 0x84, |
113 | PLL1_ACTRL5 = 0x85, | ||
114 | PLL1_ACTRL6 = 0x86, | ||
115 | PLL1_ACTRL7 = 0x87, | ||
109 | 116 | ||
110 | TX_REG_BANK = 0x070, | 117 | TX_REG_BANK = 0x070, |
111 | TX_ACTRL0 = 0x80, | 118 | TX_ACTRL0 = 0x80, |
@@ -119,6 +126,8 @@ enum sata_phy_regs { | |||
119 | AEQ_FRC_EQ_FORCE = BIT(0), | 126 | AEQ_FRC_EQ_FORCE = BIT(0), |
120 | AEQ_FRC_EQ_FORCE_VAL = BIT(1), | 127 | AEQ_FRC_EQ_FORCE_VAL = BIT(1), |
121 | AEQRX_REG_BANK_1 = 0xe0, | 128 | AEQRX_REG_BANK_1 = 0xe0, |
129 | AEQRX_SLCAL0_CTRL0 = 0x82, | ||
130 | AEQRX_SLCAL1_CTRL0 = 0x86, | ||
122 | 131 | ||
123 | OOB_REG_BANK = 0x150, | 132 | OOB_REG_BANK = 0x150, |
124 | OOB1_REG_BANK = 0x160, | 133 | OOB1_REG_BANK = 0x160, |
@@ -168,6 +177,7 @@ static inline void __iomem *brcm_sata_pcb_base(struct brcm_sata_port *port) | |||
168 | switch (priv->version) { | 177 | switch (priv->version) { |
169 | case BRCM_SATA_PHY_STB_28NM: | 178 | case BRCM_SATA_PHY_STB_28NM: |
170 | case BRCM_SATA_PHY_IPROC_NS2: | 179 | case BRCM_SATA_PHY_IPROC_NS2: |
180 | case BRCM_SATA_PHY_DSL_28NM: | ||
171 | size = SATA_PCB_REG_28NM_SPACE_SIZE; | 181 | size = SATA_PCB_REG_28NM_SPACE_SIZE; |
172 | break; | 182 | break; |
173 | case BRCM_SATA_PHY_STB_40NM: | 183 | case BRCM_SATA_PHY_STB_40NM: |
@@ -482,6 +492,61 @@ static int brcm_sr_sata_init(struct brcm_sata_port *port) | |||
482 | return 0; | 492 | return 0; |
483 | } | 493 | } |
484 | 494 | ||
495 | static int brcm_dsl_sata_init(struct brcm_sata_port *port) | ||
496 | { | ||
497 | void __iomem *base = brcm_sata_pcb_base(port); | ||
498 | struct device *dev = port->phy_priv->dev; | ||
499 | unsigned int try; | ||
500 | u32 tmp; | ||
501 | |||
502 | brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL7, 0, 0x873); | ||
503 | |||
504 | brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL6, 0, 0xc000); | ||
505 | |||
506 | brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0, | ||
507 | 0, 0x3089); | ||
508 | usleep_range(1000, 2000); | ||
509 | |||
510 | brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0, | ||
511 | 0, 0x3088); | ||
512 | usleep_range(1000, 2000); | ||
513 | |||
514 | brcm_sata_phy_wr(base, AEQRX_REG_BANK_1, AEQRX_SLCAL0_CTRL0, | ||
515 | 0, 0x3000); | ||
516 | |||
517 | brcm_sata_phy_wr(base, AEQRX_REG_BANK_1, AEQRX_SLCAL1_CTRL0, | ||
518 | 0, 0x3000); | ||
519 | usleep_range(1000, 2000); | ||
520 | |||
521 | brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_CAP_CHARGE_TIME, 0, 0x32); | ||
522 | |||
523 | brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_VCO_CAL_THRESH, 0, 0xa); | ||
524 | |||
525 | brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_FREQ_DET_TIME, 0, 0x64); | ||
526 | usleep_range(1000, 2000); | ||
527 | |||
528 | /* Acquire PLL lock */ | ||
529 | try = 50; | ||
530 | while (try) { | ||
531 | tmp = brcm_sata_phy_rd(base, BLOCK0_REG_BANK, | ||
532 | BLOCK0_XGXSSTATUS); | ||
533 | if (tmp & BLOCK0_XGXSSTATUS_PLL_LOCK) | ||
534 | break; | ||
535 | msleep(20); | ||
536 | try--; | ||
537 | }; | ||
538 | |||
539 | if (!try) { | ||
540 | /* PLL did not lock; give up */ | ||
541 | dev_err(dev, "port%d PLL did not lock\n", port->portnum); | ||
542 | return -ETIMEDOUT; | ||
543 | } | ||
544 | |||
545 | dev_dbg(dev, "port%d initialized\n", port->portnum); | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | |||
485 | static int brcm_sata_phy_init(struct phy *phy) | 550 | static int brcm_sata_phy_init(struct phy *phy) |
486 | { | 551 | { |
487 | int rc; | 552 | int rc; |
@@ -501,6 +566,9 @@ static int brcm_sata_phy_init(struct phy *phy) | |||
501 | case BRCM_SATA_PHY_IPROC_SR: | 566 | case BRCM_SATA_PHY_IPROC_SR: |
502 | rc = brcm_sr_sata_init(port); | 567 | rc = brcm_sr_sata_init(port); |
503 | break; | 568 | break; |
569 | case BRCM_SATA_PHY_DSL_28NM: | ||
570 | rc = brcm_dsl_sata_init(port); | ||
571 | break; | ||
504 | default: | 572 | default: |
505 | rc = -ENODEV; | 573 | rc = -ENODEV; |
506 | } | 574 | } |
@@ -552,6 +620,8 @@ static const struct of_device_id brcm_sata_phy_of_match[] = { | |||
552 | .data = (void *)BRCM_SATA_PHY_IPROC_NSP }, | 620 | .data = (void *)BRCM_SATA_PHY_IPROC_NSP }, |
553 | { .compatible = "brcm,iproc-sr-sata-phy", | 621 | { .compatible = "brcm,iproc-sr-sata-phy", |
554 | .data = (void *)BRCM_SATA_PHY_IPROC_SR }, | 622 | .data = (void *)BRCM_SATA_PHY_IPROC_SR }, |
623 | { .compatible = "brcm,bcm63138-sata-phy", | ||
624 | .data = (void *)BRCM_SATA_PHY_DSL_28NM }, | ||
555 | {}, | 625 | {}, |
556 | }; | 626 | }; |
557 | MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match); | 627 | MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match); |
@@ -600,8 +670,8 @@ static int brcm_sata_phy_probe(struct platform_device *pdev) | |||
600 | struct brcm_sata_port *port; | 670 | struct brcm_sata_port *port; |
601 | 671 | ||
602 | if (of_property_read_u32(child, "reg", &id)) { | 672 | if (of_property_read_u32(child, "reg", &id)) { |
603 | dev_err(dev, "missing reg property in node %s\n", | 673 | dev_err(dev, "missing reg property in node %pOFn\n", |
604 | child->name); | 674 | child); |
605 | ret = -EINVAL; | 675 | ret = -EINVAL; |
606 | goto put_child; | 676 | goto put_child; |
607 | } | 677 | } |
diff --git a/drivers/phy/broadcom/phy-brcm-usb.c b/drivers/phy/broadcom/phy-brcm-usb.c index d1dab36fa5b7..f59b1dc30399 100644 --- a/drivers/phy/broadcom/phy-brcm-usb.c +++ b/drivers/phy/broadcom/phy-brcm-usb.c | |||
@@ -372,10 +372,8 @@ static int brcm_usb_phy_probe(struct platform_device *pdev) | |||
372 | clk_disable(priv->usb_30_clk); | 372 | clk_disable(priv->usb_30_clk); |
373 | 373 | ||
374 | phy_provider = devm_of_phy_provider_register(dev, brcm_usb_phy_xlate); | 374 | phy_provider = devm_of_phy_provider_register(dev, brcm_usb_phy_xlate); |
375 | if (IS_ERR(phy_provider)) | ||
376 | return PTR_ERR(phy_provider); | ||
377 | 375 | ||
378 | return 0; | 376 | return PTR_ERR_OR_ZERO(phy_provider); |
379 | } | 377 | } |
380 | 378 | ||
381 | #ifdef CONFIG_PM_SLEEP | 379 | #ifdef CONFIG_PM_SLEEP |
diff --git a/drivers/phy/cadence/Kconfig b/drivers/phy/cadence/Kconfig new file mode 100644 index 000000000000..57fff7de4031 --- /dev/null +++ b/drivers/phy/cadence/Kconfig | |||
@@ -0,0 +1,10 @@ | |||
1 | # | ||
2 | # Phy driver for Cadence MHDP DisplayPort controller | ||
3 | # | ||
4 | config PHY_CADENCE_DP | ||
5 | tristate "Cadence MHDP DisplayPort PHY driver" | ||
6 | depends on OF | ||
7 | depends on HAS_IOMEM | ||
8 | select GENERIC_PHY | ||
9 | help | ||
10 | Support for Cadence MHDP DisplayPort PHY. | ||
diff --git a/drivers/phy/cadence/Makefile b/drivers/phy/cadence/Makefile new file mode 100644 index 000000000000..e5b0a11cf28a --- /dev/null +++ b/drivers/phy/cadence/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_PHY_CADENCE_DP) += phy-cadence-dp.o | |||
diff --git a/drivers/phy/cadence/phy-cadence-dp.c b/drivers/phy/cadence/phy-cadence-dp.c new file mode 100644 index 000000000000..bc10cb264b7a --- /dev/null +++ b/drivers/phy/cadence/phy-cadence-dp.c | |||
@@ -0,0 +1,541 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * Cadence MHDP DisplayPort SD0801 PHY driver. | ||
4 | * | ||
5 | * Copyright 2018 Cadence Design Systems, Inc. | ||
6 | * | ||
7 | */ | ||
8 | |||
9 | #include <linux/delay.h> | ||
10 | #include <linux/err.h> | ||
11 | #include <linux/io.h> | ||
12 | #include <linux/iopoll.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/of.h> | ||
16 | #include <linux/of_address.h> | ||
17 | #include <linux/of_device.h> | ||
18 | #include <linux/phy/phy.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | |||
21 | #define DEFAULT_NUM_LANES 2 | ||
22 | #define MAX_NUM_LANES 4 | ||
23 | #define DEFAULT_MAX_BIT_RATE 8100 /* in Mbps */ | ||
24 | |||
25 | #define POLL_TIMEOUT_US 2000 | ||
26 | #define LANE_MASK 0x7 | ||
27 | |||
28 | /* | ||
29 | * register offsets from DPTX PHY register block base (i.e MHDP | ||
30 | * register base + 0x30a00) | ||
31 | */ | ||
32 | #define PHY_AUX_CONFIG 0x00 | ||
33 | #define PHY_AUX_CTRL 0x04 | ||
34 | #define PHY_RESET 0x20 | ||
35 | #define PHY_PMA_XCVR_PLLCLK_EN 0x24 | ||
36 | #define PHY_PMA_XCVR_PLLCLK_EN_ACK 0x28 | ||
37 | #define PHY_PMA_XCVR_POWER_STATE_REQ 0x2c | ||
38 | #define PHY_POWER_STATE_LN_0 0x0000 | ||
39 | #define PHY_POWER_STATE_LN_1 0x0008 | ||
40 | #define PHY_POWER_STATE_LN_2 0x0010 | ||
41 | #define PHY_POWER_STATE_LN_3 0x0018 | ||
42 | #define PHY_PMA_XCVR_POWER_STATE_ACK 0x30 | ||
43 | #define PHY_PMA_CMN_READY 0x34 | ||
44 | #define PHY_PMA_XCVR_TX_VMARGIN 0x38 | ||
45 | #define PHY_PMA_XCVR_TX_DEEMPH 0x3c | ||
46 | |||
47 | /* | ||
48 | * register offsets from SD0801 PHY register block base (i.e MHDP | ||
49 | * register base + 0x500000) | ||
50 | */ | ||
51 | #define CMN_SSM_BANDGAP_TMR 0x00084 | ||
52 | #define CMN_SSM_BIAS_TMR 0x00088 | ||
53 | #define CMN_PLLSM0_PLLPRE_TMR 0x000a8 | ||
54 | #define CMN_PLLSM0_PLLLOCK_TMR 0x000b0 | ||
55 | #define CMN_PLLSM1_PLLPRE_TMR 0x000c8 | ||
56 | #define CMN_PLLSM1_PLLLOCK_TMR 0x000d0 | ||
57 | #define CMN_BGCAL_INIT_TMR 0x00190 | ||
58 | #define CMN_BGCAL_ITER_TMR 0x00194 | ||
59 | #define CMN_IBCAL_INIT_TMR 0x001d0 | ||
60 | #define CMN_PLL0_VCOCAL_INIT_TMR 0x00210 | ||
61 | #define CMN_PLL0_VCOCAL_ITER_TMR 0x00214 | ||
62 | #define CMN_PLL0_VCOCAL_REFTIM_START 0x00218 | ||
63 | #define CMN_PLL0_VCOCAL_PLLCNT_START 0x00220 | ||
64 | #define CMN_PLL0_INTDIV_M0 0x00240 | ||
65 | #define CMN_PLL0_FRACDIVL_M0 0x00244 | ||
66 | #define CMN_PLL0_FRACDIVH_M0 0x00248 | ||
67 | #define CMN_PLL0_HIGH_THR_M0 0x0024c | ||
68 | #define CMN_PLL0_DSM_DIAG_M0 0x00250 | ||
69 | #define CMN_PLL0_LOCK_PLLCNT_START 0x00278 | ||
70 | #define CMN_PLL1_VCOCAL_INIT_TMR 0x00310 | ||
71 | #define CMN_PLL1_VCOCAL_ITER_TMR 0x00314 | ||
72 | #define CMN_PLL1_DSM_DIAG_M0 0x00350 | ||
73 | #define CMN_TXPUCAL_INIT_TMR 0x00410 | ||
74 | #define CMN_TXPUCAL_ITER_TMR 0x00414 | ||
75 | #define CMN_TXPDCAL_INIT_TMR 0x00430 | ||
76 | #define CMN_TXPDCAL_ITER_TMR 0x00434 | ||
77 | #define CMN_RXCAL_INIT_TMR 0x00450 | ||
78 | #define CMN_RXCAL_ITER_TMR 0x00454 | ||
79 | #define CMN_SD_CAL_INIT_TMR 0x00490 | ||
80 | #define CMN_SD_CAL_ITER_TMR 0x00494 | ||
81 | #define CMN_SD_CAL_REFTIM_START 0x00498 | ||
82 | #define CMN_SD_CAL_PLLCNT_START 0x004a0 | ||
83 | #define CMN_PDIAG_PLL0_CTRL_M0 0x00680 | ||
84 | #define CMN_PDIAG_PLL0_CLK_SEL_M0 0x00684 | ||
85 | #define CMN_PDIAG_PLL0_CP_PADJ_M0 0x00690 | ||
86 | #define CMN_PDIAG_PLL0_CP_IADJ_M0 0x00694 | ||
87 | #define CMN_PDIAG_PLL0_FILT_PADJ_M0 0x00698 | ||
88 | #define CMN_PDIAG_PLL0_CP_PADJ_M1 0x006d0 | ||
89 | #define CMN_PDIAG_PLL0_CP_IADJ_M1 0x006d4 | ||
90 | #define CMN_PDIAG_PLL1_CLK_SEL_M0 0x00704 | ||
91 | #define XCVR_DIAG_PLLDRC_CTRL 0x10394 | ||
92 | #define XCVR_DIAG_HSCLK_SEL 0x10398 | ||
93 | #define XCVR_DIAG_HSCLK_DIV 0x1039c | ||
94 | #define TX_PSC_A0 0x10400 | ||
95 | #define TX_PSC_A1 0x10404 | ||
96 | #define TX_PSC_A2 0x10408 | ||
97 | #define TX_PSC_A3 0x1040c | ||
98 | #define RX_PSC_A0 0x20000 | ||
99 | #define RX_PSC_A1 0x20004 | ||
100 | #define RX_PSC_A2 0x20008 | ||
101 | #define RX_PSC_A3 0x2000c | ||
102 | #define PHY_PLL_CFG 0x30038 | ||
103 | |||
104 | struct cdns_dp_phy { | ||
105 | void __iomem *base; /* DPTX registers base */ | ||
106 | void __iomem *sd_base; /* SD0801 registers base */ | ||
107 | u32 num_lanes; /* Number of lanes to use */ | ||
108 | u32 max_bit_rate; /* Maximum link bit rate to use (in Mbps) */ | ||
109 | struct device *dev; | ||
110 | }; | ||
111 | |||
112 | static int cdns_dp_phy_init(struct phy *phy); | ||
113 | static void cdns_dp_phy_run(struct cdns_dp_phy *cdns_phy); | ||
114 | static void cdns_dp_phy_wait_pma_cmn_ready(struct cdns_dp_phy *cdns_phy); | ||
115 | static void cdns_dp_phy_pma_cfg(struct cdns_dp_phy *cdns_phy); | ||
116 | static void cdns_dp_phy_pma_cmn_cfg_25mhz(struct cdns_dp_phy *cdns_phy); | ||
117 | static void cdns_dp_phy_pma_lane_cfg(struct cdns_dp_phy *cdns_phy, | ||
118 | unsigned int lane); | ||
119 | static void cdns_dp_phy_pma_cmn_vco_cfg_25mhz(struct cdns_dp_phy *cdns_phy); | ||
120 | static void cdns_dp_phy_pma_cmn_rate(struct cdns_dp_phy *cdns_phy); | ||
121 | static void cdns_dp_phy_write_field(struct cdns_dp_phy *cdns_phy, | ||
122 | unsigned int offset, | ||
123 | unsigned char start_bit, | ||
124 | unsigned char num_bits, | ||
125 | unsigned int val); | ||
126 | |||
127 | static const struct phy_ops cdns_dp_phy_ops = { | ||
128 | .init = cdns_dp_phy_init, | ||
129 | .owner = THIS_MODULE, | ||
130 | }; | ||
131 | |||
132 | static int cdns_dp_phy_init(struct phy *phy) | ||
133 | { | ||
134 | unsigned char lane_bits; | ||
135 | |||
136 | struct cdns_dp_phy *cdns_phy = phy_get_drvdata(phy); | ||
137 | |||
138 | writel(0x0003, cdns_phy->base + PHY_AUX_CTRL); /* enable AUX */ | ||
139 | |||
140 | /* PHY PMA registers configuration function */ | ||
141 | cdns_dp_phy_pma_cfg(cdns_phy); | ||
142 | |||
143 | /* | ||
144 | * Set lines power state to A0 | ||
145 | * Set lines pll clk enable to 0 | ||
146 | */ | ||
147 | |||
148 | cdns_dp_phy_write_field(cdns_phy, PHY_PMA_XCVR_POWER_STATE_REQ, | ||
149 | PHY_POWER_STATE_LN_0, 6, 0x0000); | ||
150 | |||
151 | if (cdns_phy->num_lanes >= 2) { | ||
152 | cdns_dp_phy_write_field(cdns_phy, | ||
153 | PHY_PMA_XCVR_POWER_STATE_REQ, | ||
154 | PHY_POWER_STATE_LN_1, 6, 0x0000); | ||
155 | |||
156 | if (cdns_phy->num_lanes == 4) { | ||
157 | cdns_dp_phy_write_field(cdns_phy, | ||
158 | PHY_PMA_XCVR_POWER_STATE_REQ, | ||
159 | PHY_POWER_STATE_LN_2, 6, 0); | ||
160 | cdns_dp_phy_write_field(cdns_phy, | ||
161 | PHY_PMA_XCVR_POWER_STATE_REQ, | ||
162 | PHY_POWER_STATE_LN_3, 6, 0); | ||
163 | } | ||
164 | } | ||
165 | |||
166 | cdns_dp_phy_write_field(cdns_phy, PHY_PMA_XCVR_PLLCLK_EN, | ||
167 | 0, 1, 0x0000); | ||
168 | |||
169 | if (cdns_phy->num_lanes >= 2) { | ||
170 | cdns_dp_phy_write_field(cdns_phy, PHY_PMA_XCVR_PLLCLK_EN, | ||
171 | 1, 1, 0x0000); | ||
172 | if (cdns_phy->num_lanes == 4) { | ||
173 | cdns_dp_phy_write_field(cdns_phy, | ||
174 | PHY_PMA_XCVR_PLLCLK_EN, | ||
175 | 2, 1, 0x0000); | ||
176 | cdns_dp_phy_write_field(cdns_phy, | ||
177 | PHY_PMA_XCVR_PLLCLK_EN, | ||
178 | 3, 1, 0x0000); | ||
179 | } | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * release phy_l0*_reset_n and pma_tx_elec_idle_ln_* based on | ||
184 | * used lanes | ||
185 | */ | ||
186 | lane_bits = (1 << cdns_phy->num_lanes) - 1; | ||
187 | writel(((0xF & ~lane_bits) << 4) | (0xF & lane_bits), | ||
188 | cdns_phy->base + PHY_RESET); | ||
189 | |||
190 | /* release pma_xcvr_pllclk_en_ln_*, only for the master lane */ | ||
191 | writel(0x0001, cdns_phy->base + PHY_PMA_XCVR_PLLCLK_EN); | ||
192 | |||
193 | /* PHY PMA registers configuration functions */ | ||
194 | cdns_dp_phy_pma_cmn_vco_cfg_25mhz(cdns_phy); | ||
195 | cdns_dp_phy_pma_cmn_rate(cdns_phy); | ||
196 | |||
197 | /* take out of reset */ | ||
198 | cdns_dp_phy_write_field(cdns_phy, PHY_RESET, 8, 1, 1); | ||
199 | cdns_dp_phy_wait_pma_cmn_ready(cdns_phy); | ||
200 | cdns_dp_phy_run(cdns_phy); | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static void cdns_dp_phy_wait_pma_cmn_ready(struct cdns_dp_phy *cdns_phy) | ||
206 | { | ||
207 | unsigned int reg; | ||
208 | int ret; | ||
209 | |||
210 | ret = readl_poll_timeout(cdns_phy->base + PHY_PMA_CMN_READY, reg, | ||
211 | reg & 1, 0, 500); | ||
212 | if (ret == -ETIMEDOUT) | ||
213 | dev_err(cdns_phy->dev, | ||
214 | "timeout waiting for PMA common ready\n"); | ||
215 | } | ||
216 | |||
217 | static void cdns_dp_phy_pma_cfg(struct cdns_dp_phy *cdns_phy) | ||
218 | { | ||
219 | unsigned int i; | ||
220 | |||
221 | /* PMA common configuration */ | ||
222 | cdns_dp_phy_pma_cmn_cfg_25mhz(cdns_phy); | ||
223 | |||
224 | /* PMA lane configuration to deal with multi-link operation */ | ||
225 | for (i = 0; i < cdns_phy->num_lanes; i++) | ||
226 | cdns_dp_phy_pma_lane_cfg(cdns_phy, i); | ||
227 | } | ||
228 | |||
229 | static void cdns_dp_phy_pma_cmn_cfg_25mhz(struct cdns_dp_phy *cdns_phy) | ||
230 | { | ||
231 | /* refclock registers - assumes 25 MHz refclock */ | ||
232 | writel(0x0019, cdns_phy->sd_base + CMN_SSM_BIAS_TMR); | ||
233 | writel(0x0032, cdns_phy->sd_base + CMN_PLLSM0_PLLPRE_TMR); | ||
234 | writel(0x00D1, cdns_phy->sd_base + CMN_PLLSM0_PLLLOCK_TMR); | ||
235 | writel(0x0032, cdns_phy->sd_base + CMN_PLLSM1_PLLPRE_TMR); | ||
236 | writel(0x00D1, cdns_phy->sd_base + CMN_PLLSM1_PLLLOCK_TMR); | ||
237 | writel(0x007D, cdns_phy->sd_base + CMN_BGCAL_INIT_TMR); | ||
238 | writel(0x007D, cdns_phy->sd_base + CMN_BGCAL_ITER_TMR); | ||
239 | writel(0x0019, cdns_phy->sd_base + CMN_IBCAL_INIT_TMR); | ||
240 | writel(0x001E, cdns_phy->sd_base + CMN_TXPUCAL_INIT_TMR); | ||
241 | writel(0x0006, cdns_phy->sd_base + CMN_TXPUCAL_ITER_TMR); | ||
242 | writel(0x001E, cdns_phy->sd_base + CMN_TXPDCAL_INIT_TMR); | ||
243 | writel(0x0006, cdns_phy->sd_base + CMN_TXPDCAL_ITER_TMR); | ||
244 | writel(0x02EE, cdns_phy->sd_base + CMN_RXCAL_INIT_TMR); | ||
245 | writel(0x0006, cdns_phy->sd_base + CMN_RXCAL_ITER_TMR); | ||
246 | writel(0x0002, cdns_phy->sd_base + CMN_SD_CAL_INIT_TMR); | ||
247 | writel(0x0002, cdns_phy->sd_base + CMN_SD_CAL_ITER_TMR); | ||
248 | writel(0x000E, cdns_phy->sd_base + CMN_SD_CAL_REFTIM_START); | ||
249 | writel(0x012B, cdns_phy->sd_base + CMN_SD_CAL_PLLCNT_START); | ||
250 | /* PLL registers */ | ||
251 | writel(0x0409, cdns_phy->sd_base + CMN_PDIAG_PLL0_CP_PADJ_M0); | ||
252 | writel(0x1001, cdns_phy->sd_base + CMN_PDIAG_PLL0_CP_IADJ_M0); | ||
253 | writel(0x0F08, cdns_phy->sd_base + CMN_PDIAG_PLL0_FILT_PADJ_M0); | ||
254 | writel(0x0004, cdns_phy->sd_base + CMN_PLL0_DSM_DIAG_M0); | ||
255 | writel(0x00FA, cdns_phy->sd_base + CMN_PLL0_VCOCAL_INIT_TMR); | ||
256 | writel(0x0004, cdns_phy->sd_base + CMN_PLL0_VCOCAL_ITER_TMR); | ||
257 | writel(0x00FA, cdns_phy->sd_base + CMN_PLL1_VCOCAL_INIT_TMR); | ||
258 | writel(0x0004, cdns_phy->sd_base + CMN_PLL1_VCOCAL_ITER_TMR); | ||
259 | writel(0x0318, cdns_phy->sd_base + CMN_PLL0_VCOCAL_REFTIM_START); | ||
260 | } | ||
261 | |||
262 | static void cdns_dp_phy_pma_cmn_vco_cfg_25mhz(struct cdns_dp_phy *cdns_phy) | ||
263 | { | ||
264 | /* Assumes 25 MHz refclock */ | ||
265 | switch (cdns_phy->max_bit_rate) { | ||
266 | /* Setting VCO for 10.8GHz */ | ||
267 | case 2700: | ||
268 | case 5400: | ||
269 | writel(0x01B0, cdns_phy->sd_base + CMN_PLL0_INTDIV_M0); | ||
270 | writel(0x0000, cdns_phy->sd_base + CMN_PLL0_FRACDIVL_M0); | ||
271 | writel(0x0002, cdns_phy->sd_base + CMN_PLL0_FRACDIVH_M0); | ||
272 | writel(0x0120, cdns_phy->sd_base + CMN_PLL0_HIGH_THR_M0); | ||
273 | break; | ||
274 | /* Setting VCO for 9.72GHz */ | ||
275 | case 2430: | ||
276 | case 3240: | ||
277 | writel(0x0184, cdns_phy->sd_base + CMN_PLL0_INTDIV_M0); | ||
278 | writel(0xCCCD, cdns_phy->sd_base + CMN_PLL0_FRACDIVL_M0); | ||
279 | writel(0x0002, cdns_phy->sd_base + CMN_PLL0_FRACDIVH_M0); | ||
280 | writel(0x0104, cdns_phy->sd_base + CMN_PLL0_HIGH_THR_M0); | ||
281 | break; | ||
282 | /* Setting VCO for 8.64GHz */ | ||
283 | case 2160: | ||
284 | case 4320: | ||
285 | writel(0x0159, cdns_phy->sd_base + CMN_PLL0_INTDIV_M0); | ||
286 | writel(0x999A, cdns_phy->sd_base + CMN_PLL0_FRACDIVL_M0); | ||
287 | writel(0x0002, cdns_phy->sd_base + CMN_PLL0_FRACDIVH_M0); | ||
288 | writel(0x00E7, cdns_phy->sd_base + CMN_PLL0_HIGH_THR_M0); | ||
289 | break; | ||
290 | /* Setting VCO for 8.1GHz */ | ||
291 | case 8100: | ||
292 | writel(0x0144, cdns_phy->sd_base + CMN_PLL0_INTDIV_M0); | ||
293 | writel(0x0000, cdns_phy->sd_base + CMN_PLL0_FRACDIVL_M0); | ||
294 | writel(0x0002, cdns_phy->sd_base + CMN_PLL0_FRACDIVH_M0); | ||
295 | writel(0x00D8, cdns_phy->sd_base + CMN_PLL0_HIGH_THR_M0); | ||
296 | break; | ||
297 | } | ||
298 | |||
299 | writel(0x0002, cdns_phy->sd_base + CMN_PDIAG_PLL0_CTRL_M0); | ||
300 | writel(0x0318, cdns_phy->sd_base + CMN_PLL0_VCOCAL_PLLCNT_START); | ||
301 | } | ||
302 | |||
303 | static void cdns_dp_phy_pma_cmn_rate(struct cdns_dp_phy *cdns_phy) | ||
304 | { | ||
305 | unsigned int clk_sel_val = 0; | ||
306 | unsigned int hsclk_div_val = 0; | ||
307 | unsigned int i; | ||
308 | |||
309 | /* 16'h0000 for single DP link configuration */ | ||
310 | writel(0x0000, cdns_phy->sd_base + PHY_PLL_CFG); | ||
311 | |||
312 | switch (cdns_phy->max_bit_rate) { | ||
313 | case 1620: | ||
314 | clk_sel_val = 0x0f01; | ||
315 | hsclk_div_val = 2; | ||
316 | break; | ||
317 | case 2160: | ||
318 | case 2430: | ||
319 | case 2700: | ||
320 | clk_sel_val = 0x0701; | ||
321 | hsclk_div_val = 1; | ||
322 | break; | ||
323 | case 3240: | ||
324 | clk_sel_val = 0x0b00; | ||
325 | hsclk_div_val = 2; | ||
326 | break; | ||
327 | case 4320: | ||
328 | case 5400: | ||
329 | clk_sel_val = 0x0301; | ||
330 | hsclk_div_val = 0; | ||
331 | break; | ||
332 | case 8100: | ||
333 | clk_sel_val = 0x0200; | ||
334 | hsclk_div_val = 0; | ||
335 | break; | ||
336 | } | ||
337 | |||
338 | writel(clk_sel_val, cdns_phy->sd_base + CMN_PDIAG_PLL0_CLK_SEL_M0); | ||
339 | |||
340 | /* PMA lane configuration to deal with multi-link operation */ | ||
341 | for (i = 0; i < cdns_phy->num_lanes; i++) { | ||
342 | writel(hsclk_div_val, | ||
343 | cdns_phy->sd_base + (XCVR_DIAG_HSCLK_DIV | (i<<11))); | ||
344 | } | ||
345 | } | ||
346 | |||
347 | static void cdns_dp_phy_pma_lane_cfg(struct cdns_dp_phy *cdns_phy, | ||
348 | unsigned int lane) | ||
349 | { | ||
350 | unsigned int lane_bits = (lane & LANE_MASK) << 11; | ||
351 | |||
352 | /* Writing Tx/Rx Power State Controllers registers */ | ||
353 | writel(0x00FB, cdns_phy->sd_base + (TX_PSC_A0 | lane_bits)); | ||
354 | writel(0x04AA, cdns_phy->sd_base + (TX_PSC_A2 | lane_bits)); | ||
355 | writel(0x04AA, cdns_phy->sd_base + (TX_PSC_A3 | lane_bits)); | ||
356 | writel(0x0000, cdns_phy->sd_base + (RX_PSC_A0 | lane_bits)); | ||
357 | writel(0x0000, cdns_phy->sd_base + (RX_PSC_A2 | lane_bits)); | ||
358 | writel(0x0000, cdns_phy->sd_base + (RX_PSC_A3 | lane_bits)); | ||
359 | |||
360 | writel(0x0001, cdns_phy->sd_base + (XCVR_DIAG_PLLDRC_CTRL | lane_bits)); | ||
361 | writel(0x0000, cdns_phy->sd_base + (XCVR_DIAG_HSCLK_SEL | lane_bits)); | ||
362 | } | ||
363 | |||
364 | static void cdns_dp_phy_run(struct cdns_dp_phy *cdns_phy) | ||
365 | { | ||
366 | unsigned int read_val; | ||
367 | u32 write_val1 = 0; | ||
368 | u32 write_val2 = 0; | ||
369 | u32 mask = 0; | ||
370 | int ret; | ||
371 | |||
372 | /* | ||
373 | * waiting for ACK of pma_xcvr_pllclk_en_ln_*, only for the | ||
374 | * master lane | ||
375 | */ | ||
376 | ret = readl_poll_timeout(cdns_phy->base + PHY_PMA_XCVR_PLLCLK_EN_ACK, | ||
377 | read_val, read_val & 1, 0, POLL_TIMEOUT_US); | ||
378 | if (ret == -ETIMEDOUT) | ||
379 | dev_err(cdns_phy->dev, | ||
380 | "timeout waiting for link PLL clock enable ack\n"); | ||
381 | |||
382 | ndelay(100); | ||
383 | |||
384 | switch (cdns_phy->num_lanes) { | ||
385 | |||
386 | case 1: /* lane 0 */ | ||
387 | write_val1 = 0x00000004; | ||
388 | write_val2 = 0x00000001; | ||
389 | mask = 0x0000003f; | ||
390 | break; | ||
391 | case 2: /* lane 0-1 */ | ||
392 | write_val1 = 0x00000404; | ||
393 | write_val2 = 0x00000101; | ||
394 | mask = 0x00003f3f; | ||
395 | break; | ||
396 | case 4: /* lane 0-3 */ | ||
397 | write_val1 = 0x04040404; | ||
398 | write_val2 = 0x01010101; | ||
399 | mask = 0x3f3f3f3f; | ||
400 | break; | ||
401 | } | ||
402 | |||
403 | writel(write_val1, cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_REQ); | ||
404 | |||
405 | ret = readl_poll_timeout(cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_ACK, | ||
406 | read_val, (read_val & mask) == write_val1, 0, | ||
407 | POLL_TIMEOUT_US); | ||
408 | if (ret == -ETIMEDOUT) | ||
409 | dev_err(cdns_phy->dev, | ||
410 | "timeout waiting for link power state ack\n"); | ||
411 | |||
412 | writel(0, cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_REQ); | ||
413 | ndelay(100); | ||
414 | |||
415 | writel(write_val2, cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_REQ); | ||
416 | |||
417 | ret = readl_poll_timeout(cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_ACK, | ||
418 | read_val, (read_val & mask) == write_val2, 0, | ||
419 | POLL_TIMEOUT_US); | ||
420 | if (ret == -ETIMEDOUT) | ||
421 | dev_err(cdns_phy->dev, | ||
422 | "timeout waiting for link power state ack\n"); | ||
423 | |||
424 | writel(0, cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_REQ); | ||
425 | ndelay(100); | ||
426 | } | ||
427 | |||
428 | static void cdns_dp_phy_write_field(struct cdns_dp_phy *cdns_phy, | ||
429 | unsigned int offset, | ||
430 | unsigned char start_bit, | ||
431 | unsigned char num_bits, | ||
432 | unsigned int val) | ||
433 | { | ||
434 | unsigned int read_val; | ||
435 | |||
436 | read_val = readl(cdns_phy->base + offset); | ||
437 | writel(((val << start_bit) | (read_val & ~(((1 << num_bits) - 1) << | ||
438 | start_bit))), cdns_phy->base + offset); | ||
439 | } | ||
440 | |||
441 | static int cdns_dp_phy_probe(struct platform_device *pdev) | ||
442 | { | ||
443 | struct resource *regs; | ||
444 | struct cdns_dp_phy *cdns_phy; | ||
445 | struct device *dev = &pdev->dev; | ||
446 | struct phy_provider *phy_provider; | ||
447 | struct phy *phy; | ||
448 | int err; | ||
449 | |||
450 | cdns_phy = devm_kzalloc(dev, sizeof(*cdns_phy), GFP_KERNEL); | ||
451 | if (!cdns_phy) | ||
452 | return -ENOMEM; | ||
453 | |||
454 | cdns_phy->dev = &pdev->dev; | ||
455 | |||
456 | phy = devm_phy_create(dev, NULL, &cdns_dp_phy_ops); | ||
457 | if (IS_ERR(phy)) { | ||
458 | dev_err(dev, "failed to create DisplayPort PHY\n"); | ||
459 | return PTR_ERR(phy); | ||
460 | } | ||
461 | |||
462 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
463 | cdns_phy->base = devm_ioremap_resource(&pdev->dev, regs); | ||
464 | if (IS_ERR(cdns_phy->base)) | ||
465 | return PTR_ERR(cdns_phy->base); | ||
466 | |||
467 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
468 | cdns_phy->sd_base = devm_ioremap_resource(&pdev->dev, regs); | ||
469 | if (IS_ERR(cdns_phy->sd_base)) | ||
470 | return PTR_ERR(cdns_phy->sd_base); | ||
471 | |||
472 | err = device_property_read_u32(dev, "num_lanes", | ||
473 | &(cdns_phy->num_lanes)); | ||
474 | if (err) | ||
475 | cdns_phy->num_lanes = DEFAULT_NUM_LANES; | ||
476 | |||
477 | switch (cdns_phy->num_lanes) { | ||
478 | case 1: | ||
479 | case 2: | ||
480 | case 4: | ||
481 | /* valid number of lanes */ | ||
482 | break; | ||
483 | default: | ||
484 | dev_err(dev, "unsupported number of lanes: %d\n", | ||
485 | cdns_phy->num_lanes); | ||
486 | return -EINVAL; | ||
487 | } | ||
488 | |||
489 | err = device_property_read_u32(dev, "max_bit_rate", | ||
490 | &(cdns_phy->max_bit_rate)); | ||
491 | if (err) | ||
492 | cdns_phy->max_bit_rate = DEFAULT_MAX_BIT_RATE; | ||
493 | |||
494 | switch (cdns_phy->max_bit_rate) { | ||
495 | case 2160: | ||
496 | case 2430: | ||
497 | case 2700: | ||
498 | case 3240: | ||
499 | case 4320: | ||
500 | case 5400: | ||
501 | case 8100: | ||
502 | /* valid bit rate */ | ||
503 | break; | ||
504 | default: | ||
505 | dev_err(dev, "unsupported max bit rate: %dMbps\n", | ||
506 | cdns_phy->max_bit_rate); | ||
507 | return -EINVAL; | ||
508 | } | ||
509 | |||
510 | phy_set_drvdata(phy, cdns_phy); | ||
511 | |||
512 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | ||
513 | |||
514 | dev_info(dev, "%d lanes, max bit rate %d.%03d Gbps\n", | ||
515 | cdns_phy->num_lanes, | ||
516 | cdns_phy->max_bit_rate / 1000, | ||
517 | cdns_phy->max_bit_rate % 1000); | ||
518 | |||
519 | return PTR_ERR_OR_ZERO(phy_provider); | ||
520 | } | ||
521 | |||
522 | static const struct of_device_id cdns_dp_phy_of_match[] = { | ||
523 | { | ||
524 | .compatible = "cdns,dp-phy" | ||
525 | }, | ||
526 | {} | ||
527 | }; | ||
528 | MODULE_DEVICE_TABLE(of, cdns_dp_phy_of_match); | ||
529 | |||
530 | static struct platform_driver cdns_dp_phy_driver = { | ||
531 | .probe = cdns_dp_phy_probe, | ||
532 | .driver = { | ||
533 | .name = "cdns-dp-phy", | ||
534 | .of_match_table = cdns_dp_phy_of_match, | ||
535 | } | ||
536 | }; | ||
537 | module_platform_driver(cdns_dp_phy_driver); | ||
538 | |||
539 | MODULE_AUTHOR("Cadence Design Systems, Inc."); | ||
540 | MODULE_DESCRIPTION("Cadence MHDP PHY driver"); | ||
541 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c b/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c index 986224fca9e9..f9e0dd19ff26 100644 --- a/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c +++ b/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c | |||
@@ -156,7 +156,6 @@ static int ltq_rcu_usb2_of_parse(struct ltq_rcu_usb2_priv *priv, | |||
156 | { | 156 | { |
157 | struct device *dev = priv->dev; | 157 | struct device *dev = priv->dev; |
158 | const __be32 *offset; | 158 | const __be32 *offset; |
159 | int ret; | ||
160 | 159 | ||
161 | priv->reg_bits = of_device_get_match_data(dev); | 160 | priv->reg_bits = of_device_get_match_data(dev); |
162 | 161 | ||
@@ -196,10 +195,8 @@ static int ltq_rcu_usb2_of_parse(struct ltq_rcu_usb2_priv *priv, | |||
196 | } | 195 | } |
197 | 196 | ||
198 | priv->phy_reset = devm_reset_control_get_optional(dev, "phy"); | 197 | priv->phy_reset = devm_reset_control_get_optional(dev, "phy"); |
199 | if (IS_ERR(priv->phy_reset)) | ||
200 | return PTR_ERR(priv->phy_reset); | ||
201 | 198 | ||
202 | return 0; | 199 | return PTR_ERR_OR_ZERO(priv->phy_reset); |
203 | } | 200 | } |
204 | 201 | ||
205 | static int ltq_rcu_usb2_phy_probe(struct platform_device *pdev) | 202 | static int ltq_rcu_usb2_phy_probe(struct platform_device *pdev) |
diff --git a/drivers/phy/marvell/Kconfig b/drivers/phy/marvell/Kconfig index 68e321225400..6fb4b56e4c14 100644 --- a/drivers/phy/marvell/Kconfig +++ b/drivers/phy/marvell/Kconfig | |||
@@ -59,3 +59,14 @@ config PHY_PXA_28NM_USB2 | |||
59 | The PHY driver will be used by Marvell udc/ehci/otg driver. | 59 | The PHY driver will be used by Marvell udc/ehci/otg driver. |
60 | 60 | ||
61 | To compile this driver as a module, choose M here. | 61 | To compile this driver as a module, choose M here. |
62 | |||
63 | config PHY_PXA_USB | ||
64 | tristate "Marvell PXA USB PHY Driver" | ||
65 | depends on ARCH_PXA || ARCH_MMP | ||
66 | select GENERIC_PHY | ||
67 | help | ||
68 | Enable this to support Marvell PXA USB PHY driver for Marvell | ||
69 | SoC. This driver will do the PHY initialization and shutdown. | ||
70 | The PHY driver will be used by Marvell udc/ehci/otg driver. | ||
71 | |||
72 | To compile this driver as a module, choose M here. | ||
diff --git a/drivers/phy/marvell/Makefile b/drivers/phy/marvell/Makefile index 5c3ec5d10e0d..3975b144f8ec 100644 --- a/drivers/phy/marvell/Makefile +++ b/drivers/phy/marvell/Makefile | |||
@@ -6,3 +6,4 @@ obj-$(CONFIG_PHY_MVEBU_CP110_COMPHY) += phy-mvebu-cp110-comphy.o | |||
6 | obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o | 6 | obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o |
7 | obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o | 7 | obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o |
8 | obj-$(CONFIG_PHY_PXA_28NM_USB2) += phy-pxa-28nm-usb2.o | 8 | obj-$(CONFIG_PHY_PXA_28NM_USB2) += phy-pxa-28nm-usb2.o |
9 | obj-$(CONFIG_PHY_PXA_USB) += phy-pxa-usb.o | ||
diff --git a/drivers/phy/marvell/phy-berlin-sata.c b/drivers/phy/marvell/phy-berlin-sata.c index c1bb6725e48f..a91fc67fc4e0 100644 --- a/drivers/phy/marvell/phy-berlin-sata.c +++ b/drivers/phy/marvell/phy-berlin-sata.c | |||
@@ -231,14 +231,14 @@ static int phy_berlin_sata_probe(struct platform_device *pdev) | |||
231 | struct phy_berlin_desc *phy_desc; | 231 | struct phy_berlin_desc *phy_desc; |
232 | 232 | ||
233 | if (of_property_read_u32(child, "reg", &phy_id)) { | 233 | if (of_property_read_u32(child, "reg", &phy_id)) { |
234 | dev_err(dev, "missing reg property in node %s\n", | 234 | dev_err(dev, "missing reg property in node %pOFn\n", |
235 | child->name); | 235 | child); |
236 | ret = -EINVAL; | 236 | ret = -EINVAL; |
237 | goto put_child; | 237 | goto put_child; |
238 | } | 238 | } |
239 | 239 | ||
240 | if (phy_id >= ARRAY_SIZE(phy_berlin_power_down_bits)) { | 240 | if (phy_id >= ARRAY_SIZE(phy_berlin_power_down_bits)) { |
241 | dev_err(dev, "invalid reg in node %s\n", child->name); | 241 | dev_err(dev, "invalid reg in node %pOFn\n", child); |
242 | ret = -EINVAL; | 242 | ret = -EINVAL; |
243 | goto put_child; | 243 | goto put_child; |
244 | } | 244 | } |
diff --git a/drivers/phy/marvell/phy-pxa-usb.c b/drivers/phy/marvell/phy-pxa-usb.c new file mode 100644 index 000000000000..87ff7550b912 --- /dev/null +++ b/drivers/phy/marvell/phy-pxa-usb.c | |||
@@ -0,0 +1,345 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Copyright (C) 2011 Marvell International Ltd. All rights reserved. | ||
4 | * Copyright (C) 2018 Lubomir Rintel <lkundrak@v3.sk> | ||
5 | */ | ||
6 | |||
7 | #include <dt-bindings/phy/phy.h> | ||
8 | #include <linux/clk.h> | ||
9 | #include <linux/delay.h> | ||
10 | #include <linux/io.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/of_address.h> | ||
13 | #include <linux/phy/phy.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | |||
16 | /* phy regs */ | ||
17 | #define UTMI_REVISION 0x0 | ||
18 | #define UTMI_CTRL 0x4 | ||
19 | #define UTMI_PLL 0x8 | ||
20 | #define UTMI_TX 0xc | ||
21 | #define UTMI_RX 0x10 | ||
22 | #define UTMI_IVREF 0x14 | ||
23 | #define UTMI_T0 0x18 | ||
24 | #define UTMI_T1 0x1c | ||
25 | #define UTMI_T2 0x20 | ||
26 | #define UTMI_T3 0x24 | ||
27 | #define UTMI_T4 0x28 | ||
28 | #define UTMI_T5 0x2c | ||
29 | #define UTMI_RESERVE 0x30 | ||
30 | #define UTMI_USB_INT 0x34 | ||
31 | #define UTMI_DBG_CTL 0x38 | ||
32 | #define UTMI_OTG_ADDON 0x3c | ||
33 | |||
34 | /* For UTMICTRL Register */ | ||
35 | #define UTMI_CTRL_USB_CLK_EN (1 << 31) | ||
36 | /* pxa168 */ | ||
37 | #define UTMI_CTRL_SUSPEND_SET1 (1 << 30) | ||
38 | #define UTMI_CTRL_SUSPEND_SET2 (1 << 29) | ||
39 | #define UTMI_CTRL_RXBUF_PDWN (1 << 24) | ||
40 | #define UTMI_CTRL_TXBUF_PDWN (1 << 11) | ||
41 | |||
42 | #define UTMI_CTRL_INPKT_DELAY_SHIFT 30 | ||
43 | #define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT 28 | ||
44 | #define UTMI_CTRL_PU_REF_SHIFT 20 | ||
45 | #define UTMI_CTRL_ARC_PULLDN_SHIFT 12 | ||
46 | #define UTMI_CTRL_PLL_PWR_UP_SHIFT 1 | ||
47 | #define UTMI_CTRL_PWR_UP_SHIFT 0 | ||
48 | |||
49 | /* For UTMI_PLL Register */ | ||
50 | #define UTMI_PLL_PLLCALI12_SHIFT 29 | ||
51 | #define UTMI_PLL_PLLCALI12_MASK (0x3 << 29) | ||
52 | |||
53 | #define UTMI_PLL_PLLVDD18_SHIFT 27 | ||
54 | #define UTMI_PLL_PLLVDD18_MASK (0x3 << 27) | ||
55 | |||
56 | #define UTMI_PLL_PLLVDD12_SHIFT 25 | ||
57 | #define UTMI_PLL_PLLVDD12_MASK (0x3 << 25) | ||
58 | |||
59 | #define UTMI_PLL_CLK_BLK_EN_SHIFT 24 | ||
60 | #define CLK_BLK_EN (0x1 << 24) | ||
61 | #define PLL_READY (0x1 << 23) | ||
62 | #define KVCO_EXT (0x1 << 22) | ||
63 | #define VCOCAL_START (0x1 << 21) | ||
64 | |||
65 | #define UTMI_PLL_KVCO_SHIFT 15 | ||
66 | #define UTMI_PLL_KVCO_MASK (0x7 << 15) | ||
67 | |||
68 | #define UTMI_PLL_ICP_SHIFT 12 | ||
69 | #define UTMI_PLL_ICP_MASK (0x7 << 12) | ||
70 | |||
71 | #define UTMI_PLL_FBDIV_SHIFT 4 | ||
72 | #define UTMI_PLL_FBDIV_MASK (0xFF << 4) | ||
73 | |||
74 | #define UTMI_PLL_REFDIV_SHIFT 0 | ||
75 | #define UTMI_PLL_REFDIV_MASK (0xF << 0) | ||
76 | |||
77 | /* For UTMI_TX Register */ | ||
78 | #define UTMI_TX_REG_EXT_FS_RCAL_SHIFT 27 | ||
79 | #define UTMI_TX_REG_EXT_FS_RCAL_MASK (0xf << 27) | ||
80 | |||
81 | #define UTMI_TX_REG_EXT_FS_RCAL_EN_SHIFT 26 | ||
82 | #define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK (0x1 << 26) | ||
83 | |||
84 | #define UTMI_TX_TXVDD12_SHIFT 22 | ||
85 | #define UTMI_TX_TXVDD12_MASK (0x3 << 22) | ||
86 | |||
87 | #define UTMI_TX_CK60_PHSEL_SHIFT 17 | ||
88 | #define UTMI_TX_CK60_PHSEL_MASK (0xf << 17) | ||
89 | |||
90 | #define UTMI_TX_IMPCAL_VTH_SHIFT 14 | ||
91 | #define UTMI_TX_IMPCAL_VTH_MASK (0x7 << 14) | ||
92 | |||
93 | #define REG_RCAL_START (0x1 << 12) | ||
94 | |||
95 | #define UTMI_TX_LOW_VDD_EN_SHIFT 11 | ||
96 | |||
97 | #define UTMI_TX_AMP_SHIFT 0 | ||
98 | #define UTMI_TX_AMP_MASK (0x7 << 0) | ||
99 | |||
100 | /* For UTMI_RX Register */ | ||
101 | #define UTMI_REG_SQ_LENGTH_SHIFT 15 | ||
102 | #define UTMI_REG_SQ_LENGTH_MASK (0x3 << 15) | ||
103 | |||
104 | #define UTMI_RX_SQ_THRESH_SHIFT 4 | ||
105 | #define UTMI_RX_SQ_THRESH_MASK (0xf << 4) | ||
106 | |||
107 | #define UTMI_OTG_ADDON_OTG_ON (1 << 0) | ||
108 | |||
109 | enum pxa_usb_phy_version { | ||
110 | PXA_USB_PHY_MMP2, | ||
111 | PXA_USB_PHY_PXA910, | ||
112 | PXA_USB_PHY_PXA168, | ||
113 | }; | ||
114 | |||
115 | struct pxa_usb_phy { | ||
116 | struct phy *phy; | ||
117 | void __iomem *base; | ||
118 | enum pxa_usb_phy_version version; | ||
119 | }; | ||
120 | |||
121 | /***************************************************************************** | ||
122 | * The registers read/write routines | ||
123 | *****************************************************************************/ | ||
124 | |||
125 | static unsigned int u2o_get(void __iomem *base, unsigned int offset) | ||
126 | { | ||
127 | return readl_relaxed(base + offset); | ||
128 | } | ||
129 | |||
130 | static void u2o_set(void __iomem *base, unsigned int offset, | ||
131 | unsigned int value) | ||
132 | { | ||
133 | u32 reg; | ||
134 | |||
135 | reg = readl_relaxed(base + offset); | ||
136 | reg |= value; | ||
137 | writel_relaxed(reg, base + offset); | ||
138 | readl_relaxed(base + offset); | ||
139 | } | ||
140 | |||
141 | static void u2o_clear(void __iomem *base, unsigned int offset, | ||
142 | unsigned int value) | ||
143 | { | ||
144 | u32 reg; | ||
145 | |||
146 | reg = readl_relaxed(base + offset); | ||
147 | reg &= ~value; | ||
148 | writel_relaxed(reg, base + offset); | ||
149 | readl_relaxed(base + offset); | ||
150 | } | ||
151 | |||
152 | static void u2o_write(void __iomem *base, unsigned int offset, | ||
153 | unsigned int value) | ||
154 | { | ||
155 | writel_relaxed(value, base + offset); | ||
156 | readl_relaxed(base + offset); | ||
157 | } | ||
158 | |||
159 | static int pxa_usb_phy_init(struct phy *phy) | ||
160 | { | ||
161 | struct pxa_usb_phy *pxa_usb_phy = phy_get_drvdata(phy); | ||
162 | void __iomem *base = pxa_usb_phy->base; | ||
163 | int loops; | ||
164 | |||
165 | dev_info(&phy->dev, "initializing Marvell PXA USB PHY"); | ||
166 | |||
167 | /* Initialize the USB PHY power */ | ||
168 | if (pxa_usb_phy->version == PXA_USB_PHY_PXA910) { | ||
169 | u2o_set(base, UTMI_CTRL, (1<<UTMI_CTRL_INPKT_DELAY_SOF_SHIFT) | ||
170 | | (1<<UTMI_CTRL_PU_REF_SHIFT)); | ||
171 | } | ||
172 | |||
173 | u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT); | ||
174 | u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT); | ||
175 | |||
176 | /* UTMI_PLL settings */ | ||
177 | u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK | ||
178 | | UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK | ||
179 | | UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK | ||
180 | | UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK); | ||
181 | |||
182 | u2o_set(base, UTMI_PLL, 0xee<<UTMI_PLL_FBDIV_SHIFT | ||
183 | | 0xb<<UTMI_PLL_REFDIV_SHIFT | 3<<UTMI_PLL_PLLVDD18_SHIFT | ||
184 | | 3<<UTMI_PLL_PLLVDD12_SHIFT | 3<<UTMI_PLL_PLLCALI12_SHIFT | ||
185 | | 1<<UTMI_PLL_ICP_SHIFT | 3<<UTMI_PLL_KVCO_SHIFT); | ||
186 | |||
187 | /* UTMI_TX */ | ||
188 | u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK | ||
189 | | UTMI_TX_TXVDD12_MASK | UTMI_TX_CK60_PHSEL_MASK | ||
190 | | UTMI_TX_IMPCAL_VTH_MASK | UTMI_TX_REG_EXT_FS_RCAL_MASK | ||
191 | | UTMI_TX_AMP_MASK); | ||
192 | u2o_set(base, UTMI_TX, 3<<UTMI_TX_TXVDD12_SHIFT | ||
193 | | 4<<UTMI_TX_CK60_PHSEL_SHIFT | 4<<UTMI_TX_IMPCAL_VTH_SHIFT | ||
194 | | 8<<UTMI_TX_REG_EXT_FS_RCAL_SHIFT | 3<<UTMI_TX_AMP_SHIFT); | ||
195 | |||
196 | /* UTMI_RX */ | ||
197 | u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK | ||
198 | | UTMI_REG_SQ_LENGTH_MASK); | ||
199 | u2o_set(base, UTMI_RX, 7<<UTMI_RX_SQ_THRESH_SHIFT | ||
200 | | 2<<UTMI_REG_SQ_LENGTH_SHIFT); | ||
201 | |||
202 | /* UTMI_IVREF */ | ||
203 | if (pxa_usb_phy->version == PXA_USB_PHY_PXA168) { | ||
204 | /* | ||
205 | * fixing Microsoft Altair board interface with NEC hub issue - | ||
206 | * Set UTMI_IVREF from 0x4a3 to 0x4bf | ||
207 | */ | ||
208 | u2o_write(base, UTMI_IVREF, 0x4bf); | ||
209 | } | ||
210 | |||
211 | /* toggle VCOCAL_START bit of UTMI_PLL */ | ||
212 | udelay(200); | ||
213 | u2o_set(base, UTMI_PLL, VCOCAL_START); | ||
214 | udelay(40); | ||
215 | u2o_clear(base, UTMI_PLL, VCOCAL_START); | ||
216 | |||
217 | /* toggle REG_RCAL_START bit of UTMI_TX */ | ||
218 | udelay(400); | ||
219 | u2o_set(base, UTMI_TX, REG_RCAL_START); | ||
220 | udelay(40); | ||
221 | u2o_clear(base, UTMI_TX, REG_RCAL_START); | ||
222 | udelay(400); | ||
223 | |||
224 | /* Make sure PHY PLL is ready */ | ||
225 | loops = 0; | ||
226 | while ((u2o_get(base, UTMI_PLL) & PLL_READY) == 0) { | ||
227 | mdelay(1); | ||
228 | loops++; | ||
229 | if (loops > 100) { | ||
230 | dev_warn(&phy->dev, "calibrate timeout, UTMI_PLL %x\n", | ||
231 | u2o_get(base, UTMI_PLL)); | ||
232 | break; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | if (pxa_usb_phy->version == PXA_USB_PHY_PXA168) { | ||
237 | u2o_set(base, UTMI_RESERVE, 1 << 5); | ||
238 | /* Turn on UTMI PHY OTG extension */ | ||
239 | u2o_write(base, UTMI_OTG_ADDON, 1); | ||
240 | } | ||
241 | |||
242 | return 0; | ||
243 | |||
244 | } | ||
245 | |||
246 | static int pxa_usb_phy_exit(struct phy *phy) | ||
247 | { | ||
248 | struct pxa_usb_phy *pxa_usb_phy = phy_get_drvdata(phy); | ||
249 | void __iomem *base = pxa_usb_phy->base; | ||
250 | |||
251 | dev_info(&phy->dev, "deinitializing Marvell PXA USB PHY"); | ||
252 | |||
253 | if (pxa_usb_phy->version == PXA_USB_PHY_PXA168) | ||
254 | u2o_clear(base, UTMI_OTG_ADDON, UTMI_OTG_ADDON_OTG_ON); | ||
255 | |||
256 | u2o_clear(base, UTMI_CTRL, UTMI_CTRL_RXBUF_PDWN); | ||
257 | u2o_clear(base, UTMI_CTRL, UTMI_CTRL_TXBUF_PDWN); | ||
258 | u2o_clear(base, UTMI_CTRL, UTMI_CTRL_USB_CLK_EN); | ||
259 | u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT); | ||
260 | u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT); | ||
261 | |||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | static const struct phy_ops pxa_usb_phy_ops = { | ||
266 | .init = pxa_usb_phy_init, | ||
267 | .exit = pxa_usb_phy_exit, | ||
268 | .owner = THIS_MODULE, | ||
269 | }; | ||
270 | |||
271 | static const struct of_device_id pxa_usb_phy_of_match[] = { | ||
272 | { | ||
273 | .compatible = "marvell,mmp2-usb-phy", | ||
274 | .data = (void *)PXA_USB_PHY_MMP2, | ||
275 | }, { | ||
276 | .compatible = "marvell,pxa910-usb-phy", | ||
277 | .data = (void *)PXA_USB_PHY_PXA910, | ||
278 | }, { | ||
279 | .compatible = "marvell,pxa168-usb-phy", | ||
280 | .data = (void *)PXA_USB_PHY_PXA168, | ||
281 | }, | ||
282 | { }, | ||
283 | }; | ||
284 | MODULE_DEVICE_TABLE(of, pxa_usb_phy_of_match); | ||
285 | |||
286 | static int pxa_usb_phy_probe(struct platform_device *pdev) | ||
287 | { | ||
288 | struct device *dev = &pdev->dev; | ||
289 | struct resource *resource; | ||
290 | struct pxa_usb_phy *pxa_usb_phy; | ||
291 | struct phy_provider *provider; | ||
292 | const struct of_device_id *of_id; | ||
293 | |||
294 | pxa_usb_phy = devm_kzalloc(dev, sizeof(struct pxa_usb_phy), GFP_KERNEL); | ||
295 | if (!pxa_usb_phy) | ||
296 | return -ENOMEM; | ||
297 | |||
298 | of_id = of_match_node(pxa_usb_phy_of_match, dev->of_node); | ||
299 | if (of_id) | ||
300 | pxa_usb_phy->version = (enum pxa_usb_phy_version)of_id->data; | ||
301 | else | ||
302 | pxa_usb_phy->version = PXA_USB_PHY_MMP2; | ||
303 | |||
304 | resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
305 | pxa_usb_phy->base = devm_ioremap_resource(dev, resource); | ||
306 | if (IS_ERR(pxa_usb_phy->base)) { | ||
307 | dev_err(dev, "failed to remap PHY regs\n"); | ||
308 | return PTR_ERR(pxa_usb_phy->base); | ||
309 | } | ||
310 | |||
311 | pxa_usb_phy->phy = devm_phy_create(dev, NULL, &pxa_usb_phy_ops); | ||
312 | if (IS_ERR(pxa_usb_phy->phy)) { | ||
313 | dev_err(dev, "failed to create PHY\n"); | ||
314 | return PTR_ERR(pxa_usb_phy->phy); | ||
315 | } | ||
316 | |||
317 | phy_set_drvdata(pxa_usb_phy->phy, pxa_usb_phy); | ||
318 | provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | ||
319 | if (IS_ERR(provider)) { | ||
320 | dev_err(dev, "failed to register PHY provider\n"); | ||
321 | return PTR_ERR(provider); | ||
322 | } | ||
323 | |||
324 | if (!dev->of_node) { | ||
325 | phy_create_lookup(pxa_usb_phy->phy, "usb", "mv-udc"); | ||
326 | phy_create_lookup(pxa_usb_phy->phy, "usb", "pxa-u2oehci"); | ||
327 | phy_create_lookup(pxa_usb_phy->phy, "usb", "mv-otg"); | ||
328 | } | ||
329 | |||
330 | dev_info(dev, "Marvell PXA USB PHY"); | ||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static struct platform_driver pxa_usb_phy_driver = { | ||
335 | .probe = pxa_usb_phy_probe, | ||
336 | .driver = { | ||
337 | .name = "pxa-usb-phy", | ||
338 | .of_match_table = pxa_usb_phy_of_match, | ||
339 | }, | ||
340 | }; | ||
341 | module_platform_driver(pxa_usb_phy_driver); | ||
342 | |||
343 | MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>"); | ||
344 | MODULE_DESCRIPTION("Marvell PXA USB PHY Driver"); | ||
345 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig index 632a0e73ee10..32f7d34eb784 100644 --- a/drivers/phy/qualcomm/Kconfig +++ b/drivers/phy/qualcomm/Kconfig | |||
@@ -50,6 +50,23 @@ config PHY_QCOM_UFS | |||
50 | help | 50 | help |
51 | Support for UFS PHY on QCOM chipsets. | 51 | Support for UFS PHY on QCOM chipsets. |
52 | 52 | ||
53 | if PHY_QCOM_UFS | ||
54 | |||
55 | config PHY_QCOM_UFS_14NM | ||
56 | tristate | ||
57 | default PHY_QCOM_UFS | ||
58 | help | ||
59 | Support for 14nm UFS QMP phy present on QCOM chipsets. | ||
60 | |||
61 | config PHY_QCOM_UFS_20NM | ||
62 | tristate | ||
63 | default PHY_QCOM_UFS | ||
64 | depends on BROKEN | ||
65 | help | ||
66 | Support for 20nm UFS QMP phy present on QCOM chipsets. | ||
67 | |||
68 | endif | ||
69 | |||
53 | config PHY_QCOM_USB_HS | 70 | config PHY_QCOM_USB_HS |
54 | tristate "Qualcomm USB HS PHY module" | 71 | tristate "Qualcomm USB HS PHY module" |
55 | depends on USB_ULPI_BUS | 72 | depends on USB_ULPI_BUS |
diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile index deb831f453ae..c56efd3af205 100644 --- a/drivers/phy/qualcomm/Makefile +++ b/drivers/phy/qualcomm/Makefile | |||
@@ -5,7 +5,7 @@ obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o | |||
5 | obj-$(CONFIG_PHY_QCOM_QMP) += phy-qcom-qmp.o | 5 | obj-$(CONFIG_PHY_QCOM_QMP) += phy-qcom-qmp.o |
6 | obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o | 6 | obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o |
7 | obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o | 7 | obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o |
8 | obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o | 8 | obj-$(CONFIG_PHY_QCOM_UFS_14NM) += phy-qcom-ufs-qmp-14nm.o |
9 | obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o | 9 | obj-$(CONFIG_PHY_QCOM_UFS_20NM) += phy-qcom-ufs-qmp-20nm.o |
10 | obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o | 10 | obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o |
11 | obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o | 11 | obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o |
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index 4c470104a0d6..a83332411026 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c | |||
@@ -156,6 +156,11 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[] = { | |||
156 | [QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x170, | 156 | [QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x170, |
157 | }; | 157 | }; |
158 | 158 | ||
159 | static const unsigned int sdm845_ufsphy_regs_layout[] = { | ||
160 | [QPHY_START_CTRL] = 0x00, | ||
161 | [QPHY_PCS_READY_STATUS] = 0x160, | ||
162 | }; | ||
163 | |||
159 | static const struct qmp_phy_init_tbl msm8996_pcie_serdes_tbl[] = { | 164 | static const struct qmp_phy_init_tbl msm8996_pcie_serdes_tbl[] = { |
160 | QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1c), | 165 | QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1c), |
161 | QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x10), | 166 | QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x10), |
@@ -601,6 +606,83 @@ static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_pcs_tbl[] = { | |||
601 | QMP_PHY_INIT_CFG(QPHY_V3_PCS_REFGEN_REQ_CONFIG2, 0x60), | 606 | QMP_PHY_INIT_CFG(QPHY_V3_PCS_REFGEN_REQ_CONFIG2, 0x60), |
602 | }; | 607 | }; |
603 | 608 | ||
609 | static const struct qmp_phy_init_tbl sdm845_ufsphy_serdes_tbl[] = { | ||
610 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02), | ||
611 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04), | ||
612 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_BG_TIMER, 0x0a), | ||
613 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07), | ||
614 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06), | ||
615 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0xd5), | ||
616 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL, 0x20), | ||
617 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30), | ||
618 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x00), | ||
619 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x01), | ||
620 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_CTRL, 0x00), | ||
621 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00), | ||
622 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x04), | ||
623 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x05), | ||
624 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_INITVAL1, 0xff), | ||
625 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_INITVAL2, 0x00), | ||
626 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82), | ||
627 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06), | ||
628 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16), | ||
629 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36), | ||
630 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f), | ||
631 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00), | ||
632 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xda), | ||
633 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01), | ||
634 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0xff), | ||
635 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x0c), | ||
636 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE1, 0x98), | ||
637 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE1, 0x06), | ||
638 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE1, 0x16), | ||
639 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE1, 0x36), | ||
640 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE1, 0x3f), | ||
641 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE1, 0x00), | ||
642 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE1, 0xc1), | ||
643 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE1, 0x00), | ||
644 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE1, 0x32), | ||
645 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE1, 0x0f), | ||
646 | |||
647 | /* Rate B */ | ||
648 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x44), | ||
649 | }; | ||
650 | |||
651 | static const struct qmp_phy_init_tbl sdm845_ufsphy_tx_tbl[] = { | ||
652 | QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x06), | ||
653 | QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x04), | ||
654 | QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x07), | ||
655 | }; | ||
656 | |||
657 | static const struct qmp_phy_init_tbl sdm845_ufsphy_rx_tbl[] = { | ||
658 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_LVL, 0x24), | ||
659 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x0f), | ||
660 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1e), | ||
661 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_INTERFACE_MODE, 0x40), | ||
662 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), | ||
663 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_TERM_BW, 0x5b), | ||
664 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x06), | ||
665 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x04), | ||
666 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x1b), | ||
667 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_HALF, 0x04), | ||
668 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_QUARTER, 0x04), | ||
669 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN, 0x04), | ||
670 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x4b), | ||
671 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x81), | ||
672 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x80), | ||
673 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x59), | ||
674 | }; | ||
675 | |||
676 | static const struct qmp_phy_init_tbl sdm845_ufsphy_pcs_tbl[] = { | ||
677 | QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_CTRL2, 0x6e), | ||
678 | QMP_PHY_INIT_CFG(QPHY_V3_PCS_TX_LARGE_AMP_DRV_LVL, 0x0a), | ||
679 | QMP_PHY_INIT_CFG(QPHY_V3_PCS_TX_SMALL_AMP_DRV_LVL, 0x02), | ||
680 | QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SYM_RESYNC_CTRL, 0x03), | ||
681 | QMP_PHY_INIT_CFG(QPHY_V3_PCS_TX_MID_TERM_CTRL1, 0x43), | ||
682 | QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_CTRL1, 0x0f), | ||
683 | QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_MIN_HIBERN8_TIME, 0x9a), | ||
684 | QMP_PHY_INIT_CFG(QPHY_V3_PCS_MULTI_LANE_CTRL1, 0x02), | ||
685 | }; | ||
604 | 686 | ||
605 | /* struct qmp_phy_cfg - per-PHY initialization config */ | 687 | /* struct qmp_phy_cfg - per-PHY initialization config */ |
606 | struct qmp_phy_cfg { | 688 | struct qmp_phy_cfg { |
@@ -649,9 +731,14 @@ struct qmp_phy_cfg { | |||
649 | 731 | ||
650 | /* true, if PHY has a separate DP_COM control block */ | 732 | /* true, if PHY has a separate DP_COM control block */ |
651 | bool has_phy_dp_com_ctrl; | 733 | bool has_phy_dp_com_ctrl; |
734 | /* true, if PHY has secondary tx/rx lanes to be configured */ | ||
735 | bool is_dual_lane_phy; | ||
652 | /* Register offset of secondary tx/rx lanes for USB DP combo PHY */ | 736 | /* Register offset of secondary tx/rx lanes for USB DP combo PHY */ |
653 | unsigned int tx_b_lane_offset; | 737 | unsigned int tx_b_lane_offset; |
654 | unsigned int rx_b_lane_offset; | 738 | unsigned int rx_b_lane_offset; |
739 | |||
740 | /* true, if PCS block has no separate SW_RESET register */ | ||
741 | bool no_pcs_sw_reset; | ||
655 | }; | 742 | }; |
656 | 743 | ||
657 | /** | 744 | /** |
@@ -748,6 +835,10 @@ static const char * const qmp_v3_phy_clk_l[] = { | |||
748 | "aux", "cfg_ahb", "ref", "com_aux", | 835 | "aux", "cfg_ahb", "ref", "com_aux", |
749 | }; | 836 | }; |
750 | 837 | ||
838 | static const char * const sdm845_ufs_phy_clk_l[] = { | ||
839 | "ref", "ref_aux", | ||
840 | }; | ||
841 | |||
751 | /* list of resets */ | 842 | /* list of resets */ |
752 | static const char * const msm8996_pciephy_reset_l[] = { | 843 | static const char * const msm8996_pciephy_reset_l[] = { |
753 | "phy", "common", "cfg", | 844 | "phy", "common", "cfg", |
@@ -758,7 +849,7 @@ static const char * const msm8996_usb3phy_reset_l[] = { | |||
758 | }; | 849 | }; |
759 | 850 | ||
760 | /* list of regulators */ | 851 | /* list of regulators */ |
761 | static const char * const msm8996_phy_vreg_l[] = { | 852 | static const char * const qmp_phy_vreg_l[] = { |
762 | "vdda-phy", "vdda-pll", | 853 | "vdda-phy", "vdda-pll", |
763 | }; | 854 | }; |
764 | 855 | ||
@@ -778,8 +869,8 @@ static const struct qmp_phy_cfg msm8996_pciephy_cfg = { | |||
778 | .num_clks = ARRAY_SIZE(msm8996_phy_clk_l), | 869 | .num_clks = ARRAY_SIZE(msm8996_phy_clk_l), |
779 | .reset_list = msm8996_pciephy_reset_l, | 870 | .reset_list = msm8996_pciephy_reset_l, |
780 | .num_resets = ARRAY_SIZE(msm8996_pciephy_reset_l), | 871 | .num_resets = ARRAY_SIZE(msm8996_pciephy_reset_l), |
781 | .vreg_list = msm8996_phy_vreg_l, | 872 | .vreg_list = qmp_phy_vreg_l, |
782 | .num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l), | 873 | .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), |
783 | .regs = pciephy_regs_layout, | 874 | .regs = pciephy_regs_layout, |
784 | 875 | ||
785 | .start_ctrl = PCS_START | PLL_READY_GATE_EN, | 876 | .start_ctrl = PCS_START | PLL_READY_GATE_EN, |
@@ -809,8 +900,8 @@ static const struct qmp_phy_cfg msm8996_usb3phy_cfg = { | |||
809 | .num_clks = ARRAY_SIZE(msm8996_phy_clk_l), | 900 | .num_clks = ARRAY_SIZE(msm8996_phy_clk_l), |
810 | .reset_list = msm8996_usb3phy_reset_l, | 901 | .reset_list = msm8996_usb3phy_reset_l, |
811 | .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), | 902 | .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), |
812 | .vreg_list = msm8996_phy_vreg_l, | 903 | .vreg_list = qmp_phy_vreg_l, |
813 | .num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l), | 904 | .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), |
814 | .regs = usb3phy_regs_layout, | 905 | .regs = usb3phy_regs_layout, |
815 | 906 | ||
816 | .start_ctrl = SERDES_START | PCS_START, | 907 | .start_ctrl = SERDES_START | PCS_START, |
@@ -870,8 +961,8 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = { | |||
870 | .num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l), | 961 | .num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l), |
871 | .reset_list = msm8996_usb3phy_reset_l, | 962 | .reset_list = msm8996_usb3phy_reset_l, |
872 | .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), | 963 | .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), |
873 | .vreg_list = msm8996_phy_vreg_l, | 964 | .vreg_list = qmp_phy_vreg_l, |
874 | .num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l), | 965 | .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), |
875 | .regs = qmp_v3_usb3phy_regs_layout, | 966 | .regs = qmp_v3_usb3phy_regs_layout, |
876 | 967 | ||
877 | .start_ctrl = SERDES_START | PCS_START, | 968 | .start_ctrl = SERDES_START | PCS_START, |
@@ -883,6 +974,7 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = { | |||
883 | .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, | 974 | .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, |
884 | 975 | ||
885 | .has_phy_dp_com_ctrl = true, | 976 | .has_phy_dp_com_ctrl = true, |
977 | .is_dual_lane_phy = true, | ||
886 | .tx_b_lane_offset = 0x400, | 978 | .tx_b_lane_offset = 0x400, |
887 | .rx_b_lane_offset = 0x400, | 979 | .rx_b_lane_offset = 0x400, |
888 | }; | 980 | }; |
@@ -903,8 +995,8 @@ static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = { | |||
903 | .num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l), | 995 | .num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l), |
904 | .reset_list = msm8996_usb3phy_reset_l, | 996 | .reset_list = msm8996_usb3phy_reset_l, |
905 | .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), | 997 | .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), |
906 | .vreg_list = msm8996_phy_vreg_l, | 998 | .vreg_list = qmp_phy_vreg_l, |
907 | .num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l), | 999 | .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), |
908 | .regs = qmp_v3_usb3phy_regs_layout, | 1000 | .regs = qmp_v3_usb3phy_regs_layout, |
909 | 1001 | ||
910 | .start_ctrl = SERDES_START | PCS_START, | 1002 | .start_ctrl = SERDES_START | PCS_START, |
@@ -916,6 +1008,35 @@ static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = { | |||
916 | .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, | 1008 | .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, |
917 | }; | 1009 | }; |
918 | 1010 | ||
1011 | static const struct qmp_phy_cfg sdm845_ufsphy_cfg = { | ||
1012 | .type = PHY_TYPE_UFS, | ||
1013 | .nlanes = 2, | ||
1014 | |||
1015 | .serdes_tbl = sdm845_ufsphy_serdes_tbl, | ||
1016 | .serdes_tbl_num = ARRAY_SIZE(sdm845_ufsphy_serdes_tbl), | ||
1017 | .tx_tbl = sdm845_ufsphy_tx_tbl, | ||
1018 | .tx_tbl_num = ARRAY_SIZE(sdm845_ufsphy_tx_tbl), | ||
1019 | .rx_tbl = sdm845_ufsphy_rx_tbl, | ||
1020 | .rx_tbl_num = ARRAY_SIZE(sdm845_ufsphy_rx_tbl), | ||
1021 | .pcs_tbl = sdm845_ufsphy_pcs_tbl, | ||
1022 | .pcs_tbl_num = ARRAY_SIZE(sdm845_ufsphy_pcs_tbl), | ||
1023 | .clk_list = sdm845_ufs_phy_clk_l, | ||
1024 | .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), | ||
1025 | .vreg_list = qmp_phy_vreg_l, | ||
1026 | .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), | ||
1027 | .regs = sdm845_ufsphy_regs_layout, | ||
1028 | |||
1029 | .start_ctrl = SERDES_START, | ||
1030 | .pwrdn_ctrl = SW_PWRDN, | ||
1031 | .mask_pcs_ready = PCS_READY, | ||
1032 | |||
1033 | .is_dual_lane_phy = true, | ||
1034 | .tx_b_lane_offset = 0x400, | ||
1035 | .rx_b_lane_offset = 0x400, | ||
1036 | |||
1037 | .no_pcs_sw_reset = true, | ||
1038 | }; | ||
1039 | |||
919 | static void qcom_qmp_phy_configure(void __iomem *base, | 1040 | static void qcom_qmp_phy_configure(void __iomem *base, |
920 | const unsigned int *regs, | 1041 | const unsigned int *regs, |
921 | const struct qmp_phy_init_tbl tbl[], | 1042 | const struct qmp_phy_init_tbl tbl[], |
@@ -935,10 +1056,12 @@ static void qcom_qmp_phy_configure(void __iomem *base, | |||
935 | } | 1056 | } |
936 | } | 1057 | } |
937 | 1058 | ||
938 | static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp) | 1059 | static int qcom_qmp_phy_com_init(struct qmp_phy *qphy) |
939 | { | 1060 | { |
1061 | struct qcom_qmp *qmp = qphy->qmp; | ||
940 | const struct qmp_phy_cfg *cfg = qmp->cfg; | 1062 | const struct qmp_phy_cfg *cfg = qmp->cfg; |
941 | void __iomem *serdes = qmp->serdes; | 1063 | void __iomem *serdes = qmp->serdes; |
1064 | void __iomem *pcs = qphy->pcs; | ||
942 | void __iomem *dp_com = qmp->dp_com; | 1065 | void __iomem *dp_com = qmp->dp_com; |
943 | int ret, i; | 1066 | int ret, i; |
944 | 1067 | ||
@@ -979,10 +1102,6 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp) | |||
979 | goto err_rst; | 1102 | goto err_rst; |
980 | } | 1103 | } |
981 | 1104 | ||
982 | if (cfg->has_phy_com_ctrl) | ||
983 | qphy_setbits(serdes, cfg->regs[QPHY_COM_POWER_DOWN_CONTROL], | ||
984 | SW_PWRDN); | ||
985 | |||
986 | if (cfg->has_phy_dp_com_ctrl) { | 1105 | if (cfg->has_phy_dp_com_ctrl) { |
987 | qphy_setbits(dp_com, QPHY_V3_DP_COM_POWER_DOWN_CTRL, | 1106 | qphy_setbits(dp_com, QPHY_V3_DP_COM_POWER_DOWN_CTRL, |
988 | SW_PWRDN); | 1107 | SW_PWRDN); |
@@ -1000,6 +1119,12 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp) | |||
1000 | SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET); | 1119 | SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET); |
1001 | } | 1120 | } |
1002 | 1121 | ||
1122 | if (cfg->has_phy_com_ctrl) | ||
1123 | qphy_setbits(serdes, cfg->regs[QPHY_COM_POWER_DOWN_CONTROL], | ||
1124 | SW_PWRDN); | ||
1125 | else | ||
1126 | qphy_setbits(pcs, QPHY_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl); | ||
1127 | |||
1003 | /* Serdes configuration */ | 1128 | /* Serdes configuration */ |
1004 | qcom_qmp_phy_configure(serdes, cfg->regs, cfg->serdes_tbl, | 1129 | qcom_qmp_phy_configure(serdes, cfg->regs, cfg->serdes_tbl, |
1005 | cfg->serdes_tbl_num); | 1130 | cfg->serdes_tbl_num); |
@@ -1090,7 +1215,7 @@ static int qcom_qmp_phy_init(struct phy *phy) | |||
1090 | 1215 | ||
1091 | dev_vdbg(qmp->dev, "Initializing QMP phy\n"); | 1216 | dev_vdbg(qmp->dev, "Initializing QMP phy\n"); |
1092 | 1217 | ||
1093 | ret = qcom_qmp_phy_com_init(qmp); | 1218 | ret = qcom_qmp_phy_com_init(qphy); |
1094 | if (ret) | 1219 | if (ret) |
1095 | return ret; | 1220 | return ret; |
1096 | 1221 | ||
@@ -1112,22 +1237,31 @@ static int qcom_qmp_phy_init(struct phy *phy) | |||
1112 | /* Tx, Rx, and PCS configurations */ | 1237 | /* Tx, Rx, and PCS configurations */ |
1113 | qcom_qmp_phy_configure(tx, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num); | 1238 | qcom_qmp_phy_configure(tx, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num); |
1114 | /* Configuration for other LANE for USB-DP combo PHY */ | 1239 | /* Configuration for other LANE for USB-DP combo PHY */ |
1115 | if (cfg->has_phy_dp_com_ctrl) | 1240 | if (cfg->is_dual_lane_phy) |
1116 | qcom_qmp_phy_configure(tx + cfg->tx_b_lane_offset, cfg->regs, | 1241 | qcom_qmp_phy_configure(tx + cfg->tx_b_lane_offset, cfg->regs, |
1117 | cfg->tx_tbl, cfg->tx_tbl_num); | 1242 | cfg->tx_tbl, cfg->tx_tbl_num); |
1118 | 1243 | ||
1119 | qcom_qmp_phy_configure(rx, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num); | 1244 | qcom_qmp_phy_configure(rx, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num); |
1120 | if (cfg->has_phy_dp_com_ctrl) | 1245 | if (cfg->is_dual_lane_phy) |
1121 | qcom_qmp_phy_configure(rx + cfg->rx_b_lane_offset, cfg->regs, | 1246 | qcom_qmp_phy_configure(rx + cfg->rx_b_lane_offset, cfg->regs, |
1122 | cfg->rx_tbl, cfg->rx_tbl_num); | 1247 | cfg->rx_tbl, cfg->rx_tbl_num); |
1123 | 1248 | ||
1124 | qcom_qmp_phy_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num); | 1249 | qcom_qmp_phy_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num); |
1125 | 1250 | ||
1126 | /* | 1251 | /* |
1252 | * UFS PHY requires the deassert of software reset before serdes start. | ||
1253 | * For UFS PHYs that do not have software reset control bits, defer | ||
1254 | * starting serdes until the power on callback. | ||
1255 | */ | ||
1256 | if ((cfg->type == PHY_TYPE_UFS) && cfg->no_pcs_sw_reset) | ||
1257 | goto out; | ||
1258 | |||
1259 | /* | ||
1127 | * Pull out PHY from POWER DOWN state. | 1260 | * Pull out PHY from POWER DOWN state. |
1128 | * This is active low enable signal to power-down PHY. | 1261 | * This is active low enable signal to power-down PHY. |
1129 | */ | 1262 | */ |
1130 | qphy_setbits(pcs, QPHY_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl); | 1263 | if(cfg->type == PHY_TYPE_PCIE) |
1264 | qphy_setbits(pcs, QPHY_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl); | ||
1131 | 1265 | ||
1132 | if (cfg->has_pwrdn_delay) | 1266 | if (cfg->has_pwrdn_delay) |
1133 | usleep_range(cfg->pwrdn_delay_min, cfg->pwrdn_delay_max); | 1267 | usleep_range(cfg->pwrdn_delay_min, cfg->pwrdn_delay_max); |
@@ -1151,6 +1285,7 @@ static int qcom_qmp_phy_init(struct phy *phy) | |||
1151 | } | 1285 | } |
1152 | qmp->phy_initialized = true; | 1286 | qmp->phy_initialized = true; |
1153 | 1287 | ||
1288 | out: | ||
1154 | return ret; | 1289 | return ret; |
1155 | 1290 | ||
1156 | err_pcs_ready: | 1291 | err_pcs_ready: |
@@ -1173,7 +1308,8 @@ static int qcom_qmp_phy_exit(struct phy *phy) | |||
1173 | clk_disable_unprepare(qphy->pipe_clk); | 1308 | clk_disable_unprepare(qphy->pipe_clk); |
1174 | 1309 | ||
1175 | /* PHY reset */ | 1310 | /* PHY reset */ |
1176 | qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); | 1311 | if (!cfg->no_pcs_sw_reset) |
1312 | qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); | ||
1177 | 1313 | ||
1178 | /* stop SerDes and Phy-Coding-Sublayer */ | 1314 | /* stop SerDes and Phy-Coding-Sublayer */ |
1179 | qphy_clrbits(qphy->pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl); | 1315 | qphy_clrbits(qphy->pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl); |
@@ -1191,6 +1327,44 @@ static int qcom_qmp_phy_exit(struct phy *phy) | |||
1191 | return 0; | 1327 | return 0; |
1192 | } | 1328 | } |
1193 | 1329 | ||
1330 | static int qcom_qmp_phy_poweron(struct phy *phy) | ||
1331 | { | ||
1332 | struct qmp_phy *qphy = phy_get_drvdata(phy); | ||
1333 | struct qcom_qmp *qmp = qphy->qmp; | ||
1334 | const struct qmp_phy_cfg *cfg = qmp->cfg; | ||
1335 | void __iomem *pcs = qphy->pcs; | ||
1336 | void __iomem *status; | ||
1337 | unsigned int mask, val; | ||
1338 | int ret = 0; | ||
1339 | |||
1340 | if (cfg->type != PHY_TYPE_UFS) | ||
1341 | return 0; | ||
1342 | |||
1343 | /* | ||
1344 | * For UFS PHY that has not software reset control, serdes start | ||
1345 | * should only happen when UFS driver explicitly calls phy_power_on | ||
1346 | * after it deasserts software reset. | ||
1347 | */ | ||
1348 | if (cfg->no_pcs_sw_reset && !qmp->phy_initialized && | ||
1349 | (qmp->init_count != 0)) { | ||
1350 | /* start SerDes and Phy-Coding-Sublayer */ | ||
1351 | qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl); | ||
1352 | |||
1353 | status = pcs + cfg->regs[QPHY_PCS_READY_STATUS]; | ||
1354 | mask = cfg->mask_pcs_ready; | ||
1355 | |||
1356 | ret = readl_poll_timeout(status, val, !(val & mask), 1, | ||
1357 | PHY_INIT_COMPLETE_TIMEOUT); | ||
1358 | if (ret) { | ||
1359 | dev_err(qmp->dev, "phy initialization timed-out\n"); | ||
1360 | return ret; | ||
1361 | } | ||
1362 | qmp->phy_initialized = true; | ||
1363 | } | ||
1364 | |||
1365 | return ret; | ||
1366 | } | ||
1367 | |||
1194 | static int qcom_qmp_phy_set_mode(struct phy *phy, enum phy_mode mode) | 1368 | static int qcom_qmp_phy_set_mode(struct phy *phy, enum phy_mode mode) |
1195 | { | 1369 | { |
1196 | struct qmp_phy *qphy = phy_get_drvdata(phy); | 1370 | struct qmp_phy *qphy = phy_get_drvdata(phy); |
@@ -1400,7 +1574,7 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np) | |||
1400 | 1574 | ||
1401 | ret = of_property_read_string(np, "clock-output-names", &init.name); | 1575 | ret = of_property_read_string(np, "clock-output-names", &init.name); |
1402 | if (ret) { | 1576 | if (ret) { |
1403 | dev_err(qmp->dev, "%s: No clock-output-names\n", np->name); | 1577 | dev_err(qmp->dev, "%pOFn: No clock-output-names\n", np); |
1404 | return ret; | 1578 | return ret; |
1405 | } | 1579 | } |
1406 | 1580 | ||
@@ -1420,6 +1594,7 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np) | |||
1420 | static const struct phy_ops qcom_qmp_phy_gen_ops = { | 1594 | static const struct phy_ops qcom_qmp_phy_gen_ops = { |
1421 | .init = qcom_qmp_phy_init, | 1595 | .init = qcom_qmp_phy_init, |
1422 | .exit = qcom_qmp_phy_exit, | 1596 | .exit = qcom_qmp_phy_exit, |
1597 | .power_on = qcom_qmp_phy_poweron, | ||
1423 | .set_mode = qcom_qmp_phy_set_mode, | 1598 | .set_mode = qcom_qmp_phy_set_mode, |
1424 | .owner = THIS_MODULE, | 1599 | .owner = THIS_MODULE, |
1425 | }; | 1600 | }; |
@@ -1522,6 +1697,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = { | |||
1522 | }, { | 1697 | }, { |
1523 | .compatible = "qcom,sdm845-qmp-usb3-uni-phy", | 1698 | .compatible = "qcom,sdm845-qmp-usb3-uni-phy", |
1524 | .data = &qmp_v3_usb3_uniphy_cfg, | 1699 | .data = &qmp_v3_usb3_uniphy_cfg, |
1700 | }, { | ||
1701 | .compatible = "qcom,sdm845-qmp-ufs-phy", | ||
1702 | .data = &sdm845_ufsphy_cfg, | ||
1525 | }, | 1703 | }, |
1526 | { }, | 1704 | { }, |
1527 | }; | 1705 | }; |
@@ -1586,7 +1764,9 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev) | |||
1586 | 1764 | ||
1587 | ret = qcom_qmp_phy_vreg_init(dev); | 1765 | ret = qcom_qmp_phy_vreg_init(dev); |
1588 | if (ret) { | 1766 | if (ret) { |
1589 | dev_err(dev, "failed to get regulator supplies\n"); | 1767 | if (ret != -EPROBE_DEFER) |
1768 | dev_err(dev, "failed to get regulator supplies: %d\n", | ||
1769 | ret); | ||
1590 | return ret; | 1770 | return ret; |
1591 | } | 1771 | } |
1592 | 1772 | ||
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h index 5d78d43ba9fc..d201cc307151 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp.h | |||
@@ -184,6 +184,8 @@ | |||
184 | #define QSERDES_V3_COM_VCO_TUNE2_MODE0 0x0f8 | 184 | #define QSERDES_V3_COM_VCO_TUNE2_MODE0 0x0f8 |
185 | #define QSERDES_V3_COM_VCO_TUNE1_MODE1 0x0fc | 185 | #define QSERDES_V3_COM_VCO_TUNE1_MODE1 0x0fc |
186 | #define QSERDES_V3_COM_VCO_TUNE2_MODE1 0x100 | 186 | #define QSERDES_V3_COM_VCO_TUNE2_MODE1 0x100 |
187 | #define QSERDES_V3_COM_VCO_TUNE_INITVAL1 0x104 | ||
188 | #define QSERDES_V3_COM_VCO_TUNE_INITVAL2 0x108 | ||
187 | #define QSERDES_V3_COM_VCO_TUNE_TIMER1 0x11c | 189 | #define QSERDES_V3_COM_VCO_TUNE_TIMER1 0x11c |
188 | #define QSERDES_V3_COM_VCO_TUNE_TIMER2 0x120 | 190 | #define QSERDES_V3_COM_VCO_TUNE_TIMER2 0x120 |
189 | #define QSERDES_V3_COM_CLK_SELECT 0x138 | 191 | #define QSERDES_V3_COM_CLK_SELECT 0x138 |
@@ -211,8 +213,13 @@ | |||
211 | /* Only for QMP V3 PHY - RX registers */ | 213 | /* Only for QMP V3 PHY - RX registers */ |
212 | #define QSERDES_V3_RX_UCDR_SO_GAIN_HALF 0x00c | 214 | #define QSERDES_V3_RX_UCDR_SO_GAIN_HALF 0x00c |
213 | #define QSERDES_V3_RX_UCDR_SO_GAIN 0x014 | 215 | #define QSERDES_V3_RX_UCDR_SO_GAIN 0x014 |
216 | #define QSERDES_V3_RX_UCDR_SVS_SO_GAIN_HALF 0x024 | ||
217 | #define QSERDES_V3_RX_UCDR_SVS_SO_GAIN_QUARTER 0x028 | ||
218 | #define QSERDES_V3_RX_UCDR_SVS_SO_GAIN 0x02c | ||
214 | #define QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN 0x030 | 219 | #define QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN 0x030 |
215 | #define QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034 | 220 | #define QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034 |
221 | #define QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW 0x03c | ||
222 | #define QSERDES_V3_RX_UCDR_PI_CONTROLS 0x044 | ||
216 | #define QSERDES_V3_RX_RX_TERM_BW 0x07c | 223 | #define QSERDES_V3_RX_RX_TERM_BW 0x07c |
217 | #define QSERDES_V3_RX_VGA_CAL_CNTRL1 0x0bc | 224 | #define QSERDES_V3_RX_VGA_CAL_CNTRL1 0x0bc |
218 | #define QSERDES_V3_RX_VGA_CAL_CNTRL2 0x0c0 | 225 | #define QSERDES_V3_RX_VGA_CAL_CNTRL2 0x0c0 |
@@ -239,6 +246,8 @@ | |||
239 | #define QPHY_V3_PCS_TXMGN_V3 0x018 | 246 | #define QPHY_V3_PCS_TXMGN_V3 0x018 |
240 | #define QPHY_V3_PCS_TXMGN_V4 0x01c | 247 | #define QPHY_V3_PCS_TXMGN_V4 0x01c |
241 | #define QPHY_V3_PCS_TXMGN_LS 0x020 | 248 | #define QPHY_V3_PCS_TXMGN_LS 0x020 |
249 | #define QPHY_V3_PCS_TX_LARGE_AMP_DRV_LVL 0x02c | ||
250 | #define QPHY_V3_PCS_TX_SMALL_AMP_DRV_LVL 0x034 | ||
242 | #define QPHY_V3_PCS_TXDEEMPH_M6DB_V0 0x024 | 251 | #define QPHY_V3_PCS_TXDEEMPH_M6DB_V0 0x024 |
243 | #define QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0 0x028 | 252 | #define QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0 0x028 |
244 | #define QPHY_V3_PCS_TXDEEMPH_M6DB_V1 0x02c | 253 | #define QPHY_V3_PCS_TXDEEMPH_M6DB_V1 0x02c |
@@ -275,6 +284,12 @@ | |||
275 | #define QPHY_V3_PCS_FLL_CNT_VAL_L 0x0cc | 284 | #define QPHY_V3_PCS_FLL_CNT_VAL_L 0x0cc |
276 | #define QPHY_V3_PCS_FLL_CNT_VAL_H_TOL 0x0d0 | 285 | #define QPHY_V3_PCS_FLL_CNT_VAL_H_TOL 0x0d0 |
277 | #define QPHY_V3_PCS_FLL_MAN_CODE 0x0d4 | 286 | #define QPHY_V3_PCS_FLL_MAN_CODE 0x0d4 |
287 | #define QPHY_V3_PCS_RX_SYM_RESYNC_CTRL 0x134 | ||
288 | #define QPHY_V3_PCS_RX_MIN_HIBERN8_TIME 0x138 | ||
289 | #define QPHY_V3_PCS_RX_SIGDET_CTRL1 0x13c | ||
290 | #define QPHY_V3_PCS_RX_SIGDET_CTRL2 0x140 | ||
291 | #define QPHY_V3_PCS_TX_MID_TERM_CTRL1 0x1bc | ||
292 | #define QPHY_V3_PCS_MULTI_LANE_CTRL1 0x1c4 | ||
278 | #define QPHY_V3_PCS_RX_SIGDET_LVL 0x1d8 | 293 | #define QPHY_V3_PCS_RX_SIGDET_LVL 0x1d8 |
279 | #define QPHY_V3_PCS_REFGEN_REQ_CONFIG1 0x20c | 294 | #define QPHY_V3_PCS_REFGEN_REQ_CONFIG1 0x20c |
280 | #define QPHY_V3_PCS_REFGEN_REQ_CONFIG2 0x210 | 295 | #define QPHY_V3_PCS_REFGEN_REQ_CONFIG2 0x210 |
diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c index e70e425f26f5..9ce531194f8a 100644 --- a/drivers/phy/qualcomm/phy-qcom-qusb2.c +++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c | |||
@@ -800,7 +800,9 @@ static int qusb2_phy_probe(struct platform_device *pdev) | |||
800 | 800 | ||
801 | ret = devm_regulator_bulk_get(dev, num, qphy->vregs); | 801 | ret = devm_regulator_bulk_get(dev, num, qphy->vregs); |
802 | if (ret) { | 802 | if (ret) { |
803 | dev_err(dev, "failed to get regulator supplies\n"); | 803 | if (ret != -EPROBE_DEFER) |
804 | dev_err(dev, "failed to get regulator supplies: %d\n", | ||
805 | ret); | ||
804 | return ret; | 806 | return ret; |
805 | } | 807 | } |
806 | 808 | ||
diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-i.h b/drivers/phy/qualcomm/phy-qcom-ufs-i.h index 822c83b8efcd..681644e43248 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs-i.h +++ b/drivers/phy/qualcomm/phy-qcom-ufs-i.h | |||
@@ -17,9 +17,9 @@ | |||
17 | 17 | ||
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/clk.h> | 19 | #include <linux/clk.h> |
20 | #include <linux/phy/phy.h> | ||
20 | #include <linux/regulator/consumer.h> | 21 | #include <linux/regulator/consumer.h> |
21 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
22 | #include <linux/phy/phy-qcom-ufs.h> | ||
23 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
24 | #include <linux/io.h> | 24 | #include <linux/io.h> |
25 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c b/drivers/phy/qualcomm/phy-qcom-ufs.c index c5493ea51282..f2979ccad00a 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs.c | |||
@@ -431,56 +431,6 @@ static void ufs_qcom_phy_disable_ref_clk(struct ufs_qcom_phy *phy) | |||
431 | } | 431 | } |
432 | } | 432 | } |
433 | 433 | ||
434 | #define UFS_REF_CLK_EN (1 << 5) | ||
435 | |||
436 | static void ufs_qcom_phy_dev_ref_clk_ctrl(struct phy *generic_phy, bool enable) | ||
437 | { | ||
438 | struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy); | ||
439 | |||
440 | if (phy->dev_ref_clk_ctrl_mmio && | ||
441 | (enable ^ phy->is_dev_ref_clk_enabled)) { | ||
442 | u32 temp = readl_relaxed(phy->dev_ref_clk_ctrl_mmio); | ||
443 | |||
444 | if (enable) | ||
445 | temp |= UFS_REF_CLK_EN; | ||
446 | else | ||
447 | temp &= ~UFS_REF_CLK_EN; | ||
448 | |||
449 | /* | ||
450 | * If we are here to disable this clock immediately after | ||
451 | * entering into hibern8, we need to make sure that device | ||
452 | * ref_clk is active atleast 1us after the hibern8 enter. | ||
453 | */ | ||
454 | if (!enable) | ||
455 | udelay(1); | ||
456 | |||
457 | writel_relaxed(temp, phy->dev_ref_clk_ctrl_mmio); | ||
458 | /* ensure that ref_clk is enabled/disabled before we return */ | ||
459 | wmb(); | ||
460 | /* | ||
461 | * If we call hibern8 exit after this, we need to make sure that | ||
462 | * device ref_clk is stable for atleast 1us before the hibern8 | ||
463 | * exit command. | ||
464 | */ | ||
465 | if (enable) | ||
466 | udelay(1); | ||
467 | |||
468 | phy->is_dev_ref_clk_enabled = enable; | ||
469 | } | ||
470 | } | ||
471 | |||
472 | void ufs_qcom_phy_enable_dev_ref_clk(struct phy *generic_phy) | ||
473 | { | ||
474 | ufs_qcom_phy_dev_ref_clk_ctrl(generic_phy, true); | ||
475 | } | ||
476 | EXPORT_SYMBOL_GPL(ufs_qcom_phy_enable_dev_ref_clk); | ||
477 | |||
478 | void ufs_qcom_phy_disable_dev_ref_clk(struct phy *generic_phy) | ||
479 | { | ||
480 | ufs_qcom_phy_dev_ref_clk_ctrl(generic_phy, false); | ||
481 | } | ||
482 | EXPORT_SYMBOL_GPL(ufs_qcom_phy_disable_dev_ref_clk); | ||
483 | |||
484 | /* Turn ON M-PHY RMMI interface clocks */ | 434 | /* Turn ON M-PHY RMMI interface clocks */ |
485 | static int ufs_qcom_phy_enable_iface_clk(struct ufs_qcom_phy *phy) | 435 | static int ufs_qcom_phy_enable_iface_clk(struct ufs_qcom_phy *phy) |
486 | { | 436 | { |
diff --git a/drivers/phy/renesas/Kconfig b/drivers/phy/renesas/Kconfig index 4bd390c79d21..e340a925bbb1 100644 --- a/drivers/phy/renesas/Kconfig +++ b/drivers/phy/renesas/Kconfig | |||
@@ -1,3 +1,4 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
1 | # | 2 | # |
2 | # Phy drivers for Renesas platforms | 3 | # Phy drivers for Renesas platforms |
3 | # | 4 | # |
diff --git a/drivers/phy/renesas/Makefile b/drivers/phy/renesas/Makefile index 4b76fc439ed6..b599ff8a4349 100644 --- a/drivers/phy/renesas/Makefile +++ b/drivers/phy/renesas/Makefile | |||
@@ -1,3 +1,4 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
1 | obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o | 2 | obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o |
2 | obj-$(CONFIG_PHY_RCAR_GEN3_PCIE) += phy-rcar-gen3-pcie.o | 3 | obj-$(CONFIG_PHY_RCAR_GEN3_PCIE) += phy-rcar-gen3-pcie.o |
3 | obj-$(CONFIG_PHY_RCAR_GEN3_USB2) += phy-rcar-gen3-usb2.o | 4 | obj-$(CONFIG_PHY_RCAR_GEN3_USB2) += phy-rcar-gen3-usb2.o |
diff --git a/drivers/phy/renesas/phy-rcar-gen2.c b/drivers/phy/renesas/phy-rcar-gen2.c index 97d4dd6ea924..72eeb066912d 100644 --- a/drivers/phy/renesas/phy-rcar-gen2.c +++ b/drivers/phy/renesas/phy-rcar-gen2.c | |||
@@ -1,12 +1,9 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * Renesas R-Car Gen2 PHY driver | 3 | * Renesas R-Car Gen2 PHY driver |
3 | * | 4 | * |
4 | * Copyright (C) 2014 Renesas Solutions Corp. | 5 | * Copyright (C) 2014 Renesas Solutions Corp. |
5 | * Copyright (C) 2014 Cogent Embedded, Inc. | 6 | * Copyright (C) 2014 Cogent Embedded, Inc. |
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | 7 | */ |
11 | 8 | ||
12 | #include <linux/clk.h> | 9 | #include <linux/clk.h> |
diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index fb8f05e39cf7..d0f412c25981 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c | |||
@@ -1,3 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * Renesas R-Car Gen3 for USB2.0 PHY driver | 3 | * Renesas R-Car Gen3 for USB2.0 PHY driver |
3 | * | 4 | * |
@@ -6,10 +7,6 @@ | |||
6 | * This is based on the phy-rcar-gen2 driver: | 7 | * This is based on the phy-rcar-gen2 driver: |
7 | * Copyright (C) 2014 Renesas Solutions Corp. | 8 | * Copyright (C) 2014 Renesas Solutions Corp. |
8 | * Copyright (C) 2014 Cogent Embedded, Inc. | 9 | * Copyright (C) 2014 Cogent Embedded, Inc. |
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | 10 | */ |
14 | 11 | ||
15 | #include <linux/extcon-provider.h> | 12 | #include <linux/extcon-provider.h> |
@@ -81,18 +78,29 @@ | |||
81 | #define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */ | 78 | #define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */ |
82 | #define USB2_ADPCTRL_DRVVBUS BIT(4) | 79 | #define USB2_ADPCTRL_DRVVBUS BIT(4) |
83 | 80 | ||
84 | #define RCAR_GEN3_PHY_HAS_DEDICATED_PINS 1 | ||
85 | |||
86 | struct rcar_gen3_chan { | 81 | struct rcar_gen3_chan { |
87 | void __iomem *base; | 82 | void __iomem *base; |
88 | struct extcon_dev *extcon; | 83 | struct extcon_dev *extcon; |
89 | struct phy *phy; | 84 | struct phy *phy; |
90 | struct regulator *vbus; | 85 | struct regulator *vbus; |
91 | struct work_struct work; | 86 | struct work_struct work; |
87 | enum usb_dr_mode dr_mode; | ||
92 | bool extcon_host; | 88 | bool extcon_host; |
93 | bool has_otg_pins; | 89 | bool is_otg_channel; |
90 | bool uses_otg_pins; | ||
94 | }; | 91 | }; |
95 | 92 | ||
93 | /* | ||
94 | * Combination about is_otg_channel and uses_otg_pins: | ||
95 | * | ||
96 | * Parameters || Behaviors | ||
97 | * is_otg_channel | uses_otg_pins || irqs | role sysfs | ||
98 | * ---------------------+---------------++--------------+------------ | ||
99 | * true | true || enabled | enabled | ||
100 | * true | false || disabled | enabled | ||
101 | * false | any || disabled | disabled | ||
102 | */ | ||
103 | |||
96 | static void rcar_gen3_phy_usb2_work(struct work_struct *work) | 104 | static void rcar_gen3_phy_usb2_work(struct work_struct *work) |
97 | { | 105 | { |
98 | struct rcar_gen3_chan *ch = container_of(work, struct rcar_gen3_chan, | 106 | struct rcar_gen3_chan *ch = container_of(work, struct rcar_gen3_chan, |
@@ -147,6 +155,18 @@ static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) | |||
147 | writel(val, usb2_base + USB2_ADPCTRL); | 155 | writel(val, usb2_base + USB2_ADPCTRL); |
148 | } | 156 | } |
149 | 157 | ||
158 | static void rcar_gen3_control_otg_irq(struct rcar_gen3_chan *ch, int enable) | ||
159 | { | ||
160 | void __iomem *usb2_base = ch->base; | ||
161 | u32 val = readl(usb2_base + USB2_OBINTEN); | ||
162 | |||
163 | if (ch->uses_otg_pins && enable) | ||
164 | val |= USB2_OBINT_BITS; | ||
165 | else | ||
166 | val &= ~USB2_OBINT_BITS; | ||
167 | writel(val, usb2_base + USB2_OBINTEN); | ||
168 | } | ||
169 | |||
150 | static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch) | 170 | static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch) |
151 | { | 171 | { |
152 | rcar_gen3_set_linectrl(ch, 1, 1); | 172 | rcar_gen3_set_linectrl(ch, 1, 1); |
@@ -192,20 +212,19 @@ static void rcar_gen3_init_for_a_peri(struct rcar_gen3_chan *ch) | |||
192 | 212 | ||
193 | static void rcar_gen3_init_from_a_peri_to_a_host(struct rcar_gen3_chan *ch) | 213 | static void rcar_gen3_init_from_a_peri_to_a_host(struct rcar_gen3_chan *ch) |
194 | { | 214 | { |
195 | void __iomem *usb2_base = ch->base; | 215 | rcar_gen3_control_otg_irq(ch, 0); |
196 | u32 val; | ||
197 | 216 | ||
198 | val = readl(usb2_base + USB2_OBINTEN); | 217 | rcar_gen3_enable_vbus_ctrl(ch, 1); |
199 | writel(val & ~USB2_OBINT_BITS, usb2_base + USB2_OBINTEN); | ||
200 | |||
201 | rcar_gen3_enable_vbus_ctrl(ch, 0); | ||
202 | rcar_gen3_init_for_host(ch); | 218 | rcar_gen3_init_for_host(ch); |
203 | 219 | ||
204 | writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN); | 220 | rcar_gen3_control_otg_irq(ch, 1); |
205 | } | 221 | } |
206 | 222 | ||
207 | static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) | 223 | static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) |
208 | { | 224 | { |
225 | if (!ch->uses_otg_pins) | ||
226 | return (ch->dr_mode == USB_DR_MODE_HOST) ? false : true; | ||
227 | |||
209 | return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); | 228 | return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); |
210 | } | 229 | } |
211 | 230 | ||
@@ -237,7 +256,7 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr, | |||
237 | bool is_b_device; | 256 | bool is_b_device; |
238 | enum phy_mode cur_mode, new_mode; | 257 | enum phy_mode cur_mode, new_mode; |
239 | 258 | ||
240 | if (!ch->has_otg_pins || !ch->phy->init_count) | 259 | if (!ch->is_otg_channel || !ch->phy->init_count) |
241 | return -EIO; | 260 | return -EIO; |
242 | 261 | ||
243 | if (!strncmp(buf, "host", strlen("host"))) | 262 | if (!strncmp(buf, "host", strlen("host"))) |
@@ -275,7 +294,7 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr, | |||
275 | { | 294 | { |
276 | struct rcar_gen3_chan *ch = dev_get_drvdata(dev); | 295 | struct rcar_gen3_chan *ch = dev_get_drvdata(dev); |
277 | 296 | ||
278 | if (!ch->has_otg_pins || !ch->phy->init_count) | 297 | if (!ch->is_otg_channel || !ch->phy->init_count) |
279 | return -EIO; | 298 | return -EIO; |
280 | 299 | ||
281 | return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" : | 300 | return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" : |
@@ -291,8 +310,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) | |||
291 | val = readl(usb2_base + USB2_VBCTRL); | 310 | val = readl(usb2_base + USB2_VBCTRL); |
292 | writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL); | 311 | writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL); |
293 | writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA); | 312 | writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA); |
294 | val = readl(usb2_base + USB2_OBINTEN); | 313 | rcar_gen3_control_otg_irq(ch, 1); |
295 | writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN); | ||
296 | val = readl(usb2_base + USB2_ADPCTRL); | 314 | val = readl(usb2_base + USB2_ADPCTRL); |
297 | writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL); | 315 | writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL); |
298 | val = readl(usb2_base + USB2_LINECTRL1); | 316 | val = readl(usb2_base + USB2_LINECTRL1); |
@@ -314,7 +332,7 @@ static int rcar_gen3_phy_usb2_init(struct phy *p) | |||
314 | writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET); | 332 | writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET); |
315 | 333 | ||
316 | /* Initialize otg part */ | 334 | /* Initialize otg part */ |
317 | if (channel->has_otg_pins) | 335 | if (channel->is_otg_channel) |
318 | rcar_gen3_init_otg(channel); | 336 | rcar_gen3_init_otg(channel); |
319 | 337 | ||
320 | return 0; | 338 | return 0; |
@@ -388,21 +406,10 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) | |||
388 | } | 406 | } |
389 | 407 | ||
390 | static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { | 408 | static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { |
391 | { | 409 | { .compatible = "renesas,usb2-phy-r8a7795" }, |
392 | .compatible = "renesas,usb2-phy-r8a7795", | 410 | { .compatible = "renesas,usb2-phy-r8a7796" }, |
393 | .data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS, | 411 | { .compatible = "renesas,usb2-phy-r8a77965" }, |
394 | }, | 412 | { .compatible = "renesas,rcar-gen3-usb2-phy" }, |
395 | { | ||
396 | .compatible = "renesas,usb2-phy-r8a7796", | ||
397 | .data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS, | ||
398 | }, | ||
399 | { | ||
400 | .compatible = "renesas,usb2-phy-r8a77965", | ||
401 | .data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS, | ||
402 | }, | ||
403 | { | ||
404 | .compatible = "renesas,rcar-gen3-usb2-phy", | ||
405 | }, | ||
406 | { } | 413 | { } |
407 | }; | 414 | }; |
408 | MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table); | 415 | MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table); |
@@ -445,10 +452,13 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) | |||
445 | dev_err(dev, "No irq handler (%d)\n", irq); | 452 | dev_err(dev, "No irq handler (%d)\n", irq); |
446 | } | 453 | } |
447 | 454 | ||
448 | if (of_usb_get_dr_mode_by_phy(dev->of_node, 0) == USB_DR_MODE_OTG) { | 455 | channel->dr_mode = of_usb_get_dr_mode_by_phy(dev->of_node, 0); |
456 | if (channel->dr_mode != USB_DR_MODE_UNKNOWN) { | ||
449 | int ret; | 457 | int ret; |
450 | 458 | ||
451 | channel->has_otg_pins = (uintptr_t)of_device_get_match_data(dev); | 459 | channel->is_otg_channel = true; |
460 | channel->uses_otg_pins = !of_property_read_bool(dev->of_node, | ||
461 | "renesas,no-otg-pins"); | ||
452 | channel->extcon = devm_extcon_dev_allocate(dev, | 462 | channel->extcon = devm_extcon_dev_allocate(dev, |
453 | rcar_gen3_phy_cable); | 463 | rcar_gen3_phy_cable); |
454 | if (IS_ERR(channel->extcon)) | 464 | if (IS_ERR(channel->extcon)) |
@@ -490,7 +500,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) | |||
490 | dev_err(dev, "Failed to register PHY provider\n"); | 500 | dev_err(dev, "Failed to register PHY provider\n"); |
491 | ret = PTR_ERR(provider); | 501 | ret = PTR_ERR(provider); |
492 | goto error; | 502 | goto error; |
493 | } else if (channel->has_otg_pins) { | 503 | } else if (channel->is_otg_channel) { |
494 | int ret; | 504 | int ret; |
495 | 505 | ||
496 | ret = device_create_file(dev, &dev_attr_role); | 506 | ret = device_create_file(dev, &dev_attr_role); |
@@ -510,7 +520,7 @@ static int rcar_gen3_phy_usb2_remove(struct platform_device *pdev) | |||
510 | { | 520 | { |
511 | struct rcar_gen3_chan *channel = platform_get_drvdata(pdev); | 521 | struct rcar_gen3_chan *channel = platform_get_drvdata(pdev); |
512 | 522 | ||
513 | if (channel->has_otg_pins) | 523 | if (channel->is_otg_channel) |
514 | device_remove_file(&pdev->dev, &dev_attr_role); | 524 | device_remove_file(&pdev->dev, &dev_attr_role); |
515 | 525 | ||
516 | pm_runtime_disable(&pdev->dev); | 526 | pm_runtime_disable(&pdev->dev); |
diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb3.c b/drivers/phy/renesas/phy-rcar-gen3-usb3.c index 88c83c9b8ff9..566b4cf4ff38 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb3.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb3.c | |||
@@ -1,11 +1,8 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * Renesas R-Car Gen3 for USB3.0 PHY driver | 3 | * Renesas R-Car Gen3 for USB3.0 PHY driver |
3 | * | 4 | * |
4 | * Copyright (C) 2017 Renesas Electronics Corporation | 5 | * Copyright (C) 2017 Renesas Electronics Corporation |
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | 6 | */ |
10 | 7 | ||
11 | #include <linux/clk.h> | 8 | #include <linux/clk.h> |
diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig index 0e15119ddfc6..990204a46eb6 100644 --- a/drivers/phy/rockchip/Kconfig +++ b/drivers/phy/rockchip/Kconfig | |||
@@ -15,6 +15,14 @@ config PHY_ROCKCHIP_EMMC | |||
15 | help | 15 | help |
16 | Enable this to support the Rockchip EMMC PHY. | 16 | Enable this to support the Rockchip EMMC PHY. |
17 | 17 | ||
18 | config PHY_ROCKCHIP_INNO_HDMI | ||
19 | tristate "Rockchip INNO HDMI PHY Driver" | ||
20 | depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF | ||
21 | depends on COMMON_CLK | ||
22 | select GENERIC_PHY | ||
23 | help | ||
24 | Enable this to support the Rockchip Innosilicon HDMI PHY. | ||
25 | |||
18 | config PHY_ROCKCHIP_INNO_USB2 | 26 | config PHY_ROCKCHIP_INNO_USB2 |
19 | tristate "Rockchip INNO USB2PHY Driver" | 27 | tristate "Rockchip INNO USB2PHY Driver" |
20 | depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF | 28 | depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF |
diff --git a/drivers/phy/rockchip/Makefile b/drivers/phy/rockchip/Makefile index 7f149d989046..fd21cbaf40dd 100644 --- a/drivers/phy/rockchip/Makefile +++ b/drivers/phy/rockchip/Makefile | |||
@@ -1,6 +1,7 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | 1 | # SPDX-License-Identifier: GPL-2.0 |
2 | obj-$(CONFIG_PHY_ROCKCHIP_DP) += phy-rockchip-dp.o | 2 | obj-$(CONFIG_PHY_ROCKCHIP_DP) += phy-rockchip-dp.o |
3 | obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o | 3 | obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o |
4 | obj-$(CONFIG_PHY_ROCKCHIP_INNO_HDMI) += phy-rockchip-inno-hdmi.o | ||
4 | obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o | 5 | obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o |
5 | obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o | 6 | obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o |
6 | obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o | 7 | obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o |
diff --git a/drivers/phy/rockchip/phy-rockchip-emmc.c b/drivers/phy/rockchip/phy-rockchip-emmc.c index b237360f95f6..19bf84f0bc67 100644 --- a/drivers/phy/rockchip/phy-rockchip-emmc.c +++ b/drivers/phy/rockchip/phy-rockchip-emmc.c | |||
@@ -337,8 +337,8 @@ static int rockchip_emmc_phy_probe(struct platform_device *pdev) | |||
337 | return -ENOMEM; | 337 | return -ENOMEM; |
338 | 338 | ||
339 | if (of_property_read_u32(dev->of_node, "reg", ®_offset)) { | 339 | if (of_property_read_u32(dev->of_node, "reg", ®_offset)) { |
340 | dev_err(dev, "missing reg property in node %s\n", | 340 | dev_err(dev, "missing reg property in node %pOFn\n", |
341 | dev->of_node->name); | 341 | dev->of_node); |
342 | return -EINVAL; | 342 | return -EINVAL; |
343 | } | 343 | } |
344 | 344 | ||
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c new file mode 100644 index 000000000000..b10a84cab4a7 --- /dev/null +++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | |||
@@ -0,0 +1,1277 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
2 | /* | ||
3 | * Copyright (c) 2017 Rockchip Electronics Co. Ltd. | ||
4 | * | ||
5 | * Author: Zheng Yang <zhengyang@rock-chips.com> | ||
6 | * Heiko Stuebner <heiko@sntech.de> | ||
7 | */ | ||
8 | |||
9 | #include <linux/clk.h> | ||
10 | #include <linux/clk-provider.h> | ||
11 | #include <linux/delay.h> | ||
12 | #include <linux/io.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/nvmem-consumer.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/of_device.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/regmap.h> | ||
21 | #include <linux/phy/phy.h> | ||
22 | #include <linux/slab.h> | ||
23 | |||
24 | #define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l))) | ||
25 | |||
26 | /* REG: 0x00 */ | ||
27 | #define RK3228_PRE_PLL_REFCLK_SEL_PCLK BIT(0) | ||
28 | /* REG: 0x01 */ | ||
29 | #define RK3228_BYPASS_RXSENSE_EN BIT(2) | ||
30 | #define RK3228_BYPASS_PWRON_EN BIT(1) | ||
31 | #define RK3228_BYPASS_PLLPD_EN BIT(0) | ||
32 | /* REG: 0x02 */ | ||
33 | #define RK3228_BYPASS_PDATA_EN BIT(4) | ||
34 | #define RK3228_PDATAEN_DISABLE BIT(0) | ||
35 | /* REG: 0x03 */ | ||
36 | #define RK3228_BYPASS_AUTO_TERM_RES_CAL BIT(7) | ||
37 | #define RK3228_AUTO_TERM_RES_CAL_SPEED_14_8(x) UPDATE(x, 6, 0) | ||
38 | /* REG: 0x04 */ | ||
39 | #define RK3228_AUTO_TERM_RES_CAL_SPEED_7_0(x) UPDATE(x, 7, 0) | ||
40 | /* REG: 0xaa */ | ||
41 | #define RK3228_POST_PLL_CTRL_MANUAL BIT(0) | ||
42 | /* REG: 0xe0 */ | ||
43 | #define RK3228_POST_PLL_POWER_DOWN BIT(5) | ||
44 | #define RK3228_PRE_PLL_POWER_DOWN BIT(4) | ||
45 | #define RK3228_RXSENSE_CLK_CH_ENABLE BIT(3) | ||
46 | #define RK3228_RXSENSE_DATA_CH2_ENABLE BIT(2) | ||
47 | #define RK3228_RXSENSE_DATA_CH1_ENABLE BIT(1) | ||
48 | #define RK3228_RXSENSE_DATA_CH0_ENABLE BIT(0) | ||
49 | /* REG: 0xe1 */ | ||
50 | #define RK3228_BANDGAP_ENABLE BIT(4) | ||
51 | #define RK3228_TMDS_DRIVER_ENABLE GENMASK(3, 0) | ||
52 | /* REG: 0xe2 */ | ||
53 | #define RK3228_PRE_PLL_FB_DIV_8_MASK BIT(7) | ||
54 | #define RK3228_PRE_PLL_FB_DIV_8(x) UPDATE((x) >> 8, 7, 7) | ||
55 | #define RK3228_PCLK_VCO_DIV_5_MASK BIT(5) | ||
56 | #define RK3228_PCLK_VCO_DIV_5(x) UPDATE(x, 5, 5) | ||
57 | #define RK3228_PRE_PLL_PRE_DIV_MASK GENMASK(4, 0) | ||
58 | #define RK3228_PRE_PLL_PRE_DIV(x) UPDATE(x, 4, 0) | ||
59 | /* REG: 0xe3 */ | ||
60 | #define RK3228_PRE_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0) | ||
61 | /* REG: 0xe4 */ | ||
62 | #define RK3228_PRE_PLL_PCLK_DIV_B_MASK GENMASK(6, 5) | ||
63 | #define RK3228_PRE_PLL_PCLK_DIV_B_SHIFT 5 | ||
64 | #define RK3228_PRE_PLL_PCLK_DIV_B(x) UPDATE(x, 6, 5) | ||
65 | #define RK3228_PRE_PLL_PCLK_DIV_A_MASK GENMASK(4, 0) | ||
66 | #define RK3228_PRE_PLL_PCLK_DIV_A(x) UPDATE(x, 4, 0) | ||
67 | /* REG: 0xe5 */ | ||
68 | #define RK3228_PRE_PLL_PCLK_DIV_C_MASK GENMASK(6, 5) | ||
69 | #define RK3228_PRE_PLL_PCLK_DIV_C(x) UPDATE(x, 6, 5) | ||
70 | #define RK3228_PRE_PLL_PCLK_DIV_D_MASK GENMASK(4, 0) | ||
71 | #define RK3228_PRE_PLL_PCLK_DIV_D(x) UPDATE(x, 4, 0) | ||
72 | /* REG: 0xe6 */ | ||
73 | #define RK3228_PRE_PLL_TMDSCLK_DIV_C_MASK GENMASK(5, 4) | ||
74 | #define RK3228_PRE_PLL_TMDSCLK_DIV_C(x) UPDATE(x, 5, 4) | ||
75 | #define RK3228_PRE_PLL_TMDSCLK_DIV_A_MASK GENMASK(3, 2) | ||
76 | #define RK3228_PRE_PLL_TMDSCLK_DIV_A(x) UPDATE(x, 3, 2) | ||
77 | #define RK3228_PRE_PLL_TMDSCLK_DIV_B_MASK GENMASK(1, 0) | ||
78 | #define RK3228_PRE_PLL_TMDSCLK_DIV_B(x) UPDATE(x, 1, 0) | ||
79 | /* REG: 0xe8 */ | ||
80 | #define RK3228_PRE_PLL_LOCK_STATUS BIT(0) | ||
81 | /* REG: 0xe9 */ | ||
82 | #define RK3228_POST_PLL_POST_DIV_ENABLE UPDATE(3, 7, 6) | ||
83 | #define RK3228_POST_PLL_PRE_DIV_MASK GENMASK(4, 0) | ||
84 | #define RK3228_POST_PLL_PRE_DIV(x) UPDATE(x, 4, 0) | ||
85 | /* REG: 0xea */ | ||
86 | #define RK3228_POST_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0) | ||
87 | /* REG: 0xeb */ | ||
88 | #define RK3228_POST_PLL_FB_DIV_8_MASK BIT(7) | ||
89 | #define RK3228_POST_PLL_FB_DIV_8(x) UPDATE((x) >> 8, 7, 7) | ||
90 | #define RK3228_POST_PLL_POST_DIV_MASK GENMASK(5, 4) | ||
91 | #define RK3228_POST_PLL_POST_DIV(x) UPDATE(x, 5, 4) | ||
92 | #define RK3228_POST_PLL_LOCK_STATUS BIT(0) | ||
93 | /* REG: 0xee */ | ||
94 | #define RK3228_TMDS_CH_TA_ENABLE GENMASK(7, 4) | ||
95 | /* REG: 0xef */ | ||
96 | #define RK3228_TMDS_CLK_CH_TA(x) UPDATE(x, 7, 6) | ||
97 | #define RK3228_TMDS_DATA_CH2_TA(x) UPDATE(x, 5, 4) | ||
98 | #define RK3228_TMDS_DATA_CH1_TA(x) UPDATE(x, 3, 2) | ||
99 | #define RK3228_TMDS_DATA_CH0_TA(x) UPDATE(x, 1, 0) | ||
100 | /* REG: 0xf0 */ | ||
101 | #define RK3228_TMDS_DATA_CH2_PRE_EMPHASIS_MASK GENMASK(5, 4) | ||
102 | #define RK3228_TMDS_DATA_CH2_PRE_EMPHASIS(x) UPDATE(x, 5, 4) | ||
103 | #define RK3228_TMDS_DATA_CH1_PRE_EMPHASIS_MASK GENMASK(3, 2) | ||
104 | #define RK3228_TMDS_DATA_CH1_PRE_EMPHASIS(x) UPDATE(x, 3, 2) | ||
105 | #define RK3228_TMDS_DATA_CH0_PRE_EMPHASIS_MASK GENMASK(1, 0) | ||
106 | #define RK3228_TMDS_DATA_CH0_PRE_EMPHASIS(x) UPDATE(x, 1, 0) | ||
107 | /* REG: 0xf1 */ | ||
108 | #define RK3228_TMDS_CLK_CH_OUTPUT_SWING(x) UPDATE(x, 7, 4) | ||
109 | #define RK3228_TMDS_DATA_CH2_OUTPUT_SWING(x) UPDATE(x, 3, 0) | ||
110 | /* REG: 0xf2 */ | ||
111 | #define RK3228_TMDS_DATA_CH1_OUTPUT_SWING(x) UPDATE(x, 7, 4) | ||
112 | #define RK3228_TMDS_DATA_CH0_OUTPUT_SWING(x) UPDATE(x, 3, 0) | ||
113 | |||
114 | /* REG: 0x01 */ | ||
115 | #define RK3328_BYPASS_RXSENSE_EN BIT(2) | ||
116 | #define RK3328_BYPASS_POWERON_EN BIT(1) | ||
117 | #define RK3328_BYPASS_PLLPD_EN BIT(0) | ||
118 | /* REG: 0x02 */ | ||
119 | #define RK3328_INT_POL_HIGH BIT(7) | ||
120 | #define RK3328_BYPASS_PDATA_EN BIT(4) | ||
121 | #define RK3328_PDATA_EN BIT(0) | ||
122 | /* REG:0x05 */ | ||
123 | #define RK3328_INT_TMDS_CLK(x) UPDATE(x, 7, 4) | ||
124 | #define RK3328_INT_TMDS_D2(x) UPDATE(x, 3, 0) | ||
125 | /* REG:0x07 */ | ||
126 | #define RK3328_INT_TMDS_D1(x) UPDATE(x, 7, 4) | ||
127 | #define RK3328_INT_TMDS_D0(x) UPDATE(x, 3, 0) | ||
128 | /* for all RK3328_INT_TMDS_*, ESD_DET as defined in 0xc8-0xcb */ | ||
129 | #define RK3328_INT_AGND_LOW_PULSE_LOCKED BIT(3) | ||
130 | #define RK3328_INT_RXSENSE_LOW_PULSE_LOCKED BIT(2) | ||
131 | #define RK3328_INT_VSS_AGND_ESD_DET BIT(1) | ||
132 | #define RK3328_INT_AGND_VSS_ESD_DET BIT(0) | ||
133 | /* REG: 0xa0 */ | ||
134 | #define RK3328_PCLK_VCO_DIV_5_MASK BIT(1) | ||
135 | #define RK3328_PCLK_VCO_DIV_5(x) UPDATE(x, 1, 1) | ||
136 | #define RK3328_PRE_PLL_POWER_DOWN BIT(0) | ||
137 | /* REG: 0xa1 */ | ||
138 | #define RK3328_PRE_PLL_PRE_DIV_MASK GENMASK(5, 0) | ||
139 | #define RK3328_PRE_PLL_PRE_DIV(x) UPDATE(x, 5, 0) | ||
140 | /* REG: 0xa2 */ | ||
141 | /* unset means center spread */ | ||
142 | #define RK3328_SPREAD_SPECTRUM_MOD_DOWN BIT(7) | ||
143 | #define RK3328_SPREAD_SPECTRUM_MOD_DISABLE BIT(6) | ||
144 | #define RK3328_PRE_PLL_FRAC_DIV_DISABLE UPDATE(3, 5, 4) | ||
145 | #define RK3328_PRE_PLL_FB_DIV_11_8_MASK GENMASK(3, 0) | ||
146 | #define RK3328_PRE_PLL_FB_DIV_11_8(x) UPDATE((x) >> 8, 3, 0) | ||
147 | /* REG: 0xa3 */ | ||
148 | #define RK3328_PRE_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0) | ||
149 | /* REG: 0xa4*/ | ||
150 | #define RK3328_PRE_PLL_TMDSCLK_DIV_C_MASK GENMASK(1, 0) | ||
151 | #define RK3328_PRE_PLL_TMDSCLK_DIV_C(x) UPDATE(x, 1, 0) | ||
152 | #define RK3328_PRE_PLL_TMDSCLK_DIV_B_MASK GENMASK(3, 2) | ||
153 | #define RK3328_PRE_PLL_TMDSCLK_DIV_B(x) UPDATE(x, 3, 2) | ||
154 | #define RK3328_PRE_PLL_TMDSCLK_DIV_A_MASK GENMASK(5, 4) | ||
155 | #define RK3328_PRE_PLL_TMDSCLK_DIV_A(x) UPDATE(x, 5, 4) | ||
156 | /* REG: 0xa5 */ | ||
157 | #define RK3328_PRE_PLL_PCLK_DIV_B_SHIFT 5 | ||
158 | #define RK3328_PRE_PLL_PCLK_DIV_B_MASK GENMASK(6, 5) | ||
159 | #define RK3328_PRE_PLL_PCLK_DIV_B(x) UPDATE(x, 6, 5) | ||
160 | #define RK3328_PRE_PLL_PCLK_DIV_A_MASK GENMASK(4, 0) | ||
161 | #define RK3328_PRE_PLL_PCLK_DIV_A(x) UPDATE(x, 4, 0) | ||
162 | /* REG: 0xa6 */ | ||
163 | #define RK3328_PRE_PLL_PCLK_DIV_C_SHIFT 5 | ||
164 | #define RK3328_PRE_PLL_PCLK_DIV_C_MASK GENMASK(6, 5) | ||
165 | #define RK3328_PRE_PLL_PCLK_DIV_C(x) UPDATE(x, 6, 5) | ||
166 | #define RK3328_PRE_PLL_PCLK_DIV_D_MASK GENMASK(4, 0) | ||
167 | #define RK3328_PRE_PLL_PCLK_DIV_D(x) UPDATE(x, 4, 0) | ||
168 | /* REG: 0xa9 */ | ||
169 | #define RK3328_PRE_PLL_LOCK_STATUS BIT(0) | ||
170 | /* REG: 0xaa */ | ||
171 | #define RK3328_POST_PLL_POST_DIV_ENABLE GENMASK(3, 2) | ||
172 | #define RK3328_POST_PLL_REFCLK_SEL_TMDS BIT(1) | ||
173 | #define RK3328_POST_PLL_POWER_DOWN BIT(0) | ||
174 | /* REG:0xab */ | ||
175 | #define RK3328_POST_PLL_FB_DIV_8(x) UPDATE((x) >> 8, 7, 7) | ||
176 | #define RK3328_POST_PLL_PRE_DIV(x) UPDATE(x, 4, 0) | ||
177 | /* REG: 0xac */ | ||
178 | #define RK3328_POST_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0) | ||
179 | /* REG: 0xad */ | ||
180 | #define RK3328_POST_PLL_POST_DIV_MASK GENMASK(1, 0) | ||
181 | #define RK3328_POST_PLL_POST_DIV_2 0x0 | ||
182 | #define RK3328_POST_PLL_POST_DIV_4 0x1 | ||
183 | #define RK3328_POST_PLL_POST_DIV_8 0x3 | ||
184 | /* REG: 0xaf */ | ||
185 | #define RK3328_POST_PLL_LOCK_STATUS BIT(0) | ||
186 | /* REG: 0xb0 */ | ||
187 | #define RK3328_BANDGAP_ENABLE BIT(2) | ||
188 | /* REG: 0xb2 */ | ||
189 | #define RK3328_TMDS_CLK_DRIVER_EN BIT(3) | ||
190 | #define RK3328_TMDS_D2_DRIVER_EN BIT(2) | ||
191 | #define RK3328_TMDS_D1_DRIVER_EN BIT(1) | ||
192 | #define RK3328_TMDS_D0_DRIVER_EN BIT(0) | ||
193 | #define RK3328_TMDS_DRIVER_ENABLE (RK3328_TMDS_CLK_DRIVER_EN | \ | ||
194 | RK3328_TMDS_D2_DRIVER_EN | \ | ||
195 | RK3328_TMDS_D1_DRIVER_EN | \ | ||
196 | RK3328_TMDS_D0_DRIVER_EN) | ||
197 | /* REG:0xc5 */ | ||
198 | #define RK3328_BYPASS_TERM_RESISTOR_CALIB BIT(7) | ||
199 | #define RK3328_TERM_RESISTOR_CALIB_SPEED_14_8(x) UPDATE((x) >> 8, 6, 0) | ||
200 | /* REG:0xc6 */ | ||
201 | #define RK3328_TERM_RESISTOR_CALIB_SPEED_7_0(x) UPDATE(x, 7, 9) | ||
202 | /* REG:0xc7 */ | ||
203 | #define RK3328_TERM_RESISTOR_50 UPDATE(0, 2, 1) | ||
204 | #define RK3328_TERM_RESISTOR_62_5 UPDATE(1, 2, 1) | ||
205 | #define RK3328_TERM_RESISTOR_75 UPDATE(2, 2, 1) | ||
206 | #define RK3328_TERM_RESISTOR_100 UPDATE(3, 2, 1) | ||
207 | /* REG 0xc8 - 0xcb */ | ||
208 | #define RK3328_ESD_DETECT_MASK GENMASK(7, 6) | ||
209 | #define RK3328_ESD_DETECT_340MV (0x0 << 6) | ||
210 | #define RK3328_ESD_DETECT_280MV (0x1 << 6) | ||
211 | #define RK3328_ESD_DETECT_260MV (0x2 << 6) | ||
212 | #define RK3328_ESD_DETECT_240MV (0x3 << 6) | ||
213 | /* resistors can be used in parallel */ | ||
214 | #define RK3328_TMDS_TERM_RESIST_MASK GENMASK(5, 0) | ||
215 | #define RK3328_TMDS_TERM_RESIST_75 BIT(5) | ||
216 | #define RK3328_TMDS_TERM_RESIST_150 BIT(4) | ||
217 | #define RK3328_TMDS_TERM_RESIST_300 BIT(3) | ||
218 | #define RK3328_TMDS_TERM_RESIST_600 BIT(2) | ||
219 | #define RK3328_TMDS_TERM_RESIST_1000 BIT(1) | ||
220 | #define RK3328_TMDS_TERM_RESIST_2000 BIT(0) | ||
221 | /* REG: 0xd1 */ | ||
222 | #define RK3328_PRE_PLL_FRAC_DIV_23_16(x) UPDATE((x) >> 16, 7, 0) | ||
223 | /* REG: 0xd2 */ | ||
224 | #define RK3328_PRE_PLL_FRAC_DIV_15_8(x) UPDATE((x) >> 8, 7, 0) | ||
225 | /* REG: 0xd3 */ | ||
226 | #define RK3328_PRE_PLL_FRAC_DIV_7_0(x) UPDATE(x, 7, 0) | ||
227 | |||
228 | struct inno_hdmi_phy_drv_data; | ||
229 | |||
230 | struct inno_hdmi_phy { | ||
231 | struct device *dev; | ||
232 | struct regmap *regmap; | ||
233 | int irq; | ||
234 | |||
235 | struct phy *phy; | ||
236 | struct clk *sysclk; | ||
237 | struct clk *refoclk; | ||
238 | struct clk *refpclk; | ||
239 | |||
240 | /* platform data */ | ||
241 | const struct inno_hdmi_phy_drv_data *plat_data; | ||
242 | int chip_version; | ||
243 | |||
244 | /* clk provider */ | ||
245 | struct clk_hw hw; | ||
246 | struct clk *phyclk; | ||
247 | unsigned long pixclock; | ||
248 | }; | ||
249 | |||
250 | struct pre_pll_config { | ||
251 | unsigned long pixclock; | ||
252 | unsigned long tmdsclock; | ||
253 | u8 prediv; | ||
254 | u16 fbdiv; | ||
255 | u8 tmds_div_a; | ||
256 | u8 tmds_div_b; | ||
257 | u8 tmds_div_c; | ||
258 | u8 pclk_div_a; | ||
259 | u8 pclk_div_b; | ||
260 | u8 pclk_div_c; | ||
261 | u8 pclk_div_d; | ||
262 | u8 vco_div_5_en; | ||
263 | u32 fracdiv; | ||
264 | }; | ||
265 | |||
266 | struct post_pll_config { | ||
267 | unsigned long tmdsclock; | ||
268 | u8 prediv; | ||
269 | u16 fbdiv; | ||
270 | u8 postdiv; | ||
271 | u8 version; | ||
272 | }; | ||
273 | |||
274 | struct phy_config { | ||
275 | unsigned long tmdsclock; | ||
276 | u8 regs[14]; | ||
277 | }; | ||
278 | |||
279 | struct inno_hdmi_phy_ops { | ||
280 | int (*init)(struct inno_hdmi_phy *inno); | ||
281 | int (*power_on)(struct inno_hdmi_phy *inno, | ||
282 | const struct post_pll_config *cfg, | ||
283 | const struct phy_config *phy_cfg); | ||
284 | void (*power_off)(struct inno_hdmi_phy *inno); | ||
285 | }; | ||
286 | |||
287 | struct inno_hdmi_phy_drv_data { | ||
288 | const struct inno_hdmi_phy_ops *ops; | ||
289 | const struct clk_ops *clk_ops; | ||
290 | const struct phy_config *phy_cfg_table; | ||
291 | }; | ||
292 | |||
293 | static const struct pre_pll_config pre_pll_cfg_table[] = { | ||
294 | { 27000000, 27000000, 1, 90, 3, 2, 2, 10, 3, 3, 4, 0, 0}, | ||
295 | { 27000000, 33750000, 1, 90, 1, 3, 3, 10, 3, 3, 4, 0, 0}, | ||
296 | { 40000000, 40000000, 1, 80, 2, 2, 2, 12, 2, 2, 2, 0, 0}, | ||
297 | { 59341000, 59341000, 1, 98, 3, 1, 2, 1, 3, 3, 4, 0, 0xE6AE6B}, | ||
298 | { 59400000, 59400000, 1, 99, 3, 1, 1, 1, 3, 3, 4, 0, 0}, | ||
299 | { 59341000, 74176250, 1, 98, 0, 3, 3, 1, 3, 3, 4, 0, 0xE6AE6B}, | ||
300 | { 59400000, 74250000, 1, 99, 1, 2, 2, 1, 3, 3, 4, 0, 0}, | ||
301 | { 74176000, 74176000, 1, 98, 1, 2, 2, 1, 2, 3, 4, 0, 0xE6AE6B}, | ||
302 | { 74250000, 74250000, 1, 99, 1, 2, 2, 1, 2, 3, 4, 0, 0}, | ||
303 | { 74176000, 92720000, 4, 494, 1, 2, 2, 1, 3, 3, 4, 0, 0x816817}, | ||
304 | { 74250000, 92812500, 4, 495, 1, 2, 2, 1, 3, 3, 4, 0, 0}, | ||
305 | {148352000, 148352000, 1, 98, 1, 1, 1, 1, 2, 2, 2, 0, 0xE6AE6B}, | ||
306 | {148500000, 148500000, 1, 99, 1, 1, 1, 1, 2, 2, 2, 0, 0}, | ||
307 | {148352000, 185440000, 4, 494, 0, 2, 2, 1, 3, 2, 2, 0, 0x816817}, | ||
308 | {148500000, 185625000, 4, 495, 0, 2, 2, 1, 3, 2, 2, 0, 0}, | ||
309 | {296703000, 296703000, 1, 98, 0, 1, 1, 1, 0, 2, 2, 0, 0xE6AE6B}, | ||
310 | {297000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 2, 0, 0}, | ||
311 | {296703000, 370878750, 4, 494, 1, 2, 0, 1, 3, 1, 1, 0, 0x816817}, | ||
312 | {297000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 0, 0}, | ||
313 | {593407000, 296703500, 1, 98, 0, 1, 1, 1, 0, 2, 1, 0, 0xE6AE6B}, | ||
314 | {594000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 1, 0, 0}, | ||
315 | {593407000, 370879375, 4, 494, 1, 2, 0, 1, 3, 1, 1, 1, 0x816817}, | ||
316 | {594000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 1, 0}, | ||
317 | {593407000, 593407000, 1, 98, 0, 2, 0, 1, 0, 1, 1, 0, 0xE6AE6B}, | ||
318 | {594000000, 594000000, 1, 99, 0, 2, 0, 1, 0, 1, 1, 0, 0}, | ||
319 | { /* sentinel */ } | ||
320 | }; | ||
321 | |||
322 | static const struct post_pll_config post_pll_cfg_table[] = { | ||
323 | {33750000, 1, 40, 8, 1}, | ||
324 | {33750000, 1, 80, 8, 2}, | ||
325 | {74250000, 1, 40, 8, 1}, | ||
326 | {74250000, 18, 80, 8, 2}, | ||
327 | {148500000, 2, 40, 4, 3}, | ||
328 | {297000000, 4, 40, 2, 3}, | ||
329 | {594000000, 8, 40, 1, 3}, | ||
330 | { /* sentinel */ } | ||
331 | }; | ||
332 | |||
333 | /* phy tuning values for an undocumented set of registers */ | ||
334 | static const struct phy_config rk3228_phy_cfg[] = { | ||
335 | { 165000000, { | ||
336 | 0xaa, 0x00, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
337 | 0x00, 0x00, 0x00, 0x00, 0x00, | ||
338 | }, | ||
339 | }, { | ||
340 | 340000000, { | ||
341 | 0xaa, 0x15, 0x6a, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
342 | 0x00, 0x00, 0x00, 0x00, 0x00, | ||
343 | }, | ||
344 | }, { | ||
345 | 594000000, { | ||
346 | 0xaa, 0x15, 0x7a, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
347 | 0x00, 0x00, 0x00, 0x00, 0x00, | ||
348 | }, | ||
349 | }, { /* sentinel */ }, | ||
350 | }; | ||
351 | |||
352 | /* phy tuning values for an undocumented set of registers */ | ||
353 | static const struct phy_config rk3328_phy_cfg[] = { | ||
354 | { 165000000, { | ||
355 | 0x07, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x08, 0x08, 0x08, | ||
356 | 0x00, 0xac, 0xcc, 0xcc, 0xcc, | ||
357 | }, | ||
358 | }, { | ||
359 | 340000000, { | ||
360 | 0x0b, 0x0d, 0x0d, 0x0d, 0x07, 0x15, 0x08, 0x08, 0x08, | ||
361 | 0x3f, 0xac, 0xcc, 0xcd, 0xdd, | ||
362 | }, | ||
363 | }, { | ||
364 | 594000000, { | ||
365 | 0x10, 0x1a, 0x1a, 0x1a, 0x07, 0x15, 0x08, 0x08, 0x08, | ||
366 | 0x00, 0xac, 0xcc, 0xcc, 0xcc, | ||
367 | }, | ||
368 | }, { /* sentinel */ }, | ||
369 | }; | ||
370 | |||
371 | static inline struct inno_hdmi_phy *to_inno_hdmi_phy(struct clk_hw *hw) | ||
372 | { | ||
373 | return container_of(hw, struct inno_hdmi_phy, hw); | ||
374 | } | ||
375 | |||
376 | /* | ||
377 | * The register description of the IP block does not use any distinct names | ||
378 | * but instead the databook simply numbers the registers in one-increments. | ||
379 | * As the registers are obviously 32bit sized, the inno_* functions | ||
380 | * translate the databook register names to the actual registers addresses. | ||
381 | */ | ||
382 | static inline void inno_write(struct inno_hdmi_phy *inno, u32 reg, u8 val) | ||
383 | { | ||
384 | regmap_write(inno->regmap, reg * 4, val); | ||
385 | } | ||
386 | |||
387 | static inline u8 inno_read(struct inno_hdmi_phy *inno, u32 reg) | ||
388 | { | ||
389 | u32 val; | ||
390 | |||
391 | regmap_read(inno->regmap, reg * 4, &val); | ||
392 | |||
393 | return val; | ||
394 | } | ||
395 | |||
396 | static inline void inno_update_bits(struct inno_hdmi_phy *inno, u8 reg, | ||
397 | u8 mask, u8 val) | ||
398 | { | ||
399 | regmap_update_bits(inno->regmap, reg * 4, mask, val); | ||
400 | } | ||
401 | |||
402 | #define inno_poll(inno, reg, val, cond, sleep_us, timeout_us) \ | ||
403 | regmap_read_poll_timeout((inno)->regmap, (reg) * 4, val, cond, \ | ||
404 | sleep_us, timeout_us) | ||
405 | |||
406 | static unsigned long inno_hdmi_phy_get_tmdsclk(struct inno_hdmi_phy *inno, | ||
407 | unsigned long rate) | ||
408 | { | ||
409 | int bus_width = phy_get_bus_width(inno->phy); | ||
410 | |||
411 | switch (bus_width) { | ||
412 | case 4: | ||
413 | case 5: | ||
414 | case 6: | ||
415 | case 10: | ||
416 | case 12: | ||
417 | case 16: | ||
418 | return (u64)rate * bus_width / 8; | ||
419 | default: | ||
420 | return rate; | ||
421 | } | ||
422 | } | ||
423 | |||
424 | static irqreturn_t inno_hdmi_phy_rk3328_hardirq(int irq, void *dev_id) | ||
425 | { | ||
426 | struct inno_hdmi_phy *inno = dev_id; | ||
427 | int intr_stat1, intr_stat2, intr_stat3; | ||
428 | |||
429 | intr_stat1 = inno_read(inno, 0x04); | ||
430 | intr_stat2 = inno_read(inno, 0x06); | ||
431 | intr_stat3 = inno_read(inno, 0x08); | ||
432 | |||
433 | if (intr_stat1) | ||
434 | inno_write(inno, 0x04, intr_stat1); | ||
435 | if (intr_stat2) | ||
436 | inno_write(inno, 0x06, intr_stat2); | ||
437 | if (intr_stat3) | ||
438 | inno_write(inno, 0x08, intr_stat3); | ||
439 | |||
440 | if (intr_stat1 || intr_stat2 || intr_stat3) | ||
441 | return IRQ_WAKE_THREAD; | ||
442 | |||
443 | return IRQ_HANDLED; | ||
444 | } | ||
445 | |||
446 | static irqreturn_t inno_hdmi_phy_rk3328_irq(int irq, void *dev_id) | ||
447 | { | ||
448 | struct inno_hdmi_phy *inno = dev_id; | ||
449 | |||
450 | inno_update_bits(inno, 0x02, RK3328_PDATA_EN, 0); | ||
451 | usleep_range(10, 20); | ||
452 | inno_update_bits(inno, 0x02, RK3328_PDATA_EN, RK3328_PDATA_EN); | ||
453 | |||
454 | return IRQ_HANDLED; | ||
455 | } | ||
456 | |||
457 | static int inno_hdmi_phy_power_on(struct phy *phy) | ||
458 | { | ||
459 | struct inno_hdmi_phy *inno = phy_get_drvdata(phy); | ||
460 | const struct post_pll_config *cfg = post_pll_cfg_table; | ||
461 | const struct phy_config *phy_cfg = inno->plat_data->phy_cfg_table; | ||
462 | unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, | ||
463 | inno->pixclock); | ||
464 | int ret; | ||
465 | |||
466 | if (!tmdsclock) { | ||
467 | dev_err(inno->dev, "TMDS clock is zero!\n"); | ||
468 | return -EINVAL; | ||
469 | } | ||
470 | |||
471 | if (!inno->plat_data->ops->power_on) | ||
472 | return -EINVAL; | ||
473 | |||
474 | for (; cfg->tmdsclock != 0; cfg++) | ||
475 | if (tmdsclock <= cfg->tmdsclock && | ||
476 | cfg->version & inno->chip_version) | ||
477 | break; | ||
478 | |||
479 | for (; phy_cfg->tmdsclock != 0; phy_cfg++) | ||
480 | if (tmdsclock <= phy_cfg->tmdsclock) | ||
481 | break; | ||
482 | |||
483 | if (cfg->tmdsclock == 0 || phy_cfg->tmdsclock == 0) | ||
484 | return -EINVAL; | ||
485 | |||
486 | dev_dbg(inno->dev, "Inno HDMI PHY Power On\n"); | ||
487 | |||
488 | ret = clk_prepare_enable(inno->phyclk); | ||
489 | if (ret) | ||
490 | return ret; | ||
491 | |||
492 | ret = inno->plat_data->ops->power_on(inno, cfg, phy_cfg); | ||
493 | if (ret) { | ||
494 | clk_disable_unprepare(inno->phyclk); | ||
495 | return ret; | ||
496 | } | ||
497 | |||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | static int inno_hdmi_phy_power_off(struct phy *phy) | ||
502 | { | ||
503 | struct inno_hdmi_phy *inno = phy_get_drvdata(phy); | ||
504 | |||
505 | if (!inno->plat_data->ops->power_off) | ||
506 | return -EINVAL; | ||
507 | |||
508 | inno->plat_data->ops->power_off(inno); | ||
509 | |||
510 | clk_disable_unprepare(inno->phyclk); | ||
511 | |||
512 | dev_dbg(inno->dev, "Inno HDMI PHY Power Off\n"); | ||
513 | |||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | static const struct phy_ops inno_hdmi_phy_ops = { | ||
518 | .owner = THIS_MODULE, | ||
519 | .power_on = inno_hdmi_phy_power_on, | ||
520 | .power_off = inno_hdmi_phy_power_off, | ||
521 | }; | ||
522 | |||
523 | static const | ||
524 | struct pre_pll_config *inno_hdmi_phy_get_pre_pll_cfg(struct inno_hdmi_phy *inno, | ||
525 | unsigned long rate) | ||
526 | { | ||
527 | const struct pre_pll_config *cfg = pre_pll_cfg_table; | ||
528 | unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, rate); | ||
529 | |||
530 | for (; cfg->pixclock != 0; cfg++) | ||
531 | if (cfg->pixclock == rate && cfg->tmdsclock == tmdsclock) | ||
532 | break; | ||
533 | |||
534 | if (cfg->pixclock == 0) | ||
535 | return ERR_PTR(-EINVAL); | ||
536 | |||
537 | return cfg; | ||
538 | } | ||
539 | |||
540 | static int inno_hdmi_phy_rk3228_clk_is_prepared(struct clk_hw *hw) | ||
541 | { | ||
542 | struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); | ||
543 | u8 status; | ||
544 | |||
545 | status = inno_read(inno, 0xe0) & RK3228_PRE_PLL_POWER_DOWN; | ||
546 | return status ? 0 : 1; | ||
547 | } | ||
548 | |||
549 | static int inno_hdmi_phy_rk3228_clk_prepare(struct clk_hw *hw) | ||
550 | { | ||
551 | struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); | ||
552 | |||
553 | inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN, 0); | ||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | static void inno_hdmi_phy_rk3228_clk_unprepare(struct clk_hw *hw) | ||
558 | { | ||
559 | struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); | ||
560 | |||
561 | inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN, | ||
562 | RK3228_PRE_PLL_POWER_DOWN); | ||
563 | } | ||
564 | |||
565 | static | ||
566 | unsigned long inno_hdmi_phy_rk3228_clk_recalc_rate(struct clk_hw *hw, | ||
567 | unsigned long parent_rate) | ||
568 | { | ||
569 | struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); | ||
570 | u8 nd, no_a, no_b, no_d; | ||
571 | u64 vco; | ||
572 | u16 nf; | ||
573 | |||
574 | nd = inno_read(inno, 0xe2) & RK3228_PRE_PLL_PRE_DIV_MASK; | ||
575 | nf = (inno_read(inno, 0xe2) & RK3228_PRE_PLL_FB_DIV_8_MASK) << 1; | ||
576 | nf |= inno_read(inno, 0xe3); | ||
577 | vco = parent_rate * nf; | ||
578 | |||
579 | if (inno_read(inno, 0xe2) & RK3228_PCLK_VCO_DIV_5_MASK) { | ||
580 | do_div(vco, nd * 5); | ||
581 | } else { | ||
582 | no_a = inno_read(inno, 0xe4) & RK3228_PRE_PLL_PCLK_DIV_A_MASK; | ||
583 | if (!no_a) | ||
584 | no_a = 1; | ||
585 | no_b = inno_read(inno, 0xe4) & RK3228_PRE_PLL_PCLK_DIV_B_MASK; | ||
586 | no_b >>= RK3228_PRE_PLL_PCLK_DIV_B_SHIFT; | ||
587 | no_b += 2; | ||
588 | no_d = inno_read(inno, 0xe5) & RK3228_PRE_PLL_PCLK_DIV_D_MASK; | ||
589 | |||
590 | do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2)); | ||
591 | } | ||
592 | |||
593 | inno->pixclock = vco; | ||
594 | |||
595 | dev_dbg(inno->dev, "%s rate %lu\n", __func__, inno->pixclock); | ||
596 | |||
597 | return vco; | ||
598 | } | ||
599 | |||
600 | static long inno_hdmi_phy_rk3228_clk_round_rate(struct clk_hw *hw, | ||
601 | unsigned long rate, | ||
602 | unsigned long *parent_rate) | ||
603 | { | ||
604 | const struct pre_pll_config *cfg = pre_pll_cfg_table; | ||
605 | |||
606 | for (; cfg->pixclock != 0; cfg++) | ||
607 | if (cfg->pixclock == rate && !cfg->fracdiv) | ||
608 | break; | ||
609 | |||
610 | if (cfg->pixclock == 0) | ||
611 | return -EINVAL; | ||
612 | |||
613 | return cfg->pixclock; | ||
614 | } | ||
615 | |||
616 | static int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw, | ||
617 | unsigned long rate, | ||
618 | unsigned long parent_rate) | ||
619 | { | ||
620 | struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); | ||
621 | const struct pre_pll_config *cfg = pre_pll_cfg_table; | ||
622 | unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, rate); | ||
623 | u32 v; | ||
624 | int ret; | ||
625 | |||
626 | dev_dbg(inno->dev, "%s rate %lu tmdsclk %lu\n", | ||
627 | __func__, rate, tmdsclock); | ||
628 | |||
629 | cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate); | ||
630 | if (IS_ERR(cfg)) | ||
631 | return PTR_ERR(cfg); | ||
632 | |||
633 | /* Power down PRE-PLL */ | ||
634 | inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN, | ||
635 | RK3228_PRE_PLL_POWER_DOWN); | ||
636 | |||
637 | inno_update_bits(inno, 0xe2, RK3228_PRE_PLL_FB_DIV_8_MASK | | ||
638 | RK3228_PCLK_VCO_DIV_5_MASK | | ||
639 | RK3228_PRE_PLL_PRE_DIV_MASK, | ||
640 | RK3228_PRE_PLL_FB_DIV_8(cfg->fbdiv) | | ||
641 | RK3228_PCLK_VCO_DIV_5(cfg->vco_div_5_en) | | ||
642 | RK3228_PRE_PLL_PRE_DIV(cfg->prediv)); | ||
643 | inno_write(inno, 0xe3, RK3228_PRE_PLL_FB_DIV_7_0(cfg->fbdiv)); | ||
644 | inno_update_bits(inno, 0xe4, RK3228_PRE_PLL_PCLK_DIV_B_MASK | | ||
645 | RK3228_PRE_PLL_PCLK_DIV_A_MASK, | ||
646 | RK3228_PRE_PLL_PCLK_DIV_B(cfg->pclk_div_b) | | ||
647 | RK3228_PRE_PLL_PCLK_DIV_A(cfg->pclk_div_a)); | ||
648 | inno_update_bits(inno, 0xe5, RK3228_PRE_PLL_PCLK_DIV_C_MASK | | ||
649 | RK3228_PRE_PLL_PCLK_DIV_D_MASK, | ||
650 | RK3228_PRE_PLL_PCLK_DIV_C(cfg->pclk_div_c) | | ||
651 | RK3228_PRE_PLL_PCLK_DIV_D(cfg->pclk_div_d)); | ||
652 | inno_update_bits(inno, 0xe6, RK3228_PRE_PLL_TMDSCLK_DIV_C_MASK | | ||
653 | RK3228_PRE_PLL_TMDSCLK_DIV_A_MASK | | ||
654 | RK3228_PRE_PLL_TMDSCLK_DIV_B_MASK, | ||
655 | RK3228_PRE_PLL_TMDSCLK_DIV_C(cfg->tmds_div_c) | | ||
656 | RK3228_PRE_PLL_TMDSCLK_DIV_A(cfg->tmds_div_a) | | ||
657 | RK3228_PRE_PLL_TMDSCLK_DIV_B(cfg->tmds_div_b)); | ||
658 | |||
659 | /* Power up PRE-PLL */ | ||
660 | inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN, 0); | ||
661 | |||
662 | /* Wait for Pre-PLL lock */ | ||
663 | ret = inno_poll(inno, 0xe8, v, v & RK3228_PRE_PLL_LOCK_STATUS, | ||
664 | 100, 100000); | ||
665 | if (ret) { | ||
666 | dev_err(inno->dev, "Pre-PLL locking failed\n"); | ||
667 | return ret; | ||
668 | } | ||
669 | |||
670 | inno->pixclock = rate; | ||
671 | |||
672 | return 0; | ||
673 | } | ||
674 | |||
675 | static const struct clk_ops inno_hdmi_phy_rk3228_clk_ops = { | ||
676 | .prepare = inno_hdmi_phy_rk3228_clk_prepare, | ||
677 | .unprepare = inno_hdmi_phy_rk3228_clk_unprepare, | ||
678 | .is_prepared = inno_hdmi_phy_rk3228_clk_is_prepared, | ||
679 | .recalc_rate = inno_hdmi_phy_rk3228_clk_recalc_rate, | ||
680 | .round_rate = inno_hdmi_phy_rk3228_clk_round_rate, | ||
681 | .set_rate = inno_hdmi_phy_rk3228_clk_set_rate, | ||
682 | }; | ||
683 | |||
684 | static int inno_hdmi_phy_rk3328_clk_is_prepared(struct clk_hw *hw) | ||
685 | { | ||
686 | struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); | ||
687 | u8 status; | ||
688 | |||
689 | status = inno_read(inno, 0xa0) & RK3328_PRE_PLL_POWER_DOWN; | ||
690 | return status ? 0 : 1; | ||
691 | } | ||
692 | |||
693 | static int inno_hdmi_phy_rk3328_clk_prepare(struct clk_hw *hw) | ||
694 | { | ||
695 | struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); | ||
696 | |||
697 | inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN, 0); | ||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | static void inno_hdmi_phy_rk3328_clk_unprepare(struct clk_hw *hw) | ||
702 | { | ||
703 | struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); | ||
704 | |||
705 | inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN, | ||
706 | RK3328_PRE_PLL_POWER_DOWN); | ||
707 | } | ||
708 | |||
709 | static | ||
710 | unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw, | ||
711 | unsigned long parent_rate) | ||
712 | { | ||
713 | struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); | ||
714 | unsigned long frac; | ||
715 | u8 nd, no_a, no_b, no_c, no_d; | ||
716 | u64 vco; | ||
717 | u16 nf; | ||
718 | |||
719 | nd = inno_read(inno, 0xa1) & RK3328_PRE_PLL_PRE_DIV_MASK; | ||
720 | nf = ((inno_read(inno, 0xa2) & RK3328_PRE_PLL_FB_DIV_11_8_MASK) << 8); | ||
721 | nf |= inno_read(inno, 0xa3); | ||
722 | vco = parent_rate * nf; | ||
723 | |||
724 | if (!(inno_read(inno, 0xa2) & RK3328_PRE_PLL_FRAC_DIV_DISABLE)) { | ||
725 | frac = inno_read(inno, 0xd3) | | ||
726 | (inno_read(inno, 0xd2) << 8) | | ||
727 | (inno_read(inno, 0xd1) << 16); | ||
728 | vco += DIV_ROUND_CLOSEST(parent_rate * frac, (1 << 24)); | ||
729 | } | ||
730 | |||
731 | if (inno_read(inno, 0xa0) & RK3328_PCLK_VCO_DIV_5_MASK) { | ||
732 | do_div(vco, nd * 5); | ||
733 | } else { | ||
734 | no_a = inno_read(inno, 0xa5) & RK3328_PRE_PLL_PCLK_DIV_A_MASK; | ||
735 | no_b = inno_read(inno, 0xa5) & RK3328_PRE_PLL_PCLK_DIV_B_MASK; | ||
736 | no_b >>= RK3328_PRE_PLL_PCLK_DIV_B_SHIFT; | ||
737 | no_b += 2; | ||
738 | no_c = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_C_MASK; | ||
739 | no_c >>= RK3328_PRE_PLL_PCLK_DIV_C_SHIFT; | ||
740 | no_c = 1 << no_c; | ||
741 | no_d = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_D_MASK; | ||
742 | |||
743 | do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2)); | ||
744 | } | ||
745 | |||
746 | inno->pixclock = vco; | ||
747 | dev_dbg(inno->dev, "%s rate %lu\n", __func__, inno->pixclock); | ||
748 | |||
749 | return vco; | ||
750 | } | ||
751 | |||
752 | static long inno_hdmi_phy_rk3328_clk_round_rate(struct clk_hw *hw, | ||
753 | unsigned long rate, | ||
754 | unsigned long *parent_rate) | ||
755 | { | ||
756 | const struct pre_pll_config *cfg = pre_pll_cfg_table; | ||
757 | |||
758 | for (; cfg->pixclock != 0; cfg++) | ||
759 | if (cfg->pixclock == rate) | ||
760 | break; | ||
761 | |||
762 | if (cfg->pixclock == 0) | ||
763 | return -EINVAL; | ||
764 | |||
765 | return cfg->pixclock; | ||
766 | } | ||
767 | |||
768 | static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw, | ||
769 | unsigned long rate, | ||
770 | unsigned long parent_rate) | ||
771 | { | ||
772 | struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); | ||
773 | const struct pre_pll_config *cfg = pre_pll_cfg_table; | ||
774 | unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, rate); | ||
775 | u32 val; | ||
776 | int ret; | ||
777 | |||
778 | dev_dbg(inno->dev, "%s rate %lu tmdsclk %lu\n", | ||
779 | __func__, rate, tmdsclock); | ||
780 | |||
781 | cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate); | ||
782 | if (IS_ERR(cfg)) | ||
783 | return PTR_ERR(cfg); | ||
784 | |||
785 | inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN, | ||
786 | RK3328_PRE_PLL_POWER_DOWN); | ||
787 | |||
788 | /* Configure pre-pll */ | ||
789 | inno_update_bits(inno, 0xa0, RK3228_PCLK_VCO_DIV_5_MASK, | ||
790 | RK3228_PCLK_VCO_DIV_5(cfg->vco_div_5_en)); | ||
791 | inno_write(inno, 0xa1, RK3328_PRE_PLL_PRE_DIV(cfg->prediv)); | ||
792 | |||
793 | val = RK3328_SPREAD_SPECTRUM_MOD_DISABLE; | ||
794 | if (!cfg->fracdiv) | ||
795 | val |= RK3328_PRE_PLL_FRAC_DIV_DISABLE; | ||
796 | inno_write(inno, 0xa2, RK3328_PRE_PLL_FB_DIV_11_8(cfg->fbdiv) | val); | ||
797 | inno_write(inno, 0xa3, RK3328_PRE_PLL_FB_DIV_7_0(cfg->fbdiv)); | ||
798 | inno_write(inno, 0xa5, RK3328_PRE_PLL_PCLK_DIV_A(cfg->pclk_div_a) | | ||
799 | RK3328_PRE_PLL_PCLK_DIV_B(cfg->pclk_div_b)); | ||
800 | inno_write(inno, 0xa6, RK3328_PRE_PLL_PCLK_DIV_C(cfg->pclk_div_c) | | ||
801 | RK3328_PRE_PLL_PCLK_DIV_D(cfg->pclk_div_d)); | ||
802 | inno_write(inno, 0xa4, RK3328_PRE_PLL_TMDSCLK_DIV_C(cfg->tmds_div_c) | | ||
803 | RK3328_PRE_PLL_TMDSCLK_DIV_A(cfg->tmds_div_a) | | ||
804 | RK3328_PRE_PLL_TMDSCLK_DIV_B(cfg->tmds_div_b)); | ||
805 | inno_write(inno, 0xd3, RK3328_PRE_PLL_FRAC_DIV_7_0(cfg->fracdiv)); | ||
806 | inno_write(inno, 0xd2, RK3328_PRE_PLL_FRAC_DIV_15_8(cfg->fracdiv)); | ||
807 | inno_write(inno, 0xd1, RK3328_PRE_PLL_FRAC_DIV_23_16(cfg->fracdiv)); | ||
808 | |||
809 | inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN, 0); | ||
810 | |||
811 | /* Wait for Pre-PLL lock */ | ||
812 | ret = inno_poll(inno, 0xa9, val, val & RK3328_PRE_PLL_LOCK_STATUS, | ||
813 | 1000, 10000); | ||
814 | if (ret) { | ||
815 | dev_err(inno->dev, "Pre-PLL locking failed\n"); | ||
816 | return ret; | ||
817 | } | ||
818 | |||
819 | inno->pixclock = rate; | ||
820 | |||
821 | return 0; | ||
822 | } | ||
823 | |||
824 | static const struct clk_ops inno_hdmi_phy_rk3328_clk_ops = { | ||
825 | .prepare = inno_hdmi_phy_rk3328_clk_prepare, | ||
826 | .unprepare = inno_hdmi_phy_rk3328_clk_unprepare, | ||
827 | .is_prepared = inno_hdmi_phy_rk3328_clk_is_prepared, | ||
828 | .recalc_rate = inno_hdmi_phy_rk3328_clk_recalc_rate, | ||
829 | .round_rate = inno_hdmi_phy_rk3328_clk_round_rate, | ||
830 | .set_rate = inno_hdmi_phy_rk3328_clk_set_rate, | ||
831 | }; | ||
832 | |||
833 | static int inno_hdmi_phy_clk_register(struct inno_hdmi_phy *inno) | ||
834 | { | ||
835 | struct device *dev = inno->dev; | ||
836 | struct device_node *np = dev->of_node; | ||
837 | struct clk_init_data init; | ||
838 | const char *parent_name; | ||
839 | int ret; | ||
840 | |||
841 | parent_name = __clk_get_name(inno->refoclk); | ||
842 | |||
843 | init.parent_names = &parent_name; | ||
844 | init.num_parents = 1; | ||
845 | init.flags = 0; | ||
846 | init.name = "pin_hd20_pclk"; | ||
847 | init.ops = inno->plat_data->clk_ops; | ||
848 | |||
849 | /* optional override of the clock name */ | ||
850 | of_property_read_string(np, "clock-output-names", &init.name); | ||
851 | |||
852 | inno->hw.init = &init; | ||
853 | |||
854 | inno->phyclk = devm_clk_register(dev, &inno->hw); | ||
855 | if (IS_ERR(inno->phyclk)) { | ||
856 | ret = PTR_ERR(inno->phyclk); | ||
857 | dev_err(dev, "failed to register clock: %d\n", ret); | ||
858 | return ret; | ||
859 | } | ||
860 | |||
861 | ret = of_clk_add_provider(np, of_clk_src_simple_get, inno->phyclk); | ||
862 | if (ret) { | ||
863 | dev_err(dev, "failed to register clock provider: %d\n", ret); | ||
864 | return ret; | ||
865 | } | ||
866 | |||
867 | return 0; | ||
868 | } | ||
869 | |||
870 | static int inno_hdmi_phy_rk3228_init(struct inno_hdmi_phy *inno) | ||
871 | { | ||
872 | /* | ||
873 | * Use phy internal register control | ||
874 | * rxsense/poweron/pllpd/pdataen signal. | ||
875 | */ | ||
876 | inno_write(inno, 0x01, RK3228_BYPASS_RXSENSE_EN | | ||
877 | RK3228_BYPASS_PWRON_EN | | ||
878 | RK3228_BYPASS_PLLPD_EN); | ||
879 | inno_update_bits(inno, 0x02, RK3228_BYPASS_PDATA_EN, | ||
880 | RK3228_BYPASS_PDATA_EN); | ||
881 | |||
882 | /* manual power down post-PLL */ | ||
883 | inno_update_bits(inno, 0xaa, RK3228_POST_PLL_CTRL_MANUAL, | ||
884 | RK3228_POST_PLL_CTRL_MANUAL); | ||
885 | |||
886 | inno->chip_version = 1; | ||
887 | |||
888 | return 0; | ||
889 | } | ||
890 | |||
891 | static int | ||
892 | inno_hdmi_phy_rk3228_power_on(struct inno_hdmi_phy *inno, | ||
893 | const struct post_pll_config *cfg, | ||
894 | const struct phy_config *phy_cfg) | ||
895 | { | ||
896 | int ret; | ||
897 | u32 v; | ||
898 | |||
899 | inno_update_bits(inno, 0x02, RK3228_PDATAEN_DISABLE, | ||
900 | RK3228_PDATAEN_DISABLE); | ||
901 | inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN | | ||
902 | RK3228_POST_PLL_POWER_DOWN, | ||
903 | RK3228_PRE_PLL_POWER_DOWN | | ||
904 | RK3228_POST_PLL_POWER_DOWN); | ||
905 | |||
906 | /* Post-PLL update */ | ||
907 | inno_update_bits(inno, 0xe9, RK3228_POST_PLL_PRE_DIV_MASK, | ||
908 | RK3228_POST_PLL_PRE_DIV(cfg->prediv)); | ||
909 | inno_update_bits(inno, 0xeb, RK3228_POST_PLL_FB_DIV_8_MASK, | ||
910 | RK3228_POST_PLL_FB_DIV_8(cfg->fbdiv)); | ||
911 | inno_write(inno, 0xea, RK3228_POST_PLL_FB_DIV_7_0(cfg->fbdiv)); | ||
912 | |||
913 | if (cfg->postdiv == 1) { | ||
914 | inno_update_bits(inno, 0xe9, RK3228_POST_PLL_POST_DIV_ENABLE, | ||
915 | 0); | ||
916 | } else { | ||
917 | int div = cfg->postdiv / 2 - 1; | ||
918 | |||
919 | inno_update_bits(inno, 0xe9, RK3228_POST_PLL_POST_DIV_ENABLE, | ||
920 | RK3228_POST_PLL_POST_DIV_ENABLE); | ||
921 | inno_update_bits(inno, 0xeb, RK3228_POST_PLL_POST_DIV_MASK, | ||
922 | RK3228_POST_PLL_POST_DIV(div)); | ||
923 | } | ||
924 | |||
925 | for (v = 0; v < 4; v++) | ||
926 | inno_write(inno, 0xef + v, phy_cfg->regs[v]); | ||
927 | |||
928 | inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN | | ||
929 | RK3228_POST_PLL_POWER_DOWN, 0); | ||
930 | inno_update_bits(inno, 0xe1, RK3228_BANDGAP_ENABLE, | ||
931 | RK3228_BANDGAP_ENABLE); | ||
932 | inno_update_bits(inno, 0xe1, RK3228_TMDS_DRIVER_ENABLE, | ||
933 | RK3228_TMDS_DRIVER_ENABLE); | ||
934 | |||
935 | /* Wait for post PLL lock */ | ||
936 | ret = inno_poll(inno, 0xeb, v, v & RK3228_POST_PLL_LOCK_STATUS, | ||
937 | 100, 100000); | ||
938 | if (ret) { | ||
939 | dev_err(inno->dev, "Post-PLL locking failed\n"); | ||
940 | return ret; | ||
941 | } | ||
942 | |||
943 | if (cfg->tmdsclock > 340000000) | ||
944 | msleep(100); | ||
945 | |||
946 | inno_update_bits(inno, 0x02, RK3228_PDATAEN_DISABLE, 0); | ||
947 | return 0; | ||
948 | } | ||
949 | |||
950 | static void inno_hdmi_phy_rk3228_power_off(struct inno_hdmi_phy *inno) | ||
951 | { | ||
952 | inno_update_bits(inno, 0xe1, RK3228_TMDS_DRIVER_ENABLE, 0); | ||
953 | inno_update_bits(inno, 0xe1, RK3228_BANDGAP_ENABLE, 0); | ||
954 | inno_update_bits(inno, 0xe0, RK3228_POST_PLL_POWER_DOWN, | ||
955 | RK3228_POST_PLL_POWER_DOWN); | ||
956 | } | ||
957 | |||
958 | static const struct inno_hdmi_phy_ops rk3228_hdmi_phy_ops = { | ||
959 | .init = inno_hdmi_phy_rk3228_init, | ||
960 | .power_on = inno_hdmi_phy_rk3228_power_on, | ||
961 | .power_off = inno_hdmi_phy_rk3228_power_off, | ||
962 | }; | ||
963 | |||
964 | static int inno_hdmi_phy_rk3328_init(struct inno_hdmi_phy *inno) | ||
965 | { | ||
966 | struct nvmem_cell *cell; | ||
967 | unsigned char *efuse_buf; | ||
968 | size_t len; | ||
969 | |||
970 | /* | ||
971 | * Use phy internal register control | ||
972 | * rxsense/poweron/pllpd/pdataen signal. | ||
973 | */ | ||
974 | inno_write(inno, 0x01, RK3328_BYPASS_RXSENSE_EN | | ||
975 | RK3328_BYPASS_POWERON_EN | | ||
976 | RK3328_BYPASS_PLLPD_EN); | ||
977 | inno_write(inno, 0x02, RK3328_INT_POL_HIGH | RK3328_BYPASS_PDATA_EN | | ||
978 | RK3328_PDATA_EN); | ||
979 | |||
980 | /* Disable phy irq */ | ||
981 | inno_write(inno, 0x05, 0); | ||
982 | inno_write(inno, 0x07, 0); | ||
983 | |||
984 | /* try to read the chip-version */ | ||
985 | inno->chip_version = 1; | ||
986 | cell = nvmem_cell_get(inno->dev, "cpu-version"); | ||
987 | if (IS_ERR(cell)) { | ||
988 | if (PTR_ERR(cell) == -EPROBE_DEFER) | ||
989 | return -EPROBE_DEFER; | ||
990 | |||
991 | return 0; | ||
992 | } | ||
993 | |||
994 | efuse_buf = nvmem_cell_read(cell, &len); | ||
995 | nvmem_cell_put(cell); | ||
996 | |||
997 | if (IS_ERR(efuse_buf)) | ||
998 | return 0; | ||
999 | if (len == 1) | ||
1000 | inno->chip_version = efuse_buf[0] + 1; | ||
1001 | kfree(efuse_buf); | ||
1002 | |||
1003 | return 0; | ||
1004 | } | ||
1005 | |||
1006 | static int | ||
1007 | inno_hdmi_phy_rk3328_power_on(struct inno_hdmi_phy *inno, | ||
1008 | const struct post_pll_config *cfg, | ||
1009 | const struct phy_config *phy_cfg) | ||
1010 | { | ||
1011 | int ret; | ||
1012 | u32 v; | ||
1013 | |||
1014 | inno_update_bits(inno, 0x02, RK3328_PDATA_EN, 0); | ||
1015 | inno_update_bits(inno, 0xaa, RK3328_POST_PLL_POWER_DOWN, | ||
1016 | RK3328_POST_PLL_POWER_DOWN); | ||
1017 | |||
1018 | inno_write(inno, 0xac, RK3328_POST_PLL_FB_DIV_7_0(cfg->fbdiv)); | ||
1019 | if (cfg->postdiv == 1) { | ||
1020 | inno_write(inno, 0xaa, RK3328_POST_PLL_REFCLK_SEL_TMDS); | ||
1021 | inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) | | ||
1022 | RK3328_POST_PLL_PRE_DIV(cfg->prediv)); | ||
1023 | } else { | ||
1024 | v = (cfg->postdiv / 2) - 1; | ||
1025 | v &= RK3328_POST_PLL_POST_DIV_MASK; | ||
1026 | inno_write(inno, 0xad, v); | ||
1027 | inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) | | ||
1028 | RK3328_POST_PLL_PRE_DIV(cfg->prediv)); | ||
1029 | inno_write(inno, 0xaa, RK3328_POST_PLL_POST_DIV_ENABLE | | ||
1030 | RK3328_POST_PLL_REFCLK_SEL_TMDS); | ||
1031 | } | ||
1032 | |||
1033 | for (v = 0; v < 14; v++) | ||
1034 | inno_write(inno, 0xb5 + v, phy_cfg->regs[v]); | ||
1035 | |||
1036 | /* set ESD detection threshold for TMDS CLK, D2, D1 and D0 */ | ||
1037 | for (v = 0; v < 4; v++) | ||
1038 | inno_update_bits(inno, 0xc8 + v, RK3328_ESD_DETECT_MASK, | ||
1039 | RK3328_ESD_DETECT_340MV); | ||
1040 | |||
1041 | if (phy_cfg->tmdsclock > 340000000) { | ||
1042 | /* Set termination resistor to 100ohm */ | ||
1043 | v = clk_get_rate(inno->sysclk) / 100000; | ||
1044 | inno_write(inno, 0xc5, RK3328_TERM_RESISTOR_CALIB_SPEED_14_8(v) | ||
1045 | | RK3328_BYPASS_TERM_RESISTOR_CALIB); | ||
1046 | inno_write(inno, 0xc6, RK3328_TERM_RESISTOR_CALIB_SPEED_7_0(v)); | ||
1047 | inno_write(inno, 0xc7, RK3328_TERM_RESISTOR_100); | ||
1048 | inno_update_bits(inno, 0xc5, | ||
1049 | RK3328_BYPASS_TERM_RESISTOR_CALIB, 0); | ||
1050 | } else { | ||
1051 | inno_write(inno, 0xc5, RK3328_BYPASS_TERM_RESISTOR_CALIB); | ||
1052 | |||
1053 | /* clk termination resistor is 50ohm (parallel resistors) */ | ||
1054 | if (phy_cfg->tmdsclock > 165000000) | ||
1055 | inno_update_bits(inno, 0xc8, | ||
1056 | RK3328_TMDS_TERM_RESIST_MASK, | ||
1057 | RK3328_TMDS_TERM_RESIST_75 | | ||
1058 | RK3328_TMDS_TERM_RESIST_150); | ||
1059 | |||
1060 | /* data termination resistor for D2, D1 and D0 is 150ohm */ | ||
1061 | for (v = 0; v < 3; v++) | ||
1062 | inno_update_bits(inno, 0xc9 + v, | ||
1063 | RK3328_TMDS_TERM_RESIST_MASK, | ||
1064 | RK3328_TMDS_TERM_RESIST_150); | ||
1065 | } | ||
1066 | |||
1067 | inno_update_bits(inno, 0xaa, RK3328_POST_PLL_POWER_DOWN, 0); | ||
1068 | inno_update_bits(inno, 0xb0, RK3328_BANDGAP_ENABLE, | ||
1069 | RK3328_BANDGAP_ENABLE); | ||
1070 | inno_update_bits(inno, 0xb2, RK3328_TMDS_DRIVER_ENABLE, | ||
1071 | RK3328_TMDS_DRIVER_ENABLE); | ||
1072 | |||
1073 | /* Wait for post PLL lock */ | ||
1074 | ret = inno_poll(inno, 0xaf, v, v & RK3328_POST_PLL_LOCK_STATUS, | ||
1075 | 1000, 10000); | ||
1076 | if (ret) { | ||
1077 | dev_err(inno->dev, "Post-PLL locking failed\n"); | ||
1078 | return ret; | ||
1079 | } | ||
1080 | |||
1081 | if (phy_cfg->tmdsclock > 340000000) | ||
1082 | msleep(100); | ||
1083 | |||
1084 | inno_update_bits(inno, 0x02, RK3328_PDATA_EN, RK3328_PDATA_EN); | ||
1085 | |||
1086 | /* Enable PHY IRQ */ | ||
1087 | inno_write(inno, 0x05, RK3328_INT_TMDS_CLK(RK3328_INT_VSS_AGND_ESD_DET) | ||
1088 | | RK3328_INT_TMDS_D2(RK3328_INT_VSS_AGND_ESD_DET)); | ||
1089 | inno_write(inno, 0x07, RK3328_INT_TMDS_D1(RK3328_INT_VSS_AGND_ESD_DET) | ||
1090 | | RK3328_INT_TMDS_D0(RK3328_INT_VSS_AGND_ESD_DET)); | ||
1091 | return 0; | ||
1092 | } | ||
1093 | |||
1094 | static void inno_hdmi_phy_rk3328_power_off(struct inno_hdmi_phy *inno) | ||
1095 | { | ||
1096 | inno_update_bits(inno, 0xb2, RK3328_TMDS_DRIVER_ENABLE, 0); | ||
1097 | inno_update_bits(inno, 0xb0, RK3328_BANDGAP_ENABLE, 0); | ||
1098 | inno_update_bits(inno, 0xaa, RK3328_POST_PLL_POWER_DOWN, | ||
1099 | RK3328_POST_PLL_POWER_DOWN); | ||
1100 | |||
1101 | /* Disable PHY IRQ */ | ||
1102 | inno_write(inno, 0x05, 0); | ||
1103 | inno_write(inno, 0x07, 0); | ||
1104 | } | ||
1105 | |||
1106 | static const struct inno_hdmi_phy_ops rk3328_hdmi_phy_ops = { | ||
1107 | .init = inno_hdmi_phy_rk3328_init, | ||
1108 | .power_on = inno_hdmi_phy_rk3328_power_on, | ||
1109 | .power_off = inno_hdmi_phy_rk3328_power_off, | ||
1110 | }; | ||
1111 | |||
1112 | static const struct inno_hdmi_phy_drv_data rk3228_hdmi_phy_drv_data = { | ||
1113 | .ops = &rk3228_hdmi_phy_ops, | ||
1114 | .clk_ops = &inno_hdmi_phy_rk3228_clk_ops, | ||
1115 | .phy_cfg_table = rk3228_phy_cfg, | ||
1116 | }; | ||
1117 | |||
1118 | static const struct inno_hdmi_phy_drv_data rk3328_hdmi_phy_drv_data = { | ||
1119 | .ops = &rk3328_hdmi_phy_ops, | ||
1120 | .clk_ops = &inno_hdmi_phy_rk3328_clk_ops, | ||
1121 | .phy_cfg_table = rk3328_phy_cfg, | ||
1122 | }; | ||
1123 | |||
1124 | static const struct regmap_config inno_hdmi_phy_regmap_config = { | ||
1125 | .reg_bits = 32, | ||
1126 | .val_bits = 32, | ||
1127 | .reg_stride = 4, | ||
1128 | .max_register = 0x400, | ||
1129 | }; | ||
1130 | |||
1131 | static void inno_hdmi_phy_action(void *data) | ||
1132 | { | ||
1133 | struct inno_hdmi_phy *inno = data; | ||
1134 | |||
1135 | clk_disable_unprepare(inno->refpclk); | ||
1136 | clk_disable_unprepare(inno->sysclk); | ||
1137 | } | ||
1138 | |||
1139 | static int inno_hdmi_phy_probe(struct platform_device *pdev) | ||
1140 | { | ||
1141 | struct inno_hdmi_phy *inno; | ||
1142 | struct phy_provider *phy_provider; | ||
1143 | struct resource *res; | ||
1144 | void __iomem *regs; | ||
1145 | int ret; | ||
1146 | |||
1147 | inno = devm_kzalloc(&pdev->dev, sizeof(*inno), GFP_KERNEL); | ||
1148 | if (!inno) | ||
1149 | return -ENOMEM; | ||
1150 | |||
1151 | inno->dev = &pdev->dev; | ||
1152 | |||
1153 | inno->plat_data = of_device_get_match_data(inno->dev); | ||
1154 | if (!inno->plat_data || !inno->plat_data->ops) | ||
1155 | return -EINVAL; | ||
1156 | |||
1157 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1158 | regs = devm_ioremap_resource(inno->dev, res); | ||
1159 | if (IS_ERR(regs)) | ||
1160 | return PTR_ERR(regs); | ||
1161 | |||
1162 | inno->sysclk = devm_clk_get(inno->dev, "sysclk"); | ||
1163 | if (IS_ERR(inno->sysclk)) { | ||
1164 | ret = PTR_ERR(inno->sysclk); | ||
1165 | dev_err(inno->dev, "failed to get sysclk: %d\n", ret); | ||
1166 | return ret; | ||
1167 | } | ||
1168 | |||
1169 | inno->refpclk = devm_clk_get(inno->dev, "refpclk"); | ||
1170 | if (IS_ERR(inno->refpclk)) { | ||
1171 | ret = PTR_ERR(inno->refpclk); | ||
1172 | dev_err(inno->dev, "failed to get ref clock: %d\n", ret); | ||
1173 | return ret; | ||
1174 | } | ||
1175 | |||
1176 | inno->refoclk = devm_clk_get(inno->dev, "refoclk"); | ||
1177 | if (IS_ERR(inno->refoclk)) { | ||
1178 | ret = PTR_ERR(inno->refoclk); | ||
1179 | dev_err(inno->dev, "failed to get oscillator-ref clock: %d\n", | ||
1180 | ret); | ||
1181 | return ret; | ||
1182 | } | ||
1183 | |||
1184 | ret = clk_prepare_enable(inno->sysclk); | ||
1185 | if (ret) { | ||
1186 | dev_err(inno->dev, "Cannot enable inno phy sysclk: %d\n", ret); | ||
1187 | return ret; | ||
1188 | } | ||
1189 | |||
1190 | /* | ||
1191 | * Refpclk needs to be on, on at least the rk3328 for still | ||
1192 | * unknown reasons. | ||
1193 | */ | ||
1194 | ret = clk_prepare_enable(inno->refpclk); | ||
1195 | if (ret) { | ||
1196 | dev_err(inno->dev, "failed to enable refpclk\n"); | ||
1197 | clk_disable_unprepare(inno->sysclk); | ||
1198 | return ret; | ||
1199 | } | ||
1200 | |||
1201 | ret = devm_add_action_or_reset(inno->dev, inno_hdmi_phy_action, | ||
1202 | inno); | ||
1203 | if (ret) | ||
1204 | return ret; | ||
1205 | |||
1206 | inno->regmap = devm_regmap_init_mmio(inno->dev, regs, | ||
1207 | &inno_hdmi_phy_regmap_config); | ||
1208 | if (IS_ERR(inno->regmap)) | ||
1209 | return PTR_ERR(inno->regmap); | ||
1210 | |||
1211 | /* only the newer rk3328 hdmiphy has an interrupt */ | ||
1212 | inno->irq = platform_get_irq(pdev, 0); | ||
1213 | if (inno->irq > 0) { | ||
1214 | ret = devm_request_threaded_irq(inno->dev, inno->irq, | ||
1215 | inno_hdmi_phy_rk3328_hardirq, | ||
1216 | inno_hdmi_phy_rk3328_irq, | ||
1217 | IRQF_SHARED, | ||
1218 | dev_name(inno->dev), inno); | ||
1219 | if (ret) | ||
1220 | return ret; | ||
1221 | } | ||
1222 | |||
1223 | inno->phy = devm_phy_create(inno->dev, NULL, &inno_hdmi_phy_ops); | ||
1224 | if (IS_ERR(inno->phy)) { | ||
1225 | dev_err(inno->dev, "failed to create HDMI PHY\n"); | ||
1226 | return PTR_ERR(inno->phy); | ||
1227 | } | ||
1228 | |||
1229 | phy_set_drvdata(inno->phy, inno); | ||
1230 | phy_set_bus_width(inno->phy, 8); | ||
1231 | |||
1232 | if (inno->plat_data->ops->init) { | ||
1233 | ret = inno->plat_data->ops->init(inno); | ||
1234 | if (ret) | ||
1235 | return ret; | ||
1236 | } | ||
1237 | |||
1238 | ret = inno_hdmi_phy_clk_register(inno); | ||
1239 | if (ret) | ||
1240 | return ret; | ||
1241 | |||
1242 | phy_provider = devm_of_phy_provider_register(inno->dev, | ||
1243 | of_phy_simple_xlate); | ||
1244 | return PTR_ERR_OR_ZERO(phy_provider); | ||
1245 | } | ||
1246 | |||
1247 | static int inno_hdmi_phy_remove(struct platform_device *pdev) | ||
1248 | { | ||
1249 | of_clk_del_provider(pdev->dev.of_node); | ||
1250 | |||
1251 | return 0; | ||
1252 | } | ||
1253 | |||
1254 | static const struct of_device_id inno_hdmi_phy_of_match[] = { | ||
1255 | { | ||
1256 | .compatible = "rockchip,rk3228-hdmi-phy", | ||
1257 | .data = &rk3228_hdmi_phy_drv_data | ||
1258 | }, { | ||
1259 | .compatible = "rockchip,rk3328-hdmi-phy", | ||
1260 | .data = &rk3328_hdmi_phy_drv_data | ||
1261 | }, { /* sentinel */ } | ||
1262 | }; | ||
1263 | MODULE_DEVICE_TABLE(of, inno_hdmi_phy_of_match); | ||
1264 | |||
1265 | static struct platform_driver inno_hdmi_phy_driver = { | ||
1266 | .probe = inno_hdmi_phy_probe, | ||
1267 | .remove = inno_hdmi_phy_remove, | ||
1268 | .driver = { | ||
1269 | .name = "inno-hdmi-phy", | ||
1270 | .of_match_table = inno_hdmi_phy_of_match, | ||
1271 | }, | ||
1272 | }; | ||
1273 | module_platform_driver(inno_hdmi_phy_driver); | ||
1274 | |||
1275 | MODULE_AUTHOR("Zheng Yang <zhengyang@rock-chips.com>"); | ||
1276 | MODULE_DESCRIPTION("Innosilion HDMI 2.0 Transmitter PHY Driver"); | ||
1277 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index 5049dac79bd0..24bd2717abdb 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c | |||
@@ -1116,8 +1116,8 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) | |||
1116 | } | 1116 | } |
1117 | 1117 | ||
1118 | if (of_property_read_u32(np, "reg", ®)) { | 1118 | if (of_property_read_u32(np, "reg", ®)) { |
1119 | dev_err(dev, "the reg property is not assigned in %s node\n", | 1119 | dev_err(dev, "the reg property is not assigned in %pOFn node\n", |
1120 | np->name); | 1120 | np); |
1121 | return -EINVAL; | 1121 | return -EINVAL; |
1122 | } | 1122 | } |
1123 | 1123 | ||
@@ -1143,8 +1143,8 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) | |||
1143 | } | 1143 | } |
1144 | 1144 | ||
1145 | if (!rphy->phy_cfg) { | 1145 | if (!rphy->phy_cfg) { |
1146 | dev_err(dev, "no phy-config can be matched with %s node\n", | 1146 | dev_err(dev, "no phy-config can be matched with %pOFn node\n", |
1147 | np->name); | 1147 | np); |
1148 | return -EINVAL; | 1148 | return -EINVAL; |
1149 | } | 1149 | } |
1150 | 1150 | ||
diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 76a4b58ec771..c57e496f0b0c 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c | |||
@@ -1145,8 +1145,8 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev) | |||
1145 | } | 1145 | } |
1146 | 1146 | ||
1147 | if (!tcphy->port_cfgs) { | 1147 | if (!tcphy->port_cfgs) { |
1148 | dev_err(dev, "no phy-config can be matched with %s node\n", | 1148 | dev_err(dev, "no phy-config can be matched with %pOFn node\n", |
1149 | np->name); | 1149 | np); |
1150 | return -EINVAL; | 1150 | return -EINVAL; |
1151 | } | 1151 | } |
1152 | 1152 | ||
@@ -1186,8 +1186,8 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev) | |||
1186 | continue; | 1186 | continue; |
1187 | 1187 | ||
1188 | if (IS_ERR(phy)) { | 1188 | if (IS_ERR(phy)) { |
1189 | dev_err(dev, "failed to create phy: %s\n", | 1189 | dev_err(dev, "failed to create phy: %pOFn\n", |
1190 | child_np->name); | 1190 | child_np); |
1191 | pm_runtime_disable(dev); | 1191 | pm_runtime_disable(dev); |
1192 | return PTR_ERR(phy); | 1192 | return PTR_ERR(phy); |
1193 | } | 1193 | } |
diff --git a/drivers/phy/rockchip/phy-rockchip-usb.c b/drivers/phy/rockchip/phy-rockchip-usb.c index 3378eeb7a562..b2899c744ad9 100644 --- a/drivers/phy/rockchip/phy-rockchip-usb.c +++ b/drivers/phy/rockchip/phy-rockchip-usb.c | |||
@@ -36,7 +36,22 @@ static int enable_usb_uart; | |||
36 | #define HIWORD_UPDATE(val, mask) \ | 36 | #define HIWORD_UPDATE(val, mask) \ |
37 | ((val) | (mask) << 16) | 37 | ((val) | (mask) << 16) |
38 | 38 | ||
39 | #define UOC_CON0_SIDDQ BIT(13) | 39 | #define UOC_CON0 0x00 |
40 | #define UOC_CON0_SIDDQ BIT(13) | ||
41 | #define UOC_CON0_DISABLE BIT(4) | ||
42 | #define UOC_CON0_COMMON_ON_N BIT(0) | ||
43 | |||
44 | #define UOC_CON2 0x08 | ||
45 | #define UOC_CON2_SOFT_CON_SEL BIT(2) | ||
46 | |||
47 | #define UOC_CON3 0x0c | ||
48 | /* bits present on rk3188 and rk3288 phys */ | ||
49 | #define UOC_CON3_UTMI_TERMSEL_FULLSPEED BIT(5) | ||
50 | #define UOC_CON3_UTMI_XCVRSEELCT_FSTRANSC (1 << 3) | ||
51 | #define UOC_CON3_UTMI_XCVRSEELCT_MASK (3 << 3) | ||
52 | #define UOC_CON3_UTMI_OPMODE_NODRIVING (1 << 1) | ||
53 | #define UOC_CON3_UTMI_OPMODE_MASK (3 << 1) | ||
54 | #define UOC_CON3_UTMI_SUSPENDN BIT(0) | ||
40 | 55 | ||
41 | struct rockchip_usb_phys { | 56 | struct rockchip_usb_phys { |
42 | int reg; | 57 | int reg; |
@@ -46,7 +61,8 @@ struct rockchip_usb_phys { | |||
46 | struct rockchip_usb_phy_base; | 61 | struct rockchip_usb_phy_base; |
47 | struct rockchip_usb_phy_pdata { | 62 | struct rockchip_usb_phy_pdata { |
48 | struct rockchip_usb_phys *phys; | 63 | struct rockchip_usb_phys *phys; |
49 | int (*init_usb_uart)(struct regmap *grf); | 64 | int (*init_usb_uart)(struct regmap *grf, |
65 | const struct rockchip_usb_phy_pdata *pdata); | ||
50 | int usb_uart_phy; | 66 | int usb_uart_phy; |
51 | }; | 67 | }; |
52 | 68 | ||
@@ -208,8 +224,8 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base, | |||
208 | rk_phy->np = child; | 224 | rk_phy->np = child; |
209 | 225 | ||
210 | if (of_property_read_u32(child, "reg", ®_offset)) { | 226 | if (of_property_read_u32(child, "reg", ®_offset)) { |
211 | dev_err(base->dev, "missing reg property in node %s\n", | 227 | dev_err(base->dev, "missing reg property in node %pOFn\n", |
212 | child->name); | 228 | child); |
213 | return -EINVAL; | 229 | return -EINVAL; |
214 | } | 230 | } |
215 | 231 | ||
@@ -313,28 +329,88 @@ static const struct rockchip_usb_phy_pdata rk3066a_pdata = { | |||
313 | }, | 329 | }, |
314 | }; | 330 | }; |
315 | 331 | ||
332 | static int __init rockchip_init_usb_uart_common(struct regmap *grf, | ||
333 | const struct rockchip_usb_phy_pdata *pdata) | ||
334 | { | ||
335 | int regoffs = pdata->phys[pdata->usb_uart_phy].reg; | ||
336 | int ret; | ||
337 | u32 val; | ||
338 | |||
339 | /* | ||
340 | * COMMON_ON and DISABLE settings are described in the TRM, | ||
341 | * but were not present in the original code. | ||
342 | * Also disable the analog phy components to save power. | ||
343 | */ | ||
344 | val = HIWORD_UPDATE(UOC_CON0_COMMON_ON_N | ||
345 | | UOC_CON0_DISABLE | ||
346 | | UOC_CON0_SIDDQ, | ||
347 | UOC_CON0_COMMON_ON_N | ||
348 | | UOC_CON0_DISABLE | ||
349 | | UOC_CON0_SIDDQ); | ||
350 | ret = regmap_write(grf, regoffs + UOC_CON0, val); | ||
351 | if (ret) | ||
352 | return ret; | ||
353 | |||
354 | val = HIWORD_UPDATE(UOC_CON2_SOFT_CON_SEL, | ||
355 | UOC_CON2_SOFT_CON_SEL); | ||
356 | ret = regmap_write(grf, regoffs + UOC_CON2, val); | ||
357 | if (ret) | ||
358 | return ret; | ||
359 | |||
360 | val = HIWORD_UPDATE(UOC_CON3_UTMI_OPMODE_NODRIVING | ||
361 | | UOC_CON3_UTMI_XCVRSEELCT_FSTRANSC | ||
362 | | UOC_CON3_UTMI_TERMSEL_FULLSPEED, | ||
363 | UOC_CON3_UTMI_SUSPENDN | ||
364 | | UOC_CON3_UTMI_OPMODE_MASK | ||
365 | | UOC_CON3_UTMI_XCVRSEELCT_MASK | ||
366 | | UOC_CON3_UTMI_TERMSEL_FULLSPEED); | ||
367 | ret = regmap_write(grf, UOC_CON3, val); | ||
368 | if (ret) | ||
369 | return ret; | ||
370 | |||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | #define RK3188_UOC0_CON0 0x10c | ||
375 | #define RK3188_UOC0_CON0_BYPASSSEL BIT(9) | ||
376 | #define RK3188_UOC0_CON0_BYPASSDMEN BIT(8) | ||
377 | |||
378 | /* | ||
379 | * Enable the bypass of uart2 data through the otg usb phy. | ||
380 | * See description of rk3288-variant for details. | ||
381 | */ | ||
382 | static int __init rk3188_init_usb_uart(struct regmap *grf, | ||
383 | const struct rockchip_usb_phy_pdata *pdata) | ||
384 | { | ||
385 | u32 val; | ||
386 | int ret; | ||
387 | |||
388 | ret = rockchip_init_usb_uart_common(grf, pdata); | ||
389 | if (ret) | ||
390 | return ret; | ||
391 | |||
392 | val = HIWORD_UPDATE(RK3188_UOC0_CON0_BYPASSSEL | ||
393 | | RK3188_UOC0_CON0_BYPASSDMEN, | ||
394 | RK3188_UOC0_CON0_BYPASSSEL | ||
395 | | RK3188_UOC0_CON0_BYPASSDMEN); | ||
396 | ret = regmap_write(grf, RK3188_UOC0_CON0, val); | ||
397 | if (ret) | ||
398 | return ret; | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
316 | static const struct rockchip_usb_phy_pdata rk3188_pdata = { | 403 | static const struct rockchip_usb_phy_pdata rk3188_pdata = { |
317 | .phys = (struct rockchip_usb_phys[]){ | 404 | .phys = (struct rockchip_usb_phys[]){ |
318 | { .reg = 0x10c, .pll_name = "sclk_otgphy0_480m" }, | 405 | { .reg = 0x10c, .pll_name = "sclk_otgphy0_480m" }, |
319 | { .reg = 0x11c, .pll_name = "sclk_otgphy1_480m" }, | 406 | { .reg = 0x11c, .pll_name = "sclk_otgphy1_480m" }, |
320 | { /* sentinel */ } | 407 | { /* sentinel */ } |
321 | }, | 408 | }, |
409 | .init_usb_uart = rk3188_init_usb_uart, | ||
410 | .usb_uart_phy = 0, | ||
322 | }; | 411 | }; |
323 | 412 | ||
324 | #define RK3288_UOC0_CON0 0x320 | ||
325 | #define RK3288_UOC0_CON0_COMMON_ON_N BIT(0) | ||
326 | #define RK3288_UOC0_CON0_DISABLE BIT(4) | ||
327 | |||
328 | #define RK3288_UOC0_CON2 0x328 | ||
329 | #define RK3288_UOC0_CON2_SOFT_CON_SEL BIT(2) | ||
330 | |||
331 | #define RK3288_UOC0_CON3 0x32c | 413 | #define RK3288_UOC0_CON3 0x32c |
332 | #define RK3288_UOC0_CON3_UTMI_SUSPENDN BIT(0) | ||
333 | #define RK3288_UOC0_CON3_UTMI_OPMODE_NODRIVING (1 << 1) | ||
334 | #define RK3288_UOC0_CON3_UTMI_OPMODE_MASK (3 << 1) | ||
335 | #define RK3288_UOC0_CON3_UTMI_XCVRSEELCT_FSTRANSC (1 << 3) | ||
336 | #define RK3288_UOC0_CON3_UTMI_XCVRSEELCT_MASK (3 << 3) | ||
337 | #define RK3288_UOC0_CON3_UTMI_TERMSEL_FULLSPEED BIT(5) | ||
338 | #define RK3288_UOC0_CON3_BYPASSDMEN BIT(6) | 414 | #define RK3288_UOC0_CON3_BYPASSDMEN BIT(6) |
339 | #define RK3288_UOC0_CON3_BYPASSSEL BIT(7) | 415 | #define RK3288_UOC0_CON3_BYPASSSEL BIT(7) |
340 | 416 | ||
@@ -353,40 +429,13 @@ static const struct rockchip_usb_phy_pdata rk3188_pdata = { | |||
353 | * | 429 | * |
354 | * The actual code in the vendor kernel does some things differently. | 430 | * The actual code in the vendor kernel does some things differently. |
355 | */ | 431 | */ |
356 | static int __init rk3288_init_usb_uart(struct regmap *grf) | 432 | static int __init rk3288_init_usb_uart(struct regmap *grf, |
433 | const struct rockchip_usb_phy_pdata *pdata) | ||
357 | { | 434 | { |
358 | u32 val; | 435 | u32 val; |
359 | int ret; | 436 | int ret; |
360 | 437 | ||
361 | /* | 438 | ret = rockchip_init_usb_uart_common(grf, pdata); |
362 | * COMMON_ON and DISABLE settings are described in the TRM, | ||
363 | * but were not present in the original code. | ||
364 | * Also disable the analog phy components to save power. | ||
365 | */ | ||
366 | val = HIWORD_UPDATE(RK3288_UOC0_CON0_COMMON_ON_N | ||
367 | | RK3288_UOC0_CON0_DISABLE | ||
368 | | UOC_CON0_SIDDQ, | ||
369 | RK3288_UOC0_CON0_COMMON_ON_N | ||
370 | | RK3288_UOC0_CON0_DISABLE | ||
371 | | UOC_CON0_SIDDQ); | ||
372 | ret = regmap_write(grf, RK3288_UOC0_CON0, val); | ||
373 | if (ret) | ||
374 | return ret; | ||
375 | |||
376 | val = HIWORD_UPDATE(RK3288_UOC0_CON2_SOFT_CON_SEL, | ||
377 | RK3288_UOC0_CON2_SOFT_CON_SEL); | ||
378 | ret = regmap_write(grf, RK3288_UOC0_CON2, val); | ||
379 | if (ret) | ||
380 | return ret; | ||
381 | |||
382 | val = HIWORD_UPDATE(RK3288_UOC0_CON3_UTMI_OPMODE_NODRIVING | ||
383 | | RK3288_UOC0_CON3_UTMI_XCVRSEELCT_FSTRANSC | ||
384 | | RK3288_UOC0_CON3_UTMI_TERMSEL_FULLSPEED, | ||
385 | RK3288_UOC0_CON3_UTMI_SUSPENDN | ||
386 | | RK3288_UOC0_CON3_UTMI_OPMODE_MASK | ||
387 | | RK3288_UOC0_CON3_UTMI_XCVRSEELCT_MASK | ||
388 | | RK3288_UOC0_CON3_UTMI_TERMSEL_FULLSPEED); | ||
389 | ret = regmap_write(grf, RK3288_UOC0_CON3, val); | ||
390 | if (ret) | 439 | if (ret) |
391 | return ret; | 440 | return ret; |
392 | 441 | ||
@@ -516,7 +565,7 @@ static int __init rockchip_init_usb_uart(void) | |||
516 | return PTR_ERR(grf); | 565 | return PTR_ERR(grf); |
517 | } | 566 | } |
518 | 567 | ||
519 | ret = data->init_usb_uart(grf); | 568 | ret = data->init_usb_uart(grf, data); |
520 | if (ret) { | 569 | if (ret) { |
521 | pr_err("%s: could not init usb_uart, %d\n", __func__, ret); | 570 | pr_err("%s: could not init usb_uart, %d\n", __func__, ret); |
522 | enable_usb_uart = 0; | 571 | enable_usb_uart = 0; |
diff --git a/drivers/phy/socionext/Kconfig b/drivers/phy/socionext/Kconfig new file mode 100644 index 000000000000..467e8147972b --- /dev/null +++ b/drivers/phy/socionext/Kconfig | |||
@@ -0,0 +1,34 @@ | |||
1 | # | ||
2 | # PHY drivers for Socionext platforms. | ||
3 | # | ||
4 | |||
5 | config PHY_UNIPHIER_USB2 | ||
6 | tristate "UniPhier USB2 PHY driver" | ||
7 | depends on ARCH_UNIPHIER || COMPILE_TEST | ||
8 | depends on OF && HAS_IOMEM | ||
9 | select GENERIC_PHY | ||
10 | select MFD_SYSCON | ||
11 | help | ||
12 | Enable this to support USB PHY implemented on USB2 controller | ||
13 | on UniPhier SoCs. This driver provides interface to interact | ||
14 | with USB 2.0 PHY that is part of the UniPhier SoC. | ||
15 | In case of Pro4, it is necessary to specify this USB2 PHY instead | ||
16 | of USB3 HS-PHY. | ||
17 | |||
18 | config PHY_UNIPHIER_USB3 | ||
19 | tristate "UniPhier USB3 PHY driver" | ||
20 | depends on ARCH_UNIPHIER || COMPILE_TEST | ||
21 | depends on OF && HAS_IOMEM | ||
22 | select GENERIC_PHY | ||
23 | help | ||
24 | Enable this to support USB PHY implemented in USB3 controller | ||
25 | on UniPhier SoCs. This controller supports USB3.0 and lower speed. | ||
26 | |||
27 | config PHY_UNIPHIER_PCIE | ||
28 | tristate "Uniphier PHY driver for PCIe controller" | ||
29 | depends on (ARCH_UNIPHIER || COMPILE_TEST) && OF | ||
30 | default PCIE_UNIPHIER | ||
31 | select GENERIC_PHY | ||
32 | help | ||
33 | Enable this to support PHY implemented in PCIe controller | ||
34 | on UniPhier SoCs. This driver supports LD20 and PXs3 SoCs. | ||
diff --git a/drivers/phy/socionext/Makefile b/drivers/phy/socionext/Makefile new file mode 100644 index 000000000000..7dc9095b5bb7 --- /dev/null +++ b/drivers/phy/socionext/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | # | ||
3 | # Makefile for the phy drivers. | ||
4 | # | ||
5 | |||
6 | obj-$(CONFIG_PHY_UNIPHIER_USB2) += phy-uniphier-usb2.o | ||
7 | obj-$(CONFIG_PHY_UNIPHIER_USB3) += phy-uniphier-usb3hs.o phy-uniphier-usb3ss.o | ||
8 | obj-$(CONFIG_PHY_UNIPHIER_PCIE) += phy-uniphier-pcie.o | ||
diff --git a/drivers/phy/socionext/phy-uniphier-pcie.c b/drivers/phy/socionext/phy-uniphier-pcie.c new file mode 100644 index 000000000000..93ffbd2940fa --- /dev/null +++ b/drivers/phy/socionext/phy-uniphier-pcie.c | |||
@@ -0,0 +1,240 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * phy-uniphier-pcie.c - PHY driver for UniPhier PCIe controller | ||
4 | * Copyright 2018, Socionext Inc. | ||
5 | * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com> | ||
6 | */ | ||
7 | |||
8 | #include <linux/bitops.h> | ||
9 | #include <linux/bitfield.h> | ||
10 | #include <linux/clk.h> | ||
11 | #include <linux/iopoll.h> | ||
12 | #include <linux/mfd/syscon.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/of_device.h> | ||
15 | #include <linux/phy/phy.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/regmap.h> | ||
18 | #include <linux/reset.h> | ||
19 | #include <linux/resource.h> | ||
20 | |||
21 | /* PHY */ | ||
22 | #define PCL_PHY_TEST_I 0x2000 | ||
23 | #define PCL_PHY_TEST_O 0x2004 | ||
24 | #define TESTI_DAT_MASK GENMASK(13, 6) | ||
25 | #define TESTI_ADR_MASK GENMASK(5, 1) | ||
26 | #define TESTI_WR_EN BIT(0) | ||
27 | |||
28 | #define PCL_PHY_RESET 0x200c | ||
29 | #define PCL_PHY_RESET_N_MNMODE BIT(8) /* =1:manual */ | ||
30 | #define PCL_PHY_RESET_N BIT(0) /* =1:deasssert */ | ||
31 | |||
32 | /* SG */ | ||
33 | #define SG_USBPCIESEL 0x590 | ||
34 | #define SG_USBPCIESEL_PCIE BIT(0) | ||
35 | |||
36 | #define PCL_PHY_R00 0 | ||
37 | #define RX_EQ_ADJ_EN BIT(3) /* enable for EQ adjustment */ | ||
38 | #define PCL_PHY_R06 6 | ||
39 | #define RX_EQ_ADJ GENMASK(5, 0) /* EQ adjustment value */ | ||
40 | #define RX_EQ_ADJ_VAL 0 | ||
41 | #define PCL_PHY_R26 26 | ||
42 | #define VCO_CTRL GENMASK(7, 4) /* Tx VCO adjustment value */ | ||
43 | #define VCO_CTRL_INIT_VAL 5 | ||
44 | |||
45 | struct uniphier_pciephy_priv { | ||
46 | void __iomem *base; | ||
47 | struct device *dev; | ||
48 | struct clk *clk; | ||
49 | struct reset_control *rst; | ||
50 | const struct uniphier_pciephy_soc_data *data; | ||
51 | }; | ||
52 | |||
53 | struct uniphier_pciephy_soc_data { | ||
54 | bool has_syscon; | ||
55 | }; | ||
56 | |||
57 | static void uniphier_pciephy_testio_write(struct uniphier_pciephy_priv *priv, | ||
58 | u32 data) | ||
59 | { | ||
60 | /* need to read TESTO twice after accessing TESTI */ | ||
61 | writel(data, priv->base + PCL_PHY_TEST_I); | ||
62 | readl(priv->base + PCL_PHY_TEST_O); | ||
63 | readl(priv->base + PCL_PHY_TEST_O); | ||
64 | } | ||
65 | |||
66 | static void uniphier_pciephy_set_param(struct uniphier_pciephy_priv *priv, | ||
67 | u32 reg, u32 mask, u32 param) | ||
68 | { | ||
69 | u32 val; | ||
70 | |||
71 | /* read previous data */ | ||
72 | val = FIELD_PREP(TESTI_DAT_MASK, 1); | ||
73 | val |= FIELD_PREP(TESTI_ADR_MASK, reg); | ||
74 | uniphier_pciephy_testio_write(priv, val); | ||
75 | val = readl(priv->base + PCL_PHY_TEST_O); | ||
76 | |||
77 | /* update value */ | ||
78 | val &= ~FIELD_PREP(TESTI_DAT_MASK, mask); | ||
79 | val = FIELD_PREP(TESTI_DAT_MASK, mask & param); | ||
80 | val |= FIELD_PREP(TESTI_ADR_MASK, reg); | ||
81 | uniphier_pciephy_testio_write(priv, val); | ||
82 | uniphier_pciephy_testio_write(priv, val | TESTI_WR_EN); | ||
83 | uniphier_pciephy_testio_write(priv, val); | ||
84 | |||
85 | /* read current data as dummy */ | ||
86 | val = FIELD_PREP(TESTI_DAT_MASK, 1); | ||
87 | val |= FIELD_PREP(TESTI_ADR_MASK, reg); | ||
88 | uniphier_pciephy_testio_write(priv, val); | ||
89 | readl(priv->base + PCL_PHY_TEST_O); | ||
90 | } | ||
91 | |||
92 | static void uniphier_pciephy_assert(struct uniphier_pciephy_priv *priv) | ||
93 | { | ||
94 | u32 val; | ||
95 | |||
96 | val = readl(priv->base + PCL_PHY_RESET); | ||
97 | val &= ~PCL_PHY_RESET_N; | ||
98 | val |= PCL_PHY_RESET_N_MNMODE; | ||
99 | writel(val, priv->base + PCL_PHY_RESET); | ||
100 | } | ||
101 | |||
102 | static void uniphier_pciephy_deassert(struct uniphier_pciephy_priv *priv) | ||
103 | { | ||
104 | u32 val; | ||
105 | |||
106 | val = readl(priv->base + PCL_PHY_RESET); | ||
107 | val |= PCL_PHY_RESET_N_MNMODE | PCL_PHY_RESET_N; | ||
108 | writel(val, priv->base + PCL_PHY_RESET); | ||
109 | } | ||
110 | |||
111 | static int uniphier_pciephy_init(struct phy *phy) | ||
112 | { | ||
113 | struct uniphier_pciephy_priv *priv = phy_get_drvdata(phy); | ||
114 | int ret; | ||
115 | |||
116 | ret = clk_prepare_enable(priv->clk); | ||
117 | if (ret) | ||
118 | return ret; | ||
119 | |||
120 | ret = reset_control_deassert(priv->rst); | ||
121 | if (ret) | ||
122 | goto out_clk_disable; | ||
123 | |||
124 | uniphier_pciephy_set_param(priv, PCL_PHY_R00, | ||
125 | RX_EQ_ADJ_EN, RX_EQ_ADJ_EN); | ||
126 | uniphier_pciephy_set_param(priv, PCL_PHY_R06, RX_EQ_ADJ, | ||
127 | FIELD_PREP(RX_EQ_ADJ, RX_EQ_ADJ_VAL)); | ||
128 | uniphier_pciephy_set_param(priv, PCL_PHY_R26, VCO_CTRL, | ||
129 | FIELD_PREP(VCO_CTRL, VCO_CTRL_INIT_VAL)); | ||
130 | usleep_range(1, 10); | ||
131 | |||
132 | uniphier_pciephy_deassert(priv); | ||
133 | usleep_range(1, 10); | ||
134 | |||
135 | return 0; | ||
136 | |||
137 | out_clk_disable: | ||
138 | clk_disable_unprepare(priv->clk); | ||
139 | |||
140 | return ret; | ||
141 | } | ||
142 | |||
143 | static int uniphier_pciephy_exit(struct phy *phy) | ||
144 | { | ||
145 | struct uniphier_pciephy_priv *priv = phy_get_drvdata(phy); | ||
146 | |||
147 | uniphier_pciephy_assert(priv); | ||
148 | reset_control_assert(priv->rst); | ||
149 | clk_disable_unprepare(priv->clk); | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static const struct phy_ops uniphier_pciephy_ops = { | ||
155 | .init = uniphier_pciephy_init, | ||
156 | .exit = uniphier_pciephy_exit, | ||
157 | .owner = THIS_MODULE, | ||
158 | }; | ||
159 | |||
160 | static int uniphier_pciephy_probe(struct platform_device *pdev) | ||
161 | { | ||
162 | struct uniphier_pciephy_priv *priv; | ||
163 | struct phy_provider *phy_provider; | ||
164 | struct device *dev = &pdev->dev; | ||
165 | struct regmap *regmap; | ||
166 | struct resource *res; | ||
167 | struct phy *phy; | ||
168 | |||
169 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
170 | if (!priv) | ||
171 | return -ENOMEM; | ||
172 | |||
173 | priv->data = of_device_get_match_data(dev); | ||
174 | if (WARN_ON(!priv->data)) | ||
175 | return -EINVAL; | ||
176 | |||
177 | priv->dev = dev; | ||
178 | |||
179 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
180 | priv->base = devm_ioremap_resource(dev, res); | ||
181 | if (IS_ERR(priv->base)) | ||
182 | return PTR_ERR(priv->base); | ||
183 | |||
184 | priv->clk = devm_clk_get(dev, NULL); | ||
185 | if (IS_ERR(priv->clk)) | ||
186 | return PTR_ERR(priv->clk); | ||
187 | |||
188 | priv->rst = devm_reset_control_get_shared(dev, NULL); | ||
189 | if (IS_ERR(priv->rst)) | ||
190 | return PTR_ERR(priv->rst); | ||
191 | |||
192 | phy = devm_phy_create(dev, dev->of_node, &uniphier_pciephy_ops); | ||
193 | if (IS_ERR(phy)) | ||
194 | return PTR_ERR(phy); | ||
195 | |||
196 | regmap = syscon_regmap_lookup_by_phandle(dev->of_node, | ||
197 | "socionext,syscon"); | ||
198 | if (!IS_ERR(regmap) && priv->data->has_syscon) | ||
199 | regmap_update_bits(regmap, SG_USBPCIESEL, | ||
200 | SG_USBPCIESEL_PCIE, SG_USBPCIESEL_PCIE); | ||
201 | |||
202 | phy_set_drvdata(phy, priv); | ||
203 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | ||
204 | |||
205 | return PTR_ERR_OR_ZERO(phy_provider); | ||
206 | } | ||
207 | |||
208 | static const struct uniphier_pciephy_soc_data uniphier_ld20_data = { | ||
209 | .has_syscon = true, | ||
210 | }; | ||
211 | |||
212 | static const struct uniphier_pciephy_soc_data uniphier_pxs3_data = { | ||
213 | .has_syscon = false, | ||
214 | }; | ||
215 | |||
216 | static const struct of_device_id uniphier_pciephy_match[] = { | ||
217 | { | ||
218 | .compatible = "socionext,uniphier-ld20-pcie-phy", | ||
219 | .data = &uniphier_ld20_data, | ||
220 | }, | ||
221 | { | ||
222 | .compatible = "socionext,uniphier-pxs3-pcie-phy", | ||
223 | .data = &uniphier_pxs3_data, | ||
224 | }, | ||
225 | { /* sentinel */ }, | ||
226 | }; | ||
227 | MODULE_DEVICE_TABLE(of, uniphier_pciephy_match); | ||
228 | |||
229 | static struct platform_driver uniphier_pciephy_driver = { | ||
230 | .probe = uniphier_pciephy_probe, | ||
231 | .driver = { | ||
232 | .name = "uniphier-pcie-phy", | ||
233 | .of_match_table = uniphier_pciephy_match, | ||
234 | }, | ||
235 | }; | ||
236 | module_platform_driver(uniphier_pciephy_driver); | ||
237 | |||
238 | MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>"); | ||
239 | MODULE_DESCRIPTION("UniPhier PHY driver for PCIe controller"); | ||
240 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/socionext/phy-uniphier-usb2.c b/drivers/phy/socionext/phy-uniphier-usb2.c new file mode 100644 index 000000000000..3f2086ed4fe4 --- /dev/null +++ b/drivers/phy/socionext/phy-uniphier-usb2.c | |||
@@ -0,0 +1,244 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * phy-uniphier-usb2.c - PHY driver for UniPhier USB2 controller | ||
4 | * Copyright 2015-2018 Socionext Inc. | ||
5 | * Author: | ||
6 | * Kunihiko Hayashi <hayashi.kunihiko@socionext.com> | ||
7 | */ | ||
8 | |||
9 | #include <linux/mfd/syscon.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/of.h> | ||
12 | #include <linux/of_platform.h> | ||
13 | #include <linux/phy/phy.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/regmap.h> | ||
16 | #include <linux/regulator/consumer.h> | ||
17 | |||
18 | #define SG_USBPHY1CTRL 0x500 | ||
19 | #define SG_USBPHY1CTRL2 0x504 | ||
20 | #define SG_USBPHY2CTRL 0x508 | ||
21 | #define SG_USBPHY2CTRL2 0x50c /* LD11 */ | ||
22 | #define SG_USBPHY12PLL 0x50c /* Pro4 */ | ||
23 | #define SG_USBPHY3CTRL 0x510 | ||
24 | #define SG_USBPHY3CTRL2 0x514 | ||
25 | #define SG_USBPHY4CTRL 0x518 /* Pro4 */ | ||
26 | #define SG_USBPHY4CTRL2 0x51c /* Pro4 */ | ||
27 | #define SG_USBPHY34PLL 0x51c /* Pro4 */ | ||
28 | |||
29 | struct uniphier_u2phy_param { | ||
30 | u32 offset; | ||
31 | u32 value; | ||
32 | }; | ||
33 | |||
34 | struct uniphier_u2phy_soc_data { | ||
35 | struct uniphier_u2phy_param config0; | ||
36 | struct uniphier_u2phy_param config1; | ||
37 | }; | ||
38 | |||
39 | struct uniphier_u2phy_priv { | ||
40 | struct regmap *regmap; | ||
41 | struct phy *phy; | ||
42 | struct regulator *vbus; | ||
43 | const struct uniphier_u2phy_soc_data *data; | ||
44 | struct uniphier_u2phy_priv *next; | ||
45 | }; | ||
46 | |||
47 | static int uniphier_u2phy_power_on(struct phy *phy) | ||
48 | { | ||
49 | struct uniphier_u2phy_priv *priv = phy_get_drvdata(phy); | ||
50 | int ret = 0; | ||
51 | |||
52 | if (priv->vbus) | ||
53 | ret = regulator_enable(priv->vbus); | ||
54 | |||
55 | return ret; | ||
56 | } | ||
57 | |||
58 | static int uniphier_u2phy_power_off(struct phy *phy) | ||
59 | { | ||
60 | struct uniphier_u2phy_priv *priv = phy_get_drvdata(phy); | ||
61 | |||
62 | if (priv->vbus) | ||
63 | regulator_disable(priv->vbus); | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | static int uniphier_u2phy_init(struct phy *phy) | ||
69 | { | ||
70 | struct uniphier_u2phy_priv *priv = phy_get_drvdata(phy); | ||
71 | |||
72 | if (!priv->data) | ||
73 | return 0; | ||
74 | |||
75 | regmap_write(priv->regmap, priv->data->config0.offset, | ||
76 | priv->data->config0.value); | ||
77 | regmap_write(priv->regmap, priv->data->config1.offset, | ||
78 | priv->data->config1.value); | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static struct phy *uniphier_u2phy_xlate(struct device *dev, | ||
84 | struct of_phandle_args *args) | ||
85 | { | ||
86 | struct uniphier_u2phy_priv *priv = dev_get_drvdata(dev); | ||
87 | |||
88 | while (priv && args->np != priv->phy->dev.of_node) | ||
89 | priv = priv->next; | ||
90 | |||
91 | if (!priv) { | ||
92 | dev_err(dev, "Failed to find appropriate phy\n"); | ||
93 | return ERR_PTR(-EINVAL); | ||
94 | } | ||
95 | |||
96 | return priv->phy; | ||
97 | } | ||
98 | |||
99 | static const struct phy_ops uniphier_u2phy_ops = { | ||
100 | .init = uniphier_u2phy_init, | ||
101 | .power_on = uniphier_u2phy_power_on, | ||
102 | .power_off = uniphier_u2phy_power_off, | ||
103 | .owner = THIS_MODULE, | ||
104 | }; | ||
105 | |||
106 | static int uniphier_u2phy_probe(struct platform_device *pdev) | ||
107 | { | ||
108 | struct device *dev = &pdev->dev; | ||
109 | struct device_node *parent, *child; | ||
110 | struct uniphier_u2phy_priv *priv = NULL, *next = NULL; | ||
111 | struct phy_provider *phy_provider; | ||
112 | struct regmap *regmap; | ||
113 | const struct uniphier_u2phy_soc_data *data; | ||
114 | int ret, data_idx, ndatas; | ||
115 | |||
116 | data = of_device_get_match_data(dev); | ||
117 | if (WARN_ON(!data)) | ||
118 | return -EINVAL; | ||
119 | |||
120 | /* get number of data */ | ||
121 | for (ndatas = 0; data[ndatas].config0.offset; ndatas++) | ||
122 | ; | ||
123 | |||
124 | parent = of_get_parent(dev->of_node); | ||
125 | regmap = syscon_node_to_regmap(parent); | ||
126 | of_node_put(parent); | ||
127 | if (IS_ERR(regmap)) { | ||
128 | dev_err(dev, "Failed to get regmap\n"); | ||
129 | return PTR_ERR(regmap); | ||
130 | } | ||
131 | |||
132 | for_each_child_of_node(dev->of_node, child) { | ||
133 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
134 | if (!priv) { | ||
135 | ret = -ENOMEM; | ||
136 | goto out_put_child; | ||
137 | } | ||
138 | priv->regmap = regmap; | ||
139 | |||
140 | priv->vbus = devm_regulator_get_optional(dev, "vbus"); | ||
141 | if (IS_ERR(priv->vbus)) { | ||
142 | if (PTR_ERR(priv->vbus) == -EPROBE_DEFER) { | ||
143 | ret = PTR_ERR(priv->vbus); | ||
144 | goto out_put_child; | ||
145 | } | ||
146 | priv->vbus = NULL; | ||
147 | } | ||
148 | |||
149 | priv->phy = devm_phy_create(dev, child, &uniphier_u2phy_ops); | ||
150 | if (IS_ERR(priv->phy)) { | ||
151 | dev_err(dev, "Failed to create phy\n"); | ||
152 | ret = PTR_ERR(priv->phy); | ||
153 | goto out_put_child; | ||
154 | } | ||
155 | |||
156 | ret = of_property_read_u32(child, "reg", &data_idx); | ||
157 | if (ret) { | ||
158 | dev_err(dev, "Failed to get reg property\n"); | ||
159 | goto out_put_child; | ||
160 | } | ||
161 | |||
162 | if (data_idx < ndatas) | ||
163 | priv->data = &data[data_idx]; | ||
164 | else | ||
165 | dev_warn(dev, "No phy configuration: %s\n", | ||
166 | child->full_name); | ||
167 | |||
168 | phy_set_drvdata(priv->phy, priv); | ||
169 | priv->next = next; | ||
170 | next = priv; | ||
171 | } | ||
172 | |||
173 | dev_set_drvdata(dev, priv); | ||
174 | phy_provider = devm_of_phy_provider_register(dev, | ||
175 | uniphier_u2phy_xlate); | ||
176 | return PTR_ERR_OR_ZERO(phy_provider); | ||
177 | |||
178 | out_put_child: | ||
179 | of_node_put(child); | ||
180 | |||
181 | return ret; | ||
182 | } | ||
183 | |||
184 | static const struct uniphier_u2phy_soc_data uniphier_pro4_data[] = { | ||
185 | { | ||
186 | .config0 = { SG_USBPHY1CTRL, 0x05142400 }, | ||
187 | .config1 = { SG_USBPHY12PLL, 0x00010010 }, | ||
188 | }, | ||
189 | { | ||
190 | .config0 = { SG_USBPHY2CTRL, 0x05142400 }, | ||
191 | .config1 = { SG_USBPHY12PLL, 0x00010010 }, | ||
192 | }, | ||
193 | { | ||
194 | .config0 = { SG_USBPHY3CTRL, 0x05142400 }, | ||
195 | .config1 = { SG_USBPHY34PLL, 0x00010010 }, | ||
196 | }, | ||
197 | { | ||
198 | .config0 = { SG_USBPHY4CTRL, 0x05142400 }, | ||
199 | .config1 = { SG_USBPHY34PLL, 0x00010010 }, | ||
200 | }, | ||
201 | { /* sentinel */ } | ||
202 | }; | ||
203 | |||
204 | static const struct uniphier_u2phy_soc_data uniphier_ld11_data[] = { | ||
205 | { | ||
206 | .config0 = { SG_USBPHY1CTRL, 0x82280000 }, | ||
207 | .config1 = { SG_USBPHY1CTRL2, 0x00000106 }, | ||
208 | }, | ||
209 | { | ||
210 | .config0 = { SG_USBPHY2CTRL, 0x82280000 }, | ||
211 | .config1 = { SG_USBPHY2CTRL2, 0x00000106 }, | ||
212 | }, | ||
213 | { | ||
214 | .config0 = { SG_USBPHY3CTRL, 0x82280000 }, | ||
215 | .config1 = { SG_USBPHY3CTRL2, 0x00000106 }, | ||
216 | }, | ||
217 | { /* sentinel */ } | ||
218 | }; | ||
219 | |||
220 | static const struct of_device_id uniphier_u2phy_match[] = { | ||
221 | { | ||
222 | .compatible = "socionext,uniphier-pro4-usb2-phy", | ||
223 | .data = &uniphier_pro4_data, | ||
224 | }, | ||
225 | { | ||
226 | .compatible = "socionext,uniphier-ld11-usb2-phy", | ||
227 | .data = &uniphier_ld11_data, | ||
228 | }, | ||
229 | { /* sentinel */ } | ||
230 | }; | ||
231 | MODULE_DEVICE_TABLE(of, uniphier_u2phy_match); | ||
232 | |||
233 | static struct platform_driver uniphier_u2phy_driver = { | ||
234 | .probe = uniphier_u2phy_probe, | ||
235 | .driver = { | ||
236 | .name = "uniphier-usb2-phy", | ||
237 | .of_match_table = uniphier_u2phy_match, | ||
238 | }, | ||
239 | }; | ||
240 | module_platform_driver(uniphier_u2phy_driver); | ||
241 | |||
242 | MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>"); | ||
243 | MODULE_DESCRIPTION("UniPhier PHY driver for USB2 controller"); | ||
244 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/socionext/phy-uniphier-usb3hs.c b/drivers/phy/socionext/phy-uniphier-usb3hs.c new file mode 100644 index 000000000000..b1b048be6166 --- /dev/null +++ b/drivers/phy/socionext/phy-uniphier-usb3hs.c | |||
@@ -0,0 +1,422 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * phy-uniphier-usb3hs.c - HS-PHY driver for Socionext UniPhier USB3 controller | ||
4 | * Copyright 2015-2018 Socionext Inc. | ||
5 | * Author: | ||
6 | * Kunihiko Hayashi <hayashi.kunihiko@socionext.com> | ||
7 | * Contributors: | ||
8 | * Motoya Tanigawa <tanigawa.motoya@socionext.com> | ||
9 | * Masami Hiramatsu <masami.hiramatsu@linaro.org> | ||
10 | */ | ||
11 | |||
12 | #include <linux/bitfield.h> | ||
13 | #include <linux/bitops.h> | ||
14 | #include <linux/clk.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/nvmem-consumer.h> | ||
18 | #include <linux/of.h> | ||
19 | #include <linux/of_platform.h> | ||
20 | #include <linux/phy/phy.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/regulator/consumer.h> | ||
23 | #include <linux/reset.h> | ||
24 | #include <linux/slab.h> | ||
25 | |||
26 | #define HSPHY_CFG0 0x0 | ||
27 | #define HSPHY_CFG0_HS_I_MASK GENMASK(31, 28) | ||
28 | #define HSPHY_CFG0_HSDISC_MASK GENMASK(27, 26) | ||
29 | #define HSPHY_CFG0_SWING_MASK GENMASK(17, 16) | ||
30 | #define HSPHY_CFG0_SEL_T_MASK GENMASK(15, 12) | ||
31 | #define HSPHY_CFG0_RTERM_MASK GENMASK(7, 6) | ||
32 | #define HSPHY_CFG0_TRIMMASK (HSPHY_CFG0_HS_I_MASK \ | ||
33 | | HSPHY_CFG0_SEL_T_MASK \ | ||
34 | | HSPHY_CFG0_RTERM_MASK) | ||
35 | |||
36 | #define HSPHY_CFG1 0x4 | ||
37 | #define HSPHY_CFG1_DAT_EN BIT(29) | ||
38 | #define HSPHY_CFG1_ADR_EN BIT(28) | ||
39 | #define HSPHY_CFG1_ADR_MASK GENMASK(27, 16) | ||
40 | #define HSPHY_CFG1_DAT_MASK GENMASK(23, 16) | ||
41 | |||
42 | #define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) } | ||
43 | |||
44 | #define LS_SLEW PHY_F(10, 6, 6) /* LS mode slew rate */ | ||
45 | #define FS_LS_DRV PHY_F(10, 5, 5) /* FS/LS slew rate */ | ||
46 | |||
47 | #define MAX_PHY_PARAMS 2 | ||
48 | |||
49 | struct uniphier_u3hsphy_param { | ||
50 | struct { | ||
51 | int reg_no; | ||
52 | int msb; | ||
53 | int lsb; | ||
54 | } field; | ||
55 | u8 value; | ||
56 | }; | ||
57 | |||
58 | struct uniphier_u3hsphy_trim_param { | ||
59 | unsigned int rterm; | ||
60 | unsigned int sel_t; | ||
61 | unsigned int hs_i; | ||
62 | }; | ||
63 | |||
64 | #define trim_param_is_valid(p) ((p)->rterm || (p)->sel_t || (p)->hs_i) | ||
65 | |||
66 | struct uniphier_u3hsphy_priv { | ||
67 | struct device *dev; | ||
68 | void __iomem *base; | ||
69 | struct clk *clk, *clk_parent, *clk_ext; | ||
70 | struct reset_control *rst, *rst_parent; | ||
71 | struct regulator *vbus; | ||
72 | const struct uniphier_u3hsphy_soc_data *data; | ||
73 | }; | ||
74 | |||
75 | struct uniphier_u3hsphy_soc_data { | ||
76 | int nparams; | ||
77 | const struct uniphier_u3hsphy_param param[MAX_PHY_PARAMS]; | ||
78 | u32 config0; | ||
79 | u32 config1; | ||
80 | void (*trim_func)(struct uniphier_u3hsphy_priv *priv, u32 *pconfig, | ||
81 | struct uniphier_u3hsphy_trim_param *pt); | ||
82 | }; | ||
83 | |||
84 | static void uniphier_u3hsphy_trim_ld20(struct uniphier_u3hsphy_priv *priv, | ||
85 | u32 *pconfig, | ||
86 | struct uniphier_u3hsphy_trim_param *pt) | ||
87 | { | ||
88 | *pconfig &= ~HSPHY_CFG0_RTERM_MASK; | ||
89 | *pconfig |= FIELD_PREP(HSPHY_CFG0_RTERM_MASK, pt->rterm); | ||
90 | |||
91 | *pconfig &= ~HSPHY_CFG0_SEL_T_MASK; | ||
92 | *pconfig |= FIELD_PREP(HSPHY_CFG0_SEL_T_MASK, pt->sel_t); | ||
93 | |||
94 | *pconfig &= ~HSPHY_CFG0_HS_I_MASK; | ||
95 | *pconfig |= FIELD_PREP(HSPHY_CFG0_HS_I_MASK, pt->hs_i); | ||
96 | } | ||
97 | |||
98 | static int uniphier_u3hsphy_get_nvparam(struct uniphier_u3hsphy_priv *priv, | ||
99 | const char *name, unsigned int *val) | ||
100 | { | ||
101 | struct nvmem_cell *cell; | ||
102 | u8 *buf; | ||
103 | |||
104 | cell = devm_nvmem_cell_get(priv->dev, name); | ||
105 | if (IS_ERR(cell)) | ||
106 | return PTR_ERR(cell); | ||
107 | |||
108 | buf = nvmem_cell_read(cell, NULL); | ||
109 | if (IS_ERR(buf)) | ||
110 | return PTR_ERR(buf); | ||
111 | |||
112 | *val = *buf; | ||
113 | |||
114 | kfree(buf); | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static int uniphier_u3hsphy_get_nvparams(struct uniphier_u3hsphy_priv *priv, | ||
120 | struct uniphier_u3hsphy_trim_param *pt) | ||
121 | { | ||
122 | int ret; | ||
123 | |||
124 | ret = uniphier_u3hsphy_get_nvparam(priv, "rterm", &pt->rterm); | ||
125 | if (ret) | ||
126 | return ret; | ||
127 | |||
128 | ret = uniphier_u3hsphy_get_nvparam(priv, "sel_t", &pt->sel_t); | ||
129 | if (ret) | ||
130 | return ret; | ||
131 | |||
132 | ret = uniphier_u3hsphy_get_nvparam(priv, "hs_i", &pt->hs_i); | ||
133 | if (ret) | ||
134 | return ret; | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static int uniphier_u3hsphy_update_config(struct uniphier_u3hsphy_priv *priv, | ||
140 | u32 *pconfig) | ||
141 | { | ||
142 | struct uniphier_u3hsphy_trim_param trim; | ||
143 | int ret, trimmed = 0; | ||
144 | |||
145 | if (priv->data->trim_func) { | ||
146 | ret = uniphier_u3hsphy_get_nvparams(priv, &trim); | ||
147 | if (ret == -EPROBE_DEFER) | ||
148 | return ret; | ||
149 | |||
150 | /* | ||
151 | * call trim_func only when trimming parameters that aren't | ||
152 | * all-zero can be acquired. All-zero parameters mean nothing | ||
153 | * has been written to nvmem. | ||
154 | */ | ||
155 | if (!ret && trim_param_is_valid(&trim)) { | ||
156 | priv->data->trim_func(priv, pconfig, &trim); | ||
157 | trimmed = 1; | ||
158 | } else { | ||
159 | dev_dbg(priv->dev, "can't get parameter from nvmem\n"); | ||
160 | } | ||
161 | } | ||
162 | |||
163 | /* use default parameters without trimming values */ | ||
164 | if (!trimmed) { | ||
165 | *pconfig &= ~HSPHY_CFG0_HSDISC_MASK; | ||
166 | *pconfig |= FIELD_PREP(HSPHY_CFG0_HSDISC_MASK, 3); | ||
167 | } | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static void uniphier_u3hsphy_set_param(struct uniphier_u3hsphy_priv *priv, | ||
173 | const struct uniphier_u3hsphy_param *p) | ||
174 | { | ||
175 | u32 val; | ||
176 | u32 field_mask = GENMASK(p->field.msb, p->field.lsb); | ||
177 | u8 data; | ||
178 | |||
179 | val = readl(priv->base + HSPHY_CFG1); | ||
180 | val &= ~HSPHY_CFG1_ADR_MASK; | ||
181 | val |= FIELD_PREP(HSPHY_CFG1_ADR_MASK, p->field.reg_no) | ||
182 | | HSPHY_CFG1_ADR_EN; | ||
183 | writel(val, priv->base + HSPHY_CFG1); | ||
184 | |||
185 | val = readl(priv->base + HSPHY_CFG1); | ||
186 | val &= ~HSPHY_CFG1_ADR_EN; | ||
187 | writel(val, priv->base + HSPHY_CFG1); | ||
188 | |||
189 | val = readl(priv->base + HSPHY_CFG1); | ||
190 | val &= ~FIELD_PREP(HSPHY_CFG1_DAT_MASK, field_mask); | ||
191 | data = field_mask & (p->value << p->field.lsb); | ||
192 | val |= FIELD_PREP(HSPHY_CFG1_DAT_MASK, data) | HSPHY_CFG1_DAT_EN; | ||
193 | writel(val, priv->base + HSPHY_CFG1); | ||
194 | |||
195 | val = readl(priv->base + HSPHY_CFG1); | ||
196 | val &= ~HSPHY_CFG1_DAT_EN; | ||
197 | writel(val, priv->base + HSPHY_CFG1); | ||
198 | } | ||
199 | |||
200 | static int uniphier_u3hsphy_power_on(struct phy *phy) | ||
201 | { | ||
202 | struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy); | ||
203 | int ret; | ||
204 | |||
205 | ret = clk_prepare_enable(priv->clk_ext); | ||
206 | if (ret) | ||
207 | return ret; | ||
208 | |||
209 | ret = clk_prepare_enable(priv->clk); | ||
210 | if (ret) | ||
211 | goto out_clk_ext_disable; | ||
212 | |||
213 | ret = reset_control_deassert(priv->rst); | ||
214 | if (ret) | ||
215 | goto out_clk_disable; | ||
216 | |||
217 | if (priv->vbus) { | ||
218 | ret = regulator_enable(priv->vbus); | ||
219 | if (ret) | ||
220 | goto out_rst_assert; | ||
221 | } | ||
222 | |||
223 | return 0; | ||
224 | |||
225 | out_rst_assert: | ||
226 | reset_control_assert(priv->rst); | ||
227 | out_clk_disable: | ||
228 | clk_disable_unprepare(priv->clk); | ||
229 | out_clk_ext_disable: | ||
230 | clk_disable_unprepare(priv->clk_ext); | ||
231 | |||
232 | return ret; | ||
233 | } | ||
234 | |||
235 | static int uniphier_u3hsphy_power_off(struct phy *phy) | ||
236 | { | ||
237 | struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy); | ||
238 | |||
239 | if (priv->vbus) | ||
240 | regulator_disable(priv->vbus); | ||
241 | |||
242 | reset_control_assert(priv->rst); | ||
243 | clk_disable_unprepare(priv->clk); | ||
244 | clk_disable_unprepare(priv->clk_ext); | ||
245 | |||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static int uniphier_u3hsphy_init(struct phy *phy) | ||
250 | { | ||
251 | struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy); | ||
252 | u32 config0, config1; | ||
253 | int i, ret; | ||
254 | |||
255 | ret = clk_prepare_enable(priv->clk_parent); | ||
256 | if (ret) | ||
257 | return ret; | ||
258 | |||
259 | ret = reset_control_deassert(priv->rst_parent); | ||
260 | if (ret) | ||
261 | goto out_clk_disable; | ||
262 | |||
263 | if (!priv->data->config0 && !priv->data->config1) | ||
264 | return 0; | ||
265 | |||
266 | config0 = priv->data->config0; | ||
267 | config1 = priv->data->config1; | ||
268 | |||
269 | ret = uniphier_u3hsphy_update_config(priv, &config0); | ||
270 | if (ret) | ||
271 | goto out_rst_assert; | ||
272 | |||
273 | writel(config0, priv->base + HSPHY_CFG0); | ||
274 | writel(config1, priv->base + HSPHY_CFG1); | ||
275 | |||
276 | for (i = 0; i < priv->data->nparams; i++) | ||
277 | uniphier_u3hsphy_set_param(priv, &priv->data->param[i]); | ||
278 | |||
279 | return 0; | ||
280 | |||
281 | out_rst_assert: | ||
282 | reset_control_assert(priv->rst_parent); | ||
283 | out_clk_disable: | ||
284 | clk_disable_unprepare(priv->clk_parent); | ||
285 | |||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | static int uniphier_u3hsphy_exit(struct phy *phy) | ||
290 | { | ||
291 | struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy); | ||
292 | |||
293 | reset_control_assert(priv->rst_parent); | ||
294 | clk_disable_unprepare(priv->clk_parent); | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static const struct phy_ops uniphier_u3hsphy_ops = { | ||
300 | .init = uniphier_u3hsphy_init, | ||
301 | .exit = uniphier_u3hsphy_exit, | ||
302 | .power_on = uniphier_u3hsphy_power_on, | ||
303 | .power_off = uniphier_u3hsphy_power_off, | ||
304 | .owner = THIS_MODULE, | ||
305 | }; | ||
306 | |||
307 | static int uniphier_u3hsphy_probe(struct platform_device *pdev) | ||
308 | { | ||
309 | struct device *dev = &pdev->dev; | ||
310 | struct uniphier_u3hsphy_priv *priv; | ||
311 | struct phy_provider *phy_provider; | ||
312 | struct resource *res; | ||
313 | struct phy *phy; | ||
314 | |||
315 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
316 | if (!priv) | ||
317 | return -ENOMEM; | ||
318 | |||
319 | priv->dev = dev; | ||
320 | priv->data = of_device_get_match_data(dev); | ||
321 | if (WARN_ON(!priv->data || | ||
322 | priv->data->nparams > MAX_PHY_PARAMS)) | ||
323 | return -EINVAL; | ||
324 | |||
325 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
326 | priv->base = devm_ioremap_resource(dev, res); | ||
327 | if (IS_ERR(priv->base)) | ||
328 | return PTR_ERR(priv->base); | ||
329 | |||
330 | priv->clk = devm_clk_get(dev, "phy"); | ||
331 | if (IS_ERR(priv->clk)) | ||
332 | return PTR_ERR(priv->clk); | ||
333 | |||
334 | priv->clk_parent = devm_clk_get(dev, "link"); | ||
335 | if (IS_ERR(priv->clk_parent)) | ||
336 | return PTR_ERR(priv->clk_parent); | ||
337 | |||
338 | priv->clk_ext = devm_clk_get(dev, "phy-ext"); | ||
339 | if (IS_ERR(priv->clk_ext)) { | ||
340 | if (PTR_ERR(priv->clk_ext) == -ENOENT) | ||
341 | priv->clk_ext = NULL; | ||
342 | else | ||
343 | return PTR_ERR(priv->clk_ext); | ||
344 | } | ||
345 | |||
346 | priv->rst = devm_reset_control_get_shared(dev, "phy"); | ||
347 | if (IS_ERR(priv->rst)) | ||
348 | return PTR_ERR(priv->rst); | ||
349 | |||
350 | priv->rst_parent = devm_reset_control_get_shared(dev, "link"); | ||
351 | if (IS_ERR(priv->rst_parent)) | ||
352 | return PTR_ERR(priv->rst_parent); | ||
353 | |||
354 | priv->vbus = devm_regulator_get_optional(dev, "vbus"); | ||
355 | if (IS_ERR(priv->vbus)) { | ||
356 | if (PTR_ERR(priv->vbus) == -EPROBE_DEFER) | ||
357 | return PTR_ERR(priv->vbus); | ||
358 | priv->vbus = NULL; | ||
359 | } | ||
360 | |||
361 | phy = devm_phy_create(dev, dev->of_node, &uniphier_u3hsphy_ops); | ||
362 | if (IS_ERR(phy)) | ||
363 | return PTR_ERR(phy); | ||
364 | |||
365 | phy_set_drvdata(phy, priv); | ||
366 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | ||
367 | |||
368 | return PTR_ERR_OR_ZERO(phy_provider); | ||
369 | } | ||
370 | |||
371 | static const struct uniphier_u3hsphy_soc_data uniphier_pxs2_data = { | ||
372 | .nparams = 0, | ||
373 | }; | ||
374 | |||
375 | static const struct uniphier_u3hsphy_soc_data uniphier_ld20_data = { | ||
376 | .nparams = 2, | ||
377 | .param = { | ||
378 | { LS_SLEW, 1 }, | ||
379 | { FS_LS_DRV, 1 }, | ||
380 | }, | ||
381 | .trim_func = uniphier_u3hsphy_trim_ld20, | ||
382 | .config0 = 0x92316680, | ||
383 | .config1 = 0x00000106, | ||
384 | }; | ||
385 | |||
386 | static const struct uniphier_u3hsphy_soc_data uniphier_pxs3_data = { | ||
387 | .nparams = 0, | ||
388 | .trim_func = uniphier_u3hsphy_trim_ld20, | ||
389 | .config0 = 0x92316680, | ||
390 | .config1 = 0x00000106, | ||
391 | }; | ||
392 | |||
393 | static const struct of_device_id uniphier_u3hsphy_match[] = { | ||
394 | { | ||
395 | .compatible = "socionext,uniphier-pxs2-usb3-hsphy", | ||
396 | .data = &uniphier_pxs2_data, | ||
397 | }, | ||
398 | { | ||
399 | .compatible = "socionext,uniphier-ld20-usb3-hsphy", | ||
400 | .data = &uniphier_ld20_data, | ||
401 | }, | ||
402 | { | ||
403 | .compatible = "socionext,uniphier-pxs3-usb3-hsphy", | ||
404 | .data = &uniphier_pxs3_data, | ||
405 | }, | ||
406 | { /* sentinel */ } | ||
407 | }; | ||
408 | MODULE_DEVICE_TABLE(of, uniphier_u3hsphy_match); | ||
409 | |||
410 | static struct platform_driver uniphier_u3hsphy_driver = { | ||
411 | .probe = uniphier_u3hsphy_probe, | ||
412 | .driver = { | ||
413 | .name = "uniphier-usb3-hsphy", | ||
414 | .of_match_table = uniphier_u3hsphy_match, | ||
415 | }, | ||
416 | }; | ||
417 | |||
418 | module_platform_driver(uniphier_u3hsphy_driver); | ||
419 | |||
420 | MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>"); | ||
421 | MODULE_DESCRIPTION("UniPhier HS-PHY driver for USB3 controller"); | ||
422 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/socionext/phy-uniphier-usb3ss.c b/drivers/phy/socionext/phy-uniphier-usb3ss.c new file mode 100644 index 000000000000..4be95679c7d8 --- /dev/null +++ b/drivers/phy/socionext/phy-uniphier-usb3ss.c | |||
@@ -0,0 +1,349 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * phy-uniphier-usb3ss.c - SS-PHY driver for Socionext UniPhier USB3 controller | ||
4 | * Copyright 2015-2018 Socionext Inc. | ||
5 | * Author: | ||
6 | * Kunihiko Hayashi <hayashi.kunihiko@socionext.com> | ||
7 | * Contributors: | ||
8 | * Motoya Tanigawa <tanigawa.motoya@socionext.com> | ||
9 | * Masami Hiramatsu <masami.hiramatsu@linaro.org> | ||
10 | */ | ||
11 | |||
12 | #include <linux/bitfield.h> | ||
13 | #include <linux/bitops.h> | ||
14 | #include <linux/clk.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/of_platform.h> | ||
19 | #include <linux/phy/phy.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/regulator/consumer.h> | ||
22 | #include <linux/reset.h> | ||
23 | |||
24 | #define SSPHY_TESTI 0x0 | ||
25 | #define SSPHY_TESTO 0x4 | ||
26 | #define TESTI_DAT_MASK GENMASK(13, 6) | ||
27 | #define TESTI_ADR_MASK GENMASK(5, 1) | ||
28 | #define TESTI_WR_EN BIT(0) | ||
29 | |||
30 | #define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) } | ||
31 | |||
32 | #define CDR_CPD_TRIM PHY_F(7, 3, 0) /* RxPLL charge pump current */ | ||
33 | #define CDR_CPF_TRIM PHY_F(8, 3, 0) /* RxPLL charge pump current 2 */ | ||
34 | #define TX_PLL_TRIM PHY_F(9, 3, 0) /* TxPLL charge pump current */ | ||
35 | #define BGAP_TRIM PHY_F(11, 3, 0) /* Bandgap voltage */ | ||
36 | #define CDR_TRIM PHY_F(13, 6, 5) /* Clock Data Recovery setting */ | ||
37 | #define VCO_CTRL PHY_F(26, 7, 4) /* VCO control */ | ||
38 | #define VCOPLL_CTRL PHY_F(27, 2, 0) /* TxPLL VCO tuning */ | ||
39 | #define VCOPLL_CM PHY_F(28, 1, 0) /* TxPLL voltage */ | ||
40 | |||
41 | #define MAX_PHY_PARAMS 7 | ||
42 | |||
43 | struct uniphier_u3ssphy_param { | ||
44 | struct { | ||
45 | int reg_no; | ||
46 | int msb; | ||
47 | int lsb; | ||
48 | } field; | ||
49 | u8 value; | ||
50 | }; | ||
51 | |||
52 | struct uniphier_u3ssphy_priv { | ||
53 | struct device *dev; | ||
54 | void __iomem *base; | ||
55 | struct clk *clk, *clk_ext, *clk_parent, *clk_parent_gio; | ||
56 | struct reset_control *rst, *rst_parent, *rst_parent_gio; | ||
57 | struct regulator *vbus; | ||
58 | const struct uniphier_u3ssphy_soc_data *data; | ||
59 | }; | ||
60 | |||
61 | struct uniphier_u3ssphy_soc_data { | ||
62 | bool is_legacy; | ||
63 | int nparams; | ||
64 | const struct uniphier_u3ssphy_param param[MAX_PHY_PARAMS]; | ||
65 | }; | ||
66 | |||
67 | static void uniphier_u3ssphy_testio_write(struct uniphier_u3ssphy_priv *priv, | ||
68 | u32 data) | ||
69 | { | ||
70 | /* need to read TESTO twice after accessing TESTI */ | ||
71 | writel(data, priv->base + SSPHY_TESTI); | ||
72 | readl(priv->base + SSPHY_TESTO); | ||
73 | readl(priv->base + SSPHY_TESTO); | ||
74 | } | ||
75 | |||
76 | static void uniphier_u3ssphy_set_param(struct uniphier_u3ssphy_priv *priv, | ||
77 | const struct uniphier_u3ssphy_param *p) | ||
78 | { | ||
79 | u32 val; | ||
80 | u8 field_mask = GENMASK(p->field.msb, p->field.lsb); | ||
81 | u8 data; | ||
82 | |||
83 | /* read previous data */ | ||
84 | val = FIELD_PREP(TESTI_DAT_MASK, 1); | ||
85 | val |= FIELD_PREP(TESTI_ADR_MASK, p->field.reg_no); | ||
86 | uniphier_u3ssphy_testio_write(priv, val); | ||
87 | val = readl(priv->base + SSPHY_TESTO); | ||
88 | |||
89 | /* update value */ | ||
90 | val &= ~FIELD_PREP(TESTI_DAT_MASK, field_mask); | ||
91 | data = field_mask & (p->value << p->field.lsb); | ||
92 | val = FIELD_PREP(TESTI_DAT_MASK, data); | ||
93 | val |= FIELD_PREP(TESTI_ADR_MASK, p->field.reg_no); | ||
94 | uniphier_u3ssphy_testio_write(priv, val); | ||
95 | uniphier_u3ssphy_testio_write(priv, val | TESTI_WR_EN); | ||
96 | uniphier_u3ssphy_testio_write(priv, val); | ||
97 | |||
98 | /* read current data as dummy */ | ||
99 | val = FIELD_PREP(TESTI_DAT_MASK, 1); | ||
100 | val |= FIELD_PREP(TESTI_ADR_MASK, p->field.reg_no); | ||
101 | uniphier_u3ssphy_testio_write(priv, val); | ||
102 | readl(priv->base + SSPHY_TESTO); | ||
103 | } | ||
104 | |||
105 | static int uniphier_u3ssphy_power_on(struct phy *phy) | ||
106 | { | ||
107 | struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy); | ||
108 | int ret; | ||
109 | |||
110 | ret = clk_prepare_enable(priv->clk_ext); | ||
111 | if (ret) | ||
112 | return ret; | ||
113 | |||
114 | ret = clk_prepare_enable(priv->clk); | ||
115 | if (ret) | ||
116 | goto out_clk_ext_disable; | ||
117 | |||
118 | ret = reset_control_deassert(priv->rst); | ||
119 | if (ret) | ||
120 | goto out_clk_disable; | ||
121 | |||
122 | if (priv->vbus) { | ||
123 | ret = regulator_enable(priv->vbus); | ||
124 | if (ret) | ||
125 | goto out_rst_assert; | ||
126 | } | ||
127 | |||
128 | return 0; | ||
129 | |||
130 | out_rst_assert: | ||
131 | reset_control_assert(priv->rst); | ||
132 | out_clk_disable: | ||
133 | clk_disable_unprepare(priv->clk); | ||
134 | out_clk_ext_disable: | ||
135 | clk_disable_unprepare(priv->clk_ext); | ||
136 | |||
137 | return ret; | ||
138 | } | ||
139 | |||
140 | static int uniphier_u3ssphy_power_off(struct phy *phy) | ||
141 | { | ||
142 | struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy); | ||
143 | |||
144 | if (priv->vbus) | ||
145 | regulator_disable(priv->vbus); | ||
146 | |||
147 | reset_control_assert(priv->rst); | ||
148 | clk_disable_unprepare(priv->clk); | ||
149 | clk_disable_unprepare(priv->clk_ext); | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int uniphier_u3ssphy_init(struct phy *phy) | ||
155 | { | ||
156 | struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy); | ||
157 | int i, ret; | ||
158 | |||
159 | ret = clk_prepare_enable(priv->clk_parent); | ||
160 | if (ret) | ||
161 | return ret; | ||
162 | |||
163 | ret = clk_prepare_enable(priv->clk_parent_gio); | ||
164 | if (ret) | ||
165 | goto out_clk_disable; | ||
166 | |||
167 | ret = reset_control_deassert(priv->rst_parent); | ||
168 | if (ret) | ||
169 | goto out_clk_gio_disable; | ||
170 | |||
171 | ret = reset_control_deassert(priv->rst_parent_gio); | ||
172 | if (ret) | ||
173 | goto out_rst_assert; | ||
174 | |||
175 | if (priv->data->is_legacy) | ||
176 | return 0; | ||
177 | |||
178 | for (i = 0; i < priv->data->nparams; i++) | ||
179 | uniphier_u3ssphy_set_param(priv, &priv->data->param[i]); | ||
180 | |||
181 | return 0; | ||
182 | |||
183 | out_rst_assert: | ||
184 | reset_control_assert(priv->rst_parent); | ||
185 | out_clk_gio_disable: | ||
186 | clk_disable_unprepare(priv->clk_parent_gio); | ||
187 | out_clk_disable: | ||
188 | clk_disable_unprepare(priv->clk_parent); | ||
189 | |||
190 | return ret; | ||
191 | } | ||
192 | |||
193 | static int uniphier_u3ssphy_exit(struct phy *phy) | ||
194 | { | ||
195 | struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy); | ||
196 | |||
197 | reset_control_assert(priv->rst_parent_gio); | ||
198 | reset_control_assert(priv->rst_parent); | ||
199 | clk_disable_unprepare(priv->clk_parent_gio); | ||
200 | clk_disable_unprepare(priv->clk_parent); | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static const struct phy_ops uniphier_u3ssphy_ops = { | ||
206 | .init = uniphier_u3ssphy_init, | ||
207 | .exit = uniphier_u3ssphy_exit, | ||
208 | .power_on = uniphier_u3ssphy_power_on, | ||
209 | .power_off = uniphier_u3ssphy_power_off, | ||
210 | .owner = THIS_MODULE, | ||
211 | }; | ||
212 | |||
213 | static int uniphier_u3ssphy_probe(struct platform_device *pdev) | ||
214 | { | ||
215 | struct device *dev = &pdev->dev; | ||
216 | struct uniphier_u3ssphy_priv *priv; | ||
217 | struct phy_provider *phy_provider; | ||
218 | struct resource *res; | ||
219 | struct phy *phy; | ||
220 | |||
221 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
222 | if (!priv) | ||
223 | return -ENOMEM; | ||
224 | |||
225 | priv->dev = dev; | ||
226 | priv->data = of_device_get_match_data(dev); | ||
227 | if (WARN_ON(!priv->data || | ||
228 | priv->data->nparams > MAX_PHY_PARAMS)) | ||
229 | return -EINVAL; | ||
230 | |||
231 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
232 | priv->base = devm_ioremap_resource(dev, res); | ||
233 | if (IS_ERR(priv->base)) | ||
234 | return PTR_ERR(priv->base); | ||
235 | |||
236 | if (!priv->data->is_legacy) { | ||
237 | priv->clk = devm_clk_get(dev, "phy"); | ||
238 | if (IS_ERR(priv->clk)) | ||
239 | return PTR_ERR(priv->clk); | ||
240 | |||
241 | priv->clk_ext = devm_clk_get(dev, "phy-ext"); | ||
242 | if (IS_ERR(priv->clk_ext)) { | ||
243 | if (PTR_ERR(priv->clk_ext) == -ENOENT) | ||
244 | priv->clk_ext = NULL; | ||
245 | else | ||
246 | return PTR_ERR(priv->clk_ext); | ||
247 | } | ||
248 | |||
249 | priv->rst = devm_reset_control_get_shared(dev, "phy"); | ||
250 | if (IS_ERR(priv->rst)) | ||
251 | return PTR_ERR(priv->rst); | ||
252 | } else { | ||
253 | priv->clk_parent_gio = devm_clk_get(dev, "gio"); | ||
254 | if (IS_ERR(priv->clk_parent_gio)) | ||
255 | return PTR_ERR(priv->clk_parent_gio); | ||
256 | |||
257 | priv->rst_parent_gio = | ||
258 | devm_reset_control_get_shared(dev, "gio"); | ||
259 | if (IS_ERR(priv->rst_parent_gio)) | ||
260 | return PTR_ERR(priv->rst_parent_gio); | ||
261 | } | ||
262 | |||
263 | priv->clk_parent = devm_clk_get(dev, "link"); | ||
264 | if (IS_ERR(priv->clk_parent)) | ||
265 | return PTR_ERR(priv->clk_parent); | ||
266 | |||
267 | priv->rst_parent = devm_reset_control_get_shared(dev, "link"); | ||
268 | if (IS_ERR(priv->rst_parent)) | ||
269 | return PTR_ERR(priv->rst_parent); | ||
270 | |||
271 | priv->vbus = devm_regulator_get_optional(dev, "vbus"); | ||
272 | if (IS_ERR(priv->vbus)) { | ||
273 | if (PTR_ERR(priv->vbus) == -EPROBE_DEFER) | ||
274 | return PTR_ERR(priv->vbus); | ||
275 | priv->vbus = NULL; | ||
276 | } | ||
277 | |||
278 | phy = devm_phy_create(dev, dev->of_node, &uniphier_u3ssphy_ops); | ||
279 | if (IS_ERR(phy)) | ||
280 | return PTR_ERR(phy); | ||
281 | |||
282 | phy_set_drvdata(phy, priv); | ||
283 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | ||
284 | |||
285 | return PTR_ERR_OR_ZERO(phy_provider); | ||
286 | } | ||
287 | |||
288 | static const struct uniphier_u3ssphy_soc_data uniphier_pro4_data = { | ||
289 | .is_legacy = true, | ||
290 | }; | ||
291 | |||
292 | static const struct uniphier_u3ssphy_soc_data uniphier_pxs2_data = { | ||
293 | .is_legacy = false, | ||
294 | .nparams = 7, | ||
295 | .param = { | ||
296 | { CDR_CPD_TRIM, 10 }, | ||
297 | { CDR_CPF_TRIM, 3 }, | ||
298 | { TX_PLL_TRIM, 5 }, | ||
299 | { BGAP_TRIM, 9 }, | ||
300 | { CDR_TRIM, 2 }, | ||
301 | { VCOPLL_CTRL, 7 }, | ||
302 | { VCOPLL_CM, 1 }, | ||
303 | }, | ||
304 | }; | ||
305 | |||
306 | static const struct uniphier_u3ssphy_soc_data uniphier_ld20_data = { | ||
307 | .is_legacy = false, | ||
308 | .nparams = 3, | ||
309 | .param = { | ||
310 | { CDR_CPD_TRIM, 6 }, | ||
311 | { CDR_TRIM, 2 }, | ||
312 | { VCO_CTRL, 5 }, | ||
313 | }, | ||
314 | }; | ||
315 | |||
316 | static const struct of_device_id uniphier_u3ssphy_match[] = { | ||
317 | { | ||
318 | .compatible = "socionext,uniphier-pro4-usb3-ssphy", | ||
319 | .data = &uniphier_pro4_data, | ||
320 | }, | ||
321 | { | ||
322 | .compatible = "socionext,uniphier-pxs2-usb3-ssphy", | ||
323 | .data = &uniphier_pxs2_data, | ||
324 | }, | ||
325 | { | ||
326 | .compatible = "socionext,uniphier-ld20-usb3-ssphy", | ||
327 | .data = &uniphier_ld20_data, | ||
328 | }, | ||
329 | { | ||
330 | .compatible = "socionext,uniphier-pxs3-usb3-ssphy", | ||
331 | .data = &uniphier_ld20_data, | ||
332 | }, | ||
333 | { /* sentinel */ } | ||
334 | }; | ||
335 | MODULE_DEVICE_TABLE(of, uniphier_u3ssphy_match); | ||
336 | |||
337 | static struct platform_driver uniphier_u3ssphy_driver = { | ||
338 | .probe = uniphier_u3ssphy_probe, | ||
339 | .driver = { | ||
340 | .name = "uniphier-usb3-ssphy", | ||
341 | .of_match_table = uniphier_u3ssphy_match, | ||
342 | }, | ||
343 | }; | ||
344 | |||
345 | module_platform_driver(uniphier_u3ssphy_driver); | ||
346 | |||
347 | MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>"); | ||
348 | MODULE_DESCRIPTION("UniPhier SS-PHY driver for USB3 controller"); | ||
349 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c index de1b4ebe4de2..5b3b8863363e 100644 --- a/drivers/phy/tegra/xusb.c +++ b/drivers/phy/tegra/xusb.c | |||
@@ -115,8 +115,8 @@ int tegra_xusb_lane_parse_dt(struct tegra_xusb_lane *lane, | |||
115 | 115 | ||
116 | err = match_string(lane->soc->funcs, lane->soc->num_funcs, function); | 116 | err = match_string(lane->soc->funcs, lane->soc->num_funcs, function); |
117 | if (err < 0) { | 117 | if (err < 0) { |
118 | dev_err(dev, "invalid function \"%s\" for lane \"%s\"\n", | 118 | dev_err(dev, "invalid function \"%s\" for lane \"%pOFn\"\n", |
119 | function, np->name); | 119 | function, np); |
120 | return err; | 120 | return err; |
121 | } | 121 | } |
122 | 122 | ||
diff --git a/drivers/phy/ti/phy-twl4030-usb.c b/drivers/phy/ti/phy-twl4030-usb.c index a44680d64f9b..c267afb68f07 100644 --- a/drivers/phy/ti/phy-twl4030-usb.c +++ b/drivers/phy/ti/phy-twl4030-usb.c | |||
@@ -144,6 +144,7 @@ | |||
144 | #define PMBR1 0x0D | 144 | #define PMBR1 0x0D |
145 | #define GPIO_USB_4PIN_ULPI_2430C (3 << 0) | 145 | #define GPIO_USB_4PIN_ULPI_2430C (3 << 0) |
146 | 146 | ||
147 | static irqreturn_t twl4030_usb_irq(int irq, void *_twl); | ||
147 | /* | 148 | /* |
148 | * If VBUS is valid or ID is ground, then we know a | 149 | * If VBUS is valid or ID is ground, then we know a |
149 | * cable is present and we need to be runtime-enabled | 150 | * cable is present and we need to be runtime-enabled |
@@ -395,6 +396,33 @@ static void __twl4030_phy_power(struct twl4030_usb *twl, int on) | |||
395 | WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0); | 396 | WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0); |
396 | } | 397 | } |
397 | 398 | ||
399 | static int __maybe_unused twl4030_usb_suspend(struct device *dev) | ||
400 | { | ||
401 | struct twl4030_usb *twl = dev_get_drvdata(dev); | ||
402 | |||
403 | /* | ||
404 | * we need enabled runtime on resume, | ||
405 | * so turn irq off here, so we do not get it early | ||
406 | * note: wakeup on usb plug works independently of this | ||
407 | */ | ||
408 | dev_dbg(twl->dev, "%s\n", __func__); | ||
409 | disable_irq(twl->irq); | ||
410 | |||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | static int __maybe_unused twl4030_usb_resume(struct device *dev) | ||
415 | { | ||
416 | struct twl4030_usb *twl = dev_get_drvdata(dev); | ||
417 | |||
418 | dev_dbg(twl->dev, "%s\n", __func__); | ||
419 | enable_irq(twl->irq); | ||
420 | /* check whether cable status changed */ | ||
421 | twl4030_usb_irq(0, twl); | ||
422 | |||
423 | return 0; | ||
424 | } | ||
425 | |||
398 | static int __maybe_unused twl4030_usb_runtime_suspend(struct device *dev) | 426 | static int __maybe_unused twl4030_usb_runtime_suspend(struct device *dev) |
399 | { | 427 | { |
400 | struct twl4030_usb *twl = dev_get_drvdata(dev); | 428 | struct twl4030_usb *twl = dev_get_drvdata(dev); |
@@ -655,6 +683,7 @@ static const struct phy_ops ops = { | |||
655 | static const struct dev_pm_ops twl4030_usb_pm_ops = { | 683 | static const struct dev_pm_ops twl4030_usb_pm_ops = { |
656 | SET_RUNTIME_PM_OPS(twl4030_usb_runtime_suspend, | 684 | SET_RUNTIME_PM_OPS(twl4030_usb_runtime_suspend, |
657 | twl4030_usb_runtime_resume, NULL) | 685 | twl4030_usb_runtime_resume, NULL) |
686 | SET_SYSTEM_SLEEP_PM_OPS(twl4030_usb_suspend, twl4030_usb_resume) | ||
658 | }; | 687 | }; |
659 | 688 | ||
660 | static int twl4030_usb_probe(struct platform_device *pdev) | 689 | static int twl4030_usb_probe(struct platform_device *pdev) |
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 0c1aa6c314f5..bdac939de223 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig | |||
@@ -867,6 +867,8 @@ config INTEL_CHT_INT33FE | |||
867 | tristate "Intel Cherry Trail ACPI INT33FE Driver" | 867 | tristate "Intel Cherry Trail ACPI INT33FE Driver" |
868 | depends on X86 && ACPI && I2C && REGULATOR | 868 | depends on X86 && ACPI && I2C && REGULATOR |
869 | depends on CHARGER_BQ24190=y || (CHARGER_BQ24190=m && m) | 869 | depends on CHARGER_BQ24190=y || (CHARGER_BQ24190=m && m) |
870 | depends on USB_ROLES_INTEL_XHCI=y || (USB_ROLES_INTEL_XHCI=m && m) | ||
871 | depends on TYPEC_MUX_PI3USB30532=y || (TYPEC_MUX_PI3USB30532=m && m) | ||
870 | ---help--- | 872 | ---help--- |
871 | This driver add support for the INT33FE ACPI device found on | 873 | This driver add support for the INT33FE ACPI device found on |
872 | some Intel Cherry Trail devices. | 874 | some Intel Cherry Trail devices. |
diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c index 7166f1cf8a1d..f40b1c192106 100644 --- a/drivers/platform/x86/intel_cht_int33fe.c +++ b/drivers/platform/x86/intel_cht_int33fe.c | |||
@@ -35,7 +35,7 @@ struct cht_int33fe_data { | |||
35 | struct i2c_client *fusb302; | 35 | struct i2c_client *fusb302; |
36 | struct i2c_client *pi3usb30532; | 36 | struct i2c_client *pi3usb30532; |
37 | /* Contain a list-head must be per device */ | 37 | /* Contain a list-head must be per device */ |
38 | struct device_connection connections[3]; | 38 | struct device_connection connections[5]; |
39 | }; | 39 | }; |
40 | 40 | ||
41 | /* | 41 | /* |
@@ -175,19 +175,20 @@ static int cht_int33fe_probe(struct platform_device *pdev) | |||
175 | return -EPROBE_DEFER; /* Wait for i2c-adapter to load */ | 175 | return -EPROBE_DEFER; /* Wait for i2c-adapter to load */ |
176 | } | 176 | } |
177 | 177 | ||
178 | data->connections[0].endpoint[0] = "i2c-fusb302"; | 178 | data->connections[0].endpoint[0] = "port0"; |
179 | data->connections[0].endpoint[1] = "i2c-pi3usb30532"; | 179 | data->connections[0].endpoint[1] = "i2c-pi3usb30532"; |
180 | data->connections[0].id = "typec-switch"; | 180 | data->connections[0].id = "typec-switch"; |
181 | data->connections[1].endpoint[0] = "i2c-fusb302"; | 181 | data->connections[1].endpoint[0] = "port0"; |
182 | data->connections[1].endpoint[1] = "i2c-pi3usb30532"; | 182 | data->connections[1].endpoint[1] = "i2c-pi3usb30532"; |
183 | data->connections[1].id = "typec-mux"; | 183 | data->connections[1].id = "typec-mux"; |
184 | data->connections[2].endpoint[0] = "i2c-fusb302"; | 184 | data->connections[2].endpoint[0] = "port0"; |
185 | data->connections[2].endpoint[1] = "intel_xhci_usb_sw-role-switch"; | 185 | data->connections[2].endpoint[1] = "i2c-pi3usb30532"; |
186 | data->connections[2].id = "usb-role-switch"; | 186 | data->connections[2].id = "idff01m01"; |
187 | data->connections[3].endpoint[0] = "i2c-fusb302"; | ||
188 | data->connections[3].endpoint[1] = "intel_xhci_usb_sw-role-switch"; | ||
189 | data->connections[3].id = "usb-role-switch"; | ||
187 | 190 | ||
188 | device_connection_add(&data->connections[0]); | 191 | device_connections_add(data->connections); |
189 | device_connection_add(&data->connections[1]); | ||
190 | device_connection_add(&data->connections[2]); | ||
191 | 192 | ||
192 | memset(&board_info, 0, sizeof(board_info)); | 193 | memset(&board_info, 0, sizeof(board_info)); |
193 | strlcpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE); | 194 | strlcpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE); |
@@ -218,9 +219,7 @@ out_unregister_max17047: | |||
218 | if (data->max17047) | 219 | if (data->max17047) |
219 | i2c_unregister_device(data->max17047); | 220 | i2c_unregister_device(data->max17047); |
220 | 221 | ||
221 | device_connection_remove(&data->connections[2]); | 222 | device_connections_remove(data->connections); |
222 | device_connection_remove(&data->connections[1]); | ||
223 | device_connection_remove(&data->connections[0]); | ||
224 | 223 | ||
225 | return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */ | 224 | return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */ |
226 | } | 225 | } |
@@ -234,9 +233,7 @@ static int cht_int33fe_remove(struct platform_device *pdev) | |||
234 | if (data->max17047) | 233 | if (data->max17047) |
235 | i2c_unregister_device(data->max17047); | 234 | i2c_unregister_device(data->max17047); |
236 | 235 | ||
237 | device_connection_remove(&data->connections[2]); | 236 | device_connections_remove(data->connections); |
238 | device_connection_remove(&data->connections[1]); | ||
239 | device_connection_remove(&data->connections[0]); | ||
240 | 237 | ||
241 | return 0; | 238 | return 0; |
242 | } | 239 | } |
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 4a6b2b350ace..3aeadb14aae1 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c | |||
@@ -16,7 +16,6 @@ | |||
16 | #include <linux/of.h> | 16 | #include <linux/of.h> |
17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/phy/phy.h> | 18 | #include <linux/phy/phy.h> |
19 | #include <linux/phy/phy-qcom-ufs.h> | ||
20 | 19 | ||
21 | #include "ufshcd.h" | 20 | #include "ufshcd.h" |
22 | #include "ufshcd-pltfrm.h" | 21 | #include "ufshcd-pltfrm.h" |
@@ -191,22 +190,9 @@ out: | |||
191 | 190 | ||
192 | static int ufs_qcom_link_startup_post_change(struct ufs_hba *hba) | 191 | static int ufs_qcom_link_startup_post_change(struct ufs_hba *hba) |
193 | { | 192 | { |
194 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); | ||
195 | struct phy *phy = host->generic_phy; | ||
196 | u32 tx_lanes; | 193 | u32 tx_lanes; |
197 | int err = 0; | ||
198 | |||
199 | err = ufs_qcom_get_connected_tx_lanes(hba, &tx_lanes); | ||
200 | if (err) | ||
201 | goto out; | ||
202 | 194 | ||
203 | err = ufs_qcom_phy_set_tx_lane_enable(phy, tx_lanes); | 195 | return ufs_qcom_get_connected_tx_lanes(hba, &tx_lanes); |
204 | if (err) | ||
205 | dev_err(hba->dev, "%s: ufs_qcom_phy_set_tx_lane_enable failed\n", | ||
206 | __func__); | ||
207 | |||
208 | out: | ||
209 | return err; | ||
210 | } | 196 | } |
211 | 197 | ||
212 | static int ufs_qcom_check_hibern8(struct ufs_hba *hba) | 198 | static int ufs_qcom_check_hibern8(struct ufs_hba *hba) |
@@ -934,10 +920,8 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, | |||
934 | { | 920 | { |
935 | u32 val; | 921 | u32 val; |
936 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); | 922 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); |
937 | struct phy *phy = host->generic_phy; | ||
938 | struct ufs_qcom_dev_params ufs_qcom_cap; | 923 | struct ufs_qcom_dev_params ufs_qcom_cap; |
939 | int ret = 0; | 924 | int ret = 0; |
940 | int res = 0; | ||
941 | 925 | ||
942 | if (!dev_req_params) { | 926 | if (!dev_req_params) { |
943 | pr_err("%s: incoming dev_req_params is NULL\n", __func__); | 927 | pr_err("%s: incoming dev_req_params is NULL\n", __func__); |
@@ -1004,12 +988,6 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, | |||
1004 | } | 988 | } |
1005 | 989 | ||
1006 | val = ~(MAX_U32 << dev_req_params->lane_tx); | 990 | val = ~(MAX_U32 << dev_req_params->lane_tx); |
1007 | res = ufs_qcom_phy_set_tx_lane_enable(phy, val); | ||
1008 | if (res) { | ||
1009 | dev_err(hba->dev, "%s: ufs_qcom_phy_set_tx_lane_enable() failed res = %d\n", | ||
1010 | __func__, res); | ||
1011 | ret = res; | ||
1012 | } | ||
1013 | 991 | ||
1014 | /* cache the power mode parameters to use internally */ | 992 | /* cache the power mode parameters to use internally */ |
1015 | memcpy(&host->dev_req_params, | 993 | memcpy(&host->dev_req_params, |
@@ -1266,10 +1244,6 @@ static int ufs_qcom_init(struct ufs_hba *hba) | |||
1266 | } | 1244 | } |
1267 | } | 1245 | } |
1268 | 1246 | ||
1269 | /* update phy revision information before calling phy_init() */ | ||
1270 | ufs_qcom_phy_save_controller_version(host->generic_phy, | ||
1271 | host->hw_ver.major, host->hw_ver.minor, host->hw_ver.step); | ||
1272 | |||
1273 | err = ufs_qcom_init_lane_clks(host); | 1247 | err = ufs_qcom_init_lane_clks(host); |
1274 | if (err) | 1248 | if (err) |
1275 | goto out_variant_clear; | 1249 | goto out_variant_clear; |
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index 295f4bef6a0e..c114826316eb 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h | |||
@@ -129,11 +129,6 @@ enum { | |||
129 | MASK_CLK_NS_REG = 0xFFFC00, | 129 | MASK_CLK_NS_REG = 0xFFFC00, |
130 | }; | 130 | }; |
131 | 131 | ||
132 | enum ufs_qcom_phy_init_type { | ||
133 | UFS_PHY_INIT_FULL, | ||
134 | UFS_PHY_INIT_CFG_RESTORE, | ||
135 | }; | ||
136 | |||
137 | /* QCOM UFS debug print bit mask */ | 132 | /* QCOM UFS debug print bit mask */ |
138 | #define UFS_QCOM_DBG_PRINT_REGS_EN BIT(0) | 133 | #define UFS_QCOM_DBG_PRINT_REGS_EN BIT(0) |
139 | #define UFS_QCOM_DBG_PRINT_ICE_REGS_EN BIT(1) | 134 | #define UFS_QCOM_DBG_PRINT_ICE_REGS_EN BIT(1) |
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 19f5f5f2a48a..09b37c0d075d 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c | |||
@@ -364,8 +364,7 @@ static void ci_hdrc_imx_shutdown(struct platform_device *pdev) | |||
364 | ci_hdrc_imx_remove(pdev); | 364 | ci_hdrc_imx_remove(pdev); |
365 | } | 365 | } |
366 | 366 | ||
367 | #ifdef CONFIG_PM | 367 | static int __maybe_unused imx_controller_suspend(struct device *dev) |
368 | static int imx_controller_suspend(struct device *dev) | ||
369 | { | 368 | { |
370 | struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); | 369 | struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); |
371 | 370 | ||
@@ -377,7 +376,7 @@ static int imx_controller_suspend(struct device *dev) | |||
377 | return 0; | 376 | return 0; |
378 | } | 377 | } |
379 | 378 | ||
380 | static int imx_controller_resume(struct device *dev) | 379 | static int __maybe_unused imx_controller_resume(struct device *dev) |
381 | { | 380 | { |
382 | struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); | 381 | struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); |
383 | int ret = 0; | 382 | int ret = 0; |
@@ -408,8 +407,7 @@ clk_disable: | |||
408 | return ret; | 407 | return ret; |
409 | } | 408 | } |
410 | 409 | ||
411 | #ifdef CONFIG_PM_SLEEP | 410 | static int __maybe_unused ci_hdrc_imx_suspend(struct device *dev) |
412 | static int ci_hdrc_imx_suspend(struct device *dev) | ||
413 | { | 411 | { |
414 | int ret; | 412 | int ret; |
415 | 413 | ||
@@ -431,7 +429,7 @@ static int ci_hdrc_imx_suspend(struct device *dev) | |||
431 | return imx_controller_suspend(dev); | 429 | return imx_controller_suspend(dev); |
432 | } | 430 | } |
433 | 431 | ||
434 | static int ci_hdrc_imx_resume(struct device *dev) | 432 | static int __maybe_unused ci_hdrc_imx_resume(struct device *dev) |
435 | { | 433 | { |
436 | struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); | 434 | struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); |
437 | int ret; | 435 | int ret; |
@@ -445,9 +443,8 @@ static int ci_hdrc_imx_resume(struct device *dev) | |||
445 | 443 | ||
446 | return ret; | 444 | return ret; |
447 | } | 445 | } |
448 | #endif /* CONFIG_PM_SLEEP */ | ||
449 | 446 | ||
450 | static int ci_hdrc_imx_runtime_suspend(struct device *dev) | 447 | static int __maybe_unused ci_hdrc_imx_runtime_suspend(struct device *dev) |
451 | { | 448 | { |
452 | struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); | 449 | struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); |
453 | int ret; | 450 | int ret; |
@@ -466,13 +463,11 @@ static int ci_hdrc_imx_runtime_suspend(struct device *dev) | |||
466 | return imx_controller_suspend(dev); | 463 | return imx_controller_suspend(dev); |
467 | } | 464 | } |
468 | 465 | ||
469 | static int ci_hdrc_imx_runtime_resume(struct device *dev) | 466 | static int __maybe_unused ci_hdrc_imx_runtime_resume(struct device *dev) |
470 | { | 467 | { |
471 | return imx_controller_resume(dev); | 468 | return imx_controller_resume(dev); |
472 | } | 469 | } |
473 | 470 | ||
474 | #endif /* CONFIG_PM */ | ||
475 | |||
476 | static const struct dev_pm_ops ci_hdrc_imx_pm_ops = { | 471 | static const struct dev_pm_ops ci_hdrc_imx_pm_ops = { |
477 | SET_SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume) | 472 | SET_SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume) |
478 | SET_RUNTIME_PM_OPS(ci_hdrc_imx_runtime_suspend, | 473 | SET_RUNTIME_PM_OPS(ci_hdrc_imx_runtime_suspend, |
@@ -492,7 +487,7 @@ static struct platform_driver ci_hdrc_imx_driver = { | |||
492 | module_platform_driver(ci_hdrc_imx_driver); | 487 | module_platform_driver(ci_hdrc_imx_driver); |
493 | 488 | ||
494 | MODULE_ALIAS("platform:imx-usb"); | 489 | MODULE_ALIAS("platform:imx-usb"); |
495 | MODULE_LICENSE("GPL v2"); | 490 | MODULE_LICENSE("GPL"); |
496 | MODULE_DESCRIPTION("CI HDRC i.MX USB binding"); | 491 | MODULE_DESCRIPTION("CI HDRC i.MX USB binding"); |
497 | MODULE_AUTHOR("Marek Vasut <marex@denx.de>"); | 492 | MODULE_AUTHOR("Marek Vasut <marex@denx.de>"); |
498 | MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>"); | 493 | MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>"); |
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 85fc6db48e44..7bfcbb23c2a4 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #include <linux/kernel.h> | 53 | #include <linux/kernel.h> |
54 | #include <linux/slab.h> | 54 | #include <linux/slab.h> |
55 | #include <linux/pm_runtime.h> | 55 | #include <linux/pm_runtime.h> |
56 | #include <linux/pinctrl/consumer.h> | ||
56 | #include <linux/usb/ch9.h> | 57 | #include <linux/usb/ch9.h> |
57 | #include <linux/usb/gadget.h> | 58 | #include <linux/usb/gadget.h> |
58 | #include <linux/usb/otg.h> | 59 | #include <linux/usb/otg.h> |
@@ -723,6 +724,24 @@ static int ci_get_platdata(struct device *dev, | |||
723 | else | 724 | else |
724 | cable->connected = false; | 725 | cable->connected = false; |
725 | } | 726 | } |
727 | |||
728 | platdata->pctl = devm_pinctrl_get(dev); | ||
729 | if (!IS_ERR(platdata->pctl)) { | ||
730 | struct pinctrl_state *p; | ||
731 | |||
732 | p = pinctrl_lookup_state(platdata->pctl, "default"); | ||
733 | if (!IS_ERR(p)) | ||
734 | platdata->pins_default = p; | ||
735 | |||
736 | p = pinctrl_lookup_state(platdata->pctl, "host"); | ||
737 | if (!IS_ERR(p)) | ||
738 | platdata->pins_host = p; | ||
739 | |||
740 | p = pinctrl_lookup_state(platdata->pctl, "device"); | ||
741 | if (!IS_ERR(p)) | ||
742 | platdata->pins_device = p; | ||
743 | } | ||
744 | |||
726 | return 0; | 745 | return 0; |
727 | } | 746 | } |
728 | 747 | ||
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 4638d9b066be..d858a82c4f44 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/usb/hcd.h> | 13 | #include <linux/usb/hcd.h> |
14 | #include <linux/usb/chipidea.h> | 14 | #include <linux/usb/chipidea.h> |
15 | #include <linux/regulator/consumer.h> | 15 | #include <linux/regulator/consumer.h> |
16 | #include <linux/pinctrl/consumer.h> | ||
16 | 17 | ||
17 | #include "../host/ehci.h" | 18 | #include "../host/ehci.h" |
18 | 19 | ||
@@ -153,6 +154,10 @@ static int host_start(struct ci_hdrc *ci) | |||
153 | } | 154 | } |
154 | } | 155 | } |
155 | 156 | ||
157 | if (ci->platdata->pins_host) | ||
158 | pinctrl_select_state(ci->platdata->pctl, | ||
159 | ci->platdata->pins_host); | ||
160 | |||
156 | ret = usb_add_hcd(hcd, 0, 0); | 161 | ret = usb_add_hcd(hcd, 0, 0); |
157 | if (ret) { | 162 | if (ret) { |
158 | goto disable_reg; | 163 | goto disable_reg; |
@@ -197,6 +202,10 @@ static void host_stop(struct ci_hdrc *ci) | |||
197 | } | 202 | } |
198 | ci->hcd = NULL; | 203 | ci->hcd = NULL; |
199 | ci->otg.host = NULL; | 204 | ci->otg.host = NULL; |
205 | |||
206 | if (ci->platdata->pins_host && ci->platdata->pins_default) | ||
207 | pinctrl_select_state(ci->platdata->pctl, | ||
208 | ci->platdata->pins_default); | ||
200 | } | 209 | } |
201 | 210 | ||
202 | 211 | ||
diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index db4ceffcf2a6..f25d4827fd49 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c | |||
@@ -203,14 +203,17 @@ static void ci_otg_work(struct work_struct *work) | |||
203 | } | 203 | } |
204 | 204 | ||
205 | pm_runtime_get_sync(ci->dev); | 205 | pm_runtime_get_sync(ci->dev); |
206 | |||
206 | if (ci->id_event) { | 207 | if (ci->id_event) { |
207 | ci->id_event = false; | 208 | ci->id_event = false; |
208 | ci_handle_id_switch(ci); | 209 | ci_handle_id_switch(ci); |
209 | } else if (ci->b_sess_valid_event) { | 210 | } |
211 | |||
212 | if (ci->b_sess_valid_event) { | ||
210 | ci->b_sess_valid_event = false; | 213 | ci->b_sess_valid_event = false; |
211 | ci_handle_vbus_change(ci); | 214 | ci_handle_vbus_change(ci); |
212 | } else | 215 | } |
213 | dev_err(ci->dev, "unexpected event occurs at %s\n", __func__); | 216 | |
214 | pm_runtime_put_sync(ci->dev); | 217 | pm_runtime_put_sync(ci->dev); |
215 | 218 | ||
216 | enable_irq(ci->irq); | 219 | enable_irq(ci->irq); |
diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h index 7e7428e48bfa..4f8b8179ec96 100644 --- a/drivers/usb/chipidea/otg.h +++ b/drivers/usb/chipidea/otg.h | |||
@@ -17,7 +17,8 @@ void ci_handle_vbus_change(struct ci_hdrc *ci); | |||
17 | static inline void ci_otg_queue_work(struct ci_hdrc *ci) | 17 | static inline void ci_otg_queue_work(struct ci_hdrc *ci) |
18 | { | 18 | { |
19 | disable_irq_nosync(ci->irq); | 19 | disable_irq_nosync(ci->irq); |
20 | queue_work(ci->wq, &ci->work); | 20 | if (queue_work(ci->wq, &ci->work) == false) |
21 | enable_irq(ci->irq); | ||
21 | } | 22 | } |
22 | 23 | ||
23 | #endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */ | 24 | #endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */ |
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 9852ec5e6e01..829e947cabf5 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/pm_runtime.h> | 17 | #include <linux/pm_runtime.h> |
18 | #include <linux/pinctrl/consumer.h> | ||
18 | #include <linux/usb/ch9.h> | 19 | #include <linux/usb/ch9.h> |
19 | #include <linux/usb/gadget.h> | 20 | #include <linux/usb/gadget.h> |
20 | #include <linux/usb/otg-fsm.h> | 21 | #include <linux/usb/otg-fsm.h> |
@@ -1965,6 +1966,10 @@ void ci_hdrc_gadget_destroy(struct ci_hdrc *ci) | |||
1965 | 1966 | ||
1966 | static int udc_id_switch_for_device(struct ci_hdrc *ci) | 1967 | static int udc_id_switch_for_device(struct ci_hdrc *ci) |
1967 | { | 1968 | { |
1969 | if (ci->platdata->pins_device) | ||
1970 | pinctrl_select_state(ci->platdata->pctl, | ||
1971 | ci->platdata->pins_device); | ||
1972 | |||
1968 | if (ci->is_otg) | 1973 | if (ci->is_otg) |
1969 | /* Clear and enable BSV irq */ | 1974 | /* Clear and enable BSV irq */ |
1970 | hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE, | 1975 | hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE, |
@@ -1983,6 +1988,10 @@ static void udc_id_switch_for_host(struct ci_hdrc *ci) | |||
1983 | hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS); | 1988 | hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS); |
1984 | 1989 | ||
1985 | ci->vbus_active = 0; | 1990 | ci->vbus_active = 0; |
1991 | |||
1992 | if (ci->platdata->pins_device && ci->platdata->pins_default) | ||
1993 | pinctrl_select_state(ci->platdata->pctl, | ||
1994 | ci->platdata->pins_default); | ||
1986 | } | 1995 | } |
1987 | 1996 | ||
1988 | /** | 1997 | /** |
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index 34ad5bf8acd8..def80ff547e4 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c | |||
@@ -343,6 +343,8 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data) | |||
343 | } else if (data->oc_polarity == 1) { | 343 | } else if (data->oc_polarity == 1) { |
344 | /* High active */ | 344 | /* High active */ |
345 | reg &= ~(MX6_BM_OVER_CUR_DIS | MX6_BM_OVER_CUR_POLARITY); | 345 | reg &= ~(MX6_BM_OVER_CUR_DIS | MX6_BM_OVER_CUR_POLARITY); |
346 | } else { | ||
347 | reg &= ~(MX6_BM_OVER_CUR_DIS); | ||
346 | } | 348 | } |
347 | writel(reg, usbmisc->base + data->index * 4); | 349 | writel(reg, usbmisc->base + data->index * 4); |
348 | 350 | ||
@@ -633,6 +635,6 @@ static struct platform_driver usbmisc_imx_driver = { | |||
633 | module_platform_driver(usbmisc_imx_driver); | 635 | module_platform_driver(usbmisc_imx_driver); |
634 | 636 | ||
635 | MODULE_ALIAS("platform:usbmisc-imx"); | 637 | MODULE_ALIAS("platform:usbmisc-imx"); |
636 | MODULE_LICENSE("GPL v2"); | 638 | MODULE_LICENSE("GPL"); |
637 | MODULE_DESCRIPTION("driver for imx usb non-core registers"); | 639 | MODULE_DESCRIPTION("driver for imx usb non-core registers"); |
638 | MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>"); | 640 | MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>"); |
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 83ffa5a14c3d..4942122b2346 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany | 5 | * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany |
6 | * Copyright (C) 2008 Novell, Inc. | 6 | * Copyright (C) 2008 Novell, Inc. |
7 | * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de> | 7 | * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de> |
8 | * Copyright (C) 2018 IVI Foundation, Inc. | ||
8 | */ | 9 | */ |
9 | 10 | ||
10 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 11 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
@@ -21,21 +22,24 @@ | |||
21 | #include <linux/compat.h> | 22 | #include <linux/compat.h> |
22 | #include <linux/usb/tmc.h> | 23 | #include <linux/usb/tmc.h> |
23 | 24 | ||
25 | /* Increment API VERSION when changing tmc.h with new flags or ioctls | ||
26 | * or when changing a significant behavior of the driver. | ||
27 | */ | ||
28 | #define USBTMC_API_VERSION (2) | ||
24 | 29 | ||
25 | #define USBTMC_HEADER_SIZE 12 | 30 | #define USBTMC_HEADER_SIZE 12 |
26 | #define USBTMC_MINOR_BASE 176 | 31 | #define USBTMC_MINOR_BASE 176 |
27 | 32 | ||
28 | /* | ||
29 | * Size of driver internal IO buffer. Must be multiple of 4 and at least as | ||
30 | * large as wMaxPacketSize (which is usually 512 bytes). | ||
31 | */ | ||
32 | #define USBTMC_SIZE_IOBUFFER 2048 | ||
33 | |||
34 | /* Minimum USB timeout (in milliseconds) */ | 33 | /* Minimum USB timeout (in milliseconds) */ |
35 | #define USBTMC_MIN_TIMEOUT 100 | 34 | #define USBTMC_MIN_TIMEOUT 100 |
36 | /* Default USB timeout (in milliseconds) */ | 35 | /* Default USB timeout (in milliseconds) */ |
37 | #define USBTMC_TIMEOUT 5000 | 36 | #define USBTMC_TIMEOUT 5000 |
38 | 37 | ||
38 | /* Max number of urbs used in write transfers */ | ||
39 | #define MAX_URBS_IN_FLIGHT 16 | ||
40 | /* I/O buffer size used in generic read/write functions */ | ||
41 | #define USBTMC_BUFSIZE (4096) | ||
42 | |||
39 | /* | 43 | /* |
40 | * Maximum number of read cycles to empty bulk in endpoint during CLEAR and | 44 | * Maximum number of read cycles to empty bulk in endpoint during CLEAR and |
41 | * ABORT_BULK_IN requests. Ends the loop if (for whatever reason) a short | 45 | * ABORT_BULK_IN requests. Ends the loop if (for whatever reason) a short |
@@ -79,6 +83,9 @@ struct usbtmc_device_data { | |||
79 | u8 bTag_last_write; /* needed for abort */ | 83 | u8 bTag_last_write; /* needed for abort */ |
80 | u8 bTag_last_read; /* needed for abort */ | 84 | u8 bTag_last_read; /* needed for abort */ |
81 | 85 | ||
86 | /* packet size of IN bulk */ | ||
87 | u16 wMaxPacketSize; | ||
88 | |||
82 | /* data for interrupt in endpoint handling */ | 89 | /* data for interrupt in endpoint handling */ |
83 | u8 bNotify1; | 90 | u8 bNotify1; |
84 | u8 bNotify2; | 91 | u8 bNotify2; |
@@ -95,11 +102,6 @@ struct usbtmc_device_data { | |||
95 | /* coalesced usb488_caps from usbtmc_dev_capabilities */ | 102 | /* coalesced usb488_caps from usbtmc_dev_capabilities */ |
96 | __u8 usb488_caps; | 103 | __u8 usb488_caps; |
97 | 104 | ||
98 | /* attributes from the USB TMC spec for this device */ | ||
99 | u8 TermChar; | ||
100 | bool TermCharEnabled; | ||
101 | bool auto_abort; | ||
102 | |||
103 | bool zombie; /* fd of disconnected device */ | 105 | bool zombie; /* fd of disconnected device */ |
104 | 106 | ||
105 | struct usbtmc_dev_capabilities capabilities; | 107 | struct usbtmc_dev_capabilities capabilities; |
@@ -121,13 +123,34 @@ struct usbtmc_file_data { | |||
121 | u32 timeout; | 123 | u32 timeout; |
122 | u8 srq_byte; | 124 | u8 srq_byte; |
123 | atomic_t srq_asserted; | 125 | atomic_t srq_asserted; |
126 | atomic_t closing; | ||
127 | u8 bmTransferAttributes; /* member of DEV_DEP_MSG_IN */ | ||
128 | |||
124 | u8 eom_val; | 129 | u8 eom_val; |
125 | u8 term_char; | 130 | u8 term_char; |
126 | bool term_char_enabled; | 131 | bool term_char_enabled; |
132 | bool auto_abort; | ||
133 | |||
134 | spinlock_t err_lock; /* lock for errors */ | ||
135 | |||
136 | struct usb_anchor submitted; | ||
137 | |||
138 | /* data for generic_write */ | ||
139 | struct semaphore limit_write_sem; | ||
140 | u32 out_transfer_size; | ||
141 | int out_status; | ||
142 | |||
143 | /* data for generic_read */ | ||
144 | u32 in_transfer_size; | ||
145 | int in_status; | ||
146 | int in_urbs_used; | ||
147 | struct usb_anchor in_anchor; | ||
148 | wait_queue_head_t wait_bulk_in; | ||
127 | }; | 149 | }; |
128 | 150 | ||
129 | /* Forward declarations */ | 151 | /* Forward declarations */ |
130 | static struct usb_driver usbtmc_driver; | 152 | static struct usb_driver usbtmc_driver; |
153 | static void usbtmc_draw_down(struct usbtmc_file_data *file_data); | ||
131 | 154 | ||
132 | static void usbtmc_delete(struct kref *kref) | 155 | static void usbtmc_delete(struct kref *kref) |
133 | { | 156 | { |
@@ -153,6 +176,12 @@ static int usbtmc_open(struct inode *inode, struct file *filp) | |||
153 | if (!file_data) | 176 | if (!file_data) |
154 | return -ENOMEM; | 177 | return -ENOMEM; |
155 | 178 | ||
179 | spin_lock_init(&file_data->err_lock); | ||
180 | sema_init(&file_data->limit_write_sem, MAX_URBS_IN_FLIGHT); | ||
181 | init_usb_anchor(&file_data->submitted); | ||
182 | init_usb_anchor(&file_data->in_anchor); | ||
183 | init_waitqueue_head(&file_data->wait_bulk_in); | ||
184 | |||
156 | data = usb_get_intfdata(intf); | 185 | data = usb_get_intfdata(intf); |
157 | /* Protect reference to data from file structure until release */ | 186 | /* Protect reference to data from file structure until release */ |
158 | kref_get(&data->kref); | 187 | kref_get(&data->kref); |
@@ -160,10 +189,12 @@ static int usbtmc_open(struct inode *inode, struct file *filp) | |||
160 | mutex_lock(&data->io_mutex); | 189 | mutex_lock(&data->io_mutex); |
161 | file_data->data = data; | 190 | file_data->data = data; |
162 | 191 | ||
163 | /* copy default values from device settings */ | 192 | atomic_set(&file_data->closing, 0); |
193 | |||
164 | file_data->timeout = USBTMC_TIMEOUT; | 194 | file_data->timeout = USBTMC_TIMEOUT; |
165 | file_data->term_char = data->TermChar; | 195 | file_data->term_char = '\n'; |
166 | file_data->term_char_enabled = data->TermCharEnabled; | 196 | file_data->term_char_enabled = 0; |
197 | file_data->auto_abort = 0; | ||
167 | file_data->eom_val = 1; | 198 | file_data->eom_val = 1; |
168 | 199 | ||
169 | INIT_LIST_HEAD(&file_data->file_elem); | 200 | INIT_LIST_HEAD(&file_data->file_elem); |
@@ -178,6 +209,40 @@ static int usbtmc_open(struct inode *inode, struct file *filp) | |||
178 | return 0; | 209 | return 0; |
179 | } | 210 | } |
180 | 211 | ||
212 | /* | ||
213 | * usbtmc_flush - called before file handle is closed | ||
214 | */ | ||
215 | static int usbtmc_flush(struct file *file, fl_owner_t id) | ||
216 | { | ||
217 | struct usbtmc_file_data *file_data; | ||
218 | struct usbtmc_device_data *data; | ||
219 | |||
220 | file_data = file->private_data; | ||
221 | if (file_data == NULL) | ||
222 | return -ENODEV; | ||
223 | |||
224 | atomic_set(&file_data->closing, 1); | ||
225 | data = file_data->data; | ||
226 | |||
227 | /* wait for io to stop */ | ||
228 | mutex_lock(&data->io_mutex); | ||
229 | |||
230 | usbtmc_draw_down(file_data); | ||
231 | |||
232 | spin_lock_irq(&file_data->err_lock); | ||
233 | file_data->in_status = 0; | ||
234 | file_data->in_transfer_size = 0; | ||
235 | file_data->in_urbs_used = 0; | ||
236 | file_data->out_status = 0; | ||
237 | file_data->out_transfer_size = 0; | ||
238 | spin_unlock_irq(&file_data->err_lock); | ||
239 | |||
240 | wake_up_interruptible_all(&data->waitq); | ||
241 | mutex_unlock(&data->io_mutex); | ||
242 | |||
243 | return 0; | ||
244 | } | ||
245 | |||
181 | static int usbtmc_release(struct inode *inode, struct file *file) | 246 | static int usbtmc_release(struct inode *inode, struct file *file) |
182 | { | 247 | { |
183 | struct usbtmc_file_data *file_data = file->private_data; | 248 | struct usbtmc_file_data *file_data = file->private_data; |
@@ -197,18 +262,17 @@ static int usbtmc_release(struct inode *inode, struct file *file) | |||
197 | return 0; | 262 | return 0; |
198 | } | 263 | } |
199 | 264 | ||
200 | static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data) | 265 | static int usbtmc_ioctl_abort_bulk_in_tag(struct usbtmc_device_data *data, |
266 | u8 tag) | ||
201 | { | 267 | { |
202 | u8 *buffer; | 268 | u8 *buffer; |
203 | struct device *dev; | 269 | struct device *dev; |
204 | int rv; | 270 | int rv; |
205 | int n; | 271 | int n; |
206 | int actual; | 272 | int actual; |
207 | struct usb_host_interface *current_setting; | ||
208 | int max_size; | ||
209 | 273 | ||
210 | dev = &data->intf->dev; | 274 | dev = &data->intf->dev; |
211 | buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); | 275 | buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL); |
212 | if (!buffer) | 276 | if (!buffer) |
213 | return -ENOMEM; | 277 | return -ENOMEM; |
214 | 278 | ||
@@ -216,86 +280,88 @@ static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data) | |||
216 | usb_rcvctrlpipe(data->usb_dev, 0), | 280 | usb_rcvctrlpipe(data->usb_dev, 0), |
217 | USBTMC_REQUEST_INITIATE_ABORT_BULK_IN, | 281 | USBTMC_REQUEST_INITIATE_ABORT_BULK_IN, |
218 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, | 282 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, |
219 | data->bTag_last_read, data->bulk_in, | 283 | tag, data->bulk_in, |
220 | buffer, 2, USBTMC_TIMEOUT); | 284 | buffer, 2, USB_CTRL_GET_TIMEOUT); |
221 | 285 | ||
222 | if (rv < 0) { | 286 | if (rv < 0) { |
223 | dev_err(dev, "usb_control_msg returned %d\n", rv); | 287 | dev_err(dev, "usb_control_msg returned %d\n", rv); |
224 | goto exit; | 288 | goto exit; |
225 | } | 289 | } |
226 | 290 | ||
227 | dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]); | 291 | dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x with tag %02x\n", |
292 | buffer[0], buffer[1]); | ||
228 | 293 | ||
229 | if (buffer[0] == USBTMC_STATUS_FAILED) { | 294 | if (buffer[0] == USBTMC_STATUS_FAILED) { |
295 | /* No transfer in progress and the Bulk-OUT FIFO is empty. */ | ||
230 | rv = 0; | 296 | rv = 0; |
231 | goto exit; | 297 | goto exit; |
232 | } | 298 | } |
233 | 299 | ||
234 | if (buffer[0] != USBTMC_STATUS_SUCCESS) { | 300 | if (buffer[0] == USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS) { |
235 | dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", | 301 | /* The device returns this status if either: |
236 | buffer[0]); | 302 | * - There is a transfer in progress, but the specified bTag |
237 | rv = -EPERM; | 303 | * does not match. |
304 | * - There is no transfer in progress, but the Bulk-OUT FIFO | ||
305 | * is not empty. | ||
306 | */ | ||
307 | rv = -ENOMSG; | ||
238 | goto exit; | 308 | goto exit; |
239 | } | 309 | } |
240 | 310 | ||
241 | max_size = 0; | 311 | if (buffer[0] != USBTMC_STATUS_SUCCESS) { |
242 | current_setting = data->intf->cur_altsetting; | 312 | dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", |
243 | for (n = 0; n < current_setting->desc.bNumEndpoints; n++) | 313 | buffer[0]); |
244 | if (current_setting->endpoint[n].desc.bEndpointAddress == | ||
245 | data->bulk_in) | ||
246 | max_size = usb_endpoint_maxp(¤t_setting->endpoint[n].desc); | ||
247 | |||
248 | if (max_size == 0) { | ||
249 | dev_err(dev, "Couldn't get wMaxPacketSize\n"); | ||
250 | rv = -EPERM; | 314 | rv = -EPERM; |
251 | goto exit; | 315 | goto exit; |
252 | } | 316 | } |
253 | 317 | ||
254 | dev_dbg(&data->intf->dev, "wMaxPacketSize is %d\n", max_size); | ||
255 | |||
256 | n = 0; | 318 | n = 0; |
257 | 319 | ||
258 | do { | 320 | usbtmc_abort_bulk_in_status: |
259 | dev_dbg(dev, "Reading from bulk in EP\n"); | 321 | dev_dbg(dev, "Reading from bulk in EP\n"); |
260 | 322 | ||
261 | rv = usb_bulk_msg(data->usb_dev, | 323 | /* Data must be present. So use low timeout 300 ms */ |
262 | usb_rcvbulkpipe(data->usb_dev, | 324 | actual = 0; |
263 | data->bulk_in), | 325 | rv = usb_bulk_msg(data->usb_dev, |
264 | buffer, USBTMC_SIZE_IOBUFFER, | 326 | usb_rcvbulkpipe(data->usb_dev, |
265 | &actual, USBTMC_TIMEOUT); | 327 | data->bulk_in), |
328 | buffer, USBTMC_BUFSIZE, | ||
329 | &actual, 300); | ||
266 | 330 | ||
267 | n++; | 331 | print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 16, 1, |
332 | buffer, actual, true); | ||
268 | 333 | ||
269 | if (rv < 0) { | 334 | n++; |
270 | dev_err(dev, "usb_bulk_msg returned %d\n", rv); | 335 | |
336 | if (rv < 0) { | ||
337 | dev_err(dev, "usb_bulk_msg returned %d\n", rv); | ||
338 | if (rv != -ETIMEDOUT) | ||
271 | goto exit; | 339 | goto exit; |
272 | } | 340 | } |
273 | } while ((actual == max_size) && | ||
274 | (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); | ||
275 | 341 | ||
276 | if (actual == max_size) { | 342 | if (actual == USBTMC_BUFSIZE) |
343 | goto usbtmc_abort_bulk_in_status; | ||
344 | |||
345 | if (n >= USBTMC_MAX_READS_TO_CLEAR_BULK_IN) { | ||
277 | dev_err(dev, "Couldn't clear device buffer within %d cycles\n", | 346 | dev_err(dev, "Couldn't clear device buffer within %d cycles\n", |
278 | USBTMC_MAX_READS_TO_CLEAR_BULK_IN); | 347 | USBTMC_MAX_READS_TO_CLEAR_BULK_IN); |
279 | rv = -EPERM; | 348 | rv = -EPERM; |
280 | goto exit; | 349 | goto exit; |
281 | } | 350 | } |
282 | 351 | ||
283 | n = 0; | ||
284 | |||
285 | usbtmc_abort_bulk_in_status: | ||
286 | rv = usb_control_msg(data->usb_dev, | 352 | rv = usb_control_msg(data->usb_dev, |
287 | usb_rcvctrlpipe(data->usb_dev, 0), | 353 | usb_rcvctrlpipe(data->usb_dev, 0), |
288 | USBTMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS, | 354 | USBTMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS, |
289 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, | 355 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, |
290 | 0, data->bulk_in, buffer, 0x08, | 356 | 0, data->bulk_in, buffer, 0x08, |
291 | USBTMC_TIMEOUT); | 357 | USB_CTRL_GET_TIMEOUT); |
292 | 358 | ||
293 | if (rv < 0) { | 359 | if (rv < 0) { |
294 | dev_err(dev, "usb_control_msg returned %d\n", rv); | 360 | dev_err(dev, "usb_control_msg returned %d\n", rv); |
295 | goto exit; | 361 | goto exit; |
296 | } | 362 | } |
297 | 363 | ||
298 | dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]); | 364 | dev_dbg(dev, "CHECK_ABORT_BULK_IN returned %x\n", buffer[0]); |
299 | 365 | ||
300 | if (buffer[0] == USBTMC_STATUS_SUCCESS) { | 366 | if (buffer[0] == USBTMC_STATUS_SUCCESS) { |
301 | rv = 0; | 367 | rv = 0; |
@@ -303,46 +369,30 @@ usbtmc_abort_bulk_in_status: | |||
303 | } | 369 | } |
304 | 370 | ||
305 | if (buffer[0] != USBTMC_STATUS_PENDING) { | 371 | if (buffer[0] != USBTMC_STATUS_PENDING) { |
306 | dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]); | 372 | dev_err(dev, "CHECK_ABORT_BULK_IN returned %x\n", buffer[0]); |
307 | rv = -EPERM; | 373 | rv = -EPERM; |
308 | goto exit; | 374 | goto exit; |
309 | } | 375 | } |
310 | 376 | ||
311 | if (buffer[1] == 1) | 377 | if ((buffer[1] & 1) > 0) { |
312 | do { | 378 | /* The device has 1 or more queued packets the Host can read */ |
313 | dev_dbg(dev, "Reading from bulk in EP\n"); | 379 | goto usbtmc_abort_bulk_in_status; |
314 | |||
315 | rv = usb_bulk_msg(data->usb_dev, | ||
316 | usb_rcvbulkpipe(data->usb_dev, | ||
317 | data->bulk_in), | ||
318 | buffer, USBTMC_SIZE_IOBUFFER, | ||
319 | &actual, USBTMC_TIMEOUT); | ||
320 | |||
321 | n++; | ||
322 | |||
323 | if (rv < 0) { | ||
324 | dev_err(dev, "usb_bulk_msg returned %d\n", rv); | ||
325 | goto exit; | ||
326 | } | ||
327 | } while ((actual == max_size) && | ||
328 | (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); | ||
329 | |||
330 | if (actual == max_size) { | ||
331 | dev_err(dev, "Couldn't clear device buffer within %d cycles\n", | ||
332 | USBTMC_MAX_READS_TO_CLEAR_BULK_IN); | ||
333 | rv = -EPERM; | ||
334 | goto exit; | ||
335 | } | 380 | } |
336 | 381 | ||
337 | goto usbtmc_abort_bulk_in_status; | 382 | /* The Host must send CHECK_ABORT_BULK_IN_STATUS at a later time. */ |
338 | 383 | rv = -EAGAIN; | |
339 | exit: | 384 | exit: |
340 | kfree(buffer); | 385 | kfree(buffer); |
341 | return rv; | 386 | return rv; |
387 | } | ||
342 | 388 | ||
389 | static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data) | ||
390 | { | ||
391 | return usbtmc_ioctl_abort_bulk_in_tag(data, data->bTag_last_read); | ||
343 | } | 392 | } |
344 | 393 | ||
345 | static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data) | 394 | static int usbtmc_ioctl_abort_bulk_out_tag(struct usbtmc_device_data *data, |
395 | u8 tag) | ||
346 | { | 396 | { |
347 | struct device *dev; | 397 | struct device *dev; |
348 | u8 *buffer; | 398 | u8 *buffer; |
@@ -359,8 +409,8 @@ static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data) | |||
359 | usb_rcvctrlpipe(data->usb_dev, 0), | 409 | usb_rcvctrlpipe(data->usb_dev, 0), |
360 | USBTMC_REQUEST_INITIATE_ABORT_BULK_OUT, | 410 | USBTMC_REQUEST_INITIATE_ABORT_BULK_OUT, |
361 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, | 411 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, |
362 | data->bTag_last_write, data->bulk_out, | 412 | tag, data->bulk_out, |
363 | buffer, 2, USBTMC_TIMEOUT); | 413 | buffer, 2, USB_CTRL_GET_TIMEOUT); |
364 | 414 | ||
365 | if (rv < 0) { | 415 | if (rv < 0) { |
366 | dev_err(dev, "usb_control_msg returned %d\n", rv); | 416 | dev_err(dev, "usb_control_msg returned %d\n", rv); |
@@ -379,12 +429,14 @@ static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data) | |||
379 | n = 0; | 429 | n = 0; |
380 | 430 | ||
381 | usbtmc_abort_bulk_out_check_status: | 431 | usbtmc_abort_bulk_out_check_status: |
432 | /* do not stress device with subsequent requests */ | ||
433 | msleep(50); | ||
382 | rv = usb_control_msg(data->usb_dev, | 434 | rv = usb_control_msg(data->usb_dev, |
383 | usb_rcvctrlpipe(data->usb_dev, 0), | 435 | usb_rcvctrlpipe(data->usb_dev, 0), |
384 | USBTMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS, | 436 | USBTMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS, |
385 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, | 437 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, |
386 | 0, data->bulk_out, buffer, 0x08, | 438 | 0, data->bulk_out, buffer, 0x08, |
387 | USBTMC_TIMEOUT); | 439 | USB_CTRL_GET_TIMEOUT); |
388 | n++; | 440 | n++; |
389 | if (rv < 0) { | 441 | if (rv < 0) { |
390 | dev_err(dev, "usb_control_msg returned %d\n", rv); | 442 | dev_err(dev, "usb_control_msg returned %d\n", rv); |
@@ -418,6 +470,11 @@ exit: | |||
418 | return rv; | 470 | return rv; |
419 | } | 471 | } |
420 | 472 | ||
473 | static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data) | ||
474 | { | ||
475 | return usbtmc_ioctl_abort_bulk_out_tag(data, data->bTag_last_write); | ||
476 | } | ||
477 | |||
421 | static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data, | 478 | static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data, |
422 | void __user *arg) | 479 | void __user *arg) |
423 | { | 480 | { |
@@ -457,7 +514,7 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data, | |||
457 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | 514 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, |
458 | data->iin_bTag, | 515 | data->iin_bTag, |
459 | data->ifnum, | 516 | data->ifnum, |
460 | buffer, 0x03, USBTMC_TIMEOUT); | 517 | buffer, 0x03, USB_CTRL_GET_TIMEOUT); |
461 | if (rv < 0) { | 518 | if (rv < 0) { |
462 | dev_err(dev, "stb usb_control_msg returned %d\n", rv); | 519 | dev_err(dev, "stb usb_control_msg returned %d\n", rv); |
463 | goto exit; | 520 | goto exit; |
@@ -510,6 +567,54 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data, | |||
510 | return rv; | 567 | return rv; |
511 | } | 568 | } |
512 | 569 | ||
570 | static int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data, | ||
571 | __u32 __user *arg) | ||
572 | { | ||
573 | struct usbtmc_device_data *data = file_data->data; | ||
574 | struct device *dev = &data->intf->dev; | ||
575 | int rv; | ||
576 | u32 timeout; | ||
577 | unsigned long expire; | ||
578 | |||
579 | if (!data->iin_ep_present) { | ||
580 | dev_dbg(dev, "no interrupt endpoint present\n"); | ||
581 | return -EFAULT; | ||
582 | } | ||
583 | |||
584 | if (get_user(timeout, arg)) | ||
585 | return -EFAULT; | ||
586 | |||
587 | expire = msecs_to_jiffies(timeout); | ||
588 | |||
589 | mutex_unlock(&data->io_mutex); | ||
590 | |||
591 | rv = wait_event_interruptible_timeout( | ||
592 | data->waitq, | ||
593 | atomic_read(&file_data->srq_asserted) != 0 || | ||
594 | atomic_read(&file_data->closing), | ||
595 | expire); | ||
596 | |||
597 | mutex_lock(&data->io_mutex); | ||
598 | |||
599 | /* Note! disconnect or close could be called in the meantime */ | ||
600 | if (atomic_read(&file_data->closing) || data->zombie) | ||
601 | rv = -ENODEV; | ||
602 | |||
603 | if (rv < 0) { | ||
604 | /* dev can be invalid now! */ | ||
605 | pr_debug("%s - wait interrupted %d\n", __func__, rv); | ||
606 | return rv; | ||
607 | } | ||
608 | |||
609 | if (rv == 0) { | ||
610 | dev_dbg(dev, "%s - wait timed out\n", __func__); | ||
611 | return -ETIMEDOUT; | ||
612 | } | ||
613 | |||
614 | dev_dbg(dev, "%s - srq asserted\n", __func__); | ||
615 | return 0; | ||
616 | } | ||
617 | |||
513 | static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data, | 618 | static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data, |
514 | void __user *arg, unsigned int cmd) | 619 | void __user *arg, unsigned int cmd) |
515 | { | 620 | { |
@@ -543,7 +648,7 @@ static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data, | |||
543 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | 648 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, |
544 | wValue, | 649 | wValue, |
545 | data->ifnum, | 650 | data->ifnum, |
546 | buffer, 0x01, USBTMC_TIMEOUT); | 651 | buffer, 0x01, USB_CTRL_GET_TIMEOUT); |
547 | if (rv < 0) { | 652 | if (rv < 0) { |
548 | dev_err(dev, "simple usb_control_msg failed %d\n", rv); | 653 | dev_err(dev, "simple usb_control_msg failed %d\n", rv); |
549 | goto exit; | 654 | goto exit; |
@@ -610,6 +715,559 @@ static int usbtmc488_ioctl_trigger(struct usbtmc_file_data *file_data) | |||
610 | return 0; | 715 | return 0; |
611 | } | 716 | } |
612 | 717 | ||
718 | static struct urb *usbtmc_create_urb(void) | ||
719 | { | ||
720 | const size_t bufsize = USBTMC_BUFSIZE; | ||
721 | u8 *dmabuf = NULL; | ||
722 | struct urb *urb = usb_alloc_urb(0, GFP_KERNEL); | ||
723 | |||
724 | if (!urb) | ||
725 | return NULL; | ||
726 | |||
727 | dmabuf = kmalloc(bufsize, GFP_KERNEL); | ||
728 | if (!dmabuf) { | ||
729 | usb_free_urb(urb); | ||
730 | return NULL; | ||
731 | } | ||
732 | |||
733 | urb->transfer_buffer = dmabuf; | ||
734 | urb->transfer_buffer_length = bufsize; | ||
735 | urb->transfer_flags |= URB_FREE_BUFFER; | ||
736 | return urb; | ||
737 | } | ||
738 | |||
739 | static void usbtmc_read_bulk_cb(struct urb *urb) | ||
740 | { | ||
741 | struct usbtmc_file_data *file_data = urb->context; | ||
742 | int status = urb->status; | ||
743 | unsigned long flags; | ||
744 | |||
745 | /* sync/async unlink faults aren't errors */ | ||
746 | if (status) { | ||
747 | if (!(/* status == -ENOENT || */ | ||
748 | status == -ECONNRESET || | ||
749 | status == -EREMOTEIO || /* Short packet */ | ||
750 | status == -ESHUTDOWN)) | ||
751 | dev_err(&file_data->data->intf->dev, | ||
752 | "%s - nonzero read bulk status received: %d\n", | ||
753 | __func__, status); | ||
754 | |||
755 | spin_lock_irqsave(&file_data->err_lock, flags); | ||
756 | if (!file_data->in_status) | ||
757 | file_data->in_status = status; | ||
758 | spin_unlock_irqrestore(&file_data->err_lock, flags); | ||
759 | } | ||
760 | |||
761 | spin_lock_irqsave(&file_data->err_lock, flags); | ||
762 | file_data->in_transfer_size += urb->actual_length; | ||
763 | dev_dbg(&file_data->data->intf->dev, | ||
764 | "%s - total size: %u current: %d status: %d\n", | ||
765 | __func__, file_data->in_transfer_size, | ||
766 | urb->actual_length, status); | ||
767 | spin_unlock_irqrestore(&file_data->err_lock, flags); | ||
768 | usb_anchor_urb(urb, &file_data->in_anchor); | ||
769 | |||
770 | wake_up_interruptible(&file_data->wait_bulk_in); | ||
771 | wake_up_interruptible(&file_data->data->waitq); | ||
772 | } | ||
773 | |||
774 | static inline bool usbtmc_do_transfer(struct usbtmc_file_data *file_data) | ||
775 | { | ||
776 | bool data_or_error; | ||
777 | |||
778 | spin_lock_irq(&file_data->err_lock); | ||
779 | data_or_error = !usb_anchor_empty(&file_data->in_anchor) | ||
780 | || file_data->in_status; | ||
781 | spin_unlock_irq(&file_data->err_lock); | ||
782 | dev_dbg(&file_data->data->intf->dev, "%s: returns %d\n", __func__, | ||
783 | data_or_error); | ||
784 | return data_or_error; | ||
785 | } | ||
786 | |||
787 | static ssize_t usbtmc_generic_read(struct usbtmc_file_data *file_data, | ||
788 | void __user *user_buffer, | ||
789 | u32 transfer_size, | ||
790 | u32 *transferred, | ||
791 | u32 flags) | ||
792 | { | ||
793 | struct usbtmc_device_data *data = file_data->data; | ||
794 | struct device *dev = &data->intf->dev; | ||
795 | u32 done = 0; | ||
796 | u32 remaining; | ||
797 | const u32 bufsize = USBTMC_BUFSIZE; | ||
798 | int retval = 0; | ||
799 | u32 max_transfer_size; | ||
800 | unsigned long expire; | ||
801 | int bufcount = 1; | ||
802 | int again = 0; | ||
803 | |||
804 | /* mutex already locked */ | ||
805 | |||
806 | *transferred = done; | ||
807 | |||
808 | max_transfer_size = transfer_size; | ||
809 | |||
810 | if (flags & USBTMC_FLAG_IGNORE_TRAILER) { | ||
811 | /* The device may send extra alignment bytes (up to | ||
812 | * wMaxPacketSize – 1) to avoid sending a zero-length | ||
813 | * packet | ||
814 | */ | ||
815 | remaining = transfer_size; | ||
816 | if ((max_transfer_size % data->wMaxPacketSize) == 0) | ||
817 | max_transfer_size += (data->wMaxPacketSize - 1); | ||
818 | } else { | ||
819 | /* round down to bufsize to avoid truncated data left */ | ||
820 | if (max_transfer_size > bufsize) { | ||
821 | max_transfer_size = | ||
822 | roundup(max_transfer_size + 1 - bufsize, | ||
823 | bufsize); | ||
824 | } | ||
825 | remaining = max_transfer_size; | ||
826 | } | ||
827 | |||
828 | spin_lock_irq(&file_data->err_lock); | ||
829 | |||
830 | if (file_data->in_status) { | ||
831 | /* return the very first error */ | ||
832 | retval = file_data->in_status; | ||
833 | spin_unlock_irq(&file_data->err_lock); | ||
834 | goto error; | ||
835 | } | ||
836 | |||
837 | if (flags & USBTMC_FLAG_ASYNC) { | ||
838 | if (usb_anchor_empty(&file_data->in_anchor)) | ||
839 | again = 1; | ||
840 | |||
841 | if (file_data->in_urbs_used == 0) { | ||
842 | file_data->in_transfer_size = 0; | ||
843 | file_data->in_status = 0; | ||
844 | } | ||
845 | } else { | ||
846 | file_data->in_transfer_size = 0; | ||
847 | file_data->in_status = 0; | ||
848 | } | ||
849 | |||
850 | if (max_transfer_size == 0) { | ||
851 | bufcount = 0; | ||
852 | } else { | ||
853 | bufcount = roundup(max_transfer_size, bufsize) / bufsize; | ||
854 | if (bufcount > file_data->in_urbs_used) | ||
855 | bufcount -= file_data->in_urbs_used; | ||
856 | else | ||
857 | bufcount = 0; | ||
858 | |||
859 | if (bufcount + file_data->in_urbs_used > MAX_URBS_IN_FLIGHT) { | ||
860 | bufcount = MAX_URBS_IN_FLIGHT - | ||
861 | file_data->in_urbs_used; | ||
862 | } | ||
863 | } | ||
864 | spin_unlock_irq(&file_data->err_lock); | ||
865 | |||
866 | dev_dbg(dev, "%s: requested=%u flags=0x%X size=%u bufs=%d used=%d\n", | ||
867 | __func__, transfer_size, flags, | ||
868 | max_transfer_size, bufcount, file_data->in_urbs_used); | ||
869 | |||
870 | while (bufcount > 0) { | ||
871 | u8 *dmabuf = NULL; | ||
872 | struct urb *urb = usbtmc_create_urb(); | ||
873 | |||
874 | if (!urb) { | ||
875 | retval = -ENOMEM; | ||
876 | goto error; | ||
877 | } | ||
878 | |||
879 | dmabuf = urb->transfer_buffer; | ||
880 | |||
881 | usb_fill_bulk_urb(urb, data->usb_dev, | ||
882 | usb_rcvbulkpipe(data->usb_dev, data->bulk_in), | ||
883 | dmabuf, bufsize, | ||
884 | usbtmc_read_bulk_cb, file_data); | ||
885 | |||
886 | usb_anchor_urb(urb, &file_data->submitted); | ||
887 | retval = usb_submit_urb(urb, GFP_KERNEL); | ||
888 | /* urb is anchored. We can release our reference. */ | ||
889 | usb_free_urb(urb); | ||
890 | if (unlikely(retval)) { | ||
891 | usb_unanchor_urb(urb); | ||
892 | goto error; | ||
893 | } | ||
894 | file_data->in_urbs_used++; | ||
895 | bufcount--; | ||
896 | } | ||
897 | |||
898 | if (again) { | ||
899 | dev_dbg(dev, "%s: ret=again\n", __func__); | ||
900 | return -EAGAIN; | ||
901 | } | ||
902 | |||
903 | if (user_buffer == NULL) | ||
904 | return -EINVAL; | ||
905 | |||
906 | expire = msecs_to_jiffies(file_data->timeout); | ||
907 | |||
908 | while (max_transfer_size > 0) { | ||
909 | u32 this_part; | ||
910 | struct urb *urb = NULL; | ||
911 | |||
912 | if (!(flags & USBTMC_FLAG_ASYNC)) { | ||
913 | dev_dbg(dev, "%s: before wait time %lu\n", | ||
914 | __func__, expire); | ||
915 | retval = wait_event_interruptible_timeout( | ||
916 | file_data->wait_bulk_in, | ||
917 | usbtmc_do_transfer(file_data), | ||
918 | expire); | ||
919 | |||
920 | dev_dbg(dev, "%s: wait returned %d\n", | ||
921 | __func__, retval); | ||
922 | |||
923 | if (retval <= 0) { | ||
924 | if (retval == 0) | ||
925 | retval = -ETIMEDOUT; | ||
926 | goto error; | ||
927 | } | ||
928 | } | ||
929 | |||
930 | urb = usb_get_from_anchor(&file_data->in_anchor); | ||
931 | if (!urb) { | ||
932 | if (!(flags & USBTMC_FLAG_ASYNC)) { | ||
933 | /* synchronous case: must not happen */ | ||
934 | retval = -EFAULT; | ||
935 | goto error; | ||
936 | } | ||
937 | |||
938 | /* asynchronous case: ready, do not block or wait */ | ||
939 | *transferred = done; | ||
940 | dev_dbg(dev, "%s: (async) done=%u ret=0\n", | ||
941 | __func__, done); | ||
942 | return 0; | ||
943 | } | ||
944 | |||
945 | file_data->in_urbs_used--; | ||
946 | |||
947 | if (max_transfer_size > urb->actual_length) | ||
948 | max_transfer_size -= urb->actual_length; | ||
949 | else | ||
950 | max_transfer_size = 0; | ||
951 | |||
952 | if (remaining > urb->actual_length) | ||
953 | this_part = urb->actual_length; | ||
954 | else | ||
955 | this_part = remaining; | ||
956 | |||
957 | print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 16, 1, | ||
958 | urb->transfer_buffer, urb->actual_length, true); | ||
959 | |||
960 | if (copy_to_user(user_buffer + done, | ||
961 | urb->transfer_buffer, this_part)) { | ||
962 | usb_free_urb(urb); | ||
963 | retval = -EFAULT; | ||
964 | goto error; | ||
965 | } | ||
966 | |||
967 | remaining -= this_part; | ||
968 | done += this_part; | ||
969 | |||
970 | spin_lock_irq(&file_data->err_lock); | ||
971 | if (urb->status) { | ||
972 | /* return the very first error */ | ||
973 | retval = file_data->in_status; | ||
974 | spin_unlock_irq(&file_data->err_lock); | ||
975 | usb_free_urb(urb); | ||
976 | goto error; | ||
977 | } | ||
978 | spin_unlock_irq(&file_data->err_lock); | ||
979 | |||
980 | if (urb->actual_length < bufsize) { | ||
981 | /* short packet or ZLP received => ready */ | ||
982 | usb_free_urb(urb); | ||
983 | retval = 1; | ||
984 | break; | ||
985 | } | ||
986 | |||
987 | if (!(flags & USBTMC_FLAG_ASYNC) && | ||
988 | max_transfer_size > (bufsize * file_data->in_urbs_used)) { | ||
989 | /* resubmit, since other buffers still not enough */ | ||
990 | usb_anchor_urb(urb, &file_data->submitted); | ||
991 | retval = usb_submit_urb(urb, GFP_KERNEL); | ||
992 | if (unlikely(retval)) { | ||
993 | usb_unanchor_urb(urb); | ||
994 | usb_free_urb(urb); | ||
995 | goto error; | ||
996 | } | ||
997 | file_data->in_urbs_used++; | ||
998 | } | ||
999 | usb_free_urb(urb); | ||
1000 | retval = 0; | ||
1001 | } | ||
1002 | |||
1003 | error: | ||
1004 | *transferred = done; | ||
1005 | |||
1006 | dev_dbg(dev, "%s: before kill\n", __func__); | ||
1007 | /* Attention: killing urbs can take long time (2 ms) */ | ||
1008 | usb_kill_anchored_urbs(&file_data->submitted); | ||
1009 | dev_dbg(dev, "%s: after kill\n", __func__); | ||
1010 | usb_scuttle_anchored_urbs(&file_data->in_anchor); | ||
1011 | file_data->in_urbs_used = 0; | ||
1012 | file_data->in_status = 0; /* no spinlock needed here */ | ||
1013 | dev_dbg(dev, "%s: done=%u ret=%d\n", __func__, done, retval); | ||
1014 | |||
1015 | return retval; | ||
1016 | } | ||
1017 | |||
1018 | static ssize_t usbtmc_ioctl_generic_read(struct usbtmc_file_data *file_data, | ||
1019 | void __user *arg) | ||
1020 | { | ||
1021 | struct usbtmc_message msg; | ||
1022 | ssize_t retval = 0; | ||
1023 | |||
1024 | /* mutex already locked */ | ||
1025 | |||
1026 | if (copy_from_user(&msg, arg, sizeof(struct usbtmc_message))) | ||
1027 | return -EFAULT; | ||
1028 | |||
1029 | retval = usbtmc_generic_read(file_data, msg.message, | ||
1030 | msg.transfer_size, &msg.transferred, | ||
1031 | msg.flags); | ||
1032 | |||
1033 | if (put_user(msg.transferred, | ||
1034 | &((struct usbtmc_message __user *)arg)->transferred)) | ||
1035 | return -EFAULT; | ||
1036 | |||
1037 | return retval; | ||
1038 | } | ||
1039 | |||
1040 | static void usbtmc_write_bulk_cb(struct urb *urb) | ||
1041 | { | ||
1042 | struct usbtmc_file_data *file_data = urb->context; | ||
1043 | int wakeup = 0; | ||
1044 | unsigned long flags; | ||
1045 | |||
1046 | spin_lock_irqsave(&file_data->err_lock, flags); | ||
1047 | file_data->out_transfer_size += urb->actual_length; | ||
1048 | |||
1049 | /* sync/async unlink faults aren't errors */ | ||
1050 | if (urb->status) { | ||
1051 | if (!(urb->status == -ENOENT || | ||
1052 | urb->status == -ECONNRESET || | ||
1053 | urb->status == -ESHUTDOWN)) | ||
1054 | dev_err(&file_data->data->intf->dev, | ||
1055 | "%s - nonzero write bulk status received: %d\n", | ||
1056 | __func__, urb->status); | ||
1057 | |||
1058 | if (!file_data->out_status) { | ||
1059 | file_data->out_status = urb->status; | ||
1060 | wakeup = 1; | ||
1061 | } | ||
1062 | } | ||
1063 | spin_unlock_irqrestore(&file_data->err_lock, flags); | ||
1064 | |||
1065 | dev_dbg(&file_data->data->intf->dev, | ||
1066 | "%s - write bulk total size: %u\n", | ||
1067 | __func__, file_data->out_transfer_size); | ||
1068 | |||
1069 | up(&file_data->limit_write_sem); | ||
1070 | if (usb_anchor_empty(&file_data->submitted) || wakeup) | ||
1071 | wake_up_interruptible(&file_data->data->waitq); | ||
1072 | } | ||
1073 | |||
1074 | static ssize_t usbtmc_generic_write(struct usbtmc_file_data *file_data, | ||
1075 | const void __user *user_buffer, | ||
1076 | u32 transfer_size, | ||
1077 | u32 *transferred, | ||
1078 | u32 flags) | ||
1079 | { | ||
1080 | struct usbtmc_device_data *data = file_data->data; | ||
1081 | struct device *dev; | ||
1082 | u32 done = 0; | ||
1083 | u32 remaining; | ||
1084 | unsigned long expire; | ||
1085 | const u32 bufsize = USBTMC_BUFSIZE; | ||
1086 | struct urb *urb = NULL; | ||
1087 | int retval = 0; | ||
1088 | u32 timeout; | ||
1089 | |||
1090 | *transferred = 0; | ||
1091 | |||
1092 | /* Get pointer to private data structure */ | ||
1093 | dev = &data->intf->dev; | ||
1094 | |||
1095 | dev_dbg(dev, "%s: size=%u flags=0x%X sema=%u\n", | ||
1096 | __func__, transfer_size, flags, | ||
1097 | file_data->limit_write_sem.count); | ||
1098 | |||
1099 | if (flags & USBTMC_FLAG_APPEND) { | ||
1100 | spin_lock_irq(&file_data->err_lock); | ||
1101 | retval = file_data->out_status; | ||
1102 | spin_unlock_irq(&file_data->err_lock); | ||
1103 | if (retval < 0) | ||
1104 | return retval; | ||
1105 | } else { | ||
1106 | spin_lock_irq(&file_data->err_lock); | ||
1107 | file_data->out_transfer_size = 0; | ||
1108 | file_data->out_status = 0; | ||
1109 | spin_unlock_irq(&file_data->err_lock); | ||
1110 | } | ||
1111 | |||
1112 | remaining = transfer_size; | ||
1113 | if (remaining > INT_MAX) | ||
1114 | remaining = INT_MAX; | ||
1115 | |||
1116 | timeout = file_data->timeout; | ||
1117 | expire = msecs_to_jiffies(timeout); | ||
1118 | |||
1119 | while (remaining > 0) { | ||
1120 | u32 this_part, aligned; | ||
1121 | u8 *buffer = NULL; | ||
1122 | |||
1123 | if (flags & USBTMC_FLAG_ASYNC) { | ||
1124 | if (down_trylock(&file_data->limit_write_sem)) { | ||
1125 | retval = (done)?(0):(-EAGAIN); | ||
1126 | goto exit; | ||
1127 | } | ||
1128 | } else { | ||
1129 | retval = down_timeout(&file_data->limit_write_sem, | ||
1130 | expire); | ||
1131 | if (retval < 0) { | ||
1132 | retval = -ETIMEDOUT; | ||
1133 | goto error; | ||
1134 | } | ||
1135 | } | ||
1136 | |||
1137 | spin_lock_irq(&file_data->err_lock); | ||
1138 | retval = file_data->out_status; | ||
1139 | spin_unlock_irq(&file_data->err_lock); | ||
1140 | if (retval < 0) { | ||
1141 | up(&file_data->limit_write_sem); | ||
1142 | goto error; | ||
1143 | } | ||
1144 | |||
1145 | /* prepare next urb to send */ | ||
1146 | urb = usbtmc_create_urb(); | ||
1147 | if (!urb) { | ||
1148 | retval = -ENOMEM; | ||
1149 | up(&file_data->limit_write_sem); | ||
1150 | goto error; | ||
1151 | } | ||
1152 | buffer = urb->transfer_buffer; | ||
1153 | |||
1154 | if (remaining > bufsize) | ||
1155 | this_part = bufsize; | ||
1156 | else | ||
1157 | this_part = remaining; | ||
1158 | |||
1159 | if (copy_from_user(buffer, user_buffer + done, this_part)) { | ||
1160 | retval = -EFAULT; | ||
1161 | up(&file_data->limit_write_sem); | ||
1162 | goto error; | ||
1163 | } | ||
1164 | |||
1165 | print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, | ||
1166 | 16, 1, buffer, this_part, true); | ||
1167 | |||
1168 | /* fill bulk with 32 bit alignment to meet USBTMC specification | ||
1169 | * (size + 3 & ~3) rounds up and simplifies user code | ||
1170 | */ | ||
1171 | aligned = (this_part + 3) & ~3; | ||
1172 | dev_dbg(dev, "write(size:%u align:%u done:%u)\n", | ||
1173 | (unsigned int)this_part, | ||
1174 | (unsigned int)aligned, | ||
1175 | (unsigned int)done); | ||
1176 | |||
1177 | usb_fill_bulk_urb(urb, data->usb_dev, | ||
1178 | usb_sndbulkpipe(data->usb_dev, data->bulk_out), | ||
1179 | urb->transfer_buffer, aligned, | ||
1180 | usbtmc_write_bulk_cb, file_data); | ||
1181 | |||
1182 | usb_anchor_urb(urb, &file_data->submitted); | ||
1183 | retval = usb_submit_urb(urb, GFP_KERNEL); | ||
1184 | if (unlikely(retval)) { | ||
1185 | usb_unanchor_urb(urb); | ||
1186 | up(&file_data->limit_write_sem); | ||
1187 | goto error; | ||
1188 | } | ||
1189 | |||
1190 | usb_free_urb(urb); | ||
1191 | urb = NULL; /* urb will be finally released by usb driver */ | ||
1192 | |||
1193 | remaining -= this_part; | ||
1194 | done += this_part; | ||
1195 | } | ||
1196 | |||
1197 | /* All urbs are on the fly */ | ||
1198 | if (!(flags & USBTMC_FLAG_ASYNC)) { | ||
1199 | if (!usb_wait_anchor_empty_timeout(&file_data->submitted, | ||
1200 | timeout)) { | ||
1201 | retval = -ETIMEDOUT; | ||
1202 | goto error; | ||
1203 | } | ||
1204 | } | ||
1205 | |||
1206 | retval = 0; | ||
1207 | goto exit; | ||
1208 | |||
1209 | error: | ||
1210 | usb_kill_anchored_urbs(&file_data->submitted); | ||
1211 | exit: | ||
1212 | usb_free_urb(urb); | ||
1213 | |||
1214 | spin_lock_irq(&file_data->err_lock); | ||
1215 | if (!(flags & USBTMC_FLAG_ASYNC)) | ||
1216 | done = file_data->out_transfer_size; | ||
1217 | if (!retval && file_data->out_status) | ||
1218 | retval = file_data->out_status; | ||
1219 | spin_unlock_irq(&file_data->err_lock); | ||
1220 | |||
1221 | *transferred = done; | ||
1222 | |||
1223 | dev_dbg(dev, "%s: done=%u, retval=%d, urbstat=%d\n", | ||
1224 | __func__, done, retval, file_data->out_status); | ||
1225 | |||
1226 | return retval; | ||
1227 | } | ||
1228 | |||
1229 | static ssize_t usbtmc_ioctl_generic_write(struct usbtmc_file_data *file_data, | ||
1230 | void __user *arg) | ||
1231 | { | ||
1232 | struct usbtmc_message msg; | ||
1233 | ssize_t retval = 0; | ||
1234 | |||
1235 | /* mutex already locked */ | ||
1236 | |||
1237 | if (copy_from_user(&msg, arg, sizeof(struct usbtmc_message))) | ||
1238 | return -EFAULT; | ||
1239 | |||
1240 | retval = usbtmc_generic_write(file_data, msg.message, | ||
1241 | msg.transfer_size, &msg.transferred, | ||
1242 | msg.flags); | ||
1243 | |||
1244 | if (put_user(msg.transferred, | ||
1245 | &((struct usbtmc_message __user *)arg)->transferred)) | ||
1246 | return -EFAULT; | ||
1247 | |||
1248 | return retval; | ||
1249 | } | ||
1250 | |||
1251 | /* | ||
1252 | * Get the generic write result | ||
1253 | */ | ||
1254 | static ssize_t usbtmc_ioctl_write_result(struct usbtmc_file_data *file_data, | ||
1255 | void __user *arg) | ||
1256 | { | ||
1257 | u32 transferred; | ||
1258 | int retval; | ||
1259 | |||
1260 | spin_lock_irq(&file_data->err_lock); | ||
1261 | transferred = file_data->out_transfer_size; | ||
1262 | retval = file_data->out_status; | ||
1263 | spin_unlock_irq(&file_data->err_lock); | ||
1264 | |||
1265 | if (put_user(transferred, (__u32 __user *)arg)) | ||
1266 | return -EFAULT; | ||
1267 | |||
1268 | return retval; | ||
1269 | } | ||
1270 | |||
613 | /* | 1271 | /* |
614 | * Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-OUT endpoint. | 1272 | * Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-OUT endpoint. |
615 | * @transfer_size: number of bytes to request from the device. | 1273 | * @transfer_size: number of bytes to request from the device. |
@@ -619,7 +1277,7 @@ static int usbtmc488_ioctl_trigger(struct usbtmc_file_data *file_data) | |||
619 | * Also updates bTag_last_write. | 1277 | * Also updates bTag_last_write. |
620 | */ | 1278 | */ |
621 | static int send_request_dev_dep_msg_in(struct usbtmc_file_data *file_data, | 1279 | static int send_request_dev_dep_msg_in(struct usbtmc_file_data *file_data, |
622 | size_t transfer_size) | 1280 | u32 transfer_size) |
623 | { | 1281 | { |
624 | struct usbtmc_device_data *data = file_data->data; | 1282 | struct usbtmc_device_data *data = file_data->data; |
625 | int retval; | 1283 | int retval; |
@@ -662,12 +1320,11 @@ static int send_request_dev_dep_msg_in(struct usbtmc_file_data *file_data, | |||
662 | data->bTag++; | 1320 | data->bTag++; |
663 | 1321 | ||
664 | kfree(buffer); | 1322 | kfree(buffer); |
665 | if (retval < 0) { | 1323 | if (retval < 0) |
666 | dev_err(&data->intf->dev, "usb_bulk_msg in send_request_dev_dep_msg_in() returned %d\n", retval); | 1324 | dev_err(&data->intf->dev, "%s returned %d\n", |
667 | return retval; | 1325 | __func__, retval); |
668 | } | ||
669 | 1326 | ||
670 | return 0; | 1327 | return retval; |
671 | } | 1328 | } |
672 | 1329 | ||
673 | static ssize_t usbtmc_read(struct file *filp, char __user *buf, | 1330 | static ssize_t usbtmc_read(struct file *filp, char __user *buf, |
@@ -676,20 +1333,20 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, | |||
676 | struct usbtmc_file_data *file_data; | 1333 | struct usbtmc_file_data *file_data; |
677 | struct usbtmc_device_data *data; | 1334 | struct usbtmc_device_data *data; |
678 | struct device *dev; | 1335 | struct device *dev; |
1336 | const u32 bufsize = USBTMC_BUFSIZE; | ||
679 | u32 n_characters; | 1337 | u32 n_characters; |
680 | u8 *buffer; | 1338 | u8 *buffer; |
681 | int actual; | 1339 | int actual; |
682 | size_t done; | 1340 | u32 done = 0; |
683 | size_t remaining; | 1341 | u32 remaining; |
684 | int retval; | 1342 | int retval; |
685 | size_t this_part; | ||
686 | 1343 | ||
687 | /* Get pointer to private data structure */ | 1344 | /* Get pointer to private data structure */ |
688 | file_data = filp->private_data; | 1345 | file_data = filp->private_data; |
689 | data = file_data->data; | 1346 | data = file_data->data; |
690 | dev = &data->intf->dev; | 1347 | dev = &data->intf->dev; |
691 | 1348 | ||
692 | buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); | 1349 | buffer = kmalloc(bufsize, GFP_KERNEL); |
693 | if (!buffer) | 1350 | if (!buffer) |
694 | return -ENOMEM; | 1351 | return -ENOMEM; |
695 | 1352 | ||
@@ -699,124 +1356,116 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, | |||
699 | goto exit; | 1356 | goto exit; |
700 | } | 1357 | } |
701 | 1358 | ||
702 | dev_dbg(dev, "usb_bulk_msg_in: count(%zu)\n", count); | 1359 | if (count > INT_MAX) |
1360 | count = INT_MAX; | ||
1361 | |||
1362 | dev_dbg(dev, "%s(count:%zu)\n", __func__, count); | ||
703 | 1363 | ||
704 | retval = send_request_dev_dep_msg_in(file_data, count); | 1364 | retval = send_request_dev_dep_msg_in(file_data, count); |
705 | 1365 | ||
706 | if (retval < 0) { | 1366 | if (retval < 0) { |
707 | if (data->auto_abort) | 1367 | if (file_data->auto_abort) |
708 | usbtmc_ioctl_abort_bulk_out(data); | 1368 | usbtmc_ioctl_abort_bulk_out(data); |
709 | goto exit; | 1369 | goto exit; |
710 | } | 1370 | } |
711 | 1371 | ||
712 | /* Loop until we have fetched everything we requested */ | 1372 | /* Loop until we have fetched everything we requested */ |
713 | remaining = count; | 1373 | remaining = count; |
714 | this_part = remaining; | 1374 | actual = 0; |
715 | done = 0; | ||
716 | 1375 | ||
717 | while (remaining > 0) { | 1376 | /* Send bulk URB */ |
718 | /* Send bulk URB */ | 1377 | retval = usb_bulk_msg(data->usb_dev, |
719 | retval = usb_bulk_msg(data->usb_dev, | 1378 | usb_rcvbulkpipe(data->usb_dev, |
720 | usb_rcvbulkpipe(data->usb_dev, | 1379 | data->bulk_in), |
721 | data->bulk_in), | 1380 | buffer, bufsize, &actual, |
722 | buffer, USBTMC_SIZE_IOBUFFER, &actual, | 1381 | file_data->timeout); |
723 | file_data->timeout); | ||
724 | |||
725 | dev_dbg(dev, "usb_bulk_msg: retval(%u), done(%zu), remaining(%zu), actual(%d)\n", retval, done, remaining, actual); | ||
726 | 1382 | ||
727 | /* Store bTag (in case we need to abort) */ | 1383 | dev_dbg(dev, "%s: bulk_msg retval(%u), actual(%d)\n", |
728 | data->bTag_last_read = data->bTag; | 1384 | __func__, retval, actual); |
729 | 1385 | ||
730 | if (retval < 0) { | 1386 | /* Store bTag (in case we need to abort) */ |
731 | dev_dbg(dev, "Unable to read data, error %d\n", retval); | 1387 | data->bTag_last_read = data->bTag; |
732 | if (data->auto_abort) | ||
733 | usbtmc_ioctl_abort_bulk_in(data); | ||
734 | goto exit; | ||
735 | } | ||
736 | |||
737 | /* Parse header in first packet */ | ||
738 | if (done == 0) { | ||
739 | /* Sanity checks for the header */ | ||
740 | if (actual < USBTMC_HEADER_SIZE) { | ||
741 | dev_err(dev, "Device sent too small first packet: %u < %u\n", actual, USBTMC_HEADER_SIZE); | ||
742 | if (data->auto_abort) | ||
743 | usbtmc_ioctl_abort_bulk_in(data); | ||
744 | goto exit; | ||
745 | } | ||
746 | 1388 | ||
747 | if (buffer[0] != 2) { | 1389 | if (retval < 0) { |
748 | dev_err(dev, "Device sent reply with wrong MsgID: %u != 2\n", buffer[0]); | 1390 | if (file_data->auto_abort) |
749 | if (data->auto_abort) | 1391 | usbtmc_ioctl_abort_bulk_in(data); |
750 | usbtmc_ioctl_abort_bulk_in(data); | 1392 | goto exit; |
751 | goto exit; | 1393 | } |
752 | } | ||
753 | 1394 | ||
754 | if (buffer[1] != data->bTag_last_write) { | 1395 | /* Sanity checks for the header */ |
755 | dev_err(dev, "Device sent reply with wrong bTag: %u != %u\n", buffer[1], data->bTag_last_write); | 1396 | if (actual < USBTMC_HEADER_SIZE) { |
756 | if (data->auto_abort) | 1397 | dev_err(dev, "Device sent too small first packet: %u < %u\n", |
757 | usbtmc_ioctl_abort_bulk_in(data); | 1398 | actual, USBTMC_HEADER_SIZE); |
758 | goto exit; | 1399 | if (file_data->auto_abort) |
759 | } | 1400 | usbtmc_ioctl_abort_bulk_in(data); |
1401 | goto exit; | ||
1402 | } | ||
760 | 1403 | ||
761 | /* How many characters did the instrument send? */ | 1404 | if (buffer[0] != 2) { |
762 | n_characters = buffer[4] + | 1405 | dev_err(dev, "Device sent reply with wrong MsgID: %u != 2\n", |
763 | (buffer[5] << 8) + | 1406 | buffer[0]); |
764 | (buffer[6] << 16) + | 1407 | if (file_data->auto_abort) |
765 | (buffer[7] << 24); | 1408 | usbtmc_ioctl_abort_bulk_in(data); |
1409 | goto exit; | ||
1410 | } | ||
766 | 1411 | ||
767 | if (n_characters > this_part) { | 1412 | if (buffer[1] != data->bTag_last_write) { |
768 | dev_err(dev, "Device wants to return more data than requested: %u > %zu\n", n_characters, count); | 1413 | dev_err(dev, "Device sent reply with wrong bTag: %u != %u\n", |
769 | if (data->auto_abort) | 1414 | buffer[1], data->bTag_last_write); |
770 | usbtmc_ioctl_abort_bulk_in(data); | 1415 | if (file_data->auto_abort) |
771 | goto exit; | 1416 | usbtmc_ioctl_abort_bulk_in(data); |
772 | } | 1417 | goto exit; |
1418 | } | ||
773 | 1419 | ||
774 | /* Remove the USBTMC header */ | 1420 | /* How many characters did the instrument send? */ |
775 | actual -= USBTMC_HEADER_SIZE; | 1421 | n_characters = buffer[4] + |
1422 | (buffer[5] << 8) + | ||
1423 | (buffer[6] << 16) + | ||
1424 | (buffer[7] << 24); | ||
776 | 1425 | ||
777 | /* Check if the message is smaller than requested */ | 1426 | file_data->bmTransferAttributes = buffer[8]; |
778 | if (remaining > n_characters) | ||
779 | remaining = n_characters; | ||
780 | /* Remove padding if it exists */ | ||
781 | if (actual > remaining) | ||
782 | actual = remaining; | ||
783 | 1427 | ||
784 | dev_dbg(dev, "Bulk-IN header: N_characters(%u), bTransAttr(%u)\n", n_characters, buffer[8]); | 1428 | dev_dbg(dev, "Bulk-IN header: N_characters(%u), bTransAttr(%u)\n", |
1429 | n_characters, buffer[8]); | ||
785 | 1430 | ||
786 | remaining -= actual; | 1431 | if (n_characters > remaining) { |
1432 | dev_err(dev, "Device wants to return more data than requested: %u > %zu\n", | ||
1433 | n_characters, count); | ||
1434 | if (file_data->auto_abort) | ||
1435 | usbtmc_ioctl_abort_bulk_in(data); | ||
1436 | goto exit; | ||
1437 | } | ||
787 | 1438 | ||
788 | /* Terminate if end-of-message bit received from device */ | 1439 | print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, |
789 | if ((buffer[8] & 0x01) && (actual >= n_characters)) | 1440 | 16, 1, buffer, actual, true); |
790 | remaining = 0; | ||
791 | 1441 | ||
792 | dev_dbg(dev, "Bulk-IN header: remaining(%zu), buf(%p), buffer(%p) done(%zu)\n", remaining,buf,buffer,done); | 1442 | remaining = n_characters; |
793 | 1443 | ||
1444 | /* Remove the USBTMC header */ | ||
1445 | actual -= USBTMC_HEADER_SIZE; | ||
794 | 1446 | ||
795 | /* Copy buffer to user space */ | 1447 | /* Remove padding if it exists */ |
796 | if (copy_to_user(buf + done, &buffer[USBTMC_HEADER_SIZE], actual)) { | 1448 | if (actual > remaining) |
797 | /* There must have been an addressing problem */ | 1449 | actual = remaining; |
798 | retval = -EFAULT; | ||
799 | goto exit; | ||
800 | } | ||
801 | done += actual; | ||
802 | } | ||
803 | else { | ||
804 | if (actual > remaining) | ||
805 | actual = remaining; | ||
806 | 1450 | ||
807 | remaining -= actual; | 1451 | remaining -= actual; |
808 | 1452 | ||
809 | dev_dbg(dev, "Bulk-IN header cont: actual(%u), done(%zu), remaining(%zu), buf(%p), buffer(%p)\n", actual, done, remaining,buf,buffer); | 1453 | /* Copy buffer to user space */ |
1454 | if (copy_to_user(buf, &buffer[USBTMC_HEADER_SIZE], actual)) { | ||
1455 | /* There must have been an addressing problem */ | ||
1456 | retval = -EFAULT; | ||
1457 | goto exit; | ||
1458 | } | ||
810 | 1459 | ||
811 | /* Copy buffer to user space */ | 1460 | if ((actual + USBTMC_HEADER_SIZE) == bufsize) { |
812 | if (copy_to_user(buf + done, buffer, actual)) { | 1461 | retval = usbtmc_generic_read(file_data, buf + actual, |
813 | /* There must have been an addressing problem */ | 1462 | remaining, |
814 | retval = -EFAULT; | 1463 | &done, |
815 | goto exit; | 1464 | USBTMC_FLAG_IGNORE_TRAILER); |
816 | } | 1465 | if (retval < 0) |
817 | done += actual; | 1466 | goto exit; |
818 | } | ||
819 | } | 1467 | } |
1468 | done += actual; | ||
820 | 1469 | ||
821 | /* Update file position value */ | 1470 | /* Update file position value */ |
822 | *f_pos = *f_pos + done; | 1471 | *f_pos = *f_pos + done; |
@@ -833,113 +1482,152 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf, | |||
833 | { | 1482 | { |
834 | struct usbtmc_file_data *file_data; | 1483 | struct usbtmc_file_data *file_data; |
835 | struct usbtmc_device_data *data; | 1484 | struct usbtmc_device_data *data; |
1485 | struct urb *urb = NULL; | ||
1486 | ssize_t retval = 0; | ||
836 | u8 *buffer; | 1487 | u8 *buffer; |
837 | int retval; | 1488 | u32 remaining, done; |
838 | int actual; | 1489 | u32 transfersize, aligned, buflen; |
839 | unsigned long int n_bytes; | ||
840 | int remaining; | ||
841 | int done; | ||
842 | int this_part; | ||
843 | 1490 | ||
844 | file_data = filp->private_data; | 1491 | file_data = filp->private_data; |
845 | data = file_data->data; | 1492 | data = file_data->data; |
846 | 1493 | ||
847 | buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); | ||
848 | if (!buffer) | ||
849 | return -ENOMEM; | ||
850 | |||
851 | mutex_lock(&data->io_mutex); | 1494 | mutex_lock(&data->io_mutex); |
1495 | |||
852 | if (data->zombie) { | 1496 | if (data->zombie) { |
853 | retval = -ENODEV; | 1497 | retval = -ENODEV; |
854 | goto exit; | 1498 | goto exit; |
855 | } | 1499 | } |
856 | 1500 | ||
857 | remaining = count; | ||
858 | done = 0; | 1501 | done = 0; |
859 | 1502 | ||
860 | while (remaining > 0) { | 1503 | spin_lock_irq(&file_data->err_lock); |
861 | if (remaining > USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE) { | 1504 | file_data->out_transfer_size = 0; |
862 | this_part = USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE; | 1505 | file_data->out_status = 0; |
863 | buffer[8] = 0; | 1506 | spin_unlock_irq(&file_data->err_lock); |
864 | } else { | ||
865 | this_part = remaining; | ||
866 | buffer[8] = file_data->eom_val; | ||
867 | } | ||
868 | 1507 | ||
869 | /* Setup IO buffer for DEV_DEP_MSG_OUT message */ | 1508 | if (!count) |
870 | buffer[0] = 1; | 1509 | goto exit; |
871 | buffer[1] = data->bTag; | ||
872 | buffer[2] = ~data->bTag; | ||
873 | buffer[3] = 0; /* Reserved */ | ||
874 | buffer[4] = this_part >> 0; | ||
875 | buffer[5] = this_part >> 8; | ||
876 | buffer[6] = this_part >> 16; | ||
877 | buffer[7] = this_part >> 24; | ||
878 | /* buffer[8] is set above... */ | ||
879 | buffer[9] = 0; /* Reserved */ | ||
880 | buffer[10] = 0; /* Reserved */ | ||
881 | buffer[11] = 0; /* Reserved */ | ||
882 | |||
883 | if (copy_from_user(&buffer[USBTMC_HEADER_SIZE], buf + done, this_part)) { | ||
884 | retval = -EFAULT; | ||
885 | goto exit; | ||
886 | } | ||
887 | 1510 | ||
888 | n_bytes = roundup(USBTMC_HEADER_SIZE + this_part, 4); | 1511 | if (down_trylock(&file_data->limit_write_sem)) { |
889 | memset(buffer + USBTMC_HEADER_SIZE + this_part, 0, n_bytes - (USBTMC_HEADER_SIZE + this_part)); | 1512 | /* previous calls were async */ |
1513 | retval = -EBUSY; | ||
1514 | goto exit; | ||
1515 | } | ||
890 | 1516 | ||
891 | do { | 1517 | urb = usbtmc_create_urb(); |
892 | retval = usb_bulk_msg(data->usb_dev, | 1518 | if (!urb) { |
893 | usb_sndbulkpipe(data->usb_dev, | 1519 | retval = -ENOMEM; |
894 | data->bulk_out), | 1520 | up(&file_data->limit_write_sem); |
895 | buffer, n_bytes, | 1521 | goto exit; |
896 | &actual, file_data->timeout); | 1522 | } |
897 | if (retval != 0) | 1523 | |
898 | break; | 1524 | buffer = urb->transfer_buffer; |
899 | n_bytes -= actual; | 1525 | buflen = urb->transfer_buffer_length; |
900 | } while (n_bytes); | 1526 | |
901 | 1527 | if (count > INT_MAX) { | |
902 | data->bTag_last_write = data->bTag; | 1528 | transfersize = INT_MAX; |
1529 | buffer[8] = 0; | ||
1530 | } else { | ||
1531 | transfersize = count; | ||
1532 | buffer[8] = file_data->eom_val; | ||
1533 | } | ||
1534 | |||
1535 | /* Setup IO buffer for DEV_DEP_MSG_OUT message */ | ||
1536 | buffer[0] = 1; | ||
1537 | buffer[1] = data->bTag; | ||
1538 | buffer[2] = ~data->bTag; | ||
1539 | buffer[3] = 0; /* Reserved */ | ||
1540 | buffer[4] = transfersize >> 0; | ||
1541 | buffer[5] = transfersize >> 8; | ||
1542 | buffer[6] = transfersize >> 16; | ||
1543 | buffer[7] = transfersize >> 24; | ||
1544 | /* buffer[8] is set above... */ | ||
1545 | buffer[9] = 0; /* Reserved */ | ||
1546 | buffer[10] = 0; /* Reserved */ | ||
1547 | buffer[11] = 0; /* Reserved */ | ||
1548 | |||
1549 | remaining = transfersize; | ||
1550 | |||
1551 | if (transfersize + USBTMC_HEADER_SIZE > buflen) { | ||
1552 | transfersize = buflen - USBTMC_HEADER_SIZE; | ||
1553 | aligned = buflen; | ||
1554 | } else { | ||
1555 | aligned = (transfersize + (USBTMC_HEADER_SIZE + 3)) & ~3; | ||
1556 | } | ||
1557 | |||
1558 | if (copy_from_user(&buffer[USBTMC_HEADER_SIZE], buf, transfersize)) { | ||
1559 | retval = -EFAULT; | ||
1560 | up(&file_data->limit_write_sem); | ||
1561 | goto exit; | ||
1562 | } | ||
1563 | |||
1564 | dev_dbg(&data->intf->dev, "%s(size:%u align:%u)\n", __func__, | ||
1565 | (unsigned int)transfersize, (unsigned int)aligned); | ||
1566 | |||
1567 | print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, | ||
1568 | 16, 1, buffer, aligned, true); | ||
1569 | |||
1570 | usb_fill_bulk_urb(urb, data->usb_dev, | ||
1571 | usb_sndbulkpipe(data->usb_dev, data->bulk_out), | ||
1572 | urb->transfer_buffer, aligned, | ||
1573 | usbtmc_write_bulk_cb, file_data); | ||
1574 | |||
1575 | usb_anchor_urb(urb, &file_data->submitted); | ||
1576 | retval = usb_submit_urb(urb, GFP_KERNEL); | ||
1577 | if (unlikely(retval)) { | ||
1578 | usb_unanchor_urb(urb); | ||
1579 | up(&file_data->limit_write_sem); | ||
1580 | goto exit; | ||
1581 | } | ||
1582 | |||
1583 | remaining -= transfersize; | ||
1584 | |||
1585 | data->bTag_last_write = data->bTag; | ||
1586 | data->bTag++; | ||
1587 | |||
1588 | if (!data->bTag) | ||
903 | data->bTag++; | 1589 | data->bTag++; |
904 | 1590 | ||
905 | if (!data->bTag) | 1591 | /* call generic_write even when remaining = 0 */ |
906 | data->bTag++; | 1592 | retval = usbtmc_generic_write(file_data, buf + transfersize, remaining, |
1593 | &done, USBTMC_FLAG_APPEND); | ||
1594 | /* truncate alignment bytes */ | ||
1595 | if (done > remaining) | ||
1596 | done = remaining; | ||
907 | 1597 | ||
908 | if (retval < 0) { | 1598 | /*add size of first urb*/ |
909 | dev_err(&data->intf->dev, | 1599 | done += transfersize; |
910 | "Unable to send data, error %d\n", retval); | ||
911 | if (data->auto_abort) | ||
912 | usbtmc_ioctl_abort_bulk_out(data); | ||
913 | goto exit; | ||
914 | } | ||
915 | 1600 | ||
916 | remaining -= this_part; | 1601 | if (retval < 0) { |
917 | done += this_part; | 1602 | usb_kill_anchored_urbs(&file_data->submitted); |
1603 | |||
1604 | dev_err(&data->intf->dev, | ||
1605 | "Unable to send data, error %d\n", (int)retval); | ||
1606 | if (file_data->auto_abort) | ||
1607 | usbtmc_ioctl_abort_bulk_out(data); | ||
1608 | goto exit; | ||
918 | } | 1609 | } |
919 | 1610 | ||
920 | retval = count; | 1611 | retval = done; |
921 | exit: | 1612 | exit: |
1613 | usb_free_urb(urb); | ||
922 | mutex_unlock(&data->io_mutex); | 1614 | mutex_unlock(&data->io_mutex); |
923 | kfree(buffer); | ||
924 | return retval; | 1615 | return retval; |
925 | } | 1616 | } |
926 | 1617 | ||
927 | static int usbtmc_ioctl_clear(struct usbtmc_device_data *data) | 1618 | static int usbtmc_ioctl_clear(struct usbtmc_device_data *data) |
928 | { | 1619 | { |
929 | struct usb_host_interface *current_setting; | ||
930 | struct usb_endpoint_descriptor *desc; | ||
931 | struct device *dev; | 1620 | struct device *dev; |
932 | u8 *buffer; | 1621 | u8 *buffer; |
933 | int rv; | 1622 | int rv; |
934 | int n; | 1623 | int n; |
935 | int actual = 0; | 1624 | int actual = 0; |
936 | int max_size; | ||
937 | 1625 | ||
938 | dev = &data->intf->dev; | 1626 | dev = &data->intf->dev; |
939 | 1627 | ||
940 | dev_dbg(dev, "Sending INITIATE_CLEAR request\n"); | 1628 | dev_dbg(dev, "Sending INITIATE_CLEAR request\n"); |
941 | 1629 | ||
942 | buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); | 1630 | buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL); |
943 | if (!buffer) | 1631 | if (!buffer) |
944 | return -ENOMEM; | 1632 | return -ENOMEM; |
945 | 1633 | ||
@@ -947,7 +1635,7 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data *data) | |||
947 | usb_rcvctrlpipe(data->usb_dev, 0), | 1635 | usb_rcvctrlpipe(data->usb_dev, 0), |
948 | USBTMC_REQUEST_INITIATE_CLEAR, | 1636 | USBTMC_REQUEST_INITIATE_CLEAR, |
949 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | 1637 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, |
950 | 0, 0, buffer, 1, USBTMC_TIMEOUT); | 1638 | 0, 0, buffer, 1, USB_CTRL_GET_TIMEOUT); |
951 | if (rv < 0) { | 1639 | if (rv < 0) { |
952 | dev_err(dev, "usb_control_msg returned %d\n", rv); | 1640 | dev_err(dev, "usb_control_msg returned %d\n", rv); |
953 | goto exit; | 1641 | goto exit; |
@@ -961,22 +1649,6 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data *data) | |||
961 | goto exit; | 1649 | goto exit; |
962 | } | 1650 | } |
963 | 1651 | ||
964 | max_size = 0; | ||
965 | current_setting = data->intf->cur_altsetting; | ||
966 | for (n = 0; n < current_setting->desc.bNumEndpoints; n++) { | ||
967 | desc = ¤t_setting->endpoint[n].desc; | ||
968 | if (desc->bEndpointAddress == data->bulk_in) | ||
969 | max_size = usb_endpoint_maxp(desc); | ||
970 | } | ||
971 | |||
972 | if (max_size == 0) { | ||
973 | dev_err(dev, "Couldn't get wMaxPacketSize\n"); | ||
974 | rv = -EPERM; | ||
975 | goto exit; | ||
976 | } | ||
977 | |||
978 | dev_dbg(dev, "wMaxPacketSize is %d\n", max_size); | ||
979 | |||
980 | n = 0; | 1652 | n = 0; |
981 | 1653 | ||
982 | usbtmc_clear_check_status: | 1654 | usbtmc_clear_check_status: |
@@ -987,7 +1659,7 @@ usbtmc_clear_check_status: | |||
987 | usb_rcvctrlpipe(data->usb_dev, 0), | 1659 | usb_rcvctrlpipe(data->usb_dev, 0), |
988 | USBTMC_REQUEST_CHECK_CLEAR_STATUS, | 1660 | USBTMC_REQUEST_CHECK_CLEAR_STATUS, |
989 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | 1661 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, |
990 | 0, 0, buffer, 2, USBTMC_TIMEOUT); | 1662 | 0, 0, buffer, 2, USB_CTRL_GET_TIMEOUT); |
991 | if (rv < 0) { | 1663 | if (rv < 0) { |
992 | dev_err(dev, "usb_control_msg returned %d\n", rv); | 1664 | dev_err(dev, "usb_control_msg returned %d\n", rv); |
993 | goto exit; | 1665 | goto exit; |
@@ -1004,15 +1676,20 @@ usbtmc_clear_check_status: | |||
1004 | goto exit; | 1676 | goto exit; |
1005 | } | 1677 | } |
1006 | 1678 | ||
1007 | if (buffer[1] == 1) | 1679 | if ((buffer[1] & 1) != 0) { |
1008 | do { | 1680 | do { |
1009 | dev_dbg(dev, "Reading from bulk in EP\n"); | 1681 | dev_dbg(dev, "Reading from bulk in EP\n"); |
1010 | 1682 | ||
1683 | actual = 0; | ||
1011 | rv = usb_bulk_msg(data->usb_dev, | 1684 | rv = usb_bulk_msg(data->usb_dev, |
1012 | usb_rcvbulkpipe(data->usb_dev, | 1685 | usb_rcvbulkpipe(data->usb_dev, |
1013 | data->bulk_in), | 1686 | data->bulk_in), |
1014 | buffer, USBTMC_SIZE_IOBUFFER, | 1687 | buffer, USBTMC_BUFSIZE, |
1015 | &actual, USBTMC_TIMEOUT); | 1688 | &actual, USB_CTRL_GET_TIMEOUT); |
1689 | |||
1690 | print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, | ||
1691 | 16, 1, buffer, actual, true); | ||
1692 | |||
1016 | n++; | 1693 | n++; |
1017 | 1694 | ||
1018 | if (rv < 0) { | 1695 | if (rv < 0) { |
@@ -1020,10 +1697,15 @@ usbtmc_clear_check_status: | |||
1020 | rv); | 1697 | rv); |
1021 | goto exit; | 1698 | goto exit; |
1022 | } | 1699 | } |
1023 | } while ((actual == max_size) && | 1700 | } while ((actual == USBTMC_BUFSIZE) && |
1024 | (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); | 1701 | (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); |
1702 | } else { | ||
1703 | /* do not stress device with subsequent requests */ | ||
1704 | msleep(50); | ||
1705 | n++; | ||
1706 | } | ||
1025 | 1707 | ||
1026 | if (actual == max_size) { | 1708 | if (n >= USBTMC_MAX_READS_TO_CLEAR_BULK_IN) { |
1027 | dev_err(dev, "Couldn't clear device buffer within %d cycles\n", | 1709 | dev_err(dev, "Couldn't clear device buffer within %d cycles\n", |
1028 | USBTMC_MAX_READS_TO_CLEAR_BULK_IN); | 1710 | USBTMC_MAX_READS_TO_CLEAR_BULK_IN); |
1029 | rv = -EPERM; | 1711 | rv = -EPERM; |
@@ -1037,7 +1719,7 @@ usbtmc_clear_bulk_out_halt: | |||
1037 | rv = usb_clear_halt(data->usb_dev, | 1719 | rv = usb_clear_halt(data->usb_dev, |
1038 | usb_sndbulkpipe(data->usb_dev, data->bulk_out)); | 1720 | usb_sndbulkpipe(data->usb_dev, data->bulk_out)); |
1039 | if (rv < 0) { | 1721 | if (rv < 0) { |
1040 | dev_err(dev, "usb_control_msg returned %d\n", rv); | 1722 | dev_err(dev, "usb_clear_halt returned %d\n", rv); |
1041 | goto exit; | 1723 | goto exit; |
1042 | } | 1724 | } |
1043 | rv = 0; | 1725 | rv = 0; |
@@ -1054,12 +1736,9 @@ static int usbtmc_ioctl_clear_out_halt(struct usbtmc_device_data *data) | |||
1054 | rv = usb_clear_halt(data->usb_dev, | 1736 | rv = usb_clear_halt(data->usb_dev, |
1055 | usb_sndbulkpipe(data->usb_dev, data->bulk_out)); | 1737 | usb_sndbulkpipe(data->usb_dev, data->bulk_out)); |
1056 | 1738 | ||
1057 | if (rv < 0) { | 1739 | if (rv < 0) |
1058 | dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n", | 1740 | dev_err(&data->usb_dev->dev, "%s returned %d\n", __func__, rv); |
1059 | rv); | 1741 | return rv; |
1060 | return rv; | ||
1061 | } | ||
1062 | return 0; | ||
1063 | } | 1742 | } |
1064 | 1743 | ||
1065 | static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data) | 1744 | static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data) |
@@ -1069,11 +1748,33 @@ static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data) | |||
1069 | rv = usb_clear_halt(data->usb_dev, | 1748 | rv = usb_clear_halt(data->usb_dev, |
1070 | usb_rcvbulkpipe(data->usb_dev, data->bulk_in)); | 1749 | usb_rcvbulkpipe(data->usb_dev, data->bulk_in)); |
1071 | 1750 | ||
1072 | if (rv < 0) { | 1751 | if (rv < 0) |
1073 | dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n", | 1752 | dev_err(&data->usb_dev->dev, "%s returned %d\n", __func__, rv); |
1074 | rv); | 1753 | return rv; |
1075 | return rv; | 1754 | } |
1076 | } | 1755 | |
1756 | static int usbtmc_ioctl_cancel_io(struct usbtmc_file_data *file_data) | ||
1757 | { | ||
1758 | spin_lock_irq(&file_data->err_lock); | ||
1759 | file_data->in_status = -ECANCELED; | ||
1760 | file_data->out_status = -ECANCELED; | ||
1761 | spin_unlock_irq(&file_data->err_lock); | ||
1762 | usb_kill_anchored_urbs(&file_data->submitted); | ||
1763 | return 0; | ||
1764 | } | ||
1765 | |||
1766 | static int usbtmc_ioctl_cleanup_io(struct usbtmc_file_data *file_data) | ||
1767 | { | ||
1768 | usb_kill_anchored_urbs(&file_data->submitted); | ||
1769 | usb_scuttle_anchored_urbs(&file_data->in_anchor); | ||
1770 | spin_lock_irq(&file_data->err_lock); | ||
1771 | file_data->in_status = 0; | ||
1772 | file_data->in_transfer_size = 0; | ||
1773 | file_data->out_status = 0; | ||
1774 | file_data->out_transfer_size = 0; | ||
1775 | spin_unlock_irq(&file_data->err_lock); | ||
1776 | |||
1777 | file_data->in_urbs_used = 0; | ||
1077 | return 0; | 1778 | return 0; |
1078 | } | 1779 | } |
1079 | 1780 | ||
@@ -1090,7 +1791,7 @@ static int get_capabilities(struct usbtmc_device_data *data) | |||
1090 | rv = usb_control_msg(data->usb_dev, usb_rcvctrlpipe(data->usb_dev, 0), | 1791 | rv = usb_control_msg(data->usb_dev, usb_rcvctrlpipe(data->usb_dev, 0), |
1091 | USBTMC_REQUEST_GET_CAPABILITIES, | 1792 | USBTMC_REQUEST_GET_CAPABILITIES, |
1092 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | 1793 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, |
1093 | 0, 0, buffer, 0x18, USBTMC_TIMEOUT); | 1794 | 0, 0, buffer, 0x18, USB_CTRL_GET_TIMEOUT); |
1094 | if (rv < 0) { | 1795 | if (rv < 0) { |
1095 | dev_err(dev, "usb_control_msg returned %d\n", rv); | 1796 | dev_err(dev, "usb_control_msg returned %d\n", rv); |
1096 | goto err_out; | 1797 | goto err_out; |
@@ -1147,72 +1848,6 @@ static const struct attribute_group capability_attr_grp = { | |||
1147 | .attrs = capability_attrs, | 1848 | .attrs = capability_attrs, |
1148 | }; | 1849 | }; |
1149 | 1850 | ||
1150 | static ssize_t TermChar_show(struct device *dev, | ||
1151 | struct device_attribute *attr, char *buf) | ||
1152 | { | ||
1153 | struct usb_interface *intf = to_usb_interface(dev); | ||
1154 | struct usbtmc_device_data *data = usb_get_intfdata(intf); | ||
1155 | |||
1156 | return sprintf(buf, "%c\n", data->TermChar); | ||
1157 | } | ||
1158 | |||
1159 | static ssize_t TermChar_store(struct device *dev, | ||
1160 | struct device_attribute *attr, | ||
1161 | const char *buf, size_t count) | ||
1162 | { | ||
1163 | struct usb_interface *intf = to_usb_interface(dev); | ||
1164 | struct usbtmc_device_data *data = usb_get_intfdata(intf); | ||
1165 | |||
1166 | if (count < 1) | ||
1167 | return -EINVAL; | ||
1168 | data->TermChar = buf[0]; | ||
1169 | return count; | ||
1170 | } | ||
1171 | static DEVICE_ATTR_RW(TermChar); | ||
1172 | |||
1173 | #define data_attribute(name) \ | ||
1174 | static ssize_t name##_show(struct device *dev, \ | ||
1175 | struct device_attribute *attr, char *buf) \ | ||
1176 | { \ | ||
1177 | struct usb_interface *intf = to_usb_interface(dev); \ | ||
1178 | struct usbtmc_device_data *data = usb_get_intfdata(intf); \ | ||
1179 | \ | ||
1180 | return sprintf(buf, "%d\n", data->name); \ | ||
1181 | } \ | ||
1182 | static ssize_t name##_store(struct device *dev, \ | ||
1183 | struct device_attribute *attr, \ | ||
1184 | const char *buf, size_t count) \ | ||
1185 | { \ | ||
1186 | struct usb_interface *intf = to_usb_interface(dev); \ | ||
1187 | struct usbtmc_device_data *data = usb_get_intfdata(intf); \ | ||
1188 | ssize_t result; \ | ||
1189 | unsigned val; \ | ||
1190 | \ | ||
1191 | result = sscanf(buf, "%u\n", &val); \ | ||
1192 | if (result != 1) \ | ||
1193 | result = -EINVAL; \ | ||
1194 | data->name = val; \ | ||
1195 | if (result < 0) \ | ||
1196 | return result; \ | ||
1197 | else \ | ||
1198 | return count; \ | ||
1199 | } \ | ||
1200 | static DEVICE_ATTR_RW(name) | ||
1201 | |||
1202 | data_attribute(TermCharEnabled); | ||
1203 | data_attribute(auto_abort); | ||
1204 | |||
1205 | static struct attribute *data_attrs[] = { | ||
1206 | &dev_attr_TermChar.attr, | ||
1207 | &dev_attr_TermCharEnabled.attr, | ||
1208 | &dev_attr_auto_abort.attr, | ||
1209 | NULL, | ||
1210 | }; | ||
1211 | |||
1212 | static const struct attribute_group data_attr_grp = { | ||
1213 | .attrs = data_attrs, | ||
1214 | }; | ||
1215 | |||
1216 | static int usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data) | 1851 | static int usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data) |
1217 | { | 1852 | { |
1218 | struct device *dev; | 1853 | struct device *dev; |
@@ -1229,7 +1864,7 @@ static int usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data) | |||
1229 | usb_rcvctrlpipe(data->usb_dev, 0), | 1864 | usb_rcvctrlpipe(data->usb_dev, 0), |
1230 | USBTMC_REQUEST_INDICATOR_PULSE, | 1865 | USBTMC_REQUEST_INDICATOR_PULSE, |
1231 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | 1866 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, |
1232 | 0, 0, buffer, 0x01, USBTMC_TIMEOUT); | 1867 | 0, 0, buffer, 0x01, USB_CTRL_GET_TIMEOUT); |
1233 | 1868 | ||
1234 | if (rv < 0) { | 1869 | if (rv < 0) { |
1235 | dev_err(dev, "usb_control_msg returned %d\n", rv); | 1870 | dev_err(dev, "usb_control_msg returned %d\n", rv); |
@@ -1250,6 +1885,63 @@ exit: | |||
1250 | return rv; | 1885 | return rv; |
1251 | } | 1886 | } |
1252 | 1887 | ||
1888 | static int usbtmc_ioctl_request(struct usbtmc_device_data *data, | ||
1889 | void __user *arg) | ||
1890 | { | ||
1891 | struct device *dev = &data->intf->dev; | ||
1892 | struct usbtmc_ctrlrequest request; | ||
1893 | u8 *buffer = NULL; | ||
1894 | int rv; | ||
1895 | unsigned long res; | ||
1896 | |||
1897 | res = copy_from_user(&request, arg, sizeof(struct usbtmc_ctrlrequest)); | ||
1898 | if (res) | ||
1899 | return -EFAULT; | ||
1900 | |||
1901 | if (request.req.wLength > USBTMC_BUFSIZE) | ||
1902 | return -EMSGSIZE; | ||
1903 | |||
1904 | if (request.req.wLength) { | ||
1905 | buffer = kmalloc(request.req.wLength, GFP_KERNEL); | ||
1906 | if (!buffer) | ||
1907 | return -ENOMEM; | ||
1908 | |||
1909 | if ((request.req.bRequestType & USB_DIR_IN) == 0) { | ||
1910 | /* Send control data to device */ | ||
1911 | res = copy_from_user(buffer, request.data, | ||
1912 | request.req.wLength); | ||
1913 | if (res) { | ||
1914 | rv = -EFAULT; | ||
1915 | goto exit; | ||
1916 | } | ||
1917 | } | ||
1918 | } | ||
1919 | |||
1920 | rv = usb_control_msg(data->usb_dev, | ||
1921 | usb_rcvctrlpipe(data->usb_dev, 0), | ||
1922 | request.req.bRequest, | ||
1923 | request.req.bRequestType, | ||
1924 | request.req.wValue, | ||
1925 | request.req.wIndex, | ||
1926 | buffer, request.req.wLength, USB_CTRL_GET_TIMEOUT); | ||
1927 | |||
1928 | if (rv < 0) { | ||
1929 | dev_err(dev, "%s failed %d\n", __func__, rv); | ||
1930 | goto exit; | ||
1931 | } | ||
1932 | |||
1933 | if (rv && (request.req.bRequestType & USB_DIR_IN)) { | ||
1934 | /* Read control data from device */ | ||
1935 | res = copy_to_user(request.data, buffer, rv); | ||
1936 | if (res) | ||
1937 | rv = -EFAULT; | ||
1938 | } | ||
1939 | |||
1940 | exit: | ||
1941 | kfree(buffer); | ||
1942 | return rv; | ||
1943 | } | ||
1944 | |||
1253 | /* | 1945 | /* |
1254 | * Get the usb timeout value | 1946 | * Get the usb timeout value |
1255 | */ | 1947 | */ |
@@ -1331,6 +2023,7 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
1331 | struct usbtmc_file_data *file_data; | 2023 | struct usbtmc_file_data *file_data; |
1332 | struct usbtmc_device_data *data; | 2024 | struct usbtmc_device_data *data; |
1333 | int retval = -EBADRQC; | 2025 | int retval = -EBADRQC; |
2026 | __u8 tmp_byte; | ||
1334 | 2027 | ||
1335 | file_data = file->private_data; | 2028 | file_data = file->private_data; |
1336 | data = file_data->data; | 2029 | data = file_data->data; |
@@ -1366,6 +2059,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
1366 | retval = usbtmc_ioctl_abort_bulk_in(data); | 2059 | retval = usbtmc_ioctl_abort_bulk_in(data); |
1367 | break; | 2060 | break; |
1368 | 2061 | ||
2062 | case USBTMC_IOCTL_CTRL_REQUEST: | ||
2063 | retval = usbtmc_ioctl_request(data, (void __user *)arg); | ||
2064 | break; | ||
2065 | |||
1369 | case USBTMC_IOCTL_GET_TIMEOUT: | 2066 | case USBTMC_IOCTL_GET_TIMEOUT: |
1370 | retval = usbtmc_ioctl_get_timeout(file_data, | 2067 | retval = usbtmc_ioctl_get_timeout(file_data, |
1371 | (void __user *)arg); | 2068 | (void __user *)arg); |
@@ -1386,12 +2083,29 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
1386 | (void __user *)arg); | 2083 | (void __user *)arg); |
1387 | break; | 2084 | break; |
1388 | 2085 | ||
2086 | case USBTMC_IOCTL_WRITE: | ||
2087 | retval = usbtmc_ioctl_generic_write(file_data, | ||
2088 | (void __user *)arg); | ||
2089 | break; | ||
2090 | |||
2091 | case USBTMC_IOCTL_READ: | ||
2092 | retval = usbtmc_ioctl_generic_read(file_data, | ||
2093 | (void __user *)arg); | ||
2094 | break; | ||
2095 | |||
2096 | case USBTMC_IOCTL_WRITE_RESULT: | ||
2097 | retval = usbtmc_ioctl_write_result(file_data, | ||
2098 | (void __user *)arg); | ||
2099 | break; | ||
2100 | |||
2101 | case USBTMC_IOCTL_API_VERSION: | ||
2102 | retval = put_user(USBTMC_API_VERSION, | ||
2103 | (__u32 __user *)arg); | ||
2104 | break; | ||
2105 | |||
1389 | case USBTMC488_IOCTL_GET_CAPS: | 2106 | case USBTMC488_IOCTL_GET_CAPS: |
1390 | retval = copy_to_user((void __user *)arg, | 2107 | retval = put_user(data->usb488_caps, |
1391 | &data->usb488_caps, | 2108 | (unsigned char __user *)arg); |
1392 | sizeof(data->usb488_caps)); | ||
1393 | if (retval) | ||
1394 | retval = -EFAULT; | ||
1395 | break; | 2109 | break; |
1396 | 2110 | ||
1397 | case USBTMC488_IOCTL_READ_STB: | 2111 | case USBTMC488_IOCTL_READ_STB: |
@@ -1417,6 +2131,30 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
1417 | case USBTMC488_IOCTL_TRIGGER: | 2131 | case USBTMC488_IOCTL_TRIGGER: |
1418 | retval = usbtmc488_ioctl_trigger(file_data); | 2132 | retval = usbtmc488_ioctl_trigger(file_data); |
1419 | break; | 2133 | break; |
2134 | |||
2135 | case USBTMC488_IOCTL_WAIT_SRQ: | ||
2136 | retval = usbtmc488_ioctl_wait_srq(file_data, | ||
2137 | (__u32 __user *)arg); | ||
2138 | break; | ||
2139 | |||
2140 | case USBTMC_IOCTL_MSG_IN_ATTR: | ||
2141 | retval = put_user(file_data->bmTransferAttributes, | ||
2142 | (__u8 __user *)arg); | ||
2143 | break; | ||
2144 | |||
2145 | case USBTMC_IOCTL_AUTO_ABORT: | ||
2146 | retval = get_user(tmp_byte, (unsigned char __user *)arg); | ||
2147 | if (retval == 0) | ||
2148 | file_data->auto_abort = !!tmp_byte; | ||
2149 | break; | ||
2150 | |||
2151 | case USBTMC_IOCTL_CANCEL_IO: | ||
2152 | retval = usbtmc_ioctl_cancel_io(file_data); | ||
2153 | break; | ||
2154 | |||
2155 | case USBTMC_IOCTL_CLEANUP_IO: | ||
2156 | retval = usbtmc_ioctl_cleanup_io(file_data); | ||
2157 | break; | ||
1420 | } | 2158 | } |
1421 | 2159 | ||
1422 | skip_io_on_zombie: | 2160 | skip_io_on_zombie: |
@@ -1446,7 +2184,28 @@ static __poll_t usbtmc_poll(struct file *file, poll_table *wait) | |||
1446 | 2184 | ||
1447 | poll_wait(file, &data->waitq, wait); | 2185 | poll_wait(file, &data->waitq, wait); |
1448 | 2186 | ||
1449 | mask = (atomic_read(&file_data->srq_asserted)) ? EPOLLPRI : 0; | 2187 | /* Note that EPOLLPRI is now assigned to SRQ, and |
2188 | * EPOLLIN|EPOLLRDNORM to normal read data. | ||
2189 | */ | ||
2190 | mask = 0; | ||
2191 | if (atomic_read(&file_data->srq_asserted)) | ||
2192 | mask |= EPOLLPRI; | ||
2193 | |||
2194 | /* Note that the anchor submitted includes all urbs for BULK IN | ||
2195 | * and OUT. So EPOLLOUT is signaled when BULK OUT is empty and | ||
2196 | * all BULK IN urbs are completed and moved to in_anchor. | ||
2197 | */ | ||
2198 | if (usb_anchor_empty(&file_data->submitted)) | ||
2199 | mask |= (EPOLLOUT | EPOLLWRNORM); | ||
2200 | if (!usb_anchor_empty(&file_data->in_anchor)) | ||
2201 | mask |= (EPOLLIN | EPOLLRDNORM); | ||
2202 | |||
2203 | spin_lock_irq(&file_data->err_lock); | ||
2204 | if (file_data->in_status || file_data->out_status) | ||
2205 | mask |= EPOLLERR; | ||
2206 | spin_unlock_irq(&file_data->err_lock); | ||
2207 | |||
2208 | dev_dbg(&data->intf->dev, "poll mask = %x\n", mask); | ||
1450 | 2209 | ||
1451 | no_poll: | 2210 | no_poll: |
1452 | mutex_unlock(&data->io_mutex); | 2211 | mutex_unlock(&data->io_mutex); |
@@ -1459,6 +2218,7 @@ static const struct file_operations fops = { | |||
1459 | .write = usbtmc_write, | 2218 | .write = usbtmc_write, |
1460 | .open = usbtmc_open, | 2219 | .open = usbtmc_open, |
1461 | .release = usbtmc_release, | 2220 | .release = usbtmc_release, |
2221 | .flush = usbtmc_flush, | ||
1462 | .unlocked_ioctl = usbtmc_ioctl, | 2222 | .unlocked_ioctl = usbtmc_ioctl, |
1463 | #ifdef CONFIG_COMPAT | 2223 | #ifdef CONFIG_COMPAT |
1464 | .compat_ioctl = usbtmc_ioctl, | 2224 | .compat_ioctl = usbtmc_ioctl, |
@@ -1552,7 +2312,9 @@ static void usbtmc_free_int(struct usbtmc_device_data *data) | |||
1552 | return; | 2312 | return; |
1553 | usb_kill_urb(data->iin_urb); | 2313 | usb_kill_urb(data->iin_urb); |
1554 | kfree(data->iin_buffer); | 2314 | kfree(data->iin_buffer); |
2315 | data->iin_buffer = NULL; | ||
1555 | usb_free_urb(data->iin_urb); | 2316 | usb_free_urb(data->iin_urb); |
2317 | data->iin_urb = NULL; | ||
1556 | kref_put(&data->kref, usbtmc_delete); | 2318 | kref_put(&data->kref, usbtmc_delete); |
1557 | } | 2319 | } |
1558 | 2320 | ||
@@ -1585,8 +2347,6 @@ static int usbtmc_probe(struct usb_interface *intf, | |||
1585 | 2347 | ||
1586 | /* Initialize USBTMC bTag and other fields */ | 2348 | /* Initialize USBTMC bTag and other fields */ |
1587 | data->bTag = 1; | 2349 | data->bTag = 1; |
1588 | data->TermCharEnabled = 0; | ||
1589 | data->TermChar = '\n'; | ||
1590 | /* 2 <= bTag <= 127 USBTMC-USB488 subclass specification 4.3.1 */ | 2350 | /* 2 <= bTag <= 127 USBTMC-USB488 subclass specification 4.3.1 */ |
1591 | data->iin_bTag = 2; | 2351 | data->iin_bTag = 2; |
1592 | 2352 | ||
@@ -1603,6 +2363,7 @@ static int usbtmc_probe(struct usb_interface *intf, | |||
1603 | } | 2363 | } |
1604 | 2364 | ||
1605 | data->bulk_in = bulk_in->bEndpointAddress; | 2365 | data->bulk_in = bulk_in->bEndpointAddress; |
2366 | data->wMaxPacketSize = usb_endpoint_maxp(bulk_in); | ||
1606 | dev_dbg(&intf->dev, "Found bulk in endpoint at %u\n", data->bulk_in); | 2367 | dev_dbg(&intf->dev, "Found bulk in endpoint at %u\n", data->bulk_in); |
1607 | 2368 | ||
1608 | data->bulk_out = bulk_out->bEndpointAddress; | 2369 | data->bulk_out = bulk_out->bEndpointAddress; |
@@ -1659,12 +2420,10 @@ static int usbtmc_probe(struct usb_interface *intf, | |||
1659 | } | 2420 | } |
1660 | } | 2421 | } |
1661 | 2422 | ||
1662 | retcode = sysfs_create_group(&intf->dev.kobj, &data_attr_grp); | ||
1663 | |||
1664 | retcode = usb_register_dev(intf, &usbtmc_class); | 2423 | retcode = usb_register_dev(intf, &usbtmc_class); |
1665 | if (retcode) { | 2424 | if (retcode) { |
1666 | dev_err(&intf->dev, "Not able to get a minor" | 2425 | dev_err(&intf->dev, "Not able to get a minor (base %u, slice default): %d\n", |
1667 | " (base %u, slice default): %d\n", USBTMC_MINOR_BASE, | 2426 | USBTMC_MINOR_BASE, |
1668 | retcode); | 2427 | retcode); |
1669 | goto error_register; | 2428 | goto error_register; |
1670 | } | 2429 | } |
@@ -1674,7 +2433,6 @@ static int usbtmc_probe(struct usb_interface *intf, | |||
1674 | 2433 | ||
1675 | error_register: | 2434 | error_register: |
1676 | sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); | 2435 | sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); |
1677 | sysfs_remove_group(&intf->dev.kobj, &data_attr_grp); | ||
1678 | usbtmc_free_int(data); | 2436 | usbtmc_free_int(data); |
1679 | err_put: | 2437 | err_put: |
1680 | kref_put(&data->kref, usbtmc_delete); | 2438 | kref_put(&data->kref, usbtmc_delete); |
@@ -1684,26 +2442,103 @@ err_put: | |||
1684 | static void usbtmc_disconnect(struct usb_interface *intf) | 2442 | static void usbtmc_disconnect(struct usb_interface *intf) |
1685 | { | 2443 | { |
1686 | struct usbtmc_device_data *data = usb_get_intfdata(intf); | 2444 | struct usbtmc_device_data *data = usb_get_intfdata(intf); |
2445 | struct list_head *elem; | ||
1687 | 2446 | ||
1688 | usb_deregister_dev(intf, &usbtmc_class); | 2447 | usb_deregister_dev(intf, &usbtmc_class); |
1689 | sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); | 2448 | sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); |
1690 | sysfs_remove_group(&intf->dev.kobj, &data_attr_grp); | ||
1691 | mutex_lock(&data->io_mutex); | 2449 | mutex_lock(&data->io_mutex); |
1692 | data->zombie = 1; | 2450 | data->zombie = 1; |
1693 | wake_up_interruptible_all(&data->waitq); | 2451 | wake_up_interruptible_all(&data->waitq); |
2452 | list_for_each(elem, &data->file_list) { | ||
2453 | struct usbtmc_file_data *file_data; | ||
2454 | |||
2455 | file_data = list_entry(elem, | ||
2456 | struct usbtmc_file_data, | ||
2457 | file_elem); | ||
2458 | usb_kill_anchored_urbs(&file_data->submitted); | ||
2459 | usb_scuttle_anchored_urbs(&file_data->in_anchor); | ||
2460 | } | ||
1694 | mutex_unlock(&data->io_mutex); | 2461 | mutex_unlock(&data->io_mutex); |
1695 | usbtmc_free_int(data); | 2462 | usbtmc_free_int(data); |
1696 | kref_put(&data->kref, usbtmc_delete); | 2463 | kref_put(&data->kref, usbtmc_delete); |
1697 | } | 2464 | } |
1698 | 2465 | ||
2466 | static void usbtmc_draw_down(struct usbtmc_file_data *file_data) | ||
2467 | { | ||
2468 | int time; | ||
2469 | |||
2470 | time = usb_wait_anchor_empty_timeout(&file_data->submitted, 1000); | ||
2471 | if (!time) | ||
2472 | usb_kill_anchored_urbs(&file_data->submitted); | ||
2473 | usb_scuttle_anchored_urbs(&file_data->in_anchor); | ||
2474 | } | ||
2475 | |||
1699 | static int usbtmc_suspend(struct usb_interface *intf, pm_message_t message) | 2476 | static int usbtmc_suspend(struct usb_interface *intf, pm_message_t message) |
1700 | { | 2477 | { |
1701 | /* this driver does not have pending URBs */ | 2478 | struct usbtmc_device_data *data = usb_get_intfdata(intf); |
2479 | struct list_head *elem; | ||
2480 | |||
2481 | if (!data) | ||
2482 | return 0; | ||
2483 | |||
2484 | mutex_lock(&data->io_mutex); | ||
2485 | list_for_each(elem, &data->file_list) { | ||
2486 | struct usbtmc_file_data *file_data; | ||
2487 | |||
2488 | file_data = list_entry(elem, | ||
2489 | struct usbtmc_file_data, | ||
2490 | file_elem); | ||
2491 | usbtmc_draw_down(file_data); | ||
2492 | } | ||
2493 | |||
2494 | if (data->iin_ep_present && data->iin_urb) | ||
2495 | usb_kill_urb(data->iin_urb); | ||
2496 | |||
2497 | mutex_unlock(&data->io_mutex); | ||
1702 | return 0; | 2498 | return 0; |
1703 | } | 2499 | } |
1704 | 2500 | ||
1705 | static int usbtmc_resume(struct usb_interface *intf) | 2501 | static int usbtmc_resume(struct usb_interface *intf) |
1706 | { | 2502 | { |
2503 | struct usbtmc_device_data *data = usb_get_intfdata(intf); | ||
2504 | int retcode = 0; | ||
2505 | |||
2506 | if (data->iin_ep_present && data->iin_urb) | ||
2507 | retcode = usb_submit_urb(data->iin_urb, GFP_KERNEL); | ||
2508 | if (retcode) | ||
2509 | dev_err(&intf->dev, "Failed to submit iin_urb\n"); | ||
2510 | |||
2511 | return retcode; | ||
2512 | } | ||
2513 | |||
2514 | static int usbtmc_pre_reset(struct usb_interface *intf) | ||
2515 | { | ||
2516 | struct usbtmc_device_data *data = usb_get_intfdata(intf); | ||
2517 | struct list_head *elem; | ||
2518 | |||
2519 | if (!data) | ||
2520 | return 0; | ||
2521 | |||
2522 | mutex_lock(&data->io_mutex); | ||
2523 | |||
2524 | list_for_each(elem, &data->file_list) { | ||
2525 | struct usbtmc_file_data *file_data; | ||
2526 | |||
2527 | file_data = list_entry(elem, | ||
2528 | struct usbtmc_file_data, | ||
2529 | file_elem); | ||
2530 | usbtmc_ioctl_cancel_io(file_data); | ||
2531 | } | ||
2532 | |||
2533 | return 0; | ||
2534 | } | ||
2535 | |||
2536 | static int usbtmc_post_reset(struct usb_interface *intf) | ||
2537 | { | ||
2538 | struct usbtmc_device_data *data = usb_get_intfdata(intf); | ||
2539 | |||
2540 | mutex_unlock(&data->io_mutex); | ||
2541 | |||
1707 | return 0; | 2542 | return 0; |
1708 | } | 2543 | } |
1709 | 2544 | ||
@@ -1714,6 +2549,8 @@ static struct usb_driver usbtmc_driver = { | |||
1714 | .disconnect = usbtmc_disconnect, | 2549 | .disconnect = usbtmc_disconnect, |
1715 | .suspend = usbtmc_suspend, | 2550 | .suspend = usbtmc_suspend, |
1716 | .resume = usbtmc_resume, | 2551 | .resume = usbtmc_resume, |
2552 | .pre_reset = usbtmc_pre_reset, | ||
2553 | .post_reset = usbtmc_post_reset, | ||
1717 | }; | 2554 | }; |
1718 | 2555 | ||
1719 | module_usb_driver(usbtmc_driver); | 2556 | module_usb_driver(usbtmc_driver); |
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index 77eef8acff94..f641342cdec0 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c | |||
@@ -101,12 +101,8 @@ void hcd_buffer_destroy(struct usb_hcd *hcd) | |||
101 | return; | 101 | return; |
102 | 102 | ||
103 | for (i = 0; i < HCD_BUFFER_POOLS; i++) { | 103 | for (i = 0; i < HCD_BUFFER_POOLS; i++) { |
104 | struct dma_pool *pool = hcd->pool[i]; | 104 | dma_pool_destroy(hcd->pool[i]); |
105 | 105 | hcd->pool[i] = NULL; | |
106 | if (pool) { | ||
107 | dma_pool_destroy(pool); | ||
108 | hcd->pool[i] = NULL; | ||
109 | } | ||
110 | } | 106 | } |
111 | } | 107 | } |
112 | 108 | ||
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index a1f225f077cd..53564386ed57 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c | |||
@@ -510,7 +510,6 @@ int usb_driver_claim_interface(struct usb_driver *driver, | |||
510 | struct usb_interface *iface, void *priv) | 510 | struct usb_interface *iface, void *priv) |
511 | { | 511 | { |
512 | struct device *dev; | 512 | struct device *dev; |
513 | struct usb_device *udev; | ||
514 | int retval = 0; | 513 | int retval = 0; |
515 | 514 | ||
516 | if (!iface) | 515 | if (!iface) |
@@ -524,8 +523,6 @@ int usb_driver_claim_interface(struct usb_driver *driver, | |||
524 | if (!iface->authorized) | 523 | if (!iface->authorized) |
525 | return -ENODEV; | 524 | return -ENODEV; |
526 | 525 | ||
527 | udev = interface_to_usbdev(iface); | ||
528 | |||
529 | dev->driver = &driver->drvwrap.driver; | 526 | dev->driver = &driver->drvwrap.driver; |
530 | usb_set_intfdata(iface, priv); | 527 | usb_set_intfdata(iface, priv); |
531 | iface->needs_binding = 0; | 528 | iface->needs_binding = 0; |
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index bc8242bc4564..356b05c82dbc 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c | |||
@@ -21,6 +21,7 @@ | |||
21 | 21 | ||
22 | #include <linux/usb.h> | 22 | #include <linux/usb.h> |
23 | #include <linux/usb/hcd.h> | 23 | #include <linux/usb/hcd.h> |
24 | #include <uapi/linux/usb/audio.h> | ||
24 | #include "usb.h" | 25 | #include "usb.h" |
25 | 26 | ||
26 | static inline const char *plural(int n) | 27 | static inline const char *plural(int n) |
@@ -42,6 +43,16 @@ static int is_activesync(struct usb_interface_descriptor *desc) | |||
42 | && desc->bInterfaceProtocol == 1; | 43 | && desc->bInterfaceProtocol == 1; |
43 | } | 44 | } |
44 | 45 | ||
46 | static bool is_audio(struct usb_interface_descriptor *desc) | ||
47 | { | ||
48 | return desc->bInterfaceClass == USB_CLASS_AUDIO; | ||
49 | } | ||
50 | |||
51 | static bool is_uac3_config(struct usb_interface_descriptor *desc) | ||
52 | { | ||
53 | return desc->bInterfaceProtocol == UAC_VERSION_3; | ||
54 | } | ||
55 | |||
45 | int usb_choose_configuration(struct usb_device *udev) | 56 | int usb_choose_configuration(struct usb_device *udev) |
46 | { | 57 | { |
47 | int i; | 58 | int i; |
@@ -121,6 +132,22 @@ int usb_choose_configuration(struct usb_device *udev) | |||
121 | #endif | 132 | #endif |
122 | } | 133 | } |
123 | 134 | ||
135 | /* | ||
136 | * Select first configuration as default for audio so that | ||
137 | * devices that don't comply with UAC3 protocol are supported. | ||
138 | * But, still iterate through other configurations and | ||
139 | * select UAC3 compliant config if present. | ||
140 | */ | ||
141 | if (i == 0 && num_configs > 1 && desc && is_audio(desc)) { | ||
142 | best = c; | ||
143 | continue; | ||
144 | } | ||
145 | |||
146 | if (i > 0 && desc && is_audio(desc) && is_uac3_config(desc)) { | ||
147 | best = c; | ||
148 | break; | ||
149 | } | ||
150 | |||
124 | /* From the remaining configs, choose the first one whose | 151 | /* From the remaining configs, choose the first one whose |
125 | * first interface is for a non-vendor-specific class. | 152 | * first interface is for a non-vendor-specific class. |
126 | * Reason: Linux is more likely to have a class driver | 153 | * Reason: Linux is more likely to have a class driver |
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 1c21955fe7c0..487025d31d44 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
@@ -1738,7 +1738,6 @@ static void __usb_hcd_giveback_urb(struct urb *urb) | |||
1738 | struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); | 1738 | struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); |
1739 | struct usb_anchor *anchor = urb->anchor; | 1739 | struct usb_anchor *anchor = urb->anchor; |
1740 | int status = urb->unlinked; | 1740 | int status = urb->unlinked; |
1741 | unsigned long flags; | ||
1742 | 1741 | ||
1743 | urb->hcpriv = NULL; | 1742 | urb->hcpriv = NULL; |
1744 | if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && | 1743 | if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && |
@@ -1755,20 +1754,7 @@ static void __usb_hcd_giveback_urb(struct urb *urb) | |||
1755 | 1754 | ||
1756 | /* pass ownership to the completion handler */ | 1755 | /* pass ownership to the completion handler */ |
1757 | urb->status = status; | 1756 | urb->status = status; |
1758 | |||
1759 | /* | ||
1760 | * We disable local IRQs here avoid possible deadlock because | ||
1761 | * drivers may call spin_lock() to hold lock which might be | ||
1762 | * acquired in one hard interrupt handler. | ||
1763 | * | ||
1764 | * The local_irq_save()/local_irq_restore() around complete() | ||
1765 | * will be removed if current USB drivers have been cleaned up | ||
1766 | * and no one may trigger the above deadlock situation when | ||
1767 | * running complete() in tasklet. | ||
1768 | */ | ||
1769 | local_irq_save(flags); | ||
1770 | urb->complete(urb); | 1757 | urb->complete(urb); |
1771 | local_irq_restore(flags); | ||
1772 | 1758 | ||
1773 | usb_anchor_resume_wakeups(anchor); | 1759 | usb_anchor_resume_wakeups(anchor); |
1774 | atomic_dec(&urb->use_count); | 1760 | atomic_dec(&urb->use_count); |
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 462ce49f683a..c6077d582d29 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/mutex.h> | 28 | #include <linux/mutex.h> |
29 | #include <linux/random.h> | 29 | #include <linux/random.h> |
30 | #include <linux/pm_qos.h> | 30 | #include <linux/pm_qos.h> |
31 | #include <linux/kobject.h> | ||
31 | 32 | ||
32 | #include <linux/uaccess.h> | 33 | #include <linux/uaccess.h> |
33 | #include <asm/byteorder.h> | 34 | #include <asm/byteorder.h> |
@@ -2660,11 +2661,13 @@ static bool use_new_scheme(struct usb_device *udev, int retry, | |||
2660 | { | 2661 | { |
2661 | int old_scheme_first_port = | 2662 | int old_scheme_first_port = |
2662 | port_dev->quirks & USB_PORT_QUIRK_OLD_SCHEME; | 2663 | port_dev->quirks & USB_PORT_QUIRK_OLD_SCHEME; |
2664 | int quick_enumeration = (udev->speed == USB_SPEED_HIGH); | ||
2663 | 2665 | ||
2664 | if (udev->speed >= USB_SPEED_SUPER) | 2666 | if (udev->speed >= USB_SPEED_SUPER) |
2665 | return false; | 2667 | return false; |
2666 | 2668 | ||
2667 | return USE_NEW_SCHEME(retry, old_scheme_first_port || old_scheme_first); | 2669 | return USE_NEW_SCHEME(retry, old_scheme_first_port || old_scheme_first |
2670 | || quick_enumeration); | ||
2668 | } | 2671 | } |
2669 | 2672 | ||
2670 | /* Is a USB 3.0 port in the Inactive or Compliance Mode state? | 2673 | /* Is a USB 3.0 port in the Inactive or Compliance Mode state? |
@@ -5147,6 +5150,42 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, | |||
5147 | usb_lock_port(port_dev); | 5150 | usb_lock_port(port_dev); |
5148 | } | 5151 | } |
5149 | 5152 | ||
5153 | /* Handle notifying userspace about hub over-current events */ | ||
5154 | static void port_over_current_notify(struct usb_port *port_dev) | ||
5155 | { | ||
5156 | static char *envp[] = { NULL, NULL, NULL }; | ||
5157 | struct device *hub_dev; | ||
5158 | char *port_dev_path; | ||
5159 | |||
5160 | sysfs_notify(&port_dev->dev.kobj, NULL, "over_current_count"); | ||
5161 | |||
5162 | hub_dev = port_dev->dev.parent; | ||
5163 | |||
5164 | if (!hub_dev) | ||
5165 | return; | ||
5166 | |||
5167 | port_dev_path = kobject_get_path(&port_dev->dev.kobj, GFP_KERNEL); | ||
5168 | if (!port_dev_path) | ||
5169 | return; | ||
5170 | |||
5171 | envp[0] = kasprintf(GFP_KERNEL, "OVER_CURRENT_PORT=%s", port_dev_path); | ||
5172 | if (!envp[0]) | ||
5173 | goto exit_path; | ||
5174 | |||
5175 | envp[1] = kasprintf(GFP_KERNEL, "OVER_CURRENT_COUNT=%u", | ||
5176 | port_dev->over_current_count); | ||
5177 | if (!envp[1]) | ||
5178 | goto exit; | ||
5179 | |||
5180 | kobject_uevent_env(&hub_dev->kobj, KOBJ_CHANGE, envp); | ||
5181 | |||
5182 | kfree(envp[1]); | ||
5183 | exit: | ||
5184 | kfree(envp[0]); | ||
5185 | exit_path: | ||
5186 | kfree(port_dev_path); | ||
5187 | } | ||
5188 | |||
5150 | static void port_event(struct usb_hub *hub, int port1) | 5189 | static void port_event(struct usb_hub *hub, int port1) |
5151 | __must_hold(&port_dev->status_lock) | 5190 | __must_hold(&port_dev->status_lock) |
5152 | { | 5191 | { |
@@ -5189,6 +5228,7 @@ static void port_event(struct usb_hub *hub, int port1) | |||
5189 | if (portchange & USB_PORT_STAT_C_OVERCURRENT) { | 5228 | if (portchange & USB_PORT_STAT_C_OVERCURRENT) { |
5190 | u16 status = 0, unused; | 5229 | u16 status = 0, unused; |
5191 | port_dev->over_current_count++; | 5230 | port_dev->over_current_count++; |
5231 | port_over_current_notify(port_dev); | ||
5192 | 5232 | ||
5193 | dev_dbg(&port_dev->dev, "over-current change #%u\n", | 5233 | dev_dbg(&port_dev->dev, "over-current change #%u\n", |
5194 | port_dev->over_current_count); | 5234 | port_dev->over_current_count); |
diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c index 9879767452a2..38b2c776c4b4 100644 --- a/drivers/usb/core/phy.c +++ b/drivers/usb/core/phy.c | |||
@@ -23,10 +23,11 @@ static int usb_phy_roothub_add_phy(struct device *dev, int index, | |||
23 | struct list_head *list) | 23 | struct list_head *list) |
24 | { | 24 | { |
25 | struct usb_phy_roothub *roothub_entry; | 25 | struct usb_phy_roothub *roothub_entry; |
26 | struct phy *phy = devm_of_phy_get_by_index(dev, dev->of_node, index); | 26 | struct phy *phy; |
27 | 27 | ||
28 | if (IS_ERR_OR_NULL(phy)) { | 28 | phy = devm_of_phy_get_by_index(dev, dev->of_node, index); |
29 | if (!phy || PTR_ERR(phy) == -ENODEV) | 29 | if (IS_ERR(phy)) { |
30 | if (PTR_ERR(phy) == -ENODEV) | ||
30 | return 0; | 31 | return 0; |
31 | else | 32 | else |
32 | return PTR_ERR(phy); | 33 | return PTR_ERR(phy); |
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 4a2143195395..1a06a4b5fbb1 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c | |||
@@ -16,6 +16,15 @@ static int usb_port_block_power_off; | |||
16 | 16 | ||
17 | static const struct attribute_group *port_dev_group[]; | 17 | static const struct attribute_group *port_dev_group[]; |
18 | 18 | ||
19 | static ssize_t location_show(struct device *dev, | ||
20 | struct device_attribute *attr, char *buf) | ||
21 | { | ||
22 | struct usb_port *port_dev = to_usb_port(dev); | ||
23 | |||
24 | return sprintf(buf, "0x%08x\n", port_dev->location); | ||
25 | } | ||
26 | static DEVICE_ATTR_RO(location); | ||
27 | |||
19 | static ssize_t connect_type_show(struct device *dev, | 28 | static ssize_t connect_type_show(struct device *dev, |
20 | struct device_attribute *attr, char *buf) | 29 | struct device_attribute *attr, char *buf) |
21 | { | 30 | { |
@@ -140,6 +149,7 @@ static DEVICE_ATTR_RW(usb3_lpm_permit); | |||
140 | 149 | ||
141 | static struct attribute *port_dev_attrs[] = { | 150 | static struct attribute *port_dev_attrs[] = { |
142 | &dev_attr_connect_type.attr, | 151 | &dev_attr_connect_type.attr, |
152 | &dev_attr_location.attr, | ||
143 | &dev_attr_quirks.attr, | 153 | &dev_attr_quirks.attr, |
144 | &dev_attr_over_current_count.attr, | 154 | &dev_attr_over_current_count.attr, |
145 | NULL, | 155 | NULL, |
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index cc9c93affa14..30bab8463c96 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h | |||
@@ -393,6 +393,20 @@ enum dwc2_ep0_state { | |||
393 | * 0 - No | 393 | * 0 - No |
394 | * 1 - Yes | 394 | * 1 - Yes |
395 | * @hird_threshold: Value of BESL or HIRD Threshold. | 395 | * @hird_threshold: Value of BESL or HIRD Threshold. |
396 | * @ref_clk_per: Indicates in terms of pico seconds the period | ||
397 | * of ref_clk. | ||
398 | * 62500 - 16MHz | ||
399 | * 58823 - 17MHz | ||
400 | * 52083 - 19.2MHz | ||
401 | * 50000 - 20MHz | ||
402 | * 41666 - 24MHz | ||
403 | * 33333 - 30MHz (default) | ||
404 | * 25000 - 40MHz | ||
405 | * @sof_cnt_wkup_alert: Indicates in term of number of SOF's after which | ||
406 | * the controller should generate an interrupt if the | ||
407 | * device had been in L1 state until that period. | ||
408 | * This is used by SW to initiate Remote WakeUp in the | ||
409 | * controller so as to sync to the uF number from the host. | ||
396 | * @activate_stm_fs_transceiver: Activate internal transceiver using GGPIO | 410 | * @activate_stm_fs_transceiver: Activate internal transceiver using GGPIO |
397 | * register. | 411 | * register. |
398 | * 0 - Deactivate the transceiver (default) | 412 | * 0 - Deactivate the transceiver (default) |
@@ -416,6 +430,9 @@ enum dwc2_ep0_state { | |||
416 | * back to DWC2_SPEED_PARAM_HIGH while device is gone. | 430 | * back to DWC2_SPEED_PARAM_HIGH while device is gone. |
417 | * 0 - No (default) | 431 | * 0 - No (default) |
418 | * 1 - Yes | 432 | * 1 - Yes |
433 | * @service_interval: Enable service interval based scheduling. | ||
434 | * 0 - No | ||
435 | * 1 - Yes | ||
419 | * | 436 | * |
420 | * The following parameters may be specified when starting the module. These | 437 | * The following parameters may be specified when starting the module. These |
421 | * parameters define how the DWC_otg controller should be configured. A | 438 | * parameters define how the DWC_otg controller should be configured. A |
@@ -461,6 +478,7 @@ struct dwc2_core_params { | |||
461 | bool lpm_clock_gating; | 478 | bool lpm_clock_gating; |
462 | bool besl; | 479 | bool besl; |
463 | bool hird_threshold_en; | 480 | bool hird_threshold_en; |
481 | bool service_interval; | ||
464 | u8 hird_threshold; | 482 | u8 hird_threshold; |
465 | bool activate_stm_fs_transceiver; | 483 | bool activate_stm_fs_transceiver; |
466 | bool ipg_isoc_en; | 484 | bool ipg_isoc_en; |
@@ -468,6 +486,10 @@ struct dwc2_core_params { | |||
468 | u32 max_transfer_size; | 486 | u32 max_transfer_size; |
469 | u32 ahbcfg; | 487 | u32 ahbcfg; |
470 | 488 | ||
489 | /* GREFCLK parameters */ | ||
490 | u32 ref_clk_per; | ||
491 | u16 sof_cnt_wkup_alert; | ||
492 | |||
471 | /* Host parameters */ | 493 | /* Host parameters */ |
472 | bool host_dma; | 494 | bool host_dma; |
473 | bool dma_desc_enable; | 495 | bool dma_desc_enable; |
@@ -605,6 +627,10 @@ struct dwc2_core_params { | |||
605 | * FIFO sizing is enabled 16 to 32768 | 627 | * FIFO sizing is enabled 16 to 32768 |
606 | * Actual maximum value is autodetected and also | 628 | * Actual maximum value is autodetected and also |
607 | * the default. | 629 | * the default. |
630 | * @service_interval_mode: For enabling service interval based scheduling in the | ||
631 | * controller. | ||
632 | * 0 - Disable | ||
633 | * 1 - Enable | ||
608 | */ | 634 | */ |
609 | struct dwc2_hw_params { | 635 | struct dwc2_hw_params { |
610 | unsigned op_mode:3; | 636 | unsigned op_mode:3; |
@@ -635,6 +661,7 @@ struct dwc2_hw_params { | |||
635 | unsigned utmi_phy_data_width:2; | 661 | unsigned utmi_phy_data_width:2; |
636 | unsigned lpm_mode:1; | 662 | unsigned lpm_mode:1; |
637 | unsigned ipg_isoc_en:1; | 663 | unsigned ipg_isoc_en:1; |
664 | unsigned service_interval_mode:1; | ||
638 | u32 snpsid; | 665 | u32 snpsid; |
639 | u32 dev_ep_dirs; | 666 | u32 dev_ep_dirs; |
640 | u32 g_tx_fifo_size[MAX_EPS_CHANNELS]; | 667 | u32 g_tx_fifo_size[MAX_EPS_CHANNELS]; |
@@ -1354,6 +1381,7 @@ int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg); | |||
1354 | int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg); | 1381 | int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg); |
1355 | int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg); | 1382 | int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg); |
1356 | void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg); | 1383 | void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg); |
1384 | void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg); | ||
1357 | #else | 1385 | #else |
1358 | static inline int dwc2_hsotg_remove(struct dwc2_hsotg *dwc2) | 1386 | static inline int dwc2_hsotg_remove(struct dwc2_hsotg *dwc2) |
1359 | { return 0; } | 1387 | { return 0; } |
@@ -1388,6 +1416,7 @@ static inline int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg) | |||
1388 | static inline int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg) | 1416 | static inline int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg) |
1389 | { return 0; } | 1417 | { return 0; } |
1390 | static inline void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) {} | 1418 | static inline void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) {} |
1419 | static inline void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg) {} | ||
1391 | #endif | 1420 | #endif |
1392 | 1421 | ||
1393 | #if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) | 1422 | #if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) |
diff --git a/drivers/usb/dwc2/debugfs.c b/drivers/usb/dwc2/debugfs.c index 22d015b0424f..7f62f4cdc265 100644 --- a/drivers/usb/dwc2/debugfs.c +++ b/drivers/usb/dwc2/debugfs.c | |||
@@ -701,6 +701,7 @@ static int params_show(struct seq_file *seq, void *v) | |||
701 | print_param(seq, p, besl); | 701 | print_param(seq, p, besl); |
702 | print_param(seq, p, hird_threshold_en); | 702 | print_param(seq, p, hird_threshold_en); |
703 | print_param(seq, p, hird_threshold); | 703 | print_param(seq, p, hird_threshold); |
704 | print_param(seq, p, service_interval); | ||
704 | print_param(seq, p, host_dma); | 705 | print_param(seq, p, host_dma); |
705 | print_param(seq, p, g_dma); | 706 | print_param(seq, p, g_dma); |
706 | print_param(seq, p, g_dma_desc); | 707 | print_param(seq, p, g_dma_desc); |
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 220c0f9b89b0..2d6d2c8244de 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c | |||
@@ -123,6 +123,24 @@ static inline void dwc2_gadget_incr_frame_num(struct dwc2_hsotg_ep *hs_ep) | |||
123 | } | 123 | } |
124 | 124 | ||
125 | /** | 125 | /** |
126 | * dwc2_gadget_dec_frame_num_by_one - Decrements the targeted frame number | ||
127 | * by one. | ||
128 | * @hs_ep: The endpoint. | ||
129 | * | ||
130 | * This function used in service interval based scheduling flow to calculate | ||
131 | * descriptor frame number filed value. For service interval mode frame | ||
132 | * number in descriptor should point to last (u)frame in the interval. | ||
133 | * | ||
134 | */ | ||
135 | static inline void dwc2_gadget_dec_frame_num_by_one(struct dwc2_hsotg_ep *hs_ep) | ||
136 | { | ||
137 | if (hs_ep->target_frame) | ||
138 | hs_ep->target_frame -= 1; | ||
139 | else | ||
140 | hs_ep->target_frame = DSTS_SOFFN_LIMIT; | ||
141 | } | ||
142 | |||
143 | /** | ||
126 | * dwc2_hsotg_en_gsint - enable one or more of the general interrupt | 144 | * dwc2_hsotg_en_gsint - enable one or more of the general interrupt |
127 | * @hsotg: The device state | 145 | * @hsotg: The device state |
128 | * @ints: A bitmask of the interrupts to enable | 146 | * @ints: A bitmask of the interrupts to enable |
@@ -228,6 +246,27 @@ int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg) | |||
228 | } | 246 | } |
229 | 247 | ||
230 | /** | 248 | /** |
249 | * dwc2_gadget_wkup_alert_handler - Handler for WKUP_ALERT interrupt | ||
250 | * | ||
251 | * @hsotg: Programming view of the DWC_otg controller | ||
252 | * | ||
253 | */ | ||
254 | static void dwc2_gadget_wkup_alert_handler(struct dwc2_hsotg *hsotg) | ||
255 | { | ||
256 | u32 gintsts2; | ||
257 | u32 gintmsk2; | ||
258 | |||
259 | gintsts2 = dwc2_readl(hsotg, GINTSTS2); | ||
260 | gintmsk2 = dwc2_readl(hsotg, GINTMSK2); | ||
261 | |||
262 | if (gintsts2 & GINTSTS2_WKUP_ALERT_INT) { | ||
263 | dev_dbg(hsotg->dev, "%s: Wkup_Alert_Int\n", __func__); | ||
264 | dwc2_clear_bit(hsotg, GINTSTS2, GINTSTS2_WKUP_ALERT_INT); | ||
265 | dwc2_set_bit(hsotg, DCFG, DCTL_RMTWKUPSIG); | ||
266 | } | ||
267 | } | ||
268 | |||
269 | /** | ||
231 | * dwc2_hsotg_tx_fifo_average_depth - returns average depth of device mode | 270 | * dwc2_hsotg_tx_fifo_average_depth - returns average depth of device mode |
232 | * TX FIFOs | 271 | * TX FIFOs |
233 | * | 272 | * |
@@ -2812,6 +2851,23 @@ static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep) | |||
2812 | if (using_desc_dma(hsotg)) { | 2851 | if (using_desc_dma(hsotg)) { |
2813 | hs_ep->target_frame = hsotg->frame_number; | 2852 | hs_ep->target_frame = hsotg->frame_number; |
2814 | dwc2_gadget_incr_frame_num(hs_ep); | 2853 | dwc2_gadget_incr_frame_num(hs_ep); |
2854 | |||
2855 | /* In service interval mode target_frame must | ||
2856 | * be set to last (u)frame of the service interval. | ||
2857 | */ | ||
2858 | if (hsotg->params.service_interval) { | ||
2859 | /* Set target_frame to the first (u)frame of | ||
2860 | * the service interval | ||
2861 | */ | ||
2862 | hs_ep->target_frame &= ~hs_ep->interval + 1; | ||
2863 | |||
2864 | /* Set target_frame to the last (u)frame of | ||
2865 | * the service interval | ||
2866 | */ | ||
2867 | dwc2_gadget_incr_frame_num(hs_ep); | ||
2868 | dwc2_gadget_dec_frame_num_by_one(hs_ep); | ||
2869 | } | ||
2870 | |||
2815 | dwc2_gadget_start_isoc_ddma(hs_ep); | 2871 | dwc2_gadget_start_isoc_ddma(hs_ep); |
2816 | return; | 2872 | return; |
2817 | } | 2873 | } |
@@ -3109,6 +3165,8 @@ static void kill_all_requests(struct dwc2_hsotg *hsotg, | |||
3109 | dwc2_hsotg_txfifo_flush(hsotg, ep->fifo_index); | 3165 | dwc2_hsotg_txfifo_flush(hsotg, ep->fifo_index); |
3110 | } | 3166 | } |
3111 | 3167 | ||
3168 | static int dwc2_hsotg_ep_disable(struct usb_ep *ep); | ||
3169 | |||
3112 | /** | 3170 | /** |
3113 | * dwc2_hsotg_disconnect - disconnect service | 3171 | * dwc2_hsotg_disconnect - disconnect service |
3114 | * @hsotg: The device state. | 3172 | * @hsotg: The device state. |
@@ -3127,13 +3185,12 @@ void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg) | |||
3127 | hsotg->connected = 0; | 3185 | hsotg->connected = 0; |
3128 | hsotg->test_mode = 0; | 3186 | hsotg->test_mode = 0; |
3129 | 3187 | ||
3188 | /* all endpoints should be shutdown */ | ||
3130 | for (ep = 0; ep < hsotg->num_of_eps; ep++) { | 3189 | for (ep = 0; ep < hsotg->num_of_eps; ep++) { |
3131 | if (hsotg->eps_in[ep]) | 3190 | if (hsotg->eps_in[ep]) |
3132 | kill_all_requests(hsotg, hsotg->eps_in[ep], | 3191 | dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); |
3133 | -ESHUTDOWN); | ||
3134 | if (hsotg->eps_out[ep]) | 3192 | if (hsotg->eps_out[ep]) |
3135 | kill_all_requests(hsotg, hsotg->eps_out[ep], | 3193 | dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); |
3136 | -ESHUTDOWN); | ||
3137 | } | 3194 | } |
3138 | 3195 | ||
3139 | call_gadget(hsotg, disconnect); | 3196 | call_gadget(hsotg, disconnect); |
@@ -3191,13 +3248,23 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, | |||
3191 | u32 val; | 3248 | u32 val; |
3192 | u32 usbcfg; | 3249 | u32 usbcfg; |
3193 | u32 dcfg = 0; | 3250 | u32 dcfg = 0; |
3251 | int ep; | ||
3194 | 3252 | ||
3195 | /* Kill any ep0 requests as controller will be reinitialized */ | 3253 | /* Kill any ep0 requests as controller will be reinitialized */ |
3196 | kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); | 3254 | kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); |
3197 | 3255 | ||
3198 | if (!is_usb_reset) | 3256 | if (!is_usb_reset) { |
3199 | if (dwc2_core_reset(hsotg, true)) | 3257 | if (dwc2_core_reset(hsotg, true)) |
3200 | return; | 3258 | return; |
3259 | } else { | ||
3260 | /* all endpoints should be shutdown */ | ||
3261 | for (ep = 1; ep < hsotg->num_of_eps; ep++) { | ||
3262 | if (hsotg->eps_in[ep]) | ||
3263 | dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); | ||
3264 | if (hsotg->eps_out[ep]) | ||
3265 | dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); | ||
3266 | } | ||
3267 | } | ||
3201 | 3268 | ||
3202 | /* | 3269 | /* |
3203 | * we must now enable ep0 ready for host detection and then | 3270 | * we must now enable ep0 ready for host detection and then |
@@ -3312,6 +3379,10 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, | |||
3312 | dwc2_set_bit(hsotg, DIEPMSK, DIEPMSK_BNAININTRMSK); | 3379 | dwc2_set_bit(hsotg, DIEPMSK, DIEPMSK_BNAININTRMSK); |
3313 | } | 3380 | } |
3314 | 3381 | ||
3382 | /* Enable Service Interval mode if supported */ | ||
3383 | if (using_desc_dma(hsotg) && hsotg->params.service_interval) | ||
3384 | dwc2_set_bit(hsotg, DCTL, DCTL_SERVICE_INTERVAL_SUPPORTED); | ||
3385 | |||
3315 | dwc2_writel(hsotg, 0, DAINTMSK); | 3386 | dwc2_writel(hsotg, 0, DAINTMSK); |
3316 | 3387 | ||
3317 | dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", | 3388 | dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", |
@@ -3368,6 +3439,10 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, | |||
3368 | /* configure the core to support LPM */ | 3439 | /* configure the core to support LPM */ |
3369 | dwc2_gadget_init_lpm(hsotg); | 3440 | dwc2_gadget_init_lpm(hsotg); |
3370 | 3441 | ||
3442 | /* program GREFCLK register if needed */ | ||
3443 | if (using_desc_dma(hsotg) && hsotg->params.service_interval) | ||
3444 | dwc2_gadget_program_ref_clk(hsotg); | ||
3445 | |||
3371 | /* must be at-least 3ms to allow bus to see disconnect */ | 3446 | /* must be at-least 3ms to allow bus to see disconnect */ |
3372 | mdelay(3); | 3447 | mdelay(3); |
3373 | 3448 | ||
@@ -3676,6 +3751,10 @@ irq_retry: | |||
3676 | if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) | 3751 | if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) |
3677 | goto irq_retry; | 3752 | goto irq_retry; |
3678 | 3753 | ||
3754 | /* Check WKUP_ALERT interrupt*/ | ||
3755 | if (hsotg->params.service_interval) | ||
3756 | dwc2_gadget_wkup_alert_handler(hsotg); | ||
3757 | |||
3679 | spin_unlock(&hsotg->lock); | 3758 | spin_unlock(&hsotg->lock); |
3680 | 3759 | ||
3681 | return IRQ_HANDLED; | 3760 | return IRQ_HANDLED; |
@@ -3993,6 +4072,7 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep) | |||
3993 | unsigned long flags; | 4072 | unsigned long flags; |
3994 | u32 epctrl_reg; | 4073 | u32 epctrl_reg; |
3995 | u32 ctrl; | 4074 | u32 ctrl; |
4075 | int locked; | ||
3996 | 4076 | ||
3997 | dev_dbg(hsotg->dev, "%s(ep %p)\n", __func__, ep); | 4077 | dev_dbg(hsotg->dev, "%s(ep %p)\n", __func__, ep); |
3998 | 4078 | ||
@@ -4008,7 +4088,9 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep) | |||
4008 | 4088 | ||
4009 | epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); | 4089 | epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); |
4010 | 4090 | ||
4011 | spin_lock_irqsave(&hsotg->lock, flags); | 4091 | locked = spin_is_locked(&hsotg->lock); |
4092 | if (!locked) | ||
4093 | spin_lock_irqsave(&hsotg->lock, flags); | ||
4012 | 4094 | ||
4013 | ctrl = dwc2_readl(hsotg, epctrl_reg); | 4095 | ctrl = dwc2_readl(hsotg, epctrl_reg); |
4014 | 4096 | ||
@@ -4032,7 +4114,9 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep) | |||
4032 | hs_ep->fifo_index = 0; | 4114 | hs_ep->fifo_index = 0; |
4033 | hs_ep->fifo_size = 0; | 4115 | hs_ep->fifo_size = 0; |
4034 | 4116 | ||
4035 | spin_unlock_irqrestore(&hsotg->lock, flags); | 4117 | if (!locked) |
4118 | spin_unlock_irqrestore(&hsotg->lock, flags); | ||
4119 | |||
4036 | return 0; | 4120 | return 0; |
4037 | } | 4121 | } |
4038 | 4122 | ||
@@ -4944,6 +5028,29 @@ void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) | |||
4944 | val |= hsotg->params.besl ? GLPMCFG_ENBESL : 0; | 5028 | val |= hsotg->params.besl ? GLPMCFG_ENBESL : 0; |
4945 | dwc2_writel(hsotg, val, GLPMCFG); | 5029 | dwc2_writel(hsotg, val, GLPMCFG); |
4946 | dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg, GLPMCFG)); | 5030 | dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg, GLPMCFG)); |
5031 | |||
5032 | /* Unmask WKUP_ALERT Interrupt */ | ||
5033 | if (hsotg->params.service_interval) | ||
5034 | dwc2_set_bit(hsotg, GINTMSK2, GINTMSK2_WKUP_ALERT_INT_MSK); | ||
5035 | } | ||
5036 | |||
5037 | /** | ||
5038 | * dwc2_gadget_program_ref_clk - Program GREFCLK register in device mode | ||
5039 | * | ||
5040 | * @hsotg: Programming view of DWC_otg controller | ||
5041 | * | ||
5042 | */ | ||
5043 | void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg) | ||
5044 | { | ||
5045 | u32 val = 0; | ||
5046 | |||
5047 | val |= GREFCLK_REF_CLK_MODE; | ||
5048 | val |= hsotg->params.ref_clk_per << GREFCLK_REFCLKPER_SHIFT; | ||
5049 | val |= hsotg->params.sof_cnt_wkup_alert << | ||
5050 | GREFCLK_SOF_CNT_WKUP_ALERT_SHIFT; | ||
5051 | |||
5052 | dwc2_writel(hsotg, val, GREFCLK); | ||
5053 | dev_dbg(hsotg->dev, "GREFCLK=0x%08x\n", dwc2_readl(hsotg, GREFCLK)); | ||
4947 | } | 5054 | } |
4948 | 5055 | ||
4949 | /** | 5056 | /** |
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 2bd6e6bfc241..dd82fa516f3f 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c | |||
@@ -358,16 +358,10 @@ static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg) | |||
358 | 358 | ||
359 | static int dwc2_vbus_supply_init(struct dwc2_hsotg *hsotg) | 359 | static int dwc2_vbus_supply_init(struct dwc2_hsotg *hsotg) |
360 | { | 360 | { |
361 | int ret; | 361 | if (hsotg->vbus_supply) |
362 | 362 | return regulator_enable(hsotg->vbus_supply); | |
363 | hsotg->vbus_supply = devm_regulator_get_optional(hsotg->dev, "vbus"); | ||
364 | if (IS_ERR(hsotg->vbus_supply)) { | ||
365 | ret = PTR_ERR(hsotg->vbus_supply); | ||
366 | hsotg->vbus_supply = NULL; | ||
367 | return ret == -ENODEV ? 0 : ret; | ||
368 | } | ||
369 | 363 | ||
370 | return regulator_enable(hsotg->vbus_supply); | 364 | return 0; |
371 | } | 365 | } |
372 | 366 | ||
373 | static int dwc2_vbus_supply_exit(struct dwc2_hsotg *hsotg) | 367 | static int dwc2_vbus_supply_exit(struct dwc2_hsotg *hsotg) |
@@ -1328,14 +1322,11 @@ static void dwc2_hc_write_packet(struct dwc2_hsotg *hsotg, | |||
1328 | u32 remaining_count; | 1322 | u32 remaining_count; |
1329 | u32 byte_count; | 1323 | u32 byte_count; |
1330 | u32 dword_count; | 1324 | u32 dword_count; |
1331 | u32 __iomem *data_fifo; | ||
1332 | u32 *data_buf = (u32 *)chan->xfer_buf; | 1325 | u32 *data_buf = (u32 *)chan->xfer_buf; |
1333 | 1326 | ||
1334 | if (dbg_hc(chan)) | 1327 | if (dbg_hc(chan)) |
1335 | dev_vdbg(hsotg->dev, "%s()\n", __func__); | 1328 | dev_vdbg(hsotg->dev, "%s()\n", __func__); |
1336 | 1329 | ||
1337 | data_fifo = (u32 __iomem *)(hsotg->regs + HCFIFO(chan->hc_num)); | ||
1338 | |||
1339 | remaining_count = chan->xfer_len - chan->xfer_count; | 1330 | remaining_count = chan->xfer_len - chan->xfer_count; |
1340 | if (remaining_count > chan->max_packet) | 1331 | if (remaining_count > chan->max_packet) |
1341 | byte_count = chan->max_packet; | 1332 | byte_count = chan->max_packet; |
@@ -3564,6 +3555,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, | |||
3564 | u32 port_status; | 3555 | u32 port_status; |
3565 | u32 speed; | 3556 | u32 speed; |
3566 | u32 pcgctl; | 3557 | u32 pcgctl; |
3558 | u32 pwr; | ||
3567 | 3559 | ||
3568 | switch (typereq) { | 3560 | switch (typereq) { |
3569 | case ClearHubFeature: | 3561 | case ClearHubFeature: |
@@ -3612,8 +3604,11 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, | |||
3612 | dev_dbg(hsotg->dev, | 3604 | dev_dbg(hsotg->dev, |
3613 | "ClearPortFeature USB_PORT_FEAT_POWER\n"); | 3605 | "ClearPortFeature USB_PORT_FEAT_POWER\n"); |
3614 | hprt0 = dwc2_read_hprt0(hsotg); | 3606 | hprt0 = dwc2_read_hprt0(hsotg); |
3607 | pwr = hprt0 & HPRT0_PWR; | ||
3615 | hprt0 &= ~HPRT0_PWR; | 3608 | hprt0 &= ~HPRT0_PWR; |
3616 | dwc2_writel(hsotg, hprt0, HPRT0); | 3609 | dwc2_writel(hsotg, hprt0, HPRT0); |
3610 | if (pwr) | ||
3611 | dwc2_vbus_supply_exit(hsotg); | ||
3617 | break; | 3612 | break; |
3618 | 3613 | ||
3619 | case USB_PORT_FEAT_INDICATOR: | 3614 | case USB_PORT_FEAT_INDICATOR: |
@@ -3823,8 +3818,11 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, | |||
3823 | dev_dbg(hsotg->dev, | 3818 | dev_dbg(hsotg->dev, |
3824 | "SetPortFeature - USB_PORT_FEAT_POWER\n"); | 3819 | "SetPortFeature - USB_PORT_FEAT_POWER\n"); |
3825 | hprt0 = dwc2_read_hprt0(hsotg); | 3820 | hprt0 = dwc2_read_hprt0(hsotg); |
3821 | pwr = hprt0 & HPRT0_PWR; | ||
3826 | hprt0 |= HPRT0_PWR; | 3822 | hprt0 |= HPRT0_PWR; |
3827 | dwc2_writel(hsotg, hprt0, HPRT0); | 3823 | dwc2_writel(hsotg, hprt0, HPRT0); |
3824 | if (!pwr) | ||
3825 | dwc2_vbus_supply_init(hsotg); | ||
3828 | break; | 3826 | break; |
3829 | 3827 | ||
3830 | case USB_PORT_FEAT_RESET: | 3828 | case USB_PORT_FEAT_RESET: |
@@ -3841,6 +3839,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, | |||
3841 | dwc2_writel(hsotg, 0, PCGCTL); | 3839 | dwc2_writel(hsotg, 0, PCGCTL); |
3842 | 3840 | ||
3843 | hprt0 = dwc2_read_hprt0(hsotg); | 3841 | hprt0 = dwc2_read_hprt0(hsotg); |
3842 | pwr = hprt0 & HPRT0_PWR; | ||
3844 | /* Clear suspend bit if resetting from suspend state */ | 3843 | /* Clear suspend bit if resetting from suspend state */ |
3845 | hprt0 &= ~HPRT0_SUSP; | 3844 | hprt0 &= ~HPRT0_SUSP; |
3846 | 3845 | ||
@@ -3854,6 +3853,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, | |||
3854 | dev_dbg(hsotg->dev, | 3853 | dev_dbg(hsotg->dev, |
3855 | "In host mode, hprt0=%08x\n", hprt0); | 3854 | "In host mode, hprt0=%08x\n", hprt0); |
3856 | dwc2_writel(hsotg, hprt0, HPRT0); | 3855 | dwc2_writel(hsotg, hprt0, HPRT0); |
3856 | if (!pwr) | ||
3857 | dwc2_vbus_supply_init(hsotg); | ||
3857 | } | 3858 | } |
3858 | 3859 | ||
3859 | /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */ | 3860 | /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */ |
@@ -4393,6 +4394,8 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd) | |||
4393 | struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); | 4394 | struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); |
4394 | struct usb_bus *bus = hcd_to_bus(hcd); | 4395 | struct usb_bus *bus = hcd_to_bus(hcd); |
4395 | unsigned long flags; | 4396 | unsigned long flags; |
4397 | u32 hprt0; | ||
4398 | int ret; | ||
4396 | 4399 | ||
4397 | dev_dbg(hsotg->dev, "DWC OTG HCD START\n"); | 4400 | dev_dbg(hsotg->dev, "DWC OTG HCD START\n"); |
4398 | 4401 | ||
@@ -4408,6 +4411,17 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd) | |||
4408 | 4411 | ||
4409 | dwc2_hcd_reinit(hsotg); | 4412 | dwc2_hcd_reinit(hsotg); |
4410 | 4413 | ||
4414 | hprt0 = dwc2_read_hprt0(hsotg); | ||
4415 | /* Has vbus power been turned on in dwc2_core_host_init ? */ | ||
4416 | if (hprt0 & HPRT0_PWR) { | ||
4417 | /* Enable external vbus supply before resuming root hub */ | ||
4418 | spin_unlock_irqrestore(&hsotg->lock, flags); | ||
4419 | ret = dwc2_vbus_supply_init(hsotg); | ||
4420 | if (ret) | ||
4421 | return ret; | ||
4422 | spin_lock_irqsave(&hsotg->lock, flags); | ||
4423 | } | ||
4424 | |||
4411 | /* Initialize and connect root hub if one is not already attached */ | 4425 | /* Initialize and connect root hub if one is not already attached */ |
4412 | if (bus->root_hub) { | 4426 | if (bus->root_hub) { |
4413 | dev_dbg(hsotg->dev, "DWC OTG HCD Has Root Hub\n"); | 4427 | dev_dbg(hsotg->dev, "DWC OTG HCD Has Root Hub\n"); |
@@ -4417,7 +4431,7 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd) | |||
4417 | 4431 | ||
4418 | spin_unlock_irqrestore(&hsotg->lock, flags); | 4432 | spin_unlock_irqrestore(&hsotg->lock, flags); |
4419 | 4433 | ||
4420 | return dwc2_vbus_supply_init(hsotg); | 4434 | return 0; |
4421 | } | 4435 | } |
4422 | 4436 | ||
4423 | /* | 4437 | /* |
@@ -4428,6 +4442,7 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd) | |||
4428 | { | 4442 | { |
4429 | struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); | 4443 | struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); |
4430 | unsigned long flags; | 4444 | unsigned long flags; |
4445 | u32 hprt0; | ||
4431 | 4446 | ||
4432 | /* Turn off all host-specific interrupts */ | 4447 | /* Turn off all host-specific interrupts */ |
4433 | dwc2_disable_host_interrupts(hsotg); | 4448 | dwc2_disable_host_interrupts(hsotg); |
@@ -4436,6 +4451,7 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd) | |||
4436 | synchronize_irq(hcd->irq); | 4451 | synchronize_irq(hcd->irq); |
4437 | 4452 | ||
4438 | spin_lock_irqsave(&hsotg->lock, flags); | 4453 | spin_lock_irqsave(&hsotg->lock, flags); |
4454 | hprt0 = dwc2_read_hprt0(hsotg); | ||
4439 | /* Ensure hcd is disconnected */ | 4455 | /* Ensure hcd is disconnected */ |
4440 | dwc2_hcd_disconnect(hsotg, true); | 4456 | dwc2_hcd_disconnect(hsotg, true); |
4441 | dwc2_hcd_stop(hsotg); | 4457 | dwc2_hcd_stop(hsotg); |
@@ -4444,7 +4460,9 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd) | |||
4444 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | 4460 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); |
4445 | spin_unlock_irqrestore(&hsotg->lock, flags); | 4461 | spin_unlock_irqrestore(&hsotg->lock, flags); |
4446 | 4462 | ||
4447 | dwc2_vbus_supply_exit(hsotg); | 4463 | /* keep balanced supply init/exit by checking HPRT0_PWR */ |
4464 | if (hprt0 & HPRT0_PWR) | ||
4465 | dwc2_vbus_supply_exit(hsotg); | ||
4448 | 4466 | ||
4449 | usleep_range(1000, 3000); | 4467 | usleep_range(1000, 3000); |
4450 | } | 4468 | } |
@@ -4482,7 +4500,9 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd) | |||
4482 | hprt0 |= HPRT0_SUSP; | 4500 | hprt0 |= HPRT0_SUSP; |
4483 | hprt0 &= ~HPRT0_PWR; | 4501 | hprt0 &= ~HPRT0_PWR; |
4484 | dwc2_writel(hsotg, hprt0, HPRT0); | 4502 | dwc2_writel(hsotg, hprt0, HPRT0); |
4503 | spin_unlock_irqrestore(&hsotg->lock, flags); | ||
4485 | dwc2_vbus_supply_exit(hsotg); | 4504 | dwc2_vbus_supply_exit(hsotg); |
4505 | spin_lock_irqsave(&hsotg->lock, flags); | ||
4486 | } | 4506 | } |
4487 | 4507 | ||
4488 | /* Enter partial_power_down */ | 4508 | /* Enter partial_power_down */ |
diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h index 0ca8e7bc7aaf..2b1ea441b7d4 100644 --- a/drivers/usb/dwc2/hw.h +++ b/drivers/usb/dwc2/hw.h | |||
@@ -312,6 +312,7 @@ | |||
312 | #define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT 14 | 312 | #define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT 14 |
313 | #define GHWCFG4_ACG_SUPPORTED BIT(12) | 313 | #define GHWCFG4_ACG_SUPPORTED BIT(12) |
314 | #define GHWCFG4_IPG_ISOC_SUPPORTED BIT(11) | 314 | #define GHWCFG4_IPG_ISOC_SUPPORTED BIT(11) |
315 | #define GHWCFG4_SERVICE_INTERVAL_SUPPORTED BIT(10) | ||
315 | #define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0 | 316 | #define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0 |
316 | #define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1 | 317 | #define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1 |
317 | #define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2 | 318 | #define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2 |
@@ -404,6 +405,19 @@ | |||
404 | #define ADPCTL_PRB_DSCHRG_MASK (0x3 << 0) | 405 | #define ADPCTL_PRB_DSCHRG_MASK (0x3 << 0) |
405 | #define ADPCTL_PRB_DSCHRG_SHIFT 0 | 406 | #define ADPCTL_PRB_DSCHRG_SHIFT 0 |
406 | 407 | ||
408 | #define GREFCLK HSOTG_REG(0x0064) | ||
409 | #define GREFCLK_REFCLKPER_MASK (0x1ffff << 15) | ||
410 | #define GREFCLK_REFCLKPER_SHIFT 15 | ||
411 | #define GREFCLK_REF_CLK_MODE BIT(14) | ||
412 | #define GREFCLK_SOF_CNT_WKUP_ALERT_MASK (0x3ff) | ||
413 | #define GREFCLK_SOF_CNT_WKUP_ALERT_SHIFT 0 | ||
414 | |||
415 | #define GINTMSK2 HSOTG_REG(0x0068) | ||
416 | #define GINTMSK2_WKUP_ALERT_INT_MSK BIT(0) | ||
417 | |||
418 | #define GINTSTS2 HSOTG_REG(0x006c) | ||
419 | #define GINTSTS2_WKUP_ALERT_INT BIT(0) | ||
420 | |||
407 | #define HPTXFSIZ HSOTG_REG(0x100) | 421 | #define HPTXFSIZ HSOTG_REG(0x100) |
408 | /* Use FIFOSIZE_* constants to access this register */ | 422 | /* Use FIFOSIZE_* constants to access this register */ |
409 | 423 | ||
@@ -443,6 +457,7 @@ | |||
443 | #define DCFG_DEVSPD_FS48 3 | 457 | #define DCFG_DEVSPD_FS48 3 |
444 | 458 | ||
445 | #define DCTL HSOTG_REG(0x804) | 459 | #define DCTL HSOTG_REG(0x804) |
460 | #define DCTL_SERVICE_INTERVAL_SUPPORTED BIT(19) | ||
446 | #define DCTL_PWRONPRGDONE BIT(11) | 461 | #define DCTL_PWRONPRGDONE BIT(11) |
447 | #define DCTL_CGOUTNAK BIT(10) | 462 | #define DCTL_CGOUTNAK BIT(10) |
448 | #define DCTL_SGOUTNAK BIT(9) | 463 | #define DCTL_SGOUTNAK BIT(9) |
diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index bf7052e037d6..7c1b6938f212 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c | |||
@@ -81,6 +81,7 @@ static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg) | |||
81 | p->host_perio_tx_fifo_size = 256; | 81 | p->host_perio_tx_fifo_size = 256; |
82 | p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << | 82 | p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << |
83 | GAHBCFG_HBSTLEN_SHIFT; | 83 | GAHBCFG_HBSTLEN_SHIFT; |
84 | p->power_down = 0; | ||
84 | } | 85 | } |
85 | 86 | ||
86 | static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg) | 87 | static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg) |
@@ -299,9 +300,12 @@ static void dwc2_set_default_params(struct dwc2_hsotg *hsotg) | |||
299 | p->hird_threshold_en = true; | 300 | p->hird_threshold_en = true; |
300 | p->hird_threshold = 4; | 301 | p->hird_threshold = 4; |
301 | p->ipg_isoc_en = false; | 302 | p->ipg_isoc_en = false; |
303 | p->service_interval = false; | ||
302 | p->max_packet_count = hw->max_packet_count; | 304 | p->max_packet_count = hw->max_packet_count; |
303 | p->max_transfer_size = hw->max_transfer_size; | 305 | p->max_transfer_size = hw->max_transfer_size; |
304 | p->ahbcfg = GAHBCFG_HBSTLEN_INCR << GAHBCFG_HBSTLEN_SHIFT; | 306 | p->ahbcfg = GAHBCFG_HBSTLEN_INCR << GAHBCFG_HBSTLEN_SHIFT; |
307 | p->ref_clk_per = 33333; | ||
308 | p->sof_cnt_wkup_alert = 100; | ||
305 | 309 | ||
306 | if ((hsotg->dr_mode == USB_DR_MODE_HOST) || | 310 | if ((hsotg->dr_mode == USB_DR_MODE_HOST) || |
307 | (hsotg->dr_mode == USB_DR_MODE_OTG)) { | 311 | (hsotg->dr_mode == USB_DR_MODE_OTG)) { |
@@ -592,6 +596,7 @@ static void dwc2_check_params(struct dwc2_hsotg *hsotg) | |||
592 | CHECK_BOOL(besl, (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a)); | 596 | CHECK_BOOL(besl, (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a)); |
593 | CHECK_BOOL(hird_threshold_en, hsotg->params.lpm); | 597 | CHECK_BOOL(hird_threshold_en, hsotg->params.lpm); |
594 | CHECK_RANGE(hird_threshold, 0, hsotg->params.besl ? 12 : 7, 0); | 598 | CHECK_RANGE(hird_threshold, 0, hsotg->params.besl ? 12 : 7, 0); |
599 | CHECK_BOOL(service_interval, hw->service_interval_mode); | ||
595 | CHECK_RANGE(max_packet_count, | 600 | CHECK_RANGE(max_packet_count, |
596 | 15, hw->max_packet_count, | 601 | 15, hw->max_packet_count, |
597 | hw->max_packet_count); | 602 | hw->max_packet_count); |
@@ -780,6 +785,8 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg) | |||
780 | GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT; | 785 | GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT; |
781 | hw->acg_enable = !!(hwcfg4 & GHWCFG4_ACG_SUPPORTED); | 786 | hw->acg_enable = !!(hwcfg4 & GHWCFG4_ACG_SUPPORTED); |
782 | hw->ipg_isoc_en = !!(hwcfg4 & GHWCFG4_IPG_ISOC_SUPPORTED); | 787 | hw->ipg_isoc_en = !!(hwcfg4 & GHWCFG4_IPG_ISOC_SUPPORTED); |
788 | hw->service_interval_mode = !!(hwcfg4 & | ||
789 | GHWCFG4_SERVICE_INTERVAL_SUPPORTED); | ||
783 | 790 | ||
784 | /* fifo sizes */ | 791 | /* fifo sizes */ |
785 | hw->rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >> | 792 | hw->rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >> |
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 577642895b57..c0b64d483552 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c | |||
@@ -432,6 +432,14 @@ static int dwc2_driver_probe(struct platform_device *dev) | |||
432 | if (retval) | 432 | if (retval) |
433 | return retval; | 433 | return retval; |
434 | 434 | ||
435 | hsotg->vbus_supply = devm_regulator_get_optional(hsotg->dev, "vbus"); | ||
436 | if (IS_ERR(hsotg->vbus_supply)) { | ||
437 | retval = PTR_ERR(hsotg->vbus_supply); | ||
438 | hsotg->vbus_supply = NULL; | ||
439 | if (retval != -ENODEV) | ||
440 | return retval; | ||
441 | } | ||
442 | |||
435 | retval = dwc2_lowlevel_hw_enable(hsotg); | 443 | retval = dwc2_lowlevel_hw_enable(hsotg); |
436 | if (retval) | 444 | if (retval) |
437 | return retval; | 445 | return retval; |
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 518ead12458d..1a0404fda596 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig | |||
@@ -113,7 +113,7 @@ config USB_DWC3_ST | |||
113 | 113 | ||
114 | config USB_DWC3_QCOM | 114 | config USB_DWC3_QCOM |
115 | tristate "Qualcomm Platform" | 115 | tristate "Qualcomm Platform" |
116 | depends on ARCH_QCOM || COMPILE_TEST | 116 | depends on EXTCON && (ARCH_QCOM || COMPILE_TEST) |
117 | depends on OF | 117 | depends on OF |
118 | default USB_DWC3 | 118 | default USB_DWC3 |
119 | help | 119 | help |
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 88c80fcc39f5..becfbb87f791 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c | |||
@@ -756,7 +756,7 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc) | |||
756 | 756 | ||
757 | /* check if current dwc3 is on simulation board */ | 757 | /* check if current dwc3 is on simulation board */ |
758 | if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) { | 758 | if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) { |
759 | dev_info(dwc->dev, "Running with FPGA optmizations\n"); | 759 | dev_info(dwc->dev, "Running with FPGA optimizations\n"); |
760 | dwc->is_fpga = true; | 760 | dwc->is_fpga = true; |
761 | } | 761 | } |
762 | 762 | ||
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index a94fb1ba8f2c..cb7fcd7c0ad8 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c | |||
@@ -13,80 +13,30 @@ | |||
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
15 | #include <linux/clk.h> | 15 | #include <linux/clk.h> |
16 | #include <linux/usb/otg.h> | ||
17 | #include <linux/usb/usb_phy_generic.h> | ||
18 | #include <linux/of.h> | 16 | #include <linux/of.h> |
19 | #include <linux/of_platform.h> | 17 | #include <linux/of_platform.h> |
20 | #include <linux/regulator/consumer.h> | 18 | #include <linux/regulator/consumer.h> |
21 | 19 | ||
20 | #define DWC3_EXYNOS_MAX_CLOCKS 4 | ||
21 | |||
22 | struct dwc3_exynos_driverdata { | ||
23 | const char *clk_names[DWC3_EXYNOS_MAX_CLOCKS]; | ||
24 | int num_clks; | ||
25 | int suspend_clk_idx; | ||
26 | }; | ||
27 | |||
22 | struct dwc3_exynos { | 28 | struct dwc3_exynos { |
23 | struct platform_device *usb2_phy; | ||
24 | struct platform_device *usb3_phy; | ||
25 | struct device *dev; | 29 | struct device *dev; |
26 | 30 | ||
27 | struct clk *clk; | 31 | const char **clk_names; |
28 | struct clk *susp_clk; | 32 | struct clk *clks[DWC3_EXYNOS_MAX_CLOCKS]; |
29 | struct clk *axius_clk; | 33 | int num_clks; |
34 | int suspend_clk_idx; | ||
30 | 35 | ||
31 | struct regulator *vdd33; | 36 | struct regulator *vdd33; |
32 | struct regulator *vdd10; | 37 | struct regulator *vdd10; |
33 | }; | 38 | }; |
34 | 39 | ||
35 | static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos) | ||
36 | { | ||
37 | struct usb_phy_generic_platform_data pdata; | ||
38 | struct platform_device *pdev; | ||
39 | int ret; | ||
40 | |||
41 | memset(&pdata, 0x00, sizeof(pdata)); | ||
42 | |||
43 | pdev = platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO); | ||
44 | if (!pdev) | ||
45 | return -ENOMEM; | ||
46 | |||
47 | exynos->usb2_phy = pdev; | ||
48 | pdata.type = USB_PHY_TYPE_USB2; | ||
49 | pdata.gpio_reset = -1; | ||
50 | |||
51 | ret = platform_device_add_data(exynos->usb2_phy, &pdata, sizeof(pdata)); | ||
52 | if (ret) | ||
53 | goto err1; | ||
54 | |||
55 | pdev = platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO); | ||
56 | if (!pdev) { | ||
57 | ret = -ENOMEM; | ||
58 | goto err1; | ||
59 | } | ||
60 | |||
61 | exynos->usb3_phy = pdev; | ||
62 | pdata.type = USB_PHY_TYPE_USB3; | ||
63 | |||
64 | ret = platform_device_add_data(exynos->usb3_phy, &pdata, sizeof(pdata)); | ||
65 | if (ret) | ||
66 | goto err2; | ||
67 | |||
68 | ret = platform_device_add(exynos->usb2_phy); | ||
69 | if (ret) | ||
70 | goto err2; | ||
71 | |||
72 | ret = platform_device_add(exynos->usb3_phy); | ||
73 | if (ret) | ||
74 | goto err3; | ||
75 | |||
76 | return 0; | ||
77 | |||
78 | err3: | ||
79 | platform_device_del(exynos->usb2_phy); | ||
80 | |||
81 | err2: | ||
82 | platform_device_put(exynos->usb3_phy); | ||
83 | |||
84 | err1: | ||
85 | platform_device_put(exynos->usb2_phy); | ||
86 | |||
87 | return ret; | ||
88 | } | ||
89 | |||
90 | static int dwc3_exynos_remove_child(struct device *dev, void *unused) | 40 | static int dwc3_exynos_remove_child(struct device *dev, void *unused) |
91 | { | 41 | { |
92 | struct platform_device *pdev = to_platform_device(dev); | 42 | struct platform_device *pdev = to_platform_device(dev); |
@@ -101,47 +51,42 @@ static int dwc3_exynos_probe(struct platform_device *pdev) | |||
101 | struct dwc3_exynos *exynos; | 51 | struct dwc3_exynos *exynos; |
102 | struct device *dev = &pdev->dev; | 52 | struct device *dev = &pdev->dev; |
103 | struct device_node *node = dev->of_node; | 53 | struct device_node *node = dev->of_node; |
104 | 54 | const struct dwc3_exynos_driverdata *driver_data; | |
105 | int ret; | 55 | int i, ret; |
106 | 56 | ||
107 | exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL); | 57 | exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL); |
108 | if (!exynos) | 58 | if (!exynos) |
109 | return -ENOMEM; | 59 | return -ENOMEM; |
110 | 60 | ||
111 | platform_set_drvdata(pdev, exynos); | 61 | driver_data = of_device_get_match_data(dev); |
62 | exynos->dev = dev; | ||
63 | exynos->num_clks = driver_data->num_clks; | ||
64 | exynos->clk_names = (const char **)driver_data->clk_names; | ||
65 | exynos->suspend_clk_idx = driver_data->suspend_clk_idx; | ||
112 | 66 | ||
113 | exynos->dev = dev; | 67 | platform_set_drvdata(pdev, exynos); |
114 | 68 | ||
115 | exynos->clk = devm_clk_get(dev, "usbdrd30"); | 69 | for (i = 0; i < exynos->num_clks; i++) { |
116 | if (IS_ERR(exynos->clk)) { | 70 | exynos->clks[i] = devm_clk_get(dev, exynos->clk_names[i]); |
117 | dev_err(dev, "couldn't get clock\n"); | 71 | if (IS_ERR(exynos->clks[i])) { |
118 | return -EINVAL; | 72 | dev_err(dev, "failed to get clock: %s\n", |
73 | exynos->clk_names[i]); | ||
74 | return PTR_ERR(exynos->clks[i]); | ||
75 | } | ||
119 | } | 76 | } |
120 | ret = clk_prepare_enable(exynos->clk); | ||
121 | if (ret) | ||
122 | return ret; | ||
123 | 77 | ||
124 | exynos->susp_clk = devm_clk_get(dev, "usbdrd30_susp_clk"); | 78 | for (i = 0; i < exynos->num_clks; i++) { |
125 | if (IS_ERR(exynos->susp_clk)) | 79 | ret = clk_prepare_enable(exynos->clks[i]); |
126 | exynos->susp_clk = NULL; | 80 | if (ret) { |
127 | ret = clk_prepare_enable(exynos->susp_clk); | 81 | while (--i > 0) |
128 | if (ret) | 82 | clk_disable_unprepare(exynos->clks[i]); |
129 | goto susp_clk_err; | 83 | return ret; |
130 | |||
131 | if (of_device_is_compatible(node, "samsung,exynos7-dwusb3")) { | ||
132 | exynos->axius_clk = devm_clk_get(dev, "usbdrd30_axius_clk"); | ||
133 | if (IS_ERR(exynos->axius_clk)) { | ||
134 | dev_err(dev, "no AXI UpScaler clk specified\n"); | ||
135 | ret = -ENODEV; | ||
136 | goto axius_clk_err; | ||
137 | } | 84 | } |
138 | ret = clk_prepare_enable(exynos->axius_clk); | ||
139 | if (ret) | ||
140 | goto axius_clk_err; | ||
141 | } else { | ||
142 | exynos->axius_clk = NULL; | ||
143 | } | 85 | } |
144 | 86 | ||
87 | if (exynos->suspend_clk_idx >= 0) | ||
88 | clk_prepare_enable(exynos->clks[exynos->suspend_clk_idx]); | ||
89 | |||
145 | exynos->vdd33 = devm_regulator_get(dev, "vdd33"); | 90 | exynos->vdd33 = devm_regulator_get(dev, "vdd33"); |
146 | if (IS_ERR(exynos->vdd33)) { | 91 | if (IS_ERR(exynos->vdd33)) { |
147 | ret = PTR_ERR(exynos->vdd33); | 92 | ret = PTR_ERR(exynos->vdd33); |
@@ -164,12 +109,6 @@ static int dwc3_exynos_probe(struct platform_device *pdev) | |||
164 | goto vdd10_err; | 109 | goto vdd10_err; |
165 | } | 110 | } |
166 | 111 | ||
167 | ret = dwc3_exynos_register_phys(exynos); | ||
168 | if (ret) { | ||
169 | dev_err(dev, "couldn't register PHYs\n"); | ||
170 | goto phys_err; | ||
171 | } | ||
172 | |||
173 | if (node) { | 112 | if (node) { |
174 | ret = of_platform_populate(node, NULL, NULL, dev); | 113 | ret = of_platform_populate(node, NULL, NULL, dev); |
175 | if (ret) { | 114 | if (ret) { |
@@ -185,32 +124,31 @@ static int dwc3_exynos_probe(struct platform_device *pdev) | |||
185 | return 0; | 124 | return 0; |
186 | 125 | ||
187 | populate_err: | 126 | populate_err: |
188 | platform_device_unregister(exynos->usb2_phy); | ||
189 | platform_device_unregister(exynos->usb3_phy); | ||
190 | phys_err: | ||
191 | regulator_disable(exynos->vdd10); | 127 | regulator_disable(exynos->vdd10); |
192 | vdd10_err: | 128 | vdd10_err: |
193 | regulator_disable(exynos->vdd33); | 129 | regulator_disable(exynos->vdd33); |
194 | vdd33_err: | 130 | vdd33_err: |
195 | clk_disable_unprepare(exynos->axius_clk); | 131 | for (i = exynos->num_clks - 1; i >= 0; i--) |
196 | axius_clk_err: | 132 | clk_disable_unprepare(exynos->clks[i]); |
197 | clk_disable_unprepare(exynos->susp_clk); | 133 | |
198 | susp_clk_err: | 134 | if (exynos->suspend_clk_idx >= 0) |
199 | clk_disable_unprepare(exynos->clk); | 135 | clk_disable_unprepare(exynos->clks[exynos->suspend_clk_idx]); |
136 | |||
200 | return ret; | 137 | return ret; |
201 | } | 138 | } |
202 | 139 | ||
203 | static int dwc3_exynos_remove(struct platform_device *pdev) | 140 | static int dwc3_exynos_remove(struct platform_device *pdev) |
204 | { | 141 | { |
205 | struct dwc3_exynos *exynos = platform_get_drvdata(pdev); | 142 | struct dwc3_exynos *exynos = platform_get_drvdata(pdev); |
143 | int i; | ||
206 | 144 | ||
207 | device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child); | 145 | device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child); |
208 | platform_device_unregister(exynos->usb2_phy); | ||
209 | platform_device_unregister(exynos->usb3_phy); | ||
210 | 146 | ||
211 | clk_disable_unprepare(exynos->axius_clk); | 147 | for (i = exynos->num_clks - 1; i >= 0; i--) |
212 | clk_disable_unprepare(exynos->susp_clk); | 148 | clk_disable_unprepare(exynos->clks[i]); |
213 | clk_disable_unprepare(exynos->clk); | 149 | |
150 | if (exynos->suspend_clk_idx >= 0) | ||
151 | clk_disable_unprepare(exynos->clks[exynos->suspend_clk_idx]); | ||
214 | 152 | ||
215 | regulator_disable(exynos->vdd33); | 153 | regulator_disable(exynos->vdd33); |
216 | regulator_disable(exynos->vdd10); | 154 | regulator_disable(exynos->vdd10); |
@@ -218,10 +156,36 @@ static int dwc3_exynos_remove(struct platform_device *pdev) | |||
218 | return 0; | 156 | return 0; |
219 | } | 157 | } |
220 | 158 | ||
159 | static const struct dwc3_exynos_driverdata exynos5250_drvdata = { | ||
160 | .clk_names = { "usbdrd30" }, | ||
161 | .num_clks = 1, | ||
162 | .suspend_clk_idx = -1, | ||
163 | }; | ||
164 | |||
165 | static const struct dwc3_exynos_driverdata exynos5433_drvdata = { | ||
166 | .clk_names = { "aclk", "susp_clk", "pipe_pclk", "phyclk" }, | ||
167 | .num_clks = 4, | ||
168 | .suspend_clk_idx = 1, | ||
169 | }; | ||
170 | |||
171 | static const struct dwc3_exynos_driverdata exynos7_drvdata = { | ||
172 | .clk_names = { "usbdrd30", "usbdrd30_susp_clk", "usbdrd30_axius_clk" }, | ||
173 | .num_clks = 3, | ||
174 | .suspend_clk_idx = 1, | ||
175 | }; | ||
176 | |||
221 | static const struct of_device_id exynos_dwc3_match[] = { | 177 | static const struct of_device_id exynos_dwc3_match[] = { |
222 | { .compatible = "samsung,exynos5250-dwusb3" }, | 178 | { |
223 | { .compatible = "samsung,exynos7-dwusb3" }, | 179 | .compatible = "samsung,exynos5250-dwusb3", |
224 | {}, | 180 | .data = &exynos5250_drvdata, |
181 | }, { | ||
182 | .compatible = "samsung,exynos5433-dwusb3", | ||
183 | .data = &exynos5433_drvdata, | ||
184 | }, { | ||
185 | .compatible = "samsung,exynos7-dwusb3", | ||
186 | .data = &exynos7_drvdata, | ||
187 | }, { | ||
188 | } | ||
225 | }; | 189 | }; |
226 | MODULE_DEVICE_TABLE(of, exynos_dwc3_match); | 190 | MODULE_DEVICE_TABLE(of, exynos_dwc3_match); |
227 | 191 | ||
@@ -229,9 +193,10 @@ MODULE_DEVICE_TABLE(of, exynos_dwc3_match); | |||
229 | static int dwc3_exynos_suspend(struct device *dev) | 193 | static int dwc3_exynos_suspend(struct device *dev) |
230 | { | 194 | { |
231 | struct dwc3_exynos *exynos = dev_get_drvdata(dev); | 195 | struct dwc3_exynos *exynos = dev_get_drvdata(dev); |
196 | int i; | ||
232 | 197 | ||
233 | clk_disable(exynos->axius_clk); | 198 | for (i = exynos->num_clks - 1; i >= 0; i--) |
234 | clk_disable(exynos->clk); | 199 | clk_disable_unprepare(exynos->clks[i]); |
235 | 200 | ||
236 | regulator_disable(exynos->vdd33); | 201 | regulator_disable(exynos->vdd33); |
237 | regulator_disable(exynos->vdd10); | 202 | regulator_disable(exynos->vdd10); |
@@ -242,7 +207,7 @@ static int dwc3_exynos_suspend(struct device *dev) | |||
242 | static int dwc3_exynos_resume(struct device *dev) | 207 | static int dwc3_exynos_resume(struct device *dev) |
243 | { | 208 | { |
244 | struct dwc3_exynos *exynos = dev_get_drvdata(dev); | 209 | struct dwc3_exynos *exynos = dev_get_drvdata(dev); |
245 | int ret; | 210 | int i, ret; |
246 | 211 | ||
247 | ret = regulator_enable(exynos->vdd33); | 212 | ret = regulator_enable(exynos->vdd33); |
248 | if (ret) { | 213 | if (ret) { |
@@ -255,13 +220,14 @@ static int dwc3_exynos_resume(struct device *dev) | |||
255 | return ret; | 220 | return ret; |
256 | } | 221 | } |
257 | 222 | ||
258 | clk_enable(exynos->clk); | 223 | for (i = 0; i < exynos->num_clks; i++) { |
259 | clk_enable(exynos->axius_clk); | 224 | ret = clk_prepare_enable(exynos->clks[i]); |
260 | 225 | if (ret) { | |
261 | /* runtime set active to reflect active state. */ | 226 | while (--i > 0) |
262 | pm_runtime_disable(dev); | 227 | clk_disable_unprepare(exynos->clks[i]); |
263 | pm_runtime_set_active(dev); | 228 | return ret; |
264 | pm_runtime_enable(dev); | 229 | } |
230 | } | ||
265 | 231 | ||
266 | return 0; | 232 | return 0; |
267 | } | 233 | } |
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 2b53194081ba..679c12e14522 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c | |||
@@ -270,27 +270,36 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, | |||
270 | const struct usb_endpoint_descriptor *desc = dep->endpoint.desc; | 270 | const struct usb_endpoint_descriptor *desc = dep->endpoint.desc; |
271 | struct dwc3 *dwc = dep->dwc; | 271 | struct dwc3 *dwc = dep->dwc; |
272 | u32 timeout = 1000; | 272 | u32 timeout = 1000; |
273 | u32 saved_config = 0; | ||
273 | u32 reg; | 274 | u32 reg; |
274 | 275 | ||
275 | int cmd_status = 0; | 276 | int cmd_status = 0; |
276 | int susphy = false; | ||
277 | int ret = -EINVAL; | 277 | int ret = -EINVAL; |
278 | 278 | ||
279 | /* | 279 | /* |
280 | * Synopsys Databook 2.60a states, on section 6.3.2.5.[1-8], that if | 280 | * When operating in USB 2.0 speeds (HS/FS), if GUSB2PHYCFG.ENBLSLPM or |
281 | * we're issuing an endpoint command, we must check if | 281 | * GUSB2PHYCFG.SUSPHY is set, it must be cleared before issuing an |
282 | * GUSB2PHYCFG.SUSPHY bit is set. If it is, then we need to clear it. | 282 | * endpoint command. |
283 | * | 283 | * |
284 | * We will also set SUSPHY bit to what it was before returning as stated | 284 | * Save and clear both GUSB2PHYCFG.ENBLSLPM and GUSB2PHYCFG.SUSPHY |
285 | * by the same section on Synopsys databook. | 285 | * settings. Restore them after the command is completed. |
286 | * | ||
287 | * DWC_usb3 3.30a and DWC_usb31 1.90a programming guide section 3.2.2 | ||
286 | */ | 288 | */ |
287 | if (dwc->gadget.speed <= USB_SPEED_HIGH) { | 289 | if (dwc->gadget.speed <= USB_SPEED_HIGH) { |
288 | reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); | 290 | reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); |
289 | if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) { | 291 | if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) { |
290 | susphy = true; | 292 | saved_config |= DWC3_GUSB2PHYCFG_SUSPHY; |
291 | reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; | 293 | reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; |
292 | dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); | ||
293 | } | 294 | } |
295 | |||
296 | if (reg & DWC3_GUSB2PHYCFG_ENBLSLPM) { | ||
297 | saved_config |= DWC3_GUSB2PHYCFG_ENBLSLPM; | ||
298 | reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; | ||
299 | } | ||
300 | |||
301 | if (saved_config) | ||
302 | dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); | ||
294 | } | 303 | } |
295 | 304 | ||
296 | if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) { | 305 | if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) { |
@@ -389,9 +398,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, | |||
389 | } | 398 | } |
390 | } | 399 | } |
391 | 400 | ||
392 | if (unlikely(susphy)) { | 401 | if (saved_config) { |
393 | reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); | 402 | reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); |
394 | reg |= DWC3_GUSB2PHYCFG_SUSPHY; | 403 | reg |= saved_config; |
395 | dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); | 404 | dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); |
396 | } | 405 | } |
397 | 406 | ||
diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c index e15e896f356c..165653a5e45d 100644 --- a/drivers/usb/early/xhci-dbc.c +++ b/drivers/usb/early/xhci-dbc.c | |||
@@ -717,17 +717,14 @@ static void xdbc_handle_port_status(struct xdbc_trb *evt_trb) | |||
717 | 717 | ||
718 | static void xdbc_handle_tx_event(struct xdbc_trb *evt_trb) | 718 | static void xdbc_handle_tx_event(struct xdbc_trb *evt_trb) |
719 | { | 719 | { |
720 | size_t remain_length; | ||
721 | u32 comp_code; | 720 | u32 comp_code; |
722 | int ep_id; | 721 | int ep_id; |
723 | 722 | ||
724 | comp_code = GET_COMP_CODE(le32_to_cpu(evt_trb->field[2])); | 723 | comp_code = GET_COMP_CODE(le32_to_cpu(evt_trb->field[2])); |
725 | remain_length = EVENT_TRB_LEN(le32_to_cpu(evt_trb->field[2])); | ||
726 | ep_id = TRB_TO_EP_ID(le32_to_cpu(evt_trb->field[3])); | 724 | ep_id = TRB_TO_EP_ID(le32_to_cpu(evt_trb->field[3])); |
727 | 725 | ||
728 | switch (comp_code) { | 726 | switch (comp_code) { |
729 | case COMP_SUCCESS: | 727 | case COMP_SUCCESS: |
730 | remain_length = 0; | ||
731 | case COMP_SHORT_PACKET: | 728 | case COMP_SHORT_PACKET: |
732 | break; | 729 | break; |
733 | case COMP_TRB_ERROR: | 730 | case COMP_TRB_ERROR: |
diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index d582921f7257..db2d4980cb35 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c | |||
@@ -22,12 +22,8 @@ | |||
22 | * controlled by two clock sources : | 22 | * controlled by two clock sources : |
23 | * CLK_5 := c_srate, and CLK_6 := p_srate | 23 | * CLK_5 := c_srate, and CLK_6 := p_srate |
24 | */ | 24 | */ |
25 | #define USB_OUT_IT_ID 1 | 25 | #define USB_OUT_CLK_ID (out_clk_src_desc.bClockID) |
26 | #define IO_IN_IT_ID 2 | 26 | #define USB_IN_CLK_ID (in_clk_src_desc.bClockID) |
27 | #define IO_OUT_OT_ID 3 | ||
28 | #define USB_IN_OT_ID 4 | ||
29 | #define USB_OUT_CLK_ID 5 | ||
30 | #define USB_IN_CLK_ID 6 | ||
31 | 27 | ||
32 | #define CONTROL_ABSENT 0 | 28 | #define CONTROL_ABSENT 0 |
33 | #define CONTROL_RDONLY 1 | 29 | #define CONTROL_RDONLY 1 |
@@ -43,6 +39,9 @@ | |||
43 | #define UNFLW_CTRL 8 | 39 | #define UNFLW_CTRL 8 |
44 | #define OVFLW_CTRL 10 | 40 | #define OVFLW_CTRL 10 |
45 | 41 | ||
42 | #define EPIN_EN(_opts) ((_opts)->p_chmask != 0) | ||
43 | #define EPOUT_EN(_opts) ((_opts)->c_chmask != 0) | ||
44 | |||
46 | struct f_uac2 { | 45 | struct f_uac2 { |
47 | struct g_audio g_audio; | 46 | struct g_audio g_audio; |
48 | u8 ac_intf, as_in_intf, as_out_intf; | 47 | u8 ac_intf, as_in_intf, as_out_intf; |
@@ -135,7 +134,7 @@ static struct uac_clock_source_descriptor in_clk_src_desc = { | |||
135 | .bDescriptorType = USB_DT_CS_INTERFACE, | 134 | .bDescriptorType = USB_DT_CS_INTERFACE, |
136 | 135 | ||
137 | .bDescriptorSubtype = UAC2_CLOCK_SOURCE, | 136 | .bDescriptorSubtype = UAC2_CLOCK_SOURCE, |
138 | .bClockID = USB_IN_CLK_ID, | 137 | /* .bClockID = DYNAMIC */ |
139 | .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED, | 138 | .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED, |
140 | .bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL), | 139 | .bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL), |
141 | .bAssocTerminal = 0, | 140 | .bAssocTerminal = 0, |
@@ -147,7 +146,7 @@ static struct uac_clock_source_descriptor out_clk_src_desc = { | |||
147 | .bDescriptorType = USB_DT_CS_INTERFACE, | 146 | .bDescriptorType = USB_DT_CS_INTERFACE, |
148 | 147 | ||
149 | .bDescriptorSubtype = UAC2_CLOCK_SOURCE, | 148 | .bDescriptorSubtype = UAC2_CLOCK_SOURCE, |
150 | .bClockID = USB_OUT_CLK_ID, | 149 | /* .bClockID = DYNAMIC */ |
151 | .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED, | 150 | .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED, |
152 | .bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL), | 151 | .bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL), |
153 | .bAssocTerminal = 0, | 152 | .bAssocTerminal = 0, |
@@ -159,10 +158,10 @@ static struct uac2_input_terminal_descriptor usb_out_it_desc = { | |||
159 | .bDescriptorType = USB_DT_CS_INTERFACE, | 158 | .bDescriptorType = USB_DT_CS_INTERFACE, |
160 | 159 | ||
161 | .bDescriptorSubtype = UAC_INPUT_TERMINAL, | 160 | .bDescriptorSubtype = UAC_INPUT_TERMINAL, |
162 | .bTerminalID = USB_OUT_IT_ID, | 161 | /* .bTerminalID = DYNAMIC */ |
163 | .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), | 162 | .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), |
164 | .bAssocTerminal = 0, | 163 | .bAssocTerminal = 0, |
165 | .bCSourceID = USB_OUT_CLK_ID, | 164 | /* .bCSourceID = DYNAMIC */ |
166 | .iChannelNames = 0, | 165 | .iChannelNames = 0, |
167 | .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), | 166 | .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), |
168 | }; | 167 | }; |
@@ -173,10 +172,10 @@ static struct uac2_input_terminal_descriptor io_in_it_desc = { | |||
173 | .bDescriptorType = USB_DT_CS_INTERFACE, | 172 | .bDescriptorType = USB_DT_CS_INTERFACE, |
174 | 173 | ||
175 | .bDescriptorSubtype = UAC_INPUT_TERMINAL, | 174 | .bDescriptorSubtype = UAC_INPUT_TERMINAL, |
176 | .bTerminalID = IO_IN_IT_ID, | 175 | /* .bTerminalID = DYNAMIC */ |
177 | .wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_UNDEFINED), | 176 | .wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_UNDEFINED), |
178 | .bAssocTerminal = 0, | 177 | .bAssocTerminal = 0, |
179 | .bCSourceID = USB_IN_CLK_ID, | 178 | /* .bCSourceID = DYNAMIC */ |
180 | .iChannelNames = 0, | 179 | .iChannelNames = 0, |
181 | .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), | 180 | .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), |
182 | }; | 181 | }; |
@@ -187,11 +186,11 @@ static struct uac2_output_terminal_descriptor usb_in_ot_desc = { | |||
187 | .bDescriptorType = USB_DT_CS_INTERFACE, | 186 | .bDescriptorType = USB_DT_CS_INTERFACE, |
188 | 187 | ||
189 | .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, | 188 | .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, |
190 | .bTerminalID = USB_IN_OT_ID, | 189 | /* .bTerminalID = DYNAMIC */ |
191 | .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), | 190 | .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), |
192 | .bAssocTerminal = 0, | 191 | .bAssocTerminal = 0, |
193 | .bSourceID = IO_IN_IT_ID, | 192 | /* .bSourceID = DYNAMIC */ |
194 | .bCSourceID = USB_IN_CLK_ID, | 193 | /* .bCSourceID = DYNAMIC */ |
195 | .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), | 194 | .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), |
196 | }; | 195 | }; |
197 | 196 | ||
@@ -201,11 +200,11 @@ static struct uac2_output_terminal_descriptor io_out_ot_desc = { | |||
201 | .bDescriptorType = USB_DT_CS_INTERFACE, | 200 | .bDescriptorType = USB_DT_CS_INTERFACE, |
202 | 201 | ||
203 | .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, | 202 | .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, |
204 | .bTerminalID = IO_OUT_OT_ID, | 203 | /* .bTerminalID = DYNAMIC */ |
205 | .wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_UNDEFINED), | 204 | .wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_UNDEFINED), |
206 | .bAssocTerminal = 0, | 205 | .bAssocTerminal = 0, |
207 | .bSourceID = USB_OUT_IT_ID, | 206 | /* .bSourceID = DYNAMIC */ |
208 | .bCSourceID = USB_OUT_CLK_ID, | 207 | /* .bCSourceID = DYNAMIC */ |
209 | .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), | 208 | .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), |
210 | }; | 209 | }; |
211 | 210 | ||
@@ -253,7 +252,7 @@ static struct uac2_as_header_descriptor as_out_hdr_desc = { | |||
253 | .bDescriptorType = USB_DT_CS_INTERFACE, | 252 | .bDescriptorType = USB_DT_CS_INTERFACE, |
254 | 253 | ||
255 | .bDescriptorSubtype = UAC_AS_GENERAL, | 254 | .bDescriptorSubtype = UAC_AS_GENERAL, |
256 | .bTerminalLink = USB_OUT_IT_ID, | 255 | /* .bTerminalLink = DYNAMIC */ |
257 | .bmControls = 0, | 256 | .bmControls = 0, |
258 | .bFormatType = UAC_FORMAT_TYPE_I, | 257 | .bFormatType = UAC_FORMAT_TYPE_I, |
259 | .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM), | 258 | .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM), |
@@ -330,7 +329,7 @@ static struct uac2_as_header_descriptor as_in_hdr_desc = { | |||
330 | .bDescriptorType = USB_DT_CS_INTERFACE, | 329 | .bDescriptorType = USB_DT_CS_INTERFACE, |
331 | 330 | ||
332 | .bDescriptorSubtype = UAC_AS_GENERAL, | 331 | .bDescriptorSubtype = UAC_AS_GENERAL, |
333 | .bTerminalLink = USB_IN_OT_ID, | 332 | /* .bTerminalLink = DYNAMIC */ |
334 | .bmControls = 0, | 333 | .bmControls = 0, |
335 | .bFormatType = UAC_FORMAT_TYPE_I, | 334 | .bFormatType = UAC_FORMAT_TYPE_I, |
336 | .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM), | 335 | .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM), |
@@ -471,6 +470,125 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, | |||
471 | le16_to_cpu(ep_desc->wMaxPacketSize))); | 470 | le16_to_cpu(ep_desc->wMaxPacketSize))); |
472 | } | 471 | } |
473 | 472 | ||
473 | /* Use macro to overcome line length limitation */ | ||
474 | #define USBDHDR(p) (struct usb_descriptor_header *)(p) | ||
475 | |||
476 | static void setup_descriptor(struct f_uac2_opts *opts) | ||
477 | { | ||
478 | /* patch descriptors */ | ||
479 | int i = 1; /* ID's start with 1 */ | ||
480 | |||
481 | if (EPOUT_EN(opts)) | ||
482 | usb_out_it_desc.bTerminalID = i++; | ||
483 | if (EPIN_EN(opts)) | ||
484 | io_in_it_desc.bTerminalID = i++; | ||
485 | if (EPOUT_EN(opts)) | ||
486 | io_out_ot_desc.bTerminalID = i++; | ||
487 | if (EPIN_EN(opts)) | ||
488 | usb_in_ot_desc.bTerminalID = i++; | ||
489 | if (EPOUT_EN(opts)) | ||
490 | out_clk_src_desc.bClockID = i++; | ||
491 | if (EPIN_EN(opts)) | ||
492 | in_clk_src_desc.bClockID = i++; | ||
493 | |||
494 | usb_out_it_desc.bCSourceID = out_clk_src_desc.bClockID; | ||
495 | usb_in_ot_desc.bSourceID = io_in_it_desc.bTerminalID; | ||
496 | usb_in_ot_desc.bCSourceID = in_clk_src_desc.bClockID; | ||
497 | io_in_it_desc.bCSourceID = in_clk_src_desc.bClockID; | ||
498 | io_out_ot_desc.bCSourceID = out_clk_src_desc.bClockID; | ||
499 | io_out_ot_desc.bSourceID = usb_out_it_desc.bTerminalID; | ||
500 | as_out_hdr_desc.bTerminalLink = usb_out_it_desc.bTerminalID; | ||
501 | as_in_hdr_desc.bTerminalLink = usb_in_ot_desc.bTerminalID; | ||
502 | |||
503 | iad_desc.bInterfaceCount = 1; | ||
504 | ac_hdr_desc.wTotalLength = 0; | ||
505 | |||
506 | if (EPIN_EN(opts)) { | ||
507 | u16 len = le16_to_cpu(ac_hdr_desc.wTotalLength); | ||
508 | |||
509 | len += sizeof(in_clk_src_desc); | ||
510 | len += sizeof(usb_in_ot_desc); | ||
511 | len += sizeof(io_in_it_desc); | ||
512 | ac_hdr_desc.wTotalLength = cpu_to_le16(len); | ||
513 | iad_desc.bInterfaceCount++; | ||
514 | } | ||
515 | if (EPOUT_EN(opts)) { | ||
516 | u16 len = le16_to_cpu(ac_hdr_desc.wTotalLength); | ||
517 | |||
518 | len += sizeof(out_clk_src_desc); | ||
519 | len += sizeof(usb_out_it_desc); | ||
520 | len += sizeof(io_out_ot_desc); | ||
521 | ac_hdr_desc.wTotalLength = cpu_to_le16(len); | ||
522 | iad_desc.bInterfaceCount++; | ||
523 | } | ||
524 | |||
525 | i = 0; | ||
526 | fs_audio_desc[i++] = USBDHDR(&iad_desc); | ||
527 | fs_audio_desc[i++] = USBDHDR(&std_ac_if_desc); | ||
528 | fs_audio_desc[i++] = USBDHDR(&ac_hdr_desc); | ||
529 | if (EPIN_EN(opts)) | ||
530 | fs_audio_desc[i++] = USBDHDR(&in_clk_src_desc); | ||
531 | if (EPOUT_EN(opts)) { | ||
532 | fs_audio_desc[i++] = USBDHDR(&out_clk_src_desc); | ||
533 | fs_audio_desc[i++] = USBDHDR(&usb_out_it_desc); | ||
534 | } | ||
535 | if (EPIN_EN(opts)) { | ||
536 | fs_audio_desc[i++] = USBDHDR(&io_in_it_desc); | ||
537 | fs_audio_desc[i++] = USBDHDR(&usb_in_ot_desc); | ||
538 | } | ||
539 | if (EPOUT_EN(opts)) { | ||
540 | fs_audio_desc[i++] = USBDHDR(&io_out_ot_desc); | ||
541 | fs_audio_desc[i++] = USBDHDR(&std_as_out_if0_desc); | ||
542 | fs_audio_desc[i++] = USBDHDR(&std_as_out_if1_desc); | ||
543 | fs_audio_desc[i++] = USBDHDR(&as_out_hdr_desc); | ||
544 | fs_audio_desc[i++] = USBDHDR(&as_out_fmt1_desc); | ||
545 | fs_audio_desc[i++] = USBDHDR(&fs_epout_desc); | ||
546 | fs_audio_desc[i++] = USBDHDR(&as_iso_out_desc); | ||
547 | } | ||
548 | if (EPIN_EN(opts)) { | ||
549 | fs_audio_desc[i++] = USBDHDR(&std_as_in_if0_desc); | ||
550 | fs_audio_desc[i++] = USBDHDR(&std_as_in_if1_desc); | ||
551 | fs_audio_desc[i++] = USBDHDR(&as_in_hdr_desc); | ||
552 | fs_audio_desc[i++] = USBDHDR(&as_in_fmt1_desc); | ||
553 | fs_audio_desc[i++] = USBDHDR(&fs_epin_desc); | ||
554 | fs_audio_desc[i++] = USBDHDR(&as_iso_in_desc); | ||
555 | } | ||
556 | fs_audio_desc[i] = NULL; | ||
557 | |||
558 | i = 0; | ||
559 | hs_audio_desc[i++] = USBDHDR(&iad_desc); | ||
560 | hs_audio_desc[i++] = USBDHDR(&std_ac_if_desc); | ||
561 | hs_audio_desc[i++] = USBDHDR(&ac_hdr_desc); | ||
562 | if (EPIN_EN(opts)) | ||
563 | hs_audio_desc[i++] = USBDHDR(&in_clk_src_desc); | ||
564 | if (EPOUT_EN(opts)) { | ||
565 | hs_audio_desc[i++] = USBDHDR(&out_clk_src_desc); | ||
566 | hs_audio_desc[i++] = USBDHDR(&usb_out_it_desc); | ||
567 | } | ||
568 | if (EPIN_EN(opts)) { | ||
569 | hs_audio_desc[i++] = USBDHDR(&io_in_it_desc); | ||
570 | hs_audio_desc[i++] = USBDHDR(&usb_in_ot_desc); | ||
571 | } | ||
572 | if (EPOUT_EN(opts)) { | ||
573 | hs_audio_desc[i++] = USBDHDR(&io_out_ot_desc); | ||
574 | hs_audio_desc[i++] = USBDHDR(&std_as_out_if0_desc); | ||
575 | hs_audio_desc[i++] = USBDHDR(&std_as_out_if1_desc); | ||
576 | hs_audio_desc[i++] = USBDHDR(&as_out_hdr_desc); | ||
577 | hs_audio_desc[i++] = USBDHDR(&as_out_fmt1_desc); | ||
578 | hs_audio_desc[i++] = USBDHDR(&hs_epout_desc); | ||
579 | hs_audio_desc[i++] = USBDHDR(&as_iso_out_desc); | ||
580 | } | ||
581 | if (EPIN_EN(opts)) { | ||
582 | hs_audio_desc[i++] = USBDHDR(&std_as_in_if0_desc); | ||
583 | hs_audio_desc[i++] = USBDHDR(&std_as_in_if1_desc); | ||
584 | hs_audio_desc[i++] = USBDHDR(&as_in_hdr_desc); | ||
585 | hs_audio_desc[i++] = USBDHDR(&as_in_fmt1_desc); | ||
586 | hs_audio_desc[i++] = USBDHDR(&hs_epin_desc); | ||
587 | hs_audio_desc[i++] = USBDHDR(&as_iso_in_desc); | ||
588 | } | ||
589 | hs_audio_desc[i] = NULL; | ||
590 | } | ||
591 | |||
474 | static int | 592 | static int |
475 | afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) | 593 | afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) |
476 | { | 594 | { |
@@ -530,25 +648,29 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) | |||
530 | uac2->ac_intf = ret; | 648 | uac2->ac_intf = ret; |
531 | uac2->ac_alt = 0; | 649 | uac2->ac_alt = 0; |
532 | 650 | ||
533 | ret = usb_interface_id(cfg, fn); | 651 | if (EPOUT_EN(uac2_opts)) { |
534 | if (ret < 0) { | 652 | ret = usb_interface_id(cfg, fn); |
535 | dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); | 653 | if (ret < 0) { |
536 | return ret; | 654 | dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); |
655 | return ret; | ||
656 | } | ||
657 | std_as_out_if0_desc.bInterfaceNumber = ret; | ||
658 | std_as_out_if1_desc.bInterfaceNumber = ret; | ||
659 | uac2->as_out_intf = ret; | ||
660 | uac2->as_out_alt = 0; | ||
537 | } | 661 | } |
538 | std_as_out_if0_desc.bInterfaceNumber = ret; | ||
539 | std_as_out_if1_desc.bInterfaceNumber = ret; | ||
540 | uac2->as_out_intf = ret; | ||
541 | uac2->as_out_alt = 0; | ||
542 | 662 | ||
543 | ret = usb_interface_id(cfg, fn); | 663 | if (EPIN_EN(uac2_opts)) { |
544 | if (ret < 0) { | 664 | ret = usb_interface_id(cfg, fn); |
545 | dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); | 665 | if (ret < 0) { |
546 | return ret; | 666 | dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); |
667 | return ret; | ||
668 | } | ||
669 | std_as_in_if0_desc.bInterfaceNumber = ret; | ||
670 | std_as_in_if1_desc.bInterfaceNumber = ret; | ||
671 | uac2->as_in_intf = ret; | ||
672 | uac2->as_in_alt = 0; | ||
547 | } | 673 | } |
548 | std_as_in_if0_desc.bInterfaceNumber = ret; | ||
549 | std_as_in_if1_desc.bInterfaceNumber = ret; | ||
550 | uac2->as_in_intf = ret; | ||
551 | uac2->as_in_alt = 0; | ||
552 | 674 | ||
553 | /* Calculate wMaxPacketSize according to audio bandwidth */ | 675 | /* Calculate wMaxPacketSize according to audio bandwidth */ |
554 | set_ep_max_packet_size(uac2_opts, &fs_epin_desc, 1000, true); | 676 | set_ep_max_packet_size(uac2_opts, &fs_epin_desc, 1000, true); |
@@ -556,16 +678,20 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) | |||
556 | set_ep_max_packet_size(uac2_opts, &hs_epin_desc, 8000, true); | 678 | set_ep_max_packet_size(uac2_opts, &hs_epin_desc, 8000, true); |
557 | set_ep_max_packet_size(uac2_opts, &hs_epout_desc, 8000, false); | 679 | set_ep_max_packet_size(uac2_opts, &hs_epout_desc, 8000, false); |
558 | 680 | ||
559 | agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc); | 681 | if (EPOUT_EN(uac2_opts)) { |
560 | if (!agdev->out_ep) { | 682 | agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc); |
561 | dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); | 683 | if (!agdev->out_ep) { |
562 | return -ENODEV; | 684 | dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); |
685 | return -ENODEV; | ||
686 | } | ||
563 | } | 687 | } |
564 | 688 | ||
565 | agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc); | 689 | if (EPIN_EN(uac2_opts)) { |
566 | if (!agdev->in_ep) { | 690 | agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc); |
567 | dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); | 691 | if (!agdev->in_ep) { |
568 | return -ENODEV; | 692 | dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); |
693 | return -ENODEV; | ||
694 | } | ||
569 | } | 695 | } |
570 | 696 | ||
571 | agdev->in_ep_maxpsize = max_t(u16, | 697 | agdev->in_ep_maxpsize = max_t(u16, |
@@ -578,6 +704,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) | |||
578 | hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; | 704 | hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; |
579 | hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; | 705 | hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; |
580 | 706 | ||
707 | setup_descriptor(uac2_opts); | ||
708 | |||
581 | ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL, | 709 | ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL, |
582 | NULL); | 710 | NULL); |
583 | if (ret) | 711 | if (ret) |
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index d8ce7868fe22..8c99392df593 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c | |||
@@ -197,12 +197,6 @@ static const struct usb_descriptor_header * const uvc_ss_streaming[] = { | |||
197 | NULL, | 197 | NULL, |
198 | }; | 198 | }; |
199 | 199 | ||
200 | void uvc_set_trace_param(unsigned int trace) | ||
201 | { | ||
202 | uvc_gadget_trace_param = trace; | ||
203 | } | ||
204 | EXPORT_SYMBOL(uvc_set_trace_param); | ||
205 | |||
206 | /* -------------------------------------------------------------------------- | 200 | /* -------------------------------------------------------------------------- |
207 | * Control requests | 201 | * Control requests |
208 | */ | 202 | */ |
@@ -232,13 +226,8 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) | |||
232 | struct v4l2_event v4l2_event; | 226 | struct v4l2_event v4l2_event; |
233 | struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; | 227 | struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; |
234 | 228 | ||
235 | /* printk(KERN_INFO "setup request %02x %02x value %04x index %04x %04x\n", | ||
236 | * ctrl->bRequestType, ctrl->bRequest, le16_to_cpu(ctrl->wValue), | ||
237 | * le16_to_cpu(ctrl->wIndex), le16_to_cpu(ctrl->wLength)); | ||
238 | */ | ||
239 | |||
240 | if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS) { | 229 | if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS) { |
241 | INFO(f->config->cdev, "invalid request type\n"); | 230 | uvcg_info(f, "invalid request type\n"); |
242 | return -EINVAL; | 231 | return -EINVAL; |
243 | } | 232 | } |
244 | 233 | ||
@@ -272,7 +261,7 @@ uvc_function_get_alt(struct usb_function *f, unsigned interface) | |||
272 | { | 261 | { |
273 | struct uvc_device *uvc = to_uvc(f); | 262 | struct uvc_device *uvc = to_uvc(f); |
274 | 263 | ||
275 | INFO(f->config->cdev, "uvc_function_get_alt(%u)\n", interface); | 264 | uvcg_info(f, "%s(%u)\n", __func__, interface); |
276 | 265 | ||
277 | if (interface == uvc->control_intf) | 266 | if (interface == uvc->control_intf) |
278 | return 0; | 267 | return 0; |
@@ -291,13 +280,13 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) | |||
291 | struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; | 280 | struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; |
292 | int ret; | 281 | int ret; |
293 | 282 | ||
294 | INFO(cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt); | 283 | uvcg_info(f, "%s(%u, %u)\n", __func__, interface, alt); |
295 | 284 | ||
296 | if (interface == uvc->control_intf) { | 285 | if (interface == uvc->control_intf) { |
297 | if (alt) | 286 | if (alt) |
298 | return -EINVAL; | 287 | return -EINVAL; |
299 | 288 | ||
300 | INFO(cdev, "reset UVC Control\n"); | 289 | uvcg_info(f, "reset UVC Control\n"); |
301 | usb_ep_disable(uvc->control_ep); | 290 | usb_ep_disable(uvc->control_ep); |
302 | 291 | ||
303 | if (!uvc->control_ep->desc) | 292 | if (!uvc->control_ep->desc) |
@@ -348,7 +337,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) | |||
348 | if (!uvc->video.ep) | 337 | if (!uvc->video.ep) |
349 | return -EINVAL; | 338 | return -EINVAL; |
350 | 339 | ||
351 | INFO(cdev, "reset UVC\n"); | 340 | uvcg_info(f, "reset UVC\n"); |
352 | usb_ep_disable(uvc->video.ep); | 341 | usb_ep_disable(uvc->video.ep); |
353 | 342 | ||
354 | ret = config_ep_by_speed(f->config->cdev->gadget, | 343 | ret = config_ep_by_speed(f->config->cdev->gadget, |
@@ -373,7 +362,7 @@ uvc_function_disable(struct usb_function *f) | |||
373 | struct uvc_device *uvc = to_uvc(f); | 362 | struct uvc_device *uvc = to_uvc(f); |
374 | struct v4l2_event v4l2_event; | 363 | struct v4l2_event v4l2_event; |
375 | 364 | ||
376 | INFO(f->config->cdev, "uvc_function_disable\n"); | 365 | uvcg_info(f, "%s()\n", __func__); |
377 | 366 | ||
378 | memset(&v4l2_event, 0, sizeof(v4l2_event)); | 367 | memset(&v4l2_event, 0, sizeof(v4l2_event)); |
379 | v4l2_event.type = UVC_EVENT_DISCONNECT; | 368 | v4l2_event.type = UVC_EVENT_DISCONNECT; |
@@ -392,21 +381,19 @@ uvc_function_disable(struct usb_function *f) | |||
392 | void | 381 | void |
393 | uvc_function_connect(struct uvc_device *uvc) | 382 | uvc_function_connect(struct uvc_device *uvc) |
394 | { | 383 | { |
395 | struct usb_composite_dev *cdev = uvc->func.config->cdev; | ||
396 | int ret; | 384 | int ret; |
397 | 385 | ||
398 | if ((ret = usb_function_activate(&uvc->func)) < 0) | 386 | if ((ret = usb_function_activate(&uvc->func)) < 0) |
399 | INFO(cdev, "UVC connect failed with %d\n", ret); | 387 | uvcg_info(&uvc->func, "UVC connect failed with %d\n", ret); |
400 | } | 388 | } |
401 | 389 | ||
402 | void | 390 | void |
403 | uvc_function_disconnect(struct uvc_device *uvc) | 391 | uvc_function_disconnect(struct uvc_device *uvc) |
404 | { | 392 | { |
405 | struct usb_composite_dev *cdev = uvc->func.config->cdev; | ||
406 | int ret; | 393 | int ret; |
407 | 394 | ||
408 | if ((ret = usb_function_deactivate(&uvc->func)) < 0) | 395 | if ((ret = usb_function_deactivate(&uvc->func)) < 0) |
409 | INFO(cdev, "UVC disconnect failed with %d\n", ret); | 396 | uvcg_info(&uvc->func, "UVC disconnect failed with %d\n", ret); |
410 | } | 397 | } |
411 | 398 | ||
412 | /* -------------------------------------------------------------------------- | 399 | /* -------------------------------------------------------------------------- |
@@ -605,7 +592,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) | |||
605 | struct f_uvc_opts *opts; | 592 | struct f_uvc_opts *opts; |
606 | int ret = -EINVAL; | 593 | int ret = -EINVAL; |
607 | 594 | ||
608 | INFO(cdev, "uvc_function_bind\n"); | 595 | uvcg_info(f, "%s()\n", __func__); |
609 | 596 | ||
610 | opts = fi_to_f_uvc_opts(f->fi); | 597 | opts = fi_to_f_uvc_opts(f->fi); |
611 | /* Sanity check the streaming endpoint module parameters. | 598 | /* Sanity check the streaming endpoint module parameters. |
@@ -618,8 +605,8 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) | |||
618 | if (opts->streaming_maxburst && | 605 | if (opts->streaming_maxburst && |
619 | (opts->streaming_maxpacket % 1024) != 0) { | 606 | (opts->streaming_maxpacket % 1024) != 0) { |
620 | opts->streaming_maxpacket = roundup(opts->streaming_maxpacket, 1024); | 607 | opts->streaming_maxpacket = roundup(opts->streaming_maxpacket, 1024); |
621 | INFO(cdev, "overriding streaming_maxpacket to %d\n", | 608 | uvcg_info(f, "overriding streaming_maxpacket to %d\n", |
622 | opts->streaming_maxpacket); | 609 | opts->streaming_maxpacket); |
623 | } | 610 | } |
624 | 611 | ||
625 | /* Fill in the FS/HS/SS Video Streaming specific descriptors from the | 612 | /* Fill in the FS/HS/SS Video Streaming specific descriptors from the |
@@ -658,7 +645,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) | |||
658 | /* Allocate endpoints. */ | 645 | /* Allocate endpoints. */ |
659 | ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep); | 646 | ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep); |
660 | if (!ep) { | 647 | if (!ep) { |
661 | INFO(cdev, "Unable to allocate control EP\n"); | 648 | uvcg_info(f, "Unable to allocate control EP\n"); |
662 | goto error; | 649 | goto error; |
663 | } | 650 | } |
664 | uvc->control_ep = ep; | 651 | uvc->control_ep = ep; |
@@ -672,7 +659,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) | |||
672 | ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep); | 659 | ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep); |
673 | 660 | ||
674 | if (!ep) { | 661 | if (!ep) { |
675 | INFO(cdev, "Unable to allocate streaming EP\n"); | 662 | uvcg_info(f, "Unable to allocate streaming EP\n"); |
676 | goto error; | 663 | goto error; |
677 | } | 664 | } |
678 | uvc->video.ep = ep; | 665 | uvc->video.ep = ep; |
@@ -699,12 +686,14 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) | |||
699 | uvc_iad.bFirstInterface = ret; | 686 | uvc_iad.bFirstInterface = ret; |
700 | uvc_control_intf.bInterfaceNumber = ret; | 687 | uvc_control_intf.bInterfaceNumber = ret; |
701 | uvc->control_intf = ret; | 688 | uvc->control_intf = ret; |
689 | opts->control_interface = ret; | ||
702 | 690 | ||
703 | if ((ret = usb_interface_id(c, f)) < 0) | 691 | if ((ret = usb_interface_id(c, f)) < 0) |
704 | goto error; | 692 | goto error; |
705 | uvc_streaming_intf_alt0.bInterfaceNumber = ret; | 693 | uvc_streaming_intf_alt0.bInterfaceNumber = ret; |
706 | uvc_streaming_intf_alt1.bInterfaceNumber = ret; | 694 | uvc_streaming_intf_alt1.bInterfaceNumber = ret; |
707 | uvc->streaming_intf = ret; | 695 | uvc->streaming_intf = ret; |
696 | opts->streaming_interface = ret; | ||
708 | 697 | ||
709 | /* Copy descriptors */ | 698 | /* Copy descriptors */ |
710 | f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL); | 699 | f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL); |
@@ -743,19 +732,19 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) | |||
743 | uvc->control_req->context = uvc; | 732 | uvc->control_req->context = uvc; |
744 | 733 | ||
745 | if (v4l2_device_register(&cdev->gadget->dev, &uvc->v4l2_dev)) { | 734 | if (v4l2_device_register(&cdev->gadget->dev, &uvc->v4l2_dev)) { |
746 | printk(KERN_INFO "v4l2_device_register failed\n"); | 735 | uvcg_err(f, "failed to register V4L2 device\n"); |
747 | goto error; | 736 | goto error; |
748 | } | 737 | } |
749 | 738 | ||
750 | /* Initialise video. */ | 739 | /* Initialise video. */ |
751 | ret = uvcg_video_init(&uvc->video); | 740 | ret = uvcg_video_init(&uvc->video, uvc); |
752 | if (ret < 0) | 741 | if (ret < 0) |
753 | goto error; | 742 | goto error; |
754 | 743 | ||
755 | /* Register a V4L2 device. */ | 744 | /* Register a V4L2 device. */ |
756 | ret = uvc_register_video(uvc); | 745 | ret = uvc_register_video(uvc); |
757 | if (ret < 0) { | 746 | if (ret < 0) { |
758 | printk(KERN_INFO "Unable to register video device\n"); | 747 | uvcg_err(f, "failed to register video device\n"); |
759 | goto error; | 748 | goto error; |
760 | } | 749 | } |
761 | 750 | ||
@@ -792,6 +781,7 @@ static struct usb_function_instance *uvc_alloc_inst(void) | |||
792 | struct uvc_output_terminal_descriptor *od; | 781 | struct uvc_output_terminal_descriptor *od; |
793 | struct uvc_color_matching_descriptor *md; | 782 | struct uvc_color_matching_descriptor *md; |
794 | struct uvc_descriptor_header **ctl_cls; | 783 | struct uvc_descriptor_header **ctl_cls; |
784 | int ret; | ||
795 | 785 | ||
796 | opts = kzalloc(sizeof(*opts), GFP_KERNEL); | 786 | opts = kzalloc(sizeof(*opts), GFP_KERNEL); |
797 | if (!opts) | 787 | if (!opts) |
@@ -868,7 +858,12 @@ static struct usb_function_instance *uvc_alloc_inst(void) | |||
868 | opts->streaming_interval = 1; | 858 | opts->streaming_interval = 1; |
869 | opts->streaming_maxpacket = 1024; | 859 | opts->streaming_maxpacket = 1024; |
870 | 860 | ||
871 | uvcg_attach_configfs(opts); | 861 | ret = uvcg_attach_configfs(opts); |
862 | if (ret < 0) { | ||
863 | kfree(opts); | ||
864 | return ERR_PTR(ret); | ||
865 | } | ||
866 | |||
872 | return &opts->func_inst; | 867 | return &opts->func_inst; |
873 | } | 868 | } |
874 | 869 | ||
@@ -886,7 +881,7 @@ static void uvc_unbind(struct usb_configuration *c, struct usb_function *f) | |||
886 | struct usb_composite_dev *cdev = c->cdev; | 881 | struct usb_composite_dev *cdev = c->cdev; |
887 | struct uvc_device *uvc = to_uvc(f); | 882 | struct uvc_device *uvc = to_uvc(f); |
888 | 883 | ||
889 | INFO(cdev, "%s\n", __func__); | 884 | uvcg_info(f, "%s\n", __func__); |
890 | 885 | ||
891 | device_remove_file(&uvc->vdev.dev, &dev_attr_function_name); | 886 | device_remove_file(&uvc->vdev.dev, &dev_attr_function_name); |
892 | video_unregister_device(&uvc->vdev); | 887 | video_unregister_device(&uvc->vdev); |
diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h index 2ed292e94fbc..5242d489e20a 100644 --- a/drivers/usb/gadget/function/u_uvc.h +++ b/drivers/usb/gadget/function/u_uvc.h | |||
@@ -25,6 +25,9 @@ struct f_uvc_opts { | |||
25 | unsigned int streaming_maxpacket; | 25 | unsigned int streaming_maxpacket; |
26 | unsigned int streaming_maxburst; | 26 | unsigned int streaming_maxburst; |
27 | 27 | ||
28 | unsigned int control_interface; | ||
29 | unsigned int streaming_interface; | ||
30 | |||
28 | /* | 31 | /* |
29 | * Control descriptors array pointers for full-/high-speed and | 32 | * Control descriptors array pointers for full-/high-speed and |
30 | * super-speed. They point by default to the uvc_fs_control_cls and | 33 | * super-speed. They point by default to the uvc_fs_control_cls and |
diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index 93cf78b420fe..099d650082e5 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h | |||
@@ -24,6 +24,7 @@ | |||
24 | struct usb_ep; | 24 | struct usb_ep; |
25 | struct usb_request; | 25 | struct usb_request; |
26 | struct uvc_descriptor_header; | 26 | struct uvc_descriptor_header; |
27 | struct uvc_device; | ||
27 | 28 | ||
28 | /* ------------------------------------------------------------------------ | 29 | /* ------------------------------------------------------------------------ |
29 | * Debugging, printing and logging | 30 | * Debugging, printing and logging |
@@ -51,14 +52,12 @@ extern unsigned int uvc_gadget_trace_param; | |||
51 | printk(KERN_DEBUG "uvcvideo: " msg); \ | 52 | printk(KERN_DEBUG "uvcvideo: " msg); \ |
52 | } while (0) | 53 | } while (0) |
53 | 54 | ||
54 | #define uvc_warn_once(dev, warn, msg...) \ | 55 | #define uvcg_dbg(f, fmt, args...) \ |
55 | do { \ | 56 | dev_dbg(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args) |
56 | if (!test_and_set_bit(warn, &dev->warnings)) \ | 57 | #define uvcg_info(f, fmt, args...) \ |
57 | printk(KERN_INFO "uvcvideo: " msg); \ | 58 | dev_info(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args) |
58 | } while (0) | 59 | #define uvcg_err(f, fmt, args...) \ |
59 | 60 | dev_err(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args) | |
60 | #define uvc_printk(level, msg...) \ | ||
61 | printk(level "uvcvideo: " msg) | ||
62 | 61 | ||
63 | /* ------------------------------------------------------------------------ | 62 | /* ------------------------------------------------------------------------ |
64 | * Driver specific constants | 63 | * Driver specific constants |
@@ -73,6 +72,7 @@ extern unsigned int uvc_gadget_trace_param; | |||
73 | */ | 72 | */ |
74 | 73 | ||
75 | struct uvc_video { | 74 | struct uvc_video { |
75 | struct uvc_device *uvc; | ||
76 | struct usb_ep *ep; | 76 | struct usb_ep *ep; |
77 | 77 | ||
78 | /* Frame parameters */ | 78 | /* Frame parameters */ |
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index b51f0d278826..bc1e2af566c3 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c | |||
@@ -9,9 +9,16 @@ | |||
9 | * | 9 | * |
10 | * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> | 10 | * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> |
11 | */ | 11 | */ |
12 | |||
13 | #include <linux/sort.h> | ||
14 | |||
12 | #include "u_uvc.h" | 15 | #include "u_uvc.h" |
13 | #include "uvc_configfs.h" | 16 | #include "uvc_configfs.h" |
14 | 17 | ||
18 | /* ----------------------------------------------------------------------------- | ||
19 | * Global Utility Structures and Macros | ||
20 | */ | ||
21 | |||
15 | #define UVCG_STREAMING_CONTROL_SIZE 1 | 22 | #define UVCG_STREAMING_CONTROL_SIZE 1 |
16 | 23 | ||
17 | #define UVC_ATTR(prefix, cname, aname) \ | 24 | #define UVC_ATTR(prefix, cname, aname) \ |
@@ -31,13 +38,93 @@ static struct configfs_attribute prefix##attr_##cname = { \ | |||
31 | .show = prefix##cname##_show, \ | 38 | .show = prefix##cname##_show, \ |
32 | } | 39 | } |
33 | 40 | ||
41 | #define le8_to_cpu(x) (x) | ||
42 | #define cpu_to_le8(x) (x) | ||
43 | |||
44 | static int uvcg_config_compare_u32(const void *l, const void *r) | ||
45 | { | ||
46 | u32 li = *(const u32 *)l; | ||
47 | u32 ri = *(const u32 *)r; | ||
48 | |||
49 | return li < ri ? -1 : li == ri ? 0 : 1; | ||
50 | } | ||
51 | |||
34 | static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item) | 52 | static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item) |
35 | { | 53 | { |
36 | return container_of(to_config_group(item), struct f_uvc_opts, | 54 | return container_of(to_config_group(item), struct f_uvc_opts, |
37 | func_inst.group); | 55 | func_inst.group); |
38 | } | 56 | } |
39 | 57 | ||
40 | /* control/header/<NAME> */ | 58 | struct uvcg_config_group_type { |
59 | struct config_item_type type; | ||
60 | const char *name; | ||
61 | const struct uvcg_config_group_type **children; | ||
62 | int (*create_children)(struct config_group *group); | ||
63 | }; | ||
64 | |||
65 | static void uvcg_config_item_release(struct config_item *item) | ||
66 | { | ||
67 | struct config_group *group = to_config_group(item); | ||
68 | |||
69 | kfree(group); | ||
70 | } | ||
71 | |||
72 | static struct configfs_item_operations uvcg_config_item_ops = { | ||
73 | .release = uvcg_config_item_release, | ||
74 | }; | ||
75 | |||
76 | static int uvcg_config_create_group(struct config_group *parent, | ||
77 | const struct uvcg_config_group_type *type); | ||
78 | |||
79 | static int uvcg_config_create_children(struct config_group *group, | ||
80 | const struct uvcg_config_group_type *type) | ||
81 | { | ||
82 | const struct uvcg_config_group_type **child; | ||
83 | int ret; | ||
84 | |||
85 | if (type->create_children) | ||
86 | return type->create_children(group); | ||
87 | |||
88 | for (child = type->children; child && *child; ++child) { | ||
89 | ret = uvcg_config_create_group(group, *child); | ||
90 | if (ret < 0) | ||
91 | return ret; | ||
92 | } | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static int uvcg_config_create_group(struct config_group *parent, | ||
98 | const struct uvcg_config_group_type *type) | ||
99 | { | ||
100 | struct config_group *group; | ||
101 | |||
102 | group = kzalloc(sizeof(*group), GFP_KERNEL); | ||
103 | if (!group) | ||
104 | return -ENOMEM; | ||
105 | |||
106 | config_group_init_type_name(group, type->name, &type->type); | ||
107 | configfs_add_default_group(group, parent); | ||
108 | |||
109 | return uvcg_config_create_children(group, type); | ||
110 | } | ||
111 | |||
112 | static void uvcg_config_remove_children(struct config_group *group) | ||
113 | { | ||
114 | struct config_group *child, *n; | ||
115 | |||
116 | list_for_each_entry_safe(child, n, &group->default_groups, group_entry) { | ||
117 | list_del(&child->group_entry); | ||
118 | uvcg_config_remove_children(child); | ||
119 | config_item_put(&child->cg_item); | ||
120 | } | ||
121 | } | ||
122 | |||
123 | /* ----------------------------------------------------------------------------- | ||
124 | * control/header/<NAME> | ||
125 | * control/header | ||
126 | */ | ||
127 | |||
41 | DECLARE_UVC_HEADER_DESCRIPTOR(1); | 128 | DECLARE_UVC_HEADER_DESCRIPTOR(1); |
42 | 129 | ||
43 | struct uvcg_control_header { | 130 | struct uvcg_control_header { |
@@ -51,9 +138,9 @@ static struct uvcg_control_header *to_uvcg_control_header(struct config_item *it | |||
51 | return container_of(item, struct uvcg_control_header, item); | 138 | return container_of(item, struct uvcg_control_header, item); |
52 | } | 139 | } |
53 | 140 | ||
54 | #define UVCG_CTRL_HDR_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \ | 141 | #define UVCG_CTRL_HDR_ATTR(cname, aname, bits, limit) \ |
55 | static ssize_t uvcg_control_header_##cname##_show( \ | 142 | static ssize_t uvcg_control_header_##cname##_show( \ |
56 | struct config_item *item, char *page) \ | 143 | struct config_item *item, char *page) \ |
57 | { \ | 144 | { \ |
58 | struct uvcg_control_header *ch = to_uvcg_control_header(item); \ | 145 | struct uvcg_control_header *ch = to_uvcg_control_header(item); \ |
59 | struct f_uvc_opts *opts; \ | 146 | struct f_uvc_opts *opts; \ |
@@ -67,7 +154,7 @@ static ssize_t uvcg_control_header_##cname##_show( \ | |||
67 | opts = to_f_uvc_opts(opts_item); \ | 154 | opts = to_f_uvc_opts(opts_item); \ |
68 | \ | 155 | \ |
69 | mutex_lock(&opts->lock); \ | 156 | mutex_lock(&opts->lock); \ |
70 | result = sprintf(page, "%d\n", conv(ch->desc.aname)); \ | 157 | result = sprintf(page, "%u\n", le##bits##_to_cpu(ch->desc.aname));\ |
71 | mutex_unlock(&opts->lock); \ | 158 | mutex_unlock(&opts->lock); \ |
72 | \ | 159 | \ |
73 | mutex_unlock(su_mutex); \ | 160 | mutex_unlock(su_mutex); \ |
@@ -83,7 +170,7 @@ uvcg_control_header_##cname##_store(struct config_item *item, \ | |||
83 | struct config_item *opts_item; \ | 170 | struct config_item *opts_item; \ |
84 | struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;\ | 171 | struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;\ |
85 | int ret; \ | 172 | int ret; \ |
86 | uxx num; \ | 173 | u##bits num; \ |
87 | \ | 174 | \ |
88 | mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ | 175 | mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ |
89 | \ | 176 | \ |
@@ -96,7 +183,7 @@ uvcg_control_header_##cname##_store(struct config_item *item, \ | |||
96 | goto end; \ | 183 | goto end; \ |
97 | } \ | 184 | } \ |
98 | \ | 185 | \ |
99 | ret = str2u(page, 0, &num); \ | 186 | ret = kstrtou##bits(page, 0, &num); \ |
100 | if (ret) \ | 187 | if (ret) \ |
101 | goto end; \ | 188 | goto end; \ |
102 | \ | 189 | \ |
@@ -104,7 +191,7 @@ uvcg_control_header_##cname##_store(struct config_item *item, \ | |||
104 | ret = -EINVAL; \ | 191 | ret = -EINVAL; \ |
105 | goto end; \ | 192 | goto end; \ |
106 | } \ | 193 | } \ |
107 | ch->desc.aname = vnoc(num); \ | 194 | ch->desc.aname = cpu_to_le##bits(num); \ |
108 | ret = len; \ | 195 | ret = len; \ |
109 | end: \ | 196 | end: \ |
110 | mutex_unlock(&opts->lock); \ | 197 | mutex_unlock(&opts->lock); \ |
@@ -114,11 +201,9 @@ end: \ | |||
114 | \ | 201 | \ |
115 | UVC_ATTR(uvcg_control_header_, cname, aname) | 202 | UVC_ATTR(uvcg_control_header_, cname, aname) |
116 | 203 | ||
117 | UVCG_CTRL_HDR_ATTR(bcd_uvc, bcdUVC, le16_to_cpu, kstrtou16, u16, cpu_to_le16, | 204 | UVCG_CTRL_HDR_ATTR(bcd_uvc, bcdUVC, 16, 0xffff); |
118 | 0xffff); | ||
119 | 205 | ||
120 | UVCG_CTRL_HDR_ATTR(dw_clock_frequency, dwClockFrequency, le32_to_cpu, kstrtou32, | 206 | UVCG_CTRL_HDR_ATTR(dw_clock_frequency, dwClockFrequency, 32, 0x7fffffff); |
121 | u32, cpu_to_le32, 0x7fffffff); | ||
122 | 207 | ||
123 | #undef UVCG_CTRL_HDR_ATTR | 208 | #undef UVCG_CTRL_HDR_ATTR |
124 | 209 | ||
@@ -129,6 +214,7 @@ static struct configfs_attribute *uvcg_control_header_attrs[] = { | |||
129 | }; | 214 | }; |
130 | 215 | ||
131 | static const struct config_item_type uvcg_control_header_type = { | 216 | static const struct config_item_type uvcg_control_header_type = { |
217 | .ct_item_ops = &uvcg_config_item_ops, | ||
132 | .ct_attrs = uvcg_control_header_attrs, | 218 | .ct_attrs = uvcg_control_header_attrs, |
133 | .ct_owner = THIS_MODULE, | 219 | .ct_owner = THIS_MODULE, |
134 | }; | 220 | }; |
@@ -153,60 +239,42 @@ static struct config_item *uvcg_control_header_make(struct config_group *group, | |||
153 | return &h->item; | 239 | return &h->item; |
154 | } | 240 | } |
155 | 241 | ||
156 | static void uvcg_control_header_drop(struct config_group *group, | ||
157 | struct config_item *item) | ||
158 | { | ||
159 | struct uvcg_control_header *h = to_uvcg_control_header(item); | ||
160 | |||
161 | kfree(h); | ||
162 | } | ||
163 | |||
164 | /* control/header */ | ||
165 | static struct uvcg_control_header_grp { | ||
166 | struct config_group group; | ||
167 | } uvcg_control_header_grp; | ||
168 | |||
169 | static struct configfs_group_operations uvcg_control_header_grp_ops = { | 242 | static struct configfs_group_operations uvcg_control_header_grp_ops = { |
170 | .make_item = uvcg_control_header_make, | 243 | .make_item = uvcg_control_header_make, |
171 | .drop_item = uvcg_control_header_drop, | ||
172 | }; | 244 | }; |
173 | 245 | ||
174 | static const struct config_item_type uvcg_control_header_grp_type = { | 246 | static const struct uvcg_config_group_type uvcg_control_header_grp_type = { |
175 | .ct_group_ops = &uvcg_control_header_grp_ops, | 247 | .type = { |
176 | .ct_owner = THIS_MODULE, | 248 | .ct_item_ops = &uvcg_config_item_ops, |
249 | .ct_group_ops = &uvcg_control_header_grp_ops, | ||
250 | .ct_owner = THIS_MODULE, | ||
251 | }, | ||
252 | .name = "header", | ||
177 | }; | 253 | }; |
178 | 254 | ||
179 | /* control/processing/default */ | 255 | /* ----------------------------------------------------------------------------- |
180 | static struct uvcg_default_processing { | 256 | * control/processing/default |
181 | struct config_group group; | 257 | */ |
182 | } uvcg_default_processing; | ||
183 | |||
184 | static inline struct uvcg_default_processing | ||
185 | *to_uvcg_default_processing(struct config_item *item) | ||
186 | { | ||
187 | return container_of(to_config_group(item), | ||
188 | struct uvcg_default_processing, group); | ||
189 | } | ||
190 | 258 | ||
191 | #define UVCG_DEFAULT_PROCESSING_ATTR(cname, aname, conv) \ | 259 | #define UVCG_DEFAULT_PROCESSING_ATTR(cname, aname, bits) \ |
192 | static ssize_t uvcg_default_processing_##cname##_show( \ | 260 | static ssize_t uvcg_default_processing_##cname##_show( \ |
193 | struct config_item *item, char *page) \ | 261 | struct config_item *item, char *page) \ |
194 | { \ | 262 | { \ |
195 | struct uvcg_default_processing *dp = to_uvcg_default_processing(item); \ | 263 | struct config_group *group = to_config_group(item); \ |
196 | struct f_uvc_opts *opts; \ | 264 | struct f_uvc_opts *opts; \ |
197 | struct config_item *opts_item; \ | 265 | struct config_item *opts_item; \ |
198 | struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex; \ | 266 | struct mutex *su_mutex = &group->cg_subsys->su_mutex; \ |
199 | struct uvc_processing_unit_descriptor *pd; \ | 267 | struct uvc_processing_unit_descriptor *pd; \ |
200 | int result; \ | 268 | int result; \ |
201 | \ | 269 | \ |
202 | mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ | 270 | mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ |
203 | \ | 271 | \ |
204 | opts_item = dp->group.cg_item.ci_parent->ci_parent->ci_parent; \ | 272 | opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; \ |
205 | opts = to_f_uvc_opts(opts_item); \ | 273 | opts = to_f_uvc_opts(opts_item); \ |
206 | pd = &opts->uvc_processing; \ | 274 | pd = &opts->uvc_processing; \ |
207 | \ | 275 | \ |
208 | mutex_lock(&opts->lock); \ | 276 | mutex_lock(&opts->lock); \ |
209 | result = sprintf(page, "%d\n", conv(pd->aname)); \ | 277 | result = sprintf(page, "%u\n", le##bits##_to_cpu(pd->aname)); \ |
210 | mutex_unlock(&opts->lock); \ | 278 | mutex_unlock(&opts->lock); \ |
211 | \ | 279 | \ |
212 | mutex_unlock(su_mutex); \ | 280 | mutex_unlock(su_mutex); \ |
@@ -215,37 +283,33 @@ static ssize_t uvcg_default_processing_##cname##_show( \ | |||
215 | \ | 283 | \ |
216 | UVC_ATTR_RO(uvcg_default_processing_, cname, aname) | 284 | UVC_ATTR_RO(uvcg_default_processing_, cname, aname) |
217 | 285 | ||
218 | #define identity_conv(x) (x) | 286 | UVCG_DEFAULT_PROCESSING_ATTR(b_unit_id, bUnitID, 8); |
219 | 287 | UVCG_DEFAULT_PROCESSING_ATTR(b_source_id, bSourceID, 8); | |
220 | UVCG_DEFAULT_PROCESSING_ATTR(b_unit_id, bUnitID, identity_conv); | 288 | UVCG_DEFAULT_PROCESSING_ATTR(w_max_multiplier, wMaxMultiplier, 16); |
221 | UVCG_DEFAULT_PROCESSING_ATTR(b_source_id, bSourceID, identity_conv); | 289 | UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, 8); |
222 | UVCG_DEFAULT_PROCESSING_ATTR(w_max_multiplier, wMaxMultiplier, le16_to_cpu); | ||
223 | UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, identity_conv); | ||
224 | |||
225 | #undef identity_conv | ||
226 | 290 | ||
227 | #undef UVCG_DEFAULT_PROCESSING_ATTR | 291 | #undef UVCG_DEFAULT_PROCESSING_ATTR |
228 | 292 | ||
229 | static ssize_t uvcg_default_processing_bm_controls_show( | 293 | static ssize_t uvcg_default_processing_bm_controls_show( |
230 | struct config_item *item, char *page) | 294 | struct config_item *item, char *page) |
231 | { | 295 | { |
232 | struct uvcg_default_processing *dp = to_uvcg_default_processing(item); | 296 | struct config_group *group = to_config_group(item); |
233 | struct f_uvc_opts *opts; | 297 | struct f_uvc_opts *opts; |
234 | struct config_item *opts_item; | 298 | struct config_item *opts_item; |
235 | struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex; | 299 | struct mutex *su_mutex = &group->cg_subsys->su_mutex; |
236 | struct uvc_processing_unit_descriptor *pd; | 300 | struct uvc_processing_unit_descriptor *pd; |
237 | int result, i; | 301 | int result, i; |
238 | char *pg = page; | 302 | char *pg = page; |
239 | 303 | ||
240 | mutex_lock(su_mutex); /* for navigating configfs hierarchy */ | 304 | mutex_lock(su_mutex); /* for navigating configfs hierarchy */ |
241 | 305 | ||
242 | opts_item = dp->group.cg_item.ci_parent->ci_parent->ci_parent; | 306 | opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; |
243 | opts = to_f_uvc_opts(opts_item); | 307 | opts = to_f_uvc_opts(opts_item); |
244 | pd = &opts->uvc_processing; | 308 | pd = &opts->uvc_processing; |
245 | 309 | ||
246 | mutex_lock(&opts->lock); | 310 | mutex_lock(&opts->lock); |
247 | for (result = 0, i = 0; i < pd->bControlSize; ++i) { | 311 | for (result = 0, i = 0; i < pd->bControlSize; ++i) { |
248 | result += sprintf(pg, "%d\n", pd->bmControls[i]); | 312 | result += sprintf(pg, "%u\n", pd->bmControls[i]); |
249 | pg = page + result; | 313 | pg = page + result; |
250 | } | 314 | } |
251 | mutex_unlock(&opts->lock); | 315 | mutex_unlock(&opts->lock); |
@@ -266,54 +330,55 @@ static struct configfs_attribute *uvcg_default_processing_attrs[] = { | |||
266 | NULL, | 330 | NULL, |
267 | }; | 331 | }; |
268 | 332 | ||
269 | static const struct config_item_type uvcg_default_processing_type = { | 333 | static const struct uvcg_config_group_type uvcg_default_processing_type = { |
270 | .ct_attrs = uvcg_default_processing_attrs, | 334 | .type = { |
271 | .ct_owner = THIS_MODULE, | 335 | .ct_item_ops = &uvcg_config_item_ops, |
336 | .ct_attrs = uvcg_default_processing_attrs, | ||
337 | .ct_owner = THIS_MODULE, | ||
338 | }, | ||
339 | .name = "default", | ||
272 | }; | 340 | }; |
273 | 341 | ||
274 | /* struct uvcg_processing {}; */ | 342 | /* ----------------------------------------------------------------------------- |
275 | 343 | * control/processing | |
276 | /* control/processing */ | 344 | */ |
277 | static struct uvcg_processing_grp { | ||
278 | struct config_group group; | ||
279 | } uvcg_processing_grp; | ||
280 | 345 | ||
281 | static const struct config_item_type uvcg_processing_grp_type = { | 346 | static const struct uvcg_config_group_type uvcg_processing_grp_type = { |
282 | .ct_owner = THIS_MODULE, | 347 | .type = { |
348 | .ct_item_ops = &uvcg_config_item_ops, | ||
349 | .ct_owner = THIS_MODULE, | ||
350 | }, | ||
351 | .name = "processing", | ||
352 | .children = (const struct uvcg_config_group_type*[]) { | ||
353 | &uvcg_default_processing_type, | ||
354 | NULL, | ||
355 | }, | ||
283 | }; | 356 | }; |
284 | 357 | ||
285 | /* control/terminal/camera/default */ | 358 | /* ----------------------------------------------------------------------------- |
286 | static struct uvcg_default_camera { | 359 | * control/terminal/camera/default |
287 | struct config_group group; | 360 | */ |
288 | } uvcg_default_camera; | ||
289 | |||
290 | static inline struct uvcg_default_camera | ||
291 | *to_uvcg_default_camera(struct config_item *item) | ||
292 | { | ||
293 | return container_of(to_config_group(item), | ||
294 | struct uvcg_default_camera, group); | ||
295 | } | ||
296 | 361 | ||
297 | #define UVCG_DEFAULT_CAMERA_ATTR(cname, aname, conv) \ | 362 | #define UVCG_DEFAULT_CAMERA_ATTR(cname, aname, bits) \ |
298 | static ssize_t uvcg_default_camera_##cname##_show( \ | 363 | static ssize_t uvcg_default_camera_##cname##_show( \ |
299 | struct config_item *item, char *page) \ | 364 | struct config_item *item, char *page) \ |
300 | { \ | 365 | { \ |
301 | struct uvcg_default_camera *dc = to_uvcg_default_camera(item); \ | 366 | struct config_group *group = to_config_group(item); \ |
302 | struct f_uvc_opts *opts; \ | 367 | struct f_uvc_opts *opts; \ |
303 | struct config_item *opts_item; \ | 368 | struct config_item *opts_item; \ |
304 | struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; \ | 369 | struct mutex *su_mutex = &group->cg_subsys->su_mutex; \ |
305 | struct uvc_camera_terminal_descriptor *cd; \ | 370 | struct uvc_camera_terminal_descriptor *cd; \ |
306 | int result; \ | 371 | int result; \ |
307 | \ | 372 | \ |
308 | mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ | 373 | mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ |
309 | \ | 374 | \ |
310 | opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent-> \ | 375 | opts_item = group->cg_item.ci_parent->ci_parent->ci_parent-> \ |
311 | ci_parent; \ | 376 | ci_parent; \ |
312 | opts = to_f_uvc_opts(opts_item); \ | 377 | opts = to_f_uvc_opts(opts_item); \ |
313 | cd = &opts->uvc_camera_terminal; \ | 378 | cd = &opts->uvc_camera_terminal; \ |
314 | \ | 379 | \ |
315 | mutex_lock(&opts->lock); \ | 380 | mutex_lock(&opts->lock); \ |
316 | result = sprintf(page, "%d\n", conv(cd->aname)); \ | 381 | result = sprintf(page, "%u\n", le##bits##_to_cpu(cd->aname)); \ |
317 | mutex_unlock(&opts->lock); \ | 382 | mutex_unlock(&opts->lock); \ |
318 | \ | 383 | \ |
319 | mutex_unlock(su_mutex); \ | 384 | mutex_unlock(su_mutex); \ |
@@ -323,44 +388,40 @@ static ssize_t uvcg_default_camera_##cname##_show( \ | |||
323 | \ | 388 | \ |
324 | UVC_ATTR_RO(uvcg_default_camera_, cname, aname) | 389 | UVC_ATTR_RO(uvcg_default_camera_, cname, aname) |
325 | 390 | ||
326 | #define identity_conv(x) (x) | 391 | UVCG_DEFAULT_CAMERA_ATTR(b_terminal_id, bTerminalID, 8); |
327 | 392 | UVCG_DEFAULT_CAMERA_ATTR(w_terminal_type, wTerminalType, 16); | |
328 | UVCG_DEFAULT_CAMERA_ATTR(b_terminal_id, bTerminalID, identity_conv); | 393 | UVCG_DEFAULT_CAMERA_ATTR(b_assoc_terminal, bAssocTerminal, 8); |
329 | UVCG_DEFAULT_CAMERA_ATTR(w_terminal_type, wTerminalType, le16_to_cpu); | 394 | UVCG_DEFAULT_CAMERA_ATTR(i_terminal, iTerminal, 8); |
330 | UVCG_DEFAULT_CAMERA_ATTR(b_assoc_terminal, bAssocTerminal, identity_conv); | ||
331 | UVCG_DEFAULT_CAMERA_ATTR(i_terminal, iTerminal, identity_conv); | ||
332 | UVCG_DEFAULT_CAMERA_ATTR(w_objective_focal_length_min, wObjectiveFocalLengthMin, | 395 | UVCG_DEFAULT_CAMERA_ATTR(w_objective_focal_length_min, wObjectiveFocalLengthMin, |
333 | le16_to_cpu); | 396 | 16); |
334 | UVCG_DEFAULT_CAMERA_ATTR(w_objective_focal_length_max, wObjectiveFocalLengthMax, | 397 | UVCG_DEFAULT_CAMERA_ATTR(w_objective_focal_length_max, wObjectiveFocalLengthMax, |
335 | le16_to_cpu); | 398 | 16); |
336 | UVCG_DEFAULT_CAMERA_ATTR(w_ocular_focal_length, wOcularFocalLength, | 399 | UVCG_DEFAULT_CAMERA_ATTR(w_ocular_focal_length, wOcularFocalLength, |
337 | le16_to_cpu); | 400 | 16); |
338 | |||
339 | #undef identity_conv | ||
340 | 401 | ||
341 | #undef UVCG_DEFAULT_CAMERA_ATTR | 402 | #undef UVCG_DEFAULT_CAMERA_ATTR |
342 | 403 | ||
343 | static ssize_t uvcg_default_camera_bm_controls_show( | 404 | static ssize_t uvcg_default_camera_bm_controls_show( |
344 | struct config_item *item, char *page) | 405 | struct config_item *item, char *page) |
345 | { | 406 | { |
346 | struct uvcg_default_camera *dc = to_uvcg_default_camera(item); | 407 | struct config_group *group = to_config_group(item); |
347 | struct f_uvc_opts *opts; | 408 | struct f_uvc_opts *opts; |
348 | struct config_item *opts_item; | 409 | struct config_item *opts_item; |
349 | struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; | 410 | struct mutex *su_mutex = &group->cg_subsys->su_mutex; |
350 | struct uvc_camera_terminal_descriptor *cd; | 411 | struct uvc_camera_terminal_descriptor *cd; |
351 | int result, i; | 412 | int result, i; |
352 | char *pg = page; | 413 | char *pg = page; |
353 | 414 | ||
354 | mutex_lock(su_mutex); /* for navigating configfs hierarchy */ | 415 | mutex_lock(su_mutex); /* for navigating configfs hierarchy */ |
355 | 416 | ||
356 | opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent-> | 417 | opts_item = group->cg_item.ci_parent->ci_parent->ci_parent-> |
357 | ci_parent; | 418 | ci_parent; |
358 | opts = to_f_uvc_opts(opts_item); | 419 | opts = to_f_uvc_opts(opts_item); |
359 | cd = &opts->uvc_camera_terminal; | 420 | cd = &opts->uvc_camera_terminal; |
360 | 421 | ||
361 | mutex_lock(&opts->lock); | 422 | mutex_lock(&opts->lock); |
362 | for (result = 0, i = 0; i < cd->bControlSize; ++i) { | 423 | for (result = 0, i = 0; i < cd->bControlSize; ++i) { |
363 | result += sprintf(pg, "%d\n", cd->bmControls[i]); | 424 | result += sprintf(pg, "%u\n", cd->bmControls[i]); |
364 | pg = page + result; | 425 | pg = page + result; |
365 | } | 426 | } |
366 | mutex_unlock(&opts->lock); | 427 | mutex_unlock(&opts->lock); |
@@ -383,54 +444,55 @@ static struct configfs_attribute *uvcg_default_camera_attrs[] = { | |||
383 | NULL, | 444 | NULL, |
384 | }; | 445 | }; |
385 | 446 | ||
386 | static const struct config_item_type uvcg_default_camera_type = { | 447 | static const struct uvcg_config_group_type uvcg_default_camera_type = { |
387 | .ct_attrs = uvcg_default_camera_attrs, | 448 | .type = { |
388 | .ct_owner = THIS_MODULE, | 449 | .ct_item_ops = &uvcg_config_item_ops, |
450 | .ct_attrs = uvcg_default_camera_attrs, | ||
451 | .ct_owner = THIS_MODULE, | ||
452 | }, | ||
453 | .name = "default", | ||
389 | }; | 454 | }; |
390 | 455 | ||
391 | /* struct uvcg_camera {}; */ | 456 | /* ----------------------------------------------------------------------------- |
392 | 457 | * control/terminal/camera | |
393 | /* control/terminal/camera */ | 458 | */ |
394 | static struct uvcg_camera_grp { | ||
395 | struct config_group group; | ||
396 | } uvcg_camera_grp; | ||
397 | 459 | ||
398 | static const struct config_item_type uvcg_camera_grp_type = { | 460 | static const struct uvcg_config_group_type uvcg_camera_grp_type = { |
399 | .ct_owner = THIS_MODULE, | 461 | .type = { |
462 | .ct_item_ops = &uvcg_config_item_ops, | ||
463 | .ct_owner = THIS_MODULE, | ||
464 | }, | ||
465 | .name = "camera", | ||
466 | .children = (const struct uvcg_config_group_type*[]) { | ||
467 | &uvcg_default_camera_type, | ||
468 | NULL, | ||
469 | }, | ||
400 | }; | 470 | }; |
401 | 471 | ||
402 | /* control/terminal/output/default */ | 472 | /* ----------------------------------------------------------------------------- |
403 | static struct uvcg_default_output { | 473 | * control/terminal/output/default |
404 | struct config_group group; | 474 | */ |
405 | } uvcg_default_output; | ||
406 | |||
407 | static inline struct uvcg_default_output | ||
408 | *to_uvcg_default_output(struct config_item *item) | ||
409 | { | ||
410 | return container_of(to_config_group(item), | ||
411 | struct uvcg_default_output, group); | ||
412 | } | ||
413 | 475 | ||
414 | #define UVCG_DEFAULT_OUTPUT_ATTR(cname, aname, conv) \ | 476 | #define UVCG_DEFAULT_OUTPUT_ATTR(cname, aname, bits) \ |
415 | static ssize_t uvcg_default_output_##cname##_show( \ | 477 | static ssize_t uvcg_default_output_##cname##_show( \ |
416 | struct config_item *item, char *page) \ | 478 | struct config_item *item, char *page) \ |
417 | { \ | 479 | { \ |
418 | struct uvcg_default_output *dout = to_uvcg_default_output(item); \ | 480 | struct config_group *group = to_config_group(item); \ |
419 | struct f_uvc_opts *opts; \ | 481 | struct f_uvc_opts *opts; \ |
420 | struct config_item *opts_item; \ | 482 | struct config_item *opts_item; \ |
421 | struct mutex *su_mutex = &dout->group.cg_subsys->su_mutex; \ | 483 | struct mutex *su_mutex = &group->cg_subsys->su_mutex; \ |
422 | struct uvc_output_terminal_descriptor *cd; \ | 484 | struct uvc_output_terminal_descriptor *cd; \ |
423 | int result; \ | 485 | int result; \ |
424 | \ | 486 | \ |
425 | mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ | 487 | mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ |
426 | \ | 488 | \ |
427 | opts_item = dout->group.cg_item.ci_parent->ci_parent-> \ | 489 | opts_item = group->cg_item.ci_parent->ci_parent-> \ |
428 | ci_parent->ci_parent; \ | 490 | ci_parent->ci_parent; \ |
429 | opts = to_f_uvc_opts(opts_item); \ | 491 | opts = to_f_uvc_opts(opts_item); \ |
430 | cd = &opts->uvc_output_terminal; \ | 492 | cd = &opts->uvc_output_terminal; \ |
431 | \ | 493 | \ |
432 | mutex_lock(&opts->lock); \ | 494 | mutex_lock(&opts->lock); \ |
433 | result = sprintf(page, "%d\n", conv(cd->aname)); \ | 495 | result = sprintf(page, "%u\n", le##bits##_to_cpu(cd->aname)); \ |
434 | mutex_unlock(&opts->lock); \ | 496 | mutex_unlock(&opts->lock); \ |
435 | \ | 497 | \ |
436 | mutex_unlock(su_mutex); \ | 498 | mutex_unlock(su_mutex); \ |
@@ -440,15 +502,11 @@ static ssize_t uvcg_default_output_##cname##_show( \ | |||
440 | \ | 502 | \ |
441 | UVC_ATTR_RO(uvcg_default_output_, cname, aname) | 503 | UVC_ATTR_RO(uvcg_default_output_, cname, aname) |
442 | 504 | ||
443 | #define identity_conv(x) (x) | 505 | UVCG_DEFAULT_OUTPUT_ATTR(b_terminal_id, bTerminalID, 8); |
444 | 506 | UVCG_DEFAULT_OUTPUT_ATTR(w_terminal_type, wTerminalType, 16); | |
445 | UVCG_DEFAULT_OUTPUT_ATTR(b_terminal_id, bTerminalID, identity_conv); | 507 | UVCG_DEFAULT_OUTPUT_ATTR(b_assoc_terminal, bAssocTerminal, 8); |
446 | UVCG_DEFAULT_OUTPUT_ATTR(w_terminal_type, wTerminalType, le16_to_cpu); | 508 | UVCG_DEFAULT_OUTPUT_ATTR(b_source_id, bSourceID, 8); |
447 | UVCG_DEFAULT_OUTPUT_ATTR(b_assoc_terminal, bAssocTerminal, identity_conv); | 509 | UVCG_DEFAULT_OUTPUT_ATTR(i_terminal, iTerminal, 8); |
448 | UVCG_DEFAULT_OUTPUT_ATTR(b_source_id, bSourceID, identity_conv); | ||
449 | UVCG_DEFAULT_OUTPUT_ATTR(i_terminal, iTerminal, identity_conv); | ||
450 | |||
451 | #undef identity_conv | ||
452 | 510 | ||
453 | #undef UVCG_DEFAULT_OUTPUT_ATTR | 511 | #undef UVCG_DEFAULT_OUTPUT_ATTR |
454 | 512 | ||
@@ -461,47 +519,68 @@ static struct configfs_attribute *uvcg_default_output_attrs[] = { | |||
461 | NULL, | 519 | NULL, |
462 | }; | 520 | }; |
463 | 521 | ||
464 | static const struct config_item_type uvcg_default_output_type = { | 522 | static const struct uvcg_config_group_type uvcg_default_output_type = { |
465 | .ct_attrs = uvcg_default_output_attrs, | 523 | .type = { |
466 | .ct_owner = THIS_MODULE, | 524 | .ct_item_ops = &uvcg_config_item_ops, |
525 | .ct_attrs = uvcg_default_output_attrs, | ||
526 | .ct_owner = THIS_MODULE, | ||
527 | }, | ||
528 | .name = "default", | ||
467 | }; | 529 | }; |
468 | 530 | ||
469 | /* struct uvcg_output {}; */ | 531 | /* ----------------------------------------------------------------------------- |
470 | 532 | * control/terminal/output | |
471 | /* control/terminal/output */ | 533 | */ |
472 | static struct uvcg_output_grp { | ||
473 | struct config_group group; | ||
474 | } uvcg_output_grp; | ||
475 | 534 | ||
476 | static const struct config_item_type uvcg_output_grp_type = { | 535 | static const struct uvcg_config_group_type uvcg_output_grp_type = { |
477 | .ct_owner = THIS_MODULE, | 536 | .type = { |
537 | .ct_item_ops = &uvcg_config_item_ops, | ||
538 | .ct_owner = THIS_MODULE, | ||
539 | }, | ||
540 | .name = "output", | ||
541 | .children = (const struct uvcg_config_group_type*[]) { | ||
542 | &uvcg_default_output_type, | ||
543 | NULL, | ||
544 | }, | ||
478 | }; | 545 | }; |
479 | 546 | ||
480 | /* control/terminal */ | 547 | /* ----------------------------------------------------------------------------- |
481 | static struct uvcg_terminal_grp { | 548 | * control/terminal |
482 | struct config_group group; | 549 | */ |
483 | } uvcg_terminal_grp; | ||
484 | 550 | ||
485 | static const struct config_item_type uvcg_terminal_grp_type = { | 551 | static const struct uvcg_config_group_type uvcg_terminal_grp_type = { |
486 | .ct_owner = THIS_MODULE, | 552 | .type = { |
553 | .ct_item_ops = &uvcg_config_item_ops, | ||
554 | .ct_owner = THIS_MODULE, | ||
555 | }, | ||
556 | .name = "terminal", | ||
557 | .children = (const struct uvcg_config_group_type*[]) { | ||
558 | &uvcg_camera_grp_type, | ||
559 | &uvcg_output_grp_type, | ||
560 | NULL, | ||
561 | }, | ||
487 | }; | 562 | }; |
488 | 563 | ||
489 | /* control/class/{fs} */ | 564 | /* ----------------------------------------------------------------------------- |
490 | static struct uvcg_control_class { | 565 | * control/class/{fs|ss} |
491 | struct config_group group; | 566 | */ |
492 | } uvcg_control_class_fs, uvcg_control_class_ss; | ||
493 | 567 | ||
568 | struct uvcg_control_class_group { | ||
569 | struct config_group group; | ||
570 | const char *name; | ||
571 | }; | ||
494 | 572 | ||
495 | static inline struct uvc_descriptor_header | 573 | static inline struct uvc_descriptor_header |
496 | **uvcg_get_ctl_class_arr(struct config_item *i, struct f_uvc_opts *o) | 574 | **uvcg_get_ctl_class_arr(struct config_item *i, struct f_uvc_opts *o) |
497 | { | 575 | { |
498 | struct uvcg_control_class *cl = container_of(to_config_group(i), | 576 | struct uvcg_control_class_group *group = |
499 | struct uvcg_control_class, group); | 577 | container_of(i, struct uvcg_control_class_group, |
578 | group.cg_item); | ||
500 | 579 | ||
501 | if (cl == &uvcg_control_class_fs) | 580 | if (!strcmp(group->name, "fs")) |
502 | return o->uvc_fs_control_cls; | 581 | return o->uvc_fs_control_cls; |
503 | 582 | ||
504 | if (cl == &uvcg_control_class_ss) | 583 | if (!strcmp(group->name, "ss")) |
505 | return o->uvc_ss_control_cls; | 584 | return o->uvc_ss_control_cls; |
506 | 585 | ||
507 | return NULL; | 586 | return NULL; |
@@ -544,6 +623,7 @@ static int uvcg_control_class_allow_link(struct config_item *src, | |||
544 | unlock: | 623 | unlock: |
545 | mutex_unlock(&opts->lock); | 624 | mutex_unlock(&opts->lock); |
546 | out: | 625 | out: |
626 | config_item_put(header); | ||
547 | mutex_unlock(su_mutex); | 627 | mutex_unlock(su_mutex); |
548 | return ret; | 628 | return ret; |
549 | } | 629 | } |
@@ -579,10 +659,12 @@ static void uvcg_control_class_drop_link(struct config_item *src, | |||
579 | unlock: | 659 | unlock: |
580 | mutex_unlock(&opts->lock); | 660 | mutex_unlock(&opts->lock); |
581 | out: | 661 | out: |
662 | config_item_put(header); | ||
582 | mutex_unlock(su_mutex); | 663 | mutex_unlock(su_mutex); |
583 | } | 664 | } |
584 | 665 | ||
585 | static struct configfs_item_operations uvcg_control_class_item_ops = { | 666 | static struct configfs_item_operations uvcg_control_class_item_ops = { |
667 | .release = uvcg_config_item_release, | ||
586 | .allow_link = uvcg_control_class_allow_link, | 668 | .allow_link = uvcg_control_class_allow_link, |
587 | .drop_link = uvcg_control_class_drop_link, | 669 | .drop_link = uvcg_control_class_drop_link, |
588 | }; | 670 | }; |
@@ -592,37 +674,99 @@ static const struct config_item_type uvcg_control_class_type = { | |||
592 | .ct_owner = THIS_MODULE, | 674 | .ct_owner = THIS_MODULE, |
593 | }; | 675 | }; |
594 | 676 | ||
595 | /* control/class */ | 677 | /* ----------------------------------------------------------------------------- |
596 | static struct uvcg_control_class_grp { | 678 | * control/class |
597 | struct config_group group; | 679 | */ |
598 | } uvcg_control_class_grp; | 680 | |
681 | static int uvcg_control_class_create_children(struct config_group *parent) | ||
682 | { | ||
683 | static const char * const names[] = { "fs", "ss" }; | ||
684 | unsigned int i; | ||
599 | 685 | ||
600 | static const struct config_item_type uvcg_control_class_grp_type = { | 686 | for (i = 0; i < ARRAY_SIZE(names); ++i) { |
601 | .ct_owner = THIS_MODULE, | 687 | struct uvcg_control_class_group *group; |
688 | |||
689 | group = kzalloc(sizeof(*group), GFP_KERNEL); | ||
690 | if (!group) | ||
691 | return -ENOMEM; | ||
692 | |||
693 | group->name = names[i]; | ||
694 | |||
695 | config_group_init_type_name(&group->group, group->name, | ||
696 | &uvcg_control_class_type); | ||
697 | configfs_add_default_group(&group->group, parent); | ||
698 | } | ||
699 | |||
700 | return 0; | ||
701 | } | ||
702 | |||
703 | static const struct uvcg_config_group_type uvcg_control_class_grp_type = { | ||
704 | .type = { | ||
705 | .ct_item_ops = &uvcg_config_item_ops, | ||
706 | .ct_owner = THIS_MODULE, | ||
707 | }, | ||
708 | .name = "class", | ||
709 | .create_children = uvcg_control_class_create_children, | ||
602 | }; | 710 | }; |
603 | 711 | ||
604 | /* control */ | 712 | /* ----------------------------------------------------------------------------- |
605 | static struct uvcg_control_grp { | 713 | * control |
606 | struct config_group group; | 714 | */ |
607 | } uvcg_control_grp; | 715 | |
716 | static ssize_t uvcg_default_control_b_interface_number_show( | ||
717 | struct config_item *item, char *page) | ||
718 | { | ||
719 | struct config_group *group = to_config_group(item); | ||
720 | struct mutex *su_mutex = &group->cg_subsys->su_mutex; | ||
721 | struct config_item *opts_item; | ||
722 | struct f_uvc_opts *opts; | ||
723 | int result = 0; | ||
724 | |||
725 | mutex_lock(su_mutex); /* for navigating configfs hierarchy */ | ||
726 | |||
727 | opts_item = item->ci_parent; | ||
728 | opts = to_f_uvc_opts(opts_item); | ||
729 | |||
730 | mutex_lock(&opts->lock); | ||
731 | result += sprintf(page, "%u\n", opts->control_interface); | ||
732 | mutex_unlock(&opts->lock); | ||
733 | |||
734 | mutex_unlock(su_mutex); | ||
735 | |||
736 | return result; | ||
737 | } | ||
738 | |||
739 | UVC_ATTR_RO(uvcg_default_control_, b_interface_number, bInterfaceNumber); | ||
608 | 740 | ||
609 | static const struct config_item_type uvcg_control_grp_type = { | 741 | static struct configfs_attribute *uvcg_default_control_attrs[] = { |
610 | .ct_owner = THIS_MODULE, | 742 | &uvcg_default_control_attr_b_interface_number, |
743 | NULL, | ||
611 | }; | 744 | }; |
612 | 745 | ||
613 | /* streaming/uncompressed */ | 746 | static const struct uvcg_config_group_type uvcg_control_grp_type = { |
614 | static struct uvcg_uncompressed_grp { | 747 | .type = { |
615 | struct config_group group; | 748 | .ct_item_ops = &uvcg_config_item_ops, |
616 | } uvcg_uncompressed_grp; | 749 | .ct_attrs = uvcg_default_control_attrs, |
750 | .ct_owner = THIS_MODULE, | ||
751 | }, | ||
752 | .name = "control", | ||
753 | .children = (const struct uvcg_config_group_type*[]) { | ||
754 | &uvcg_control_header_grp_type, | ||
755 | &uvcg_processing_grp_type, | ||
756 | &uvcg_terminal_grp_type, | ||
757 | &uvcg_control_class_grp_type, | ||
758 | NULL, | ||
759 | }, | ||
760 | }; | ||
617 | 761 | ||
618 | /* streaming/mjpeg */ | 762 | /* ----------------------------------------------------------------------------- |
619 | static struct uvcg_mjpeg_grp { | 763 | * streaming/uncompressed |
620 | struct config_group group; | 764 | * streaming/mjpeg |
621 | } uvcg_mjpeg_grp; | 765 | */ |
622 | 766 | ||
623 | static struct config_item *fmt_parent[] = { | 767 | static const char * const uvcg_format_names[] = { |
624 | &uvcg_uncompressed_grp.group.cg_item, | 768 | "uncompressed", |
625 | &uvcg_mjpeg_grp.group.cg_item, | 769 | "mjpeg", |
626 | }; | 770 | }; |
627 | 771 | ||
628 | enum uvcg_format_type { | 772 | enum uvcg_format_type { |
@@ -706,7 +850,11 @@ struct uvcg_format_ptr { | |||
706 | struct list_head entry; | 850 | struct list_head entry; |
707 | }; | 851 | }; |
708 | 852 | ||
709 | /* streaming/header/<NAME> */ | 853 | /* ----------------------------------------------------------------------------- |
854 | * streaming/header/<NAME> | ||
855 | * streaming/header | ||
856 | */ | ||
857 | |||
710 | struct uvcg_streaming_header { | 858 | struct uvcg_streaming_header { |
711 | struct config_item item; | 859 | struct config_item item; |
712 | struct uvc_input_header_descriptor desc; | 860 | struct uvc_input_header_descriptor desc; |
@@ -720,6 +868,8 @@ static struct uvcg_streaming_header *to_uvcg_streaming_header(struct config_item | |||
720 | return container_of(item, struct uvcg_streaming_header, item); | 868 | return container_of(item, struct uvcg_streaming_header, item); |
721 | } | 869 | } |
722 | 870 | ||
871 | static void uvcg_format_set_indices(struct config_group *fmt); | ||
872 | |||
723 | static int uvcg_streaming_header_allow_link(struct config_item *src, | 873 | static int uvcg_streaming_header_allow_link(struct config_item *src, |
724 | struct config_item *target) | 874 | struct config_item *target) |
725 | { | 875 | { |
@@ -744,10 +894,22 @@ static int uvcg_streaming_header_allow_link(struct config_item *src, | |||
744 | goto out; | 894 | goto out; |
745 | } | 895 | } |
746 | 896 | ||
747 | for (i = 0; i < ARRAY_SIZE(fmt_parent); ++i) | 897 | /* |
748 | if (target->ci_parent == fmt_parent[i]) | 898 | * Linking is only allowed to direct children of the format nodes |
899 | * (streaming/uncompressed or streaming/mjpeg nodes). First check that | ||
900 | * the grand-parent of the target matches the grand-parent of the source | ||
901 | * (the streaming node), and then verify that the target parent is a | ||
902 | * format node. | ||
903 | */ | ||
904 | if (src->ci_parent->ci_parent != target->ci_parent->ci_parent) | ||
905 | goto out; | ||
906 | |||
907 | for (i = 0; i < ARRAY_SIZE(uvcg_format_names); ++i) { | ||
908 | if (!strcmp(target->ci_parent->ci_name, uvcg_format_names[i])) | ||
749 | break; | 909 | break; |
750 | if (i == ARRAY_SIZE(fmt_parent)) | 910 | } |
911 | |||
912 | if (i == ARRAY_SIZE(uvcg_format_names)) | ||
751 | goto out; | 913 | goto out; |
752 | 914 | ||
753 | target_fmt = container_of(to_config_group(target), struct uvcg_format, | 915 | target_fmt = container_of(to_config_group(target), struct uvcg_format, |
@@ -755,6 +917,8 @@ static int uvcg_streaming_header_allow_link(struct config_item *src, | |||
755 | if (!target_fmt) | 917 | if (!target_fmt) |
756 | goto out; | 918 | goto out; |
757 | 919 | ||
920 | uvcg_format_set_indices(to_config_group(target)); | ||
921 | |||
758 | format_ptr = kzalloc(sizeof(*format_ptr), GFP_KERNEL); | 922 | format_ptr = kzalloc(sizeof(*format_ptr), GFP_KERNEL); |
759 | if (!format_ptr) { | 923 | if (!format_ptr) { |
760 | ret = -ENOMEM; | 924 | ret = -ENOMEM; |
@@ -764,6 +928,7 @@ static int uvcg_streaming_header_allow_link(struct config_item *src, | |||
764 | format_ptr->fmt = target_fmt; | 928 | format_ptr->fmt = target_fmt; |
765 | list_add_tail(&format_ptr->entry, &src_hdr->formats); | 929 | list_add_tail(&format_ptr->entry, &src_hdr->formats); |
766 | ++src_hdr->num_fmt; | 930 | ++src_hdr->num_fmt; |
931 | ++target_fmt->linked; | ||
767 | 932 | ||
768 | out: | 933 | out: |
769 | mutex_unlock(&opts->lock); | 934 | mutex_unlock(&opts->lock); |
@@ -801,19 +966,22 @@ static void uvcg_streaming_header_drop_link(struct config_item *src, | |||
801 | break; | 966 | break; |
802 | } | 967 | } |
803 | 968 | ||
969 | --target_fmt->linked; | ||
970 | |||
804 | out: | 971 | out: |
805 | mutex_unlock(&opts->lock); | 972 | mutex_unlock(&opts->lock); |
806 | mutex_unlock(su_mutex); | 973 | mutex_unlock(su_mutex); |
807 | } | 974 | } |
808 | 975 | ||
809 | static struct configfs_item_operations uvcg_streaming_header_item_ops = { | 976 | static struct configfs_item_operations uvcg_streaming_header_item_ops = { |
810 | .allow_link = uvcg_streaming_header_allow_link, | 977 | .release = uvcg_config_item_release, |
811 | .drop_link = uvcg_streaming_header_drop_link, | 978 | .allow_link = uvcg_streaming_header_allow_link, |
979 | .drop_link = uvcg_streaming_header_drop_link, | ||
812 | }; | 980 | }; |
813 | 981 | ||
814 | #define UVCG_STREAMING_HEADER_ATTR(cname, aname, conv) \ | 982 | #define UVCG_STREAMING_HEADER_ATTR(cname, aname, bits) \ |
815 | static ssize_t uvcg_streaming_header_##cname##_show( \ | 983 | static ssize_t uvcg_streaming_header_##cname##_show( \ |
816 | struct config_item *item, char *page) \ | 984 | struct config_item *item, char *page) \ |
817 | { \ | 985 | { \ |
818 | struct uvcg_streaming_header *sh = to_uvcg_streaming_header(item); \ | 986 | struct uvcg_streaming_header *sh = to_uvcg_streaming_header(item); \ |
819 | struct f_uvc_opts *opts; \ | 987 | struct f_uvc_opts *opts; \ |
@@ -827,7 +995,7 @@ static ssize_t uvcg_streaming_header_##cname##_show( \ | |||
827 | opts = to_f_uvc_opts(opts_item); \ | 995 | opts = to_f_uvc_opts(opts_item); \ |
828 | \ | 996 | \ |
829 | mutex_lock(&opts->lock); \ | 997 | mutex_lock(&opts->lock); \ |
830 | result = sprintf(page, "%d\n", conv(sh->desc.aname)); \ | 998 | result = sprintf(page, "%u\n", le##bits##_to_cpu(sh->desc.aname));\ |
831 | mutex_unlock(&opts->lock); \ | 999 | mutex_unlock(&opts->lock); \ |
832 | \ | 1000 | \ |
833 | mutex_unlock(su_mutex); \ | 1001 | mutex_unlock(su_mutex); \ |
@@ -836,16 +1004,11 @@ static ssize_t uvcg_streaming_header_##cname##_show( \ | |||
836 | \ | 1004 | \ |
837 | UVC_ATTR_RO(uvcg_streaming_header_, cname, aname) | 1005 | UVC_ATTR_RO(uvcg_streaming_header_, cname, aname) |
838 | 1006 | ||
839 | #define identity_conv(x) (x) | 1007 | UVCG_STREAMING_HEADER_ATTR(bm_info, bmInfo, 8); |
840 | 1008 | UVCG_STREAMING_HEADER_ATTR(b_terminal_link, bTerminalLink, 8); | |
841 | UVCG_STREAMING_HEADER_ATTR(bm_info, bmInfo, identity_conv); | 1009 | UVCG_STREAMING_HEADER_ATTR(b_still_capture_method, bStillCaptureMethod, 8); |
842 | UVCG_STREAMING_HEADER_ATTR(b_terminal_link, bTerminalLink, identity_conv); | 1010 | UVCG_STREAMING_HEADER_ATTR(b_trigger_support, bTriggerSupport, 8); |
843 | UVCG_STREAMING_HEADER_ATTR(b_still_capture_method, bStillCaptureMethod, | 1011 | UVCG_STREAMING_HEADER_ATTR(b_trigger_usage, bTriggerUsage, 8); |
844 | identity_conv); | ||
845 | UVCG_STREAMING_HEADER_ATTR(b_trigger_support, bTriggerSupport, identity_conv); | ||
846 | UVCG_STREAMING_HEADER_ATTR(b_trigger_usage, bTriggerUsage, identity_conv); | ||
847 | |||
848 | #undef identity_conv | ||
849 | 1012 | ||
850 | #undef UVCG_STREAMING_HEADER_ATTR | 1013 | #undef UVCG_STREAMING_HEADER_ATTR |
851 | 1014 | ||
@@ -884,31 +1047,26 @@ static struct config_item | |||
884 | return &h->item; | 1047 | return &h->item; |
885 | } | 1048 | } |
886 | 1049 | ||
887 | static void uvcg_streaming_header_drop(struct config_group *group, | ||
888 | struct config_item *item) | ||
889 | { | ||
890 | struct uvcg_streaming_header *h = to_uvcg_streaming_header(item); | ||
891 | |||
892 | kfree(h); | ||
893 | } | ||
894 | |||
895 | /* streaming/header */ | ||
896 | static struct uvcg_streaming_header_grp { | ||
897 | struct config_group group; | ||
898 | } uvcg_streaming_header_grp; | ||
899 | |||
900 | static struct configfs_group_operations uvcg_streaming_header_grp_ops = { | 1050 | static struct configfs_group_operations uvcg_streaming_header_grp_ops = { |
901 | .make_item = uvcg_streaming_header_make, | 1051 | .make_item = uvcg_streaming_header_make, |
902 | .drop_item = uvcg_streaming_header_drop, | ||
903 | }; | 1052 | }; |
904 | 1053 | ||
905 | static const struct config_item_type uvcg_streaming_header_grp_type = { | 1054 | static const struct uvcg_config_group_type uvcg_streaming_header_grp_type = { |
906 | .ct_group_ops = &uvcg_streaming_header_grp_ops, | 1055 | .type = { |
907 | .ct_owner = THIS_MODULE, | 1056 | .ct_item_ops = &uvcg_config_item_ops, |
1057 | .ct_group_ops = &uvcg_streaming_header_grp_ops, | ||
1058 | .ct_owner = THIS_MODULE, | ||
1059 | }, | ||
1060 | .name = "header", | ||
908 | }; | 1061 | }; |
909 | 1062 | ||
910 | /* streaming/<mode>/<format>/<NAME> */ | 1063 | /* ----------------------------------------------------------------------------- |
1064 | * streaming/<mode>/<format>/<NAME> | ||
1065 | */ | ||
1066 | |||
911 | struct uvcg_frame { | 1067 | struct uvcg_frame { |
1068 | struct config_item item; | ||
1069 | enum uvcg_format_type fmt_type; | ||
912 | struct { | 1070 | struct { |
913 | u8 b_length; | 1071 | u8 b_length; |
914 | u8 b_descriptor_type; | 1072 | u8 b_descriptor_type; |
@@ -924,8 +1082,6 @@ struct uvcg_frame { | |||
924 | u8 b_frame_interval_type; | 1082 | u8 b_frame_interval_type; |
925 | } __attribute__((packed)) frame; | 1083 | } __attribute__((packed)) frame; |
926 | u32 *dw_frame_interval; | 1084 | u32 *dw_frame_interval; |
927 | enum uvcg_format_type fmt_type; | ||
928 | struct config_item item; | ||
929 | }; | 1085 | }; |
930 | 1086 | ||
931 | static struct uvcg_frame *to_uvcg_frame(struct config_item *item) | 1087 | static struct uvcg_frame *to_uvcg_frame(struct config_item *item) |
@@ -933,7 +1089,7 @@ static struct uvcg_frame *to_uvcg_frame(struct config_item *item) | |||
933 | return container_of(item, struct uvcg_frame, item); | 1089 | return container_of(item, struct uvcg_frame, item); |
934 | } | 1090 | } |
935 | 1091 | ||
936 | #define UVCG_FRAME_ATTR(cname, aname, to_cpu_endian, to_little_endian, bits) \ | 1092 | #define UVCG_FRAME_ATTR(cname, aname, bits) \ |
937 | static ssize_t uvcg_frame_##cname##_show(struct config_item *item, char *page)\ | 1093 | static ssize_t uvcg_frame_##cname##_show(struct config_item *item, char *page)\ |
938 | { \ | 1094 | { \ |
939 | struct uvcg_frame *f = to_uvcg_frame(item); \ | 1095 | struct uvcg_frame *f = to_uvcg_frame(item); \ |
@@ -948,7 +1104,7 @@ static ssize_t uvcg_frame_##cname##_show(struct config_item *item, char *page)\ | |||
948 | opts = to_f_uvc_opts(opts_item); \ | 1104 | opts = to_f_uvc_opts(opts_item); \ |
949 | \ | 1105 | \ |
950 | mutex_lock(&opts->lock); \ | 1106 | mutex_lock(&opts->lock); \ |
951 | result = sprintf(page, "%d\n", to_cpu_endian(f->frame.cname)); \ | 1107 | result = sprintf(page, "%u\n", f->frame.cname); \ |
952 | mutex_unlock(&opts->lock); \ | 1108 | mutex_unlock(&opts->lock); \ |
953 | \ | 1109 | \ |
954 | mutex_unlock(su_mutex); \ | 1110 | mutex_unlock(su_mutex); \ |
@@ -963,8 +1119,8 @@ static ssize_t uvcg_frame_##cname##_store(struct config_item *item, \ | |||
963 | struct config_item *opts_item; \ | 1119 | struct config_item *opts_item; \ |
964 | struct uvcg_format *fmt; \ | 1120 | struct uvcg_format *fmt; \ |
965 | struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex;\ | 1121 | struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex;\ |
1122 | typeof(f->frame.cname) num; \ | ||
966 | int ret; \ | 1123 | int ret; \ |
967 | u##bits num; \ | ||
968 | \ | 1124 | \ |
969 | ret = kstrtou##bits(page, 0, &num); \ | 1125 | ret = kstrtou##bits(page, 0, &num); \ |
970 | if (ret) \ | 1126 | if (ret) \ |
@@ -982,7 +1138,7 @@ static ssize_t uvcg_frame_##cname##_store(struct config_item *item, \ | |||
982 | goto end; \ | 1138 | goto end; \ |
983 | } \ | 1139 | } \ |
984 | \ | 1140 | \ |
985 | f->frame.cname = to_little_endian(num); \ | 1141 | f->frame.cname = num; \ |
986 | ret = len; \ | 1142 | ret = len; \ |
987 | end: \ | 1143 | end: \ |
988 | mutex_unlock(&opts->lock); \ | 1144 | mutex_unlock(&opts->lock); \ |
@@ -992,20 +1148,48 @@ end: \ | |||
992 | \ | 1148 | \ |
993 | UVC_ATTR(uvcg_frame_, cname, aname); | 1149 | UVC_ATTR(uvcg_frame_, cname, aname); |
994 | 1150 | ||
995 | #define noop_conversion(x) (x) | 1151 | static ssize_t uvcg_frame_b_frame_index_show(struct config_item *item, |
1152 | char *page) | ||
1153 | { | ||
1154 | struct uvcg_frame *f = to_uvcg_frame(item); | ||
1155 | struct uvcg_format *fmt; | ||
1156 | struct f_uvc_opts *opts; | ||
1157 | struct config_item *opts_item; | ||
1158 | struct config_item *fmt_item; | ||
1159 | struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex; | ||
1160 | int result; | ||
1161 | |||
1162 | mutex_lock(su_mutex); /* for navigating configfs hierarchy */ | ||
1163 | |||
1164 | fmt_item = f->item.ci_parent; | ||
1165 | fmt = to_uvcg_format(fmt_item); | ||
996 | 1166 | ||
997 | UVCG_FRAME_ATTR(bm_capabilities, bmCapabilities, noop_conversion, | 1167 | if (!fmt->linked) { |
998 | noop_conversion, 8); | 1168 | result = -EBUSY; |
999 | UVCG_FRAME_ATTR(w_width, wWidth, le16_to_cpu, cpu_to_le16, 16); | 1169 | goto out; |
1000 | UVCG_FRAME_ATTR(w_height, wHeight, le16_to_cpu, cpu_to_le16, 16); | 1170 | } |
1001 | UVCG_FRAME_ATTR(dw_min_bit_rate, dwMinBitRate, le32_to_cpu, cpu_to_le32, 32); | ||
1002 | UVCG_FRAME_ATTR(dw_max_bit_rate, dwMaxBitRate, le32_to_cpu, cpu_to_le32, 32); | ||
1003 | UVCG_FRAME_ATTR(dw_max_video_frame_buffer_size, dwMaxVideoFrameBufferSize, | ||
1004 | le32_to_cpu, cpu_to_le32, 32); | ||
1005 | UVCG_FRAME_ATTR(dw_default_frame_interval, dwDefaultFrameInterval, | ||
1006 | le32_to_cpu, cpu_to_le32, 32); | ||
1007 | 1171 | ||
1008 | #undef noop_conversion | 1172 | opts_item = fmt_item->ci_parent->ci_parent->ci_parent; |
1173 | opts = to_f_uvc_opts(opts_item); | ||
1174 | |||
1175 | mutex_lock(&opts->lock); | ||
1176 | result = sprintf(page, "%u\n", f->frame.b_frame_index); | ||
1177 | mutex_unlock(&opts->lock); | ||
1178 | |||
1179 | out: | ||
1180 | mutex_unlock(su_mutex); | ||
1181 | return result; | ||
1182 | } | ||
1183 | |||
1184 | UVC_ATTR_RO(uvcg_frame_, b_frame_index, bFrameIndex); | ||
1185 | |||
1186 | UVCG_FRAME_ATTR(bm_capabilities, bmCapabilities, 8); | ||
1187 | UVCG_FRAME_ATTR(w_width, wWidth, 16); | ||
1188 | UVCG_FRAME_ATTR(w_height, wHeight, 16); | ||
1189 | UVCG_FRAME_ATTR(dw_min_bit_rate, dwMinBitRate, 32); | ||
1190 | UVCG_FRAME_ATTR(dw_max_bit_rate, dwMaxBitRate, 32); | ||
1191 | UVCG_FRAME_ATTR(dw_max_video_frame_buffer_size, dwMaxVideoFrameBufferSize, 32); | ||
1192 | UVCG_FRAME_ATTR(dw_default_frame_interval, dwDefaultFrameInterval, 32); | ||
1009 | 1193 | ||
1010 | #undef UVCG_FRAME_ATTR | 1194 | #undef UVCG_FRAME_ATTR |
1011 | 1195 | ||
@@ -1026,8 +1210,7 @@ static ssize_t uvcg_frame_dw_frame_interval_show(struct config_item *item, | |||
1026 | 1210 | ||
1027 | mutex_lock(&opts->lock); | 1211 | mutex_lock(&opts->lock); |
1028 | for (result = 0, i = 0; i < frm->frame.b_frame_interval_type; ++i) { | 1212 | for (result = 0, i = 0; i < frm->frame.b_frame_interval_type; ++i) { |
1029 | result += sprintf(pg, "%d\n", | 1213 | result += sprintf(pg, "%u\n", frm->dw_frame_interval[i]); |
1030 | le32_to_cpu(frm->dw_frame_interval[i])); | ||
1031 | pg = page + result; | 1214 | pg = page + result; |
1032 | } | 1215 | } |
1033 | mutex_unlock(&opts->lock); | 1216 | mutex_unlock(&opts->lock); |
@@ -1052,7 +1235,7 @@ static inline int __uvcg_fill_frm_intrv(char *buf, void *priv) | |||
1052 | return ret; | 1235 | return ret; |
1053 | 1236 | ||
1054 | interv = priv; | 1237 | interv = priv; |
1055 | **interv = cpu_to_le32(num); | 1238 | **interv = num; |
1056 | ++*interv; | 1239 | ++*interv; |
1057 | 1240 | ||
1058 | return 0; | 1241 | return 0; |
@@ -1129,6 +1312,8 @@ static ssize_t uvcg_frame_dw_frame_interval_store(struct config_item *item, | |||
1129 | kfree(ch->dw_frame_interval); | 1312 | kfree(ch->dw_frame_interval); |
1130 | ch->dw_frame_interval = frm_intrv; | 1313 | ch->dw_frame_interval = frm_intrv; |
1131 | ch->frame.b_frame_interval_type = n; | 1314 | ch->frame.b_frame_interval_type = n; |
1315 | sort(ch->dw_frame_interval, n, sizeof(*ch->dw_frame_interval), | ||
1316 | uvcg_config_compare_u32, NULL); | ||
1132 | ret = len; | 1317 | ret = len; |
1133 | 1318 | ||
1134 | end: | 1319 | end: |
@@ -1140,6 +1325,7 @@ end: | |||
1140 | UVC_ATTR(uvcg_frame_, dw_frame_interval, dwFrameInterval); | 1325 | UVC_ATTR(uvcg_frame_, dw_frame_interval, dwFrameInterval); |
1141 | 1326 | ||
1142 | static struct configfs_attribute *uvcg_frame_attrs[] = { | 1327 | static struct configfs_attribute *uvcg_frame_attrs[] = { |
1328 | &uvcg_frame_attr_b_frame_index, | ||
1143 | &uvcg_frame_attr_bm_capabilities, | 1329 | &uvcg_frame_attr_bm_capabilities, |
1144 | &uvcg_frame_attr_w_width, | 1330 | &uvcg_frame_attr_w_width, |
1145 | &uvcg_frame_attr_w_height, | 1331 | &uvcg_frame_attr_w_height, |
@@ -1152,6 +1338,7 @@ static struct configfs_attribute *uvcg_frame_attrs[] = { | |||
1152 | }; | 1338 | }; |
1153 | 1339 | ||
1154 | static const struct config_item_type uvcg_frame_type = { | 1340 | static const struct config_item_type uvcg_frame_type = { |
1341 | .ct_item_ops = &uvcg_config_item_ops, | ||
1155 | .ct_attrs = uvcg_frame_attrs, | 1342 | .ct_attrs = uvcg_frame_attrs, |
1156 | .ct_owner = THIS_MODULE, | 1343 | .ct_owner = THIS_MODULE, |
1157 | }; | 1344 | }; |
@@ -1170,12 +1357,12 @@ static struct config_item *uvcg_frame_make(struct config_group *group, | |||
1170 | 1357 | ||
1171 | h->frame.b_descriptor_type = USB_DT_CS_INTERFACE; | 1358 | h->frame.b_descriptor_type = USB_DT_CS_INTERFACE; |
1172 | h->frame.b_frame_index = 1; | 1359 | h->frame.b_frame_index = 1; |
1173 | h->frame.w_width = cpu_to_le16(640); | 1360 | h->frame.w_width = 640; |
1174 | h->frame.w_height = cpu_to_le16(360); | 1361 | h->frame.w_height = 360; |
1175 | h->frame.dw_min_bit_rate = cpu_to_le32(18432000); | 1362 | h->frame.dw_min_bit_rate = 18432000; |
1176 | h->frame.dw_max_bit_rate = cpu_to_le32(55296000); | 1363 | h->frame.dw_max_bit_rate = 55296000; |
1177 | h->frame.dw_max_video_frame_buffer_size = cpu_to_le32(460800); | 1364 | h->frame.dw_max_video_frame_buffer_size = 460800; |
1178 | h->frame.dw_default_frame_interval = cpu_to_le32(666666); | 1365 | h->frame.dw_default_frame_interval = 666666; |
1179 | 1366 | ||
1180 | opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; | 1367 | opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; |
1181 | opts = to_f_uvc_opts(opts_item); | 1368 | opts = to_f_uvc_opts(opts_item); |
@@ -1203,7 +1390,6 @@ static struct config_item *uvcg_frame_make(struct config_group *group, | |||
1203 | 1390 | ||
1204 | static void uvcg_frame_drop(struct config_group *group, struct config_item *item) | 1391 | static void uvcg_frame_drop(struct config_group *group, struct config_item *item) |
1205 | { | 1392 | { |
1206 | struct uvcg_frame *h = to_uvcg_frame(item); | ||
1207 | struct uvcg_format *fmt; | 1393 | struct uvcg_format *fmt; |
1208 | struct f_uvc_opts *opts; | 1394 | struct f_uvc_opts *opts; |
1209 | struct config_item *opts_item; | 1395 | struct config_item *opts_item; |
@@ -1214,11 +1400,31 @@ static void uvcg_frame_drop(struct config_group *group, struct config_item *item | |||
1214 | mutex_lock(&opts->lock); | 1400 | mutex_lock(&opts->lock); |
1215 | fmt = to_uvcg_format(&group->cg_item); | 1401 | fmt = to_uvcg_format(&group->cg_item); |
1216 | --fmt->num_frames; | 1402 | --fmt->num_frames; |
1217 | kfree(h); | ||
1218 | mutex_unlock(&opts->lock); | 1403 | mutex_unlock(&opts->lock); |
1404 | |||
1405 | config_item_put(item); | ||
1406 | } | ||
1407 | |||
1408 | static void uvcg_format_set_indices(struct config_group *fmt) | ||
1409 | { | ||
1410 | struct config_item *ci; | ||
1411 | unsigned int i = 1; | ||
1412 | |||
1413 | list_for_each_entry(ci, &fmt->cg_children, ci_entry) { | ||
1414 | struct uvcg_frame *frm; | ||
1415 | |||
1416 | if (ci->ci_type != &uvcg_frame_type) | ||
1417 | continue; | ||
1418 | |||
1419 | frm = to_uvcg_frame(ci); | ||
1420 | frm->frame.b_frame_index = i++; | ||
1421 | } | ||
1219 | } | 1422 | } |
1220 | 1423 | ||
1221 | /* streaming/uncompressed/<NAME> */ | 1424 | /* ----------------------------------------------------------------------------- |
1425 | * streaming/uncompressed/<NAME> | ||
1426 | */ | ||
1427 | |||
1222 | struct uvcg_uncompressed { | 1428 | struct uvcg_uncompressed { |
1223 | struct uvcg_format fmt; | 1429 | struct uvcg_format fmt; |
1224 | struct uvc_format_uncompressed desc; | 1430 | struct uvc_format_uncompressed desc; |
@@ -1290,7 +1496,7 @@ end: | |||
1290 | 1496 | ||
1291 | UVC_ATTR(uvcg_uncompressed_, guid_format, guidFormat); | 1497 | UVC_ATTR(uvcg_uncompressed_, guid_format, guidFormat); |
1292 | 1498 | ||
1293 | #define UVCG_UNCOMPRESSED_ATTR_RO(cname, aname, conv) \ | 1499 | #define UVCG_UNCOMPRESSED_ATTR_RO(cname, aname, bits) \ |
1294 | static ssize_t uvcg_uncompressed_##cname##_show( \ | 1500 | static ssize_t uvcg_uncompressed_##cname##_show( \ |
1295 | struct config_item *item, char *page) \ | 1501 | struct config_item *item, char *page) \ |
1296 | { \ | 1502 | { \ |
@@ -1306,7 +1512,7 @@ static ssize_t uvcg_uncompressed_##cname##_show( \ | |||
1306 | opts = to_f_uvc_opts(opts_item); \ | 1512 | opts = to_f_uvc_opts(opts_item); \ |
1307 | \ | 1513 | \ |
1308 | mutex_lock(&opts->lock); \ | 1514 | mutex_lock(&opts->lock); \ |
1309 | result = sprintf(page, "%d\n", conv(u->desc.aname)); \ | 1515 | result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\ |
1310 | mutex_unlock(&opts->lock); \ | 1516 | mutex_unlock(&opts->lock); \ |
1311 | \ | 1517 | \ |
1312 | mutex_unlock(su_mutex); \ | 1518 | mutex_unlock(su_mutex); \ |
@@ -1315,7 +1521,7 @@ static ssize_t uvcg_uncompressed_##cname##_show( \ | |||
1315 | \ | 1521 | \ |
1316 | UVC_ATTR_RO(uvcg_uncompressed_, cname, aname); | 1522 | UVC_ATTR_RO(uvcg_uncompressed_, cname, aname); |
1317 | 1523 | ||
1318 | #define UVCG_UNCOMPRESSED_ATTR(cname, aname, conv) \ | 1524 | #define UVCG_UNCOMPRESSED_ATTR(cname, aname, bits) \ |
1319 | static ssize_t uvcg_uncompressed_##cname##_show( \ | 1525 | static ssize_t uvcg_uncompressed_##cname##_show( \ |
1320 | struct config_item *item, char *page) \ | 1526 | struct config_item *item, char *page) \ |
1321 | { \ | 1527 | { \ |
@@ -1331,7 +1537,7 @@ static ssize_t uvcg_uncompressed_##cname##_show( \ | |||
1331 | opts = to_f_uvc_opts(opts_item); \ | 1537 | opts = to_f_uvc_opts(opts_item); \ |
1332 | \ | 1538 | \ |
1333 | mutex_lock(&opts->lock); \ | 1539 | mutex_lock(&opts->lock); \ |
1334 | result = sprintf(page, "%d\n", conv(u->desc.aname)); \ | 1540 | result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\ |
1335 | mutex_unlock(&opts->lock); \ | 1541 | mutex_unlock(&opts->lock); \ |
1336 | \ | 1542 | \ |
1337 | mutex_unlock(su_mutex); \ | 1543 | mutex_unlock(su_mutex); \ |
@@ -1378,16 +1584,12 @@ end: \ | |||
1378 | \ | 1584 | \ |
1379 | UVC_ATTR(uvcg_uncompressed_, cname, aname); | 1585 | UVC_ATTR(uvcg_uncompressed_, cname, aname); |
1380 | 1586 | ||
1381 | #define identity_conv(x) (x) | 1587 | UVCG_UNCOMPRESSED_ATTR_RO(b_format_index, bFormatIndex, 8); |
1382 | 1588 | UVCG_UNCOMPRESSED_ATTR(b_bits_per_pixel, bBitsPerPixel, 8); | |
1383 | UVCG_UNCOMPRESSED_ATTR(b_bits_per_pixel, bBitsPerPixel, identity_conv); | 1589 | UVCG_UNCOMPRESSED_ATTR(b_default_frame_index, bDefaultFrameIndex, 8); |
1384 | UVCG_UNCOMPRESSED_ATTR(b_default_frame_index, bDefaultFrameIndex, | 1590 | UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, 8); |
1385 | identity_conv); | 1591 | UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, 8); |
1386 | UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, identity_conv); | 1592 | UVCG_UNCOMPRESSED_ATTR_RO(bm_interface_flags, bmInterfaceFlags, 8); |
1387 | UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, identity_conv); | ||
1388 | UVCG_UNCOMPRESSED_ATTR_RO(bm_interface_flags, bmInterfaceFlags, identity_conv); | ||
1389 | |||
1390 | #undef identity_conv | ||
1391 | 1593 | ||
1392 | #undef UVCG_UNCOMPRESSED_ATTR | 1594 | #undef UVCG_UNCOMPRESSED_ATTR |
1393 | #undef UVCG_UNCOMPRESSED_ATTR_RO | 1595 | #undef UVCG_UNCOMPRESSED_ATTR_RO |
@@ -1410,6 +1612,7 @@ uvcg_uncompressed_bma_controls_store(struct config_item *item, | |||
1410 | UVC_ATTR(uvcg_uncompressed_, bma_controls, bmaControls); | 1612 | UVC_ATTR(uvcg_uncompressed_, bma_controls, bmaControls); |
1411 | 1613 | ||
1412 | static struct configfs_attribute *uvcg_uncompressed_attrs[] = { | 1614 | static struct configfs_attribute *uvcg_uncompressed_attrs[] = { |
1615 | &uvcg_uncompressed_attr_b_format_index, | ||
1413 | &uvcg_uncompressed_attr_guid_format, | 1616 | &uvcg_uncompressed_attr_guid_format, |
1414 | &uvcg_uncompressed_attr_b_bits_per_pixel, | 1617 | &uvcg_uncompressed_attr_b_bits_per_pixel, |
1415 | &uvcg_uncompressed_attr_b_default_frame_index, | 1618 | &uvcg_uncompressed_attr_b_default_frame_index, |
@@ -1421,6 +1624,7 @@ static struct configfs_attribute *uvcg_uncompressed_attrs[] = { | |||
1421 | }; | 1624 | }; |
1422 | 1625 | ||
1423 | static const struct config_item_type uvcg_uncompressed_type = { | 1626 | static const struct config_item_type uvcg_uncompressed_type = { |
1627 | .ct_item_ops = &uvcg_config_item_ops, | ||
1424 | .ct_group_ops = &uvcg_uncompressed_group_ops, | 1628 | .ct_group_ops = &uvcg_uncompressed_group_ops, |
1425 | .ct_attrs = uvcg_uncompressed_attrs, | 1629 | .ct_attrs = uvcg_uncompressed_attrs, |
1426 | .ct_owner = THIS_MODULE, | 1630 | .ct_owner = THIS_MODULE, |
@@ -1457,25 +1661,23 @@ static struct config_group *uvcg_uncompressed_make(struct config_group *group, | |||
1457 | return &h->fmt.group; | 1661 | return &h->fmt.group; |
1458 | } | 1662 | } |
1459 | 1663 | ||
1460 | static void uvcg_uncompressed_drop(struct config_group *group, | ||
1461 | struct config_item *item) | ||
1462 | { | ||
1463 | struct uvcg_uncompressed *h = to_uvcg_uncompressed(item); | ||
1464 | |||
1465 | kfree(h); | ||
1466 | } | ||
1467 | |||
1468 | static struct configfs_group_operations uvcg_uncompressed_grp_ops = { | 1664 | static struct configfs_group_operations uvcg_uncompressed_grp_ops = { |
1469 | .make_group = uvcg_uncompressed_make, | 1665 | .make_group = uvcg_uncompressed_make, |
1470 | .drop_item = uvcg_uncompressed_drop, | ||
1471 | }; | 1666 | }; |
1472 | 1667 | ||
1473 | static const struct config_item_type uvcg_uncompressed_grp_type = { | 1668 | static const struct uvcg_config_group_type uvcg_uncompressed_grp_type = { |
1474 | .ct_group_ops = &uvcg_uncompressed_grp_ops, | 1669 | .type = { |
1475 | .ct_owner = THIS_MODULE, | 1670 | .ct_item_ops = &uvcg_config_item_ops, |
1671 | .ct_group_ops = &uvcg_uncompressed_grp_ops, | ||
1672 | .ct_owner = THIS_MODULE, | ||
1673 | }, | ||
1674 | .name = "uncompressed", | ||
1476 | }; | 1675 | }; |
1477 | 1676 | ||
1478 | /* streaming/mjpeg/<NAME> */ | 1677 | /* ----------------------------------------------------------------------------- |
1678 | * streaming/mjpeg/<NAME> | ||
1679 | */ | ||
1680 | |||
1479 | struct uvcg_mjpeg { | 1681 | struct uvcg_mjpeg { |
1480 | struct uvcg_format fmt; | 1682 | struct uvcg_format fmt; |
1481 | struct uvc_format_mjpeg desc; | 1683 | struct uvc_format_mjpeg desc; |
@@ -1493,7 +1695,7 @@ static struct configfs_group_operations uvcg_mjpeg_group_ops = { | |||
1493 | .drop_item = uvcg_frame_drop, | 1695 | .drop_item = uvcg_frame_drop, |
1494 | }; | 1696 | }; |
1495 | 1697 | ||
1496 | #define UVCG_MJPEG_ATTR_RO(cname, aname, conv) \ | 1698 | #define UVCG_MJPEG_ATTR_RO(cname, aname, bits) \ |
1497 | static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\ | 1699 | static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\ |
1498 | { \ | 1700 | { \ |
1499 | struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \ | 1701 | struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \ |
@@ -1508,7 +1710,7 @@ static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\ | |||
1508 | opts = to_f_uvc_opts(opts_item); \ | 1710 | opts = to_f_uvc_opts(opts_item); \ |
1509 | \ | 1711 | \ |
1510 | mutex_lock(&opts->lock); \ | 1712 | mutex_lock(&opts->lock); \ |
1511 | result = sprintf(page, "%d\n", conv(u->desc.aname)); \ | 1713 | result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\ |
1512 | mutex_unlock(&opts->lock); \ | 1714 | mutex_unlock(&opts->lock); \ |
1513 | \ | 1715 | \ |
1514 | mutex_unlock(su_mutex); \ | 1716 | mutex_unlock(su_mutex); \ |
@@ -1517,7 +1719,7 @@ static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\ | |||
1517 | \ | 1719 | \ |
1518 | UVC_ATTR_RO(uvcg_mjpeg_, cname, aname) | 1720 | UVC_ATTR_RO(uvcg_mjpeg_, cname, aname) |
1519 | 1721 | ||
1520 | #define UVCG_MJPEG_ATTR(cname, aname, conv) \ | 1722 | #define UVCG_MJPEG_ATTR(cname, aname, bits) \ |
1521 | static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\ | 1723 | static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\ |
1522 | { \ | 1724 | { \ |
1523 | struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \ | 1725 | struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \ |
@@ -1532,7 +1734,7 @@ static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\ | |||
1532 | opts = to_f_uvc_opts(opts_item); \ | 1734 | opts = to_f_uvc_opts(opts_item); \ |
1533 | \ | 1735 | \ |
1534 | mutex_lock(&opts->lock); \ | 1736 | mutex_lock(&opts->lock); \ |
1535 | result = sprintf(page, "%d\n", conv(u->desc.aname)); \ | 1737 | result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\ |
1536 | mutex_unlock(&opts->lock); \ | 1738 | mutex_unlock(&opts->lock); \ |
1537 | \ | 1739 | \ |
1538 | mutex_unlock(su_mutex); \ | 1740 | mutex_unlock(su_mutex); \ |
@@ -1579,16 +1781,12 @@ end: \ | |||
1579 | \ | 1781 | \ |
1580 | UVC_ATTR(uvcg_mjpeg_, cname, aname) | 1782 | UVC_ATTR(uvcg_mjpeg_, cname, aname) |
1581 | 1783 | ||
1582 | #define identity_conv(x) (x) | 1784 | UVCG_MJPEG_ATTR_RO(b_format_index, bFormatIndex, 8); |
1583 | 1785 | UVCG_MJPEG_ATTR(b_default_frame_index, bDefaultFrameIndex, 8); | |
1584 | UVCG_MJPEG_ATTR(b_default_frame_index, bDefaultFrameIndex, | 1786 | UVCG_MJPEG_ATTR_RO(bm_flags, bmFlags, 8); |
1585 | identity_conv); | 1787 | UVCG_MJPEG_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, 8); |
1586 | UVCG_MJPEG_ATTR_RO(bm_flags, bmFlags, identity_conv); | 1788 | UVCG_MJPEG_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, 8); |
1587 | UVCG_MJPEG_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, identity_conv); | 1789 | UVCG_MJPEG_ATTR_RO(bm_interface_flags, bmInterfaceFlags, 8); |
1588 | UVCG_MJPEG_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, identity_conv); | ||
1589 | UVCG_MJPEG_ATTR_RO(bm_interface_flags, bmInterfaceFlags, identity_conv); | ||
1590 | |||
1591 | #undef identity_conv | ||
1592 | 1790 | ||
1593 | #undef UVCG_MJPEG_ATTR | 1791 | #undef UVCG_MJPEG_ATTR |
1594 | #undef UVCG_MJPEG_ATTR_RO | 1792 | #undef UVCG_MJPEG_ATTR_RO |
@@ -1611,6 +1809,7 @@ uvcg_mjpeg_bma_controls_store(struct config_item *item, | |||
1611 | UVC_ATTR(uvcg_mjpeg_, bma_controls, bmaControls); | 1809 | UVC_ATTR(uvcg_mjpeg_, bma_controls, bmaControls); |
1612 | 1810 | ||
1613 | static struct configfs_attribute *uvcg_mjpeg_attrs[] = { | 1811 | static struct configfs_attribute *uvcg_mjpeg_attrs[] = { |
1812 | &uvcg_mjpeg_attr_b_format_index, | ||
1614 | &uvcg_mjpeg_attr_b_default_frame_index, | 1813 | &uvcg_mjpeg_attr_b_default_frame_index, |
1615 | &uvcg_mjpeg_attr_bm_flags, | 1814 | &uvcg_mjpeg_attr_bm_flags, |
1616 | &uvcg_mjpeg_attr_b_aspect_ratio_x, | 1815 | &uvcg_mjpeg_attr_b_aspect_ratio_x, |
@@ -1621,6 +1820,7 @@ static struct configfs_attribute *uvcg_mjpeg_attrs[] = { | |||
1621 | }; | 1820 | }; |
1622 | 1821 | ||
1623 | static const struct config_item_type uvcg_mjpeg_type = { | 1822 | static const struct config_item_type uvcg_mjpeg_type = { |
1823 | .ct_item_ops = &uvcg_config_item_ops, | ||
1624 | .ct_group_ops = &uvcg_mjpeg_group_ops, | 1824 | .ct_group_ops = &uvcg_mjpeg_group_ops, |
1625 | .ct_attrs = uvcg_mjpeg_attrs, | 1825 | .ct_attrs = uvcg_mjpeg_attrs, |
1626 | .ct_owner = THIS_MODULE, | 1826 | .ct_owner = THIS_MODULE, |
@@ -1651,56 +1851,42 @@ static struct config_group *uvcg_mjpeg_make(struct config_group *group, | |||
1651 | return &h->fmt.group; | 1851 | return &h->fmt.group; |
1652 | } | 1852 | } |
1653 | 1853 | ||
1654 | static void uvcg_mjpeg_drop(struct config_group *group, | ||
1655 | struct config_item *item) | ||
1656 | { | ||
1657 | struct uvcg_mjpeg *h = to_uvcg_mjpeg(item); | ||
1658 | |||
1659 | kfree(h); | ||
1660 | } | ||
1661 | |||
1662 | static struct configfs_group_operations uvcg_mjpeg_grp_ops = { | 1854 | static struct configfs_group_operations uvcg_mjpeg_grp_ops = { |
1663 | .make_group = uvcg_mjpeg_make, | 1855 | .make_group = uvcg_mjpeg_make, |
1664 | .drop_item = uvcg_mjpeg_drop, | ||
1665 | }; | 1856 | }; |
1666 | 1857 | ||
1667 | static const struct config_item_type uvcg_mjpeg_grp_type = { | 1858 | static const struct uvcg_config_group_type uvcg_mjpeg_grp_type = { |
1668 | .ct_group_ops = &uvcg_mjpeg_grp_ops, | 1859 | .type = { |
1669 | .ct_owner = THIS_MODULE, | 1860 | .ct_item_ops = &uvcg_config_item_ops, |
1861 | .ct_group_ops = &uvcg_mjpeg_grp_ops, | ||
1862 | .ct_owner = THIS_MODULE, | ||
1863 | }, | ||
1864 | .name = "mjpeg", | ||
1670 | }; | 1865 | }; |
1671 | 1866 | ||
1672 | /* streaming/color_matching/default */ | 1867 | /* ----------------------------------------------------------------------------- |
1673 | static struct uvcg_default_color_matching { | 1868 | * streaming/color_matching/default |
1674 | struct config_group group; | 1869 | */ |
1675 | } uvcg_default_color_matching; | ||
1676 | |||
1677 | static inline struct uvcg_default_color_matching | ||
1678 | *to_uvcg_default_color_matching(struct config_item *item) | ||
1679 | { | ||
1680 | return container_of(to_config_group(item), | ||
1681 | struct uvcg_default_color_matching, group); | ||
1682 | } | ||
1683 | 1870 | ||
1684 | #define UVCG_DEFAULT_COLOR_MATCHING_ATTR(cname, aname, conv) \ | 1871 | #define UVCG_DEFAULT_COLOR_MATCHING_ATTR(cname, aname, bits) \ |
1685 | static ssize_t uvcg_default_color_matching_##cname##_show( \ | 1872 | static ssize_t uvcg_default_color_matching_##cname##_show( \ |
1686 | struct config_item *item, char *page) \ | 1873 | struct config_item *item, char *page) \ |
1687 | { \ | 1874 | { \ |
1688 | struct uvcg_default_color_matching *dc = \ | 1875 | struct config_group *group = to_config_group(item); \ |
1689 | to_uvcg_default_color_matching(item); \ | ||
1690 | struct f_uvc_opts *opts; \ | 1876 | struct f_uvc_opts *opts; \ |
1691 | struct config_item *opts_item; \ | 1877 | struct config_item *opts_item; \ |
1692 | struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; \ | 1878 | struct mutex *su_mutex = &group->cg_subsys->su_mutex; \ |
1693 | struct uvc_color_matching_descriptor *cd; \ | 1879 | struct uvc_color_matching_descriptor *cd; \ |
1694 | int result; \ | 1880 | int result; \ |
1695 | \ | 1881 | \ |
1696 | mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ | 1882 | mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ |
1697 | \ | 1883 | \ |
1698 | opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent; \ | 1884 | opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; \ |
1699 | opts = to_f_uvc_opts(opts_item); \ | 1885 | opts = to_f_uvc_opts(opts_item); \ |
1700 | cd = &opts->uvc_color_matching; \ | 1886 | cd = &opts->uvc_color_matching; \ |
1701 | \ | 1887 | \ |
1702 | mutex_lock(&opts->lock); \ | 1888 | mutex_lock(&opts->lock); \ |
1703 | result = sprintf(page, "%d\n", conv(cd->aname)); \ | 1889 | result = sprintf(page, "%u\n", le##bits##_to_cpu(cd->aname)); \ |
1704 | mutex_unlock(&opts->lock); \ | 1890 | mutex_unlock(&opts->lock); \ |
1705 | \ | 1891 | \ |
1706 | mutex_unlock(su_mutex); \ | 1892 | mutex_unlock(su_mutex); \ |
@@ -1709,16 +1895,10 @@ static ssize_t uvcg_default_color_matching_##cname##_show( \ | |||
1709 | \ | 1895 | \ |
1710 | UVC_ATTR_RO(uvcg_default_color_matching_, cname, aname) | 1896 | UVC_ATTR_RO(uvcg_default_color_matching_, cname, aname) |
1711 | 1897 | ||
1712 | #define identity_conv(x) (x) | 1898 | UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_color_primaries, bColorPrimaries, 8); |
1713 | |||
1714 | UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_color_primaries, bColorPrimaries, | ||
1715 | identity_conv); | ||
1716 | UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_transfer_characteristics, | 1899 | UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_transfer_characteristics, |
1717 | bTransferCharacteristics, identity_conv); | 1900 | bTransferCharacteristics, 8); |
1718 | UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_matrix_coefficients, bMatrixCoefficients, | 1901 | UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_matrix_coefficients, bMatrixCoefficients, 8); |
1719 | identity_conv); | ||
1720 | |||
1721 | #undef identity_conv | ||
1722 | 1902 | ||
1723 | #undef UVCG_DEFAULT_COLOR_MATCHING_ATTR | 1903 | #undef UVCG_DEFAULT_COLOR_MATCHING_ATTR |
1724 | 1904 | ||
@@ -1729,41 +1909,54 @@ static struct configfs_attribute *uvcg_default_color_matching_attrs[] = { | |||
1729 | NULL, | 1909 | NULL, |
1730 | }; | 1910 | }; |
1731 | 1911 | ||
1732 | static const struct config_item_type uvcg_default_color_matching_type = { | 1912 | static const struct uvcg_config_group_type uvcg_default_color_matching_type = { |
1733 | .ct_attrs = uvcg_default_color_matching_attrs, | 1913 | .type = { |
1734 | .ct_owner = THIS_MODULE, | 1914 | .ct_item_ops = &uvcg_config_item_ops, |
1915 | .ct_attrs = uvcg_default_color_matching_attrs, | ||
1916 | .ct_owner = THIS_MODULE, | ||
1917 | }, | ||
1918 | .name = "default", | ||
1735 | }; | 1919 | }; |
1736 | 1920 | ||
1737 | /* struct uvcg_color_matching {}; */ | 1921 | /* ----------------------------------------------------------------------------- |
1738 | 1922 | * streaming/color_matching | |
1739 | /* streaming/color_matching */ | 1923 | */ |
1740 | static struct uvcg_color_matching_grp { | ||
1741 | struct config_group group; | ||
1742 | } uvcg_color_matching_grp; | ||
1743 | 1924 | ||
1744 | static const struct config_item_type uvcg_color_matching_grp_type = { | 1925 | static const struct uvcg_config_group_type uvcg_color_matching_grp_type = { |
1745 | .ct_owner = THIS_MODULE, | 1926 | .type = { |
1927 | .ct_item_ops = &uvcg_config_item_ops, | ||
1928 | .ct_owner = THIS_MODULE, | ||
1929 | }, | ||
1930 | .name = "color_matching", | ||
1931 | .children = (const struct uvcg_config_group_type*[]) { | ||
1932 | &uvcg_default_color_matching_type, | ||
1933 | NULL, | ||
1934 | }, | ||
1746 | }; | 1935 | }; |
1747 | 1936 | ||
1748 | /* streaming/class/{fs|hs|ss} */ | 1937 | /* ----------------------------------------------------------------------------- |
1749 | static struct uvcg_streaming_class { | 1938 | * streaming/class/{fs|hs|ss} |
1750 | struct config_group group; | 1939 | */ |
1751 | } uvcg_streaming_class_fs, uvcg_streaming_class_hs, uvcg_streaming_class_ss; | ||
1752 | 1940 | ||
1941 | struct uvcg_streaming_class_group { | ||
1942 | struct config_group group; | ||
1943 | const char *name; | ||
1944 | }; | ||
1753 | 1945 | ||
1754 | static inline struct uvc_descriptor_header | 1946 | static inline struct uvc_descriptor_header |
1755 | ***__uvcg_get_stream_class_arr(struct config_item *i, struct f_uvc_opts *o) | 1947 | ***__uvcg_get_stream_class_arr(struct config_item *i, struct f_uvc_opts *o) |
1756 | { | 1948 | { |
1757 | struct uvcg_streaming_class *cl = container_of(to_config_group(i), | 1949 | struct uvcg_streaming_class_group *group = |
1758 | struct uvcg_streaming_class, group); | 1950 | container_of(i, struct uvcg_streaming_class_group, |
1951 | group.cg_item); | ||
1759 | 1952 | ||
1760 | if (cl == &uvcg_streaming_class_fs) | 1953 | if (!strcmp(group->name, "fs")) |
1761 | return &o->uvc_fs_streaming_cls; | 1954 | return &o->uvc_fs_streaming_cls; |
1762 | 1955 | ||
1763 | if (cl == &uvcg_streaming_class_hs) | 1956 | if (!strcmp(group->name, "hs")) |
1764 | return &o->uvc_hs_streaming_cls; | 1957 | return &o->uvc_hs_streaming_cls; |
1765 | 1958 | ||
1766 | if (cl == &uvcg_streaming_class_ss) | 1959 | if (!strcmp(group->name, "ss")) |
1767 | return &o->uvc_ss_streaming_cls; | 1960 | return &o->uvc_ss_streaming_cls; |
1768 | 1961 | ||
1769 | return NULL; | 1962 | return NULL; |
@@ -1922,24 +2115,22 @@ static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n, | |||
1922 | struct uvcg_format *fmt = priv1; | 2115 | struct uvcg_format *fmt = priv1; |
1923 | 2116 | ||
1924 | if (fmt->type == UVCG_UNCOMPRESSED) { | 2117 | if (fmt->type == UVCG_UNCOMPRESSED) { |
1925 | struct uvc_format_uncompressed *unc = *dest; | ||
1926 | struct uvcg_uncompressed *u = | 2118 | struct uvcg_uncompressed *u = |
1927 | container_of(fmt, struct uvcg_uncompressed, | 2119 | container_of(fmt, struct uvcg_uncompressed, |
1928 | fmt); | 2120 | fmt); |
1929 | 2121 | ||
2122 | u->desc.bFormatIndex = n + 1; | ||
2123 | u->desc.bNumFrameDescriptors = fmt->num_frames; | ||
1930 | memcpy(*dest, &u->desc, sizeof(u->desc)); | 2124 | memcpy(*dest, &u->desc, sizeof(u->desc)); |
1931 | *dest += sizeof(u->desc); | 2125 | *dest += sizeof(u->desc); |
1932 | unc->bNumFrameDescriptors = fmt->num_frames; | ||
1933 | unc->bFormatIndex = n + 1; | ||
1934 | } else if (fmt->type == UVCG_MJPEG) { | 2126 | } else if (fmt->type == UVCG_MJPEG) { |
1935 | struct uvc_format_mjpeg *mjp = *dest; | ||
1936 | struct uvcg_mjpeg *m = | 2127 | struct uvcg_mjpeg *m = |
1937 | container_of(fmt, struct uvcg_mjpeg, fmt); | 2128 | container_of(fmt, struct uvcg_mjpeg, fmt); |
1938 | 2129 | ||
2130 | m->desc.bFormatIndex = n + 1; | ||
2131 | m->desc.bNumFrameDescriptors = fmt->num_frames; | ||
1939 | memcpy(*dest, &m->desc, sizeof(m->desc)); | 2132 | memcpy(*dest, &m->desc, sizeof(m->desc)); |
1940 | *dest += sizeof(m->desc); | 2133 | *dest += sizeof(m->desc); |
1941 | mjp->bNumFrameDescriptors = fmt->num_frames; | ||
1942 | mjp->bFormatIndex = n + 1; | ||
1943 | } else { | 2134 | } else { |
1944 | return -EINVAL; | 2135 | return -EINVAL; |
1945 | } | 2136 | } |
@@ -2038,6 +2229,7 @@ static int uvcg_streaming_class_allow_link(struct config_item *src, | |||
2038 | unlock: | 2229 | unlock: |
2039 | mutex_unlock(&opts->lock); | 2230 | mutex_unlock(&opts->lock); |
2040 | out: | 2231 | out: |
2232 | config_item_put(header); | ||
2041 | mutex_unlock(su_mutex); | 2233 | mutex_unlock(su_mutex); |
2042 | return ret; | 2234 | return ret; |
2043 | } | 2235 | } |
@@ -2078,10 +2270,12 @@ static void uvcg_streaming_class_drop_link(struct config_item *src, | |||
2078 | unlock: | 2270 | unlock: |
2079 | mutex_unlock(&opts->lock); | 2271 | mutex_unlock(&opts->lock); |
2080 | out: | 2272 | out: |
2273 | config_item_put(header); | ||
2081 | mutex_unlock(su_mutex); | 2274 | mutex_unlock(su_mutex); |
2082 | } | 2275 | } |
2083 | 2276 | ||
2084 | static struct configfs_item_operations uvcg_streaming_class_item_ops = { | 2277 | static struct configfs_item_operations uvcg_streaming_class_item_ops = { |
2278 | .release = uvcg_config_item_release, | ||
2085 | .allow_link = uvcg_streaming_class_allow_link, | 2279 | .allow_link = uvcg_streaming_class_allow_link, |
2086 | .drop_link = uvcg_streaming_class_drop_link, | 2280 | .drop_link = uvcg_streaming_class_drop_link, |
2087 | }; | 2281 | }; |
@@ -2091,36 +2285,109 @@ static const struct config_item_type uvcg_streaming_class_type = { | |||
2091 | .ct_owner = THIS_MODULE, | 2285 | .ct_owner = THIS_MODULE, |
2092 | }; | 2286 | }; |
2093 | 2287 | ||
2094 | /* streaming/class */ | 2288 | /* ----------------------------------------------------------------------------- |
2095 | static struct uvcg_streaming_class_grp { | 2289 | * streaming/class |
2096 | struct config_group group; | 2290 | */ |
2097 | } uvcg_streaming_class_grp; | 2291 | |
2292 | static int uvcg_streaming_class_create_children(struct config_group *parent) | ||
2293 | { | ||
2294 | static const char * const names[] = { "fs", "hs", "ss" }; | ||
2295 | unsigned int i; | ||
2296 | |||
2297 | for (i = 0; i < ARRAY_SIZE(names); ++i) { | ||
2298 | struct uvcg_streaming_class_group *group; | ||
2299 | |||
2300 | group = kzalloc(sizeof(*group), GFP_KERNEL); | ||
2301 | if (!group) | ||
2302 | return -ENOMEM; | ||
2098 | 2303 | ||
2099 | static const struct config_item_type uvcg_streaming_class_grp_type = { | 2304 | group->name = names[i]; |
2100 | .ct_owner = THIS_MODULE, | 2305 | |
2306 | config_group_init_type_name(&group->group, group->name, | ||
2307 | &uvcg_streaming_class_type); | ||
2308 | configfs_add_default_group(&group->group, parent); | ||
2309 | } | ||
2310 | |||
2311 | return 0; | ||
2312 | } | ||
2313 | |||
2314 | static const struct uvcg_config_group_type uvcg_streaming_class_grp_type = { | ||
2315 | .type = { | ||
2316 | .ct_item_ops = &uvcg_config_item_ops, | ||
2317 | .ct_owner = THIS_MODULE, | ||
2318 | }, | ||
2319 | .name = "class", | ||
2320 | .create_children = uvcg_streaming_class_create_children, | ||
2101 | }; | 2321 | }; |
2102 | 2322 | ||
2103 | /* streaming */ | 2323 | /* ----------------------------------------------------------------------------- |
2104 | static struct uvcg_streaming_grp { | 2324 | * streaming |
2105 | struct config_group group; | 2325 | */ |
2106 | } uvcg_streaming_grp; | ||
2107 | 2326 | ||
2108 | static const struct config_item_type uvcg_streaming_grp_type = { | 2327 | static ssize_t uvcg_default_streaming_b_interface_number_show( |
2109 | .ct_owner = THIS_MODULE, | 2328 | struct config_item *item, char *page) |
2329 | { | ||
2330 | struct config_group *group = to_config_group(item); | ||
2331 | struct mutex *su_mutex = &group->cg_subsys->su_mutex; | ||
2332 | struct config_item *opts_item; | ||
2333 | struct f_uvc_opts *opts; | ||
2334 | int result = 0; | ||
2335 | |||
2336 | mutex_lock(su_mutex); /* for navigating configfs hierarchy */ | ||
2337 | |||
2338 | opts_item = item->ci_parent; | ||
2339 | opts = to_f_uvc_opts(opts_item); | ||
2340 | |||
2341 | mutex_lock(&opts->lock); | ||
2342 | result += sprintf(page, "%u\n", opts->streaming_interface); | ||
2343 | mutex_unlock(&opts->lock); | ||
2344 | |||
2345 | mutex_unlock(su_mutex); | ||
2346 | |||
2347 | return result; | ||
2348 | } | ||
2349 | |||
2350 | UVC_ATTR_RO(uvcg_default_streaming_, b_interface_number, bInterfaceNumber); | ||
2351 | |||
2352 | static struct configfs_attribute *uvcg_default_streaming_attrs[] = { | ||
2353 | &uvcg_default_streaming_attr_b_interface_number, | ||
2354 | NULL, | ||
2355 | }; | ||
2356 | |||
2357 | static const struct uvcg_config_group_type uvcg_streaming_grp_type = { | ||
2358 | .type = { | ||
2359 | .ct_item_ops = &uvcg_config_item_ops, | ||
2360 | .ct_attrs = uvcg_default_streaming_attrs, | ||
2361 | .ct_owner = THIS_MODULE, | ||
2362 | }, | ||
2363 | .name = "streaming", | ||
2364 | .children = (const struct uvcg_config_group_type*[]) { | ||
2365 | &uvcg_streaming_header_grp_type, | ||
2366 | &uvcg_uncompressed_grp_type, | ||
2367 | &uvcg_mjpeg_grp_type, | ||
2368 | &uvcg_color_matching_grp_type, | ||
2369 | &uvcg_streaming_class_grp_type, | ||
2370 | NULL, | ||
2371 | }, | ||
2110 | }; | 2372 | }; |
2111 | 2373 | ||
2112 | static void uvc_attr_release(struct config_item *item) | 2374 | /* ----------------------------------------------------------------------------- |
2375 | * UVC function | ||
2376 | */ | ||
2377 | |||
2378 | static void uvc_func_item_release(struct config_item *item) | ||
2113 | { | 2379 | { |
2114 | struct f_uvc_opts *opts = to_f_uvc_opts(item); | 2380 | struct f_uvc_opts *opts = to_f_uvc_opts(item); |
2115 | 2381 | ||
2382 | uvcg_config_remove_children(to_config_group(item)); | ||
2116 | usb_put_function_instance(&opts->func_inst); | 2383 | usb_put_function_instance(&opts->func_inst); |
2117 | } | 2384 | } |
2118 | 2385 | ||
2119 | static struct configfs_item_operations uvc_item_ops = { | 2386 | static struct configfs_item_operations uvc_func_item_ops = { |
2120 | .release = uvc_attr_release, | 2387 | .release = uvc_func_item_release, |
2121 | }; | 2388 | }; |
2122 | 2389 | ||
2123 | #define UVCG_OPTS_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \ | 2390 | #define UVCG_OPTS_ATTR(cname, aname, limit) \ |
2124 | static ssize_t f_uvc_opts_##cname##_show( \ | 2391 | static ssize_t f_uvc_opts_##cname##_show( \ |
2125 | struct config_item *item, char *page) \ | 2392 | struct config_item *item, char *page) \ |
2126 | { \ | 2393 | { \ |
@@ -2128,7 +2395,7 @@ static ssize_t f_uvc_opts_##cname##_show( \ | |||
2128 | int result; \ | 2395 | int result; \ |
2129 | \ | 2396 | \ |
2130 | mutex_lock(&opts->lock); \ | 2397 | mutex_lock(&opts->lock); \ |
2131 | result = sprintf(page, "%d\n", conv(opts->cname)); \ | 2398 | result = sprintf(page, "%u\n", opts->cname); \ |
2132 | mutex_unlock(&opts->lock); \ | 2399 | mutex_unlock(&opts->lock); \ |
2133 | \ | 2400 | \ |
2134 | return result; \ | 2401 | return result; \ |
@@ -2139,8 +2406,8 @@ f_uvc_opts_##cname##_store(struct config_item *item, \ | |||
2139 | const char *page, size_t len) \ | 2406 | const char *page, size_t len) \ |
2140 | { \ | 2407 | { \ |
2141 | struct f_uvc_opts *opts = to_f_uvc_opts(item); \ | 2408 | struct f_uvc_opts *opts = to_f_uvc_opts(item); \ |
2409 | unsigned int num; \ | ||
2142 | int ret; \ | 2410 | int ret; \ |
2143 | uxx num; \ | ||
2144 | \ | 2411 | \ |
2145 | mutex_lock(&opts->lock); \ | 2412 | mutex_lock(&opts->lock); \ |
2146 | if (opts->refcnt) { \ | 2413 | if (opts->refcnt) { \ |
@@ -2148,7 +2415,7 @@ f_uvc_opts_##cname##_store(struct config_item *item, \ | |||
2148 | goto end; \ | 2415 | goto end; \ |
2149 | } \ | 2416 | } \ |
2150 | \ | 2417 | \ |
2151 | ret = str2u(page, 0, &num); \ | 2418 | ret = kstrtouint(page, 0, &num); \ |
2152 | if (ret) \ | 2419 | if (ret) \ |
2153 | goto end; \ | 2420 | goto end; \ |
2154 | \ | 2421 | \ |
@@ -2156,7 +2423,7 @@ f_uvc_opts_##cname##_store(struct config_item *item, \ | |||
2156 | ret = -EINVAL; \ | 2423 | ret = -EINVAL; \ |
2157 | goto end; \ | 2424 | goto end; \ |
2158 | } \ | 2425 | } \ |
2159 | opts->cname = vnoc(num); \ | 2426 | opts->cname = num; \ |
2160 | ret = len; \ | 2427 | ret = len; \ |
2161 | end: \ | 2428 | end: \ |
2162 | mutex_unlock(&opts->lock); \ | 2429 | mutex_unlock(&opts->lock); \ |
@@ -2165,16 +2432,9 @@ end: \ | |||
2165 | \ | 2432 | \ |
2166 | UVC_ATTR(f_uvc_opts_, cname, cname) | 2433 | UVC_ATTR(f_uvc_opts_, cname, cname) |
2167 | 2434 | ||
2168 | #define identity_conv(x) (x) | 2435 | UVCG_OPTS_ATTR(streaming_interval, streaming_interval, 16); |
2169 | 2436 | UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, 3072); | |
2170 | UVCG_OPTS_ATTR(streaming_interval, streaming_interval, identity_conv, | 2437 | UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, 15); |
2171 | kstrtou8, u8, identity_conv, 16); | ||
2172 | UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, le16_to_cpu, | ||
2173 | kstrtou16, u16, le16_to_cpu, 3072); | ||
2174 | UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, identity_conv, | ||
2175 | kstrtou8, u8, identity_conv, 15); | ||
2176 | |||
2177 | #undef identity_conv | ||
2178 | 2438 | ||
2179 | #undef UVCG_OPTS_ATTR | 2439 | #undef UVCG_OPTS_ATTR |
2180 | 2440 | ||
@@ -2185,123 +2445,31 @@ static struct configfs_attribute *uvc_attrs[] = { | |||
2185 | NULL, | 2445 | NULL, |
2186 | }; | 2446 | }; |
2187 | 2447 | ||
2188 | static const struct config_item_type uvc_func_type = { | 2448 | static const struct uvcg_config_group_type uvc_func_type = { |
2189 | .ct_item_ops = &uvc_item_ops, | 2449 | .type = { |
2190 | .ct_attrs = uvc_attrs, | 2450 | .ct_item_ops = &uvc_func_item_ops, |
2191 | .ct_owner = THIS_MODULE, | 2451 | .ct_attrs = uvc_attrs, |
2452 | .ct_owner = THIS_MODULE, | ||
2453 | }, | ||
2454 | .name = "", | ||
2455 | .children = (const struct uvcg_config_group_type*[]) { | ||
2456 | &uvcg_control_grp_type, | ||
2457 | &uvcg_streaming_grp_type, | ||
2458 | NULL, | ||
2459 | }, | ||
2192 | }; | 2460 | }; |
2193 | 2461 | ||
2194 | int uvcg_attach_configfs(struct f_uvc_opts *opts) | 2462 | int uvcg_attach_configfs(struct f_uvc_opts *opts) |
2195 | { | 2463 | { |
2196 | config_group_init_type_name(&uvcg_control_header_grp.group, | 2464 | int ret; |
2197 | "header", | ||
2198 | &uvcg_control_header_grp_type); | ||
2199 | |||
2200 | config_group_init_type_name(&uvcg_default_processing.group, | ||
2201 | "default", &uvcg_default_processing_type); | ||
2202 | config_group_init_type_name(&uvcg_processing_grp.group, | ||
2203 | "processing", &uvcg_processing_grp_type); | ||
2204 | configfs_add_default_group(&uvcg_default_processing.group, | ||
2205 | &uvcg_processing_grp.group); | ||
2206 | |||
2207 | config_group_init_type_name(&uvcg_default_camera.group, | ||
2208 | "default", &uvcg_default_camera_type); | ||
2209 | config_group_init_type_name(&uvcg_camera_grp.group, | ||
2210 | "camera", &uvcg_camera_grp_type); | ||
2211 | configfs_add_default_group(&uvcg_default_camera.group, | ||
2212 | &uvcg_camera_grp.group); | ||
2213 | |||
2214 | config_group_init_type_name(&uvcg_default_output.group, | ||
2215 | "default", &uvcg_default_output_type); | ||
2216 | config_group_init_type_name(&uvcg_output_grp.group, | ||
2217 | "output", &uvcg_output_grp_type); | ||
2218 | configfs_add_default_group(&uvcg_default_output.group, | ||
2219 | &uvcg_output_grp.group); | ||
2220 | |||
2221 | config_group_init_type_name(&uvcg_terminal_grp.group, | ||
2222 | "terminal", &uvcg_terminal_grp_type); | ||
2223 | configfs_add_default_group(&uvcg_camera_grp.group, | ||
2224 | &uvcg_terminal_grp.group); | ||
2225 | configfs_add_default_group(&uvcg_output_grp.group, | ||
2226 | &uvcg_terminal_grp.group); | ||
2227 | |||
2228 | config_group_init_type_name(&uvcg_control_class_fs.group, | ||
2229 | "fs", &uvcg_control_class_type); | ||
2230 | config_group_init_type_name(&uvcg_control_class_ss.group, | ||
2231 | "ss", &uvcg_control_class_type); | ||
2232 | config_group_init_type_name(&uvcg_control_class_grp.group, | ||
2233 | "class", | ||
2234 | &uvcg_control_class_grp_type); | ||
2235 | configfs_add_default_group(&uvcg_control_class_fs.group, | ||
2236 | &uvcg_control_class_grp.group); | ||
2237 | configfs_add_default_group(&uvcg_control_class_ss.group, | ||
2238 | &uvcg_control_class_grp.group); | ||
2239 | |||
2240 | config_group_init_type_name(&uvcg_control_grp.group, | ||
2241 | "control", | ||
2242 | &uvcg_control_grp_type); | ||
2243 | configfs_add_default_group(&uvcg_control_header_grp.group, | ||
2244 | &uvcg_control_grp.group); | ||
2245 | configfs_add_default_group(&uvcg_processing_grp.group, | ||
2246 | &uvcg_control_grp.group); | ||
2247 | configfs_add_default_group(&uvcg_terminal_grp.group, | ||
2248 | &uvcg_control_grp.group); | ||
2249 | configfs_add_default_group(&uvcg_control_class_grp.group, | ||
2250 | &uvcg_control_grp.group); | ||
2251 | |||
2252 | config_group_init_type_name(&uvcg_streaming_header_grp.group, | ||
2253 | "header", | ||
2254 | &uvcg_streaming_header_grp_type); | ||
2255 | config_group_init_type_name(&uvcg_uncompressed_grp.group, | ||
2256 | "uncompressed", | ||
2257 | &uvcg_uncompressed_grp_type); | ||
2258 | config_group_init_type_name(&uvcg_mjpeg_grp.group, | ||
2259 | "mjpeg", | ||
2260 | &uvcg_mjpeg_grp_type); | ||
2261 | config_group_init_type_name(&uvcg_default_color_matching.group, | ||
2262 | "default", | ||
2263 | &uvcg_default_color_matching_type); | ||
2264 | config_group_init_type_name(&uvcg_color_matching_grp.group, | ||
2265 | "color_matching", | ||
2266 | &uvcg_color_matching_grp_type); | ||
2267 | configfs_add_default_group(&uvcg_default_color_matching.group, | ||
2268 | &uvcg_color_matching_grp.group); | ||
2269 | |||
2270 | config_group_init_type_name(&uvcg_streaming_class_fs.group, | ||
2271 | "fs", &uvcg_streaming_class_type); | ||
2272 | config_group_init_type_name(&uvcg_streaming_class_hs.group, | ||
2273 | "hs", &uvcg_streaming_class_type); | ||
2274 | config_group_init_type_name(&uvcg_streaming_class_ss.group, | ||
2275 | "ss", &uvcg_streaming_class_type); | ||
2276 | config_group_init_type_name(&uvcg_streaming_class_grp.group, | ||
2277 | "class", &uvcg_streaming_class_grp_type); | ||
2278 | configfs_add_default_group(&uvcg_streaming_class_fs.group, | ||
2279 | &uvcg_streaming_class_grp.group); | ||
2280 | configfs_add_default_group(&uvcg_streaming_class_hs.group, | ||
2281 | &uvcg_streaming_class_grp.group); | ||
2282 | configfs_add_default_group(&uvcg_streaming_class_ss.group, | ||
2283 | &uvcg_streaming_class_grp.group); | ||
2284 | |||
2285 | config_group_init_type_name(&uvcg_streaming_grp.group, | ||
2286 | "streaming", &uvcg_streaming_grp_type); | ||
2287 | configfs_add_default_group(&uvcg_streaming_header_grp.group, | ||
2288 | &uvcg_streaming_grp.group); | ||
2289 | configfs_add_default_group(&uvcg_uncompressed_grp.group, | ||
2290 | &uvcg_streaming_grp.group); | ||
2291 | configfs_add_default_group(&uvcg_mjpeg_grp.group, | ||
2292 | &uvcg_streaming_grp.group); | ||
2293 | configfs_add_default_group(&uvcg_color_matching_grp.group, | ||
2294 | &uvcg_streaming_grp.group); | ||
2295 | configfs_add_default_group(&uvcg_streaming_class_grp.group, | ||
2296 | &uvcg_streaming_grp.group); | ||
2297 | |||
2298 | config_group_init_type_name(&opts->func_inst.group, | ||
2299 | "", | ||
2300 | &uvc_func_type); | ||
2301 | configfs_add_default_group(&uvcg_control_grp.group, | ||
2302 | &opts->func_inst.group); | ||
2303 | configfs_add_default_group(&uvcg_streaming_grp.group, | ||
2304 | &opts->func_inst.group); | ||
2305 | 2465 | ||
2306 | return 0; | 2466 | config_group_init_type_name(&opts->func_inst.group, uvc_func_type.name, |
2467 | &uvc_func_type.type); | ||
2468 | |||
2469 | ret = uvcg_config_create_children(&opts->func_inst.group, | ||
2470 | &uvc_func_type); | ||
2471 | if (ret < 0) | ||
2472 | config_group_put(&opts->func_inst.group); | ||
2473 | |||
2474 | return ret; | ||
2307 | } | 2475 | } |
diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index 7f1ca3b57823..a1183eccee22 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c | |||
@@ -115,8 +115,8 @@ uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt) | |||
115 | } | 115 | } |
116 | 116 | ||
117 | if (i == ARRAY_SIZE(uvc_formats)) { | 117 | if (i == ARRAY_SIZE(uvc_formats)) { |
118 | printk(KERN_INFO "Unsupported format 0x%08x.\n", | 118 | uvcg_info(&uvc->func, "Unsupported format 0x%08x.\n", |
119 | fmt->fmt.pix.pixelformat); | 119 | fmt->fmt.pix.pixelformat); |
120 | return -EINVAL; | 120 | return -EINVAL; |
121 | } | 121 | } |
122 | 122 | ||
diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index d3567b90343a..5c042f380708 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c | |||
@@ -125,6 +125,23 @@ uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video, | |||
125 | * Request handling | 125 | * Request handling |
126 | */ | 126 | */ |
127 | 127 | ||
128 | static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req) | ||
129 | { | ||
130 | int ret; | ||
131 | |||
132 | ret = usb_ep_queue(video->ep, req, GFP_ATOMIC); | ||
133 | if (ret < 0) { | ||
134 | uvcg_err(&video->uvc->func, "Failed to queue request (%d).\n", | ||
135 | ret); | ||
136 | |||
137 | /* Isochronous endpoints can't be halted. */ | ||
138 | if (usb_endpoint_xfer_bulk(video->ep->desc)) | ||
139 | usb_ep_set_halt(video->ep); | ||
140 | } | ||
141 | |||
142 | return ret; | ||
143 | } | ||
144 | |||
128 | /* | 145 | /* |
129 | * I somehow feel that synchronisation won't be easy to achieve here. We have | 146 | * I somehow feel that synchronisation won't be easy to achieve here. We have |
130 | * three events that control USB requests submission: | 147 | * three events that control USB requests submission: |
@@ -169,13 +186,14 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req) | |||
169 | break; | 186 | break; |
170 | 187 | ||
171 | case -ESHUTDOWN: /* disconnect from host. */ | 188 | case -ESHUTDOWN: /* disconnect from host. */ |
172 | printk(KERN_DEBUG "VS request cancelled.\n"); | 189 | uvcg_dbg(&video->uvc->func, "VS request cancelled.\n"); |
173 | uvcg_queue_cancel(queue, 1); | 190 | uvcg_queue_cancel(queue, 1); |
174 | goto requeue; | 191 | goto requeue; |
175 | 192 | ||
176 | default: | 193 | default: |
177 | printk(KERN_INFO "VS request completed with status %d.\n", | 194 | uvcg_info(&video->uvc->func, |
178 | req->status); | 195 | "VS request completed with status %d.\n", |
196 | req->status); | ||
179 | uvcg_queue_cancel(queue, 0); | 197 | uvcg_queue_cancel(queue, 0); |
180 | goto requeue; | 198 | goto requeue; |
181 | } | 199 | } |
@@ -189,14 +207,13 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req) | |||
189 | 207 | ||
190 | video->encode(req, video, buf); | 208 | video->encode(req, video, buf); |
191 | 209 | ||
192 | if ((ret = usb_ep_queue(ep, req, GFP_ATOMIC)) < 0) { | 210 | ret = uvcg_video_ep_queue(video, req); |
193 | printk(KERN_INFO "Failed to queue request (%d).\n", ret); | 211 | spin_unlock_irqrestore(&video->queue.irqlock, flags); |
194 | usb_ep_set_halt(ep); | 212 | |
195 | spin_unlock_irqrestore(&video->queue.irqlock, flags); | 213 | if (ret < 0) { |
196 | uvcg_queue_cancel(queue, 0); | 214 | uvcg_queue_cancel(queue, 0); |
197 | goto requeue; | 215 | goto requeue; |
198 | } | 216 | } |
199 | spin_unlock_irqrestore(&video->queue.irqlock, flags); | ||
200 | 217 | ||
201 | return; | 218 | return; |
202 | 219 | ||
@@ -316,15 +333,13 @@ int uvcg_video_pump(struct uvc_video *video) | |||
316 | video->encode(req, video, buf); | 333 | video->encode(req, video, buf); |
317 | 334 | ||
318 | /* Queue the USB request */ | 335 | /* Queue the USB request */ |
319 | ret = usb_ep_queue(video->ep, req, GFP_ATOMIC); | 336 | ret = uvcg_video_ep_queue(video, req); |
337 | spin_unlock_irqrestore(&queue->irqlock, flags); | ||
338 | |||
320 | if (ret < 0) { | 339 | if (ret < 0) { |
321 | printk(KERN_INFO "Failed to queue request (%d)\n", ret); | ||
322 | usb_ep_set_halt(video->ep); | ||
323 | spin_unlock_irqrestore(&queue->irqlock, flags); | ||
324 | uvcg_queue_cancel(queue, 0); | 340 | uvcg_queue_cancel(queue, 0); |
325 | break; | 341 | break; |
326 | } | 342 | } |
327 | spin_unlock_irqrestore(&queue->irqlock, flags); | ||
328 | } | 343 | } |
329 | 344 | ||
330 | spin_lock_irqsave(&video->req_lock, flags); | 345 | spin_lock_irqsave(&video->req_lock, flags); |
@@ -342,8 +357,8 @@ int uvcg_video_enable(struct uvc_video *video, int enable) | |||
342 | int ret; | 357 | int ret; |
343 | 358 | ||
344 | if (video->ep == NULL) { | 359 | if (video->ep == NULL) { |
345 | printk(KERN_INFO "Video enable failed, device is " | 360 | uvcg_info(&video->uvc->func, |
346 | "uninitialized.\n"); | 361 | "Video enable failed, device is uninitialized.\n"); |
347 | return -ENODEV; | 362 | return -ENODEV; |
348 | } | 363 | } |
349 | 364 | ||
@@ -375,11 +390,12 @@ int uvcg_video_enable(struct uvc_video *video, int enable) | |||
375 | /* | 390 | /* |
376 | * Initialize the UVC video stream. | 391 | * Initialize the UVC video stream. |
377 | */ | 392 | */ |
378 | int uvcg_video_init(struct uvc_video *video) | 393 | int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc) |
379 | { | 394 | { |
380 | INIT_LIST_HEAD(&video->req_free); | 395 | INIT_LIST_HEAD(&video->req_free); |
381 | spin_lock_init(&video->req_lock); | 396 | spin_lock_init(&video->req_lock); |
382 | 397 | ||
398 | video->uvc = uvc; | ||
383 | video->fcc = V4L2_PIX_FMT_YUYV; | 399 | video->fcc = V4L2_PIX_FMT_YUYV; |
384 | video->bpp = 16; | 400 | video->bpp = 16; |
385 | video->width = 320; | 401 | video->width = 320; |
diff --git a/drivers/usb/gadget/function/uvc_video.h b/drivers/usb/gadget/function/uvc_video.h index 7d77122b0ff9..278dc52c7604 100644 --- a/drivers/usb/gadget/function/uvc_video.h +++ b/drivers/usb/gadget/function/uvc_video.h | |||
@@ -18,6 +18,6 @@ int uvcg_video_pump(struct uvc_video *video); | |||
18 | 18 | ||
19 | int uvcg_video_enable(struct uvc_video *video, int enable); | 19 | int uvcg_video_enable(struct uvc_video *video, int enable); |
20 | 20 | ||
21 | int uvcg_video_init(struct uvc_video *video); | 21 | int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc); |
22 | 22 | ||
23 | #endif /* __UVC_VIDEO_H__ */ | 23 | #endif /* __UVC_VIDEO_H__ */ |
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/epn.c b/drivers/usb/gadget/udc/aspeed-vhub/epn.c index 5939eb1e97f2..4a28e3fbeb0b 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/epn.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/epn.c | |||
@@ -353,7 +353,7 @@ static int ast_vhub_epn_queue(struct usb_ep* u_ep, struct usb_request *u_req, | |||
353 | /* Endpoint enabled ? */ | 353 | /* Endpoint enabled ? */ |
354 | if (!ep->epn.enabled || !u_ep->desc || !ep->dev || !ep->d_idx || | 354 | if (!ep->epn.enabled || !u_ep->desc || !ep->dev || !ep->d_idx || |
355 | !ep->dev->enabled || ep->dev->suspended) { | 355 | !ep->dev->enabled || ep->dev->suspended) { |
356 | EPDBG(ep,"Enqueing request on wrong or disabled EP\n"); | 356 | EPDBG(ep, "Enqueuing request on wrong or disabled EP\n"); |
357 | return -ESHUTDOWN; | 357 | return -ESHUTDOWN; |
358 | } | 358 | } |
359 | 359 | ||
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 17147b8c771e..11247322d587 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c | |||
@@ -2004,7 +2004,6 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, | |||
2004 | struct usba_udc *udc) | 2004 | struct usba_udc *udc) |
2005 | { | 2005 | { |
2006 | u32 val; | 2006 | u32 val; |
2007 | const char *name; | ||
2008 | struct device_node *np = pdev->dev.of_node; | 2007 | struct device_node *np = pdev->dev.of_node; |
2009 | const struct of_device_id *match; | 2008 | const struct of_device_id *match; |
2010 | struct device_node *pp; | 2009 | struct device_node *pp; |
@@ -2018,6 +2017,8 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, | |||
2018 | udc->errata = match->data; | 2017 | udc->errata = match->data; |
2019 | udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9g45-pmc"); | 2018 | udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9g45-pmc"); |
2020 | if (IS_ERR(udc->pmc)) | 2019 | if (IS_ERR(udc->pmc)) |
2020 | udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9rl-pmc"); | ||
2021 | if (IS_ERR(udc->pmc)) | ||
2021 | udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9x5-pmc"); | 2022 | udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9x5-pmc"); |
2022 | if (udc->errata && IS_ERR(udc->pmc)) | 2023 | if (udc->errata && IS_ERR(udc->pmc)) |
2023 | return ERR_CAST(udc->pmc); | 2024 | return ERR_CAST(udc->pmc); |
@@ -2094,11 +2095,6 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, | |||
2094 | ep->can_dma = of_property_read_bool(pp, "atmel,can-dma"); | 2095 | ep->can_dma = of_property_read_bool(pp, "atmel,can-dma"); |
2095 | ep->can_isoc = of_property_read_bool(pp, "atmel,can-isoc"); | 2096 | ep->can_isoc = of_property_read_bool(pp, "atmel,can-isoc"); |
2096 | 2097 | ||
2097 | ret = of_property_read_string(pp, "name", &name); | ||
2098 | if (ret) { | ||
2099 | dev_err(&pdev->dev, "of_probe: name error(%d)\n", ret); | ||
2100 | goto err; | ||
2101 | } | ||
2102 | sprintf(ep->name, "ep%d", ep->index); | 2098 | sprintf(ep->name, "ep%d", ep->index); |
2103 | ep->ep.name = ep->name; | 2099 | ep->ep.name = ep->name; |
2104 | 2100 | ||
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index af88b48c1cea..87d6b12779f2 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c | |||
@@ -690,6 +690,9 @@ EXPORT_SYMBOL_GPL(usb_gadget_connect); | |||
690 | * as a disconnect (when a VBUS session is active). Not all systems | 690 | * as a disconnect (when a VBUS session is active). Not all systems |
691 | * support software pullup controls. | 691 | * support software pullup controls. |
692 | * | 692 | * |
693 | * Following a successful disconnect, invoke the ->disconnect() callback | ||
694 | * for the current gadget driver so that UDC drivers don't need to. | ||
695 | * | ||
693 | * Returns zero on success, else negative errno. | 696 | * Returns zero on success, else negative errno. |
694 | */ | 697 | */ |
695 | int usb_gadget_disconnect(struct usb_gadget *gadget) | 698 | int usb_gadget_disconnect(struct usb_gadget *gadget) |
@@ -711,8 +714,10 @@ int usb_gadget_disconnect(struct usb_gadget *gadget) | |||
711 | } | 714 | } |
712 | 715 | ||
713 | ret = gadget->ops->pullup(gadget, 0); | 716 | ret = gadget->ops->pullup(gadget, 0); |
714 | if (!ret) | 717 | if (!ret) { |
715 | gadget->connected = 0; | 718 | gadget->connected = 0; |
719 | gadget->udc->driver->disconnect(gadget); | ||
720 | } | ||
716 | 721 | ||
717 | out: | 722 | out: |
718 | trace_usb_gadget_disconnect(gadget, ret); | 723 | trace_usb_gadget_disconnect(gadget, ret); |
@@ -1281,7 +1286,6 @@ static void usb_gadget_remove_driver(struct usb_udc *udc) | |||
1281 | kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); | 1286 | kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); |
1282 | 1287 | ||
1283 | usb_gadget_disconnect(udc->gadget); | 1288 | usb_gadget_disconnect(udc->gadget); |
1284 | udc->driver->disconnect(udc->gadget); | ||
1285 | udc->driver->unbind(udc->gadget); | 1289 | udc->driver->unbind(udc->gadget); |
1286 | usb_gadget_udc_stop(udc); | 1290 | usb_gadget_udc_stop(udc); |
1287 | 1291 | ||
@@ -1471,7 +1475,6 @@ static ssize_t soft_connect_store(struct device *dev, | |||
1471 | usb_gadget_connect(udc->gadget); | 1475 | usb_gadget_connect(udc->gadget); |
1472 | } else if (sysfs_streq(buf, "disconnect")) { | 1476 | } else if (sysfs_streq(buf, "disconnect")) { |
1473 | usb_gadget_disconnect(udc->gadget); | 1477 | usb_gadget_disconnect(udc->gadget); |
1474 | udc->driver->disconnect(udc->gadget); | ||
1475 | usb_gadget_udc_stop(udc); | 1478 | usb_gadget_udc_stop(udc); |
1476 | } else { | 1479 | } else { |
1477 | dev_err(dev, "unsupported command '%s'\n", buf); | 1480 | dev_err(dev, "unsupported command '%s'\n", buf); |
diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c index 587c5037ff07..bc6abaea907d 100644 --- a/drivers/usb/gadget/udc/fotg210-udc.c +++ b/drivers/usb/gadget/udc/fotg210-udc.c | |||
@@ -741,7 +741,7 @@ static void fotg210_get_status(struct fotg210_udc *fotg210, | |||
741 | fotg210->ep0_req->length = 2; | 741 | fotg210->ep0_req->length = 2; |
742 | 742 | ||
743 | spin_unlock(&fotg210->lock); | 743 | spin_unlock(&fotg210->lock); |
744 | fotg210_ep_queue(fotg210->gadget.ep0, fotg210->ep0_req, GFP_KERNEL); | 744 | fotg210_ep_queue(fotg210->gadget.ep0, fotg210->ep0_req, GFP_ATOMIC); |
745 | spin_lock(&fotg210->lock); | 745 | spin_lock(&fotg210->lock); |
746 | } | 746 | } |
747 | 747 | ||
diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index be59309e848c..20141c3096f6 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c | |||
@@ -2234,8 +2234,10 @@ static void fsl_udc_release(struct device *dev) | |||
2234 | Internal structure setup functions | 2234 | Internal structure setup functions |
2235 | *******************************************************************/ | 2235 | *******************************************************************/ |
2236 | /*------------------------------------------------------------------ | 2236 | /*------------------------------------------------------------------ |
2237 | * init resource for globle controller | 2237 | * init resource for global controller called by fsl_udc_probe() |
2238 | * Return the udc handle on success or NULL on failure | 2238 | * On success the udc handle is initialized, on failure it is |
2239 | * unchanged (reset). | ||
2240 | * Return 0 on success and -1 on allocation failure | ||
2239 | ------------------------------------------------------------------*/ | 2241 | ------------------------------------------------------------------*/ |
2240 | static int struct_udc_setup(struct fsl_udc *udc, | 2242 | static int struct_udc_setup(struct fsl_udc *udc, |
2241 | struct platform_device *pdev) | 2243 | struct platform_device *pdev) |
@@ -2247,8 +2249,10 @@ static int struct_udc_setup(struct fsl_udc *udc, | |||
2247 | udc->phy_mode = pdata->phy_mode; | 2249 | udc->phy_mode = pdata->phy_mode; |
2248 | 2250 | ||
2249 | udc->eps = kcalloc(udc->max_ep, sizeof(struct fsl_ep), GFP_KERNEL); | 2251 | udc->eps = kcalloc(udc->max_ep, sizeof(struct fsl_ep), GFP_KERNEL); |
2250 | if (!udc->eps) | 2252 | if (!udc->eps) { |
2251 | return -1; | 2253 | ERR("kmalloc udc endpoint status failed\n"); |
2254 | goto eps_alloc_failed; | ||
2255 | } | ||
2252 | 2256 | ||
2253 | /* initialized QHs, take care of alignment */ | 2257 | /* initialized QHs, take care of alignment */ |
2254 | size = udc->max_ep * sizeof(struct ep_queue_head); | 2258 | size = udc->max_ep * sizeof(struct ep_queue_head); |
@@ -2262,8 +2266,7 @@ static int struct_udc_setup(struct fsl_udc *udc, | |||
2262 | &udc->ep_qh_dma, GFP_KERNEL); | 2266 | &udc->ep_qh_dma, GFP_KERNEL); |
2263 | if (!udc->ep_qh) { | 2267 | if (!udc->ep_qh) { |
2264 | ERR("malloc QHs for udc failed\n"); | 2268 | ERR("malloc QHs for udc failed\n"); |
2265 | kfree(udc->eps); | 2269 | goto ep_queue_alloc_failed; |
2266 | return -1; | ||
2267 | } | 2270 | } |
2268 | 2271 | ||
2269 | udc->ep_qh_size = size; | 2272 | udc->ep_qh_size = size; |
@@ -2272,8 +2275,17 @@ static int struct_udc_setup(struct fsl_udc *udc, | |||
2272 | /* FIXME: fsl_alloc_request() ignores ep argument */ | 2275 | /* FIXME: fsl_alloc_request() ignores ep argument */ |
2273 | udc->status_req = container_of(fsl_alloc_request(NULL, GFP_KERNEL), | 2276 | udc->status_req = container_of(fsl_alloc_request(NULL, GFP_KERNEL), |
2274 | struct fsl_req, req); | 2277 | struct fsl_req, req); |
2278 | if (!udc->status_req) { | ||
2279 | ERR("kzalloc for udc status request failed\n"); | ||
2280 | goto udc_status_alloc_failed; | ||
2281 | } | ||
2282 | |||
2275 | /* allocate a small amount of memory to get valid address */ | 2283 | /* allocate a small amount of memory to get valid address */ |
2276 | udc->status_req->req.buf = kmalloc(8, GFP_KERNEL); | 2284 | udc->status_req->req.buf = kmalloc(8, GFP_KERNEL); |
2285 | if (!udc->status_req->req.buf) { | ||
2286 | ERR("kzalloc for udc request buffer failed\n"); | ||
2287 | goto udc_req_buf_alloc_failed; | ||
2288 | } | ||
2277 | 2289 | ||
2278 | udc->resume_state = USB_STATE_NOTATTACHED; | 2290 | udc->resume_state = USB_STATE_NOTATTACHED; |
2279 | udc->usb_state = USB_STATE_POWERED; | 2291 | udc->usb_state = USB_STATE_POWERED; |
@@ -2281,6 +2293,18 @@ static int struct_udc_setup(struct fsl_udc *udc, | |||
2281 | udc->remote_wakeup = 0; /* default to 0 on reset */ | 2293 | udc->remote_wakeup = 0; /* default to 0 on reset */ |
2282 | 2294 | ||
2283 | return 0; | 2295 | return 0; |
2296 | |||
2297 | udc_req_buf_alloc_failed: | ||
2298 | kfree(udc->status_req); | ||
2299 | udc_status_alloc_failed: | ||
2300 | kfree(udc->ep_qh); | ||
2301 | udc->ep_qh_size = 0; | ||
2302 | ep_queue_alloc_failed: | ||
2303 | kfree(udc->eps); | ||
2304 | eps_alloc_failed: | ||
2305 | udc->phy_mode = 0; | ||
2306 | return -1; | ||
2307 | |||
2284 | } | 2308 | } |
2285 | 2309 | ||
2286 | /*---------------------------------------------------------------- | 2310 | /*---------------------------------------------------------------- |
diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index 95f52232493b..cafde053788b 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c | |||
@@ -185,7 +185,7 @@ static int process_ep_req(struct mv_udc *udc, int index, | |||
185 | else | 185 | else |
186 | bit_pos = 1 << (16 + curr_req->ep->ep_num); | 186 | bit_pos = 1 << (16 + curr_req->ep->ep_num); |
187 | 187 | ||
188 | while ((curr_dqh->curr_dtd_ptr == curr_dtd->td_dma)) { | 188 | while (curr_dqh->curr_dtd_ptr == curr_dtd->td_dma) { |
189 | if (curr_dtd->dtd_next == EP_QUEUE_HEAD_NEXT_TERMINATE) { | 189 | if (curr_dtd->dtd_next == EP_QUEUE_HEAD_NEXT_TERMINATE) { |
190 | while (readl(&udc->op_regs->epstatus) & bit_pos) | 190 | while (readl(&udc->op_regs->epstatus) & bit_pos) |
191 | udelay(1); | 191 | udelay(1); |
diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index b02ab2a8d927..e7dae5379e04 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c | |||
@@ -1550,9 +1550,6 @@ static int net2280_pullup(struct usb_gadget *_gadget, int is_on) | |||
1550 | 1550 | ||
1551 | spin_unlock_irqrestore(&dev->lock, flags); | 1551 | spin_unlock_irqrestore(&dev->lock, flags); |
1552 | 1552 | ||
1553 | if (!is_on && dev->driver) | ||
1554 | dev->driver->disconnect(&dev->gadget); | ||
1555 | |||
1556 | return 0; | 1553 | return 0; |
1557 | } | 1554 | } |
1558 | 1555 | ||
diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index e1656f361e08..cdffbd1e0316 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c | |||
@@ -2437,6 +2437,9 @@ static ssize_t renesas_usb3_b_device_write(struct file *file, | |||
2437 | else | 2437 | else |
2438 | usb3->forced_b_device = false; | 2438 | usb3->forced_b_device = false; |
2439 | 2439 | ||
2440 | if (usb3->workaround_for_vbus) | ||
2441 | usb3_disconnect(usb3); | ||
2442 | |||
2440 | /* Let this driver call usb3_connect() anyway */ | 2443 | /* Let this driver call usb3_connect() anyway */ |
2441 | usb3_check_id(usb3); | 2444 | usb3_check_id(usb3); |
2442 | 2445 | ||
@@ -2600,6 +2603,13 @@ static const struct renesas_usb3_priv renesas_usb3_priv_gen3 = { | |||
2600 | .ramsize_per_pipe = SZ_4K, | 2603 | .ramsize_per_pipe = SZ_4K, |
2601 | }; | 2604 | }; |
2602 | 2605 | ||
2606 | static const struct renesas_usb3_priv renesas_usb3_priv_r8a77990 = { | ||
2607 | .ramsize_per_ramif = SZ_16K, | ||
2608 | .num_ramif = 4, | ||
2609 | .ramsize_per_pipe = SZ_4K, | ||
2610 | .workaround_for_vbus = true, | ||
2611 | }; | ||
2612 | |||
2603 | static const struct of_device_id usb3_of_match[] = { | 2613 | static const struct of_device_id usb3_of_match[] = { |
2604 | { | 2614 | { |
2605 | .compatible = "renesas,r8a7795-usb3-peri", | 2615 | .compatible = "renesas,r8a7795-usb3-peri", |
@@ -2618,6 +2628,10 @@ static const struct soc_device_attribute renesas_usb3_quirks_match[] = { | |||
2618 | .soc_id = "r8a7795", .revision = "ES1.*", | 2628 | .soc_id = "r8a7795", .revision = "ES1.*", |
2619 | .data = &renesas_usb3_priv_r8a7795_es1, | 2629 | .data = &renesas_usb3_priv_r8a7795_es1, |
2620 | }, | 2630 | }, |
2631 | { | ||
2632 | .soc_id = "r8a77990", | ||
2633 | .data = &renesas_usb3_priv_r8a77990, | ||
2634 | }, | ||
2621 | { /* sentinel */ }, | 2635 | { /* sentinel */ }, |
2622 | }; | 2636 | }; |
2623 | 2637 | ||
diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index 6407e433bc78..b1f4104d1283 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c | |||
@@ -1078,7 +1078,7 @@ static int xudc_ep_queue(struct usb_ep *_ep, struct usb_request *_req, | |||
1078 | unsigned long flags; | 1078 | unsigned long flags; |
1079 | 1079 | ||
1080 | if (!ep->desc) { | 1080 | if (!ep->desc) { |
1081 | dev_dbg(udc->dev, "%s:queing request to disabled %s\n", | 1081 | dev_dbg(udc->dev, "%s: queuing request to disabled %s\n", |
1082 | __func__, ep->name); | 1082 | __func__, ep->name); |
1083 | return -ESHUTDOWN; | 1083 | return -ESHUTDOWN; |
1084 | } | 1084 | } |
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 1a4ea98cac2a..16758b12a5e9 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig | |||
@@ -276,7 +276,7 @@ config USB_EHCI_EXYNOS | |||
276 | Enable support for the Samsung Exynos SOC's on-chip EHCI controller. | 276 | Enable support for the Samsung Exynos SOC's on-chip EHCI controller. |
277 | 277 | ||
278 | config USB_EHCI_MV | 278 | config USB_EHCI_MV |
279 | bool "EHCI support for Marvell PXA/MMP USB controller" | 279 | tristate "EHCI support for Marvell PXA/MMP USB controller" |
280 | depends on (ARCH_PXA || ARCH_MMP) | 280 | depends on (ARCH_PXA || ARCH_MMP) |
281 | select USB_EHCI_ROOT_HUB_TT | 281 | select USB_EHCI_ROOT_HUB_TT |
282 | ---help--- | 282 | ---help--- |
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index e6235269c151..84514f71ae44 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile | |||
@@ -87,6 +87,7 @@ obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o | |||
87 | obj-$(CONFIG_USB_FSL_USB2) += fsl-mph-dr-of.o | 87 | obj-$(CONFIG_USB_FSL_USB2) += fsl-mph-dr-of.o |
88 | obj-$(CONFIG_USB_EHCI_FSL) += fsl-mph-dr-of.o | 88 | obj-$(CONFIG_USB_EHCI_FSL) += fsl-mph-dr-of.o |
89 | obj-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o | 89 | obj-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o |
90 | obj-$(CONFIG_USB_EHCI_MV) += ehci-mv.o | ||
90 | obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o | 91 | obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o |
91 | obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o | 92 | obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o |
92 | obj-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o | 93 | obj-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o |
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 8608ac513fb7..cdafa97f632d 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -730,9 +730,9 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) | |||
730 | /* normal [4.15.1.2] or error [4.15.1.1] completion */ | 730 | /* normal [4.15.1.2] or error [4.15.1.1] completion */ |
731 | if (likely ((status & (STS_INT|STS_ERR)) != 0)) { | 731 | if (likely ((status & (STS_INT|STS_ERR)) != 0)) { |
732 | if (likely ((status & STS_ERR) == 0)) | 732 | if (likely ((status & STS_ERR) == 0)) |
733 | COUNT (ehci->stats.normal); | 733 | INCR(ehci->stats.normal); |
734 | else | 734 | else |
735 | COUNT (ehci->stats.error); | 735 | INCR(ehci->stats.error); |
736 | bh = 1; | 736 | bh = 1; |
737 | } | 737 | } |
738 | 738 | ||
@@ -756,7 +756,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) | |||
756 | if (cmd & CMD_IAAD) | 756 | if (cmd & CMD_IAAD) |
757 | ehci_dbg(ehci, "IAA with IAAD still set?\n"); | 757 | ehci_dbg(ehci, "IAA with IAAD still set?\n"); |
758 | if (ehci->iaa_in_progress) | 758 | if (ehci->iaa_in_progress) |
759 | COUNT(ehci->stats.iaa); | 759 | INCR(ehci->stats.iaa); |
760 | end_iaa_cycle(ehci); | 760 | end_iaa_cycle(ehci); |
761 | } | 761 | } |
762 | 762 | ||
@@ -1286,11 +1286,6 @@ MODULE_LICENSE ("GPL"); | |||
1286 | #define PLATFORM_DRIVER ehci_grlib_driver | 1286 | #define PLATFORM_DRIVER ehci_grlib_driver |
1287 | #endif | 1287 | #endif |
1288 | 1288 | ||
1289 | #ifdef CONFIG_USB_EHCI_MV | ||
1290 | #include "ehci-mv.c" | ||
1291 | #define PLATFORM_DRIVER ehci_mv_driver | ||
1292 | #endif | ||
1293 | |||
1294 | static int __init ehci_hcd_init(void) | 1289 | static int __init ehci_hcd_init(void) |
1295 | { | 1290 | { |
1296 | int retval = 0; | 1291 | int retval = 0; |
diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index de764459e05a..f26109eafdbf 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c | |||
@@ -12,24 +12,33 @@ | |||
12 | #include <linux/err.h> | 12 | #include <linux/err.h> |
13 | #include <linux/usb/otg.h> | 13 | #include <linux/usb/otg.h> |
14 | #include <linux/platform_data/mv_usb.h> | 14 | #include <linux/platform_data/mv_usb.h> |
15 | #include <linux/io.h> | ||
16 | |||
17 | #include <linux/usb/hcd.h> | ||
18 | |||
19 | #include "ehci.h" | ||
20 | |||
21 | /* registers */ | ||
22 | #define U2x_CAPREGS_OFFSET 0x100 | ||
15 | 23 | ||
16 | #define CAPLENGTH_MASK (0xff) | 24 | #define CAPLENGTH_MASK (0xff) |
17 | 25 | ||
18 | struct ehci_hcd_mv { | 26 | #define hcd_to_ehci_hcd_mv(h) ((struct ehci_hcd_mv *)hcd_to_ehci(h)->priv) |
19 | struct usb_hcd *hcd; | ||
20 | 27 | ||
28 | struct ehci_hcd_mv { | ||
21 | /* Which mode does this ehci running OTG/Host ? */ | 29 | /* Which mode does this ehci running OTG/Host ? */ |
22 | int mode; | 30 | int mode; |
23 | 31 | ||
24 | void __iomem *phy_regs; | 32 | void __iomem *base; |
25 | void __iomem *cap_regs; | 33 | void __iomem *cap_regs; |
26 | void __iomem *op_regs; | 34 | void __iomem *op_regs; |
27 | 35 | ||
28 | struct usb_phy *otg; | 36 | struct usb_phy *otg; |
37 | struct clk *clk; | ||
29 | 38 | ||
30 | struct mv_usb_platform_data *pdata; | 39 | struct phy *phy; |
31 | 40 | ||
32 | struct clk *clk; | 41 | int (*set_vbus)(unsigned int vbus); |
33 | }; | 42 | }; |
34 | 43 | ||
35 | static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv) | 44 | static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv) |
@@ -44,29 +53,20 @@ static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv) | |||
44 | 53 | ||
45 | static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv) | 54 | static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv) |
46 | { | 55 | { |
47 | int retval; | ||
48 | |||
49 | ehci_clock_enable(ehci_mv); | 56 | ehci_clock_enable(ehci_mv); |
50 | if (ehci_mv->pdata->phy_init) { | 57 | return phy_init(ehci_mv->phy); |
51 | retval = ehci_mv->pdata->phy_init(ehci_mv->phy_regs); | ||
52 | if (retval) | ||
53 | return retval; | ||
54 | } | ||
55 | |||
56 | return 0; | ||
57 | } | 58 | } |
58 | 59 | ||
59 | static void mv_ehci_disable(struct ehci_hcd_mv *ehci_mv) | 60 | static void mv_ehci_disable(struct ehci_hcd_mv *ehci_mv) |
60 | { | 61 | { |
61 | if (ehci_mv->pdata->phy_deinit) | 62 | phy_exit(ehci_mv->phy); |
62 | ehci_mv->pdata->phy_deinit(ehci_mv->phy_regs); | ||
63 | ehci_clock_disable(ehci_mv); | 63 | ehci_clock_disable(ehci_mv); |
64 | } | 64 | } |
65 | 65 | ||
66 | static int mv_ehci_reset(struct usb_hcd *hcd) | 66 | static int mv_ehci_reset(struct usb_hcd *hcd) |
67 | { | 67 | { |
68 | struct device *dev = hcd->self.controller; | 68 | struct device *dev = hcd->self.controller; |
69 | struct ehci_hcd_mv *ehci_mv = dev_get_drvdata(dev); | 69 | struct ehci_hcd_mv *ehci_mv = hcd_to_ehci_hcd_mv(hcd); |
70 | int retval; | 70 | int retval; |
71 | 71 | ||
72 | if (ehci_mv == NULL) { | 72 | if (ehci_mv == NULL) { |
@@ -83,46 +83,11 @@ static int mv_ehci_reset(struct usb_hcd *hcd) | |||
83 | return retval; | 83 | return retval; |
84 | } | 84 | } |
85 | 85 | ||
86 | static const struct hc_driver mv_ehci_hc_driver = { | 86 | static struct hc_driver __read_mostly ehci_platform_hc_driver; |
87 | .description = hcd_name, | 87 | |
88 | .product_desc = "Marvell EHCI", | 88 | static const struct ehci_driver_overrides platform_overrides __initconst = { |
89 | .hcd_priv_size = sizeof(struct ehci_hcd), | 89 | .reset = mv_ehci_reset, |
90 | 90 | .extra_priv_size = sizeof(struct ehci_hcd_mv), | |
91 | /* | ||
92 | * generic hardware linkage | ||
93 | */ | ||
94 | .irq = ehci_irq, | ||
95 | .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, | ||
96 | |||
97 | /* | ||
98 | * basic lifecycle operations | ||
99 | */ | ||
100 | .reset = mv_ehci_reset, | ||
101 | .start = ehci_run, | ||
102 | .stop = ehci_stop, | ||
103 | .shutdown = ehci_shutdown, | ||
104 | |||
105 | /* | ||
106 | * managing i/o requests and associated device resources | ||
107 | */ | ||
108 | .urb_enqueue = ehci_urb_enqueue, | ||
109 | .urb_dequeue = ehci_urb_dequeue, | ||
110 | .endpoint_disable = ehci_endpoint_disable, | ||
111 | .endpoint_reset = ehci_endpoint_reset, | ||
112 | .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, | ||
113 | |||
114 | /* | ||
115 | * scheduling support | ||
116 | */ | ||
117 | .get_frame_number = ehci_get_frame, | ||
118 | |||
119 | /* | ||
120 | * root hub support | ||
121 | */ | ||
122 | .hub_status_data = ehci_hub_status_data, | ||
123 | .hub_control = ehci_hub_control, | ||
124 | .bus_suspend = ehci_bus_suspend, | ||
125 | .bus_resume = ehci_bus_resume, | ||
126 | }; | 91 | }; |
127 | 92 | ||
128 | static int mv_ehci_probe(struct platform_device *pdev) | 93 | static int mv_ehci_probe(struct platform_device *pdev) |
@@ -135,27 +100,29 @@ static int mv_ehci_probe(struct platform_device *pdev) | |||
135 | int retval = -ENODEV; | 100 | int retval = -ENODEV; |
136 | u32 offset; | 101 | u32 offset; |
137 | 102 | ||
138 | if (!pdata) { | ||
139 | dev_err(&pdev->dev, "missing platform_data\n"); | ||
140 | return -ENODEV; | ||
141 | } | ||
142 | |||
143 | if (usb_disabled()) | 103 | if (usb_disabled()) |
144 | return -ENODEV; | 104 | return -ENODEV; |
145 | 105 | ||
146 | hcd = usb_create_hcd(&mv_ehci_hc_driver, &pdev->dev, "mv ehci"); | 106 | hcd = usb_create_hcd(&ehci_platform_hc_driver, &pdev->dev, "mv ehci"); |
147 | if (!hcd) | 107 | if (!hcd) |
148 | return -ENOMEM; | 108 | return -ENOMEM; |
149 | 109 | ||
150 | ehci_mv = devm_kzalloc(&pdev->dev, sizeof(*ehci_mv), GFP_KERNEL); | 110 | platform_set_drvdata(pdev, hcd); |
151 | if (ehci_mv == NULL) { | 111 | ehci_mv = hcd_to_ehci_hcd_mv(hcd); |
152 | retval = -ENOMEM; | 112 | |
153 | goto err_put_hcd; | 113 | ehci_mv->mode = MV_USB_MODE_HOST; |
114 | if (pdata) { | ||
115 | ehci_mv->mode = pdata->mode; | ||
116 | ehci_mv->set_vbus = pdata->set_vbus; | ||
154 | } | 117 | } |
155 | 118 | ||
156 | platform_set_drvdata(pdev, ehci_mv); | 119 | ehci_mv->phy = devm_phy_get(&pdev->dev, "usb"); |
157 | ehci_mv->pdata = pdata; | 120 | if (IS_ERR(ehci_mv->phy)) { |
158 | ehci_mv->hcd = hcd; | 121 | retval = PTR_ERR(ehci_mv->phy); |
122 | if (retval != -EPROBE_DEFER) | ||
123 | dev_err(&pdev->dev, "Failed to get phy.\n"); | ||
124 | goto err_put_hcd; | ||
125 | } | ||
159 | 126 | ||
160 | ehci_mv->clk = devm_clk_get(&pdev->dev, NULL); | 127 | ehci_mv->clk = devm_clk_get(&pdev->dev, NULL); |
161 | if (IS_ERR(ehci_mv->clk)) { | 128 | if (IS_ERR(ehci_mv->clk)) { |
@@ -164,17 +131,12 @@ static int mv_ehci_probe(struct platform_device *pdev) | |||
164 | goto err_put_hcd; | 131 | goto err_put_hcd; |
165 | } | 132 | } |
166 | 133 | ||
167 | r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs"); | ||
168 | ehci_mv->phy_regs = devm_ioremap_resource(&pdev->dev, r); | ||
169 | if (IS_ERR(ehci_mv->phy_regs)) { | ||
170 | retval = PTR_ERR(ehci_mv->phy_regs); | ||
171 | goto err_put_hcd; | ||
172 | } | ||
173 | 134 | ||
174 | r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "capregs"); | 135 | |
175 | ehci_mv->cap_regs = devm_ioremap_resource(&pdev->dev, r); | 136 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
176 | if (IS_ERR(ehci_mv->cap_regs)) { | 137 | ehci_mv->base = devm_ioremap_resource(&pdev->dev, r); |
177 | retval = PTR_ERR(ehci_mv->cap_regs); | 138 | if (IS_ERR(ehci_mv->base)) { |
139 | retval = PTR_ERR(ehci_mv->base); | ||
178 | goto err_put_hcd; | 140 | goto err_put_hcd; |
179 | } | 141 | } |
180 | 142 | ||
@@ -184,6 +146,8 @@ static int mv_ehci_probe(struct platform_device *pdev) | |||
184 | goto err_put_hcd; | 146 | goto err_put_hcd; |
185 | } | 147 | } |
186 | 148 | ||
149 | ehci_mv->cap_regs = | ||
150 | (void __iomem *) ((unsigned long) ehci_mv->base + U2x_CAPREGS_OFFSET); | ||
187 | offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK; | 151 | offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK; |
188 | ehci_mv->op_regs = | 152 | ehci_mv->op_regs = |
189 | (void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset); | 153 | (void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset); |
@@ -202,7 +166,6 @@ static int mv_ehci_probe(struct platform_device *pdev) | |||
202 | ehci = hcd_to_ehci(hcd); | 166 | ehci = hcd_to_ehci(hcd); |
203 | ehci->caps = (struct ehci_caps *) ehci_mv->cap_regs; | 167 | ehci->caps = (struct ehci_caps *) ehci_mv->cap_regs; |
204 | 168 | ||
205 | ehci_mv->mode = pdata->mode; | ||
206 | if (ehci_mv->mode == MV_USB_MODE_OTG) { | 169 | if (ehci_mv->mode == MV_USB_MODE_OTG) { |
207 | ehci_mv->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); | 170 | ehci_mv->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); |
208 | if (IS_ERR(ehci_mv->otg)) { | 171 | if (IS_ERR(ehci_mv->otg)) { |
@@ -227,8 +190,8 @@ static int mv_ehci_probe(struct platform_device *pdev) | |||
227 | /* otg will enable clock before use as host */ | 190 | /* otg will enable clock before use as host */ |
228 | mv_ehci_disable(ehci_mv); | 191 | mv_ehci_disable(ehci_mv); |
229 | } else { | 192 | } else { |
230 | if (pdata->set_vbus) | 193 | if (ehci_mv->set_vbus) |
231 | pdata->set_vbus(1); | 194 | ehci_mv->set_vbus(1); |
232 | 195 | ||
233 | retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); | 196 | retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); |
234 | if (retval) { | 197 | if (retval) { |
@@ -239,9 +202,6 @@ static int mv_ehci_probe(struct platform_device *pdev) | |||
239 | device_wakeup_enable(hcd->self.controller); | 202 | device_wakeup_enable(hcd->self.controller); |
240 | } | 203 | } |
241 | 204 | ||
242 | if (pdata->private_init) | ||
243 | pdata->private_init(ehci_mv->op_regs, ehci_mv->phy_regs); | ||
244 | |||
245 | dev_info(&pdev->dev, | 205 | dev_info(&pdev->dev, |
246 | "successful find EHCI device with regs 0x%p irq %d" | 206 | "successful find EHCI device with regs 0x%p irq %d" |
247 | " working in %s mode\n", hcd->regs, hcd->irq, | 207 | " working in %s mode\n", hcd->regs, hcd->irq, |
@@ -250,8 +210,8 @@ static int mv_ehci_probe(struct platform_device *pdev) | |||
250 | return 0; | 210 | return 0; |
251 | 211 | ||
252 | err_set_vbus: | 212 | err_set_vbus: |
253 | if (pdata->set_vbus) | 213 | if (ehci_mv->set_vbus) |
254 | pdata->set_vbus(0); | 214 | ehci_mv->set_vbus(0); |
255 | err_disable_clk: | 215 | err_disable_clk: |
256 | mv_ehci_disable(ehci_mv); | 216 | mv_ehci_disable(ehci_mv); |
257 | err_put_hcd: | 217 | err_put_hcd: |
@@ -262,8 +222,8 @@ err_put_hcd: | |||
262 | 222 | ||
263 | static int mv_ehci_remove(struct platform_device *pdev) | 223 | static int mv_ehci_remove(struct platform_device *pdev) |
264 | { | 224 | { |
265 | struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev); | 225 | struct usb_hcd *hcd = platform_get_drvdata(pdev); |
266 | struct usb_hcd *hcd = ehci_mv->hcd; | 226 | struct ehci_hcd_mv *ehci_mv = hcd_to_ehci_hcd_mv(hcd); |
267 | 227 | ||
268 | if (hcd->rh_registered) | 228 | if (hcd->rh_registered) |
269 | usb_remove_hcd(hcd); | 229 | usb_remove_hcd(hcd); |
@@ -272,8 +232,8 @@ static int mv_ehci_remove(struct platform_device *pdev) | |||
272 | otg_set_host(ehci_mv->otg->otg, NULL); | 232 | otg_set_host(ehci_mv->otg->otg, NULL); |
273 | 233 | ||
274 | if (ehci_mv->mode == MV_USB_MODE_HOST) { | 234 | if (ehci_mv->mode == MV_USB_MODE_HOST) { |
275 | if (ehci_mv->pdata->set_vbus) | 235 | if (ehci_mv->set_vbus) |
276 | ehci_mv->pdata->set_vbus(0); | 236 | ehci_mv->set_vbus(0); |
277 | 237 | ||
278 | mv_ehci_disable(ehci_mv); | 238 | mv_ehci_disable(ehci_mv); |
279 | } | 239 | } |
@@ -295,8 +255,7 @@ static const struct platform_device_id ehci_id_table[] = { | |||
295 | 255 | ||
296 | static void mv_ehci_shutdown(struct platform_device *pdev) | 256 | static void mv_ehci_shutdown(struct platform_device *pdev) |
297 | { | 257 | { |
298 | struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev); | 258 | struct usb_hcd *hcd = platform_get_drvdata(pdev); |
299 | struct usb_hcd *hcd = ehci_mv->hcd; | ||
300 | 259 | ||
301 | if (!hcd->rh_registered) | 260 | if (!hcd->rh_registered) |
302 | return; | 261 | return; |
@@ -305,13 +264,41 @@ static void mv_ehci_shutdown(struct platform_device *pdev) | |||
305 | hcd->driver->shutdown(hcd); | 264 | hcd->driver->shutdown(hcd); |
306 | } | 265 | } |
307 | 266 | ||
267 | static const struct of_device_id ehci_mv_dt_ids[] = { | ||
268 | { .compatible = "marvell,pxau2o-ehci", }, | ||
269 | {}, | ||
270 | }; | ||
271 | |||
308 | static struct platform_driver ehci_mv_driver = { | 272 | static struct platform_driver ehci_mv_driver = { |
309 | .probe = mv_ehci_probe, | 273 | .probe = mv_ehci_probe, |
310 | .remove = mv_ehci_remove, | 274 | .remove = mv_ehci_remove, |
311 | .shutdown = mv_ehci_shutdown, | 275 | .shutdown = mv_ehci_shutdown, |
312 | .driver = { | 276 | .driver = { |
313 | .name = "mv-ehci", | 277 | .name = "mv-ehci", |
314 | .bus = &platform_bus_type, | 278 | .bus = &platform_bus_type, |
315 | }, | 279 | .of_match_table = ehci_mv_dt_ids, |
280 | }, | ||
316 | .id_table = ehci_id_table, | 281 | .id_table = ehci_id_table, |
317 | }; | 282 | }; |
283 | |||
284 | static int __init ehci_platform_init(void) | ||
285 | { | ||
286 | if (usb_disabled()) | ||
287 | return -ENODEV; | ||
288 | |||
289 | ehci_init_driver(&ehci_platform_hc_driver, &platform_overrides); | ||
290 | return platform_driver_register(&ehci_mv_driver); | ||
291 | } | ||
292 | module_init(ehci_platform_init); | ||
293 | |||
294 | static void __exit ehci_platform_cleanup(void) | ||
295 | { | ||
296 | platform_driver_unregister(&ehci_mv_driver); | ||
297 | } | ||
298 | module_exit(ehci_platform_cleanup); | ||
299 | |||
300 | MODULE_DESCRIPTION("Marvell EHCI driver"); | ||
301 | MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>"); | ||
302 | MODULE_AUTHOR("Neil Zhang <zhangwm@marvell.com>"); | ||
303 | MODULE_ALIAS("mv-ehci"); | ||
304 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 327630405695..aa2f77f1506d 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c | |||
@@ -245,12 +245,12 @@ ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status) | |||
245 | } | 245 | } |
246 | 246 | ||
247 | if (unlikely(urb->unlinked)) { | 247 | if (unlikely(urb->unlinked)) { |
248 | COUNT(ehci->stats.unlink); | 248 | INCR(ehci->stats.unlink); |
249 | } else { | 249 | } else { |
250 | /* report non-error and short read status as zero */ | 250 | /* report non-error and short read status as zero */ |
251 | if (status == -EINPROGRESS || status == -EREMOTEIO) | 251 | if (status == -EINPROGRESS || status == -EREMOTEIO) |
252 | status = 0; | 252 | status = 0; |
253 | COUNT(ehci->stats.complete); | 253 | INCR(ehci->stats.complete); |
254 | } | 254 | } |
255 | 255 | ||
256 | #ifdef EHCI_URB_TRACE | 256 | #ifdef EHCI_URB_TRACE |
diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index 4fcebda4b79d..a79c8ac0a55f 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c | |||
@@ -347,7 +347,7 @@ static void ehci_iaa_watchdog(struct ehci_hcd *ehci) | |||
347 | */ | 347 | */ |
348 | status = ehci_readl(ehci, &ehci->regs->status); | 348 | status = ehci_readl(ehci, &ehci->regs->status); |
349 | if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { | 349 | if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { |
350 | COUNT(ehci->stats.lost_iaa); | 350 | INCR(ehci->stats.lost_iaa); |
351 | ehci_writel(ehci, STS_IAA, &ehci->regs->status); | 351 | ehci_writel(ehci, STS_IAA, &ehci->regs->status); |
352 | } | 352 | } |
353 | 353 | ||
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index c8e9a48e1d51..ac5e967907d1 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h | |||
@@ -235,9 +235,9 @@ struct ehci_hcd { /* one per controller */ | |||
235 | /* irq statistics */ | 235 | /* irq statistics */ |
236 | #ifdef EHCI_STATS | 236 | #ifdef EHCI_STATS |
237 | struct ehci_stats stats; | 237 | struct ehci_stats stats; |
238 | # define COUNT(x) ((x)++) | 238 | # define INCR(x) ((x)++) |
239 | #else | 239 | #else |
240 | # define COUNT(x) | 240 | # define INCR(x) do {} while (0) |
241 | #endif | 241 | #endif |
242 | 242 | ||
243 | /* debug files */ | 243 | /* debug files */ |
diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index e64eb47770c8..0da68df259c8 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/uaccess.h> | 31 | #include <linux/uaccess.h> |
32 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
33 | #include <linux/io.h> | 33 | #include <linux/io.h> |
34 | #include <linux/clk.h> | ||
34 | 35 | ||
35 | #include <asm/byteorder.h> | 36 | #include <asm/byteorder.h> |
36 | #include <asm/irq.h> | 37 | #include <asm/irq.h> |
@@ -1285,7 +1286,7 @@ static void fotg210_iaa_watchdog(struct fotg210_hcd *fotg210) | |||
1285 | */ | 1286 | */ |
1286 | status = fotg210_readl(fotg210, &fotg210->regs->status); | 1287 | status = fotg210_readl(fotg210, &fotg210->regs->status); |
1287 | if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { | 1288 | if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { |
1288 | COUNT(fotg210->stats.lost_iaa); | 1289 | INCR(fotg210->stats.lost_iaa); |
1289 | fotg210_writel(fotg210, STS_IAA, | 1290 | fotg210_writel(fotg210, STS_IAA, |
1290 | &fotg210->regs->status); | 1291 | &fotg210->regs->status); |
1291 | } | 1292 | } |
@@ -2204,12 +2205,12 @@ __acquires(fotg210->lock) | |||
2204 | } | 2205 | } |
2205 | 2206 | ||
2206 | if (unlikely(urb->unlinked)) { | 2207 | if (unlikely(urb->unlinked)) { |
2207 | COUNT(fotg210->stats.unlink); | 2208 | INCR(fotg210->stats.unlink); |
2208 | } else { | 2209 | } else { |
2209 | /* report non-error and short read status as zero */ | 2210 | /* report non-error and short read status as zero */ |
2210 | if (status == -EINPROGRESS || status == -EREMOTEIO) | 2211 | if (status == -EINPROGRESS || status == -EREMOTEIO) |
2211 | status = 0; | 2212 | status = 0; |
2212 | COUNT(fotg210->stats.complete); | 2213 | INCR(fotg210->stats.complete); |
2213 | } | 2214 | } |
2214 | 2215 | ||
2215 | #ifdef FOTG210_URB_TRACE | 2216 | #ifdef FOTG210_URB_TRACE |
@@ -5153,9 +5154,9 @@ static irqreturn_t fotg210_irq(struct usb_hcd *hcd) | |||
5153 | /* normal [4.15.1.2] or error [4.15.1.1] completion */ | 5154 | /* normal [4.15.1.2] or error [4.15.1.1] completion */ |
5154 | if (likely((status & (STS_INT|STS_ERR)) != 0)) { | 5155 | if (likely((status & (STS_INT|STS_ERR)) != 0)) { |
5155 | if (likely((status & STS_ERR) == 0)) | 5156 | if (likely((status & STS_ERR) == 0)) |
5156 | COUNT(fotg210->stats.normal); | 5157 | INCR(fotg210->stats.normal); |
5157 | else | 5158 | else |
5158 | COUNT(fotg210->stats.error); | 5159 | INCR(fotg210->stats.error); |
5159 | bh = 1; | 5160 | bh = 1; |
5160 | } | 5161 | } |
5161 | 5162 | ||
@@ -5180,7 +5181,7 @@ static irqreturn_t fotg210_irq(struct usb_hcd *hcd) | |||
5180 | if (cmd & CMD_IAAD) | 5181 | if (cmd & CMD_IAAD) |
5181 | fotg210_dbg(fotg210, "IAA with IAAD still set?\n"); | 5182 | fotg210_dbg(fotg210, "IAA with IAAD still set?\n"); |
5182 | if (fotg210->async_iaa) { | 5183 | if (fotg210->async_iaa) { |
5183 | COUNT(fotg210->stats.iaa); | 5184 | INCR(fotg210->stats.iaa); |
5184 | end_unlink_async(fotg210); | 5185 | end_unlink_async(fotg210); |
5185 | } else | 5186 | } else |
5186 | fotg210_dbg(fotg210, "IAA with nothing unlinked?\n"); | 5187 | fotg210_dbg(fotg210, "IAA with nothing unlinked?\n"); |
@@ -5596,7 +5597,7 @@ static int fotg210_hcd_probe(struct platform_device *pdev) | |||
5596 | hcd->regs = devm_ioremap_resource(&pdev->dev, res); | 5597 | hcd->regs = devm_ioremap_resource(&pdev->dev, res); |
5597 | if (IS_ERR(hcd->regs)) { | 5598 | if (IS_ERR(hcd->regs)) { |
5598 | retval = PTR_ERR(hcd->regs); | 5599 | retval = PTR_ERR(hcd->regs); |
5599 | goto failed; | 5600 | goto failed_put_hcd; |
5600 | } | 5601 | } |
5601 | 5602 | ||
5602 | hcd->rsrc_start = res->start; | 5603 | hcd->rsrc_start = res->start; |
@@ -5606,22 +5607,43 @@ static int fotg210_hcd_probe(struct platform_device *pdev) | |||
5606 | 5607 | ||
5607 | fotg210->caps = hcd->regs; | 5608 | fotg210->caps = hcd->regs; |
5608 | 5609 | ||
5610 | /* It's OK not to supply this clock */ | ||
5611 | fotg210->pclk = clk_get(dev, "PCLK"); | ||
5612 | if (!IS_ERR(fotg210->pclk)) { | ||
5613 | retval = clk_prepare_enable(fotg210->pclk); | ||
5614 | if (retval) { | ||
5615 | dev_err(dev, "failed to enable PCLK\n"); | ||
5616 | goto failed_put_hcd; | ||
5617 | } | ||
5618 | } else if (PTR_ERR(fotg210->pclk) == -EPROBE_DEFER) { | ||
5619 | /* | ||
5620 | * Percolate deferrals, for anything else, | ||
5621 | * just live without the clocking. | ||
5622 | */ | ||
5623 | retval = PTR_ERR(fotg210->pclk); | ||
5624 | goto failed_dis_clk; | ||
5625 | } | ||
5626 | |||
5609 | retval = fotg210_setup(hcd); | 5627 | retval = fotg210_setup(hcd); |
5610 | if (retval) | 5628 | if (retval) |
5611 | goto failed; | 5629 | goto failed_dis_clk; |
5612 | 5630 | ||
5613 | fotg210_init(fotg210); | 5631 | fotg210_init(fotg210); |
5614 | 5632 | ||
5615 | retval = usb_add_hcd(hcd, irq, IRQF_SHARED); | 5633 | retval = usb_add_hcd(hcd, irq, IRQF_SHARED); |
5616 | if (retval) { | 5634 | if (retval) { |
5617 | dev_err(dev, "failed to add hcd with err %d\n", retval); | 5635 | dev_err(dev, "failed to add hcd with err %d\n", retval); |
5618 | goto failed; | 5636 | goto failed_dis_clk; |
5619 | } | 5637 | } |
5620 | device_wakeup_enable(hcd->self.controller); | 5638 | device_wakeup_enable(hcd->self.controller); |
5639 | platform_set_drvdata(pdev, hcd); | ||
5621 | 5640 | ||
5622 | return retval; | 5641 | return retval; |
5623 | 5642 | ||
5624 | failed: | 5643 | failed_dis_clk: |
5644 | if (!IS_ERR(fotg210->pclk)) | ||
5645 | clk_disable_unprepare(fotg210->pclk); | ||
5646 | failed_put_hcd: | ||
5625 | usb_put_hcd(hcd); | 5647 | usb_put_hcd(hcd); |
5626 | fail_create_hcd: | 5648 | fail_create_hcd: |
5627 | dev_err(dev, "init %s fail, %d\n", dev_name(dev), retval); | 5649 | dev_err(dev, "init %s fail, %d\n", dev_name(dev), retval); |
@@ -5635,11 +5657,11 @@ fail_create_hcd: | |||
5635 | */ | 5657 | */ |
5636 | static int fotg210_hcd_remove(struct platform_device *pdev) | 5658 | static int fotg210_hcd_remove(struct platform_device *pdev) |
5637 | { | 5659 | { |
5638 | struct device *dev = &pdev->dev; | 5660 | struct usb_hcd *hcd = platform_get_drvdata(pdev); |
5639 | struct usb_hcd *hcd = dev_get_drvdata(dev); | 5661 | struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); |
5640 | 5662 | ||
5641 | if (!hcd) | 5663 | if (!IS_ERR(fotg210->pclk)) |
5642 | return 0; | 5664 | clk_disable_unprepare(fotg210->pclk); |
5643 | 5665 | ||
5644 | usb_remove_hcd(hcd); | 5666 | usb_remove_hcd(hcd); |
5645 | usb_put_hcd(hcd); | 5667 | usb_put_hcd(hcd); |
diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/host/fotg210.h index 7fcd785c7bc8..1b4db95e5c43 100644 --- a/drivers/usb/host/fotg210.h +++ b/drivers/usb/host/fotg210.h | |||
@@ -177,11 +177,14 @@ struct fotg210_hcd { /* one per controller */ | |||
177 | /* irq statistics */ | 177 | /* irq statistics */ |
178 | #ifdef FOTG210_STATS | 178 | #ifdef FOTG210_STATS |
179 | struct fotg210_stats stats; | 179 | struct fotg210_stats stats; |
180 | # define COUNT(x) ((x)++) | 180 | # define INCR(x) ((x)++) |
181 | #else | 181 | #else |
182 | # define COUNT(x) | 182 | # define INCR(x) do {} while (0) |
183 | #endif | 183 | #endif |
184 | 184 | ||
185 | /* silicon clock */ | ||
186 | struct clk *pclk; | ||
187 | |||
185 | /* debug files */ | 188 | /* debug files */ |
186 | struct dentry *debug_dir; | 189 | struct dentry *debug_dir; |
187 | }; | 190 | }; |
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index e98673954020..ec6739ef3129 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c | |||
@@ -551,6 +551,8 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) | |||
551 | pdata->overcurrent_pin[i] = | 551 | pdata->overcurrent_pin[i] = |
552 | devm_gpiod_get_index_optional(&pdev->dev, "atmel,oc", | 552 | devm_gpiod_get_index_optional(&pdev->dev, "atmel,oc", |
553 | i, GPIOD_IN); | 553 | i, GPIOD_IN); |
554 | if (!pdata->overcurrent_pin[i]) | ||
555 | continue; | ||
554 | if (IS_ERR(pdata->overcurrent_pin[i])) { | 556 | if (IS_ERR(pdata->overcurrent_pin[i])) { |
555 | err = PTR_ERR(pdata->overcurrent_pin[i]); | 557 | err = PTR_ERR(pdata->overcurrent_pin[i]); |
556 | dev_err(&pdev->dev, "unable to claim gpio \"overcurrent\": %d\n", err); | 558 | dev_err(&pdev->dev, "unable to claim gpio \"overcurrent\": %d\n", err); |
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 3625a5c1a41b..3ce71cbfbb58 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c | |||
@@ -783,15 +783,9 @@ static void quirk_usb_handoff_ohci(struct pci_dev *pdev) | |||
783 | /* disable interrupts */ | 783 | /* disable interrupts */ |
784 | writel((u32) ~0, base + OHCI_INTRDISABLE); | 784 | writel((u32) ~0, base + OHCI_INTRDISABLE); |
785 | 785 | ||
786 | /* Reset the USB bus, if the controller isn't already in RESET */ | 786 | /* Go into the USB_RESET state, preserving RWC (and possibly IR) */ |
787 | if (control & OHCI_HCFS) { | 787 | writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); |
788 | /* Go into RESET, preserving RWC (and possibly IR) */ | 788 | readl(base + OHCI_CONTROL); |
789 | writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); | ||
790 | readl(base + OHCI_CONTROL); | ||
791 | |||
792 | /* drive bus reset for at least 50 ms (7.1.7.5) */ | ||
793 | msleep(50); | ||
794 | } | ||
795 | 789 | ||
796 | /* software reset of the controller, preserving HcFmInterval */ | 790 | /* software reset of the controller, preserving HcFmInterval */ |
797 | if (!no_fminterval) | 791 | if (!no_fminterval) |
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 7e2a531ba321..12eea73d9f20 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c | |||
@@ -900,6 +900,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, | |||
900 | set_bit(wIndex, &bus_state->resuming_ports); | 900 | set_bit(wIndex, &bus_state->resuming_ports); |
901 | bus_state->resume_done[wIndex] = timeout; | 901 | bus_state->resume_done[wIndex] = timeout; |
902 | mod_timer(&hcd->rh_timer, timeout); | 902 | mod_timer(&hcd->rh_timer, timeout); |
903 | usb_hcd_start_port_resume(&hcd->self, wIndex); | ||
903 | } | 904 | } |
904 | /* Has resume been signalled for USB_RESUME_TIME yet? */ | 905 | /* Has resume been signalled for USB_RESUME_TIME yet? */ |
905 | } else if (time_after_eq(jiffies, | 906 | } else if (time_after_eq(jiffies, |
@@ -940,6 +941,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, | |||
940 | clear_bit(wIndex, &bus_state->rexit_ports); | 941 | clear_bit(wIndex, &bus_state->rexit_ports); |
941 | } | 942 | } |
942 | 943 | ||
944 | usb_hcd_end_port_resume(&hcd->self, wIndex); | ||
943 | bus_state->port_c_suspend |= 1 << wIndex; | 945 | bus_state->port_c_suspend |= 1 << wIndex; |
944 | bus_state->suspended_ports &= ~(1 << wIndex); | 946 | bus_state->suspended_ports &= ~(1 << wIndex); |
945 | } else { | 947 | } else { |
@@ -962,6 +964,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, | |||
962 | (raw_port_status & PORT_PLS_MASK) != XDEV_RESUME) { | 964 | (raw_port_status & PORT_PLS_MASK) != XDEV_RESUME) { |
963 | bus_state->resume_done[wIndex] = 0; | 965 | bus_state->resume_done[wIndex] = 0; |
964 | clear_bit(wIndex, &bus_state->resuming_ports); | 966 | clear_bit(wIndex, &bus_state->resuming_ports); |
967 | usb_hcd_end_port_resume(&hcd->self, wIndex); | ||
965 | } | 968 | } |
966 | 969 | ||
967 | 970 | ||
@@ -1337,6 +1340,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
1337 | goto error; | 1340 | goto error; |
1338 | 1341 | ||
1339 | set_bit(wIndex, &bus_state->resuming_ports); | 1342 | set_bit(wIndex, &bus_state->resuming_ports); |
1343 | usb_hcd_start_port_resume(&hcd->self, wIndex); | ||
1340 | xhci_set_link_state(xhci, ports[wIndex], | 1344 | xhci_set_link_state(xhci, ports[wIndex], |
1341 | XDEV_RESUME); | 1345 | XDEV_RESUME); |
1342 | spin_unlock_irqrestore(&xhci->lock, flags); | 1346 | spin_unlock_irqrestore(&xhci->lock, flags); |
@@ -1345,6 +1349,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
1345 | xhci_set_link_state(xhci, ports[wIndex], | 1349 | xhci_set_link_state(xhci, ports[wIndex], |
1346 | XDEV_U0); | 1350 | XDEV_U0); |
1347 | clear_bit(wIndex, &bus_state->resuming_ports); | 1351 | clear_bit(wIndex, &bus_state->resuming_ports); |
1352 | usb_hcd_end_port_resume(&hcd->self, wIndex); | ||
1348 | } | 1353 | } |
1349 | bus_state->port_c_suspend |= 1 << wIndex; | 1354 | bus_state->port_c_suspend |= 1 << wIndex; |
1350 | 1355 | ||
diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c index fa33d6e5b1cb..fea555570ad4 100644 --- a/drivers/usb/host/xhci-mtk-sch.c +++ b/drivers/usb/host/xhci-mtk-sch.c | |||
@@ -13,14 +13,20 @@ | |||
13 | #include "xhci.h" | 13 | #include "xhci.h" |
14 | #include "xhci-mtk.h" | 14 | #include "xhci-mtk.h" |
15 | 15 | ||
16 | #define SSP_BW_BOUNDARY 130000 | ||
16 | #define SS_BW_BOUNDARY 51000 | 17 | #define SS_BW_BOUNDARY 51000 |
17 | /* table 5-5. High-speed Isoc Transaction Limits in usb_20 spec */ | 18 | /* table 5-5. High-speed Isoc Transaction Limits in usb_20 spec */ |
18 | #define HS_BW_BOUNDARY 6144 | 19 | #define HS_BW_BOUNDARY 6144 |
19 | /* usb2 spec section11.18.1: at most 188 FS bytes per microframe */ | 20 | /* usb2 spec section11.18.1: at most 188 FS bytes per microframe */ |
20 | #define FS_PAYLOAD_MAX 188 | 21 | #define FS_PAYLOAD_MAX 188 |
22 | /* | ||
23 | * max number of microframes for split transfer, | ||
24 | * for fs isoc in : 1 ss + 1 idle + 7 cs | ||
25 | */ | ||
26 | #define TT_MICROFRAMES_MAX 9 | ||
21 | 27 | ||
22 | /* mtk scheduler bitmasks */ | 28 | /* mtk scheduler bitmasks */ |
23 | #define EP_BPKTS(p) ((p) & 0x3f) | 29 | #define EP_BPKTS(p) ((p) & 0x7f) |
24 | #define EP_BCSCOUNT(p) (((p) & 0x7) << 8) | 30 | #define EP_BCSCOUNT(p) (((p) & 0x7) << 8) |
25 | #define EP_BBM(p) ((p) << 11) | 31 | #define EP_BBM(p) ((p) << 11) |
26 | #define EP_BOFFSET(p) ((p) & 0x3fff) | 32 | #define EP_BOFFSET(p) ((p) & 0x3fff) |
@@ -51,7 +57,7 @@ static int get_bw_index(struct xhci_hcd *xhci, struct usb_device *udev, | |||
51 | 57 | ||
52 | virt_dev = xhci->devs[udev->slot_id]; | 58 | virt_dev = xhci->devs[udev->slot_id]; |
53 | 59 | ||
54 | if (udev->speed == USB_SPEED_SUPER) { | 60 | if (udev->speed >= USB_SPEED_SUPER) { |
55 | if (usb_endpoint_dir_out(&ep->desc)) | 61 | if (usb_endpoint_dir_out(&ep->desc)) |
56 | bw_index = (virt_dev->real_port - 1) * 2; | 62 | bw_index = (virt_dev->real_port - 1) * 2; |
57 | else | 63 | else |
@@ -64,25 +70,167 @@ static int get_bw_index(struct xhci_hcd *xhci, struct usb_device *udev, | |||
64 | return bw_index; | 70 | return bw_index; |
65 | } | 71 | } |
66 | 72 | ||
73 | static u32 get_esit(struct xhci_ep_ctx *ep_ctx) | ||
74 | { | ||
75 | u32 esit; | ||
76 | |||
77 | esit = 1 << CTX_TO_EP_INTERVAL(le32_to_cpu(ep_ctx->ep_info)); | ||
78 | if (esit > XHCI_MTK_MAX_ESIT) | ||
79 | esit = XHCI_MTK_MAX_ESIT; | ||
80 | |||
81 | return esit; | ||
82 | } | ||
83 | |||
84 | static struct mu3h_sch_tt *find_tt(struct usb_device *udev) | ||
85 | { | ||
86 | struct usb_tt *utt = udev->tt; | ||
87 | struct mu3h_sch_tt *tt, **tt_index, **ptt; | ||
88 | unsigned int port; | ||
89 | bool allocated_index = false; | ||
90 | |||
91 | if (!utt) | ||
92 | return NULL; /* Not below a TT */ | ||
93 | |||
94 | /* | ||
95 | * Find/create our data structure. | ||
96 | * For hubs with a single TT, we get it directly. | ||
97 | * For hubs with multiple TTs, there's an extra level of pointers. | ||
98 | */ | ||
99 | tt_index = NULL; | ||
100 | if (utt->multi) { | ||
101 | tt_index = utt->hcpriv; | ||
102 | if (!tt_index) { /* Create the index array */ | ||
103 | tt_index = kcalloc(utt->hub->maxchild, | ||
104 | sizeof(*tt_index), GFP_KERNEL); | ||
105 | if (!tt_index) | ||
106 | return ERR_PTR(-ENOMEM); | ||
107 | utt->hcpriv = tt_index; | ||
108 | allocated_index = true; | ||
109 | } | ||
110 | port = udev->ttport - 1; | ||
111 | ptt = &tt_index[port]; | ||
112 | } else { | ||
113 | port = 0; | ||
114 | ptt = (struct mu3h_sch_tt **) &utt->hcpriv; | ||
115 | } | ||
116 | |||
117 | tt = *ptt; | ||
118 | if (!tt) { /* Create the mu3h_sch_tt */ | ||
119 | tt = kzalloc(sizeof(*tt), GFP_KERNEL); | ||
120 | if (!tt) { | ||
121 | if (allocated_index) { | ||
122 | utt->hcpriv = NULL; | ||
123 | kfree(tt_index); | ||
124 | } | ||
125 | return ERR_PTR(-ENOMEM); | ||
126 | } | ||
127 | INIT_LIST_HEAD(&tt->ep_list); | ||
128 | tt->usb_tt = utt; | ||
129 | tt->tt_port = port; | ||
130 | *ptt = tt; | ||
131 | } | ||
132 | |||
133 | return tt; | ||
134 | } | ||
135 | |||
136 | /* Release the TT above udev, if it's not in use */ | ||
137 | static void drop_tt(struct usb_device *udev) | ||
138 | { | ||
139 | struct usb_tt *utt = udev->tt; | ||
140 | struct mu3h_sch_tt *tt, **tt_index, **ptt; | ||
141 | int i, cnt; | ||
142 | |||
143 | if (!utt || !utt->hcpriv) | ||
144 | return; /* Not below a TT, or never allocated */ | ||
145 | |||
146 | cnt = 0; | ||
147 | if (utt->multi) { | ||
148 | tt_index = utt->hcpriv; | ||
149 | ptt = &tt_index[udev->ttport - 1]; | ||
150 | /* How many entries are left in tt_index? */ | ||
151 | for (i = 0; i < utt->hub->maxchild; ++i) | ||
152 | cnt += !!tt_index[i]; | ||
153 | } else { | ||
154 | tt_index = NULL; | ||
155 | ptt = (struct mu3h_sch_tt **)&utt->hcpriv; | ||
156 | } | ||
157 | |||
158 | tt = *ptt; | ||
159 | if (!tt || !list_empty(&tt->ep_list)) | ||
160 | return; /* never allocated , or still in use*/ | ||
161 | |||
162 | *ptt = NULL; | ||
163 | kfree(tt); | ||
164 | |||
165 | if (cnt == 1) { | ||
166 | utt->hcpriv = NULL; | ||
167 | kfree(tt_index); | ||
168 | } | ||
169 | } | ||
170 | |||
171 | static struct mu3h_sch_ep_info *create_sch_ep(struct usb_device *udev, | ||
172 | struct usb_host_endpoint *ep, struct xhci_ep_ctx *ep_ctx) | ||
173 | { | ||
174 | struct mu3h_sch_ep_info *sch_ep; | ||
175 | struct mu3h_sch_tt *tt = NULL; | ||
176 | u32 len_bw_budget_table; | ||
177 | size_t mem_size; | ||
178 | |||
179 | if (is_fs_or_ls(udev->speed)) | ||
180 | len_bw_budget_table = TT_MICROFRAMES_MAX; | ||
181 | else if ((udev->speed >= USB_SPEED_SUPER) | ||
182 | && usb_endpoint_xfer_isoc(&ep->desc)) | ||
183 | len_bw_budget_table = get_esit(ep_ctx); | ||
184 | else | ||
185 | len_bw_budget_table = 1; | ||
186 | |||
187 | mem_size = sizeof(struct mu3h_sch_ep_info) + | ||
188 | len_bw_budget_table * sizeof(u32); | ||
189 | sch_ep = kzalloc(mem_size, GFP_KERNEL); | ||
190 | if (!sch_ep) | ||
191 | return ERR_PTR(-ENOMEM); | ||
192 | |||
193 | if (is_fs_or_ls(udev->speed)) { | ||
194 | tt = find_tt(udev); | ||
195 | if (IS_ERR(tt)) { | ||
196 | kfree(sch_ep); | ||
197 | return ERR_PTR(-ENOMEM); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | sch_ep->sch_tt = tt; | ||
202 | sch_ep->ep = ep; | ||
203 | |||
204 | return sch_ep; | ||
205 | } | ||
206 | |||
67 | static void setup_sch_info(struct usb_device *udev, | 207 | static void setup_sch_info(struct usb_device *udev, |
68 | struct xhci_ep_ctx *ep_ctx, struct mu3h_sch_ep_info *sch_ep) | 208 | struct xhci_ep_ctx *ep_ctx, struct mu3h_sch_ep_info *sch_ep) |
69 | { | 209 | { |
70 | u32 ep_type; | 210 | u32 ep_type; |
71 | u32 ep_interval; | 211 | u32 maxpkt; |
72 | u32 max_packet_size; | ||
73 | u32 max_burst; | 212 | u32 max_burst; |
74 | u32 mult; | 213 | u32 mult; |
75 | u32 esit_pkts; | 214 | u32 esit_pkts; |
215 | u32 max_esit_payload; | ||
216 | u32 *bwb_table = sch_ep->bw_budget_table; | ||
217 | int i; | ||
76 | 218 | ||
77 | ep_type = CTX_TO_EP_TYPE(le32_to_cpu(ep_ctx->ep_info2)); | 219 | ep_type = CTX_TO_EP_TYPE(le32_to_cpu(ep_ctx->ep_info2)); |
78 | ep_interval = CTX_TO_EP_INTERVAL(le32_to_cpu(ep_ctx->ep_info)); | 220 | maxpkt = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2)); |
79 | max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2)); | ||
80 | max_burst = CTX_TO_MAX_BURST(le32_to_cpu(ep_ctx->ep_info2)); | 221 | max_burst = CTX_TO_MAX_BURST(le32_to_cpu(ep_ctx->ep_info2)); |
81 | mult = CTX_TO_EP_MULT(le32_to_cpu(ep_ctx->ep_info)); | 222 | mult = CTX_TO_EP_MULT(le32_to_cpu(ep_ctx->ep_info)); |
82 | 223 | max_esit_payload = | |
83 | sch_ep->esit = 1 << ep_interval; | 224 | (CTX_TO_MAX_ESIT_PAYLOAD_HI( |
225 | le32_to_cpu(ep_ctx->ep_info)) << 16) | | ||
226 | CTX_TO_MAX_ESIT_PAYLOAD(le32_to_cpu(ep_ctx->tx_info)); | ||
227 | |||
228 | sch_ep->esit = get_esit(ep_ctx); | ||
229 | sch_ep->ep_type = ep_type; | ||
230 | sch_ep->maxpkt = maxpkt; | ||
84 | sch_ep->offset = 0; | 231 | sch_ep->offset = 0; |
85 | sch_ep->burst_mode = 0; | 232 | sch_ep->burst_mode = 0; |
233 | sch_ep->repeat = 0; | ||
86 | 234 | ||
87 | if (udev->speed == USB_SPEED_HIGH) { | 235 | if (udev->speed == USB_SPEED_HIGH) { |
88 | sch_ep->cs_count = 0; | 236 | sch_ep->cs_count = 0; |
@@ -93,7 +241,6 @@ static void setup_sch_info(struct usb_device *udev, | |||
93 | * in a interval | 241 | * in a interval |
94 | */ | 242 | */ |
95 | sch_ep->num_budget_microframes = 1; | 243 | sch_ep->num_budget_microframes = 1; |
96 | sch_ep->repeat = 0; | ||
97 | 244 | ||
98 | /* | 245 | /* |
99 | * xHCI spec section6.2.3.4 | 246 | * xHCI spec section6.2.3.4 |
@@ -101,19 +248,33 @@ static void setup_sch_info(struct usb_device *udev, | |||
101 | * opportunities per microframe | 248 | * opportunities per microframe |
102 | */ | 249 | */ |
103 | sch_ep->pkts = max_burst + 1; | 250 | sch_ep->pkts = max_burst + 1; |
104 | sch_ep->bw_cost_per_microframe = max_packet_size * sch_ep->pkts; | 251 | sch_ep->bw_cost_per_microframe = maxpkt * sch_ep->pkts; |
105 | } else if (udev->speed == USB_SPEED_SUPER) { | 252 | bwb_table[0] = sch_ep->bw_cost_per_microframe; |
253 | } else if (udev->speed >= USB_SPEED_SUPER) { | ||
106 | /* usb3_r1 spec section4.4.7 & 4.4.8 */ | 254 | /* usb3_r1 spec section4.4.7 & 4.4.8 */ |
107 | sch_ep->cs_count = 0; | 255 | sch_ep->cs_count = 0; |
108 | esit_pkts = (mult + 1) * (max_burst + 1); | 256 | sch_ep->burst_mode = 1; |
257 | /* | ||
258 | * some device's (d)wBytesPerInterval is set as 0, | ||
259 | * then max_esit_payload is 0, so evaluate esit_pkts from | ||
260 | * mult and burst | ||
261 | */ | ||
262 | esit_pkts = DIV_ROUND_UP(max_esit_payload, maxpkt); | ||
263 | if (esit_pkts == 0) | ||
264 | esit_pkts = (mult + 1) * (max_burst + 1); | ||
265 | |||
109 | if (ep_type == INT_IN_EP || ep_type == INT_OUT_EP) { | 266 | if (ep_type == INT_IN_EP || ep_type == INT_OUT_EP) { |
110 | sch_ep->pkts = esit_pkts; | 267 | sch_ep->pkts = esit_pkts; |
111 | sch_ep->num_budget_microframes = 1; | 268 | sch_ep->num_budget_microframes = 1; |
112 | sch_ep->repeat = 0; | 269 | bwb_table[0] = maxpkt * sch_ep->pkts; |
113 | } | 270 | } |
114 | 271 | ||
115 | if (ep_type == ISOC_IN_EP || ep_type == ISOC_OUT_EP) { | 272 | if (ep_type == ISOC_IN_EP || ep_type == ISOC_OUT_EP) { |
116 | if (esit_pkts <= sch_ep->esit) | 273 | u32 remainder; |
274 | |||
275 | if (sch_ep->esit == 1) | ||
276 | sch_ep->pkts = esit_pkts; | ||
277 | else if (esit_pkts <= sch_ep->esit) | ||
117 | sch_ep->pkts = 1; | 278 | sch_ep->pkts = 1; |
118 | else | 279 | else |
119 | sch_ep->pkts = roundup_pow_of_two(esit_pkts) | 280 | sch_ep->pkts = roundup_pow_of_two(esit_pkts) |
@@ -122,43 +283,48 @@ static void setup_sch_info(struct usb_device *udev, | |||
122 | sch_ep->num_budget_microframes = | 283 | sch_ep->num_budget_microframes = |
123 | DIV_ROUND_UP(esit_pkts, sch_ep->pkts); | 284 | DIV_ROUND_UP(esit_pkts, sch_ep->pkts); |
124 | 285 | ||
125 | if (sch_ep->num_budget_microframes > 1) | 286 | sch_ep->repeat = !!(sch_ep->num_budget_microframes > 1); |
126 | sch_ep->repeat = 1; | 287 | sch_ep->bw_cost_per_microframe = maxpkt * sch_ep->pkts; |
127 | else | 288 | |
128 | sch_ep->repeat = 0; | 289 | remainder = sch_ep->bw_cost_per_microframe; |
290 | remainder *= sch_ep->num_budget_microframes; | ||
291 | remainder -= (maxpkt * esit_pkts); | ||
292 | for (i = 0; i < sch_ep->num_budget_microframes - 1; i++) | ||
293 | bwb_table[i] = sch_ep->bw_cost_per_microframe; | ||
294 | |||
295 | /* last one <= bw_cost_per_microframe */ | ||
296 | bwb_table[i] = remainder; | ||
129 | } | 297 | } |
130 | sch_ep->bw_cost_per_microframe = max_packet_size * sch_ep->pkts; | ||
131 | } else if (is_fs_or_ls(udev->speed)) { | 298 | } else if (is_fs_or_ls(udev->speed)) { |
299 | sch_ep->pkts = 1; /* at most one packet for each microframe */ | ||
132 | 300 | ||
133 | /* | 301 | /* |
134 | * usb_20 spec section11.18.4 | 302 | * num_budget_microframes and cs_count will be updated when |
135 | * assume worst cases | 303 | * check TT for INT_OUT_EP, ISOC/INT_IN_EP type |
136 | */ | 304 | */ |
137 | sch_ep->repeat = 0; | 305 | sch_ep->cs_count = DIV_ROUND_UP(maxpkt, FS_PAYLOAD_MAX); |
138 | sch_ep->pkts = 1; /* at most one packet for each microframe */ | 306 | sch_ep->num_budget_microframes = sch_ep->cs_count; |
139 | if (ep_type == INT_IN_EP || ep_type == INT_OUT_EP) { | 307 | sch_ep->bw_cost_per_microframe = |
140 | sch_ep->cs_count = 3; /* at most need 3 CS*/ | 308 | (maxpkt < FS_PAYLOAD_MAX) ? maxpkt : FS_PAYLOAD_MAX; |
141 | /* one for SS and one for budgeted transaction */ | ||
142 | sch_ep->num_budget_microframes = sch_ep->cs_count + 2; | ||
143 | sch_ep->bw_cost_per_microframe = max_packet_size; | ||
144 | } | ||
145 | if (ep_type == ISOC_OUT_EP) { | ||
146 | 309 | ||
310 | /* init budget table */ | ||
311 | if (ep_type == ISOC_OUT_EP) { | ||
312 | for (i = 0; i < sch_ep->num_budget_microframes; i++) | ||
313 | bwb_table[i] = sch_ep->bw_cost_per_microframe; | ||
314 | } else if (ep_type == INT_OUT_EP) { | ||
315 | /* only first one consumes bandwidth, others as zero */ | ||
316 | bwb_table[0] = sch_ep->bw_cost_per_microframe; | ||
317 | } else { /* INT_IN_EP or ISOC_IN_EP */ | ||
318 | bwb_table[0] = 0; /* start split */ | ||
319 | bwb_table[1] = 0; /* idle */ | ||
147 | /* | 320 | /* |
148 | * the best case FS budget assumes that 188 FS bytes | 321 | * due to cs_count will be updated according to cs |
149 | * occur in each microframe | 322 | * position, assign all remainder budget array |
323 | * elements as @bw_cost_per_microframe, but only first | ||
324 | * @num_budget_microframes elements will be used later | ||
150 | */ | 325 | */ |
151 | sch_ep->num_budget_microframes = DIV_ROUND_UP( | 326 | for (i = 2; i < TT_MICROFRAMES_MAX; i++) |
152 | max_packet_size, FS_PAYLOAD_MAX); | 327 | bwb_table[i] = sch_ep->bw_cost_per_microframe; |
153 | sch_ep->bw_cost_per_microframe = FS_PAYLOAD_MAX; | ||
154 | sch_ep->cs_count = sch_ep->num_budget_microframes; | ||
155 | } | ||
156 | if (ep_type == ISOC_IN_EP) { | ||
157 | /* at most need additional two CS. */ | ||
158 | sch_ep->cs_count = DIV_ROUND_UP( | ||
159 | max_packet_size, FS_PAYLOAD_MAX) + 2; | ||
160 | sch_ep->num_budget_microframes = sch_ep->cs_count + 2; | ||
161 | sch_ep->bw_cost_per_microframe = FS_PAYLOAD_MAX; | ||
162 | } | 328 | } |
163 | } | 329 | } |
164 | } | 330 | } |
@@ -169,6 +335,7 @@ static u32 get_max_bw(struct mu3h_sch_bw_info *sch_bw, | |||
169 | { | 335 | { |
170 | u32 num_esit; | 336 | u32 num_esit; |
171 | u32 max_bw = 0; | 337 | u32 max_bw = 0; |
338 | u32 bw; | ||
172 | int i; | 339 | int i; |
173 | int j; | 340 | int j; |
174 | 341 | ||
@@ -177,15 +344,17 @@ static u32 get_max_bw(struct mu3h_sch_bw_info *sch_bw, | |||
177 | u32 base = offset + i * sch_ep->esit; | 344 | u32 base = offset + i * sch_ep->esit; |
178 | 345 | ||
179 | for (j = 0; j < sch_ep->num_budget_microframes; j++) { | 346 | for (j = 0; j < sch_ep->num_budget_microframes; j++) { |
180 | if (sch_bw->bus_bw[base + j] > max_bw) | 347 | bw = sch_bw->bus_bw[base + j] + |
181 | max_bw = sch_bw->bus_bw[base + j]; | 348 | sch_ep->bw_budget_table[j]; |
349 | if (bw > max_bw) | ||
350 | max_bw = bw; | ||
182 | } | 351 | } |
183 | } | 352 | } |
184 | return max_bw; | 353 | return max_bw; |
185 | } | 354 | } |
186 | 355 | ||
187 | static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw, | 356 | static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw, |
188 | struct mu3h_sch_ep_info *sch_ep, int bw_cost) | 357 | struct mu3h_sch_ep_info *sch_ep, bool used) |
189 | { | 358 | { |
190 | u32 num_esit; | 359 | u32 num_esit; |
191 | u32 base; | 360 | u32 base; |
@@ -195,9 +364,105 @@ static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw, | |||
195 | num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit; | 364 | num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit; |
196 | for (i = 0; i < num_esit; i++) { | 365 | for (i = 0; i < num_esit; i++) { |
197 | base = sch_ep->offset + i * sch_ep->esit; | 366 | base = sch_ep->offset + i * sch_ep->esit; |
367 | for (j = 0; j < sch_ep->num_budget_microframes; j++) { | ||
368 | if (used) | ||
369 | sch_bw->bus_bw[base + j] += | ||
370 | sch_ep->bw_budget_table[j]; | ||
371 | else | ||
372 | sch_bw->bus_bw[base + j] -= | ||
373 | sch_ep->bw_budget_table[j]; | ||
374 | } | ||
375 | } | ||
376 | } | ||
377 | |||
378 | static int check_sch_tt(struct usb_device *udev, | ||
379 | struct mu3h_sch_ep_info *sch_ep, u32 offset) | ||
380 | { | ||
381 | struct mu3h_sch_tt *tt = sch_ep->sch_tt; | ||
382 | u32 extra_cs_count; | ||
383 | u32 fs_budget_start; | ||
384 | u32 start_ss, last_ss; | ||
385 | u32 start_cs, last_cs; | ||
386 | int i; | ||
387 | |||
388 | start_ss = offset % 8; | ||
389 | fs_budget_start = (start_ss + 1) % 8; | ||
390 | |||
391 | if (sch_ep->ep_type == ISOC_OUT_EP) { | ||
392 | last_ss = start_ss + sch_ep->cs_count - 1; | ||
393 | |||
394 | /* | ||
395 | * usb_20 spec section11.18: | ||
396 | * must never schedule Start-Split in Y6 | ||
397 | */ | ||
398 | if (!(start_ss == 7 || last_ss < 6)) | ||
399 | return -ERANGE; | ||
400 | |||
401 | for (i = 0; i < sch_ep->cs_count; i++) | ||
402 | if (test_bit(offset + i, tt->split_bit_map)) | ||
403 | return -ERANGE; | ||
404 | |||
405 | } else { | ||
406 | u32 cs_count = DIV_ROUND_UP(sch_ep->maxpkt, FS_PAYLOAD_MAX); | ||
407 | |||
408 | /* | ||
409 | * usb_20 spec section11.18: | ||
410 | * must never schedule Start-Split in Y6 | ||
411 | */ | ||
412 | if (start_ss == 6) | ||
413 | return -ERANGE; | ||
414 | |||
415 | /* one uframe for ss + one uframe for idle */ | ||
416 | start_cs = (start_ss + 2) % 8; | ||
417 | last_cs = start_cs + cs_count - 1; | ||
418 | |||
419 | if (last_cs > 7) | ||
420 | return -ERANGE; | ||
421 | |||
422 | if (sch_ep->ep_type == ISOC_IN_EP) | ||
423 | extra_cs_count = (last_cs == 7) ? 1 : 2; | ||
424 | else /* ep_type : INTR IN / INTR OUT */ | ||
425 | extra_cs_count = (fs_budget_start == 6) ? 1 : 2; | ||
426 | |||
427 | cs_count += extra_cs_count; | ||
428 | if (cs_count > 7) | ||
429 | cs_count = 7; /* HW limit */ | ||
430 | |||
431 | for (i = 0; i < cs_count + 2; i++) { | ||
432 | if (test_bit(offset + i, tt->split_bit_map)) | ||
433 | return -ERANGE; | ||
434 | } | ||
435 | |||
436 | sch_ep->cs_count = cs_count; | ||
437 | /* one for ss, the other for idle */ | ||
438 | sch_ep->num_budget_microframes = cs_count + 2; | ||
439 | |||
440 | /* | ||
441 | * if interval=1, maxp >752, num_budge_micoframe is larger | ||
442 | * than sch_ep->esit, will overstep boundary | ||
443 | */ | ||
444 | if (sch_ep->num_budget_microframes > sch_ep->esit) | ||
445 | sch_ep->num_budget_microframes = sch_ep->esit; | ||
446 | } | ||
447 | |||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | static void update_sch_tt(struct usb_device *udev, | ||
452 | struct mu3h_sch_ep_info *sch_ep) | ||
453 | { | ||
454 | struct mu3h_sch_tt *tt = sch_ep->sch_tt; | ||
455 | u32 base, num_esit; | ||
456 | int i, j; | ||
457 | |||
458 | num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit; | ||
459 | for (i = 0; i < num_esit; i++) { | ||
460 | base = sch_ep->offset + i * sch_ep->esit; | ||
198 | for (j = 0; j < sch_ep->num_budget_microframes; j++) | 461 | for (j = 0; j < sch_ep->num_budget_microframes; j++) |
199 | sch_bw->bus_bw[base + j] += bw_cost; | 462 | set_bit(base + j, tt->split_bit_map); |
200 | } | 463 | } |
464 | |||
465 | list_add_tail(&sch_ep->tt_endpoint, &tt->ep_list); | ||
201 | } | 466 | } |
202 | 467 | ||
203 | static int check_sch_bw(struct usb_device *udev, | 468 | static int check_sch_bw(struct usb_device *udev, |
@@ -205,17 +470,16 @@ static int check_sch_bw(struct usb_device *udev, | |||
205 | { | 470 | { |
206 | u32 offset; | 471 | u32 offset; |
207 | u32 esit; | 472 | u32 esit; |
208 | u32 num_budget_microframes; | ||
209 | u32 min_bw; | 473 | u32 min_bw; |
210 | u32 min_index; | 474 | u32 min_index; |
211 | u32 worst_bw; | 475 | u32 worst_bw; |
212 | u32 bw_boundary; | 476 | u32 bw_boundary; |
213 | 477 | u32 min_num_budget; | |
214 | if (sch_ep->esit > XHCI_MTK_MAX_ESIT) | 478 | u32 min_cs_count; |
215 | sch_ep->esit = XHCI_MTK_MAX_ESIT; | 479 | bool tt_offset_ok = false; |
480 | int ret; | ||
216 | 481 | ||
217 | esit = sch_ep->esit; | 482 | esit = sch_ep->esit; |
218 | num_budget_microframes = sch_ep->num_budget_microframes; | ||
219 | 483 | ||
220 | /* | 484 | /* |
221 | * Search through all possible schedule microframes. | 485 | * Search through all possible schedule microframes. |
@@ -223,36 +487,56 @@ static int check_sch_bw(struct usb_device *udev, | |||
223 | */ | 487 | */ |
224 | min_bw = ~0; | 488 | min_bw = ~0; |
225 | min_index = 0; | 489 | min_index = 0; |
490 | min_cs_count = sch_ep->cs_count; | ||
491 | min_num_budget = sch_ep->num_budget_microframes; | ||
226 | for (offset = 0; offset < esit; offset++) { | 492 | for (offset = 0; offset < esit; offset++) { |
227 | if ((offset + num_budget_microframes) > sch_ep->esit) | 493 | if (is_fs_or_ls(udev->speed)) { |
228 | break; | 494 | ret = check_sch_tt(udev, sch_ep, offset); |
495 | if (ret) | ||
496 | continue; | ||
497 | else | ||
498 | tt_offset_ok = true; | ||
499 | } | ||
229 | 500 | ||
230 | /* | 501 | if ((offset + sch_ep->num_budget_microframes) > sch_ep->esit) |
231 | * usb_20 spec section11.18: | 502 | break; |
232 | * must never schedule Start-Split in Y6 | ||
233 | */ | ||
234 | if (is_fs_or_ls(udev->speed) && (offset % 8 == 6)) | ||
235 | continue; | ||
236 | 503 | ||
237 | worst_bw = get_max_bw(sch_bw, sch_ep, offset); | 504 | worst_bw = get_max_bw(sch_bw, sch_ep, offset); |
238 | if (min_bw > worst_bw) { | 505 | if (min_bw > worst_bw) { |
239 | min_bw = worst_bw; | 506 | min_bw = worst_bw; |
240 | min_index = offset; | 507 | min_index = offset; |
508 | min_cs_count = sch_ep->cs_count; | ||
509 | min_num_budget = sch_ep->num_budget_microframes; | ||
241 | } | 510 | } |
242 | if (min_bw == 0) | 511 | if (min_bw == 0) |
243 | break; | 512 | break; |
244 | } | 513 | } |
245 | sch_ep->offset = min_index; | ||
246 | 514 | ||
247 | bw_boundary = (udev->speed == USB_SPEED_SUPER) | 515 | if (udev->speed == USB_SPEED_SUPER_PLUS) |
248 | ? SS_BW_BOUNDARY : HS_BW_BOUNDARY; | 516 | bw_boundary = SSP_BW_BOUNDARY; |
517 | else if (udev->speed == USB_SPEED_SUPER) | ||
518 | bw_boundary = SS_BW_BOUNDARY; | ||
519 | else | ||
520 | bw_boundary = HS_BW_BOUNDARY; | ||
249 | 521 | ||
250 | /* check bandwidth */ | 522 | /* check bandwidth */ |
251 | if (min_bw + sch_ep->bw_cost_per_microframe > bw_boundary) | 523 | if (min_bw > bw_boundary) |
252 | return -ERANGE; | 524 | return -ERANGE; |
253 | 525 | ||
526 | sch_ep->offset = min_index; | ||
527 | sch_ep->cs_count = min_cs_count; | ||
528 | sch_ep->num_budget_microframes = min_num_budget; | ||
529 | |||
530 | if (is_fs_or_ls(udev->speed)) { | ||
531 | /* all offset for tt is not ok*/ | ||
532 | if (!tt_offset_ok) | ||
533 | return -ERANGE; | ||
534 | |||
535 | update_sch_tt(udev, sch_ep); | ||
536 | } | ||
537 | |||
254 | /* update bus bandwidth info */ | 538 | /* update bus bandwidth info */ |
255 | update_bus_bw(sch_bw, sch_ep, sch_ep->bw_cost_per_microframe); | 539 | update_bus_bw(sch_bw, sch_ep, 1); |
256 | 540 | ||
257 | return 0; | 541 | return 0; |
258 | } | 542 | } |
@@ -347,8 +631,8 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, | |||
347 | bw_index = get_bw_index(xhci, udev, ep); | 631 | bw_index = get_bw_index(xhci, udev, ep); |
348 | sch_bw = &sch_array[bw_index]; | 632 | sch_bw = &sch_array[bw_index]; |
349 | 633 | ||
350 | sch_ep = kzalloc(sizeof(struct mu3h_sch_ep_info), GFP_NOIO); | 634 | sch_ep = create_sch_ep(udev, ep, ep_ctx); |
351 | if (!sch_ep) | 635 | if (IS_ERR_OR_NULL(sch_ep)) |
352 | return -ENOMEM; | 636 | return -ENOMEM; |
353 | 637 | ||
354 | setup_sch_info(udev, ep_ctx, sch_ep); | 638 | setup_sch_info(udev, ep_ctx, sch_ep); |
@@ -356,12 +640,14 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, | |||
356 | ret = check_sch_bw(udev, sch_bw, sch_ep); | 640 | ret = check_sch_bw(udev, sch_bw, sch_ep); |
357 | if (ret) { | 641 | if (ret) { |
358 | xhci_err(xhci, "Not enough bandwidth!\n"); | 642 | xhci_err(xhci, "Not enough bandwidth!\n"); |
643 | if (is_fs_or_ls(udev->speed)) | ||
644 | drop_tt(udev); | ||
645 | |||
359 | kfree(sch_ep); | 646 | kfree(sch_ep); |
360 | return -ENOSPC; | 647 | return -ENOSPC; |
361 | } | 648 | } |
362 | 649 | ||
363 | list_add_tail(&sch_ep->endpoint, &sch_bw->bw_ep_list); | 650 | list_add_tail(&sch_ep->endpoint, &sch_bw->bw_ep_list); |
364 | sch_ep->ep = ep; | ||
365 | 651 | ||
366 | ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts) | 652 | ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts) |
367 | | EP_BCSCOUNT(sch_ep->cs_count) | EP_BBM(sch_ep->burst_mode)); | 653 | | EP_BCSCOUNT(sch_ep->cs_count) | EP_BBM(sch_ep->burst_mode)); |
@@ -406,9 +692,12 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, | |||
406 | 692 | ||
407 | list_for_each_entry(sch_ep, &sch_bw->bw_ep_list, endpoint) { | 693 | list_for_each_entry(sch_ep, &sch_bw->bw_ep_list, endpoint) { |
408 | if (sch_ep->ep == ep) { | 694 | if (sch_ep->ep == ep) { |
409 | update_bus_bw(sch_bw, sch_ep, | 695 | update_bus_bw(sch_bw, sch_ep, 0); |
410 | -sch_ep->bw_cost_per_microframe); | ||
411 | list_del(&sch_ep->endpoint); | 696 | list_del(&sch_ep->endpoint); |
697 | if (is_fs_or_ls(udev->speed)) { | ||
698 | list_del(&sch_ep->tt_endpoint); | ||
699 | drop_tt(udev); | ||
700 | } | ||
412 | kfree(sch_ep); | 701 | kfree(sch_ep); |
413 | break; | 702 | break; |
414 | } | 703 | } |
diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h index cc59d80b663b..8be8c5f7ff62 100644 --- a/drivers/usb/host/xhci-mtk.h +++ b/drivers/usb/host/xhci-mtk.h | |||
@@ -20,6 +20,19 @@ | |||
20 | #define XHCI_MTK_MAX_ESIT 64 | 20 | #define XHCI_MTK_MAX_ESIT 64 |
21 | 21 | ||
22 | /** | 22 | /** |
23 | * @split_bit_map: used to avoid split microframes overlay | ||
24 | * @ep_list: Endpoints using this TT | ||
25 | * @usb_tt: usb TT related | ||
26 | * @tt_port: TT port number | ||
27 | */ | ||
28 | struct mu3h_sch_tt { | ||
29 | DECLARE_BITMAP(split_bit_map, XHCI_MTK_MAX_ESIT); | ||
30 | struct list_head ep_list; | ||
31 | struct usb_tt *usb_tt; | ||
32 | int tt_port; | ||
33 | }; | ||
34 | |||
35 | /** | ||
23 | * struct mu3h_sch_bw_info: schedule information for bandwidth domain | 36 | * struct mu3h_sch_bw_info: schedule information for bandwidth domain |
24 | * | 37 | * |
25 | * @bus_bw: array to keep track of bandwidth already used at each uframes | 38 | * @bus_bw: array to keep track of bandwidth already used at each uframes |
@@ -41,6 +54,10 @@ struct mu3h_sch_bw_info { | |||
41 | * (@repeat==1) scheduled within the interval | 54 | * (@repeat==1) scheduled within the interval |
42 | * @bw_cost_per_microframe: bandwidth cost per microframe | 55 | * @bw_cost_per_microframe: bandwidth cost per microframe |
43 | * @endpoint: linked into bandwidth domain which it belongs to | 56 | * @endpoint: linked into bandwidth domain which it belongs to |
57 | * @tt_endpoint: linked into mu3h_sch_tt's list which it belongs to | ||
58 | * @sch_tt: mu3h_sch_tt linked into | ||
59 | * @ep_type: endpoint type | ||
60 | * @maxpkt: max packet size of endpoint | ||
44 | * @ep: address of usb_host_endpoint struct | 61 | * @ep: address of usb_host_endpoint struct |
45 | * @offset: which uframe of the interval that transfer should be | 62 | * @offset: which uframe of the interval that transfer should be |
46 | * scheduled first time within the interval | 63 | * scheduled first time within the interval |
@@ -57,12 +74,17 @@ struct mu3h_sch_bw_info { | |||
57 | * times; 1: distribute the (bMaxBurst+1)*(Mult+1) packets | 74 | * times; 1: distribute the (bMaxBurst+1)*(Mult+1) packets |
58 | * according to @pkts and @repeat. normal mode is used by | 75 | * according to @pkts and @repeat. normal mode is used by |
59 | * default | 76 | * default |
77 | * @bw_budget_table: table to record bandwidth budget per microframe | ||
60 | */ | 78 | */ |
61 | struct mu3h_sch_ep_info { | 79 | struct mu3h_sch_ep_info { |
62 | u32 esit; | 80 | u32 esit; |
63 | u32 num_budget_microframes; | 81 | u32 num_budget_microframes; |
64 | u32 bw_cost_per_microframe; | 82 | u32 bw_cost_per_microframe; |
65 | struct list_head endpoint; | 83 | struct list_head endpoint; |
84 | struct list_head tt_endpoint; | ||
85 | struct mu3h_sch_tt *sch_tt; | ||
86 | u32 ep_type; | ||
87 | u32 maxpkt; | ||
66 | void *ep; | 88 | void *ep; |
67 | /* | 89 | /* |
68 | * mtk xHCI scheduling information put into reserved DWs | 90 | * mtk xHCI scheduling information put into reserved DWs |
@@ -73,6 +95,7 @@ struct mu3h_sch_ep_info { | |||
73 | u32 pkts; | 95 | u32 pkts; |
74 | u32 cs_count; | 96 | u32 cs_count; |
75 | u32 burst_mode; | 97 | u32 burst_mode; |
98 | u32 bw_budget_table[0]; | ||
76 | }; | 99 | }; |
77 | 100 | ||
78 | #define MU3C_U3_PORT_MAX 4 | 101 | #define MU3C_U3_PORT_MAX 4 |
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 51dd8e00c4f8..01c57055c0c5 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c | |||
@@ -41,6 +41,13 @@ | |||
41 | #define PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI 0x1aa8 | 41 | #define PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI 0x1aa8 |
42 | #define PCI_DEVICE_ID_INTEL_APL_XHCI 0x5aa8 | 42 | #define PCI_DEVICE_ID_INTEL_APL_XHCI 0x5aa8 |
43 | #define PCI_DEVICE_ID_INTEL_DNV_XHCI 0x19d0 | 43 | #define PCI_DEVICE_ID_INTEL_DNV_XHCI 0x19d0 |
44 | #define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_XHCI 0x15b5 | ||
45 | #define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_XHCI 0x15b6 | ||
46 | #define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_2C_XHCI 0x15db | ||
47 | #define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_4C_XHCI 0x15d4 | ||
48 | #define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_XHCI 0x15e9 | ||
49 | #define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_XHCI 0x15ec | ||
50 | #define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI 0x15f0 | ||
44 | 51 | ||
45 | #define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9 | 52 | #define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9 |
46 | #define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba | 53 | #define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba |
@@ -193,6 +200,16 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) | |||
193 | pdev->device == PCI_DEVICE_ID_INTEL_DNV_XHCI)) | 200 | pdev->device == PCI_DEVICE_ID_INTEL_DNV_XHCI)) |
194 | xhci->quirks |= XHCI_MISSING_CAS; | 201 | xhci->quirks |= XHCI_MISSING_CAS; |
195 | 202 | ||
203 | if (pdev->vendor == PCI_VENDOR_ID_INTEL && | ||
204 | (pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_XHCI || | ||
205 | pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_XHCI || | ||
206 | pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_2C_XHCI || | ||
207 | pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_4C_XHCI || | ||
208 | pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_XHCI || | ||
209 | pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_XHCI || | ||
210 | pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI)) | ||
211 | xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW; | ||
212 | |||
196 | if (pdev->vendor == PCI_VENDOR_ID_ETRON && | 213 | if (pdev->vendor == PCI_VENDOR_ID_ETRON && |
197 | pdev->device == PCI_DEVICE_ID_EJ168) { | 214 | pdev->device == PCI_DEVICE_ID_EJ168) { |
198 | xhci->quirks |= XHCI_RESET_ON_RESUME; | 215 | xhci->quirks |= XHCI_RESET_ON_RESUME; |
@@ -336,6 +353,9 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
336 | /* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */ | 353 | /* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */ |
337 | pm_runtime_put_noidle(&dev->dev); | 354 | pm_runtime_put_noidle(&dev->dev); |
338 | 355 | ||
356 | if (xhci->quirks & XHCI_DEFAULT_PM_RUNTIME_ALLOW) | ||
357 | pm_runtime_allow(&dev->dev); | ||
358 | |||
339 | return 0; | 359 | return 0; |
340 | 360 | ||
341 | put_usb3_hcd: | 361 | put_usb3_hcd: |
@@ -353,6 +373,10 @@ static void xhci_pci_remove(struct pci_dev *dev) | |||
353 | 373 | ||
354 | xhci = hcd_to_xhci(pci_get_drvdata(dev)); | 374 | xhci = hcd_to_xhci(pci_get_drvdata(dev)); |
355 | xhci->xhc_state |= XHCI_STATE_REMOVING; | 375 | xhci->xhc_state |= XHCI_STATE_REMOVING; |
376 | |||
377 | if (xhci->quirks & XHCI_DEFAULT_PM_RUNTIME_ALLOW) | ||
378 | pm_runtime_forbid(&dev->dev); | ||
379 | |||
356 | if (xhci->shared_hcd) { | 380 | if (xhci->shared_hcd) { |
357 | usb_remove_hcd(xhci->shared_hcd); | 381 | usb_remove_hcd(xhci->shared_hcd); |
358 | usb_put_hcd(xhci->shared_hcd); | 382 | usb_put_hcd(xhci->shared_hcd); |
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 94e939249b2b..32b5574ad5c5 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/usb/phy.h> | 18 | #include <linux/usb/phy.h> |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/acpi.h> | 20 | #include <linux/acpi.h> |
21 | #include <linux/usb/of.h> | ||
21 | 22 | ||
22 | #include "xhci.h" | 23 | #include "xhci.h" |
23 | #include "xhci-plat.h" | 24 | #include "xhci-plat.h" |
@@ -305,6 +306,8 @@ static int xhci_plat_probe(struct platform_device *pdev) | |||
305 | hcd->skip_phy_initialization = 1; | 306 | hcd->skip_phy_initialization = 1; |
306 | } | 307 | } |
307 | 308 | ||
309 | hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node); | ||
310 | xhci->shared_hcd->tpl_support = hcd->tpl_support; | ||
308 | ret = usb_add_hcd(hcd, irq, IRQF_SHARED); | 311 | ret = usb_add_hcd(hcd, irq, IRQF_SHARED); |
309 | if (ret) | 312 | if (ret) |
310 | goto disable_usb_phy; | 313 | goto disable_usb_phy; |
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index f0a99aa0ac58..a8d92c90fb58 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c | |||
@@ -1155,6 +1155,10 @@ static void xhci_handle_cmd_reset_ep(struct xhci_hcd *xhci, int slot_id, | |||
1155 | /* Clear our internal halted state */ | 1155 | /* Clear our internal halted state */ |
1156 | xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_HALTED; | 1156 | xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_HALTED; |
1157 | } | 1157 | } |
1158 | |||
1159 | /* if this was a soft reset, then restart */ | ||
1160 | if ((le32_to_cpu(trb->generic.field[3])) & TRB_TSP) | ||
1161 | ring_doorbell_for_active_rings(xhci, slot_id, ep_index); | ||
1158 | } | 1162 | } |
1159 | 1163 | ||
1160 | static void xhci_handle_cmd_enable_slot(struct xhci_hcd *xhci, int slot_id, | 1164 | static void xhci_handle_cmd_enable_slot(struct xhci_hcd *xhci, int slot_id, |
@@ -1602,6 +1606,7 @@ static void handle_port_status(struct xhci_hcd *xhci, | |||
1602 | set_bit(HCD_FLAG_POLL_RH, &hcd->flags); | 1606 | set_bit(HCD_FLAG_POLL_RH, &hcd->flags); |
1603 | mod_timer(&hcd->rh_timer, | 1607 | mod_timer(&hcd->rh_timer, |
1604 | bus_state->resume_done[hcd_portnum]); | 1608 | bus_state->resume_done[hcd_portnum]); |
1609 | usb_hcd_start_port_resume(&hcd->self, hcd_portnum); | ||
1605 | bogus_port_status = true; | 1610 | bogus_port_status = true; |
1606 | } | 1611 | } |
1607 | } | 1612 | } |
@@ -2132,10 +2137,16 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, | |||
2132 | union xhci_trb *ep_trb, struct xhci_transfer_event *event, | 2137 | union xhci_trb *ep_trb, struct xhci_transfer_event *event, |
2133 | struct xhci_virt_ep *ep, int *status) | 2138 | struct xhci_virt_ep *ep, int *status) |
2134 | { | 2139 | { |
2140 | struct xhci_slot_ctx *slot_ctx; | ||
2135 | struct xhci_ring *ep_ring; | 2141 | struct xhci_ring *ep_ring; |
2136 | u32 trb_comp_code; | 2142 | u32 trb_comp_code; |
2137 | u32 remaining, requested, ep_trb_len; | 2143 | u32 remaining, requested, ep_trb_len; |
2144 | unsigned int slot_id; | ||
2145 | int ep_index; | ||
2138 | 2146 | ||
2147 | slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); | ||
2148 | slot_ctx = xhci_get_slot_ctx(xhci, xhci->devs[slot_id]->out_ctx); | ||
2149 | ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1; | ||
2139 | ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); | 2150 | ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); |
2140 | trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); | 2151 | trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); |
2141 | remaining = EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); | 2152 | remaining = EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); |
@@ -2144,6 +2155,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, | |||
2144 | 2155 | ||
2145 | switch (trb_comp_code) { | 2156 | switch (trb_comp_code) { |
2146 | case COMP_SUCCESS: | 2157 | case COMP_SUCCESS: |
2158 | ep_ring->err_count = 0; | ||
2147 | /* handle success with untransferred data as short packet */ | 2159 | /* handle success with untransferred data as short packet */ |
2148 | if (ep_trb != td->last_trb || remaining) { | 2160 | if (ep_trb != td->last_trb || remaining) { |
2149 | xhci_warn(xhci, "WARN Successful completion on short TX\n"); | 2161 | xhci_warn(xhci, "WARN Successful completion on short TX\n"); |
@@ -2167,6 +2179,14 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, | |||
2167 | ep_trb_len = 0; | 2179 | ep_trb_len = 0; |
2168 | remaining = 0; | 2180 | remaining = 0; |
2169 | break; | 2181 | break; |
2182 | case COMP_USB_TRANSACTION_ERROR: | ||
2183 | if ((ep_ring->err_count++ > MAX_SOFT_RETRY) || | ||
2184 | le32_to_cpu(slot_ctx->tt_info) & TT_SLOT) | ||
2185 | break; | ||
2186 | *status = 0; | ||
2187 | xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index, | ||
2188 | ep_ring->stream_id, td, EP_SOFT_RESET); | ||
2189 | return 0; | ||
2170 | default: | 2190 | default: |
2171 | /* do nothing */ | 2191 | /* do nothing */ |
2172 | break; | 2192 | break; |
diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 4b463e5202a4..6b5db344de30 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/phy/tegra/xusb.h> | 18 | #include <linux/phy/tegra/xusb.h> |
19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
20 | #include <linux/pm.h> | 20 | #include <linux/pm.h> |
21 | #include <linux/pm_domain.h> | ||
21 | #include <linux/pm_runtime.h> | 22 | #include <linux/pm_runtime.h> |
22 | #include <linux/regulator/consumer.h> | 23 | #include <linux/regulator/consumer.h> |
23 | #include <linux/reset.h> | 24 | #include <linux/reset.h> |
@@ -107,35 +108,35 @@ | |||
107 | #define IMEM_BLOCK_SIZE 256 | 108 | #define IMEM_BLOCK_SIZE 256 |
108 | 109 | ||
109 | struct tegra_xusb_fw_header { | 110 | struct tegra_xusb_fw_header { |
110 | u32 boot_loadaddr_in_imem; | 111 | __le32 boot_loadaddr_in_imem; |
111 | u32 boot_codedfi_offset; | 112 | __le32 boot_codedfi_offset; |
112 | u32 boot_codetag; | 113 | __le32 boot_codetag; |
113 | u32 boot_codesize; | 114 | __le32 boot_codesize; |
114 | u32 phys_memaddr; | 115 | __le32 phys_memaddr; |
115 | u16 reqphys_memsize; | 116 | __le16 reqphys_memsize; |
116 | u16 alloc_phys_memsize; | 117 | __le16 alloc_phys_memsize; |
117 | u32 rodata_img_offset; | 118 | __le32 rodata_img_offset; |
118 | u32 rodata_section_start; | 119 | __le32 rodata_section_start; |
119 | u32 rodata_section_end; | 120 | __le32 rodata_section_end; |
120 | u32 main_fnaddr; | 121 | __le32 main_fnaddr; |
121 | u32 fwimg_cksum; | 122 | __le32 fwimg_cksum; |
122 | u32 fwimg_created_time; | 123 | __le32 fwimg_created_time; |
123 | u32 imem_resident_start; | 124 | __le32 imem_resident_start; |
124 | u32 imem_resident_end; | 125 | __le32 imem_resident_end; |
125 | u32 idirect_start; | 126 | __le32 idirect_start; |
126 | u32 idirect_end; | 127 | __le32 idirect_end; |
127 | u32 l2_imem_start; | 128 | __le32 l2_imem_start; |
128 | u32 l2_imem_end; | 129 | __le32 l2_imem_end; |
129 | u32 version_id; | 130 | __le32 version_id; |
130 | u8 init_ddirect; | 131 | u8 init_ddirect; |
131 | u8 reserved[3]; | 132 | u8 reserved[3]; |
132 | u32 phys_addr_log_buffer; | 133 | __le32 phys_addr_log_buffer; |
133 | u32 total_log_entries; | 134 | __le32 total_log_entries; |
134 | u32 dequeue_ptr; | 135 | __le32 dequeue_ptr; |
135 | u32 dummy_var[2]; | 136 | __le32 dummy_var[2]; |
136 | u32 fwimg_len; | 137 | __le32 fwimg_len; |
137 | u8 magic[8]; | 138 | u8 magic[8]; |
138 | u32 ss_low_power_entry_timeout; | 139 | __le32 ss_low_power_entry_timeout; |
139 | u8 num_hsic_port; | 140 | u8 num_hsic_port; |
140 | u8 padding[139]; /* Pad to 256 bytes */ | 141 | u8 padding[139]; /* Pad to 256 bytes */ |
141 | }; | 142 | }; |
@@ -194,6 +195,11 @@ struct tegra_xusb { | |||
194 | struct reset_control *host_rst; | 195 | struct reset_control *host_rst; |
195 | struct reset_control *ss_rst; | 196 | struct reset_control *ss_rst; |
196 | 197 | ||
198 | struct device *genpd_dev_host; | ||
199 | struct device *genpd_dev_ss; | ||
200 | struct device_link *genpd_dl_host; | ||
201 | struct device_link *genpd_dl_ss; | ||
202 | |||
197 | struct phy **phys; | 203 | struct phy **phys; |
198 | unsigned int num_phys; | 204 | unsigned int num_phys; |
199 | 205 | ||
@@ -928,6 +934,57 @@ static int tegra_xusb_load_firmware(struct tegra_xusb *tegra) | |||
928 | return 0; | 934 | return 0; |
929 | } | 935 | } |
930 | 936 | ||
937 | static void tegra_xusb_powerdomain_remove(struct device *dev, | ||
938 | struct tegra_xusb *tegra) | ||
939 | { | ||
940 | if (tegra->genpd_dl_ss) | ||
941 | device_link_del(tegra->genpd_dl_ss); | ||
942 | if (tegra->genpd_dl_host) | ||
943 | device_link_del(tegra->genpd_dl_host); | ||
944 | if (tegra->genpd_dev_ss) | ||
945 | dev_pm_domain_detach(tegra->genpd_dev_ss, true); | ||
946 | if (tegra->genpd_dev_host) | ||
947 | dev_pm_domain_detach(tegra->genpd_dev_host, true); | ||
948 | } | ||
949 | |||
950 | static int tegra_xusb_powerdomain_init(struct device *dev, | ||
951 | struct tegra_xusb *tegra) | ||
952 | { | ||
953 | int err; | ||
954 | |||
955 | tegra->genpd_dev_host = dev_pm_domain_attach_by_name(dev, "xusb_host"); | ||
956 | if (IS_ERR(tegra->genpd_dev_host)) { | ||
957 | err = PTR_ERR(tegra->genpd_dev_host); | ||
958 | dev_err(dev, "failed to get host pm-domain: %d\n", err); | ||
959 | return err; | ||
960 | } | ||
961 | |||
962 | tegra->genpd_dev_ss = dev_pm_domain_attach_by_name(dev, "xusb_ss"); | ||
963 | if (IS_ERR(tegra->genpd_dev_ss)) { | ||
964 | err = PTR_ERR(tegra->genpd_dev_ss); | ||
965 | dev_err(dev, "failed to get superspeed pm-domain: %d\n", err); | ||
966 | return err; | ||
967 | } | ||
968 | |||
969 | tegra->genpd_dl_host = device_link_add(dev, tegra->genpd_dev_host, | ||
970 | DL_FLAG_PM_RUNTIME | | ||
971 | DL_FLAG_STATELESS); | ||
972 | if (!tegra->genpd_dl_host) { | ||
973 | dev_err(dev, "adding host device link failed!\n"); | ||
974 | return -ENODEV; | ||
975 | } | ||
976 | |||
977 | tegra->genpd_dl_ss = device_link_add(dev, tegra->genpd_dev_ss, | ||
978 | DL_FLAG_PM_RUNTIME | | ||
979 | DL_FLAG_STATELESS); | ||
980 | if (!tegra->genpd_dl_ss) { | ||
981 | dev_err(dev, "adding superspeed device link failed!\n"); | ||
982 | return -ENODEV; | ||
983 | } | ||
984 | |||
985 | return 0; | ||
986 | } | ||
987 | |||
931 | static int tegra_xusb_probe(struct platform_device *pdev) | 988 | static int tegra_xusb_probe(struct platform_device *pdev) |
932 | { | 989 | { |
933 | struct tegra_xusb_mbox_msg msg; | 990 | struct tegra_xusb_mbox_msg msg; |
@@ -1038,7 +1095,7 @@ static int tegra_xusb_probe(struct platform_device *pdev) | |||
1038 | goto put_padctl; | 1095 | goto put_padctl; |
1039 | } | 1096 | } |
1040 | 1097 | ||
1041 | if (!pdev->dev.pm_domain) { | 1098 | if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) { |
1042 | tegra->host_rst = devm_reset_control_get(&pdev->dev, | 1099 | tegra->host_rst = devm_reset_control_get(&pdev->dev, |
1043 | "xusb_host"); | 1100 | "xusb_host"); |
1044 | if (IS_ERR(tegra->host_rst)) { | 1101 | if (IS_ERR(tegra->host_rst)) { |
@@ -1069,17 +1126,22 @@ static int tegra_xusb_probe(struct platform_device *pdev) | |||
1069 | tegra->host_clk, | 1126 | tegra->host_clk, |
1070 | tegra->host_rst); | 1127 | tegra->host_rst); |
1071 | if (err) { | 1128 | if (err) { |
1129 | tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA); | ||
1072 | dev_err(&pdev->dev, | 1130 | dev_err(&pdev->dev, |
1073 | "failed to enable XUSBC domain: %d\n", err); | 1131 | "failed to enable XUSBC domain: %d\n", err); |
1074 | goto disable_xusba; | 1132 | goto put_padctl; |
1075 | } | 1133 | } |
1134 | } else { | ||
1135 | err = tegra_xusb_powerdomain_init(&pdev->dev, tegra); | ||
1136 | if (err) | ||
1137 | goto put_powerdomains; | ||
1076 | } | 1138 | } |
1077 | 1139 | ||
1078 | tegra->supplies = devm_kcalloc(&pdev->dev, tegra->soc->num_supplies, | 1140 | tegra->supplies = devm_kcalloc(&pdev->dev, tegra->soc->num_supplies, |
1079 | sizeof(*tegra->supplies), GFP_KERNEL); | 1141 | sizeof(*tegra->supplies), GFP_KERNEL); |
1080 | if (!tegra->supplies) { | 1142 | if (!tegra->supplies) { |
1081 | err = -ENOMEM; | 1143 | err = -ENOMEM; |
1082 | goto disable_xusbc; | 1144 | goto put_powerdomains; |
1083 | } | 1145 | } |
1084 | 1146 | ||
1085 | for (i = 0; i < tegra->soc->num_supplies; i++) | 1147 | for (i = 0; i < tegra->soc->num_supplies; i++) |
@@ -1089,7 +1151,7 @@ static int tegra_xusb_probe(struct platform_device *pdev) | |||
1089 | tegra->supplies); | 1151 | tegra->supplies); |
1090 | if (err) { | 1152 | if (err) { |
1091 | dev_err(&pdev->dev, "failed to get regulators: %d\n", err); | 1153 | dev_err(&pdev->dev, "failed to get regulators: %d\n", err); |
1092 | goto disable_xusbc; | 1154 | goto put_powerdomains; |
1093 | } | 1155 | } |
1094 | 1156 | ||
1095 | for (i = 0; i < tegra->soc->num_types; i++) | 1157 | for (i = 0; i < tegra->soc->num_types; i++) |
@@ -1099,7 +1161,7 @@ static int tegra_xusb_probe(struct platform_device *pdev) | |||
1099 | sizeof(*tegra->phys), GFP_KERNEL); | 1161 | sizeof(*tegra->phys), GFP_KERNEL); |
1100 | if (!tegra->phys) { | 1162 | if (!tegra->phys) { |
1101 | err = -ENOMEM; | 1163 | err = -ENOMEM; |
1102 | goto disable_xusbc; | 1164 | goto put_powerdomains; |
1103 | } | 1165 | } |
1104 | 1166 | ||
1105 | for (i = 0, k = 0; i < tegra->soc->num_types; i++) { | 1167 | for (i = 0, k = 0; i < tegra->soc->num_types; i++) { |
@@ -1115,7 +1177,7 @@ static int tegra_xusb_probe(struct platform_device *pdev) | |||
1115 | "failed to get PHY %s: %ld\n", prop, | 1177 | "failed to get PHY %s: %ld\n", prop, |
1116 | PTR_ERR(phy)); | 1178 | PTR_ERR(phy)); |
1117 | err = PTR_ERR(phy); | 1179 | err = PTR_ERR(phy); |
1118 | goto disable_xusbc; | 1180 | goto put_powerdomains; |
1119 | } | 1181 | } |
1120 | 1182 | ||
1121 | tegra->phys[k++] = phy; | 1183 | tegra->phys[k++] = phy; |
@@ -1126,7 +1188,7 @@ static int tegra_xusb_probe(struct platform_device *pdev) | |||
1126 | dev_name(&pdev->dev)); | 1188 | dev_name(&pdev->dev)); |
1127 | if (!tegra->hcd) { | 1189 | if (!tegra->hcd) { |
1128 | err = -ENOMEM; | 1190 | err = -ENOMEM; |
1129 | goto disable_xusbc; | 1191 | goto put_powerdomains; |
1130 | } | 1192 | } |
1131 | 1193 | ||
1132 | /* | 1194 | /* |
@@ -1222,12 +1284,13 @@ put_rpm: | |||
1222 | disable_rpm: | 1284 | disable_rpm: |
1223 | pm_runtime_disable(&pdev->dev); | 1285 | pm_runtime_disable(&pdev->dev); |
1224 | usb_put_hcd(tegra->hcd); | 1286 | usb_put_hcd(tegra->hcd); |
1225 | disable_xusbc: | 1287 | put_powerdomains: |
1226 | if (!pdev->dev.pm_domain) | 1288 | if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) { |
1227 | tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC); | 1289 | tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC); |
1228 | disable_xusba: | ||
1229 | if (!pdev->dev.pm_domain) | ||
1230 | tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA); | 1290 | tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA); |
1291 | } else { | ||
1292 | tegra_xusb_powerdomain_remove(&pdev->dev, tegra); | ||
1293 | } | ||
1231 | put_padctl: | 1294 | put_padctl: |
1232 | tegra_xusb_padctl_put(tegra->padctl); | 1295 | tegra_xusb_padctl_put(tegra->padctl); |
1233 | return err; | 1296 | return err; |
@@ -1249,6 +1312,13 @@ static int tegra_xusb_remove(struct platform_device *pdev) | |||
1249 | pm_runtime_put_sync(&pdev->dev); | 1312 | pm_runtime_put_sync(&pdev->dev); |
1250 | pm_runtime_disable(&pdev->dev); | 1313 | pm_runtime_disable(&pdev->dev); |
1251 | 1314 | ||
1315 | if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) { | ||
1316 | tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC); | ||
1317 | tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA); | ||
1318 | } else { | ||
1319 | tegra_xusb_powerdomain_remove(&pdev->dev, tegra); | ||
1320 | } | ||
1321 | |||
1252 | tegra_xusb_padctl_put(tegra->padctl); | 1322 | tegra_xusb_padctl_put(tegra->padctl); |
1253 | 1323 | ||
1254 | return 0; | 1324 | return 0; |
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 6230a578324c..bf0b3692dc9a 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
@@ -1496,6 +1496,7 @@ static inline const char *xhci_trb_type_string(u8 type) | |||
1496 | /* How much data is left before the 64KB boundary? */ | 1496 | /* How much data is left before the 64KB boundary? */ |
1497 | #define TRB_BUFF_LEN_UP_TO_BOUNDARY(addr) (TRB_MAX_BUFF_SIZE - \ | 1497 | #define TRB_BUFF_LEN_UP_TO_BOUNDARY(addr) (TRB_MAX_BUFF_SIZE - \ |
1498 | (addr & (TRB_MAX_BUFF_SIZE - 1))) | 1498 | (addr & (TRB_MAX_BUFF_SIZE - 1))) |
1499 | #define MAX_SOFT_RETRY 3 | ||
1499 | 1500 | ||
1500 | struct xhci_segment { | 1501 | struct xhci_segment { |
1501 | union xhci_trb *trbs; | 1502 | union xhci_trb *trbs; |
@@ -1583,6 +1584,7 @@ struct xhci_ring { | |||
1583 | * if we own the TRB (if we are the consumer). See section 4.9.1. | 1584 | * if we own the TRB (if we are the consumer). See section 4.9.1. |
1584 | */ | 1585 | */ |
1585 | u32 cycle_state; | 1586 | u32 cycle_state; |
1587 | unsigned int err_count; | ||
1586 | unsigned int stream_id; | 1588 | unsigned int stream_id; |
1587 | unsigned int num_segs; | 1589 | unsigned int num_segs; |
1588 | unsigned int num_trbs_free; | 1590 | unsigned int num_trbs_free; |
@@ -1846,6 +1848,7 @@ struct xhci_hcd { | |||
1846 | #define XHCI_SUSPEND_DELAY BIT_ULL(30) | 1848 | #define XHCI_SUSPEND_DELAY BIT_ULL(30) |
1847 | #define XHCI_INTEL_USB_ROLE_SW BIT_ULL(31) | 1849 | #define XHCI_INTEL_USB_ROLE_SW BIT_ULL(31) |
1848 | #define XHCI_ZERO_64B_REGS BIT_ULL(32) | 1850 | #define XHCI_ZERO_64B_REGS BIT_ULL(32) |
1851 | #define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33) | ||
1849 | 1852 | ||
1850 | unsigned int num_active_eps; | 1853 | unsigned int num_active_eps; |
1851 | unsigned int limit_active_eps; | 1854 | unsigned int limit_active_eps; |
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index d746c26a8055..bd539f3058bc 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c | |||
@@ -146,8 +146,11 @@ static int appledisplay_bl_update_status(struct backlight_device *bd) | |||
146 | pdata->msgdata, 2, | 146 | pdata->msgdata, 2, |
147 | ACD_USB_TIMEOUT); | 147 | ACD_USB_TIMEOUT); |
148 | mutex_unlock(&pdata->sysfslock); | 148 | mutex_unlock(&pdata->sysfslock); |
149 | 149 | ||
150 | return retval; | 150 | if (retval < 0) |
151 | return retval; | ||
152 | else | ||
153 | return 0; | ||
151 | } | 154 | } |
152 | 155 | ||
153 | static int appledisplay_bl_get_brightness(struct backlight_device *bd) | 156 | static int appledisplay_bl_get_brightness(struct backlight_device *bd) |
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index c2991b8a65ce..ba05dd80a020 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c | |||
@@ -808,8 +808,8 @@ static int iowarrior_probe(struct usb_interface *interface, | |||
808 | dev->int_in_endpoint->bInterval); | 808 | dev->int_in_endpoint->bInterval); |
809 | /* create an internal buffer for interrupt data from the device */ | 809 | /* create an internal buffer for interrupt data from the device */ |
810 | dev->read_queue = | 810 | dev->read_queue = |
811 | kmalloc(((dev->report_size + 1) * MAX_INTERRUPT_BUFFER), | 811 | kmalloc_array(dev->report_size + 1, MAX_INTERRUPT_BUFFER, |
812 | GFP_KERNEL); | 812 | GFP_KERNEL); |
813 | if (!dev->read_queue) | 813 | if (!dev->read_queue) |
814 | goto error; | 814 | goto error; |
815 | /* Get the serial-number of the chip */ | 815 | /* Get the serial-number of the chip */ |
diff --git a/drivers/usb/misc/trancevibrator.c b/drivers/usb/misc/trancevibrator.c index b3e1f553954a..ac357ce2d1a6 100644 --- a/drivers/usb/misc/trancevibrator.c +++ b/drivers/usb/misc/trancevibrator.c | |||
@@ -46,7 +46,9 @@ static ssize_t speed_store(struct device *dev, struct device_attribute *attr, | |||
46 | struct trancevibrator *tv = usb_get_intfdata(intf); | 46 | struct trancevibrator *tv = usb_get_intfdata(intf); |
47 | int temp, retval, old; | 47 | int temp, retval, old; |
48 | 48 | ||
49 | temp = simple_strtoul(buf, NULL, 10); | 49 | retval = kstrtoint(buf, 10, &temp); |
50 | if (retval) | ||
51 | return retval; | ||
50 | if (temp > 255) | 52 | if (temp > 255) |
51 | temp = 255; | 53 | temp = 255; |
52 | else if (temp < 0) | 54 | else if (temp < 0) |
diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c index d045d8458f81..ae70b9bfd797 100644 --- a/drivers/usb/mtu3/mtu3_core.c +++ b/drivers/usb/mtu3/mtu3_core.c | |||
@@ -185,8 +185,8 @@ static void mtu3_intr_enable(struct mtu3 *mtu) | |||
185 | 185 | ||
186 | if (mtu->is_u3_ip) { | 186 | if (mtu->is_u3_ip) { |
187 | /* Enable U3 LTSSM interrupts */ | 187 | /* Enable U3 LTSSM interrupts */ |
188 | value = HOT_RST_INTR | WARM_RST_INTR | VBUS_RISE_INTR | | 188 | value = HOT_RST_INTR | WARM_RST_INTR | |
189 | VBUS_FALL_INTR | ENTER_U3_INTR | EXIT_U3_INTR; | 189 | ENTER_U3_INTR | EXIT_U3_INTR; |
190 | mtu3_writel(mbase, U3D_LTSSM_INTR_ENABLE, value); | 190 | mtu3_writel(mbase, U3D_LTSSM_INTR_ENABLE, value); |
191 | } | 191 | } |
192 | 192 | ||
diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c index 5c60a8c5a0b5..bbcd3332471d 100644 --- a/drivers/usb/mtu3/mtu3_gadget.c +++ b/drivers/usb/mtu3/mtu3_gadget.c | |||
@@ -585,6 +585,17 @@ static const struct usb_gadget_ops mtu3_gadget_ops = { | |||
585 | .udc_stop = mtu3_gadget_stop, | 585 | .udc_stop = mtu3_gadget_stop, |
586 | }; | 586 | }; |
587 | 587 | ||
588 | static void mtu3_state_reset(struct mtu3 *mtu) | ||
589 | { | ||
590 | mtu->address = 0; | ||
591 | mtu->ep0_state = MU3D_EP0_STATE_SETUP; | ||
592 | mtu->may_wakeup = 0; | ||
593 | mtu->u1_enable = 0; | ||
594 | mtu->u2_enable = 0; | ||
595 | mtu->delayed_status = false; | ||
596 | mtu->test_mode = false; | ||
597 | } | ||
598 | |||
588 | static void init_hw_ep(struct mtu3 *mtu, struct mtu3_ep *mep, | 599 | static void init_hw_ep(struct mtu3 *mtu, struct mtu3_ep *mep, |
589 | u32 epnum, u32 is_in) | 600 | u32 epnum, u32 is_in) |
590 | { | 601 | { |
@@ -702,6 +713,7 @@ void mtu3_gadget_disconnect(struct mtu3 *mtu) | |||
702 | spin_lock(&mtu->lock); | 713 | spin_lock(&mtu->lock); |
703 | } | 714 | } |
704 | 715 | ||
716 | mtu3_state_reset(mtu); | ||
705 | usb_gadget_set_state(&mtu->g, USB_STATE_NOTATTACHED); | 717 | usb_gadget_set_state(&mtu->g, USB_STATE_NOTATTACHED); |
706 | } | 718 | } |
707 | 719 | ||
@@ -712,12 +724,6 @@ void mtu3_gadget_reset(struct mtu3 *mtu) | |||
712 | /* report disconnect, if we didn't flush EP state */ | 724 | /* report disconnect, if we didn't flush EP state */ |
713 | if (mtu->g.speed != USB_SPEED_UNKNOWN) | 725 | if (mtu->g.speed != USB_SPEED_UNKNOWN) |
714 | mtu3_gadget_disconnect(mtu); | 726 | mtu3_gadget_disconnect(mtu); |
715 | 727 | else | |
716 | mtu->address = 0; | 728 | mtu3_state_reset(mtu); |
717 | mtu->ep0_state = MU3D_EP0_STATE_SETUP; | ||
718 | mtu->may_wakeup = 0; | ||
719 | mtu->u1_enable = 0; | ||
720 | mtu->u2_enable = 0; | ||
721 | mtu->delayed_status = false; | ||
722 | mtu->test_mode = false; | ||
723 | } | 729 | } |
diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index 66143ab8c043..aaf363f19714 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c | |||
@@ -505,15 +505,19 @@ static int abx500_usb_link_status_update(struct ab8500_usb *ab) | |||
505 | if (is_ab8500(ab->ab8500)) { | 505 | if (is_ab8500(ab->ab8500)) { |
506 | enum ab8500_usb_link_status lsts; | 506 | enum ab8500_usb_link_status lsts; |
507 | 507 | ||
508 | abx500_get_register_interruptible(ab->dev, | 508 | ret = abx500_get_register_interruptible(ab->dev, |
509 | AB8500_USB, AB8500_USB_LINE_STAT_REG, ®); | 509 | AB8500_USB, AB8500_USB_LINE_STAT_REG, ®); |
510 | if (ret < 0) | ||
511 | return ret; | ||
510 | lsts = (reg >> 3) & 0x0F; | 512 | lsts = (reg >> 3) & 0x0F; |
511 | ret = ab8500_usb_link_status_update(ab, lsts); | 513 | ret = ab8500_usb_link_status_update(ab, lsts); |
512 | } else if (is_ab8505(ab->ab8500)) { | 514 | } else if (is_ab8505(ab->ab8500)) { |
513 | enum ab8505_usb_link_status lsts; | 515 | enum ab8505_usb_link_status lsts; |
514 | 516 | ||
515 | abx500_get_register_interruptible(ab->dev, | 517 | ret = abx500_get_register_interruptible(ab->dev, |
516 | AB8500_USB, AB8505_USB_LINE_STAT_REG, ®); | 518 | AB8500_USB, AB8505_USB_LINE_STAT_REG, ®); |
519 | if (ret < 0) | ||
520 | return ret; | ||
517 | lsts = (reg >> 3) & 0x1F; | 521 | lsts = (reg >> 3) & 0x1F; |
518 | ret = ab8505_usb_link_status_update(ab, lsts); | 522 | ret = ab8505_usb_link_status_update(ab, lsts); |
519 | } | 523 | } |
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index e5aa24c1e4fd..1b1bb0ad40c3 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c | |||
@@ -563,7 +563,7 @@ static enum usb_charger_type mxs_charger_primary_detection(struct mxs_phy *x) | |||
563 | regmap_read(regmap, ANADIG_USB1_CHRG_DET_STAT, &val); | 563 | regmap_read(regmap, ANADIG_USB1_CHRG_DET_STAT, &val); |
564 | if (!(val & ANADIG_USB1_CHRG_DET_STAT_CHRG_DETECTED)) { | 564 | if (!(val & ANADIG_USB1_CHRG_DET_STAT_CHRG_DETECTED)) { |
565 | chgr_type = SDP_TYPE; | 565 | chgr_type = SDP_TYPE; |
566 | dev_dbg(x->phy.dev, "It is a stardard downstream port\n"); | 566 | dev_dbg(x->phy.dev, "It is a standard downstream port\n"); |
567 | } | 567 | } |
568 | 568 | ||
569 | /* Disable charger detector */ | 569 | /* Disable charger detector */ |
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 4310df46639d..a3e1290d682d 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * Copyright (C) 2011 Renesas Solutions Corp. | 5 | * Copyright (C) 2011 Renesas Solutions Corp. |
6 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 6 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> |
7 | */ | 7 | */ |
8 | #include <linux/clk.h> | ||
8 | #include <linux/err.h> | 9 | #include <linux/err.h> |
9 | #include <linux/gpio.h> | 10 | #include <linux/gpio.h> |
10 | #include <linux/io.h> | 11 | #include <linux/io.h> |
@@ -12,6 +13,7 @@ | |||
12 | #include <linux/of_device.h> | 13 | #include <linux/of_device.h> |
13 | #include <linux/of_gpio.h> | 14 | #include <linux/of_gpio.h> |
14 | #include <linux/pm_runtime.h> | 15 | #include <linux/pm_runtime.h> |
16 | #include <linux/reset.h> | ||
15 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
16 | #include <linux/sysfs.h> | 18 | #include <linux/sysfs.h> |
17 | #include "common.h" | 19 | #include "common.h" |
@@ -290,6 +292,79 @@ static void usbhsc_set_buswait(struct usbhs_priv *priv) | |||
290 | usbhs_bset(priv, BUSWAIT, 0x000F, wait); | 292 | usbhs_bset(priv, BUSWAIT, 0x000F, wait); |
291 | } | 293 | } |
292 | 294 | ||
295 | static bool usbhsc_is_multi_clks(struct usbhs_priv *priv) | ||
296 | { | ||
297 | if (priv->dparam.type == USBHS_TYPE_RCAR_GEN3 || | ||
298 | priv->dparam.type == USBHS_TYPE_RCAR_GEN3_WITH_PLL) | ||
299 | return true; | ||
300 | |||
301 | return false; | ||
302 | } | ||
303 | |||
304 | static int usbhsc_clk_get(struct device *dev, struct usbhs_priv *priv) | ||
305 | { | ||
306 | if (!usbhsc_is_multi_clks(priv)) | ||
307 | return 0; | ||
308 | |||
309 | /* The first clock should exist */ | ||
310 | priv->clks[0] = of_clk_get(dev->of_node, 0); | ||
311 | if (IS_ERR(priv->clks[0])) | ||
312 | return PTR_ERR(priv->clks[0]); | ||
313 | |||
314 | /* | ||
315 | * To backward compatibility with old DT, this driver checks the return | ||
316 | * value if it's -ENOENT or not. | ||
317 | */ | ||
318 | priv->clks[1] = of_clk_get(dev->of_node, 1); | ||
319 | if (PTR_ERR(priv->clks[1]) == -ENOENT) | ||
320 | priv->clks[1] = NULL; | ||
321 | else if (IS_ERR(priv->clks[1])) | ||
322 | return PTR_ERR(priv->clks[1]); | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static void usbhsc_clk_put(struct usbhs_priv *priv) | ||
328 | { | ||
329 | int i; | ||
330 | |||
331 | if (!usbhsc_is_multi_clks(priv)) | ||
332 | return; | ||
333 | |||
334 | for (i = 0; i < ARRAY_SIZE(priv->clks); i++) | ||
335 | clk_put(priv->clks[i]); | ||
336 | } | ||
337 | |||
338 | static int usbhsc_clk_prepare_enable(struct usbhs_priv *priv) | ||
339 | { | ||
340 | int i, ret; | ||
341 | |||
342 | if (!usbhsc_is_multi_clks(priv)) | ||
343 | return 0; | ||
344 | |||
345 | for (i = 0; i < ARRAY_SIZE(priv->clks); i++) { | ||
346 | ret = clk_prepare_enable(priv->clks[i]); | ||
347 | if (ret) { | ||
348 | while (--i >= 0) | ||
349 | clk_disable_unprepare(priv->clks[i]); | ||
350 | return ret; | ||
351 | } | ||
352 | } | ||
353 | |||
354 | return ret; | ||
355 | } | ||
356 | |||
357 | static void usbhsc_clk_disable_unprepare(struct usbhs_priv *priv) | ||
358 | { | ||
359 | int i; | ||
360 | |||
361 | if (!usbhsc_is_multi_clks(priv)) | ||
362 | return; | ||
363 | |||
364 | for (i = 0; i < ARRAY_SIZE(priv->clks); i++) | ||
365 | clk_disable_unprepare(priv->clks[i]); | ||
366 | } | ||
367 | |||
293 | /* | 368 | /* |
294 | * platform default param | 369 | * platform default param |
295 | */ | 370 | */ |
@@ -340,6 +415,10 @@ static void usbhsc_power_ctrl(struct usbhs_priv *priv, int enable) | |||
340 | /* enable PM */ | 415 | /* enable PM */ |
341 | pm_runtime_get_sync(dev); | 416 | pm_runtime_get_sync(dev); |
342 | 417 | ||
418 | /* enable clks */ | ||
419 | if (usbhsc_clk_prepare_enable(priv)) | ||
420 | return; | ||
421 | |||
343 | /* enable platform power */ | 422 | /* enable platform power */ |
344 | usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable); | 423 | usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable); |
345 | 424 | ||
@@ -352,6 +431,9 @@ static void usbhsc_power_ctrl(struct usbhs_priv *priv, int enable) | |||
352 | /* disable platform power */ | 431 | /* disable platform power */ |
353 | usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable); | 432 | usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable); |
354 | 433 | ||
434 | /* disable clks */ | ||
435 | usbhsc_clk_disable_unprepare(priv); | ||
436 | |||
355 | /* disable PM */ | 437 | /* disable PM */ |
356 | pm_runtime_put_sync(dev); | 438 | pm_runtime_put_sync(dev); |
357 | } | 439 | } |
@@ -478,6 +560,10 @@ static const struct of_device_id usbhs_of_match[] = { | |||
478 | .data = (void *)USBHS_TYPE_RCAR_GEN3, | 560 | .data = (void *)USBHS_TYPE_RCAR_GEN3, |
479 | }, | 561 | }, |
480 | { | 562 | { |
563 | .compatible = "renesas,usbhs-r8a77990", | ||
564 | .data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL, | ||
565 | }, | ||
566 | { | ||
481 | .compatible = "renesas,usbhs-r8a77995", | 567 | .compatible = "renesas,usbhs-r8a77995", |
482 | .data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL, | 568 | .data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL, |
483 | }, | 569 | }, |
@@ -574,6 +660,10 @@ static int usbhs_probe(struct platform_device *pdev) | |||
574 | return PTR_ERR(priv->edev); | 660 | return PTR_ERR(priv->edev); |
575 | } | 661 | } |
576 | 662 | ||
663 | priv->rsts = devm_reset_control_array_get_optional_shared(&pdev->dev); | ||
664 | if (IS_ERR(priv->rsts)) | ||
665 | return PTR_ERR(priv->rsts); | ||
666 | |||
577 | /* | 667 | /* |
578 | * care platform info | 668 | * care platform info |
579 | */ | 669 | */ |
@@ -591,15 +681,6 @@ static int usbhs_probe(struct platform_device *pdev) | |||
591 | break; | 681 | break; |
592 | case USBHS_TYPE_RCAR_GEN3_WITH_PLL: | 682 | case USBHS_TYPE_RCAR_GEN3_WITH_PLL: |
593 | priv->pfunc = usbhs_rcar3_with_pll_ops; | 683 | priv->pfunc = usbhs_rcar3_with_pll_ops; |
594 | if (!IS_ERR_OR_NULL(priv->edev)) { | ||
595 | priv->nb.notifier_call = priv->pfunc.notifier; | ||
596 | ret = devm_extcon_register_notifier(&pdev->dev, | ||
597 | priv->edev, | ||
598 | EXTCON_USB_HOST, | ||
599 | &priv->nb); | ||
600 | if (ret < 0) | ||
601 | dev_err(&pdev->dev, "no notifier registered\n"); | ||
602 | } | ||
603 | break; | 684 | break; |
604 | case USBHS_TYPE_RZA1: | 685 | case USBHS_TYPE_RZA1: |
605 | priv->pfunc = usbhs_rza1_ops; | 686 | priv->pfunc = usbhs_rza1_ops; |
@@ -658,6 +739,14 @@ static int usbhs_probe(struct platform_device *pdev) | |||
658 | /* dev_set_drvdata should be called after usbhs_mod_init */ | 739 | /* dev_set_drvdata should be called after usbhs_mod_init */ |
659 | platform_set_drvdata(pdev, priv); | 740 | platform_set_drvdata(pdev, priv); |
660 | 741 | ||
742 | ret = reset_control_deassert(priv->rsts); | ||
743 | if (ret) | ||
744 | goto probe_fail_rst; | ||
745 | |||
746 | ret = usbhsc_clk_get(&pdev->dev, priv); | ||
747 | if (ret) | ||
748 | goto probe_fail_clks; | ||
749 | |||
661 | /* | 750 | /* |
662 | * deviece reset here because | 751 | * deviece reset here because |
663 | * USB device might be used in boot loader. | 752 | * USB device might be used in boot loader. |
@@ -711,6 +800,10 @@ static int usbhs_probe(struct platform_device *pdev) | |||
711 | return ret; | 800 | return ret; |
712 | 801 | ||
713 | probe_end_mod_exit: | 802 | probe_end_mod_exit: |
803 | usbhsc_clk_put(priv); | ||
804 | probe_fail_clks: | ||
805 | reset_control_assert(priv->rsts); | ||
806 | probe_fail_rst: | ||
714 | usbhs_mod_remove(priv); | 807 | usbhs_mod_remove(priv); |
715 | probe_end_fifo_exit: | 808 | probe_end_fifo_exit: |
716 | usbhs_fifo_remove(priv); | 809 | usbhs_fifo_remove(priv); |
@@ -739,6 +832,8 @@ static int usbhs_remove(struct platform_device *pdev) | |||
739 | pm_runtime_disable(&pdev->dev); | 832 | pm_runtime_disable(&pdev->dev); |
740 | 833 | ||
741 | usbhs_platform_call(priv, hardware_exit, pdev); | 834 | usbhs_platform_call(priv, hardware_exit, pdev); |
835 | usbhsc_clk_put(priv); | ||
836 | reset_control_assert(priv->rsts); | ||
742 | usbhs_mod_remove(priv); | 837 | usbhs_mod_remove(priv); |
743 | usbhs_fifo_remove(priv); | 838 | usbhs_fifo_remove(priv); |
744 | usbhs_pipe_remove(priv); | 839 | usbhs_pipe_remove(priv); |
diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index 6137f7942c05..3777af848a35 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h | |||
@@ -8,8 +8,10 @@ | |||
8 | #ifndef RENESAS_USB_DRIVER_H | 8 | #ifndef RENESAS_USB_DRIVER_H |
9 | #define RENESAS_USB_DRIVER_H | 9 | #define RENESAS_USB_DRIVER_H |
10 | 10 | ||
11 | #include <linux/clk.h> | ||
11 | #include <linux/extcon.h> | 12 | #include <linux/extcon.h> |
12 | #include <linux/platform_device.h> | 13 | #include <linux/platform_device.h> |
14 | #include <linux/reset.h> | ||
13 | #include <linux/usb/renesas_usbhs.h> | 15 | #include <linux/usb/renesas_usbhs.h> |
14 | 16 | ||
15 | struct usbhs_priv; | 17 | struct usbhs_priv; |
@@ -255,7 +257,6 @@ struct usbhs_priv { | |||
255 | struct platform_device *pdev; | 257 | struct platform_device *pdev; |
256 | 258 | ||
257 | struct extcon_dev *edev; | 259 | struct extcon_dev *edev; |
258 | struct notifier_block nb; | ||
259 | 260 | ||
260 | spinlock_t lock; | 261 | spinlock_t lock; |
261 | 262 | ||
@@ -277,6 +278,8 @@ struct usbhs_priv { | |||
277 | struct usbhs_fifo_info fifo_info; | 278 | struct usbhs_fifo_info fifo_info; |
278 | 279 | ||
279 | struct phy *phy; | 280 | struct phy *phy; |
281 | struct reset_control *rsts; | ||
282 | struct clk *clks[2]; | ||
280 | }; | 283 | }; |
281 | 284 | ||
282 | /* | 285 | /* |
diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c index d0ea4ff89622..aa3820448286 100644 --- a/drivers/usb/renesas_usbhs/rcar3.c +++ b/drivers/usb/renesas_usbhs/rcar3.c | |||
@@ -27,7 +27,6 @@ | |||
27 | * Remarks: bit[31:11] and bit[9:6] should be 0 | 27 | * Remarks: bit[31:11] and bit[9:6] should be 0 |
28 | */ | 28 | */ |
29 | #define UGCTRL2_RESERVED_3 0x00000001 /* bit[3:0] should be B'0001 */ | 29 | #define UGCTRL2_RESERVED_3 0x00000001 /* bit[3:0] should be B'0001 */ |
30 | #define UGCTRL2_USB0SEL_EHCI 0x00000010 | ||
31 | #define UGCTRL2_USB0SEL_HSUSB 0x00000020 | 30 | #define UGCTRL2_USB0SEL_HSUSB 0x00000020 |
32 | #define UGCTRL2_USB0SEL_OTG 0x00000030 | 31 | #define UGCTRL2_USB0SEL_OTG 0x00000030 |
33 | #define UGCTRL2_VBUSSEL 0x00000400 | 32 | #define UGCTRL2_VBUSSEL 0x00000400 |
@@ -50,14 +49,6 @@ static void usbhs_rcar3_set_ugctrl2(struct usbhs_priv *priv, u32 val) | |||
50 | usbhs_write32(priv, UGCTRL2, val | UGCTRL2_RESERVED_3); | 49 | usbhs_write32(priv, UGCTRL2, val | UGCTRL2_RESERVED_3); |
51 | } | 50 | } |
52 | 51 | ||
53 | static void usbhs_rcar3_set_usbsel(struct usbhs_priv *priv, bool ehci) | ||
54 | { | ||
55 | if (ehci) | ||
56 | usbhs_rcar3_set_ugctrl2(priv, UGCTRL2_USB0SEL_EHCI); | ||
57 | else | ||
58 | usbhs_rcar3_set_ugctrl2(priv, UGCTRL2_USB0SEL_HSUSB); | ||
59 | } | ||
60 | |||
61 | static int usbhs_rcar3_power_ctrl(struct platform_device *pdev, | 52 | static int usbhs_rcar3_power_ctrl(struct platform_device *pdev, |
62 | void __iomem *base, int enable) | 53 | void __iomem *base, int enable) |
63 | { | 54 | { |
@@ -83,14 +74,11 @@ static int usbhs_rcar3_power_and_pll_ctrl(struct platform_device *pdev, | |||
83 | struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); | 74 | struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); |
84 | u32 val; | 75 | u32 val; |
85 | int timeout = 1000; | 76 | int timeout = 1000; |
86 | bool is_host = false; | ||
87 | 77 | ||
88 | if (enable) { | 78 | if (enable) { |
89 | usbhs_write32(priv, UGCTRL, 0); /* release PLLRESET */ | 79 | usbhs_write32(priv, UGCTRL, 0); /* release PLLRESET */ |
90 | if (priv->edev) | 80 | usbhs_rcar3_set_ugctrl2(priv, |
91 | is_host = extcon_get_state(priv->edev, EXTCON_USB_HOST); | 81 | UGCTRL2_USB0SEL_OTG | UGCTRL2_VBUSSEL); |
92 | |||
93 | usbhs_rcar3_set_usbsel(priv, is_host); | ||
94 | 82 | ||
95 | usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM); | 83 | usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM); |
96 | do { | 84 | do { |
@@ -112,16 +100,6 @@ static int usbhs_rcar3_get_id(struct platform_device *pdev) | |||
112 | return USBHS_GADGET; | 100 | return USBHS_GADGET; |
113 | } | 101 | } |
114 | 102 | ||
115 | static int usbhs_rcar3_notifier(struct notifier_block *nb, unsigned long event, | ||
116 | void *data) | ||
117 | { | ||
118 | struct usbhs_priv *priv = container_of(nb, struct usbhs_priv, nb); | ||
119 | |||
120 | usbhs_rcar3_set_usbsel(priv, !!event); | ||
121 | |||
122 | return NOTIFY_DONE; | ||
123 | } | ||
124 | |||
125 | const struct renesas_usbhs_platform_callback usbhs_rcar3_ops = { | 103 | const struct renesas_usbhs_platform_callback usbhs_rcar3_ops = { |
126 | .power_ctrl = usbhs_rcar3_power_ctrl, | 104 | .power_ctrl = usbhs_rcar3_power_ctrl, |
127 | .get_id = usbhs_rcar3_get_id, | 105 | .get_id = usbhs_rcar3_get_id, |
@@ -130,5 +108,4 @@ const struct renesas_usbhs_platform_callback usbhs_rcar3_ops = { | |||
130 | const struct renesas_usbhs_platform_callback usbhs_rcar3_with_pll_ops = { | 108 | const struct renesas_usbhs_platform_callback usbhs_rcar3_with_pll_ops = { |
131 | .power_ctrl = usbhs_rcar3_power_and_pll_ctrl, | 109 | .power_ctrl = usbhs_rcar3_power_and_pll_ctrl, |
132 | .get_id = usbhs_rcar3_get_id, | 110 | .get_id = usbhs_rcar3_get_id, |
133 | .notifier = usbhs_rcar3_notifier, | ||
134 | }; | 111 | }; |
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index e0035c023120..ed51bc48eea6 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c | |||
@@ -378,7 +378,7 @@ static int cypress_serial_control(struct tty_struct *tty, | |||
378 | retval = -ENOTTY; | 378 | retval = -ENOTTY; |
379 | goto out; | 379 | goto out; |
380 | } | 380 | } |
381 | dev_dbg(dev, "%s - retreiving serial line settings\n", __func__); | 381 | dev_dbg(dev, "%s - retrieving serial line settings\n", __func__); |
382 | do { | 382 | do { |
383 | retval = usb_control_msg(port->serial->dev, | 383 | retval = usb_control_msg(port->serial->dev, |
384 | usb_rcvctrlpipe(port->serial->dev, 0), | 384 | usb_rcvctrlpipe(port->serial->dev, 0), |
@@ -769,7 +769,7 @@ send: | |||
769 | 769 | ||
770 | usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev, | 770 | usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev, |
771 | usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress), | 771 | usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress), |
772 | port->interrupt_out_buffer, port->interrupt_out_size, | 772 | port->interrupt_out_buffer, actual_size, |
773 | cypress_write_int_callback, port, priv->write_urb_interval); | 773 | cypress_write_int_callback, port, priv->write_urb_interval); |
774 | result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC); | 774 | result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC); |
775 | if (result) { | 775 | if (result) { |
@@ -863,7 +863,7 @@ static void cypress_set_termios(struct tty_struct *tty, | |||
863 | struct cypress_private *priv = usb_get_serial_port_data(port); | 863 | struct cypress_private *priv = usb_get_serial_port_data(port); |
864 | struct device *dev = &port->dev; | 864 | struct device *dev = &port->dev; |
865 | int data_bits, stop_bits, parity_type, parity_enable; | 865 | int data_bits, stop_bits, parity_type, parity_enable; |
866 | unsigned cflag, iflag; | 866 | unsigned int cflag; |
867 | unsigned long flags; | 867 | unsigned long flags; |
868 | __u8 oldlines; | 868 | __u8 oldlines; |
869 | int linechange = 0; | 869 | int linechange = 0; |
@@ -899,7 +899,6 @@ static void cypress_set_termios(struct tty_struct *tty, | |||
899 | tty->termios.c_cflag &= ~(CMSPAR|CRTSCTS); | 899 | tty->termios.c_cflag &= ~(CMSPAR|CRTSCTS); |
900 | 900 | ||
901 | cflag = tty->termios.c_cflag; | 901 | cflag = tty->termios.c_cflag; |
902 | iflag = tty->termios.c_iflag; | ||
903 | 902 | ||
904 | /* check if there are new settings */ | 903 | /* check if there are new settings */ |
905 | if (old_termios) { | 904 | if (old_termios) { |
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 758ba789e997..609198d9594c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/uaccess.h> | 39 | #include <linux/uaccess.h> |
40 | #include <linux/usb.h> | 40 | #include <linux/usb.h> |
41 | #include <linux/serial.h> | 41 | #include <linux/serial.h> |
42 | #include <linux/gpio/driver.h> | ||
42 | #include <linux/usb/serial.h> | 43 | #include <linux/usb/serial.h> |
43 | #include "ftdi_sio.h" | 44 | #include "ftdi_sio.h" |
44 | #include "ftdi_sio_ids.h" | 45 | #include "ftdi_sio_ids.h" |
@@ -72,6 +73,15 @@ struct ftdi_private { | |||
72 | unsigned int latency; /* latency setting in use */ | 73 | unsigned int latency; /* latency setting in use */ |
73 | unsigned short max_packet_size; | 74 | unsigned short max_packet_size; |
74 | struct mutex cfg_lock; /* Avoid mess by parallel calls of config ioctl() and change_speed() */ | 75 | struct mutex cfg_lock; /* Avoid mess by parallel calls of config ioctl() and change_speed() */ |
76 | #ifdef CONFIG_GPIOLIB | ||
77 | struct gpio_chip gc; | ||
78 | struct mutex gpio_lock; /* protects GPIO state */ | ||
79 | bool gpio_registered; /* is the gpiochip in kernel registered */ | ||
80 | bool gpio_used; /* true if the user requested a gpio */ | ||
81 | u8 gpio_altfunc; /* which pins are in gpio mode */ | ||
82 | u8 gpio_output; /* pin directions cache */ | ||
83 | u8 gpio_value; /* pin value for outputs */ | ||
84 | #endif | ||
75 | }; | 85 | }; |
76 | 86 | ||
77 | /* struct ftdi_sio_quirk is used by devices requiring special attention. */ | 87 | /* struct ftdi_sio_quirk is used by devices requiring special attention. */ |
@@ -1764,6 +1774,375 @@ static void remove_sysfs_attrs(struct usb_serial_port *port) | |||
1764 | 1774 | ||
1765 | } | 1775 | } |
1766 | 1776 | ||
1777 | #ifdef CONFIG_GPIOLIB | ||
1778 | |||
1779 | static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode) | ||
1780 | { | ||
1781 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
1782 | struct usb_serial *serial = port->serial; | ||
1783 | int result; | ||
1784 | u16 val; | ||
1785 | |||
1786 | val = (mode << 8) | (priv->gpio_output << 4) | priv->gpio_value; | ||
1787 | result = usb_control_msg(serial->dev, | ||
1788 | usb_sndctrlpipe(serial->dev, 0), | ||
1789 | FTDI_SIO_SET_BITMODE_REQUEST, | ||
1790 | FTDI_SIO_SET_BITMODE_REQUEST_TYPE, val, | ||
1791 | priv->interface, NULL, 0, WDR_TIMEOUT); | ||
1792 | if (result < 0) { | ||
1793 | dev_err(&serial->interface->dev, | ||
1794 | "bitmode request failed for value 0x%04x: %d\n", | ||
1795 | val, result); | ||
1796 | } | ||
1797 | |||
1798 | return result; | ||
1799 | } | ||
1800 | |||
1801 | static int ftdi_set_cbus_pins(struct usb_serial_port *port) | ||
1802 | { | ||
1803 | return ftdi_set_bitmode(port, FTDI_SIO_BITMODE_CBUS); | ||
1804 | } | ||
1805 | |||
1806 | static int ftdi_exit_cbus_mode(struct usb_serial_port *port) | ||
1807 | { | ||
1808 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
1809 | |||
1810 | priv->gpio_output = 0; | ||
1811 | priv->gpio_value = 0; | ||
1812 | return ftdi_set_bitmode(port, FTDI_SIO_BITMODE_RESET); | ||
1813 | } | ||
1814 | |||
1815 | static int ftdi_gpio_request(struct gpio_chip *gc, unsigned int offset) | ||
1816 | { | ||
1817 | struct usb_serial_port *port = gpiochip_get_data(gc); | ||
1818 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
1819 | int result; | ||
1820 | |||
1821 | if (priv->gpio_altfunc & BIT(offset)) | ||
1822 | return -ENODEV; | ||
1823 | |||
1824 | mutex_lock(&priv->gpio_lock); | ||
1825 | if (!priv->gpio_used) { | ||
1826 | /* Set default pin states, as we cannot get them from device */ | ||
1827 | priv->gpio_output = 0x00; | ||
1828 | priv->gpio_value = 0x00; | ||
1829 | result = ftdi_set_cbus_pins(port); | ||
1830 | if (result) { | ||
1831 | mutex_unlock(&priv->gpio_lock); | ||
1832 | return result; | ||
1833 | } | ||
1834 | |||
1835 | priv->gpio_used = true; | ||
1836 | } | ||
1837 | mutex_unlock(&priv->gpio_lock); | ||
1838 | |||
1839 | return 0; | ||
1840 | } | ||
1841 | |||
1842 | static int ftdi_read_cbus_pins(struct usb_serial_port *port) | ||
1843 | { | ||
1844 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
1845 | struct usb_serial *serial = port->serial; | ||
1846 | unsigned char *buf; | ||
1847 | int result; | ||
1848 | |||
1849 | buf = kmalloc(1, GFP_KERNEL); | ||
1850 | if (!buf) | ||
1851 | return -ENOMEM; | ||
1852 | |||
1853 | result = usb_control_msg(serial->dev, | ||
1854 | usb_rcvctrlpipe(serial->dev, 0), | ||
1855 | FTDI_SIO_READ_PINS_REQUEST, | ||
1856 | FTDI_SIO_READ_PINS_REQUEST_TYPE, 0, | ||
1857 | priv->interface, buf, 1, WDR_TIMEOUT); | ||
1858 | if (result < 1) { | ||
1859 | if (result >= 0) | ||
1860 | result = -EIO; | ||
1861 | } else { | ||
1862 | result = buf[0]; | ||
1863 | } | ||
1864 | |||
1865 | kfree(buf); | ||
1866 | |||
1867 | return result; | ||
1868 | } | ||
1869 | |||
1870 | static int ftdi_gpio_get(struct gpio_chip *gc, unsigned int gpio) | ||
1871 | { | ||
1872 | struct usb_serial_port *port = gpiochip_get_data(gc); | ||
1873 | int result; | ||
1874 | |||
1875 | result = ftdi_read_cbus_pins(port); | ||
1876 | if (result < 0) | ||
1877 | return result; | ||
1878 | |||
1879 | return !!(result & BIT(gpio)); | ||
1880 | } | ||
1881 | |||
1882 | static void ftdi_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) | ||
1883 | { | ||
1884 | struct usb_serial_port *port = gpiochip_get_data(gc); | ||
1885 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
1886 | |||
1887 | mutex_lock(&priv->gpio_lock); | ||
1888 | |||
1889 | if (value) | ||
1890 | priv->gpio_value |= BIT(gpio); | ||
1891 | else | ||
1892 | priv->gpio_value &= ~BIT(gpio); | ||
1893 | |||
1894 | ftdi_set_cbus_pins(port); | ||
1895 | |||
1896 | mutex_unlock(&priv->gpio_lock); | ||
1897 | } | ||
1898 | |||
1899 | static int ftdi_gpio_get_multiple(struct gpio_chip *gc, unsigned long *mask, | ||
1900 | unsigned long *bits) | ||
1901 | { | ||
1902 | struct usb_serial_port *port = gpiochip_get_data(gc); | ||
1903 | int result; | ||
1904 | |||
1905 | result = ftdi_read_cbus_pins(port); | ||
1906 | if (result < 0) | ||
1907 | return result; | ||
1908 | |||
1909 | *bits = result & *mask; | ||
1910 | |||
1911 | return 0; | ||
1912 | } | ||
1913 | |||
1914 | static void ftdi_gpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, | ||
1915 | unsigned long *bits) | ||
1916 | { | ||
1917 | struct usb_serial_port *port = gpiochip_get_data(gc); | ||
1918 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
1919 | |||
1920 | mutex_lock(&priv->gpio_lock); | ||
1921 | |||
1922 | priv->gpio_value &= ~(*mask); | ||
1923 | priv->gpio_value |= *bits & *mask; | ||
1924 | ftdi_set_cbus_pins(port); | ||
1925 | |||
1926 | mutex_unlock(&priv->gpio_lock); | ||
1927 | } | ||
1928 | |||
1929 | static int ftdi_gpio_direction_get(struct gpio_chip *gc, unsigned int gpio) | ||
1930 | { | ||
1931 | struct usb_serial_port *port = gpiochip_get_data(gc); | ||
1932 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
1933 | |||
1934 | return !(priv->gpio_output & BIT(gpio)); | ||
1935 | } | ||
1936 | |||
1937 | static int ftdi_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio) | ||
1938 | { | ||
1939 | struct usb_serial_port *port = gpiochip_get_data(gc); | ||
1940 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
1941 | int result; | ||
1942 | |||
1943 | mutex_lock(&priv->gpio_lock); | ||
1944 | |||
1945 | priv->gpio_output &= ~BIT(gpio); | ||
1946 | result = ftdi_set_cbus_pins(port); | ||
1947 | |||
1948 | mutex_unlock(&priv->gpio_lock); | ||
1949 | |||
1950 | return result; | ||
1951 | } | ||
1952 | |||
1953 | static int ftdi_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio, | ||
1954 | int value) | ||
1955 | { | ||
1956 | struct usb_serial_port *port = gpiochip_get_data(gc); | ||
1957 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
1958 | int result; | ||
1959 | |||
1960 | mutex_lock(&priv->gpio_lock); | ||
1961 | |||
1962 | priv->gpio_output |= BIT(gpio); | ||
1963 | if (value) | ||
1964 | priv->gpio_value |= BIT(gpio); | ||
1965 | else | ||
1966 | priv->gpio_value &= ~BIT(gpio); | ||
1967 | |||
1968 | result = ftdi_set_cbus_pins(port); | ||
1969 | |||
1970 | mutex_unlock(&priv->gpio_lock); | ||
1971 | |||
1972 | return result; | ||
1973 | } | ||
1974 | |||
1975 | static int ftdi_read_eeprom(struct usb_serial *serial, void *dst, u16 addr, | ||
1976 | u16 nbytes) | ||
1977 | { | ||
1978 | int read = 0; | ||
1979 | |||
1980 | if (addr % 2 != 0) | ||
1981 | return -EINVAL; | ||
1982 | if (nbytes % 2 != 0) | ||
1983 | return -EINVAL; | ||
1984 | |||
1985 | /* Read EEPROM two bytes at a time */ | ||
1986 | while (read < nbytes) { | ||
1987 | int rv; | ||
1988 | |||
1989 | rv = usb_control_msg(serial->dev, | ||
1990 | usb_rcvctrlpipe(serial->dev, 0), | ||
1991 | FTDI_SIO_READ_EEPROM_REQUEST, | ||
1992 | FTDI_SIO_READ_EEPROM_REQUEST_TYPE, | ||
1993 | 0, (addr + read) / 2, dst + read, 2, | ||
1994 | WDR_TIMEOUT); | ||
1995 | if (rv < 2) { | ||
1996 | if (rv >= 0) | ||
1997 | return -EIO; | ||
1998 | else | ||
1999 | return rv; | ||
2000 | } | ||
2001 | |||
2002 | read += rv; | ||
2003 | } | ||
2004 | |||
2005 | return 0; | ||
2006 | } | ||
2007 | |||
2008 | static int ftdi_gpio_init_ft232r(struct usb_serial_port *port) | ||
2009 | { | ||
2010 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
2011 | u16 cbus_config; | ||
2012 | u8 *buf; | ||
2013 | int ret; | ||
2014 | int i; | ||
2015 | |||
2016 | buf = kmalloc(2, GFP_KERNEL); | ||
2017 | if (!buf) | ||
2018 | return -ENOMEM; | ||
2019 | |||
2020 | ret = ftdi_read_eeprom(port->serial, buf, 0x14, 2); | ||
2021 | if (ret < 0) | ||
2022 | goto out_free; | ||
2023 | |||
2024 | cbus_config = le16_to_cpup((__le16 *)buf); | ||
2025 | dev_dbg(&port->dev, "cbus_config = 0x%04x\n", cbus_config); | ||
2026 | |||
2027 | priv->gc.ngpio = 4; | ||
2028 | |||
2029 | priv->gpio_altfunc = 0xff; | ||
2030 | for (i = 0; i < priv->gc.ngpio; ++i) { | ||
2031 | if ((cbus_config & 0xf) == FTDI_FT232R_CBUS_MUX_GPIO) | ||
2032 | priv->gpio_altfunc &= ~BIT(i); | ||
2033 | cbus_config >>= 4; | ||
2034 | } | ||
2035 | out_free: | ||
2036 | kfree(buf); | ||
2037 | |||
2038 | return ret; | ||
2039 | } | ||
2040 | |||
2041 | static int ftdi_gpio_init_ftx(struct usb_serial_port *port) | ||
2042 | { | ||
2043 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
2044 | struct usb_serial *serial = port->serial; | ||
2045 | const u16 cbus_cfg_addr = 0x1a; | ||
2046 | const u16 cbus_cfg_size = 4; | ||
2047 | u8 *cbus_cfg_buf; | ||
2048 | int result; | ||
2049 | u8 i; | ||
2050 | |||
2051 | cbus_cfg_buf = kmalloc(cbus_cfg_size, GFP_KERNEL); | ||
2052 | if (!cbus_cfg_buf) | ||
2053 | return -ENOMEM; | ||
2054 | |||
2055 | result = ftdi_read_eeprom(serial, cbus_cfg_buf, | ||
2056 | cbus_cfg_addr, cbus_cfg_size); | ||
2057 | if (result < 0) | ||
2058 | goto out_free; | ||
2059 | |||
2060 | /* FIXME: FT234XD alone has 1 GPIO, but how to recognize this IC? */ | ||
2061 | priv->gc.ngpio = 4; | ||
2062 | |||
2063 | /* Determine which pins are configured for CBUS bitbanging */ | ||
2064 | priv->gpio_altfunc = 0xff; | ||
2065 | for (i = 0; i < priv->gc.ngpio; ++i) { | ||
2066 | if (cbus_cfg_buf[i] == FTDI_FTX_CBUS_MUX_GPIO) | ||
2067 | priv->gpio_altfunc &= ~BIT(i); | ||
2068 | } | ||
2069 | |||
2070 | out_free: | ||
2071 | kfree(cbus_cfg_buf); | ||
2072 | |||
2073 | return result; | ||
2074 | } | ||
2075 | |||
2076 | static int ftdi_gpio_init(struct usb_serial_port *port) | ||
2077 | { | ||
2078 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
2079 | struct usb_serial *serial = port->serial; | ||
2080 | int result; | ||
2081 | |||
2082 | switch (priv->chip_type) { | ||
2083 | case FT232RL: | ||
2084 | result = ftdi_gpio_init_ft232r(port); | ||
2085 | break; | ||
2086 | case FTX: | ||
2087 | result = ftdi_gpio_init_ftx(port); | ||
2088 | break; | ||
2089 | default: | ||
2090 | return 0; | ||
2091 | } | ||
2092 | |||
2093 | if (result < 0) | ||
2094 | return result; | ||
2095 | |||
2096 | mutex_init(&priv->gpio_lock); | ||
2097 | |||
2098 | priv->gc.label = "ftdi-cbus"; | ||
2099 | priv->gc.request = ftdi_gpio_request; | ||
2100 | priv->gc.get_direction = ftdi_gpio_direction_get; | ||
2101 | priv->gc.direction_input = ftdi_gpio_direction_input; | ||
2102 | priv->gc.direction_output = ftdi_gpio_direction_output; | ||
2103 | priv->gc.get = ftdi_gpio_get; | ||
2104 | priv->gc.set = ftdi_gpio_set; | ||
2105 | priv->gc.get_multiple = ftdi_gpio_get_multiple; | ||
2106 | priv->gc.set_multiple = ftdi_gpio_set_multiple; | ||
2107 | priv->gc.owner = THIS_MODULE; | ||
2108 | priv->gc.parent = &serial->interface->dev; | ||
2109 | priv->gc.base = -1; | ||
2110 | priv->gc.can_sleep = true; | ||
2111 | |||
2112 | result = gpiochip_add_data(&priv->gc, port); | ||
2113 | if (!result) | ||
2114 | priv->gpio_registered = true; | ||
2115 | |||
2116 | return result; | ||
2117 | } | ||
2118 | |||
2119 | static void ftdi_gpio_remove(struct usb_serial_port *port) | ||
2120 | { | ||
2121 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
2122 | |||
2123 | if (priv->gpio_registered) { | ||
2124 | gpiochip_remove(&priv->gc); | ||
2125 | priv->gpio_registered = false; | ||
2126 | } | ||
2127 | |||
2128 | if (priv->gpio_used) { | ||
2129 | /* Exiting CBUS-mode does not reset pin states. */ | ||
2130 | ftdi_exit_cbus_mode(port); | ||
2131 | priv->gpio_used = false; | ||
2132 | } | ||
2133 | } | ||
2134 | |||
2135 | #else | ||
2136 | |||
2137 | static int ftdi_gpio_init(struct usb_serial_port *port) | ||
2138 | { | ||
2139 | return 0; | ||
2140 | } | ||
2141 | |||
2142 | static void ftdi_gpio_remove(struct usb_serial_port *port) { } | ||
2143 | |||
2144 | #endif /* CONFIG_GPIOLIB */ | ||
2145 | |||
1767 | /* | 2146 | /* |
1768 | * *************************************************************************** | 2147 | * *************************************************************************** |
1769 | * FTDI driver specific functions | 2148 | * FTDI driver specific functions |
@@ -1792,7 +2171,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) | |||
1792 | { | 2171 | { |
1793 | struct ftdi_private *priv; | 2172 | struct ftdi_private *priv; |
1794 | const struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial); | 2173 | const struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial); |
1795 | 2174 | int result; | |
1796 | 2175 | ||
1797 | priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL); | 2176 | priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL); |
1798 | if (!priv) | 2177 | if (!priv) |
@@ -1811,6 +2190,14 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) | |||
1811 | priv->latency = 16; | 2190 | priv->latency = 16; |
1812 | write_latency_timer(port); | 2191 | write_latency_timer(port); |
1813 | create_sysfs_attrs(port); | 2192 | create_sysfs_attrs(port); |
2193 | |||
2194 | result = ftdi_gpio_init(port); | ||
2195 | if (result < 0) { | ||
2196 | dev_err(&port->serial->interface->dev, | ||
2197 | "GPIO initialisation failed: %d\n", | ||
2198 | result); | ||
2199 | } | ||
2200 | |||
1814 | return 0; | 2201 | return 0; |
1815 | } | 2202 | } |
1816 | 2203 | ||
@@ -1928,6 +2315,8 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port) | |||
1928 | { | 2315 | { |
1929 | struct ftdi_private *priv = usb_get_serial_port_data(port); | 2316 | struct ftdi_private *priv = usb_get_serial_port_data(port); |
1930 | 2317 | ||
2318 | ftdi_gpio_remove(port); | ||
2319 | |||
1931 | remove_sysfs_attrs(port); | 2320 | remove_sysfs_attrs(port); |
1932 | 2321 | ||
1933 | kfree(priv); | 2322 | kfree(priv); |
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index dcd0b6e05baf..a79a1325b4d9 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h | |||
@@ -35,7 +35,10 @@ | |||
35 | #define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ | 35 | #define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ |
36 | #define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ | 36 | #define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ |
37 | #define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */ | 37 | #define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */ |
38 | #define FTDI_SIO_GET_LATENCY_TIMER 10 /* Get the latency timer */ | 38 | #define FTDI_SIO_GET_LATENCY_TIMER 0x0a /* Get the latency timer */ |
39 | #define FTDI_SIO_SET_BITMODE 0x0b /* Set bitbang mode */ | ||
40 | #define FTDI_SIO_READ_PINS 0x0c /* Read immediate value of pins */ | ||
41 | #define FTDI_SIO_READ_EEPROM 0x90 /* Read EEPROM */ | ||
39 | 42 | ||
40 | /* Interface indices for FT2232, FT2232H and FT4232H devices */ | 43 | /* Interface indices for FT2232, FT2232H and FT4232H devices */ |
41 | #define INTERFACE_A 1 | 44 | #define INTERFACE_A 1 |
@@ -433,6 +436,29 @@ enum ftdi_sio_baudrate { | |||
433 | * 1 = active | 436 | * 1 = active |
434 | */ | 437 | */ |
435 | 438 | ||
439 | /* FTDI_SIO_SET_BITMODE */ | ||
440 | #define FTDI_SIO_SET_BITMODE_REQUEST_TYPE 0x40 | ||
441 | #define FTDI_SIO_SET_BITMODE_REQUEST FTDI_SIO_SET_BITMODE | ||
442 | |||
443 | /* Possible bitmodes for FTDI_SIO_SET_BITMODE_REQUEST */ | ||
444 | #define FTDI_SIO_BITMODE_RESET 0x00 | ||
445 | #define FTDI_SIO_BITMODE_CBUS 0x20 | ||
446 | |||
447 | /* FTDI_SIO_READ_PINS */ | ||
448 | #define FTDI_SIO_READ_PINS_REQUEST_TYPE 0xc0 | ||
449 | #define FTDI_SIO_READ_PINS_REQUEST FTDI_SIO_READ_PINS | ||
450 | |||
451 | /* | ||
452 | * FTDI_SIO_READ_EEPROM | ||
453 | * | ||
454 | * EEPROM format found in FTDI AN_201, "FT-X MTP memory Configuration", | ||
455 | * http://www.ftdichip.com/Support/Documents/AppNotes/AN_201_FT-X%20MTP%20Memory%20Configuration.pdf | ||
456 | */ | ||
457 | #define FTDI_SIO_READ_EEPROM_REQUEST_TYPE 0xc0 | ||
458 | #define FTDI_SIO_READ_EEPROM_REQUEST FTDI_SIO_READ_EEPROM | ||
459 | |||
460 | #define FTDI_FTX_CBUS_MUX_GPIO 0x8 | ||
461 | #define FTDI_FT232R_CBUS_MUX_GPIO 0xa | ||
436 | 462 | ||
437 | 463 | ||
438 | /* Descriptors returned by the device | 464 | /* Descriptors returned by the device |
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig index ec84758f0e23..6fd427284b12 100644 --- a/drivers/usb/storage/Kconfig +++ b/drivers/usb/storage/Kconfig | |||
@@ -23,16 +23,16 @@ config USB_STORAGE | |||
23 | To compile this driver as a module, choose M here: the | 23 | To compile this driver as a module, choose M here: the |
24 | module will be called usb-storage. | 24 | module will be called usb-storage. |
25 | 25 | ||
26 | if USB_STORAGE | ||
27 | |||
26 | config USB_STORAGE_DEBUG | 28 | config USB_STORAGE_DEBUG |
27 | bool "USB Mass Storage verbose debug" | 29 | bool "USB Mass Storage verbose debug" |
28 | depends on USB_STORAGE | ||
29 | help | 30 | help |
30 | Say Y here in order to have the USB Mass Storage code generate | 31 | Say Y here in order to have the USB Mass Storage code generate |
31 | verbose debugging messages. | 32 | verbose debugging messages. |
32 | 33 | ||
33 | config USB_STORAGE_REALTEK | 34 | config USB_STORAGE_REALTEK |
34 | tristate "Realtek Card Reader support" | 35 | tristate "Realtek Card Reader support" |
35 | depends on USB_STORAGE | ||
36 | help | 36 | help |
37 | Say Y here to include additional code to support the power-saving function | 37 | Say Y here to include additional code to support the power-saving function |
38 | for Realtek RTS51xx USB card readers. | 38 | for Realtek RTS51xx USB card readers. |
@@ -46,7 +46,6 @@ config REALTEK_AUTOPM | |||
46 | 46 | ||
47 | config USB_STORAGE_DATAFAB | 47 | config USB_STORAGE_DATAFAB |
48 | tristate "Datafab Compact Flash Reader support" | 48 | tristate "Datafab Compact Flash Reader support" |
49 | depends on USB_STORAGE | ||
50 | help | 49 | help |
51 | Support for certain Datafab CompactFlash readers. | 50 | Support for certain Datafab CompactFlash readers. |
52 | Datafab has a web page at <http://www.datafab.com/>. | 51 | Datafab has a web page at <http://www.datafab.com/>. |
@@ -55,7 +54,6 @@ config USB_STORAGE_DATAFAB | |||
55 | 54 | ||
56 | config USB_STORAGE_FREECOM | 55 | config USB_STORAGE_FREECOM |
57 | tristate "Freecom USB/ATAPI Bridge support" | 56 | tristate "Freecom USB/ATAPI Bridge support" |
58 | depends on USB_STORAGE | ||
59 | help | 57 | help |
60 | Support for the Freecom USB to IDE/ATAPI adaptor. | 58 | Support for the Freecom USB to IDE/ATAPI adaptor. |
61 | Freecom has a web page at <http://www.freecom.de/>. | 59 | Freecom has a web page at <http://www.freecom.de/>. |
@@ -64,7 +62,6 @@ config USB_STORAGE_FREECOM | |||
64 | 62 | ||
65 | config USB_STORAGE_ISD200 | 63 | config USB_STORAGE_ISD200 |
66 | tristate "ISD-200 USB/ATA Bridge support" | 64 | tristate "ISD-200 USB/ATA Bridge support" |
67 | depends on USB_STORAGE | ||
68 | ---help--- | 65 | ---help--- |
69 | Say Y here if you want to use USB Mass Store devices based | 66 | Say Y here if you want to use USB Mass Store devices based |
70 | on the In-Systems Design ISD-200 USB/ATA bridge. | 67 | on the In-Systems Design ISD-200 USB/ATA bridge. |
@@ -82,7 +79,6 @@ config USB_STORAGE_ISD200 | |||
82 | 79 | ||
83 | config USB_STORAGE_USBAT | 80 | config USB_STORAGE_USBAT |
84 | tristate "USBAT/USBAT02-based storage support" | 81 | tristate "USBAT/USBAT02-based storage support" |
85 | depends on USB_STORAGE | ||
86 | help | 82 | help |
87 | Say Y here to include additional code to support storage devices | 83 | Say Y here to include additional code to support storage devices |
88 | based on the SCM/Shuttle USBAT/USBAT02 processors. | 84 | based on the SCM/Shuttle USBAT/USBAT02 processors. |
@@ -105,7 +101,6 @@ config USB_STORAGE_USBAT | |||
105 | 101 | ||
106 | config USB_STORAGE_SDDR09 | 102 | config USB_STORAGE_SDDR09 |
107 | tristate "SanDisk SDDR-09 (and other SmartMedia, including DPCM) support" | 103 | tristate "SanDisk SDDR-09 (and other SmartMedia, including DPCM) support" |
108 | depends on USB_STORAGE | ||
109 | help | 104 | help |
110 | Say Y here to include additional code to support the Sandisk SDDR-09 | 105 | Say Y here to include additional code to support the Sandisk SDDR-09 |
111 | SmartMedia reader in the USB Mass Storage driver. | 106 | SmartMedia reader in the USB Mass Storage driver. |
@@ -115,7 +110,6 @@ config USB_STORAGE_SDDR09 | |||
115 | 110 | ||
116 | config USB_STORAGE_SDDR55 | 111 | config USB_STORAGE_SDDR55 |
117 | tristate "SanDisk SDDR-55 SmartMedia support" | 112 | tristate "SanDisk SDDR-55 SmartMedia support" |
118 | depends on USB_STORAGE | ||
119 | help | 113 | help |
120 | Say Y here to include additional code to support the Sandisk SDDR-55 | 114 | Say Y here to include additional code to support the Sandisk SDDR-55 |
121 | SmartMedia reader in the USB Mass Storage driver. | 115 | SmartMedia reader in the USB Mass Storage driver. |
@@ -124,7 +118,6 @@ config USB_STORAGE_SDDR55 | |||
124 | 118 | ||
125 | config USB_STORAGE_JUMPSHOT | 119 | config USB_STORAGE_JUMPSHOT |
126 | tristate "Lexar Jumpshot Compact Flash Reader" | 120 | tristate "Lexar Jumpshot Compact Flash Reader" |
127 | depends on USB_STORAGE | ||
128 | help | 121 | help |
129 | Say Y here to include additional code to support the Lexar Jumpshot | 122 | Say Y here to include additional code to support the Lexar Jumpshot |
130 | USB CompactFlash reader. | 123 | USB CompactFlash reader. |
@@ -133,7 +126,6 @@ config USB_STORAGE_JUMPSHOT | |||
133 | 126 | ||
134 | config USB_STORAGE_ALAUDA | 127 | config USB_STORAGE_ALAUDA |
135 | tristate "Olympus MAUSB-10/Fuji DPC-R1 support" | 128 | tristate "Olympus MAUSB-10/Fuji DPC-R1 support" |
136 | depends on USB_STORAGE | ||
137 | help | 129 | help |
138 | Say Y here to include additional code to support the Olympus MAUSB-10 | 130 | Say Y here to include additional code to support the Olympus MAUSB-10 |
139 | and Fujifilm DPC-R1 USB Card reader/writer devices. | 131 | and Fujifilm DPC-R1 USB Card reader/writer devices. |
@@ -145,7 +137,6 @@ config USB_STORAGE_ALAUDA | |||
145 | 137 | ||
146 | config USB_STORAGE_ONETOUCH | 138 | config USB_STORAGE_ONETOUCH |
147 | tristate "Support OneTouch Button on Maxtor Hard Drives" | 139 | tristate "Support OneTouch Button on Maxtor Hard Drives" |
148 | depends on USB_STORAGE | ||
149 | depends on INPUT=y || INPUT=USB_STORAGE | 140 | depends on INPUT=y || INPUT=USB_STORAGE |
150 | help | 141 | help |
151 | Say Y here to include additional code to support the Maxtor OneTouch | 142 | Say Y here to include additional code to support the Maxtor OneTouch |
@@ -160,7 +151,6 @@ config USB_STORAGE_ONETOUCH | |||
160 | 151 | ||
161 | config USB_STORAGE_KARMA | 152 | config USB_STORAGE_KARMA |
162 | tristate "Support for Rio Karma music player" | 153 | tristate "Support for Rio Karma music player" |
163 | depends on USB_STORAGE | ||
164 | help | 154 | help |
165 | Say Y here to include additional code to support the Rio Karma | 155 | Say Y here to include additional code to support the Rio Karma |
166 | USB interface. | 156 | USB interface. |
@@ -174,7 +164,6 @@ config USB_STORAGE_KARMA | |||
174 | 164 | ||
175 | config USB_STORAGE_CYPRESS_ATACB | 165 | config USB_STORAGE_CYPRESS_ATACB |
176 | tristate "SAT emulation on Cypress USB/ATA Bridge with ATACB" | 166 | tristate "SAT emulation on Cypress USB/ATA Bridge with ATACB" |
177 | depends on USB_STORAGE | ||
178 | ---help--- | 167 | ---help--- |
179 | Say Y here if you want to use SAT (ata pass through) on devices based | 168 | Say Y here if you want to use SAT (ata pass through) on devices based |
180 | on the Cypress USB/ATA bridge supporting ATACB. This will allow you | 169 | on the Cypress USB/ATA bridge supporting ATACB. This will allow you |
@@ -187,19 +176,15 @@ config USB_STORAGE_CYPRESS_ATACB | |||
187 | 176 | ||
188 | config USB_STORAGE_ENE_UB6250 | 177 | config USB_STORAGE_ENE_UB6250 |
189 | tristate "USB ENE card reader support" | 178 | tristate "USB ENE card reader support" |
190 | depends on SCSI | ||
191 | depends on USB_STORAGE | ||
192 | ---help--- | 179 | ---help--- |
193 | Say Y here if you wish to control a ENE SD/MS Card reader. | 180 | Say Y here if you wish to control a ENE SD/MS Card reader. |
194 | Note that this driver does not support SM cards. | 181 | Note that this driver does not support SM cards. |
195 | 182 | ||
196 | This option depends on 'SCSI' support being enabled, but you | ||
197 | probably also need 'SCSI device support: SCSI disk support' | ||
198 | (BLK_DEV_SD) for most USB storage devices. | ||
199 | |||
200 | To compile this driver as a module, choose M here: the | 183 | To compile this driver as a module, choose M here: the |
201 | module will be called ums-eneub6250. | 184 | module will be called ums-eneub6250. |
202 | 185 | ||
186 | endif # USB_STORAGE | ||
187 | |||
203 | config USB_UAS | 188 | config USB_UAS |
204 | tristate "USB Attached SCSI" | 189 | tristate "USB Attached SCSI" |
205 | depends on SCSI && USB_STORAGE | 190 | depends on SCSI && USB_STORAGE |
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index f5e4500d9970..2b474d60b4db 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c | |||
@@ -1153,7 +1153,7 @@ static int isd200_get_inquiry_data( struct us_data *us ) | |||
1153 | /* Fill in vendor identification fields */ | 1153 | /* Fill in vendor identification fields */ |
1154 | src = (__be16 *)&id[ATA_ID_PROD]; | 1154 | src = (__be16 *)&id[ATA_ID_PROD]; |
1155 | dest = (__u16*)info->InquiryData.VendorId; | 1155 | dest = (__u16*)info->InquiryData.VendorId; |
1156 | for (i=0;i<4;i++) | 1156 | for (i = 0; i < 4; i++) |
1157 | dest[i] = be16_to_cpu(src[i]); | 1157 | dest[i] = be16_to_cpu(src[i]); |
1158 | 1158 | ||
1159 | src = (__be16 *)&id[ATA_ID_PROD + 8/2]; | 1159 | src = (__be16 *)&id[ATA_ID_PROD + 8/2]; |
diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig index 00878c386dd0..30a847c2089d 100644 --- a/drivers/usb/typec/Kconfig +++ b/drivers/usb/typec/Kconfig | |||
@@ -45,50 +45,7 @@ menuconfig TYPEC | |||
45 | 45 | ||
46 | if TYPEC | 46 | if TYPEC |
47 | 47 | ||
48 | config TYPEC_TCPM | 48 | source "drivers/usb/typec/tcpm/Kconfig" |
49 | tristate "USB Type-C Port Controller Manager" | ||
50 | depends on USB | ||
51 | select USB_ROLE_SWITCH | ||
52 | select POWER_SUPPLY | ||
53 | help | ||
54 | The Type-C Port Controller Manager provides a USB PD and USB Type-C | ||
55 | state machine for use with Type-C Port Controllers. | ||
56 | |||
57 | if TYPEC_TCPM | ||
58 | |||
59 | config TYPEC_TCPCI | ||
60 | tristate "Type-C Port Controller Interface driver" | ||
61 | depends on I2C | ||
62 | select REGMAP_I2C | ||
63 | help | ||
64 | Type-C Port Controller driver for TCPCI-compliant controller. | ||
65 | |||
66 | config TYPEC_RT1711H | ||
67 | tristate "Richtek RT1711H Type-C chip driver" | ||
68 | depends on I2C | ||
69 | select TYPEC_TCPCI | ||
70 | help | ||
71 | Richtek RT1711H Type-C chip driver that works with | ||
72 | Type-C Port Controller Manager to provide USB PD and USB | ||
73 | Type-C functionalities. | ||
74 | |||
75 | source "drivers/usb/typec/fusb302/Kconfig" | ||
76 | |||
77 | config TYPEC_WCOVE | ||
78 | tristate "Intel WhiskeyCove PMIC USB Type-C PHY driver" | ||
79 | depends on ACPI | ||
80 | depends on INTEL_SOC_PMIC | ||
81 | depends on INTEL_PMC_IPC | ||
82 | depends on BXT_WC_PMIC_OPREGION | ||
83 | help | ||
84 | This driver adds support for USB Type-C detection on Intel Broxton | ||
85 | platforms that have Intel Whiskey Cove PMIC. The driver can detect the | ||
86 | role and cable orientation. | ||
87 | |||
88 | To compile this driver as module, choose M here: the module will be | ||
89 | called typec_wcove | ||
90 | |||
91 | endif # TYPEC_TCPM | ||
92 | 49 | ||
93 | source "drivers/usb/typec/ucsi/Kconfig" | 50 | source "drivers/usb/typec/ucsi/Kconfig" |
94 | 51 | ||
diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile index 45b0aef428a8..6696b7263d61 100644 --- a/drivers/usb/typec/Makefile +++ b/drivers/usb/typec/Makefile | |||
@@ -2,11 +2,7 @@ | |||
2 | obj-$(CONFIG_TYPEC) += typec.o | 2 | obj-$(CONFIG_TYPEC) += typec.o |
3 | typec-y := class.o mux.o bus.o | 3 | typec-y := class.o mux.o bus.o |
4 | obj-$(CONFIG_TYPEC) += altmodes/ | 4 | obj-$(CONFIG_TYPEC) += altmodes/ |
5 | obj-$(CONFIG_TYPEC_TCPM) += tcpm.o | 5 | obj-$(CONFIG_TYPEC_TCPM) += tcpm/ |
6 | obj-y += fusb302/ | ||
7 | obj-$(CONFIG_TYPEC_WCOVE) += typec_wcove.o | ||
8 | obj-$(CONFIG_TYPEC_UCSI) += ucsi/ | 6 | obj-$(CONFIG_TYPEC_UCSI) += ucsi/ |
9 | obj-$(CONFIG_TYPEC_TPS6598X) += tps6598x.o | 7 | obj-$(CONFIG_TYPEC_TPS6598X) += tps6598x.o |
10 | obj-$(CONFIG_TYPEC) += mux/ | 8 | obj-$(CONFIG_TYPEC) += mux/ |
11 | obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o | ||
12 | obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o | ||
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index e61dffb27a0c..5db0593ca0bd 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c | |||
@@ -1322,7 +1322,7 @@ void typec_set_pwr_role(struct typec_port *port, enum typec_role role) | |||
1322 | EXPORT_SYMBOL_GPL(typec_set_pwr_role); | 1322 | EXPORT_SYMBOL_GPL(typec_set_pwr_role); |
1323 | 1323 | ||
1324 | /** | 1324 | /** |
1325 | * typec_set_pwr_role - Report VCONN source change | 1325 | * typec_set_vconn_role - Report VCONN source change |
1326 | * @port: The USB Type-C Port which VCONN role changed | 1326 | * @port: The USB Type-C Port which VCONN role changed |
1327 | * @role: Source when @port is sourcing VCONN, or Sink when it's not | 1327 | * @role: Source when @port is sourcing VCONN, or Sink when it's not |
1328 | * | 1328 | * |
@@ -1500,7 +1500,7 @@ typec_port_register_altmode(struct typec_port *port, | |||
1500 | 1500 | ||
1501 | sprintf(id, "id%04xm%02x", desc->svid, desc->mode); | 1501 | sprintf(id, "id%04xm%02x", desc->svid, desc->mode); |
1502 | 1502 | ||
1503 | mux = typec_mux_get(port->dev.parent, id); | 1503 | mux = typec_mux_get(&port->dev, id); |
1504 | if (IS_ERR(mux)) | 1504 | if (IS_ERR(mux)) |
1505 | return ERR_CAST(mux); | 1505 | return ERR_CAST(mux); |
1506 | 1506 | ||
@@ -1540,18 +1540,6 @@ struct typec_port *typec_register_port(struct device *parent, | |||
1540 | return ERR_PTR(id); | 1540 | return ERR_PTR(id); |
1541 | } | 1541 | } |
1542 | 1542 | ||
1543 | port->sw = typec_switch_get(cap->fwnode ? &port->dev : parent); | ||
1544 | if (IS_ERR(port->sw)) { | ||
1545 | ret = PTR_ERR(port->sw); | ||
1546 | goto err_switch; | ||
1547 | } | ||
1548 | |||
1549 | port->mux = typec_mux_get(parent, "typec-mux"); | ||
1550 | if (IS_ERR(port->mux)) { | ||
1551 | ret = PTR_ERR(port->mux); | ||
1552 | goto err_mux; | ||
1553 | } | ||
1554 | |||
1555 | switch (cap->type) { | 1543 | switch (cap->type) { |
1556 | case TYPEC_PORT_SRC: | 1544 | case TYPEC_PORT_SRC: |
1557 | port->pwr_role = TYPEC_SOURCE; | 1545 | port->pwr_role = TYPEC_SOURCE; |
@@ -1592,13 +1580,26 @@ struct typec_port *typec_register_port(struct device *parent, | |||
1592 | port->port_type = cap->type; | 1580 | port->port_type = cap->type; |
1593 | port->prefer_role = cap->prefer_role; | 1581 | port->prefer_role = cap->prefer_role; |
1594 | 1582 | ||
1583 | device_initialize(&port->dev); | ||
1595 | port->dev.class = typec_class; | 1584 | port->dev.class = typec_class; |
1596 | port->dev.parent = parent; | 1585 | port->dev.parent = parent; |
1597 | port->dev.fwnode = cap->fwnode; | 1586 | port->dev.fwnode = cap->fwnode; |
1598 | port->dev.type = &typec_port_dev_type; | 1587 | port->dev.type = &typec_port_dev_type; |
1599 | dev_set_name(&port->dev, "port%d", id); | 1588 | dev_set_name(&port->dev, "port%d", id); |
1600 | 1589 | ||
1601 | ret = device_register(&port->dev); | 1590 | port->sw = typec_switch_get(&port->dev); |
1591 | if (IS_ERR(port->sw)) { | ||
1592 | put_device(&port->dev); | ||
1593 | return ERR_CAST(port->sw); | ||
1594 | } | ||
1595 | |||
1596 | port->mux = typec_mux_get(&port->dev, "typec-mux"); | ||
1597 | if (IS_ERR(port->mux)) { | ||
1598 | put_device(&port->dev); | ||
1599 | return ERR_CAST(port->mux); | ||
1600 | } | ||
1601 | |||
1602 | ret = device_add(&port->dev); | ||
1602 | if (ret) { | 1603 | if (ret) { |
1603 | dev_err(parent, "failed to register port (%d)\n", ret); | 1604 | dev_err(parent, "failed to register port (%d)\n", ret); |
1604 | put_device(&port->dev); | 1605 | put_device(&port->dev); |
@@ -1606,15 +1607,6 @@ struct typec_port *typec_register_port(struct device *parent, | |||
1606 | } | 1607 | } |
1607 | 1608 | ||
1608 | return port; | 1609 | return port; |
1609 | |||
1610 | err_mux: | ||
1611 | typec_switch_put(port->sw); | ||
1612 | |||
1613 | err_switch: | ||
1614 | ida_simple_remove(&typec_index_ida, port->id); | ||
1615 | kfree(port); | ||
1616 | |||
1617 | return ERR_PTR(ret); | ||
1618 | } | 1610 | } |
1619 | EXPORT_SYMBOL_GPL(typec_register_port); | 1611 | EXPORT_SYMBOL_GPL(typec_register_port); |
1620 | 1612 | ||
diff --git a/drivers/usb/typec/fusb302/Kconfig b/drivers/usb/typec/fusb302/Kconfig deleted file mode 100644 index fce099ff39fe..000000000000 --- a/drivers/usb/typec/fusb302/Kconfig +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | config TYPEC_FUSB302 | ||
2 | tristate "Fairchild FUSB302 Type-C chip driver" | ||
3 | depends on I2C | ||
4 | help | ||
5 | The Fairchild FUSB302 Type-C chip driver that works with | ||
6 | Type-C Port Controller Manager to provide USB PD and USB | ||
7 | Type-C functionalities. | ||
diff --git a/drivers/usb/typec/fusb302/Makefile b/drivers/usb/typec/fusb302/Makefile deleted file mode 100644 index 3b51b33631a0..000000000000 --- a/drivers/usb/typec/fusb302/Makefile +++ /dev/null | |||
@@ -1,2 +0,0 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | obj-$(CONFIG_TYPEC_FUSB302) += fusb302.o | ||
diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig new file mode 100644 index 000000000000..f03ea8a61768 --- /dev/null +++ b/drivers/usb/typec/tcpm/Kconfig | |||
@@ -0,0 +1,52 @@ | |||
1 | config TYPEC_TCPM | ||
2 | tristate "USB Type-C Port Controller Manager" | ||
3 | depends on USB | ||
4 | select USB_ROLE_SWITCH | ||
5 | select POWER_SUPPLY | ||
6 | help | ||
7 | The Type-C Port Controller Manager provides a USB PD and USB Type-C | ||
8 | state machine for use with Type-C Port Controllers. | ||
9 | |||
10 | if TYPEC_TCPM | ||
11 | |||
12 | config TYPEC_TCPCI | ||
13 | tristate "Type-C Port Controller Interface driver" | ||
14 | depends on I2C | ||
15 | select REGMAP_I2C | ||
16 | help | ||
17 | Type-C Port Controller driver for TCPCI-compliant controller. | ||
18 | |||
19 | if TYPEC_TCPCI | ||
20 | |||
21 | config TYPEC_RT1711H | ||
22 | tristate "Richtek RT1711H Type-C chip driver" | ||
23 | help | ||
24 | Richtek RT1711H Type-C chip driver that works with | ||
25 | Type-C Port Controller Manager to provide USB PD and USB | ||
26 | Type-C functionalities. | ||
27 | |||
28 | endif # TYPEC_TCPCI | ||
29 | |||
30 | config TYPEC_FUSB302 | ||
31 | tristate "Fairchild FUSB302 Type-C chip driver" | ||
32 | depends on I2C | ||
33 | help | ||
34 | The Fairchild FUSB302 Type-C chip driver that works with | ||
35 | Type-C Port Controller Manager to provide USB PD and USB | ||
36 | Type-C functionalities. | ||
37 | |||
38 | config TYPEC_WCOVE | ||
39 | tristate "Intel WhiskeyCove PMIC USB Type-C PHY driver" | ||
40 | depends on ACPI | ||
41 | depends on INTEL_SOC_PMIC | ||
42 | depends on INTEL_PMC_IPC | ||
43 | depends on BXT_WC_PMIC_OPREGION | ||
44 | help | ||
45 | This driver adds support for USB Type-C on Intel Broxton platforms | ||
46 | that have Intel Whiskey Cove PMIC. The driver works with USB Type-C | ||
47 | Port Controller Manager to provide USB PD and Type-C functionalities. | ||
48 | |||
49 | To compile this driver as module, choose M here: the module will be | ||
50 | called typec_wcove.ko | ||
51 | |||
52 | endif # TYPEC_TCPM | ||
diff --git a/drivers/usb/typec/tcpm/Makefile b/drivers/usb/typec/tcpm/Makefile new file mode 100644 index 000000000000..a5ff6c8eb892 --- /dev/null +++ b/drivers/usb/typec/tcpm/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | obj-$(CONFIG_TYPEC_TCPM) += tcpm.o | ||
3 | obj-$(CONFIG_TYPEC_FUSB302) += fusb302.o | ||
4 | obj-$(CONFIG_TYPEC_WCOVE) += typec_wcove.o | ||
5 | typec_wcove-y := wcove.o | ||
6 | obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o | ||
7 | obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o | ||
diff --git a/drivers/usb/typec/fusb302/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c index 82bed9810be6..43b64d9309d0 100644 --- a/drivers/usb/typec/fusb302/fusb302.c +++ b/drivers/usb/typec/tcpm/fusb302.c | |||
@@ -42,19 +42,12 @@ | |||
42 | #define T_BC_LVL_DEBOUNCE_DELAY_MS 30 | 42 | #define T_BC_LVL_DEBOUNCE_DELAY_MS 30 |
43 | 43 | ||
44 | enum toggling_mode { | 44 | enum toggling_mode { |
45 | TOGGLINE_MODE_OFF, | 45 | TOGGLING_MODE_OFF, |
46 | TOGGLING_MODE_DRP, | 46 | TOGGLING_MODE_DRP, |
47 | TOGGLING_MODE_SNK, | 47 | TOGGLING_MODE_SNK, |
48 | TOGGLING_MODE_SRC, | 48 | TOGGLING_MODE_SRC, |
49 | }; | 49 | }; |
50 | 50 | ||
51 | static const char * const toggling_mode_name[] = { | ||
52 | [TOGGLINE_MODE_OFF] = "toggling_OFF", | ||
53 | [TOGGLING_MODE_DRP] = "toggling_DRP", | ||
54 | [TOGGLING_MODE_SNK] = "toggling_SNK", | ||
55 | [TOGGLING_MODE_SRC] = "toggling_SRC", | ||
56 | }; | ||
57 | |||
58 | enum src_current_status { | 51 | enum src_current_status { |
59 | SRC_CURRENT_DEFAULT, | 52 | SRC_CURRENT_DEFAULT, |
60 | SRC_CURRENT_MEDIUM, | 53 | SRC_CURRENT_MEDIUM, |
@@ -601,7 +594,7 @@ static int fusb302_set_toggling(struct fusb302_chip *chip, | |||
601 | chip->intr_comp_chng = false; | 594 | chip->intr_comp_chng = false; |
602 | /* configure toggling mode: none/snk/src/drp */ | 595 | /* configure toggling mode: none/snk/src/drp */ |
603 | switch (mode) { | 596 | switch (mode) { |
604 | case TOGGLINE_MODE_OFF: | 597 | case TOGGLING_MODE_OFF: |
605 | ret = fusb302_i2c_mask_write(chip, FUSB_REG_CONTROL2, | 598 | ret = fusb302_i2c_mask_write(chip, FUSB_REG_CONTROL2, |
606 | FUSB_REG_CONTROL2_MODE_MASK, | 599 | FUSB_REG_CONTROL2_MODE_MASK, |
607 | FUSB_REG_CONTROL2_MODE_NONE); | 600 | FUSB_REG_CONTROL2_MODE_NONE); |
@@ -633,7 +626,7 @@ static int fusb302_set_toggling(struct fusb302_chip *chip, | |||
633 | break; | 626 | break; |
634 | } | 627 | } |
635 | 628 | ||
636 | if (mode == TOGGLINE_MODE_OFF) { | 629 | if (mode == TOGGLING_MODE_OFF) { |
637 | /* mask TOGDONE interrupt */ | 630 | /* mask TOGDONE interrupt */ |
638 | ret = fusb302_i2c_set_bits(chip, FUSB_REG_MASKA, | 631 | ret = fusb302_i2c_set_bits(chip, FUSB_REG_MASKA, |
639 | FUSB_REG_MASKA_TOGDONE); | 632 | FUSB_REG_MASKA_TOGDONE); |
@@ -686,6 +679,7 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc) | |||
686 | int ret = 0; | 679 | int ret = 0; |
687 | bool pull_up, pull_down; | 680 | bool pull_up, pull_down; |
688 | u8 rd_mda; | 681 | u8 rd_mda; |
682 | enum toggling_mode mode; | ||
689 | 683 | ||
690 | mutex_lock(&chip->lock); | 684 | mutex_lock(&chip->lock); |
691 | switch (cc) { | 685 | switch (cc) { |
@@ -709,7 +703,7 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc) | |||
709 | ret = -EINVAL; | 703 | ret = -EINVAL; |
710 | goto done; | 704 | goto done; |
711 | } | 705 | } |
712 | ret = fusb302_set_toggling(chip, TOGGLINE_MODE_OFF); | 706 | ret = fusb302_set_toggling(chip, TOGGLING_MODE_OFF); |
713 | if (ret < 0) { | 707 | if (ret < 0) { |
714 | fusb302_log(chip, "cannot stop toggling, ret=%d", ret); | 708 | fusb302_log(chip, "cannot stop toggling, ret=%d", ret); |
715 | goto done; | 709 | goto done; |
@@ -771,6 +765,29 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc) | |||
771 | chip->intr_comp_chng = false; | 765 | chip->intr_comp_chng = false; |
772 | } | 766 | } |
773 | fusb302_log(chip, "cc := %s", typec_cc_status_name[cc]); | 767 | fusb302_log(chip, "cc := %s", typec_cc_status_name[cc]); |
768 | |||
769 | /* Enable detection for fixed SNK or SRC only roles */ | ||
770 | switch (cc) { | ||
771 | case TYPEC_CC_RD: | ||
772 | mode = TOGGLING_MODE_SNK; | ||
773 | break; | ||
774 | case TYPEC_CC_RP_DEF: | ||
775 | case TYPEC_CC_RP_1_5: | ||
776 | case TYPEC_CC_RP_3_0: | ||
777 | mode = TOGGLING_MODE_SRC; | ||
778 | break; | ||
779 | default: | ||
780 | mode = TOGGLING_MODE_OFF; | ||
781 | break; | ||
782 | } | ||
783 | |||
784 | if (mode != TOGGLING_MODE_OFF) { | ||
785 | ret = fusb302_set_toggling(chip, mode); | ||
786 | if (ret < 0) | ||
787 | fusb302_log(chip, | ||
788 | "cannot set fixed role toggling mode, ret=%d", | ||
789 | ret); | ||
790 | } | ||
774 | done: | 791 | done: |
775 | mutex_unlock(&chip->lock); | 792 | mutex_unlock(&chip->lock); |
776 | 793 | ||
@@ -1178,10 +1195,6 @@ static const u32 src_pdo[] = { | |||
1178 | PDO_FIXED(5000, 400, PDO_FIXED_FLAGS), | 1195 | PDO_FIXED(5000, 400, PDO_FIXED_FLAGS), |
1179 | }; | 1196 | }; |
1180 | 1197 | ||
1181 | static const u32 snk_pdo[] = { | ||
1182 | PDO_FIXED(5000, 400, PDO_FIXED_FLAGS), | ||
1183 | }; | ||
1184 | |||
1185 | static const struct tcpc_config fusb302_tcpc_config = { | 1198 | static const struct tcpc_config fusb302_tcpc_config = { |
1186 | .src_pdo = src_pdo, | 1199 | .src_pdo = src_pdo, |
1187 | .nr_src_pdo = ARRAY_SIZE(src_pdo), | 1200 | .nr_src_pdo = ARRAY_SIZE(src_pdo), |
@@ -1303,7 +1316,7 @@ static int fusb302_handle_togdone_snk(struct fusb302_chip *chip, | |||
1303 | tcpm_cc_change(chip->tcpm_port); | 1316 | tcpm_cc_change(chip->tcpm_port); |
1304 | } | 1317 | } |
1305 | /* turn off toggling */ | 1318 | /* turn off toggling */ |
1306 | ret = fusb302_set_toggling(chip, TOGGLINE_MODE_OFF); | 1319 | ret = fusb302_set_toggling(chip, TOGGLING_MODE_OFF); |
1307 | if (ret < 0) { | 1320 | if (ret < 0) { |
1308 | fusb302_log(chip, | 1321 | fusb302_log(chip, |
1309 | "cannot set toggling mode off, ret=%d", ret); | 1322 | "cannot set toggling mode off, ret=%d", ret); |
@@ -1399,7 +1412,7 @@ static int fusb302_handle_togdone_src(struct fusb302_chip *chip, | |||
1399 | tcpm_cc_change(chip->tcpm_port); | 1412 | tcpm_cc_change(chip->tcpm_port); |
1400 | } | 1413 | } |
1401 | /* turn off toggling */ | 1414 | /* turn off toggling */ |
1402 | ret = fusb302_set_toggling(chip, TOGGLINE_MODE_OFF); | 1415 | ret = fusb302_set_toggling(chip, TOGGLING_MODE_OFF); |
1403 | if (ret < 0) { | 1416 | if (ret < 0) { |
1404 | fusb302_log(chip, | 1417 | fusb302_log(chip, |
1405 | "cannot set toggling mode off, ret=%d", ret); | 1418 | "cannot set toggling mode off, ret=%d", ret); |
@@ -1730,12 +1743,14 @@ static int fusb302_probe(struct i2c_client *client, | |||
1730 | return -ENOMEM; | 1743 | return -ENOMEM; |
1731 | 1744 | ||
1732 | chip->i2c_client = client; | 1745 | chip->i2c_client = client; |
1733 | i2c_set_clientdata(client, chip); | ||
1734 | chip->dev = &client->dev; | 1746 | chip->dev = &client->dev; |
1735 | chip->tcpc_config = fusb302_tcpc_config; | 1747 | chip->tcpc_config = fusb302_tcpc_config; |
1736 | chip->tcpc_dev.config = &chip->tcpc_config; | 1748 | chip->tcpc_dev.config = &chip->tcpc_config; |
1737 | mutex_init(&chip->lock); | 1749 | mutex_init(&chip->lock); |
1738 | 1750 | ||
1751 | chip->tcpc_dev.fwnode = | ||
1752 | device_get_named_child_node(dev, "connector"); | ||
1753 | |||
1739 | if (!device_property_read_u32(dev, "fcs,operating-sink-microwatt", &v)) | 1754 | if (!device_property_read_u32(dev, "fcs,operating-sink-microwatt", &v)) |
1740 | chip->tcpc_config.operating_snk_mw = v / 1000; | 1755 | chip->tcpc_config.operating_snk_mw = v / 1000; |
1741 | 1756 | ||
@@ -1756,22 +1771,17 @@ static int fusb302_probe(struct i2c_client *client, | |||
1756 | return -EPROBE_DEFER; | 1771 | return -EPROBE_DEFER; |
1757 | } | 1772 | } |
1758 | 1773 | ||
1759 | fusb302_debugfs_init(chip); | 1774 | chip->vbus = devm_regulator_get(chip->dev, "vbus"); |
1775 | if (IS_ERR(chip->vbus)) | ||
1776 | return PTR_ERR(chip->vbus); | ||
1760 | 1777 | ||
1761 | chip->wq = create_singlethread_workqueue(dev_name(chip->dev)); | 1778 | chip->wq = create_singlethread_workqueue(dev_name(chip->dev)); |
1762 | if (!chip->wq) { | 1779 | if (!chip->wq) |
1763 | ret = -ENOMEM; | 1780 | return -ENOMEM; |
1764 | goto clear_client_data; | 1781 | |
1765 | } | ||
1766 | INIT_DELAYED_WORK(&chip->bc_lvl_handler, fusb302_bc_lvl_handler_work); | 1782 | INIT_DELAYED_WORK(&chip->bc_lvl_handler, fusb302_bc_lvl_handler_work); |
1767 | init_tcpc_dev(&chip->tcpc_dev); | 1783 | init_tcpc_dev(&chip->tcpc_dev); |
1768 | 1784 | ||
1769 | chip->vbus = devm_regulator_get(chip->dev, "vbus"); | ||
1770 | if (IS_ERR(chip->vbus)) { | ||
1771 | ret = PTR_ERR(chip->vbus); | ||
1772 | goto destroy_workqueue; | ||
1773 | } | ||
1774 | |||
1775 | if (client->irq) { | 1785 | if (client->irq) { |
1776 | chip->gpio_int_n_irq = client->irq; | 1786 | chip->gpio_int_n_irq = client->irq; |
1777 | } else { | 1787 | } else { |
@@ -1797,15 +1807,15 @@ static int fusb302_probe(struct i2c_client *client, | |||
1797 | goto tcpm_unregister_port; | 1807 | goto tcpm_unregister_port; |
1798 | } | 1808 | } |
1799 | enable_irq_wake(chip->gpio_int_n_irq); | 1809 | enable_irq_wake(chip->gpio_int_n_irq); |
1810 | fusb302_debugfs_init(chip); | ||
1811 | i2c_set_clientdata(client, chip); | ||
1812 | |||
1800 | return ret; | 1813 | return ret; |
1801 | 1814 | ||
1802 | tcpm_unregister_port: | 1815 | tcpm_unregister_port: |
1803 | tcpm_unregister_port(chip->tcpm_port); | 1816 | tcpm_unregister_port(chip->tcpm_port); |
1804 | destroy_workqueue: | 1817 | destroy_workqueue: |
1805 | destroy_workqueue(chip->wq); | 1818 | destroy_workqueue(chip->wq); |
1806 | clear_client_data: | ||
1807 | i2c_set_clientdata(client, NULL); | ||
1808 | fusb302_debugfs_exit(chip); | ||
1809 | 1819 | ||
1810 | return ret; | 1820 | return ret; |
1811 | } | 1821 | } |
@@ -1816,7 +1826,6 @@ static int fusb302_remove(struct i2c_client *client) | |||
1816 | 1826 | ||
1817 | tcpm_unregister_port(chip->tcpm_port); | 1827 | tcpm_unregister_port(chip->tcpm_port); |
1818 | destroy_workqueue(chip->wq); | 1828 | destroy_workqueue(chip->wq); |
1819 | i2c_set_clientdata(client, NULL); | ||
1820 | fusb302_debugfs_exit(chip); | 1829 | fusb302_debugfs_exit(chip); |
1821 | 1830 | ||
1822 | return 0; | 1831 | return 0; |
diff --git a/drivers/usb/typec/fusb302/fusb302_reg.h b/drivers/usb/typec/tcpm/fusb302_reg.h index 00b39d365478..00b39d365478 100644 --- a/drivers/usb/typec/fusb302/fusb302_reg.h +++ b/drivers/usb/typec/tcpm/fusb302_reg.h | |||
diff --git a/drivers/usb/typec/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c index ac6b418b15f1..ac6b418b15f1 100644 --- a/drivers/usb/typec/tcpci.c +++ b/drivers/usb/typec/tcpm/tcpci.c | |||
diff --git a/drivers/usb/typec/tcpci.h b/drivers/usb/typec/tcpm/tcpci.h index 303ebde26546..303ebde26546 100644 --- a/drivers/usb/typec/tcpci.h +++ b/drivers/usb/typec/tcpm/tcpci.h | |||
diff --git a/drivers/usb/typec/tcpci_rt1711h.c b/drivers/usb/typec/tcpm/tcpci_rt1711h.c index 017389021b96..017389021b96 100644 --- a/drivers/usb/typec/tcpci_rt1711h.c +++ b/drivers/usb/typec/tcpm/tcpci_rt1711h.c | |||
diff --git a/drivers/usb/typec/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 4f1f4215f3d6..dbbd71f754d0 100644 --- a/drivers/usb/typec/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c | |||
@@ -1430,8 +1430,8 @@ static enum pdo_err tcpm_caps_err(struct tcpm_port *port, const u32 *pdo, | |||
1430 | if (pdo_apdo_type(pdo[i]) != APDO_TYPE_PPS) | 1430 | if (pdo_apdo_type(pdo[i]) != APDO_TYPE_PPS) |
1431 | break; | 1431 | break; |
1432 | 1432 | ||
1433 | if (pdo_pps_apdo_max_current(pdo[i]) < | 1433 | if (pdo_pps_apdo_max_voltage(pdo[i]) < |
1434 | pdo_pps_apdo_max_current(pdo[i - 1])) | 1434 | pdo_pps_apdo_max_voltage(pdo[i - 1])) |
1435 | return PDO_ERR_PPS_APDO_NOT_SORTED; | 1435 | return PDO_ERR_PPS_APDO_NOT_SORTED; |
1436 | else if (pdo_pps_apdo_min_voltage(pdo[i]) == | 1436 | else if (pdo_pps_apdo_min_voltage(pdo[i]) == |
1437 | pdo_pps_apdo_min_voltage(pdo[i - 1]) && | 1437 | pdo_pps_apdo_min_voltage(pdo[i - 1]) && |
@@ -2209,7 +2209,7 @@ static unsigned int tcpm_pd_select_pps_apdo(struct tcpm_port *port) | |||
2209 | { | 2209 | { |
2210 | unsigned int i, j, max_mw = 0, max_mv = 0; | 2210 | unsigned int i, j, max_mw = 0, max_mv = 0; |
2211 | unsigned int min_src_mv, max_src_mv, src_ma, src_mw; | 2211 | unsigned int min_src_mv, max_src_mv, src_ma, src_mw; |
2212 | unsigned int min_snk_mv, max_snk_mv, snk_ma; | 2212 | unsigned int min_snk_mv, max_snk_mv; |
2213 | u32 pdo; | 2213 | u32 pdo; |
2214 | unsigned int src_pdo = 0, snk_pdo = 0; | 2214 | unsigned int src_pdo = 0, snk_pdo = 0; |
2215 | 2215 | ||
@@ -2253,8 +2253,6 @@ static unsigned int tcpm_pd_select_pps_apdo(struct tcpm_port *port) | |||
2253 | pdo_pps_apdo_min_voltage(pdo); | 2253 | pdo_pps_apdo_min_voltage(pdo); |
2254 | max_snk_mv = | 2254 | max_snk_mv = |
2255 | pdo_pps_apdo_max_voltage(pdo); | 2255 | pdo_pps_apdo_max_voltage(pdo); |
2256 | snk_ma = | ||
2257 | pdo_pps_apdo_max_current(pdo); | ||
2258 | break; | 2256 | break; |
2259 | default: | 2257 | default: |
2260 | tcpm_log(port, | 2258 | tcpm_log(port, |
@@ -2402,7 +2400,7 @@ static int tcpm_pd_send_request(struct tcpm_port *port) | |||
2402 | 2400 | ||
2403 | static int tcpm_pd_build_pps_request(struct tcpm_port *port, u32 *rdo) | 2401 | static int tcpm_pd_build_pps_request(struct tcpm_port *port, u32 *rdo) |
2404 | { | 2402 | { |
2405 | unsigned int out_mv, op_ma, op_mw, min_mv, max_mv, max_ma, flags; | 2403 | unsigned int out_mv, op_ma, op_mw, max_mv, max_ma, flags; |
2406 | enum pd_pdo_type type; | 2404 | enum pd_pdo_type type; |
2407 | unsigned int src_pdo_index; | 2405 | unsigned int src_pdo_index; |
2408 | u32 pdo; | 2406 | u32 pdo; |
@@ -2420,7 +2418,6 @@ static int tcpm_pd_build_pps_request(struct tcpm_port *port, u32 *rdo) | |||
2420 | tcpm_log(port, "Invalid APDO selected!"); | 2418 | tcpm_log(port, "Invalid APDO selected!"); |
2421 | return -EINVAL; | 2419 | return -EINVAL; |
2422 | } | 2420 | } |
2423 | min_mv = port->pps_data.min_volt; | ||
2424 | max_mv = port->pps_data.max_volt; | 2421 | max_mv = port->pps_data.max_volt; |
2425 | max_ma = port->pps_data.max_curr; | 2422 | max_ma = port->pps_data.max_curr; |
2426 | out_mv = port->pps_data.out_volt; | 2423 | out_mv = port->pps_data.out_volt; |
@@ -4116,6 +4113,9 @@ static int tcpm_pps_set_op_curr(struct tcpm_port *port, u16 op_curr) | |||
4116 | goto port_unlock; | 4113 | goto port_unlock; |
4117 | } | 4114 | } |
4118 | 4115 | ||
4116 | /* Round down operating current to align with PPS valid steps */ | ||
4117 | op_curr = op_curr - (op_curr % RDO_PROG_CURR_MA_STEP); | ||
4118 | |||
4119 | reinit_completion(&port->pps_complete); | 4119 | reinit_completion(&port->pps_complete); |
4120 | port->pps_data.op_curr = op_curr; | 4120 | port->pps_data.op_curr = op_curr; |
4121 | port->pps_status = 0; | 4121 | port->pps_status = 0; |
@@ -4169,6 +4169,9 @@ static int tcpm_pps_set_out_volt(struct tcpm_port *port, u16 out_volt) | |||
4169 | goto port_unlock; | 4169 | goto port_unlock; |
4170 | } | 4170 | } |
4171 | 4171 | ||
4172 | /* Round down output voltage to align with PPS valid steps */ | ||
4173 | out_volt = out_volt - (out_volt % RDO_PROG_VOLT_MV_STEP); | ||
4174 | |||
4172 | reinit_completion(&port->pps_complete); | 4175 | reinit_completion(&port->pps_complete); |
4173 | port->pps_data.out_volt = out_volt; | 4176 | port->pps_data.out_volt = out_volt; |
4174 | port->pps_status = 0; | 4177 | port->pps_status = 0; |
diff --git a/drivers/usb/typec/typec_wcove.c b/drivers/usb/typec/tcpm/wcove.c index 423208e19383..423208e19383 100644 --- a/drivers/usb/typec/typec_wcove.c +++ b/drivers/usb/typec/tcpm/wcove.c | |||
diff --git a/drivers/usb/usbip/vudc_main.c b/drivers/usb/usbip/vudc_main.c index 3fc22037a82f..390733e6937e 100644 --- a/drivers/usb/usbip/vudc_main.c +++ b/drivers/usb/usbip/vudc_main.c | |||
@@ -73,6 +73,10 @@ static int __init init(void) | |||
73 | cleanup: | 73 | cleanup: |
74 | list_for_each_entry_safe(udc_dev, udc_dev2, &vudc_devices, dev_entry) { | 74 | list_for_each_entry_safe(udc_dev, udc_dev2, &vudc_devices, dev_entry) { |
75 | list_del(&udc_dev->dev_entry); | 75 | list_del(&udc_dev->dev_entry); |
76 | /* | ||
77 | * Just do platform_device_del() here, put_vudc_device() | ||
78 | * calls the platform_device_put() | ||
79 | */ | ||
76 | platform_device_del(udc_dev->pdev); | 80 | platform_device_del(udc_dev->pdev); |
77 | put_vudc_device(udc_dev); | 81 | put_vudc_device(udc_dev); |
78 | } | 82 | } |
@@ -89,7 +93,11 @@ static void __exit cleanup(void) | |||
89 | 93 | ||
90 | list_for_each_entry_safe(udc_dev, udc_dev2, &vudc_devices, dev_entry) { | 94 | list_for_each_entry_safe(udc_dev, udc_dev2, &vudc_devices, dev_entry) { |
91 | list_del(&udc_dev->dev_entry); | 95 | list_del(&udc_dev->dev_entry); |
92 | platform_device_unregister(udc_dev->pdev); | 96 | /* |
97 | * Just do platform_device_del() here, put_vudc_device() | ||
98 | * calls the platform_device_put() | ||
99 | */ | ||
100 | platform_device_del(udc_dev->pdev); | ||
93 | put_vudc_device(udc_dev); | 101 | put_vudc_device(udc_dev); |
94 | } | 102 | } |
95 | platform_driver_unregister(&vudc_driver); | 103 | platform_driver_unregister(&vudc_driver); |
diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c index 38884aac862b..a5734cbcd5ad 100644 --- a/drivers/usb/wusbcore/wa-rpipe.c +++ b/drivers/usb/wusbcore/wa-rpipe.c | |||
@@ -470,9 +470,7 @@ error: | |||
470 | int wa_rpipes_create(struct wahc *wa) | 470 | int wa_rpipes_create(struct wahc *wa) |
471 | { | 471 | { |
472 | wa->rpipes = le16_to_cpu(wa->wa_descr->wNumRPipes); | 472 | wa->rpipes = le16_to_cpu(wa->wa_descr->wNumRPipes); |
473 | wa->rpipe_bm = kcalloc(BITS_TO_LONGS(wa->rpipes), | 473 | wa->rpipe_bm = bitmap_zalloc(wa->rpipes, GFP_KERNEL); |
474 | sizeof(unsigned long), | ||
475 | GFP_KERNEL); | ||
476 | if (wa->rpipe_bm == NULL) | 474 | if (wa->rpipe_bm == NULL) |
477 | return -ENOMEM; | 475 | return -ENOMEM; |
478 | return 0; | 476 | return 0; |
@@ -487,7 +485,7 @@ void wa_rpipes_destroy(struct wahc *wa) | |||
487 | dev_err(dev, "BUG: pipes not released on exit: %*pb\n", | 485 | dev_err(dev, "BUG: pipes not released on exit: %*pb\n", |
488 | wa->rpipes, wa->rpipe_bm); | 486 | wa->rpipes, wa->rpipe_bm); |
489 | } | 487 | } |
490 | kfree(wa->rpipe_bm); | 488 | bitmap_free(wa->rpipe_bm); |
491 | } | 489 | } |
492 | 490 | ||
493 | /* | 491 | /* |
diff --git a/include/dt-bindings/usb/pd.h b/include/dt-bindings/usb/pd.h index 7b7a92fefa0a..985f2bbd4d24 100644 --- a/include/dt-bindings/usb/pd.h +++ b/include/dt-bindings/usb/pd.h | |||
@@ -59,4 +59,30 @@ | |||
59 | (PDO_TYPE(PDO_TYPE_VAR) | PDO_VAR_MIN_VOLT(min_mv) | \ | 59 | (PDO_TYPE(PDO_TYPE_VAR) | PDO_VAR_MIN_VOLT(min_mv) | \ |
60 | PDO_VAR_MAX_VOLT(max_mv) | PDO_VAR_MAX_CURR(max_ma)) | 60 | PDO_VAR_MAX_VOLT(max_mv) | PDO_VAR_MAX_CURR(max_ma)) |
61 | 61 | ||
62 | #define APDO_TYPE_PPS 0 | ||
63 | |||
64 | #define PDO_APDO_TYPE_SHIFT 28 /* Only valid value currently is 0x0 - PPS */ | ||
65 | #define PDO_APDO_TYPE_MASK 0x3 | ||
66 | |||
67 | #define PDO_APDO_TYPE(t) ((t) << PDO_APDO_TYPE_SHIFT) | ||
68 | |||
69 | #define PDO_PPS_APDO_MAX_VOLT_SHIFT 17 /* 100mV units */ | ||
70 | #define PDO_PPS_APDO_MIN_VOLT_SHIFT 8 /* 100mV units */ | ||
71 | #define PDO_PPS_APDO_MAX_CURR_SHIFT 0 /* 50mA units */ | ||
72 | |||
73 | #define PDO_PPS_APDO_VOLT_MASK 0xff | ||
74 | #define PDO_PPS_APDO_CURR_MASK 0x7f | ||
75 | |||
76 | #define PDO_PPS_APDO_MIN_VOLT(mv) \ | ||
77 | ((((mv) / 100) & PDO_PPS_APDO_VOLT_MASK) << PDO_PPS_APDO_MIN_VOLT_SHIFT) | ||
78 | #define PDO_PPS_APDO_MAX_VOLT(mv) \ | ||
79 | ((((mv) / 100) & PDO_PPS_APDO_VOLT_MASK) << PDO_PPS_APDO_MAX_VOLT_SHIFT) | ||
80 | #define PDO_PPS_APDO_MAX_CURR(ma) \ | ||
81 | ((((ma) / 50) & PDO_PPS_APDO_CURR_MASK) << PDO_PPS_APDO_MAX_CURR_SHIFT) | ||
82 | |||
83 | #define PDO_PPS_APDO(min_mv, max_mv, max_ma) \ | ||
84 | (PDO_TYPE(PDO_TYPE_APDO) | PDO_APDO_TYPE(APDO_TYPE_PPS) | \ | ||
85 | PDO_PPS_APDO_MIN_VOLT(min_mv) | PDO_PPS_APDO_MAX_VOLT(max_mv) | \ | ||
86 | PDO_PPS_APDO_MAX_CURR(max_ma)) | ||
87 | |||
62 | #endif /* __DT_POWER_DELIVERY_H */ | 88 | #endif /* __DT_POWER_DELIVERY_H */ |
diff --git a/include/linux/device.h b/include/linux/device.h index 983506789402..90224e75ade4 100644 --- a/include/linux/device.h +++ b/include/linux/device.h | |||
@@ -774,6 +774,30 @@ void device_connection_add(struct device_connection *con); | |||
774 | void device_connection_remove(struct device_connection *con); | 774 | void device_connection_remove(struct device_connection *con); |
775 | 775 | ||
776 | /** | 776 | /** |
777 | * device_connections_add - Add multiple device connections at once | ||
778 | * @cons: Zero terminated array of device connection descriptors | ||
779 | */ | ||
780 | static inline void device_connections_add(struct device_connection *cons) | ||
781 | { | ||
782 | struct device_connection *c; | ||
783 | |||
784 | for (c = cons; c->endpoint[0]; c++) | ||
785 | device_connection_add(c); | ||
786 | } | ||
787 | |||
788 | /** | ||
789 | * device_connections_remove - Remove multiple device connections at once | ||
790 | * @cons: Zero terminated array of device connection descriptors | ||
791 | */ | ||
792 | static inline void device_connections_remove(struct device_connection *cons) | ||
793 | { | ||
794 | struct device_connection *c; | ||
795 | |||
796 | for (c = cons; c->endpoint[0]; c++) | ||
797 | device_connection_remove(c); | ||
798 | } | ||
799 | |||
800 | /** | ||
777 | * enum device_link_state - Device link states. | 801 | * enum device_link_state - Device link states. |
778 | * @DL_STATE_NONE: The presence of the drivers is not being tracked. | 802 | * @DL_STATE_NONE: The presence of the drivers is not being tracked. |
779 | * @DL_STATE_DORMANT: None of the supplier/consumer drivers is present. | 803 | * @DL_STATE_DORMANT: None of the supplier/consumer drivers is present. |
diff --git a/include/linux/phy/phy-qcom-ufs.h b/include/linux/phy/phy-qcom-ufs.h deleted file mode 100644 index 0a2c18a9771d..000000000000 --- a/include/linux/phy/phy-qcom-ufs.h +++ /dev/null | |||
@@ -1,38 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 and | ||
6 | * only version 2 as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #ifndef PHY_QCOM_UFS_H_ | ||
16 | #define PHY_QCOM_UFS_H_ | ||
17 | |||
18 | #include "phy.h" | ||
19 | |||
20 | /** | ||
21 | * ufs_qcom_phy_enable_dev_ref_clk() - Enable the device | ||
22 | * ref clock. | ||
23 | * @phy: reference to a generic phy. | ||
24 | */ | ||
25 | void ufs_qcom_phy_enable_dev_ref_clk(struct phy *phy); | ||
26 | |||
27 | /** | ||
28 | * ufs_qcom_phy_disable_dev_ref_clk() - Disable the device | ||
29 | * ref clock. | ||
30 | * @phy: reference to a generic phy. | ||
31 | */ | ||
32 | void ufs_qcom_phy_disable_dev_ref_clk(struct phy *phy); | ||
33 | |||
34 | int ufs_qcom_phy_set_tx_lane_enable(struct phy *phy, u32 tx_lanes); | ||
35 | void ufs_qcom_phy_save_controller_version(struct phy *phy, | ||
36 | u8 major, u16 minor, u16 step); | ||
37 | |||
38 | #endif /* PHY_QCOM_UFS_H_ */ | ||
diff --git a/include/linux/platform_data/ehci-sh.h b/include/linux/platform_data/ehci-sh.h index 5c15a738e116..219bd79dabfc 100644 --- a/include/linux/platform_data/ehci-sh.h +++ b/include/linux/platform_data/ehci-sh.h | |||
@@ -1,21 +1,9 @@ | |||
1 | /* | 1 | /* SPDX-License-Identifier: GPL-2.0 |
2 | * | ||
2 | * EHCI SuperH driver platform data | 3 | * EHCI SuperH driver platform data |
3 | * | 4 | * |
4 | * Copyright (C) 2012 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com> | 5 | * Copyright (C) 2012 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com> |
5 | * Copyright (C) 2012 Renesas Solutions Corp. | 6 | * Copyright (C) 2012 Renesas Solutions Corp. |
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; version 2 of the License. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
19 | */ | 7 | */ |
20 | 8 | ||
21 | #ifndef __USB_EHCI_SH_H | 9 | #ifndef __USB_EHCI_SH_H |
diff --git a/include/linux/platform_data/mv_usb.h b/include/linux/platform_data/mv_usb.h index 98b7925f1a2d..c0f624aca81c 100644 --- a/include/linux/platform_data/mv_usb.h +++ b/include/linux/platform_data/mv_usb.h | |||
@@ -48,6 +48,5 @@ struct mv_usb_platform_data { | |||
48 | int (*phy_init)(void __iomem *regbase); | 48 | int (*phy_init)(void __iomem *regbase); |
49 | void (*phy_deinit)(void __iomem *regbase); | 49 | void (*phy_deinit)(void __iomem *regbase); |
50 | int (*set_vbus)(unsigned int vbus); | 50 | int (*set_vbus)(unsigned int vbus); |
51 | int (*private_init)(void __iomem *opregs, void __iomem *phyregs); | ||
52 | }; | 51 | }; |
53 | #endif | 52 | #endif |
diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index 07f99362bc90..63758c399e4e 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h | |||
@@ -77,6 +77,12 @@ struct ci_hdrc_platform_data { | |||
77 | struct ci_hdrc_cable vbus_extcon; | 77 | struct ci_hdrc_cable vbus_extcon; |
78 | struct ci_hdrc_cable id_extcon; | 78 | struct ci_hdrc_cable id_extcon; |
79 | u32 phy_clkgate_delay_us; | 79 | u32 phy_clkgate_delay_us; |
80 | |||
81 | /* pins */ | ||
82 | struct pinctrl *pctl; | ||
83 | struct pinctrl_state *pins_default; | ||
84 | struct pinctrl_state *pins_host; | ||
85 | struct pinctrl_state *pins_device; | ||
80 | }; | 86 | }; |
81 | 87 | ||
82 | /* Default offset of capability registers */ | 88 | /* Default offset of capability registers */ |
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h index 729af2f861a4..fdd4d88a7b95 100644 --- a/include/uapi/linux/usb/tmc.h +++ b/include/uapi/linux/usb/tmc.h | |||
@@ -4,6 +4,7 @@ | |||
4 | * Copyright (C) 2008 Novell, Inc. | 4 | * Copyright (C) 2008 Novell, Inc. |
5 | * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de> | 5 | * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de> |
6 | * Copyright (C) 2015 Dave Penkler <dpenkler@gmail.com> | 6 | * Copyright (C) 2015 Dave Penkler <dpenkler@gmail.com> |
7 | * Copyright (C) 2018 IVI Foundation, Inc. | ||
7 | * | 8 | * |
8 | * This file holds USB constants defined by the USB Device Class | 9 | * This file holds USB constants defined by the USB Device Class |
9 | * and USB488 Subclass Definitions for Test and Measurement devices | 10 | * and USB488 Subclass Definitions for Test and Measurement devices |
@@ -40,11 +41,38 @@ | |||
40 | #define USBTMC488_REQUEST_GOTO_LOCAL 161 | 41 | #define USBTMC488_REQUEST_GOTO_LOCAL 161 |
41 | #define USBTMC488_REQUEST_LOCAL_LOCKOUT 162 | 42 | #define USBTMC488_REQUEST_LOCAL_LOCKOUT 162 |
42 | 43 | ||
44 | struct usbtmc_request { | ||
45 | __u8 bRequestType; | ||
46 | __u8 bRequest; | ||
47 | __u16 wValue; | ||
48 | __u16 wIndex; | ||
49 | __u16 wLength; | ||
50 | } __attribute__ ((packed)); | ||
51 | |||
52 | struct usbtmc_ctrlrequest { | ||
53 | struct usbtmc_request req; | ||
54 | void __user *data; /* pointer to user space */ | ||
55 | } __attribute__ ((packed)); | ||
56 | |||
43 | struct usbtmc_termchar { | 57 | struct usbtmc_termchar { |
44 | __u8 term_char; | 58 | __u8 term_char; |
45 | __u8 term_char_enabled; | 59 | __u8 term_char_enabled; |
46 | } __attribute__ ((packed)); | 60 | } __attribute__ ((packed)); |
47 | 61 | ||
62 | /* | ||
63 | * usbtmc_message->flags: | ||
64 | */ | ||
65 | #define USBTMC_FLAG_ASYNC 0x0001 | ||
66 | #define USBTMC_FLAG_APPEND 0x0002 | ||
67 | #define USBTMC_FLAG_IGNORE_TRAILER 0x0004 | ||
68 | |||
69 | struct usbtmc_message { | ||
70 | __u32 transfer_size; /* size of bytes to transfer */ | ||
71 | __u32 transferred; /* size of received/written bytes */ | ||
72 | __u32 flags; /* bit 0: 0 = synchronous; 1 = asynchronous */ | ||
73 | void __user *message; /* pointer to header and data in user space */ | ||
74 | } __attribute__ ((packed)); | ||
75 | |||
48 | /* Request values for USBTMC driver's ioctl entry point */ | 76 | /* Request values for USBTMC driver's ioctl entry point */ |
49 | #define USBTMC_IOC_NR 91 | 77 | #define USBTMC_IOC_NR 91 |
50 | #define USBTMC_IOCTL_INDICATOR_PULSE _IO(USBTMC_IOC_NR, 1) | 78 | #define USBTMC_IOCTL_INDICATOR_PULSE _IO(USBTMC_IOC_NR, 1) |
@@ -53,10 +81,15 @@ struct usbtmc_termchar { | |||
53 | #define USBTMC_IOCTL_ABORT_BULK_IN _IO(USBTMC_IOC_NR, 4) | 81 | #define USBTMC_IOCTL_ABORT_BULK_IN _IO(USBTMC_IOC_NR, 4) |
54 | #define USBTMC_IOCTL_CLEAR_OUT_HALT _IO(USBTMC_IOC_NR, 6) | 82 | #define USBTMC_IOCTL_CLEAR_OUT_HALT _IO(USBTMC_IOC_NR, 6) |
55 | #define USBTMC_IOCTL_CLEAR_IN_HALT _IO(USBTMC_IOC_NR, 7) | 83 | #define USBTMC_IOCTL_CLEAR_IN_HALT _IO(USBTMC_IOC_NR, 7) |
84 | #define USBTMC_IOCTL_CTRL_REQUEST _IOWR(USBTMC_IOC_NR, 8, struct usbtmc_ctrlrequest) | ||
56 | #define USBTMC_IOCTL_GET_TIMEOUT _IOR(USBTMC_IOC_NR, 9, __u32) | 85 | #define USBTMC_IOCTL_GET_TIMEOUT _IOR(USBTMC_IOC_NR, 9, __u32) |
57 | #define USBTMC_IOCTL_SET_TIMEOUT _IOW(USBTMC_IOC_NR, 10, __u32) | 86 | #define USBTMC_IOCTL_SET_TIMEOUT _IOW(USBTMC_IOC_NR, 10, __u32) |
58 | #define USBTMC_IOCTL_EOM_ENABLE _IOW(USBTMC_IOC_NR, 11, __u8) | 87 | #define USBTMC_IOCTL_EOM_ENABLE _IOW(USBTMC_IOC_NR, 11, __u8) |
59 | #define USBTMC_IOCTL_CONFIG_TERMCHAR _IOW(USBTMC_IOC_NR, 12, struct usbtmc_termchar) | 88 | #define USBTMC_IOCTL_CONFIG_TERMCHAR _IOW(USBTMC_IOC_NR, 12, struct usbtmc_termchar) |
89 | #define USBTMC_IOCTL_WRITE _IOWR(USBTMC_IOC_NR, 13, struct usbtmc_message) | ||
90 | #define USBTMC_IOCTL_READ _IOWR(USBTMC_IOC_NR, 14, struct usbtmc_message) | ||
91 | #define USBTMC_IOCTL_WRITE_RESULT _IOWR(USBTMC_IOC_NR, 15, __u32) | ||
92 | #define USBTMC_IOCTL_API_VERSION _IOR(USBTMC_IOC_NR, 16, __u32) | ||
60 | 93 | ||
61 | #define USBTMC488_IOCTL_GET_CAPS _IOR(USBTMC_IOC_NR, 17, unsigned char) | 94 | #define USBTMC488_IOCTL_GET_CAPS _IOR(USBTMC_IOC_NR, 17, unsigned char) |
62 | #define USBTMC488_IOCTL_READ_STB _IOR(USBTMC_IOC_NR, 18, unsigned char) | 95 | #define USBTMC488_IOCTL_READ_STB _IOR(USBTMC_IOC_NR, 18, unsigned char) |
@@ -64,6 +97,14 @@ struct usbtmc_termchar { | |||
64 | #define USBTMC488_IOCTL_GOTO_LOCAL _IO(USBTMC_IOC_NR, 20) | 97 | #define USBTMC488_IOCTL_GOTO_LOCAL _IO(USBTMC_IOC_NR, 20) |
65 | #define USBTMC488_IOCTL_LOCAL_LOCKOUT _IO(USBTMC_IOC_NR, 21) | 98 | #define USBTMC488_IOCTL_LOCAL_LOCKOUT _IO(USBTMC_IOC_NR, 21) |
66 | #define USBTMC488_IOCTL_TRIGGER _IO(USBTMC_IOC_NR, 22) | 99 | #define USBTMC488_IOCTL_TRIGGER _IO(USBTMC_IOC_NR, 22) |
100 | #define USBTMC488_IOCTL_WAIT_SRQ _IOW(USBTMC_IOC_NR, 23, __u32) | ||
101 | |||
102 | #define USBTMC_IOCTL_MSG_IN_ATTR _IOR(USBTMC_IOC_NR, 24, __u8) | ||
103 | #define USBTMC_IOCTL_AUTO_ABORT _IOW(USBTMC_IOC_NR, 25, __u8) | ||
104 | |||
105 | /* Cancel and cleanup asynchronous calls */ | ||
106 | #define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35) | ||
107 | #define USBTMC_IOCTL_CLEANUP_IO _IO(USBTMC_IOC_NR, 36) | ||
67 | 108 | ||
68 | /* Driver encoded usb488 capabilities */ | 109 | /* Driver encoded usb488 capabilities */ |
69 | #define USBTMC488_CAPABILITY_TRIGGER 1 | 110 | #define USBTMC488_CAPABILITY_TRIGGER 1 |
diff --git a/include/uapi/linux/usb/video.h b/include/uapi/linux/usb/video.h index ff6cc6cb4227..d854cb19c42c 100644 --- a/include/uapi/linux/usb/video.h +++ b/include/uapi/linux/usb/video.h | |||
@@ -192,14 +192,14 @@ struct uvc_descriptor_header { | |||
192 | 192 | ||
193 | /* 3.7.2. Video Control Interface Header Descriptor */ | 193 | /* 3.7.2. Video Control Interface Header Descriptor */ |
194 | struct uvc_header_descriptor { | 194 | struct uvc_header_descriptor { |
195 | __u8 bLength; | 195 | __u8 bLength; |
196 | __u8 bDescriptorType; | 196 | __u8 bDescriptorType; |
197 | __u8 bDescriptorSubType; | 197 | __u8 bDescriptorSubType; |
198 | __u16 bcdUVC; | 198 | __le16 bcdUVC; |
199 | __u16 wTotalLength; | 199 | __le16 wTotalLength; |
200 | __u32 dwClockFrequency; | 200 | __le32 dwClockFrequency; |
201 | __u8 bInCollection; | 201 | __u8 bInCollection; |
202 | __u8 baInterfaceNr[]; | 202 | __u8 baInterfaceNr[]; |
203 | } __attribute__((__packed__)); | 203 | } __attribute__((__packed__)); |
204 | 204 | ||
205 | #define UVC_DT_HEADER_SIZE(n) (12+(n)) | 205 | #define UVC_DT_HEADER_SIZE(n) (12+(n)) |
@@ -209,57 +209,57 @@ struct uvc_header_descriptor { | |||
209 | 209 | ||
210 | #define DECLARE_UVC_HEADER_DESCRIPTOR(n) \ | 210 | #define DECLARE_UVC_HEADER_DESCRIPTOR(n) \ |
211 | struct UVC_HEADER_DESCRIPTOR(n) { \ | 211 | struct UVC_HEADER_DESCRIPTOR(n) { \ |
212 | __u8 bLength; \ | 212 | __u8 bLength; \ |
213 | __u8 bDescriptorType; \ | 213 | __u8 bDescriptorType; \ |
214 | __u8 bDescriptorSubType; \ | 214 | __u8 bDescriptorSubType; \ |
215 | __u16 bcdUVC; \ | 215 | __le16 bcdUVC; \ |
216 | __u16 wTotalLength; \ | 216 | __le16 wTotalLength; \ |
217 | __u32 dwClockFrequency; \ | 217 | __le32 dwClockFrequency; \ |
218 | __u8 bInCollection; \ | 218 | __u8 bInCollection; \ |
219 | __u8 baInterfaceNr[n]; \ | 219 | __u8 baInterfaceNr[n]; \ |
220 | } __attribute__ ((packed)) | 220 | } __attribute__ ((packed)) |
221 | 221 | ||
222 | /* 3.7.2.1. Input Terminal Descriptor */ | 222 | /* 3.7.2.1. Input Terminal Descriptor */ |
223 | struct uvc_input_terminal_descriptor { | 223 | struct uvc_input_terminal_descriptor { |
224 | __u8 bLength; | 224 | __u8 bLength; |
225 | __u8 bDescriptorType; | 225 | __u8 bDescriptorType; |
226 | __u8 bDescriptorSubType; | 226 | __u8 bDescriptorSubType; |
227 | __u8 bTerminalID; | 227 | __u8 bTerminalID; |
228 | __u16 wTerminalType; | 228 | __le16 wTerminalType; |
229 | __u8 bAssocTerminal; | 229 | __u8 bAssocTerminal; |
230 | __u8 iTerminal; | 230 | __u8 iTerminal; |
231 | } __attribute__((__packed__)); | 231 | } __attribute__((__packed__)); |
232 | 232 | ||
233 | #define UVC_DT_INPUT_TERMINAL_SIZE 8 | 233 | #define UVC_DT_INPUT_TERMINAL_SIZE 8 |
234 | 234 | ||
235 | /* 3.7.2.2. Output Terminal Descriptor */ | 235 | /* 3.7.2.2. Output Terminal Descriptor */ |
236 | struct uvc_output_terminal_descriptor { | 236 | struct uvc_output_terminal_descriptor { |
237 | __u8 bLength; | 237 | __u8 bLength; |
238 | __u8 bDescriptorType; | 238 | __u8 bDescriptorType; |
239 | __u8 bDescriptorSubType; | 239 | __u8 bDescriptorSubType; |
240 | __u8 bTerminalID; | 240 | __u8 bTerminalID; |
241 | __u16 wTerminalType; | 241 | __le16 wTerminalType; |
242 | __u8 bAssocTerminal; | 242 | __u8 bAssocTerminal; |
243 | __u8 bSourceID; | 243 | __u8 bSourceID; |
244 | __u8 iTerminal; | 244 | __u8 iTerminal; |
245 | } __attribute__((__packed__)); | 245 | } __attribute__((__packed__)); |
246 | 246 | ||
247 | #define UVC_DT_OUTPUT_TERMINAL_SIZE 9 | 247 | #define UVC_DT_OUTPUT_TERMINAL_SIZE 9 |
248 | 248 | ||
249 | /* 3.7.2.3. Camera Terminal Descriptor */ | 249 | /* 3.7.2.3. Camera Terminal Descriptor */ |
250 | struct uvc_camera_terminal_descriptor { | 250 | struct uvc_camera_terminal_descriptor { |
251 | __u8 bLength; | 251 | __u8 bLength; |
252 | __u8 bDescriptorType; | 252 | __u8 bDescriptorType; |
253 | __u8 bDescriptorSubType; | 253 | __u8 bDescriptorSubType; |
254 | __u8 bTerminalID; | 254 | __u8 bTerminalID; |
255 | __u16 wTerminalType; | 255 | __le16 wTerminalType; |
256 | __u8 bAssocTerminal; | 256 | __u8 bAssocTerminal; |
257 | __u8 iTerminal; | 257 | __u8 iTerminal; |
258 | __u16 wObjectiveFocalLengthMin; | 258 | __le16 wObjectiveFocalLengthMin; |
259 | __u16 wObjectiveFocalLengthMax; | 259 | __le16 wObjectiveFocalLengthMax; |
260 | __u16 wOcularFocalLength; | 260 | __le16 wOcularFocalLength; |
261 | __u8 bControlSize; | 261 | __u8 bControlSize; |
262 | __u8 bmControls[3]; | 262 | __u8 bmControls[3]; |
263 | } __attribute__((__packed__)); | 263 | } __attribute__((__packed__)); |
264 | 264 | ||
265 | #define UVC_DT_CAMERA_TERMINAL_SIZE(n) (15+(n)) | 265 | #define UVC_DT_CAMERA_TERMINAL_SIZE(n) (15+(n)) |
@@ -293,15 +293,15 @@ struct UVC_SELECTOR_UNIT_DESCRIPTOR(n) { \ | |||
293 | 293 | ||
294 | /* 3.7.2.5. Processing Unit Descriptor */ | 294 | /* 3.7.2.5. Processing Unit Descriptor */ |
295 | struct uvc_processing_unit_descriptor { | 295 | struct uvc_processing_unit_descriptor { |
296 | __u8 bLength; | 296 | __u8 bLength; |
297 | __u8 bDescriptorType; | 297 | __u8 bDescriptorType; |
298 | __u8 bDescriptorSubType; | 298 | __u8 bDescriptorSubType; |
299 | __u8 bUnitID; | 299 | __u8 bUnitID; |
300 | __u8 bSourceID; | 300 | __u8 bSourceID; |
301 | __u16 wMaxMultiplier; | 301 | __le16 wMaxMultiplier; |
302 | __u8 bControlSize; | 302 | __u8 bControlSize; |
303 | __u8 bmControls[2]; | 303 | __u8 bmControls[2]; |
304 | __u8 iProcessing; | 304 | __u8 iProcessing; |
305 | } __attribute__((__packed__)); | 305 | } __attribute__((__packed__)); |
306 | 306 | ||
307 | #define UVC_DT_PROCESSING_UNIT_SIZE(n) (9+(n)) | 307 | #define UVC_DT_PROCESSING_UNIT_SIZE(n) (9+(n)) |
@@ -343,29 +343,29 @@ struct UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) { \ | |||
343 | 343 | ||
344 | /* 3.8.2.2. Video Control Interrupt Endpoint Descriptor */ | 344 | /* 3.8.2.2. Video Control Interrupt Endpoint Descriptor */ |
345 | struct uvc_control_endpoint_descriptor { | 345 | struct uvc_control_endpoint_descriptor { |
346 | __u8 bLength; | 346 | __u8 bLength; |
347 | __u8 bDescriptorType; | 347 | __u8 bDescriptorType; |
348 | __u8 bDescriptorSubType; | 348 | __u8 bDescriptorSubType; |
349 | __u16 wMaxTransferSize; | 349 | __le16 wMaxTransferSize; |
350 | } __attribute__((__packed__)); | 350 | } __attribute__((__packed__)); |
351 | 351 | ||
352 | #define UVC_DT_CONTROL_ENDPOINT_SIZE 5 | 352 | #define UVC_DT_CONTROL_ENDPOINT_SIZE 5 |
353 | 353 | ||
354 | /* 3.9.2.1. Input Header Descriptor */ | 354 | /* 3.9.2.1. Input Header Descriptor */ |
355 | struct uvc_input_header_descriptor { | 355 | struct uvc_input_header_descriptor { |
356 | __u8 bLength; | 356 | __u8 bLength; |
357 | __u8 bDescriptorType; | 357 | __u8 bDescriptorType; |
358 | __u8 bDescriptorSubType; | 358 | __u8 bDescriptorSubType; |
359 | __u8 bNumFormats; | 359 | __u8 bNumFormats; |
360 | __u16 wTotalLength; | 360 | __le16 wTotalLength; |
361 | __u8 bEndpointAddress; | 361 | __u8 bEndpointAddress; |
362 | __u8 bmInfo; | 362 | __u8 bmInfo; |
363 | __u8 bTerminalLink; | 363 | __u8 bTerminalLink; |
364 | __u8 bStillCaptureMethod; | 364 | __u8 bStillCaptureMethod; |
365 | __u8 bTriggerSupport; | 365 | __u8 bTriggerSupport; |
366 | __u8 bTriggerUsage; | 366 | __u8 bTriggerUsage; |
367 | __u8 bControlSize; | 367 | __u8 bControlSize; |
368 | __u8 bmaControls[]; | 368 | __u8 bmaControls[]; |
369 | } __attribute__((__packed__)); | 369 | } __attribute__((__packed__)); |
370 | 370 | ||
371 | #define UVC_DT_INPUT_HEADER_SIZE(n, p) (13+(n*p)) | 371 | #define UVC_DT_INPUT_HEADER_SIZE(n, p) (13+(n*p)) |
@@ -375,32 +375,32 @@ struct uvc_input_header_descriptor { | |||
375 | 375 | ||
376 | #define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n, p) \ | 376 | #define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n, p) \ |
377 | struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) { \ | 377 | struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) { \ |
378 | __u8 bLength; \ | 378 | __u8 bLength; \ |
379 | __u8 bDescriptorType; \ | 379 | __u8 bDescriptorType; \ |
380 | __u8 bDescriptorSubType; \ | 380 | __u8 bDescriptorSubType; \ |
381 | __u8 bNumFormats; \ | 381 | __u8 bNumFormats; \ |
382 | __u16 wTotalLength; \ | 382 | __le16 wTotalLength; \ |
383 | __u8 bEndpointAddress; \ | 383 | __u8 bEndpointAddress; \ |
384 | __u8 bmInfo; \ | 384 | __u8 bmInfo; \ |
385 | __u8 bTerminalLink; \ | 385 | __u8 bTerminalLink; \ |
386 | __u8 bStillCaptureMethod; \ | 386 | __u8 bStillCaptureMethod; \ |
387 | __u8 bTriggerSupport; \ | 387 | __u8 bTriggerSupport; \ |
388 | __u8 bTriggerUsage; \ | 388 | __u8 bTriggerUsage; \ |
389 | __u8 bControlSize; \ | 389 | __u8 bControlSize; \ |
390 | __u8 bmaControls[p][n]; \ | 390 | __u8 bmaControls[p][n]; \ |
391 | } __attribute__ ((packed)) | 391 | } __attribute__ ((packed)) |
392 | 392 | ||
393 | /* 3.9.2.2. Output Header Descriptor */ | 393 | /* 3.9.2.2. Output Header Descriptor */ |
394 | struct uvc_output_header_descriptor { | 394 | struct uvc_output_header_descriptor { |
395 | __u8 bLength; | 395 | __u8 bLength; |
396 | __u8 bDescriptorType; | 396 | __u8 bDescriptorType; |
397 | __u8 bDescriptorSubType; | 397 | __u8 bDescriptorSubType; |
398 | __u8 bNumFormats; | 398 | __u8 bNumFormats; |
399 | __u16 wTotalLength; | 399 | __le16 wTotalLength; |
400 | __u8 bEndpointAddress; | 400 | __u8 bEndpointAddress; |
401 | __u8 bTerminalLink; | 401 | __u8 bTerminalLink; |
402 | __u8 bControlSize; | 402 | __u8 bControlSize; |
403 | __u8 bmaControls[]; | 403 | __u8 bmaControls[]; |
404 | } __attribute__((__packed__)); | 404 | } __attribute__((__packed__)); |
405 | 405 | ||
406 | #define UVC_DT_OUTPUT_HEADER_SIZE(n, p) (9+(n*p)) | 406 | #define UVC_DT_OUTPUT_HEADER_SIZE(n, p) (9+(n*p)) |
@@ -410,15 +410,15 @@ struct uvc_output_header_descriptor { | |||
410 | 410 | ||
411 | #define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \ | 411 | #define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \ |
412 | struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) { \ | 412 | struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) { \ |
413 | __u8 bLength; \ | 413 | __u8 bLength; \ |
414 | __u8 bDescriptorType; \ | 414 | __u8 bDescriptorType; \ |
415 | __u8 bDescriptorSubType; \ | 415 | __u8 bDescriptorSubType; \ |
416 | __u8 bNumFormats; \ | 416 | __u8 bNumFormats; \ |
417 | __u16 wTotalLength; \ | 417 | __le16 wTotalLength; \ |
418 | __u8 bEndpointAddress; \ | 418 | __u8 bEndpointAddress; \ |
419 | __u8 bTerminalLink; \ | 419 | __u8 bTerminalLink; \ |
420 | __u8 bControlSize; \ | 420 | __u8 bControlSize; \ |
421 | __u8 bmaControls[p][n]; \ | 421 | __u8 bmaControls[p][n]; \ |
422 | } __attribute__ ((packed)) | 422 | } __attribute__ ((packed)) |
423 | 423 | ||
424 | /* 3.9.2.6. Color matching descriptor */ | 424 | /* 3.9.2.6. Color matching descriptor */ |
@@ -473,19 +473,19 @@ struct uvc_format_uncompressed { | |||
473 | 473 | ||
474 | /* Uncompressed Payload - 3.1.2. Uncompressed Video Frame Descriptor */ | 474 | /* Uncompressed Payload - 3.1.2. Uncompressed Video Frame Descriptor */ |
475 | struct uvc_frame_uncompressed { | 475 | struct uvc_frame_uncompressed { |
476 | __u8 bLength; | 476 | __u8 bLength; |
477 | __u8 bDescriptorType; | 477 | __u8 bDescriptorType; |
478 | __u8 bDescriptorSubType; | 478 | __u8 bDescriptorSubType; |
479 | __u8 bFrameIndex; | 479 | __u8 bFrameIndex; |
480 | __u8 bmCapabilities; | 480 | __u8 bmCapabilities; |
481 | __u16 wWidth; | 481 | __le16 wWidth; |
482 | __u16 wHeight; | 482 | __le16 wHeight; |
483 | __u32 dwMinBitRate; | 483 | __le32 dwMinBitRate; |
484 | __u32 dwMaxBitRate; | 484 | __le32 dwMaxBitRate; |
485 | __u32 dwMaxVideoFrameBufferSize; | 485 | __le32 dwMaxVideoFrameBufferSize; |
486 | __u32 dwDefaultFrameInterval; | 486 | __le32 dwDefaultFrameInterval; |
487 | __u8 bFrameIntervalType; | 487 | __u8 bFrameIntervalType; |
488 | __u32 dwFrameInterval[]; | 488 | __le32 dwFrameInterval[]; |
489 | } __attribute__((__packed__)); | 489 | } __attribute__((__packed__)); |
490 | 490 | ||
491 | #define UVC_DT_FRAME_UNCOMPRESSED_SIZE(n) (26+4*(n)) | 491 | #define UVC_DT_FRAME_UNCOMPRESSED_SIZE(n) (26+4*(n)) |
@@ -495,19 +495,19 @@ struct uvc_frame_uncompressed { | |||
495 | 495 | ||
496 | #define DECLARE_UVC_FRAME_UNCOMPRESSED(n) \ | 496 | #define DECLARE_UVC_FRAME_UNCOMPRESSED(n) \ |
497 | struct UVC_FRAME_UNCOMPRESSED(n) { \ | 497 | struct UVC_FRAME_UNCOMPRESSED(n) { \ |
498 | __u8 bLength; \ | 498 | __u8 bLength; \ |
499 | __u8 bDescriptorType; \ | 499 | __u8 bDescriptorType; \ |
500 | __u8 bDescriptorSubType; \ | 500 | __u8 bDescriptorSubType; \ |
501 | __u8 bFrameIndex; \ | 501 | __u8 bFrameIndex; \ |
502 | __u8 bmCapabilities; \ | 502 | __u8 bmCapabilities; \ |
503 | __u16 wWidth; \ | 503 | __le16 wWidth; \ |
504 | __u16 wHeight; \ | 504 | __le16 wHeight; \ |
505 | __u32 dwMinBitRate; \ | 505 | __le32 dwMinBitRate; \ |
506 | __u32 dwMaxBitRate; \ | 506 | __le32 dwMaxBitRate; \ |
507 | __u32 dwMaxVideoFrameBufferSize; \ | 507 | __le32 dwMaxVideoFrameBufferSize; \ |
508 | __u32 dwDefaultFrameInterval; \ | 508 | __le32 dwDefaultFrameInterval; \ |
509 | __u8 bFrameIntervalType; \ | 509 | __u8 bFrameIntervalType; \ |
510 | __u32 dwFrameInterval[n]; \ | 510 | __le32 dwFrameInterval[n]; \ |
511 | } __attribute__ ((packed)) | 511 | } __attribute__ ((packed)) |
512 | 512 | ||
513 | /* MJPEG Payload - 3.1.1. MJPEG Video Format Descriptor */ | 513 | /* MJPEG Payload - 3.1.1. MJPEG Video Format Descriptor */ |
@@ -529,19 +529,19 @@ struct uvc_format_mjpeg { | |||
529 | 529 | ||
530 | /* MJPEG Payload - 3.1.2. MJPEG Video Frame Descriptor */ | 530 | /* MJPEG Payload - 3.1.2. MJPEG Video Frame Descriptor */ |
531 | struct uvc_frame_mjpeg { | 531 | struct uvc_frame_mjpeg { |
532 | __u8 bLength; | 532 | __u8 bLength; |
533 | __u8 bDescriptorType; | 533 | __u8 bDescriptorType; |
534 | __u8 bDescriptorSubType; | 534 | __u8 bDescriptorSubType; |
535 | __u8 bFrameIndex; | 535 | __u8 bFrameIndex; |
536 | __u8 bmCapabilities; | 536 | __u8 bmCapabilities; |
537 | __u16 wWidth; | 537 | __le16 wWidth; |
538 | __u16 wHeight; | 538 | __le16 wHeight; |
539 | __u32 dwMinBitRate; | 539 | __le32 dwMinBitRate; |
540 | __u32 dwMaxBitRate; | 540 | __le32 dwMaxBitRate; |
541 | __u32 dwMaxVideoFrameBufferSize; | 541 | __le32 dwMaxVideoFrameBufferSize; |
542 | __u32 dwDefaultFrameInterval; | 542 | __le32 dwDefaultFrameInterval; |
543 | __u8 bFrameIntervalType; | 543 | __u8 bFrameIntervalType; |
544 | __u32 dwFrameInterval[]; | 544 | __le32 dwFrameInterval[]; |
545 | } __attribute__((__packed__)); | 545 | } __attribute__((__packed__)); |
546 | 546 | ||
547 | #define UVC_DT_FRAME_MJPEG_SIZE(n) (26+4*(n)) | 547 | #define UVC_DT_FRAME_MJPEG_SIZE(n) (26+4*(n)) |
@@ -551,19 +551,19 @@ struct uvc_frame_mjpeg { | |||
551 | 551 | ||
552 | #define DECLARE_UVC_FRAME_MJPEG(n) \ | 552 | #define DECLARE_UVC_FRAME_MJPEG(n) \ |
553 | struct UVC_FRAME_MJPEG(n) { \ | 553 | struct UVC_FRAME_MJPEG(n) { \ |
554 | __u8 bLength; \ | 554 | __u8 bLength; \ |
555 | __u8 bDescriptorType; \ | 555 | __u8 bDescriptorType; \ |
556 | __u8 bDescriptorSubType; \ | 556 | __u8 bDescriptorSubType; \ |
557 | __u8 bFrameIndex; \ | 557 | __u8 bFrameIndex; \ |
558 | __u8 bmCapabilities; \ | 558 | __u8 bmCapabilities; \ |
559 | __u16 wWidth; \ | 559 | __le16 wWidth; \ |
560 | __u16 wHeight; \ | 560 | __le16 wHeight; \ |
561 | __u32 dwMinBitRate; \ | 561 | __le32 dwMinBitRate; \ |
562 | __u32 dwMaxBitRate; \ | 562 | __le32 dwMaxBitRate; \ |
563 | __u32 dwMaxVideoFrameBufferSize; \ | 563 | __le32 dwMaxVideoFrameBufferSize; \ |
564 | __u32 dwDefaultFrameInterval; \ | 564 | __le32 dwDefaultFrameInterval; \ |
565 | __u8 bFrameIntervalType; \ | 565 | __u8 bFrameIntervalType; \ |
566 | __u32 dwFrameInterval[n]; \ | 566 | __le32 dwFrameInterval[n]; \ |
567 | } __attribute__ ((packed)) | 567 | } __attribute__ ((packed)) |
568 | 568 | ||
569 | #endif /* __LINUX_USB_VIDEO_H */ | 569 | #endif /* __LINUX_USB_VIDEO_H */ |
diff --git a/tools/usb/usbip/libsrc/usbip_host_common.c b/tools/usb/usbip/libsrc/usbip_host_common.c index dc93fadbee96..d79c7581b175 100644 --- a/tools/usb/usbip/libsrc/usbip_host_common.c +++ b/tools/usb/usbip/libsrc/usbip_host_common.c | |||
@@ -43,7 +43,7 @@ static int32_t read_attr_usbip_status(struct usbip_usb_device *udev) | |||
43 | int size; | 43 | int size; |
44 | int fd; | 44 | int fd; |
45 | int length; | 45 | int length; |
46 | char status; | 46 | char status[2] = { 0 }; |
47 | int value = 0; | 47 | int value = 0; |
48 | 48 | ||
49 | size = snprintf(status_attr_path, sizeof(status_attr_path), | 49 | size = snprintf(status_attr_path, sizeof(status_attr_path), |
@@ -61,14 +61,14 @@ static int32_t read_attr_usbip_status(struct usbip_usb_device *udev) | |||
61 | return -1; | 61 | return -1; |
62 | } | 62 | } |
63 | 63 | ||
64 | length = read(fd, &status, 1); | 64 | length = read(fd, status, 1); |
65 | if (length < 0) { | 65 | if (length < 0) { |
66 | err("error reading attribute %s", status_attr_path); | 66 | err("error reading attribute %s", status_attr_path); |
67 | close(fd); | 67 | close(fd); |
68 | return -1; | 68 | return -1; |
69 | } | 69 | } |
70 | 70 | ||
71 | value = atoi(&status); | 71 | value = atoi(status); |
72 | 72 | ||
73 | return value; | 73 | return value; |
74 | } | 74 | } |
diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c index 4204359c9fee..8159fd98680b 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.c +++ b/tools/usb/usbip/libsrc/vhci_driver.c | |||
@@ -150,7 +150,7 @@ static int get_nports(struct udev_device *hc_device) | |||
150 | 150 | ||
151 | static int vhci_hcd_filter(const struct dirent *dirent) | 151 | static int vhci_hcd_filter(const struct dirent *dirent) |
152 | { | 152 | { |
153 | return strcmp(dirent->d_name, "vhci_hcd") >= 0; | 153 | return !strncmp(dirent->d_name, "vhci_hcd.", 9); |
154 | } | 154 | } |
155 | 155 | ||
156 | static int get_ncontrollers(void) | 156 | static int get_ncontrollers(void) |