提交 03f8d4cc 编写于 作者: L Linus Torvalds

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

Pull USB/PHY updates from Greg KH:
 "Here's the big set of USB/PHY patches for 4.10-rc1.

  A number of new drivers are here in this set of changes. We have a new
  USB controller type "mtu3", a new usb-serial driver, and the usual
  churn in the gadget subsystem and the xhci host controller driver,
  along with a few other new small drivers added. And lots of little
  other changes all over the USB and PHY driver tree. Full details are
  in the shortlog

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

* tag 'usb-4.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (309 commits)
  USB: serial: option: add dlink dwm-158
  USB: serial: option: add support for Telit LE922A PIDs 0x1040, 0x1041
  USB: OHCI: nxp: fix code warnings
  USB: OHCI: nxp: remove useless extern declaration
  USB: OHCI: at91: remove useless extern declaration
  usb: misc: rio500: fix result type for error message
  usb: mtu3: fix U3 port link issue
  usb: mtu3: enable auto switch from U3 to U2
  usbip: fix warning in vhci_hcd_probe/lockdep_init_map
  usb: core: usbport: Use proper LED API to fix potential crash
  usbip: add missing compile time generated files to .gitignore
  usb: hcd.h: construct hub class request constants from simpler constants
  USB: OHCI: ohci-pxa27x: remove useless functions
  USB: OHCI: omap: remove useless extern declaration
  USB: OHCI: ohci-omap: remove useless functions
  USB: OHCI: ohci-s3c2410: remove useless functions
  USB: cdc-acm: add device id for GW Instek AFG-125
  fsl/usb: Workarourd for USB erratum-A005697
  usb: hub: Wait for connection to be reestablished after port reset
  usbip: vudc: Refactor init_vudc_hw() to be more obvious
  ...
...@@ -8,3 +8,17 @@ Description: ...@@ -8,3 +8,17 @@ Description:
Any device associated with a device-tree node will have Any device associated with a device-tree node will have
an of_path symlink pointing to the corresponding device an of_path symlink pointing to the corresponding device
node in /sys/firmware/devicetree/ node in /sys/firmware/devicetree/
What: /sys/devices/*/devspec
Date: October 2016
Contact: Device Tree mailing list <devicetree@vger.kernel.org>
Description:
If CONFIG_OF is enabled, then this file is present. When
read, it returns full name of the device node.
What: /sys/devices/*/obppath
Date: October 2016
Contact: Device Tree mailing list <devicetree@vger.kernel.org>
Description:
If CONFIG_OF is enabled, then this file is present. When
read, it returns full name of the device node.
What: /sys/devices/platform/<phy-name>/role
Date: October 2016
KernelVersion: 4.10
Contact: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Description:
This file can be read and write.
The file can show/change the phy mode for role swap of usb.
Write the following strings to change the mode:
"host" - switching mode from peripheral to host.
"peripheral" - switching mode from host to peripheral.
Read the file, then it shows the following strings:
"host" - The mode is host now.
"peripheral" - The mode is peripheral now.
...@@ -5,7 +5,10 @@ connected to a GPIO pin. ...@@ -5,7 +5,10 @@ connected to a GPIO pin.
Required properties: Required properties:
- compatible: Should be "linux,extcon-usb-gpio" - compatible: Should be "linux,extcon-usb-gpio"
Either one of id-gpio or vbus-gpio must be present. Both can be present as well.
- id-gpio: gpio for USB ID pin. See gpio binding. - id-gpio: gpio for USB ID pin. See gpio binding.
- vbus-gpio: gpio for USB VBUS pin.
Example: Examples of extcon-usb-gpio node in dra7-evm.dts as listed below: Example: Examples of extcon-usb-gpio node in dra7-evm.dts as listed below:
extcon_usb1 { extcon_usb1 {
......
* Amlogic USB2 PHY * Amlogic Meson8b and GXBB USB2 PHY
Required properties: Required properties:
- compatible: Depending on the platform this should be one of: - compatible: Depending on the platform this should be one of:
...@@ -16,10 +16,10 @@ Optional properties: ...@@ -16,10 +16,10 @@ Optional properties:
Example: Example:
usb0_phy: usb_phy@0 { usb0_phy: usb-phy@c0000000 {
compatible = "amlogic,meson-gxbb-usb2-phy"; compatible = "amlogic,meson-gxbb-usb2-phy";
#phy-cells = <0>; #phy-cells = <0>;
reg = <0x0 0x0 0x0 0x20>; reg = <0x0 0xc0000000 0x0 0x20>;
resets = <&reset RESET_USB_OTG>; resets = <&reset RESET_USB_OTG>;
clocks = <&clkc CLKID_USB>, <&clkc CLKID_USB0>; clocks = <&clkc CLKID_USB>, <&clkc CLKID_USB0>;
clock-names = "usb_general", "usb"; clock-names = "usb_general", "usb";
......
TI DA8xx MUSB
~~~~~~~~~~~~~
For DA8xx/OMAP-L1x/AM17xx/AM18xx platforms.
Required properties:
~~~~~~~~~~~~~~~~~~~~
- compatible : Should be set to "ti,da830-musb".
- reg: Offset and length of the USB controller register set.
- interrupts: The USB interrupt number.
- interrupt-names: Should be set to "mc".
- dr_mode: The USB operation mode. Should be one of "host", "peripheral" or "otg".
- phys: Phandle for the PHY device
- phy-names: Should be "usb-phy"
Optional properties:
~~~~~~~~~~~~~~~~~~~~
- vbus-supply: Phandle to a regulator providing the USB bus power.
Example:
usb_phy: usb-phy {
compatible = "ti,da830-usb-phy";
#phy-cells = <0>;
status = "okay";
};
usb0: usb@200000 {
compatible = "ti,da830-musb";
reg = <0x00200000 0x10000>;
interrupts = <58>;
interrupt-names = "mc";
dr_mode = "host";
vbus-supply = <&usb_vbus>;
phys = <&usb_phy 0>;
phy-names = "usb-phy";
status = "okay";
};
...@@ -12,6 +12,7 @@ Required properties: ...@@ -12,6 +12,7 @@ Required properties:
- "lantiq,xrx200-usb": The DWC2 USB controller instance in Lantiq XRX SoCs; - "lantiq,xrx200-usb": The DWC2 USB controller instance in Lantiq XRX SoCs;
- "amlogic,meson8b-usb": The DWC2 USB controller instance in Amlogic Meson8b SoCs; - "amlogic,meson8b-usb": The DWC2 USB controller instance in Amlogic Meson8b SoCs;
- "amlogic,meson-gxbb-usb": The DWC2 USB controller instance in Amlogic S905 SoCs; - "amlogic,meson-gxbb-usb": The DWC2 USB controller instance in Amlogic S905 SoCs;
- "amcc,dwc-otg": The DWC2 USB controller instance in AMCC Canyonlands 460EX SoCs;
- snps,dwc2: A generic DWC2 USB controller with default parameters. - snps,dwc2: A generic DWC2 USB controller with default parameters.
- reg : Should contain 1 register range (address and length) - reg : Should contain 1 register range (address and length)
- interrupts : Should contain 1 interrupt - interrupts : Should contain 1 interrupt
...@@ -25,11 +26,13 @@ Optional properties: ...@@ -25,11 +26,13 @@ Optional properties:
Refer to phy/phy-bindings.txt for generic phy consumer properties Refer to phy/phy-bindings.txt for generic phy consumer properties
- dr_mode: shall be one of "host", "peripheral" and "otg" - dr_mode: shall be one of "host", "peripheral" and "otg"
Refer to usb/generic.txt Refer to usb/generic.txt
- g-use-dma: enable dma usage in gadget driver.
- g-rx-fifo-size: size of rx fifo size in gadget mode. - g-rx-fifo-size: size of rx fifo size in gadget mode.
- g-np-tx-fifo-size: size of non-periodic tx fifo size in gadget mode. - g-np-tx-fifo-size: size of non-periodic tx fifo size in gadget mode.
- g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0) in gadget mode. - g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0) in gadget mode.
Deprecated properties:
- g-use-dma: gadget DMA mode is automatically detected
Example: Example:
usb@101c0000 { usb@101c0000 {
......
The device node for Mediatek USB3.0 DRD controller
Required properties:
- compatible : should be "mediatek,mt8173-mtu3"
- reg : specifies physical base address and size of the registers
- reg-names: should be "mac" for device IP and "ippc" for IP port control
- interrupts : interrupt used by the device IP
- power-domains : a phandle to USB power domain node to control USB's
mtcmos
- vusb33-supply : regulator of USB avdd3.3v
- clocks : a list of phandle + clock-specifier pairs, one for each
entry in clock-names
- clock-names : must contain "sys_ck" for clock of controller;
"wakeup_deb_p0" and "wakeup_deb_p1" are optional, they are
depends on "mediatek,enable-wakeup"
- phys : a list of phandle + phy specifier pairs
- dr_mode : should be one of "host", "peripheral" or "otg",
refer to usb/generic.txt
Optional properties:
- #address-cells, #size-cells : should be '2' if the device has sub-nodes
with 'reg' property
- ranges : allows valid 1:1 translation between child's address space and
parent's address space
- extcon : external connector for vbus and idpin changes detection, needed
when supports dual-role mode.
- vbus-supply : reference to the VBUS regulator, needed when supports
dual-role mode.
- pinctl-names : a pinctrl state named "default" must be defined,
"id_float" and "id_ground" are optinal which depends on
"mediatek,enable-manual-drd"
- pinctrl-0 : pin control group
See: Documentation/devicetree/bindings/pinctrl/pinctrl-binding.txt
- maximum-speed : valid arguments are "super-speed", "high-speed" and
"full-speed"; refer to usb/generic.txt
- enable-manual-drd : supports manual dual-role switch via debugfs; usually
used when receptacle is TYPE-A and also wants to support dual-role
mode.
- mediatek,enable-wakeup : supports ip sleep wakeup used by host mode
- mediatek,syscon-wakeup : phandle to syscon used to access USB wakeup
control register, it depends on "mediatek,enable-wakeup".
Sub-nodes:
The xhci should be added as subnode to mtu3 as shown in the following example
if host mode is enabled. The DT binding details of xhci can be found in:
Documentation/devicetree/bindings/usb/mt8173-xhci.txt
Example:
ssusb: usb@11271000 {
compatible = "mediatek,mt8173-mtu3";
reg = <0 0x11271000 0 0x3000>,
<0 0x11280700 0 0x0100>;
reg-names = "mac", "ippc";
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_LOW>;
phys = <&phy_port0 PHY_TYPE_USB3>,
<&phy_port1 PHY_TYPE_USB2>;
power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>;
clocks = <&topckgen CLK_TOP_USB30_SEL>,
<&pericfg CLK_PERI_USB0>,
<&pericfg CLK_PERI_USB1>;
clock-names = "sys_ck",
"wakeup_deb_p0",
"wakeup_deb_p1";
vusb33-supply = <&mt6397_vusb_reg>;
vbus-supply = <&usb_p0_vbus>;
extcon = <&extcon_usb>;
dr_mode = "otg";
mediatek,enable-wakeup;
mediatek,syscon-wakeup = <&pericfg>;
#address-cells = <2>;
#size-cells = <2>;
ranges;
status = "disabled";
usb_host: xhci@11270000 {
compatible = "mediatek,mt8173-xhci";
reg = <0 0x11270000 0 0x1000>;
reg-names = "mac";
interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>;
power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>;
clocks = <&topckgen CLK_TOP_USB30_SEL>;
clock-names = "sys_ck";
vusb33-supply = <&mt6397_vusb_reg>;
status = "disabled";
};
};
...@@ -2,10 +2,18 @@ MT8173 xHCI ...@@ -2,10 +2,18 @@ MT8173 xHCI
The device node for Mediatek SOC USB3.0 host controller The device node for Mediatek SOC USB3.0 host controller
There are two scenarios: the first one only supports xHCI driver;
the second one supports dual-role mode, and the host is based on xHCI
driver. Take account of backward compatibility, we divide bindings
into two parts.
1st: only supports xHCI driver
------------------------------------------------------------------------
Required properties: Required properties:
- compatible : should contain "mediatek,mt8173-xhci" - compatible : should contain "mediatek,mt8173-xhci"
- reg : specifies physical base address and size of the registers, - reg : specifies physical base address and size of the registers
the first one for MAC, the second for IPPC - reg-names: should be "mac" for xHCI MAC and "ippc" for IP port control
- interrupts : interrupt used by the controller - interrupts : interrupt used by the controller
- power-domains : a phandle to USB power domain node to control USB's - power-domains : a phandle to USB power domain node to control USB's
mtcmos mtcmos
...@@ -27,12 +35,16 @@ Optional properties: ...@@ -27,12 +35,16 @@ Optional properties:
control register, it depends on "mediatek,wakeup-src". control register, it depends on "mediatek,wakeup-src".
- vbus-supply : reference to the VBUS regulator; - vbus-supply : reference to the VBUS regulator;
- usb3-lpm-capable : supports USB3.0 LPM - usb3-lpm-capable : supports USB3.0 LPM
- pinctrl-names : a pinctrl state named "default" must be defined
- pinctrl-0 : pin control group
See: Documentation/devicetree/bindings/pinctrl/pinctrl-binding.txt
Example: Example:
usb30: usb@11270000 { usb30: usb@11270000 {
compatible = "mediatek,mt8173-xhci"; compatible = "mediatek,mt8173-xhci";
reg = <0 0x11270000 0 0x1000>, reg = <0 0x11270000 0 0x1000>,
<0 0x11280700 0 0x0100>; <0 0x11280700 0 0x0100>;
reg-names = "mac", "ippc";
interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>; interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>;
power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>; power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>;
clocks = <&topckgen CLK_TOP_USB30_SEL>, clocks = <&topckgen CLK_TOP_USB30_SEL>,
...@@ -49,3 +61,41 @@ usb30: usb@11270000 { ...@@ -49,3 +61,41 @@ usb30: usb@11270000 {
mediatek,syscon-wakeup = <&pericfg>; mediatek,syscon-wakeup = <&pericfg>;
mediatek,wakeup-src = <1>; mediatek,wakeup-src = <1>;
}; };
2nd: dual-role mode with xHCI driver
------------------------------------------------------------------------
In the case, xhci is added as subnode to mtu3. An example and the DT binding
details of mtu3 can be found in:
Documentation/devicetree/bindings/usb/mtu3.txt
Required properties:
- compatible : should contain "mediatek,mt8173-xhci"
- reg : specifies physical base address and size of the registers
- reg-names: should be "mac" for xHCI MAC
- interrupts : interrupt used by the host controller
- power-domains : a phandle to USB power domain node to control USB's
mtcmos
- vusb33-supply : regulator of USB avdd3.3v
- clocks : a list of phandle + clock-specifier pairs, one for each
entry in clock-names
- clock-names : must be
"sys_ck": for clock of xHCI MAC
Optional properties:
- vbus-supply : reference to the VBUS regulator;
- usb3-lpm-capable : supports USB3.0 LPM
Example:
usb30: usb@11270000 {
compatible = "mediatek,mt8173-xhci";
reg = <0 0x11270000 0 0x1000>;
reg-names = "mac";
interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>;
power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>;
clocks = <&topckgen CLK_TOP_USB30_SEL>;
clock-names = "sys_ck";
vusb33-supply = <&mt6397_vusb_reg>;
usb3-lpm-capable;
};
DA8XX USB OHCI controller
Required properties:
- compatible: Should be "ti,da830-ohci"
- reg: Should contain one register range i.e. start and length
- interrupts: Description of the interrupt line
- phys: Phandle for the PHY device
- phy-names: Should be "usb-phy"
Optional properties:
- vbus-supply: phandle of regulator that controls vbus power / over-current
Example:
ohci: usb@0225000 {
compatible = "ti,da830-ohci";
reg = <0x225000 0x1000>;
interrupts = <59>;
phys = <&usb_phy 1>;
phy-names = "usb-phy";
vbus-supply = <&reg_usb_ohci>;
};
Samsung S3C2410 and compatible SoC USB controller
OHCI
Required properties:
- compatible: should be "samsung,s3c2410-ohci" for USB host controller
- reg: address and lenght of the controller memory mapped region
- interrupts: interrupt number for the USB OHCI controller
- clocks: Should reference the bus and host clocks
- clock-names: Should contain two strings
"usb-bus-host" for the USB bus clock
"usb-host" for the USB host clock
Example:
usb0: ohci@49000000 {
compatible = "samsung,s3c2410-ohci";
reg = <0x49000000 0x100>;
interrupts = <0 0 26 3>;
clocks = <&clocks UCLK>, <&clocks HCLK_USBH>;
clock-names = "usb-bus-host", "usb-host";
};
...@@ -11,6 +11,7 @@ Required properties: ...@@ -11,6 +11,7 @@ Required properties:
- "renesas,xhci-r8a7791" for r8a7791 SoC - "renesas,xhci-r8a7791" for r8a7791 SoC
- "renesas,xhci-r8a7793" for r8a7793 SoC - "renesas,xhci-r8a7793" for r8a7793 SoC
- "renesas,xhci-r8a7795" for r8a7795 SoC - "renesas,xhci-r8a7795" for r8a7795 SoC
- "renesas,xhci-r8a7796" for r8a7796 SoC
- "renesas,rcar-gen2-xhci" for a generic R-Car Gen2 compatible device - "renesas,rcar-gen2-xhci" for a generic R-Car Gen2 compatible device
- "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 compatible device - "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 compatible device
- "xhci-platform" (deprecated) - "xhci-platform" (deprecated)
......
...@@ -204,7 +204,6 @@ ...@@ -204,7 +204,6 @@
g-np-tx-fifo-size = <16>; g-np-tx-fifo-size = <16>;
g-rx-fifo-size = <275>; g-rx-fifo-size = <275>;
g-tx-fifo-size = <256 128 128 64 64 32>; g-tx-fifo-size = <256 128 128 64 64 32>;
g-use-dma;
status = "disabled"; status = "disabled";
}; };
......
...@@ -596,7 +596,6 @@ ...@@ -596,7 +596,6 @@
g-np-tx-fifo-size = <16>; g-np-tx-fifo-size = <16>;
g-rx-fifo-size = <275>; g-rx-fifo-size = <275>;
g-tx-fifo-size = <256 128 128 64 64 32>; g-tx-fifo-size = <256 128 128 64 64 32>;
g-use-dma;
phys = <&usbphy0>; phys = <&usbphy0>;
phy-names = "usb2-phy"; phy-names = "usb2-phy";
status = "disabled"; status = "disabled";
......
...@@ -181,7 +181,6 @@ ...@@ -181,7 +181,6 @@
g-np-tx-fifo-size = <16>; g-np-tx-fifo-size = <16>;
g-rx-fifo-size = <275>; g-rx-fifo-size = <275>;
g-tx-fifo-size = <256 128 128 64 64 32>; g-tx-fifo-size = <256 128 128 64 64 32>;
g-use-dma;
phys = <&usbphy0>; phys = <&usbphy0>;
phy-names = "usb2-phy"; phy-names = "usb2-phy";
status = "disabled"; status = "disabled";
......
...@@ -747,7 +747,6 @@ ...@@ -747,7 +747,6 @@
clocks = <&sys_ctrl HI6220_USBOTG_HCLK>; clocks = <&sys_ctrl HI6220_USBOTG_HCLK>;
clock-names = "otg"; clock-names = "otg";
dr_mode = "otg"; dr_mode = "otg";
g-use-dma;
g-rx-fifo-size = <512>; g-rx-fifo-size = <512>;
g-np-tx-fifo-size = <128>; g-np-tx-fifo-size = <128>;
g-tx-fifo-size = <128 128 128 128 128 128>; g-tx-fifo-size = <128 128 128 128 128 128>;
......
...@@ -34,15 +34,6 @@ ...@@ -34,15 +34,6 @@
chosen { }; chosen { };
usb_p1_vbus: regulator@0 {
compatible = "regulator-fixed";
regulator-name = "usb_vbus";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
gpio = <&pio 130 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
connector { connector {
compatible = "hdmi-connector"; compatible = "hdmi-connector";
label = "hdmi"; label = "hdmi";
...@@ -54,6 +45,29 @@ ...@@ -54,6 +45,29 @@
}; };
}; };
}; };
extcon_usb: extcon_iddig {
compatible = "linux,extcon-usb-gpio";
id-gpio = <&pio 16 GPIO_ACTIVE_HIGH>;
};
usb_p1_vbus: regulator@0 {
compatible = "regulator-fixed";
regulator-name = "usb_vbus";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
gpio = <&pio 130 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
usb_p0_vbus: regulator@1 {
compatible = "regulator-fixed";
regulator-name = "vbus";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
gpio = <&pio 9 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
}; };
&cec { &cec {
...@@ -243,6 +257,20 @@ ...@@ -243,6 +257,20 @@
bias-pull-down = <MTK_PUPD_SET_R1R0_10>; bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
}; };
}; };
usb_id_pins_float: usb_iddig_pull_up {
pins_iddig {
pinmux = <MT8173_PIN_16_IDDIG__FUNC_IDDIG>;
bias-pull-up;
};
};
usb_id_pins_ground: usb_iddig_pull_down {
pins_iddig {
pinmux = <MT8173_PIN_16_IDDIG__FUNC_IDDIG>;
bias-pull-down;
};
};
}; };
&pwm0 { &pwm0 {
...@@ -469,12 +497,25 @@ ...@@ -469,12 +497,25 @@
status = "okay"; status = "okay";
}; };
&ssusb {
vusb33-supply = <&mt6397_vusb_reg>;
vbus-supply = <&usb_p0_vbus>;
extcon = <&extcon_usb>;
dr_mode = "otg";
mediatek,enable-wakeup;
pinctrl-names = "default", "id_float", "id_ground";
pinctrl-0 = <&usb_id_pins_float>;
pinctrl-1 = <&usb_id_pins_float>;
pinctrl-2 = <&usb_id_pins_ground>;
status = "okay";
};
&uart0 { &uart0 {
status = "okay"; status = "okay";
}; };
&usb30 { &usb_host {
vusb33-supply = <&mt6397_vusb_reg>; vusb33-supply = <&mt6397_vusb_reg>;
vbus-supply = <&usb_p1_vbus>; vbus-supply = <&usb_p1_vbus>;
mediatek,wakeup-src = <1>; status = "okay";
}; };
...@@ -707,11 +707,14 @@ ...@@ -707,11 +707,14 @@
status = "disabled"; status = "disabled";
}; };
usb30: usb@11270000 { ssusb: usb@11271000 {
compatible = "mediatek,mt8173-xhci"; compatible = "mediatek,mt8173-mtu3";
reg = <0 0x11270000 0 0x1000>, reg = <0 0x11271000 0 0x3000>,
<0 0x11280700 0 0x0100>; <0 0x11280700 0 0x0100>;
interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>; reg-names = "mac", "ippc";
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_LOW>;
phys = <&phy_port0 PHY_TYPE_USB3>,
<&phy_port1 PHY_TYPE_USB2>;
power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>; power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>;
clocks = <&topckgen CLK_TOP_USB30_SEL>, clocks = <&topckgen CLK_TOP_USB30_SEL>,
<&pericfg CLK_PERI_USB0>, <&pericfg CLK_PERI_USB0>,
...@@ -719,10 +722,22 @@ ...@@ -719,10 +722,22 @@
clock-names = "sys_ck", clock-names = "sys_ck",
"wakeup_deb_p0", "wakeup_deb_p0",
"wakeup_deb_p1"; "wakeup_deb_p1";
phys = <&phy_port0 PHY_TYPE_USB3>,
<&phy_port1 PHY_TYPE_USB2>;
mediatek,syscon-wakeup = <&pericfg>; mediatek,syscon-wakeup = <&pericfg>;
status = "okay"; #address-cells = <2>;
#size-cells = <2>;
ranges;
status = "disabled";
usb_host: xhci@11270000 {
compatible = "mediatek,mt8173-xhci";
reg = <0 0x11270000 0 0x1000>;
reg-names = "mac";
interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>;
power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>;
clocks = <&topckgen CLK_TOP_USB30_SEL>;
clock-names = "sys_ck";
status = "disabled";
};
}; };
u3phy: usb-phy@11290000 { u3phy: usb-phy@11290000 {
......
...@@ -537,7 +537,6 @@ ...@@ -537,7 +537,6 @@
g-np-tx-fifo-size = <16>; g-np-tx-fifo-size = <16>;
g-rx-fifo-size = <275>; g-rx-fifo-size = <275>;
g-tx-fifo-size = <256 128 128 64 64 32>; g-tx-fifo-size = <256 128 128 64 64 32>;
g-use-dma;
status = "disabled"; status = "disabled";
}; };
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_wakeirq.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/acpi.h> #include <linux/acpi.h>
...@@ -36,7 +35,9 @@ struct usb_extcon_info { ...@@ -36,7 +35,9 @@ struct usb_extcon_info {
struct extcon_dev *edev; struct extcon_dev *edev;
struct gpio_desc *id_gpiod; struct gpio_desc *id_gpiod;
struct gpio_desc *vbus_gpiod;
int id_irq; int id_irq;
int vbus_irq;
unsigned long debounce_jiffies; unsigned long debounce_jiffies;
struct delayed_work wq_detcable; struct delayed_work wq_detcable;
...@@ -48,31 +49,47 @@ static const unsigned int usb_extcon_cable[] = { ...@@ -48,31 +49,47 @@ static const unsigned int usb_extcon_cable[] = {
EXTCON_NONE, EXTCON_NONE,
}; };
/*
* "USB" = VBUS and "USB-HOST" = !ID, so we have:
* Both "USB" and "USB-HOST" can't be set as active at the
* same time so if "USB-HOST" is active (i.e. ID is 0) we keep "USB" inactive
* even if VBUS is on.
*
* State | ID | VBUS
* ----------------------------------------
* [1] USB | H | H
* [2] none | H | L
* [3] USB-HOST | L | H
* [4] USB-HOST | L | L
*
* In case we have only one of these signals:
* - VBUS only - we want to distinguish between [1] and [2], so ID is always 1.
* - ID only - we want to distinguish between [1] and [4], so VBUS = ID.
*/
static void usb_extcon_detect_cable(struct work_struct *work) static void usb_extcon_detect_cable(struct work_struct *work)
{ {
int id; int id, vbus;
struct usb_extcon_info *info = container_of(to_delayed_work(work), struct usb_extcon_info *info = container_of(to_delayed_work(work),
struct usb_extcon_info, struct usb_extcon_info,
wq_detcable); wq_detcable);
/* check ID and update cable state */ /* check ID and VBUS and update cable state */
id = gpiod_get_value_cansleep(info->id_gpiod); id = info->id_gpiod ?
if (id) { gpiod_get_value_cansleep(info->id_gpiod) : 1;
/* vbus = info->vbus_gpiod ?
* ID = 1 means USB HOST cable detached. gpiod_get_value_cansleep(info->vbus_gpiod) : id;
* As we don't have event for USB peripheral cable attached,
* we simulate USB peripheral attach here. /* at first we clean states which are no longer active */
*/ if (id)
extcon_set_state_sync(info->edev, EXTCON_USB_HOST, false); extcon_set_state_sync(info->edev, EXTCON_USB_HOST, false);
extcon_set_state_sync(info->edev, EXTCON_USB, true); if (!vbus)
} else {
/*
* ID = 0 means USB HOST cable attached.
* As we don't have event for USB peripheral cable detached,
* we simulate USB peripheral detach here.
*/
extcon_set_state_sync(info->edev, EXTCON_USB, false); extcon_set_state_sync(info->edev, EXTCON_USB, false);
if (!id) {
extcon_set_state_sync(info->edev, EXTCON_USB_HOST, true); extcon_set_state_sync(info->edev, EXTCON_USB_HOST, true);
} else {
if (vbus)
extcon_set_state_sync(info->edev, EXTCON_USB, true);
} }
} }
...@@ -101,12 +118,21 @@ static int usb_extcon_probe(struct platform_device *pdev) ...@@ -101,12 +118,21 @@ static int usb_extcon_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
info->dev = dev; info->dev = dev;
info->id_gpiod = devm_gpiod_get(&pdev->dev, "id", GPIOD_IN); info->id_gpiod = devm_gpiod_get_optional(&pdev->dev, "id", GPIOD_IN);
if (IS_ERR(info->id_gpiod)) { info->vbus_gpiod = devm_gpiod_get_optional(&pdev->dev, "vbus",
dev_err(dev, "failed to get ID GPIO\n"); GPIOD_IN);
return PTR_ERR(info->id_gpiod);
if (!info->id_gpiod && !info->vbus_gpiod) {
dev_err(dev, "failed to get gpios\n");
return -ENODEV;
} }
if (IS_ERR(info->id_gpiod))
return PTR_ERR(info->id_gpiod);
if (IS_ERR(info->vbus_gpiod))
return PTR_ERR(info->vbus_gpiod);
info->edev = devm_extcon_dev_allocate(dev, usb_extcon_cable); info->edev = devm_extcon_dev_allocate(dev, usb_extcon_cable);
if (IS_ERR(info->edev)) { if (IS_ERR(info->edev)) {
dev_err(dev, "failed to allocate extcon device\n"); dev_err(dev, "failed to allocate extcon device\n");
...@@ -119,32 +145,56 @@ static int usb_extcon_probe(struct platform_device *pdev) ...@@ -119,32 +145,56 @@ static int usb_extcon_probe(struct platform_device *pdev)
return ret; return ret;
} }
ret = gpiod_set_debounce(info->id_gpiod, if (info->id_gpiod)
USB_GPIO_DEBOUNCE_MS * 1000); ret = gpiod_set_debounce(info->id_gpiod,
USB_GPIO_DEBOUNCE_MS * 1000);
if (!ret && info->vbus_gpiod)
ret = gpiod_set_debounce(info->vbus_gpiod,
USB_GPIO_DEBOUNCE_MS * 1000);
if (ret < 0) if (ret < 0)
info->debounce_jiffies = msecs_to_jiffies(USB_GPIO_DEBOUNCE_MS); info->debounce_jiffies = msecs_to_jiffies(USB_GPIO_DEBOUNCE_MS);
INIT_DELAYED_WORK(&info->wq_detcable, usb_extcon_detect_cable); INIT_DELAYED_WORK(&info->wq_detcable, usb_extcon_detect_cable);
info->id_irq = gpiod_to_irq(info->id_gpiod); if (info->id_gpiod) {
if (info->id_irq < 0) { info->id_irq = gpiod_to_irq(info->id_gpiod);
dev_err(dev, "failed to get ID IRQ\n"); if (info->id_irq < 0) {
return info->id_irq; dev_err(dev, "failed to get ID IRQ\n");
return info->id_irq;
}
ret = devm_request_threaded_irq(dev, info->id_irq, NULL,
usb_irq_handler,
IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
pdev->name, info);
if (ret < 0) {
dev_err(dev, "failed to request handler for ID IRQ\n");
return ret;
}
} }
ret = devm_request_threaded_irq(dev, info->id_irq, NULL, if (info->vbus_gpiod) {
usb_irq_handler, info->vbus_irq = gpiod_to_irq(info->vbus_gpiod);
IRQF_TRIGGER_RISING | if (info->vbus_irq < 0) {
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, dev_err(dev, "failed to get VBUS IRQ\n");
pdev->name, info); return info->vbus_irq;
if (ret < 0) { }
dev_err(dev, "failed to request handler for ID IRQ\n");
return ret; ret = devm_request_threaded_irq(dev, info->vbus_irq, NULL,
usb_irq_handler,
IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
pdev->name, info);
if (ret < 0) {
dev_err(dev, "failed to request handler for VBUS IRQ\n");
return ret;
}
} }
platform_set_drvdata(pdev, info); platform_set_drvdata(pdev, info);
device_init_wakeup(dev, true); device_init_wakeup(dev, true);
dev_pm_set_wake_irq(dev, info->id_irq);
/* Perform initial detection */ /* Perform initial detection */
usb_extcon_detect_cable(&info->wq_detcable.work); usb_extcon_detect_cable(&info->wq_detcable.work);
...@@ -157,8 +207,6 @@ static int usb_extcon_remove(struct platform_device *pdev) ...@@ -157,8 +207,6 @@ static int usb_extcon_remove(struct platform_device *pdev)
struct usb_extcon_info *info = platform_get_drvdata(pdev); struct usb_extcon_info *info = platform_get_drvdata(pdev);
cancel_delayed_work_sync(&info->wq_detcable); cancel_delayed_work_sync(&info->wq_detcable);
dev_pm_clear_wake_irq(&pdev->dev);
device_init_wakeup(&pdev->dev, false); device_init_wakeup(&pdev->dev, false);
return 0; return 0;
...@@ -170,12 +218,32 @@ static int usb_extcon_suspend(struct device *dev) ...@@ -170,12 +218,32 @@ static int usb_extcon_suspend(struct device *dev)
struct usb_extcon_info *info = dev_get_drvdata(dev); struct usb_extcon_info *info = dev_get_drvdata(dev);
int ret = 0; int ret = 0;
if (device_may_wakeup(dev)) {
if (info->id_gpiod) {
ret = enable_irq_wake(info->id_irq);
if (ret)
return ret;
}
if (info->vbus_gpiod) {
ret = enable_irq_wake(info->vbus_irq);
if (ret) {
if (info->id_gpiod)
disable_irq_wake(info->id_irq);
return ret;
}
}
}
/* /*
* We don't want to process any IRQs after this point * We don't want to process any IRQs after this point
* as GPIOs used behind I2C subsystem might not be * as GPIOs used behind I2C subsystem might not be
* accessible until resume completes. So disable IRQ. * accessible until resume completes. So disable IRQ.
*/ */
disable_irq(info->id_irq); if (info->id_gpiod)
disable_irq(info->id_irq);
if (info->vbus_gpiod)
disable_irq(info->vbus_irq);
return ret; return ret;
} }
...@@ -185,7 +253,28 @@ static int usb_extcon_resume(struct device *dev) ...@@ -185,7 +253,28 @@ static int usb_extcon_resume(struct device *dev)
struct usb_extcon_info *info = dev_get_drvdata(dev); struct usb_extcon_info *info = dev_get_drvdata(dev);
int ret = 0; int ret = 0;
enable_irq(info->id_irq); if (device_may_wakeup(dev)) {
if (info->id_gpiod) {
ret = disable_irq_wake(info->id_irq);
if (ret)
return ret;
}
if (info->vbus_gpiod) {
ret = disable_irq_wake(info->vbus_irq);
if (ret) {
if (info->id_gpiod)
enable_irq_wake(info->id_irq);
return ret;
}
}
}
if (info->id_gpiod)
enable_irq(info->id_irq);
if (info->vbus_gpiod)
enable_irq(info->vbus_irq);
if (!device_may_wakeup(dev)) if (!device_may_wakeup(dev))
queue_delayed_work(system_power_efficient_wq, queue_delayed_work(system_power_efficient_wq,
&info->wq_detcable, 0); &info->wq_detcable, 0);
......
...@@ -71,6 +71,7 @@ static int usbtv_probe(struct usb_interface *intf, ...@@ -71,6 +71,7 @@ static int usbtv_probe(struct usb_interface *intf,
int size; int size;
struct device *dev = &intf->dev; struct device *dev = &intf->dev;
struct usbtv *usbtv; struct usbtv *usbtv;
struct usb_host_endpoint *ep;
/* Checks that the device is what we think it is. */ /* Checks that the device is what we think it is. */
if (intf->num_altsetting != 2) if (intf->num_altsetting != 2)
...@@ -78,10 +79,12 @@ static int usbtv_probe(struct usb_interface *intf, ...@@ -78,10 +79,12 @@ static int usbtv_probe(struct usb_interface *intf,
if (intf->altsetting[1].desc.bNumEndpoints != 4) if (intf->altsetting[1].desc.bNumEndpoints != 4)
return -ENODEV; return -ENODEV;
ep = &intf->altsetting[1].endpoint[0];
/* Packet size is split into 11 bits of base size and count of /* Packet size is split into 11 bits of base size and count of
* extra multiplies of it.*/ * extra multiplies of it.*/
size = usb_endpoint_maxp(&intf->altsetting[1].endpoint[0].desc); size = usb_endpoint_maxp(&ep->desc);
size = (size & 0x07ff) * (((size & 0x1800) >> 11) + 1); size = (size & 0x07ff) * usb_endpoint_maxp_mult(&ep->desc);
/* Device structure */ /* Device structure */
usbtv = kzalloc(sizeof(struct usbtv), GFP_KERNEL); usbtv = kzalloc(sizeof(struct usbtv), GFP_KERNEL);
......
...@@ -1467,6 +1467,7 @@ static unsigned int uvc_endpoint_max_bpi(struct usb_device *dev, ...@@ -1467,6 +1467,7 @@ static unsigned int uvc_endpoint_max_bpi(struct usb_device *dev,
struct usb_host_endpoint *ep) struct usb_host_endpoint *ep)
{ {
u16 psize; u16 psize;
u16 mult;
switch (dev->speed) { switch (dev->speed) {
case USB_SPEED_SUPER: case USB_SPEED_SUPER:
...@@ -1474,7 +1475,8 @@ static unsigned int uvc_endpoint_max_bpi(struct usb_device *dev, ...@@ -1474,7 +1475,8 @@ static unsigned int uvc_endpoint_max_bpi(struct usb_device *dev,
return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval); return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval);
case USB_SPEED_HIGH: case USB_SPEED_HIGH:
psize = usb_endpoint_maxp(&ep->desc); psize = usb_endpoint_maxp(&ep->desc);
return (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); mult = usb_endpoint_maxp_mult(&ep->desc);
return (psize & 0x07ff) * mult;
case USB_SPEED_WIRELESS: case USB_SPEED_WIRELESS:
psize = usb_endpoint_maxp(&ep->desc); psize = usb_endpoint_maxp(&ep->desc);
return psize; return psize;
...@@ -1551,7 +1553,7 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream, ...@@ -1551,7 +1553,7 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream,
u16 psize; u16 psize;
u32 size; u32 size;
psize = usb_endpoint_maxp(&ep->desc) & 0x7ff; psize = usb_endpoint_maxp(&ep->desc);
size = stream->ctrl.dwMaxPayloadTransferSize; size = stream->ctrl.dwMaxPayloadTransferSize;
stream->bulk.max_payload_size = size; stream->bulk.max_payload_size = size;
......
...@@ -129,16 +129,6 @@ config PHY_MIPHY28LP ...@@ -129,16 +129,6 @@ config PHY_MIPHY28LP
Enable this to support the miphy transceiver (for SATA/PCIE/USB3) Enable this to support the miphy transceiver (for SATA/PCIE/USB3)
that is part of STMicroelectronics STiH407 SoC. that is part of STMicroelectronics STiH407 SoC.
config PHY_MIPHY365X
tristate "STMicroelectronics MIPHY365X PHY driver for STiH41x series"
depends on ARCH_STI
depends on HAS_IOMEM
depends on OF
select GENERIC_PHY
help
Enable this to support the miphy transceiver (for SATA/PCIE)
that is part of STMicroelectronics STiH41x SoC series.
config PHY_RCAR_GEN2 config PHY_RCAR_GEN2
tristate "Renesas R-Car generation 2 USB PHY driver" tristate "Renesas R-Car generation 2 USB PHY driver"
depends on ARCH_RENESAS depends on ARCH_RENESAS
...@@ -373,7 +363,9 @@ config PHY_ROCKCHIP_INNO_USB2 ...@@ -373,7 +363,9 @@ config PHY_ROCKCHIP_INNO_USB2
tristate "Rockchip INNO USB2PHY Driver" tristate "Rockchip INNO USB2PHY Driver"
depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF
depends on COMMON_CLK depends on COMMON_CLK
depends on USB_SUPPORT
select GENERIC_PHY select GENERIC_PHY
select USB_COMMON
help help
Support for Rockchip USB2.0 PHY with Innosilicon IP block. Support for Rockchip USB2.0 PHY with Innosilicon IP block.
...@@ -438,14 +430,6 @@ config PHY_STIH407_USB ...@@ -438,14 +430,6 @@ config PHY_STIH407_USB
Enable this support to enable the picoPHY device used by USB2 Enable this support to enable the picoPHY device used by USB2
and USB3 controllers on STMicroelectronics STiH407 SoC families. and USB3 controllers on STMicroelectronics STiH407 SoC families.
config PHY_STIH41X_USB
tristate "STMicroelectronics USB2 PHY driver for STiH41x series"
depends on ARCH_STI
select GENERIC_PHY
help
Enable this to support the USB transceiver that is part of
STMicroelectronics STiH41x SoC series.
config PHY_QCOM_UFS config PHY_QCOM_UFS
tristate "Qualcomm UFS PHY driver" tristate "Qualcomm UFS PHY driver"
depends on OF && ARCH_QCOM depends on OF && ARCH_QCOM
...@@ -489,4 +473,17 @@ config PHY_NS2_PCIE ...@@ -489,4 +473,17 @@ config PHY_NS2_PCIE
help help
Enable this to support the Broadcom Northstar2 PCIe PHY. Enable this to support the Broadcom Northstar2 PCIe PHY.
If unsure, say N. If unsure, say N.
config PHY_MESON8B_USB2
tristate "Meson8b and GXBB USB2 PHY driver"
default ARCH_MESON
depends on OF && (ARCH_MESON || COMPILE_TEST)
depends on USB_SUPPORT
select USB_COMMON
select GENERIC_PHY
help
Enable this to support the Meson USB2 PHYs found in Meson8b
and GXBB SoCs.
If unsure, say N.
endmenu endmenu
...@@ -18,7 +18,6 @@ obj-$(CONFIG_PHY_PXA_28NM_USB2) += phy-pxa-28nm-usb2.o ...@@ -18,7 +18,6 @@ obj-$(CONFIG_PHY_PXA_28NM_USB2) += phy-pxa-28nm-usb2.o
obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o
obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o
obj-$(CONFIG_PHY_MIPHY28LP) += phy-miphy28lp.o obj-$(CONFIG_PHY_MIPHY28LP) += phy-miphy28lp.o
obj-$(CONFIG_PHY_MIPHY365X) += phy-miphy365x.o
obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o
obj-$(CONFIG_PHY_RCAR_GEN3_USB2) += phy-rcar-gen3-usb2.o obj-$(CONFIG_PHY_RCAR_GEN3_USB2) += phy-rcar-gen3-usb2.o
obj-$(CONFIG_OMAP_CONTROL_PHY) += phy-omap-control.o obj-$(CONFIG_OMAP_CONTROL_PHY) += phy-omap-control.o
...@@ -50,7 +49,6 @@ obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o ...@@ -50,7 +49,6 @@ obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o
obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o
obj-$(CONFIG_PHY_XGENE) += phy-xgene.o obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o
obj-$(CONFIG_PHY_STIH41X_USB) += phy-stih41x-usb.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o
...@@ -60,3 +58,4 @@ obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o ...@@ -60,3 +58,4 @@ obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o
obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o
...@@ -85,7 +85,6 @@ static int phy_berlin_sata_power_on(struct phy *phy) ...@@ -85,7 +85,6 @@ static int phy_berlin_sata_power_on(struct phy *phy)
struct phy_berlin_desc *desc = phy_get_drvdata(phy); struct phy_berlin_desc *desc = phy_get_drvdata(phy);
struct phy_berlin_priv *priv = dev_get_drvdata(phy->dev.parent); struct phy_berlin_priv *priv = dev_get_drvdata(phy->dev.parent);
void __iomem *ctrl_reg = priv->base + 0x60 + (desc->index * 0x80); void __iomem *ctrl_reg = priv->base + 0x60 + (desc->index * 0x80);
int ret = 0;
u32 regval; u32 regval;
clk_prepare_enable(priv->clk); clk_prepare_enable(priv->clk);
...@@ -130,7 +129,7 @@ static int phy_berlin_sata_power_on(struct phy *phy) ...@@ -130,7 +129,7 @@ static int phy_berlin_sata_power_on(struct phy *phy)
clk_disable_unprepare(priv->clk); clk_disable_unprepare(priv->clk);
return ret; return 0;
} }
static int phy_berlin_sata_power_off(struct phy *phy) static int phy_berlin_sata_power_off(struct phy *phy)
......
...@@ -140,7 +140,7 @@ static inline void __iomem *brcm_sata_pcb_base(struct brcm_sata_port *port) ...@@ -140,7 +140,7 @@ static inline void __iomem *brcm_sata_pcb_base(struct brcm_sata_port *port)
default: default:
dev_err(priv->dev, "invalid phy version\n"); dev_err(priv->dev, "invalid phy version\n");
break; break;
}; }
return priv->phy_base + (port->portnum * size); return priv->phy_base + (port->portnum * size);
} }
...@@ -157,7 +157,7 @@ static inline void __iomem *brcm_sata_ctrl_base(struct brcm_sata_port *port) ...@@ -157,7 +157,7 @@ static inline void __iomem *brcm_sata_ctrl_base(struct brcm_sata_port *port)
default: default:
dev_err(priv->dev, "invalid phy version\n"); dev_err(priv->dev, "invalid phy version\n");
break; break;
}; }
return priv->ctrl_base + (port->portnum * size); return priv->ctrl_base + (port->portnum * size);
} }
...@@ -365,7 +365,7 @@ static int brcm_sata_phy_init(struct phy *phy) ...@@ -365,7 +365,7 @@ static int brcm_sata_phy_init(struct phy *phy)
break; break;
default: default:
rc = -ENODEV; rc = -ENODEV;
}; }
return rc; return rc;
} }
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#define PHY_INIT_BITS (CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN)
struct da8xx_usb_phy { struct da8xx_usb_phy {
struct phy_provider *phy_provider; struct phy_provider *phy_provider;
struct phy *usb11_phy; struct phy *usb11_phy;
...@@ -208,6 +210,9 @@ static int da8xx_usb_phy_probe(struct platform_device *pdev) ...@@ -208,6 +210,9 @@ static int da8xx_usb_phy_probe(struct platform_device *pdev)
dev_warn(dev, "Failed to create usb20 phy lookup\n"); dev_warn(dev, "Failed to create usb20 phy lookup\n");
} }
regmap_write_bits(d_phy->regmap, CFGCHIP(2),
PHY_INIT_BITS, PHY_INIT_BITS);
return 0; return 0;
} }
......
...@@ -229,19 +229,6 @@ struct exynos_mipi_video_phy { ...@@ -229,19 +229,6 @@ struct exynos_mipi_video_phy {
spinlock_t slock; spinlock_t slock;
}; };
static inline int __is_running(const struct exynos_mipi_phy_desc *data,
struct exynos_mipi_video_phy *state)
{
u32 val;
int ret;
ret = regmap_read(state->regmaps[data->resetn_map], data->resetn_reg, &val);
if (ret)
return 0;
return val & data->resetn_val;
}
static int __set_phy_state(const struct exynos_mipi_phy_desc *data, static int __set_phy_state(const struct exynos_mipi_phy_desc *data,
struct exynos_mipi_video_phy *state, unsigned int on) struct exynos_mipi_video_phy *state, unsigned int on)
{ {
...@@ -251,7 +238,7 @@ static int __set_phy_state(const struct exynos_mipi_phy_desc *data, ...@@ -251,7 +238,7 @@ static int __set_phy_state(const struct exynos_mipi_phy_desc *data,
/* disable in PMU sysreg */ /* disable in PMU sysreg */
if (!on && data->coupled_phy_id >= 0 && if (!on && data->coupled_phy_id >= 0 &&
!__is_running(state->phys[data->coupled_phy_id].data, state)) { state->phys[data->coupled_phy_id].phy->power_count == 0) {
regmap_read(state->regmaps[data->enable_map], data->enable_reg, regmap_read(state->regmaps[data->enable_map], data->enable_reg,
&val); &val);
val &= ~data->enable_val; val &= ~data->enable_val;
......
...@@ -141,7 +141,7 @@ static void exynos4210_isol(struct samsung_usb2_phy_instance *inst, bool on) ...@@ -141,7 +141,7 @@ static void exynos4210_isol(struct samsung_usb2_phy_instance *inst, bool on)
break; break;
default: default:
return; return;
}; }
regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask); regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
} }
...@@ -179,7 +179,7 @@ static void exynos4210_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on) ...@@ -179,7 +179,7 @@ static void exynos4210_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
rstbits = EXYNOS_4210_URSTCON_PHY1_P1P2 | rstbits = EXYNOS_4210_URSTCON_PHY1_P1P2 |
EXYNOS_4210_URSTCON_HOST_LINK_P2; EXYNOS_4210_URSTCON_HOST_LINK_P2;
break; break;
}; }
if (on) { if (on) {
clk = readl(drv->reg_phy + EXYNOS_4210_UPHYCLK); clk = readl(drv->reg_phy + EXYNOS_4210_UPHYCLK);
......
...@@ -187,7 +187,7 @@ static void exynos4x12_isol(struct samsung_usb2_phy_instance *inst, bool on) ...@@ -187,7 +187,7 @@ static void exynos4x12_isol(struct samsung_usb2_phy_instance *inst, bool on)
break; break;
default: default:
return; return;
}; }
regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask); regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
} }
...@@ -237,7 +237,7 @@ static void exynos4x12_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on) ...@@ -237,7 +237,7 @@ static void exynos4x12_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
rstbits = EXYNOS_4x12_URSTCON_HSIC1 | rstbits = EXYNOS_4x12_URSTCON_HSIC1 |
EXYNOS_4x12_URSTCON_HOST_LINK_P1; EXYNOS_4x12_URSTCON_HOST_LINK_P1;
break; break;
}; }
if (on) { if (on) {
pwr = readl(drv->reg_phy + EXYNOS_4x12_UPHYPWR); pwr = readl(drv->reg_phy + EXYNOS_4x12_UPHYPWR);
......
...@@ -192,7 +192,7 @@ static void exynos5250_isol(struct samsung_usb2_phy_instance *inst, bool on) ...@@ -192,7 +192,7 @@ static void exynos5250_isol(struct samsung_usb2_phy_instance *inst, bool on)
break; break;
default: default:
return; return;
}; }
regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask); regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
} }
......
/*
* Meson8b and GXBB USB2 PHY driver
*
* Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/reset.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/usb/of.h>
#define REG_CONFIG 0x00
#define REG_CONFIG_CLK_EN BIT(0)
#define REG_CONFIG_CLK_SEL_MASK GENMASK(3, 1)
#define REG_CONFIG_CLK_DIV_MASK GENMASK(10, 4)
#define REG_CONFIG_CLK_32k_ALTSEL BIT(15)
#define REG_CONFIG_TEST_TRIG BIT(31)
#define REG_CTRL 0x04
#define REG_CTRL_SOFT_PRST BIT(0)
#define REG_CTRL_SOFT_HRESET BIT(1)
#define REG_CTRL_SS_SCALEDOWN_MODE_MASK GENMASK(3, 2)
#define REG_CTRL_CLK_DET_RST BIT(4)
#define REG_CTRL_INTR_SEL BIT(5)
#define REG_CTRL_CLK_DETECTED BIT(8)
#define REG_CTRL_SOF_SENT_RCVD_TGL BIT(9)
#define REG_CTRL_SOF_TOGGLE_OUT BIT(10)
#define REG_CTRL_POWER_ON_RESET BIT(15)
#define REG_CTRL_SLEEPM BIT(16)
#define REG_CTRL_TX_BITSTUFF_ENN_H BIT(17)
#define REG_CTRL_TX_BITSTUFF_ENN BIT(18)
#define REG_CTRL_COMMON_ON BIT(19)
#define REG_CTRL_REF_CLK_SEL_MASK GENMASK(21, 20)
#define REG_CTRL_REF_CLK_SEL_SHIFT 20
#define REG_CTRL_FSEL_MASK GENMASK(24, 22)
#define REG_CTRL_FSEL_SHIFT 22
#define REG_CTRL_PORT_RESET BIT(25)
#define REG_CTRL_THREAD_ID_MASK GENMASK(31, 26)
#define REG_ENDP_INTR 0x08
/* bits [31:26], [24:21] and [15:3] seem to be read-only */
#define REG_ADP_BC 0x0c
#define REG_ADP_BC_VBUS_VLD_EXT_SEL BIT(0)
#define REG_ADP_BC_VBUS_VLD_EXT BIT(1)
#define REG_ADP_BC_OTG_DISABLE BIT(2)
#define REG_ADP_BC_ID_PULLUP BIT(3)
#define REG_ADP_BC_DRV_VBUS BIT(4)
#define REG_ADP_BC_ADP_PRB_EN BIT(5)
#define REG_ADP_BC_ADP_DISCHARGE BIT(6)
#define REG_ADP_BC_ADP_CHARGE BIT(7)
#define REG_ADP_BC_SESS_END BIT(8)
#define REG_ADP_BC_DEVICE_SESS_VLD BIT(9)
#define REG_ADP_BC_B_VALID BIT(10)
#define REG_ADP_BC_A_VALID BIT(11)
#define REG_ADP_BC_ID_DIG BIT(12)
#define REG_ADP_BC_VBUS_VALID BIT(13)
#define REG_ADP_BC_ADP_PROBE BIT(14)
#define REG_ADP_BC_ADP_SENSE BIT(15)
#define REG_ADP_BC_ACA_ENABLE BIT(16)
#define REG_ADP_BC_DCD_ENABLE BIT(17)
#define REG_ADP_BC_VDAT_DET_EN_B BIT(18)
#define REG_ADP_BC_VDAT_SRC_EN_B BIT(19)
#define REG_ADP_BC_CHARGE_SEL BIT(20)
#define REG_ADP_BC_CHARGE_DETECT BIT(21)
#define REG_ADP_BC_ACA_PIN_RANGE_C BIT(22)
#define REG_ADP_BC_ACA_PIN_RANGE_B BIT(23)
#define REG_ADP_BC_ACA_PIN_RANGE_A BIT(24)
#define REG_ADP_BC_ACA_PIN_GND BIT(25)
#define REG_ADP_BC_ACA_PIN_FLOAT BIT(26)
#define REG_DBG_UART 0x14
#define REG_TEST 0x18
#define REG_TEST_DATA_IN_MASK GENMASK(3, 0)
#define REG_TEST_EN_MASK GENMASK(7, 4)
#define REG_TEST_ADDR_MASK GENMASK(11, 8)
#define REG_TEST_DATA_OUT_SEL BIT(12)
#define REG_TEST_CLK BIT(13)
#define REG_TEST_VA_TEST_EN_B_MASK GENMASK(15, 14)
#define REG_TEST_DATA_OUT_MASK GENMASK(19, 16)
#define REG_TEST_DISABLE_ID_PULLUP BIT(20)
#define REG_TUNE 0x1c
#define REG_TUNE_TX_RES_TUNE_MASK GENMASK(1, 0)
#define REG_TUNE_TX_HSXV_TUNE_MASK GENMASK(3, 2)
#define REG_TUNE_TX_VREF_TUNE_MASK GENMASK(7, 4)
#define REG_TUNE_TX_RISE_TUNE_MASK GENMASK(9, 8)
#define REG_TUNE_TX_PREEMP_PULSE_TUNE BIT(10)
#define REG_TUNE_TX_PREEMP_AMP_TUNE_MASK GENMASK(12, 11)
#define REG_TUNE_TX_FSLS_TUNE_MASK GENMASK(16, 13)
#define REG_TUNE_SQRX_TUNE_MASK GENMASK(19, 17)
#define REG_TUNE_OTG_TUNE GENMASK(22, 20)
#define REG_TUNE_COMP_DIS_TUNE GENMASK(25, 23)
#define REG_TUNE_HOST_DM_PULLDOWN BIT(26)
#define REG_TUNE_HOST_DP_PULLDOWN BIT(27)
#define RESET_COMPLETE_TIME 500
#define ACA_ENABLE_COMPLETE_TIME 50
struct phy_meson8b_usb2_priv {
void __iomem *regs;
enum usb_dr_mode dr_mode;
struct clk *clk_usb_general;
struct clk *clk_usb;
struct reset_control *reset;
};
static u32 phy_meson8b_usb2_read(struct phy_meson8b_usb2_priv *phy_priv,
u32 reg)
{
return readl(phy_priv->regs + reg);
}
static void phy_meson8b_usb2_mask_bits(struct phy_meson8b_usb2_priv *phy_priv,
u32 reg, u32 mask, u32 value)
{
u32 data;
data = phy_meson8b_usb2_read(phy_priv, reg);
data &= ~mask;
data |= (value & mask);
writel(data, phy_priv->regs + reg);
}
static int phy_meson8b_usb2_power_on(struct phy *phy)
{
struct phy_meson8b_usb2_priv *priv = phy_get_drvdata(phy);
int ret;
if (!IS_ERR_OR_NULL(priv->reset)) {
ret = reset_control_reset(priv->reset);
if (ret) {
dev_err(&phy->dev, "Failed to trigger USB reset\n");
return ret;
}
}
ret = clk_prepare_enable(priv->clk_usb_general);
if (ret) {
dev_err(&phy->dev, "Failed to enable USB general clock\n");
return ret;
}
ret = clk_prepare_enable(priv->clk_usb);
if (ret) {
dev_err(&phy->dev, "Failed to enable USB DDR clock\n");
clk_disable_unprepare(priv->clk_usb_general);
return ret;
}
phy_meson8b_usb2_mask_bits(priv, REG_CONFIG, REG_CONFIG_CLK_32k_ALTSEL,
REG_CONFIG_CLK_32k_ALTSEL);
phy_meson8b_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_REF_CLK_SEL_MASK,
0x2 << REG_CTRL_REF_CLK_SEL_SHIFT);
phy_meson8b_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_FSEL_MASK,
0x5 << REG_CTRL_FSEL_SHIFT);
/* reset the PHY */
phy_meson8b_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_POWER_ON_RESET,
REG_CTRL_POWER_ON_RESET);
udelay(RESET_COMPLETE_TIME);
phy_meson8b_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_POWER_ON_RESET, 0);
udelay(RESET_COMPLETE_TIME);
phy_meson8b_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_SOF_TOGGLE_OUT,
REG_CTRL_SOF_TOGGLE_OUT);
if (priv->dr_mode == USB_DR_MODE_HOST) {
phy_meson8b_usb2_mask_bits(priv, REG_ADP_BC,
REG_ADP_BC_ACA_ENABLE,
REG_ADP_BC_ACA_ENABLE);
udelay(ACA_ENABLE_COMPLETE_TIME);
if (phy_meson8b_usb2_read(priv, REG_ADP_BC) &
REG_ADP_BC_ACA_PIN_FLOAT) {
dev_warn(&phy->dev, "USB ID detect failed!\n");
clk_disable_unprepare(priv->clk_usb);
clk_disable_unprepare(priv->clk_usb_general);
return -EINVAL;
}
}
return 0;
}
static int phy_meson8b_usb2_power_off(struct phy *phy)
{
struct phy_meson8b_usb2_priv *priv = phy_get_drvdata(phy);
clk_disable_unprepare(priv->clk_usb);
clk_disable_unprepare(priv->clk_usb_general);
return 0;
}
static const struct phy_ops phy_meson8b_usb2_ops = {
.power_on = phy_meson8b_usb2_power_on,
.power_off = phy_meson8b_usb2_power_off,
.owner = THIS_MODULE,
};
static int phy_meson8b_usb2_probe(struct platform_device *pdev)
{
struct phy_meson8b_usb2_priv *priv;
struct resource *res;
struct phy *phy;
struct phy_provider *phy_provider;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->regs))
return PTR_ERR(priv->regs);
priv->clk_usb_general = devm_clk_get(&pdev->dev, "usb_general");
if (IS_ERR(priv->clk_usb_general))
return PTR_ERR(priv->clk_usb_general);
priv->clk_usb = devm_clk_get(&pdev->dev, "usb");
if (IS_ERR(priv->clk_usb))
return PTR_ERR(priv->clk_usb);
priv->reset = devm_reset_control_get_optional_shared(&pdev->dev, NULL);
if (PTR_ERR(priv->reset) == -EPROBE_DEFER)
return PTR_ERR(priv->reset);
priv->dr_mode = of_usb_get_dr_mode_by_phy(pdev->dev.of_node, -1);
if (priv->dr_mode == USB_DR_MODE_UNKNOWN) {
dev_err(&pdev->dev,
"missing dual role configuration of the controller\n");
return -EINVAL;
}
phy = devm_phy_create(&pdev->dev, NULL, &phy_meson8b_usb2_ops);
if (IS_ERR(phy)) {
dev_err(&pdev->dev, "failed to create PHY\n");
return PTR_ERR(phy);
}
phy_set_drvdata(phy, priv);
phy_provider =
devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id phy_meson8b_usb2_of_match[] = {
{ .compatible = "amlogic,meson8b-usb2-phy", },
{ .compatible = "amlogic,meson-gxbb-usb2-phy", },
{ },
};
MODULE_DEVICE_TABLE(of, phy_meson8b_usb2_of_match);
static struct platform_driver phy_meson8b_usb2_driver = {
.probe = phy_meson8b_usb2_probe,
.driver = {
.name = "phy-meson-usb2",
.of_match_table = phy_meson8b_usb2_of_match,
},
};
module_platform_driver(phy_meson8b_usb2_driver);
MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
MODULE_DESCRIPTION("Meson8b and GXBB USB2 PHY driver");
MODULE_LICENSE("GPL");
/*
* Copyright (C) 2014 STMicroelectronics – All Rights Reserved
*
* STMicroelectronics PHY driver MiPHY365 (for SoC STiH416).
*
* Authors: Alexandre Torgue <alexandre.torgue@st.com>
* Lee Jones <lee.jones@linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
*/
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/clk.h>
#include <linux/phy/phy.h>
#include <linux/delay.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <dt-bindings/phy/phy.h>
#define HFC_TIMEOUT 100
#define SYSCFG_SELECT_SATA_MASK BIT(1)
#define SYSCFG_SELECT_SATA_POS 1
/* MiPHY365x register definitions */
#define RESET_REG 0x00
#define RST_PLL BIT(1)
#define RST_PLL_CAL BIT(2)
#define RST_RX BIT(4)
#define RST_MACRO BIT(7)
#define STATUS_REG 0x01
#define IDLL_RDY BIT(0)
#define PLL_RDY BIT(1)
#define DES_BIT_LOCK BIT(2)
#define DES_SYMBOL_LOCK BIT(3)
#define CTRL_REG 0x02
#define TERM_EN BIT(0)
#define PCI_EN BIT(2)
#define DES_BIT_LOCK_EN BIT(3)
#define TX_POL BIT(5)
#define INT_CTRL_REG 0x03
#define BOUNDARY1_REG 0x10
#define SPDSEL_SEL BIT(0)
#define BOUNDARY3_REG 0x12
#define TX_SPDSEL_GEN1_VAL 0
#define TX_SPDSEL_GEN2_VAL 0x01
#define TX_SPDSEL_GEN3_VAL 0x02
#define RX_SPDSEL_GEN1_VAL 0
#define RX_SPDSEL_GEN2_VAL (0x01 << 3)
#define RX_SPDSEL_GEN3_VAL (0x02 << 3)
#define PCIE_REG 0x16
#define BUF_SEL_REG 0x20
#define CONF_GEN_SEL_GEN3 0x02
#define CONF_GEN_SEL_GEN2 0x01
#define PD_VDDTFILTER BIT(4)
#define TXBUF1_REG 0x21
#define SWING_VAL 0x04
#define SWING_VAL_GEN1 0x03
#define PREEMPH_VAL (0x3 << 5)
#define TXBUF2_REG 0x22
#define TXSLEW_VAL 0x2
#define TXSLEW_VAL_GEN1 0x4
#define RXBUF_OFFSET_CTRL_REG 0x23
#define RXBUF_REG 0x25
#define SDTHRES_VAL 0x01
#define EQ_ON3 (0x03 << 4)
#define EQ_ON1 (0x01 << 4)
#define COMP_CTRL1_REG 0x40
#define START_COMSR BIT(0)
#define START_COMZC BIT(1)
#define COMSR_DONE BIT(2)
#define COMZC_DONE BIT(3)
#define COMP_AUTO_LOAD BIT(4)
#define COMP_CTRL2_REG 0x41
#define COMP_2MHZ_RAT_GEN1 0x1e
#define COMP_2MHZ_RAT 0xf
#define COMP_CTRL3_REG 0x42
#define COMSR_COMP_REF 0x33
#define COMP_IDLL_REG 0x47
#define COMZC_IDLL 0x2a
#define PLL_CTRL1_REG 0x50
#define PLL_START_CAL BIT(0)
#define BUF_EN BIT(2)
#define SYNCHRO_TX BIT(3)
#define SSC_EN BIT(6)
#define CONFIG_PLL BIT(7)
#define PLL_CTRL2_REG 0x51
#define BYPASS_PLL_CAL BIT(1)
#define PLL_RAT_REG 0x52
#define PLL_SSC_STEP_MSB_REG 0x56
#define PLL_SSC_STEP_MSB_VAL 0x03
#define PLL_SSC_STEP_LSB_REG 0x57
#define PLL_SSC_STEP_LSB_VAL 0x63
#define PLL_SSC_PER_MSB_REG 0x58
#define PLL_SSC_PER_MSB_VAL 0
#define PLL_SSC_PER_LSB_REG 0x59
#define PLL_SSC_PER_LSB_VAL 0xf1
#define IDLL_TEST_REG 0x72
#define START_CLK_HF BIT(6)
#define DES_BITLOCK_REG 0x86
#define BIT_LOCK_LEVEL 0x01
#define BIT_LOCK_CNT_512 (0x03 << 5)
struct miphy365x_phy {
struct phy *phy;
void __iomem *base;
bool pcie_tx_pol_inv;
bool sata_tx_pol_inv;
u32 sata_gen;
u32 ctrlreg;
u8 type;
};
struct miphy365x_dev {
struct device *dev;
struct regmap *regmap;
struct mutex miphy_mutex;
struct miphy365x_phy **phys;
int nphys;
};
/*
* These values are represented in Device tree. They are considered to be ABI
* and although they can be extended any existing values must not change.
*/
enum miphy_sata_gen {
SATA_GEN1 = 1,
SATA_GEN2,
SATA_GEN3
};
static u8 rx_tx_spd[] = {
0, /* GEN0 doesn't exist. */
TX_SPDSEL_GEN1_VAL | RX_SPDSEL_GEN1_VAL,
TX_SPDSEL_GEN2_VAL | RX_SPDSEL_GEN2_VAL,
TX_SPDSEL_GEN3_VAL | RX_SPDSEL_GEN3_VAL
};
/*
* This function selects the system configuration,
* either two SATA, one SATA and one PCIe, or two PCIe lanes.
*/
static int miphy365x_set_path(struct miphy365x_phy *miphy_phy,
struct miphy365x_dev *miphy_dev)
{
bool sata = (miphy_phy->type == PHY_TYPE_SATA);
return regmap_update_bits(miphy_dev->regmap,
miphy_phy->ctrlreg,
SYSCFG_SELECT_SATA_MASK,
sata << SYSCFG_SELECT_SATA_POS);
}
static int miphy365x_init_pcie_port(struct miphy365x_phy *miphy_phy,
struct miphy365x_dev *miphy_dev)
{
u8 val;
if (miphy_phy->pcie_tx_pol_inv) {
/* Invert Tx polarity and clear pci_txdetect_pol bit */
val = TERM_EN | PCI_EN | DES_BIT_LOCK_EN | TX_POL;
writeb_relaxed(val, miphy_phy->base + CTRL_REG);
writeb_relaxed(0x00, miphy_phy->base + PCIE_REG);
}
return 0;
}
static inline int miphy365x_hfc_not_rdy(struct miphy365x_phy *miphy_phy,
struct miphy365x_dev *miphy_dev)
{
unsigned long timeout = jiffies + msecs_to_jiffies(HFC_TIMEOUT);
u8 mask = IDLL_RDY | PLL_RDY;
u8 regval;
do {
regval = readb_relaxed(miphy_phy->base + STATUS_REG);
if (!(regval & mask))
return 0;
usleep_range(2000, 2500);
} while (time_before(jiffies, timeout));
dev_err(miphy_dev->dev, "HFC ready timeout!\n");
return -EBUSY;
}
static inline int miphy365x_rdy(struct miphy365x_phy *miphy_phy,
struct miphy365x_dev *miphy_dev)
{
unsigned long timeout = jiffies + msecs_to_jiffies(HFC_TIMEOUT);
u8 mask = IDLL_RDY | PLL_RDY;
u8 regval;
do {
regval = readb_relaxed(miphy_phy->base + STATUS_REG);
if ((regval & mask) == mask)
return 0;
usleep_range(2000, 2500);
} while (time_before(jiffies, timeout));
dev_err(miphy_dev->dev, "PHY not ready timeout!\n");
return -EBUSY;
}
static inline void miphy365x_set_comp(struct miphy365x_phy *miphy_phy,
struct miphy365x_dev *miphy_dev)
{
u8 val, mask;
if (miphy_phy->sata_gen == SATA_GEN1)
writeb_relaxed(COMP_2MHZ_RAT_GEN1,
miphy_phy->base + COMP_CTRL2_REG);
else
writeb_relaxed(COMP_2MHZ_RAT,
miphy_phy->base + COMP_CTRL2_REG);
if (miphy_phy->sata_gen != SATA_GEN3) {
writeb_relaxed(COMSR_COMP_REF,
miphy_phy->base + COMP_CTRL3_REG);
/*
* Force VCO current to value defined by address 0x5A
* and disable PCIe100Mref bit
* Enable auto load compensation for pll_i_bias
*/
writeb_relaxed(BYPASS_PLL_CAL, miphy_phy->base + PLL_CTRL2_REG);
writeb_relaxed(COMZC_IDLL, miphy_phy->base + COMP_IDLL_REG);
}
/*
* Force restart compensation and enable auto load
* for Comzc_Tx, Comzc_Rx and Comsr on macro
*/
val = START_COMSR | START_COMZC | COMP_AUTO_LOAD;
writeb_relaxed(val, miphy_phy->base + COMP_CTRL1_REG);
mask = COMSR_DONE | COMZC_DONE;
while ((readb_relaxed(miphy_phy->base + COMP_CTRL1_REG) & mask) != mask)
cpu_relax();
}
static inline void miphy365x_set_ssc(struct miphy365x_phy *miphy_phy,
struct miphy365x_dev *miphy_dev)
{
u8 val;
/*
* SSC Settings. SSC will be enabled through Link
* SSC Ampl. = 0.4%
* SSC Freq = 31KHz
*/
writeb_relaxed(PLL_SSC_STEP_MSB_VAL,
miphy_phy->base + PLL_SSC_STEP_MSB_REG);
writeb_relaxed(PLL_SSC_STEP_LSB_VAL,
miphy_phy->base + PLL_SSC_STEP_LSB_REG);
writeb_relaxed(PLL_SSC_PER_MSB_VAL,
miphy_phy->base + PLL_SSC_PER_MSB_REG);
writeb_relaxed(PLL_SSC_PER_LSB_VAL,
miphy_phy->base + PLL_SSC_PER_LSB_REG);
/* SSC Settings complete */
if (miphy_phy->sata_gen == SATA_GEN1) {
val = PLL_START_CAL | BUF_EN | SYNCHRO_TX | CONFIG_PLL;
writeb_relaxed(val, miphy_phy->base + PLL_CTRL1_REG);
} else {
val = SSC_EN | PLL_START_CAL | BUF_EN | SYNCHRO_TX | CONFIG_PLL;
writeb_relaxed(val, miphy_phy->base + PLL_CTRL1_REG);
}
}
static int miphy365x_init_sata_port(struct miphy365x_phy *miphy_phy,
struct miphy365x_dev *miphy_dev)
{
int ret;
u8 val;
/*
* Force PHY macro reset, PLL calibration reset, PLL reset
* and assert Deserializer Reset
*/
val = RST_PLL | RST_PLL_CAL | RST_RX | RST_MACRO;
writeb_relaxed(val, miphy_phy->base + RESET_REG);
if (miphy_phy->sata_tx_pol_inv)
writeb_relaxed(TX_POL, miphy_phy->base + CTRL_REG);
/*
* Force macro1 to use rx_lspd, tx_lspd
* Force Rx_Clock on first I-DLL phase
* Force Des in HP mode on macro, rx_lspd, tx_lspd for Gen2/3
*/
writeb_relaxed(SPDSEL_SEL, miphy_phy->base + BOUNDARY1_REG);
writeb_relaxed(START_CLK_HF, miphy_phy->base + IDLL_TEST_REG);
val = rx_tx_spd[miphy_phy->sata_gen];
writeb_relaxed(val, miphy_phy->base + BOUNDARY3_REG);
/* Wait for HFC_READY = 0 */
ret = miphy365x_hfc_not_rdy(miphy_phy, miphy_dev);
if (ret)
return ret;
/* Compensation Recalibration */
miphy365x_set_comp(miphy_phy, miphy_dev);
switch (miphy_phy->sata_gen) {
case SATA_GEN3:
/*
* TX Swing target 550-600mv peak to peak diff
* Tx Slew target 90-110ps rising/falling time
* Rx Eq ON3, Sigdet threshold SDTH1
*/
val = PD_VDDTFILTER | CONF_GEN_SEL_GEN3;
writeb_relaxed(val, miphy_phy->base + BUF_SEL_REG);
val = SWING_VAL | PREEMPH_VAL;
writeb_relaxed(val, miphy_phy->base + TXBUF1_REG);
writeb_relaxed(TXSLEW_VAL, miphy_phy->base + TXBUF2_REG);
writeb_relaxed(0x00, miphy_phy->base + RXBUF_OFFSET_CTRL_REG);
val = SDTHRES_VAL | EQ_ON3;
writeb_relaxed(val, miphy_phy->base + RXBUF_REG);
break;
case SATA_GEN2:
/*
* conf gen sel=0x1 to program Gen2 banked registers
* VDDT filter ON
* Tx Swing target 550-600mV peak-to-peak diff
* Tx Slew target 90-110 ps rising/falling time
* RX Equalization ON1, Sigdet threshold SDTH1
*/
writeb_relaxed(CONF_GEN_SEL_GEN2,
miphy_phy->base + BUF_SEL_REG);
writeb_relaxed(SWING_VAL, miphy_phy->base + TXBUF1_REG);
writeb_relaxed(TXSLEW_VAL, miphy_phy->base + TXBUF2_REG);
val = SDTHRES_VAL | EQ_ON1;
writeb_relaxed(val, miphy_phy->base + RXBUF_REG);
break;
case SATA_GEN1:
/*
* conf gen sel = 00b to program Gen1 banked registers
* VDDT filter ON
* Tx Swing target 500-550mV peak-to-peak diff
* Tx Slew target120-140 ps rising/falling time
*/
writeb_relaxed(PD_VDDTFILTER, miphy_phy->base + BUF_SEL_REG);
writeb_relaxed(SWING_VAL_GEN1, miphy_phy->base + TXBUF1_REG);
writeb_relaxed(TXSLEW_VAL_GEN1, miphy_phy->base + TXBUF2_REG);
break;
default:
break;
}
/* Force Macro1 in partial mode & release pll cal reset */
writeb_relaxed(RST_RX, miphy_phy->base + RESET_REG);
usleep_range(100, 150);
miphy365x_set_ssc(miphy_phy, miphy_dev);
/* Wait for phy_ready */
ret = miphy365x_rdy(miphy_phy, miphy_dev);
if (ret)
return ret;
/*
* Enable macro1 to use rx_lspd & tx_lspd
* Release Rx_Clock on first I-DLL phase on macro1
* Assert deserializer reset
* des_bit_lock_en is set
* bit lock detection strength
* Deassert deserializer reset
*/
writeb_relaxed(0x00, miphy_phy->base + BOUNDARY1_REG);
writeb_relaxed(0x00, miphy_phy->base + IDLL_TEST_REG);
writeb_relaxed(RST_RX, miphy_phy->base + RESET_REG);
val = miphy_phy->sata_tx_pol_inv ?
(TX_POL | DES_BIT_LOCK_EN) : DES_BIT_LOCK_EN;
writeb_relaxed(val, miphy_phy->base + CTRL_REG);
val = BIT_LOCK_CNT_512 | BIT_LOCK_LEVEL;
writeb_relaxed(val, miphy_phy->base + DES_BITLOCK_REG);
writeb_relaxed(0x00, miphy_phy->base + RESET_REG);
return 0;
}
static int miphy365x_init(struct phy *phy)
{
struct miphy365x_phy *miphy_phy = phy_get_drvdata(phy);
struct miphy365x_dev *miphy_dev = dev_get_drvdata(phy->dev.parent);
int ret = 0;
mutex_lock(&miphy_dev->miphy_mutex);
ret = miphy365x_set_path(miphy_phy, miphy_dev);
if (ret) {
mutex_unlock(&miphy_dev->miphy_mutex);
return ret;
}
/* Initialise Miphy for PCIe or SATA */
if (miphy_phy->type == PHY_TYPE_PCIE)
ret = miphy365x_init_pcie_port(miphy_phy, miphy_dev);
else
ret = miphy365x_init_sata_port(miphy_phy, miphy_dev);
mutex_unlock(&miphy_dev->miphy_mutex);
return ret;
}
static int miphy365x_get_addr(struct device *dev,
struct miphy365x_phy *miphy_phy, int index)
{
struct device_node *phynode = miphy_phy->phy->dev.of_node;
const char *name;
int type = miphy_phy->type;
int ret;
ret = of_property_read_string_index(phynode, "reg-names", index, &name);
if (ret) {
dev_err(dev, "no reg-names property not found\n");
return ret;
}
if (!((!strncmp(name, "sata", 4) && type == PHY_TYPE_SATA) ||
(!strncmp(name, "pcie", 4) && type == PHY_TYPE_PCIE)))
return 0;
miphy_phy->base = of_iomap(phynode, index);
if (!miphy_phy->base) {
dev_err(dev, "Failed to map %s\n", phynode->full_name);
return -EINVAL;
}
return 0;
}
static struct phy *miphy365x_xlate(struct device *dev,
struct of_phandle_args *args)
{
struct miphy365x_dev *miphy_dev = dev_get_drvdata(dev);
struct miphy365x_phy *miphy_phy = NULL;
struct device_node *phynode = args->np;
int ret, index;
if (args->args_count != 1) {
dev_err(dev, "Invalid number of cells in 'phy' property\n");
return ERR_PTR(-EINVAL);
}
for (index = 0; index < miphy_dev->nphys; index++)
if (phynode == miphy_dev->phys[index]->phy->dev.of_node) {
miphy_phy = miphy_dev->phys[index];
break;
}
if (!miphy_phy) {
dev_err(dev, "Failed to find appropriate phy\n");
return ERR_PTR(-EINVAL);
}
miphy_phy->type = args->args[0];
if (!(miphy_phy->type == PHY_TYPE_SATA ||
miphy_phy->type == PHY_TYPE_PCIE)) {
dev_err(dev, "Unsupported device type: %d\n", miphy_phy->type);
return ERR_PTR(-EINVAL);
}
/* Each port handles SATA and PCIE - third entry is always sysconf. */
for (index = 0; index < 3; index++) {
ret = miphy365x_get_addr(dev, miphy_phy, index);
if (ret < 0)
return ERR_PTR(ret);
}
return miphy_phy->phy;
}
static const struct phy_ops miphy365x_ops = {
.init = miphy365x_init,
.owner = THIS_MODULE,
};
static int miphy365x_of_probe(struct device_node *phynode,
struct miphy365x_phy *miphy_phy)
{
of_property_read_u32(phynode, "st,sata-gen", &miphy_phy->sata_gen);
if (!miphy_phy->sata_gen)
miphy_phy->sata_gen = SATA_GEN1;
miphy_phy->pcie_tx_pol_inv =
of_property_read_bool(phynode, "st,pcie-tx-pol-inv");
miphy_phy->sata_tx_pol_inv =
of_property_read_bool(phynode, "st,sata-tx-pol-inv");
return 0;
}
static int miphy365x_probe(struct platform_device *pdev)
{
struct device_node *child, *np = pdev->dev.of_node;
struct miphy365x_dev *miphy_dev;
struct phy_provider *provider;
struct phy *phy;
int ret, port = 0;
miphy_dev = devm_kzalloc(&pdev->dev, sizeof(*miphy_dev), GFP_KERNEL);
if (!miphy_dev)
return -ENOMEM;
miphy_dev->nphys = of_get_child_count(np);
miphy_dev->phys = devm_kcalloc(&pdev->dev, miphy_dev->nphys,
sizeof(*miphy_dev->phys), GFP_KERNEL);
if (!miphy_dev->phys)
return -ENOMEM;
miphy_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
if (IS_ERR(miphy_dev->regmap)) {
dev_err(miphy_dev->dev, "No syscfg phandle specified\n");
return PTR_ERR(miphy_dev->regmap);
}
miphy_dev->dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, miphy_dev);
mutex_init(&miphy_dev->miphy_mutex);
for_each_child_of_node(np, child) {
struct miphy365x_phy *miphy_phy;
miphy_phy = devm_kzalloc(&pdev->dev, sizeof(*miphy_phy),
GFP_KERNEL);
if (!miphy_phy) {
ret = -ENOMEM;
goto put_child;
}
miphy_dev->phys[port] = miphy_phy;
phy = devm_phy_create(&pdev->dev, child, &miphy365x_ops);
if (IS_ERR(phy)) {
dev_err(&pdev->dev, "failed to create PHY\n");
ret = PTR_ERR(phy);
goto put_child;
}
miphy_dev->phys[port]->phy = phy;
ret = miphy365x_of_probe(child, miphy_phy);
if (ret)
goto put_child;
phy_set_drvdata(phy, miphy_dev->phys[port]);
port++;
/* sysconfig offsets are indexed from 1 */
ret = of_property_read_u32_index(np, "st,syscfg", port,
&miphy_phy->ctrlreg);
if (ret) {
dev_err(&pdev->dev, "No sysconfig offset found\n");
goto put_child;
}
}
provider = devm_of_phy_provider_register(&pdev->dev, miphy365x_xlate);
return PTR_ERR_OR_ZERO(provider);
put_child:
of_node_put(child);
return ret;
}
static const struct of_device_id miphy365x_of_match[] = {
{ .compatible = "st,miphy365x-phy", },
{ },
};
MODULE_DEVICE_TABLE(of, miphy365x_of_match);
static struct platform_driver miphy365x_driver = {
.probe = miphy365x_probe,
.driver = {
.name = "miphy365x-phy",
.of_match_table = miphy365x_of_match,
}
};
module_platform_driver(miphy365x_driver);
MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@st.com>");
MODULE_DESCRIPTION("STMicroelectronics miphy365x driver");
MODULE_LICENSE("GPL v2");
...@@ -70,6 +70,7 @@ ...@@ -70,6 +70,7 @@
#define USB2_LINECTRL1_DP_RPD BIT(18) #define USB2_LINECTRL1_DP_RPD BIT(18)
#define USB2_LINECTRL1_DMRPD_EN BIT(17) #define USB2_LINECTRL1_DMRPD_EN BIT(17)
#define USB2_LINECTRL1_DM_RPD BIT(16) #define USB2_LINECTRL1_DM_RPD BIT(16)
#define USB2_LINECTRL1_OPMODE_NODRV BIT(6)
/* ADPCTRL */ /* ADPCTRL */
#define USB2_ADPCTRL_OTGSESSVLD BIT(20) #define USB2_ADPCTRL_OTGSESSVLD BIT(20)
...@@ -161,6 +162,43 @@ static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch) ...@@ -161,6 +162,43 @@ static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch)
schedule_work(&ch->work); schedule_work(&ch->work);
} }
static void rcar_gen3_init_for_b_host(struct rcar_gen3_chan *ch)
{
void __iomem *usb2_base = ch->base;
u32 val;
val = readl(usb2_base + USB2_LINECTRL1);
writel(val | USB2_LINECTRL1_OPMODE_NODRV, usb2_base + USB2_LINECTRL1);
rcar_gen3_set_linectrl(ch, 1, 1);
rcar_gen3_set_host_mode(ch, 1);
rcar_gen3_enable_vbus_ctrl(ch, 0);
val = readl(usb2_base + USB2_LINECTRL1);
writel(val & ~USB2_LINECTRL1_OPMODE_NODRV, usb2_base + USB2_LINECTRL1);
}
static void rcar_gen3_init_for_a_peri(struct rcar_gen3_chan *ch)
{
rcar_gen3_set_linectrl(ch, 0, 1);
rcar_gen3_set_host_mode(ch, 0);
rcar_gen3_enable_vbus_ctrl(ch, 1);
}
static void rcar_gen3_init_from_a_peri_to_a_host(struct rcar_gen3_chan *ch)
{
void __iomem *usb2_base = ch->base;
u32 val;
val = readl(usb2_base + USB2_OBINTEN);
writel(val & ~USB2_OBINT_BITS, usb2_base + USB2_OBINTEN);
rcar_gen3_enable_vbus_ctrl(ch, 0);
rcar_gen3_init_for_host(ch);
writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN);
}
static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch)
{ {
return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG);
...@@ -174,6 +212,65 @@ static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch) ...@@ -174,6 +212,65 @@ static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch)
rcar_gen3_init_for_peri(ch); rcar_gen3_init_for_peri(ch);
} }
static bool rcar_gen3_is_host(struct rcar_gen3_chan *ch)
{
return !(readl(ch->base + USB2_COMMCTRL) & USB2_COMMCTRL_OTG_PERI);
}
static ssize_t role_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct rcar_gen3_chan *ch = dev_get_drvdata(dev);
bool is_b_device, is_host, new_mode_is_host;
if (!ch->has_otg || !ch->phy->init_count)
return -EIO;
/*
* is_b_device: true is B-Device. false is A-Device.
* If {new_mode_}is_host: true is Host mode. false is Peripheral mode.
*/
is_b_device = rcar_gen3_check_id(ch);
is_host = rcar_gen3_is_host(ch);
if (!strncmp(buf, "host", strlen("host")))
new_mode_is_host = true;
else if (!strncmp(buf, "peripheral", strlen("peripheral")))
new_mode_is_host = false;
else
return -EINVAL;
/* If current and new mode is the same, this returns the error */
if (is_host == new_mode_is_host)
return -EINVAL;
if (new_mode_is_host) { /* And is_host must be false */
if (!is_b_device) /* A-Peripheral */
rcar_gen3_init_from_a_peri_to_a_host(ch);
else /* B-Peripheral */
rcar_gen3_init_for_b_host(ch);
} else { /* And is_host must be true */
if (!is_b_device) /* A-Host */
rcar_gen3_init_for_a_peri(ch);
else /* B-Host */
rcar_gen3_init_for_peri(ch);
}
return count;
}
static ssize_t role_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct rcar_gen3_chan *ch = dev_get_drvdata(dev);
if (!ch->has_otg || !ch->phy->init_count)
return -EIO;
return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" :
"peripheral");
}
static DEVICE_ATTR_RW(role);
static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
{ {
void __iomem *usb2_base = ch->base; void __iomem *usb2_base = ch->base;
...@@ -351,21 +448,40 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) ...@@ -351,21 +448,40 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
channel->vbus = NULL; channel->vbus = NULL;
} }
platform_set_drvdata(pdev, channel);
phy_set_drvdata(channel->phy, channel); phy_set_drvdata(channel->phy, channel);
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (IS_ERR(provider)) if (IS_ERR(provider)) {
dev_err(dev, "Failed to register PHY provider\n"); dev_err(dev, "Failed to register PHY provider\n");
} else if (channel->has_otg) {
int ret;
ret = device_create_file(dev, &dev_attr_role);
if (ret < 0)
return ret;
}
return PTR_ERR_OR_ZERO(provider); return PTR_ERR_OR_ZERO(provider);
} }
static int rcar_gen3_phy_usb2_remove(struct platform_device *pdev)
{
struct rcar_gen3_chan *channel = platform_get_drvdata(pdev);
if (channel->has_otg)
device_remove_file(&pdev->dev, &dev_attr_role);
return 0;
};
static struct platform_driver rcar_gen3_phy_usb2_driver = { static struct platform_driver rcar_gen3_phy_usb2_driver = {
.driver = { .driver = {
.name = "phy_rcar_gen3_usb2", .name = "phy_rcar_gen3_usb2",
.of_match_table = rcar_gen3_phy_usb2_match_table, .of_match_table = rcar_gen3_phy_usb2_match_table,
}, },
.probe = rcar_gen3_phy_usb2_probe, .probe = rcar_gen3_phy_usb2_probe,
.remove = rcar_gen3_phy_usb2_remove,
}; };
module_platform_driver(rcar_gen3_phy_usb2_driver); module_platform_driver(rcar_gen3_phy_usb2_driver);
......
...@@ -132,7 +132,7 @@ static int rockchip_emmc_phy_power(struct phy *phy, bool on_off) ...@@ -132,7 +132,7 @@ static int rockchip_emmc_phy_power(struct phy *phy, bool on_off)
default: default:
ideal_rate = 200000000; ideal_rate = 200000000;
break; break;
}; }
diff = (rate > ideal_rate) ? diff = (rate > ideal_rate) ?
rate - ideal_rate : ideal_rate - rate; rate - ideal_rate : ideal_rate - rate;
......
...@@ -103,7 +103,7 @@ static void s5pv210_isol(struct samsung_usb2_phy_instance *inst, bool on) ...@@ -103,7 +103,7 @@ static void s5pv210_isol(struct samsung_usb2_phy_instance *inst, bool on)
break; break;
default: default:
return; return;
}; }
regmap_update_bits(drv->reg_pmu, S5PV210_USB_ISOL_OFFSET, regmap_update_bits(drv->reg_pmu, S5PV210_USB_ISOL_OFFSET,
mask, on ? 0 : mask); mask, on ? 0 : mask);
...@@ -127,7 +127,7 @@ static void s5pv210_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on) ...@@ -127,7 +127,7 @@ static void s5pv210_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
rstbits = S5PV210_URSTCON_PHY1_ALL | rstbits = S5PV210_URSTCON_PHY1_ALL |
S5PV210_URSTCON_HOST_LINK_ALL; S5PV210_URSTCON_HOST_LINK_ALL;
break; break;
}; }
if (on) { if (on) {
writel(drv->ref_reg_val, drv->reg_phy + S5PV210_UPHYCLK); writel(drv->ref_reg_val, drv->reg_phy + S5PV210_UPHYCLK);
......
/*
* Copyright (C) 2014 STMicroelectronics
*
* STMicroelectronics PHY driver for STiH41x USB.
*
* Author: Maxime Coquelin <maxime.coquelin@st.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
*/
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/clk.h>
#include <linux/phy/phy.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#define SYSCFG332 0x80
#define SYSCFG2520 0x820
/**
* struct stih41x_usb_cfg - SoC specific PHY register mapping
* @syscfg: Offset in syscfg registers bank
* @cfg_mask: Bits mask for PHY configuration
* @cfg: Static configuration value for PHY
* @oscok: Notify the PHY oscillator clock is ready
* Setting this bit enable the PHY
*/
struct stih41x_usb_cfg {
u32 syscfg;
u32 cfg_mask;
u32 cfg;
u32 oscok;
};
/**
* struct stih41x_usb_phy - Private data for the PHY
* @dev: device for this controller
* @regmap: Syscfg registers bank in which PHY is configured
* @cfg: SoC specific PHY register mapping
* @clk: Oscillator used by the PHY
*/
struct stih41x_usb_phy {
struct device *dev;
struct regmap *regmap;
const struct stih41x_usb_cfg *cfg;
struct clk *clk;
};
static struct stih41x_usb_cfg stih415_usb_phy_cfg = {
.syscfg = SYSCFG332,
.cfg_mask = 0x3f,
.cfg = 0x38,
.oscok = BIT(6),
};
static struct stih41x_usb_cfg stih416_usb_phy_cfg = {
.syscfg = SYSCFG2520,
.cfg_mask = 0x33f,
.cfg = 0x238,
.oscok = BIT(6),
};
static int stih41x_usb_phy_init(struct phy *phy)
{
struct stih41x_usb_phy *phy_dev = phy_get_drvdata(phy);
return regmap_update_bits(phy_dev->regmap, phy_dev->cfg->syscfg,
phy_dev->cfg->cfg_mask, phy_dev->cfg->cfg);
}
static int stih41x_usb_phy_power_on(struct phy *phy)
{
struct stih41x_usb_phy *phy_dev = phy_get_drvdata(phy);
int ret;
ret = clk_prepare_enable(phy_dev->clk);
if (ret) {
dev_err(phy_dev->dev, "Failed to enable osc_phy clock\n");
return ret;
}
ret = regmap_update_bits(phy_dev->regmap, phy_dev->cfg->syscfg,
phy_dev->cfg->oscok, phy_dev->cfg->oscok);
if (ret)
clk_disable_unprepare(phy_dev->clk);
return ret;
}
static int stih41x_usb_phy_power_off(struct phy *phy)
{
struct stih41x_usb_phy *phy_dev = phy_get_drvdata(phy);
int ret;
ret = regmap_update_bits(phy_dev->regmap, phy_dev->cfg->syscfg,
phy_dev->cfg->oscok, 0);
if (ret) {
dev_err(phy_dev->dev, "Failed to clear oscok bit\n");
return ret;
}
clk_disable_unprepare(phy_dev->clk);
return 0;
}
static const struct phy_ops stih41x_usb_phy_ops = {
.init = stih41x_usb_phy_init,
.power_on = stih41x_usb_phy_power_on,
.power_off = stih41x_usb_phy_power_off,
.owner = THIS_MODULE,
};
static const struct of_device_id stih41x_usb_phy_of_match[];
static int stih41x_usb_phy_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match;
struct stih41x_usb_phy *phy_dev;
struct device *dev = &pdev->dev;
struct phy_provider *phy_provider;
struct phy *phy;
phy_dev = devm_kzalloc(dev, sizeof(*phy_dev), GFP_KERNEL);
if (!phy_dev)
return -ENOMEM;
match = of_match_device(stih41x_usb_phy_of_match, &pdev->dev);
if (!match)
return -ENODEV;
phy_dev->cfg = match->data;
phy_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
if (IS_ERR(phy_dev->regmap)) {
dev_err(dev, "No syscfg phandle specified\n");
return PTR_ERR(phy_dev->regmap);
}
phy_dev->clk = devm_clk_get(dev, "osc_phy");
if (IS_ERR(phy_dev->clk)) {
dev_err(dev, "osc_phy clk not found\n");
return PTR_ERR(phy_dev->clk);
}
phy = devm_phy_create(dev, NULL, &stih41x_usb_phy_ops);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create phy\n");
return PTR_ERR(phy);
}
phy_dev->dev = dev;
phy_set_drvdata(phy, phy_dev);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id stih41x_usb_phy_of_match[] = {
{ .compatible = "st,stih415-usb-phy", .data = &stih415_usb_phy_cfg },
{ .compatible = "st,stih416-usb-phy", .data = &stih416_usb_phy_cfg },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, stih41x_usb_phy_of_match);
static struct platform_driver stih41x_usb_phy_driver = {
.probe = stih41x_usb_phy_probe,
.driver = {
.name = "stih41x-usb-phy",
.of_match_table = stih41x_usb_phy_of_match,
}
};
module_platform_driver(stih41x_usb_phy_driver);
MODULE_AUTHOR("Maxime Coquelin <maxime.coquelin@st.com>");
MODULE_DESCRIPTION("STMicroelectronics USB PHY driver for STiH41x series");
MODULE_LICENSE("GPL v2");
...@@ -436,25 +436,31 @@ static int sun4i_usb_phy_set_mode(struct phy *_phy, enum phy_mode mode) ...@@ -436,25 +436,31 @@ static int sun4i_usb_phy_set_mode(struct phy *_phy, enum phy_mode mode)
{ {
struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy); struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
int new_mode;
if (phy->index != 0) if (phy->index != 0)
return -EINVAL; return -EINVAL;
switch (mode) { switch (mode) {
case PHY_MODE_USB_HOST: case PHY_MODE_USB_HOST:
data->dr_mode = USB_DR_MODE_HOST; new_mode = USB_DR_MODE_HOST;
break; break;
case PHY_MODE_USB_DEVICE: case PHY_MODE_USB_DEVICE:
data->dr_mode = USB_DR_MODE_PERIPHERAL; new_mode = USB_DR_MODE_PERIPHERAL;
break; break;
case PHY_MODE_USB_OTG: case PHY_MODE_USB_OTG:
data->dr_mode = USB_DR_MODE_OTG; new_mode = USB_DR_MODE_OTG;
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
dev_info(&_phy->dev, "Changing dr_mode to %d\n", (int)data->dr_mode); if (new_mode != data->dr_mode) {
dev_info(&_phy->dev, "Changing dr_mode to %d\n", new_mode);
data->dr_mode = new_mode;
}
data->id_det = -1; /* Force reprocessing of id */
data->force_session_end = true; data->force_session_end = true;
queue_delayed_work(system_wq, &data->detect, 0); queue_delayed_work(system_wq, &data->detect, 0);
......
...@@ -537,10 +537,7 @@ static int ti_pipe3_get_pll_base(struct ti_pipe3 *phy) ...@@ -537,10 +537,7 @@ static int ti_pipe3_get_pll_base(struct ti_pipe3 *phy)
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"pll_ctrl"); "pll_ctrl");
phy->pll_ctrl_base = devm_ioremap_resource(dev, res); phy->pll_ctrl_base = devm_ioremap_resource(dev, res);
if (IS_ERR(phy->pll_ctrl_base)) return PTR_ERR_OR_ZERO(phy->pll_ctrl_base);
return PTR_ERR(phy->pll_ctrl_base);
return 0;
} }
static int ti_pipe3_probe(struct platform_device *pdev) static int ti_pipe3_probe(struct platform_device *pdev)
...@@ -592,10 +589,7 @@ static int ti_pipe3_probe(struct platform_device *pdev) ...@@ -592,10 +589,7 @@ static int ti_pipe3_probe(struct platform_device *pdev)
ti_pipe3_power_off(generic_phy); ti_pipe3_power_off(generic_phy);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (IS_ERR(phy_provider)) return PTR_ERR_OR_ZERO(phy_provider);
return PTR_ERR(phy_provider);
return 0;
} }
static int ti_pipe3_remove(struct platform_device *pdev) static int ti_pipe3_remove(struct platform_device *pdev)
......
...@@ -317,6 +317,9 @@ static enum musb_vbus_id_status ...@@ -317,6 +317,9 @@ static enum musb_vbus_id_status
linkstat = MUSB_VBUS_OFF; linkstat = MUSB_VBUS_OFF;
} }
kobject_uevent(&twl->dev->kobj, linkstat == MUSB_VBUS_VALID
? KOBJ_ONLINE : KOBJ_OFFLINE);
dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n", dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n",
status, status, linkstat); status, status, linkstat);
......
...@@ -1483,7 +1483,6 @@ static int tegra124_usb3_port_enable(struct tegra_xusb_port *port) ...@@ -1483,7 +1483,6 @@ static int tegra124_usb3_port_enable(struct tegra_xusb_port *port)
struct tegra_xusb_padctl *padctl = port->padctl; struct tegra_xusb_padctl *padctl = port->padctl;
struct tegra_xusb_lane *lane = usb3->base.lane; struct tegra_xusb_lane *lane = usb3->base.lane;
unsigned int index = port->index, offset; unsigned int index = port->index, offset;
int ret = 0;
u32 value; u32 value;
value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP); value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
...@@ -1612,7 +1611,7 @@ static int tegra124_usb3_port_enable(struct tegra_xusb_port *port) ...@@ -1612,7 +1611,7 @@ static int tegra124_usb3_port_enable(struct tegra_xusb_port *port)
value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN(index); value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN(index);
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
return ret; return 0;
} }
static void tegra124_usb3_port_disable(struct tegra_xusb_port *port) static void tegra124_usb3_port_disable(struct tegra_xusb_port *port)
......
...@@ -561,10 +561,7 @@ static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2) ...@@ -561,10 +561,7 @@ static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2)
usb2->internal = of_property_read_bool(np, "nvidia,internal"); usb2->internal = of_property_read_bool(np, "nvidia,internal");
usb2->supply = devm_regulator_get(&port->dev, "vbus"); usb2->supply = devm_regulator_get(&port->dev, "vbus");
if (IS_ERR(usb2->supply)) return PTR_ERR_OR_ZERO(usb2->supply);
return PTR_ERR(usb2->supply);
return 0;
} }
static int tegra_xusb_add_usb2_port(struct tegra_xusb_padctl *padctl, static int tegra_xusb_add_usb2_port(struct tegra_xusb_padctl *padctl,
...@@ -731,10 +728,7 @@ static int tegra_xusb_usb3_port_parse_dt(struct tegra_xusb_usb3_port *usb3) ...@@ -731,10 +728,7 @@ static int tegra_xusb_usb3_port_parse_dt(struct tegra_xusb_usb3_port *usb3)
usb3->internal = of_property_read_bool(np, "nvidia,internal"); usb3->internal = of_property_read_bool(np, "nvidia,internal");
usb3->supply = devm_regulator_get(&port->dev, "vbus"); usb3->supply = devm_regulator_get(&port->dev, "vbus");
if (IS_ERR(usb3->supply)) return PTR_ERR_OR_ZERO(usb3->supply);
return PTR_ERR(usb3->supply);
return 0;
} }
static int tegra_xusb_add_usb3_port(struct tegra_xusb_padctl *padctl, static int tegra_xusb_add_usb3_port(struct tegra_xusb_padctl *padctl,
......
...@@ -95,6 +95,8 @@ source "drivers/usb/usbip/Kconfig" ...@@ -95,6 +95,8 @@ source "drivers/usb/usbip/Kconfig"
endif endif
source "drivers/usb/mtu3/Kconfig"
source "drivers/usb/musb/Kconfig" source "drivers/usb/musb/Kconfig"
source "drivers/usb/dwc3/Kconfig" source "drivers/usb/dwc3/Kconfig"
......
...@@ -12,6 +12,7 @@ obj-$(CONFIG_USB_DWC2) += dwc2/ ...@@ -12,6 +12,7 @@ obj-$(CONFIG_USB_DWC2) += dwc2/
obj-$(CONFIG_USB_ISP1760) += isp1760/ obj-$(CONFIG_USB_ISP1760) += isp1760/
obj-$(CONFIG_USB_MON) += mon/ obj-$(CONFIG_USB_MON) += mon/
obj-$(CONFIG_USB_MTU3) += mtu3/
obj-$(CONFIG_PCI) += host/ obj-$(CONFIG_PCI) += host/
obj-$(CONFIG_USB_EHCI_HCD) += host/ obj-$(CONFIG_USB_EHCI_HCD) += host/
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/usb/chipidea.h> #include <linux/usb/chipidea.h>
#include <linux/usb/of.h>
#include <linux/clk.h> #include <linux/clk.h>
#include "ci.h" #include "ci.h"
...@@ -146,6 +147,9 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev) ...@@ -146,6 +147,9 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
if (of_find_property(np, "external-vbus-divider", NULL)) if (of_find_property(np, "external-vbus-divider", NULL))
data->evdo = 1; data->evdo = 1;
if (of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI)
data->ulpi = 1;
return data; return data;
} }
......
...@@ -19,6 +19,7 @@ struct imx_usbmisc_data { ...@@ -19,6 +19,7 @@ struct imx_usbmisc_data {
unsigned int disable_oc:1; /* over current detect disabled */ unsigned int disable_oc:1; /* over current detect disabled */
unsigned int oc_polarity:1; /* over current polarity if oc enabled */ unsigned int oc_polarity:1; /* over current polarity if oc enabled */
unsigned int evdo:1; /* set external vbus divider option */ unsigned int evdo:1; /* set external vbus divider option */
unsigned int ulpi:1; /* connected to an ULPI phy */
}; };
int imx_usbmisc_init(struct imx_usbmisc_data *); int imx_usbmisc_init(struct imx_usbmisc_data *);
......
...@@ -365,7 +365,7 @@ static int add_td_to_list(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq, ...@@ -365,7 +365,7 @@ static int add_td_to_list(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq,
if (hwreq->req.length == 0 if (hwreq->req.length == 0
|| hwreq->req.length % hwep->ep.maxpacket) || hwreq->req.length % hwep->ep.maxpacket)
mul++; mul++;
node->ptr->token |= mul << __ffs(TD_MULTO); node->ptr->token |= cpu_to_le32(mul << __ffs(TD_MULTO));
} }
temp = (u32) (hwreq->req.dma + hwreq->req.actual); temp = (u32) (hwreq->req.dma + hwreq->req.actual);
...@@ -504,7 +504,7 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq) ...@@ -504,7 +504,7 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
if (hwreq->req.length == 0 if (hwreq->req.length == 0
|| hwreq->req.length % hwep->ep.maxpacket) || hwreq->req.length % hwep->ep.maxpacket)
mul++; mul++;
hwep->qh.ptr->cap |= mul << __ffs(QH_MULT); hwep->qh.ptr->cap |= cpu_to_le32(mul << __ffs(QH_MULT));
} }
ret = hw_ep_prime(ci, hwep->num, hwep->dir, ret = hw_ep_prime(ci, hwep->num, hwep->dir,
...@@ -529,7 +529,7 @@ static void free_pending_td(struct ci_hw_ep *hwep) ...@@ -529,7 +529,7 @@ static void free_pending_td(struct ci_hw_ep *hwep)
static int reprime_dtd(struct ci_hdrc *ci, struct ci_hw_ep *hwep, static int reprime_dtd(struct ci_hdrc *ci, struct ci_hw_ep *hwep,
struct td_node *node) struct td_node *node)
{ {
hwep->qh.ptr->td.next = node->dma; hwep->qh.ptr->td.next = cpu_to_le32(node->dma);
hwep->qh.ptr->td.token &= hwep->qh.ptr->td.token &=
cpu_to_le32(~(TD_STATUS_HALTED | TD_STATUS_ACTIVE)); cpu_to_le32(~(TD_STATUS_HALTED | TD_STATUS_ACTIVE));
...@@ -821,7 +821,7 @@ static int _ep_queue(struct usb_ep *ep, struct usb_request *req, ...@@ -821,7 +821,7 @@ static int _ep_queue(struct usb_ep *ep, struct usb_request *req,
} }
if (usb_endpoint_xfer_isoc(hwep->ep.desc) && if (usb_endpoint_xfer_isoc(hwep->ep.desc) &&
hwreq->req.length > (1 + hwep->ep.mult) * hwep->ep.maxpacket) { hwreq->req.length > hwep->ep.mult * hwep->ep.maxpacket) {
dev_err(hwep->ci->dev, "request length too big for isochronous\n"); dev_err(hwep->ci->dev, "request length too big for isochronous\n");
return -EMSGSIZE; return -EMSGSIZE;
} }
...@@ -1253,8 +1253,8 @@ static int ep_enable(struct usb_ep *ep, ...@@ -1253,8 +1253,8 @@ static int ep_enable(struct usb_ep *ep,
hwep->num = usb_endpoint_num(desc); hwep->num = usb_endpoint_num(desc);
hwep->type = usb_endpoint_type(desc); hwep->type = usb_endpoint_type(desc);
hwep->ep.maxpacket = usb_endpoint_maxp(desc) & 0x07ff; hwep->ep.maxpacket = usb_endpoint_maxp(desc);
hwep->ep.mult = QH_ISO_MULT(usb_endpoint_maxp(desc)); hwep->ep.mult = usb_endpoint_maxp_mult(desc);
if (hwep->type == USB_ENDPOINT_XFER_CONTROL) if (hwep->type == USB_ENDPOINT_XFER_CONTROL)
cap |= QH_IOS; cap |= QH_IOS;
......
...@@ -22,11 +22,11 @@ ...@@ -22,11 +22,11 @@
/* DMA layout of transfer descriptors */ /* DMA layout of transfer descriptors */
struct ci_hw_td { struct ci_hw_td {
/* 0 */ /* 0 */
u32 next; __le32 next;
#define TD_TERMINATE BIT(0) #define TD_TERMINATE BIT(0)
#define TD_ADDR_MASK (0xFFFFFFEUL << 5) #define TD_ADDR_MASK (0xFFFFFFEUL << 5)
/* 1 */ /* 1 */
u32 token; __le32 token;
#define TD_STATUS (0x00FFUL << 0) #define TD_STATUS (0x00FFUL << 0)
#define TD_STATUS_TR_ERR BIT(3) #define TD_STATUS_TR_ERR BIT(3)
#define TD_STATUS_DT_ERR BIT(5) #define TD_STATUS_DT_ERR BIT(5)
...@@ -36,7 +36,7 @@ struct ci_hw_td { ...@@ -36,7 +36,7 @@ struct ci_hw_td {
#define TD_IOC BIT(15) #define TD_IOC BIT(15)
#define TD_TOTAL_BYTES (0x7FFFUL << 16) #define TD_TOTAL_BYTES (0x7FFFUL << 16)
/* 2 */ /* 2 */
u32 page[5]; __le32 page[5];
#define TD_CURR_OFFSET (0x0FFFUL << 0) #define TD_CURR_OFFSET (0x0FFFUL << 0)
#define TD_FRAME_NUM (0x07FFUL << 0) #define TD_FRAME_NUM (0x07FFUL << 0)
#define TD_RESERVED_MASK (0x0FFFUL << 0) #define TD_RESERVED_MASK (0x0FFFUL << 0)
...@@ -45,18 +45,18 @@ struct ci_hw_td { ...@@ -45,18 +45,18 @@ struct ci_hw_td {
/* DMA layout of queue heads */ /* DMA layout of queue heads */
struct ci_hw_qh { struct ci_hw_qh {
/* 0 */ /* 0 */
u32 cap; __le32 cap;
#define QH_IOS BIT(15) #define QH_IOS BIT(15)
#define QH_MAX_PKT (0x07FFUL << 16) #define QH_MAX_PKT (0x07FFUL << 16)
#define QH_ZLT BIT(29) #define QH_ZLT BIT(29)
#define QH_MULT (0x0003UL << 30) #define QH_MULT (0x0003UL << 30)
#define QH_ISO_MULT(x) ((x >> 11) & 0x03) #define QH_ISO_MULT(x) ((x >> 11) & 0x03)
/* 1 */ /* 1 */
u32 curr; __le32 curr;
/* 2 - 8 */ /* 2 - 8 */
struct ci_hw_td td; struct ci_hw_td td;
/* 9 */ /* 9 */
u32 RESERVED; __le32 RESERVED;
struct usb_ctrlrequest setup; struct usb_ctrlrequest setup;
} __attribute__ ((packed, aligned(4))); } __attribute__ ((packed, aligned(4)));
......
...@@ -46,11 +46,23 @@ ...@@ -46,11 +46,23 @@
#define MX53_USB_OTG_PHY_CTRL_0_OFFSET 0x08 #define MX53_USB_OTG_PHY_CTRL_0_OFFSET 0x08
#define MX53_USB_OTG_PHY_CTRL_1_OFFSET 0x0c #define MX53_USB_OTG_PHY_CTRL_1_OFFSET 0x0c
#define MX53_USB_CTRL_1_OFFSET 0x10
#define MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_MASK (0x11 << 2)
#define MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_ULPI BIT(2)
#define MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_MASK (0x11 << 6)
#define MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_ULPI BIT(6)
#define MX53_USB_UH2_CTRL_OFFSET 0x14 #define MX53_USB_UH2_CTRL_OFFSET 0x14
#define MX53_USB_UH3_CTRL_OFFSET 0x18 #define MX53_USB_UH3_CTRL_OFFSET 0x18
#define MX53_USB_CLKONOFF_CTRL_OFFSET 0x24
#define MX53_USB_CLKONOFF_CTRL_H2_INT60CKOFF BIT(21)
#define MX53_USB_CLKONOFF_CTRL_H3_INT60CKOFF BIT(22)
#define MX53_BM_OVER_CUR_DIS_H1 BIT(5) #define MX53_BM_OVER_CUR_DIS_H1 BIT(5)
#define MX53_BM_OVER_CUR_DIS_OTG BIT(8) #define MX53_BM_OVER_CUR_DIS_OTG BIT(8)
#define MX53_BM_OVER_CUR_DIS_UHx BIT(30) #define MX53_BM_OVER_CUR_DIS_UHx BIT(30)
#define MX53_USB_CTRL_1_UH2_ULPI_EN BIT(26)
#define MX53_USB_CTRL_1_UH3_ULPI_EN BIT(27)
#define MX53_USB_UHx_CTRL_WAKE_UP_EN BIT(7)
#define MX53_USB_UHx_CTRL_ULPI_INT_EN BIT(8)
#define MX53_USB_PHYCTRL1_PLLDIV_MASK 0x3 #define MX53_USB_PHYCTRL1_PLLDIV_MASK 0x3
#define MX53_USB_PLL_DIV_24_MHZ 0x01 #define MX53_USB_PLL_DIV_24_MHZ 0x01
...@@ -199,31 +211,77 @@ static int usbmisc_imx53_init(struct imx_usbmisc_data *data) ...@@ -199,31 +211,77 @@ static int usbmisc_imx53_init(struct imx_usbmisc_data *data)
val |= MX53_USB_PLL_DIV_24_MHZ; val |= MX53_USB_PLL_DIV_24_MHZ;
writel(val, usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET); writel(val, usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET);
if (data->disable_oc) { spin_lock_irqsave(&usbmisc->lock, flags);
spin_lock_irqsave(&usbmisc->lock, flags);
switch (data->index) { switch (data->index) {
case 0: case 0:
if (data->disable_oc) {
reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG; val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG;
break; writel(val, reg);
case 1: }
break;
case 1:
if (data->disable_oc) {
reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1; val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1;
break; writel(val, reg);
case 2: }
break;
case 2:
if (data->ulpi) {
/* set USBH2 into ULPI-mode. */
reg = usbmisc->base + MX53_USB_CTRL_1_OFFSET;
val = readl(reg) | MX53_USB_CTRL_1_UH2_ULPI_EN;
/* select ULPI clock */
val &= ~MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_MASK;
val |= MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_ULPI;
writel(val, reg);
/* Set interrupt wake up enable */
reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET;
val = readl(reg) | MX53_USB_UHx_CTRL_WAKE_UP_EN
| MX53_USB_UHx_CTRL_ULPI_INT_EN;
writel(val, reg);
/* Disable internal 60Mhz clock */
reg = usbmisc->base + MX53_USB_CLKONOFF_CTRL_OFFSET;
val = readl(reg) | MX53_USB_CLKONOFF_CTRL_H2_INT60CKOFF;
writel(val, reg);
}
if (data->disable_oc) {
reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET; reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET;
val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx; val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
break; writel(val, reg);
case 3: }
break;
case 3:
if (data->ulpi) {
/* set USBH3 into ULPI-mode. */
reg = usbmisc->base + MX53_USB_CTRL_1_OFFSET;
val = readl(reg) | MX53_USB_CTRL_1_UH3_ULPI_EN;
/* select ULPI clock */
val &= ~MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_MASK;
val |= MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_ULPI;
writel(val, reg);
/* Set interrupt wake up enable */
reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET; reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET;
val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx; val = readl(reg) | MX53_USB_UHx_CTRL_WAKE_UP_EN
break; | MX53_USB_UHx_CTRL_ULPI_INT_EN;
writel(val, reg);
/* Disable internal 60Mhz clock */
reg = usbmisc->base + MX53_USB_CLKONOFF_CTRL_OFFSET;
val = readl(reg) | MX53_USB_CLKONOFF_CTRL_H3_INT60CKOFF;
writel(val, reg);
} }
if (reg && val) if (data->disable_oc) {
reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET;
val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
writel(val, reg); writel(val, reg);
spin_unlock_irqrestore(&usbmisc->lock, flags); }
break;
} }
spin_unlock_irqrestore(&usbmisc->lock, flags);
return 0; return 0;
} }
......
...@@ -133,8 +133,8 @@ static int acm_ctrl_msg(struct acm *acm, int request, int value, ...@@ -133,8 +133,8 @@ static int acm_ctrl_msg(struct acm *acm, int request, int value,
buf, len, 5000); buf, len, 5000);
dev_dbg(&acm->control->dev, dev_dbg(&acm->control->dev,
"%s - rq 0x%02x, val %#x, len %#x, result %d\n", "%s - rq 0x%02x, val %#x, len %#x, result %d\n",
__func__, request, value, len, retval); __func__, request, value, len, retval);
usb_autopm_put_interface(acm->control); usb_autopm_put_interface(acm->control);
...@@ -158,6 +158,17 @@ static inline int acm_set_control(struct acm *acm, int control) ...@@ -158,6 +158,17 @@ static inline int acm_set_control(struct acm *acm, int control)
#define acm_send_break(acm, ms) \ #define acm_send_break(acm, ms) \
acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0) acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
static void acm_kill_urbs(struct acm *acm)
{
int i;
usb_kill_urb(acm->ctrlurb);
for (i = 0; i < ACM_NW; i++)
usb_kill_urb(acm->wb[i].urb);
for (i = 0; i < acm->rx_buflimit; i++)
usb_kill_urb(acm->read_urbs[i]);
}
/* /*
* Write buffer management. * Write buffer management.
* All of these assume proper locks taken by the caller. * All of these assume proper locks taken by the caller.
...@@ -291,13 +302,13 @@ static void acm_ctrl_irq(struct urb *urb) ...@@ -291,13 +302,13 @@ static void acm_ctrl_irq(struct urb *urb)
case -ESHUTDOWN: case -ESHUTDOWN:
/* this urb is terminated, clean up */ /* this urb is terminated, clean up */
dev_dbg(&acm->control->dev, dev_dbg(&acm->control->dev,
"%s - urb shutting down with status: %d\n", "%s - urb shutting down with status: %d\n",
__func__, status); __func__, status);
return; return;
default: default:
dev_dbg(&acm->control->dev, dev_dbg(&acm->control->dev,
"%s - nonzero urb status received: %d\n", "%s - nonzero urb status received: %d\n",
__func__, status); __func__, status);
goto exit; goto exit;
} }
...@@ -306,16 +317,16 @@ static void acm_ctrl_irq(struct urb *urb) ...@@ -306,16 +317,16 @@ static void acm_ctrl_irq(struct urb *urb)
data = (unsigned char *)(dr + 1); data = (unsigned char *)(dr + 1);
switch (dr->bNotificationType) { switch (dr->bNotificationType) {
case USB_CDC_NOTIFY_NETWORK_CONNECTION: case USB_CDC_NOTIFY_NETWORK_CONNECTION:
dev_dbg(&acm->control->dev, "%s - network connection: %d\n", dev_dbg(&acm->control->dev,
__func__, dr->wValue); "%s - network connection: %d\n", __func__, dr->wValue);
break; break;
case USB_CDC_NOTIFY_SERIAL_STATE: case USB_CDC_NOTIFY_SERIAL_STATE:
newctrl = get_unaligned_le16(data); newctrl = get_unaligned_le16(data);
if (!acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { if (!acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
dev_dbg(&acm->control->dev, "%s - calling hangup\n", dev_dbg(&acm->control->dev,
__func__); "%s - calling hangup\n", __func__);
tty_port_tty_hangup(&acm->port, false); tty_port_tty_hangup(&acm->port, false);
} }
...@@ -357,8 +368,8 @@ static void acm_ctrl_irq(struct urb *urb) ...@@ -357,8 +368,8 @@ static void acm_ctrl_irq(struct urb *urb)
exit: exit:
retval = usb_submit_urb(urb, GFP_ATOMIC); retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval && retval != -EPERM) if (retval && retval != -EPERM)
dev_err(&acm->control->dev, "%s - usb_submit_urb failed: %d\n", dev_err(&acm->control->dev,
__func__, retval); "%s - usb_submit_urb failed: %d\n", __func__, retval);
} }
static int acm_submit_read_urb(struct acm *acm, int index, gfp_t mem_flags) static int acm_submit_read_urb(struct acm *acm, int index, gfp_t mem_flags)
...@@ -372,8 +383,8 @@ static int acm_submit_read_urb(struct acm *acm, int index, gfp_t mem_flags) ...@@ -372,8 +383,8 @@ static int acm_submit_read_urb(struct acm *acm, int index, gfp_t mem_flags)
if (res) { if (res) {
if (res != -EPERM) { if (res != -EPERM) {
dev_err(&acm->data->dev, dev_err(&acm->data->dev,
"urb %d failed submission with %d\n", "urb %d failed submission with %d\n",
index, res); index, res);
} }
set_bit(index, &acm->read_urbs_free); set_bit(index, &acm->read_urbs_free);
return res; return res;
...@@ -416,30 +427,43 @@ static void acm_read_bulk_callback(struct urb *urb) ...@@ -416,30 +427,43 @@ static void acm_read_bulk_callback(struct urb *urb)
int status = urb->status; int status = urb->status;
dev_vdbg(&acm->data->dev, "got urb %d, len %d, status %d\n", dev_vdbg(&acm->data->dev, "got urb %d, len %d, status %d\n",
rb->index, urb->actual_length, rb->index, urb->actual_length, status);
status);
set_bit(rb->index, &acm->read_urbs_free);
if (!acm->dev) { if (!acm->dev) {
set_bit(rb->index, &acm->read_urbs_free);
dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__); dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__);
return; return;
} }
if (status) { switch (status) {
set_bit(rb->index, &acm->read_urbs_free); case 0:
if ((status != -ENOENT) || (urb->actual_length == 0)) usb_mark_last_busy(acm->dev);
return; acm_process_read_urb(acm, urb);
break;
case -EPIPE:
set_bit(EVENT_RX_STALL, &acm->flags);
schedule_work(&acm->work);
return;
case -ENOENT:
case -ECONNRESET:
case -ESHUTDOWN:
dev_dbg(&acm->data->dev,
"%s - urb shutting down with status: %d\n",
__func__, status);
return;
default:
dev_dbg(&acm->data->dev,
"%s - nonzero urb status received: %d\n",
__func__, status);
break;
} }
usb_mark_last_busy(acm->dev);
acm_process_read_urb(acm, urb);
/* /*
* Unthrottle may run on another CPU which needs to see events * Unthrottle may run on another CPU which needs to see events
* in the same order. Submission has an implict barrier * in the same order. Submission has an implict barrier
*/ */
smp_mb__before_atomic(); smp_mb__before_atomic();
set_bit(rb->index, &acm->read_urbs_free);
/* throttle device if requested by tty */ /* throttle device if requested by tty */
spin_lock_irqsave(&acm->read_lock, flags); spin_lock_irqsave(&acm->read_lock, flags);
...@@ -469,14 +493,30 @@ static void acm_write_bulk(struct urb *urb) ...@@ -469,14 +493,30 @@ static void acm_write_bulk(struct urb *urb)
spin_lock_irqsave(&acm->write_lock, flags); spin_lock_irqsave(&acm->write_lock, flags);
acm_write_done(acm, wb); acm_write_done(acm, wb);
spin_unlock_irqrestore(&acm->write_lock, flags); spin_unlock_irqrestore(&acm->write_lock, flags);
set_bit(EVENT_TTY_WAKEUP, &acm->flags);
schedule_work(&acm->work); schedule_work(&acm->work);
} }
static void acm_softint(struct work_struct *work) static void acm_softint(struct work_struct *work)
{ {
int i;
struct acm *acm = container_of(work, struct acm, work); struct acm *acm = container_of(work, struct acm, work);
tty_port_tty_wakeup(&acm->port); if (test_bit(EVENT_RX_STALL, &acm->flags)) {
if (!(usb_autopm_get_interface(acm->data))) {
for (i = 0; i < acm->rx_buflimit; i++)
usb_kill_urb(acm->read_urbs[i]);
usb_clear_halt(acm->dev, acm->in);
acm_submit_read_urbs(acm, GFP_KERNEL);
usb_autopm_put_interface(acm->data);
}
clear_bit(EVENT_RX_STALL, &acm->flags);
}
if (test_bit(EVENT_TTY_WAKEUP, &acm->flags)) {
tty_port_tty_wakeup(&acm->port);
clear_bit(EVENT_TTY_WAKEUP, &acm->flags);
}
} }
/* /*
...@@ -608,7 +648,6 @@ static void acm_port_shutdown(struct tty_port *port) ...@@ -608,7 +648,6 @@ static void acm_port_shutdown(struct tty_port *port)
struct acm *acm = container_of(port, struct acm, port); struct acm *acm = container_of(port, struct acm, port);
struct urb *urb; struct urb *urb;
struct acm_wb *wb; struct acm_wb *wb;
int i;
/* /*
* Need to grab write_lock to prevent race with resume, but no need to * Need to grab write_lock to prevent race with resume, but no need to
...@@ -630,11 +669,7 @@ static void acm_port_shutdown(struct tty_port *port) ...@@ -630,11 +669,7 @@ static void acm_port_shutdown(struct tty_port *port)
usb_autopm_put_interface_async(acm->control); usb_autopm_put_interface_async(acm->control);
} }
usb_kill_urb(acm->ctrlurb); acm_kill_urbs(acm);
for (i = 0; i < ACM_NW; i++)
usb_kill_urb(acm->wb[i].urb);
for (i = 0; i < acm->rx_buflimit; i++)
usb_kill_urb(acm->read_urbs[i]);
} }
static void acm_tty_cleanup(struct tty_struct *tty) static void acm_tty_cleanup(struct tty_struct *tty)
...@@ -837,8 +872,8 @@ static int acm_tty_break_ctl(struct tty_struct *tty, int state) ...@@ -837,8 +872,8 @@ static int acm_tty_break_ctl(struct tty_struct *tty, int state)
retval = acm_send_break(acm, state ? 0xffff : 0); retval = acm_send_break(acm, state ? 0xffff : 0);
if (retval < 0) if (retval < 0)
dev_dbg(&acm->control->dev, "%s - send break failed\n", dev_dbg(&acm->control->dev,
__func__); "%s - send break failed\n", __func__);
return retval; return retval;
} }
...@@ -877,9 +912,6 @@ static int get_serial_info(struct acm *acm, struct serial_struct __user *info) ...@@ -877,9 +912,6 @@ static int get_serial_info(struct acm *acm, struct serial_struct __user *info)
{ {
struct serial_struct tmp; struct serial_struct tmp;
if (!info)
return -EINVAL;
memset(&tmp, 0, sizeof(tmp)); memset(&tmp, 0, sizeof(tmp));
tmp.flags = ASYNC_LOW_LATENCY; tmp.flags = ASYNC_LOW_LATENCY;
tmp.xmit_fifo_size = acm->writesize; tmp.xmit_fifo_size = acm->writesize;
...@@ -969,25 +1001,20 @@ static int wait_serial_change(struct acm *acm, unsigned long arg) ...@@ -969,25 +1001,20 @@ static int wait_serial_change(struct acm *acm, unsigned long arg)
return rv; return rv;
} }
static int get_serial_usage(struct acm *acm, static int acm_tty_get_icount(struct tty_struct *tty,
struct serial_icounter_struct __user *count) struct serial_icounter_struct *icount)
{ {
struct serial_icounter_struct icount; struct acm *acm = tty->driver_data;
int rv = 0;
memset(&icount, 0, sizeof(icount));
icount.dsr = acm->iocount.dsr;
icount.rng = acm->iocount.rng;
icount.dcd = acm->iocount.dcd;
icount.frame = acm->iocount.frame;
icount.overrun = acm->iocount.overrun;
icount.parity = acm->iocount.parity;
icount.brk = acm->iocount.brk;
if (copy_to_user(count, &icount, sizeof(icount)) > 0) icount->dsr = acm->iocount.dsr;
rv = -EFAULT; icount->rng = acm->iocount.rng;
icount->dcd = acm->iocount.dcd;
icount->frame = acm->iocount.frame;
icount->overrun = acm->iocount.overrun;
icount->parity = acm->iocount.parity;
icount->brk = acm->iocount.brk;
return rv; return 0;
} }
static int acm_tty_ioctl(struct tty_struct *tty, static int acm_tty_ioctl(struct tty_struct *tty,
...@@ -1012,9 +1039,6 @@ static int acm_tty_ioctl(struct tty_struct *tty, ...@@ -1012,9 +1039,6 @@ static int acm_tty_ioctl(struct tty_struct *tty,
rv = wait_serial_change(acm, arg); rv = wait_serial_change(acm, arg);
usb_autopm_put_interface(acm->control); usb_autopm_put_interface(acm->control);
break; break;
case TIOCGICOUNT:
rv = get_serial_usage(acm, (struct serial_icounter_struct __user *) arg);
break;
} }
return rv; return rv;
...@@ -1088,19 +1112,17 @@ static void acm_write_buffers_free(struct acm *acm) ...@@ -1088,19 +1112,17 @@ static void acm_write_buffers_free(struct acm *acm)
{ {
int i; int i;
struct acm_wb *wb; struct acm_wb *wb;
struct usb_device *usb_dev = interface_to_usbdev(acm->control);
for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++)
usb_free_coherent(usb_dev, acm->writesize, wb->buf, wb->dmah); usb_free_coherent(acm->dev, acm->writesize, wb->buf, wb->dmah);
} }
static void acm_read_buffers_free(struct acm *acm) static void acm_read_buffers_free(struct acm *acm)
{ {
struct usb_device *usb_dev = interface_to_usbdev(acm->control);
int i; int i;
for (i = 0; i < acm->rx_buflimit; i++) for (i = 0; i < acm->rx_buflimit; i++)
usb_free_coherent(usb_dev, acm->readsize, usb_free_coherent(acm->dev, acm->readsize,
acm->read_buffers[i].base, acm->read_buffers[i].dma); acm->read_buffers[i].base, acm->read_buffers[i].dma);
} }
...@@ -1345,9 +1367,16 @@ static int acm_probe(struct usb_interface *intf, ...@@ -1345,9 +1367,16 @@ static int acm_probe(struct usb_interface *intf,
spin_lock_init(&acm->write_lock); spin_lock_init(&acm->write_lock);
spin_lock_init(&acm->read_lock); spin_lock_init(&acm->read_lock);
mutex_init(&acm->mutex); mutex_init(&acm->mutex);
acm->is_int_ep = usb_endpoint_xfer_int(epread); if (usb_endpoint_xfer_int(epread)) {
if (acm->is_int_ep)
acm->bInterval = epread->bInterval; acm->bInterval = epread->bInterval;
acm->in = usb_rcvintpipe(usb_dev, epread->bEndpointAddress);
} else {
acm->in = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
}
if (usb_endpoint_xfer_int(epwrite))
acm->out = usb_sndintpipe(usb_dev, epwrite->bEndpointAddress);
else
acm->out = usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress);
tty_port_init(&acm->port); tty_port_init(&acm->port);
acm->port.ops = &acm_port_ops; acm->port.ops = &acm_port_ops;
init_usb_anchor(&acm->delayed); init_usb_anchor(&acm->delayed);
...@@ -1382,20 +1411,15 @@ static int acm_probe(struct usb_interface *intf, ...@@ -1382,20 +1411,15 @@ static int acm_probe(struct usb_interface *intf,
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
urb->transfer_dma = rb->dma; urb->transfer_dma = rb->dma;
if (acm->is_int_ep) { if (usb_endpoint_xfer_int(epread))
usb_fill_int_urb(urb, acm->dev, usb_fill_int_urb(urb, acm->dev, acm->in, rb->base,
usb_rcvintpipe(usb_dev, epread->bEndpointAddress),
rb->base,
acm->readsize, acm->readsize,
acm_read_bulk_callback, rb, acm_read_bulk_callback, rb,
acm->bInterval); acm->bInterval);
} else { else
usb_fill_bulk_urb(urb, acm->dev, usb_fill_bulk_urb(urb, acm->dev, acm->in, rb->base,
usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress),
rb->base,
acm->readsize, acm->readsize,
acm_read_bulk_callback, rb); acm_read_bulk_callback, rb);
}
acm->read_urbs[i] = urb; acm->read_urbs[i] = urb;
__set_bit(i, &acm->read_urbs_free); __set_bit(i, &acm->read_urbs_free);
...@@ -1408,12 +1432,10 @@ static int acm_probe(struct usb_interface *intf, ...@@ -1408,12 +1432,10 @@ static int acm_probe(struct usb_interface *intf,
goto alloc_fail7; goto alloc_fail7;
if (usb_endpoint_xfer_int(epwrite)) if (usb_endpoint_xfer_int(epwrite))
usb_fill_int_urb(snd->urb, usb_dev, usb_fill_int_urb(snd->urb, usb_dev, acm->out,
usb_sndintpipe(usb_dev, epwrite->bEndpointAddress),
NULL, acm->writesize, acm_write_bulk, snd, epwrite->bInterval); NULL, acm->writesize, acm_write_bulk, snd, epwrite->bInterval);
else else
usb_fill_bulk_urb(snd->urb, usb_dev, usb_fill_bulk_urb(snd->urb, usb_dev, acm->out,
usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
NULL, acm->writesize, acm_write_bulk, snd); NULL, acm->writesize, acm_write_bulk, snd);
snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
if (quirks & SEND_ZERO_PACKET) if (quirks & SEND_ZERO_PACKET)
...@@ -1485,8 +1507,8 @@ static int acm_probe(struct usb_interface *intf, ...@@ -1485,8 +1507,8 @@ static int acm_probe(struct usb_interface *intf,
} }
if (quirks & CLEAR_HALT_CONDITIONS) { if (quirks & CLEAR_HALT_CONDITIONS) {
usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress)); usb_clear_halt(usb_dev, acm->in);
usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress)); usb_clear_halt(usb_dev, acm->out);
} }
return 0; return 0;
...@@ -1520,25 +1542,10 @@ static int acm_probe(struct usb_interface *intf, ...@@ -1520,25 +1542,10 @@ static int acm_probe(struct usb_interface *intf,
return rv; return rv;
} }
static void stop_data_traffic(struct acm *acm)
{
int i;
usb_kill_urb(acm->ctrlurb);
for (i = 0; i < ACM_NW; i++)
usb_kill_urb(acm->wb[i].urb);
for (i = 0; i < acm->rx_buflimit; i++)
usb_kill_urb(acm->read_urbs[i]);
cancel_work_sync(&acm->work);
}
static void acm_disconnect(struct usb_interface *intf) static void acm_disconnect(struct usb_interface *intf)
{ {
struct acm *acm = usb_get_intfdata(intf); struct acm *acm = usb_get_intfdata(intf);
struct usb_device *usb_dev = interface_to_usbdev(intf);
struct tty_struct *tty; struct tty_struct *tty;
int i;
/* sibling interface is already cleaning up */ /* sibling interface is already cleaning up */
if (!acm) if (!acm)
...@@ -1564,17 +1571,13 @@ static void acm_disconnect(struct usb_interface *intf) ...@@ -1564,17 +1571,13 @@ static void acm_disconnect(struct usb_interface *intf)
tty_kref_put(tty); tty_kref_put(tty);
} }
stop_data_traffic(acm); acm_kill_urbs(acm);
cancel_work_sync(&acm->work);
tty_unregister_device(acm_tty_driver, acm->minor); tty_unregister_device(acm_tty_driver, acm->minor);
usb_free_urb(acm->ctrlurb);
for (i = 0; i < ACM_NW; i++)
usb_free_urb(acm->wb[i].urb);
for (i = 0; i < acm->rx_buflimit; i++)
usb_free_urb(acm->read_urbs[i]);
acm_write_buffers_free(acm); acm_write_buffers_free(acm);
usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); usb_free_coherent(acm->dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
acm_read_buffers_free(acm); acm_read_buffers_free(acm);
if (!acm->combined_interfaces) if (!acm->combined_interfaces)
...@@ -1603,7 +1606,8 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message) ...@@ -1603,7 +1606,8 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
if (cnt) if (cnt)
return 0; return 0;
stop_data_traffic(acm); acm_kill_urbs(acm);
cancel_work_sync(&acm->work);
return 0; return 0;
} }
...@@ -1657,6 +1661,15 @@ static int acm_reset_resume(struct usb_interface *intf) ...@@ -1657,6 +1661,15 @@ static int acm_reset_resume(struct usb_interface *intf)
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
static int acm_pre_reset(struct usb_interface *intf)
{
struct acm *acm = usb_get_intfdata(intf);
clear_bit(EVENT_RX_STALL, &acm->flags);
return 0;
}
#define NOKIA_PCSUITE_ACM_INFO(x) \ #define NOKIA_PCSUITE_ACM_INFO(x) \
USB_DEVICE_AND_INTERFACE_INFO(0x0421, x, \ USB_DEVICE_AND_INTERFACE_INFO(0x0421, x, \
USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \ USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \
...@@ -1719,6 +1732,7 @@ static const struct usb_device_id acm_ids[] = { ...@@ -1719,6 +1732,7 @@ static const struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x20df, 0x0001), /* Simtec Electronics Entropy Key */ { USB_DEVICE(0x20df, 0x0001), /* Simtec Electronics Entropy Key */
.driver_info = QUIRK_CONTROL_LINE_STATE, }, .driver_info = QUIRK_CONTROL_LINE_STATE, },
{ USB_DEVICE(0x2184, 0x001c) }, /* GW Instek AFG-2225 */ { USB_DEVICE(0x2184, 0x001c) }, /* GW Instek AFG-2225 */
{ USB_DEVICE(0x2184, 0x0036) }, /* GW Instek AFG-125 */
{ USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */ { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */
}, },
/* Motorola H24 HSPA module: */ /* Motorola H24 HSPA module: */
...@@ -1898,6 +1912,7 @@ static struct usb_driver acm_driver = { ...@@ -1898,6 +1912,7 @@ static struct usb_driver acm_driver = {
.resume = acm_resume, .resume = acm_resume,
.reset_resume = acm_reset_resume, .reset_resume = acm_reset_resume,
#endif #endif
.pre_reset = acm_pre_reset,
.id_table = acm_ids, .id_table = acm_ids,
#ifdef CONFIG_PM #ifdef CONFIG_PM
.supports_autosuspend = 1, .supports_autosuspend = 1,
...@@ -1927,6 +1942,7 @@ static const struct tty_operations acm_ops = { ...@@ -1927,6 +1942,7 @@ static const struct tty_operations acm_ops = {
.set_termios = acm_tty_set_termios, .set_termios = acm_tty_set_termios,
.tiocmget = acm_tty_tiocmget, .tiocmget = acm_tty_tiocmget,
.tiocmset = acm_tty_tiocmset, .tiocmset = acm_tty_tiocmset,
.get_icount = acm_tty_get_icount,
}; };
/* /*
......
...@@ -83,6 +83,7 @@ struct acm { ...@@ -83,6 +83,7 @@ struct acm {
struct usb_device *dev; /* the corresponding usb device */ struct usb_device *dev; /* the corresponding usb device */
struct usb_interface *control; /* control interface */ struct usb_interface *control; /* control interface */
struct usb_interface *data; /* data interface */ struct usb_interface *data; /* data interface */
unsigned in, out; /* i/o pipes */
struct tty_port port; /* our tty port data */ struct tty_port port; /* our tty port data */
struct urb *ctrlurb; /* urbs */ struct urb *ctrlurb; /* urbs */
u8 *ctrl_buffer; /* buffers of urbs */ u8 *ctrl_buffer; /* buffers of urbs */
...@@ -102,6 +103,9 @@ struct acm { ...@@ -102,6 +103,9 @@ struct acm {
spinlock_t write_lock; spinlock_t write_lock;
struct mutex mutex; struct mutex mutex;
bool disconnected; bool disconnected;
unsigned long flags;
# define EVENT_TTY_WAKEUP 0
# define EVENT_RX_STALL 1
struct usb_cdc_line_coding line; /* bits, stop, parity */ struct usb_cdc_line_coding line; /* bits, stop, parity */
struct work_struct work; /* work queue entry for line discipline waking up */ struct work_struct work; /* work queue entry for line discipline waking up */
unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */
...@@ -116,7 +120,6 @@ struct acm { ...@@ -116,7 +120,6 @@ struct acm {
unsigned int ctrl_caps; /* control capabilities from the class specific header */ unsigned int ctrl_caps; /* control capabilities from the class specific header */
unsigned int susp_count; /* number of suspended interfaces */ unsigned int susp_count; /* number of suspended interfaces */
unsigned int combined_interfaces:1; /* control and data collapsed */ unsigned int combined_interfaces:1; /* control and data collapsed */
unsigned int is_int_ep:1; /* interrupt endpoints contrary to spec used */
unsigned int throttled:1; /* actually throttled */ unsigned int throttled:1; /* actually throttled */
unsigned int throttle_req:1; /* throttle requested */ unsigned int throttle_req:1; /* throttle requested */
u8 bInterval; u8 bInterval;
......
...@@ -157,6 +157,7 @@ static int usbtmc_open(struct inode *inode, struct file *filp) ...@@ -157,6 +157,7 @@ static int usbtmc_open(struct inode *inode, struct file *filp)
} }
data = usb_get_intfdata(intf); data = usb_get_intfdata(intf);
/* Protect reference to data from file structure until release */
kref_get(&data->kref); kref_get(&data->kref);
/* Store pointer in file structure's private data field */ /* Store pointer in file structure's private data field */
...@@ -531,7 +532,7 @@ static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data, ...@@ -531,7 +532,7 @@ static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data,
} }
/* /*
* Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-IN endpoint. * Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-OUT endpoint.
* @transfer_size: number of bytes to request from the device. * @transfer_size: number of bytes to request from the device.
* *
* See the USBTMC specification, Table 4. * See the USBTMC specification, Table 4.
...@@ -1471,7 +1472,7 @@ static int usbtmc_probe(struct usb_interface *intf, ...@@ -1471,7 +1472,7 @@ static int usbtmc_probe(struct usb_interface *intf,
if (!data->iin_urb) if (!data->iin_urb)
goto error_register; goto error_register;
/* will reference data in int urb */ /* Protect interrupt in endpoint data until iin_urb is freed */
kref_get(&data->kref); kref_get(&data->kref);
/* allocate buffer for interrupt in */ /* allocate buffer for interrupt in */
......
...@@ -3,6 +3,9 @@ ...@@ -3,6 +3,9 @@
* *
* This implementation plugs in through generic "usb_bus" level methods, * This implementation plugs in through generic "usb_bus" level methods,
* and should work with all USB controllers, regardless of bus type. * and should work with all USB controllers, regardless of bus type.
*
* Released under the GPLv2 only.
* SPDX-License-Identifier: GPL-2.0
*/ */
#include <linux/module.h> #include <linux/module.h>
......
/*
* Released under the GPLv2 only.
* SPDX-License-Identifier: GPL-2.0
*/
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/usb/ch9.h> #include <linux/usb/ch9.h>
#include <linux/usb/hcd.h> #include <linux/usb/hcd.h>
......
...@@ -182,14 +182,8 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end, ...@@ -182,14 +182,8 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
dir = usb_endpoint_dir_in(desc) ? 'I' : 'O'; dir = usb_endpoint_dir_in(desc) ? 'I' : 'O';
if (speed == USB_SPEED_HIGH) { if (speed == USB_SPEED_HIGH)
switch (usb_endpoint_maxp(desc) & (0x03 << 11)) { bandwidth = usb_endpoint_maxp_mult(desc);
case 1 << 11:
bandwidth = 2; break;
case 2 << 11:
bandwidth = 3; break;
}
}
/* this isn't checking for illegal values */ /* this isn't checking for illegal values */
switch (usb_endpoint_type(desc)) { switch (usb_endpoint_type(desc)) {
...@@ -233,7 +227,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end, ...@@ -233,7 +227,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
start += sprintf(start, format_endpt, desc->bEndpointAddress, dir, start += sprintf(start, format_endpt, desc->bEndpointAddress, dir,
desc->bmAttributes, type, desc->bmAttributes, type,
(usb_endpoint_maxp(desc) & 0x07ff) * usb_endpoint_maxp(desc) *
bandwidth, bandwidth,
interval, unit); interval, unit);
return start; return start;
......
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
* (usb_device_id matching changes by Adam J. Richter) * (usb_device_id matching changes by Adam J. Richter)
* (C) Copyright Greg Kroah-Hartman 2002-2003 * (C) Copyright Greg Kroah-Hartman 2002-2003
* *
* Released under the GPLv2 only.
* SPDX-License-Identifier: GPL-2.0
*
* NOTE! This is not actually a driver at all, rather this is * NOTE! This is not actually a driver at all, rather this is
* just a collection of helper routines that implement the * just a collection of helper routines that implement the
* matching, probing, releasing, suspending and resuming for * matching, probing, releasing, suspending and resuming for
......
...@@ -5,8 +5,10 @@ ...@@ -5,8 +5,10 @@
* (C) Copyright 2002,2004 IBM Corp. * (C) Copyright 2002,2004 IBM Corp.
* (C) Copyright 2006 Novell Inc. * (C) Copyright 2006 Novell Inc.
* *
* Endpoint sysfs stuff * Released under the GPLv2 only.
* SPDX-License-Identifier: GPL-2.0
* *
* Endpoint sysfs stuff
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -50,8 +52,7 @@ static ssize_t wMaxPacketSize_show(struct device *dev, ...@@ -50,8 +52,7 @@ static ssize_t wMaxPacketSize_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct ep_device *ep = to_ep_device(dev); struct ep_device *ep = to_ep_device(dev);
return sprintf(buf, "%04x\n", return sprintf(buf, "%04x\n", usb_endpoint_maxp(ep->desc));
usb_endpoint_maxp(ep->desc) & 0x07ff);
} }
static DEVICE_ATTR_RO(wMaxPacketSize); static DEVICE_ATTR_RO(wMaxPacketSize);
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
* (usb_device_id matching changes by Adam J. Richter) * (usb_device_id matching changes by Adam J. Richter)
* (C) Copyright Greg Kroah-Hartman 2002-2003 * (C) Copyright Greg Kroah-Hartman 2002-2003
* *
* Released under the GPLv2 only.
* SPDX-License-Identifier: GPL-2.0
*/ */
#include <linux/module.h> #include <linux/module.h>
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
* (usb_device_id matching changes by Adam J. Richter) * (usb_device_id matching changes by Adam J. Richter)
* (C) Copyright Greg Kroah-Hartman 2002-2003 * (C) Copyright Greg Kroah-Hartman 2002-2003
* *
* Released under the GPLv2 only.
* SPDX-License-Identifier: GPL-2.0
*/ */
#include <linux/usb.h> #include <linux/usb.h>
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
* (C) Copyright 1999 Gregory P. Smith * (C) Copyright 1999 Gregory P. Smith
* (C) Copyright 2001 Brad Hards (bhards@bigpond.net.au) * (C) Copyright 2001 Brad Hards (bhards@bigpond.net.au)
* *
* Released under the GPLv2 only.
* SPDX-License-Identifier: GPL-2.0
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -101,6 +103,8 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); ...@@ -101,6 +103,8 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
static void hub_release(struct kref *kref); static void hub_release(struct kref *kref);
static int usb_reset_and_verify_device(struct usb_device *udev); static int usb_reset_and_verify_device(struct usb_device *udev);
static void hub_usb3_port_prepare_disable(struct usb_hub *hub,
struct usb_port *port_dev);
static inline char *portspeed(struct usb_hub *hub, int portstatus) static inline char *portspeed(struct usb_hub *hub, int portstatus)
{ {
...@@ -899,82 +903,28 @@ static int hub_set_port_link_state(struct usb_hub *hub, int port1, ...@@ -899,82 +903,28 @@ static int hub_set_port_link_state(struct usb_hub *hub, int port1,
} }
/* /*
* If USB 3.0 ports are placed into the Disabled state, they will no longer * USB-3 does not have a similar link state as USB-2 that will avoid negotiating
* detect any device connects or disconnects. This is generally not what the * a connection with a plugged-in cable but will signal the host when the cable
* USB core wants, since it expects a disabled port to produce a port status * is unplugged. Disable remote wake and set link state to U3 for USB-3 devices
* change event when a new device connects.
*
* Instead, set the link state to Disabled, wait for the link to settle into
* that state, clear any change bits, and then put the port into the RxDetect
* state.
*/ */
static int hub_usb3_port_disable(struct usb_hub *hub, int port1)
{
int ret;
int total_time;
u16 portchange, portstatus;
if (!hub_is_superspeed(hub->hdev))
return -EINVAL;
ret = hub_port_status(hub, port1, &portstatus, &portchange);
if (ret < 0)
return ret;
/*
* USB controller Advanced Micro Devices, Inc. [AMD] FCH USB XHCI
* Controller [1022:7814] will have spurious result making the following
* usb 3.0 device hotplugging route to the 2.0 root hub and recognized
* as high-speed device if we set the usb 3.0 port link state to
* Disabled. Since it's already in USB_SS_PORT_LS_RX_DETECT state, we
* check the state here to avoid the bug.
*/
if ((portstatus & USB_PORT_STAT_LINK_STATE) ==
USB_SS_PORT_LS_RX_DETECT) {
dev_dbg(&hub->ports[port1 - 1]->dev,
"Not disabling port; link state is RxDetect\n");
return ret;
}
ret = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_SS_DISABLED);
if (ret)
return ret;
/* Wait for the link to enter the disabled state. */
for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) {
ret = hub_port_status(hub, port1, &portstatus, &portchange);
if (ret < 0)
return ret;
if ((portstatus & USB_PORT_STAT_LINK_STATE) ==
USB_SS_PORT_LS_SS_DISABLED)
break;
if (total_time >= HUB_DEBOUNCE_TIMEOUT)
break;
msleep(HUB_DEBOUNCE_STEP);
}
if (total_time >= HUB_DEBOUNCE_TIMEOUT)
dev_warn(&hub->ports[port1 - 1]->dev,
"Could not disable after %d ms\n", total_time);
return hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_RX_DETECT);
}
static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
{ {
struct usb_port *port_dev = hub->ports[port1 - 1]; struct usb_port *port_dev = hub->ports[port1 - 1];
struct usb_device *hdev = hub->hdev; struct usb_device *hdev = hub->hdev;
int ret = 0; int ret = 0;
if (port_dev->child && set_state)
usb_set_device_state(port_dev->child, USB_STATE_NOTATTACHED);
if (!hub->error) { if (!hub->error) {
if (hub_is_superspeed(hub->hdev)) if (hub_is_superspeed(hub->hdev)) {
ret = hub_usb3_port_disable(hub, port1); hub_usb3_port_prepare_disable(hub, port_dev);
else ret = hub_set_port_link_state(hub, port_dev->portnum,
USB_SS_PORT_LS_U3);
} else {
ret = usb_clear_port_feature(hdev, port1, ret = usb_clear_port_feature(hdev, port1,
USB_PORT_FEAT_ENABLE); USB_PORT_FEAT_ENABLE);
}
} }
if (port_dev->child && set_state)
usb_set_device_state(port_dev->child, USB_STATE_NOTATTACHED);
if (ret && ret != -ENODEV) if (ret && ret != -ENODEV)
dev_err(&port_dev->dev, "cannot disable (err = %d)\n", ret); dev_err(&port_dev->dev, "cannot disable (err = %d)\n", ret);
return ret; return ret;
...@@ -2731,8 +2681,15 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, ...@@ -2731,8 +2681,15 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
if (ret < 0) if (ret < 0)
return ret; return ret;
/* The port state is unknown until the reset completes. */ /*
if (!(portstatus & USB_PORT_STAT_RESET)) * The port state is unknown until the reset completes.
*
* On top of that, some chips may require additional time
* to re-establish a connection after the reset is complete,
* so also wait for the connection to be re-established.
*/
if (!(portstatus & USB_PORT_STAT_RESET) &&
(portstatus & USB_PORT_STAT_CONNECTION))
break; break;
/* switch to the long delay after two short delay failures */ /* switch to the long delay after two short delay failures */
...@@ -4140,6 +4097,26 @@ void usb_unlocked_enable_lpm(struct usb_device *udev) ...@@ -4140,6 +4097,26 @@ void usb_unlocked_enable_lpm(struct usb_device *udev)
} }
EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm); EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm);
/* usb3 devices use U3 for disabled, make sure remote wakeup is disabled */
static void hub_usb3_port_prepare_disable(struct usb_hub *hub,
struct usb_port *port_dev)
{
struct usb_device *udev = port_dev->child;
int ret;
if (udev && udev->port_is_suspended && udev->do_remote_wakeup) {
ret = hub_set_port_link_state(hub, port_dev->portnum,
USB_SS_PORT_LS_U0);
if (!ret) {
msleep(USB_RESUME_TIMEOUT);
ret = usb_disable_remote_wakeup(udev);
}
if (ret)
dev_warn(&udev->dev,
"Port disable: can't disable remote wake\n");
udev->do_remote_wakeup = 0;
}
}
#else /* CONFIG_PM */ #else /* CONFIG_PM */
...@@ -4147,6 +4124,9 @@ EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm); ...@@ -4147,6 +4124,9 @@ EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm);
#define hub_resume NULL #define hub_resume NULL
#define hub_reset_resume NULL #define hub_reset_resume NULL
static inline void hub_usb3_port_prepare_disable(struct usb_hub *hub,
struct usb_port *port_dev) { }
int usb_disable_lpm(struct usb_device *udev) int usb_disable_lpm(struct usb_device *udev)
{ {
return 0; return 0;
......
...@@ -74,8 +74,7 @@ static void usbport_trig_update_count(struct usbport_trig_data *usbport_data) ...@@ -74,8 +74,7 @@ static void usbport_trig_update_count(struct usbport_trig_data *usbport_data)
usbport_data->count = 0; usbport_data->count = 0;
usb_for_each_dev(usbport_data, usbport_trig_usb_dev_check); usb_for_each_dev(usbport_data, usbport_trig_usb_dev_check);
led_cdev->brightness_set(led_cdev, led_set_brightness(led_cdev, usbport_data->count ? LED_FULL : LED_OFF);
usbport_data->count ? LED_FULL : LED_OFF);
} }
/*************************************** /***************************************
...@@ -228,12 +227,12 @@ static int usbport_trig_notify(struct notifier_block *nb, unsigned long action, ...@@ -228,12 +227,12 @@ static int usbport_trig_notify(struct notifier_block *nb, unsigned long action,
case USB_DEVICE_ADD: case USB_DEVICE_ADD:
usbport_trig_add_usb_dev_ports(usb_dev, usbport_data); usbport_trig_add_usb_dev_ports(usb_dev, usbport_data);
if (observed && usbport_data->count++ == 0) if (observed && usbport_data->count++ == 0)
led_cdev->brightness_set(led_cdev, LED_FULL); led_set_brightness(led_cdev, LED_FULL);
return NOTIFY_OK; return NOTIFY_OK;
case USB_DEVICE_REMOVE: case USB_DEVICE_REMOVE:
usbport_trig_remove_usb_dev_ports(usbport_data, usb_dev); usbport_trig_remove_usb_dev_ports(usbport_data, usb_dev);
if (observed && --usbport_data->count == 0) if (observed && --usbport_data->count == 0)
led_cdev->brightness_set(led_cdev, LED_OFF); led_set_brightness(led_cdev, LED_OFF);
return NOTIFY_OK; return NOTIFY_OK;
} }
......
/* /*
* message.c - synchronous message handling * message.c - synchronous message handling
*
* Released under the GPLv2 only.
* SPDX-License-Identifier: GPL-2.0
*/ */
#include <linux/pci.h> /* for scatterlist macros */ #include <linux/pci.h> /* for scatterlist macros */
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
* notifier functions originally based on those in kernel/sys.c * notifier functions originally based on those in kernel/sys.c
* but fixed up to not be so broken. * but fixed up to not be so broken.
* *
* Released under the GPLv2 only.
* SPDX-License-Identifier: GPL-2.0
*/ */
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
* *
* All of the sysfs file attributes for usb devices and interfaces. * All of the sysfs file attributes for usb devices and interfaces.
* *
* Released under the GPLv2 only.
* SPDX-License-Identifier: GPL-2.0
*/ */
...@@ -14,6 +16,7 @@ ...@@ -14,6 +16,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/usb/quirks.h> #include <linux/usb/quirks.h>
#include <linux/of.h>
#include "usb.h" #include "usb.h"
/* Active configuration fields */ /* Active configuration fields */
...@@ -104,6 +107,17 @@ static ssize_t bConfigurationValue_store(struct device *dev, ...@@ -104,6 +107,17 @@ static ssize_t bConfigurationValue_store(struct device *dev,
static DEVICE_ATTR_IGNORE_LOCKDEP(bConfigurationValue, S_IRUGO | S_IWUSR, static DEVICE_ATTR_IGNORE_LOCKDEP(bConfigurationValue, S_IRUGO | S_IWUSR,
bConfigurationValue_show, bConfigurationValue_store); bConfigurationValue_show, bConfigurationValue_store);
#ifdef CONFIG_OF
static ssize_t devspec_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct device_node *of_node = dev->of_node;
return sprintf(buf, "%s\n", of_node_full_name(of_node));
}
static DEVICE_ATTR_RO(devspec);
#endif
/* String fields */ /* String fields */
#define usb_string_attr(name) \ #define usb_string_attr(name) \
static ssize_t name##_show(struct device *dev, \ static ssize_t name##_show(struct device *dev, \
...@@ -786,6 +800,9 @@ static struct attribute *dev_attrs[] = { ...@@ -786,6 +800,9 @@ static struct attribute *dev_attrs[] = {
&dev_attr_remove.attr, &dev_attr_remove.attr,
&dev_attr_removable.attr, &dev_attr_removable.attr,
&dev_attr_ltm_capable.attr, &dev_attr_ltm_capable.attr,
#ifdef CONFIG_OF
&dev_attr_devspec.attr,
#endif
NULL, NULL,
}; };
static struct attribute_group dev_attr_grp = { static struct attribute_group dev_attr_grp = {
......
/*
* Released under the GPLv2 only.
* SPDX-License-Identifier: GPL-2.0
*/
#include <linux/module.h> #include <linux/module.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/bitops.h> #include <linux/bitops.h>
...@@ -407,11 +412,8 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) ...@@ -407,11 +412,8 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
} }
/* "high bandwidth" mode, 1-3 packets/uframe? */ /* "high bandwidth" mode, 1-3 packets/uframe? */
if (dev->speed == USB_SPEED_HIGH) { if (dev->speed == USB_SPEED_HIGH)
int mult = 1 + ((max >> 11) & 0x03); max *= usb_endpoint_maxp_mult(&ep->desc);
max &= 0x07ff;
max *= mult;
}
if (urb->number_of_packets <= 0) if (urb->number_of_packets <= 0)
return -EINVAL; return -EINVAL;
......
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
* (usb_device_id matching changes by Adam J. Richter) * (usb_device_id matching changes by Adam J. Richter)
* (C) Copyright Greg Kroah-Hartman 2002-2003 * (C) Copyright Greg Kroah-Hartman 2002-2003
* *
* Released under the GPLv2 only.
* SPDX-License-Identifier: GPL-2.0
*
* NOTE! This is not actually a driver at all, rather this is * NOTE! This is not actually a driver at all, rather this is
* just a collection of helper routines that implement the * just a collection of helper routines that implement the
* generic USB things that the real drivers can use.. * generic USB things that the real drivers can use..
......
/*
* Released under the GPLv2 only.
* SPDX-License-Identifier: GPL-2.0
*/
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/acpi.h> #include <linux/acpi.h>
......
...@@ -3,6 +3,7 @@ ccflags-$(CONFIG_USB_DWC2_VERBOSE) += -DVERBOSE_DEBUG ...@@ -3,6 +3,7 @@ ccflags-$(CONFIG_USB_DWC2_VERBOSE) += -DVERBOSE_DEBUG
obj-$(CONFIG_USB_DWC2) += dwc2.o obj-$(CONFIG_USB_DWC2) += dwc2.o
dwc2-y := core.o core_intr.o platform.o dwc2-y := core.o core_intr.o platform.o
dwc2-y += params.o
ifneq ($(filter y,$(CONFIG_USB_DWC2_HOST) $(CONFIG_USB_DWC2_DUAL_ROLE)),) ifneq ($(filter y,$(CONFIG_USB_DWC2_HOST) $(CONFIG_USB_DWC2_DUAL_ROLE)),)
dwc2-y += hcd.o hcd_intr.o dwc2-y += hcd.o hcd_intr.o
......
此差异已折叠。
...@@ -172,6 +172,11 @@ struct dwc2_hsotg_req; ...@@ -172,6 +172,11 @@ struct dwc2_hsotg_req;
* @periodic: Set if this is a periodic ep, such as Interrupt * @periodic: Set if this is a periodic ep, such as Interrupt
* @isochronous: Set if this is a isochronous ep * @isochronous: Set if this is a isochronous ep
* @send_zlp: Set if we need to send a zero-length packet. * @send_zlp: Set if we need to send a zero-length packet.
* @desc_list_dma: The DMA address of descriptor chain currently in use.
* @desc_list: Pointer to descriptor DMA chain head currently in use.
* @desc_count: Count of entries within the DMA descriptor chain of EP.
* @isoc_chain_num: Number of ISOC chain currently in use - either 0 or 1.
* @next_desc: index of next free descriptor in the ISOC chain under SW control.
* @total_data: The total number of data bytes done. * @total_data: The total number of data bytes done.
* @fifo_size: The size of the FIFO (for periodic IN endpoints) * @fifo_size: The size of the FIFO (for periodic IN endpoints)
* @fifo_load: The amount of data loaded into the FIFO (periodic IN) * @fifo_load: The amount of data loaded into the FIFO (periodic IN)
...@@ -219,6 +224,13 @@ struct dwc2_hsotg_ep { ...@@ -219,6 +224,13 @@ struct dwc2_hsotg_ep {
#define TARGET_FRAME_INITIAL 0xFFFFFFFF #define TARGET_FRAME_INITIAL 0xFFFFFFFF
bool frame_overrun; bool frame_overrun;
dma_addr_t desc_list_dma;
struct dwc2_dma_desc *desc_list;
u8 desc_count;
unsigned char isoc_chain_num;
unsigned int next_desc;
char name[10]; char name[10];
}; };
...@@ -286,7 +298,7 @@ enum dwc2_ep0_state { ...@@ -286,7 +298,7 @@ enum dwc2_ep0_state {
* @otg_ver: OTG version supported * @otg_ver: OTG version supported
* 0 - 1.3 (default) * 0 - 1.3 (default)
* 1 - 2.0 * 1 - 2.0
* @dma_enable: Specifies whether to use slave or DMA mode for accessing * @host_dma: Specifies whether to use slave or DMA mode for accessing
* the data FIFOs. The driver will automatically detect the * the data FIFOs. The driver will automatically detect the
* value for this parameter if none is specified. * value for this parameter if none is specified.
* 0 - Slave (always available) * 0 - Slave (always available)
...@@ -314,7 +326,8 @@ enum dwc2_ep0_state { ...@@ -314,7 +326,8 @@ enum dwc2_ep0_state {
* @enable_dynamic_fifo: 0 - Use coreConsultant-specified FIFO size parameters * @enable_dynamic_fifo: 0 - Use coreConsultant-specified FIFO size parameters
* 1 - Allow dynamic FIFO sizing (default, if available) * 1 - Allow dynamic FIFO sizing (default, if available)
* @en_multiple_tx_fifo: Specifies whether dedicated per-endpoint transmit FIFOs * @en_multiple_tx_fifo: Specifies whether dedicated per-endpoint transmit FIFOs
* are enabled * are enabled for non-periodic IN endpoints in device
* mode.
* @host_rx_fifo_size: Number of 4-byte words in the Rx FIFO in host mode when * @host_rx_fifo_size: Number of 4-byte words in the Rx FIFO in host mode when
* dynamic FIFO sizing is enabled * dynamic FIFO sizing is enabled
* 16 to 32768 * 16 to 32768
...@@ -417,6 +430,20 @@ enum dwc2_ep0_state { ...@@ -417,6 +430,20 @@ enum dwc2_ep0_state {
* needed. * needed.
* 0 - No (default) * 0 - No (default)
* 1 - Yes * 1 - Yes
* @g_dma: Enables gadget dma usage (default: autodetect).
* @g_dma_desc: Enables gadget descriptor DMA (default: autodetect).
* @g_rx_fifo_size: The periodic rx fifo size for the device, in
* DWORDS from 16-32768 (default: 2048 if
* possible, otherwise autodetect).
* @g_np_tx_fifo_size: The non-periodic tx fifo size for the device in
* DWORDS from 16-32768 (default: 1024 if
* possible, otherwise autodetect).
* @g_tx_fifo_size: An array of TX fifo sizes in dedicated fifo
* mode. Each value corresponds to one EP
* starting from EP1 (max 15 values). Sizes are
* in DWORDS with possible values from from
* 16-32768 (default: 256, 256, 256, 256, 768,
* 768, 768, 768, 0, 0, 0, 0, 0, 0, 0).
* *
* The following parameters may be specified when starting the module. These * The following parameters may be specified when starting the module. These
* parameters define how the DWC_otg controller should be configured. A * parameters define how the DWC_otg controller should be configured. A
...@@ -430,11 +457,18 @@ struct dwc2_core_params { ...@@ -430,11 +457,18 @@ struct dwc2_core_params {
* dwc2_set_all_params! * dwc2_set_all_params!
*/ */
int otg_cap; int otg_cap;
#define DWC2_CAP_PARAM_HNP_SRP_CAPABLE 0
#define DWC2_CAP_PARAM_SRP_ONLY_CAPABLE 1
#define DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE 2
int otg_ver; int otg_ver;
int dma_enable;
int dma_desc_enable; int dma_desc_enable;
int dma_desc_fs_enable; int dma_desc_fs_enable;
int speed; int speed;
#define DWC2_SPEED_PARAM_HIGH 0
#define DWC2_SPEED_PARAM_FULL 1
#define DWC2_SPEED_PARAM_LOW 2
int enable_dynamic_fifo; int enable_dynamic_fifo;
int en_multiple_tx_fifo; int en_multiple_tx_fifo;
int host_rx_fifo_size; int host_rx_fifo_size;
...@@ -444,19 +478,44 @@ struct dwc2_core_params { ...@@ -444,19 +478,44 @@ struct dwc2_core_params {
int max_packet_count; int max_packet_count;
int host_channels; int host_channels;
int phy_type; int phy_type;
#define DWC2_PHY_TYPE_PARAM_FS 0
#define DWC2_PHY_TYPE_PARAM_UTMI 1
#define DWC2_PHY_TYPE_PARAM_ULPI 2
int phy_utmi_width; int phy_utmi_width;
int phy_ulpi_ddr; int phy_ulpi_ddr;
int phy_ulpi_ext_vbus; int phy_ulpi_ext_vbus;
#define DWC2_PHY_ULPI_INTERNAL_VBUS 0
#define DWC2_PHY_ULPI_EXTERNAL_VBUS 1
int i2c_enable; int i2c_enable;
int ulpi_fs_ls; int ulpi_fs_ls;
int host_support_fs_ls_low_power; int host_support_fs_ls_low_power;
int host_ls_low_power_phy_clk; int host_ls_low_power_phy_clk;
#define DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0
#define DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1
int ts_dline; int ts_dline;
int reload_ctl; int reload_ctl;
int ahbcfg; int ahbcfg;
int uframe_sched; int uframe_sched;
int external_id_pin_ctl; int external_id_pin_ctl;
int hibernation; int hibernation;
/*
* The following parameters are *only* set via device
* properties and cannot be set directly in this structure.
*/
/* Host parameters */
bool host_dma;
/* Gadget parameters */
bool g_dma;
bool g_dma_desc;
u16 g_rx_fifo_size;
u16 g_np_tx_fifo_size;
u32 g_tx_fifo_size[MAX_EPS_CHANNELS];
}; };
/** /**
...@@ -516,10 +575,9 @@ struct dwc2_hw_params { ...@@ -516,10 +575,9 @@ struct dwc2_hw_params {
unsigned op_mode:3; unsigned op_mode:3;
unsigned arch:2; unsigned arch:2;
unsigned dma_desc_enable:1; unsigned dma_desc_enable:1;
unsigned dma_desc_fs_enable:1;
unsigned enable_dynamic_fifo:1; unsigned enable_dynamic_fifo:1;
unsigned en_multiple_tx_fifo:1; unsigned en_multiple_tx_fifo:1;
unsigned host_rx_fifo_size:16; unsigned rx_fifo_size:16;
unsigned host_nperio_tx_fifo_size:16; unsigned host_nperio_tx_fifo_size:16;
unsigned dev_nperio_tx_fifo_size:16; unsigned dev_nperio_tx_fifo_size:16;
unsigned host_perio_tx_fifo_size:16; unsigned host_perio_tx_fifo_size:16;
...@@ -839,11 +897,13 @@ struct dwc2_hregs_backup { ...@@ -839,11 +897,13 @@ struct dwc2_hregs_backup {
* @ctrl_req: Request for EP0 control packets. * @ctrl_req: Request for EP0 control packets.
* @ep0_state: EP0 control transfers state * @ep0_state: EP0 control transfers state
* @test_mode: USB test mode requested by the host * @test_mode: USB test mode requested by the host
* @setup_desc_dma: EP0 setup stage desc chain DMA address
* @setup_desc: EP0 setup stage desc chain pointer
* @ctrl_in_desc_dma: EP0 IN data phase desc chain DMA address
* @ctrl_in_desc: EP0 IN data phase desc chain pointer
* @ctrl_out_desc_dma: EP0 OUT data phase desc chain DMA address
* @ctrl_out_desc: EP0 OUT data phase desc chain pointer
* @eps: The endpoints being supplied to the gadget framework * @eps: The endpoints being supplied to the gadget framework
* @g_using_dma: Indicate if dma usage is enabled
* @g_rx_fifo_sz: Contains rx fifo size value
* @g_np_g_tx_fifo_sz: Contains Non-Periodic tx fifo size value
* @g_tx_fifo_sz: Contains tx fifo size value per endpoints
*/ */
struct dwc2_hsotg { struct dwc2_hsotg {
struct device *dev; struct device *dev;
...@@ -851,7 +911,7 @@ struct dwc2_hsotg { ...@@ -851,7 +911,7 @@ struct dwc2_hsotg {
/** Params detected from hardware */ /** Params detected from hardware */
struct dwc2_hw_params hw_params; struct dwc2_hw_params hw_params;
/** Params to actually use */ /** Params to actually use */
struct dwc2_core_params *core_params; struct dwc2_core_params params;
enum usb_otg_state op_state; enum usb_otg_state op_state;
enum usb_dr_mode dr_mode; enum usb_dr_mode dr_mode;
unsigned int hcd_enabled:1; unsigned int hcd_enabled:1;
...@@ -891,6 +951,8 @@ struct dwc2_hsotg { ...@@ -891,6 +951,8 @@ struct dwc2_hsotg {
#define DWC2_CORE_REV_2_94a 0x4f54294a #define DWC2_CORE_REV_2_94a 0x4f54294a
#define DWC2_CORE_REV_3_00a 0x4f54300a #define DWC2_CORE_REV_3_00a 0x4f54300a
#define DWC2_CORE_REV_3_10a 0x4f54310a #define DWC2_CORE_REV_3_10a 0x4f54310a
#define DWC2_FS_IOT_REV_1_00a 0x5531100a
#define DWC2_HS_IOT_REV_1_00a 0x5532100a
#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) #if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
union dwc2_hcd_internal_flags { union dwc2_hcd_internal_flags {
...@@ -986,15 +1048,18 @@ struct dwc2_hsotg { ...@@ -986,15 +1048,18 @@ struct dwc2_hsotg {
enum dwc2_ep0_state ep0_state; enum dwc2_ep0_state ep0_state;
u8 test_mode; u8 test_mode;
dma_addr_t setup_desc_dma[2];
struct dwc2_dma_desc *setup_desc[2];
dma_addr_t ctrl_in_desc_dma;
struct dwc2_dma_desc *ctrl_in_desc;
dma_addr_t ctrl_out_desc_dma;
struct dwc2_dma_desc *ctrl_out_desc;
struct usb_gadget gadget; struct usb_gadget gadget;
unsigned int enabled:1; unsigned int enabled:1;
unsigned int connected:1; unsigned int connected:1;
struct dwc2_hsotg_ep *eps_in[MAX_EPS_CHANNELS]; struct dwc2_hsotg_ep *eps_in[MAX_EPS_CHANNELS];
struct dwc2_hsotg_ep *eps_out[MAX_EPS_CHANNELS]; struct dwc2_hsotg_ep *eps_out[MAX_EPS_CHANNELS];
u32 g_using_dma;
u32 g_rx_fifo_sz;
u32 g_np_g_tx_fifo_sz;
u32 g_tx_fifo_sz[MAX_EPS_CHANNELS];
#endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */ #endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */
}; };
...@@ -1016,6 +1081,22 @@ enum dwc2_halt_status { ...@@ -1016,6 +1081,22 @@ enum dwc2_halt_status {
DWC2_HC_XFER_URB_DEQUEUE, DWC2_HC_XFER_URB_DEQUEUE,
}; };
/* Core version information */
static inline bool dwc2_is_iot(struct dwc2_hsotg *hsotg)
{
return (hsotg->hw_params.snpsid & 0xfff00000) == 0x55300000;
}
static inline bool dwc2_is_fs_iot(struct dwc2_hsotg *hsotg)
{
return (hsotg->hw_params.snpsid & 0xffff0000) == 0x55310000;
}
static inline bool dwc2_is_hs_iot(struct dwc2_hsotg *hsotg)
{
return (hsotg->hw_params.snpsid & 0xffff0000) == 0x55320000;
}
/* /*
* The following functions support initialization of the core driver component * The following functions support initialization of the core driver component
* and the DWC_otg controller * and the DWC_otg controller
...@@ -1025,6 +1106,8 @@ extern int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg); ...@@ -1025,6 +1106,8 @@ extern int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg);
extern int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg); extern int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg);
extern int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore); extern int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore);
bool dwc2_force_mode_if_needed(struct dwc2_hsotg *hsotg, bool host);
void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg);
void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg); void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg);
extern bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg); extern bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg);
...@@ -1044,217 +1127,16 @@ extern void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd); ...@@ -1044,217 +1127,16 @@ extern void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd);
/* This function should be called on every hardware interrupt. */ /* This function should be called on every hardware interrupt. */
extern irqreturn_t dwc2_handle_common_intr(int irq, void *dev); extern irqreturn_t dwc2_handle_common_intr(int irq, void *dev);
/* OTG Core Parameters */ /* The device ID match table */
extern const struct of_device_id dwc2_of_match_table[];
/*
* Specifies the OTG capabilities. The driver will automatically
* detect the value for this parameter if none is specified.
* 0 - HNP and SRP capable (default)
* 1 - SRP Only capable
* 2 - No HNP/SRP capable
*/
extern void dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg, int val);
#define DWC2_CAP_PARAM_HNP_SRP_CAPABLE 0
#define DWC2_CAP_PARAM_SRP_ONLY_CAPABLE 1
#define DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE 2
/*
* Specifies whether to use slave or DMA mode for accessing the data
* FIFOs. The driver will automatically detect the value for this
* parameter if none is specified.
* 0 - Slave
* 1 - DMA (default, if available)
*/
extern void dwc2_set_param_dma_enable(struct dwc2_hsotg *hsotg, int val);
/*
* When DMA mode is enabled specifies whether to use
* address DMA or DMA Descritor mode for accessing the data
* FIFOs in device mode. The driver will automatically detect
* the value for this parameter if none is specified.
* 0 - address DMA
* 1 - DMA Descriptor(default, if available)
*/
extern void dwc2_set_param_dma_desc_enable(struct dwc2_hsotg *hsotg, int val);
/*
* When DMA mode is enabled specifies whether to use
* address DMA or DMA Descritor mode with full speed devices
* for accessing the data FIFOs in host mode.
* 0 - address DMA
* 1 - FS DMA Descriptor(default, if available)
*/
extern void dwc2_set_param_dma_desc_fs_enable(struct dwc2_hsotg *hsotg,
int val);
/*
* Specifies the maximum speed of operation in host and device mode.
* The actual speed depends on the speed of the attached device and
* the value of phy_type. The actual speed depends on the speed of the
* attached device.
* 0 - High Speed (default)
* 1 - Full Speed
*/
extern void dwc2_set_param_speed(struct dwc2_hsotg *hsotg, int val);
#define DWC2_SPEED_PARAM_HIGH 0
#define DWC2_SPEED_PARAM_FULL 1
/*
* Specifies whether low power mode is supported when attached
* to a Full Speed or Low Speed device in host mode.
*
* 0 - Don't support low power mode (default)
* 1 - Support low power mode
*/
extern void dwc2_set_param_host_support_fs_ls_low_power(
struct dwc2_hsotg *hsotg, int val);
/*
* Specifies the PHY clock rate in low power mode when connected to a
* Low Speed device in host mode. This parameter is applicable only if
* HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
* then defaults to 6 MHZ otherwise 48 MHZ.
*
* 0 - 48 MHz
* 1 - 6 MHz
*/
extern void dwc2_set_param_host_ls_low_power_phy_clk(struct dwc2_hsotg *hsotg,
int val);
#define DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0
#define DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1
/*
* 0 - Use cC FIFO size parameters
* 1 - Allow dynamic FIFO sizing (default)
*/
extern void dwc2_set_param_enable_dynamic_fifo(struct dwc2_hsotg *hsotg,
int val);
/*
* Number of 4-byte words in the Rx FIFO in host mode when dynamic
* FIFO sizing is enabled.
* 16 to 32768 (default 1024)
*/
extern void dwc2_set_param_host_rx_fifo_size(struct dwc2_hsotg *hsotg, int val);
/*
* Number of 4-byte words in the non-periodic Tx FIFO in host mode
* when Dynamic FIFO sizing is enabled in the core.
* 16 to 32768 (default 256)
*/
extern void dwc2_set_param_host_nperio_tx_fifo_size(struct dwc2_hsotg *hsotg,
int val);
/*
* Number of 4-byte words in the host periodic Tx FIFO when dynamic
* FIFO sizing is enabled.
* 16 to 32768 (default 256)
*/
extern void dwc2_set_param_host_perio_tx_fifo_size(struct dwc2_hsotg *hsotg,
int val);
/*
* The maximum transfer size supported in bytes.
* 2047 to 65,535 (default 65,535)
*/
extern void dwc2_set_param_max_transfer_size(struct dwc2_hsotg *hsotg, int val);
/*
* The maximum number of packets in a transfer.
* 15 to 511 (default 511)
*/
extern void dwc2_set_param_max_packet_count(struct dwc2_hsotg *hsotg, int val);
/*
* The number of host channel registers to use.
* 1 to 16 (default 11)
* Note: The FPGA configuration supports a maximum of 11 host channels.
*/
extern void dwc2_set_param_host_channels(struct dwc2_hsotg *hsotg, int val);
/*
* Specifies the type of PHY interface to use. By default, the driver
* will automatically detect the phy_type.
*
* 0 - Full Speed PHY
* 1 - UTMI+ (default)
* 2 - ULPI
*/
extern void dwc2_set_param_phy_type(struct dwc2_hsotg *hsotg, int val);
#define DWC2_PHY_TYPE_PARAM_FS 0
#define DWC2_PHY_TYPE_PARAM_UTMI 1
#define DWC2_PHY_TYPE_PARAM_ULPI 2
/*
* Specifies the UTMI+ Data Width. This parameter is
* applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
* PHY_TYPE, this parameter indicates the data width between
* the MAC and the ULPI Wrapper.) Also, this parameter is
* applicable only if the OTG_HSPHY_WIDTH cC parameter was set
* to "8 and 16 bits", meaning that the core has been
* configured to work at either data path width.
*
* 8 or 16 bits (default 16)
*/
extern void dwc2_set_param_phy_utmi_width(struct dwc2_hsotg *hsotg, int val);
/*
* Specifies whether the ULPI operates at double or single
* data rate. This parameter is only applicable if PHY_TYPE is
* ULPI.
*
* 0 - single data rate ULPI interface with 8 bit wide data
* bus (default)
* 1 - double data rate ULPI interface with 4 bit wide data
* bus
*/
extern void dwc2_set_param_phy_ulpi_ddr(struct dwc2_hsotg *hsotg, int val);
/*
* Specifies whether to use the internal or external supply to
* drive the vbus with a ULPI phy.
*/
extern void dwc2_set_param_phy_ulpi_ext_vbus(struct dwc2_hsotg *hsotg, int val);
#define DWC2_PHY_ULPI_INTERNAL_VBUS 0
#define DWC2_PHY_ULPI_EXTERNAL_VBUS 1
/*
* Specifies whether to use the I2Cinterface for full speed PHY. This
* parameter is only applicable if PHY_TYPE is FS.
* 0 - No (default)
* 1 - Yes
*/
extern void dwc2_set_param_i2c_enable(struct dwc2_hsotg *hsotg, int val);
extern void dwc2_set_param_ulpi_fs_ls(struct dwc2_hsotg *hsotg, int val);
extern void dwc2_set_param_ts_dline(struct dwc2_hsotg *hsotg, int val);
/*
* Specifies whether dedicated transmit FIFOs are
* enabled for non periodic IN endpoints in device mode
* 0 - No
* 1 - Yes
*/
extern void dwc2_set_param_en_multiple_tx_fifo(struct dwc2_hsotg *hsotg,
int val);
extern void dwc2_set_param_reload_ctl(struct dwc2_hsotg *hsotg, int val);
extern void dwc2_set_param_ahbcfg(struct dwc2_hsotg *hsotg, int val);
extern void dwc2_set_param_otg_ver(struct dwc2_hsotg *hsotg, int val);
extern void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
const struct dwc2_core_params *params);
extern void dwc2_set_all_params(struct dwc2_core_params *params, int value);
extern int dwc2_get_hwparams(struct dwc2_hsotg *hsotg);
extern int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg); extern int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg);
extern int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg); extern int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg);
/* Parameters */
int dwc2_get_hwparams(struct dwc2_hsotg *hsotg);
int dwc2_init_params(struct dwc2_hsotg *hsotg);
/* /*
* The following functions check the controller's OTG operation mode * The following functions check the controller's OTG operation mode
* capability (GHWCFG2.OTG_MODE). * capability (GHWCFG2.OTG_MODE).
......
...@@ -159,9 +159,9 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg) ...@@ -159,9 +159,9 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
" ++OTG Interrupt: Session Request Success Status Change++\n"); " ++OTG Interrupt: Session Request Success Status Change++\n");
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL); gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
if (gotgctl & GOTGCTL_SESREQSCS) { if (gotgctl & GOTGCTL_SESREQSCS) {
if (hsotg->core_params->phy_type == if (hsotg->params.phy_type ==
DWC2_PHY_TYPE_PARAM_FS DWC2_PHY_TYPE_PARAM_FS
&& hsotg->core_params->i2c_enable > 0) { && hsotg->params.i2c_enable > 0) {
hsotg->srp_success = 1; hsotg->srp_success = 1;
} else { } else {
/* Clear Session Request */ /* Clear Session Request */
...@@ -370,7 +370,7 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg) ...@@ -370,7 +370,7 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
/* Change to L0 state */ /* Change to L0 state */
hsotg->lx_state = DWC2_L0; hsotg->lx_state = DWC2_L0;
} else { } else {
if (hsotg->core_params->hibernation) if (hsotg->params.hibernation)
return; return;
if (hsotg->lx_state != DWC2_L1) { if (hsotg->lx_state != DWC2_L1) {
......
...@@ -213,7 +213,7 @@ static int fifo_show(struct seq_file *seq, void *v) ...@@ -213,7 +213,7 @@ static int fifo_show(struct seq_file *seq, void *v)
val = dwc2_readl(regs + GNPTXFSIZ); val = dwc2_readl(regs + GNPTXFSIZ);
seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n", seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n",
val >> FIFOSIZE_DEPTH_SHIFT, val >> FIFOSIZE_DEPTH_SHIFT,
val & FIFOSIZE_DEPTH_MASK); val & FIFOSIZE_STARTADDR_MASK);
seq_puts(seq, "\nPeriodic TXFIFOs:\n"); seq_puts(seq, "\nPeriodic TXFIFOs:\n");
......
此差异已折叠。
此差异已折叠。
...@@ -348,7 +348,7 @@ struct dwc2_qh { ...@@ -348,7 +348,7 @@ struct dwc2_qh {
struct list_head qtd_list; struct list_head qtd_list;
struct dwc2_host_chan *channel; struct dwc2_host_chan *channel;
struct list_head qh_list_entry; struct list_head qh_list_entry;
struct dwc2_hcd_dma_desc *desc_list; struct dwc2_dma_desc *desc_list;
dma_addr_t desc_list_dma; dma_addr_t desc_list_dma;
u32 desc_list_sz; u32 desc_list_sz;
u32 *n_bytes; u32 *n_bytes;
...@@ -793,11 +793,6 @@ extern void dwc2_hcd_dump_frrem(struct dwc2_hsotg *hsotg); ...@@ -793,11 +793,6 @@ extern void dwc2_hcd_dump_frrem(struct dwc2_hsotg *hsotg);
#define URB_SEND_ZERO_PACKET 0x2 #define URB_SEND_ZERO_PACKET 0x2
/* Host driver callbacks */ /* Host driver callbacks */
extern void dwc2_host_start(struct dwc2_hsotg *hsotg);
extern void dwc2_host_disconnect(struct dwc2_hsotg *hsotg);
extern void dwc2_host_hub_info(struct dwc2_hsotg *hsotg, void *context,
int *hub_addr, int *hub_port);
extern struct dwc2_tt *dwc2_host_get_tt_info(struct dwc2_hsotg *hsotg, extern struct dwc2_tt *dwc2_host_get_tt_info(struct dwc2_hsotg *hsotg,
void *context, gfp_t mem_flags, void *context, gfp_t mem_flags,
int *ttport); int *ttport);
......
...@@ -95,7 +95,7 @@ static int dwc2_desc_list_alloc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, ...@@ -95,7 +95,7 @@ static int dwc2_desc_list_alloc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
else else
desc_cache = hsotg->desc_gen_cache; desc_cache = hsotg->desc_gen_cache;
qh->desc_list_sz = sizeof(struct dwc2_hcd_dma_desc) * qh->desc_list_sz = sizeof(struct dwc2_dma_desc) *
dwc2_max_desc_num(qh); dwc2_max_desc_num(qh);
qh->desc_list = kmem_cache_zalloc(desc_cache, flags | GFP_DMA); qh->desc_list = kmem_cache_zalloc(desc_cache, flags | GFP_DMA);
...@@ -297,7 +297,7 @@ static void dwc2_release_channel_ddma(struct dwc2_hsotg *hsotg, ...@@ -297,7 +297,7 @@ static void dwc2_release_channel_ddma(struct dwc2_hsotg *hsotg,
struct dwc2_host_chan *chan = qh->channel; struct dwc2_host_chan *chan = qh->channel;
if (dwc2_qh_is_non_per(qh)) { if (dwc2_qh_is_non_per(qh)) {
if (hsotg->core_params->uframe_sched > 0) if (hsotg->params.uframe_sched > 0)
hsotg->available_host_channels++; hsotg->available_host_channels++;
else else
hsotg->non_periodic_channels--; hsotg->non_periodic_channels--;
...@@ -322,7 +322,7 @@ static void dwc2_release_channel_ddma(struct dwc2_hsotg *hsotg, ...@@ -322,7 +322,7 @@ static void dwc2_release_channel_ddma(struct dwc2_hsotg *hsotg,
qh->ntd = 0; qh->ntd = 0;
if (qh->desc_list) if (qh->desc_list)
memset(qh->desc_list, 0, sizeof(struct dwc2_hcd_dma_desc) * memset(qh->desc_list, 0, sizeof(struct dwc2_dma_desc) *
dwc2_max_desc_num(qh)); dwc2_max_desc_num(qh));
} }
...@@ -404,7 +404,7 @@ void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) ...@@ -404,7 +404,7 @@ void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
if ((qh->ep_type == USB_ENDPOINT_XFER_ISOC || if ((qh->ep_type == USB_ENDPOINT_XFER_ISOC ||
qh->ep_type == USB_ENDPOINT_XFER_INT) && qh->ep_type == USB_ENDPOINT_XFER_INT) &&
(hsotg->core_params->uframe_sched > 0 || (hsotg->params.uframe_sched > 0 ||
!hsotg->periodic_channels) && hsotg->frame_list) { !hsotg->periodic_channels) && hsotg->frame_list) {
dwc2_per_sched_disable(hsotg); dwc2_per_sched_disable(hsotg);
dwc2_frame_list_free(hsotg); dwc2_frame_list_free(hsotg);
...@@ -542,7 +542,7 @@ static void dwc2_fill_host_isoc_dma_desc(struct dwc2_hsotg *hsotg, ...@@ -542,7 +542,7 @@ static void dwc2_fill_host_isoc_dma_desc(struct dwc2_hsotg *hsotg,
struct dwc2_qh *qh, u32 max_xfer_size, struct dwc2_qh *qh, u32 max_xfer_size,
u16 idx) u16 idx)
{ {
struct dwc2_hcd_dma_desc *dma_desc = &qh->desc_list[idx]; struct dwc2_dma_desc *dma_desc = &qh->desc_list[idx];
struct dwc2_hcd_iso_packet_desc *frame_desc; struct dwc2_hcd_iso_packet_desc *frame_desc;
memset(dma_desc, 0, sizeof(*dma_desc)); memset(dma_desc, 0, sizeof(*dma_desc));
...@@ -571,8 +571,8 @@ static void dwc2_fill_host_isoc_dma_desc(struct dwc2_hsotg *hsotg, ...@@ -571,8 +571,8 @@ static void dwc2_fill_host_isoc_dma_desc(struct dwc2_hsotg *hsotg,
dma_sync_single_for_device(hsotg->dev, dma_sync_single_for_device(hsotg->dev,
qh->desc_list_dma + qh->desc_list_dma +
(idx * sizeof(struct dwc2_hcd_dma_desc)), (idx * sizeof(struct dwc2_dma_desc)),
sizeof(struct dwc2_hcd_dma_desc), sizeof(struct dwc2_dma_desc),
DMA_TO_DEVICE); DMA_TO_DEVICE);
} }
...@@ -645,8 +645,8 @@ static void dwc2_init_isoc_dma_desc(struct dwc2_hsotg *hsotg, ...@@ -645,8 +645,8 @@ static void dwc2_init_isoc_dma_desc(struct dwc2_hsotg *hsotg,
qh->desc_list[idx].status |= HOST_DMA_IOC; qh->desc_list[idx].status |= HOST_DMA_IOC;
dma_sync_single_for_device(hsotg->dev, dma_sync_single_for_device(hsotg->dev,
qh->desc_list_dma + (idx * qh->desc_list_dma + (idx *
sizeof(struct dwc2_hcd_dma_desc)), sizeof(struct dwc2_dma_desc)),
sizeof(struct dwc2_hcd_dma_desc), sizeof(struct dwc2_dma_desc),
DMA_TO_DEVICE); DMA_TO_DEVICE);
} }
#else #else
...@@ -679,8 +679,8 @@ static void dwc2_init_isoc_dma_desc(struct dwc2_hsotg *hsotg, ...@@ -679,8 +679,8 @@ static void dwc2_init_isoc_dma_desc(struct dwc2_hsotg *hsotg,
qh->desc_list[idx].status |= HOST_DMA_IOC; qh->desc_list[idx].status |= HOST_DMA_IOC;
dma_sync_single_for_device(hsotg->dev, dma_sync_single_for_device(hsotg->dev,
qh->desc_list_dma + qh->desc_list_dma +
(idx * sizeof(struct dwc2_hcd_dma_desc)), (idx * sizeof(struct dwc2_dma_desc)),
sizeof(struct dwc2_hcd_dma_desc), sizeof(struct dwc2_dma_desc),
DMA_TO_DEVICE); DMA_TO_DEVICE);
#endif #endif
} }
...@@ -690,11 +690,11 @@ static void dwc2_fill_host_dma_desc(struct dwc2_hsotg *hsotg, ...@@ -690,11 +690,11 @@ static void dwc2_fill_host_dma_desc(struct dwc2_hsotg *hsotg,
struct dwc2_qtd *qtd, struct dwc2_qh *qh, struct dwc2_qtd *qtd, struct dwc2_qh *qh,
int n_desc) int n_desc)
{ {
struct dwc2_hcd_dma_desc *dma_desc = &qh->desc_list[n_desc]; struct dwc2_dma_desc *dma_desc = &qh->desc_list[n_desc];
int len = chan->xfer_len; int len = chan->xfer_len;
if (len > MAX_DMA_DESC_SIZE - (chan->max_packet - 1)) if (len > HOST_DMA_NBYTES_LIMIT - (chan->max_packet - 1))
len = MAX_DMA_DESC_SIZE - (chan->max_packet - 1); len = HOST_DMA_NBYTES_LIMIT - (chan->max_packet - 1);
if (chan->ep_is_in) { if (chan->ep_is_in) {
int num_packets; int num_packets;
...@@ -721,8 +721,8 @@ static void dwc2_fill_host_dma_desc(struct dwc2_hsotg *hsotg, ...@@ -721,8 +721,8 @@ static void dwc2_fill_host_dma_desc(struct dwc2_hsotg *hsotg,
dma_sync_single_for_device(hsotg->dev, dma_sync_single_for_device(hsotg->dev,
qh->desc_list_dma + qh->desc_list_dma +
(n_desc * sizeof(struct dwc2_hcd_dma_desc)), (n_desc * sizeof(struct dwc2_dma_desc)),
sizeof(struct dwc2_hcd_dma_desc), sizeof(struct dwc2_dma_desc),
DMA_TO_DEVICE); DMA_TO_DEVICE);
/* /*
...@@ -778,8 +778,8 @@ static void dwc2_init_non_isoc_dma_desc(struct dwc2_hsotg *hsotg, ...@@ -778,8 +778,8 @@ static void dwc2_init_non_isoc_dma_desc(struct dwc2_hsotg *hsotg,
dma_sync_single_for_device(hsotg->dev, dma_sync_single_for_device(hsotg->dev,
qh->desc_list_dma + qh->desc_list_dma +
((n_desc - 1) * ((n_desc - 1) *
sizeof(struct dwc2_hcd_dma_desc)), sizeof(struct dwc2_dma_desc)),
sizeof(struct dwc2_hcd_dma_desc), sizeof(struct dwc2_dma_desc),
DMA_TO_DEVICE); DMA_TO_DEVICE);
} }
dwc2_fill_host_dma_desc(hsotg, chan, qtd, qh, n_desc); dwc2_fill_host_dma_desc(hsotg, chan, qtd, qh, n_desc);
...@@ -808,8 +808,8 @@ static void dwc2_init_non_isoc_dma_desc(struct dwc2_hsotg *hsotg, ...@@ -808,8 +808,8 @@ static void dwc2_init_non_isoc_dma_desc(struct dwc2_hsotg *hsotg,
n_desc - 1, &qh->desc_list[n_desc - 1]); n_desc - 1, &qh->desc_list[n_desc - 1]);
dma_sync_single_for_device(hsotg->dev, dma_sync_single_for_device(hsotg->dev,
qh->desc_list_dma + (n_desc - 1) * qh->desc_list_dma + (n_desc - 1) *
sizeof(struct dwc2_hcd_dma_desc), sizeof(struct dwc2_dma_desc),
sizeof(struct dwc2_hcd_dma_desc), sizeof(struct dwc2_dma_desc),
DMA_TO_DEVICE); DMA_TO_DEVICE);
if (n_desc > 1) { if (n_desc > 1) {
qh->desc_list[0].status |= HOST_DMA_A; qh->desc_list[0].status |= HOST_DMA_A;
...@@ -817,7 +817,7 @@ static void dwc2_init_non_isoc_dma_desc(struct dwc2_hsotg *hsotg, ...@@ -817,7 +817,7 @@ static void dwc2_init_non_isoc_dma_desc(struct dwc2_hsotg *hsotg,
&qh->desc_list[0]); &qh->desc_list[0]);
dma_sync_single_for_device(hsotg->dev, dma_sync_single_for_device(hsotg->dev,
qh->desc_list_dma, qh->desc_list_dma,
sizeof(struct dwc2_hcd_dma_desc), sizeof(struct dwc2_dma_desc),
DMA_TO_DEVICE); DMA_TO_DEVICE);
} }
chan->ntd = n_desc; chan->ntd = n_desc;
...@@ -893,7 +893,7 @@ static int dwc2_cmpl_host_isoc_dma_desc(struct dwc2_hsotg *hsotg, ...@@ -893,7 +893,7 @@ static int dwc2_cmpl_host_isoc_dma_desc(struct dwc2_hsotg *hsotg,
struct dwc2_qtd *qtd, struct dwc2_qtd *qtd,
struct dwc2_qh *qh, u16 idx) struct dwc2_qh *qh, u16 idx)
{ {
struct dwc2_hcd_dma_desc *dma_desc; struct dwc2_dma_desc *dma_desc;
struct dwc2_hcd_iso_packet_desc *frame_desc; struct dwc2_hcd_iso_packet_desc *frame_desc;
u16 remain = 0; u16 remain = 0;
int rc = 0; int rc = 0;
...@@ -902,8 +902,8 @@ static int dwc2_cmpl_host_isoc_dma_desc(struct dwc2_hsotg *hsotg, ...@@ -902,8 +902,8 @@ static int dwc2_cmpl_host_isoc_dma_desc(struct dwc2_hsotg *hsotg,
return -EINVAL; return -EINVAL;
dma_sync_single_for_cpu(hsotg->dev, qh->desc_list_dma + (idx * dma_sync_single_for_cpu(hsotg->dev, qh->desc_list_dma + (idx *
sizeof(struct dwc2_hcd_dma_desc)), sizeof(struct dwc2_dma_desc)),
sizeof(struct dwc2_hcd_dma_desc), sizeof(struct dwc2_dma_desc),
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
dma_desc = &qh->desc_list[idx]; dma_desc = &qh->desc_list[idx];
...@@ -1066,7 +1066,7 @@ static void dwc2_complete_isoc_xfer_ddma(struct dwc2_hsotg *hsotg, ...@@ -1066,7 +1066,7 @@ static void dwc2_complete_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
static int dwc2_update_non_isoc_urb_state_ddma(struct dwc2_hsotg *hsotg, static int dwc2_update_non_isoc_urb_state_ddma(struct dwc2_hsotg *hsotg,
struct dwc2_host_chan *chan, struct dwc2_host_chan *chan,
struct dwc2_qtd *qtd, struct dwc2_qtd *qtd,
struct dwc2_hcd_dma_desc *dma_desc, struct dwc2_dma_desc *dma_desc,
enum dwc2_halt_status halt_status, enum dwc2_halt_status halt_status,
u32 n_bytes, int *xfer_done) u32 n_bytes, int *xfer_done)
{ {
...@@ -1154,7 +1154,7 @@ static int dwc2_process_non_isoc_desc(struct dwc2_hsotg *hsotg, ...@@ -1154,7 +1154,7 @@ static int dwc2_process_non_isoc_desc(struct dwc2_hsotg *hsotg,
{ {
struct dwc2_qh *qh = chan->qh; struct dwc2_qh *qh = chan->qh;
struct dwc2_hcd_urb *urb = qtd->urb; struct dwc2_hcd_urb *urb = qtd->urb;
struct dwc2_hcd_dma_desc *dma_desc; struct dwc2_dma_desc *dma_desc;
u32 n_bytes; u32 n_bytes;
int failed; int failed;
...@@ -1165,8 +1165,8 @@ static int dwc2_process_non_isoc_desc(struct dwc2_hsotg *hsotg, ...@@ -1165,8 +1165,8 @@ static int dwc2_process_non_isoc_desc(struct dwc2_hsotg *hsotg,
dma_sync_single_for_cpu(hsotg->dev, dma_sync_single_for_cpu(hsotg->dev,
qh->desc_list_dma + (desc_num * qh->desc_list_dma + (desc_num *
sizeof(struct dwc2_hcd_dma_desc)), sizeof(struct dwc2_dma_desc)),
sizeof(struct dwc2_hcd_dma_desc), sizeof(struct dwc2_dma_desc),
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
dma_desc = &qh->desc_list[desc_num]; dma_desc = &qh->desc_list[desc_num];
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -62,6 +62,20 @@ struct dwc2_pci_glue { ...@@ -62,6 +62,20 @@ struct dwc2_pci_glue {
struct platform_device *phy; struct platform_device *phy;
}; };
static int dwc2_pci_quirks(struct pci_dev *pdev, struct platform_device *dwc2)
{
if (pdev->vendor == PCI_VENDOR_ID_SYNOPSYS &&
pdev->device == PCI_PRODUCT_ID_HAPS_HSOTG) {
struct property_entry properties[] = {
{ },
};
return platform_device_add_properties(dwc2, properties);
}
return 0;
}
static void dwc2_pci_remove(struct pci_dev *pci) static void dwc2_pci_remove(struct pci_dev *pci)
{ {
struct dwc2_pci_glue *glue = pci_get_drvdata(pci); struct dwc2_pci_glue *glue = pci_get_drvdata(pci);
...@@ -122,6 +136,10 @@ static int dwc2_pci_probe(struct pci_dev *pci, ...@@ -122,6 +136,10 @@ static int dwc2_pci_probe(struct pci_dev *pci,
return PTR_ERR(phy); return PTR_ERR(phy);
} }
ret = dwc2_pci_quirks(pci, dwc2);
if (ret)
goto err;
ret = platform_device_add(dwc2); ret = platform_device_add(dwc2);
if (ret) { if (ret) {
dev_err(dev, "failed to register dwc2 device\n"); dev_err(dev, "failed to register dwc2 device\n");
......
此差异已折叠。
...@@ -62,7 +62,7 @@ config USB_DWC3_OMAP ...@@ -62,7 +62,7 @@ config USB_DWC3_OMAP
config USB_DWC3_EXYNOS config USB_DWC3_EXYNOS
tristate "Samsung Exynos Platform" tristate "Samsung Exynos Platform"
depends on ARCH_EXYNOS && OF || COMPILE_TEST depends on (ARCH_EXYNOS || COMPILE_TEST) && OF
default USB_DWC3 default USB_DWC3
help help
Recent Exynos5 SoCs ship with one DesignWare Core USB3 IP inside, Recent Exynos5 SoCs ship with one DesignWare Core USB3 IP inside,
...@@ -70,7 +70,7 @@ config USB_DWC3_EXYNOS ...@@ -70,7 +70,7 @@ config USB_DWC3_EXYNOS
config USB_DWC3_PCI config USB_DWC3_PCI
tristate "PCIe-based Platforms" tristate "PCIe-based Platforms"
depends on PCI depends on PCI && ACPI
default USB_DWC3 default USB_DWC3
help help
If you're using the DesignWare Core IP with a PCIe, please say If you're using the DesignWare Core IP with a PCIe, please say
...@@ -98,7 +98,7 @@ config USB_DWC3_OF_SIMPLE ...@@ -98,7 +98,7 @@ config USB_DWC3_OF_SIMPLE
config USB_DWC3_ST config USB_DWC3_ST
tristate "STMicroelectronics Platforms" tristate "STMicroelectronics Platforms"
depends on ARCH_STI && OF depends on (ARCH_STI || COMPILE_TEST) && OF
default USB_DWC3 default USB_DWC3
help help
STMicroelectronics SoCs with one DesignWare Core USB3 IP STMicroelectronics SoCs with one DesignWare Core USB3 IP
......
...@@ -3,7 +3,11 @@ CFLAGS_trace.o := -I$(src) ...@@ -3,7 +3,11 @@ CFLAGS_trace.o := -I$(src)
obj-$(CONFIG_USB_DWC3) += dwc3.o obj-$(CONFIG_USB_DWC3) += dwc3.o
dwc3-y := core.o debug.o trace.o dwc3-y := core.o
ifneq ($(CONFIG_FTRACE),)
dwc3-y += trace.o
endif
ifneq ($(filter y,$(CONFIG_USB_DWC3_HOST) $(CONFIG_USB_DWC3_DUAL_ROLE)),) ifneq ($(filter y,$(CONFIG_USB_DWC3_HOST) $(CONFIG_USB_DWC3_DUAL_ROLE)),)
dwc3-y += host.o dwc3-y += host.o
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -219,7 +219,6 @@ static int st_dwc3_probe(struct platform_device *pdev) ...@@ -219,7 +219,6 @@ static int st_dwc3_probe(struct platform_device *pdev)
if (IS_ERR(regmap)) if (IS_ERR(regmap))
return PTR_ERR(regmap); return PTR_ERR(regmap);
dma_set_coherent_mask(dev, dev->coherent_dma_mask);
dwc3_data->dev = dev; dwc3_data->dev = dev;
dwc3_data->regmap = regmap; dwc3_data->regmap = regmap;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册