diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-08-14 02:28:01 +0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-08-14 02:28:01 +0400 |
commit | 165f60642ae988f0b9dcfd4988806e7a938b26c7 (patch) | |
tree | 29293f73a4b022620f68dbf48d7450e501be5855 | |
parent | c23bda365dfbf56aa4d6d4a97f83136c36050e01 (diff) | |
parent | 8b841cb217fac676498de3dfe8fabe38b39cba4e (diff) | |
download | linux-165f60642ae988f0b9dcfd4988806e7a938b26c7.tar.xz |
Merge tag 'usb-for-v3.12' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next
Felipe writes:
usb: patches for v3.12 merge window
All patches here have been pending on linux-usb
and sitting in linux-next for a while now.
The biggest things in this tag are:
DWC3 learned proper usage of threaded IRQ
handlers and now we spend very little time
in hardirq context.
MUSB now has proper support for BeagleBone and
Beaglebone Black.
Tegra's USB support also got quite a bit of love
and is learning to use PHY layer and generic DT
attributes.
Other than that, the usual pack of cleanups and
non-critical fixes follow.
Signed-of-by: Felipe Balbi <balbi@ti.com>
Conflicts:
drivers/usb/gadget/udc-core.c
drivers/usb/host/ehci-tegra.c
drivers/usb/musb/omap2430.c
drivers/usb/musb/tusb6010.c
123 files changed, 3607 insertions, 3509 deletions
diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 7a95c651ceb3..e807635f9e1c 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -3,10 +3,12 @@ synopsys DWC3 CORE DWC3- USB3 CONTROLLER Required properties: - - compatible: must be "synopsys,dwc3" + - compatible: must be "snps,dwc3" - reg : Address and length of the register set for the device - interrupts: Interrupts used by the dwc3 controller. - - usb-phy : array of phandle for the PHY device + - usb-phy : array of phandle for the PHY device. The first element + in the array is expected to be a handle to the USB2/HS PHY and + the second element is expected to be a handle to the USB3/SS PHY Optional properties: - tx-fifo-resize: determines if the FIFO *has* to be reallocated. @@ -14,7 +16,7 @@ Optional properties: This is usually a subnode to DWC3 glue to which it is connected. dwc3@4a030000 { - compatible = "synopsys,dwc3"; + compatible = "snps,dwc3"; reg = <0x4a030000 0xcfff>; interrupts = <0 92 4> usb-phy = <&usb2_phy>, <&usb3,phy>; diff --git a/Documentation/devicetree/bindings/usb/generic.txt b/Documentation/devicetree/bindings/usb/generic.txt new file mode 100644 index 000000000000..477d5bb5e51c --- /dev/null +++ b/Documentation/devicetree/bindings/usb/generic.txt @@ -0,0 +1,24 @@ +Generic USB Properties + +Optional properties: + - maximum-speed: tells USB controllers we want to work up to a certain + speed. Valid arguments are "super-speed", "high-speed", + "full-speed" and "low-speed". In case this isn't passed + via DT, USB controllers should default to their maximum + HW capability. + - dr_mode: tells Dual-Role USB controllers that we want to work on a + particular mode. Valid arguments are "host", + "peripheral" and "otg". In case this attribute isn't + passed via DT, USB DRD controllers should default to + OTG. + +This is an attribute to a USB controller such as: + +dwc3@4a030000 { + compatible = "synopsys,dwc3"; + reg = <0x4a030000 0xcfff>; + interrupts = <0 92 4> + usb-phy = <&usb2_phy>, <&usb3,phy>; + maximum-speed = "super-speed"; + dr_mode = "otg"; +}; diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt index c4c9e9e664aa..ba797d3e6326 100644 --- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt @@ -3,7 +3,7 @@ Tegra SOC USB PHY The device node for Tegra SOC USB PHY: Required properties : - - compatible : Should be "nvidia,tegra20-usb-phy". + - compatible : Should be "nvidia,tegra<chip>-usb-phy". - reg : Defines the following set of registers, in the order listed: - The PHY's own register set. Always present. @@ -24,17 +24,26 @@ Required properties : Required properties for phy_type == ulpi: - nvidia,phy-reset-gpio : The GPIO used to reset the PHY. -Required PHY timing params for utmi phy: +Required PHY timing params for utmi phy, for all chips: - nvidia,hssync-start-delay : Number of 480 Mhz clock cycles to wait before start of sync launches RxActive - nvidia,elastic-limit : Variable FIFO Depth of elastic input store - nvidia,idle-wait-delay : Number of 480 Mhz clock cycles of idle to wait before declare IDLE. - nvidia,term-range-adj : Range adjusment on terminations - - nvidia,xcvr-setup : HS driver output control + - Either one of the following for HS driver output control: + - nvidia,xcvr-setup : integer, uses the provided value. + - nvidia,xcvr-setup-use-fuses : boolean, indicates that the value is read + from the on-chip fuses + If both are provided, nvidia,xcvr-setup-use-fuses takes precedence. - nvidia,xcvr-lsfslew : LS falling slew rate control. - nvidia,xcvr-lsrslew : LS rising slew rate control. +Required PHY timing params for utmi phy, only on Tegra30 and above: + - nvidia,xcvr-hsslew : HS slew rate control. + - nvidia,hssquelch-level : HS squelch detector level. + - nvidia,hsdiscon-level : HS disconnect detector level. + Optional properties: - nvidia,has-legacy-mode : boolean indicates whether this controller can operate in legacy mode (as APX 2500 / 2600). In legacy mode some @@ -48,5 +57,5 @@ Optional properties: peripheral means it is device controller otg means it can operate as either ("on the go") -Required properties for dr_mode == otg: +VBUS control (required for dr_mode == otg, optional for dr_mode == host): - vbus-supply: regulator for VBUS diff --git a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt new file mode 100644 index 000000000000..b83d428a265e --- /dev/null +++ b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt @@ -0,0 +1,40 @@ +Samsung High Speed USB OTG controller +----------------------------- + +The Samsung HSOTG IP can be found on Samsung SoCs, from S3C6400 onwards. +It gives functionality of OTG-compliant USB 2.0 host and device with +support for USB 2.0 high-speed (480Mbps) and full-speed (12 Mbps) +operation. + +Currently only device mode is supported. + +Binding details +----- + +Required properties: +- compatible: "samsung,s3c6400-hsotg" should be used for all currently + supported SoC, +- interrupt-parent: phandle for the interrupt controller to which the + interrupt signal of the HSOTG block is routed, +- interrupts: specifier of interrupt signal of interrupt controller, + according to bindings of interrupt controller, +- clocks: contains an array of clock specifiers: + - first entry: OTG clock +- clock-names: contains array of clock names: + - first entry: must be "otg" +- vusb_d-supply: phandle to voltage regulator of digital section, +- vusb_a-supply: phandle to voltage regulator of analog section. + +Example +----- + + hsotg@12480000 { + compatible = "samsung,s3c6400-hsotg"; + reg = <0x12480000 0x20000>; + interrupts = <0 71 0>; + clocks = <&clock 305>; + clock-names = "otg"; + vusb_d-supply = <&vusb_reg>; + vusb_a-supply = <&vusbdac_reg>; + }; + diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts index 444b4ede0d60..a8907b57c75c 100644 --- a/arch/arm/boot/dts/am335x-bone.dts +++ b/arch/arm/boot/dts/am335x-bone.dts @@ -120,6 +120,22 @@ status = "okay"; }; + musb: usb@47400000 { + status = "okay"; + + control@44e10000 { + status = "okay"; + }; + + phy@47401300 { + status = "okay"; + }; + + usb@47401000 { + status = "okay"; + }; + }; + i2c0: i2c@44e0b000 { pinctrl-names = "default"; pinctrl-0 = <&i2c0_pins>; diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts index 3aee1a43782d..c26c16cace3c 100644 --- a/arch/arm/boot/dts/am335x-evm.dts +++ b/arch/arm/boot/dts/am335x-evm.dts @@ -171,6 +171,34 @@ }; }; + musb: usb@47400000 { + status = "okay"; + + control@44e10000 { + status = "okay"; + }; + + phy@47401300 { + status = "okay"; + }; + + phy@47401b00 { + status = "okay"; + }; + + usb@47401000 { + status = "okay"; + }; + + usb@47401800 { + status = "okay"; + }; + + dma@07402000 { + status = "okay"; + }; + }; + i2c1: i2c@4802a000 { pinctrl-names = "default"; pinctrl-0 = <&i2c1_pins>; diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts index 0c8ad173d2b0..e92446c6846e 100644 --- a/arch/arm/boot/dts/am335x-evmsk.dts +++ b/arch/arm/boot/dts/am335x-evmsk.dts @@ -207,6 +207,22 @@ }; }; + musb: usb@47400000 { + status = "okay"; + + control@44e10000 { + status = "okay"; + }; + + phy@47401300 { + status = "okay"; + }; + + usb@47401000 { + status = "okay"; + }; + }; + epwmss2: epwmss@48304000 { status = "okay"; diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi index 38b446ba1ce1..24d63095ab83 100644 --- a/arch/arm/boot/dts/am33xx.dtsi +++ b/arch/arm/boot/dts/am33xx.dtsi @@ -26,6 +26,10 @@ serial5 = &uart5; d_can0 = &dcan0; d_can1 = &dcan1; + usb0 = &usb0; + usb1 = &usb1; + phy0 = &usb0_phy; + phy1 = &usb1_phy; }; cpus { @@ -333,21 +337,147 @@ status = "disabled"; }; - usb@47400000 { - compatible = "ti,musb-am33xx"; - reg = <0x47400000 0x1000 /* usbss */ - 0x47401000 0x800 /* musb instance 0 */ - 0x47401800 0x800>; /* musb instance 1 */ - interrupts = <17 /* usbss */ - 18 /* musb instance 0 */ - 19>; /* musb instance 1 */ - multipoint = <1>; - num-eps = <16>; - ram-bits = <12>; - port0-mode = <3>; - port1-mode = <3>; - power = <250>; + usb: usb@47400000 { + compatible = "ti,am33xx-usb"; + reg = <0x47400000 0x1000>; + ranges; + #address-cells = <1>; + #size-cells = <1>; ti,hwmods = "usb_otg_hs"; + status = "disabled"; + + ctrl_mod: control@44e10000 { + compatible = "ti,am335x-usb-ctrl-module"; + reg = <0x44e10620 0x10 + 0x44e10648 0x4>; + reg-names = "phy_ctrl", "wakeup"; + status = "disabled"; + }; + + usb0_phy: phy@47401300 { + compatible = "ti,am335x-usb-phy"; + reg = <0x47401300 0x100>; + reg-names = "phy"; + status = "disabled"; + ti,ctrl_mod = <&ctrl_mod>; + }; + + usb0: usb@47401000 { + compatible = "ti,musb-am33xx"; + ranges; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x47401000 0x200>; + reg-names = "control"; + status = "disabled"; + + musb0: usb@47401400 { + compatible = "mg,musbmhdrc"; + reg = <0x47401400 0x400>; + reg-names = "mc"; + interrupts = <18>; + interrupt-names = "mc"; + multipoint = <1>; + num-eps = <16>; + ram-bits = <12>; + port-mode = <3>; + power = <250>; + phys = <&usb0_phy>; + + dmas = <&cppi41dma 0 0 &cppi41dma 1 0 + &cppi41dma 2 0 &cppi41dma 3 0 + &cppi41dma 4 0 &cppi41dma 5 0 + &cppi41dma 6 0 &cppi41dma 7 0 + &cppi41dma 8 0 &cppi41dma 9 0 + &cppi41dma 10 0 &cppi41dma 11 0 + &cppi41dma 12 0 &cppi41dma 13 0 + &cppi41dma 14 0 &cppi41dma 0 1 + &cppi41dma 1 1 &cppi41dma 2 1 + &cppi41dma 3 1 &cppi41dma 4 1 + &cppi41dma 5 1 &cppi41dma 6 1 + &cppi41dma 7 1 &cppi41dma 8 1 + &cppi41dma 9 1 &cppi41dma 10 1 + &cppi41dma 11 1 &cppi41dma 12 1 + &cppi41dma 13 1 &cppi41dma 14 1>; + dma-names = + "rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7", + "rx8", "rx9", "rx10", "rx11", "rx12", "rx13", + "rx14", "rx15", + "tx1", "tx2", "tx3", "tx4", "tx5", "tx6", "tx7", + "tx8", "tx9", "tx10", "tx11", "tx12", "tx13", + "tx14", "tx15"; + }; + }; + + usb1_phy: phy@47401b00 { + compatible = "ti,am335x-usb-phy"; + reg = <0x47401b00 0x100>; + reg-names = "phy"; + status = "disabled"; + ti,ctrl_mod = <&ctrl_mod>; + }; + + usb1: usb@47401800 { + compatible = "ti,musb-am33xx"; + ranges; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x47401800 0x200>; + reg-names = "control"; + status = "disabled"; + + musb1: usb@47401c00 { + compatible = "mg,musbmhdrc"; + reg = <0x47401c00 0x400>; + reg-names = "mc"; + interrupts = <19>; + interrupt-names = "mc"; + multipoint = <1>; + num-eps = <16>; + ram-bits = <12>; + port-mode = <3>; + power = <250>; + phys = <&usb1_phy>; + + dmas = <&cppi41dma 15 0 &cppi41dma 16 0 + &cppi41dma 17 0 &cppi41dma 18 0 + &cppi41dma 19 0 &cppi41dma 20 0 + &cppi41dma 21 0 &cppi41dma 22 0 + &cppi41dma 23 0 &cppi41dma 24 0 + &cppi41dma 25 0 &cppi41dma 26 0 + &cppi41dma 27 0 &cppi41dma 28 0 + &cppi41dma 29 0 &cppi41dma 15 1 + &cppi41dma 16 1 &cppi41dma 17 1 + &cppi41dma 18 1 &cppi41dma 19 1 + &cppi41dma 20 1 &cppi41dma 21 1 + &cppi41dma 22 1 &cppi41dma 23 1 + &cppi41dma 24 1 &cppi41dma 25 1 + &cppi41dma 26 1 &cppi41dma 27 1 + &cppi41dma 28 1 &cppi41dma 29 1>; + dma-names = + "rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7", + "rx8", "rx9", "rx10", "rx11", "rx12", "rx13", + "rx14", "rx15", + "tx1", "tx2", "tx3", "tx4", "tx5", "tx6", "tx7", + "tx8", "tx9", "tx10", "tx11", "tx12", "tx13", + "tx14", "tx15"; + }; + }; + + cppi41dma: dma@07402000 { + compatible = "ti,am3359-cppi41"; + reg = <0x47400000 0x1000 + 0x47402000 0x1000 + 0x47403000 0x1000 + 0x47404000 0x4000>; + reg-names = "glue controller scheduler queuemgr"; + interrupts = <17>; + interrupt-names = "glue"; + #dma-cells = <2>; + #dma-channels = <30>; + #dma-requests = <256>; + status = "disabled"; + }; }; epwmss0: epwmss@48300000 { diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index e643620417a9..07be2cd7b318 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -644,7 +644,7 @@ utmi-mode = <2>; ranges; dwc3@4a030000 { - compatible = "synopsys,dwc3"; + compatible = "snps,dwc3"; reg = <0x4a030000 0x1000>; interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>; usb-phy = <&usb2_phy>, <&usb3_phy>; diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts index 365760b33a26..52526c9a1329 100644 --- a/arch/arm/boot/dts/tegra20-seaboard.dts +++ b/arch/arm/boot/dts/tegra20-seaboard.dts @@ -566,7 +566,6 @@ usb@c5000000 { status = "okay"; - nvidia,vbus-gpio = <&gpio TEGRA_GPIO(D, 0) GPIO_ACTIVE_HIGH>; dr_mode = "otg"; }; diff --git a/arch/arm/boot/dts/tegra20-trimslice.dts b/arch/arm/boot/dts/tegra20-trimslice.dts index ed4b901b0227..3e57b87cc75f 100644 --- a/arch/arm/boot/dts/tegra20-trimslice.dts +++ b/arch/arm/boot/dts/tegra20-trimslice.dts @@ -312,7 +312,6 @@ usb@c5000000 { status = "okay"; - nvidia,vbus-gpio = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_HIGH>; }; usb-phy@c5000000 { diff --git a/arch/arm/boot/dts/tegra20-whistler.dts b/arch/arm/boot/dts/tegra20-whistler.dts index ab67c94db280..a6b1b5bdf288 100644 --- a/arch/arm/boot/dts/tegra20-whistler.dts +++ b/arch/arm/boot/dts/tegra20-whistler.dts @@ -509,7 +509,6 @@ usb@c5000000 { status = "okay"; - nvidia,vbus-gpio = <&tca6416 0 GPIO_ACTIVE_HIGH>; }; usb-phy@c5000000 { @@ -519,7 +518,6 @@ usb@c5008000 { status = "okay"; - nvidia,vbus-gpio = <&tca6416 1 GPIO_ACTIVE_HIGH>; }; usb-phy@c5008000 { diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 9653fd8288d2..e4570834512e 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -477,13 +477,13 @@ <&tegra_car TEGRA20_CLK_USBD>; clock-names = "reg", "pll_u", "timer", "utmi-pads"; nvidia,has-legacy-mode; - hssync_start_delay = <9>; - idle_wait_delay = <17>; - elastic_limit = <16>; - term_range_adj = <6>; - xcvr_setup = <9>; - xcvr_lsfslew = <1>; - xcvr_lsrslew = <1>; + nvidia,hssync-start-delay = <9>; + nvidia,idle-wait-delay = <17>; + nvidia,elastic-limit = <16>; + nvidia,term-range-adj = <6>; + nvidia,xcvr-setup = <9>; + nvidia,xcvr-lsfslew = <1>; + nvidia,xcvr-lsrslew = <1>; status = "disabled"; }; @@ -527,13 +527,13 @@ <&tegra_car TEGRA20_CLK_CLK_M>, <&tegra_car TEGRA20_CLK_USBD>; clock-names = "reg", "pll_u", "timer", "utmi-pads"; - hssync_start_delay = <9>; - idle_wait_delay = <17>; - elastic_limit = <16>; - term_range_adj = <6>; - xcvr_setup = <9>; - xcvr_lsfslew = <2>; - xcvr_lsrslew = <2>; + nvidia,hssync-start-delay = <9>; + nvidia,idle-wait-delay = <17>; + nvidia,elastic-limit = <16>; + nvidia,term-range-adj = <6>; + nvidia,xcvr-setup = <9>; + nvidia,xcvr-lsfslew = <2>; + nvidia,xcvr-lsrslew = <2>; status = "disabled"; }; diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index 04c116555412..1c6ae5f5bae7 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -33,7 +33,7 @@ #include <linux/mtd/nand.h> #include <linux/mmc/host.h> #include <linux/usb/phy.h> -#include <linux/usb/nop-usb-xceiv.h> +#include <linux/usb/usb_phy_gen_xceiv.h> #include <linux/regulator/machine.h> #include <linux/i2c/twl.h> @@ -279,7 +279,7 @@ static struct regulator_consumer_supply beagle_vsim_supply[] = { static struct gpio_led gpio_leds[]; /* PHY's VCC regulator might be added later, so flag that we need it */ -static struct nop_usb_xceiv_platform_data hsusb2_phy_data = { +static struct usb_phy_gen_xceiv_platform_data hsusb2_phy_data = { .needs_vcc = true, }; diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index 8c026269baca..52bdddd41e0e 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -33,7 +33,7 @@ #include <linux/i2c/twl.h> #include <linux/usb/otg.h> #include <linux/usb/musb.h> -#include <linux/usb/nop-usb-xceiv.h> +#include <linux/usb/usb_phy_gen_xceiv.h> #include <linux/smsc911x.h> #include <linux/wl12xx.h> @@ -468,7 +468,7 @@ struct wl12xx_platform_data omap3evm_wlan_data __initdata = { static struct regulator_consumer_supply omap3evm_vaux2_supplies[] = { REGULATOR_SUPPLY("VDD_CSIPHY1", "omap3isp"), /* OMAP ISP */ REGULATOR_SUPPLY("VDD_CSIPHY2", "omap3isp"), /* OMAP ISP */ - REGULATOR_SUPPLY("vcc", "nop_usb_xceiv.2"), /* hsusb port 2 */ + REGULATOR_SUPPLY("vcc", "usb_phy_gen_xceiv.2"), /* hsusb port 2 */ REGULATOR_SUPPLY("vaux2", NULL), }; diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c index b1547a0edfcd..d2b455e70486 100644 --- a/arch/arm/mach-omap2/board-omap3pandora.c +++ b/arch/arm/mach-omap2/board-omap3pandora.c @@ -352,7 +352,7 @@ static struct regulator_consumer_supply pandora_vcc_lcd_supply[] = { }; static struct regulator_consumer_supply pandora_usb_phy_supply[] = { - REGULATOR_SUPPLY("vcc", "nop_usb_xceiv.2"), /* hsusb port 2 */ + REGULATOR_SUPPLY("vcc", "usb_phy_gen_xceiv.2"), /* hsusb port 2 */ }; /* ads7846 on SPI and 2 nub controllers on I2C */ diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c index 2eb19d4d0aa1..e83a6a4b184a 100644 --- a/arch/arm/mach-omap2/usb-host.c +++ b/arch/arm/mach-omap2/usb-host.c @@ -28,7 +28,7 @@ #include <linux/io.h> #include <linux/gpio.h> #include <linux/usb/phy.h> -#include <linux/usb/nop-usb-xceiv.h> +#include <linux/usb/usb_phy_gen_xceiv.h> #include "soc.h" #include "omap_device.h" @@ -349,7 +349,7 @@ static struct fixed_voltage_config hsusb_reg_config = { /* .init_data filled later */ }; -static const char *nop_name = "nop_usb_xceiv"; /* NOP PHY driver */ +static const char *nop_name = "usb_phy_gen_xceiv"; /* NOP PHY driver */ static const char *reg_name = "reg-fixed-voltage"; /* Regulator driver */ /** @@ -460,9 +460,9 @@ int usbhs_init_phys(struct usbhs_phy_data *phy, int num_phys) pdevinfo.name = nop_name; pdevinfo.id = phy->port; pdevinfo.data = phy->platform_data; - pdevinfo.size_data = sizeof(struct nop_usb_xceiv_platform_data); - - scnprintf(phy_id, MAX_STR, "nop_usb_xceiv.%d", + pdevinfo.size_data = + sizeof(struct usb_phy_gen_xceiv_platform_data); + scnprintf(phy_id, MAX_STR, "usb_phy_gen_xceiv.%d", phy->port); pdev = platform_device_register_full(&pdevinfo); if (IS_ERR(pdev)) { diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c index 0d1e4128d460..fc97cfd52769 100644 --- a/arch/arm/mach-tegra/tegra.c +++ b/arch/arm/mach-tegra/tegra.c @@ -29,7 +29,6 @@ #include <linux/of_fdt.h> #include <linux/of_platform.h> #include <linux/pda_power.h> -#include <linux/platform_data/tegra_usb.h> #include <linux/io.h> #include <linux/slab.h> #include <linux/sys_soc.h> @@ -46,40 +45,6 @@ #include "fuse.h" #include "iomap.h" -static struct tegra_ehci_platform_data tegra_ehci1_pdata = { - .operating_mode = TEGRA_USB_OTG, - .power_down_on_bus_suspend = 1, - .vbus_gpio = -1, -}; - -static struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config = { - .reset_gpio = -1, - .clk = "cdev2", -}; - -static struct tegra_ehci_platform_data tegra_ehci2_pdata = { - .phy_config = &tegra_ehci2_ulpi_phy_config, - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .vbus_gpio = -1, -}; - -static struct tegra_ehci_platform_data tegra_ehci3_pdata = { - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .vbus_gpio = -1, -}; - -static struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = { - OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5000000, "tegra-ehci.0", - &tegra_ehci1_pdata), - OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5004000, "tegra-ehci.1", - &tegra_ehci2_pdata), - OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5008000, "tegra-ehci.2", - &tegra_ehci3_pdata), - {} -}; - static void __init tegra_dt_init(void) { struct soc_device_attribute *soc_dev_attr; @@ -112,8 +77,7 @@ static void __init tegra_dt_init(void) * devices */ out: - of_platform_populate(NULL, of_default_bus_match_table, - tegra20_auxdata_lookup, parent); + of_platform_populate(NULL, of_default_bus_match_table, NULL, parent); } static void __init trimslice_init(void) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 6825957c97fb..77bc480117b7 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -287,6 +287,14 @@ config DMA_OMAP select DMA_ENGINE select DMA_VIRTUAL_CHANNELS +config TI_CPPI41 + tristate "AM33xx CPPI41 DMA support" + depends on ARCH_OMAP + select DMA_ENGINE + help + The Communications Port Programming Interface (CPPI) 4.1 DMA engine + is currently used by the USB driver on AM335x platforms. + config MMP_PDMA bool "MMP PDMA support" depends on (ARCH_MMP || ARCH_PXA) diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 5e0f2ef85614..6d62ec30c4bc 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -39,3 +39,4 @@ obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o obj-$(CONFIG_DMA_OMAP) += omap-dma.o obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o +obj-$(CONFIG_TI_CPPI41) += cppi41.o diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c new file mode 100644 index 000000000000..5dcebca37760 --- /dev/null +++ b/drivers/dma/cppi41.c @@ -0,0 +1,1048 @@ +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/slab.h> +#include <linux/of_dma.h> +#include <linux/of_irq.h> +#include <linux/dmapool.h> +#include <linux/interrupt.h> +#include <linux/of_address.h> +#include "dmaengine.h" + +#define DESC_TYPE 27 +#define DESC_TYPE_HOST 0x10 +#define DESC_TYPE_TEARD 0x13 + +#define TD_DESC_IS_RX (1 << 16) +#define TD_DESC_DMA_NUM 10 + +#define DESC_LENGTH_BITS_NUM 21 + +#define DESC_TYPE_USB (5 << 26) +#define DESC_PD_COMPLETE (1 << 31) + +/* DMA engine */ +#define DMA_TDFDQ 4 +#define DMA_TXGCR(x) (0x800 + (x) * 0x20) +#define DMA_RXGCR(x) (0x808 + (x) * 0x20) +#define RXHPCRA0 4 + +#define GCR_CHAN_ENABLE (1 << 31) +#define GCR_TEARDOWN (1 << 30) +#define GCR_STARV_RETRY (1 << 24) +#define GCR_DESC_TYPE_HOST (1 << 14) + +/* DMA scheduler */ +#define DMA_SCHED_CTRL 0 +#define DMA_SCHED_CTRL_EN (1 << 31) +#define DMA_SCHED_WORD(x) ((x) * 4 + 0x800) + +#define SCHED_ENTRY0_CHAN(x) ((x) << 0) +#define SCHED_ENTRY0_IS_RX (1 << 7) + +#define SCHED_ENTRY1_CHAN(x) ((x) << 8) +#define SCHED_ENTRY1_IS_RX (1 << 15) + +#define SCHED_ENTRY2_CHAN(x) ((x) << 16) +#define SCHED_ENTRY2_IS_RX (1 << 23) + +#define SCHED_ENTRY3_CHAN(x) ((x) << 24) +#define SCHED_ENTRY3_IS_RX (1 << 31) + +/* Queue manager */ +/* 4 KiB of memory for descriptors, 2 for each endpoint */ +#define ALLOC_DECS_NUM 128 +#define DESCS_AREAS 1 +#define TOTAL_DESCS_NUM (ALLOC_DECS_NUM * DESCS_AREAS) +#define QMGR_SCRATCH_SIZE (TOTAL_DESCS_NUM * 4) + +#define QMGR_LRAM0_BASE 0x80 +#define QMGR_LRAM_SIZE 0x84 +#define QMGR_LRAM1_BASE 0x88 +#define QMGR_MEMBASE(x) (0x1000 + (x) * 0x10) +#define QMGR_MEMCTRL(x) (0x1004 + (x) * 0x10) +#define QMGR_MEMCTRL_IDX_SH 16 +#define QMGR_MEMCTRL_DESC_SH 8 + +#define QMGR_NUM_PEND 5 +#define QMGR_PEND(x) (0x90 + (x) * 4) + +#define QMGR_PENDING_SLOT_Q(x) (x / 32) +#define QMGR_PENDING_BIT_Q(x) (x % 32) + +#define QMGR_QUEUE_A(n) (0x2000 + (n) * 0x10) +#define QMGR_QUEUE_B(n) (0x2004 + (n) * 0x10) +#define QMGR_QUEUE_C(n) (0x2008 + (n) * 0x10) +#define QMGR_QUEUE_D(n) (0x200c + (n) * 0x10) + +/* Glue layer specific */ +/* USBSS / USB AM335x */ +#define USBSS_IRQ_STATUS 0x28 +#define USBSS_IRQ_ENABLER 0x2c +#define USBSS_IRQ_CLEARR 0x30 + +#define USBSS_IRQ_PD_COMP (1 << 2) + +struct cppi41_channel { + struct dma_chan chan; + struct dma_async_tx_descriptor txd; + struct cppi41_dd *cdd; + struct cppi41_desc *desc; + dma_addr_t desc_phys; + void __iomem *gcr_reg; + int is_tx; + u32 residue; + + unsigned int q_num; + unsigned int q_comp_num; + unsigned int port_num; + + unsigned td_retry; + unsigned td_queued:1; + unsigned td_seen:1; + unsigned td_desc_seen:1; +}; + +struct cppi41_desc { + u32 pd0; + u32 pd1; + u32 pd2; + u32 pd3; + u32 pd4; + u32 pd5; + u32 pd6; + u32 pd7; +} __aligned(32); + +struct chan_queues { + u16 submit; + u16 complete; +}; + +struct cppi41_dd { + struct dma_device ddev; + + void *qmgr_scratch; + dma_addr_t scratch_phys; + + struct cppi41_desc *cd; + dma_addr_t descs_phys; + u32 first_td_desc; + struct cppi41_channel *chan_busy[ALLOC_DECS_NUM]; + + void __iomem *usbss_mem; + void __iomem *ctrl_mem; + void __iomem *sched_mem; + void __iomem *qmgr_mem; + unsigned int irq; + const struct chan_queues *queues_rx; + const struct chan_queues *queues_tx; + struct chan_queues td_queue; +}; + +#define FIST_COMPLETION_QUEUE 93 +static struct chan_queues usb_queues_tx[] = { + /* USB0 ENDP 1 */ + [ 0] = { .submit = 32, .complete = 93}, + [ 1] = { .submit = 34, .complete = 94}, + [ 2] = { .submit = 36, .complete = 95}, + [ 3] = { .submit = 38, .complete = 96}, + [ 4] = { .submit = 40, .complete = 97}, + [ 5] = { .submit = 42, .complete = 98}, + [ 6] = { .submit = 44, .complete = 99}, + [ 7] = { .submit = 46, .complete = 100}, + [ 8] = { .submit = 48, .complete = 101}, + [ 9] = { .submit = 50, .complete = 102}, + [10] = { .submit = 52, .complete = 103}, + [11] = { .submit = 54, .complete = 104}, + [12] = { .submit = 56, .complete = 105}, + [13] = { .submit = 58, .complete = 106}, + [14] = { .submit = 60, .complete = 107}, + + /* USB1 ENDP1 */ + [15] = { .submit = 62, .complete = 125}, + [16] = { .submit = 64, .complete = 126}, + [17] = { .submit = 66, .complete = 127}, + [18] = { .submit = 68, .complete = 128}, + [19] = { .submit = 70, .complete = 129}, + [20] = { .submit = 72, .complete = 130}, + [21] = { .submit = 74, .complete = 131}, + [22] = { .submit = 76, .complete = 132}, + [23] = { .submit = 78, .complete = 133}, + [24] = { .submit = 80, .complete = 134}, + [25] = { .submit = 82, .complete = 135}, + [26] = { .submit = 84, .complete = 136}, + [27] = { .submit = 86, .complete = 137}, + [28] = { .submit = 88, .complete = 138}, + [29] = { .submit = 90, .complete = 139}, +}; + +static const struct chan_queues usb_queues_rx[] = { + /* USB0 ENDP 1 */ + [ 0] = { .submit = 1, .complete = 109}, + [ 1] = { .submit = 2, .complete = 110}, + [ 2] = { .submit = 3, .complete = 111}, + [ 3] = { .submit = 4, .complete = 112}, + [ 4] = { .submit = 5, .complete = 113}, + [ 5] = { .submit = 6, .complete = 114}, + [ 6] = { .submit = 7, .complete = 115}, + [ 7] = { .submit = 8, .complete = 116}, + [ 8] = { .submit = 9, .complete = 117}, + [ 9] = { .submit = 10, .complete = 118}, + [10] = { .submit = 11, .complete = 119}, + [11] = { .submit = 12, .complete = 120}, + [12] = { .submit = 13, .complete = 121}, + [13] = { .submit = 14, .complete = 122}, + [14] = { .submit = 15, .complete = 123}, + + /* USB1 ENDP 1 */ + [15] = { .submit = 16, .complete = 141}, + [16] = { .submit = 17, .complete = 142}, + [17] = { .submit = 18, .complete = 143}, + [18] = { .submit = 19, .complete = 144}, + [19] = { .submit = 20, .complete = 145}, + [20] = { .submit = 21, .complete = 146}, + [21] = { .submit = 22, .complete = 147}, + [22] = { .submit = 23, .complete = 148}, + [23] = { .submit = 24, .complete = 149}, + [24] = { .submit = 25, .complete = 150}, + [25] = { .submit = 26, .complete = 151}, + [26] = { .submit = 27, .complete = 152}, + [27] = { .submit = 28, .complete = 153}, + [28] = { .submit = 29, .complete = 154}, + [29] = { .submit = 30, .complete = 155}, +}; + +struct cppi_glue_infos { + irqreturn_t (*isr)(int irq, void *data); + const struct chan_queues *queues_rx; + const struct chan_queues *queues_tx; + struct chan_queues td_queue; +}; + +static struct cppi41_channel *to_cpp41_chan(struct dma_chan *c) +{ + return container_of(c, struct cppi41_channel, chan); +} + +static struct cppi41_channel *desc_to_chan(struct cppi41_dd *cdd, u32 desc) +{ + struct cppi41_channel *c; + u32 descs_size; + u32 desc_num; + + descs_size = sizeof(struct cppi41_desc) * ALLOC_DECS_NUM; + + if (!((desc >= cdd->descs_phys) && + (desc < (cdd->descs_phys + descs_size)))) { + return NULL; + } + + desc_num = (desc - cdd->descs_phys) / sizeof(struct cppi41_desc); + BUG_ON(desc_num > ALLOC_DECS_NUM); + c = cdd->chan_busy[desc_num]; + cdd->chan_busy[desc_num] = NULL; + return c; +} + +static void cppi_writel(u32 val, void *__iomem *mem) +{ + __raw_writel(val, mem); +} + +static u32 cppi_readl(void *__iomem *mem) +{ + return __raw_readl(mem); +} + +static u32 pd_trans_len(u32 val) +{ + return val & ((1 << (DESC_LENGTH_BITS_NUM + 1)) - 1); +} + +static irqreturn_t cppi41_irq(int irq, void *data) +{ + struct cppi41_dd *cdd = data; + struct cppi41_channel *c; + u32 status; + int i; + + status = cppi_readl(cdd->usbss_mem + USBSS_IRQ_STATUS); + if (!(status & USBSS_IRQ_PD_COMP)) + return IRQ_NONE; + cppi_writel(status, cdd->usbss_mem + USBSS_IRQ_STATUS); + + for (i = QMGR_PENDING_SLOT_Q(FIST_COMPLETION_QUEUE); i < QMGR_NUM_PEND; + i++) { + u32 val; + u32 q_num; + + val = cppi_readl(cdd->qmgr_mem + QMGR_PEND(i)); + if (i == QMGR_PENDING_SLOT_Q(FIST_COMPLETION_QUEUE) && val) { + u32 mask; + /* set corresponding bit for completetion Q 93 */ + mask = 1 << QMGR_PENDING_BIT_Q(FIST_COMPLETION_QUEUE); + /* not set all bits for queues less than Q 93 */ + mask--; + /* now invert and keep only Q 93+ set */ + val &= ~mask; + } + + if (val) + __iormb(); + + while (val) { + u32 desc; + + q_num = __fls(val); + val &= ~(1 << q_num); + q_num += 32 * i; + desc = cppi_readl(cdd->qmgr_mem + QMGR_QUEUE_D(q_num)); + desc &= ~0x1f; + c = desc_to_chan(cdd, desc); + if (WARN_ON(!c)) { + pr_err("%s() q %d desc %08x\n", __func__, + q_num, desc); + continue; + } + c->residue = pd_trans_len(c->desc->pd6) - + pd_trans_len(c->desc->pd0); + + dma_cookie_complete(&c->txd); + c->txd.callback(c->txd.callback_param); + } + } + return IRQ_HANDLED; +} + +static dma_cookie_t cppi41_tx_submit(struct dma_async_tx_descriptor *tx) +{ + dma_cookie_t cookie; + + cookie = dma_cookie_assign(tx); + + return cookie; +} + +static int cppi41_dma_alloc_chan_resources(struct dma_chan *chan) +{ + struct cppi41_channel *c = to_cpp41_chan(chan); + + dma_cookie_init(chan); + dma_async_tx_descriptor_init(&c->txd, chan); + c->txd.tx_submit = cppi41_tx_submit; + + if (!c->is_tx) + cppi_writel(c->q_num, c->gcr_reg + RXHPCRA0); + + return 0; +} + +static void cppi41_dma_free_chan_resources(struct dma_chan *chan) +{ +} + +static enum dma_status cppi41_dma_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, struct dma_tx_state *txstate) +{ + struct cppi41_channel *c = to_cpp41_chan(chan); + enum dma_status ret; + + /* lock */ + ret = dma_cookie_status(chan, cookie, txstate); + if (txstate && ret == DMA_SUCCESS) + txstate->residue = c->residue; + /* unlock */ + + return ret; +} + +static void push_desc_queue(struct cppi41_channel *c) +{ + struct cppi41_dd *cdd = c->cdd; + u32 desc_num; + u32 desc_phys; + u32 reg; + + desc_phys = lower_32_bits(c->desc_phys); + desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc); + WARN_ON(cdd->chan_busy[desc_num]); + cdd->chan_busy[desc_num] = c; + + reg = (sizeof(struct cppi41_desc) - 24) / 4; + reg |= desc_phys; + cppi_writel(reg, cdd->qmgr_mem + QMGR_QUEUE_D(c->q_num)); +} + +static void cppi41_dma_issue_pending(struct dma_chan *chan) +{ + struct cppi41_channel *c = to_cpp41_chan(chan); + u32 reg; + + c->residue = 0; + + reg = GCR_CHAN_ENABLE; + if (!c->is_tx) { + reg |= GCR_STARV_RETRY; + reg |= GCR_DESC_TYPE_HOST; + reg |= c->q_comp_num; + } + + cppi_writel(reg, c->gcr_reg); + + /* + * We don't use writel() but __raw_writel() so we have to make sure + * that the DMA descriptor in coherent memory made to the main memory + * before starting the dma engine. + */ + __iowmb(); + push_desc_queue(c); +} + +static u32 get_host_pd0(u32 length) +{ + u32 reg; + + reg = DESC_TYPE_HOST << DESC_TYPE; + reg |= length; + + return reg; +} + +static u32 get_host_pd1(struct cppi41_channel *c) +{ + u32 reg; + + reg = 0; + + return reg; +} + +static u32 get_host_pd2(struct cppi41_channel *c) +{ + u32 reg; + + reg = DESC_TYPE_USB; + reg |= c->q_comp_num; + + return reg; +} + +static u32 get_host_pd3(u32 length) +{ + u32 reg; + + /* PD3 = packet size */ + reg = length; + + return reg; +} + +static u32 get_host_pd6(u32 length) +{ + u32 reg; + + /* PD6 buffer size */ + reg = DESC_PD_COMPLETE; + reg |= length; + + return reg; +} + +static u32 get_host_pd4_or_7(u32 addr) +{ + u32 reg; + + reg = addr; + + return reg; +} + +static u32 get_host_pd5(void) +{ + u32 reg; + + reg = 0; + + return reg; +} + +static struct dma_async_tx_descriptor *cppi41_dma_prep_slave_sg( + struct dma_chan *chan, struct scatterlist *sgl, unsigned sg_len, + enum dma_transfer_direction dir, unsigned long tx_flags, void *context) +{ + struct cppi41_channel *c = to_cpp41_chan(chan); + struct cppi41_desc *d; + struct scatterlist *sg; + unsigned int i; + unsigned int num; + + num = 0; + d = c->desc; + for_each_sg(sgl, sg, sg_len, i) { + u32 addr; + u32 len; + + /* We need to use more than one desc once musb supports sg */ + BUG_ON(num > 0); + addr = lower_32_bits(sg_dma_address(sg)); + len = sg_dma_len(sg); + + d->pd0 = get_host_pd0(len); + d->pd1 = get_host_pd1(c); + d->pd2 = get_host_pd2(c); + d->pd3 = get_host_pd3(len); + d->pd4 = get_host_pd4_or_7(addr); + d->pd5 = get_host_pd5(); + d->pd6 = get_host_pd6(len); + d->pd7 = get_host_pd4_or_7(addr); + + d++; + } + + return &c->txd; +} + +static int cpp41_cfg_chan(struct cppi41_channel *c, + struct dma_slave_config *cfg) +{ + return 0; +} + +static void cppi41_compute_td_desc(struct cppi41_desc *d) +{ + d->pd0 = DESC_TYPE_TEARD << DESC_TYPE; +} + +static u32 cppi41_pop_desc(struct cppi41_dd *cdd, unsigned queue_num) +{ + u32 desc; + + desc = cppi_readl(cdd->qmgr_mem + QMGR_QUEUE_D(queue_num)); + desc &= ~0x1f; + return desc; +} + +static int cppi41_tear_down_chan(struct cppi41_channel *c) +{ + struct cppi41_dd *cdd = c->cdd; + struct cppi41_desc *td; + u32 reg; + u32 desc_phys; + u32 td_desc_phys; + + td = cdd->cd; + td += cdd->first_td_desc; + + td_desc_phys = cdd->descs_phys; + td_desc_phys += cdd->first_td_desc * sizeof(struct cppi41_desc); + + if (!c->td_queued) { + cppi41_compute_td_desc(td); + __iowmb(); + + reg = (sizeof(struct cppi41_desc) - 24) / 4; + reg |= td_desc_phys; + cppi_writel(reg, cdd->qmgr_mem + + QMGR_QUEUE_D(cdd->td_queue.submit)); + + reg = GCR_CHAN_ENABLE; + if (!c->is_tx) { + reg |= GCR_STARV_RETRY; + reg |= GCR_DESC_TYPE_HOST; + reg |= c->q_comp_num; + } + reg |= GCR_TEARDOWN; + cppi_writel(reg, c->gcr_reg); + c->td_queued = 1; + c->td_retry = 100; + } + + if (!c->td_seen) { + unsigned td_comp_queue; + + if (c->is_tx) + td_comp_queue = cdd->td_queue.complete; + else + td_comp_queue = c->q_comp_num; + + desc_phys = cppi41_pop_desc(cdd, td_comp_queue); + if (desc_phys) { + __iormb(); + + if (desc_phys == td_desc_phys) { + u32 pd0; + pd0 = td->pd0; + WARN_ON((pd0 >> DESC_TYPE) != DESC_TYPE_TEARD); + WARN_ON(!c->is_tx && !(pd0 & TD_DESC_IS_RX)); + WARN_ON((pd0 & 0x1f) != c->port_num); + } else { + __WARN(); + } + c->td_seen = 1; + } + } + if (!c->td_desc_seen) { + desc_phys = cppi41_pop_desc(cdd, c->q_comp_num); + if (desc_phys) { + __iormb(); + WARN_ON(c->desc_phys != desc_phys); + c->td_desc_seen = 1; + } + } + c->td_retry--; + /* + * If the TX descriptor / channel is in use, the caller needs to poke + * his TD bit multiple times. After that he hardware releases the + * transfer descriptor followed by TD descriptor. Waiting seems not to + * cause any difference. + * RX seems to be thrown out right away. However once the TearDown + * descriptor gets through we are done. If we have seens the transfer + * descriptor before the TD we fetch it from enqueue, it has to be + * there waiting for us. + */ + if (!c->td_seen && c->td_retry) + return -EAGAIN; + + WARN_ON(!c->td_retry); + if (!c->td_desc_seen) { + desc_phys = cppi_readl(cdd->qmgr_mem + QMGR_QUEUE_D(c->q_num)); + WARN_ON(!desc_phys); + } + + c->td_queued = 0; + c->td_seen = 0; + c->td_desc_seen = 0; + cppi_writel(0, c->gcr_reg); + return 0; +} + +static int cppi41_stop_chan(struct dma_chan *chan) +{ + struct cppi41_channel *c = to_cpp41_chan(chan); + struct cppi41_dd *cdd = c->cdd; + u32 desc_num; + u32 desc_phys; + int ret; + + ret = cppi41_tear_down_chan(c); + if (ret) + return ret; + + desc_phys = lower_32_bits(c->desc_phys); + desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc); + WARN_ON(!cdd->chan_busy[desc_num]); + cdd->chan_busy[desc_num] = NULL; + + return 0; +} + +static int cppi41_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + unsigned long arg) +{ + struct cppi41_channel *c = to_cpp41_chan(chan); + int ret; + + switch (cmd) { + case DMA_SLAVE_CONFIG: + ret = cpp41_cfg_chan(c, (struct dma_slave_config *) arg); + break; + + case DMA_TERMINATE_ALL: + ret = cppi41_stop_chan(chan); + break; + + default: + ret = -ENXIO; + break; + } + return ret; +} + +static void cleanup_chans(struct cppi41_dd *cdd) +{ + while (!list_empty(&cdd->ddev.channels)) { + struct cppi41_channel *cchan; + + cchan = list_first_entry(&cdd->ddev.channels, + struct cppi41_channel, chan.device_node); + list_del(&cchan->chan.device_node); + kfree(cchan); + } +} + +static int cppi41_add_chans(struct platform_device *pdev, struct cppi41_dd *cdd) +{ + struct cppi41_channel *cchan; + int i; + int ret; + u32 n_chans; + + ret = of_property_read_u32(pdev->dev.of_node, "#dma-channels", + &n_chans); + if (ret) + return ret; + /* + * The channels can only be used as TX or as RX. So we add twice + * that much dma channels because USB can only do RX or TX. + */ + n_chans *= 2; + + for (i = 0; i < n_chans; i++) { + cchan = kzalloc(sizeof(*cchan), GFP_KERNEL); + if (!cchan) + goto err; + + cchan->cdd = cdd; + if (i & 1) { + cchan->gcr_reg = cdd->ctrl_mem + DMA_TXGCR(i >> 1); + cchan->is_tx = 1; + } else { + cchan->gcr_reg = cdd->ctrl_mem + DMA_RXGCR(i >> 1); + cchan->is_tx = 0; + } + cchan->port_num = i >> 1; + cchan->desc = &cdd->cd[i]; + cchan->desc_phys = cdd->descs_phys; + cchan->desc_phys += i * sizeof(struct cppi41_desc); + cchan->chan.device = &cdd->ddev; + list_add_tail(&cchan->chan.device_node, &cdd->ddev.channels); + } + cdd->first_td_desc = n_chans; + + return 0; +err: + cleanup_chans(cdd); + return -ENOMEM; +} + +static void purge_descs(struct platform_device *pdev, struct cppi41_dd *cdd) +{ + unsigned int mem_decs; + int i; + + mem_decs = ALLOC_DECS_NUM * sizeof(struct cppi41_desc); + + for (i = 0; i < DESCS_AREAS; i++) { + + cppi_writel(0, cdd->qmgr_mem + QMGR_MEMBASE(i)); + cppi_writel(0, cdd->qmgr_mem + QMGR_MEMCTRL(i)); + + dma_free_coherent(&pdev->dev, mem_decs, cdd->cd, + cdd->descs_phys); + } +} + +static void disable_sched(struct cppi41_dd *cdd) +{ + cppi_writel(0, cdd->sched_mem + DMA_SCHED_CTRL); +} + +static void deinit_cpii41(struct platform_device *pdev, struct cppi41_dd *cdd) +{ + disable_sched(cdd); + + purge_descs(pdev, cdd); + + cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM0_BASE); + cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM0_BASE); + dma_free_coherent(&pdev->dev, QMGR_SCRATCH_SIZE, cdd->qmgr_scratch, + cdd->scratch_phys); +} + +static int init_descs(struct platform_device *pdev, struct cppi41_dd *cdd) +{ + unsigned int desc_size; + unsigned int mem_decs; + int i; + u32 reg; + u32 idx; + + BUILD_BUG_ON(sizeof(struct cppi41_desc) & + (sizeof(struct cppi41_desc) - 1)); + BUILD_BUG_ON(sizeof(struct cppi41_desc) < 32); + BUILD_BUG_ON(ALLOC_DECS_NUM < 32); + + desc_size = sizeof(struct cppi41_desc); + mem_decs = ALLOC_DECS_NUM * desc_size; + + idx = 0; + for (i = 0; i < DESCS_AREAS; i++) { + + reg = idx << QMGR_MEMCTRL_IDX_SH; + reg |= (ilog2(desc_size) - 5) << QMGR_MEMCTRL_DESC_SH; + reg |= ilog2(ALLOC_DECS_NUM) - 5; + + BUILD_BUG_ON(DESCS_AREAS != 1); + cdd->cd = dma_alloc_coherent(&pdev->dev, mem_decs, + &cdd->descs_phys, GFP_KERNEL); + if (!cdd->cd) + return -ENOMEM; + + cppi_writel(cdd->descs_phys, cdd->qmgr_mem + QMGR_MEMBASE(i)); + cppi_writel(reg, cdd->qmgr_mem + QMGR_MEMCTRL(i)); + + idx += ALLOC_DECS_NUM; + } + return 0; +} + +static void init_sched(struct cppi41_dd *cdd) +{ + unsigned ch; + unsigned word; + u32 reg; + + word = 0; + cppi_writel(0, cdd->sched_mem + DMA_SCHED_CTRL); + for (ch = 0; ch < 15 * 2; ch += 2) { + + reg = SCHED_ENTRY0_CHAN(ch); + reg |= SCHED_ENTRY1_CHAN(ch) | SCHED_ENTRY1_IS_RX; + + reg |= SCHED_ENTRY2_CHAN(ch + 1); + reg |= SCHED_ENTRY3_CHAN(ch + 1) | SCHED_ENTRY3_IS_RX; + cppi_writel(reg, cdd->sched_mem + DMA_SCHED_WORD(word)); + word++; + } + reg = 15 * 2 * 2 - 1; + reg |= DMA_SCHED_CTRL_EN; + cppi_writel(reg, cdd->sched_mem + DMA_SCHED_CTRL); +} + +static int init_cppi41(struct platform_device *pdev, struct cppi41_dd *cdd) +{ + int ret; + + BUILD_BUG_ON(QMGR_SCRATCH_SIZE > ((1 << 14) - 1)); + cdd->qmgr_scratch = dma_alloc_coherent(&pdev->dev, QMGR_SCRATCH_SIZE, + &cdd->scratch_phys, GFP_KERNEL); + if (!cdd->qmgr_scratch) + return -ENOMEM; + + cppi_writel(cdd->scratch_phys, cdd->qmgr_mem + QMGR_LRAM0_BASE); + cppi_writel(QMGR_SCRATCH_SIZE, cdd->qmgr_mem + QMGR_LRAM_SIZE); + cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM1_BASE); + + ret = init_descs(pdev, cdd); + if (ret) + goto err_td; + + cppi_writel(cdd->td_queue.submit, cdd->ctrl_mem + DMA_TDFDQ); + init_sched(cdd); + return 0; +err_td: + deinit_cpii41(pdev, cdd); + return ret; +} + +static struct platform_driver cpp41_dma_driver; +/* + * The param format is: + * X Y + * X: Port + * Y: 0 = RX else TX + */ +#define INFO_PORT 0 +#define INFO_IS_TX 1 + +static bool cpp41_dma_filter_fn(struct dma_chan *chan, void *param) +{ + struct cppi41_channel *cchan; + struct cppi41_dd *cdd; + const struct chan_queues *queues; + u32 *num = param; + + if (chan->device->dev->driver != &cpp41_dma_driver.driver) + return false; + + cchan = to_cpp41_chan(chan); + + if (cchan->port_num != num[INFO_PORT]) + return false; + + if (cchan->is_tx && !num[INFO_IS_TX]) + return false; + cdd = cchan->cdd; + if (cchan->is_tx) + queues = cdd->queues_tx; + else + queues = cdd->queues_rx; + + BUILD_BUG_ON(ARRAY_SIZE(usb_queues_rx) != ARRAY_SIZE(usb_queues_tx)); + if (WARN_ON(cchan->port_num > ARRAY_SIZE(usb_queues_rx))) + return false; + + cchan->q_num = queues[cchan->port_num].submit; + cchan->q_comp_num = queues[cchan->port_num].complete; + return true; +} + +static struct of_dma_filter_info cpp41_dma_info = { + .filter_fn = cpp41_dma_filter_fn, +}; + +static struct dma_chan *cppi41_dma_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) +{ + int count = dma_spec->args_count; + struct of_dma_filter_info *info = ofdma->of_dma_data; + + if (!info || !info->filter_fn) + return NULL; + + if (count != 2) + return NULL; + + return dma_request_channel(info->dma_cap, info->filter_fn, + &dma_spec->args[0]); +} + +static const struct cppi_glue_infos usb_infos = { + .isr = cppi41_irq, + .queues_rx = usb_queues_rx, + .queues_tx = usb_queues_tx, + .td_queue = { .submit = 31, .complete = 0 }, +}; + +static const struct of_device_id cppi41_dma_ids[] = { + { .compatible = "ti,am3359-cppi41", .data = &usb_infos}, + {}, +}; +MODULE_DEVICE_TABLE(of, cppi41_dma_ids); + +static const struct cppi_glue_infos *get_glue_info(struct platform_device *pdev) +{ + const struct of_device_id *of_id; + + of_id = of_match_node(cppi41_dma_ids, pdev->dev.of_node); + if (!of_id) + return NULL; + return of_id->data; +} + +static int cppi41_dma_probe(struct platform_device *pdev) +{ + struct cppi41_dd *cdd; + const struct cppi_glue_infos *glue_info; + int irq; + int ret; + + glue_info = get_glue_info(pdev); + if (!glue_info) + return -EINVAL; + + cdd = kzalloc(sizeof(*cdd), GFP_KERNEL); + if (!cdd) + return -ENOMEM; + + dma_cap_set(DMA_SLAVE, cdd->ddev.cap_mask); + cdd->ddev.device_alloc_chan_resources = cppi41_dma_alloc_chan_resources; + cdd->ddev.device_free_chan_resources = cppi41_dma_free_chan_resources; + cdd->ddev.device_tx_status = cppi41_dma_tx_status; + cdd->ddev.device_issue_pending = cppi41_dma_issue_pending; + cdd->ddev.device_prep_slave_sg = cppi41_dma_prep_slave_sg; + cdd->ddev.device_control = cppi41_dma_control; + cdd->ddev.dev = &pdev->dev; + INIT_LIST_HEAD(&cdd->ddev.channels); + cpp41_dma_info.dma_cap = cdd->ddev.cap_mask; + + cdd->usbss_mem = of_iomap(pdev->dev.of_node, 0); + cdd->ctrl_mem = of_iomap(pdev->dev.of_node, 1); + cdd->sched_mem = of_iomap(pdev->dev.of_node, 2); + cdd->qmgr_mem = of_iomap(pdev->dev.of_node, 3); + + if (!cdd->usbss_mem || !cdd->ctrl_mem || !cdd->sched_mem || + !cdd->qmgr_mem) { + ret = -ENXIO; + goto err_remap; + } + + cdd->queues_rx = glue_info->queues_rx; + cdd->queues_tx = glue_info->queues_tx; + cdd->td_queue = glue_info->td_queue; + + ret = init_cppi41(pdev, cdd); + if (ret) + goto err_init_cppi; + + ret = cppi41_add_chans(pdev, cdd); + if (ret) + goto err_chans; + + irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (!irq) + goto err_irq; + + cppi_writel(USBSS_IRQ_PD_COMP, cdd->usbss_mem + USBSS_IRQ_ENABLER); + + ret = request_irq(irq, glue_info->isr, IRQF_SHARED, + dev_name(&pdev->dev), cdd); + if (ret) + goto err_irq; + cdd->irq = irq; + + ret = dma_async_device_register(&cdd->ddev); + if (ret) + goto err_dma_reg; + + ret = of_dma_controller_register(pdev->dev.of_node, + cppi41_dma_xlate, &cpp41_dma_info); + if (ret) + goto err_of; + + platform_set_drvdata(pdev, cdd); + return 0; +err_of: + dma_async_device_unregister(&cdd->ddev); +err_dma_reg: + free_irq(irq, cdd); +err_irq: + cppi_writel(0, cdd->usbss_mem + USBSS_IRQ_CLEARR); + cleanup_chans(cdd); +err_chans: + deinit_cpii41(pdev, cdd); +err_init_cppi: + iounmap(cdd->usbss_mem); + iounmap(cdd->ctrl_mem); + iounmap(cdd->sched_mem); + iounmap(cdd->qmgr_mem); +err_remap: + kfree(cdd); + return ret; +} + +static int cppi41_dma_remove(struct platform_device *pdev) +{ + struct cppi41_dd *cdd = platform_get_drvdata(pdev); + + of_dma_controller_free(pdev->dev.of_node); + dma_async_device_unregister(&cdd->ddev); + + cppi_writel(0, cdd->usbss_mem + USBSS_IRQ_CLEARR); + free_irq(cdd->irq, cdd); + cleanup_chans(cdd); + deinit_cpii41(pdev, cdd); + iounmap(cdd->usbss_mem); + iounmap(cdd->ctrl_mem); + iounmap(cdd->sched_mem); + iounmap(cdd->qmgr_mem); + kfree(cdd); + return 0; +} + +static struct platform_driver cpp41_dma_driver = { + .probe = cppi41_dma_probe, + .remove = cppi41_dma_remove, + .driver = { + .name = "cppi41-dma-engine", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(cppi41_dma_ids), + }, +}; + +module_platform_driver(cpp41_dma_driver); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>"); diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 5460abf045de..70d7c5b92c3c 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -46,7 +46,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/ obj-$(CONFIG_USB_SERIAL) += serial/ obj-$(CONFIG_USB) += misc/ -obj-$(CONFIG_USB_PHY) += phy/ +obj-$(CONFIG_USB_SUPPORT) += phy/ obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/ obj-$(CONFIG_USB_ATM) += atm/ diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 40d0fda4f66c..9b3aaf132bc3 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -63,6 +63,7 @@ static int host_start(struct ci_hdrc *ci) ehci = hcd_to_ehci(hcd); ehci->caps = ci->hw_bank.cap; ehci->has_hostpc = ci->hw_bank.lpm; + ehci->has_tdi_phy_lpm = ci->hw_bank.lpm; ret = usb_add_hcd(hcd, 0, 0); if (ret) diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 2378958ea63e..3e225d5846f6 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -40,6 +40,38 @@ config USB_DWC3_DUAL_ROLE endchoice +comment "Platform Glue Driver Support" + +config USB_DWC3_OMAP + tristate "Texas Instruments OMAP5 and similar Platforms" + depends on EXTCON + default USB_DWC3 + help + Some platforms from Texas Instruments like OMAP5, DRA7xxx and + AM437x use this IP for USB2/3 functionality. + + Say 'Y' or 'M' here if you have one such device + +config USB_DWC3_EXYNOS + tristate "Samsung Exynos Platform" + default USB_DWC3 + help + Recent Exynos5 SoCs ship with one DesignWare Core USB3 IP inside, + say 'Y' or 'M' if you have one such device. + +config USB_DWC3_PCI + tristate "PCIe-based Platforms" + depends on PCI + default USB_DWC3 + help + If you're using the DesignWare Core IP with a PCIe, please say + 'Y' or 'M' here. + + One such PCIe-based platform is Synopsys' PCIe HAPS model of + this IP. + +comment "Debugging features" + config USB_DWC3_DEBUG bool "Enable Debugging Messages" help diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index 0c7ac92582be..dd1760145c46 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -27,15 +27,8 @@ endif # the entire driver (with all its glue layers) on several architectures # and make sure it compiles fine. This will also help with allmodconfig # and allyesconfig builds. -# -# The only exception is the PCI glue layer, but that's only because -# PCI doesn't provide nops if CONFIG_PCI isn't enabled. ## -obj-$(CONFIG_USB_DWC3) += dwc3-omap.o -obj-$(CONFIG_USB_DWC3) += dwc3-exynos.o - -ifneq ($(CONFIG_PCI),) - obj-$(CONFIG_USB_DWC3) += dwc3-pci.o -endif - +obj-$(CONFIG_USB_DWC3_OMAP) += dwc3-omap.o +obj-$(CONFIG_USB_DWC3_EXYNOS) += dwc3-exynos.o +obj-$(CONFIG_USB_DWC3_PCI) += dwc3-pci.o diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 358375e0b291..3ff6f0ad01df 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -6,34 +6,17 @@ * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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/module.h> @@ -53,17 +36,16 @@ #include <linux/usb/otg.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> +#include <linux/usb/of.h> +#include <linux/usb/otg.h> +#include "platform_data.h" #include "core.h" #include "gadget.h" #include "io.h" #include "debug.h" -static char *maximum_speed = "super"; -module_param(maximum_speed, charp, 0); -MODULE_PARM_DESC(maximum_speed, "Maximum supported speed."); - /* -------------------------------------------------------------------------- */ void dwc3_set_mode(struct dwc3 *dwc, u32 mode) @@ -236,7 +218,7 @@ static int dwc3_event_buffers_setup(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), upper_32_bits(evt->dma)); dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), - evt->length & 0xffff); + DWC3_GEVNTSIZ_SIZE(evt->length)); dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0); } @@ -255,7 +237,8 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0); dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0); - dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0); + dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK + | DWC3_GEVNTSIZ_SIZE(0)); dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0); } } @@ -367,18 +350,17 @@ static void dwc3_core_exit(struct dwc3 *dwc) static int dwc3_probe(struct platform_device *pdev) { - struct device_node *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct dwc3_platform_data *pdata = dev_get_platdata(dev); + struct device_node *node = dev->of_node; struct resource *res; struct dwc3 *dwc; - struct device *dev = &pdev->dev; int ret = -ENOMEM; void __iomem *regs; void *mem; - u8 mode; - mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); if (!mem) { dev_err(dev, "not enough memory\n"); @@ -402,38 +384,29 @@ static int dwc3_probe(struct platform_device *pdev) dev_err(dev, "missing memory resource\n"); return -ENODEV; } - dwc->xhci_resources[0].start = res->start; - dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + - DWC3_XHCI_REGS_END; - dwc->xhci_resources[0].flags = res->flags; - dwc->xhci_resources[0].name = res->name; - - /* - * Request memory region but exclude xHCI regs, - * since it will be requested by the xhci-plat driver. - */ - res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START, - resource_size(res) - DWC3_GLOBALS_REGS_START, - dev_name(dev)); - if (!res) { - dev_err(dev, "can't request mem region\n"); - return -ENOMEM; - } - - regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); - if (!regs) { - dev_err(dev, "ioremap failed\n"); - return -ENOMEM; - } if (node) { + dwc->maximum_speed = of_usb_get_maximum_speed(node); + dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1); + + dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); + dwc->dr_mode = of_usb_get_dr_mode(node); } else { + dwc->maximum_speed = pdata->maximum_speed; + dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); + + dwc->needs_fifo_resize = pdata->tx_fifo_resize; + dwc->dr_mode = pdata->dr_mode; } + /* default to superspeed if no maximum_speed passed */ + if (dwc->maximum_speed == USB_SPEED_UNKNOWN) + dwc->maximum_speed = USB_SPEED_SUPER; + if (IS_ERR(dwc->usb2_phy)) { ret = PTR_ERR(dwc->usb2_phy); @@ -464,6 +437,22 @@ static int dwc3_probe(struct platform_device *pdev) return -EPROBE_DEFER; } + dwc->xhci_resources[0].start = res->start; + dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + + DWC3_XHCI_REGS_END; + dwc->xhci_resources[0].flags = res->flags; + dwc->xhci_resources[0].name = res->name; + + res->start += DWC3_GLOBALS_REGS_START; + + /* + * Request memory region but exclude xHCI regs, + * since it will be requested by the xhci-plat driver. + */ + regs = devm_ioremap_resource(dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + usb_phy_set_suspend(dwc->usb2_phy, 0); usb_phy_set_suspend(dwc->usb3_phy, 0); @@ -478,19 +467,6 @@ static int dwc3_probe(struct platform_device *pdev) dev->dma_parms = dev->parent->dma_parms; dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask); - if (!strncmp("super", maximum_speed, 5)) - dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; - else if (!strncmp("high", maximum_speed, 4)) - dwc->maximum_speed = DWC3_DCFG_HIGHSPEED; - else if (!strncmp("full", maximum_speed, 4)) - dwc->maximum_speed = DWC3_DCFG_FULLSPEED1; - else if (!strncmp("low", maximum_speed, 3)) - dwc->maximum_speed = DWC3_DCFG_LOWSPEED; - else - dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; - - dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); - pm_runtime_enable(dev); pm_runtime_get_sync(dev); pm_runtime_forbid(dev); @@ -517,14 +493,15 @@ static int dwc3_probe(struct platform_device *pdev) } if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) - mode = DWC3_MODE_HOST; + dwc->dr_mode = USB_DR_MODE_HOST; else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) - mode = DWC3_MODE_DEVICE; - else - mode = DWC3_MODE_DRD; + dwc->dr_mode = USB_DR_MODE_PERIPHERAL; + + if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) + dwc->dr_mode = USB_DR_MODE_OTG; - switch (mode) { - case DWC3_MODE_DEVICE: + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { @@ -532,7 +509,7 @@ static int dwc3_probe(struct platform_device *pdev) goto err2; } break; - case DWC3_MODE_HOST: + case USB_DR_MODE_HOST: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); ret = dwc3_host_init(dwc); if (ret) { @@ -540,7 +517,7 @@ static int dwc3_probe(struct platform_device *pdev) goto err2; } break; - case DWC3_MODE_DRD: + case USB_DR_MODE_OTG: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); ret = dwc3_host_init(dwc); if (ret) { @@ -555,10 +532,9 @@ static int dwc3_probe(struct platform_device *pdev) } break; default: - dev_err(dev, "Unsupported mode of operation %d\n", mode); + dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); goto err2; } - dwc->mode = mode; ret = dwc3_debugfs_init(dwc); if (ret) { @@ -571,14 +547,14 @@ static int dwc3_probe(struct platform_device *pdev) return 0; err3: - switch (mode) { - case DWC3_MODE_DEVICE: + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: dwc3_gadget_exit(dwc); break; - case DWC3_MODE_HOST: + case USB_DR_MODE_HOST: dwc3_host_exit(dwc); break; - case DWC3_MODE_DRD: + case USB_DR_MODE_OTG: dwc3_host_exit(dwc); dwc3_gadget_exit(dwc); break; @@ -611,14 +587,14 @@ static int dwc3_remove(struct platform_device *pdev) dwc3_debugfs_exit(dwc); - switch (dwc->mode) { - case DWC3_MODE_DEVICE: + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: dwc3_gadget_exit(dwc); break; - case DWC3_MODE_HOST: + case USB_DR_MODE_HOST: dwc3_host_exit(dwc); break; - case DWC3_MODE_DRD: + case USB_DR_MODE_OTG: dwc3_host_exit(dwc); dwc3_gadget_exit(dwc); break; @@ -642,12 +618,12 @@ static int dwc3_prepare(struct device *dev) spin_lock_irqsave(&dwc->lock, flags); - switch (dwc->mode) { - case DWC3_MODE_DEVICE: - case DWC3_MODE_DRD: + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + case USB_DR_MODE_OTG: dwc3_gadget_prepare(dwc); /* FALLTHROUGH */ - case DWC3_MODE_HOST: + case USB_DR_MODE_HOST: default: dwc3_event_buffers_cleanup(dwc); break; @@ -665,12 +641,12 @@ static void dwc3_complete(struct device *dev) spin_lock_irqsave(&dwc->lock, flags); - switch (dwc->mode) { - case DWC3_MODE_DEVICE: - case DWC3_MODE_DRD: + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + case USB_DR_MODE_OTG: dwc3_gadget_complete(dwc); /* FALLTHROUGH */ - case DWC3_MODE_HOST: + case USB_DR_MODE_HOST: default: dwc3_event_buffers_setup(dwc); break; @@ -686,12 +662,12 @@ static int dwc3_suspend(struct device *dev) spin_lock_irqsave(&dwc->lock, flags); - switch (dwc->mode) { - case DWC3_MODE_DEVICE: - case DWC3_MODE_DRD: + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + case USB_DR_MODE_OTG: dwc3_gadget_suspend(dwc); /* FALLTHROUGH */ - case DWC3_MODE_HOST: + case USB_DR_MODE_HOST: default: /* do nothing */ break; @@ -719,12 +695,12 @@ static int dwc3_resume(struct device *dev) dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl); - switch (dwc->mode) { - case DWC3_MODE_DEVICE: - case DWC3_MODE_DRD: + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + case USB_DR_MODE_OTG: dwc3_gadget_resume(dwc); /* FALLTHROUGH */ - case DWC3_MODE_HOST: + case USB_DR_MODE_HOST: default: /* do nothing */ break; @@ -754,6 +730,9 @@ static const struct dev_pm_ops dwc3_dev_pm_ops = { #ifdef CONFIG_OF static const struct of_device_id of_dwc3_match[] = { { + .compatible = "snps,dwc3" + }, + { .compatible = "synopsys,dwc3" }, { }, @@ -775,5 +754,5 @@ module_platform_driver(dwc3_driver); MODULE_ALIAS("platform:dwc3"); MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); -MODULE_LICENSE("Dual BSD/GPL"); +MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver"); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 27dad993b007..f8af8d44af85 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -6,34 +6,14 @@ * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #ifndef __DRIVERS_USB_DWC3_CORE_H @@ -49,6 +29,7 @@ #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> +#include <linux/usb/otg.h> /* Global constants */ #define DWC3_EP0_BOUNCE_SIZE 512 @@ -194,6 +175,10 @@ #define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff) #define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000) +/* Global Event Size Registers */ +#define DWC3_GEVNTSIZ_INTMASK (1 << 31) +#define DWC3_GEVNTSIZ_SIZE(n) ((n) & 0xffff) + /* Global HWPARAMS1 Register */ #define DWC3_GHWPARAMS1_EN_PWROPT(n) (((n) & (3 << 24)) >> 24) #define DWC3_GHWPARAMS1_EN_PWROPT_NO 0 @@ -207,7 +192,6 @@ #define DWC3_MAX_HIBER_SCRATCHBUFS 15 /* Device Configuration Register */ -#define DWC3_DCFG_LPM_CAP (1 << 22) #define DWC3_DCFG_DEVADDR(addr) ((addr) << 3) #define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f) @@ -367,7 +351,6 @@ struct dwc3_trb; /** * struct dwc3_event_buffer - Software event buffer representation - * @list: a list of event buffers * @buf: _THE_ buffer * @length: size of this buffer * @lpos: event offset @@ -415,7 +398,7 @@ struct dwc3_event_buffer { * @number: endpoint number (1 - 15) * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK * @resource_index: Resource transfer index - * @interval: the intervall on which the ISOC transfer is started + * @interval: the interval on which the ISOC transfer is started * @name: a human readable name e.g. ep1out-bulk * @direction: true for TX, false for RX * @stream_capable: true when streams are enabled @@ -566,11 +549,6 @@ struct dwc3_hwparams { /* HWPARAMS0 */ #define DWC3_MODE(n) ((n) & 0x7) -#define DWC3_MODE_DEVICE 0 -#define DWC3_MODE_HOST 1 -#define DWC3_MODE_DRD 2 -#define DWC3_MODE_HUB 3 - #define DWC3_MDWIDTH(n) (((n) & 0xff00) >> 8) /* HWPARAMS1 */ @@ -632,7 +610,7 @@ struct dwc3_scratchpad_array { * @u1u2: only used on revisions <1.83a for workaround * @maximum_speed: maximum speed requested (mainly for testing purposes) * @revision: revision register contents - * @mode: mode of operation + * @dr_mode: requested mode of operation * @usb2_phy: pointer to USB2 PHY * @usb3_phy: pointer to USB3 PHY * @dcfg: saved contents of DCFG register @@ -690,6 +668,8 @@ struct dwc3 { void __iomem *regs; size_t regs_size; + enum usb_dr_mode dr_mode; + /* used for suspend/resume */ u32 dcfg; u32 gctl; @@ -698,7 +678,6 @@ struct dwc3 { u32 u1u2; u32 maximum_speed; u32 revision; - u32 mode; #define DWC3_REVISION_173A 0x5533173a #define DWC3_REVISION_175A 0x5533175a diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index 5894ee8222af..fceb39dc4bba 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -6,34 +6,14 @@ * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include "core.h" diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 9e9f122162f2..9ac37fe1b6a7 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -6,34 +6,14 @@ * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include <linux/kernel.h> diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 8ce9d7fd6cfc..2f2e88a3a11a 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -6,10 +6,14 @@ * * Author: Anton Tikhomirov <av.tikhomirov@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include <linux/module.h> @@ -20,7 +24,7 @@ #include <linux/dma-mapping.h> #include <linux/clk.h> #include <linux/usb/otg.h> -#include <linux/usb/nop-usb-xceiv.h> +#include <linux/usb/usb_phy_gen_xceiv.h> #include <linux/of.h> #include <linux/of_platform.h> @@ -34,13 +38,13 @@ struct dwc3_exynos { static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos) { - struct nop_usb_xceiv_platform_data pdata; + struct usb_phy_gen_xceiv_platform_data pdata; struct platform_device *pdev; int ret; memset(&pdata, 0x00, sizeof(pdata)); - pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO); + pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO); if (!pdev) return -ENOMEM; @@ -51,7 +55,7 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos) if (ret) goto err1; - pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO); + pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO); if (!pdev) { ret = -ENOMEM; goto err1; @@ -228,5 +232,5 @@ module_platform_driver(dwc3_exynos_driver); MODULE_ALIAS("platform:exynos-dwc3"); MODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer"); diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 077f110bd746..ecd99451ee90 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -6,34 +6,14 @@ * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include <linux/module.h> @@ -409,11 +389,9 @@ static int dwc3_omap_probe(struct platform_device *pdev) return -EINVAL; } - base = devm_ioremap_nocache(dev, res->start, resource_size(res)); - if (!base) { - dev_err(dev, "ioremap failed\n"); - return -ENOMEM; - } + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); spin_lock_init(&omap->lock); @@ -610,5 +588,5 @@ module_platform_driver(dwc3_omap_driver); MODULE_ALIAS("platform:omap-dwc3"); MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); -MODULE_LICENSE("Dual BSD/GPL"); +MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("DesignWare USB3 OMAP Glue Layer"); diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index ed07ec04a962..9b138129e856 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -6,34 +6,14 @@ * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include <linux/kernel.h> @@ -43,7 +23,7 @@ #include <linux/platform_device.h> #include <linux/usb/otg.h> -#include <linux/usb/nop-usb-xceiv.h> +#include <linux/usb/usb_phy_gen_xceiv.h> /* FIXME define these in <linux/pci_ids.h> */ #define PCI_VENDOR_ID_SYNOPSYS 0x16c3 @@ -58,13 +38,13 @@ struct dwc3_pci { static int dwc3_pci_register_phys(struct dwc3_pci *glue) { - struct nop_usb_xceiv_platform_data pdata; + struct usb_phy_gen_xceiv_platform_data pdata; struct platform_device *pdev; int ret; memset(&pdata, 0x00, sizeof(pdata)); - pdev = platform_device_alloc("nop_usb_xceiv", 0); + pdev = platform_device_alloc("usb_phy_gen_xceiv", 0); if (!pdev) return -ENOMEM; @@ -75,7 +55,7 @@ static int dwc3_pci_register_phys(struct dwc3_pci *glue) if (ret) goto err1; - pdev = platform_device_alloc("nop_usb_xceiv", 1); + pdev = platform_device_alloc("usb_phy_gen_xceiv", 1); if (!pdev) { ret = -ENOMEM; goto err1; @@ -211,7 +191,7 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = { }; MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int dwc3_pci_suspend(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); @@ -236,28 +216,24 @@ static int dwc3_pci_resume(struct device *dev) return 0; } +#endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops dwc3_pci_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume) }; -#define DEV_PM_OPS (&dwc3_pci_dev_pm_ops) -#else -#define DEV_PM_OPS NULL -#endif /* CONFIG_PM */ - static struct pci_driver dwc3_pci_driver = { .name = "dwc3-pci", .id_table = dwc3_pci_id_table, .probe = dwc3_pci_probe, .remove = dwc3_pci_remove, .driver = { - .pm = DEV_PM_OPS, + .pm = &dwc3_pci_dev_pm_ops, }, }; MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); -MODULE_LICENSE("Dual BSD/GPL"); +MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer"); module_pci_driver(dwc3_pci_driver); diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 5acbb948b704..7fa93f4bc507 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -6,34 +6,14 @@ * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include <linux/kernel.h> @@ -168,6 +148,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, direction = !dwc->ep0_expect_in; dwc->delayed_status = false; + usb_gadget_set_state(&dwc->gadget, USB_STATE_CONFIGURED); if (dwc->ep0state == EP0_STATUS_PHASE) __dwc3_ep0_do_control_status(dwc, dwc->eps[direction]); @@ -553,8 +534,16 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) ret = dwc3_ep0_delegate_req(dwc, ctrl); /* if the cfg matches and the cfg is non zero */ if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) { - usb_gadget_set_state(&dwc->gadget, - USB_STATE_CONFIGURED); + + /* + * only change state if set_config has already + * been processed. If gadget driver returns + * USB_GADGET_DELAYED_STATUS, we will wait + * to change the state on the next usb_ep_queue() + */ + if (ret == 0) + usb_gadget_set_state(&dwc->gadget, + USB_STATE_CONFIGURED); /* * Enable transition to U1/U2 state when @@ -571,7 +560,7 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) case USB_STATE_CONFIGURED: ret = dwc3_ep0_delegate_req(dwc, ctrl); - if (!cfg) + if (!cfg && !ret) usb_gadget_set_state(&dwc->gadget, USB_STATE_ADDRESS); break; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index f77083fedc68..f168eaebdef8 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -6,34 +6,14 @@ * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include <linux/kernel.h> @@ -520,6 +500,8 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, u32 reg; int ret = -ENOMEM; + dev_vdbg(dwc->dev, "Enabling %s\n", dep->name); + if (!(dep->flags & DWC3_EP_ENABLED)) { ret = dwc3_gadget_start_config(dwc, dep); if (ret) @@ -676,8 +658,6 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep, dev_err(dwc->dev, "invalid endpoint transfer type\n"); } - dev_vdbg(dwc->dev, "Enabling %s\n", dep->name); - spin_lock_irqsave(&dwc->lock, flags); ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false); spin_unlock_irqrestore(&dwc->lock, flags); @@ -1508,6 +1488,15 @@ static int dwc3_gadget_start(struct usb_gadget *g, int irq; u32 reg; + irq = platform_get_irq(to_platform_device(dwc->dev), 0); + ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt, + IRQF_SHARED, "dwc3", dwc); + if (ret) { + dev_err(dwc->dev, "failed to request irq #%d --> %d\n", + irq, ret); + goto err0; + } + spin_lock_irqsave(&dwc->lock, flags); if (dwc->gadget_driver) { @@ -1515,7 +1504,7 @@ static int dwc3_gadget_start(struct usb_gadget *g, dwc->gadget.name, dwc->gadget_driver->driver.name); ret = -EBUSY; - goto err0; + goto err1; } dwc->gadget_driver = driver; @@ -1536,10 +1525,25 @@ static int dwc3_gadget_start(struct usb_gadget *g, * STAR#9000525659: Clock Domain Crossing on DCTL in * USB 2.0 Mode */ - if (dwc->revision < DWC3_REVISION_220A) + if (dwc->revision < DWC3_REVISION_220A) { reg |= DWC3_DCFG_SUPERSPEED; - else - reg |= dwc->maximum_speed; + } else { + switch (dwc->maximum_speed) { + case USB_SPEED_LOW: + reg |= DWC3_DSTS_LOWSPEED; + break; + case USB_SPEED_FULL: + reg |= DWC3_DSTS_FULLSPEED1; + break; + case USB_SPEED_HIGH: + reg |= DWC3_DSTS_HIGHSPEED; + break; + case USB_SPEED_SUPER: /* FALLTHROUGH */ + case USB_SPEED_UNKNOWN: /* FALTHROUGH */ + default: + reg |= DWC3_DSTS_SUPERSPEED; + } + } dwc3_writel(dwc->regs, DWC3_DCFG, reg); dwc->start_config_issued = false; @@ -1551,42 +1555,38 @@ static int dwc3_gadget_start(struct usb_gadget *g, ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); - goto err0; + goto err2; } dep = dwc->eps[1]; ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); - goto err1; + goto err3; } /* begin to receive SETUP packets */ dwc->ep0state = EP0_SETUP_PHASE; dwc3_ep0_out_start(dwc); - irq = platform_get_irq(to_platform_device(dwc->dev), 0); - ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt, - IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc); - if (ret) { - dev_err(dwc->dev, "failed to request irq #%d --> %d\n", - irq, ret); - goto err1; - } - dwc3_gadget_enable_irq(dwc); spin_unlock_irqrestore(&dwc->lock, flags); return 0; -err1: +err3: __dwc3_gadget_ep_disable(dwc->eps[0]); -err0: +err2: dwc->gadget_driver = NULL; + +err1: spin_unlock_irqrestore(&dwc->lock, flags); + free_irq(irq, dwc); + +err0: return ret; } @@ -1600,9 +1600,6 @@ static int dwc3_gadget_stop(struct usb_gadget *g, spin_lock_irqsave(&dwc->lock, flags); dwc3_gadget_disable_irq(dwc); - irq = platform_get_irq(to_platform_device(dwc->dev), 0); - free_irq(irq, dwc); - __dwc3_gadget_ep_disable(dwc->eps[0]); __dwc3_gadget_ep_disable(dwc->eps[1]); @@ -1610,6 +1607,9 @@ static int dwc3_gadget_stop(struct usb_gadget *g, spin_unlock_irqrestore(&dwc->lock, flags); + irq = platform_get_irq(to_platform_device(dwc->dev), 0); + free_irq(irq, dwc); + return 0; } @@ -1642,13 +1642,15 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc, dep->dwc = dwc; dep->number = epnum; + dep->direction = !!direction; dwc->eps[epnum] = dep; snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1, (epnum & 1) ? "in" : "out"); dep->endpoint.name = dep->name; - dep->direction = (epnum & 1); + + dev_vdbg(dwc->dev, "initializing %s\n", dep->name); if (epnum == 0 || epnum == 1) { dep->endpoint.maxpacket = 512; @@ -2105,34 +2107,6 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) dwc->setup_packet_pending = false; } -static void dwc3_gadget_usb3_phy_suspend(struct dwc3 *dwc, int suspend) -{ - u32 reg; - - reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); - - if (suspend) - reg |= DWC3_GUSB3PIPECTL_SUSPHY; - else - reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; - - dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); -} - -static void dwc3_gadget_usb2_phy_suspend(struct dwc3 *dwc, int suspend) -{ - u32 reg; - - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); - - if (suspend) - reg |= DWC3_GUSB2PHYCFG_SUSPHY; - else - reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; - - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); -} - static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) { u32 reg; @@ -2173,13 +2147,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) /* after reset -> Default State */ usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT); - /* Recent versions support automatic phy suspend and don't need this */ - if (dwc->revision < DWC3_REVISION_194A) { - /* Resume PHYs */ - dwc3_gadget_usb2_phy_suspend(dwc, false); - dwc3_gadget_usb3_phy_suspend(dwc, false); - } - if (dwc->gadget.speed != USB_SPEED_UNKNOWN) dwc3_disconnect_gadget(dwc); @@ -2223,20 +2190,6 @@ static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed) dwc3_writel(dwc->regs, DWC3_GCTL, reg); } -static void dwc3_gadget_phy_suspend(struct dwc3 *dwc, u8 speed) -{ - switch (speed) { - case USB_SPEED_SUPER: - dwc3_gadget_usb2_phy_suspend(dwc, true); - break; - case USB_SPEED_HIGH: - case USB_SPEED_FULL: - case USB_SPEED_LOW: - dwc3_gadget_usb3_phy_suspend(dwc, true); - break; - } -} - static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) { struct dwc3_ep *dep; @@ -2312,12 +2265,6 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_DCTL, reg); } - /* Recent versions support automatic phy suspend and don't need this */ - if (dwc->revision < DWC3_REVISION_194A) { - /* Suspend unneeded PHY */ - dwc3_gadget_phy_suspend(dwc, dwc->gadget.speed); - } - dep = dwc->eps[0]; ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true); if (ret) { @@ -2495,61 +2442,75 @@ static void dwc3_process_event_entry(struct dwc3 *dwc, } } -static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc) +static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) { - struct dwc3 *dwc = _dwc; - unsigned long flags; + struct dwc3_event_buffer *evt; irqreturn_t ret = IRQ_NONE; - int i; + int left; + u32 reg; - spin_lock_irqsave(&dwc->lock, flags); + evt = dwc->ev_buffs[buf]; + left = evt->count; - for (i = 0; i < dwc->num_event_buffers; i++) { - struct dwc3_event_buffer *evt; - int left; + if (!(evt->flags & DWC3_EVENT_PENDING)) + return IRQ_NONE; - evt = dwc->ev_buffs[i]; - left = evt->count; + while (left > 0) { + union dwc3_event event; - if (!(evt->flags & DWC3_EVENT_PENDING)) - continue; + event.raw = *(u32 *) (evt->buf + evt->lpos); - while (left > 0) { - union dwc3_event event; + dwc3_process_event_entry(dwc, &event); - event.raw = *(u32 *) (evt->buf + evt->lpos); + /* + * FIXME we wrap around correctly to the next entry as + * almost all entries are 4 bytes in size. There is one + * entry which has 12 bytes which is a regular entry + * followed by 8 bytes data. ATM I don't know how + * things are organized if we get next to the a + * boundary so I worry about that once we try to handle + * that. + */ + evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE; + left -= 4; - dwc3_process_event_entry(dwc, &event); + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4); + } - /* - * FIXME we wrap around correctly to the next entry as - * almost all entries are 4 bytes in size. There is one - * entry which has 12 bytes which is a regular entry - * followed by 8 bytes data. ATM I don't know how - * things are organized if we get next to the a - * boundary so I worry about that once we try to handle - * that. - */ - evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE; - left -= 4; + evt->count = 0; + evt->flags &= ~DWC3_EVENT_PENDING; + ret = IRQ_HANDLED; - dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(i), 4); - } + /* Unmask interrupt */ + reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf)); + reg &= ~DWC3_GEVNTSIZ_INTMASK; + dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg); - evt->count = 0; - evt->flags &= ~DWC3_EVENT_PENDING; - ret = IRQ_HANDLED; - } + return ret; +} + +static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc) +{ + struct dwc3 *dwc = _dwc; + unsigned long flags; + irqreturn_t ret = IRQ_NONE; + int i; + + spin_lock_irqsave(&dwc->lock, flags); + + for (i = 0; i < dwc->num_event_buffers; i++) + ret |= dwc3_process_event_buf(dwc, i); spin_unlock_irqrestore(&dwc->lock, flags); return ret; } -static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) +static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf) { struct dwc3_event_buffer *evt; u32 count; + u32 reg; evt = dwc->ev_buffs[buf]; @@ -2561,6 +2522,11 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) evt->count = count; evt->flags |= DWC3_EVENT_PENDING; + /* Mask interrupt */ + reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf)); + reg |= DWC3_GEVNTSIZ_INTMASK; + dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg); + return IRQ_WAKE_THREAD; } @@ -2575,7 +2541,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc) for (i = 0; i < dwc->num_event_buffers; i++) { irqreturn_t status; - status = dwc3_process_event_buf(dwc, i); + status = dwc3_check_event_buf(dwc, i); if (status == IRQ_WAKE_THREAD) ret = status; } @@ -2593,7 +2559,6 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc) */ int dwc3_gadget_init(struct dwc3 *dwc) { - u32 reg; int ret; dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req), @@ -2643,16 +2608,6 @@ int dwc3_gadget_init(struct dwc3 *dwc) if (ret) goto err4; - reg = dwc3_readl(dwc->regs, DWC3_DCFG); - reg |= DWC3_DCFG_LPM_CAP; - dwc3_writel(dwc->regs, DWC3_DCFG, reg); - - /* Enable USB2 LPM and automatic phy suspend only on recent versions */ - if (dwc->revision >= DWC3_REVISION_194A) { - dwc3_gadget_usb2_phy_suspend(dwc, false); - dwc3_gadget_usb3_phy_suspend(dwc, false); - } - ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget); if (ret) { dev_err(dwc->dev, "failed to register udc\n"); diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 99e6d7248820..febe1aa7b714 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -6,34 +6,14 @@ * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #ifndef __DRIVERS_USB_DWC3_GADGET_H diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index 0fa1846eda4c..32db328cc769 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -5,34 +5,14 @@ * * Authors: Felipe Balbi <balbi@ti.com>, * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include <linux/platform_device.h> diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h index a50f76b9d19b..d94441c14d8c 100644 --- a/drivers/usb/dwc3/io.h +++ b/drivers/usb/dwc3/io.h @@ -6,34 +6,14 @@ * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #ifndef __DRIVERS_USB_DWC3_IO_H diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h new file mode 100644 index 000000000000..7db34f00b89a --- /dev/null +++ b/drivers/usb/dwc3/platform_data.h @@ -0,0 +1,27 @@ +/** + * platform_data.h - USB DWC3 Platform Data Support + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * Author: Felipe Balbi <balbi@ti.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 of + * the License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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/usb/ch9.h> +#include <linux/usb/otg.h> + +struct dwc3_platform_data { + enum usb_device_speed maximum_speed; + enum usb_dr_mode dr_mode; + bool tx_fifo_resize; +}; diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 8e9368330b10..1e3f52574367 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -144,7 +144,6 @@ config USB_AT91 config USB_LPC32XX tristate "LPC32XX USB Peripheral Controller" depends on ARCH_LPC32XX - depends on USB_PHY select USB_ISP1301 help This option selects the USB device controller in the LPC32xx SoC. @@ -206,7 +205,6 @@ config USB_FOTG210_UDC config USB_OMAP tristate "OMAP USB Device Controller" depends on ARCH_OMAP1 - depends on USB_PHY select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG help Many Texas Instruments OMAP processors have flexible full @@ -287,21 +285,6 @@ config USB_S3C_HSOTG The Samsung S3C64XX USB2.0 high-speed gadget controller integrated into the S3C64XX series SoC. -config USB_IMX - tristate "Freescale i.MX1 USB Peripheral Controller" - depends on ARCH_MXC - depends on BROKEN - help - Freescale's i.MX1 includes an integrated full speed - USB 1.1 device controller. - - It has Six fixed-function endpoints, as well as endpoint - zero (for control transfers). - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "imx_udc" and force all - gadget drivers to also be dynamically linked. - config USB_S3C2410 tristate "S3C2410 USB Device Controller" depends on ARCH_S3C24XX diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index bad08e66f369..386db9daf1d9 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_USB_NET2280) += net2280.o obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o obj-$(CONFIG_USB_PXA25X) += pxa25x_udc.o obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o -obj-$(CONFIG_USB_IMX) += imx_udc.o obj-$(CONFIG_USB_GOKU) += goku_udc.o obj-$(CONFIG_USB_OMAP) += omap_udc.o obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index f52dcfe8f545..a9a4346c83aa 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -1122,7 +1122,7 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp) goto finished; } if (ep->dma) { - retval = prep_dma(ep, req, gfp); + retval = prep_dma(ep, req, GFP_ATOMIC); if (retval != 0) goto finished; /* write desc pointer to enable DMA */ @@ -1190,7 +1190,7 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp) * for PPB modes, because of chain creation reasons */ if (ep->in) { - retval = prep_dma(ep, req, gfp); + retval = prep_dma(ep, req, GFP_ATOMIC); if (retval != 0) goto finished; } diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index d9a6add0c852..4cc4fd6d1473 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -870,6 +870,11 @@ static void clk_on(struct at91_udc *udc) if (udc->clocked) return; udc->clocked = 1; + + if (IS_ENABLED(CONFIG_COMMON_CLK)) { + clk_set_rate(udc->uclk, 48000000); + clk_prepare_enable(udc->uclk); + } clk_prepare_enable(udc->iclk); clk_prepare_enable(udc->fclk); } @@ -882,6 +887,8 @@ static void clk_off(struct at91_udc *udc) udc->gadget.speed = USB_SPEED_UNKNOWN; clk_disable_unprepare(udc->fclk); clk_disable_unprepare(udc->iclk); + if (IS_ENABLED(CONFIG_COMMON_CLK)) + clk_disable_unprepare(udc->uclk); } /* @@ -1697,7 +1704,7 @@ static int at91udc_probe(struct platform_device *pdev) int retval; struct resource *res; - if (!dev->platform_data && !pdev->dev.of_node) { + if (!dev_get_platdata(dev) && !pdev->dev.of_node) { /* small (so we copy it) but critical! */ DBG("missing platform_data\n"); return -ENODEV; @@ -1728,7 +1735,7 @@ static int at91udc_probe(struct platform_device *pdev) if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) at91udc_of_init(udc, pdev->dev.of_node); else - memcpy(&udc->board, dev->platform_data, + memcpy(&udc->board, dev_get_platdata(dev), sizeof(struct at91_udc_data)); udc->pdev = pdev; udc->enabled = 0; @@ -1774,10 +1781,12 @@ static int at91udc_probe(struct platform_device *pdev) /* get interface and function clocks */ udc->iclk = clk_get(dev, "udc_clk"); udc->fclk = clk_get(dev, "udpck"); - if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) { + if (IS_ENABLED(CONFIG_COMMON_CLK)) + udc->uclk = clk_get(dev, "usb_clk"); + if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk) || + (IS_ENABLED(CONFIG_COMMON_CLK) && IS_ERR(udc->uclk))) { DBG("clocks missing\n"); retval = -ENODEV; - /* NOTE: we "know" here that refcounts on these are NOPs */ goto fail1; } @@ -1851,6 +1860,12 @@ fail3: fail2: free_irq(udc->udp_irq, udc); fail1: + if (IS_ENABLED(CONFIG_COMMON_CLK) && !IS_ERR(udc->uclk)) + clk_put(udc->uclk); + if (!IS_ERR(udc->fclk)) + clk_put(udc->fclk); + if (!IS_ERR(udc->iclk)) + clk_put(udc->iclk); iounmap(udc->udp_baseaddr); fail0a: if (cpu_is_at91rm9200()) @@ -1894,6 +1909,8 @@ static int __exit at91udc_remove(struct platform_device *pdev) clk_put(udc->iclk); clk_put(udc->fclk); + if (IS_ENABLED(CONFIG_COMMON_CLK)) + clk_put(udc->uclk); return 0; } diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h index e647d1c2ada4..017524663381 100644 --- a/drivers/usb/gadget/at91_udc.h +++ b/drivers/usb/gadget/at91_udc.h @@ -126,7 +126,7 @@ struct at91_udc { unsigned active_suspend:1; u8 addr; struct at91_udc_data board; - struct clk *iclk, *fclk; + struct clk *iclk, *fclk, *uclk; struct platform_device *pdev; struct proc_dir_entry *pde; void __iomem *udp_baseaddr; diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 1d9722203ca6..40d23384b716 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1772,6 +1772,7 @@ out: static int atmel_usba_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { + int ret = 0; struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget); unsigned long flags; @@ -1781,8 +1782,14 @@ static int atmel_usba_start(struct usb_gadget *gadget, udc->driver = driver; spin_unlock_irqrestore(&udc->lock, flags); - clk_enable(udc->pclk); - clk_enable(udc->hclk); + ret = clk_prepare_enable(udc->pclk); + if (ret) + goto out; + ret = clk_prepare_enable(udc->hclk); + if (ret) { + clk_disable_unprepare(udc->pclk); + goto out; + } DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name); @@ -1797,9 +1804,11 @@ static int atmel_usba_start(struct usb_gadget *gadget, usba_writel(udc, CTRL, USBA_ENABLE_MASK); usba_writel(udc, INT_ENB, USBA_END_OF_RESET); } + +out: spin_unlock_irqrestore(&udc->lock, flags); - return 0; + return ret; } static int atmel_usba_stop(struct usb_gadget *gadget, @@ -1822,8 +1831,8 @@ static int atmel_usba_stop(struct usb_gadget *gadget, udc->driver = NULL; - clk_disable(udc->hclk); - clk_disable(udc->pclk); + clk_disable_unprepare(udc->hclk); + clk_disable_unprepare(udc->pclk); DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name); @@ -1922,7 +1931,7 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, static struct usba_ep * usba_udc_pdata(struct platform_device *pdev, struct usba_udc *udc) { - struct usba_platform_data *pdata = pdev->dev.platform_data; + struct usba_platform_data *pdata = dev_get_platdata(&pdev->dev); struct usba_ep *eps; int i; @@ -2022,10 +2031,14 @@ static int __init usba_udc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, udc); /* Make sure we start from a clean slate */ - clk_enable(pclk); + ret = clk_prepare_enable(pclk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable pclk, aborting.\n"); + goto err_clk_enable; + } toggle_bias(0); usba_writel(udc, CTRL, USBA_DISABLE_MASK); - clk_disable(pclk); + clk_disable_unprepare(pclk); if (pdev->dev.of_node) udc->usba_ep = atmel_udc_of_init(pdev, udc); @@ -2081,6 +2094,7 @@ err_add_udc: free_irq(irq, udc); err_request_irq: err_alloc_ep: +err_clk_enable: iounmap(udc->fifo); err_map_fifo: iounmap(udc->regs); diff --git a/drivers/usb/gadget/bcm63xx_udc.c b/drivers/usb/gadget/bcm63xx_udc.c index fd24cb4540a4..c58fcf1ebe41 100644 --- a/drivers/usb/gadget/bcm63xx_udc.c +++ b/drivers/usb/gadget/bcm63xx_udc.c @@ -2313,7 +2313,7 @@ static void bcm63xx_udc_cleanup_debugfs(struct bcm63xx_udc *udc) static int bcm63xx_udc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct bcm63xx_usbd_platform_data *pd = dev->platform_data; + struct bcm63xx_usbd_platform_data *pd = dev_get_platdata(dev); struct bcm63xx_udc *udc; struct resource *res; int rc = -ENOMEM, i, irq; diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 56f1fd1cba25..4d4e96a5d2e9 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -3043,12 +3043,12 @@ fsg_config_from_params(struct fsg_config *cfg, lun->filename = params->file_count > i && params->file[i][0] ? params->file[i] - : 0; + : NULL; } /* Let MSF use defaults */ - cfg->vendor_name = 0; - cfg->product_name = 0; + cfg->vendor_name = NULL; + cfg->product_name = NULL; cfg->ops = NULL; cfg->private_data = NULL; diff --git a/drivers/usb/gadget/f_uac1.c b/drivers/usb/gadget/f_uac1.c index fa8ea4ea00c1..2b4c82d84bfc 100644 --- a/drivers/usb/gadget/f_uac1.c +++ b/drivers/usb/gadget/f_uac1.c @@ -695,7 +695,7 @@ static int generic_get_cmd(struct usb_audio_control *con, u8 cmd) } /* Todo: add more control selecotor dynamically */ -int __init control_selector_init(struct f_audio *audio) +static int __init control_selector_init(struct f_audio *audio) { INIT_LIST_HEAD(&audio->cs); list_add(&feature_unit.list, &audio->cs); @@ -719,7 +719,7 @@ int __init control_selector_init(struct f_audio *audio) * * Returns zero on success, else negative errno. */ -int __init audio_bind_config(struct usb_configuration *c) +static int __init audio_bind_config(struct usb_configuration *c) { struct f_audio *audio; int status; diff --git a/drivers/usb/gadget/fsl_mxc_udc.c b/drivers/usb/gadget/fsl_mxc_udc.c index d3bd7b095ba3..9b140fc4d3bc 100644 --- a/drivers/usb/gadget/fsl_mxc_udc.c +++ b/drivers/usb/gadget/fsl_mxc_udc.c @@ -33,7 +33,7 @@ int fsl_udc_clk_init(struct platform_device *pdev) unsigned long freq; int ret; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); mxc_ipg_clk = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(mxc_ipg_clk)) { @@ -80,7 +80,7 @@ eclkrate: int fsl_udc_clk_finalize(struct platform_device *pdev) { - struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); int ret = 0; /* workaround ENGcm09152 for i.MX35 */ diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index a766a4ca1cb7..36ac7cfba91d 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -2248,7 +2248,7 @@ static int __init struct_udc_setup(struct fsl_udc *udc, struct fsl_usb2_platform_data *pdata; size_t size; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); udc->phy_mode = pdata->phy_mode; udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL); @@ -2343,7 +2343,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev) return -ENOMEM; } - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); udc_controller->pdata = pdata; spin_lock_init(&udc_controller->lock); udc_controller->stopped = 1; @@ -2524,7 +2524,7 @@ err_kfree: static int __exit fsl_udc_remove(struct platform_device *pdev) { struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); DECLARE_COMPLETION(done); diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index c83f3e165325..f1dd6daabe21 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -557,7 +557,7 @@ static void fusb300_set_cxdone(struct fusb300 *fusb300) } /* read data from cx fifo */ -void fusb300_rdcxf(struct fusb300 *fusb300, +static void fusb300_rdcxf(struct fusb300 *fusb300, u8 *buffer, u32 length) { int i = 0; diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 52dd6cc6c0aa..c64deb9e3d62 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -772,7 +772,7 @@ goku_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) } /* else pio or dma irq handler advances the queue. */ - if (likely(req != 0)) + if (likely(req != NULL)) list_add_tail(&req->queue, &ep->queue); if (likely(!list_empty(&ep->queue)) diff --git a/drivers/usb/gadget/hid.c b/drivers/usb/gadget/hid.c index c36260ea8bf2..778613eb37af 100644 --- a/drivers/usb/gadget/hid.c +++ b/drivers/usb/gadget/hid.c @@ -185,7 +185,7 @@ static int __exit hid_unbind(struct usb_composite_dev *cdev) static int __init hidg_plat_driver_probe(struct platform_device *pdev) { - struct hidg_func_descriptor *func = pdev->dev.platform_data; + struct hidg_func_descriptor *func = dev_get_platdata(&pdev->dev); struct hidg_func_node *entry; if (!func) { diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c deleted file mode 100644 index 9b2d24e4c95f..000000000000 --- a/drivers/usb/gadget/imx_udc.c +++ /dev/null @@ -1,1544 +0,0 @@ -/* - * driver/usb/gadget/imx_udc.c - * - * Copyright (C) 2005 Mike Lee <eemike@gmail.com> - * Copyright (C) 2008 Darius Augulis <augulis.darius@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/platform_device.h> -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/list.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/device.h> -#include <linux/dma-mapping.h> -#include <linux/clk.h> -#include <linux/delay.h> -#include <linux/timer.h> -#include <linux/slab.h> -#include <linux/prefetch.h> - -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> - -#include <linux/platform_data/usb-imx_udc.h> -#include <mach/hardware.h> - -#include "imx_udc.h" - -static const char driver_name[] = "imx_udc"; -static const char ep0name[] = "ep0"; - -void ep0_chg_stat(const char *label, struct imx_udc_struct *imx_usb, - enum ep0_state stat); - -/******************************************************************************* - * IMX UDC hardware related functions - ******************************************************************************* - */ - -void imx_udc_enable(struct imx_udc_struct *imx_usb) -{ - int temp = __raw_readl(imx_usb->base + USB_CTRL); - __raw_writel(temp | CTRL_FE_ENA | CTRL_AFE_ENA, - imx_usb->base + USB_CTRL); - imx_usb->gadget.speed = USB_SPEED_FULL; -} - -void imx_udc_disable(struct imx_udc_struct *imx_usb) -{ - int temp = __raw_readl(imx_usb->base + USB_CTRL); - - __raw_writel(temp & ~(CTRL_FE_ENA | CTRL_AFE_ENA), - imx_usb->base + USB_CTRL); - - ep0_chg_stat(__func__, imx_usb, EP0_IDLE); - imx_usb->gadget.speed = USB_SPEED_UNKNOWN; -} - -void imx_udc_reset(struct imx_udc_struct *imx_usb) -{ - int temp = __raw_readl(imx_usb->base + USB_ENAB); - - /* set RST bit */ - __raw_writel(temp | ENAB_RST, imx_usb->base + USB_ENAB); - - /* wait RST bit to clear */ - do {} while (__raw_readl(imx_usb->base + USB_ENAB) & ENAB_RST); - - /* wait CFG bit to assert */ - do {} while (!(__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG)); - - /* udc module is now ready */ -} - -void imx_udc_config(struct imx_udc_struct *imx_usb) -{ - u8 ep_conf[5]; - u8 i, j, cfg; - struct imx_ep_struct *imx_ep; - - /* wait CFG bit to assert */ - do {} while (!(__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG)); - - /* Download the endpoint buffer for endpoint 0. */ - for (j = 0; j < 5; j++) { - i = (j == 2 ? imx_usb->imx_ep[0].fifosize : 0x00); - __raw_writeb(i, imx_usb->base + USB_DDAT); - do {} while (__raw_readl(imx_usb->base + USB_DADR) & DADR_BSY); - } - - /* Download the endpoint buffers for endpoints 1-5. - * We specify two configurations, one interface - */ - for (cfg = 1; cfg < 3; cfg++) { - for (i = 1; i < IMX_USB_NB_EP; i++) { - imx_ep = &imx_usb->imx_ep[i]; - /* EP no | Config no */ - ep_conf[0] = (i << 4) | (cfg << 2); - /* Type | Direction */ - ep_conf[1] = (imx_ep->bmAttributes << 3) | - (EP_DIR(imx_ep) << 2); - /* Max packet size */ - ep_conf[2] = imx_ep->fifosize; - /* TRXTYP */ - ep_conf[3] = 0xC0; - /* FIFO no */ - ep_conf[4] = i; - - D_INI(imx_usb->dev, - "<%s> ep%d_conf[%d]:" - "[%02x-%02x-%02x-%02x-%02x]\n", - __func__, i, cfg, - ep_conf[0], ep_conf[1], ep_conf[2], - ep_conf[3], ep_conf[4]); - - for (j = 0; j < 5; j++) { - __raw_writeb(ep_conf[j], - imx_usb->base + USB_DDAT); - do {} while (__raw_readl(imx_usb->base - + USB_DADR) - & DADR_BSY); - } - } - } - - /* wait CFG bit to clear */ - do {} while (__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG); -} - -void imx_udc_init_irq(struct imx_udc_struct *imx_usb) -{ - int i; - - /* Mask and clear all irqs */ - __raw_writel(0xFFFFFFFF, imx_usb->base + USB_MASK); - __raw_writel(0xFFFFFFFF, imx_usb->base + USB_INTR); - for (i = 0; i < IMX_USB_NB_EP; i++) { - __raw_writel(0x1FF, imx_usb->base + USB_EP_MASK(i)); - __raw_writel(0x1FF, imx_usb->base + USB_EP_INTR(i)); - } - - /* Enable USB irqs */ - __raw_writel(INTR_MSOF | INTR_FRAME_MATCH, imx_usb->base + USB_MASK); - - /* Enable EP0 irqs */ - __raw_writel(0x1FF & ~(EPINTR_DEVREQ | EPINTR_MDEVREQ | EPINTR_EOT - | EPINTR_EOF | EPINTR_FIFO_EMPTY | EPINTR_FIFO_FULL), - imx_usb->base + USB_EP_MASK(0)); -} - -void imx_udc_init_ep(struct imx_udc_struct *imx_usb) -{ - int i, max, temp; - struct imx_ep_struct *imx_ep; - for (i = 0; i < IMX_USB_NB_EP; i++) { - imx_ep = &imx_usb->imx_ep[i]; - switch (imx_ep->fifosize) { - case 8: - max = 0; - break; - case 16: - max = 1; - break; - case 32: - max = 2; - break; - case 64: - max = 3; - break; - default: - max = 1; - break; - } - temp = (EP_DIR(imx_ep) << 7) | (max << 5) - | (imx_ep->bmAttributes << 3); - __raw_writel(temp, imx_usb->base + USB_EP_STAT(i)); - __raw_writel(temp | EPSTAT_FLUSH, - imx_usb->base + USB_EP_STAT(i)); - D_INI(imx_usb->dev, "<%s> ep%d_stat %08x\n", __func__, i, - __raw_readl(imx_usb->base + USB_EP_STAT(i))); - } -} - -void imx_udc_init_fifo(struct imx_udc_struct *imx_usb) -{ - int i, temp; - struct imx_ep_struct *imx_ep; - for (i = 0; i < IMX_USB_NB_EP; i++) { - imx_ep = &imx_usb->imx_ep[i]; - - /* Fifo control */ - temp = EP_DIR(imx_ep) ? 0x0B000000 : 0x0F000000; - __raw_writel(temp, imx_usb->base + USB_EP_FCTRL(i)); - D_INI(imx_usb->dev, "<%s> ep%d_fctrl %08x\n", __func__, i, - __raw_readl(imx_usb->base + USB_EP_FCTRL(i))); - - /* Fifo alarm */ - temp = (i ? imx_ep->fifosize / 2 : 0); - __raw_writel(temp, imx_usb->base + USB_EP_FALRM(i)); - D_INI(imx_usb->dev, "<%s> ep%d_falrm %08x\n", __func__, i, - __raw_readl(imx_usb->base + USB_EP_FALRM(i))); - } -} - -static void imx_udc_init(struct imx_udc_struct *imx_usb) -{ - /* Reset UDC */ - imx_udc_reset(imx_usb); - - /* Download config to enpoint buffer */ - imx_udc_config(imx_usb); - - /* Setup interrups */ - imx_udc_init_irq(imx_usb); - - /* Setup endpoints */ - imx_udc_init_ep(imx_usb); - - /* Setup fifos */ - imx_udc_init_fifo(imx_usb); -} - -void imx_ep_irq_enable(struct imx_ep_struct *imx_ep) -{ - - int i = EP_NO(imx_ep); - - __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_MASK(i)); - __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_INTR(i)); - __raw_writel(0x1FF & ~(EPINTR_EOT | EPINTR_EOF), - imx_ep->imx_usb->base + USB_EP_MASK(i)); -} - -void imx_ep_irq_disable(struct imx_ep_struct *imx_ep) -{ - - int i = EP_NO(imx_ep); - - __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_MASK(i)); - __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_INTR(i)); -} - -int imx_ep_empty(struct imx_ep_struct *imx_ep) -{ - struct imx_udc_struct *imx_usb = imx_ep->imx_usb; - - return __raw_readl(imx_usb->base + USB_EP_FSTAT(EP_NO(imx_ep))) - & FSTAT_EMPTY; -} - -unsigned imx_fifo_bcount(struct imx_ep_struct *imx_ep) -{ - struct imx_udc_struct *imx_usb = imx_ep->imx_usb; - - return (__raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))) - & EPSTAT_BCOUNT) >> 16; -} - -void imx_flush(struct imx_ep_struct *imx_ep) -{ - struct imx_udc_struct *imx_usb = imx_ep->imx_usb; - - int temp = __raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); - __raw_writel(temp | EPSTAT_FLUSH, - imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); -} - -void imx_ep_stall(struct imx_ep_struct *imx_ep) -{ - struct imx_udc_struct *imx_usb = imx_ep->imx_usb; - int temp, i; - - D_ERR(imx_usb->dev, - "<%s> Forced stall on %s\n", __func__, imx_ep->ep.name); - - imx_flush(imx_ep); - - /* Special care for ep0 */ - if (!EP_NO(imx_ep)) { - temp = __raw_readl(imx_usb->base + USB_CTRL); - __raw_writel(temp | CTRL_CMDOVER | CTRL_CMDERROR, - imx_usb->base + USB_CTRL); - do { } while (__raw_readl(imx_usb->base + USB_CTRL) - & CTRL_CMDOVER); - temp = __raw_readl(imx_usb->base + USB_CTRL); - __raw_writel(temp & ~CTRL_CMDERROR, imx_usb->base + USB_CTRL); - } - else { - temp = __raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); - __raw_writel(temp | EPSTAT_STALL, - imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); - - for (i = 0; i < 100; i ++) { - temp = __raw_readl(imx_usb->base - + USB_EP_STAT(EP_NO(imx_ep))); - if (!(temp & EPSTAT_STALL)) - break; - udelay(20); - } - if (i == 100) - D_ERR(imx_usb->dev, "<%s> Non finished stall on %s\n", - __func__, imx_ep->ep.name); - } -} - -static int imx_udc_get_frame(struct usb_gadget *_gadget) -{ - struct imx_udc_struct *imx_usb = container_of(_gadget, - struct imx_udc_struct, gadget); - - return __raw_readl(imx_usb->base + USB_FRAME) & 0x7FF; -} - -static int imx_udc_wakeup(struct usb_gadget *_gadget) -{ - return 0; -} - -/******************************************************************************* - * USB request control functions - ******************************************************************************* - */ - -static void ep_add_request(struct imx_ep_struct *imx_ep, - struct imx_request *req) -{ - if (unlikely(!req)) - return; - - req->in_use = 1; - list_add_tail(&req->queue, &imx_ep->queue); -} - -static void ep_del_request(struct imx_ep_struct *imx_ep, - struct imx_request *req) -{ - if (unlikely(!req)) - return; - - list_del_init(&req->queue); - req->in_use = 0; -} - -static void done(struct imx_ep_struct *imx_ep, - struct imx_request *req, int status) -{ - ep_del_request(imx_ep, req); - - if (likely(req->req.status == -EINPROGRESS)) - req->req.status = status; - else - status = req->req.status; - - if (status && status != -ESHUTDOWN) - D_ERR(imx_ep->imx_usb->dev, - "<%s> complete %s req %p stat %d len %u/%u\n", __func__, - imx_ep->ep.name, &req->req, status, - req->req.actual, req->req.length); - - req->req.complete(&imx_ep->ep, &req->req); -} - -static void nuke(struct imx_ep_struct *imx_ep, int status) -{ - struct imx_request *req; - - while (!list_empty(&imx_ep->queue)) { - req = list_entry(imx_ep->queue.next, struct imx_request, queue); - done(imx_ep, req, status); - } -} - -/******************************************************************************* - * Data tansfer over USB functions - ******************************************************************************* - */ -static int read_packet(struct imx_ep_struct *imx_ep, struct imx_request *req) -{ - u8 *buf; - int bytes_ep, bufferspace, count, i; - - bytes_ep = imx_fifo_bcount(imx_ep); - bufferspace = req->req.length - req->req.actual; - - buf = req->req.buf + req->req.actual; - prefetchw(buf); - - if (unlikely(imx_ep_empty(imx_ep))) - count = 0; /* zlp */ - else - count = min(bytes_ep, bufferspace); - - for (i = count; i > 0; i--) - *buf++ = __raw_readb(imx_ep->imx_usb->base - + USB_EP_FDAT0(EP_NO(imx_ep))); - req->req.actual += count; - - return count; -} - -static int write_packet(struct imx_ep_struct *imx_ep, struct imx_request *req) -{ - u8 *buf; - int length, count, temp; - - if (unlikely(__raw_readl(imx_ep->imx_usb->base + - USB_EP_STAT(EP_NO(imx_ep))) & EPSTAT_ZLPS)) { - D_TRX(imx_ep->imx_usb->dev, "<%s> zlp still queued in EP %s\n", - __func__, imx_ep->ep.name); - return -1; - } - - buf = req->req.buf + req->req.actual; - prefetch(buf); - - length = min(req->req.length - req->req.actual, (u32)imx_ep->fifosize); - - if (imx_fifo_bcount(imx_ep) + length > imx_ep->fifosize) { - D_TRX(imx_ep->imx_usb->dev, "<%s> packet overfill %s fifo\n", - __func__, imx_ep->ep.name); - return -1; - } - - req->req.actual += length; - count = length; - - if (!count && req->req.zero) { /* zlp */ - temp = __raw_readl(imx_ep->imx_usb->base - + USB_EP_STAT(EP_NO(imx_ep))); - __raw_writel(temp | EPSTAT_ZLPS, imx_ep->imx_usb->base - + USB_EP_STAT(EP_NO(imx_ep))); - D_TRX(imx_ep->imx_usb->dev, "<%s> zero packet\n", __func__); - return 0; - } - - while (count--) { - if (count == 0) { /* last byte */ - temp = __raw_readl(imx_ep->imx_usb->base - + USB_EP_FCTRL(EP_NO(imx_ep))); - __raw_writel(temp | FCTRL_WFR, imx_ep->imx_usb->base - + USB_EP_FCTRL(EP_NO(imx_ep))); - } - __raw_writeb(*buf++, - imx_ep->imx_usb->base + USB_EP_FDAT0(EP_NO(imx_ep))); - } - - return length; -} - -static int read_fifo(struct imx_ep_struct *imx_ep, struct imx_request *req) -{ - int bytes = 0, - count, - completed = 0; - - while (__raw_readl(imx_ep->imx_usb->base + USB_EP_FSTAT(EP_NO(imx_ep))) - & FSTAT_FR) { - count = read_packet(imx_ep, req); - bytes += count; - - completed = (count != imx_ep->fifosize); - if (completed || req->req.actual == req->req.length) { - completed = 1; - break; - } - } - - if (completed || !req->req.length) { - done(imx_ep, req, 0); - D_REQ(imx_ep->imx_usb->dev, "<%s> %s req<%p> %s\n", - __func__, imx_ep->ep.name, req, - completed ? "completed" : "not completed"); - if (!EP_NO(imx_ep)) - ep0_chg_stat(__func__, imx_ep->imx_usb, EP0_IDLE); - } - - D_TRX(imx_ep->imx_usb->dev, "<%s> bytes read: %d\n", __func__, bytes); - - return completed; -} - -static int write_fifo(struct imx_ep_struct *imx_ep, struct imx_request *req) -{ - int bytes = 0, - count, - completed = 0; - - while (!completed) { - count = write_packet(imx_ep, req); - if (count < 0) - break; /* busy */ - bytes += count; - - /* last packet "must be" short (or a zlp) */ - completed = (count != imx_ep->fifosize); - - if (unlikely(completed)) { - done(imx_ep, req, 0); - D_REQ(imx_ep->imx_usb->dev, "<%s> %s req<%p> %s\n", - __func__, imx_ep->ep.name, req, - completed ? "completed" : "not completed"); - if (!EP_NO(imx_ep)) - ep0_chg_stat(__func__, - imx_ep->imx_usb, EP0_IDLE); - } - } - - D_TRX(imx_ep->imx_usb->dev, "<%s> bytes sent: %d\n", __func__, bytes); - - return completed; -} - -/******************************************************************************* - * Endpoint handlers - ******************************************************************************* - */ -static int handle_ep(struct imx_ep_struct *imx_ep) -{ - struct imx_request *req; - int completed = 0; - - do { - if (!list_empty(&imx_ep->queue)) - req = list_entry(imx_ep->queue.next, - struct imx_request, queue); - else { - D_REQ(imx_ep->imx_usb->dev, "<%s> no request on %s\n", - __func__, imx_ep->ep.name); - return 0; - } - - if (EP_DIR(imx_ep)) /* to host */ - completed = write_fifo(imx_ep, req); - else /* to device */ - completed = read_fifo(imx_ep, req); - - dump_ep_stat(__func__, imx_ep); - - } while (completed); - - return 0; -} - -static int handle_ep0(struct imx_ep_struct *imx_ep) -{ - struct imx_request *req = NULL; - int ret = 0; - - if (!list_empty(&imx_ep->queue)) { - req = list_entry(imx_ep->queue.next, struct imx_request, queue); - - switch (imx_ep->imx_usb->ep0state) { - - case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR */ - write_fifo(imx_ep, req); - break; - case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR */ - read_fifo(imx_ep, req); - break; - default: - D_EP0(imx_ep->imx_usb->dev, - "<%s> ep0 i/o, odd state %d\n", - __func__, imx_ep->imx_usb->ep0state); - ep_del_request(imx_ep, req); - ret = -EL2HLT; - break; - } - } - - else - D_ERR(imx_ep->imx_usb->dev, "<%s> no request on %s\n", - __func__, imx_ep->ep.name); - - return ret; -} - -static void handle_ep0_devreq(struct imx_udc_struct *imx_usb) -{ - struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[0]; - union { - struct usb_ctrlrequest r; - u8 raw[8]; - u32 word[2]; - } u; - int temp, i; - - nuke(imx_ep, -EPROTO); - - /* read SETUP packet */ - for (i = 0; i < 2; i++) { - if (imx_ep_empty(imx_ep)) { - D_ERR(imx_usb->dev, - "<%s> no setup packet received\n", __func__); - goto stall; - } - u.word[i] = __raw_readl(imx_usb->base - + USB_EP_FDAT(EP_NO(imx_ep))); - } - - temp = imx_ep_empty(imx_ep); - while (!imx_ep_empty(imx_ep)) { - i = __raw_readl(imx_usb->base + USB_EP_FDAT(EP_NO(imx_ep))); - D_ERR(imx_usb->dev, - "<%s> wrong to have extra bytes for setup : 0x%08x\n", - __func__, i); - } - if (!temp) - goto stall; - - le16_to_cpus(&u.r.wValue); - le16_to_cpus(&u.r.wIndex); - le16_to_cpus(&u.r.wLength); - - D_REQ(imx_usb->dev, "<%s> SETUP %02x.%02x v%04x i%04x l%04x\n", - __func__, u.r.bRequestType, u.r.bRequest, - u.r.wValue, u.r.wIndex, u.r.wLength); - - if (imx_usb->set_config) { - /* NACK the host by using CMDOVER */ - temp = __raw_readl(imx_usb->base + USB_CTRL); - __raw_writel(temp | CTRL_CMDOVER, imx_usb->base + USB_CTRL); - - D_ERR(imx_usb->dev, - "<%s> set config req is pending, NACK the host\n", - __func__); - return; - } - - if (u.r.bRequestType & USB_DIR_IN) - ep0_chg_stat(__func__, imx_usb, EP0_IN_DATA_PHASE); - else - ep0_chg_stat(__func__, imx_usb, EP0_OUT_DATA_PHASE); - - i = imx_usb->driver->setup(&imx_usb->gadget, &u.r); - if (i < 0) { - D_ERR(imx_usb->dev, "<%s> device setup error %d\n", - __func__, i); - goto stall; - } - - return; -stall: - D_ERR(imx_usb->dev, "<%s> protocol STALL\n", __func__); - imx_ep_stall(imx_ep); - ep0_chg_stat(__func__, imx_usb, EP0_STALL); - return; -} - -/******************************************************************************* - * USB gadget callback functions - ******************************************************************************* - */ - -static int imx_ep_enable(struct usb_ep *usb_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct imx_ep_struct *imx_ep = container_of(usb_ep, - struct imx_ep_struct, ep); - struct imx_udc_struct *imx_usb = imx_ep->imx_usb; - unsigned long flags; - - if (!usb_ep - || !desc - || !EP_NO(imx_ep) - || desc->bDescriptorType != USB_DT_ENDPOINT - || imx_ep->bEndpointAddress != desc->bEndpointAddress) { - D_ERR(imx_usb->dev, - "<%s> bad ep or descriptor\n", __func__); - return -EINVAL; - } - - if (imx_ep->bmAttributes != desc->bmAttributes) { - D_ERR(imx_usb->dev, - "<%s> %s type mismatch\n", __func__, usb_ep->name); - return -EINVAL; - } - - if (imx_ep->fifosize < usb_endpoint_maxp(desc)) { - D_ERR(imx_usb->dev, - "<%s> bad %s maxpacket\n", __func__, usb_ep->name); - return -ERANGE; - } - - if (!imx_usb->driver || imx_usb->gadget.speed == USB_SPEED_UNKNOWN) { - D_ERR(imx_usb->dev, "<%s> bogus device state\n", __func__); - return -ESHUTDOWN; - } - - local_irq_save(flags); - - imx_ep->stopped = 0; - imx_flush(imx_ep); - imx_ep_irq_enable(imx_ep); - - local_irq_restore(flags); - - D_EPX(imx_usb->dev, "<%s> ENABLED %s\n", __func__, usb_ep->name); - return 0; -} - -static int imx_ep_disable(struct usb_ep *usb_ep) -{ - struct imx_ep_struct *imx_ep = container_of(usb_ep, - struct imx_ep_struct, ep); - unsigned long flags; - - if (!usb_ep || !EP_NO(imx_ep) || !list_empty(&imx_ep->queue)) { - D_ERR(imx_ep->imx_usb->dev, "<%s> %s can not be disabled\n", - __func__, usb_ep ? imx_ep->ep.name : NULL); - return -EINVAL; - } - - local_irq_save(flags); - - imx_ep->stopped = 1; - nuke(imx_ep, -ESHUTDOWN); - imx_flush(imx_ep); - imx_ep_irq_disable(imx_ep); - - local_irq_restore(flags); - - D_EPX(imx_ep->imx_usb->dev, - "<%s> DISABLED %s\n", __func__, usb_ep->name); - return 0; -} - -static struct usb_request *imx_ep_alloc_request - (struct usb_ep *usb_ep, gfp_t gfp_flags) -{ - struct imx_request *req; - - if (!usb_ep) - return NULL; - - req = kzalloc(sizeof *req, gfp_flags); - if (!req) - return NULL; - - INIT_LIST_HEAD(&req->queue); - req->in_use = 0; - - return &req->req; -} - -static void imx_ep_free_request - (struct usb_ep *usb_ep, struct usb_request *usb_req) -{ - struct imx_request *req; - - req = container_of(usb_req, struct imx_request, req); - WARN_ON(!list_empty(&req->queue)); - kfree(req); -} - -static int imx_ep_queue - (struct usb_ep *usb_ep, struct usb_request *usb_req, gfp_t gfp_flags) -{ - struct imx_ep_struct *imx_ep; - struct imx_udc_struct *imx_usb; - struct imx_request *req; - unsigned long flags; - int ret = 0; - - imx_ep = container_of(usb_ep, struct imx_ep_struct, ep); - imx_usb = imx_ep->imx_usb; - req = container_of(usb_req, struct imx_request, req); - - /* - Special care on IMX udc. - Ignore enqueue when after set configuration from the - host. This assume all gadget drivers reply set - configuration with the next ep0 req enqueue. - */ - if (imx_usb->set_config && !EP_NO(imx_ep)) { - imx_usb->set_config = 0; - D_ERR(imx_usb->dev, - "<%s> gadget reply set config\n", __func__); - return 0; - } - - if (unlikely(!usb_req || !req || !usb_req->complete || !usb_req->buf)) { - D_ERR(imx_usb->dev, "<%s> bad params\n", __func__); - return -EINVAL; - } - - if (unlikely(!usb_ep || !imx_ep)) { - D_ERR(imx_usb->dev, "<%s> bad ep\n", __func__); - return -EINVAL; - } - - if (!imx_usb->driver || imx_usb->gadget.speed == USB_SPEED_UNKNOWN) { - D_ERR(imx_usb->dev, "<%s> bogus device state\n", __func__); - return -ESHUTDOWN; - } - - /* Debug */ - D_REQ(imx_usb->dev, "<%s> ep%d %s request for [%d] bytes\n", - __func__, EP_NO(imx_ep), - ((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state - == EP0_IN_DATA_PHASE) - || (EP_NO(imx_ep) && EP_DIR(imx_ep))) - ? "IN" : "OUT", usb_req->length); - dump_req(__func__, imx_ep, usb_req); - - if (imx_ep->stopped) { - usb_req->status = -ESHUTDOWN; - return -ESHUTDOWN; - } - - if (req->in_use) { - D_ERR(imx_usb->dev, - "<%s> refusing to queue req %p (already queued)\n", - __func__, req); - return 0; - } - - local_irq_save(flags); - - usb_req->status = -EINPROGRESS; - usb_req->actual = 0; - - ep_add_request(imx_ep, req); - - if (!EP_NO(imx_ep)) - ret = handle_ep0(imx_ep); - else - ret = handle_ep(imx_ep); - - local_irq_restore(flags); - return ret; -} - -static int imx_ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req) -{ - - struct imx_ep_struct *imx_ep = container_of - (usb_ep, struct imx_ep_struct, ep); - struct imx_request *req; - unsigned long flags; - - if (unlikely(!usb_ep || !EP_NO(imx_ep))) { - D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__); - return -EINVAL; - } - - local_irq_save(flags); - - /* make sure it's actually queued on this endpoint */ - list_for_each_entry(req, &imx_ep->queue, queue) { - if (&req->req == usb_req) - break; - } - if (&req->req != usb_req) { - local_irq_restore(flags); - return -EINVAL; - } - - done(imx_ep, req, -ECONNRESET); - - local_irq_restore(flags); - return 0; -} - -static int imx_ep_set_halt(struct usb_ep *usb_ep, int value) -{ - struct imx_ep_struct *imx_ep = container_of - (usb_ep, struct imx_ep_struct, ep); - unsigned long flags; - - if (unlikely(!usb_ep || !EP_NO(imx_ep))) { - D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__); - return -EINVAL; - } - - local_irq_save(flags); - - if ((imx_ep->bEndpointAddress & USB_DIR_IN) - && !list_empty(&imx_ep->queue)) { - local_irq_restore(flags); - return -EAGAIN; - } - - imx_ep_stall(imx_ep); - - local_irq_restore(flags); - - D_EPX(imx_ep->imx_usb->dev, "<%s> %s halt\n", __func__, usb_ep->name); - return 0; -} - -static int imx_ep_fifo_status(struct usb_ep *usb_ep) -{ - struct imx_ep_struct *imx_ep = container_of - (usb_ep, struct imx_ep_struct, ep); - - if (!usb_ep) { - D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__); - return -ENODEV; - } - - if (imx_ep->imx_usb->gadget.speed == USB_SPEED_UNKNOWN) - return 0; - else - return imx_fifo_bcount(imx_ep); -} - -static void imx_ep_fifo_flush(struct usb_ep *usb_ep) -{ - struct imx_ep_struct *imx_ep = container_of - (usb_ep, struct imx_ep_struct, ep); - unsigned long flags; - - local_irq_save(flags); - - if (!usb_ep || !EP_NO(imx_ep) || !list_empty(&imx_ep->queue)) { - D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__); - local_irq_restore(flags); - return; - } - - /* toggle and halt bits stay unchanged */ - imx_flush(imx_ep); - - local_irq_restore(flags); -} - -static struct usb_ep_ops imx_ep_ops = { - .enable = imx_ep_enable, - .disable = imx_ep_disable, - - .alloc_request = imx_ep_alloc_request, - .free_request = imx_ep_free_request, - - .queue = imx_ep_queue, - .dequeue = imx_ep_dequeue, - - .set_halt = imx_ep_set_halt, - .fifo_status = imx_ep_fifo_status, - .fifo_flush = imx_ep_fifo_flush, -}; - -/******************************************************************************* - * USB endpoint control functions - ******************************************************************************* - */ - -void ep0_chg_stat(const char *label, - struct imx_udc_struct *imx_usb, enum ep0_state stat) -{ - D_EP0(imx_usb->dev, "<%s> from %15s to %15s\n", - label, state_name[imx_usb->ep0state], state_name[stat]); - - if (imx_usb->ep0state == stat) - return; - - imx_usb->ep0state = stat; -} - -static void usb_init_data(struct imx_udc_struct *imx_usb) -{ - struct imx_ep_struct *imx_ep; - u8 i; - - /* device/ep0 records init */ - INIT_LIST_HEAD(&imx_usb->gadget.ep_list); - INIT_LIST_HEAD(&imx_usb->gadget.ep0->ep_list); - ep0_chg_stat(__func__, imx_usb, EP0_IDLE); - - /* basic endpoint records init */ - for (i = 0; i < IMX_USB_NB_EP; i++) { - imx_ep = &imx_usb->imx_ep[i]; - - if (i) { - list_add_tail(&imx_ep->ep.ep_list, - &imx_usb->gadget.ep_list); - imx_ep->stopped = 1; - } else - imx_ep->stopped = 0; - - INIT_LIST_HEAD(&imx_ep->queue); - } -} - -static void udc_stop_activity(struct imx_udc_struct *imx_usb, - struct usb_gadget_driver *driver) -{ - struct imx_ep_struct *imx_ep; - int i; - - if (imx_usb->gadget.speed == USB_SPEED_UNKNOWN) - driver = NULL; - - /* prevent new request submissions, kill any outstanding requests */ - for (i = 1; i < IMX_USB_NB_EP; i++) { - imx_ep = &imx_usb->imx_ep[i]; - imx_flush(imx_ep); - imx_ep->stopped = 1; - imx_ep_irq_disable(imx_ep); - nuke(imx_ep, -ESHUTDOWN); - } - - imx_usb->cfg = 0; - imx_usb->intf = 0; - imx_usb->alt = 0; - - if (driver) - driver->disconnect(&imx_usb->gadget); -} - -/******************************************************************************* - * Interrupt handlers - ******************************************************************************* - */ - -/* - * Called when timer expires. - * Timer is started when CFG_CHG is received. - */ -static void handle_config(unsigned long data) -{ - struct imx_udc_struct *imx_usb = (void *)data; - struct usb_ctrlrequest u; - int temp, cfg, intf, alt; - - local_irq_disable(); - - temp = __raw_readl(imx_usb->base + USB_STAT); - cfg = (temp & STAT_CFG) >> 5; - intf = (temp & STAT_INTF) >> 3; - alt = temp & STAT_ALTSET; - - D_REQ(imx_usb->dev, - "<%s> orig config C=%d, I=%d, A=%d / " - "req config C=%d, I=%d, A=%d\n", - __func__, imx_usb->cfg, imx_usb->intf, imx_usb->alt, - cfg, intf, alt); - - if (cfg == 1 || cfg == 2) { - - if (imx_usb->cfg != cfg) { - u.bRequest = USB_REQ_SET_CONFIGURATION; - u.bRequestType = USB_DIR_OUT | - USB_TYPE_STANDARD | - USB_RECIP_DEVICE; - u.wValue = cfg; - u.wIndex = 0; - u.wLength = 0; - imx_usb->cfg = cfg; - imx_usb->driver->setup(&imx_usb->gadget, &u); - - } - if (imx_usb->intf != intf || imx_usb->alt != alt) { - u.bRequest = USB_REQ_SET_INTERFACE; - u.bRequestType = USB_DIR_OUT | - USB_TYPE_STANDARD | - USB_RECIP_INTERFACE; - u.wValue = alt; - u.wIndex = intf; - u.wLength = 0; - imx_usb->intf = intf; - imx_usb->alt = alt; - imx_usb->driver->setup(&imx_usb->gadget, &u); - } - } - - imx_usb->set_config = 0; - - local_irq_enable(); -} - -static irqreturn_t imx_udc_irq(int irq, void *dev) -{ - struct imx_udc_struct *imx_usb = dev; - int intr = __raw_readl(imx_usb->base + USB_INTR); - int temp; - - if (intr & (INTR_WAKEUP | INTR_SUSPEND | INTR_RESUME | INTR_RESET_START - | INTR_RESET_STOP | INTR_CFG_CHG)) { - dump_intr(__func__, intr, imx_usb->dev); - dump_usb_stat(__func__, imx_usb); - } - - if (!imx_usb->driver) - goto end_irq; - - if (intr & INTR_SOF) { - /* Copy from Freescale BSP. - We must enable SOF intr and set CMDOVER. - Datasheet don't specifiy this action, but it - is done in Freescale BSP, so just copy it. - */ - if (imx_usb->ep0state == EP0_IDLE) { - temp = __raw_readl(imx_usb->base + USB_CTRL); - __raw_writel(temp | CTRL_CMDOVER, - imx_usb->base + USB_CTRL); - } - } - - if (intr & INTR_CFG_CHG) { - /* A workaround of serious IMX UDC bug. - Handling of CFG_CHG should be delayed for some time, because - IMX does not NACK the host when CFG_CHG interrupt is pending. - There is no time to handle current CFG_CHG - if next CFG_CHG or SETUP packed is send immediately. - We have to clear CFG_CHG, start the timer and - NACK the host by setting CTRL_CMDOVER - if it sends any SETUP packet. - When timer expires, handler is called to handle configuration - changes. While CFG_CHG is not handled (set_config=1), - we must NACK the host to every SETUP packed. - This delay prevents from going out of sync with host. - */ - __raw_writel(INTR_CFG_CHG, imx_usb->base + USB_INTR); - imx_usb->set_config = 1; - mod_timer(&imx_usb->timer, jiffies + 5); - goto end_irq; - } - - if (intr & INTR_WAKEUP) { - if (imx_usb->gadget.speed == USB_SPEED_UNKNOWN - && imx_usb->driver && imx_usb->driver->resume) - imx_usb->driver->resume(&imx_usb->gadget); - imx_usb->set_config = 0; - del_timer(&imx_usb->timer); - imx_usb->gadget.speed = USB_SPEED_FULL; - } - - if (intr & INTR_SUSPEND) { - if (imx_usb->gadget.speed != USB_SPEED_UNKNOWN - && imx_usb->driver && imx_usb->driver->suspend) - imx_usb->driver->suspend(&imx_usb->gadget); - imx_usb->set_config = 0; - del_timer(&imx_usb->timer); - imx_usb->gadget.speed = USB_SPEED_UNKNOWN; - } - - if (intr & INTR_RESET_START) { - __raw_writel(intr, imx_usb->base + USB_INTR); - udc_stop_activity(imx_usb, imx_usb->driver); - imx_usb->set_config = 0; - del_timer(&imx_usb->timer); - imx_usb->gadget.speed = USB_SPEED_UNKNOWN; - } - - if (intr & INTR_RESET_STOP) - imx_usb->gadget.speed = USB_SPEED_FULL; - -end_irq: - __raw_writel(intr, imx_usb->base + USB_INTR); - return IRQ_HANDLED; -} - -static irqreturn_t imx_udc_ctrl_irq(int irq, void *dev) -{ - struct imx_udc_struct *imx_usb = dev; - struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[0]; - int intr = __raw_readl(imx_usb->base + USB_EP_INTR(0)); - - dump_ep_intr(__func__, 0, intr, imx_usb->dev); - - if (!imx_usb->driver) { - __raw_writel(intr, imx_usb->base + USB_EP_INTR(0)); - return IRQ_HANDLED; - } - - /* DEVREQ has highest priority */ - if (intr & (EPINTR_DEVREQ | EPINTR_MDEVREQ)) - handle_ep0_devreq(imx_usb); - /* Seem i.MX is missing EOF interrupt sometimes. - * Therefore we don't monitor EOF. - * We call handle_ep0() only if a request is queued for ep0. - */ - else if (!list_empty(&imx_ep->queue)) - handle_ep0(imx_ep); - - __raw_writel(intr, imx_usb->base + USB_EP_INTR(0)); - - return IRQ_HANDLED; -} - -#ifndef MX1_INT_USBD0 -#define MX1_INT_USBD0 MX1_USBD_INT0 -#endif - -static irqreturn_t imx_udc_bulk_irq(int irq, void *dev) -{ - struct imx_udc_struct *imx_usb = dev; - struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[irq - MX1_INT_USBD0]; - int intr = __raw_readl(imx_usb->base + USB_EP_INTR(EP_NO(imx_ep))); - - dump_ep_intr(__func__, irq - MX1_INT_USBD0, intr, imx_usb->dev); - - if (!imx_usb->driver) { - __raw_writel(intr, imx_usb->base + USB_EP_INTR(EP_NO(imx_ep))); - return IRQ_HANDLED; - } - - handle_ep(imx_ep); - - __raw_writel(intr, imx_usb->base + USB_EP_INTR(EP_NO(imx_ep))); - - return IRQ_HANDLED; -} - -irq_handler_t intr_handler(int i) -{ - switch (i) { - case 0: - return imx_udc_ctrl_irq; - case 1: - case 2: - case 3: - case 4: - case 5: - return imx_udc_bulk_irq; - default: - return imx_udc_irq; - } -} - -/******************************************************************************* - * Static defined IMX UDC structure - ******************************************************************************* - */ - -static int imx_udc_start(struct usb_gadget *gadget, - struct usb_gadget_driver *driver); -static int imx_udc_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver); -static const struct usb_gadget_ops imx_udc_ops = { - .get_frame = imx_udc_get_frame, - .wakeup = imx_udc_wakeup, - .udc_start = imx_udc_start, - .udc_stop = imx_udc_stop, -}; - -static struct imx_udc_struct controller = { - .gadget = { - .ops = &imx_udc_ops, - .ep0 = &controller.imx_ep[0].ep, - .name = driver_name, - .dev = { - .init_name = "gadget", - }, - }, - - .imx_ep[0] = { - .ep = { - .name = ep0name, - .ops = &imx_ep_ops, - .maxpacket = 32, - }, - .imx_usb = &controller, - .fifosize = 32, - .bEndpointAddress = 0, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - }, - .imx_ep[1] = { - .ep = { - .name = "ep1in-bulk", - .ops = &imx_ep_ops, - .maxpacket = 64, - }, - .imx_usb = &controller, - .fifosize = 64, - .bEndpointAddress = USB_DIR_IN | 1, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - }, - .imx_ep[2] = { - .ep = { - .name = "ep2out-bulk", - .ops = &imx_ep_ops, - .maxpacket = 64, - }, - .imx_usb = &controller, - .fifosize = 64, - .bEndpointAddress = USB_DIR_OUT | 2, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - }, - .imx_ep[3] = { - .ep = { - .name = "ep3out-bulk", - .ops = &imx_ep_ops, - .maxpacket = 32, - }, - .imx_usb = &controller, - .fifosize = 32, - .bEndpointAddress = USB_DIR_OUT | 3, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - }, - .imx_ep[4] = { - .ep = { - .name = "ep4in-int", - .ops = &imx_ep_ops, - .maxpacket = 32, - }, - .imx_usb = &controller, - .fifosize = 32, - .bEndpointAddress = USB_DIR_IN | 4, - .bmAttributes = USB_ENDPOINT_XFER_INT, - }, - .imx_ep[5] = { - .ep = { - .name = "ep5out-int", - .ops = &imx_ep_ops, - .maxpacket = 32, - }, - .imx_usb = &controller, - .fifosize = 32, - .bEndpointAddress = USB_DIR_OUT | 5, - .bmAttributes = USB_ENDPOINT_XFER_INT, - }, -}; - -/******************************************************************************* - * USB gadget driver functions - ******************************************************************************* - */ -static int imx_udc_start(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - struct imx_udc_struct *imx_usb; - - imx_usb = container_of(gadget, struct imx_udc_struct, gadget); - /* first hook up the driver ... */ - imx_usb->driver = driver; - - D_INI(imx_usb->dev, "<%s> registered gadget driver '%s'\n", - __func__, driver->driver.name); - - imx_udc_enable(imx_usb); - - return 0; -} - -static int imx_udc_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - struct imx_udc_struct *imx_usb = container_of(gadget, - struct imx_udc_struct, gadget); - - udc_stop_activity(imx_usb, driver); - imx_udc_disable(imx_usb); - del_timer(&imx_usb->timer); - - imx_usb->driver = NULL; - - D_INI(imx_usb->dev, "<%s> unregistered gadget driver '%s'\n", - __func__, driver->driver.name); - - return 0; -} - -/******************************************************************************* - * Module functions - ******************************************************************************* - */ - -static int __init imx_udc_probe(struct platform_device *pdev) -{ - struct imx_udc_struct *imx_usb = &controller; - struct resource *res; - struct imxusb_platform_data *pdata; - struct clk *clk; - void __iomem *base; - int ret = 0; - int i; - resource_size_t res_size; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "can't get device resources\n"); - return -ENODEV; - } - - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "driver needs platform data\n"); - return -ENODEV; - } - - res_size = resource_size(res); - if (!request_mem_region(res->start, res_size, res->name)) { - dev_err(&pdev->dev, "can't allocate %d bytes at %d address\n", - res_size, res->start); - return -ENOMEM; - } - - if (pdata->init) { - ret = pdata->init(&pdev->dev); - if (ret) - goto fail0; - } - - base = ioremap(res->start, res_size); - if (!base) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -EIO; - goto fail1; - } - - clk = clk_get(NULL, "usbd_clk"); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - dev_err(&pdev->dev, "can't get USB clock\n"); - goto fail2; - } - clk_prepare_enable(clk); - - if (clk_get_rate(clk) != 48000000) { - D_INI(&pdev->dev, - "Bad USB clock (%d Hz), changing to 48000000 Hz\n", - (int)clk_get_rate(clk)); - if (clk_set_rate(clk, 48000000)) { - dev_err(&pdev->dev, - "Unable to set correct USB clock (48MHz)\n"); - ret = -EIO; - goto fail3; - } - } - - for (i = 0; i < IMX_USB_NB_EP + 1; i++) { - imx_usb->usbd_int[i] = platform_get_irq(pdev, i); - if (imx_usb->usbd_int[i] < 0) { - dev_err(&pdev->dev, "can't get irq number\n"); - ret = -ENODEV; - goto fail3; - } - } - - for (i = 0; i < IMX_USB_NB_EP + 1; i++) { - ret = request_irq(imx_usb->usbd_int[i], intr_handler(i), - 0, driver_name, imx_usb); - if (ret) { - dev_err(&pdev->dev, "can't get irq %i, err %d\n", - imx_usb->usbd_int[i], ret); - for (--i; i >= 0; i--) - free_irq(imx_usb->usbd_int[i], imx_usb); - goto fail3; - } - } - - imx_usb->res = res; - imx_usb->base = base; - imx_usb->clk = clk; - imx_usb->dev = &pdev->dev; - - platform_set_drvdata(pdev, imx_usb); - - usb_init_data(imx_usb); - imx_udc_init(imx_usb); - - init_timer(&imx_usb->timer); - imx_usb->timer.function = handle_config; - imx_usb->timer.data = (unsigned long)imx_usb; - - ret = usb_add_gadget_udc(&pdev->dev, &imx_usb->gadget); - if (ret) - goto fail4; - - return 0; -fail4: - for (i = 0; i < IMX_USB_NB_EP + 1; i++) - free_irq(imx_usb->usbd_int[i], imx_usb); -fail3: - clk_put(clk); - clk_disable_unprepare(clk); -fail2: - iounmap(base); -fail1: - if (pdata->exit) - pdata->exit(&pdev->dev); -fail0: - release_mem_region(res->start, res_size); - return ret; -} - -static int __exit imx_udc_remove(struct platform_device *pdev) -{ - struct imx_udc_struct *imx_usb = platform_get_drvdata(pdev); - struct imxusb_platform_data *pdata = pdev->dev.platform_data; - int i; - - usb_del_gadget_udc(&imx_usb->gadget); - imx_udc_disable(imx_usb); - del_timer(&imx_usb->timer); - - for (i = 0; i < IMX_USB_NB_EP + 1; i++) - free_irq(imx_usb->usbd_int[i], imx_usb); - - clk_put(imx_usb->clk); - clk_disable_unprepare(imx_usb->clk); - iounmap(imx_usb->base); - - release_mem_region(imx_usb->res->start, resource_size(imx_usb->res)); - - if (pdata->exit) - pdata->exit(&pdev->dev); - - return 0; -} - -/*----------------------------------------------------------------------------*/ - -#ifdef CONFIG_PM -#define imx_udc_suspend NULL -#define imx_udc_resume NULL -#else -#define imx_udc_suspend NULL -#define imx_udc_resume NULL -#endif - -/*----------------------------------------------------------------------------*/ - -static struct platform_driver udc_driver = { - .driver = { - .name = driver_name, - .owner = THIS_MODULE, - }, - .remove = __exit_p(imx_udc_remove), - .suspend = imx_udc_suspend, - .resume = imx_udc_resume, -}; - -module_platform_driver_probe(udc_driver, imx_udc_probe); - -MODULE_DESCRIPTION("IMX USB Device Controller driver"); -MODULE_AUTHOR("Darius Augulis <augulis.darius@gmail.com>"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:imx_udc"); diff --git a/drivers/usb/gadget/imx_udc.h b/drivers/usb/gadget/imx_udc.h deleted file mode 100644 index d118fb777840..000000000000 --- a/drivers/usb/gadget/imx_udc.h +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Copyright (C) 2005 Mike Lee(eemike@gmail.com) - * - * This udc driver is now under testing and code is based on pxa2xx_udc.h - * Please use it with your own risk! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef __LINUX_USB_GADGET_IMX_H -#define __LINUX_USB_GADGET_IMX_H - -#include <linux/types.h> - -/* Helper macros */ -#define EP_NO(ep) ((ep->bEndpointAddress) & ~USB_DIR_IN) /* IN:1, OUT:0 */ -#define EP_DIR(ep) ((ep->bEndpointAddress) & USB_DIR_IN ? 1 : 0) -#define IMX_USB_NB_EP 6 - -/* Driver structures */ -struct imx_request { - struct usb_request req; - struct list_head queue; - unsigned int in_use; -}; - -enum ep0_state { - EP0_IDLE, - EP0_IN_DATA_PHASE, - EP0_OUT_DATA_PHASE, - EP0_CONFIG, - EP0_STALL, -}; - -struct imx_ep_struct { - struct usb_ep ep; - struct imx_udc_struct *imx_usb; - struct list_head queue; - unsigned char stopped; - unsigned char fifosize; - unsigned char bEndpointAddress; - unsigned char bmAttributes; -}; - -struct imx_udc_struct { - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - struct device *dev; - struct imx_ep_struct imx_ep[IMX_USB_NB_EP]; - struct clk *clk; - struct timer_list timer; - enum ep0_state ep0state; - struct resource *res; - void __iomem *base; - unsigned char set_config; - int cfg, - intf, - alt, - usbd_int[7]; -}; - -/* USB registers */ -#define USB_FRAME (0x00) /* USB frame */ -#define USB_SPEC (0x04) /* USB Spec */ -#define USB_STAT (0x08) /* USB Status */ -#define USB_CTRL (0x0C) /* USB Control */ -#define USB_DADR (0x10) /* USB Desc RAM addr */ -#define USB_DDAT (0x14) /* USB Desc RAM/EP buffer data */ -#define USB_INTR (0x18) /* USB interrupt */ -#define USB_MASK (0x1C) /* USB Mask */ -#define USB_ENAB (0x24) /* USB Enable */ -#define USB_EP_STAT(x) (0x30 + (x*0x30)) /* USB status/control */ -#define USB_EP_INTR(x) (0x34 + (x*0x30)) /* USB interrupt */ -#define USB_EP_MASK(x) (0x38 + (x*0x30)) /* USB mask */ -#define USB_EP_FDAT(x) (0x3C + (x*0x30)) /* USB FIFO data */ -#define USB_EP_FDAT0(x) (0x3C + (x*0x30)) /* USB FIFO data */ -#define USB_EP_FDAT1(x) (0x3D + (x*0x30)) /* USB FIFO data */ -#define USB_EP_FDAT2(x) (0x3E + (x*0x30)) /* USB FIFO data */ -#define USB_EP_FDAT3(x) (0x3F + (x*0x30)) /* USB FIFO data */ -#define USB_EP_FSTAT(x) (0x40 + (x*0x30)) /* USB FIFO status */ -#define USB_EP_FCTRL(x) (0x44 + (x*0x30)) /* USB FIFO control */ -#define USB_EP_LRFP(x) (0x48 + (x*0x30)) /* USB last rd f. pointer */ -#define USB_EP_LWFP(x) (0x4C + (x*0x30)) /* USB last wr f. pointer */ -#define USB_EP_FALRM(x) (0x50 + (x*0x30)) /* USB FIFO alarm */ -#define USB_EP_FRDP(x) (0x54 + (x*0x30)) /* USB FIFO read pointer */ -#define USB_EP_FWRP(x) (0x58 + (x*0x30)) /* USB FIFO write pointer */ -/* USB Control Register Bit Fields.*/ -#define CTRL_CMDOVER (1<<6) /* UDC status */ -#define CTRL_CMDERROR (1<<5) /* UDC status */ -#define CTRL_FE_ENA (1<<3) /* Enable Font End logic */ -#define CTRL_UDC_RST (1<<2) /* UDC reset */ -#define CTRL_AFE_ENA (1<<1) /* Analog Font end enable */ -#define CTRL_RESUME (1<<0) /* UDC resume */ -/* USB Status Register Bit Fields.*/ -#define STAT_RST (1<<8) -#define STAT_SUSP (1<<7) -#define STAT_CFG (3<<5) -#define STAT_INTF (3<<3) -#define STAT_ALTSET (7<<0) -/* USB Interrupt Status/Mask Registers Bit fields */ -#define INTR_WAKEUP (1<<31) /* Wake up Interrupt */ -#define INTR_MSOF (1<<7) /* Missed Start of Frame */ -#define INTR_SOF (1<<6) /* Start of Frame */ -#define INTR_RESET_STOP (1<<5) /* Reset Signaling stop */ -#define INTR_RESET_START (1<<4) /* Reset Signaling start */ -#define INTR_RESUME (1<<3) /* Suspend to resume */ -#define INTR_SUSPEND (1<<2) /* Active to suspend */ -#define INTR_FRAME_MATCH (1<<1) /* Frame matched */ -#define INTR_CFG_CHG (1<<0) /* Configuration change occurred */ -/* USB Enable Register Bit Fields.*/ -#define ENAB_RST (1<<31) /* Reset USB modules */ -#define ENAB_ENAB (1<<30) /* Enable USB modules*/ -#define ENAB_SUSPEND (1<<29) /* Suspend USB modules */ -#define ENAB_ENDIAN (1<<28) /* Endian of USB modules */ -#define ENAB_PWRMD (1<<0) /* Power mode of USB modules */ -/* USB Descriptor Ram Address Register bit fields */ -#define DADR_CFG (1<<31) /* Configuration */ -#define DADR_BSY (1<<30) /* Busy status */ -#define DADR_DADR (0x1FF) /* Descriptor Ram Address */ -/* USB Descriptor RAM/Endpoint Buffer Data Register bit fields */ -#define DDAT_DDAT (0xFF) /* Descriptor Endpoint Buffer */ -/* USB Endpoint Status Register bit fields */ -#define EPSTAT_BCOUNT (0x7F<<16) /* Endpoint FIFO byte count */ -#define EPSTAT_SIP (1<<8) /* Endpoint setup in progress */ -#define EPSTAT_DIR (1<<7) /* Endpoint transfer direction */ -#define EPSTAT_MAX (3<<5) /* Endpoint Max packet size */ -#define EPSTAT_TYP (3<<3) /* Endpoint type */ -#define EPSTAT_ZLPS (1<<2) /* Send zero length packet */ -#define EPSTAT_FLUSH (1<<1) /* Endpoint FIFO Flush */ -#define EPSTAT_STALL (1<<0) /* Force stall */ -/* USB Endpoint FIFO Status Register bit fields */ -#define FSTAT_FRAME_STAT (0xF<<24) /* Frame status bit [0-3] */ -#define FSTAT_ERR (1<<22) /* FIFO error */ -#define FSTAT_UF (1<<21) /* FIFO underflow */ -#define FSTAT_OF (1<<20) /* FIFO overflow */ -#define FSTAT_FR (1<<19) /* FIFO frame ready */ -#define FSTAT_FULL (1<<18) /* FIFO full */ -#define FSTAT_ALRM (1<<17) /* FIFO alarm */ -#define FSTAT_EMPTY (1<<16) /* FIFO empty */ -/* USB Endpoint FIFO Control Register bit fields */ -#define FCTRL_WFR (1<<29) /* Write frame end */ -/* USB Endpoint Interrupt Status Regsiter bit fields */ -#define EPINTR_FIFO_FULL (1<<8) /* fifo full */ -#define EPINTR_FIFO_EMPTY (1<<7) /* fifo empty */ -#define EPINTR_FIFO_ERROR (1<<6) /* fifo error */ -#define EPINTR_FIFO_HIGH (1<<5) /* fifo high */ -#define EPINTR_FIFO_LOW (1<<4) /* fifo low */ -#define EPINTR_MDEVREQ (1<<3) /* multi Device request */ -#define EPINTR_EOT (1<<2) /* fifo end of transfer */ -#define EPINTR_DEVREQ (1<<1) /* Device request */ -#define EPINTR_EOF (1<<0) /* fifo end of frame */ - -/* Debug macros */ -#ifdef DEBUG - -/* #define DEBUG_REQ */ -/* #define DEBUG_TRX */ -/* #define DEBUG_INIT */ -/* #define DEBUG_EP0 */ -/* #define DEBUG_EPX */ -/* #define DEBUG_IRQ */ -/* #define DEBUG_EPIRQ */ -/* #define DEBUG_DUMP */ -/* #define DEBUG_ERR */ - -#ifdef DEBUG_REQ - #define D_REQ(dev, args...) dev_dbg(dev, ## args) -#else - #define D_REQ(dev, args...) do {} while (0) -#endif /* DEBUG_REQ */ - -#ifdef DEBUG_TRX - #define D_TRX(dev, args...) dev_dbg(dev, ## args) -#else - #define D_TRX(dev, args...) do {} while (0) -#endif /* DEBUG_TRX */ - -#ifdef DEBUG_INIT - #define D_INI(dev, args...) dev_dbg(dev, ## args) -#else - #define D_INI(dev, args...) do {} while (0) -#endif /* DEBUG_INIT */ - -#ifdef DEBUG_EP0 - static const char *state_name[] = { - "EP0_IDLE", - "EP0_IN_DATA_PHASE", - "EP0_OUT_DATA_PHASE", - "EP0_CONFIG", - "EP0_STALL" - }; - #define D_EP0(dev, args...) dev_dbg(dev, ## args) -#else - #define D_EP0(dev, args...) do {} while (0) -#endif /* DEBUG_EP0 */ - -#ifdef DEBUG_EPX - #define D_EPX(dev, args...) dev_dbg(dev, ## args) -#else - #define D_EPX(dev, args...) do {} while (0) -#endif /* DEBUG_EP0 */ - -#ifdef DEBUG_IRQ - static void dump_intr(const char *label, int irqreg, struct device *dev) - { - dev_dbg(dev, "<%s> USB_INTR=[%s%s%s%s%s%s%s%s%s]\n", label, - (irqreg & INTR_WAKEUP) ? " wake" : "", - (irqreg & INTR_MSOF) ? " msof" : "", - (irqreg & INTR_SOF) ? " sof" : "", - (irqreg & INTR_RESUME) ? " resume" : "", - (irqreg & INTR_SUSPEND) ? " suspend" : "", - (irqreg & INTR_RESET_STOP) ? " noreset" : "", - (irqreg & INTR_RESET_START) ? " reset" : "", - (irqreg & INTR_FRAME_MATCH) ? " fmatch" : "", - (irqreg & INTR_CFG_CHG) ? " config" : ""); - } -#else - #define dump_intr(x, y, z) do {} while (0) -#endif /* DEBUG_IRQ */ - -#ifdef DEBUG_EPIRQ - static void dump_ep_intr(const char *label, int nr, int irqreg, - struct device *dev) - { - dev_dbg(dev, "<%s> EP%d_INTR=[%s%s%s%s%s%s%s%s%s]\n", label, nr, - (irqreg & EPINTR_FIFO_FULL) ? " full" : "", - (irqreg & EPINTR_FIFO_EMPTY) ? " fempty" : "", - (irqreg & EPINTR_FIFO_ERROR) ? " ferr" : "", - (irqreg & EPINTR_FIFO_HIGH) ? " fhigh" : "", - (irqreg & EPINTR_FIFO_LOW) ? " flow" : "", - (irqreg & EPINTR_MDEVREQ) ? " mreq" : "", - (irqreg & EPINTR_EOF) ? " eof" : "", - (irqreg & EPINTR_DEVREQ) ? " devreq" : "", - (irqreg & EPINTR_EOT) ? " eot" : ""); - } -#else - #define dump_ep_intr(x, y, z, i) do {} while (0) -#endif /* DEBUG_IRQ */ - -#ifdef DEBUG_DUMP - static void dump_usb_stat(const char *label, - struct imx_udc_struct *imx_usb) - { - int temp = __raw_readl(imx_usb->base + USB_STAT); - - dev_dbg(imx_usb->dev, - "<%s> USB_STAT=[%s%s CFG=%d, INTF=%d, ALTR=%d]\n", label, - (temp & STAT_RST) ? " reset" : "", - (temp & STAT_SUSP) ? " suspend" : "", - (temp & STAT_CFG) >> 5, - (temp & STAT_INTF) >> 3, - (temp & STAT_ALTSET)); - } - - static void dump_ep_stat(const char *label, - struct imx_ep_struct *imx_ep) - { - int temp = __raw_readl(imx_ep->imx_usb->base - + USB_EP_INTR(EP_NO(imx_ep))); - - dev_dbg(imx_ep->imx_usb->dev, - "<%s> EP%d_INTR=[%s%s%s%s%s%s%s%s%s]\n", - label, EP_NO(imx_ep), - (temp & EPINTR_FIFO_FULL) ? " full" : "", - (temp & EPINTR_FIFO_EMPTY) ? " fempty" : "", - (temp & EPINTR_FIFO_ERROR) ? " ferr" : "", - (temp & EPINTR_FIFO_HIGH) ? " fhigh" : "", - (temp & EPINTR_FIFO_LOW) ? " flow" : "", - (temp & EPINTR_MDEVREQ) ? " mreq" : "", - (temp & EPINTR_EOF) ? " eof" : "", - (temp & EPINTR_DEVREQ) ? " devreq" : "", - (temp & EPINTR_EOT) ? " eot" : ""); - - temp = __raw_readl(imx_ep->imx_usb->base - + USB_EP_STAT(EP_NO(imx_ep))); - - dev_dbg(imx_ep->imx_usb->dev, - "<%s> EP%d_STAT=[%s%s bcount=%d]\n", - label, EP_NO(imx_ep), - (temp & EPSTAT_SIP) ? " sip" : "", - (temp & EPSTAT_STALL) ? " stall" : "", - (temp & EPSTAT_BCOUNT) >> 16); - - temp = __raw_readl(imx_ep->imx_usb->base - + USB_EP_FSTAT(EP_NO(imx_ep))); - - dev_dbg(imx_ep->imx_usb->dev, - "<%s> EP%d_FSTAT=[%s%s%s%s%s%s%s]\n", - label, EP_NO(imx_ep), - (temp & FSTAT_ERR) ? " ferr" : "", - (temp & FSTAT_UF) ? " funder" : "", - (temp & FSTAT_OF) ? " fover" : "", - (temp & FSTAT_FR) ? " fready" : "", - (temp & FSTAT_FULL) ? " ffull" : "", - (temp & FSTAT_ALRM) ? " falarm" : "", - (temp & FSTAT_EMPTY) ? " fempty" : ""); - } - - static void dump_req(const char *label, struct imx_ep_struct *imx_ep, - struct usb_request *req) - { - int i; - - if (!req || !req->buf) { - dev_dbg(imx_ep->imx_usb->dev, - "<%s> req or req buf is free\n", label); - return; - } - - if ((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state - == EP0_IN_DATA_PHASE) - || (EP_NO(imx_ep) && EP_DIR(imx_ep))) { - - dev_dbg(imx_ep->imx_usb->dev, - "<%s> request dump <", label); - for (i = 0; i < req->length; i++) - printk("%02x-", *((u8 *)req->buf + i)); - printk(">\n"); - } - } - -#else - #define dump_ep_stat(x, y) do {} while (0) - #define dump_usb_stat(x, y) do {} while (0) - #define dump_req(x, y, z) do {} while (0) -#endif /* DEBUG_DUMP */ - -#ifdef DEBUG_ERR - #define D_ERR(dev, args...) dev_dbg(dev, ## args) -#else - #define D_ERR(dev, args...) do {} while (0) -#endif - -#else - #define D_REQ(dev, args...) do {} while (0) - #define D_TRX(dev, args...) do {} while (0) - #define D_INI(dev, args...) do {} while (0) - #define D_EP0(dev, args...) do {} while (0) - #define D_EPX(dev, args...) do {} while (0) - #define dump_ep_intr(x, y, z, i) do {} while (0) - #define dump_intr(x, y, z) do {} while (0) - #define dump_ep_stat(x, y) do {} while (0) - #define dump_usb_stat(x, y) do {} while (0) - #define dump_req(x, y, z) do {} while (0) - #define D_ERR(dev, args...) do {} while (0) -#endif /* DEBUG */ - -#endif /* __LINUX_USB_GADGET_IMX_H */ diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 46ba9838c3a0..d5f050d30edf 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1584,7 +1584,7 @@ static int __init m66592_probe(struct platform_device *pdev) goto clean_up; } - if (pdev->dev.platform_data == NULL) { + if (dev_get_platdata(&pdev->dev) == NULL) { dev_err(&pdev->dev, "no platform data\n"); ret = -ENODEV; goto clean_up; @@ -1598,7 +1598,7 @@ static int __init m66592_probe(struct platform_device *pdev) goto clean_up; } - m66592->pdata = pdev->dev.platform_data; + m66592->pdata = dev_get_platdata(&pdev->dev); m66592->irq_trigger = ires->flags & IRQF_TRIGGER_MASK; spin_lock_init(&m66592->lock); diff --git a/drivers/usb/gadget/mv_u3d_core.c b/drivers/usb/gadget/mv_u3d_core.c index ec6a2d290398..bbb6e98c4384 100644 --- a/drivers/usb/gadget/mv_u3d_core.c +++ b/drivers/usb/gadget/mv_u3d_core.c @@ -1109,7 +1109,7 @@ static int mv_u3d_controller_reset(struct mv_u3d *u3d) static int mv_u3d_enable(struct mv_u3d *u3d) { - struct mv_usb_platform_data *pdata = u3d->dev->platform_data; + struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev); int retval; if (u3d->active) @@ -1138,7 +1138,7 @@ static int mv_u3d_enable(struct mv_u3d *u3d) static void mv_u3d_disable(struct mv_u3d *u3d) { - struct mv_usb_platform_data *pdata = u3d->dev->platform_data; + struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev); if (u3d->clock_gating && u3d->active) { dev_dbg(u3d->dev, "disable u3d\n"); if (pdata->phy_deinit) @@ -1246,7 +1246,7 @@ static int mv_u3d_start(struct usb_gadget *g, struct usb_gadget_driver *driver) { struct mv_u3d *u3d = container_of(g, struct mv_u3d, gadget); - struct mv_usb_platform_data *pdata = u3d->dev->platform_data; + struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev); unsigned long flags; if (u3d->driver) @@ -1277,7 +1277,7 @@ static int mv_u3d_stop(struct usb_gadget *g, struct usb_gadget_driver *driver) { struct mv_u3d *u3d = container_of(g, struct mv_u3d, gadget); - struct mv_usb_platform_data *pdata = u3d->dev->platform_data; + struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev); unsigned long flags; u3d->vbus_valid_detect = 0; @@ -1794,12 +1794,12 @@ static int mv_u3d_remove(struct platform_device *dev) static int mv_u3d_probe(struct platform_device *dev) { struct mv_u3d *u3d = NULL; - struct mv_usb_platform_data *pdata = dev->dev.platform_data; + struct mv_usb_platform_data *pdata = dev_get_platdata(&dev->dev); int retval = 0; struct resource *r; size_t size; - if (!dev->dev.platform_data) { + if (!dev_get_platdata(&dev->dev)) { dev_err(&dev->dev, "missing platform_data\n"); retval = -ENODEV; goto err_pdata; diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index c2a57023e467..104cdbea635a 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -2100,7 +2100,7 @@ static int mv_udc_remove(struct platform_device *pdev) static int mv_udc_probe(struct platform_device *pdev) { - struct mv_usb_platform_data *pdata = pdev->dev.platform_data; + struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); struct mv_udc *udc; int retval = 0; struct resource *r; @@ -2118,7 +2118,7 @@ static int mv_udc_probe(struct platform_device *pdev) } udc->done = &release_done; - udc->pdata = pdev->dev.platform_data; + udc->pdata = dev_get_platdata(&pdev->dev); spin_lock_init(&udc->lock); udc->dev = pdev; diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index b8ed74a823cb..83957cc225d9 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2734,7 +2734,7 @@ static int omap_udc_probe(struct platform_device *pdev) int hmc; struct usb_phy *xceiv = NULL; const char *type = NULL; - struct omap_usb_config *config = pdev->dev.platform_data; + struct omap_usb_config *config = dev_get_platdata(&pdev->dev); struct clk *dc_clk = NULL; struct clk *hhc_clk = NULL; diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index 95c531d5aa4f..cc9207473dbc 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -2117,7 +2117,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev) /* other non-static parts of init */ dev->dev = &pdev->dev; - dev->mach = pdev->dev.platform_data; + dev->mach = dev_get_platdata(&pdev->dev); dev->transceiver = usb_get_phy(USB_PHY_TYPE_USB2); diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 41cea9566ac8..3c97da7760da 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -2422,7 +2422,7 @@ static int pxa_udc_probe(struct platform_device *pdev) return udc->irq; udc->dev = &pdev->dev; - udc->mach = pdev->dev.platform_data; + udc->mach = dev_get_platdata(&pdev->dev); udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2); gpio = udc->mach->gpio_pullup; diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index c6af649f3240..68be48d33404 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1910,7 +1910,7 @@ static int __init r8a66597_probe(struct platform_device *pdev) spin_lock_init(&r8a66597->lock); platform_set_drvdata(pdev, r8a66597); - r8a66597->pdata = pdev->dev.platform_data; + r8a66597->pdata = dev_get_platdata(&pdev->dev); r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW; r8a66597->gadget.ops = &r8a66597_gadget_ops; diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 3e3ea7203030..9575085ded81 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -1142,7 +1142,7 @@ static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS]; #endif /* CONFIG_USB_GADGET_DEBUG_FILES */ -int rndis_init(void) +static int rndis_init(void) { u8 i; @@ -1176,7 +1176,7 @@ int rndis_init(void) } module_init(rndis_init); -void rndis_exit(void) +static void rndis_exit(void) { #ifdef CONFIG_USB_GADGET_DEBUG_FILES u8 i; diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index af22f24046b2..d69b36a99dbc 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -29,6 +29,7 @@ #include <linux/slab.h> #include <linux/clk.h> #include <linux/regulator/consumer.h> +#include <linux/of_platform.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> @@ -3450,7 +3451,7 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg) static int s3c_hsotg_probe(struct platform_device *pdev) { - struct s3c_hsotg_plat *plat = pdev->dev.platform_data; + struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev); struct usb_phy *phy; struct device *dev = &pdev->dev; struct s3c_hsotg_ep *eps; @@ -3469,7 +3470,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev) phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); if (IS_ERR(phy)) { /* Fallback for pdata */ - plat = pdev->dev.platform_data; + plat = dev_get_platdata(&pdev->dev); if (!plat) { dev_err(&pdev->dev, "no platform data or transceiver defined\n"); return -EPROBE_DEFER; @@ -3648,10 +3649,19 @@ static int s3c_hsotg_remove(struct platform_device *pdev) #define s3c_hsotg_resume NULL #endif +#ifdef CONFIG_OF +static const struct of_device_id s3c_hsotg_of_ids[] = { + { .compatible = "samsung,s3c6400-hsotg", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, s3c_hsotg_of_ids); +#endif + static struct platform_driver s3c_hsotg_driver = { .driver = { .name = "s3c-hsotg", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(s3c_hsotg_of_ids), }, .probe = s3c_hsotg_probe, .remove = s3c_hsotg_remove, diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index b1f0771fbd3d..1a1a41498db2 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -1262,7 +1262,7 @@ static int s3c_hsudc_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct resource *res; struct s3c_hsudc *hsudc; - struct s3c24xx_hsudc_platdata *pd = pdev->dev.platform_data; + struct s3c24xx_hsudc_platdata *pd = dev_get_platdata(&pdev->dev); int ret, i; hsudc = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsudc) + @@ -1275,7 +1275,7 @@ static int s3c_hsudc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); hsudc->dev = dev; - hsudc->pd = pdev->dev.platform_data; + hsudc->pd = dev_get_platdata(&pdev->dev); hsudc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2); diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 09c4f70c93c4..c72d810e6b36 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -1809,7 +1809,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev) } spin_lock_init(&udc->lock); - udc_info = pdev->dev.platform_data; + udc_info = dev_get_platdata(&pdev->dev); rsrc_start = S3C2410_PA_USBDEV; rsrc_len = S3C24XX_SZ_USBDEV; diff --git a/drivers/usb/gadget/u_uac1.c b/drivers/usb/gadget/u_uac1.c index c7d460f43390..7a55fea43430 100644 --- a/drivers/usb/gadget/u_uac1.c +++ b/drivers/usb/gadget/u_uac1.c @@ -191,7 +191,7 @@ try_again: frames = bytes_to_frames(runtime, count); old_fs = get_fs(); set_fs(KERNEL_DS); - result = snd_pcm_lib_write(snd->substream, buf, frames); + result = snd_pcm_lib_write(snd->substream, (void __user *)buf, frames); if (result != frames) { ERROR(card, "Playback error: %d\n", (int)result); set_fs(old_fs); diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index 13e25f80fc20..546bfda3059a 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -23,6 +23,7 @@ #include <linux/list.h> #include <linux/err.h> #include <linux/dma-mapping.h> +#include <linux/workqueue.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> @@ -105,11 +106,18 @@ EXPORT_SYMBOL_GPL(usb_gadget_unmap_request); /* ------------------------------------------------------------------------- */ +static void usb_gadget_state_work(struct work_struct *work) +{ + struct usb_gadget *gadget = work_to_gadget(work); + + sysfs_notify(&gadget->dev.kobj, NULL, "state"); +} + void usb_gadget_set_state(struct usb_gadget *gadget, enum usb_device_state state) { gadget->state = state; - sysfs_notify(&gadget->dev.kobj, NULL, "state"); + schedule_work(&gadget->work); } EXPORT_SYMBOL_GPL(usb_gadget_set_state); @@ -196,6 +204,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, goto err1; dev_set_name(&gadget->dev, "gadget"); + INIT_WORK(&gadget->work, usb_gadget_state_work); gadget->dev.parent = parent; #ifdef CONFIG_HAS_DMA @@ -315,6 +324,7 @@ found: usb_gadget_remove_driver(udc); kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE); + flush_work(&gadget->work); device_unregister(&udc->dev); device_unregister(&gadget->dev); } diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c index e6170478ea9f..0bb5d50075de 100644 --- a/drivers/usb/gadget/uvc_queue.c +++ b/drivers/usb/gadget/uvc_queue.c @@ -193,12 +193,16 @@ static int uvc_queue_buffer(struct uvc_video_queue *queue, mutex_lock(&queue->mutex); ret = vb2_qbuf(&queue->queue, buf); + if (ret < 0) + goto done; + spin_lock_irqsave(&queue->irqlock, flags); ret = (queue->flags & UVC_QUEUE_PAUSED) != 0; queue->flags &= ~UVC_QUEUE_PAUSED; spin_unlock_irqrestore(&queue->irqlock, flags); - mutex_unlock(&queue->mutex); +done: + mutex_unlock(&queue->mutex); return ret; } diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 0947aac857a2..e3ea970fe424 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -142,13 +142,11 @@ config USB_EHCI_MXC config USB_EHCI_HCD_OMAP tristate "EHCI support for OMAP3 and later chips" depends on ARCH_OMAP + select NOP_USB_XCEIV default y ---help--- Enables support for the on-chip EHCI controller on OMAP3 and later chips. - If your system uses a PHY on the USB port, you will need to - enable USB_PHY and the appropriate PHY driver as well. Most - boards need the NOP_USB_XCEIV PHY driver. config USB_EHCI_HCD_ORION tristate "Support for Marvell EBU on-chip EHCI USB controller" @@ -180,7 +178,6 @@ config USB_EHCI_HCD_AT91 config USB_EHCI_MSM tristate "Support for Qualcomm QSD/MSM on-chip EHCI USB controller" depends on ARCH_MSM - depends on USB_PHY select USB_EHCI_ROOT_HUB_TT select USB_MSM_OTG ---help--- diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index d0d4cc151e71..f8b215fa0d93 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -183,7 +183,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, spin_lock_irq(&ehci->lock); /* clear phy low-power mode before changing wakeup flags */ - if (ehci->has_hostpc) { + if (ehci->has_tdi_phy_lpm) { port = HCS_N_PORTS(ehci->hcs_params); while (port--) { u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port]; @@ -217,7 +217,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, } /* enter phy low-power mode again */ - if (ehci->has_hostpc) { + if (ehci->has_tdi_phy_lpm) { port = HCS_N_PORTS(ehci->hcs_params); while (port--) { u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port]; @@ -309,7 +309,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) } } - if (changed && ehci->has_hostpc) { + if (changed && ehci->has_tdi_phy_lpm) { spin_unlock_irq(&ehci->lock); msleep(5); /* 5 ms for HCD to enter low-power mode */ spin_lock_irq(&ehci->lock); @@ -436,7 +436,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd) goto shutdown; /* clear phy low-power mode before resume */ - if (ehci->bus_suspended && ehci->has_hostpc) { + if (ehci->bus_suspended && ehci->has_tdi_phy_lpm) { i = HCS_N_PORTS(ehci->hcs_params); while (i--) { if (test_bit(i, &ehci->bus_suspended)) { @@ -925,7 +925,7 @@ static int ehci_hub_control ( goto error; /* clear phy low-power mode before resume */ - if (ehci->has_hostpc) { + if (ehci->has_tdi_phy_lpm) { temp1 = ehci_readl(ehci, hostpc_reg); ehci_writel(ehci, temp1 & ~HOSTPC_PHCD, hostpc_reg); @@ -1162,12 +1162,12 @@ static int ehci_hub_control ( /* After above check the port must be connected. * Set appropriate bit thus could put phy into low power - * mode if we have hostpc feature + * mode if we have tdi_phy_lpm feature */ temp &= ~PORT_WKCONN_E; temp |= PORT_WKDISC_E | PORT_WKOC_E; ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); - if (ehci->has_hostpc) { + if (ehci->has_tdi_phy_lpm) { spin_unlock_irqrestore(&ehci->lock, flags); msleep(5);/* 5ms for HCD enter low pwr mode */ spin_lock_irqsave(&ehci->lock, flags); diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 5cd33cf783da..78fa76da3324 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -25,9 +25,9 @@ #include <linux/irq.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/of_gpio.h> #include <linux/platform_device.h> -#include <linux/platform_data/tegra_usb.h> #include <linux/pm_runtime.h> #include <linux/slab.h> #include <linux/usb/ehci_def.h> @@ -51,6 +51,10 @@ static struct hc_driver __read_mostly tegra_ehci_hc_driver; +struct tegra_ehci_soc_config { + bool has_hostpc; +}; + static int (*orig_hub_control)(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength); @@ -58,7 +62,6 @@ static int (*orig_hub_control)(struct usb_hcd *hcd, struct tegra_ehci_hcd { struct tegra_usb_phy *phy; struct clk *clk; - struct usb_phy *transceiver; int port_resuming; bool needs_double_reset; enum tegra_usb_phy_port_speed port_speed; @@ -322,50 +325,38 @@ static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) free_dma_aligned_buffer(urb); } -static int setup_vbus_gpio(struct platform_device *pdev, - struct tegra_ehci_platform_data *pdata) -{ - int err = 0; - int gpio; - - gpio = pdata->vbus_gpio; - if (!gpio_is_valid(gpio)) - gpio = of_get_named_gpio(pdev->dev.of_node, - "nvidia,vbus-gpio", 0); - if (!gpio_is_valid(gpio)) - return 0; +static const struct tegra_ehci_soc_config tegra30_soc_config = { + .has_hostpc = true, +}; - err = gpio_request(gpio, "vbus_gpio"); - if (err) { - dev_err(&pdev->dev, "can't request vbus gpio %d", gpio); - return err; - } - err = gpio_direction_output(gpio, 1); - if (err) { - dev_err(&pdev->dev, "can't enable vbus\n"); - return err; - } +static const struct tegra_ehci_soc_config tegra20_soc_config = { + .has_hostpc = false, +}; - return err; -} +static struct of_device_id tegra_ehci_of_match[] = { + { .compatible = "nvidia,tegra30-ehci", .data = &tegra30_soc_config }, + { .compatible = "nvidia,tegra20-ehci", .data = &tegra20_soc_config }, + { }, +}; static int tegra_ehci_probe(struct platform_device *pdev) { + const struct of_device_id *match; + const struct tegra_ehci_soc_config *soc_config; struct resource *res; struct usb_hcd *hcd; struct ehci_hcd *ehci; struct tegra_ehci_hcd *tegra; - struct tegra_ehci_platform_data *pdata; int err = 0; int irq; - struct device_node *np_phy; struct usb_phy *u_phy; - pdata = dev_get_platdata(&pdev->dev); - if (!pdata) { - dev_err(&pdev->dev, "Platform data missing\n"); - return -EINVAL; + match = of_match_device(tegra_ehci_of_match, &pdev->dev); + if (!match) { + dev_err(&pdev->dev, "Error: No device match found\n"); + return -ENODEV; } + soc_config = match->data; /* Right now device-tree probed devices don't get dma_mask set. * Since shared usb code relies on it, set it here for now. @@ -376,14 +367,11 @@ static int tegra_ehci_probe(struct platform_device *pdev) if (!pdev->dev.coherent_dma_mask) pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - setup_vbus_gpio(pdev, pdata); - hcd = usb_create_hcd(&tegra_ehci_hc_driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { dev_err(&pdev->dev, "Unable to create HCD\n"); - err = -ENOMEM; - goto cleanup_vbus_gpio; + return -ENOMEM; } platform_set_drvdata(pdev, hcd); ehci = hcd_to_ehci(hcd); @@ -406,13 +394,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) udelay(1); tegra_periph_reset_deassert(tegra->clk); - np_phy = of_parse_phandle(pdev->dev.of_node, "nvidia,phy", 0); - if (!np_phy) { - err = -ENODEV; - goto cleanup_clk_en; - } - - u_phy = tegra_usb_get_phy(np_phy); + u_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0); if (IS_ERR(u_phy)) { err = PTR_ERR(u_phy); goto cleanup_clk_en; @@ -437,6 +419,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) goto cleanup_clk_en; } ehci->caps = hcd->regs + 0x100; + ehci->has_hostpc = soc_config->has_hostpc; err = usb_phy_init(hcd->phy); if (err) { @@ -466,26 +449,18 @@ static int tegra_ehci_probe(struct platform_device *pdev) goto cleanup_phy; } - if (pdata->operating_mode == TEGRA_USB_OTG) { - tegra->transceiver = - devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); - if (!IS_ERR(tegra->transceiver)) - otg_set_host(tegra->transceiver->otg, &hcd->self); - } else { - tegra->transceiver = ERR_PTR(-ENODEV); - } + otg_set_host(u_phy->otg, &hcd->self); err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) { dev_err(&pdev->dev, "Failed to add USB HCD\n"); - goto cleanup_transceiver; + goto cleanup_otg_set_host; } return err; -cleanup_transceiver: - if (!IS_ERR(tegra->transceiver)) - otg_set_host(tegra->transceiver->otg, NULL); +cleanup_otg_set_host: + otg_set_host(u_phy->otg, NULL); cleanup_phy: usb_phy_shutdown(hcd->phy); cleanup_clk_en: @@ -494,8 +469,6 @@ cleanup_clk_get: clk_put(tegra->clk); cleanup_hcd_create: usb_put_hcd(hcd); -cleanup_vbus_gpio: - /* FIXME: Undo setup_vbus_gpio() here */ return err; } @@ -505,8 +478,7 @@ static int tegra_ehci_remove(struct platform_device *pdev) struct tegra_ehci_hcd *tegra = (struct tegra_ehci_hcd *)hcd_to_ehci(hcd)->priv; - if (!IS_ERR(tegra->transceiver)) - otg_set_host(tegra->transceiver->otg, NULL); + otg_set_host(hcd->phy->otg, NULL); usb_phy_shutdown(hcd->phy); usb_remove_hcd(hcd); @@ -525,11 +497,6 @@ static void tegra_ehci_hcd_shutdown(struct platform_device *pdev) hcd->driver->shutdown(hcd); } -static struct of_device_id tegra_ehci_of_match[] = { - { .compatible = "nvidia,tegra20-ehci", }, - { }, -}; - static struct platform_driver tegra_ehci_driver = { .probe = tegra_ehci_probe, .remove = tegra_ehci_remove, diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 947752015d5d..2822e79e1fbc 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -213,6 +213,7 @@ struct ehci_hcd { /* one per controller */ #define OHCI_HCCTRL_LEN 0x4 __hc32 *ohci_hcctrl_reg; unsigned has_hostpc:1; + unsigned has_tdi_phy_lpm:1; unsigned has_ppcd:1; /* support per-port change bits */ u8 sbrn; /* packed release number */ diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 797e3fd45510..c64ee09a7c0e 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -83,6 +83,8 @@ config USB_MUSB_AM35X config USB_MUSB_DSPS tristate "TI DSPS platforms" + select USB_MUSB_AM335X_CHILD + depends on OF_IRQ config USB_MUSB_BLACKFIN tristate "Blackfin" @@ -93,6 +95,9 @@ config USB_MUSB_UX500 endchoice +config USB_MUSB_AM335X_CHILD + tristate + choice prompt 'MUSB DMA mode' default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM @@ -125,6 +130,10 @@ config USB_TI_CPPI_DMA help Enable DMA transfers when TI CPPI DMA is available. +config USB_TI_CPPI41_DMA + bool 'TI CPPI 4.1 (AM335x)' + depends on ARCH_OMAP + config USB_TUSB_OMAP_DMA bool 'TUSB 6010' depends on USB_MUSB_TUSB6010 diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index 2b82ed7c85ca..c5ea5c6dc169 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -20,6 +20,9 @@ obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o obj-$(CONFIG_USB_MUSB_BLACKFIN) += blackfin.o obj-$(CONFIG_USB_MUSB_UX500) += ux500.o + +obj-$(CONFIG_USB_MUSB_AM335X_CHILD) += musb_am335x.o + # the kconfig must guarantee that only one of the # possible I/O schemes will be enabled at a time ... # PIO only, or DMA (several potential schemes). @@ -29,3 +32,4 @@ musb_hdrc-$(CONFIG_USB_INVENTRA_DMA) += musbhsdma.o musb_hdrc-$(CONFIG_USB_TI_CPPI_DMA) += cppi_dma.o musb_hdrc-$(CONFIG_USB_TUSB_OMAP_DMA) += tusb6010_omap.o musb_hdrc-$(CONFIG_USB_UX500_DMA) += ux500_dma.o +musb_hdrc-$(CONFIG_USB_TI_CPPI41_DMA) += musb_cppi41.o diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index 2231850c0625..5c310c664218 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -33,7 +33,7 @@ #include <linux/io.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> -#include <linux/usb/nop-usb-xceiv.h> +#include <linux/usb/usb_phy_gen_xceiv.h> #include <linux/platform_data/usb-omap.h> #include "musb_core.h" @@ -218,7 +218,7 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci) struct musb *musb = hci; void __iomem *reg_base = musb->ctrl_base; struct device *dev = musb->controller; - struct musb_hdrc_platform_data *plat = dev->platform_data; + struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); struct omap_musb_board_data *data = plat->board_data; struct usb_otg *otg = musb->xceiv->otg; unsigned long flags; @@ -335,7 +335,7 @@ eoi: static int am35x_musb_set_mode(struct musb *musb, u8 musb_mode) { struct device *dev = musb->controller; - struct musb_hdrc_platform_data *plat = dev->platform_data; + struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); struct omap_musb_board_data *data = plat->board_data; int retval = 0; @@ -350,7 +350,7 @@ static int am35x_musb_set_mode(struct musb *musb, u8 musb_mode) static int am35x_musb_init(struct musb *musb) { struct device *dev = musb->controller; - struct musb_hdrc_platform_data *plat = dev->platform_data; + struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); struct omap_musb_board_data *data = plat->board_data; void __iomem *reg_base = musb->ctrl_base; u32 rev; @@ -394,7 +394,7 @@ static int am35x_musb_init(struct musb *musb) static int am35x_musb_exit(struct musb *musb) { struct device *dev = musb->controller; - struct musb_hdrc_platform_data *plat = dev->platform_data; + struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); struct omap_musb_board_data *data = plat->board_data; del_timer_sync(&otg_workaround); @@ -456,7 +456,7 @@ static u64 am35x_dmamask = DMA_BIT_MASK(32); static int am35x_probe(struct platform_device *pdev) { - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; + struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); struct platform_device *musb; struct am35x_glue *glue; @@ -577,7 +577,7 @@ static int am35x_remove(struct platform_device *pdev) static int am35x_suspend(struct device *dev) { struct am35x_glue *glue = dev_get_drvdata(dev); - struct musb_hdrc_platform_data *plat = dev->platform_data; + struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); struct omap_musb_board_data *data = plat->board_data; /* Shutdown the on-chip PHY and its PLL. */ @@ -593,7 +593,7 @@ static int am35x_suspend(struct device *dev) static int am35x_resume(struct device *dev) { struct am35x_glue *glue = dev_get_drvdata(dev); - struct musb_hdrc_platform_data *plat = dev->platform_data; + struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); struct omap_musb_board_data *data = plat->board_data; int ret; diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 6ba8439bd5a6..72e2056b6082 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -19,7 +19,7 @@ #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/prefetch.h> -#include <linux/usb/nop-usb-xceiv.h> +#include <linux/usb/usb_phy_gen_xceiv.h> #include <asm/cacheflush.h> @@ -451,7 +451,7 @@ static u64 bfin_dmamask = DMA_BIT_MASK(32); static int bfin_probe(struct platform_device *pdev) { struct resource musb_resources[2]; - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; + struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); struct platform_device *musb; struct bfin_glue *glue; diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index 9db211ee15b5..904fb85d85a6 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c @@ -150,14 +150,11 @@ static void cppi_pool_free(struct cppi_channel *c) c->last_processed = NULL; } -static int cppi_controller_start(struct dma_controller *c) +static void cppi_controller_start(struct cppi *controller) { - struct cppi *controller; void __iomem *tibase; int i; - controller = container_of(c, struct cppi, controller); - /* do whatever is necessary to start controller */ for (i = 0; i < ARRAY_SIZE(controller->tx); i++) { controller->tx[i].transmit = true; @@ -212,8 +209,6 @@ static int cppi_controller_start(struct dma_controller *c) /* disable RNDIS mode, also host rx RNDIS autorequest */ musb_writel(tibase, DAVINCI_RNDIS_REG, 0); musb_writel(tibase, DAVINCI_AUTOREQ_REG, 0); - - return 0; } /* @@ -222,14 +217,12 @@ static int cppi_controller_start(struct dma_controller *c) * De-Init the DMA controller as necessary. */ -static int cppi_controller_stop(struct dma_controller *c) +static void cppi_controller_stop(struct cppi *controller) { - struct cppi *controller; void __iomem *tibase; int i; struct musb *musb; - controller = container_of(c, struct cppi, controller); musb = controller->musb; tibase = controller->tibase; @@ -255,8 +248,6 @@ static int cppi_controller_stop(struct dma_controller *c) /*disable tx/rx cppi */ musb_writel(tibase, DAVINCI_TXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE); musb_writel(tibase, DAVINCI_RXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE); - - return 0; } /* While dma channel is allocated, we only want the core irqs active @@ -1321,8 +1312,6 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *mr controller->tibase = mregs - DAVINCI_BASE_OFFSET; controller->musb = musb; - controller->controller.start = cppi_controller_start; - controller->controller.stop = cppi_controller_stop; controller->controller.channel_alloc = cppi_channel_allocate; controller->controller.channel_release = cppi_channel_release; controller->controller.channel_program = cppi_channel_program; @@ -1351,6 +1340,7 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *mr controller->irq = irq; } + cppi_controller_start(controller); return &controller->controller; } @@ -1363,6 +1353,8 @@ void dma_controller_destroy(struct dma_controller *c) cppi = container_of(c, struct cppi, controller); + cppi_controller_stop(cppi); + if (cppi->irq) free_irq(cppi->irq, cppi->musb); diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index 0da6f648a9fe..d9ddf4122f37 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -33,7 +33,7 @@ #include <linux/io.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> -#include <linux/usb/nop-usb-xceiv.h> +#include <linux/usb/usb_phy_gen_xceiv.h> #include <mach/da8xx.h> #include <linux/platform_data/usb-davinci.h> @@ -477,7 +477,7 @@ static u64 da8xx_dmamask = DMA_BIT_MASK(32); static int da8xx_probe(struct platform_device *pdev) { struct resource musb_resources[2]; - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; + struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); struct platform_device *musb; struct da8xx_glue *glue; diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index f8aeaf2e2cd1..ed0834e2b72e 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -33,7 +33,7 @@ #include <linux/gpio.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> -#include <linux/usb/nop-usb-xceiv.h> +#include <linux/usb/usb_phy_gen_xceiv.h> #include <mach/cputype.h> #include <mach/hardware.h> @@ -510,7 +510,7 @@ static u64 davinci_dmamask = DMA_BIT_MASK(32); static int davinci_probe(struct platform_device *pdev) { struct resource musb_resources[2]; - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; + struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); struct platform_device *musb; struct davinci_glue *glue; struct clk *clk; diff --git a/drivers/usb/musb/musb_am335x.c b/drivers/usb/musb/musb_am335x.c new file mode 100644 index 000000000000..41ac5b5b57ce --- /dev/null +++ b/drivers/usb/musb/musb_am335x.c @@ -0,0 +1,55 @@ +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/module.h> +#include <linux/of_platform.h> + +static int am335x_child_probe(struct platform_device *pdev) +{ + int ret; + + pm_runtime_enable(&pdev->dev); + + ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + if (ret) + goto err; + + return 0; +err: + pm_runtime_disable(&pdev->dev); + return ret; +} + +static int of_remove_populated_child(struct device *dev, void *d) +{ + struct platform_device *pdev = to_platform_device(dev); + + of_device_unregister(pdev); + return 0; +} + +static int am335x_child_remove(struct platform_device *pdev) +{ + device_for_each_child(&pdev->dev, NULL, of_remove_populated_child); + pm_runtime_disable(&pdev->dev); + return 0; +} + +static const struct of_device_id am335x_child_of_match[] = { + { .compatible = "ti,am33xx-usb" }, + { }, +}; +MODULE_DEVICE_TABLE(of, am335x_child_of_match); + +static struct platform_driver am335x_child_driver = { + .probe = am335x_child_probe, + .remove = am335x_child_remove, + .driver = { + .name = "am335x-usb-childs", + .of_match_table = of_match_ptr(am335x_child_of_match), + }, +}; + +module_platform_driver(am335x_child_driver); +MODULE_DESCRIPTION("AM33xx child devices"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 9e59710efee7..18e877ffe7b7 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1763,12 +1763,8 @@ static void musb_free(struct musb *musb) disable_irq_wake(musb->nIrq); free_irq(musb->nIrq, musb); } - if (is_dma_capable() && musb->dma_controller) { - struct dma_controller *c = musb->dma_controller; - - (void) c->stop(c); - dma_controller_destroy(c); - } + if (musb->dma_controller) + dma_controller_destroy(musb->dma_controller); musb_host_free(musb); } @@ -1786,7 +1782,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) { int status; struct musb *musb; - struct musb_hdrc_platform_data *plat = dev->platform_data; + struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); /* The driver might handle more features than the board; OK. * Fail when the board needs a feature that's not enabled. @@ -1843,19 +1839,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) pm_runtime_get_sync(musb->controller); -#ifndef CONFIG_MUSB_PIO_ONLY - if (use_dma && dev->dma_mask) { - struct dma_controller *c; - - c = dma_controller_create(musb, musb->mregs); - musb->dma_controller = c; - if (c) - (void) c->start(c); - } -#endif - /* ideally this would be abstracted in platform setup */ - if (!is_dma_capable() || !musb->dma_controller) - dev->dma_mask = NULL; + if (use_dma && dev->dma_mask) + musb->dma_controller = dma_controller_create(musb, musb->mregs); /* be sure interrupts are disabled before connecting ISR */ musb_platform_disable(musb); @@ -1943,6 +1928,8 @@ fail4: musb_gadget_cleanup(musb); fail3: + if (musb->dma_controller) + dma_controller_destroy(musb->dma_controller); pm_runtime_put_sync(musb->controller); fail2: @@ -2001,9 +1988,6 @@ static int musb_remove(struct platform_device *pdev) musb_free(musb); device_init_wakeup(dev, 0); -#ifndef CONFIG_MUSB_PIO_ONLY - dma_set_mask(dev, *dev->parent->dma_mask); -#endif return 0; } diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 7d341c387eab..65f3917b4fc5 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -83,11 +83,6 @@ enum { MUSB_PORT_MODE_DUAL_ROLE, }; -#ifdef CONFIG_PROC_FS -#include <linux/fs.h> -#define MUSB_CONFIG_PROC_FS -#endif - /****************************** CONSTANTS ********************************/ #ifndef MUSB_C_NUM_EPS @@ -425,9 +420,6 @@ struct musb { struct musb_hdrc_config *config; -#ifdef MUSB_CONFIG_PROC_FS - struct proc_dir_entry *proc_entry; -#endif int xceiv_old_state; #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_root; diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c new file mode 100644 index 000000000000..e64701d15401 --- /dev/null +++ b/drivers/usb/musb/musb_cppi41.c @@ -0,0 +1,555 @@ +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/dmaengine.h> +#include <linux/sizes.h> +#include <linux/platform_device.h> +#include <linux/of.h> + +#include "musb_core.h" + +#define RNDIS_REG(x) (0x80 + ((x - 1) * 4)) + +#define EP_MODE_AUTOREG_NONE 0 +#define EP_MODE_AUTOREG_ALL_NEOP 1 +#define EP_MODE_AUTOREG_ALWAYS 3 + +#define EP_MODE_DMA_TRANSPARENT 0 +#define EP_MODE_DMA_RNDIS 1 +#define EP_MODE_DMA_GEN_RNDIS 3 + +#define USB_CTRL_TX_MODE 0x70 +#define USB_CTRL_RX_MODE 0x74 +#define USB_CTRL_AUTOREQ 0xd0 +#define USB_TDOWN 0xd8 + +struct cppi41_dma_channel { + struct dma_channel channel; + struct cppi41_dma_controller *controller; + struct musb_hw_ep *hw_ep; + struct dma_chan *dc; + dma_cookie_t cookie; + u8 port_num; + u8 is_tx; + u8 is_allocated; + u8 usb_toggle; + + dma_addr_t buf_addr; + u32 total_len; + u32 prog_len; + u32 transferred; + u32 packet_sz; +}; + +#define MUSB_DMA_NUM_CHANNELS 15 + +struct cppi41_dma_controller { + struct dma_controller controller; + struct cppi41_dma_channel rx_channel[MUSB_DMA_NUM_CHANNELS]; + struct cppi41_dma_channel tx_channel[MUSB_DMA_NUM_CHANNELS]; + struct musb *musb; + u32 rx_mode; + u32 tx_mode; + u32 auto_req; +}; + +static void save_rx_toggle(struct cppi41_dma_channel *cppi41_channel) +{ + u16 csr; + u8 toggle; + + if (cppi41_channel->is_tx) + return; + if (!is_host_active(cppi41_channel->controller->musb)) + return; + + csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR); + toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0; + + cppi41_channel->usb_toggle = toggle; +} + +static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel) +{ + u16 csr; + u8 toggle; + + if (cppi41_channel->is_tx) + return; + if (!is_host_active(cppi41_channel->controller->musb)) + return; + + csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR); + toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0; + + /* + * AM335x Advisory 1.0.13: Due to internal synchronisation error the + * data toggle may reset from DATA1 to DATA0 during receiving data from + * more than one endpoint. + */ + if (!toggle && toggle == cppi41_channel->usb_toggle) { + csr |= MUSB_RXCSR_H_DATATOGGLE | MUSB_RXCSR_H_WR_DATATOGGLE; + musb_writew(cppi41_channel->hw_ep->regs, MUSB_RXCSR, csr); + dev_dbg(cppi41_channel->controller->musb->controller, + "Restoring DATA1 toggle.\n"); + } + + cppi41_channel->usb_toggle = toggle; +} + +static void cppi41_dma_callback(void *private_data) +{ + struct dma_channel *channel = private_data; + struct cppi41_dma_channel *cppi41_channel = channel->private_data; + struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; + struct musb *musb = hw_ep->musb; + unsigned long flags; + struct dma_tx_state txstate; + u32 transferred; + + spin_lock_irqsave(&musb->lock, flags); + + dmaengine_tx_status(cppi41_channel->dc, cppi41_channel->cookie, + &txstate); + transferred = cppi41_channel->prog_len - txstate.residue; + cppi41_channel->transferred += transferred; + + dev_dbg(musb->controller, "DMA transfer done on hw_ep=%d bytes=%d/%d\n", + hw_ep->epnum, cppi41_channel->transferred, + cppi41_channel->total_len); + + update_rx_toggle(cppi41_channel); + + if (cppi41_channel->transferred == cppi41_channel->total_len || + transferred < cppi41_channel->packet_sz) { + + /* done, complete */ + cppi41_channel->channel.actual_len = + cppi41_channel->transferred; + cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE; + musb_dma_completion(musb, hw_ep->epnum, cppi41_channel->is_tx); + } else { + /* next iteration, reload */ + struct dma_chan *dc = cppi41_channel->dc; + struct dma_async_tx_descriptor *dma_desc; + enum dma_transfer_direction direction; + u16 csr; + u32 remain_bytes; + void __iomem *epio = cppi41_channel->hw_ep->regs; + + cppi41_channel->buf_addr += cppi41_channel->packet_sz; + + remain_bytes = cppi41_channel->total_len; + remain_bytes -= cppi41_channel->transferred; + remain_bytes = min(remain_bytes, cppi41_channel->packet_sz); + cppi41_channel->prog_len = remain_bytes; + + direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV + : DMA_DEV_TO_MEM; + dma_desc = dmaengine_prep_slave_single(dc, + cppi41_channel->buf_addr, + remain_bytes, + direction, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (WARN_ON(!dma_desc)) + return; + + dma_desc->callback = cppi41_dma_callback; + dma_desc->callback_param = channel; + cppi41_channel->cookie = dma_desc->tx_submit(dma_desc); + dma_async_issue_pending(dc); + + if (!cppi41_channel->is_tx) { + csr = musb_readw(epio, MUSB_RXCSR); + csr |= MUSB_RXCSR_H_REQPKT; + musb_writew(epio, MUSB_RXCSR, csr); + } + } + spin_unlock_irqrestore(&musb->lock, flags); +} + +static u32 update_ep_mode(unsigned ep, unsigned mode, u32 old) +{ + unsigned shift; + + shift = (ep - 1) * 2; + old &= ~(3 << shift); + old |= mode << shift; + return old; +} + +static void cppi41_set_dma_mode(struct cppi41_dma_channel *cppi41_channel, + unsigned mode) +{ + struct cppi41_dma_controller *controller = cppi41_channel->controller; + u32 port; + u32 new_mode; + u32 old_mode; + + if (cppi41_channel->is_tx) + old_mode = controller->tx_mode; + else + old_mode = controller->rx_mode; + port = cppi41_channel->port_num; + new_mode = update_ep_mode(port, mode, old_mode); + + if (new_mode == old_mode) + return; + if (cppi41_channel->is_tx) { + controller->tx_mode = new_mode; + musb_writel(controller->musb->ctrl_base, USB_CTRL_TX_MODE, + new_mode); + } else { + controller->rx_mode = new_mode; + musb_writel(controller->musb->ctrl_base, USB_CTRL_RX_MODE, + new_mode); + } +} + +static void cppi41_set_autoreq_mode(struct cppi41_dma_channel *cppi41_channel, + unsigned mode) +{ + struct cppi41_dma_controller *controller = cppi41_channel->controller; + u32 port; + u32 new_mode; + u32 old_mode; + + old_mode = controller->auto_req; + port = cppi41_channel->port_num; + new_mode = update_ep_mode(port, mode, old_mode); + + if (new_mode == old_mode) + return; + controller->auto_req = new_mode; + musb_writel(controller->musb->ctrl_base, USB_CTRL_AUTOREQ, new_mode); +} + +static bool cppi41_configure_channel(struct dma_channel *channel, + u16 packet_sz, u8 mode, + dma_addr_t dma_addr, u32 len) +{ + struct cppi41_dma_channel *cppi41_channel = channel->private_data; + struct dma_chan *dc = cppi41_channel->dc; + struct dma_async_tx_descriptor *dma_desc; + enum dma_transfer_direction direction; + struct musb *musb = cppi41_channel->controller->musb; + unsigned use_gen_rndis = 0; + + dev_dbg(musb->controller, + "configure ep%d/%x packet_sz=%d, mode=%d, dma_addr=0x%llx, len=%d is_tx=%d\n", + cppi41_channel->port_num, RNDIS_REG(cppi41_channel->port_num), + packet_sz, mode, (unsigned long long) dma_addr, + len, cppi41_channel->is_tx); + + cppi41_channel->buf_addr = dma_addr; + cppi41_channel->total_len = len; + cppi41_channel->transferred = 0; + cppi41_channel->packet_sz = packet_sz; + + /* + * Due to AM335x' Advisory 1.0.13 we are not allowed to transfer more + * than max packet size at a time. + */ + if (cppi41_channel->is_tx) + use_gen_rndis = 1; + + if (use_gen_rndis) { + /* RNDIS mode */ + if (len > packet_sz) { + musb_writel(musb->ctrl_base, + RNDIS_REG(cppi41_channel->port_num), len); + /* gen rndis */ + cppi41_set_dma_mode(cppi41_channel, + EP_MODE_DMA_GEN_RNDIS); + + /* auto req */ + cppi41_set_autoreq_mode(cppi41_channel, + EP_MODE_AUTOREG_ALL_NEOP); + } else { + musb_writel(musb->ctrl_base, + RNDIS_REG(cppi41_channel->port_num), 0); + cppi41_set_dma_mode(cppi41_channel, + EP_MODE_DMA_TRANSPARENT); + cppi41_set_autoreq_mode(cppi41_channel, + EP_MODE_AUTOREG_NONE); + } + } else { + /* fallback mode */ + cppi41_set_dma_mode(cppi41_channel, EP_MODE_DMA_TRANSPARENT); + cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREG_NONE); + len = min_t(u32, packet_sz, len); + } + cppi41_channel->prog_len = len; + direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; + dma_desc = dmaengine_prep_slave_single(dc, dma_addr, len, direction, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!dma_desc) + return false; + + dma_desc->callback = cppi41_dma_callback; + dma_desc->callback_param = channel; + cppi41_channel->cookie = dma_desc->tx_submit(dma_desc); + + save_rx_toggle(cppi41_channel); + dma_async_issue_pending(dc); + return true; +} + +static struct dma_channel *cppi41_dma_channel_allocate(struct dma_controller *c, + struct musb_hw_ep *hw_ep, u8 is_tx) +{ + struct cppi41_dma_controller *controller = container_of(c, + struct cppi41_dma_controller, controller); + struct cppi41_dma_channel *cppi41_channel = NULL; + u8 ch_num = hw_ep->epnum - 1; + + if (ch_num >= MUSB_DMA_NUM_CHANNELS) + return NULL; + + if (is_tx) + cppi41_channel = &controller->tx_channel[ch_num]; + else + cppi41_channel = &controller->rx_channel[ch_num]; + + if (!cppi41_channel->dc) + return NULL; + + if (cppi41_channel->is_allocated) + return NULL; + + cppi41_channel->hw_ep = hw_ep; + cppi41_channel->is_allocated = 1; + + return &cppi41_channel->channel; +} + +static void cppi41_dma_channel_release(struct dma_channel *channel) +{ + struct cppi41_dma_channel *cppi41_channel = channel->private_data; + + if (cppi41_channel->is_allocated) { + cppi41_channel->is_allocated = 0; + channel->status = MUSB_DMA_STATUS_FREE; + channel->actual_len = 0; + } +} + +static int cppi41_dma_channel_program(struct dma_channel *channel, + u16 packet_sz, u8 mode, + dma_addr_t dma_addr, u32 len) +{ + int ret; + + BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN || + channel->status == MUSB_DMA_STATUS_BUSY); + + channel->status = MUSB_DMA_STATUS_BUSY; + channel->actual_len = 0; + ret = cppi41_configure_channel(channel, packet_sz, mode, dma_addr, len); + if (!ret) + channel->status = MUSB_DMA_STATUS_FREE; + + return ret; +} + +static int cppi41_is_compatible(struct dma_channel *channel, u16 maxpacket, + void *buf, u32 length) +{ + struct cppi41_dma_channel *cppi41_channel = channel->private_data; + struct cppi41_dma_controller *controller = cppi41_channel->controller; + struct musb *musb = controller->musb; + + if (is_host_active(musb)) { + WARN_ON(1); + return 1; + } + if (cppi41_channel->is_tx) + return 1; + /* AM335x Advisory 1.0.13. No workaround for device RX mode */ + return 0; +} + +static int cppi41_dma_channel_abort(struct dma_channel *channel) +{ + struct cppi41_dma_channel *cppi41_channel = channel->private_data; + struct cppi41_dma_controller *controller = cppi41_channel->controller; + struct musb *musb = controller->musb; + void __iomem *epio = cppi41_channel->hw_ep->regs; + int tdbit; + int ret; + unsigned is_tx; + u16 csr; + + is_tx = cppi41_channel->is_tx; + dev_dbg(musb->controller, "abort channel=%d, is_tx=%d\n", + cppi41_channel->port_num, is_tx); + + if (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE) + return 0; + + if (is_tx) { + csr = musb_readw(epio, MUSB_TXCSR); + csr &= ~MUSB_TXCSR_DMAENAB; + musb_writew(epio, MUSB_TXCSR, csr); + } else { + csr = musb_readw(epio, MUSB_RXCSR); + csr &= ~(MUSB_RXCSR_H_REQPKT | MUSB_RXCSR_DMAENAB); + musb_writew(epio, MUSB_RXCSR, csr); + + csr = musb_readw(epio, MUSB_RXCSR); + if (csr & MUSB_RXCSR_RXPKTRDY) { + csr |= MUSB_RXCSR_FLUSHFIFO; + musb_writew(epio, MUSB_RXCSR, csr); + musb_writew(epio, MUSB_RXCSR, csr); + } + } + + tdbit = 1 << cppi41_channel->port_num; + if (is_tx) + tdbit <<= 16; + + do { + musb_writel(musb->ctrl_base, USB_TDOWN, tdbit); + ret = dmaengine_terminate_all(cppi41_channel->dc); + } while (ret == -EAGAIN); + + musb_writel(musb->ctrl_base, USB_TDOWN, tdbit); + + if (is_tx) { + csr = musb_readw(epio, MUSB_TXCSR); + if (csr & MUSB_TXCSR_TXPKTRDY) { + csr |= MUSB_TXCSR_FLUSHFIFO; + musb_writew(epio, MUSB_TXCSR, csr); + } + } + + cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE; + return 0; +} + +static void cppi41_release_all_dma_chans(struct cppi41_dma_controller *ctrl) +{ + struct dma_chan *dc; + int i; + + for (i = 0; i < MUSB_DMA_NUM_CHANNELS; i++) { + dc = ctrl->tx_channel[i].dc; + if (dc) + dma_release_channel(dc); + dc = ctrl->rx_channel[i].dc; + if (dc) + dma_release_channel(dc); + } +} + +static void cppi41_dma_controller_stop(struct cppi41_dma_controller *controller) +{ + cppi41_release_all_dma_chans(controller); +} + +static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller) +{ + struct musb *musb = controller->musb; + struct device *dev = musb->controller; + struct device_node *np = dev->of_node; + struct cppi41_dma_channel *cppi41_channel; + int count; + int i; + int ret; + + count = of_property_count_strings(np, "dma-names"); + if (count < 0) + return count; + + for (i = 0; i < count; i++) { + struct dma_chan *dc; + struct dma_channel *musb_dma; + const char *str; + unsigned is_tx; + unsigned int port; + + ret = of_property_read_string_index(np, "dma-names", i, &str); + if (ret) + goto err; + if (!strncmp(str, "tx", 2)) + is_tx = 1; + else if (!strncmp(str, "rx", 2)) + is_tx = 0; + else { + dev_err(dev, "Wrong dmatype %s\n", str); + goto err; + } + ret = kstrtouint(str + 2, 0, &port); + if (ret) + goto err; + + if (port > MUSB_DMA_NUM_CHANNELS || !port) + goto err; + if (is_tx) + cppi41_channel = &controller->tx_channel[port - 1]; + else + cppi41_channel = &controller->rx_channel[port - 1]; + + cppi41_channel->controller = controller; + cppi41_channel->port_num = port; + cppi41_channel->is_tx = is_tx; + + musb_dma = &cppi41_channel->channel; + musb_dma->private_data = cppi41_channel; + musb_dma->status = MUSB_DMA_STATUS_FREE; + musb_dma->max_len = SZ_4M; + + dc = dma_request_slave_channel(dev, str); + if (!dc) { + dev_err(dev, "Falied to request %s.\n", str); + goto err; + } + cppi41_channel->dc = dc; + } + return 0; +err: + cppi41_release_all_dma_chans(controller); + return -EINVAL; +} + +void dma_controller_destroy(struct dma_controller *c) +{ + struct cppi41_dma_controller *controller = container_of(c, + struct cppi41_dma_controller, controller); + + cppi41_dma_controller_stop(controller); + kfree(controller); +} + +struct dma_controller *dma_controller_create(struct musb *musb, + void __iomem *base) +{ + struct cppi41_dma_controller *controller; + int ret; + + if (!musb->controller->of_node) { + dev_err(musb->controller, "Need DT for the DMA engine.\n"); + return NULL; + } + + controller = kzalloc(sizeof(*controller), GFP_KERNEL); + if (!controller) + goto kzalloc_fail; + + controller->musb = musb; + + controller->controller.channel_alloc = cppi41_dma_channel_allocate; + controller->controller.channel_release = cppi41_dma_channel_release; + controller->controller.channel_program = cppi41_dma_channel_program; + controller->controller.channel_abort = cppi41_dma_channel_abort; + controller->controller.is_compatible = cppi41_is_compatible; + + ret = cppi41_dma_controller_start(controller); + if (ret) + goto plat_get_fail; + return &controller->controller; + +plat_get_fail: + kfree(controller); +kzalloc_fail: + return NULL; +} diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h index 1b6b827b769f..1345a4ff041a 100644 --- a/drivers/usb/musb/musb_dma.h +++ b/drivers/usb/musb/musb_dma.h @@ -62,13 +62,13 @@ struct musb_hw_ep; #define DMA_ADDR_INVALID (~(dma_addr_t)0) -#ifndef CONFIG_MUSB_PIO_ONLY -#define is_dma_capable() (1) -#else +#ifdef CONFIG_MUSB_PIO_ONLY #define is_dma_capable() (0) +#else +#define is_dma_capable() (1) #endif -#ifdef CONFIG_USB_TI_CPPI_DMA +#if defined(CONFIG_USB_TI_CPPI_DMA) || defined(CONFIG_USB_TI_CPPI41_DMA) #define is_cppi_enabled() 1 #else #define is_cppi_enabled() 0 @@ -159,8 +159,6 @@ dma_channel_status(struct dma_channel *c) * Controllers manage dma channels. */ struct dma_controller { - int (*start)(struct dma_controller *); - int (*stop)(struct dma_controller *); struct dma_channel *(*channel_alloc)(struct dma_controller *, struct musb_hw_ep *, u8 is_tx); void (*channel_release)(struct dma_channel *); @@ -177,9 +175,20 @@ struct dma_controller { /* called after channel_program(), may indicate a fault */ extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit); +#ifdef CONFIG_MUSB_PIO_ONLY +static inline struct dma_controller *dma_controller_create(struct musb *m, + void __iomem *io) +{ + return NULL; +} + +static inline void dma_controller_destroy(struct dma_controller *d) { } + +#else extern struct dma_controller *dma_controller_create(struct musb *, void __iomem *); extern void dma_controller_destroy(struct dma_controller *); +#endif #endif /* __MUSB_DMA_H__ */ diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 5233804d66b1..4ffbaace7913 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -36,19 +36,18 @@ #include <linux/dma-mapping.h> #include <linux/pm_runtime.h> #include <linux/module.h> -#include <linux/usb/nop-usb-xceiv.h> +#include <linux/usb/usb_phy_gen_xceiv.h> #include <linux/platform_data/usb-omap.h> #include <linux/sizes.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_address.h> +#include <linux/of_irq.h> #include "musb_core.h" -#ifdef CONFIG_OF static const struct of_device_id musb_dsps_of_match[]; -#endif /** * avoid using musb_readx()/musb_writex() as glue layer should not be @@ -75,7 +74,6 @@ struct dsps_musb_wrapper { u16 revision; u16 control; u16 status; - u16 eoi; u16 epintr_set; u16 epintr_clear; u16 epintr_status; @@ -108,10 +106,7 @@ struct dsps_musb_wrapper { /* bit positions for mode */ unsigned iddig:5; /* miscellaneous stuff */ - u32 musb_core_offset; u8 poll_seconds; - /* number of musb instances */ - u8 instances; }; /** @@ -119,53 +114,12 @@ struct dsps_musb_wrapper { */ struct dsps_glue { struct device *dev; - struct platform_device *musb[2]; /* child musb pdev */ + struct platform_device *musb; /* child musb pdev */ const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ - struct timer_list timer[2]; /* otg_workaround timer */ - unsigned long last_timer[2]; /* last timer data for each instance */ - u32 __iomem *usb_ctrl[2]; + struct timer_list timer; /* otg_workaround timer */ + unsigned long last_timer; /* last timer data for each instance */ }; -#define DSPS_AM33XX_CONTROL_MODULE_PHYS_0 0x44e10620 -#define DSPS_AM33XX_CONTROL_MODULE_PHYS_1 0x44e10628 - -static const resource_size_t dsps_control_module_phys[] = { - DSPS_AM33XX_CONTROL_MODULE_PHYS_0, - DSPS_AM33XX_CONTROL_MODULE_PHYS_1, -}; - -#define USBPHY_CM_PWRDN (1 << 0) -#define USBPHY_OTG_PWRDN (1 << 1) -#define USBPHY_OTGVDET_EN (1 << 19) -#define USBPHY_OTGSESSEND_EN (1 << 20) - -/** - * musb_dsps_phy_control - phy on/off - * @glue: struct dsps_glue * - * @id: musb instance - * @on: flag for phy to be switched on or off - * - * This is to enable the PHY using usb_ctrl register in system control - * module space. - * - * XXX: This function will be removed once we have a seperate driver for - * control module - */ -static void musb_dsps_phy_control(struct dsps_glue *glue, u8 id, u8 on) -{ - u32 usbphycfg; - - usbphycfg = readl(glue->usb_ctrl[id]); - - if (on) { - usbphycfg &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN); - usbphycfg |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN; - } else { - usbphycfg |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN; - } - - writel(usbphycfg, glue->usb_ctrl[id]); -} /** * dsps_musb_enable - enable interrupts */ @@ -205,7 +159,6 @@ static void dsps_musb_disable(struct musb *musb) dsps_writel(reg_base, wrp->epintr_clear, wrp->txep_bitmap | wrp->rxep_bitmap); dsps_writeb(musb->mregs, MUSB_DEVCTL, 0); - dsps_writel(reg_base, wrp->eoi, 0); } static void otg_timer(unsigned long _musb) @@ -213,7 +166,6 @@ static void otg_timer(unsigned long _musb) struct musb *musb = (void *)_musb; void __iomem *mregs = musb->mregs; struct device *dev = musb->controller; - struct platform_device *pdev = to_platform_device(dev); struct dsps_glue *glue = dev_get_drvdata(dev->parent); const struct dsps_musb_wrapper *wrp = glue->wrp; u8 devctl; @@ -250,7 +202,7 @@ static void otg_timer(unsigned long _musb) case OTG_STATE_B_IDLE: devctl = dsps_readb(mregs, MUSB_DEVCTL); if (devctl & MUSB_DEVCTL_BDEVICE) - mod_timer(&glue->timer[pdev->id], + mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); else musb->xceiv->state = OTG_STATE_A_IDLE; @@ -264,7 +216,6 @@ static void otg_timer(unsigned long _musb) static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) { struct device *dev = musb->controller; - struct platform_device *pdev = to_platform_device(dev); struct dsps_glue *glue = dev_get_drvdata(dev->parent); if (timeout == 0) @@ -275,23 +226,23 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { dev_dbg(musb->controller, "%s active, deleting timer\n", usb_otg_state_string(musb->xceiv->state)); - del_timer(&glue->timer[pdev->id]); - glue->last_timer[pdev->id] = jiffies; + del_timer(&glue->timer); + glue->last_timer = jiffies; return; } - if (time_after(glue->last_timer[pdev->id], timeout) && - timer_pending(&glue->timer[pdev->id])) { + if (time_after(glue->last_timer, timeout) && + timer_pending(&glue->timer)) { dev_dbg(musb->controller, "Longer idle timer already pending, ignoring...\n"); return; } - glue->last_timer[pdev->id] = timeout; + glue->last_timer = timeout; dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", usb_otg_state_string(musb->xceiv->state), jiffies_to_msecs(timeout - jiffies)); - mod_timer(&glue->timer[pdev->id], timeout); + mod_timer(&glue->timer, timeout); } static irqreturn_t dsps_interrupt(int irq, void *hci) @@ -299,7 +250,6 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) struct musb *musb = hci; void __iomem *reg_base = musb->ctrl_base; struct device *dev = musb->controller; - struct platform_device *pdev = to_platform_device(dev); struct dsps_glue *glue = dev_get_drvdata(dev->parent); const struct dsps_musb_wrapper *wrp = glue->wrp; unsigned long flags; @@ -319,7 +269,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) /* Get usb core interrupts */ usbintr = dsps_readl(reg_base, wrp->coreintr_status); if (!usbintr && !epintr) - goto eoi; + goto out; musb->int_usb = (usbintr & wrp->usb_bitmap) >> wrp->usb_shift; if (usbintr) @@ -359,7 +309,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) */ musb->int_usb &= ~MUSB_INTR_VBUSERROR; musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; - mod_timer(&glue->timer[pdev->id], + mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); WARNING("VBUS error workaround (delay coming)\n"); } else if (drvvbus) { @@ -367,7 +317,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) MUSB_HST_MODE(musb); musb->xceiv->otg->default_a = 1; musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; - del_timer(&glue->timer[pdev->id]); + del_timer(&glue->timer); } else { musb->is_active = 0; MUSB_DEV_MODE(musb); @@ -387,16 +337,10 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) if (musb->int_tx || musb->int_rx || musb->int_usb) ret |= musb_interrupt(musb); - eoi: - /* EOI needs to be written for the IRQ to be re-asserted. */ - if (ret == IRQ_HANDLED || epintr || usbintr) - dsps_writel(reg_base, wrp->eoi, 1); - /* Poll for ID change */ if (musb->xceiv->state == OTG_STATE_B_IDLE) - mod_timer(&glue->timer[pdev->id], - jiffies + wrp->poll_seconds * HZ); - + mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); +out: spin_unlock_irqrestore(&musb->lock, flags); return ret; @@ -405,37 +349,38 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) static int dsps_musb_init(struct musb *musb) { struct device *dev = musb->controller; - struct platform_device *pdev = to_platform_device(dev); struct dsps_glue *glue = dev_get_drvdata(dev->parent); + struct platform_device *parent = to_platform_device(dev->parent); const struct dsps_musb_wrapper *wrp = glue->wrp; - void __iomem *reg_base = musb->ctrl_base; + void __iomem *reg_base; + struct resource *r; u32 rev, val; - int status; - /* mentor core register starts at offset of 0x400 from musb base */ - musb->mregs += wrp->musb_core_offset; + r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control"); + if (!r) + return -EINVAL; + + reg_base = devm_ioremap_resource(dev, r); + if (!musb->ctrl_base) + return -EINVAL; + musb->ctrl_base = reg_base; /* NOP driver needs change if supporting dual instance */ - usb_nop_xceiv_register(); - musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); - if (IS_ERR_OR_NULL(musb->xceiv)) - return -EPROBE_DEFER; + musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0); + if (IS_ERR(musb->xceiv)) + return PTR_ERR(musb->xceiv); /* Returns zero if e.g. not clocked */ rev = dsps_readl(reg_base, wrp->revision); - if (!rev) { - status = -ENODEV; - goto err0; - } + if (!rev) + return -ENODEV; - setup_timer(&glue->timer[pdev->id], otg_timer, (unsigned long) musb); + usb_phy_init(musb->xceiv); + setup_timer(&glue->timer, otg_timer, (unsigned long) musb); /* Reset the musb */ dsps_writel(reg_base, wrp->control, (1 << wrp->reset)); - /* Start the on-chip PHY and its PLL. */ - musb_dsps_phy_control(glue, pdev->id, 1); - musb->isr = dsps_interrupt; /* reset the otgdisable bit, needed for host mode to work */ @@ -443,31 +388,17 @@ static int dsps_musb_init(struct musb *musb) val &= ~(1 << wrp->otg_disable); dsps_writel(musb->ctrl_base, wrp->phy_utmi, val); - /* clear level interrupt */ - dsps_writel(reg_base, wrp->eoi, 0); - return 0; -err0: - usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); - return status; } static int dsps_musb_exit(struct musb *musb) { struct device *dev = musb->controller; - struct platform_device *pdev = to_platform_device(dev); struct dsps_glue *glue = dev_get_drvdata(dev->parent); - del_timer_sync(&glue->timer[pdev->id]); - - /* Shutdown the on-chip PHY and its PLL. */ - musb_dsps_phy_control(glue, pdev->id, 0); - - /* NOP driver needs change if supporting dual instance */ - usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); + del_timer_sync(&glue->timer); + usb_phy_shutdown(musb->xceiv); return 0; } @@ -483,116 +414,98 @@ static struct musb_platform_ops dsps_ops = { static u64 musb_dmamask = DMA_BIT_MASK(32); -static int dsps_create_musb_pdev(struct dsps_glue *glue, u8 id) +static int get_int_prop(struct device_node *dn, const char *s) { - struct device *dev = glue->dev; - struct platform_device *pdev = to_platform_device(dev); - struct musb_hdrc_platform_data *pdata = dev->platform_data; - struct device_node *np = pdev->dev.of_node; - struct musb_hdrc_config *config; - struct platform_device *musb; - struct resource *res; + int ret; + u32 val; + + ret = of_property_read_u32(dn, s, &val); + if (ret) + return 0; + return val; +} + +static int dsps_create_musb_pdev(struct dsps_glue *glue, + struct platform_device *parent) +{ + struct musb_hdrc_platform_data pdata; struct resource resources[2]; - char res_name[11]; + struct device *dev = &parent->dev; + struct musb_hdrc_config *config; + struct platform_device *musb; + struct device_node *dn = parent->dev.of_node; + struct device_node *child_node; int ret; - resources[0].start = dsps_control_module_phys[id]; - resources[0].end = resources[0].start + SZ_4 - 1; - resources[0].flags = IORESOURCE_MEM; + child_node = of_get_child_by_name(dn, "usb"); + if (!child_node) + return -EINVAL; - glue->usb_ctrl[id] = devm_ioremap_resource(&pdev->dev, resources); - if (IS_ERR(glue->usb_ctrl[id])) { - ret = PTR_ERR(glue->usb_ctrl[id]); - goto err0; + memset(resources, 0, sizeof(resources)); + ret = of_address_to_resource(child_node, 0, &resources[0]); + if (ret) { + dev_err(dev, "failed to get memory.\n"); + return ret; } - /* first resource is for usbss, so start index from 1 */ - res = platform_get_resource(pdev, IORESOURCE_MEM, id + 1); - if (!res) { - dev_err(dev, "failed to get memory for instance %d\n", id); - ret = -ENODEV; - goto err0; - } - res->parent = NULL; - resources[0] = *res; - - /* first resource is for usbss, so start index from 1 */ - res = platform_get_resource(pdev, IORESOURCE_IRQ, id + 1); - if (!res) { - dev_err(dev, "failed to get irq for instance %d\n", id); - ret = -ENODEV; - goto err0; + ret = of_irq_to_resource(child_node, 0, &resources[1]); + if (ret == 0) { + dev_err(dev, "failed to get irq.\n"); + ret = -EINVAL; + return ret; } - res->parent = NULL; - resources[1] = *res; - resources[1].name = "mc"; /* allocate the child platform device */ musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); if (!musb) { dev_err(dev, "failed to allocate musb device\n"); - ret = -ENOMEM; - goto err0; + return -ENOMEM; } musb->dev.parent = dev; musb->dev.dma_mask = &musb_dmamask; musb->dev.coherent_dma_mask = musb_dmamask; + musb->dev.of_node = of_node_get(child_node); - glue->musb[id] = musb; + glue->musb = musb; - ret = platform_device_add_resources(musb, resources, 2); + ret = platform_device_add_resources(musb, resources, + ARRAY_SIZE(resources)); if (ret) { dev_err(dev, "failed to add resources\n"); - goto err2; + goto err; } - if (np) { - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - dev_err(&pdev->dev, - "failed to allocate musb platform data\n"); - ret = -ENOMEM; - goto err2; - } - - config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL); - if (!config) { - dev_err(&pdev->dev, - "failed to allocate musb hdrc config\n"); - ret = -ENOMEM; - goto err2; - } - - of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps); - of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits); - snprintf(res_name, sizeof(res_name), "port%d-mode", id); - of_property_read_u32(np, res_name, (u32 *)&pdata->mode); - of_property_read_u32(np, "power", (u32 *)&pdata->power); - config->multipoint = of_property_read_bool(np, "multipoint"); - - pdata->config = config; + config = devm_kzalloc(&parent->dev, sizeof(*config), GFP_KERNEL); + if (!config) { + dev_err(dev, "failed to allocate musb hdrc config\n"); + ret = -ENOMEM; + goto err; } + pdata.config = config; + pdata.platform_ops = &dsps_ops; - pdata->platform_ops = &dsps_ops; + config->num_eps = get_int_prop(child_node, "num-eps"); + config->ram_bits = get_int_prop(child_node, "ram-bits"); + pdata.mode = get_int_prop(child_node, "port-mode"); + pdata.power = get_int_prop(child_node, "power"); + config->multipoint = of_property_read_bool(child_node, "multipoint"); - ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); + ret = platform_device_add_data(musb, &pdata, sizeof(pdata)); if (ret) { dev_err(dev, "failed to add platform_data\n"); - goto err2; + goto err; } ret = platform_device_add(musb); if (ret) { dev_err(dev, "failed to register musb device\n"); - goto err2; + goto err; } - return 0; -err2: +err: platform_device_put(musb); -err0: return ret; } @@ -601,14 +514,12 @@ static int dsps_probe(struct platform_device *pdev) const struct of_device_id *match; const struct dsps_musb_wrapper *wrp; struct dsps_glue *glue; - struct resource *iomem; - int ret, i; + int ret; match = of_match_node(musb_dsps_of_match, pdev->dev.of_node); if (!match) { dev_err(&pdev->dev, "fail to get matching of_match struct\n"); - ret = -EINVAL; - goto err0; + return -EINVAL; } wrp = match->data; @@ -616,29 +527,13 @@ static int dsps_probe(struct platform_device *pdev) glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { dev_err(&pdev->dev, "unable to allocate glue memory\n"); - ret = -ENOMEM; - goto err0; - } - - /* get memory resource */ - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iomem) { - dev_err(&pdev->dev, "failed to get usbss mem resourse\n"); - ret = -ENODEV; - goto err1; + return -ENOMEM; } glue->dev = &pdev->dev; + glue->wrp = wrp; - glue->wrp = kmemdup(wrp, sizeof(*wrp), GFP_KERNEL); - if (!glue->wrp) { - dev_err(&pdev->dev, "failed to duplicate wrapper struct memory\n"); - ret = -ENOMEM; - goto err1; - } platform_set_drvdata(pdev, glue); - - /* enable the usbss clocks */ pm_runtime_enable(&pdev->dev); ret = pm_runtime_get_sync(&pdev->dev); @@ -647,17 +542,9 @@ static int dsps_probe(struct platform_device *pdev) goto err2; } - /* create the child platform device for all instances of musb */ - for (i = 0; i < wrp->instances ; i++) { - ret = dsps_create_musb_pdev(glue, i); - if (ret != 0) { - dev_err(&pdev->dev, "failed to create child pdev\n"); - /* release resources of previously created instances */ - for (i--; i >= 0 ; i--) - platform_device_unregister(glue->musb[i]); - goto err3; - } - } + ret = dsps_create_musb_pdev(glue, pdev); + if (ret) + goto err3; return 0; @@ -665,65 +552,27 @@ err3: pm_runtime_put(&pdev->dev); err2: pm_runtime_disable(&pdev->dev); - kfree(glue->wrp); -err1: kfree(glue); -err0: return ret; } + static int dsps_remove(struct platform_device *pdev) { struct dsps_glue *glue = platform_get_drvdata(pdev); - const struct dsps_musb_wrapper *wrp = glue->wrp; - int i; - /* delete the child platform device */ - for (i = 0; i < wrp->instances ; i++) - platform_device_unregister(glue->musb[i]); + platform_device_unregister(glue->musb); /* disable usbss clocks */ pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); - kfree(glue->wrp); kfree(glue); return 0; } -#ifdef CONFIG_PM_SLEEP -static int dsps_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev->parent); - struct dsps_glue *glue = platform_get_drvdata(pdev); - const struct dsps_musb_wrapper *wrp = glue->wrp; - int i; - - for (i = 0; i < wrp->instances; i++) - musb_dsps_phy_control(glue, i, 0); - - return 0; -} - -static int dsps_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev->parent); - struct dsps_glue *glue = platform_get_drvdata(pdev); - const struct dsps_musb_wrapper *wrp = glue->wrp; - int i; - - for (i = 0; i < wrp->instances; i++) - musb_dsps_phy_control(glue, i, 1); - - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume); - -static const struct dsps_musb_wrapper ti81xx_driver_data = { +static const struct dsps_musb_wrapper am33xx_driver_data = { .revision = 0x00, .control = 0x14, .status = 0x18, - .eoi = 0x24, .epintr_set = 0x38, .epintr_clear = 0x40, .epintr_status = 0x30, @@ -745,38 +594,23 @@ static const struct dsps_musb_wrapper ti81xx_driver_data = { .rxep_shift = 16, .rxep_mask = 0xfffe, .rxep_bitmap = (0xfffe << 16), - .musb_core_offset = 0x400, .poll_seconds = 2, - .instances = 1, -}; - -static const struct platform_device_id musb_dsps_id_table[] = { - { - .name = "musb-ti81xx", - .driver_data = (kernel_ulong_t) &ti81xx_driver_data, - }, - { }, /* Terminating Entry */ }; -MODULE_DEVICE_TABLE(platform, musb_dsps_id_table); -#ifdef CONFIG_OF static const struct of_device_id musb_dsps_of_match[] = { { .compatible = "ti,musb-am33xx", - .data = (void *) &ti81xx_driver_data, }, + .data = (void *) &am33xx_driver_data, }, { }, }; MODULE_DEVICE_TABLE(of, musb_dsps_of_match); -#endif static struct platform_driver dsps_usbss_driver = { .probe = dsps_probe, .remove = dsps_remove, .driver = { .name = "musb-dsps", - .pm = &dsps_pm_ops, .of_match_table = of_match_ptr(musb_dsps_of_match), }, - .id_table = musb_dsps_id_table, }; MODULE_DESCRIPTION("TI DSPS MUSB Glue Layer"); @@ -784,14 +618,4 @@ MODULE_AUTHOR("Ravi B <ravibabu@ti.com>"); MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>"); MODULE_LICENSE("GPL v2"); -static int __init dsps_init(void) -{ - return platform_driver_register(&dsps_usbss_driver); -} -subsys_initcall(dsps_init); - -static void __exit dsps_exit(void) -{ - platform_driver_unregister(&dsps_usbss_driver); -} -module_exit(dsps_exit); +module_platform_driver(dsps_usbss_driver); diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 0414bc19d009..4376f51f5ef1 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -357,47 +357,49 @@ static void txstate(struct musb *musb, struct musb_request *req) } } -#elif defined(CONFIG_USB_TI_CPPI_DMA) - /* program endpoint CSR first, then setup DMA */ - csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY); - csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE | - MUSB_TXCSR_MODE; - musb_writew(epio, MUSB_TXCSR, - (MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN) - | csr); - - /* ensure writebuffer is empty */ - csr = musb_readw(epio, MUSB_TXCSR); - - /* NOTE host side sets DMAENAB later than this; both are - * OK since the transfer dma glue (between CPPI and Mentor - * fifos) just tells CPPI it could start. Data only moves - * to the USB TX fifo when both fifos are ready. - */ - - /* "mode" is irrelevant here; handle terminating ZLPs like - * PIO does, since the hardware RNDIS mode seems unreliable - * except for the last-packet-is-already-short case. - */ - use_dma = use_dma && c->channel_program( - musb_ep->dma, musb_ep->packet_sz, - 0, - request->dma + request->actual, - request_size); - if (!use_dma) { - c->channel_release(musb_ep->dma); - musb_ep->dma = NULL; - csr &= ~MUSB_TXCSR_DMAENAB; - musb_writew(epio, MUSB_TXCSR, csr); - /* invariant: prequest->buf is non-null */ - } -#elif defined(CONFIG_USB_TUSB_OMAP_DMA) - use_dma = use_dma && c->channel_program( - musb_ep->dma, musb_ep->packet_sz, - request->zero, - request->dma + request->actual, - request_size); #endif + if (is_cppi_enabled()) { + /* program endpoint CSR first, then setup DMA */ + csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY); + csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE | + MUSB_TXCSR_MODE; + musb_writew(epio, MUSB_TXCSR, (MUSB_TXCSR_P_WZC_BITS & + ~MUSB_TXCSR_P_UNDERRUN) | csr); + + /* ensure writebuffer is empty */ + csr = musb_readw(epio, MUSB_TXCSR); + + /* + * NOTE host side sets DMAENAB later than this; both are + * OK since the transfer dma glue (between CPPI and + * Mentor fifos) just tells CPPI it could start. Data + * only moves to the USB TX fifo when both fifos are + * ready. + */ + /* + * "mode" is irrelevant here; handle terminating ZLPs + * like PIO does, since the hardware RNDIS mode seems + * unreliable except for the + * last-packet-is-already-short case. + */ + use_dma = use_dma && c->channel_program( + musb_ep->dma, musb_ep->packet_sz, + 0, + request->dma + request->actual, + request_size); + if (!use_dma) { + c->channel_release(musb_ep->dma); + musb_ep->dma = NULL; + csr &= ~MUSB_TXCSR_DMAENAB; + musb_writew(epio, MUSB_TXCSR, csr); + /* invariant: prequest->buf is non-null */ + } + } else if (tusb_dma_omap()) + use_dma = use_dma && c->channel_program( + musb_ep->dma, musb_ep->packet_sz, + request->zero, + request->dma + request->actual, + request_size); } #endif @@ -1266,7 +1268,8 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, dev_dbg(musb->controller, "req %p queued to %s while ep %s\n", req, ep->name, "disabled"); status = -ESHUTDOWN; - goto cleanup; + unmap_dma_buffer(request, musb); + goto unlock; } /* add request to the list */ @@ -1276,7 +1279,7 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, if (!musb_ep->busy && &request->list == musb_ep->req_list.next) musb_ep_restart(musb, request); -cleanup: +unlock: spin_unlock_irqrestore(&musb->lock, lockflags); return status; } diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index 3d1fd52a15a9..e8e9f9aab203 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c @@ -37,18 +37,10 @@ #include "musb_core.h" #include "musbhsdma.h" -static int dma_controller_start(struct dma_controller *c) -{ - /* nothing to do */ - return 0; -} - static void dma_channel_release(struct dma_channel *channel); -static int dma_controller_stop(struct dma_controller *c) +static void dma_controller_stop(struct musb_dma_controller *controller) { - struct musb_dma_controller *controller = container_of(c, - struct musb_dma_controller, controller); struct musb *musb = controller->private_data; struct dma_channel *channel; u8 bit; @@ -67,8 +59,6 @@ static int dma_controller_stop(struct dma_controller *c) } } } - - return 0; } static struct dma_channel *dma_channel_allocate(struct dma_controller *c, @@ -371,8 +361,7 @@ void dma_controller_destroy(struct dma_controller *c) struct musb_dma_controller *controller = container_of(c, struct musb_dma_controller, controller); - if (!controller) - return; + dma_controller_stop(controller); if (controller->irq) free_irq(controller->irq, c); @@ -400,8 +389,6 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba controller->private_data = musb; controller->base = base; - controller->controller.start = dma_controller_start; - controller->controller.stop = dma_controller_stop; controller->controller.channel_alloc = dma_channel_allocate; controller->controller.channel_release = dma_channel_release; controller->controller.channel_program = dma_channel_program; diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index f44e8b5e00c9..59d2245db1c8 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -255,7 +255,7 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) { struct musb *musb = glue_to_musb(glue); struct device *dev = musb->controller; - struct musb_hdrc_platform_data *pdata = dev->platform_data; + struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev); struct omap_musb_board_data *data = pdata->board_data; struct usb_otg *otg = musb->xceiv->otg; @@ -341,7 +341,7 @@ static int omap2430_musb_init(struct musb *musb) int status = 0; struct device *dev = musb->controller; struct omap2430_glue *glue = dev_get_drvdata(dev->parent); - struct musb_hdrc_platform_data *plat = dev->platform_data; + struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); struct omap_musb_board_data *data = plat->board_data; /* We require some kind of external transceiver, hooked @@ -412,7 +412,7 @@ static void omap2430_musb_enable(struct musb *musb) unsigned long timeout = jiffies + msecs_to_jiffies(1000); struct device *dev = musb->controller; struct omap2430_glue *glue = dev_get_drvdata(dev->parent); - struct musb_hdrc_platform_data *pdata = dev->platform_data; + struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev); struct omap_musb_board_data *data = pdata->board_data; switch (glue->status) { @@ -482,7 +482,7 @@ static u64 omap2430_dmamask = DMA_BIT_MASK(32); static int omap2430_probe(struct platform_device *pdev) { struct resource musb_resources[3]; - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; + struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); struct omap_musb_board_data *data; struct platform_device *musb; struct omap2430_glue *glue; diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 6f8a9ca96ae7..b3b3ed723882 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -25,7 +25,7 @@ #include <linux/io.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> -#include <linux/usb/nop-usb-xceiv.h> +#include <linux/usb/usb_phy_gen_xceiv.h> #include "musb_core.h" @@ -1157,7 +1157,7 @@ static u64 tusb_dmamask = DMA_BIT_MASK(32); static int tusb_probe(struct platform_device *pdev) { struct resource musb_resources[3]; - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; + struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); struct platform_device *musb; struct tusb6010_glue *glue; diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c index 98df17c984a8..b8794eb81e9c 100644 --- a/drivers/usb/musb/tusb6010_omap.c +++ b/drivers/usb/musb/tusb6010_omap.c @@ -66,28 +66,6 @@ struct tusb_omap_dma { unsigned multichannel:1; }; -static int tusb_omap_dma_start(struct dma_controller *c) -{ - struct tusb_omap_dma *tusb_dma; - - tusb_dma = container_of(c, struct tusb_omap_dma, controller); - - /* dev_dbg(musb->controller, "ep%i ch: %i\n", chdat->epnum, chdat->ch); */ - - return 0; -} - -static int tusb_omap_dma_stop(struct dma_controller *c) -{ - struct tusb_omap_dma *tusb_dma; - - tusb_dma = container_of(c, struct tusb_omap_dma, controller); - - /* dev_dbg(musb->controller, "ep%i ch: %i\n", chdat->epnum, chdat->ch); */ - - return 0; -} - /* * Allocate dmareq0 to the current channel unless it's already taken */ @@ -695,8 +673,6 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba tusb_dma->dmareq = -1; tusb_dma->sync_dev = -1; - tusb_dma->controller.start = tusb_omap_dma_start; - tusb_dma->controller.stop = tusb_omap_dma_stop; tusb_dma->controller.channel_alloc = tusb_omap_dma_allocate; tusb_dma->controller.channel_release = tusb_omap_dma_release; tusb_dma->controller.channel_program = tusb_omap_dma_program; diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index fce71b605936..59256b12f746 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -227,7 +227,7 @@ ux500_of_probe(struct platform_device *pdev, struct device_node *np) static int ux500_probe(struct platform_device *pdev) { struct resource musb_resources[2]; - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; + struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); struct device_node *np = pdev->dev.of_node; struct platform_device *musb; struct ux500_glue *glue; diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c index bfb7a65d83cc..e51dd9b88e71 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -254,10 +254,8 @@ static int ux500_dma_channel_abort(struct dma_channel *channel) return 0; } -static int ux500_dma_controller_stop(struct dma_controller *c) +static void ux500_dma_controller_stop(struct ux500_dma_controller *controller) { - struct ux500_dma_controller *controller = container_of(c, - struct ux500_dma_controller, controller); struct ux500_dma_channel *ux500_channel; struct dma_channel *channel; u8 ch_num; @@ -281,18 +279,14 @@ static int ux500_dma_controller_stop(struct dma_controller *c) if (ux500_channel->dma_chan) dma_release_channel(ux500_channel->dma_chan); } - - return 0; } -static int ux500_dma_controller_start(struct dma_controller *c) +static int ux500_dma_controller_start(struct ux500_dma_controller *controller) { - struct ux500_dma_controller *controller = container_of(c, - struct ux500_dma_controller, controller); struct ux500_dma_channel *ux500_channel = NULL; struct musb *musb = controller->private_data; struct device *dev = musb->controller; - struct musb_hdrc_platform_data *plat = dev->platform_data; + struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); struct ux500_musb_board_data *data; struct dma_channel *dma_channel = NULL; char **chan_names; @@ -347,7 +341,7 @@ static int ux500_dma_controller_start(struct dma_controller *c) dir, ch_num); /* Release already allocated channels */ - ux500_dma_controller_stop(c); + ux500_dma_controller_stop(controller); return -EBUSY; } @@ -369,6 +363,7 @@ void dma_controller_destroy(struct dma_controller *c) struct ux500_dma_controller *controller = container_of(c, struct ux500_dma_controller, controller); + ux500_dma_controller_stop(controller); kfree(controller); } @@ -378,6 +373,7 @@ struct dma_controller *dma_controller_create(struct musb *musb, struct ux500_dma_controller *controller; struct platform_device *pdev = to_platform_device(musb->controller); struct resource *iomem; + int ret; controller = kzalloc(sizeof(*controller), GFP_KERNEL); if (!controller) @@ -394,14 +390,15 @@ struct dma_controller *dma_controller_create(struct musb *musb, controller->phy_base = (dma_addr_t) iomem->start; - controller->controller.start = ux500_dma_controller_start; - controller->controller.stop = ux500_dma_controller_stop; controller->controller.channel_alloc = ux500_dma_channel_allocate; controller->controller.channel_release = ux500_dma_channel_release; controller->controller.channel_program = ux500_dma_channel_program; controller->controller.channel_abort = ux500_dma_channel_abort; controller->controller.is_compatible = ux500_dma_is_compatible; + ret = ux500_dma_controller_start(controller); + if (ret) + goto plat_get_fail; return &controller->controller; plat_get_fail: diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index b57514ba486a..d5589f9c60a9 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -1,22 +1,10 @@ # # Physical Layer USB driver configuration # -menuconfig USB_PHY - bool "USB Physical Layer drivers" - help - Most USB controllers have the physical layer signalling part - (commonly called a PHY) built in. However, dual-role devices - (a.k.a. USB on-the-go) which support being USB master or slave - with the same connector often use an external PHY. - - The drivers in this submenu add support for such PHY devices. - They are not needed for standard master-only (or the vast - majority of slave-only) USB interfaces. +menu "USB Physical Layer drivers" - If you're not sure if this applies to you, it probably doesn't; - say N here. - -if USB_PHY +config USB_PHY + def_bool n # # USB Transceiver Drivers @@ -24,6 +12,7 @@ if USB_PHY config AB8500_USB tristate "AB8500 USB Transceiver Driver" depends on AB8500_CORE + select USB_PHY help Enable this to support the USB OTG transceiver in AB8500 chip. This transceiver supports high and full speed devices plus, @@ -33,12 +22,14 @@ config FSL_USB2_OTG bool "Freescale USB OTG Transceiver Driver" depends on USB_EHCI_FSL && USB_FSL_USB2 && PM_RUNTIME select USB_OTG + select USB_PHY help Enable this to support Freescale USB OTG transceiver. config ISP1301_OMAP tristate "Philips ISP1301 with OMAP OTG" depends on I2C && ARCH_OMAP_OTG + select USB_PHY help If you say yes here you get support for the Philips ISP1301 USB-On-The-Go transceiver working with the OMAP OTG controller. @@ -52,12 +43,14 @@ config ISP1301_OMAP config MV_U3D_PHY bool "Marvell USB 3.0 PHY controller Driver" depends on CPU_MMP3 + select USB_PHY help Enable this to support Marvell USB 3.0 phy controller for Marvell SoC. config NOP_USB_XCEIV tristate "NOP USB Transceiver Driver" + select USB_PHY help This driver is to be used by all the usb transceiver which are either built-in with usb ip or which are autonomous and doesn't require any @@ -77,6 +70,7 @@ config OMAP_USB2 tristate "OMAP USB2 PHY Driver" depends on ARCH_OMAP2PLUS select OMAP_CONTROL_USB + select USB_PHY help Enable this to support the transceiver that is part of SOC. This driver takes care of all the PHY functionality apart from comparator. @@ -87,12 +81,25 @@ config OMAP_USB3 tristate "OMAP USB3 PHY Driver" depends on ARCH_OMAP2PLUS || COMPILE_TEST select OMAP_CONTROL_USB + select USB_PHY help Enable this to support the USB3 PHY that is part of SOC. This driver takes care of all the PHY functionality apart from comparator. This driver interacts with the "OMAP Control USB Driver" to power on/off the PHY. +config AM335X_CONTROL_USB + tristate + +config AM335X_PHY_USB + tristate "AM335x USB PHY Driver" + select USB_PHY + select AM335X_CONTROL_USB + select NOP_USB_XCEIV + help + This driver provides PHY support for that phy which part for the + AM335x SoC. + config SAMSUNG_USBPHY tristate help @@ -103,6 +110,7 @@ config SAMSUNG_USBPHY config SAMSUNG_USB2PHY tristate "Samsung USB 2.0 PHY controller Driver" select SAMSUNG_USBPHY + select USB_PHY help Enable this to support Samsung USB 2.0 (High Speed) PHY controller driver for Samsung SoCs. @@ -110,6 +118,7 @@ config SAMSUNG_USB2PHY config SAMSUNG_USB3PHY tristate "Samsung USB 3.0 PHY controller Driver" select SAMSUNG_USBPHY + select USB_PHY help Enable this to support Samsung USB 3.0 (Super Speed) phy controller for samsung SoCs. @@ -117,6 +126,7 @@ config SAMSUNG_USB3PHY config TWL4030_USB tristate "TWL4030 USB Transceiver Driver" depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS + select USB_PHY help Enable this to support the USB OTG transceiver on TWL4030 family chips (including the TWL5030 and TPS659x0 devices). @@ -137,6 +147,7 @@ config TWL6030_USB config USB_GPIO_VBUS tristate "GPIO based peripheral-only VBUS sensing 'transceiver'" depends on GPIOLIB + select USB_PHY help Provides simple GPIO VBUS sensing for controllers with an internal transceiver via the usb_phy interface, and @@ -147,6 +158,7 @@ config USB_ISP1301 tristate "NXP ISP1301 USB transceiver support" depends on USB || USB_GADGET depends on I2C + select USB_PHY help Say Y here to add support for the NXP ISP1301 USB transceiver driver. This chip is typically used as USB transceiver for USB host, gadget @@ -158,6 +170,7 @@ config USB_ISP1301 config USB_MSM_OTG tristate "OTG support for Qualcomm on-chip USB controller" depends on (USB || USB_GADGET) && ARCH_MSM + select USB_PHY help Enable this to support the USB OTG transceiver on MSM chips. It handles PHY initialization, clock management, and workarounds @@ -171,6 +184,7 @@ config USB_MV_OTG tristate "Marvell USB OTG support" depends on USB_EHCI_MV && USB_MV_UDC && PM_RUNTIME select USB_OTG + select USB_PHY help Say Y here if you want to build Marvell USB OTG transciever driver in kernel (including PXA and MMP series). This driver @@ -182,6 +196,7 @@ config USB_MXS_PHY tristate "Freescale MXS USB PHY support" depends on ARCH_MXC || ARCH_MXS select STMP_DEVICE + select USB_PHY help Enable this to support the Freescale MXS USB PHY. @@ -190,6 +205,7 @@ config USB_MXS_PHY config USB_RCAR_PHY tristate "Renesas R-Car USB PHY support" depends on USB || USB_GADGET + select USB_PHY help Say Y here to add support for the Renesas R-Car USB common PHY driver. This chip is typically used as USB PHY for USB host, gadget. @@ -212,4 +228,4 @@ config USB_ULPI_VIEWPORT Provides read/write operations to the ULPI phy register set for controllers with a viewport register (e.g. Chipidea/ARC controllers). -endif # USB_PHY +endmenu diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index 98730ca1d5d3..2135e85f46ed 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -11,8 +11,10 @@ phy-fsl-usb2-objs := phy-fsl-usb.o phy-fsm-usb.o obj-$(CONFIG_FSL_USB2_OTG) += phy-fsl-usb2.o obj-$(CONFIG_ISP1301_OMAP) += phy-isp1301-omap.o obj-$(CONFIG_MV_U3D_PHY) += phy-mv-u3d-usb.o -obj-$(CONFIG_NOP_USB_XCEIV) += phy-nop.o +obj-$(CONFIG_NOP_USB_XCEIV) += phy-generic.o obj-$(CONFIG_OMAP_CONTROL_USB) += phy-omap-control.o +obj-$(CONFIG_AM335X_CONTROL_USB) += phy-am335x-control.o +obj-$(CONFIG_AM335X_PHY_USB) += phy-am335x.o obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o obj-$(CONFIG_OMAP_USB3) += phy-omap-usb3.o obj-$(CONFIG_SAMSUNG_USBPHY) += phy-samsung-usb.o diff --git a/drivers/usb/phy/am35x-phy-control.h b/drivers/usb/phy/am35x-phy-control.h new file mode 100644 index 000000000000..b96594d1962c --- /dev/null +++ b/drivers/usb/phy/am35x-phy-control.h @@ -0,0 +1,21 @@ +#ifndef _AM335x_PHY_CONTROL_H_ +#define _AM335x_PHY_CONTROL_H_ + +struct phy_control { + void (*phy_power)(struct phy_control *phy_ctrl, u32 id, bool on); + void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on); +}; + +static inline void phy_ctrl_power(struct phy_control *phy_ctrl, u32 id, bool on) +{ + phy_ctrl->phy_power(phy_ctrl, id, on); +} + +static inline void phy_ctrl_wkup(struct phy_control *phy_ctrl, u32 id, bool on) +{ + phy_ctrl->phy_wkup(phy_ctrl, id, on); +} + +struct phy_control *am335x_get_phy_control(struct device *dev); + +#endif diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c new file mode 100644 index 000000000000..759754521426 --- /dev/null +++ b/drivers/usb/phy/phy-am335x-control.c @@ -0,0 +1,137 @@ +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/err.h> +#include <linux/of.h> +#include <linux/io.h> + +struct phy_control { + void (*phy_power)(struct phy_control *phy_ctrl, u32 id, bool on); + void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on); +}; + +struct am335x_control_usb { + struct device *dev; + void __iomem *phy_reg; + void __iomem *wkup; + spinlock_t lock; + struct phy_control phy_ctrl; +}; + +#define AM335X_USB0_CTRL 0x0 +#define AM335X_USB1_CTRL 0x8 +#define AM335x_USB_WKUP 0x0 + +#define USBPHY_CM_PWRDN (1 << 0) +#define USBPHY_OTG_PWRDN (1 << 1) +#define USBPHY_OTGVDET_EN (1 << 19) +#define USBPHY_OTGSESSEND_EN (1 << 20) + +static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, bool on) +{ + struct am335x_control_usb *usb_ctrl; + u32 val; + u32 reg; + + usb_ctrl = container_of(phy_ctrl, struct am335x_control_usb, phy_ctrl); + + switch (id) { + case 0: + reg = AM335X_USB0_CTRL; + break; + case 1: + reg = AM335X_USB1_CTRL; + break; + default: + __WARN(); + return; + } + + val = readl(usb_ctrl->phy_reg + reg); + if (on) { + val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN); + val |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN; + } else { + val |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN; + } + + writel(val, usb_ctrl->phy_reg + reg); +} + +static const struct phy_control ctrl_am335x = { + .phy_power = am335x_phy_power, +}; + +static const struct of_device_id omap_control_usb_id_table[] = { + { .compatible = "ti,am335x-usb-ctrl-module", .data = &ctrl_am335x }, + {} +}; +MODULE_DEVICE_TABLE(of, omap_control_usb_id_table); + +static struct platform_driver am335x_control_driver; +static int match(struct device *dev, void *data) +{ + struct device_node *node = (struct device_node *)data; + return dev->of_node == node && + dev->driver == &am335x_control_driver.driver; +} + +struct phy_control *am335x_get_phy_control(struct device *dev) +{ + struct device_node *node; + struct am335x_control_usb *ctrl_usb; + + node = of_parse_phandle(dev->of_node, "ti,ctrl_mod", 0); + if (!node) + return NULL; + + dev = bus_find_device(&platform_bus_type, NULL, node, match); + ctrl_usb = dev_get_drvdata(dev); + if (!ctrl_usb) + return NULL; + return &ctrl_usb->phy_ctrl; +} +EXPORT_SYMBOL_GPL(am335x_get_phy_control); + +static int am335x_control_usb_probe(struct platform_device *pdev) +{ + struct resource *res; + struct am335x_control_usb *ctrl_usb; + const struct of_device_id *of_id; + const struct phy_control *phy_ctrl; + + of_id = of_match_node(omap_control_usb_id_table, pdev->dev.of_node); + if (!of_id) + return -EINVAL; + + phy_ctrl = of_id->data; + + ctrl_usb = devm_kzalloc(&pdev->dev, sizeof(*ctrl_usb), GFP_KERNEL); + if (!ctrl_usb) { + dev_err(&pdev->dev, "unable to alloc memory for control usb\n"); + return -ENOMEM; + } + + ctrl_usb->dev = &pdev->dev; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl"); + ctrl_usb->phy_reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ctrl_usb->phy_reg)) + return PTR_ERR(ctrl_usb->phy_reg); + spin_lock_init(&ctrl_usb->lock); + ctrl_usb->phy_ctrl = *phy_ctrl; + + dev_set_drvdata(ctrl_usb->dev, ctrl_usb); + return 0; +} + +static struct platform_driver am335x_control_driver = { + .probe = am335x_control_usb_probe, + .driver = { + .name = "am335x-control-usb", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(omap_control_usb_id_table), + }, +}; + +module_platform_driver(am335x_control_driver); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c new file mode 100644 index 000000000000..c4d614d1f173 --- /dev/null +++ b/drivers/usb/phy/phy-am335x.c @@ -0,0 +1,99 @@ +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/usb/otg.h> +#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/regulator/consumer.h> +#include <linux/of.h> +#include <linux/of_address.h> + +#include "am35x-phy-control.h" +#include "phy-generic.h" + +struct am335x_phy { + struct usb_phy_gen_xceiv usb_phy_gen; + struct phy_control *phy_ctrl; + int id; +}; + +static int am335x_init(struct usb_phy *phy) +{ + struct am335x_phy *am_phy = dev_get_drvdata(phy->dev); + + phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, true); + return 0; +} + +static void am335x_shutdown(struct usb_phy *phy) +{ + struct am335x_phy *am_phy = dev_get_drvdata(phy->dev); + + phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false); +} + +static int am335x_phy_probe(struct platform_device *pdev) +{ + struct am335x_phy *am_phy; + struct device *dev = &pdev->dev; + int ret; + + am_phy = devm_kzalloc(dev, sizeof(*am_phy), GFP_KERNEL); + if (!am_phy) + return -ENOMEM; + + am_phy->phy_ctrl = am335x_get_phy_control(dev); + if (!am_phy->phy_ctrl) + return -EPROBE_DEFER; + am_phy->id = of_alias_get_id(pdev->dev.of_node, "phy"); + if (am_phy->id < 0) { + dev_err(&pdev->dev, "Missing PHY id: %d\n", am_phy->id); + return am_phy->id; + } + + ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen, + USB_PHY_TYPE_USB2, 0, false, false); + if (ret) + return ret; + + ret = usb_add_phy_dev(&am_phy->usb_phy_gen.phy); + if (ret) + goto err_add; + am_phy->usb_phy_gen.phy.init = am335x_init; + am_phy->usb_phy_gen.phy.shutdown = am335x_shutdown; + + platform_set_drvdata(pdev, am_phy); + return 0; + +err_add: + usb_phy_gen_cleanup_phy(&am_phy->usb_phy_gen); + return ret; +} + +static int am335x_phy_remove(struct platform_device *pdev) +{ + struct am335x_phy *am_phy = platform_get_drvdata(pdev); + + usb_remove_phy(&am_phy->usb_phy_gen.phy); + return 0; +} + +static const struct of_device_id am335x_phy_ids[] = { + { .compatible = "ti,am335x-usb-phy" }, + { } +}; +MODULE_DEVICE_TABLE(of, am335x_phy_ids); + +static struct platform_driver am335x_phy_driver = { + .probe = am335x_phy_probe, + .remove = am335x_phy_remove, + .driver = { + .name = "am335x-phy-driver", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(am335x_phy_ids), + }, +}; + +module_platform_driver(am335x_phy_driver); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index 181bfb10a57a..fa7c9f9628b5 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -834,7 +834,7 @@ int usb_otg_start(struct platform_device *pdev) int status; struct resource *res; u32 temp; - struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); p_otg = container_of(otg_trans, struct fsl_otg, phy); fsm = &p_otg->fsm; @@ -1105,7 +1105,7 @@ static int fsl_otg_probe(struct platform_device *pdev) { int ret; - if (!pdev->dev.platform_data) + if (!dev_get_platdata(&pdev->dev)) return -ENODEV; /* configure the OTG */ @@ -1137,7 +1137,7 @@ static int fsl_otg_probe(struct platform_device *pdev) static int fsl_otg_remove(struct platform_device *pdev) { - struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); usb_remove_phy(&fsl_otg_dev->phy); free_irq(fsl_otg_dev->irq, fsl_otg_dev); diff --git a/drivers/usb/phy/phy-nop.c b/drivers/usb/phy/phy-generic.c index 55445e5d72e5..efe59f3f7fda 100644 --- a/drivers/usb/phy/phy-nop.c +++ b/drivers/usb/phy/phy-generic.c @@ -30,19 +30,13 @@ #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/usb/otg.h> -#include <linux/usb/nop-usb-xceiv.h> +#include <linux/usb/usb_phy_gen_xceiv.h> #include <linux/slab.h> #include <linux/clk.h> #include <linux/regulator/consumer.h> #include <linux/of.h> -struct nop_usb_xceiv { - struct usb_phy phy; - struct device *dev; - struct clk *clk; - struct regulator *vcc; - struct regulator *reset; -}; +#include "phy-generic.h" static struct platform_device *pd; @@ -50,9 +44,9 @@ void usb_nop_xceiv_register(void) { if (pd) return; - pd = platform_device_register_simple("nop_usb_xceiv", -1, NULL, 0); + pd = platform_device_register_simple("usb_phy_gen_xceiv", -1, NULL, 0); if (!pd) { - printk(KERN_ERR "Unable to register usb nop transceiver\n"); + pr_err("Unable to register generic usb transceiver\n"); return; } } @@ -70,9 +64,9 @@ static int nop_set_suspend(struct usb_phy *x, int suspend) return 0; } -static int nop_init(struct usb_phy *phy) +int usb_gen_phy_init(struct usb_phy *phy) { - struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev); + struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); if (!IS_ERR(nop->vcc)) { if (regulator_enable(nop->vcc)) @@ -90,10 +84,11 @@ static int nop_init(struct usb_phy *phy) return 0; } +EXPORT_SYMBOL_GPL(usb_gen_phy_init); -static void nop_shutdown(struct usb_phy *phy) +void usb_gen_phy_shutdown(struct usb_phy *phy) { - struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev); + struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); if (!IS_ERR(nop->reset)) { /* Assert RESET */ @@ -109,6 +104,7 @@ static void nop_shutdown(struct usb_phy *phy) dev_err(phy->dev, "Failed to disable power\n"); } } +EXPORT_SYMBOL_GPL(usb_gen_phy_shutdown); static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) { @@ -139,52 +135,27 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host) return 0; } -static int nop_usb_xceiv_probe(struct platform_device *pdev) +int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, + enum usb_phy_type type, u32 clk_rate, bool needs_vcc, + bool needs_reset) { - struct device *dev = &pdev->dev; - struct nop_usb_xceiv_platform_data *pdata = pdev->dev.platform_data; - struct nop_usb_xceiv *nop; - enum usb_phy_type type = USB_PHY_TYPE_USB2; int err; - u32 clk_rate = 0; - bool needs_vcc = false; - bool needs_reset = false; - - nop = devm_kzalloc(&pdev->dev, sizeof(*nop), GFP_KERNEL); - if (!nop) - return -ENOMEM; - nop->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*nop->phy.otg), - GFP_KERNEL); + nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg), + GFP_KERNEL); if (!nop->phy.otg) return -ENOMEM; - if (dev->of_node) { - struct device_node *node = dev->of_node; - - if (of_property_read_u32(node, "clock-frequency", &clk_rate)) - clk_rate = 0; - - needs_vcc = of_property_read_bool(node, "vcc-supply"); - needs_reset = of_property_read_bool(node, "reset-supply"); - - } else if (pdata) { - type = pdata->type; - clk_rate = pdata->clk_rate; - needs_vcc = pdata->needs_vcc; - needs_reset = pdata->needs_reset; - } - - nop->clk = devm_clk_get(&pdev->dev, "main_clk"); + nop->clk = devm_clk_get(dev, "main_clk"); if (IS_ERR(nop->clk)) { - dev_dbg(&pdev->dev, "Can't get phy clock: %ld\n", + dev_dbg(dev, "Can't get phy clock: %ld\n", PTR_ERR(nop->clk)); } if (!IS_ERR(nop->clk) && clk_rate) { err = clk_set_rate(nop->clk, clk_rate); if (err) { - dev_err(&pdev->dev, "Error setting clock rate\n"); + dev_err(dev, "Error setting clock rate\n"); return err; } } @@ -192,33 +163,31 @@ static int nop_usb_xceiv_probe(struct platform_device *pdev) if (!IS_ERR(nop->clk)) { err = clk_prepare(nop->clk); if (err) { - dev_err(&pdev->dev, "Error preparing clock\n"); + dev_err(dev, "Error preparing clock\n"); return err; } } - nop->vcc = devm_regulator_get(&pdev->dev, "vcc"); + nop->vcc = devm_regulator_get(dev, "vcc"); if (IS_ERR(nop->vcc)) { - dev_dbg(&pdev->dev, "Error getting vcc regulator: %ld\n", + dev_dbg(dev, "Error getting vcc regulator: %ld\n", PTR_ERR(nop->vcc)); if (needs_vcc) return -EPROBE_DEFER; } - nop->reset = devm_regulator_get(&pdev->dev, "reset"); + nop->reset = devm_regulator_get(dev, "reset"); if (IS_ERR(nop->reset)) { - dev_dbg(&pdev->dev, "Error getting reset regulator: %ld\n", + dev_dbg(dev, "Error getting reset regulator: %ld\n", PTR_ERR(nop->reset)); if (needs_reset) return -EPROBE_DEFER; } - nop->dev = &pdev->dev; + nop->dev = dev; nop->phy.dev = nop->dev; nop->phy.label = "nop-xceiv"; nop->phy.set_suspend = nop_set_suspend; - nop->phy.init = nop_init; - nop->phy.shutdown = nop_shutdown; nop->phy.state = OTG_STATE_UNDEFINED; nop->phy.type = type; @@ -226,6 +195,59 @@ static int nop_usb_xceiv_probe(struct platform_device *pdev) nop->phy.otg->set_host = nop_set_host; nop->phy.otg->set_peripheral = nop_set_peripheral; + ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier); + return 0; +} +EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy); + +void usb_phy_gen_cleanup_phy(struct usb_phy_gen_xceiv *nop) +{ + if (!IS_ERR(nop->clk)) + clk_unprepare(nop->clk); +} +EXPORT_SYMBOL_GPL(usb_phy_gen_cleanup_phy); + +static int usb_phy_gen_xceiv_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct usb_phy_gen_xceiv_platform_data *pdata = + dev_get_platdata(&pdev->dev); + struct usb_phy_gen_xceiv *nop; + enum usb_phy_type type = USB_PHY_TYPE_USB2; + int err; + u32 clk_rate = 0; + bool needs_vcc = false; + bool needs_reset = false; + + if (dev->of_node) { + struct device_node *node = dev->of_node; + + if (of_property_read_u32(node, "clock-frequency", &clk_rate)) + clk_rate = 0; + + needs_vcc = of_property_read_bool(node, "vcc-supply"); + needs_reset = of_property_read_bool(node, "reset-supply"); + + } else if (pdata) { + type = pdata->type; + clk_rate = pdata->clk_rate; + needs_vcc = pdata->needs_vcc; + needs_reset = pdata->needs_reset; + } + + nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL); + if (!nop) + return -ENOMEM; + + + err = usb_phy_gen_create_phy(dev, nop, type, clk_rate, needs_vcc, + needs_reset); + if (err) + return err; + + nop->phy.init = usb_gen_phy_init; + nop->phy.shutdown = usb_gen_phy_shutdown; + err = usb_add_phy_dev(&nop->phy); if (err) { dev_err(&pdev->dev, "can't register transceiver, err: %d\n", @@ -235,23 +257,18 @@ static int nop_usb_xceiv_probe(struct platform_device *pdev) platform_set_drvdata(pdev, nop); - ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier); - return 0; err_add: - if (!IS_ERR(nop->clk)) - clk_unprepare(nop->clk); + usb_phy_gen_cleanup_phy(nop); return err; } -static int nop_usb_xceiv_remove(struct platform_device *pdev) +static int usb_phy_gen_xceiv_remove(struct platform_device *pdev) { - struct nop_usb_xceiv *nop = platform_get_drvdata(pdev); - - if (!IS_ERR(nop->clk)) - clk_unprepare(nop->clk); + struct usb_phy_gen_xceiv *nop = platform_get_drvdata(pdev); + usb_phy_gen_cleanup_phy(nop); usb_remove_phy(&nop->phy); return 0; @@ -264,29 +281,29 @@ static const struct of_device_id nop_xceiv_dt_ids[] = { MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids); -static struct platform_driver nop_usb_xceiv_driver = { - .probe = nop_usb_xceiv_probe, - .remove = nop_usb_xceiv_remove, +static struct platform_driver usb_phy_gen_xceiv_driver = { + .probe = usb_phy_gen_xceiv_probe, + .remove = usb_phy_gen_xceiv_remove, .driver = { - .name = "nop_usb_xceiv", + .name = "usb_phy_gen_xceiv", .owner = THIS_MODULE, .of_match_table = nop_xceiv_dt_ids, }, }; -static int __init nop_usb_xceiv_init(void) +static int __init usb_phy_gen_xceiv_init(void) { - return platform_driver_register(&nop_usb_xceiv_driver); + return platform_driver_register(&usb_phy_gen_xceiv_driver); } -subsys_initcall(nop_usb_xceiv_init); +subsys_initcall(usb_phy_gen_xceiv_init); -static void __exit nop_usb_xceiv_exit(void) +static void __exit usb_phy_gen_xceiv_exit(void) { - platform_driver_unregister(&nop_usb_xceiv_driver); + platform_driver_unregister(&usb_phy_gen_xceiv_driver); } -module_exit(nop_usb_xceiv_exit); +module_exit(usb_phy_gen_xceiv_exit); -MODULE_ALIAS("platform:nop_usb_xceiv"); +MODULE_ALIAS("platform:usb_phy_gen_xceiv"); MODULE_AUTHOR("Texas Instruments Inc"); MODULE_DESCRIPTION("NOP USB Transceiver driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/phy/phy-generic.h b/drivers/usb/phy/phy-generic.h new file mode 100644 index 000000000000..61687d5a965b --- /dev/null +++ b/drivers/usb/phy/phy-generic.h @@ -0,0 +1,20 @@ +#ifndef _PHY_GENERIC_H_ +#define _PHY_GENERIC_H_ + +struct usb_phy_gen_xceiv { + struct usb_phy phy; + struct device *dev; + struct clk *clk; + struct regulator *vcc; + struct regulator *reset; +}; + +int usb_gen_phy_init(struct usb_phy *phy); +void usb_gen_phy_shutdown(struct usb_phy *phy); + +int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, + enum usb_phy_type type, u32 clk_rate, bool needs_vcc, + bool needs_reset); +void usb_phy_gen_cleanup_phy(struct usb_phy_gen_xceiv *nop); + +#endif diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c index 8443335c2ea0..b2f29c9aebbf 100644 --- a/drivers/usb/phy/phy-gpio-vbus-usb.c +++ b/drivers/usb/phy/phy-gpio-vbus-usb.c @@ -101,7 +101,7 @@ static void gpio_vbus_work(struct work_struct *work) { struct gpio_vbus_data *gpio_vbus = container_of(work, struct gpio_vbus_data, work.work); - struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data; + struct gpio_vbus_mach_info *pdata = dev_get_platdata(gpio_vbus->dev); int gpio, status, vbus; if (!gpio_vbus->phy.otg->gadget) @@ -155,7 +155,7 @@ static void gpio_vbus_work(struct work_struct *work) static irqreturn_t gpio_vbus_irq(int irq, void *data) { struct platform_device *pdev = data; - struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data; + struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev); struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev); struct usb_otg *otg = gpio_vbus->phy.otg; @@ -182,7 +182,7 @@ static int gpio_vbus_set_peripheral(struct usb_otg *otg, gpio_vbus = container_of(otg->phy, struct gpio_vbus_data, phy); pdev = to_platform_device(gpio_vbus->dev); - pdata = gpio_vbus->dev->platform_data; + pdata = dev_get_platdata(gpio_vbus->dev); gpio = pdata->gpio_pullup; if (!gadget) { @@ -243,7 +243,7 @@ static int gpio_vbus_set_suspend(struct usb_phy *phy, int suspend) static int __init gpio_vbus_probe(struct platform_device *pdev) { - struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data; + struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev); struct gpio_vbus_data *gpio_vbus; struct resource *res; int err, gpio, irq; @@ -352,7 +352,7 @@ err_gpio: static int __exit gpio_vbus_remove(struct platform_device *pdev) { struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev); - struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data; + struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev); int gpio = pdata->gpio_vbus; device_init_wakeup(&pdev->dev, 0); diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index d08f33435e96..e9d4cd960ecd 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1419,7 +1419,7 @@ static int __init msm_otg_probe(struct platform_device *pdev) struct usb_phy *phy; dev_info(&pdev->dev, "msm_otg probe\n"); - if (!pdev->dev.platform_data) { + if (!dev_get_platdata(&pdev->dev)) { dev_err(&pdev->dev, "No platform data given. Bailing out\n"); return -ENODEV; } @@ -1436,7 +1436,7 @@ static int __init msm_otg_probe(struct platform_device *pdev) return -ENOMEM; } - motg->pdata = pdev->dev.platform_data; + motg->pdata = dev_get_platdata(&pdev->dev); phy = &motg->phy; phy->dev = &pdev->dev; diff --git a/drivers/usb/phy/phy-mv-u3d-usb.c b/drivers/usb/phy/phy-mv-u3d-usb.c index 1568ea63e338..d317903022bf 100644 --- a/drivers/usb/phy/phy-mv-u3d-usb.c +++ b/drivers/usb/phy/phy-mv-u3d-usb.c @@ -82,7 +82,7 @@ static void mv_u3d_phy_write(void __iomem *base, u32 reg, u32 value) writel_relaxed(value, data); } -void mv_u3d_phy_shutdown(struct usb_phy *phy) +static void mv_u3d_phy_shutdown(struct usb_phy *phy) { struct mv_u3d_phy *mv_u3d_phy; void __iomem *base; @@ -271,7 +271,7 @@ static int mv_u3d_phy_probe(struct platform_device *pdev) void __iomem *phy_base; int ret; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(&pdev->dev, "%s: no platform data defined\n", __func__); return -EINVAL; diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c index 4a6b03c73876..98f6ac6a78ea 100644 --- a/drivers/usb/phy/phy-mv-usb.c +++ b/drivers/usb/phy/phy-mv-usb.c @@ -653,7 +653,7 @@ static struct attribute_group inputs_attr_group = { .attrs = inputs_attrs, }; -int mv_otg_remove(struct platform_device *pdev) +static int mv_otg_remove(struct platform_device *pdev) { struct mv_otg *mvotg = platform_get_drvdata(pdev); @@ -673,7 +673,7 @@ int mv_otg_remove(struct platform_device *pdev) static int mv_otg_probe(struct platform_device *pdev) { - struct mv_usb_platform_data *pdata = pdev->dev.platform_data; + struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); struct mv_otg *mvotg; struct usb_otg *otg; struct resource *r; @@ -893,7 +893,7 @@ static int mv_otg_resume(struct platform_device *pdev) static struct platform_driver mv_otg_driver = { .probe = mv_otg_probe, - .remove = __exit_p(mv_otg_remove), + .remove = mv_otg_remove, .driver = { .owner = THIS_MODULE, .name = driver_name, diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index bd601c537c8d..fdd33b44dbd3 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -41,11 +41,14 @@ struct mxs_phy { #define to_mxs_phy(p) container_of((p), struct mxs_phy, phy) -static void mxs_phy_hw_init(struct mxs_phy *mxs_phy) +static int mxs_phy_hw_init(struct mxs_phy *mxs_phy) { + int ret; void __iomem *base = mxs_phy->phy.io_priv; - stmp_reset_block(base + HW_USBPHY_CTRL); + ret = stmp_reset_block(base + HW_USBPHY_CTRL); + if (ret) + return ret; /* Power up the PHY */ writel(0, base + HW_USBPHY_PWD); @@ -54,6 +57,8 @@ static void mxs_phy_hw_init(struct mxs_phy *mxs_phy) writel(BM_USBPHY_CTRL_ENUTMILEVEL2 | BM_USBPHY_CTRL_ENUTMILEVEL3, base + HW_USBPHY_CTRL_SET); + + return 0; } static int mxs_phy_init(struct usb_phy *phy) @@ -61,9 +66,7 @@ static int mxs_phy_init(struct usb_phy *phy) struct mxs_phy *mxs_phy = to_mxs_phy(phy); clk_prepare_enable(mxs_phy->clk); - mxs_phy_hw_init(mxs_phy); - - return 0; + return mxs_phy_hw_init(mxs_phy); } static void mxs_phy_shutdown(struct usb_phy *phy) diff --git a/drivers/usb/phy/phy-omap-control.c b/drivers/usb/phy/phy-omap-control.c index 1419ceda9759..a4dda8e12562 100644 --- a/drivers/usb/phy/phy-omap-control.c +++ b/drivers/usb/phy/phy-omap-control.c @@ -197,7 +197,8 @@ static int omap_control_usb_probe(struct platform_device *pdev) { struct resource *res; struct device_node *np = pdev->dev.of_node; - struct omap_control_usb_platform_data *pdata = pdev->dev.platform_data; + struct omap_control_usb_platform_data *pdata = + dev_get_platdata(&pdev->dev); control_usb = devm_kzalloc(&pdev->dev, sizeof(*control_usb), GFP_KERNEL); diff --git a/drivers/usb/phy/phy-omap-usb3.c b/drivers/usb/phy/phy-omap-usb3.c index a2fb30bbb971..fc15694d3031 100644 --- a/drivers/usb/phy/phy-omap-usb3.c +++ b/drivers/usb/phy/phy-omap-usb3.c @@ -27,7 +27,6 @@ #include <linux/delay.h> #include <linux/usb/omap_control_usb.h> -#define NUM_SYS_CLKS 6 #define PLL_STATUS 0x00000004 #define PLL_GO 0x00000008 #define PLL_CONFIGURATION1 0x0000000C @@ -57,26 +56,32 @@ */ # define PLL_IDLE_TIME 100; -enum sys_clk_rate { - CLK_RATE_UNDEFINED = -1, - CLK_RATE_12MHZ, - CLK_RATE_16MHZ, - CLK_RATE_19MHZ, - CLK_RATE_20MHZ, - CLK_RATE_26MHZ, - CLK_RATE_38MHZ +struct usb_dpll_map { + unsigned long rate; + struct usb_dpll_params params; }; -static struct usb_dpll_params omap_usb3_dpll_params[NUM_SYS_CLKS] = { - {1250, 5, 4, 20, 0}, /* 12 MHz */ - {3125, 20, 4, 20, 0}, /* 16.8 MHz */ - {1172, 8, 4, 20, 65537}, /* 19.2 MHz */ - {1000, 7, 4, 10, 0}, /* 20 MHz */ - {1250, 12, 4, 20, 0}, /* 26 MHz */ - {3125, 47, 4, 20, 92843}, /* 38.4 MHz */ - +static struct usb_dpll_map dpll_map[] = { + {12000000, {1250, 5, 4, 20, 0} }, /* 12 MHz */ + {16800000, {3125, 20, 4, 20, 0} }, /* 16.8 MHz */ + {19200000, {1172, 8, 4, 20, 65537} }, /* 19.2 MHz */ + {20000000, {1000, 7, 4, 10, 0} }, /* 20 MHz */ + {26000000, {1250, 12, 4, 20, 0} }, /* 26 MHz */ + {38400000, {3125, 47, 4, 20, 92843} }, /* 38.4 MHz */ }; +static struct usb_dpll_params *omap_usb3_get_dpll_params(unsigned long rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dpll_map); i++) { + if (rate == dpll_map[i].rate) + return &dpll_map[i].params; + } + + return 0; +} + static int omap_usb3_suspend(struct usb_phy *x, int suspend) { struct omap_usb *phy = phy_to_omapusb(x); @@ -116,26 +121,6 @@ static int omap_usb3_suspend(struct usb_phy *x, int suspend) return 0; } -static inline enum sys_clk_rate __get_sys_clk_index(unsigned long rate) -{ - switch (rate) { - case 12000000: - return CLK_RATE_12MHZ; - case 16800000: - return CLK_RATE_16MHZ; - case 19200000: - return CLK_RATE_19MHZ; - case 20000000: - return CLK_RATE_20MHZ; - case 26000000: - return CLK_RATE_26MHZ; - case 38400000: - return CLK_RATE_38MHZ; - default: - return CLK_RATE_UNDEFINED; - } -} - static void omap_usb_dpll_relock(struct omap_usb *phy) { u32 val; @@ -155,39 +140,39 @@ static int omap_usb_dpll_lock(struct omap_usb *phy) { u32 val; unsigned long rate; - enum sys_clk_rate clk_index; - - rate = clk_get_rate(phy->sys_clk); - clk_index = __get_sys_clk_index(rate); + struct usb_dpll_params *dpll_params; - if (clk_index == CLK_RATE_UNDEFINED) { - pr_err("dpll cannot be locked for sys clk freq:%luHz\n", rate); + rate = clk_get_rate(phy->sys_clk); + dpll_params = omap_usb3_get_dpll_params(rate); + if (!dpll_params) { + dev_err(phy->dev, + "No DPLL configuration for %lu Hz SYS CLK\n", rate); return -EINVAL; } val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1); val &= ~PLL_REGN_MASK; - val |= omap_usb3_dpll_params[clk_index].n << PLL_REGN_SHIFT; + val |= dpll_params->n << PLL_REGN_SHIFT; omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val); val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); val &= ~PLL_SELFREQDCO_MASK; - val |= omap_usb3_dpll_params[clk_index].freq << PLL_SELFREQDCO_SHIFT; + val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT; omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1); val &= ~PLL_REGM_MASK; - val |= omap_usb3_dpll_params[clk_index].m << PLL_REGM_SHIFT; + val |= dpll_params->m << PLL_REGM_SHIFT; omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val); val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4); val &= ~PLL_REGM_F_MASK; - val |= omap_usb3_dpll_params[clk_index].mf << PLL_REGM_F_SHIFT; + val |= dpll_params->mf << PLL_REGM_F_SHIFT; omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val); val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3); val &= ~PLL_SD_MASK; - val |= omap_usb3_dpll_params[clk_index].sd << PLL_SD_SHIFT; + val |= dpll_params->sd << PLL_SD_SHIFT; omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val); omap_usb_dpll_relock(phy); @@ -198,8 +183,12 @@ static int omap_usb_dpll_lock(struct omap_usb *phy) static int omap_usb3_init(struct usb_phy *x) { struct omap_usb *phy = phy_to_omapusb(x); + int ret; + + ret = omap_usb_dpll_lock(phy); + if (ret) + return ret; - omap_usb_dpll_lock(phy); omap_control_usb3_phy_power(phy->control_dev, 1); return 0; diff --git a/drivers/usb/phy/phy-rcar-usb.c b/drivers/usb/phy/phy-rcar-usb.c index ae909408958d..33265a5b2cdf 100644 --- a/drivers/usb/phy/phy-rcar-usb.c +++ b/drivers/usb/phy/phy-rcar-usb.c @@ -83,7 +83,7 @@ static int rcar_usb_phy_init(struct usb_phy *phy) { struct rcar_usb_phy_priv *priv = usb_phy_to_priv(phy); struct device *dev = phy->dev; - struct rcar_phy_platform_data *pdata = dev->platform_data; + struct rcar_phy_platform_data *pdata = dev_get_platdata(dev); void __iomem *reg0 = priv->reg0; void __iomem *reg1 = priv->reg1; static const u8 ovcn_act[] = { OVC0_ACT, OVC1_ACT, OVC2_ACT }; @@ -184,17 +184,12 @@ static int rcar_usb_phy_probe(struct platform_device *pdev) void __iomem *reg0, *reg1 = NULL; int ret; - if (!pdev->dev.platform_data) { + if (!dev_get_platdata(&pdev->dev)) { dev_err(dev, "No platform data\n"); return -EINVAL; } res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res0) { - dev_err(dev, "Not enough platform resources\n"); - return -EINVAL; - } - reg0 = devm_ioremap_resource(dev, res0); if (IS_ERR(reg0)) return PTR_ERR(reg0); diff --git a/drivers/usb/phy/phy-samsung-usb2.c b/drivers/usb/phy/phy-samsung-usb2.c index 758b86d0fcb3..ff70e4b19b97 100644 --- a/drivers/usb/phy/phy-samsung-usb2.c +++ b/drivers/usb/phy/phy-samsung-usb2.c @@ -359,7 +359,7 @@ static int samsung_usb2phy_probe(struct platform_device *pdev) { struct samsung_usbphy *sphy; struct usb_otg *otg; - struct samsung_usbphy_data *pdata = pdev->dev.platform_data; + struct samsung_usbphy_data *pdata = dev_get_platdata(&pdev->dev); const struct samsung_usbphy_drvdata *drv_data; struct device *dev = &pdev->dev; struct resource *phy_mem; diff --git a/drivers/usb/phy/phy-samsung-usb3.c b/drivers/usb/phy/phy-samsung-usb3.c index 300e0cf5e31f..c6eb22213de6 100644 --- a/drivers/usb/phy/phy-samsung-usb3.c +++ b/drivers/usb/phy/phy-samsung-usb3.c @@ -231,7 +231,7 @@ static void samsung_usb3phy_shutdown(struct usb_phy *phy) static int samsung_usb3phy_probe(struct platform_device *pdev) { struct samsung_usbphy *sphy; - struct samsung_usbphy_data *pdata = pdev->dev.platform_data; + struct samsung_usbphy_data *pdata = dev_get_platdata(&pdev->dev); struct device *dev = &pdev->dev; struct resource *phy_mem; void __iomem *phy_base; diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index cec0855ed248..3bfb3d1957c1 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -28,20 +28,28 @@ #include <linux/io.h> #include <linux/gpio.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/of_gpio.h> #include <linux/usb/otg.h> #include <linux/usb/ulpi.h> +#include <linux/usb/of.h> #include <asm/mach-types.h> #include <linux/usb/ehci_def.h> #include <linux/usb/tegra_usb_phy.h> +#include <linux/regulator/consumer.h> #define ULPI_VIEWPORT 0x170 -/* PORTSC registers */ +/* PORTSC PTS/PHCD bits, Tegra20 only */ #define TEGRA_USB_PORTSC1 0x184 #define TEGRA_USB_PORTSC1_PTS(x) (((x) & 0x3) << 30) #define TEGRA_USB_PORTSC1_PHCD (1 << 23) +/* HOSTPC1 PTS/PHCD bits, Tegra30 and above */ +#define TEGRA_USB_HOSTPC1_DEVLC 0x1b4 +#define TEGRA_USB_HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29) +#define TEGRA_USB_HOSTPC1_DEVLC_PHCD (1 << 22) + /* Bits of PORTSC1, which will get cleared by writing 1 into them */ #define TEGRA_PORTSC1_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC) @@ -84,16 +92,22 @@ #define UTMIP_XCVR_CFG0 0x808 #define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0) +#define UTMIP_XCVR_SETUP_MSB(x) ((((x) & 0x70) >> 4) << 22) #define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8) #define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10) #define UTMIP_FORCE_PD_POWERDOWN (1 << 14) #define UTMIP_FORCE_PD2_POWERDOWN (1 << 16) #define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18) -#define UTMIP_XCVR_HSSLEW_MSB(x) (((x) & 0x7f) << 25) +#define UTMIP_XCVR_LSBIAS_SEL (1 << 21) +#define UTMIP_XCVR_HSSLEW(x) (((x) & 0x3) << 4) +#define UTMIP_XCVR_HSSLEW_MSB(x) ((((x) & 0x1fc) >> 2) << 25) #define UTMIP_BIAS_CFG0 0x80c #define UTMIP_OTGPD (1 << 11) #define UTMIP_BIASPD (1 << 10) +#define UTMIP_HSSQUELCH_LEVEL(x) (((x) & 0x3) << 0) +#define UTMIP_HSDISCON_LEVEL(x) (((x) & 0x3) << 2) +#define UTMIP_HSDISCON_LEVEL_MSB(x) ((((x) & 0x4) >> 2) << 24) #define UTMIP_HSRX_CFG0 0x810 #define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10) @@ -137,6 +151,12 @@ #define UTMIP_BIAS_CFG1 0x83c #define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3) +/* For Tegra30 and above only, the address is different in Tegra20 */ +#define USB_USBMODE 0x1f8 +#define USB_USBMODE_MASK (3 << 0) +#define USB_USBMODE_HOST (3 << 0) +#define USB_USBMODE_DEVICE (2 << 0) + static DEFINE_SPINLOCK(utmip_pad_lock); static int utmip_pad_count; @@ -184,36 +204,22 @@ static const struct tegra_xtal_freq tegra_freq_table[] = { }, }; -static struct tegra_utmip_config utmip_default[] = { - [0] = { - .hssync_start_delay = 9, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 9, - .xcvr_lsfslew = 1, - .xcvr_lsrslew = 1, - }, - [2] = { - .hssync_start_delay = 9, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 9, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, -}; - static void set_pts(struct tegra_usb_phy *phy, u8 pts_val) { void __iomem *base = phy->regs; unsigned long val; - val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS; - val &= ~TEGRA_USB_PORTSC1_PTS(3); - val |= TEGRA_USB_PORTSC1_PTS(pts_val & 3); - writel(val, base + TEGRA_USB_PORTSC1); + if (phy->soc_config->has_hostpc) { + val = readl(base + TEGRA_USB_HOSTPC1_DEVLC); + val &= ~TEGRA_USB_HOSTPC1_DEVLC_PTS(~0); + val |= TEGRA_USB_HOSTPC1_DEVLC_PTS(pts_val); + writel(val, base + TEGRA_USB_HOSTPC1_DEVLC); + } else { + val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS; + val &= ~TEGRA_USB_PORTSC1_PTS(~0); + val |= TEGRA_USB_PORTSC1_PTS(pts_val); + writel(val, base + TEGRA_USB_PORTSC1); + } } static void set_phcd(struct tegra_usb_phy *phy, bool enable) @@ -221,17 +227,26 @@ static void set_phcd(struct tegra_usb_phy *phy, bool enable) void __iomem *base = phy->regs; unsigned long val; - val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS; - if (enable) - val |= TEGRA_USB_PORTSC1_PHCD; - else - val &= ~TEGRA_USB_PORTSC1_PHCD; - writel(val, base + TEGRA_USB_PORTSC1); + if (phy->soc_config->has_hostpc) { + val = readl(base + TEGRA_USB_HOSTPC1_DEVLC); + if (enable) + val |= TEGRA_USB_HOSTPC1_DEVLC_PHCD; + else + val &= ~TEGRA_USB_HOSTPC1_DEVLC_PHCD; + writel(val, base + TEGRA_USB_HOSTPC1_DEVLC); + } else { + val = readl(base + TEGRA_USB_PORTSC1) & ~PORT_RWC_BITS; + if (enable) + val |= TEGRA_USB_PORTSC1_PHCD; + else + val &= ~TEGRA_USB_PORTSC1_PHCD; + writel(val, base + TEGRA_USB_PORTSC1); + } } static int utmip_pad_open(struct tegra_usb_phy *phy) { - phy->pad_clk = devm_clk_get(phy->dev, "utmi-pads"); + phy->pad_clk = devm_clk_get(phy->u_phy.dev, "utmi-pads"); if (IS_ERR(phy->pad_clk)) { pr_err("%s: can't get utmip pad clock\n", __func__); return PTR_ERR(phy->pad_clk); @@ -244,6 +259,7 @@ static void utmip_pad_power_on(struct tegra_usb_phy *phy) { unsigned long val, flags; void __iomem *base = phy->pad_regs; + struct tegra_utmip_config *config = phy->config; clk_prepare_enable(phy->pad_clk); @@ -252,6 +268,16 @@ static void utmip_pad_power_on(struct tegra_usb_phy *phy) if (utmip_pad_count++ == 0) { val = readl(base + UTMIP_BIAS_CFG0); val &= ~(UTMIP_OTGPD | UTMIP_BIASPD); + + if (phy->soc_config->requires_extra_tuning_parameters) { + val &= ~(UTMIP_HSSQUELCH_LEVEL(~0) | + UTMIP_HSDISCON_LEVEL(~0) | + UTMIP_HSDISCON_LEVEL_MSB(~0)); + + val |= UTMIP_HSSQUELCH_LEVEL(config->hssquelch_level); + val |= UTMIP_HSDISCON_LEVEL(config->hsdiscon_level); + val |= UTMIP_HSDISCON_LEVEL_MSB(config->hsdiscon_level); + } writel(val, base + UTMIP_BIAS_CFG0); } @@ -361,7 +387,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) } val = readl(base + UTMIP_TX_CFG0); - val &= ~UTMIP_FS_PREABMLE_J; + val |= UTMIP_FS_PREABMLE_J; writel(val, base + UTMIP_TX_CFG0); val = readl(base + UTMIP_HSRX_CFG0); @@ -384,34 +410,56 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE; writel(val, base + UTMIP_MISC_CFG0); - val = readl(base + UTMIP_MISC_CFG1); - val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) | UTMIP_PLLU_STABLE_COUNT(~0)); - val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) | - UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count); - writel(val, base + UTMIP_MISC_CFG1); - - val = readl(base + UTMIP_PLL_CFG1); - val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) | UTMIP_PLLU_ENABLE_DLY_COUNT(~0)); - val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) | - UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay); - writel(val, base + UTMIP_PLL_CFG1); + if (!phy->soc_config->utmi_pll_config_in_car_module) { + val = readl(base + UTMIP_MISC_CFG1); + val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) | + UTMIP_PLLU_STABLE_COUNT(~0)); + val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) | + UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count); + writel(val, base + UTMIP_MISC_CFG1); + + val = readl(base + UTMIP_PLL_CFG1); + val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) | + UTMIP_PLLU_ENABLE_DLY_COUNT(~0)); + val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) | + UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay); + writel(val, base + UTMIP_PLL_CFG1); + } - if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) { + if (phy->mode == USB_DR_MODE_PERIPHERAL) { val = readl(base + USB_SUSP_CTRL); val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV); writel(val, base + USB_SUSP_CTRL); + + val = readl(base + UTMIP_BAT_CHRG_CFG0); + val &= ~UTMIP_PD_CHRG; + writel(val, base + UTMIP_BAT_CHRG_CFG0); + } else { + val = readl(base + UTMIP_BAT_CHRG_CFG0); + val |= UTMIP_PD_CHRG; + writel(val, base + UTMIP_BAT_CHRG_CFG0); } utmip_pad_power_on(phy); val = readl(base + UTMIP_XCVR_CFG0); val &= ~(UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN | - UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_SETUP(~0) | - UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0) | - UTMIP_XCVR_HSSLEW_MSB(~0)); - val |= UTMIP_XCVR_SETUP(config->xcvr_setup); + UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_LSBIAS_SEL | + UTMIP_XCVR_SETUP(~0) | UTMIP_XCVR_SETUP_MSB(~0) | + UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0)); + + if (!config->xcvr_setup_use_fuses) { + val |= UTMIP_XCVR_SETUP(config->xcvr_setup); + val |= UTMIP_XCVR_SETUP_MSB(config->xcvr_setup); + } val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew); val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew); + + if (phy->soc_config->requires_extra_tuning_parameters) { + val &= ~(UTMIP_XCVR_HSSLEW(~0) | UTMIP_XCVR_HSSLEW_MSB(~0)); + val |= UTMIP_XCVR_HSSLEW(config->xcvr_hsslew); + val |= UTMIP_XCVR_HSSLEW_MSB(config->xcvr_hsslew); + } writel(val, base + UTMIP_XCVR_CFG0); val = readl(base + UTMIP_XCVR_CFG1); @@ -420,23 +468,19 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj); writel(val, base + UTMIP_XCVR_CFG1); - val = readl(base + UTMIP_BAT_CHRG_CFG0); - val &= ~UTMIP_PD_CHRG; - writel(val, base + UTMIP_BAT_CHRG_CFG0); - val = readl(base + UTMIP_BIAS_CFG1); val &= ~UTMIP_BIAS_PDTRK_COUNT(~0); val |= UTMIP_BIAS_PDTRK_COUNT(0x5); writel(val, base + UTMIP_BIAS_CFG1); - if (phy->is_legacy_phy) { - val = readl(base + UTMIP_SPARE_CFG0); - if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) - val &= ~FUSE_SETUP_SEL; - else - val |= FUSE_SETUP_SEL; - writel(val, base + UTMIP_SPARE_CFG0); - } else { + val = readl(base + UTMIP_SPARE_CFG0); + if (config->xcvr_setup_use_fuses) + val |= FUSE_SETUP_SEL; + else + val &= ~FUSE_SETUP_SEL; + writel(val, base + UTMIP_SPARE_CFG0); + + if (!phy->is_legacy_phy) { val = readl(base + USB_SUSP_CTRL); val |= UTMIP_PHY_ENABLE; writel(val, base + USB_SUSP_CTRL); @@ -459,6 +503,16 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) utmi_phy_clk_enable(phy); + if (phy->soc_config->requires_usbmode_setup) { + val = readl(base + USB_USBMODE); + val &= ~USB_USBMODE_MASK; + if (phy->mode == USB_DR_MODE_HOST) + val |= USB_USBMODE_HOST; + else + val |= USB_USBMODE_DEVICE; + writel(val, base + USB_USBMODE); + } + if (!phy->is_legacy_phy) set_pts(phy, 0); @@ -472,7 +526,7 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy) utmi_phy_clk_disable(phy); - if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) { + if (phy->mode == USB_DR_MODE_PERIPHERAL) { val = readl(base + USB_SUSP_CTRL); val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0); val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5); @@ -560,13 +614,15 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy) ret = gpio_direction_output(phy->reset_gpio, 0); if (ret < 0) { - dev_err(phy->dev, "gpio %d not set to 0\n", phy->reset_gpio); + dev_err(phy->u_phy.dev, "gpio %d not set to 0\n", + phy->reset_gpio); return ret; } msleep(5); ret = gpio_direction_output(phy->reset_gpio, 1); if (ret < 0) { - dev_err(phy->dev, "gpio %d not set to 1\n", phy->reset_gpio); + dev_err(phy->u_phy.dev, "gpio %d not set to 1\n", + phy->reset_gpio); return ret; } @@ -634,6 +690,9 @@ static void tegra_usb_phy_close(struct usb_phy *x) { struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); + if (!IS_ERR(phy->vbus)) + regulator_disable(phy->vbus); + clk_disable_unprepare(phy->pll_u); } @@ -666,29 +725,30 @@ static int ulpi_open(struct tegra_usb_phy *phy) { int err; - phy->clk = devm_clk_get(phy->dev, "ulpi-link"); + phy->clk = devm_clk_get(phy->u_phy.dev, "ulpi-link"); if (IS_ERR(phy->clk)) { pr_err("%s: can't get ulpi clock\n", __func__); return PTR_ERR(phy->clk); } - err = devm_gpio_request(phy->dev, phy->reset_gpio, "ulpi_phy_reset_b"); + err = devm_gpio_request(phy->u_phy.dev, phy->reset_gpio, + "ulpi_phy_reset_b"); if (err < 0) { - dev_err(phy->dev, "request failed for gpio: %d\n", + dev_err(phy->u_phy.dev, "request failed for gpio: %d\n", phy->reset_gpio); return err; } err = gpio_direction_output(phy->reset_gpio, 0); if (err < 0) { - dev_err(phy->dev, "gpio %d direction not set to output\n", + dev_err(phy->u_phy.dev, "gpio %d direction not set to output\n", phy->reset_gpio); return err; } phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0); if (!phy->ulpi) { - dev_err(phy->dev, "otg_ulpi_create returned NULL\n"); + dev_err(phy->u_phy.dev, "otg_ulpi_create returned NULL\n"); err = -ENOMEM; return err; } @@ -703,14 +763,7 @@ static int tegra_usb_phy_init(struct tegra_usb_phy *phy) int i; int err; - if (!phy->is_ulpi_phy) { - if (phy->is_legacy_phy) - phy->config = &utmip_default[0]; - else - phy->config = &utmip_default[2]; - } - - phy->pll_u = devm_clk_get(phy->dev, "pll_u"); + phy->pll_u = devm_clk_get(phy->u_phy.dev, "pll_u"); if (IS_ERR(phy->pll_u)) { pr_err("Can't get pll_u clock\n"); return PTR_ERR(phy->pll_u); @@ -733,6 +786,16 @@ static int tegra_usb_phy_init(struct tegra_usb_phy *phy) goto fail; } + if (!IS_ERR(phy->vbus)) { + err = regulator_enable(phy->vbus); + if (err) { + dev_err(phy->u_phy.dev, + "failed to enable usb vbus regulator: %d\n", + err); + goto fail; + } + } + if (phy->is_ulpi_phy) err = ulpi_open(phy); else @@ -784,11 +847,138 @@ void tegra_ehci_phy_restore_end(struct usb_phy *x) } EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end); +static int read_utmi_param(struct platform_device *pdev, const char *param, + u8 *dest) +{ + u32 value; + int err = of_property_read_u32(pdev->dev.of_node, param, &value); + *dest = (u8)value; + if (err < 0) + dev_err(&pdev->dev, "Failed to read USB UTMI parameter %s: %d\n", + param, err); + return err; +} + +static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy, + struct platform_device *pdev) +{ + struct resource *res; + int err; + struct tegra_utmip_config *config; + + tegra_phy->is_ulpi_phy = false; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) { + dev_err(&pdev->dev, "Failed to get UTMI Pad regs\n"); + return -ENXIO; + } + + tegra_phy->pad_regs = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!tegra_phy->regs) { + dev_err(&pdev->dev, "Failed to remap UTMI Pad regs\n"); + return -ENOMEM; + } + + tegra_phy->config = devm_kzalloc(&pdev->dev, + sizeof(*tegra_phy->config), GFP_KERNEL); + if (!tegra_phy->config) { + dev_err(&pdev->dev, + "unable to allocate memory for USB UTMIP config\n"); + return -ENOMEM; + } + + config = tegra_phy->config; + + err = read_utmi_param(pdev, "nvidia,hssync-start-delay", + &config->hssync_start_delay); + if (err < 0) + return err; + + err = read_utmi_param(pdev, "nvidia,elastic-limit", + &config->elastic_limit); + if (err < 0) + return err; + + err = read_utmi_param(pdev, "nvidia,idle-wait-delay", + &config->idle_wait_delay); + if (err < 0) + return err; + + err = read_utmi_param(pdev, "nvidia,term-range-adj", + &config->term_range_adj); + if (err < 0) + return err; + + err = read_utmi_param(pdev, "nvidia,xcvr-lsfslew", + &config->xcvr_lsfslew); + if (err < 0) + return err; + + err = read_utmi_param(pdev, "nvidia,xcvr-lsrslew", + &config->xcvr_lsrslew); + if (err < 0) + return err; + + if (tegra_phy->soc_config->requires_extra_tuning_parameters) { + err = read_utmi_param(pdev, "nvidia,xcvr-hsslew", + &config->xcvr_hsslew); + if (err < 0) + return err; + + err = read_utmi_param(pdev, "nvidia,hssquelch-level", + &config->hssquelch_level); + if (err < 0) + return err; + + err = read_utmi_param(pdev, "nvidia,hsdiscon-level", + &config->hsdiscon_level); + if (err < 0) + return err; + } + + config->xcvr_setup_use_fuses = of_property_read_bool( + pdev->dev.of_node, "nvidia,xcvr-setup-use-fuses"); + + if (!config->xcvr_setup_use_fuses) { + err = read_utmi_param(pdev, "nvidia,xcvr-setup", + &config->xcvr_setup); + if (err < 0) + return err; + } + + return 0; +} + +static const struct tegra_phy_soc_config tegra20_soc_config = { + .utmi_pll_config_in_car_module = false, + .has_hostpc = false, + .requires_usbmode_setup = false, + .requires_extra_tuning_parameters = false, +}; + +static const struct tegra_phy_soc_config tegra30_soc_config = { + .utmi_pll_config_in_car_module = true, + .has_hostpc = true, + .requires_usbmode_setup = true, + .requires_extra_tuning_parameters = true, +}; + +static struct of_device_id tegra_usb_phy_id_table[] = { + { .compatible = "nvidia,tegra30-usb-phy", .data = &tegra30_soc_config }, + { .compatible = "nvidia,tegra20-usb-phy", .data = &tegra20_soc_config }, + { }, +}; +MODULE_DEVICE_TABLE(of, tegra_usb_phy_id_table); + static int tegra_usb_phy_probe(struct platform_device *pdev) { + const struct of_device_id *match; struct resource *res; struct tegra_usb_phy *tegra_phy = NULL; struct device_node *np = pdev->dev.of_node; + enum usb_phy_interface phy_type; int err; tegra_phy = devm_kzalloc(&pdev->dev, sizeof(*tegra_phy), GFP_KERNEL); @@ -797,6 +987,13 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) return -ENOMEM; } + match = of_match_device(tegra_usb_phy_id_table, &pdev->dev); + if (!match) { + dev_err(&pdev->dev, "Error: No device match found\n"); + return -ENODEV; + } + tegra_phy->soc_config = match->data; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "Failed to get I/O memory\n"); @@ -813,23 +1010,15 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) tegra_phy->is_legacy_phy = of_property_read_bool(np, "nvidia,has-legacy-mode"); - err = of_property_match_string(np, "phy_type", "ulpi"); - if (err < 0) { - tegra_phy->is_ulpi_phy = false; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res) { - dev_err(&pdev->dev, "Failed to get UTMI Pad regs\n"); - return -ENXIO; - } + phy_type = of_usb_get_phy_mode(np); + switch (phy_type) { + case USBPHY_INTERFACE_MODE_UTMI: + err = utmi_phy_probe(tegra_phy, pdev); + if (err < 0) + return err; + break; - tegra_phy->pad_regs = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (!tegra_phy->regs) { - dev_err(&pdev->dev, "Failed to remap UTMI Pad regs\n"); - return -ENOMEM; - } - } else { + case USBPHY_INTERFACE_MODE_ULPI: tegra_phy->is_ulpi_phy = true; tegra_phy->reset_gpio = @@ -839,19 +1028,35 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) tegra_phy->reset_gpio); return tegra_phy->reset_gpio; } + tegra_phy->config = NULL; + break; + + default: + dev_err(&pdev->dev, "phy_type is invalid or unsupported\n"); + return -EINVAL; } - err = of_property_match_string(np, "dr_mode", "otg"); - if (err < 0) { - err = of_property_match_string(np, "dr_mode", "peripheral"); - if (err < 0) - tegra_phy->mode = TEGRA_USB_PHY_MODE_HOST; - else - tegra_phy->mode = TEGRA_USB_PHY_MODE_DEVICE; - } else - tegra_phy->mode = TEGRA_USB_PHY_MODE_OTG; + if (of_find_property(np, "dr_mode", NULL)) + tegra_phy->mode = of_usb_get_dr_mode(np); + else + tegra_phy->mode = USB_DR_MODE_HOST; - tegra_phy->dev = &pdev->dev; + if (tegra_phy->mode == USB_DR_MODE_UNKNOWN) { + dev_err(&pdev->dev, "dr_mode is invalid\n"); + return -EINVAL; + } + + /* On some boards, the VBUS regulator doesn't need to be controlled */ + if (of_find_property(np, "vbus-supply", NULL)) { + tegra_phy->vbus = devm_regulator_get(&pdev->dev, "vbus"); + if (IS_ERR(tegra_phy->vbus)) + return PTR_ERR(tegra_phy->vbus); + } else { + dev_notice(&pdev->dev, "no vbus regulator"); + tegra_phy->vbus = ERR_PTR(-ENODEV); + } + + tegra_phy->u_phy.dev = &pdev->dev; err = tegra_usb_phy_init(tegra_phy); if (err < 0) return err; @@ -860,17 +1065,28 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) tegra_phy->u_phy.set_suspend = tegra_usb_phy_suspend; dev_set_drvdata(&pdev->dev, tegra_phy); + + err = usb_add_phy_dev(&tegra_phy->u_phy); + if (err < 0) { + tegra_usb_phy_close(&tegra_phy->u_phy); + return err; + } + return 0; } -static struct of_device_id tegra_usb_phy_id_table[] = { - { .compatible = "nvidia,tegra20-usb-phy", }, - { }, -}; -MODULE_DEVICE_TABLE(of, tegra_usb_phy_id_table); +static int tegra_usb_phy_remove(struct platform_device *pdev) +{ + struct tegra_usb_phy *tegra_phy = platform_get_drvdata(pdev); + + usb_remove_phy(&tegra_phy->u_phy); + + return 0; +} static struct platform_driver tegra_usb_phy_driver = { .probe = tegra_usb_phy_probe, + .remove = tegra_usb_phy_remove, .driver = { .name = "tegra-phy", .owner = THIS_MODULE, @@ -879,29 +1095,5 @@ static struct platform_driver tegra_usb_phy_driver = { }; module_platform_driver(tegra_usb_phy_driver); -static int tegra_usb_phy_match(struct device *dev, void *data) -{ - struct tegra_usb_phy *tegra_phy = dev_get_drvdata(dev); - struct device_node *dn = data; - - return (tegra_phy->dev->of_node == dn) ? 1 : 0; -} - -struct usb_phy *tegra_usb_get_phy(struct device_node *dn) -{ - struct device *dev; - struct tegra_usb_phy *tegra_phy; - - dev = driver_find_device(&tegra_usb_phy_driver.driver, NULL, dn, - tegra_usb_phy_match); - if (!dev) - return ERR_PTR(-EPROBE_DEFER); - - tegra_phy = dev_get_drvdata(dev); - - return &tegra_phy->u_phy; -} -EXPORT_SYMBOL_GPL(tegra_usb_get_phy); - MODULE_DESCRIPTION("Tegra USB PHY driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/phy/phy-twl4030-usb.c b/drivers/usb/phy/phy-twl4030-usb.c index 8f78d2d40722..90730c8762b8 100644 --- a/drivers/usb/phy/phy-twl4030-usb.c +++ b/drivers/usb/phy/phy-twl4030-usb.c @@ -648,7 +648,7 @@ static int twl4030_set_host(struct usb_otg *otg, struct usb_bus *host) static int twl4030_usb_probe(struct platform_device *pdev) { - struct twl4030_usb_data *pdata = pdev->dev.platform_data; + struct twl4030_usb_data *pdata = dev_get_platdata(&pdev->dev); struct twl4030_usb *twl; int status, err; struct usb_otg *otg; diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index 1753bd367e0a..16dbc9382678 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -324,7 +324,7 @@ static int twl6030_usb_probe(struct platform_device *pdev) int status, err; struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; - struct twl4030_usb_data *pdata = dev->platform_data; + struct twl4030_usb_data *pdata = dev_get_platdata(dev); twl = devm_kzalloc(dev, sizeof *twl, GFP_KERNEL); if (!twl) diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 805940c37353..3385aeb5a364 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -77,9 +77,9 @@ struct usbhsg_recip_handle { struct usbhsg_gpriv, mod) #define __usbhsg_for_each_uep(start, pos, g, i) \ - for (i = start, pos = (g)->uep + i; \ - i < (g)->uep_size; \ - i++, pos = (g)->uep + i) + for ((i) = start; \ + ((i) < (g)->uep_size) && ((pos) = (g)->uep + (i)); \ + (i)++) #define usbhsg_for_each_uep(pos, gpriv, i) \ __usbhsg_for_each_uep(1, pos, gpriv, i) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index b86815421c8d..e40f565004d0 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -111,9 +111,9 @@ static const char usbhsh_hcd_name[] = "renesas_usbhs host"; container_of(usbhs_mod_get(priv, USBHS_HOST), struct usbhsh_hpriv, mod) #define __usbhsh_for_each_udev(start, pos, h, i) \ - for (i = start, pos = (h)->udev + i; \ - i < USBHSH_DEVICE_MAX; \ - i++, pos = (h)->udev + i) + for ((i) = start; \ + ((i) < USBHSH_DEVICE_MAX) && ((pos) = (h)->udev + (i)); \ + (i)++) #define usbhsh_for_each_udev(pos, hpriv, i) \ __usbhsh_for_each_udev(1, pos, hpriv, i) diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h index b476fde955bf..3e5349879838 100644 --- a/drivers/usb/renesas_usbhs/pipe.h +++ b/drivers/usb/renesas_usbhs/pipe.h @@ -54,9 +54,9 @@ struct usbhs_pipe_info { * pipe list */ #define __usbhs_for_each_pipe(start, pos, info, i) \ - for (i = start, pos = (info)->pipe + i; \ - i < (info)->size; \ - i++, pos = (info)->pipe + i) + for ((i) = start; \ + ((i) < (info)->size) && ((pos) = (info)->pipe + (i)); \ + (i)++) #define usbhs_for_each_pipe(pos, priv, i) \ __usbhs_for_each_pipe(1, pos, &((priv)->pipe_info), i) diff --git a/drivers/usb/usb-common.c b/drivers/usb/usb-common.c index 675384dabfe9..d771870a819e 100644 --- a/drivers/usb/usb-common.c +++ b/drivers/usb/usb-common.c @@ -43,20 +43,20 @@ const char *usb_otg_state_string(enum usb_otg_state state) } EXPORT_SYMBOL_GPL(usb_otg_state_string); +static const char *const speed_names[] = { + [USB_SPEED_UNKNOWN] = "UNKNOWN", + [USB_SPEED_LOW] = "low-speed", + [USB_SPEED_FULL] = "full-speed", + [USB_SPEED_HIGH] = "high-speed", + [USB_SPEED_WIRELESS] = "wireless", + [USB_SPEED_SUPER] = "super-speed", +}; + const char *usb_speed_string(enum usb_device_speed speed) { - static const char *const names[] = { - [USB_SPEED_UNKNOWN] = "UNKNOWN", - [USB_SPEED_LOW] = "low-speed", - [USB_SPEED_FULL] = "full-speed", - [USB_SPEED_HIGH] = "high-speed", - [USB_SPEED_WIRELESS] = "wireless", - [USB_SPEED_SUPER] = "super-speed", - }; - - if (speed < 0 || speed >= ARRAY_SIZE(names)) + if (speed < 0 || speed >= ARRAY_SIZE(speed_names)) speed = USB_SPEED_UNKNOWN; - return names[speed]; + return speed_names[speed]; } EXPORT_SYMBOL_GPL(usb_speed_string); @@ -112,6 +112,33 @@ enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np) return USB_DR_MODE_UNKNOWN; } EXPORT_SYMBOL_GPL(of_usb_get_dr_mode); + +/** + * of_usb_get_maximum_speed - Get maximum requested speed for a given USB + * controller. + * @np: Pointer to the given device_node + * + * The function gets the maximum speed string from property "maximum-speed", + * and returns the corresponding enum usb_device_speed. + */ +enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np) +{ + const char *maximum_speed; + int err; + int i; + + err = of_property_read_string(np, "maximum-speed", &maximum_speed); + if (err < 0) + return USB_SPEED_UNKNOWN; + + for (i = 0; i < ARRAY_SIZE(speed_names); i++) + if (strcmp(maximum_speed, speed_names[i]) == 0) + return i; + + return USB_SPEED_UNKNOWN; +} +EXPORT_SYMBOL_GPL(of_usb_get_maximum_speed); + #endif MODULE_LICENSE("GPL"); diff --git a/include/linux/platform_data/tegra_usb.h b/include/linux/platform_data/tegra_usb.h deleted file mode 100644 index 66c673fef408..000000000000 --- a/include/linux/platform_data/tegra_usb.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2010 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _TEGRA_USB_H_ -#define _TEGRA_USB_H_ - -enum tegra_usb_operating_modes { - TEGRA_USB_DEVICE, - TEGRA_USB_HOST, - TEGRA_USB_OTG, -}; - -struct tegra_ehci_platform_data { - enum tegra_usb_operating_modes operating_mode; - /* power down the phy on bus suspend */ - int power_down_on_bus_suspend; - void *phy_config; - int vbus_gpio; -}; - -#endif /* _TEGRA_USB_H_ */ diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index f1b0dca60f12..942ef5e053bf 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -22,6 +22,7 @@ #include <linux/slab.h> #include <linux/scatterlist.h> #include <linux/types.h> +#include <linux/workqueue.h> #include <linux/usb/ch9.h> struct usb_ep; @@ -475,6 +476,7 @@ struct usb_gadget_ops { /** * struct usb_gadget - represents a usb slave device + * @work: (internal use) Workqueue to be used for sysfs_notify() * @ops: Function pointers used to access hardware-specific operations. * @ep0: Endpoint zero, used when reading or writing responses to * driver setup() requests @@ -520,6 +522,7 @@ struct usb_gadget_ops { * device is acting as a B-Peripheral (so is_a_peripheral is false). */ struct usb_gadget { + struct work_struct work; /* readonly to gadget driver */ const struct usb_gadget_ops *ops; struct usb_ep *ep0; @@ -538,6 +541,7 @@ struct usb_gadget { unsigned out_epnum; unsigned in_epnum; }; +#define work_to_gadget(w) (container_of((w), struct usb_gadget, work)) static inline void set_gadget_data(struct usb_gadget *gadget, void *data) { dev_set_drvdata(&gadget->dev, data); } diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h index a0ef405368b8..8c38aa26b3bb 100644 --- a/include/linux/usb/of.h +++ b/include/linux/usb/of.h @@ -7,19 +7,27 @@ #ifndef __LINUX_USB_OF_H #define __LINUX_USB_OF_H +#include <linux/usb/ch9.h> #include <linux/usb/otg.h> #include <linux/usb/phy.h> #if IS_ENABLED(CONFIG_OF) enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np); +enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np); #else static inline enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np) { return USB_DR_MODE_UNKNOWN; } + +static inline enum usb_device_speed +of_usb_get_maximum_speed(struct device_node *np) +{ + return USB_SPEED_UNKNOWN; +} #endif -#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_PHY) +#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_SUPPORT) enum usb_phy_interface of_usb_get_phy_mode(struct device_node *np); #else static inline enum usb_phy_interface of_usb_get_phy_mode(struct device_node *np) diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h index 44036808bf0f..6c0b1c513db7 100644 --- a/include/linux/usb/phy.h +++ b/include/linux/usb/phy.h @@ -142,7 +142,7 @@ extern void usb_remove_phy(struct usb_phy *); /* helpers for direct access thru low-level io interface */ static inline int usb_phy_io_read(struct usb_phy *x, u32 reg) { - if (x->io_ops && x->io_ops->read) + if (x && x->io_ops && x->io_ops->read) return x->io_ops->read(x, reg); return -EINVAL; @@ -150,7 +150,7 @@ static inline int usb_phy_io_read(struct usb_phy *x, u32 reg) static inline int usb_phy_io_write(struct usb_phy *x, u32 val, u32 reg) { - if (x->io_ops && x->io_ops->write) + if (x && x->io_ops && x->io_ops->write) return x->io_ops->write(x, val, reg); return -EINVAL; @@ -159,7 +159,7 @@ static inline int usb_phy_io_write(struct usb_phy *x, u32 val, u32 reg) static inline int usb_phy_init(struct usb_phy *x) { - if (x->init) + if (x && x->init) return x->init(x); return 0; @@ -168,14 +168,14 @@ usb_phy_init(struct usb_phy *x) static inline void usb_phy_shutdown(struct usb_phy *x) { - if (x->shutdown) + if (x && x->shutdown) x->shutdown(x); } static inline int usb_phy_vbus_on(struct usb_phy *x) { - if (!x->set_vbus) + if (!x || !x->set_vbus) return 0; return x->set_vbus(x, true); @@ -184,7 +184,7 @@ usb_phy_vbus_on(struct usb_phy *x) static inline int usb_phy_vbus_off(struct usb_phy *x) { - if (!x->set_vbus) + if (!x || !x->set_vbus) return 0; return x->set_vbus(x, false); @@ -258,7 +258,7 @@ usb_phy_set_power(struct usb_phy *x, unsigned mA) static inline int usb_phy_set_suspend(struct usb_phy *x, int suspend) { - if (x->set_suspend != NULL) + if (x && x->set_suspend != NULL) return x->set_suspend(x, suspend); else return 0; @@ -267,7 +267,7 @@ usb_phy_set_suspend(struct usb_phy *x, int suspend) static inline int usb_phy_notify_connect(struct usb_phy *x, enum usb_device_speed speed) { - if (x->notify_connect) + if (x && x->notify_connect) return x->notify_connect(x, speed); else return 0; @@ -276,7 +276,7 @@ usb_phy_notify_connect(struct usb_phy *x, enum usb_device_speed speed) static inline int usb_phy_notify_disconnect(struct usb_phy *x, enum usb_device_speed speed) { - if (x->notify_disconnect) + if (x && x->notify_disconnect) return x->notify_disconnect(x, speed); else return 0; diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index d2ca919a5b73..1de16c324ec8 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -18,19 +18,36 @@ #include <linux/clk.h> #include <linux/usb/otg.h> +/* + * utmi_pll_config_in_car_module: true if the UTMI PLL configuration registers + * should be set up by clk-tegra, false if by the PHY code + * has_hostpc: true if the USB controller has the HOSTPC extension, which + * changes the location of the PHCD and PTS fields + * requires_usbmode_setup: true if the USBMODE register needs to be set to + * enter host mode + * requires_extra_tuning_parameters: true if xcvr_hsslew, hssquelch_level + * and hsdiscon_level should be set for adequate signal quality + */ + +struct tegra_phy_soc_config { + bool utmi_pll_config_in_car_module; + bool has_hostpc; + bool requires_usbmode_setup; + bool requires_extra_tuning_parameters; +}; + struct tegra_utmip_config { u8 hssync_start_delay; u8 elastic_limit; u8 idle_wait_delay; u8 term_range_adj; + bool xcvr_setup_use_fuses; u8 xcvr_setup; u8 xcvr_lsfslew; u8 xcvr_lsrslew; -}; - -struct tegra_ulpi_config { - int reset_gpio; - const char *clk; + u8 xcvr_hsslew; + u8 hssquelch_level; + u8 hsdiscon_level; }; enum tegra_usb_phy_port_speed { @@ -39,12 +56,6 @@ enum tegra_usb_phy_port_speed { TEGRA_USB_PHY_PORT_SPEED_HIGH, }; -enum tegra_usb_phy_mode { - TEGRA_USB_PHY_MODE_DEVICE, - TEGRA_USB_PHY_MODE_HOST, - TEGRA_USB_PHY_MODE_OTG, -}; - struct tegra_xtal_freq; struct tegra_usb_phy { @@ -55,18 +66,17 @@ struct tegra_usb_phy { struct clk *clk; struct clk *pll_u; struct clk *pad_clk; - enum tegra_usb_phy_mode mode; + struct regulator *vbus; + enum usb_dr_mode mode; void *config; + const struct tegra_phy_soc_config *soc_config; struct usb_phy *ulpi; struct usb_phy u_phy; - struct device *dev; bool is_legacy_phy; bool is_ulpi_phy; int reset_gpio; }; -struct usb_phy *tegra_usb_get_phy(struct device_node *dn); - void tegra_usb_phy_preresume(struct usb_phy *phy); void tegra_usb_phy_postresume(struct usb_phy *phy); diff --git a/include/linux/usb/nop-usb-xceiv.h b/include/linux/usb/usb_phy_gen_xceiv.h index 148d35171aac..f9a7e7bc925b 100644 --- a/include/linux/usb/nop-usb-xceiv.h +++ b/include/linux/usb/usb_phy_gen_xceiv.h @@ -3,7 +3,7 @@ #include <linux/usb/otg.h> -struct nop_usb_xceiv_platform_data { +struct usb_phy_gen_xceiv_platform_data { enum usb_phy_type type; unsigned long clk_rate; @@ -12,7 +12,7 @@ struct nop_usb_xceiv_platform_data { unsigned int needs_reset:1; }; -#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_NOP_USB_XCEIV) /* sometimes transceivers are accessed only through e.g. ULPI */ extern void usb_nop_xceiv_register(void); extern void usb_nop_xceiv_unregister(void); |