Merge tag 'usb-for-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 Apr 2013 22:18:00 +0000 (15:18 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 Apr 2013 22:18:00 +0000 (15:18 -0700)
Felipe writes:

usb: patches for v3.10 merge window

Here is the big Gadget & PHY pull request. Many of us have
been really busy lately getting multiple drivers to a better
position.

Since this pull request is so large, I will divide it in sections
so it's easier to grasp what's included.

- cleanups:
. UDC drivers no longer touch gadget->dev, that's now udc-core
responsibility
. Many more UDC drivers converted to usb_gadget_map/unmap_request()
. UDC drivers no longer initialize DMA-related fields from gadget's
device structure
. UDC drivers don't touch gadget.dev.driver directly
. UDC drivers don't assign gadget.dev.release directly
. Removal of some unused DMA_ADDR_INVALID
. Introduction of CONFIG_USB_PHY
. All phy drivers have been moved to drivers/usb/phy and renamed to
a common naming scheme
. Fix PHY layer so it never returns a NULL pointer, also fix all
callers to avoid using IS_ERR_OR_NULL()
. Sparse fixes all over the place
. drivers/usb/otg/ has been deleted
. Marvel drivers (mv_udc, ehci-mv, mv_otg and mv_u3d) improved clock
usage

- new features:
. UDC core now provides a generic way for tracking and reporting
UDC's state (not attached, resuming, suspended, addressed,
default, etc)
. twl4030-usb learned that it shouldn't be enabled during init
. Full DT support for DWC3 has been implemented
. ab8500-usb learned about pinctrl framework
. nop PHY learned about DeviceTree and regulators
. DWC3 learned about suspend/resume
. DWC3 can now be compiled in host-only and gadget-only (as well as
DRD) configurations
. UVC now enables streaming endpoint based on negotiated speed
. isp1301 now implements the PHY API properly
. configfs-based interface for gadget drivers which will lead to
the removal of all code which just combines functions together
to build functional gadget drivers.
. f_serial and f_obex were converted to new configfs interface while
maintaining old interface around.

- non-critical fixes:
. UVC gadget driver got fixes for Endpoint usage and stream calculation
. ab8500-usb fixed unbalanced clock and regulator API usage
. twl4030-usb got a fix for when OMAP3 is booted with cable connected
. fusb300_udc got a fix for DMA usage
. UVC got fixes for two assertions of the USB Video Class Compliance
specification revision 1.1
. build warning issues caused by recent addition of __must_check to
regulator API

These are all changes which deserve a mention, all other changes are related
to these one or minor spelling fixes and other similar tasks.

Signed-of-by: Felipe Balbi <balbi@ti.com>
159 files changed:
Documentation/devicetree/bindings/usb/omap-usb.txt
Documentation/devicetree/bindings/usb/samsung-usbphy.txt
Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt [new file with mode: 0644]
arch/arm/mach-mmp/aspenite.c
arch/arm/mach-mmp/ttc_dkb.c
arch/arm/mach-shmobile/board-armadillo800eva.c
arch/arm/mach-shmobile/board-kzm9g.c
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/mach-tegra/Kconfig
arch/sh/boards/mach-ecovec24/setup.c
drivers/Makefile
drivers/power/Kconfig
drivers/power/pda_power.c
drivers/usb/Kconfig
drivers/usb/Makefile
drivers/usb/chipidea/udc.c
drivers/usb/dwc3/Kconfig
drivers/usb/dwc3/core.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/debugfs.c
drivers/usb/dwc3/dwc3-exynos.c
drivers/usb/dwc3/dwc3-omap.c
drivers/usb/dwc3/dwc3-pci.c
drivers/usb/dwc3/ep0.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/Makefile
drivers/usb/gadget/acm_ms.c
drivers/usb/gadget/amd5536udc.c
drivers/usb/gadget/amd5536udc.h
drivers/usb/gadget/at91_udc.c
drivers/usb/gadget/atmel_usba_udc.c
drivers/usb/gadget/atmel_usba_udc.h
drivers/usb/gadget/bcm63xx_udc.c
drivers/usb/gadget/cdc2.c
drivers/usb/gadget/composite.c
drivers/usb/gadget/configfs.c [new file with mode: 0644]
drivers/usb/gadget/dummy_hcd.c
drivers/usb/gadget/ether.c
drivers/usb/gadget/f_acm.c
drivers/usb/gadget/f_ecm.c
drivers/usb/gadget/f_eem.c
drivers/usb/gadget/f_ncm.c
drivers/usb/gadget/f_obex.c
drivers/usb/gadget/f_rndis.c
drivers/usb/gadget/f_serial.c
drivers/usb/gadget/f_subset.c
drivers/usb/gadget/f_uvc.c
drivers/usb/gadget/f_uvc.h
drivers/usb/gadget/fsl_qe_udc.c
drivers/usb/gadget/fsl_udc_core.c
drivers/usb/gadget/fusb300_udc.c
drivers/usb/gadget/fusb300_udc.h
drivers/usb/gadget/g_ffs.c
drivers/usb/gadget/goku_udc.c
drivers/usb/gadget/goku_udc.h
drivers/usb/gadget/imx_udc.c
drivers/usb/gadget/lpc32xx_udc.c
drivers/usb/gadget/m66592-udc.c
drivers/usb/gadget/multi.c
drivers/usb/gadget/mv_u3d_core.c
drivers/usb/gadget/mv_udc.h
drivers/usb/gadget/mv_udc_core.c
drivers/usb/gadget/ncm.c
drivers/usb/gadget/net2272.c
drivers/usb/gadget/net2280.c
drivers/usb/gadget/nokia.c
drivers/usb/gadget/omap_udc.c
drivers/usb/gadget/pch_udc.c
drivers/usb/gadget/pxa25x_udc.c
drivers/usb/gadget/pxa27x_udc.c
drivers/usb/gadget/r8a66597-udc.c
drivers/usb/gadget/s3c-hsotg.c
drivers/usb/gadget/s3c-hsudc.c
drivers/usb/gadget/s3c2410_udc.c
drivers/usb/gadget/serial.c
drivers/usb/gadget/u_ether.c
drivers/usb/gadget/u_ether.h
drivers/usb/gadget/u_serial.h
drivers/usb/gadget/udc-core.c
drivers/usb/gadget/uvc.h
drivers/usb/gadget/uvc_queue.c
drivers/usb/gadget/uvc_queue.h
drivers/usb/gadget/uvc_v4l2.c
drivers/usb/gadget/uvc_video.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-msm.c
drivers/usb/host/ehci-mv.c
drivers/usb/host/ehci-s5p.c
drivers/usb/host/ehci-tegra.c
drivers/usb/host/ohci-exynos.c
drivers/usb/musb/Kconfig
drivers/usb/musb/am35x.c
drivers/usb/musb/blackfin.c
drivers/usb/musb/cppi_dma.c
drivers/usb/musb/da8xx.c
drivers/usb/musb/davinci.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_dsps.c
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/musb_gadget_ep0.c
drivers/usb/musb/musb_host.c
drivers/usb/musb/musb_virthub.c
drivers/usb/musb/omap2430.c
drivers/usb/musb/tusb6010.c
drivers/usb/musb/ux500.c
drivers/usb/musb/ux500_dma.c
drivers/usb/otg/Kconfig [deleted file]
drivers/usb/otg/Makefile [deleted file]
drivers/usb/otg/ab8500-usb.c [deleted file]
drivers/usb/phy/Kconfig
drivers/usb/phy/Makefile
drivers/usb/phy/isp1301.c [deleted file]
drivers/usb/phy/phy-ab8500-usb.c [new file with mode: 0644]
drivers/usb/phy/phy-fsl-usb.c [moved from drivers/usb/otg/fsl_otg.c with 97% similarity]
drivers/usb/phy/phy-fsl-usb.h [moved from drivers/usb/otg/fsl_otg.h with 100% similarity]
drivers/usb/phy/phy-fsm-usb.c [moved from drivers/usb/otg/otg_fsm.c with 99% similarity]
drivers/usb/phy/phy-fsm-usb.h [moved from drivers/usb/otg/otg_fsm.h with 100% similarity]
drivers/usb/phy/phy-gpio-vbus-usb.c [moved from drivers/usb/otg/gpio_vbus.c with 98% similarity]
drivers/usb/phy/phy-isp1301-omap.c [moved from drivers/usb/otg/isp1301_omap.c with 99% similarity]
drivers/usb/phy/phy-isp1301.c [new file with mode: 0644]
drivers/usb/phy/phy-msm-usb.c [moved from drivers/usb/otg/msm_otg.c with 100% similarity]
drivers/usb/phy/phy-mv-u3d-usb.c [moved from drivers/usb/phy/mv_u3d_phy.c with 99% similarity]
drivers/usb/phy/phy-mv-u3d-usb.h [moved from drivers/usb/phy/mv_u3d_phy.h with 100% similarity]
drivers/usb/phy/phy-mv-usb.c [moved from drivers/usb/otg/mv_otg.c with 97% similarity]
drivers/usb/phy/phy-mv-usb.h [moved from drivers/usb/otg/mv_otg.h with 99% similarity]
drivers/usb/phy/phy-mxs-usb.c [moved from drivers/usb/otg/mxs-phy.c with 84% similarity]
drivers/usb/phy/phy-nop.c [moved from drivers/usb/otg/nop-usb-xceiv.c with 55% similarity]
drivers/usb/phy/phy-omap-control.c [moved from drivers/usb/phy/omap-control-usb.c with 100% similarity]
drivers/usb/phy/phy-omap-usb2.c [moved from drivers/usb/phy/omap-usb2.c with 100% similarity]
drivers/usb/phy/phy-omap-usb3.c [moved from drivers/usb/phy/omap-usb3.c with 100% similarity]
drivers/usb/phy/phy-rcar-usb.c [moved from drivers/usb/phy/rcar-phy.c with 100% similarity]
drivers/usb/phy/phy-samsung-usb.c [new file with mode: 0644]
drivers/usb/phy/phy-samsung-usb.h [new file with mode: 0644]
drivers/usb/phy/phy-samsung-usb2.c [new file with mode: 0644]
drivers/usb/phy/phy-samsung-usb3.c [new file with mode: 0644]
drivers/usb/phy/phy-tegra-usb.c [moved from drivers/usb/phy/tegra_usb_phy.c with 100% similarity]
drivers/usb/phy/phy-twl4030-usb.c [moved from drivers/usb/otg/twl4030-usb.c with 85% similarity]
drivers/usb/phy/phy-twl6030-usb.c [moved from drivers/usb/otg/twl6030-usb.c with 98% similarity]
drivers/usb/phy/phy-ulpi-viewport.c [moved from drivers/usb/otg/ulpi_viewport.c with 100% similarity]
drivers/usb/phy/phy-ulpi.c [moved from drivers/usb/otg/ulpi.c with 100% similarity]
drivers/usb/phy/phy.c [moved from drivers/usb/otg/otg.c with 89% similarity]
drivers/usb/phy/samsung-usbphy.c [deleted file]
drivers/usb/renesas_usbhs/fifo.c
drivers/usb/renesas_usbhs/fifo.h
drivers/usb/renesas_usbhs/mod_gadget.c
drivers/usb/usb-common.c
include/linux/platform_data/dwc3-omap.h
include/linux/platform_data/mv_usb.h
include/linux/usb/ch9.h
include/linux/usb/composite.h
include/linux/usb/dwc3-omap.h
include/linux/usb/gadget.h
include/linux/usb/gadget_configfs.h [new file with mode: 0644]
include/linux/usb/musb-ux500.h [new file with mode: 0644]
include/linux/usb/nop-usb-xceiv.h
include/linux/usb/otg.h
include/linux/usb/phy.h
include/linux/usb/renesas_usbhs.h

index 1ef0ce7..662f0f1 100644 (file)
@@ -8,10 +8,10 @@ OMAP MUSB GLUE
    and disconnect.
  - multipoint : Should be "1" indicating the musb controller supports
    multipoint. This is a MUSB configuration-specific setting.
- - num_eps : Specifies the number of endpoints. This is also a
+ - num-eps : Specifies the number of endpoints. This is also a
    MUSB configuration-specific setting. Should be set to "16"
- - ram_bits : Specifies the ram address size. Should be set to "12"
- - interface_type : This is a board specific setting to describe the type of
+ - ram-bits : Specifies the ram address size. Should be set to "12"
+ - interface-type : This is a board specific setting to describe the type of
    interface between the controller and the phy. It should be "0" or "1"
    specifying ULPI and UTMI respectively.
  - mode : Should be "3" to represent OTG. "1" signifies HOST and "2"
@@ -29,18 +29,46 @@ usb_otg_hs: usb_otg_hs@4a0ab000 {
        ti,hwmods = "usb_otg_hs";
        ti,has-mailbox;
        multipoint = <1>;
-       num_eps = <16>;
-       ram_bits = <12>;
+       num-eps = <16>;
+       ram-bits = <12>;
        ctrl-module = <&omap_control_usb>;
 };
 
 Board specific device node entry
 &usb_otg_hs {
-       interface_type = <1>;
+       interface-type = <1>;
        mode = <3>;
        power = <50>;
 };
 
+OMAP DWC3 GLUE
+ - compatible : Should be "ti,dwc3"
+ - ti,hwmods : Should be "usb_otg_ss"
+ - reg : Address and length of the register set for the device.
+ - interrupts : The irq number of this device that is used to interrupt the
+   MPU
+ - #address-cells, #size-cells : Must be present if the device has sub-nodes
+ - utmi-mode : controls the source of UTMI/PIPE status for VBUS and OTG ID.
+   It should be set to "1" for HW mode and "2" for SW mode.
+ - ranges: the child address space are mapped 1:1 onto the parent address space
+
+Sub-nodes:
+The dwc3 core should be added as subnode to omap dwc3 glue.
+- dwc3 :
+   The binding details of dwc3 can be found in:
+   Documentation/devicetree/bindings/usb/dwc3.txt
+
+omap_dwc3 {
+       compatible = "ti,dwc3";
+       ti,hwmods = "usb_otg_ss";
+       reg = <0x4a020000 0x1ff>;
+       interrupts = <0 93 4>;
+       #address-cells = <1>;
+       #size-cells = <1>;
+       utmi-mode = <2>;
+       ranges;
+};
+
 OMAP CONTROL USB
 
 Required properties:
index 0331949..f575302 100644 (file)
@@ -1,20 +1,25 @@
-* Samsung's usb phy transceiver
+SAMSUNG USB-PHY controllers
 
-The Samsung's phy transceiver is used for controlling usb phy for
-s3c-hsotg as well as ehci-s5p and ohci-exynos usb controllers
-across Samsung SOCs.
+** Samsung's usb 2.0 phy transceiver
+
+The Samsung's usb 2.0 phy transceiver is used for controlling
+usb 2.0 phy for s3c-hsotg as well as ehci-s5p and ohci-exynos
+usb controllers across Samsung SOCs.
 TODO: Adding the PHY binding with controller(s) according to the under
 developement generic PHY driver.
 
 Required properties:
 
 Exynos4210:
-- compatible : should be "samsung,exynos4210-usbphy"
+- compatible : should be "samsung,exynos4210-usb2phy"
 - reg : base physical address of the phy registers and length of memory mapped
        region.
+- clocks: Clock IDs array as required by the controller.
+- clock-names: names of clock correseponding IDs clock property as requested
+              by the controller driver.
 
 Exynos5250:
-- compatible : should be "samsung,exynos5250-usbphy"
+- compatible : should be "samsung,exynos5250-usb2phy"
 - reg : base physical address of the phy registers and length of memory mapped
        region.
 
@@ -44,12 +49,69 @@ Example:
        usbphy@125B0000 {
                #address-cells = <1>;
                #size-cells = <1>;
-               compatible = "samsung,exynos4210-usbphy";
+               compatible = "samsung,exynos4210-usb2phy";
                reg = <0x125B0000 0x100>;
                ranges;
 
+               clocks = <&clock 2>, <&clock 305>;
+               clock-names = "xusbxti", "otg";
+
                usbphy-sys {
                        /* USB device and host PHY_CONTROL registers */
                        reg = <0x10020704 0x8>;
                };
        };
+
+
+** Samsung's usb 3.0 phy transceiver
+
+Starting exynso5250, Samsung's SoC have usb 3.0 phy transceiver
+which is used for controlling usb 3.0 phy for dwc3-exynos usb 3.0
+controllers across Samsung SOCs.
+
+Required properties:
+
+Exynos5250:
+- compatible : should be "samsung,exynos5250-usb3phy"
+- reg : base physical address of the phy registers and length of memory mapped
+       region.
+- clocks: Clock IDs array as required by the controller.
+- clock-names: names of clocks correseponding to IDs in the clock property
+              as requested by the controller driver.
+
+Optional properties:
+- #address-cells: should be '1' when usbphy node has a child node with 'reg'
+                 property.
+- #size-cells: should be '1' when usbphy node has a child node with 'reg'
+              property.
+- ranges: allows valid translation between child's address space and parent's
+         address space.
+
+- The child node 'usbphy-sys' to the node 'usbphy' is for the system controller
+  interface for usb-phy. It should provide the following information required by
+  usb-phy controller to control phy.
+  - reg : base physical address of PHY_CONTROL registers.
+         The size of this register is the total sum of size of all PHY_CONTROL
+         registers that the SoC has. For example, the size will be
+         '0x4' in case we have only one PHY_CONTROL register (e.g.
+         OTHERS register in S3C64XX or USB_PHY_CONTROL register in S5PV210)
+         and, '0x8' in case we have two PHY_CONTROL registers (e.g.
+         USBDEVICE_PHY_CONTROL and USBHOST_PHY_CONTROL registers in exynos4x).
+         and so on.
+
+Example:
+       usbphy@12100000 {
+               compatible = "samsung,exynos5250-usb3phy";
+               reg = <0x12100000 0x100>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               clocks = <&clock 1>, <&clock 286>;
+               clock-names = "ext_xtal", "usbdrd30";
+
+               usbphy-sys {
+                       /* USB device and host PHY_CONTROL registers */
+                       reg = <0x10040704 0x8>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt
new file mode 100644 (file)
index 0000000..d7e2726
--- /dev/null
@@ -0,0 +1,34 @@
+USB NOP PHY
+
+Required properties:
+- compatible: should be usb-nop-xceiv
+
+Optional properties:
+- clocks: phandle to the PHY clock. Use as per Documentation/devicetree
+  /bindings/clock/clock-bindings.txt
+  This property is required if clock-frequency is specified.
+
+- clock-names: Should be "main_clk"
+
+- clock-frequency: the clock frequency (in Hz) that the PHY clock must
+  be configured to.
+
+- vcc-supply: phandle to the regulator that provides RESET to the PHY.
+
+- reset-supply: phandle to the regulator that provides power to the PHY.
+
+Example:
+
+       hsusb1_phy {
+               compatible = "usb-nop-xceiv";
+               clock-frequency = <19200000>;
+               clocks = <&osc 0>;
+               clock-names = "main_clk";
+               vcc-supply = <&hsusb1_vcc_regulator>;
+               reset-supply = <&hsusb1_reset_regulator>;
+       };
+
+hsusb1_phy is a NOP USB PHY device that gets its clock from an oscillator
+and expects that clock to be configured to 19.2MHz by the NOP PHY driver.
+hsusb1_vcc_regulator provides power to the PHY and hsusb1_reset_regulator
+controls RESET.
index 9f64d56..76901f4 100644 (file)
@@ -223,13 +223,7 @@ static struct pxa27x_keypad_platform_data aspenite_keypad_info __initdata = {
 };
 
 #if defined(CONFIG_USB_EHCI_MV)
-static char *pxa168_sph_clock_name[] = {
-       [0] = "PXA168-USBCLK",
-};
-
 static struct mv_usb_platform_data pxa168_sph_pdata = {
-       .clknum         = 1,
-       .clkname        = pxa168_sph_clock_name,
        .mode           = MV_USB_MODE_HOST,
        .phy_init       = pxa_usb_phy_init,
        .phy_deinit     = pxa_usb_phy_deinit,
index 22a9058..6528a5f 100644 (file)
@@ -162,13 +162,7 @@ static struct i2c_board_info ttc_dkb_i2c_info[] = {
 #ifdef CONFIG_USB_SUPPORT
 #if defined(CONFIG_USB_MV_UDC) || defined(CONFIG_USB_EHCI_MV_U2O)
 
-static char *pxa910_usb_clock_name[] = {
-       [0] = "U2OCLK",
-};
-
 static struct mv_usb_platform_data ttc_usb_pdata = {
-       .clknum         = 1,
-       .clkname        = pxa910_usb_clock_name,
        .vbus           = NULL,
        .mode           = MV_USB_MODE_OTG,
        .otg_force_a_bus_req = 1,
index f2ec077..ff8b7ba 100644 (file)
@@ -169,7 +169,7 @@ static int usbhsf_get_id(struct platform_device *pdev)
        return USBHS_GADGET;
 }
 
-static void usbhsf_power_ctrl(struct platform_device *pdev,
+static int usbhsf_power_ctrl(struct platform_device *pdev,
                              void __iomem *base, int enable)
 {
        struct usbhsf_private *priv = usbhsf_get_priv(pdev);
@@ -223,6 +223,8 @@ static void usbhsf_power_ctrl(struct platform_device *pdev,
                clk_disable(priv->pci);         /* usb work around */
                clk_disable(priv->usb24);       /* usb work around */
        }
+
+       return 0;
 }
 
 static int usbhsf_get_vbus(struct platform_device *pdev)
@@ -239,7 +241,7 @@ static irqreturn_t usbhsf_interrupt(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static void usbhsf_hardware_exit(struct platform_device *pdev)
+static int usbhsf_hardware_exit(struct platform_device *pdev)
 {
        struct usbhsf_private *priv = usbhsf_get_priv(pdev);
 
@@ -264,6 +266,8 @@ static void usbhsf_hardware_exit(struct platform_device *pdev)
        priv->usbh_base = NULL;
 
        free_irq(IRQ7, pdev);
+
+       return 0;
 }
 
 static int usbhsf_hardware_init(struct platform_device *pdev)
index 7f3a6b7..a385f57 100644 (file)
@@ -155,12 +155,14 @@ static int usbhs_get_vbus(struct platform_device *pdev)
        return !((1 << 7) & __raw_readw(priv->cr2));
 }
 
-static void usbhs_phy_reset(struct platform_device *pdev)
+static int usbhs_phy_reset(struct platform_device *pdev)
 {
        struct usbhs_private *priv = usbhs_get_priv(pdev);
 
        /* init phy */
        __raw_writew(0x8a0a, priv->cr2);
+
+       return 0;
 }
 
 static int usbhs_get_id(struct platform_device *pdev)
@@ -202,7 +204,7 @@ static int usbhs_hardware_init(struct platform_device *pdev)
        return 0;
 }
 
-static void usbhs_hardware_exit(struct platform_device *pdev)
+static int usbhs_hardware_exit(struct platform_device *pdev)
 {
        struct usbhs_private *priv = usbhs_get_priv(pdev);
 
@@ -210,6 +212,8 @@ static void usbhs_hardware_exit(struct platform_device *pdev)
        __raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->phy);
 
        free_irq(IRQ15, pdev);
+
+       return 0;
 }
 
 static u32 usbhs_pipe_cfg[] = {
index db968a5..979237c 100644 (file)
@@ -596,12 +596,14 @@ static int usbhs_get_vbus(struct platform_device *pdev)
        return usbhs_is_connected(usbhs_get_priv(pdev));
 }
 
-static void usbhs_phy_reset(struct platform_device *pdev)
+static int usbhs_phy_reset(struct platform_device *pdev)
 {
        struct usbhs_private *priv = usbhs_get_priv(pdev);
 
        /* init phy */
        __raw_writew(0x8a0a, priv->usbcrcaddr);
+
+       return 0;
 }
 
 static int usbhs0_get_id(struct platform_device *pdev)
@@ -628,11 +630,13 @@ static int usbhs0_hardware_init(struct platform_device *pdev)
        return 0;
 }
 
-static void usbhs0_hardware_exit(struct platform_device *pdev)
+static int usbhs0_hardware_exit(struct platform_device *pdev)
 {
        struct usbhs_private *priv = usbhs_get_priv(pdev);
 
        cancel_delayed_work_sync(&priv->work);
+
+       return 0;
 }
 
 static struct usbhs_private usbhs0_private = {
@@ -735,7 +739,7 @@ static int usbhs1_hardware_init(struct platform_device *pdev)
        return 0;
 }
 
-static void usbhs1_hardware_exit(struct platform_device *pdev)
+static int usbhs1_hardware_exit(struct platform_device *pdev)
 {
        struct usbhs_private *priv = usbhs_get_priv(pdev);
 
@@ -743,6 +747,8 @@ static void usbhs1_hardware_exit(struct platform_device *pdev)
        __raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->usbphyaddr);
 
        free_irq(IRQ8, pdev);
+
+       return 0;
 }
 
 static int usbhs1_get_id(struct platform_device *pdev)
index d1c4893..dbc653e 100644 (file)
@@ -18,8 +18,8 @@ config ARCH_TEGRA_2x_SOC
        select PL310_ERRATA_727915 if CACHE_L2X0
        select PL310_ERRATA_769419 if CACHE_L2X0
        select USB_ARCH_HAS_EHCI if USB_SUPPORT
-       select USB_ULPI if USB
-       select USB_ULPI_VIEWPORT if USB_SUPPORT
+       select USB_ULPI if USB_PHY
+       select USB_ULPI_VIEWPORT if USB_PHY
        help
          Support for NVIDIA Tegra AP20 and T20 processors, based on the
          ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
@@ -37,8 +37,8 @@ config ARCH_TEGRA_3x_SOC
        select PINCTRL_TEGRA30
        select PL310_ERRATA_769419 if CACHE_L2X0
        select USB_ARCH_HAS_EHCI if USB_SUPPORT
-       select USB_ULPI if USB
-       select USB_ULPI_VIEWPORT if USB_SUPPORT
+       select USB_ULPI if USB_PHY
+       select USB_ULPI_VIEWPORT if USB_PHY
        help
          Support for NVIDIA Tegra T30 processor family, based on the
          ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
index aaff767..764530c 100644 (file)
@@ -254,11 +254,13 @@ static int usbhs_get_id(struct platform_device *pdev)
        return gpio_get_value(GPIO_PTB3);
 }
 
-static void usbhs_phy_reset(struct platform_device *pdev)
+static int usbhs_phy_reset(struct platform_device *pdev)
 {
        /* enable vbus if HOST */
        if (!gpio_get_value(GPIO_PTB3))
                gpio_set_value(GPIO_PTB5, 1);
+
+       return 0;
 }
 
 static struct renesas_usbhs_platform_info usbhs_info = {
index dce39a9..3c200a2 100644 (file)
@@ -79,7 +79,7 @@ obj-$(CONFIG_ATA_OVER_ETH)    += block/aoe/
 obj-$(CONFIG_PARIDE)           += block/paride/
 obj-$(CONFIG_TC)               += tc/
 obj-$(CONFIG_UWB)              += uwb/
-obj-$(CONFIG_USB_OTG_UTILS)    += usb/
+obj-$(CONFIG_USB_PHY)          += usb/
 obj-$(CONFIG_USB)              += usb/
 obj-$(CONFIG_PCI)              += usb/
 obj-$(CONFIG_USB_GADGET)       += usb/
index 9e00c38..ffe02fb 100644 (file)
@@ -254,7 +254,7 @@ config BATTERY_RX51
 
 config CHARGER_ISP1704
        tristate "ISP1704 USB Charger Detection"
-       depends on USB_OTG_UTILS
+       depends on USB_PHY
        help
          Say Y to enable support for USB Charger Detection with
          ISP1707/ISP1704 USB transceivers.
index 7df7c5f..0c52e2a 100644 (file)
@@ -35,7 +35,7 @@ static struct timer_list supply_timer;
 static struct timer_list polling_timer;
 static int polling;
 
-#ifdef CONFIG_USB_OTG_UTILS
+#if IS_ENABLED(CONFIG_USB_PHY)
 static struct usb_phy *transceiver;
 static struct notifier_block otg_nb;
 #endif
@@ -218,7 +218,7 @@ static void polling_timer_func(unsigned long unused)
                  jiffies + msecs_to_jiffies(pdata->polling_interval));
 }
 
-#ifdef CONFIG_USB_OTG_UTILS
+#if IS_ENABLED(CONFIG_USB_PHY)
 static int otg_is_usb_online(void)
 {
        return (transceiver->last_event == USB_EVENT_VBUS ||
@@ -315,7 +315,7 @@ static int pda_power_probe(struct platform_device *pdev)
                pda_psy_usb.num_supplicants = pdata->num_supplicants;
        }
 
-#ifdef CONFIG_USB_OTG_UTILS
+#if IS_ENABLED(CONFIG_USB_PHY)
        transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
        if (!IS_ERR_OR_NULL(transceiver)) {
                if (!pdata->is_usb_online)
@@ -367,7 +367,7 @@ static int pda_power_probe(struct platform_device *pdev)
                }
        }
 
-#ifdef CONFIG_USB_OTG_UTILS
+#if IS_ENABLED(CONFIG_USB_PHY)
        if (!IS_ERR_OR_NULL(transceiver) && pdata->use_otg_notifier) {
                otg_nb.notifier_call = otg_handle_notification;
                ret = usb_register_notifier(transceiver, &otg_nb);
@@ -391,7 +391,7 @@ static int pda_power_probe(struct platform_device *pdev)
 
        return 0;
 
-#ifdef CONFIG_USB_OTG_UTILS
+#if IS_ENABLED(CONFIG_USB_PHY)
 otg_reg_notifier_failed:
        if (pdata->is_usb_online && usb_irq)
                free_irq(usb_irq->start, &pda_psy_usb);
@@ -402,7 +402,7 @@ usb_irq_failed:
 usb_supply_failed:
        if (pdata->is_ac_online && ac_irq)
                free_irq(ac_irq->start, &pda_psy_ac);
-#ifdef CONFIG_USB_OTG_UTILS
+#if IS_ENABLED(CONFIG_USB_PHY)
        if (!IS_ERR_OR_NULL(transceiver))
                usb_put_phy(transceiver);
 #endif
@@ -437,7 +437,7 @@ static int pda_power_remove(struct platform_device *pdev)
                power_supply_unregister(&pda_psy_usb);
        if (pdata->is_ac_online)
                power_supply_unregister(&pda_psy_ac);
-#ifdef CONFIG_USB_OTG_UTILS
+#if IS_ENABLED(CONFIG_USB_PHY)
        if (!IS_ERR_OR_NULL(transceiver))
                usb_put_phy(transceiver);
 #endif
index 640ae6c..2c481b8 100644 (file)
@@ -186,6 +186,4 @@ source "drivers/usb/atm/Kconfig"
 
 source "drivers/usb/gadget/Kconfig"
 
-source "drivers/usb/otg/Kconfig"
-
 endif # USB_SUPPORT
index 8f5ebce..c41feba 100644 (file)
@@ -6,8 +6,6 @@
 
 obj-$(CONFIG_USB)              += core/
 
-obj-$(CONFIG_USB_OTG_UTILS)    += otg/
-
 obj-$(CONFIG_USB_DWC3)         += dwc3/
 
 obj-$(CONFIG_USB_MON)          += mon/
@@ -46,7 +44,7 @@ obj-$(CONFIG_USB_MICROTEK)    += image/
 obj-$(CONFIG_USB_SERIAL)       += serial/
 
 obj-$(CONFIG_USB)              += misc/
-obj-$(CONFIG_USB_OTG_UTILS)    += phy/
+obj-$(CONFIG_USB_PHY)          += phy/
 obj-$(CONFIG_EARLY_PRINTK_DBGP)        += early/
 
 obj-$(CONFIG_USB_ATM)          += atm/
index 3d90e61..519ead2 100644 (file)
@@ -1638,16 +1638,6 @@ static irqreturn_t udc_irq(struct ci13xxx *ci)
        return retval;
 }
 
-/**
- * udc_release: driver release function
- * @dev: device
- *
- * Currently does nothing
- */
-static void udc_release(struct device *dev)
-{
-}
-
 /**
  * udc_start: initialize gadget role
  * @ci: chipidea controller
@@ -1667,12 +1657,6 @@ static int udc_start(struct ci13xxx *ci)
 
        INIT_LIST_HEAD(&ci->gadget.ep_list);
 
-       dev_set_name(&ci->gadget.dev, "gadget");
-       ci->gadget.dev.dma_mask = dev->dma_mask;
-       ci->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask;
-       ci->gadget.dev.parent   = dev;
-       ci->gadget.dev.release  = udc_release;
-
        /* alloc resources */
        ci->qh_pool = dma_pool_create("ci13xxx_qh", dev,
                                       sizeof(struct ci13xxx_qh),
@@ -1710,17 +1694,11 @@ static int udc_start(struct ci13xxx *ci)
                        goto put_transceiver;
        }
 
-       retval = device_register(&ci->gadget.dev);
-       if (retval) {
-               put_device(&ci->gadget.dev);
-               goto put_transceiver;
-       }
-
        if (!IS_ERR_OR_NULL(ci->transceiver)) {
                retval = otg_set_peripheral(ci->transceiver->otg,
                                                &ci->gadget);
                if (retval)
-                       goto unreg_device;
+                       goto put_transceiver;
        }
 
        retval = usb_add_gadget_udc(dev, &ci->gadget);
@@ -1740,8 +1718,6 @@ remove_trans:
        }
 
        dev_err(dev, "error = %i\n", retval);
-unreg_device:
-       device_unregister(&ci->gadget.dev);
 put_transceiver:
        if (!IS_ERR_OR_NULL(ci->transceiver) && ci->global_phy)
                usb_put_phy(ci->transceiver);
@@ -1776,7 +1752,6 @@ static void udc_stop(struct ci13xxx *ci)
                if (ci->global_phy)
                        usb_put_phy(ci->transceiver);
        }
-       device_unregister(&ci->gadget.dev);
        /* my kobject is dynamic, I swear! */
        memset(&ci->gadget, 0, sizeof(ci->gadget));
 }
index 68e9a2c..ea5ee9c 100644 (file)
@@ -1,7 +1,6 @@
 config USB_DWC3
        tristate "DesignWare USB3 DRD Core Support"
        depends on (USB || USB_GADGET) && GENERIC_HARDIRQS
-       select USB_OTG_UTILS
        select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD
        help
          Say Y or M here if your system has a Dual Role SuperSpeed
index ffa6b00..c35d49d 100644 (file)
@@ -140,7 +140,8 @@ static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
  * Returns a pointer to the allocated event buffer structure on success
  * otherwise ERR_PTR(errno).
  */
-static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length)
+static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
+               unsigned length)
 {
        struct dwc3_event_buffer        *evt;
 
@@ -259,6 +260,17 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
        }
 }
 
+static void dwc3_core_num_eps(struct dwc3 *dwc)
+{
+       struct dwc3_hwparams    *parms = &dwc->hwparams;
+
+       dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
+       dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
+
+       dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n",
+                       dwc->num_in_eps, dwc->num_out_eps);
+}
+
 static void dwc3_cache_hwparams(struct dwc3 *dwc)
 {
        struct dwc3_hwparams    *parms = &dwc->hwparams;
@@ -335,13 +347,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
        if (dwc->revision < DWC3_REVISION_190A)
                reg |= DWC3_GCTL_U2RSTECN;
 
-       dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+       dwc3_core_num_eps(dwc);
 
-       ret = dwc3_event_buffers_setup(dwc);
-       if (ret) {
-               dev_err(dwc->dev, "failed to setup event buffers\n");
-               goto err0;
-       }
+       dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 
        return 0;
 
@@ -351,8 +359,6 @@ err0:
 
 static void dwc3_core_exit(struct dwc3 *dwc)
 {
-       dwc3_event_buffers_cleanup(dwc);
-
        usb_phy_shutdown(dwc->usb2_phy);
        usb_phy_shutdown(dwc->usb3_phy);
 }
@@ -428,12 +434,32 @@ static int dwc3_probe(struct platform_device *pdev)
                dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
        }
 
-       if (IS_ERR_OR_NULL(dwc->usb2_phy)) {
+       if (IS_ERR(dwc->usb2_phy)) {
+               ret = PTR_ERR(dwc->usb2_phy);
+
+               /*
+                * if -ENXIO is returned, it means PHY layer wasn't
+                * enabled, so it makes no sense to return -EPROBE_DEFER
+                * in that case, since no PHY driver will ever probe.
+                */
+               if (ret == -ENXIO)
+                       return ret;
+
                dev_err(dev, "no usb2 phy configured\n");
                return -EPROBE_DEFER;
        }
 
-       if (IS_ERR_OR_NULL(dwc->usb3_phy)) {
+       if (IS_ERR(dwc->usb3_phy)) {
+               ret = PTR_ERR(dwc->usb2_phy);
+
+               /*
+                * if -ENXIO is returned, it means PHY layer wasn't
+                * enabled, so it makes no sense to return -EPROBE_DEFER
+                * in that case, since no PHY driver will ever probe.
+                */
+               if (ret == -ENXIO)
+                       return ret;
+
                dev_err(dev, "no usb3 phy configured\n");
                return -EPROBE_DEFER;
        }
@@ -448,6 +474,10 @@ static int dwc3_probe(struct platform_device *pdev)
        dwc->regs_size  = resource_size(res);
        dwc->dev        = dev;
 
+       dev->dma_mask   = dev->parent->dma_mask;
+       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))
@@ -480,7 +510,18 @@ static int dwc3_probe(struct platform_device *pdev)
                goto err0;
        }
 
-       mode = DWC3_MODE(dwc->hwparams.hwparams0);
+       ret = dwc3_event_buffers_setup(dwc);
+       if (ret) {
+               dev_err(dwc->dev, "failed to setup event buffers\n");
+               goto err1;
+       }
+
+       if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
+               mode = DWC3_MODE_HOST;
+       else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
+               mode = DWC3_MODE_DEVICE;
+       else
+               mode = DWC3_MODE_DRD;
 
        switch (mode) {
        case DWC3_MODE_DEVICE:
@@ -488,7 +529,7 @@ static int dwc3_probe(struct platform_device *pdev)
                ret = dwc3_gadget_init(dwc);
                if (ret) {
                        dev_err(dev, "failed to initialize gadget\n");
-                       goto err1;
+                       goto err2;
                }
                break;
        case DWC3_MODE_HOST:
@@ -496,7 +537,7 @@ static int dwc3_probe(struct platform_device *pdev)
                ret = dwc3_host_init(dwc);
                if (ret) {
                        dev_err(dev, "failed to initialize host\n");
-                       goto err1;
+                       goto err2;
                }
                break;
        case DWC3_MODE_DRD:
@@ -504,32 +545,32 @@ static int dwc3_probe(struct platform_device *pdev)
                ret = dwc3_host_init(dwc);
                if (ret) {
                        dev_err(dev, "failed to initialize host\n");
-                       goto err1;
+                       goto err2;
                }
 
                ret = dwc3_gadget_init(dwc);
                if (ret) {
                        dev_err(dev, "failed to initialize gadget\n");
-                       goto err1;
+                       goto err2;
                }
                break;
        default:
                dev_err(dev, "Unsupported mode of operation %d\n", mode);
-               goto err1;
+               goto err2;
        }
        dwc->mode = mode;
 
        ret = dwc3_debugfs_init(dwc);
        if (ret) {
                dev_err(dev, "failed to initialize debugfs\n");
-               goto err2;
+               goto err3;
        }
 
        pm_runtime_allow(dev);
 
        return 0;
 
-err2:
+err3:
        switch (mode) {
        case DWC3_MODE_DEVICE:
                dwc3_gadget_exit(dwc);
@@ -546,6 +587,9 @@ err2:
                break;
        }
 
+err2:
+       dwc3_event_buffers_cleanup(dwc);
+
 err1:
        dwc3_core_exit(dwc);
 
@@ -583,12 +627,130 @@ static int dwc3_remove(struct platform_device *pdev)
                break;
        }
 
+       dwc3_event_buffers_cleanup(dwc);
        dwc3_free_event_buffers(dwc);
        dwc3_core_exit(dwc);
 
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int dwc3_prepare(struct device *dev)
+{
+       struct dwc3     *dwc = dev_get_drvdata(dev);
+       unsigned long   flags;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+
+       switch (dwc->mode) {
+       case DWC3_MODE_DEVICE:
+       case DWC3_MODE_DRD:
+               dwc3_gadget_prepare(dwc);
+               /* FALLTHROUGH */
+       case DWC3_MODE_HOST:
+       default:
+               dwc3_event_buffers_cleanup(dwc);
+               break;
+       }
+
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       return 0;
+}
+
+static void dwc3_complete(struct device *dev)
+{
+       struct dwc3     *dwc = dev_get_drvdata(dev);
+       unsigned long   flags;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+
+       switch (dwc->mode) {
+       case DWC3_MODE_DEVICE:
+       case DWC3_MODE_DRD:
+               dwc3_gadget_complete(dwc);
+               /* FALLTHROUGH */
+       case DWC3_MODE_HOST:
+       default:
+               dwc3_event_buffers_setup(dwc);
+               break;
+       }
+
+       spin_unlock_irqrestore(&dwc->lock, flags);
+}
+
+static int dwc3_suspend(struct device *dev)
+{
+       struct dwc3     *dwc = dev_get_drvdata(dev);
+       unsigned long   flags;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+
+       switch (dwc->mode) {
+       case DWC3_MODE_DEVICE:
+       case DWC3_MODE_DRD:
+               dwc3_gadget_suspend(dwc);
+               /* FALLTHROUGH */
+       case DWC3_MODE_HOST:
+       default:
+               /* do nothing */
+               break;
+       }
+
+       dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL);
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       usb_phy_shutdown(dwc->usb3_phy);
+       usb_phy_shutdown(dwc->usb2_phy);
+
+       return 0;
+}
+
+static int dwc3_resume(struct device *dev)
+{
+       struct dwc3     *dwc = dev_get_drvdata(dev);
+       unsigned long   flags;
+
+       usb_phy_init(dwc->usb3_phy);
+       usb_phy_init(dwc->usb2_phy);
+       msleep(100);
+
+       spin_lock_irqsave(&dwc->lock, flags);
+
+       dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
+
+       switch (dwc->mode) {
+       case DWC3_MODE_DEVICE:
+       case DWC3_MODE_DRD:
+               dwc3_gadget_resume(dwc);
+               /* FALLTHROUGH */
+       case DWC3_MODE_HOST:
+       default:
+               /* do nothing */
+               break;
+       }
+
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       pm_runtime_disable(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
+       return 0;
+}
+
+static const struct dev_pm_ops dwc3_dev_pm_ops = {
+       .prepare        = dwc3_prepare,
+       .complete       = dwc3_complete,
+
+       SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
+};
+
+#define DWC3_PM_OPS    &(dwc3_dev_pm_ops)
+#else
+#define DWC3_PM_OPS    NULL
+#endif
+
 #ifdef CONFIG_OF
 static const struct of_device_id of_dwc3_match[] = {
        {
@@ -605,6 +767,7 @@ static struct platform_driver dwc3_driver = {
        .driver         = {
                .name   = "dwc3",
                .of_match_table = of_match_ptr(of_dwc3_match),
+               .pm     = DWC3_PM_OPS,
        },
 };
 
index b417506..b69d322 100644 (file)
 /* OTG Registers */
 #define DWC3_OCFG              0xcc00
 #define DWC3_OCTL              0xcc04
-#define DWC3_OEVTEN            0xcc08
-#define DWC3_OSTS              0xcc0C
+#define DWC3_OEVT              0xcc08
+#define DWC3_OEVTEN            0xcc0C
+#define DWC3_OSTS              0xcc10
 
 /* Bit fields */
 
@@ -369,6 +370,9 @@ struct dwc3_trb;
  * @list: a list of event buffers
  * @buf: _THE_ buffer
  * @length: size of this buffer
+ * @lpos: event offset
+ * @count: cache of last read event count register
+ * @flags: flags related to this event buffer
  * @dma: dma_addr_t
  * @dwc: pointer to DWC controller
  */
@@ -376,6 +380,10 @@ struct dwc3_event_buffer {
        void                    *buf;
        unsigned                length;
        unsigned int            lpos;
+       unsigned int            count;
+       unsigned int            flags;
+
+#define DWC3_EVENT_PENDING     BIT(0)
 
        dma_addr_t              dma;
 
@@ -487,12 +495,6 @@ enum dwc3_link_state {
        DWC3_LINK_STATE_MASK            = 0x0f,
 };
 
-enum dwc3_device_state {
-       DWC3_DEFAULT_STATE,
-       DWC3_ADDRESS_STATE,
-       DWC3_CONFIGURED_STATE,
-};
-
 /* TRB Length, PCM and Status */
 #define DWC3_TRB_SIZE_MASK     (0x00ffffff)
 #define DWC3_TRB_SIZE_LENGTH(n)        ((n) & DWC3_TRB_SIZE_MASK)
@@ -574,6 +576,14 @@ struct dwc3_hwparams {
 /* HWPARAMS1 */
 #define DWC3_NUM_INT(n)                (((n) & (0x3f << 15)) >> 15)
 
+/* HWPARAMS3 */
+#define DWC3_NUM_IN_EPS_MASK   (0x1f << 18)
+#define DWC3_NUM_EPS_MASK      (0x3f << 12)
+#define DWC3_NUM_EPS(p)                (((p)->hwparams3 &              \
+                       (DWC3_NUM_EPS_MASK)) >> 12)
+#define DWC3_NUM_IN_EPS(p)     (((p)->hwparams3 &              \
+                       (DWC3_NUM_IN_EPS_MASK)) >> 18)
+
 /* HWPARAMS7 */
 #define DWC3_RAM1_DEPTH(n)     ((n) & 0xffff)
 
@@ -618,7 +628,6 @@ struct dwc3_scratchpad_array {
  * @gadget_driver: pointer to the gadget driver
  * @regs: base address for our registers
  * @regs_size: address space size
- * @irq: IRQ number
  * @num_event_buffers: calculated number of event buffers
  * @u1u2: only used on revisions <1.83a for workaround
  * @maximum_speed: maximum speed requested (mainly for testing purposes)
@@ -626,6 +635,8 @@ struct dwc3_scratchpad_array {
  * @mode: mode of operation
  * @usb2_phy: pointer to USB2 PHY
  * @usb3_phy: pointer to USB3 PHY
+ * @dcfg: saved contents of DCFG register
+ * @gctl: saved contents of GCTL register
  * @is_selfpowered: true when we are selfpowered
  * @three_stage_setup: set if we perform a three phase setup
  * @ep0_bounced: true when we used bounce buffer
@@ -639,6 +650,8 @@ struct dwc3_scratchpad_array {
  * @u2pel: parameter from Set SEL request.
  * @u1sel: parameter from Set SEL request.
  * @u1pel: parameter from Set SEL request.
+ * @num_out_eps: number of out endpoints
+ * @num_in_eps: number of in endpoints
  * @ep0_next_event: hold the next expected event
  * @ep0state: state of endpoint zero
  * @link_state: link state
@@ -656,8 +669,10 @@ struct dwc3 {
        dma_addr_t              ep0_trb_addr;
        dma_addr_t              ep0_bounce_addr;
        struct dwc3_request     ep0_usb_req;
+
        /* device lock */
        spinlock_t              lock;
+
        struct device           *dev;
 
        struct platform_device  *xhci;
@@ -675,6 +690,10 @@ struct dwc3 {
        void __iomem            *regs;
        size_t                  regs_size;
 
+       /* used for suspend/resume */
+       u32                     dcfg;
+       u32                     gctl;
+
        u32                     num_event_buffers;
        u32                     u1u2;
        u32                     maximum_speed;
@@ -694,6 +713,9 @@ struct dwc3 {
 #define DWC3_REVISION_202A     0x5533202a
 #define DWC3_REVISION_210A     0x5533210a
 #define DWC3_REVISION_220A     0x5533220a
+#define DWC3_REVISION_230A     0x5533230a
+#define DWC3_REVISION_240A     0x5533240a
+#define DWC3_REVISION_250A     0x5533250a
 
        unsigned                is_selfpowered:1;
        unsigned                three_stage_setup:1;
@@ -704,11 +726,11 @@ struct dwc3 {
        unsigned                delayed_status:1;
        unsigned                needs_fifo_resize:1;
        unsigned                resize_fifos:1;
+       unsigned                pullups_connected:1;
 
        enum dwc3_ep0_next      ep0_next_event;
        enum dwc3_ep0_state     ep0state;
        enum dwc3_link_state    link_state;
-       enum dwc3_device_state  dev_state;
 
        u16                     isoch_delay;
        u16                     u2sel;
@@ -718,6 +740,9 @@ struct dwc3 {
 
        u8                      speed;
 
+       u8                      num_out_eps;
+       u8                      num_in_eps;
+
        void                    *mem;
 
        struct dwc3_hwparams    hwparams;
@@ -884,4 +909,31 @@ static inline void dwc3_gadget_exit(struct dwc3 *dwc)
 { }
 #endif
 
+/* power management interface */
+#if !IS_ENABLED(CONFIG_USB_DWC3_HOST)
+int dwc3_gadget_prepare(struct dwc3 *dwc);
+void dwc3_gadget_complete(struct dwc3 *dwc);
+int dwc3_gadget_suspend(struct dwc3 *dwc);
+int dwc3_gadget_resume(struct dwc3 *dwc);
+#else
+static inline int dwc3_gadget_prepare(struct dwc3 *dwc)
+{
+       return 0;
+}
+
+static inline void dwc3_gadget_complete(struct dwc3 *dwc)
+{
+}
+
+static inline int dwc3_gadget_suspend(struct dwc3 *dwc)
+{
+       return 0;
+}
+
+static inline int dwc3_gadget_resume(struct dwc3 *dwc)
+{
+       return 0;
+}
+#endif /* !IS_ENABLED(CONFIG_USB_DWC3_HOST) */
+
 #endif /* __DRIVERS_USB_DWC3_CORE_H */
index 4a752e7..9e9f122 100644 (file)
@@ -59,7 +59,7 @@
        .offset = DWC3_ ##nm - DWC3_GLOBALS_REGS_START, \
 }
 
-static struct debugfs_reg32 dwc3_regs[] = {
+static const struct debugfs_reg32 dwc3_regs[] = {
        dump_register(GSBUSCFG0),
        dump_register(GSBUSCFG1),
        dump_register(GTXTHRCFG),
@@ -372,6 +372,7 @@ static struct debugfs_reg32 dwc3_regs[] = {
 
        dump_register(OCFG),
        dump_register(OCTL),
+       dump_register(OEVT),
        dump_register(OEVTEN),
        dump_register(OSTS),
 };
@@ -577,8 +578,14 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused)
        case DWC3_LINK_STATE_LPBK:
                seq_printf(s, "Loopback\n");
                break;
+       case DWC3_LINK_STATE_RESET:
+               seq_printf(s, "Reset\n");
+               break;
+       case DWC3_LINK_STATE_RESUME:
+               seq_printf(s, "Resume\n");
+               break;
        default:
-               seq_printf(s, "UNKNOWN %d\n", reg);
+               seq_printf(s, "UNKNOWN %d\n", state);
        }
 
        return 0;
@@ -661,28 +668,31 @@ int dwc3_debugfs_init(struct dwc3 *dwc)
                goto err1;
        }
 
-#if IS_ENABLED(CONFIG_USB_DWC3_GADGET)
-       file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
-                       dwc, &dwc3_mode_fops);
-       if (!file) {
-               ret = -ENOMEM;
-               goto err1;
-       }
-
-       file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root,
-                       dwc, &dwc3_testmode_fops);
-       if (!file) {
-               ret = -ENOMEM;
-               goto err1;
+       if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)) {
+               file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
+                               dwc, &dwc3_mode_fops);
+               if (!file) {
+                       ret = -ENOMEM;
+                       goto err1;
+               }
        }
 
-       file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root,
-                       dwc, &dwc3_link_state_fops);
-       if (!file) {
-               ret = -ENOMEM;
-               goto err1;
+       if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) ||
+                       IS_ENABLED(CONFIG_USB_DWC3_GADGET)) {
+               file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root,
+                               dwc, &dwc3_testmode_fops);
+               if (!file) {
+                       ret = -ENOMEM;
+                       goto err1;
+               }
+
+               file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root,
+                               dwc, &dwc3_link_state_fops);
+               if (!file) {
+                       ret = -ENOMEM;
+                       goto err1;
+               }
        }
-#endif
 
        return 0;
 
index b082bec..a8afe6e 100644 (file)
@@ -22,9 +22,9 @@
 #include <linux/usb/otg.h>
 #include <linux/usb/nop-usb-xceiv.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 
 struct dwc3_exynos {
-       struct platform_device  *dwc3;
        struct platform_device  *usb2_phy;
        struct platform_device  *usb3_phy;
        struct device           *dev;
@@ -86,21 +86,30 @@ err1:
        return ret;
 }
 
+static int dwc3_exynos_remove_child(struct device *dev, void *unused)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+
+       platform_device_unregister(pdev);
+
+       return 0;
+}
+
 static u64 dwc3_exynos_dma_mask = DMA_BIT_MASK(32);
 
 static int dwc3_exynos_probe(struct platform_device *pdev)
 {
-       struct platform_device  *dwc3;
        struct dwc3_exynos      *exynos;
        struct clk              *clk;
        struct device           *dev = &pdev->dev;
+       struct device_node      *node = dev->of_node;
 
        int                     ret = -ENOMEM;
 
        exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL);
        if (!exynos) {
                dev_err(dev, "not enough memory\n");
-               return -ENOMEM;
+               goto err1;
        }
 
        /*
@@ -108,21 +117,15 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
         * Since shared usb code relies on it, set it here for now.
         * Once we move to full device tree support this will vanish off.
         */
-       if (!pdev->dev.dma_mask)
-               pdev->dev.dma_mask = &dwc3_exynos_dma_mask;
+       if (!dev->dma_mask)
+               dev->dma_mask = &dwc3_exynos_dma_mask;
 
        platform_set_drvdata(pdev, exynos);
 
        ret = dwc3_exynos_register_phys(exynos);
        if (ret) {
                dev_err(dev, "couldn't register PHYs\n");
-               return ret;
-       }
-
-       dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
-       if (!dwc3) {
-               dev_err(dev, "couldn't allocate dwc3 device\n");
-               return -ENOMEM;
+               goto err1;
        }
 
        clk = devm_clk_get(dev, "usbdrd30");
@@ -132,37 +135,28 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
                goto err1;
        }
 
-       dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
-
-       dwc3->dev.parent = dev;
-       dwc3->dev.dma_mask = dev->dma_mask;
-       dwc3->dev.dma_parms = dev->dma_parms;
-       exynos->dwc3    = dwc3;
        exynos->dev     = dev;
        exynos->clk     = clk;
 
-       clk_enable(exynos->clk);
-
-       ret = platform_device_add_resources(dwc3, pdev->resource,
-                       pdev->num_resources);
-       if (ret) {
-               dev_err(dev, "couldn't add resources to dwc3 device\n");
-               goto err2;
-       }
-
-       ret = platform_device_add(dwc3);
-       if (ret) {
-               dev_err(dev, "failed to register dwc3 device\n");
+       clk_prepare_enable(exynos->clk);
+
+       if (node) {
+               ret = of_platform_populate(node, NULL, NULL, dev);
+               if (ret) {
+                       dev_err(dev, "failed to add dwc3 core\n");
+                       goto err2;
+               }
+       } else {
+               dev_err(dev, "no device node, failed to add dwc3 core\n");
+               ret = -ENODEV;
                goto err2;
        }
 
        return 0;
 
 err2:
-       clk_disable(clk);
+       clk_disable_unprepare(clk);
 err1:
-       platform_device_put(dwc3);
-
        return ret;
 }
 
@@ -170,11 +164,11 @@ static int dwc3_exynos_remove(struct platform_device *pdev)
 {
        struct dwc3_exynos      *exynos = platform_get_drvdata(pdev);
 
-       platform_device_unregister(exynos->dwc3);
        platform_device_unregister(exynos->usb2_phy);
        platform_device_unregister(exynos->usb3_phy);
+       device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child);
 
-       clk_disable(exynos->clk);
+       clk_disable_unprepare(exynos->clk);
 
        return 0;
 }
@@ -187,12 +181,46 @@ static const struct of_device_id exynos_dwc3_match[] = {
 MODULE_DEVICE_TABLE(of, exynos_dwc3_match);
 #endif
 
+#ifdef CONFIG_PM_SLEEP
+static int dwc3_exynos_suspend(struct device *dev)
+{
+       struct dwc3_exynos *exynos = dev_get_drvdata(dev);
+
+       clk_disable(exynos->clk);
+
+       return 0;
+}
+
+static int dwc3_exynos_resume(struct device *dev)
+{
+       struct dwc3_exynos *exynos = dev_get_drvdata(dev);
+
+       clk_enable(exynos->clk);
+
+       /* runtime set active to reflect active state. */
+       pm_runtime_disable(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
+       return 0;
+}
+
+static const struct dev_pm_ops dwc3_exynos_dev_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(dwc3_exynos_suspend, dwc3_exynos_resume)
+};
+
+#define DEV_PM_OPS     (&dwc3_exynos_dev_pm_ops)
+#else
+#define DEV_PM_OPS     NULL
+#endif /* CONFIG_PM_SLEEP */
+
 static struct platform_driver dwc3_exynos_driver = {
        .probe          = dwc3_exynos_probe,
        .remove         = dwc3_exynos_remove,
        .driver         = {
                .name   = "exynos-dwc3",
                .of_match_table = of_match_ptr(exynos_dwc3_match),
+               .pm     = DEV_PM_OPS,
        },
 };
 
index afa05e3..34638b9 100644 (file)
@@ -52,7 +52,6 @@
 #include <linux/of_platform.h>
 
 #include <linux/usb/otg.h>
-#include <linux/usb/nop-usb-xceiv.h>
 
 /*
  * All these registers belong to OMAP's Wrapper around the
@@ -117,20 +116,17 @@ struct dwc3_omap {
        /* device lock */
        spinlock_t              lock;
 
-       struct platform_device  *usb2_phy;
-       struct platform_device  *usb3_phy;
        struct device           *dev;
 
        int                     irq;
        void __iomem            *base;
 
-       void                    *context;
-       u32                     resource_size;
+       u32                     utmi_otg_status;
 
        u32                     dma_status:1;
 };
 
-struct dwc3_omap               *_omap;
+static struct dwc3_omap                *_omap;
 
 static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset)
 {
@@ -142,11 +138,14 @@ static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value)
        writel(value, base + offset);
 }
 
-void dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
+int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
 {
        u32                     val;
        struct dwc3_omap        *omap = _omap;
 
+       if (!omap)
+               return -EPROBE_DEFER;
+
        switch (status) {
        case OMAP_DWC3_ID_GROUND:
                dev_dbg(omap->dev, "ID GND\n");
@@ -189,63 +188,9 @@ void dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
                dev_dbg(omap->dev, "ID float\n");
        }
 
-       return;
-}
-EXPORT_SYMBOL_GPL(dwc3_omap_mailbox);
-
-static int dwc3_omap_register_phys(struct dwc3_omap *omap)
-{
-       struct nop_usb_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);
-       if (!pdev)
-               return -ENOMEM;
-
-       omap->usb2_phy = pdev;
-       pdata.type = USB_PHY_TYPE_USB2;
-
-       ret = platform_device_add_data(omap->usb2_phy, &pdata, sizeof(pdata));
-       if (ret)
-               goto err1;
-
-       pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
-       if (!pdev) {
-               ret = -ENOMEM;
-               goto err1;
-       }
-
-       omap->usb3_phy = pdev;
-       pdata.type = USB_PHY_TYPE_USB3;
-
-       ret = platform_device_add_data(omap->usb3_phy, &pdata, sizeof(pdata));
-       if (ret)
-               goto err2;
-
-       ret = platform_device_add(omap->usb2_phy);
-       if (ret)
-               goto err2;
-
-       ret = platform_device_add(omap->usb3_phy);
-       if (ret)
-               goto err3;
-
        return 0;
-
-err3:
-       platform_device_del(omap->usb2_phy);
-
-err2:
-       platform_device_put(omap->usb3_phy);
-
-err1:
-       platform_device_put(omap->usb2_phy);
-
-       return ret;
 }
+EXPORT_SYMBOL_GPL(dwc3_omap_mailbox);
 
 static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
 {
@@ -307,24 +252,57 @@ static int dwc3_omap_remove_core(struct device *dev, void *c)
        return 0;
 }
 
+static void dwc3_omap_enable_irqs(struct dwc3_omap *omap)
+{
+       u32                     reg;
+
+       /* enable all IRQs */
+       reg = USBOTGSS_IRQO_COREIRQ_ST;
+       dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
+
+       reg = (USBOTGSS_IRQ1_OEVT |
+                       USBOTGSS_IRQ1_DRVVBUS_RISE |
+                       USBOTGSS_IRQ1_CHRGVBUS_RISE |
+                       USBOTGSS_IRQ1_DISCHRGVBUS_RISE |
+                       USBOTGSS_IRQ1_IDPULLUP_RISE |
+                       USBOTGSS_IRQ1_DRVVBUS_FALL |
+                       USBOTGSS_IRQ1_CHRGVBUS_FALL |
+                       USBOTGSS_IRQ1_DISCHRGVBUS_FALL |
+                       USBOTGSS_IRQ1_IDPULLUP_FALL);
+
+       dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
+}
+
+static void dwc3_omap_disable_irqs(struct dwc3_omap *omap)
+{
+       /* disable all IRQs */
+       dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, 0x00);
+       dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, 0x00);
+}
+
+static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32);
+
 static int dwc3_omap_probe(struct platform_device *pdev)
 {
-       struct dwc3_omap_data   *pdata = pdev->dev.platform_data;
        struct device_node      *node = pdev->dev.of_node;
 
        struct dwc3_omap        *omap;
        struct resource         *res;
        struct device           *dev = &pdev->dev;
 
-       int                     size;
        int                     ret = -ENOMEM;
        int                     irq;
 
-       const u32               *utmi_mode;
+       int                     utmi_mode = 0;
+
        u32                     reg;
 
        void __iomem            *base;
-       void                    *context;
+
+       if (!node) {
+               dev_err(dev, "device node not found\n");
+               return -EINVAL;
+       }
 
        omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
        if (!omap) {
@@ -334,13 +312,13 @@ static int dwc3_omap_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, omap);
 
-       irq = platform_get_irq(pdev, 1);
+       irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                dev_err(dev, "missing IRQ resource\n");
                return -EINVAL;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                dev_err(dev, "missing memory base resource\n");
                return -EINVAL;
@@ -352,25 +330,12 @@ static int dwc3_omap_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
-       ret = dwc3_omap_register_phys(omap);
-       if (ret) {
-               dev_err(dev, "couldn't register PHYs\n");
-               return ret;
-       }
-
-       context = devm_kzalloc(dev, resource_size(res), GFP_KERNEL);
-       if (!context) {
-               dev_err(dev, "couldn't allocate dwc3 context memory\n");
-               return -ENOMEM;
-       }
-
        spin_lock_init(&omap->lock);
 
-       omap->resource_size = resource_size(res);
-       omap->context   = context;
        omap->dev       = dev;
        omap->irq       = irq;
        omap->base      = base;
+       dev->dma_mask   = &dwc3_omap_dma_mask;
 
        /*
         * REVISIT if we ever have two instances of the wrapper, we will be
@@ -387,25 +352,17 @@ static int dwc3_omap_probe(struct platform_device *pdev)
 
        reg = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
 
-       utmi_mode = of_get_property(node, "utmi-mode", &size);
-       if (utmi_mode && size == sizeof(*utmi_mode)) {
-               reg |= *utmi_mode;
-       } else {
-               if (!pdata) {
-                       dev_dbg(dev, "missing platform data\n");
-               } else {
-                       switch (pdata->utmi_mode) {
-                       case DWC3_OMAP_UTMI_MODE_SW:
-                               reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
-                               break;
-                       case DWC3_OMAP_UTMI_MODE_HW:
-                               reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
-                               break;
-                       default:
-                               dev_dbg(dev, "UNKNOWN utmi mode %d\n",
-                                               pdata->utmi_mode);
-                       }
-               }
+       of_property_read_u32(node, "utmi-mode", &utmi_mode);
+
+       switch (utmi_mode) {
+       case DWC3_OMAP_UTMI_MODE_SW:
+               reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+               break;
+       case DWC3_OMAP_UTMI_MODE_HW:
+               reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+               break;
+       default:
+               dev_dbg(dev, "UNKNOWN utmi mode %d\n", utmi_mode);
        }
 
        dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
@@ -422,29 +379,12 @@ static int dwc3_omap_probe(struct platform_device *pdev)
                return ret;
        }
 
-       /* enable all IRQs */
-       reg = USBOTGSS_IRQO_COREIRQ_ST;
-       dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
+       dwc3_omap_enable_irqs(omap);
 
-       reg = (USBOTGSS_IRQ1_OEVT |
-                       USBOTGSS_IRQ1_DRVVBUS_RISE |
-                       USBOTGSS_IRQ1_CHRGVBUS_RISE |
-                       USBOTGSS_IRQ1_DISCHRGVBUS_RISE |
-                       USBOTGSS_IRQ1_IDPULLUP_RISE |
-                       USBOTGSS_IRQ1_DRVVBUS_FALL |
-                       USBOTGSS_IRQ1_CHRGVBUS_FALL |
-                       USBOTGSS_IRQ1_DISCHRGVBUS_FALL |
-                       USBOTGSS_IRQ1_IDPULLUP_FALL);
-
-       dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
-
-       if (node) {
-               ret = of_platform_populate(node, NULL, NULL, dev);
-               if (ret) {
-                       dev_err(&pdev->dev,
-                               "failed to add create dwc3 core\n");
-                       return ret;
-               }
+       ret = of_platform_populate(node, NULL, NULL, dev);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to create dwc3 core\n");
+               return ret;
        }
 
        return 0;
@@ -454,8 +394,7 @@ static int dwc3_omap_remove(struct platform_device *pdev)
 {
        struct dwc3_omap        *omap = platform_get_drvdata(pdev);
 
-       platform_device_unregister(omap->usb2_phy);
-       platform_device_unregister(omap->usb3_phy);
+       dwc3_omap_disable_irqs(omap);
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        device_for_each_child(&pdev->dev, NULL, dwc3_omap_remove_core);
@@ -465,18 +404,72 @@ static int dwc3_omap_remove(struct platform_device *pdev)
 
 static const struct of_device_id of_dwc3_match[] = {
        {
-               "ti,dwc3",
+               .compatible =   "ti,dwc3"
        },
        { },
 };
 MODULE_DEVICE_TABLE(of, of_dwc3_match);
 
+#ifdef CONFIG_PM_SLEEP
+static int dwc3_omap_prepare(struct device *dev)
+{
+       struct dwc3_omap        *omap = dev_get_drvdata(dev);
+
+       dwc3_omap_disable_irqs(omap);
+
+       return 0;
+}
+
+static void dwc3_omap_complete(struct device *dev)
+{
+       struct dwc3_omap        *omap = dev_get_drvdata(dev);
+
+       dwc3_omap_enable_irqs(omap);
+}
+
+static int dwc3_omap_suspend(struct device *dev)
+{
+       struct dwc3_omap        *omap = dev_get_drvdata(dev);
+
+       omap->utmi_otg_status = dwc3_omap_readl(omap->base,
+                       USBOTGSS_UTMI_OTG_STATUS);
+
+       return 0;
+}
+
+static int dwc3_omap_resume(struct device *dev)
+{
+       struct dwc3_omap        *omap = dev_get_drvdata(dev);
+
+       dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS,
+                       omap->utmi_otg_status);
+
+       pm_runtime_disable(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
+       return 0;
+}
+
+static const struct dev_pm_ops dwc3_omap_dev_pm_ops = {
+       .prepare        = dwc3_omap_prepare,
+       .complete       = dwc3_omap_complete,
+
+       SET_SYSTEM_SLEEP_PM_OPS(dwc3_omap_suspend, dwc3_omap_resume)
+};
+
+#define DEV_PM_OPS     (&dwc3_omap_dev_pm_ops)
+#else
+#define DEV_PM_OPS     NULL
+#endif /* CONFIG_PM_SLEEP */
+
 static struct platform_driver dwc3_omap_driver = {
        .probe          = dwc3_omap_probe,
        .remove         = dwc3_omap_remove,
        .driver         = {
                .name   = "omap-dwc3",
                .of_match_table = of_dwc3_match,
+               .pm     = DEV_PM_OPS,
        },
 };
 
index e8d7768..227d4a7 100644 (file)
@@ -212,11 +212,49 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
 };
 MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
 
+#ifdef CONFIG_PM
+static int dwc3_pci_suspend(struct device *dev)
+{
+       struct pci_dev  *pci = to_pci_dev(dev);
+
+       pci_disable_device(pci);
+
+       return 0;
+}
+
+static int dwc3_pci_resume(struct device *dev)
+{
+       struct pci_dev  *pci = to_pci_dev(dev);
+       int             ret;
+
+       ret = pci_enable_device(pci);
+       if (ret) {
+               dev_err(dev, "can't re-enable device --> %d\n", ret);
+               return ret;
+       }
+
+       pci_set_master(pci);
+
+       return 0;
+}
+
+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,
+       },
 };
 
 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
index 1d139ca..5acbb94 100644 (file)
@@ -394,10 +394,13 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
        u32                     wIndex;
        u32                     reg;
        int                     ret;
+       enum usb_device_state   state;
 
        wValue = le16_to_cpu(ctrl->wValue);
        wIndex = le16_to_cpu(ctrl->wIndex);
        recip = ctrl->bRequestType & USB_RECIP_MASK;
+       state = dwc->gadget.state;
+
        switch (recip) {
        case USB_RECIP_DEVICE:
 
@@ -409,7 +412,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
                 * default control pipe
                 */
                case USB_DEVICE_U1_ENABLE:
-                       if (dwc->dev_state != DWC3_CONFIGURED_STATE)
+                       if (state != USB_STATE_CONFIGURED)
                                return -EINVAL;
                        if (dwc->speed != DWC3_DSTS_SUPERSPEED)
                                return -EINVAL;
@@ -423,7 +426,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
                        break;
 
                case USB_DEVICE_U2_ENABLE:
-                       if (dwc->dev_state != DWC3_CONFIGURED_STATE)
+                       if (state != USB_STATE_CONFIGURED)
                                return -EINVAL;
                        if (dwc->speed != DWC3_DSTS_SUPERSPEED)
                                return -EINVAL;
@@ -493,6 +496,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
 
 static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 {
+       enum usb_device_state state = dwc->gadget.state;
        u32 addr;
        u32 reg;
 
@@ -502,7 +506,7 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
                return -EINVAL;
        }
 
-       if (dwc->dev_state == DWC3_CONFIGURED_STATE) {
+       if (state == USB_STATE_CONFIGURED) {
                dev_dbg(dwc->dev, "trying to set address when configured\n");
                return -EINVAL;
        }
@@ -513,9 +517,9 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
        dwc3_writel(dwc->regs, DWC3_DCFG, reg);
 
        if (addr)
-               dwc->dev_state = DWC3_ADDRESS_STATE;
+               usb_gadget_set_state(&dwc->gadget, USB_STATE_ADDRESS);
        else
-               dwc->dev_state = DWC3_DEFAULT_STATE;
+               usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT);
 
        return 0;
 }
@@ -532,6 +536,7 @@ static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 
 static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 {
+       enum usb_device_state state = dwc->gadget.state;
        u32 cfg;
        int ret;
        u32 reg;
@@ -539,16 +544,18 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
        dwc->start_config_issued = false;
        cfg = le16_to_cpu(ctrl->wValue);
 
-       switch (dwc->dev_state) {
-       case DWC3_DEFAULT_STATE:
+       switch (state) {
+       case USB_STATE_DEFAULT:
                return -EINVAL;
                break;
 
-       case DWC3_ADDRESS_STATE:
+       case USB_STATE_ADDRESS:
                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))) {
-                       dwc->dev_state = DWC3_CONFIGURED_STATE;
+                       usb_gadget_set_state(&dwc->gadget,
+                                       USB_STATE_CONFIGURED);
+
                        /*
                         * Enable transition to U1/U2 state when
                         * nothing is pending from application.
@@ -562,10 +569,11 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
                }
                break;
 
-       case DWC3_CONFIGURED_STATE:
+       case USB_STATE_CONFIGURED:
                ret = dwc3_ep0_delegate_req(dwc, ctrl);
                if (!cfg)
-                       dwc->dev_state = DWC3_ADDRESS_STATE;
+                       usb_gadget_set_state(&dwc->gadget,
+                                       USB_STATE_ADDRESS);
                break;
        default:
                ret = -EINVAL;
@@ -620,10 +628,11 @@ static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req)
 static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 {
        struct dwc3_ep  *dep;
+       enum usb_device_state state = dwc->gadget.state;
        u16             wLength;
        u16             wValue;
 
-       if (dwc->dev_state == DWC3_DEFAULT_STATE)
+       if (state == USB_STATE_DEFAULT)
                return -EINVAL;
 
        wValue = le16_to_cpu(ctrl->wValue);
index 82e160e..2b6e7e0 100644 (file)
@@ -1425,8 +1425,10 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
                if (dwc->revision >= DWC3_REVISION_194A)
                        reg &= ~DWC3_DCTL_KEEP_CONNECT;
                reg |= DWC3_DCTL_RUN_STOP;
+               dwc->pullups_connected = true;
        } else {
                reg &= ~DWC3_DCTL_RUN_STOP;
+               dwc->pullups_connected = false;
        }
 
        dwc3_writel(dwc->regs, DWC3_DCTL, reg);
@@ -1469,6 +1471,33 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
        return ret;
 }
 
+static void dwc3_gadget_enable_irq(struct dwc3 *dwc)
+{
+       u32                     reg;
+
+       /* Enable all but Start and End of Frame IRQs */
+       reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
+                       DWC3_DEVTEN_EVNTOVERFLOWEN |
+                       DWC3_DEVTEN_CMDCMPLTEN |
+                       DWC3_DEVTEN_ERRTICERREN |
+                       DWC3_DEVTEN_WKUPEVTEN |
+                       DWC3_DEVTEN_ULSTCNGEN |
+                       DWC3_DEVTEN_CONNECTDONEEN |
+                       DWC3_DEVTEN_USBRSTEN |
+                       DWC3_DEVTEN_DISCONNEVTEN);
+
+       dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
+}
+
+static void dwc3_gadget_disable_irq(struct dwc3 *dwc)
+{
+       /* mask all interrupts */
+       dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
+}
+
+static irqreturn_t dwc3_interrupt(int irq, void *_dwc);
+static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc);
+
 static int dwc3_gadget_start(struct usb_gadget *g,
                struct usb_gadget_driver *driver)
 {
@@ -1476,6 +1505,7 @@ static int dwc3_gadget_start(struct usb_gadget *g,
        struct dwc3_ep          *dep;
        unsigned long           flags;
        int                     ret = 0;
+       int                     irq;
        u32                     reg;
 
        spin_lock_irqsave(&dwc->lock, flags);
@@ -1489,7 +1519,6 @@ static int dwc3_gadget_start(struct usb_gadget *g,
        }
 
        dwc->gadget_driver      = driver;
-       dwc->gadget.dev.driver  = &driver->driver;
 
        reg = dwc3_readl(dwc->regs, DWC3_DCFG);
        reg &= ~(DWC3_DCFG_SPEED_MASK);
@@ -1536,6 +1565,17 @@ static int dwc3_gadget_start(struct usb_gadget *g,
        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;
@@ -1554,14 +1594,18 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
 {
        struct dwc3             *dwc = gadget_to_dwc(g);
        unsigned long           flags;
+       int                     irq;
 
        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]);
 
        dwc->gadget_driver      = NULL;
-       dwc->gadget.dev.driver  = NULL;
 
        spin_unlock_irqrestore(&dwc->lock, flags);
 
@@ -1579,14 +1623,15 @@ static const struct usb_gadget_ops dwc3_gadget_ops = {
 
 /* -------------------------------------------------------------------------- */
 
-static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
+static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
+               u8 num, u32 direction)
 {
        struct dwc3_ep                  *dep;
-       u8                              epnum;
+       u8                              i;
 
-       INIT_LIST_HEAD(&dwc->gadget.ep_list);
+       for (i = 0; i < num; i++) {
+               u8 epnum = (i << 1) | (!!direction);
 
-       for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
                dep = kzalloc(sizeof(*dep), GFP_KERNEL);
                if (!dep) {
                        dev_err(dwc->dev, "can't allocate endpoint %d\n",
@@ -1600,6 +1645,7 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
 
                snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1,
                                (epnum & 1) ? "in" : "out");
+
                dep->endpoint.name = dep->name;
                dep->direction = (epnum & 1);
 
@@ -1630,6 +1676,27 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
        return 0;
 }
 
+static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
+{
+       int                             ret;
+
+       INIT_LIST_HEAD(&dwc->gadget.ep_list);
+
+       ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_out_eps, 0);
+       if (ret < 0) {
+               dev_vdbg(dwc->dev, "failed to allocate OUT endpoints\n");
+               return ret;
+       }
+
+       ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_in_eps, 1);
+       if (ret < 0) {
+               dev_vdbg(dwc->dev, "failed to allocate IN endpoints\n");
+               return ret;
+       }
+
+       return 0;
+}
+
 static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
 {
        struct dwc3_ep                  *dep;
@@ -1637,6 +1704,9 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
 
        for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
                dep = dwc->eps[epnum];
+               if (!dep)
+                       continue;
+
                dwc3_free_trb_pool(dep);
 
                if (epnum != 0 && epnum != 1)
@@ -1646,12 +1716,8 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
        }
 }
 
-static void dwc3_gadget_release(struct device *dev)
-{
-       dev_dbg(dev, "%s\n", __func__);
-}
-
 /* -------------------------------------------------------------------------- */
+
 static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
                struct dwc3_request *req, struct dwc3_trb *trb,
                const struct dwc3_event_depevt *event, int status)
@@ -1975,6 +2041,9 @@ static void dwc3_stop_active_transfers(struct dwc3 *dwc)
                struct dwc3_ep *dep;
 
                dep = dwc->eps[epnum];
+               if (!dep)
+                       continue;
+
                if (!(dep->flags & DWC3_EP_ENABLED))
                        continue;
 
@@ -1992,6 +2061,8 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
                int ret;
 
                dep = dwc->eps[epnum];
+               if (!dep)
+                       continue;
 
                if (!(dep->flags & DWC3_EP_STALL))
                        continue;
@@ -2091,7 +2162,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
        }
 
        /* after reset -> Default State */
-       dwc->dev_state = DWC3_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) {
@@ -2277,6 +2348,34 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
                unsigned int evtinfo)
 {
        enum dwc3_link_state    next = evtinfo & DWC3_LINK_STATE_MASK;
+       unsigned int            pwropt;
+
+       /*
+        * WORKAROUND: DWC3 < 2.50a have an issue when configured without
+        * Hibernation mode enabled which would show up when device detects
+        * host-initiated U3 exit.
+        *
+        * In that case, device will generate a Link State Change Interrupt
+        * from U3 to RESUME which is only necessary if Hibernation is
+        * configured in.
+        *
+        * There are no functional changes due to such spurious event and we
+        * just need to ignore it.
+        *
+        * Refers to:
+        *
+        * STAR#9000570034 RTL: SS Resume event generated in non-Hibernation
+        * operational mode
+        */
+       pwropt = DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1);
+       if ((dwc->revision < DWC3_REVISION_250A) &&
+                       (pwropt != DWC3_GHWPARAMS1_EN_PWROPT_HIB)) {
+               if ((dwc->link_state == DWC3_LINK_STATE_U3) &&
+                               (next == DWC3_LINK_STATE_RESUME)) {
+                       dev_vdbg(dwc->dev, "ignoring transition U3 -> Resume\n");
+                       return;
+               }
+       }
 
        /*
         * WORKAROUND: DWC3 Revisions <1.83a have an issue which, depending
@@ -2387,40 +2486,73 @@ static void dwc3_process_event_entry(struct dwc3 *dwc,
        }
 }
 
+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++) {
+               struct dwc3_event_buffer *evt;
+               int                     left;
+
+               evt = dwc->ev_buffs[i];
+               left = evt->count;
+
+               if (!(evt->flags & DWC3_EVENT_PENDING))
+                       continue;
+
+               while (left > 0) {
+                       union dwc3_event event;
+
+                       event.raw = *(u32 *) (evt->buf + evt->lpos);
+
+                       dwc3_process_event_entry(dwc, &event);
+
+                       /*
+                        * 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_writel(dwc->regs, DWC3_GEVNTCOUNT(i), 4);
+               }
+
+               evt->count = 0;
+               evt->flags &= ~DWC3_EVENT_PENDING;
+               ret = IRQ_HANDLED;
+       }
+
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       return ret;
+}
+
 static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
 {
        struct dwc3_event_buffer *evt;
-       int left;
        u32 count;
 
+       evt = dwc->ev_buffs[buf];
+
        count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf));
        count &= DWC3_GEVNTCOUNT_MASK;
        if (!count)
                return IRQ_NONE;
 
-       evt = dwc->ev_buffs[buf];
-       left = count;
-
-       while (left > 0) {
-               union dwc3_event event;
-
-               event.raw = *(u32 *) (evt->buf + evt->lpos);
+       evt->count = count;
+       evt->flags |= DWC3_EVENT_PENDING;
 
-               dwc3_process_event_entry(dwc, &event);
-               /*
-                * XXX 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 were 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_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
-       }
-
-       return IRQ_HANDLED;
+       return IRQ_WAKE_THREAD;
 }
 
 static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
@@ -2435,7 +2567,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
                irqreturn_t status;
 
                status = dwc3_process_event_buf(dwc, i);
-               if (status == IRQ_HANDLED)
+               if (status == IRQ_WAKE_THREAD)
                        ret = status;
        }
 
@@ -2454,7 +2586,6 @@ int dwc3_gadget_init(struct dwc3 *dwc)
 {
        u32                                     reg;
        int                                     ret;
-       int                                     irq;
 
        dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
                        &dwc->ctrl_req_addr, GFP_KERNEL);
@@ -2488,19 +2619,10 @@ int dwc3_gadget_init(struct dwc3 *dwc)
                goto err3;
        }
 
-       dev_set_name(&dwc->gadget.dev, "gadget");
-
        dwc->gadget.ops                 = &dwc3_gadget_ops;
        dwc->gadget.max_speed           = USB_SPEED_SUPER;
        dwc->gadget.speed               = USB_SPEED_UNKNOWN;
-       dwc->gadget.dev.parent          = dwc->dev;
        dwc->gadget.sg_supported        = true;
-
-       dma_set_coherent_mask(&dwc->gadget.dev, dwc->dev->coherent_dma_mask);
-
-       dwc->gadget.dev.dma_parms       = dwc->dev->dma_parms;
-       dwc->gadget.dev.dma_mask        = dwc->dev->dma_mask;
-       dwc->gadget.dev.release         = dwc3_gadget_release;
        dwc->gadget.name                = "dwc3-gadget";
 
        /*
@@ -2512,60 +2634,24 @@ int dwc3_gadget_init(struct dwc3 *dwc)
        if (ret)
                goto err4;
 
-       irq = platform_get_irq(to_platform_device(dwc->dev), 0);
-
-       ret = request_irq(irq, dwc3_interrupt, IRQF_SHARED,
-                       "dwc3", dwc);
-       if (ret) {
-               dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
-                               irq, ret);
-               goto err5;
-       }
-
        reg = dwc3_readl(dwc->regs, DWC3_DCFG);
        reg |= DWC3_DCFG_LPM_CAP;
        dwc3_writel(dwc->regs, DWC3_DCFG, reg);
 
-       /* Enable all but Start and End of Frame IRQs */
-       reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
-                       DWC3_DEVTEN_EVNTOVERFLOWEN |
-                       DWC3_DEVTEN_CMDCMPLTEN |
-                       DWC3_DEVTEN_ERRTICERREN |
-                       DWC3_DEVTEN_WKUPEVTEN |
-                       DWC3_DEVTEN_ULSTCNGEN |
-                       DWC3_DEVTEN_CONNECTDONEEN |
-                       DWC3_DEVTEN_USBRSTEN |
-                       DWC3_DEVTEN_DISCONNEVTEN);
-       dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
-
-       /* automatic phy suspend only on recent versions */
+       /* 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 = device_register(&dwc->gadget.dev);
-       if (ret) {
-               dev_err(dwc->dev, "failed to register gadget device\n");
-               put_device(&dwc->gadget.dev);
-               goto err6;
-       }
-
        ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
        if (ret) {
                dev_err(dwc->dev, "failed to register udc\n");
-               goto err7;
+               goto err5;
        }
 
        return 0;
 
-err7:
-       device_unregister(&dwc->gadget.dev);
-
-err6:
-       dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
-       free_irq(irq, dwc);
-
 err5:
        dwc3_gadget_free_endpoints(dwc);
 
@@ -2588,15 +2674,11 @@ err0:
        return ret;
 }
 
+/* -------------------------------------------------------------------------- */
+
 void dwc3_gadget_exit(struct dwc3 *dwc)
 {
-       int                     irq;
-
        usb_del_gadget_udc(&dwc->gadget);
-       irq = platform_get_irq(to_platform_device(dwc->dev), 0);
-
-       dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
-       free_irq(irq, dwc);
 
        dwc3_gadget_free_endpoints(dwc);
 
@@ -2610,6 +2692,63 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
 
        dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
                        dwc->ctrl_req, dwc->ctrl_req_addr);
+}
 
-       device_unregister(&dwc->gadget.dev);
+int dwc3_gadget_prepare(struct dwc3 *dwc)
+{
+       if (dwc->pullups_connected)
+               dwc3_gadget_disable_irq(dwc);
+
+       return 0;
+}
+
+void dwc3_gadget_complete(struct dwc3 *dwc)
+{
+       if (dwc->pullups_connected) {
+               dwc3_gadget_enable_irq(dwc);
+               dwc3_gadget_run_stop(dwc, true);
+       }
+}
+
+int dwc3_gadget_suspend(struct dwc3 *dwc)
+{
+       __dwc3_gadget_ep_disable(dwc->eps[0]);
+       __dwc3_gadget_ep_disable(dwc->eps[1]);
+
+       dwc->dcfg = dwc3_readl(dwc->regs, DWC3_DCFG);
+
+       return 0;
+}
+
+int dwc3_gadget_resume(struct dwc3 *dwc)
+{
+       struct dwc3_ep          *dep;
+       int                     ret;
+
+       /* Start with SuperSpeed Default */
+       dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+
+       dep = dwc->eps[0];
+       ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
+       if (ret)
+               goto err0;
+
+       dep = dwc->eps[1];
+       ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
+       if (ret)
+               goto err1;
+
+       /* begin to receive SETUP packets */
+       dwc->ep0state = EP0_SETUP_PHASE;
+       dwc3_ep0_out_start(dwc);
+
+       dwc3_writel(dwc->regs, DWC3_DCFG, dwc->dcfg);
+
+       return 0;
+
+err1:
+       __dwc3_gadget_ep_disable(dwc->eps[0]);
+
+err0:
+       return ret;
 }
index c7525b1..a61d981 100644 (file)
@@ -196,7 +196,6 @@ config USB_OMAP
        tristate "OMAP USB Device Controller"
        depends on ARCH_OMAP1
        select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
-       select USB_OTG_UTILS if ARCH_OMAP
        help
           Many Texas Instruments OMAP processors have flexible full
           speed USB device controllers, with support for up to 30
@@ -211,7 +210,6 @@ config USB_OMAP
 config USB_PXA25X
        tristate "PXA 25x or IXP 4xx"
        depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
-       select USB_OTG_UTILS
        help
           Intel's PXA 25x series XScale ARM-5TE processors include
           an integrated full speed USB 1.1 device controller.  The
@@ -259,8 +257,6 @@ config USB_RENESAS_USBHS_UDC
 
 config USB_PXA27X
        tristate "PXA 27x"
-       depends on ARCH_PXA && (PXA27x || PXA3xx)
-       select USB_OTG_UTILS
        help
           Intel's PXA 27x series XScale ARM v5TE processors include
           an integrated full speed USB 1.1 device controller.
@@ -329,9 +325,6 @@ config USB_MV_UDC
 
 config USB_MV_U3D
        tristate "MARVELL PXA2128 USB 3.0 controller"
-       depends on CPU_MMP3
-       select USB_GADGET_DUALSPEED
-       select USB_GADGET_SUPERSPEED
        help
          MARVELL PXA2128 Processor series include a super speed USB3.0 device
          controller, which support super speed USB peripheral.
@@ -501,6 +494,7 @@ endmenu
 # composite based drivers
 config USB_LIBCOMPOSITE
        tristate
+       select CONFIGFS_FS
        depends on USB_GADGET
 
 config USB_F_ACM
@@ -512,6 +506,12 @@ config USB_F_SS_LB
 config USB_U_SERIAL
        tristate
 
+config USB_F_SERIAL
+       tristate
+
+config USB_F_OBEX
+       tristate
+
 choice
        tristate "USB Gadget Drivers"
        default USB_ETH
@@ -766,6 +766,8 @@ config USB_G_SERIAL
        depends on TTY
        select USB_U_SERIAL
        select USB_F_ACM
+       select USB_F_SERIAL
+       select USB_F_OBEX
        select USB_LIBCOMPOSITE
        help
          The Serial Gadget talks to the Linux-USB generic serial driver.
@@ -839,6 +841,7 @@ config USB_G_NOKIA
        depends on PHONET
        select USB_LIBCOMPOSITE
        select USB_U_SERIAL
+       select USB_F_ACM
        help
          The Nokia composite gadget provides support for acm, obex
          and phonet in only one composite gadget driver.
@@ -957,6 +960,7 @@ config USB_G_WEBCAM
        tristate "USB Webcam Gadget"
        depends on VIDEO_DEV
        select USB_LIBCOMPOSITE
+       select VIDEOBUF2_VMALLOC
        help
          The Webcam Gadget acts as a composite USB Audio and Video Class
          device. It provides a userspace API to process UVC control requests
index 82fb225..6afd166 100644 (file)
@@ -6,7 +6,7 @@ ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
 obj-$(CONFIG_USB_GADGET)       += udc-core.o
 obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o
 libcomposite-y                 := usbstring.o config.o epautoconf.o
-libcomposite-y                 += composite.o functions.o
+libcomposite-y                 += composite.o functions.o configfs.o
 obj-$(CONFIG_USB_DUMMY_HCD)    += dummy_hcd.o
 obj-$(CONFIG_USB_NET2272)      += net2272.o
 obj-$(CONFIG_USB_NET2280)      += net2280.o
@@ -36,10 +36,15 @@ obj-$(CONFIG_USB_FUSB300)   += fusb300_udc.o
 obj-$(CONFIG_USB_MV_U3D)       += mv_u3d_core.o
 
 # USB Functions
-obj-$(CONFIG_USB_F_ACM)                += f_acm.o
-f_ss_lb-y                      := f_loopback.o f_sourcesink.o
-obj-$(CONFIG_USB_F_SS_LB)      += f_ss_lb.o
+usb_f_acm-y                    := f_acm.o
+obj-$(CONFIG_USB_F_ACM)                += usb_f_acm.o
+usb_f_ss_lb-y                  := f_loopback.o f_sourcesink.o
+obj-$(CONFIG_USB_F_SS_LB)      += usb_f_ss_lb.o
 obj-$(CONFIG_USB_U_SERIAL)     += u_serial.o
+usb_f_serial-y                 := f_serial.o
+obj-$(CONFIG_USB_F_SERIAL)     += usb_f_serial.o
+usb_f_obex-y                   := f_obex.o
+obj-$(CONFIG_USB_F_OBEX)       += usb_f_obex.o
 
 #
 # USB gadget drivers
index 8f2b0e3..4b947bb 100644 (file)
@@ -109,7 +109,6 @@ FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
 static struct fsg_common fsg_common;
 
 /*-------------------------------------------------------------------------*/
-static unsigned char tty_line;
 static struct usb_function *f_acm;
 static struct usb_function_instance *f_acm_inst;
 /*
@@ -117,7 +116,6 @@ static struct usb_function_instance *f_acm_inst;
  */
 static int __init acm_ms_do_config(struct usb_configuration *c)
 {
-       struct f_serial_opts *opts;
        int     status;
 
        if (gadget_is_otg(c->cdev->gadget)) {
@@ -129,9 +127,6 @@ static int __init acm_ms_do_config(struct usb_configuration *c)
        if (IS_ERR(f_acm_inst))
                return PTR_ERR(f_acm_inst);
 
-       opts = container_of(f_acm_inst, struct f_serial_opts, func_inst);
-       opts->port_num = tty_line;
-
        f_acm = usb_get_function(f_acm_inst);
        if (IS_ERR(f_acm)) {
                status = PTR_ERR(f_acm);
@@ -171,16 +166,11 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev)
        int                     status;
        void                    *retp;
 
-       /* set up serial link layer */
-       status = gserial_alloc_line(&tty_line);
-       if (status < 0)
-               return status;
-
        /* set up mass storage function */
        retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data);
        if (IS_ERR(retp)) {
                status = PTR_ERR(retp);
-               goto fail0;
+               return PTR_ERR(retp);
        }
 
        /*
@@ -207,8 +197,6 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev)
        /* error recovery */
 fail1:
        fsg_common_put(&fsg_common);
-fail0:
-       gserial_free_line(tty_line);
        return status;
 }
 
@@ -216,7 +204,6 @@ static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)
 {
        usb_put_function(f_acm);
        usb_put_function_instance(f_acm_inst);
-       gserial_free_line(tty_line);
        return 0;
 }
 
index 75973f3..f52dcfe 100644 (file)
@@ -1922,7 +1922,6 @@ static int amd5536_udc_start(struct usb_gadget *g,
 
        driver->driver.bus = NULL;
        dev->driver = driver;
-       dev->gadget.dev.driver = &driver->driver;
 
        /* Some gadget drivers use both ep0 directions.
         * NOTE: to gadget driver, ep0 is just one endpoint...
@@ -1973,7 +1972,6 @@ static int amd5536_udc_stop(struct usb_gadget *g,
        shutdown(dev, driver);
        spin_unlock_irqrestore(&dev->lock, flags);
 
-       dev->gadget.dev.driver = NULL;
        dev->driver = NULL;
 
        /* set SD */
@@ -3080,7 +3078,6 @@ static void udc_pci_remove(struct pci_dev *pdev)
        if (dev->active)
                pci_disable_device(pdev);
 
-       device_unregister(&dev->gadget.dev);
        pci_set_drvdata(pdev, NULL);
 
        udc_remove(dev);
@@ -3245,8 +3242,6 @@ static int udc_pci_probe(
        dev->phys_addr = resource;
        dev->irq = pdev->irq;
        dev->pdev = pdev;
-       dev->gadget.dev.parent = &pdev->dev;
-       dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
 
        /* general probing */
        if (udc_probe(dev) == 0)
@@ -3273,7 +3268,6 @@ static int udc_probe(struct udc *dev)
        dev->gadget.ops = &udc_ops;
 
        dev_set_name(&dev->gadget.dev, "gadget");
-       dev->gadget.dev.release = gadget_release;
        dev->gadget.name = name;
        dev->gadget.max_speed = USB_SPEED_HIGH;
 
@@ -3297,17 +3291,11 @@ static int udc_probe(struct udc *dev)
                "driver version: %s(for Geode5536 B1)\n", tmp);
        udc = dev;
 
-       retval = usb_add_gadget_udc(&udc->pdev->dev, &dev->gadget);
+       retval = usb_add_gadget_udc_release(&udc->pdev->dev, &dev->gadget,
+                       gadget_release);
        if (retval)
                goto finished;
 
-       retval = device_register(&dev->gadget.dev);
-       if (retval) {
-               usb_del_gadget_udc(&dev->gadget);
-               put_device(&dev->gadget.dev);
-               goto finished;
-       }
-
        /* timer init */
        init_timer(&udc_timer);
        udc_timer.function = udc_timer_function;
index f1bf32e..6744d3b 100644 (file)
@@ -472,7 +472,6 @@ struct udc_request {
 
        /* flags */
        unsigned                        dma_going : 1,
-                                       dma_mapping : 1,
                                        dma_done : 1;
        /* phys. address */
        dma_addr_t                      td_phys;
index 45dd292..a690d64 100644 (file)
@@ -1631,7 +1631,6 @@ static int at91_start(struct usb_gadget *gadget,
 
        udc = container_of(gadget, struct at91_udc, gadget);
        udc->driver = driver;
-       udc->gadget.dev.driver = &driver->driver;
        udc->gadget.dev.of_node = udc->pdev->dev.of_node;
        udc->enabled = 1;
        udc->selfpowered = 1;
@@ -1652,7 +1651,6 @@ static int at91_stop(struct usb_gadget *gadget,
        at91_udp_write(udc, AT91_UDP_IDR, ~0);
        spin_unlock_irqrestore(&udc->lock, flags);
 
-       udc->gadget.dev.driver = NULL;
        udc->driver = NULL;
 
        DBG("unbound from %s\n", driver->driver.name);
@@ -1780,13 +1778,7 @@ static int at91udc_probe(struct platform_device *pdev)
                DBG("clocks missing\n");
                retval = -ENODEV;
                /* NOTE: we "know" here that refcounts on these are NOPs */
-               goto fail0b;
-       }
-
-       retval = device_register(&udc->gadget.dev);
-       if (retval < 0) {
-               put_device(&udc->gadget.dev);
-               goto fail0b;
+               goto fail1;
        }
 
        /* don't do anything until we have both gadget driver and VBUS */
@@ -1857,8 +1849,6 @@ fail3:
 fail2:
        free_irq(udc->udp_irq, udc);
 fail1:
-       device_unregister(&udc->gadget.dev);
-fail0b:
        iounmap(udc->udp_baseaddr);
 fail0a:
        if (cpu_is_at91rm9200())
@@ -1892,8 +1882,6 @@ static int __exit at91udc_remove(struct platform_device *pdev)
                gpio_free(udc->board.vbus_pin);
        }
        free_irq(udc->udp_irq, udc);
-       device_unregister(&udc->gadget.dev);
-
        iounmap(udc->udp_baseaddr);
 
        if (cpu_is_at91rm9200())
index b66130c..f2a970f 100644 (file)
@@ -489,13 +489,8 @@ request_complete(struct usba_ep *ep, struct usba_request *req, int status)
        if (req->req.status == -EINPROGRESS)
                req->req.status = status;
 
-       if (req->mapped) {
-               dma_unmap_single(
-                       &udc->pdev->dev, req->req.dma, req->req.length,
-                       ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-               req->req.dma = DMA_ADDR_INVALID;
-               req->mapped = 0;
-       }
+       if (req->using_dma)
+               usb_gadget_unmap_request(&udc->gadget, &req->req, ep->is_in);
 
        DBG(DBG_GADGET | DBG_REQ,
                "%s: req %p complete: status %d, actual %u\n",
@@ -684,7 +679,6 @@ usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
                return NULL;
 
        INIT_LIST_HEAD(&req->queue);
-       req->req.dma = DMA_ADDR_INVALID;
 
        return &req->req;
 }
@@ -717,20 +711,11 @@ static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,
                return -EINVAL;
        }
 
-       req->using_dma = 1;
-
-       if (req->req.dma == DMA_ADDR_INVALID) {
-               req->req.dma = dma_map_single(
-                       &udc->pdev->dev, req->req.buf, req->req.length,
-                       ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-               req->mapped = 1;
-       } else {
-               dma_sync_single_for_device(
-                       &udc->pdev->dev, req->req.dma, req->req.length,
-                       ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-               req->mapped = 0;
-       }
+       ret = usb_gadget_map_request(&udc->gadget, &req->req, ep->is_in);
+       if (ret)
+               return ret;
 
+       req->using_dma = 1;
        req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length)
                        | USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE
                        | USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE;
@@ -1799,7 +1784,6 @@ static int atmel_usba_start(struct usb_gadget *gadget,
 
        udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
        udc->driver = driver;
-       udc->gadget.dev.driver = &driver->driver;
        spin_unlock_irqrestore(&udc->lock, flags);
 
        clk_enable(udc->pclk);
@@ -1841,7 +1825,6 @@ static int atmel_usba_stop(struct usb_gadget *gadget,
        toggle_bias(0);
        usba_writel(udc, CTRL, USBA_DISABLE_MASK);
 
-       udc->gadget.dev.driver = NULL;
        udc->driver = NULL;
 
        clk_disable(udc->hclk);
@@ -1900,10 +1883,6 @@ static int __init usba_udc_probe(struct platform_device *pdev)
        dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n",
                 (unsigned long)fifo->start, udc->fifo);
 
-       device_initialize(&udc->gadget.dev);
-       udc->gadget.dev.parent = &pdev->dev;
-       udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
-
        platform_set_drvdata(pdev, udc);
 
        /* Make sure we start from a clean slate */
@@ -1962,12 +1941,6 @@ static int __init usba_udc_probe(struct platform_device *pdev)
        }
        udc->irq = irq;
 
-       ret = device_add(&udc->gadget.dev);
-       if (ret) {
-               dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret);
-               goto err_device_add;
-       }
-
        if (gpio_is_valid(pdata->vbus_pin)) {
                if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
                        udc->vbus_pin = pdata->vbus_pin;
@@ -2007,9 +1980,6 @@ err_add_udc:
                gpio_free(udc->vbus_pin);
        }
 
-       device_unregister(&udc->gadget.dev);
-
-err_device_add:
        free_irq(irq, udc);
 err_request_irq:
        kfree(usba_ep);
@@ -2053,8 +2023,6 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
        clk_put(udc->hclk);
        clk_put(udc->pclk);
 
-       device_unregister(&udc->gadget.dev);
-
        return 0;
 }
 
index 9791259..d65a618 100644 (file)
 #define EP0_EPT_SIZE           USBA_EPT_SIZE_64
 #define EP0_NR_BANKS           1
 
-/*
- * REVISIT: Try to eliminate this value. Can we rely on req->mapped to
- * provide this information?
- */
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-
 #define FIFO_IOMEM_ID  0
 #define CTRL_IOMEM_ID  1
 
index 8cc8253..6e65182 100644 (file)
@@ -1819,7 +1819,6 @@ static int bcm63xx_udc_start(struct usb_gadget *gadget,
 
        udc->driver = driver;
        driver->driver.bus = NULL;
-       udc->gadget.dev.driver = &driver->driver;
        udc->gadget.dev.of_node = udc->dev->of_node;
 
        spin_unlock_irqrestore(&udc->lock, flags);
@@ -1841,7 +1840,6 @@ static int bcm63xx_udc_stop(struct usb_gadget *gadget,
        spin_lock_irqsave(&udc->lock, flags);
 
        udc->driver = NULL;
-       udc->gadget.dev.driver = NULL;
 
        /*
         * If we switch the PHY too abruptly after dropping D+, the host
@@ -2305,17 +2303,6 @@ static void bcm63xx_udc_cleanup_debugfs(struct bcm63xx_udc *udc)
  * Driver init/exit
  ***********************************************************************/
 
-/**
- * bcm63xx_udc_gadget_release - Called from device_release().
- * @dev: Unused.
- *
- * We get a warning if this function doesn't exist, but it's empty because
- * we don't have to free any of the memory allocated with the devm_* APIs.
- */
-static void bcm63xx_udc_gadget_release(struct device *dev)
-{
-}
-
 /**
  * bcm63xx_udc_probe - Initialize a new instance of the UDC.
  * @pdev: Platform device struct from the bcm63xx BSP code.
@@ -2368,13 +2355,9 @@ static int bcm63xx_udc_probe(struct platform_device *pdev)
 
        spin_lock_init(&udc->lock);
        INIT_WORK(&udc->ep0_wq, bcm63xx_ep0_process);
-       dev_set_name(&udc->gadget.dev, "gadget");
 
        udc->gadget.ops = &bcm63xx_udc_ops;
        udc->gadget.name = dev_name(dev);
-       udc->gadget.dev.parent = dev;
-       udc->gadget.dev.release = bcm63xx_udc_gadget_release;
-       udc->gadget.dev.dma_mask = dev->dma_mask;
 
        if (!pd->use_fullspeed && !use_fullspeed)
                udc->gadget.max_speed = USB_SPEED_HIGH;
@@ -2414,17 +2397,12 @@ static int bcm63xx_udc_probe(struct platform_device *pdev)
                }
        }
 
-       rc = device_register(&udc->gadget.dev);
-       if (rc)
-               goto out_uninit;
-
        bcm63xx_udc_init_debugfs(udc);
        rc = usb_add_gadget_udc(dev, &udc->gadget);
        if (!rc)
                return 0;
 
        bcm63xx_udc_cleanup_debugfs(udc);
-       device_unregister(&udc->gadget.dev);
 out_uninit:
        bcm63xx_uninit_udc_hw(udc);
        return rc;
@@ -2440,7 +2418,6 @@ static int bcm63xx_udc_remove(struct platform_device *pdev)
 
        bcm63xx_udc_cleanup_debugfs(udc);
        usb_del_gadget_udc(&udc->gadget);
-       device_unregister(&udc->gadget.dev);
        BUG_ON(udc->driver);
 
        platform_set_drvdata(pdev, NULL);
index a7d6f70..c6ee6f1 100644 (file)
@@ -103,18 +103,16 @@ static struct usb_gadget_strings *dev_strings[] = {
 };
 
 static u8 hostaddr[ETH_ALEN];
-
+static struct eth_dev *the_dev;
 /*-------------------------------------------------------------------------*/
 static struct usb_function *f_acm;
 static struct usb_function_instance *fi_serial;
 
-static unsigned char tty_line;
 /*
  * We _always_ have both CDC ECM and CDC ACM functions.
  */
 static int __init cdc_do_config(struct usb_configuration *c)
 {
-       struct f_serial_opts *opts;
        int     status;
 
        if (gadget_is_otg(c->cdev->gadget)) {
@@ -122,7 +120,7 @@ static int __init cdc_do_config(struct usb_configuration *c)
                c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
        }
 
-       status = ecm_bind_config(c, hostaddr);
+       status = ecm_bind_config(c, hostaddr, the_dev);
        if (status < 0)
                return status;
 
@@ -130,9 +128,6 @@ static int __init cdc_do_config(struct usb_configuration *c)
        if (IS_ERR(fi_serial))
                return PTR_ERR(fi_serial);
 
-       opts = container_of(fi_serial, struct f_serial_opts, func_inst);
-       opts->port_num = tty_line;
-
        f_acm = usb_get_function(fi_serial);
        if (IS_ERR(f_acm))
                goto err_func_acm;
@@ -169,14 +164,9 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
        }
 
        /* set up network link layer */
-       status = gether_setup(cdev->gadget, hostaddr);
-       if (status < 0)
-               return status;
-
-       /* set up serial link layer */
-       status = gserial_alloc_line(&tty_line);
-       if (status < 0)
-               goto fail0;
+       the_dev = gether_setup(cdev->gadget, hostaddr);
+       if (IS_ERR(the_dev))
+               return PTR_ERR(the_dev);
 
        /* Allocate string descriptor numbers ... note that string
         * contents can be overridden by the composite_dev glue.
@@ -200,9 +190,7 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
        return 0;
 
 fail1:
-       gserial_free_line(tty_line);
-fail0:
-       gether_cleanup();
+       gether_cleanup(the_dev);
        return status;
 }
 
@@ -210,8 +198,7 @@ static int __exit cdc_unbind(struct usb_composite_dev *cdev)
 {
        usb_put_function(f_acm);
        usb_put_function_instance(fi_serial);
-       gserial_free_line(tty_line);
-       gether_cleanup();
+       gether_cleanup(the_dev);
        return 0;
 }
 
index c0d62b2..55f4df6 100644 (file)
@@ -1637,6 +1637,7 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev)
                kfree(cdev->req->buf);
                usb_ep_free_request(cdev->gadget->ep0, cdev->req);
        }
+       cdev->next_string_id = 0;
        device_remove_file(&cdev->gadget->dev, &dev_attr_suspended);
 }
 
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
new file mode 100644 (file)
index 0000000..a34633a
--- /dev/null
@@ -0,0 +1,1003 @@
+#include <linux/configfs.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/gadget_configfs.h>
+
+int check_user_usb_string(const char *name,
+               struct usb_gadget_strings *stringtab_dev)
+{
+       unsigned primary_lang;
+       unsigned sub_lang;
+       u16 num;
+       int ret;
+
+       ret = kstrtou16(name, 0, &num);
+       if (ret)
+               return ret;
+
+       primary_lang = num & 0x3ff;
+       sub_lang = num >> 10;
+
+       /* simple sanity check for valid langid */
+       switch (primary_lang) {
+       case 0:
+       case 0x62 ... 0xfe:
+       case 0x100 ... 0x3ff:
+               return -EINVAL;
+       }
+       if (!sub_lang)
+               return -EINVAL;
+
+       stringtab_dev->language = num;
+       return 0;
+}
+
+#define MAX_NAME_LEN   40
+#define MAX_USB_STRING_LANGS 2
+
+struct gadget_info {
+       struct config_group group;
+       struct config_group functions_group;
+       struct config_group configs_group;
+       struct config_group strings_group;
+       struct config_group *default_groups[4];
+
+       struct mutex lock;
+       struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1];
+       struct list_head string_list;
+       struct list_head available_func;
+
+       const char *udc_name;
+#ifdef CONFIG_USB_OTG
+       struct usb_otg_descriptor otg;
+#endif
+       struct usb_composite_driver composite;
+       struct usb_composite_dev cdev;
+};
+
+struct config_usb_cfg {
+       struct config_group group;
+       struct config_group strings_group;
+       struct config_group *default_groups[2];
+       struct list_head string_list;
+       struct usb_configuration c;
+       struct list_head func_list;
+       struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1];
+};
+
+struct gadget_strings {
+       struct usb_gadget_strings stringtab_dev;
+       struct usb_string strings[USB_GADGET_FIRST_AVAIL_IDX];
+       char *manufacturer;
+       char *product;
+       char *serialnumber;
+
+       struct config_group group;
+       struct list_head list;
+};
+
+struct gadget_config_name {
+       struct usb_gadget_strings stringtab_dev;
+       struct usb_string strings;
+       char *configuration;
+
+       struct config_group group;
+       struct list_head list;
+};
+
+static int usb_string_copy(const char *s, char **s_copy)
+{
+       int ret;
+       char *str;
+       char *copy = *s_copy;
+       ret = strlen(s);
+       if (ret > 126)
+               return -EOVERFLOW;
+
+       str = kstrdup(s, GFP_KERNEL);
+       if (!str)
+               return -ENOMEM;
+       if (str[ret - 1] == '\n')
+               str[ret - 1] = '\0';
+       kfree(copy);
+       *s_copy = str;
+       return 0;
+}
+
+CONFIGFS_ATTR_STRUCT(gadget_info);
+CONFIGFS_ATTR_STRUCT(config_usb_cfg);
+
+#define GI_DEVICE_DESC_ITEM_ATTR(name) \
+       static struct gadget_info_attribute gadget_cdev_desc_##name = \
+               __CONFIGFS_ATTR(name,  S_IRUGO | S_IWUSR,               \
+                               gadget_dev_desc_##name##_show,          \
+                               gadget_dev_desc_##name##_store)
+
+#define GI_DEVICE_DESC_SIMPLE_R_u8(__name)     \
+       static ssize_t gadget_dev_desc_##__name##_show(struct gadget_info *gi, \
+                       char *page)     \
+{      \
+       return sprintf(page, "0x%02x\n", gi->cdev.desc.__name); \
+}
+
+#define GI_DEVICE_DESC_SIMPLE_R_u16(__name)    \
+       static ssize_t gadget_dev_desc_##__name##_show(struct gadget_info *gi, \
+                       char *page)     \
+{      \
+       return sprintf(page, "0x%04x\n", le16_to_cpup(&gi->cdev.desc.__name)); \
+}
+
+
+#define GI_DEVICE_DESC_SIMPLE_W_u8(_name)              \
+       static ssize_t gadget_dev_desc_##_name##_store(struct gadget_info *gi, \
+               const char *page, size_t len)           \
+{                                                      \
+       u8 val;                                         \
+       int ret;                                        \
+       ret = kstrtou8(page, 0, &val);                  \
+       if (ret)                                        \
+               return ret;                             \
+       gi->cdev.desc._name = val;                      \
+       return len;                                     \
+}
+
+#define GI_DEVICE_DESC_SIMPLE_W_u16(_name)     \
+       static ssize_t gadget_dev_desc_##_name##_store(struct gadget_info *gi, \
+               const char *page, size_t len)           \
+{                                                      \
+       u16 val;                                        \
+       int ret;                                        \
+       ret = kstrtou16(page, 0, &val);                 \
+       if (ret)                                        \
+               return ret;                             \
+       gi->cdev.desc._name = cpu_to_le16p(&val);       \
+       return len;                                     \
+}
+
+#define GI_DEVICE_DESC_SIMPLE_RW(_name, _type) \
+       GI_DEVICE_DESC_SIMPLE_R_##_type(_name)  \
+       GI_DEVICE_DESC_SIMPLE_W_##_type(_name)
+
+GI_DEVICE_DESC_SIMPLE_R_u16(bcdUSB);
+GI_DEVICE_DESC_SIMPLE_RW(bDeviceClass, u8);
+GI_DEVICE_DESC_SIMPLE_RW(bDeviceSubClass, u8);
+GI_DEVICE_DESC_SIMPLE_RW(bDeviceProtocol, u8);
+GI_DEVICE_DESC_SIMPLE_RW(bMaxPacketSize0, u8);
+GI_DEVICE_DESC_SIMPLE_RW(idVendor, u16);
+GI_DEVICE_DESC_SIMPLE_RW(idProduct, u16);
+GI_DEVICE_DESC_SIMPLE_R_u16(bcdDevice);
+
+static ssize_t is_valid_bcd(u16 bcd_val)
+{
+       if ((bcd_val & 0xf) > 9)
+               return -EINVAL;
+       if (((bcd_val >> 4) & 0xf) > 9)
+               return -EINVAL;
+       if (((bcd_val >> 8) & 0xf) > 9)
+               return -EINVAL;
+       if (((bcd_val >> 12) & 0xf) > 9)
+               return -EINVAL;
+       return 0;
+}
+
+static ssize_t gadget_dev_desc_bcdDevice_store(struct gadget_info *gi,
+               const char *page, size_t len)
+{
+       u16 bcdDevice;
+       int ret;
+
+       ret = kstrtou16(page, 0, &bcdDevice);
+       if (ret)
+               return ret;
+       ret = is_valid_bcd(bcdDevice);
+       if (ret)
+               return ret;
+
+       gi->cdev.desc.bcdDevice = cpu_to_le16(bcdDevice);
+       return len;
+}
+
+static ssize_t gadget_dev_desc_bcdUSB_store(struct gadget_info *gi,
+               const char *page, size_t len)
+{
+       u16 bcdUSB;
+       int ret;
+
+       ret = kstrtou16(page, 0, &bcdUSB);
+       if (ret)
+               return ret;
+       ret = is_valid_bcd(bcdUSB);
+       if (ret)
+               return ret;
+
+       gi->cdev.desc.bcdUSB = cpu_to_le16(bcdUSB);
+       return len;
+}
+
+static ssize_t gadget_dev_desc_UDC_show(struct gadget_info *gi, char *page)
+{
+       return sprintf(page, "%s\n", gi->udc_name ?: "");
+}
+
+static int unregister_gadget(struct gadget_info *gi)
+{
+       int ret;
+
+       if (!gi->udc_name)
+               return -ENODEV;
+
+       ret = usb_gadget_unregister_driver(&gi->composite.gadget_driver);
+       if (ret)
+               return ret;
+       kfree(gi->udc_name);
+       gi->udc_name = NULL;
+       return 0;
+}
+
+static ssize_t gadget_dev_desc_UDC_store(struct gadget_info *gi,
+               const char *page, size_t len)
+{
+       char *name;
+       int ret;
+
+       name = kstrdup(page, GFP_KERNEL);
+       if (!name)
+               return -ENOMEM;
+       if (name[len - 1] == '\n')
+               name[len - 1] = '\0';
+
+       mutex_lock(&gi->lock);
+
+       if (!strlen(name)) {
+               ret = unregister_gadget(gi);
+               if (ret)
+                       goto err;
+       } else {
+               if (gi->udc_name) {
+                       ret = -EBUSY;
+                       goto err;
+               }
+               ret = udc_attach_driver(name, &gi->composite.gadget_driver);
+               if (ret)
+                       goto err;
+               gi->udc_name = name;
+       }
+       mutex_unlock(&gi->lock);
+       return len;
+err:
+       kfree(name);
+       mutex_unlock(&gi->lock);
+       return ret;
+}
+
+GI_DEVICE_DESC_ITEM_ATTR(bDeviceClass);
+GI_DEVICE_DESC_ITEM_ATTR(bDeviceSubClass);
+GI_DEVICE_DESC_ITEM_ATTR(bDeviceProtocol);
+GI_DEVICE_DESC_ITEM_ATTR(bMaxPacketSize0);
+GI_DEVICE_DESC_ITEM_ATTR(idVendor);
+GI_DEVICE_DESC_ITEM_ATTR(idProduct);
+GI_DEVICE_DESC_ITEM_ATTR(bcdDevice);
+GI_DEVICE_DESC_ITEM_ATTR(bcdUSB);
+GI_DEVICE_DESC_ITEM_ATTR(UDC);
+
+static struct configfs_attribute *gadget_root_attrs[] = {
+       &gadget_cdev_desc_bDeviceClass.attr,
+       &gadget_cdev_desc_bDeviceSubClass.attr,
+       &gadget_cdev_desc_bDeviceProtocol.attr,
+       &gadget_cdev_desc_bMaxPacketSize0.attr,
+       &gadget_cdev_desc_idVendor.attr,
+       &gadget_cdev_desc_idProduct.attr,
+       &gadget_cdev_desc_bcdDevice.attr,
+       &gadget_cdev_desc_bcdUSB.attr,
+       &gadget_cdev_desc_UDC.attr,
+       NULL,
+};
+
+static inline struct gadget_info *to_gadget_info(struct config_item *item)
+{
+        return container_of(to_config_group(item), struct gadget_info, group);
+}
+
+static inline struct gadget_strings *to_gadget_strings(struct config_item *item)
+{
+        return container_of(to_config_group(item), struct gadget_strings,
+                        group);
+}
+
+static inline struct gadget_config_name *to_gadget_config_name(
+               struct config_item *item)
+{
+        return container_of(to_config_group(item), struct gadget_config_name,
+                        group);
+}
+
+static inline struct config_usb_cfg *to_config_usb_cfg(struct config_item *item)
+{
+       return container_of(to_config_group(item), struct config_usb_cfg,
+                       group);
+}
+
+static inline struct usb_function_instance *to_usb_function_instance(
+               struct config_item *item)
+{
+        return container_of(to_config_group(item),
+                        struct usb_function_instance, group);
+}
+
+static void gadget_info_attr_release(struct config_item *item)
+{
+       struct gadget_info *gi = to_gadget_info(item);
+
+       WARN_ON(!list_empty(&gi->cdev.configs));
+       WARN_ON(!list_empty(&gi->string_list));
+       WARN_ON(!list_empty(&gi->available_func));
+       kfree(gi->composite.gadget_driver.function);
+       kfree(gi);
+}
+
+CONFIGFS_ATTR_OPS(gadget_info);
+
+static struct configfs_item_operations gadget_root_item_ops = {
+       .release                = gadget_info_attr_release,
+       .show_attribute         = gadget_info_attr_show,
+       .store_attribute        = gadget_info_attr_store,
+};
+
+static void gadget_config_attr_release(struct config_item *item)
+{
+       struct config_usb_cfg *cfg = to_config_usb_cfg(item);
+
+       WARN_ON(!list_empty(&cfg->c.functions));
+       list_del(&cfg->c.list);
+       kfree(cfg->c.label);
+       kfree(cfg);
+}
+
+static int config_usb_cfg_link(
+       struct config_item *usb_cfg_ci,
+       struct config_item *usb_func_ci)
+{
+       struct config_usb_cfg *cfg = to_config_usb_cfg(usb_cfg_ci);
+       struct usb_composite_dev *cdev = cfg->c.cdev;
+       struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev);
+
+       struct config_group *group = to_config_group(usb_func_ci);
+       struct usb_function_instance *fi = container_of(group,
+                       struct usb_function_instance, group);
+       struct usb_function_instance *a_fi;
+       struct usb_function *f;
+       int ret;
+
+       mutex_lock(&gi->lock);
+       /*
+        * Make sure this function is from within our _this_ gadget and not
+        * from another gadget or a random directory.
+        * Also a function instance can only be linked once.
+        */
+       list_for_each_entry(a_fi, &gi->available_func, cfs_list) {
+               if (a_fi == fi)
+                       break;
+       }
+       if (a_fi != fi) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       list_for_each_entry(f, &cfg->func_list, list) {
+               if (f->fi == fi) {
+                       ret = -EEXIST;
+                       goto out;
+               }
+       }
+
+       f = usb_get_function(fi);
+       if (IS_ERR(f)) {
+               ret = PTR_ERR(f);
+               goto out;
+       }
+
+       /* stash the function until we bind it to the gadget */
+       list_add_tail(&f->list, &cfg->func_list);
+       ret = 0;
+out:
+       mutex_unlock(&gi->lock);
+       return ret;
+}
+
+static int config_usb_cfg_unlink(
+       struct config_item *usb_cfg_ci,
+       struct config_item *usb_func_ci)
+{
+       struct config_usb_cfg *cfg = to_config_usb_cfg(usb_cfg_ci);
+       struct usb_composite_dev *cdev = cfg->c.cdev;
+       struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev);
+
+       struct config_group *group = to_config_group(usb_func_ci);
+       struct usb_function_instance *fi = container_of(group,
+                       struct usb_function_instance, group);
+       struct usb_function *f;
+
+       /*
+        * ideally I would like to forbid to unlink functions while a gadget is
+        * bound to an UDC. Since this isn't possible at the moment, we simply
+        * force an unbind, the function is available here and then we can
+        * remove the function.
+        */
+       mutex_lock(&gi->lock);
+       if (gi->udc_name)
+               unregister_gadget(gi);
+       WARN_ON(gi->udc_name);
+
+       list_for_each_entry(f, &cfg->func_list, list) {
+               if (f->fi == fi) {
+                       list_del(&f->list);
+                       usb_put_function(f);
+                       mutex_unlock(&gi->lock);
+                       return 0;
+               }
+       }
+       mutex_unlock(&gi->lock);
+       __WARN_printf("Unable to locate function to unbind\n");
+       return 0;
+}
+
+CONFIGFS_ATTR_OPS(config_usb_cfg);
+
+static struct configfs_item_operations gadget_config_item_ops = {
+       .release                = gadget_config_attr_release,
+       .show_attribute         = config_usb_cfg_attr_show,
+       .store_attribute        = config_usb_cfg_attr_store,
+       .allow_link             = config_usb_cfg_link,
+       .drop_link              = config_usb_cfg_unlink,
+};
+
+
+static ssize_t gadget_config_desc_MaxPower_show(struct config_usb_cfg *cfg,
+               char *page)
+{
+       return sprintf(page, "%u\n", cfg->c.MaxPower);
+}
+
+static ssize_t gadget_config_desc_MaxPower_store(struct config_usb_cfg *cfg,
+               const char *page, size_t len)
+{
+       u16 val;
+       int ret;
+       ret = kstrtou16(page, 0, &val);
+       if (ret)
+               return ret;
+       if (DIV_ROUND_UP(val, 8) > 0xff)
+               return -ERANGE;
+       cfg->c.MaxPower = val;
+       return len;
+}
+
+static ssize_t gadget_config_desc_bmAttributes_show(struct config_usb_cfg *cfg,
+               char *page)
+{
+       return sprintf(page, "0x%02x\n", cfg->c.bmAttributes);
+}
+
+static ssize_t gadget_config_desc_bmAttributes_store(struct config_usb_cfg *cfg,
+               const char *page, size_t len)
+{
+       u8 val;
+       int ret;
+       ret = kstrtou8(page, 0, &val);
+       if (ret)
+               return ret;
+       if (!(val & USB_CONFIG_ATT_ONE))
+               return -EINVAL;
+       if (val & ~(USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER |
+                               USB_CONFIG_ATT_WAKEUP))
+               return -EINVAL;
+       cfg->c.bmAttributes = val;
+       return len;
+}
+
+#define CFG_CONFIG_DESC_ITEM_ATTR(name)        \
+       static struct config_usb_cfg_attribute gadget_usb_cfg_##name = \
+               __CONFIGFS_ATTR(name,  S_IRUGO | S_IWUSR,               \
+                               gadget_config_desc_##name##_show,       \
+                               gadget_config_desc_##name##_store)
+
+CFG_CONFIG_DESC_ITEM_ATTR(MaxPower);
+CFG_CONFIG_DESC_ITEM_ATTR(bmAttributes);
+
+static struct configfs_attribute *gadget_config_attrs[] = {
+       &gadget_usb_cfg_MaxPower.attr,
+       &gadget_usb_cfg_bmAttributes.attr,
+       NULL,
+};
+
+static struct config_item_type gadget_config_type = {
+       .ct_item_ops    = &gadget_config_item_ops,
+       .ct_attrs       = gadget_config_attrs,
+       .ct_owner       = THIS_MODULE,
+};
+
+static struct config_item_type gadget_root_type = {
+       .ct_item_ops    = &gadget_root_item_ops,
+       .ct_attrs       = gadget_root_attrs,
+       .ct_owner       = THIS_MODULE,
+};
+
+static void composite_init_dev(struct usb_composite_dev *cdev)
+{
+       spin_lock_init(&cdev->lock);
+       INIT_LIST_HEAD(&cdev->configs);
+       INIT_LIST_HEAD(&cdev->gstrings);
+}
+
+static struct config_group *function_make(
+               struct config_group *group,
+               const char *name)
+{
+       struct gadget_info *gi;
+       struct usb_function_instance *fi;
+       char buf[MAX_NAME_LEN];
+       char *func_name;
+       char *instance_name;
+       int ret;
+
+       ret = snprintf(buf, MAX_NAME_LEN, "%s", name);
+       if (ret >= MAX_NAME_LEN)
+               return ERR_PTR(-ENAMETOOLONG);
+
+       func_name = buf;
+       instance_name = strchr(func_name, '.');
+       if (!instance_name) {
+               pr_err("Unable to locate . in FUNC.INSTANCE\n");
+               return ERR_PTR(-EINVAL);
+       }
+       *instance_name = '\0';
+       instance_name++;
+
+       fi = usb_get_function_instance(func_name);
+       if (IS_ERR(fi))
+               return ERR_PTR(PTR_ERR(fi));
+
+       ret = config_item_set_name(&fi->group.cg_item, name);
+       if (ret) {
+               usb_put_function_instance(fi);
+               return ERR_PTR(ret);
+       }
+
+       gi = container_of(group, struct gadget_info, functions_group);
+
+       mutex_lock(&gi->lock);
+       list_add_tail(&fi->cfs_list, &gi->available_func);
+       mutex_unlock(&gi->lock);
+       return &fi->group;
+}
+
+static void function_drop(
+               struct config_group *group,
+               struct config_item *item)
+{
+       struct usb_function_instance *fi = to_usb_function_instance(item);
+       struct gadget_info *gi;
+
+       gi = container_of(group, struct gadget_info, functions_group);
+
+       mutex_lock(&gi->lock);
+       list_del(&fi->cfs_list);
+       mutex_unlock(&gi->lock);
+       config_item_put(item);
+}
+
+static struct configfs_group_operations functions_ops = {
+       .make_group     = &function_make,
+       .drop_item      = &function_drop,
+};
+
+static struct config_item_type functions_type = {
+       .ct_group_ops   = &functions_ops,
+       .ct_owner       = THIS_MODULE,
+};
+
+CONFIGFS_ATTR_STRUCT(gadget_config_name);
+GS_STRINGS_RW(gadget_config_name, configuration);
+
+static struct configfs_attribute *gadget_config_name_langid_attrs[] = {
+       &gadget_config_name_configuration.attr,
+       NULL,
+};
+
+static void gadget_config_name_attr_release(struct config_item *item)
+{
+       struct gadget_config_name *cn = to_gadget_config_name(item);
+
+       kfree(cn->configuration);
+
+       list_del(&cn->list);
+       kfree(cn);
+}
+
+USB_CONFIG_STRING_RW_OPS(gadget_config_name);
+USB_CONFIG_STRINGS_LANG(gadget_config_name, config_usb_cfg);
+
+static struct config_group *config_desc_make(
+               struct config_group *group,
+               const char *name)
+{
+       struct gadget_info *gi;
+       struct config_usb_cfg *cfg;
+       char buf[MAX_NAME_LEN];
+       char *num_str;
+       u8 num;
+       int ret;
+
+       gi = container_of(group, struct gadget_info, configs_group);
+       ret = snprintf(buf, MAX_NAME_LEN, "%s", name);
+       if (ret >= MAX_NAME_LEN)
+               return ERR_PTR(-ENAMETOOLONG);
+
+       num_str = strchr(buf, '.');
+       if (!num_str) {
+               pr_err("Unable to locate . in name.bConfigurationValue\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       *num_str = '\0';
+       num_str++;
+
+       if (!strlen(buf))
+               return ERR_PTR(-EINVAL);
+
+       ret = kstrtou8(num_str, 0, &num);
+       if (ret)
+               return ERR_PTR(ret);
+
+       cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
+       if (!cfg)
+               return ERR_PTR(-ENOMEM);
+       cfg->c.label = kstrdup(buf, GFP_KERNEL);
+       if (!cfg->c.label) {
+               ret = -ENOMEM;
+               goto err;
+       }
+       cfg->c.bConfigurationValue = num;
+       cfg->c.MaxPower = CONFIG_USB_GADGET_VBUS_DRAW;
+       cfg->c.bmAttributes = USB_CONFIG_ATT_ONE;
+       INIT_LIST_HEAD(&cfg->string_list);
+       INIT_LIST_HEAD(&cfg->func_list);
+
+       cfg->group.default_groups = cfg->default_groups;
+       cfg->default_groups[0] = &cfg->strings_group;
+
+       config_group_init_type_name(&cfg->group, name,
+                               &gadget_config_type);
+       config_group_init_type_name(&cfg->strings_group, "strings",
+                       &gadget_config_name_strings_type);
+
+       ret = usb_add_config_only(&gi->cdev, &cfg->c);
+       if (ret)
+               goto err;
+
+       return &cfg->group;
+err:
+       kfree(cfg->c.label);
+       kfree(cfg);
+       return ERR_PTR(ret);
+}
+
+static void config_desc_drop(
+               struct config_group *group,
+               struct config_item *item)
+{
+       config_item_put(item);
+}
+
+static struct configfs_group_operations config_desc_ops = {
+       .make_group     = &config_desc_make,
+       .drop_item      = &config_desc_drop,
+};
+
+static struct config_item_type config_desc_type = {
+       .ct_group_ops   = &config_desc_ops,
+       .ct_owner       = THIS_MODULE,
+};
+
+CONFIGFS_ATTR_STRUCT(gadget_strings);
+GS_STRINGS_RW(gadget_strings, manufacturer);
+GS_STRINGS_RW(gadget_strings, product);
+GS_STRINGS_RW(gadget_strings, serialnumber);
+
+static struct configfs_attribute *gadget_strings_langid_attrs[] = {
+       &gadget_strings_manufacturer.attr,
+       &gadget_strings_product.attr,
+       &gadget_strings_serialnumber.attr,
+       NULL,
+};
+
+static void gadget_strings_attr_release(struct config_item *item)
+{
+       struct gadget_strings *gs = to_gadget_strings(item);
+
+       kfree(gs->manufacturer);
+       kfree(gs->product);
+       kfree(gs->serialnumber);
+
+       list_del(&gs->list);
+       kfree(gs);
+}
+
+USB_CONFIG_STRING_RW_OPS(gadget_strings);
+USB_CONFIG_STRINGS_LANG(gadget_strings, gadget_info);
+
+static int configfs_do_nothing(struct usb_composite_dev *cdev)
+{
+       __WARN();
+       return -EINVAL;
+}
+
+int composite_dev_prepare(struct usb_composite_driver *composite,
+               struct usb_composite_dev *dev);
+
+static void purge_configs_funcs(struct gadget_info *gi)
+{
+       struct usb_configuration        *c;
+
+       list_for_each_entry(c, &gi->cdev.configs, list) {
+               struct usb_function *f, *tmp;
+               struct config_usb_cfg *cfg;
+
+               cfg = container_of(c, struct config_usb_cfg, c);
+
+               list_for_each_entry_safe(f, tmp, &c->functions, list) {
+
+                       list_move_tail(&f->list, &cfg->func_list);
+                       if (f->unbind) {
+                               dev_err(&gi->cdev.gadget->dev, "unbind function"
+                                               " '%s'/%p\n", f->name, f);
+                               f->unbind(c, f);
+                       }
+               }
+               c->next_interface_id = 0;
+               c->superspeed = 0;
+               c->highspeed = 0;
+               c->fullspeed = 0;
+       }
+}
+
+static int configfs_composite_bind(struct usb_gadget *gadget,
+               struct usb_gadget_driver *gdriver)
+{
+       struct usb_composite_driver     *composite = to_cdriver(gdriver);
+       struct gadget_info              *gi = container_of(composite,
+                                               struct gadget_info, composite);
+       struct usb_composite_dev        *cdev = &gi->cdev;
+       struct usb_configuration        *c;
+       struct usb_string               *s;
+       unsigned                        i;
+       int                             ret;
+
+       /* the gi->lock is hold by the caller */
+       cdev->gadget = gadget;
+       set_gadget_data(gadget, cdev);
+       ret = composite_dev_prepare(composite, cdev);
+       if (ret)
+               return ret;
+       /* and now the gadget bind */
+       ret = -EINVAL;
+
+       if (list_empty(&gi->cdev.configs)) {
+               pr_err("Need atleast one configuration in %s.\n",
+                               gi->composite.name);
+               goto err_comp_cleanup;
+       }
+
+
+       list_for_each_entry(c, &gi->cdev.configs, list) {
+               struct config_usb_cfg *cfg;
+
+               cfg = container_of(c, struct config_usb_cfg, c);
+               if (list_empty(&cfg->func_list)) {
+                       pr_err("Config %s/%d of %s needs atleast one function.\n",
+                             c->label, c->bConfigurationValue,
+                             gi->composite.name);
+                       goto err_comp_cleanup;
+               }
+       }
+
+       /* init all strings */
+       if (!list_empty(&gi->string_list)) {
+               struct gadget_strings *gs;
+
+               i = 0;
+               list_for_each_entry(gs, &gi->string_list, list) {
+
+                       gi->gstrings[i] = &gs->stringtab_dev;
+                       gs->stringtab_dev.strings = gs->strings;
+                       gs->strings[USB_GADGET_MANUFACTURER_IDX].s =
+                               gs->manufacturer;
+                       gs->strings[USB_GADGET_PRODUCT_IDX].s = gs->product;
+                       gs->strings[USB_GADGET_SERIAL_IDX].s = gs->serialnumber;
+                       i++;
+               }
+               gi->gstrings[i] = NULL;
+               s = usb_gstrings_attach(&gi->cdev, gi->gstrings,
+                               USB_GADGET_FIRST_AVAIL_IDX);
+               if (IS_ERR(s))
+                       goto err_comp_cleanup;
+
+               gi->cdev.desc.iManufacturer = s[USB_GADGET_MANUFACTURER_IDX].id;
+               gi->cdev.desc.iProduct = s[USB_GADGET_PRODUCT_IDX].id;
+               gi->cdev.desc.iSerialNumber = s[USB_GADGET_SERIAL_IDX].id;
+       }
+
+       /* Go through all configs, attach all functions */
+       list_for_each_entry(c, &gi->cdev.configs, list) {
+               struct config_usb_cfg *cfg;
+               struct usb_function *f;
+               struct usb_function *tmp;
+               struct gadget_config_name *cn;
+
+               cfg = container_of(c, struct config_usb_cfg, c);
+               if (!list_empty(&cfg->string_list)) {
+                       i = 0;
+                       list_for_each_entry(cn, &cfg->string_list, list) {
+                               cfg->gstrings[i] = &cn->stringtab_dev;
+                               cn->stringtab_dev.strings = &cn->strings;
+                               cn->strings.s = cn->configuration;
+                               i++;
+                       }
+                       cfg->gstrings[i] = NULL;
+                       s = usb_gstrings_attach(&gi->cdev, cfg->gstrings, 1);
+                       if (IS_ERR(s))
+                               goto err_comp_cleanup;
+                       c->iConfiguration = s[0].id;
+               }
+
+               list_for_each_entry_safe(f, tmp, &cfg->func_list, list) {
+                       list_del(&f->list);
+                       ret = usb_add_function(c, f);
+                       if (ret)
+                               goto err_purge_funcs;
+               }
+               usb_ep_autoconfig_reset(cdev->gadget);
+       }
+       usb_ep_autoconfig_reset(cdev->gadget);
+       return 0;
+
+err_purge_funcs:
+       purge_configs_funcs(gi);
+err_comp_cleanup:
+       composite_dev_cleanup(cdev);
+       return ret;
+}
+
+static void configfs_composite_unbind(struct usb_gadget *gadget)
+{
+       struct usb_composite_dev        *cdev;
+       struct gadget_info              *gi;
+
+       /* the gi->lock is hold by the caller */
+
+       cdev = get_gadget_data(gadget);
+       gi = container_of(cdev, struct gadget_info, cdev);
+
+       purge_configs_funcs(gi);
+       composite_dev_cleanup(cdev);
+       usb_ep_autoconfig_reset(cdev->gadget);
+       cdev->gadget = NULL;
+       set_gadget_data(gadget, NULL);
+}
+
+static const struct usb_gadget_driver configfs_driver_template = {
+       .bind           = configfs_composite_bind,
+       .unbind         = configfs_composite_unbind,
+
+       .setup          = composite_setup,
+       .disconnect     = composite_disconnect,
+
+       .max_speed      = USB_SPEED_SUPER,
+       .driver = {
+               .owner          = THIS_MODULE,
+               .name           = "configfs-gadget",
+       },
+};
+
+static struct config_group *gadgets_make(
+               struct config_group *group,
+               const char *name)
+{
+       struct gadget_info *gi;
+
+       gi = kzalloc(sizeof(*gi), GFP_KERNEL);
+       if (!gi)
+               return ERR_PTR(-ENOMEM);
+
+       gi->group.default_groups = gi->default_groups;
+       gi->group.default_groups[0] = &gi->functions_group;
+       gi->group.default_groups[1] = &gi->configs_group;
+       gi->group.default_groups[2] = &gi->strings_group;
+
+       config_group_init_type_name(&gi->functions_group, "functions",
+                       &functions_type);
+       config_group_init_type_name(&gi->configs_group, "configs",
+                       &config_desc_type);
+       config_group_init_type_name(&gi->strings_group, "strings",
+                       &gadget_strings_strings_type);
+
+       gi->composite.bind = configfs_do_nothing;
+       gi->composite.unbind = configfs_do_nothing;
+       gi->composite.suspend = NULL;
+       gi->composite.resume = NULL;
+       gi->composite.max_speed = USB_SPEED_SUPER;
+
+       mutex_init(&gi->lock);
+       INIT_LIST_HEAD(&gi->string_list);
+       INIT_LIST_HEAD(&gi->available_func);
+
+       composite_init_dev(&gi->cdev);
+       gi->cdev.desc.bLength = USB_DT_DEVICE_SIZE;
+       gi->cdev.desc.bDescriptorType = USB_DT_DEVICE;
+       gi->cdev.desc.bcdDevice = cpu_to_le16(get_default_bcdDevice());
+
+       gi->composite.gadget_driver = configfs_driver_template;
+
+       gi->composite.gadget_driver.function = kstrdup(name, GFP_KERNEL);
+       gi->composite.name = gi->composite.gadget_driver.function;
+
+       if (!gi->composite.gadget_driver.function)
+               goto err;
+
+#ifdef CONFIG_USB_OTG
+       gi->otg.bLength = sizeof(struct usb_otg_descriptor);
+       gi->otg.bDescriptorType = USB_DT_OTG;
+       gi->otg.bmAttributes = USB_OTG_SRP | USB_OTG_HNP;
+#endif
+
+       config_group_init_type_name(&gi->group, name,
+                               &gadget_root_type);
+       return &gi->group;
+err:
+       kfree(gi);
+       return ERR_PTR(-ENOMEM);
+}
+
+static void gadgets_drop(struct config_group *group, struct config_item *item)
+{
+       config_item_put(item);
+}
+
+static struct configfs_group_operations gadgets_ops = {
+       .make_group     = &gadgets_make,
+       .drop_item      = &gadgets_drop,
+};
+
+static struct config_item_type gadgets_type = {
+       .ct_group_ops   = &gadgets_ops,
+       .ct_owner       = THIS_MODULE,
+};
+
+static struct configfs_subsystem gadget_subsys = {
+       .su_group = {
+               .cg_item = {
+                       .ci_namebuf = "usb_gadget",
+                       .ci_type = &gadgets_type,
+               },
+       },
+       .su_mutex = __MUTEX_INITIALIZER(gadget_subsys.su_mutex),
+};
+
+static int __init gadget_cfs_init(void)
+{
+       int ret;
+
+       config_group_init(&gadget_subsys.su_group);
+
+       ret = configfs_register_subsystem(&gadget_subsys);
+       return ret;
+}
+module_init(gadget_cfs_init);
+
+static void __exit gadget_cfs_exit(void)
+{
+       configfs_unregister_subsystem(&gadget_subsys);
+}
+module_exit(gadget_cfs_exit);
index 8cf0c0f..a792e32 100644 (file)
@@ -912,7 +912,6 @@ static int dummy_udc_start(struct usb_gadget *g,
        dum->devstatus = 0;
 
        dum->driver = driver;
-       dum->gadget.dev.driver = &driver->driver;
        dev_dbg(udc_dev(dum), "binding gadget driver '%s'\n",
                        driver->driver.name);
        return 0;
@@ -927,7 +926,6 @@ static int dummy_udc_stop(struct usb_gadget *g,
        dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n",
                        driver->driver.name);
 
-       dum->gadget.dev.driver = NULL;
        dum->driver = NULL;
 
        return 0;
@@ -937,11 +935,6 @@ static int dummy_udc_stop(struct usb_gadget *g,
 
 /* The gadget structure is stored inside the hcd structure and will be
  * released along with it. */
-static void dummy_gadget_release(struct device *dev)
-{
-       return;
-}
-
 static void init_dummy_udc_hw(struct dummy *dum)
 {
        int i;
@@ -984,15 +977,7 @@ static int dummy_udc_probe(struct platform_device *pdev)
        dum->gadget.ops = &dummy_ops;
        dum->gadget.max_speed = USB_SPEED_SUPER;
 
-       dev_set_name(&dum->gadget.dev, "gadget");
        dum->gadget.dev.parent = &pdev->dev;
-       dum->gadget.dev.release = dummy_gadget_release;
-       rc = device_register(&dum->gadget.dev);
-       if (rc < 0) {
-               put_device(&dum->gadget.dev);
-               return rc;
-       }
-
        init_dummy_udc_hw(dum);
 
        rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget);
@@ -1008,7 +993,6 @@ static int dummy_udc_probe(struct platform_device *pdev)
 err_dev:
        usb_del_gadget_udc(&dum->gadget);
 err_udc:
-       device_unregister(&dum->gadget.dev);
        return rc;
 }
 
@@ -1019,7 +1003,6 @@ static int dummy_udc_remove(struct platform_device *pdev)
        usb_del_gadget_udc(&dum->gadget);
        platform_set_drvdata(pdev, NULL);
        device_remove_file(&dum->gadget.dev, &dev_attr_function);
-       device_unregister(&dum->gadget.dev);
        return 0;
 }
 
@@ -1923,7 +1906,7 @@ done:
 }
 
 /* usb 3.0 root hub device descriptor */
-struct {
+static struct {
        struct usb_bos_descriptor bos;
        struct usb_ss_cap_descriptor ss_cap;
 } __packed usb3_bos_desc = {
index 18c3f42..56c8eca 100644 (file)
@@ -207,7 +207,7 @@ static struct usb_gadget_strings *dev_strings[] = {
 };
 
 static u8 hostaddr[ETH_ALEN];
-
+static struct eth_dev *the_dev;
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -224,7 +224,7 @@ static int __init rndis_do_config(struct usb_configuration *c)
                c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
        }
 
-       return rndis_bind_config(c, hostaddr);
+       return rndis_bind_config(c, hostaddr, the_dev);
 }
 
 static struct usb_configuration rndis_config_driver = {
@@ -257,11 +257,11 @@ static int __init eth_do_config(struct usb_configuration *c)
        }
 
        if (use_eem)
-               return eem_bind_config(c);
+               return eem_bind_config(c, the_dev);
        else if (can_support_ecm(c->cdev->gadget))
-               return ecm_bind_config(c, hostaddr);
+               return ecm_bind_config(c, hostaddr, the_dev);
        else
-               return geth_bind_config(c, hostaddr);
+               return geth_bind_config(c, hostaddr, the_dev);
 }
 
 static struct usb_configuration eth_config_driver = {
@@ -279,9 +279,9 @@ static int __init eth_bind(struct usb_composite_dev *cdev)
        int                     status;
 
        /* set up network link layer */
-       status = gether_setup(cdev->gadget, hostaddr);
-       if (status < 0)
-               return status;
+       the_dev = gether_setup(cdev->gadget, hostaddr);
+       if (IS_ERR(the_dev))
+               return PTR_ERR(the_dev);
 
        /* set up main config label and device descriptor */
        if (use_eem) {
@@ -338,13 +338,13 @@ static int __init eth_bind(struct usb_composite_dev *cdev)
        return 0;
 
 fail:
-       gether_cleanup();
+       gether_cleanup(the_dev);
        return status;
 }
 
 static int __exit eth_unbind(struct usb_composite_dev *cdev)
 {
-       gether_cleanup();
+       gether_cleanup(the_dev);
        return 0;
 }
 
index 1ae180b..4b7e33e 100644 (file)
@@ -715,13 +715,31 @@ fail:
        return status;
 }
 
-static struct f_acm *acm_alloc_basic_func(void)
+static void acm_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+       struct f_acm            *acm = func_to_acm(f);
+
+       acm_string_defs[0].id = 0;
+       usb_free_all_descriptors(f);
+       if (acm->notify_req)
+               gs_free_req(acm->notify, acm->notify_req);
+}
+
+static void acm_free_func(struct usb_function *f)
+{
+       struct f_acm            *acm = func_to_acm(f);
+
+       kfree(acm);
+}
+
+static struct usb_function *acm_alloc_func(struct usb_function_instance *fi)
 {
-       struct f_acm    *acm;
+       struct f_serial_opts *opts;
+       struct f_acm *acm;
 
        acm = kzalloc(sizeof(*acm), GFP_KERNEL);
        if (!acm)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        spin_lock_init(&acm->lock);
 
@@ -730,109 +748,100 @@ static struct f_acm *acm_alloc_basic_func(void)
        acm->port.send_break = acm_send_break;
 
        acm->port.func.name = "acm";
+       acm->port.func.strings = acm_strings;
        /* descriptors are per-instance copies */
        acm->port.func.bind = acm_bind;
        acm->port.func.set_alt = acm_set_alt;
        acm->port.func.setup = acm_setup;
        acm->port.func.disable = acm_disable;
 
-       return acm;
+       opts = container_of(fi, struct f_serial_opts, func_inst);
+       acm->port_num = opts->port_num;
+       acm->port.func.unbind = acm_unbind;
+       acm->port.func.free_func = acm_free_func;
+
+       return &acm->port.func;
 }
 
-#ifdef USB_FACM_INCLUDED
-static void
-acm_old_unbind(struct usb_configuration *c, struct usb_function *f)
+static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
 {
-       struct f_acm            *acm = func_to_acm(f);
-
-       usb_free_all_descriptors(f);
-       if (acm->notify_req)
-               gs_free_req(acm->notify, acm->notify_req);
-       kfree(acm);
+       return container_of(to_config_group(item), struct f_serial_opts,
+                       func_inst.group);
 }
 
-/**
- * acm_bind_config - add a CDC ACM function to a configuration
- * @c: the configuration to support the CDC ACM instance
- * @port_num: /dev/ttyGS* port this interface will use
- * Context: single threaded during gadget setup
- *
- * Returns zero on success, else negative errno.
- *
- */
-int acm_bind_config(struct usb_configuration *c, u8 port_num)
+CONFIGFS_ATTR_STRUCT(f_serial_opts);
+static ssize_t f_acm_attr_show(struct config_item *item,
+                                struct configfs_attribute *attr,
+                                char *page)
 {
-       struct f_acm    *acm;
-       int             status;
-
-       /* allocate and initialize one new instance */
-       acm = acm_alloc_basic_func();
-       if (!acm)
-               return -ENOMEM;
-
-       acm->port_num = port_num;
-       acm->port.func.unbind = acm_old_unbind;
-
-       status = usb_add_function(c, &acm->port.func);
-       if (status)
-               kfree(acm);
-       return status;
+       struct f_serial_opts *opts = to_f_serial_opts(item);
+       struct f_serial_opts_attribute *f_serial_opts_attr =
+               container_of(attr, struct f_serial_opts_attribute, attr);
+       ssize_t ret = 0;
+
+       if (f_serial_opts_attr->show)
+               ret = f_serial_opts_attr->show(opts, page);
+       return ret;
 }
 
-#else
-
-static void acm_unbind(struct usb_configuration *c, struct usb_function *f)
+static void acm_attr_release(struct config_item *item)
 {
-       struct f_acm            *acm = func_to_acm(f);
+       struct f_serial_opts *opts = to_f_serial_opts(item);
 
-       acm_string_defs[0].id = 0;
-       usb_free_all_descriptors(f);
-       if (acm->notify_req)
-               gs_free_req(acm->notify, acm->notify_req);
+       usb_put_function_instance(&opts->func_inst);
 }
 
-static void acm_free_func(struct usb_function *f)
-{
-       struct f_acm            *acm = func_to_acm(f);
+static struct configfs_item_operations acm_item_ops = {
+       .release                = acm_attr_release,
+       .show_attribute         = f_acm_attr_show,
+};
 
-       kfree(acm);
+static ssize_t f_acm_port_num_show(struct f_serial_opts *opts, char *page)
+{
+       return sprintf(page, "%u\n", opts->port_num);
 }
 
-static struct usb_function *acm_alloc_func(struct usb_function_instance *fi)
-{
-       struct f_serial_opts *opts;
-       struct f_acm *acm;
+static struct f_serial_opts_attribute f_acm_port_num =
+       __CONFIGFS_ATTR_RO(port_num, f_acm_port_num_show);
 
-       acm = acm_alloc_basic_func();
-       if (!acm)
-               return ERR_PTR(-ENOMEM);
 
-       opts = container_of(fi, struct f_serial_opts, func_inst);
-       acm->port_num = opts->port_num;
-       acm->port.func.unbind = acm_unbind;
-       acm->port.func.free_func = acm_free_func;
+static struct configfs_attribute *acm_attrs[] = {
+       &f_acm_port_num.attr,
+       NULL,
+};
 
-       return &acm->port.func;
-}
+static struct config_item_type acm_func_type = {
+       .ct_item_ops    = &acm_item_ops,
+       .ct_attrs       = acm_attrs,
+       .ct_owner       = THIS_MODULE,
+};
 
 static void acm_free_instance(struct usb_function_instance *fi)
 {
        struct f_serial_opts *opts;
 
        opts = container_of(fi, struct f_serial_opts, func_inst);
+       gserial_free_line(opts->port_num);
        kfree(opts);
 }
 
 static struct usb_function_instance *acm_alloc_instance(void)
 {
        struct f_serial_opts *opts;
+       int ret;
 
        opts = kzalloc(sizeof(*opts), GFP_KERNEL);
        if (!opts)
                return ERR_PTR(-ENOMEM);
        opts->func_inst.free_func_inst = acm_free_instance;
+       ret = gserial_alloc_line(&opts->port_num);
+       if (ret) {
+               kfree(opts);
+               return ERR_PTR(ret);
+       }
+       config_group_init_type_name(&opts->func_inst.group, "",
+                       &acm_func_type);
        return &opts->func_inst;
 }
 DECLARE_USB_FUNCTION_INIT(acm, acm_alloc_instance, acm_alloc_func);
 MODULE_LICENSE("GPL");
-#endif
index 83420a3..d893d69 100644 (file)
@@ -824,7 +824,8 @@ ecm_unbind(struct usb_configuration *c, struct usb_function *f)
  * for calling @gether_cleanup() before module unload.
  */
 int
-ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+               struct eth_dev *dev)
 {
        struct f_ecm    *ecm;
        int             status;
@@ -852,6 +853,7 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
        snprintf(ecm->ethaddr, sizeof ecm->ethaddr, "%pm", ethaddr);
        ecm_string_defs[1].s = ecm->ethaddr;
 
+       ecm->port.ioport = dev;
        ecm->port.cdc_filter = DEFAULT_FILTER;
 
        ecm->port.func.name = "cdc_ethernet";
index cf0ebee..f4e0bbe 100644 (file)
@@ -528,7 +528,7 @@ error:
  * Caller must have called @gether_setup().  Caller is also responsible
  * for calling @gether_cleanup() before module unload.
  */
-int __init eem_bind_config(struct usb_configuration *c)
+int __init eem_bind_config(struct usb_configuration *c, struct eth_dev *dev)
 {
        struct f_eem    *eem;
        int             status;
@@ -549,6 +549,7 @@ int __init eem_bind_config(struct usb_configuration *c)
        if (!eem)
                return -ENOMEM;
 
+       eem->port.ioport = dev;
        eem->port.cdc_filter = DEFAULT_FILTER;
 
        eem->port.func.name = "cdc_eem";
index 5e7557e..ee19bc8 100644 (file)
@@ -1287,7 +1287,8 @@ ncm_unbind(struct usb_configuration *c, struct usb_function *f)
  * Caller must have called @gether_setup().  Caller is also responsible
  * for calling @gether_cleanup() before module unload.
  */
-int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+               struct eth_dev *dev)
 {
        struct f_ncm    *ncm;
        int             status;
@@ -1321,6 +1322,7 @@ int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
 
        spin_lock_init(&ncm->lock);
        ncm_reset_values(ncm);
+       ncm->port.ioport = dev;
        ncm->port.is_fixed = true;
 
        ncm->port.func.name = "cdc_network";
index 36a0045..29a348a 100644 (file)
@@ -72,7 +72,7 @@ static struct usb_gadget_strings *obex_strings[] = {
 
 /*-------------------------------------------------------------------------*/
 
-static struct usb_interface_descriptor obex_control_intf __initdata = {
+static struct usb_interface_descriptor obex_control_intf = {
        .bLength                = sizeof(obex_control_intf),
        .bDescriptorType        = USB_DT_INTERFACE,
        .bInterfaceNumber       = 0,
@@ -83,7 +83,7 @@ static struct usb_interface_descriptor obex_control_intf __initdata = {
        .bInterfaceSubClass     = USB_CDC_SUBCLASS_OBEX,
 };
 
-static struct usb_interface_descriptor obex_data_nop_intf __initdata = {
+static struct usb_interface_descriptor obex_data_nop_intf = {
        .bLength                = sizeof(obex_data_nop_intf),
        .bDescriptorType        = USB_DT_INTERFACE,
        .bInterfaceNumber       = 1,
@@ -93,7 +93,7 @@ static struct usb_interface_descriptor obex_data_nop_intf __initdata = {
        .bInterfaceClass        = USB_CLASS_CDC_DATA,
 };
 
-static struct usb_interface_descriptor obex_data_intf __initdata = {
+static struct usb_interface_descriptor obex_data_intf = {
        .bLength                = sizeof(obex_data_intf),
        .bDescriptorType        = USB_DT_INTERFACE,
        .bInterfaceNumber       = 2,
@@ -103,14 +103,14 @@ static struct usb_interface_descriptor obex_data_intf __initdata = {
        .bInterfaceClass        = USB_CLASS_CDC_DATA,
 };
 
-static struct usb_cdc_header_desc obex_cdc_header_desc __initdata = {
+static struct usb_cdc_header_desc obex_cdc_header_desc = {
        .bLength                = sizeof(obex_cdc_header_desc),
        .bDescriptorType        = USB_DT_CS_INTERFACE,
        .bDescriptorSubType     = USB_CDC_HEADER_TYPE,
        .bcdCDC                 = cpu_to_le16(0x0120),
 };
 
-static struct usb_cdc_union_desc obex_cdc_union_desc __initdata = {
+static struct usb_cdc_union_desc obex_cdc_union_desc = {
        .bLength                = sizeof(obex_cdc_union_desc),
        .bDescriptorType        = USB_DT_CS_INTERFACE,
        .bDescriptorSubType     = USB_CDC_UNION_TYPE,
@@ -118,7 +118,7 @@ static struct usb_cdc_union_desc obex_cdc_union_desc __initdata = {
        .bSlaveInterface0       = 2,
 };
 
-static struct usb_cdc_obex_desc obex_desc __initdata = {
+static struct usb_cdc_obex_desc obex_desc = {
        .bLength                = sizeof(obex_desc),
        .bDescriptorType        = USB_DT_CS_INTERFACE,
        .bDescriptorSubType     = USB_CDC_OBEX_TYPE,
@@ -127,7 +127,7 @@ static struct usb_cdc_obex_desc obex_desc __initdata = {
 
 /* High-Speed Support */
 
-static struct usb_endpoint_descriptor obex_hs_ep_out_desc __initdata = {
+static struct usb_endpoint_descriptor obex_hs_ep_out_desc = {
        .bLength                = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType        = USB_DT_ENDPOINT,
 
@@ -136,7 +136,7 @@ static struct usb_endpoint_descriptor obex_hs_ep_out_desc __initdata = {
        .wMaxPacketSize         = cpu_to_le16(512),
 };
 
-static struct usb_endpoint_descriptor obex_hs_ep_in_desc __initdata = {
+static struct usb_endpoint_descriptor obex_hs_ep_in_desc = {
        .bLength                = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType        = USB_DT_ENDPOINT,
 
@@ -145,7 +145,7 @@ static struct usb_endpoint_descriptor obex_hs_ep_in_desc __initdata = {
        .wMaxPacketSize         = cpu_to_le16(512),
 };
 
-static struct usb_descriptor_header *hs_function[] __initdata = {
+static struct usb_descriptor_header *hs_function[] = {
        (struct usb_descriptor_header *) &obex_control_intf,
        (struct usb_descriptor_header *) &obex_cdc_header_desc,
        (struct usb_descriptor_header *) &obex_desc,
@@ -160,7 +160,7 @@ static struct usb_descriptor_header *hs_function[] __initdata = {
 
 /* Full-Speed Support */
 
-static struct usb_endpoint_descriptor obex_fs_ep_in_desc __initdata = {
+static struct usb_endpoint_descriptor obex_fs_ep_in_desc = {
        .bLength                = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType        = USB_DT_ENDPOINT,
 
@@ -168,7 +168,7 @@ static struct usb_endpoint_descriptor obex_fs_ep_in_desc __initdata = {
        .bmAttributes           = USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_endpoint_descriptor obex_fs_ep_out_desc __initdata = {
+static struct usb_endpoint_descriptor obex_fs_ep_out_desc = {
        .bLength                = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType        = USB_DT_ENDPOINT,
 
@@ -176,7 +176,7 @@ static struct usb_endpoint_descriptor obex_fs_ep_out_desc __initdata = {
        .bmAttributes           = USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_descriptor_header *fs_function[] __initdata = {
+static struct usb_descriptor_header *fs_function[] = {
        (struct usb_descriptor_header *) &obex_control_intf,
        (struct usb_descriptor_header *) &obex_cdc_header_desc,
        (struct usb_descriptor_header *) &obex_desc,
@@ -290,14 +290,43 @@ static void obex_disconnect(struct gserial *g)
 
 /*-------------------------------------------------------------------------*/
 
-static int __init
-obex_bind(struct usb_configuration *c, struct usb_function *f)
+/* Some controllers can't support CDC OBEX ... */
+static inline bool can_support_obex(struct usb_configuration *c)
+{
+       /* Since the first interface is a NOP, we can ignore the
+        * issue of multi-interface support on most controllers.
+        *
+        * Altsettings are mandatory, however...
+        */
+       if (!gadget_supports_altsettings(c->cdev->gadget))
+               return false;
+
+       /* everything else is *probably* fine ... */
+       return true;
+}
+
+static int obex_bind(struct usb_configuration *c, struct usb_function *f)
 {
        struct usb_composite_dev *cdev = c->cdev;
        struct f_obex           *obex = func_to_obex(f);
        int                     status;
        struct usb_ep           *ep;
 
+       if (!can_support_obex(c))
+               return -EINVAL;
+
+       if (obex_string_defs[OBEX_CTRL_IDX].id == 0) {
+               status = usb_string_ids_tab(c->cdev, obex_string_defs);
+               if (status < 0)
+                       return status;
+               obex_control_intf.iInterface =
+                       obex_string_defs[OBEX_CTRL_IDX].id;
+
+               status = obex_string_defs[OBEX_DATA_IDX].id;
+               obex_data_nop_intf.iInterface = status;
+               obex_data_intf.iInterface = status;
+       }
+
        /* allocate instance-specific interface IDs, and patch descriptors */
 
        status = usb_interface_id(c, f);
@@ -376,29 +405,16 @@ fail:
        return status;
 }
 
+#ifdef USBF_OBEX_INCLUDED
+
 static void
-obex_unbind(struct usb_configuration *c, struct usb_function *f)
+obex_old_unbind(struct usb_configuration *c, struct usb_function *f)
 {
        obex_string_defs[OBEX_CTRL_IDX].id = 0;
        usb_free_all_descriptors(f);
        kfree(func_to_obex(f));
 }
 
-/* Some controllers can't support CDC OBEX ... */
-static inline bool can_support_obex(struct usb_configuration *c)
-{
-       /* Since the first interface is a NOP, we can ignore the
-        * issue of multi-interface support on most controllers.
-        *
-        * Altsettings are mandatory, however...
-        */
-       if (!gadget_supports_altsettings(c->cdev->gadget))
-               return false;
-
-       /* everything else is *probably* fine ... */
-       return true;
-}
-
 /**
  * obex_bind_config - add a CDC OBEX function to a configuration
  * @c: the configuration to support the CDC OBEX instance
@@ -412,21 +428,6 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
        struct f_obex   *obex;
        int             status;
 
-       if (!can_support_obex(c))
-               return -EINVAL;
-
-       if (obex_string_defs[OBEX_CTRL_IDX].id == 0) {
-               status = usb_string_ids_tab(c->cdev, obex_string_defs);
-               if (status < 0)
-                       return status;
-               obex_control_intf.iInterface =
-                       obex_string_defs[OBEX_CTRL_IDX].id;
-
-               status = obex_string_defs[OBEX_DATA_IDX].id;
-               obex_data_nop_intf.iInterface = status;
-               obex_data_intf.iInterface = status;
-       }
-
        /* allocate and initialize one new instance */
        obex = kzalloc(sizeof *obex, GFP_KERNEL);
        if (!obex)
@@ -441,7 +442,7 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
        obex->port.func.strings = obex_strings;
        /* descriptors are per-instance copies */
        obex->port.func.bind = obex_bind;
-       obex->port.func.unbind = obex_unbind;
+       obex->port.func.unbind = obex_old_unbind;
        obex->port.func.set_alt = obex_set_alt;
        obex->port.func.get_alt = obex_get_alt;
        obex->port.func.disable = obex_disable;
@@ -453,5 +454,138 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
        return status;
 }
 
+#else
+
+static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
+{
+       return container_of(to_config_group(item), struct f_serial_opts,
+                           func_inst.group);
+}
+
+CONFIGFS_ATTR_STRUCT(f_serial_opts);
+static ssize_t f_obex_attr_show(struct config_item *item,
+                               struct configfs_attribute *attr,
+                               char *page)
+{
+       struct f_serial_opts *opts = to_f_serial_opts(item);
+       struct f_serial_opts_attribute *f_serial_opts_attr =
+               container_of(attr, struct f_serial_opts_attribute, attr);
+       ssize_t ret = 0;
+
+       if (f_serial_opts_attr->show)
+               ret = f_serial_opts_attr->show(opts, page);
+
+       return ret;
+}
+
+static void obex_attr_release(struct config_item *item)
+{
+       struct f_serial_opts *opts = to_f_serial_opts(item);
+
+       usb_put_function_instance(&opts->func_inst);
+}
+
+static struct configfs_item_operations obex_item_ops = {
+       .release        = obex_attr_release,
+       .show_attribute = f_obex_attr_show,
+};
+
+static ssize_t f_obex_port_num_show(struct f_serial_opts *opts, char *page)
+{
+       return sprintf(page, "%u\n", opts->port_num);
+}
+
+static struct f_serial_opts_attribute f_obex_port_num =
+       __CONFIGFS_ATTR_RO(port_num, f_obex_port_num_show);
+
+static struct configfs_attribute *acm_attrs[] = {
+       &f_obex_port_num.attr,
+       NULL,
+};
+
+static struct config_item_type obex_func_type = {
+       .ct_item_ops    = &obex_item_ops,
+       .ct_attrs       = acm_attrs,
+       .ct_owner       = THIS_MODULE,
+};
+
+static void obex_free_inst(struct usb_function_instance *f)
+{
+       struct f_serial_opts *opts;
+
+       opts = container_of(f, struct f_serial_opts, func_inst);
+       gserial_free_line(opts->port_num);
+       kfree(opts);
+}
+
+static struct usb_function_instance *obex_alloc_inst(void)
+{
+       struct f_serial_opts *opts;
+       int ret;
+
+       opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+       if (!opts)
+               return ERR_PTR(-ENOMEM);
+
+       opts->func_inst.free_func_inst = obex_free_inst;
+       ret = gserial_alloc_line(&opts->port_num);
+       if (ret) {
+               kfree(opts);
+               return ERR_PTR(ret);
+       }
+       config_group_init_type_name(&opts->func_inst.group, "",
+                                   &obex_func_type);
+
+       return &opts->func_inst;
+}
+
+static void obex_free(struct usb_function *f)
+{
+       struct f_obex *obex;
+
+       obex = func_to_obex(f);
+       kfree(obex);
+}
+
+static void obex_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+       obex_string_defs[OBEX_CTRL_IDX].id = 0;
+       usb_free_all_descriptors(f);
+}
+
+struct usb_function *obex_alloc(struct usb_function_instance *fi)
+{
+       struct f_obex   *obex;
+       struct f_serial_opts *opts;
+
+       /* allocate and initialize one new instance */
+       obex = kzalloc(sizeof(*obex), GFP_KERNEL);
+       if (!obex)
+               return ERR_PTR(-ENOMEM);
+
+       opts = container_of(fi, struct f_serial_opts, func_inst);
+
+       obex->port_num = opts->port_num;
+
+       obex->port.connect = obex_connect;
+       obex->port.disconnect = obex_disconnect;
+
+       obex->port.func.name = "obex";
+       obex->port.func.strings = obex_strings;
+       /* descriptors are per-instance copies */
+       obex->port.func.bind = obex_bind;
+       obex->port.func.unbind = obex_unbind;
+       obex->port.func.set_alt = obex_set_alt;
+       obex->port.func.get_alt = obex_get_alt;
+       obex->port.func.disable = obex_disable;
+       obex->port.func.free_func = obex_free;
+
+       return &obex->port.func;
+}
+
+DECLARE_USB_FUNCTION_INIT(obex, obex_alloc_inst, obex_alloc);
+
+#endif
+
 MODULE_AUTHOR("Felipe Balbi");
 MODULE_LICENSE("GPL");
index cc9c49c..36e8c44 100644 (file)
@@ -813,7 +813,7 @@ static inline bool can_support_rndis(struct usb_configuration *c)
 
 int
 rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
-                               u32 vendorID, const char *manufacturer)
+               u32 vendorID, const char *manufacturer, struct eth_dev *dev)
 {
        struct f_rndis  *rndis;
        int             status;
@@ -846,6 +846,7 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
        rndis->vendorID = vendorID;
        rndis->manufacturer = manufacturer;
 
+       rndis->port.ioport = dev;
        /* RNDIS activates when the host changes this filter */
        rndis->port.cdc_filter = 0;
 
index da33cfb..981113c 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/slab.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/device.h>
 
 #include "u_serial.h"
@@ -42,7 +43,7 @@ static inline struct f_gser *func_to_gser(struct usb_function *f)
 
 /* interface descriptor: */
 
-static struct usb_interface_descriptor gser_interface_desc __initdata = {
+static struct usb_interface_descriptor gser_interface_desc = {
        .bLength =              USB_DT_INTERFACE_SIZE,
        .bDescriptorType =      USB_DT_INTERFACE,
        /* .bInterfaceNumber = DYNAMIC */
@@ -55,21 +56,21 @@ static struct usb_interface_descriptor gser_interface_desc __initdata = {
 
 /* full speed support: */
 
-static struct usb_endpoint_descriptor gser_fs_in_desc __initdata = {
+static struct usb_endpoint_descriptor gser_fs_in_desc = {
        .bLength =              USB_DT_ENDPOINT_SIZE,
        .bDescriptorType =      USB_DT_ENDPOINT,
        .bEndpointAddress =     USB_DIR_IN,
        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_endpoint_descriptor gser_fs_out_desc __initdata = {
+static struct usb_endpoint_descriptor gser_fs_out_desc = {
        .bLength =              USB_DT_ENDPOINT_SIZE,
        .bDescriptorType =      USB_DT_ENDPOINT,
        .bEndpointAddress =     USB_DIR_OUT,
        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_descriptor_header *gser_fs_function[] __initdata = {
+static struct usb_descriptor_header *gser_fs_function[] = {
        (struct usb_descriptor_header *) &gser_interface_desc,
        (struct usb_descriptor_header *) &gser_fs_in_desc,
        (struct usb_descriptor_header *) &gser_fs_out_desc,
@@ -78,47 +79,47 @@ static struct usb_descriptor_header *gser_fs_function[] __initdata = {
 
 /* high speed support: */
 
-static struct usb_endpoint_descriptor gser_hs_in_desc __initdata = {
+static struct usb_endpoint_descriptor gser_hs_in_desc = {
        .bLength =              USB_DT_ENDPOINT_SIZE,
        .bDescriptorType =      USB_DT_ENDPOINT,
        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
        .wMaxPacketSize =       cpu_to_le16(512),
 };
 
-static struct usb_endpoint_descriptor gser_hs_out_desc __initdata = {
+static struct usb_endpoint_descriptor gser_hs_out_desc = {
        .bLength =              USB_DT_ENDPOINT_SIZE,
        .bDescriptorType =      USB_DT_ENDPOINT,
        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
        .wMaxPacketSize =       cpu_to_le16(512),
 };
 
-static struct usb_descriptor_header *gser_hs_function[] __initdata = {
+static struct usb_descriptor_header *gser_hs_function[] = {
        (struct usb_descriptor_header *) &gser_interface_desc,
        (struct usb_descriptor_header *) &gser_hs_in_desc,
        (struct usb_descriptor_header *) &gser_hs_out_desc,
        NULL,
 };
 
-static struct usb_endpoint_descriptor gser_ss_in_desc __initdata = {
+static struct usb_endpoint_descriptor gser_ss_in_desc = {
        .bLength =              USB_DT_ENDPOINT_SIZE,
        .bDescriptorType =      USB_DT_ENDPOINT,
        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
        .wMaxPacketSize =       cpu_to_le16(1024),
 };
 
-static struct usb_endpoint_descriptor gser_ss_out_desc __initdata = {
+static struct usb_endpoint_descriptor gser_ss_out_desc = {
        .bLength =              USB_DT_ENDPOINT_SIZE,
        .bDescriptorType =      USB_DT_ENDPOINT,
        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
        .wMaxPacketSize =       cpu_to_le16(1024),
 };
 
-static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc __initdata = {
+static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc = {
        .bLength =              sizeof gser_ss_bulk_comp_desc,
        .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
 };
 
-static struct usb_descriptor_header *gser_ss_function[] __initdata = {
+static struct usb_descriptor_header *gser_ss_function[] = {
        (struct usb_descriptor_header *) &gser_interface_desc,
        (struct usb_descriptor_header *) &gser_ss_in_desc,
        (struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
@@ -183,14 +184,25 @@ static void gser_disable(struct usb_function *f)
 
 /* serial function driver setup/binding */
 
-static int __init
-gser_bind(struct usb_configuration *c, struct usb_function *f)
+static int gser_bind(struct usb_configuration *c, struct usb_function *f)
 {
        struct usb_composite_dev *cdev = c->cdev;
        struct f_gser           *gser = func_to_gser(f);
        int                     status;
        struct usb_ep           *ep;
 
+       /* REVISIT might want instance-specific strings to help
+        * distinguish instances ...
+        */
+
+       /* maybe allocate device-global string ID */
+       if (gser_string_defs[0].id == 0) {
+               status = usb_string_id(c->cdev);
+               if (status < 0)
+                       return status;
+               gser_string_defs[0].id = status;
+       }
+
        /* allocate instance-specific interface IDs */
        status = usb_interface_id(c, f);
        if (status < 0)
@@ -246,44 +258,115 @@ fail:
        return status;
 }
 
-static void
-gser_unbind(struct usb_configuration *c, struct usb_function *f)
+static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
 {
-       usb_free_all_descriptors(f);
-       kfree(func_to_gser(f));
+       return container_of(to_config_group(item), struct f_serial_opts,
+                           func_inst.group);
 }
 
-/**
- * gser_bind_config - add a generic serial function to a configuration
- * @c: the configuration to support the serial instance
- * @port_num: /dev/ttyGS* port this interface will use
- * Context: single threaded during gadget setup
- *
- * Returns zero on success, else negative errno.
- */
-int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
+CONFIGFS_ATTR_STRUCT(f_serial_opts);
+static ssize_t f_serial_attr_show(struct config_item *item,
+                                 struct configfs_attribute *attr,
+                                 char *page)
 {
-       struct f_gser   *gser;
-       int             status;
+       struct f_serial_opts *opts = to_f_serial_opts(item);
+       struct f_serial_opts_attribute *f_serial_opts_attr =
+               container_of(attr, struct f_serial_opts_attribute, attr);
+       ssize_t ret = 0;
 
-       /* REVISIT might want instance-specific strings to help
-        * distinguish instances ...
-        */
+       if (f_serial_opts_attr->show)
+               ret = f_serial_opts_attr->show(opts, page);
 
-       /* maybe allocate device-global string ID */
-       if (gser_string_defs[0].id == 0) {
-               status = usb_string_id(c->cdev);
-               if (status < 0)
-                       return status;
-               gser_string_defs[0].id = status;
+       return ret;
+}
+
+static void serial_attr_release(struct config_item *item)
+{
+       struct f_serial_opts *opts = to_f_serial_opts(item);
+
+       usb_put_function_instance(&opts->func_inst);
+}
+
+static struct configfs_item_operations serial_item_ops = {
+       .release        = serial_attr_release,
+       .show_attribute = f_serial_attr_show,
+};
+
+static ssize_t f_serial_port_num_show(struct f_serial_opts *opts, char *page)
+{
+       return sprintf(page, "%u\n", opts->port_num);
+}
+
+static struct f_serial_opts_attribute f_serial_port_num =
+       __CONFIGFS_ATTR_RO(port_num, f_serial_port_num_show);
+
+static struct configfs_attribute *acm_attrs[] = {
+       &f_serial_port_num.attr,
+       NULL,
+};
+
+static struct config_item_type serial_func_type = {
+       .ct_item_ops    = &serial_item_ops,
+       .ct_attrs       = acm_attrs,
+       .ct_owner       = THIS_MODULE,
+};
+
+static void gser_free_inst(struct usb_function_instance *f)
+{
+       struct f_serial_opts *opts;
+
+       opts = container_of(f, struct f_serial_opts, func_inst);
+       gserial_free_line(opts->port_num);
+       kfree(opts);
+}
+
+static struct usb_function_instance *gser_alloc_inst(void)
+{
+       struct f_serial_opts *opts;
+       int ret;
+
+       opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+       if (!opts)
+               return ERR_PTR(-ENOMEM);
+
+       opts->func_inst.free_func_inst = gser_free_inst;
+       ret = gserial_alloc_line(&opts->port_num);
+       if (ret) {
+               kfree(opts);
+               return ERR_PTR(ret);
        }
+       config_group_init_type_name(&opts->func_inst.group, "",
+                                   &serial_func_type);
+
+       return &opts->func_inst;
+}
+
+static void gser_free(struct usb_function *f)
+{
+       struct f_gser *serial;
+
+       serial = func_to_gser(f);
+       kfree(serial);
+}
+
+static void gser_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+       usb_free_all_descriptors(f);
+}
+
+struct usb_function *gser_alloc(struct usb_function_instance *fi)
+{
+       struct f_gser   *gser;
+       struct f_serial_opts *opts;
 
        /* allocate and initialize one new instance */
-       gser = kzalloc(sizeof *gser, GFP_KERNEL);
+       gser = kzalloc(sizeof(*gser), GFP_KERNEL);
        if (!gser)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
 
-       gser->port_num = port_num;
+       opts = container_of(fi, struct f_serial_opts, func_inst);
+
+       gser->port_num = opts->port_num;
 
        gser->port.func.name = "gser";
        gser->port.func.strings = gser_strings;
@@ -291,9 +374,12 @@ int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
        gser->port.func.unbind = gser_unbind;
        gser->port.func.set_alt = gser_set_alt;
        gser->port.func.disable = gser_disable;
+       gser->port.func.free_func = gser_free;
 
-       status = usb_add_function(c, &gser->port.func);
-       if (status)
-               kfree(gser);
-       return status;
+       return &gser->port.func;
 }
+
+DECLARE_USB_FUNCTION_INIT(gser, gser_alloc_inst, gser_alloc);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Al Borchers");
+MODULE_AUTHOR("David Brownell");
index f172bd1..185d6f5 100644 (file)
@@ -380,7 +380,8 @@ geth_unbind(struct usb_configuration *c, struct usb_function *f)
  * Caller must have called @gether_setup().  Caller is also responsible
  * for calling @gether_cleanup() before module unload.
  */
-int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+               struct eth_dev *dev)
 {
        struct f_gether *geth;
        int             status;
@@ -406,6 +407,7 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
        snprintf(geth->ethaddr, sizeof geth->ethaddr, "%pm", ethaddr);
        geth_string_defs[1].s = geth->ethaddr;
 
+       geth->port.ioport = dev;
        geth->port.cdc_filter = DEFAULT_FILTER;
 
        geth->port.func.name = "cdc_subset";
index 92efd6e..38dcedd 100644 (file)
@@ -33,19 +33,15 @@ unsigned int uvc_gadget_trace_param;
 /*-------------------------------------------------------------------------*/
 
 /* module parameters specific to the Video streaming endpoint */
-static unsigned streaming_interval = 1;
+static unsigned int streaming_interval = 1;
 module_param(streaming_interval, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(streaming_interval, "1 - 16");
 
-static unsigned streaming_maxpacket = 1024;
+static unsigned int streaming_maxpacket = 1024;
 module_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(streaming_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)");
+MODULE_PARM_DESC(streaming_maxpacket, "1 - 1023 (FS), 1 - 3072 (hs/ss)");
 
-static unsigned streaming_mult;
-module_param(streaming_mult, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(streaming_mult, "0 - 2 (hs/ss only)");
-
-static unsigned streaming_maxburst;
+static unsigned int streaming_maxburst;
 module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)");
 
@@ -55,13 +51,11 @@ MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)");
 
 /* string IDs are assigned dynamically */
 
-#define UVC_STRING_ASSOCIATION_IDX             0
-#define UVC_STRING_CONTROL_IDX                 1
-#define UVC_STRING_STREAMING_IDX               2
+#define UVC_STRING_CONTROL_IDX                 0
+#define UVC_STRING_STREAMING_IDX               1
 
 static struct usb_string uvc_en_us_strings[] = {
-       [UVC_STRING_ASSOCIATION_IDX].s = "UVC Camera",
-       [UVC_STRING_CONTROL_IDX].s = "Video Control",
+       [UVC_STRING_CONTROL_IDX].s = "UVC Camera",
        [UVC_STRING_STREAMING_IDX].s = "Video Streaming",
        {  }
 };
@@ -79,7 +73,7 @@ static struct usb_gadget_strings *uvc_function_strings[] = {
 #define UVC_INTF_VIDEO_CONTROL                 0
 #define UVC_INTF_VIDEO_STREAMING               1
 
-#define STATUS_BYTECOUNT                       16      /* 16 bytes status */
+#define UVC_STATUS_MAX_PACKET_SIZE             16      /* 16 bytes status */
 
 static struct usb_interface_assoc_descriptor uvc_iad __initdata = {
        .bLength                = sizeof(uvc_iad),
@@ -104,20 +98,29 @@ static struct usb_interface_descriptor uvc_control_intf __initdata = {
        .iInterface             = 0,
 };
 
-static struct usb_endpoint_descriptor uvc_fs_control_ep __initdata = {
+static struct usb_endpoint_descriptor uvc_control_ep __initdata = {
        .bLength                = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType        = USB_DT_ENDPOINT,
        .bEndpointAddress       = USB_DIR_IN,
        .bmAttributes           = USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize         = cpu_to_le16(STATUS_BYTECOUNT),
+       .wMaxPacketSize         = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE),
        .bInterval              = 8,
 };
 
+static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp __initdata = {
+       .bLength                = sizeof(uvc_ss_control_comp),
+       .bDescriptorType        = USB_DT_SS_ENDPOINT_COMP,
+       /* The following 3 values can be tweaked if necessary. */
+       .bMaxBurst              = 0,
+       .bmAttributes           = 0,
+       .wBytesPerInterval      = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE),
+};
+
 static struct uvc_control_endpoint_descriptor uvc_control_cs_ep __initdata = {
        .bLength                = UVC_DT_CONTROL_ENDPOINT_SIZE,
        .bDescriptorType        = USB_DT_CS_ENDPOINT,
        .bDescriptorSubType     = UVC_EP_INTERRUPT,
-       .wMaxTransferSize       = cpu_to_le16(STATUS_BYTECOUNT),
+       .wMaxTransferSize       = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE),
 };
 
 static struct usb_interface_descriptor uvc_streaming_intf_alt0 __initdata = {
@@ -144,63 +147,53 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = {
        .iInterface             = 0,
 };
 
-static struct usb_endpoint_descriptor uvc_fs_streaming_ep = {
+static struct usb_endpoint_descriptor uvc_fs_streaming_ep __initdata = {
        .bLength                = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType        = USB_DT_ENDPOINT,
        .bEndpointAddress       = USB_DIR_IN,
-       .bmAttributes           = USB_ENDPOINT_XFER_ISOC,
-       .wMaxPacketSize         = cpu_to_le16(512),
-       .bInterval              = 1,
+       .bmAttributes           = USB_ENDPOINT_SYNC_ASYNC
+                               | USB_ENDPOINT_XFER_ISOC,
+       /* The wMaxPacketSize and bInterval values will be initialized from
+        * module parameters.
+        */
+       .wMaxPacketSize         = 0,
+       .bInterval              = 0,
 };
 
-static struct usb_endpoint_descriptor uvc_hs_streaming_ep = {
+static struct usb_endpoint_descriptor uvc_hs_streaming_ep __initdata = {
        .bLength                = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType        = USB_DT_ENDPOINT,
        .bEndpointAddress       = USB_DIR_IN,
-       .bmAttributes           = USB_ENDPOINT_XFER_ISOC,
-       .wMaxPacketSize         = cpu_to_le16(1024),
-       .bInterval              = 1,
-};
-
-/* super speed support */
-static struct usb_endpoint_descriptor uvc_ss_control_ep __initdata = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bEndpointAddress =     USB_DIR_IN,
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(STATUS_BYTECOUNT),
-       .bInterval =            8,
-};
-
-static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp __initdata = {
-       .bLength =              sizeof uvc_ss_control_comp,
-       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
-
-       /* the following 3 values can be tweaked if necessary */
-       /* .bMaxBurst =         0, */
-       /* .bmAttributes =      0, */
-       .wBytesPerInterval =    cpu_to_le16(STATUS_BYTECOUNT),
+       .bmAttributes           = USB_ENDPOINT_SYNC_ASYNC
+                               | USB_ENDPOINT_XFER_ISOC,
+       /* The wMaxPacketSize and bInterval values will be initialized from
+        * module parameters.
+        */
+       .wMaxPacketSize         = 0,
+       .bInterval              = 0,
 };
 
 static struct usb_endpoint_descriptor uvc_ss_streaming_ep __initdata = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bLength                = USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType        = USB_DT_ENDPOINT,
 
-       .bEndpointAddress =     USB_DIR_IN,
-       .bmAttributes =         USB_ENDPOINT_XFER_ISOC,
-       .wMaxPacketSize =       cpu_to_le16(1024),
-       .bInterval =            4,
+       .bEndpointAddress       = USB_DIR_IN,
+       .bmAttributes           = USB_ENDPOINT_SYNC_ASYNC
+                               | USB_ENDPOINT_XFER_ISOC,
+       /* The wMaxPacketSize and bInterval values will be initialized from
+        * module parameters.
+        */
+       .wMaxPacketSize         = 0,
+       .bInterval              = 0,
 };
 
-static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp = {
-       .bLength =              sizeof uvc_ss_streaming_comp,
-       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
-
-       /* the following 3 values can be tweaked if necessary */
-       .bMaxBurst =            0,
-       .bmAttributes = 0,
-       .wBytesPerInterval =    cpu_to_le16(1024),
+static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp __initdata = {
+       .bLength                = sizeof(uvc_ss_streaming_comp),
+       .bDescriptorType        = USB_DT_SS_ENDPOINT_COMP,
+       /* The following 3 values can be tweaked if necessary. */
+       .bMaxBurst              = 0,
+       .bmAttributes           = 0,
+       .wBytesPerInterval      = cpu_to_le16(1024),
 };
 
 static const struct usb_descriptor_header * const uvc_fs_streaming[] = {
@@ -273,6 +266,13 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
        return 0;
 }
 
+void uvc_function_setup_continue(struct uvc_device *uvc)
+{
+       struct usb_composite_dev *cdev = uvc->func.config->cdev;
+
+       usb_composite_setup_continue(cdev);
+}
+
 static int
 uvc_function_get_alt(struct usb_function *f, unsigned interface)
 {
@@ -335,7 +335,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
                v4l2_event_queue(uvc->vdev, &v4l2_event);
 
                uvc->state = UVC_STATE_CONNECTED;
-               break;
+               return 0;
 
        case 1:
                if (uvc->state != UVC_STATE_CONNECTED)
@@ -352,15 +352,11 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
                memset(&v4l2_event, 0, sizeof(v4l2_event));
                v4l2_event.type = UVC_EVENT_STREAMON;
                v4l2_event_queue(uvc->vdev, &v4l2_event);
-
-               uvc->state = UVC_STATE_STREAMING;
-               break;
+               return USB_GADGET_DELAYED_STATUS;
 
        default:
                return -EINVAL;
        }
-
-       return 0;
 }
 
 static void
@@ -454,7 +450,6 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
        const struct uvc_descriptor_header * const *uvc_streaming_cls;
        const struct usb_descriptor_header * const *uvc_streaming_std;
        const struct usb_descriptor_header * const *src;
-       static struct usb_endpoint_descriptor *uvc_control_ep;
        struct usb_descriptor_header **dst;
        struct usb_descriptor_header **hdr;
        unsigned int control_size;
@@ -468,14 +463,12 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
                uvc_control_desc = uvc->desc.ss_control;
                uvc_streaming_cls = uvc->desc.ss_streaming;
                uvc_streaming_std = uvc_ss_streaming;
-               uvc_control_ep = &uvc_ss_control_ep;
                break;
 
        case USB_SPEED_HIGH:
                uvc_control_desc = uvc->desc.fs_control;
                uvc_streaming_cls = uvc->desc.hs_streaming;
                uvc_streaming_std = uvc_hs_streaming;
-               uvc_control_ep = &uvc_fs_control_ep;
                break;
 
        case USB_SPEED_FULL:
@@ -483,7 +476,6 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
                uvc_control_desc = uvc->desc.fs_control;
                uvc_streaming_cls = uvc->desc.fs_streaming;
                uvc_streaming_std = uvc_fs_streaming;
-               uvc_control_ep = &uvc_fs_control_ep;
                break;
        }
 
@@ -494,6 +486,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
         * Class-specific UVC control descriptors
         * uvc_control_ep
         * uvc_control_cs_ep
+        * uvc_ss_control_comp (for SS only)
         * uvc_streaming_intf_alt0
         * Class-specific UVC streaming descriptors
         * uvc_{fs|hs}_streaming
@@ -503,7 +496,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
        control_size = 0;
        streaming_size = 0;
        bytes = uvc_iad.bLength + uvc_control_intf.bLength
-             + uvc_control_ep->bLength + uvc_control_cs_ep.bLength
+             + uvc_control_ep.bLength + uvc_control_cs_ep.bLength
              + uvc_streaming_intf_alt0.bLength;
 
        if (speed == USB_SPEED_SUPER) {
@@ -514,13 +507,13 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
        }
 
        for (src = (const struct usb_descriptor_header **)uvc_control_desc;
-                       *src; ++src) {
+            *src; ++src) {
                control_size += (*src)->bLength;
                bytes += (*src)->bLength;
                n_desc++;
        }
        for (src = (const struct usb_descriptor_header **)uvc_streaming_cls;
-                       *src; ++src) {
+            *src; ++src) {
                streaming_size += (*src)->bLength;
                bytes += (*src)->bLength;
                n_desc++;
@@ -549,7 +542,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
        uvc_control_header->bInCollection = 1;
        uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf;
 
-       UVC_COPY_DESCRIPTOR(mem, dst, uvc_control_ep);
+       UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_ep);
        if (speed == USB_SPEED_SUPER)
                UVC_COPY_DESCRIPTOR(mem, dst, &uvc_ss_control_comp);
 
@@ -560,8 +553,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
        UVC_COPY_DESCRIPTORS(mem, dst,
                (const struct usb_descriptor_header**)uvc_streaming_cls);
        uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size);
-       uvc_streaming_header->bEndpointAddress =
-               uvc_fs_streaming_ep.bEndpointAddress;
+       uvc_streaming_header->bEndpointAddress = uvc->video.ep->address;
 
        UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std);
 
@@ -581,7 +573,7 @@ uvc_function_unbind(struct usb_configuration *c, struct usb_function *f)
        uvc->control_ep->driver_data = NULL;
        uvc->video.ep->driver_data = NULL;
 
-       uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = 0;
+       uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id = 0;
        usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
        kfree(uvc->control_buf);
 
@@ -595,31 +587,52 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
 {
        struct usb_composite_dev *cdev = c->cdev;
        struct uvc_device *uvc = to_uvc(f);
+       unsigned int max_packet_mult;
+       unsigned int max_packet_size;
        struct usb_ep *ep;
        int ret = -EINVAL;
 
        INFO(cdev, "uvc_function_bind\n");
 
-       /* sanity check the streaming endpoint module parameters */
-       if (streaming_interval < 1)
-               streaming_interval = 1;
-       if (streaming_interval > 16)
-               streaming_interval = 16;
-       if (streaming_mult > 2)
-               streaming_mult = 2;
-       if (streaming_maxburst > 15)
-               streaming_maxburst = 15;
-
-       /*
-        * fill in the FS video streaming specific descriptors from the
-        * module parameters
+       /* Sanity check the streaming endpoint module parameters.
         */
-       uvc_fs_streaming_ep.wMaxPacketSize = streaming_maxpacket > 1023 ?
-                                               1023 : streaming_maxpacket;
+       streaming_interval = clamp(streaming_interval, 1U, 16U);
+       streaming_maxpacket = clamp(streaming_maxpacket, 1U, 3072U);
+       streaming_maxburst = min(streaming_maxburst, 15U);
+
+       /* Fill in the FS/HS/SS Video Streaming specific descriptors from the
+        * module parameters.
+        *
+        * NOTE: We assume that the user knows what they are doing and won't
+        * give parameters that their UDC doesn't support.
+        */
+       if (streaming_maxpacket <= 1024) {
+               max_packet_mult = 1;
+               max_packet_size = streaming_maxpacket;
+       } else if (streaming_maxpacket <= 2048) {
+               max_packet_mult = 2;
+               max_packet_size = streaming_maxpacket / 2;
+       } else {
+               max_packet_mult = 3;
+               max_packet_size = streaming_maxpacket / 3;
+       }
+
+       uvc_fs_streaming_ep.wMaxPacketSize = min(streaming_maxpacket, 1023U);
        uvc_fs_streaming_ep.bInterval = streaming_interval;
 
+       uvc_hs_streaming_ep.wMaxPacketSize = max_packet_size;
+       uvc_hs_streaming_ep.wMaxPacketSize |= ((max_packet_mult - 1) << 11);
+       uvc_hs_streaming_ep.bInterval = streaming_interval;
+
+       uvc_ss_streaming_ep.wMaxPacketSize = max_packet_size;
+       uvc_ss_streaming_ep.bInterval = streaming_interval;
+       uvc_ss_streaming_comp.bmAttributes = max_packet_mult - 1;
+       uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst;
+       uvc_ss_streaming_comp.wBytesPerInterval =
+               max_packet_size * max_packet_mult * streaming_maxburst;
+
        /* Allocate endpoints. */
-       ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_control_ep);
+       ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
        if (!ep) {
                INFO(cdev, "Unable to allocate control EP\n");
                goto error;
@@ -627,7 +640,14 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
        uvc->control_ep = ep;
        ep->driver_data = uvc;
 
-       ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
+       if (gadget_is_superspeed(c->cdev->gadget))
+               ep = usb_ep_autoconfig_ss(cdev->gadget, &uvc_ss_streaming_ep,
+                                         &uvc_ss_streaming_comp);
+       else if (gadget_is_dualspeed(cdev->gadget))
+               ep = usb_ep_autoconfig(cdev->gadget, &uvc_hs_streaming_ep);
+       else
+               ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
+
        if (!ep) {
                INFO(cdev, "Unable to allocate streaming EP\n");
                goto error;
@@ -635,6 +655,10 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
        uvc->video.ep = ep;
        ep->driver_data = uvc;
 
+       uvc_fs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
+       uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
+       uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address;
+
        /* Allocate interface IDs. */
        if ((ret = usb_interface_id(c, f)) < 0)
                goto error;
@@ -648,37 +672,6 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
        uvc_streaming_intf_alt1.bInterfaceNumber = ret;
        uvc->streaming_intf = ret;
 
-       /* sanity check the streaming endpoint module parameters */
-       if (streaming_maxpacket > 1024)
-               streaming_maxpacket = 1024;
-       /*
-        * Fill in the HS descriptors from the module parameters for the Video
-        * Streaming endpoint.
-        * NOTE: We assume that the user knows what they are doing and won't
-        * give parameters that their UDC doesn't support.
-        */
-       uvc_hs_streaming_ep.wMaxPacketSize = streaming_maxpacket;
-       uvc_hs_streaming_ep.wMaxPacketSize |= streaming_mult << 11;
-       uvc_hs_streaming_ep.bInterval = streaming_interval;
-       uvc_hs_streaming_ep.bEndpointAddress =
-               uvc_fs_streaming_ep.bEndpointAddress;
-
-       /*
-        * Fill in the SS descriptors from the module parameters for the Video
-        * Streaming endpoint.
-        * NOTE: We assume that the user knows what they are doing and won't
-        * give parameters that their UDC doesn't support.
-        */
-       uvc_ss_streaming_ep.wMaxPacketSize = streaming_maxpacket;
-       uvc_ss_streaming_ep.bInterval = streaming_interval;
-       uvc_ss_streaming_comp.bmAttributes = streaming_mult;
-       uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst;
-       uvc_ss_streaming_comp.wBytesPerInterval =
-               streaming_maxpacket * (streaming_mult + 1) *
-               (streaming_maxburst + 1);
-       uvc_ss_streaming_ep.bEndpointAddress =
-               uvc_fs_streaming_ep.bEndpointAddress;
-
        /* Copy descriptors */
        f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
        if (gadget_is_dualspeed(cdev->gadget))
@@ -775,23 +768,23 @@ uvc_bind_config(struct usb_configuration *c,
 
        /* Validate the descriptors. */
        if (fs_control == NULL || fs_control[0] == NULL ||
-               fs_control[0]->bDescriptorSubType != UVC_VC_HEADER)
+           fs_control[0]->bDescriptorSubType != UVC_VC_HEADER)
                goto error;
 
        if (ss_control == NULL || ss_control[0] == NULL ||
-               ss_control[0]->bDescriptorSubType != UVC_VC_HEADER)
+           ss_control[0]->bDescriptorSubType != UVC_VC_HEADER)
                goto error;
 
        if (fs_streaming == NULL || fs_streaming[0] == NULL ||
-               fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
+           fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
                goto error;
 
        if (hs_streaming == NULL || hs_streaming[0] == NULL ||
-               hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
+           hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
                goto error;
 
        if (ss_streaming == NULL || ss_streaming[0] == NULL ||
-               ss_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
+           ss_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
                goto error;
 
        uvc->desc.fs_control = fs_control;
@@ -800,13 +793,16 @@ uvc_bind_config(struct usb_configuration *c,
        uvc->desc.hs_streaming = hs_streaming;
        uvc->desc.ss_streaming = ss_streaming;
 
-       /* Allocate string descriptor numbers. */
-       if (uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id == 0) {
+       /* String descriptors are global, we only need to allocate string IDs
+        * for the first UVC function. UVC functions beyond the first (if any)
+        * will reuse the same IDs.
+        */
+       if (uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id == 0) {
                ret = usb_string_ids_tab(c->cdev, uvc_en_us_strings);
                if (ret)
                        goto error;
                uvc_iad.iFunction =
-                       uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id;
+                       uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id;
                uvc_control_intf.iInterface =
                        uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id;
                ret = uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id;
index c3d258d..ec52752 100644 (file)
 #include <linux/usb/composite.h>
 #include <linux/usb/video.h>
 
-extern int uvc_bind_config(struct usb_configuration *c,
-                  const struct uvc_descriptor_header * const *fs_control,
-                  const struct uvc_descriptor_header * const *hs_control,
-                  const struct uvc_descriptor_header * const *fs_streaming,
-                  const struct uvc_descriptor_header * const *hs_streaming,
-                  const struct uvc_descriptor_header * const *ss_streaming);
+int uvc_bind_config(struct usb_configuration *c,
+                   const struct uvc_descriptor_header * const *fs_control,
+                   const struct uvc_descriptor_header * const *hs_control,
+                   const struct uvc_descriptor_header * const *fs_streaming,
+                   const struct uvc_descriptor_header * const *hs_streaming,
+                   const struct uvc_descriptor_header * const *ss_streaming);
 
 #endif /* _F_UVC_H_ */
 
index 034477c..9a7ee33 100644 (file)
@@ -2296,7 +2296,6 @@ static int fsl_qe_start(struct usb_gadget *gadget,
        driver->driver.bus = NULL;
        /* hook up the driver */
        udc->driver = driver;
-       udc->gadget.dev.driver = &driver->driver;
        udc->gadget.speed = driver->max_speed;
 
        /* Enable IRQ reg and Set usbcmd reg EN bit */
@@ -2338,7 +2337,6 @@ static int fsl_qe_stop(struct usb_gadget *gadget,
                nuke(loop_ep, -ESHUTDOWN);
        spin_unlock_irqrestore(&udc->lock, flags);
 
-       udc->gadget.dev.driver = NULL;
        udc->driver = NULL;
 
        dev_info(udc->dev, "unregistered gadget driver '%s'\r\n",
@@ -2523,12 +2521,6 @@ static int qe_udc_probe(struct platform_device *ofdev)
 
        /* name: Identifies the controller hardware type. */
        udc->gadget.name = driver_name;
-
-       device_initialize(&udc->gadget.dev);
-
-       dev_set_name(&udc->gadget.dev, "gadget");
-
-       udc->gadget.dev.release = qe_udc_release;
        udc->gadget.dev.parent = &ofdev->dev;
 
        /* initialize qe_ep struct */
@@ -2592,22 +2584,17 @@ static int qe_udc_probe(struct platform_device *ofdev)
                goto err5;
        }
 
-       ret = device_add(&udc->gadget.dev);
+       ret = usb_add_gadget_udc_release(&ofdev->dev, &udc->gadget,
+                       qe_udc_release);
        if (ret)
                goto err6;
 
-       ret = usb_add_gadget_udc(&ofdev->dev, &udc->gadget);
-       if (ret)
-               goto err7;
-
        dev_set_drvdata(&ofdev->dev, udc);
        dev_info(udc->dev,
                        "%s USB controller initialized as device\n",
                        (udc->soc_type == PORT_QE) ? "QE" : "CPM");
        return 0;
 
-err7:
-       device_unregister(&udc->gadget.dev);
 err6:
        free_irq(udc->usb_irq, udc);
 err5:
@@ -2702,7 +2689,6 @@ static int qe_udc_remove(struct platform_device *ofdev)
 
        iounmap(udc->usb_regs);
 
-       device_unregister(&udc->gadget.dev);
        /* wait for release() of gadget.dev to free udc */
        wait_for_completion(&done);
 
index 04d5fef..7c2a101 100644 (file)
@@ -185,20 +185,7 @@ static void done(struct fsl_ep *ep, struct fsl_req *req, int status)
                dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma);
        }
 
-       if (req->mapped) {
-               dma_unmap_single(ep->udc->gadget.dev.parent,
-                       req->req.dma, req->req.length,
-                       ep_is_in(ep)
-                               ? DMA_TO_DEVICE
-                               : DMA_FROM_DEVICE);
-               req->req.dma = DMA_ADDR_INVALID;
-               req->mapped = 0;
-       } else
-               dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
-                       req->req.dma, req->req.length,
-                       ep_is_in(ep)
-                               ? DMA_TO_DEVICE
-                               : DMA_FROM_DEVICE);
+       usb_gadget_unmap_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
 
        if (status && (status != -ESHUTDOWN))
                VDBG("complete %s req %p stat %d len %u/%u",
@@ -888,6 +875,7 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
        struct fsl_req *req = container_of(_req, struct fsl_req, req);
        struct fsl_udc *udc;
        unsigned long flags;
+       int ret;
 
        /* catch various bogus parameters */
        if (!_req || !req->req.complete || !req->req.buf
@@ -910,22 +898,9 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 
        req->ep = ep;
 
-       /* map virtual address to hardware */
-       if (req->req.dma == DMA_ADDR_INVALID) {
-               req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
-                                       req->req.buf,
-                                       req->req.length, ep_is_in(ep)
-                                               ? DMA_TO_DEVICE
-                                               : DMA_FROM_DEVICE);
-               req->mapped = 1;
-       } else {
-               dma_sync_single_for_device(ep->udc->gadget.dev.parent,
-                                       req->req.dma, req->req.length,
-                                       ep_is_in(ep)
-                                               ? DMA_TO_DEVICE
-                                               : DMA_FROM_DEVICE);
-               req->mapped = 0;
-       }
+       ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
+       if (ret)
+               return ret;
 
        req->req.status = -EINPROGRESS;
        req->req.actual = 0;
@@ -1290,6 +1265,7 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction)
 {
        struct fsl_req *req = udc->status_req;
        struct fsl_ep *ep;
+       int ret;
 
        if (direction == EP_DIR_IN)
                udc->ep0_dir = USB_DIR_IN;
@@ -1307,10 +1283,9 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction)
        req->req.complete = NULL;
        req->dtd_count = 0;
 
-       req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
-                       req->req.buf, req->req.length,
-                       ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-       req->mapped = 1;
+       ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
+       if (ret)
+               return ret;
 
        if (fsl_req_to_dtd(req, GFP_ATOMIC) == 0)
                fsl_queue_td(ep, req);
@@ -1353,6 +1328,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
        u16 tmp = 0;            /* Status, cpu endian */
        struct fsl_req *req;
        struct fsl_ep *ep;
+       int ret;
 
        ep = &udc->eps[0];
 
@@ -1390,10 +1366,9 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
        req->req.complete = NULL;
        req->dtd_count = 0;
 
-       req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
-                               req->req.buf, req->req.length,
-                               ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-       req->mapped = 1;
+       ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
+       if (ret)
+               goto stall;
 
        /* prime the data phase */
        if ((fsl_req_to_dtd(req, GFP_ATOMIC) == 0))
@@ -1964,7 +1939,6 @@ static int fsl_udc_start(struct usb_gadget *g,
        driver->driver.bus = NULL;
        /* hook up the driver */
        udc_controller->driver = driver;
-       udc_controller->gadget.dev.driver = &driver->driver;
        spin_unlock_irqrestore(&udc_controller->lock, flags);
 
        if (!IS_ERR_OR_NULL(udc_controller->transceiver)) {
@@ -1980,7 +1954,6 @@ static int fsl_udc_start(struct usb_gadget *g,
                        if (retval < 0) {
                                ERR("can't bind to transceiver\n");
                                driver->unbind(&udc_controller->gadget);
-                               udc_controller->gadget.dev.driver = 0;
                                udc_controller->driver = 0;
                                return retval;
                        }
@@ -2023,7 +1996,6 @@ static int fsl_udc_stop(struct usb_gadget *g,
                nuke(loop_ep, -ESHUTDOWN);
        spin_unlock_irqrestore(&udc_controller->lock, flags);
 
-       udc_controller->gadget.dev.driver = NULL;
        udc_controller->driver = NULL;
 
        return 0;
@@ -2521,12 +2493,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
 
        /* Setup gadget.dev and register with kernel */
        dev_set_name(&udc_controller->gadget.dev, "gadget");
-       udc_controller->gadget.dev.release = fsl_udc_release;
-       udc_controller->gadget.dev.parent = &pdev->dev;
        udc_controller->gadget.dev.of_node = pdev->dev.of_node;
-       ret = device_register(&udc_controller->gadget.dev);
-       if (ret < 0)
-               goto err_free_irq;
 
        if (!IS_ERR_OR_NULL(udc_controller->transceiver))
                udc_controller->gadget.is_otg = 1;
@@ -2559,10 +2526,11 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
                        DTD_ALIGNMENT, UDC_DMA_BOUNDARY);
        if (udc_controller->td_pool == NULL) {
                ret = -ENOMEM;
-               goto err_unregister;
+               goto err_free_irq;
        }
 
-       ret = usb_add_gadget_udc(&pdev->dev, &udc_controller->gadget);
+       ret = usb_add_gadget_udc_release(&pdev->dev, &udc_controller->gadget,
+                       fsl_udc_release);
        if (ret)
                goto err_del_udc;
 
@@ -2571,8 +2539,6 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
 
 err_del_udc:
        dma_pool_destroy(udc_controller->td_pool);
-err_unregister:
-       device_unregister(&udc_controller->gadget.dev);
 err_free_irq:
        free_irq(udc_controller->irq, udc_controller);
 err_iounmap:
@@ -2622,7 +2588,6 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
        if (pdata->operating_mode == FSL_USB2_DR_DEVICE)
                release_mem_region(res->start, resource_size(res));
 
-       device_unregister(&udc_controller->gadget.dev);
        /* free udc --wait for the release() finished */
        wait_for_completion(&done);
 
@@ -2747,21 +2712,7 @@ static struct platform_driver udc_driver = {
        },
 };
 
-static int __init udc_init(void)
-{
-       printk(KERN_INFO "%s (%s)\n", driver_desc, DRIVER_VERSION);
-       return platform_driver_probe(&udc_driver, fsl_udc_probe);
-}
-
-module_init(udc_init);
-
-static void __exit udc_exit(void)
-{
-       platform_driver_unregister(&udc_driver);
-       printk(KERN_WARNING "%s unregistered\n", driver_desc);
-}
-
-module_exit(udc_exit);
+module_platform_driver_probe(udc_driver, fsl_udc_probe);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_AUTHOR(DRIVER_AUTHOR);
index 066cb89..cec8871 100644 (file)
@@ -394,7 +394,7 @@ static void fusb300_clear_epnstall(struct fusb300 *fusb300, u8 ep)
 
        if (reg & FUSB300_EPSET0_STL) {
                printk(KERN_DEBUG "EP%d stall... Clear!!\n", ep);
-               reg &= ~FUSB300_EPSET0_STL;
+               reg |= FUSB300_EPSET0_STL_CLR;
                iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET0(ep));
        }
 }
@@ -930,33 +930,33 @@ static void fusb300_wait_idma_finished(struct fusb300_ep *ep)
 
        fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGR0,
                FUSB300_IGR0_EPn_PRD_INT(ep->epnum));
+       return;
+
 IDMA_RESET:
-       fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGER0,
-               FUSB300_IGER0_EEPn_PRD_INT(ep->epnum));
+       reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGER0);
+       reg &= ~FUSB300_IGER0_EEPn_PRD_INT(ep->epnum);
+       iowrite32(reg, ep->fusb300->reg + FUSB300_OFFSET_IGER0);
 }
 
-static void  fusb300_set_idma(struct fusb300_ep *ep,
+static void fusb300_set_idma(struct fusb300_ep *ep,
                        struct fusb300_request *req)
 {
-       dma_addr_t d;
-
-       d = dma_map_single(NULL, req->req.buf, req->req.length, DMA_TO_DEVICE);
+       int ret;
 
-       if (dma_mapping_error(NULL, d)) {
-               printk(KERN_DEBUG "dma_mapping_error\n");
+       ret = usb_gadget_map_request(&ep->fusb300->gadget,
+                       &req->req, DMA_TO_DEVICE);
+       if (ret)
                return;
-       }
-
-       dma_sync_single_for_device(NULL, d, req->req.length, DMA_TO_DEVICE);
 
        fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER0,
                FUSB300_IGER0_EEPn_PRD_INT(ep->epnum));
 
-       fusb300_fill_idma_prdtbl(ep, d, req->req.length);
+       fusb300_fill_idma_prdtbl(ep, req->req.dma, req->req.length);
        /* check idma is done */
        fusb300_wait_idma_finished(ep);
 
-       dma_unmap_single(NULL, d, req->req.length, DMA_TO_DEVICE);
+       usb_gadget_unmap_request(&ep->fusb300->gadget,
+                       &req->req, DMA_TO_DEVICE);
 }
 
 static void in_ep_fifo_handler(struct fusb300_ep *ep)
@@ -1316,7 +1316,6 @@ static int fusb300_udc_start(struct usb_gadget *g,
        /* hook up the driver */
        driver->driver.bus = NULL;
        fusb300->driver = driver;
-       fusb300->gadget.dev.driver = &driver->driver;
 
        return 0;
 }
@@ -1327,7 +1326,6 @@ static int fusb300_udc_stop(struct usb_gadget *g,
        struct fusb300 *fusb300 = to_fusb300(g);
 
        driver->unbind(&fusb300->gadget);
-       fusb300->gadget.dev.driver = NULL;
 
        init_controller(fusb300);
        fusb300->driver = NULL;
@@ -1422,14 +1420,7 @@ static int __init fusb300_probe(struct platform_device *pdev)
 
        fusb300->gadget.ops = &fusb300_gadget_ops;
 
-       device_initialize(&fusb300->gadget.dev);
-
-       dev_set_name(&fusb300->gadget.dev, "gadget");
-
        fusb300->gadget.max_speed = USB_SPEED_HIGH;
-       fusb300->gadget.dev.parent = &pdev->dev;
-       fusb300->gadget.dev.dma_mask = pdev->dev.dma_mask;
-       fusb300->gadget.dev.release = pdev->dev.release;
        fusb300->gadget.name = udc_name;
        fusb300->reg = reg;
 
@@ -1478,19 +1469,10 @@ static int __init fusb300_probe(struct platform_device *pdev)
        if (ret)
                goto err_add_udc;
 
-       ret = device_add(&fusb300->gadget.dev);
-       if (ret) {
-               pr_err("device_add error (%d)\n", ret);
-               goto err_add_device;
-       }
-
        dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
 
        return 0;
 
-err_add_device:
-       usb_del_gadget_udc(&fusb300->gadget);
-
 err_add_udc:
        fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);
 
index 6ba444a..ae811d8 100644 (file)
 /*
  * * EPn Setting 0 (EPn_SET0, offset = 020H+(n-1)*30H, n=1~15 )
  * */
+#define FUSB300_EPSET0_STL_CLR         (1 << 3)
 #define FUSB300_EPSET0_CLRSEQNUM       (1 << 2)
-#define FUSB300_EPSET0_EPn_TX0BYTE     (1 << 1)
 #define FUSB300_EPSET0_STL             (1 << 0)
 
 /*
index 3b343b2..787a78e 100644 (file)
@@ -13,7 +13,6 @@
 #define pr_fmt(fmt) "g_ffs: " fmt
 
 #include <linux/module.h>
-
 /*
  * kbuild is not very cooperative with respect to linking separately
  * compiled library objects into one module.  So for now we won't use
 #  include "u_ether.c"
 
 static u8 gfs_hostaddr[ETH_ALEN];
+static struct eth_dev *the_dev;
 #  ifdef CONFIG_USB_FUNCTIONFS_ETH
-static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
+static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+               struct eth_dev *dev);
 #  endif
 #else
-#  define gether_cleanup() do { } while (0)
-#  define gether_setup(gadget, hostaddr)   ((int)0)
+#  define the_dev      NULL
+#  define gether_cleanup(dev) do { } while (0)
 #  define gfs_hostaddr NULL
+struct eth_dev;
 #endif
 
 #include "f_fs.c"
@@ -137,7 +139,8 @@ static struct usb_gadget_strings *gfs_dev_strings[] = {
 
 struct gfs_configuration {
        struct usb_configuration c;
-       int (*eth)(struct usb_configuration *c, u8 *ethaddr);
+       int (*eth)(struct usb_configuration *c, u8 *ethaddr,
+                       struct eth_dev *dev);
 } gfs_configurations[] = {
 #ifdef CONFIG_USB_FUNCTIONFS_RNDIS
        {
@@ -346,10 +349,13 @@ static int gfs_bind(struct usb_composite_dev *cdev)
 
        if (missing_funcs)
                return -ENODEV;
-
-       ret = gether_setup(cdev->gadget, gfs_hostaddr);
-       if (unlikely(ret < 0))
+#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
+       the_dev = gether_setup(cdev->gadget, gfs_hostaddr);
+#endif
+       if (IS_ERR(the_dev)) {
+               ret = PTR_ERR(the_dev);
                goto error_quick;
+       }
        gfs_ether_setup = true;
 
        ret = usb_string_ids_tab(cdev, gfs_strings);
@@ -386,7 +392,7 @@ error_unbind:
        for (i = 0; i < func_num; i++)
                functionfs_unbind(ffs_tab[i].ffs_data);
 error:
-       gether_cleanup();
+       gether_cleanup(the_dev);
 error_quick:
        gfs_ether_setup = false;
        return ret;
@@ -410,7 +416,7 @@ static int gfs_unbind(struct usb_composite_dev *cdev)
         * do...?
         */
        if (gfs_ether_setup)
-               gether_cleanup();
+               gether_cleanup(the_dev);
        gfs_ether_setup = false;
 
        for (i = func_num; i--; )
@@ -440,7 +446,7 @@ static int gfs_do_config(struct usb_configuration *c)
        }
 
        if (gc->eth) {
-               ret = gc->eth(c, gfs_hostaddr);
+               ret = gc->eth(c, gfs_hostaddr, the_dev);
                if (unlikely(ret < 0))
                        return ret;
        }
@@ -469,11 +475,12 @@ static int gfs_do_config(struct usb_configuration *c)
 
 #ifdef CONFIG_USB_FUNCTIONFS_ETH
 
-static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+               struct eth_dev *dev)
 {
        return can_support_ecm(c->cdev->gadget)
-               ? ecm_bind_config(c, ethaddr)
-               : geth_bind_config(c, ethaddr);
+               ? ecm_bind_config(c, ethaddr, dev)
+               : geth_bind_config(c, ethaddr, dev);
 }
 
 #endif
index 85742d4..991aba3 100644 (file)
@@ -51,8 +51,6 @@
 #define        DRIVER_DESC             "TC86C001 USB Device Controller"
 #define        DRIVER_VERSION          "30-Oct 2003"
 
-#define        DMA_ADDR_INVALID        (~(dma_addr_t)0)
-
 static const char driver_name [] = "goku_udc";
 static const char driver_desc [] = DRIVER_DESC;
 
@@ -275,7 +273,6 @@ goku_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
        if (!req)
                return NULL;
 
-       req->req.dma = DMA_ADDR_INVALID;
        INIT_LIST_HEAD(&req->queue);
        return &req->req;
 }
@@ -1354,7 +1351,6 @@ static int goku_udc_start(struct usb_gadget *g,
        /* hook up the driver */
        driver->driver.bus = NULL;
        dev->driver = driver;
-       dev->gadget.dev.driver = &driver->driver;
 
        /*
         * then enable host detection and ep0; and we're ready
@@ -1394,7 +1390,6 @@ static int goku_udc_stop(struct usb_gadget *g,
        dev->driver = NULL;
        stop_activity(dev, driver);
        spin_unlock_irqrestore(&dev->lock, flags);
-       dev->gadget.dev.driver = NULL;
 
        return 0;
 }
@@ -1716,8 +1711,6 @@ static void goku_remove(struct pci_dev *pdev)
                                pci_resource_len (pdev, 0));
        if (dev->enabled)
                pci_disable_device(pdev);
-       if (dev->registered)
-               device_unregister(&dev->gadget.dev);
 
        pci_set_drvdata(pdev, NULL);
        dev->regs = NULL;
@@ -1756,10 +1749,6 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        dev->gadget.max_speed = USB_SPEED_FULL;
 
        /* the "gadget" abstracts/virtualizes the controller */
-       dev_set_name(&dev->gadget.dev, "gadget");
-       dev->gadget.dev.parent = &pdev->dev;
-       dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
-       dev->gadget.dev.release = gadget_release;
        dev->gadget.name = driver_name;
 
        /* now all the pci goodies ... */
@@ -1810,13 +1799,8 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev);
 #endif
 
-       retval = device_register(&dev->gadget.dev);
-       if (retval) {
-               put_device(&dev->gadget.dev);
-               goto err;
-       }
-       dev->registered = 1;
-       retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+       retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
+                       gadget_release);
        if (retval)
                goto err;
 
index b4470d2..86d2ada 100644 (file)
@@ -250,8 +250,7 @@ struct goku_udc {
                                        got_region:1,
                                        req_config:1,
                                        configured:1,
-                                       enabled:1,
-                                       registered:1;
+                                       enabled:1;
 
        /* pci state used to access those endpoints */
        struct pci_dev                  *pdev;
index 5bd930d..b5cebd6 100644 (file)
@@ -1338,7 +1338,6 @@ static int imx_udc_start(struct usb_gadget *gadget,
        imx_usb = container_of(gadget, struct imx_udc_struct, gadget);
        /* first hook up the driver ... */
        imx_usb->driver = driver;
-       imx_usb->gadget.dev.driver = &driver->driver;
 
        D_INI(imx_usb->dev, "<%s> registered gadget driver '%s'\n",
                __func__, driver->driver.name);
@@ -1358,7 +1357,6 @@ static int imx_udc_stop(struct usb_gadget *gadget,
        imx_udc_disable(imx_usb);
        del_timer(&imx_usb->timer);
 
-       imx_usb->gadget.dev.driver = NULL;
        imx_usb->driver = NULL;
 
        D_INI(imx_usb->dev, "<%s> unregistered gadget driver '%s'\n",
@@ -1461,15 +1459,6 @@ static int __init imx_udc_probe(struct platform_device *pdev)
        imx_usb->clk = clk;
        imx_usb->dev = &pdev->dev;
 
-       device_initialize(&imx_usb->gadget.dev);
-
-       imx_usb->gadget.dev.parent = &pdev->dev;
-       imx_usb->gadget.dev.dma_mask = pdev->dev.dma_mask;
-
-       ret = device_add(&imx_usb->gadget.dev);
-       if (retval)
-               goto fail4;
-
        platform_set_drvdata(pdev, imx_usb);
 
        usb_init_data(imx_usb);
@@ -1481,11 +1470,9 @@ static int __init imx_udc_probe(struct platform_device *pdev)
 
        ret = usb_add_gadget_udc(&pdev->dev, &imx_usb->gadget);
        if (ret)
-               goto fail5;
+               goto fail4;
 
        return 0;
-fail5:
-       device_unregister(&imx_usb->gadget.dev);
 fail4:
        for (i = 0; i < IMX_USB_NB_EP + 1; i++)
                free_irq(imx_usb->usbd_int[i], imx_usb);
@@ -1509,7 +1496,6 @@ static int __exit imx_udc_remove(struct platform_device *pdev)
        int i;
 
        usb_del_gadget_udc(&imx_usb->gadget);
-       device_unregister(&imx_usb->gadget.dev);
        imx_udc_disable(imx_usb);
        del_timer(&imx_usb->timer);
 
index aa04089..b943d8c 100644 (file)
@@ -1469,23 +1469,7 @@ static void done(struct lpc32xx_ep *ep, struct lpc32xx_request *req, int status)
                status = req->req.status;
 
        if (ep->lep) {
-               enum dma_data_direction direction;
-
-               if (ep->is_in)
-                       direction = DMA_TO_DEVICE;
-               else
-                       direction = DMA_FROM_DEVICE;
-
-               if (req->mapped) {
-                       dma_unmap_single(ep->udc->gadget.dev.parent,
-                                       req->req.dma, req->req.length,
-                                       direction);
-                       req->req.dma = 0;
-                       req->mapped = 0;
-               } else
-                       dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
-                                               req->req.dma, req->req.length,
-                                               direction);
+               usb_gadget_unmap_request(&udc->gadget, &req->req, ep->is_in);
 
                /* Free DDs */
                udc_dd_free(udc, req->dd_desc_ptr);
@@ -1841,26 +1825,11 @@ static int lpc32xx_ep_queue(struct usb_ep *_ep,
        }
 
        if (ep->lep) {
-               enum dma_data_direction direction;
                struct lpc32xx_usbd_dd_gad *dd;
 
-               /* Map DMA pointer */
-               if (ep->is_in)
-                       direction = DMA_TO_DEVICE;
-               else
-                       direction = DMA_FROM_DEVICE;
-
-               if (req->req.dma == 0) {
-                       req->req.dma = dma_map_single(
-                               ep->udc->gadget.dev.parent,
-                               req->req.buf, req->req.length, direction);
-                       req->mapped = 1;
-               } else {
-                       dma_sync_single_for_device(
-                               ep->udc->gadget.dev.parent, req->req.dma,
-                               req->req.length, direction);
-                       req->mapped = 0;
-               }
+               status = usb_gadget_map_request(&udc->gadget, _req, ep->is_in);
+               if (status)
+                       return status;
 
                /* For the request, build a list of DDs */
                dd = udc_dd_alloc(udc);
@@ -2977,7 +2946,6 @@ static int lpc32xx_start(struct usb_gadget *gadget,
        }
 
        udc->driver = driver;
-       udc->gadget.dev.driver = &driver->driver;
        udc->gadget.dev.of_node = udc->dev->of_node;
        udc->enabled = 1;
        udc->selfpowered = 1;
@@ -3026,7 +2994,6 @@ static int lpc32xx_stop(struct usb_gadget *gadget,
        }
 
        udc->enabled = 0;
-       udc->gadget.dev.driver = NULL;
        udc->driver = NULL;
 
        return 0;
@@ -3248,12 +3215,6 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev)
        udc_disable(udc);
        udc_reinit(udc);
 
-       retval = device_register(&udc->gadget.dev);
-       if (retval < 0) {
-               dev_err(udc->dev, "Device registration failure\n");
-               goto dev_register_fail;
-       }
-
        /* Request IRQs - low and high priority USB device IRQs are routed to
         * the same handler, while the DMA interrupt is routed elsewhere */
        retval = request_irq(udc->udp_irq[IRQ_USB_LP], lpc32xx_usb_lp_irq,
@@ -3320,8 +3281,6 @@ irq_dev_fail:
 irq_hp_fail:
        free_irq(udc->udp_irq[IRQ_USB_LP], udc);
 irq_lp_fail:
-       device_unregister(&udc->gadget.dev);
-dev_register_fail:
        dma_pool_destroy(udc->dd_cache);
 dma_alloc_fail:
        dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE,
@@ -3376,8 +3335,6 @@ static int lpc32xx_udc_remove(struct platform_device *pdev)
        free_irq(udc->udp_irq[IRQ_USB_HP], udc);
        free_irq(udc->udp_irq[IRQ_USB_LP], udc);
 
-       device_unregister(&udc->gadget.dev);
-
        clk_disable(udc->usb_otg_clk);
        clk_put(udc->usb_otg_clk);
        clk_disable(udc->usb_slv_clk);
index c1b8c2d..866ef09 100644 (file)
@@ -1471,7 +1471,6 @@ static int m66592_udc_start(struct usb_gadget *g,
        /* hook up the driver */
        driver->driver.bus = NULL;
        m66592->driver = driver;
-       m66592->gadget.dev.driver = &driver->driver;
 
        m66592_bset(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
        if (m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS) {
@@ -1494,7 +1493,6 @@ static int m66592_udc_stop(struct usb_gadget *g,
        m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
 
        driver->unbind(&m66592->gadget);
-       m66592->gadget.dev.driver = NULL;
 
        init_controller(m66592);
        disable_controller(m66592);
@@ -1538,7 +1536,6 @@ static int __exit m66592_remove(struct platform_device *pdev)
        struct m66592           *m66592 = dev_get_drvdata(&pdev->dev);
 
        usb_del_gadget_udc(&m66592->gadget);
-       device_del(&m66592->gadget.dev);
 
        del_timer_sync(&m66592->timer);
        iounmap(m66592->reg);
@@ -1608,12 +1605,7 @@ static int __init m66592_probe(struct platform_device *pdev)
        dev_set_drvdata(&pdev->dev, m66592);
 
        m66592->gadget.ops = &m66592_gadget_ops;
-       device_initialize(&m66592->gadget.dev);
-       dev_set_name(&m66592->gadget.dev, "gadget");
        m66592->gadget.max_speed = USB_SPEED_HIGH;
-       m66592->gadget.dev.parent = &pdev->dev;
-       m66592->gadget.dev.dma_mask = pdev->dev.dma_mask;
-       m66592->gadget.dev.release = pdev->dev.release;
        m66592->gadget.name = udc_name;
 
        init_timer(&m66592->timer);
@@ -1674,12 +1666,6 @@ static int __init m66592_probe(struct platform_device *pdev)
 
        init_controller(m66592);
 
-       ret = device_add(&m66592->gadget.dev);
-       if (ret) {
-               pr_err("device_add error (%d)\n", ret);
-               goto err_device_add;
-       }
-
        ret = usb_add_gadget_udc(&pdev->dev, &m66592->gadget);
        if (ret)
                goto err_add_udc;
@@ -1688,9 +1674,6 @@ static int __init m66592_probe(struct platform_device *pdev)
        return 0;
 
 err_add_udc:
-       device_del(&m66592->gadget.dev);
-
-err_device_add:
        m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
 
 clean_up3:
index 20bbbf9..a74ebef 100644 (file)
@@ -135,8 +135,8 @@ static struct fsg_common fsg_common;
 
 static u8 hostaddr[ETH_ALEN];
 
-static unsigned char tty_line;
 static struct usb_function_instance *fi_acm;
+static struct eth_dev *the_dev;
 
 /********** RNDIS **********/
 
@@ -152,7 +152,7 @@ static __init int rndis_do_config(struct usb_configuration *c)
                c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
        }
 
-       ret = rndis_bind_config(c, hostaddr);
+       ret = rndis_bind_config(c, hostaddr, the_dev);
        if (ret < 0)
                return ret;
 
@@ -214,7 +214,7 @@ static __init int cdc_do_config(struct usb_configuration *c)
                c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
        }
 
-       ret = ecm_bind_config(c, hostaddr);
+       ret = ecm_bind_config(c, hostaddr, the_dev);
        if (ret < 0)
                return ret;
 
@@ -269,7 +269,6 @@ static int cdc_config_register(struct usb_composite_dev *cdev)
 static int __ref multi_bind(struct usb_composite_dev *cdev)
 {
        struct usb_gadget *gadget = cdev->gadget;
-       struct f_serial_opts *opts;
        int status;
 
        if (!can_support_ecm(cdev->gadget)) {
@@ -279,24 +278,17 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
        }
 
        /* set up network link layer */
-       status = gether_setup(cdev->gadget, hostaddr);
-       if (status < 0)
-               return status;
+       the_dev = gether_setup(cdev->gadget, hostaddr);
+       if (IS_ERR(the_dev))
+               return PTR_ERR(the_dev);
 
        /* set up serial link layer */
-       status = gserial_alloc_line(&tty_line);
-       if (status < 0)
-               goto fail0;
-
        fi_acm = usb_get_function_instance("acm");
        if (IS_ERR(fi_acm)) {
                status = PTR_ERR(fi_acm);
-               goto fail0dot5;
+               goto fail0;
        }
 
-       opts = container_of(fi_acm, struct f_serial_opts, func_inst);
-       opts->port_num = tty_line;
-
        /* set up mass storage function */
        {
                void *retp;
@@ -334,10 +326,8 @@ fail2:
        fsg_common_put(&fsg_common);
 fail1:
        usb_put_function_instance(fi_acm);
-fail0dot5:
-       gserial_free_line(tty_line);
 fail0:
-       gether_cleanup();
+       gether_cleanup(the_dev);
        return status;
 }
 
@@ -350,8 +340,7 @@ static int __exit multi_unbind(struct usb_composite_dev *cdev)
        usb_put_function(f_acm_rndis);
 #endif
        usb_put_function_instance(fi_acm);
-       gserial_free_line(tty_line);
-       gether_cleanup();
+       gether_cleanup(the_dev);
        return 0;
 }
 
index b5cea27..58288e9 100644 (file)
@@ -30,9 +30,6 @@
 #include <linux/platform_device.h>
 #include <linux/platform_data/mv_usb.h>
 #include <linux/clk.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
-#include <asm/byteorder.h>
 
 #include "mv_u3d.h"
 
@@ -125,7 +122,7 @@ static int mv_u3d_process_ep_req(struct mv_u3d *u3d, int index,
        struct mv_u3d_trb       *curr_trb;
        dma_addr_t cur_deq_lo;
        struct mv_u3d_ep_context        *curr_ep_context;
-       int trb_complete, actual, remaining_length;
+       int trb_complete, actual, remaining_length = 0;
        int direction, ep_num;
        int retval = 0;
        u32 tmp, status, length;
@@ -189,6 +186,8 @@ static int mv_u3d_process_ep_req(struct mv_u3d *u3d, int index,
  */
 static
 void mv_u3d_done(struct mv_u3d_ep *ep, struct mv_u3d_req *req, int status)
+       __releases(&ep->udc->lock)
+       __acquires(&ep->udc->lock)
 {
        struct mv_u3d *u3d = (struct mv_u3d *)ep->u3d;
 
@@ -812,19 +811,19 @@ mv_u3d_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
                return 0;
        }
 
-       dev_dbg(u3d->dev, "%s: %s, req: 0x%x\n",
-                       __func__, _ep->name, (u32)req);
+       dev_dbg(u3d->dev, "%s: %s, req: 0x%p\n",
+                       __func__, _ep->name, req);
 
        /* catch various bogus parameters */
        if (!req->req.complete || !req->req.buf
                        || !list_empty(&req->queue)) {
                dev_err(u3d->dev,
-                       "%s, bad params, _req: 0x%x,"
-                       "req->req.complete: 0x%x, req->req.buf: 0x%x,"
+                       "%s, bad params, _req: 0x%p,"
+                       "req->req.complete: 0x%p, req->req.buf: 0x%p,"
                        "list_empty: 0x%x\n",
-                       __func__, (u32)_req,
-                       (u32)req->req.complete, (u32)req->req.buf,
-                       (u32)list_empty(&req->queue));
+                       __func__, _req,
+                       req->req.complete, req->req.buf,
+                       list_empty(&req->queue));
                return -EINVAL;
        }
        if (unlikely(!ep->ep.desc)) {
@@ -905,7 +904,7 @@ static int mv_u3d_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
                                        struct mv_u3d_req, queue);
 
                        /* Point first TRB of next request to the EP context. */
-                       iowrite32((u32) next_req->trb_head,
+                       iowrite32((unsigned long) next_req->trb_head,
                                        &ep_context->trb_addr_lo);
                } else {
                        struct mv_u3d_ep_context *ep_context;
@@ -1264,7 +1263,6 @@ static int mv_u3d_start(struct usb_gadget *g,
        /* hook up the driver ... */
        driver->driver.bus = NULL;
        u3d->driver = driver;
-       u3d->gadget.dev.driver = &driver->driver;
 
        u3d->ep0_dir = USB_DIR_OUT;
 
@@ -1302,7 +1300,6 @@ static int mv_u3d_stop(struct usb_gadget *g,
 
        spin_unlock_irqrestore(&u3d->lock, flags);
 
-       u3d->gadget.dev.driver = NULL;
        u3d->driver = NULL;
 
        return 0;
@@ -1525,6 +1522,8 @@ static int mv_u3d_is_set_configuration(struct usb_ctrlrequest *setup)
 
 static void mv_u3d_handle_setup_packet(struct mv_u3d *u3d, u8 ep_num,
        struct usb_ctrlrequest *setup)
+       __releases(&u3c->lock)
+       __acquires(&u3c->lock)
 {
        bool delegate = false;
 
@@ -1758,11 +1757,6 @@ static irqreturn_t mv_u3d_irq(int irq, void *dev)
        return IRQ_HANDLED;
 }
 
-static void mv_u3d_gadget_release(struct device *dev)
-{
-       dev_dbg(dev, "%s\n", __func__);
-}
-
 static int mv_u3d_remove(struct platform_device *dev)
 {
        struct mv_u3d *u3d = platform_get_drvdata(dev);
@@ -1792,8 +1786,6 @@ static int mv_u3d_remove(struct platform_device *dev)
 
        clk_put(u3d->clk);
 
-       device_unregister(&u3d->gadget.dev);
-
        platform_set_drvdata(dev, NULL);
 
        kfree(u3d);
@@ -1829,7 +1821,7 @@ static int mv_u3d_probe(struct platform_device *dev)
        u3d->dev = &dev->dev;
        u3d->vbus = pdata->vbus;
 
-       u3d->clk = clk_get(&dev->dev, pdata->clkname[0]);
+       u3d->clk = clk_get(&dev->dev, NULL);
        if (IS_ERR(u3d->clk)) {
                retval = PTR_ERR(u3d->clk);
                goto err_get_clk;
@@ -1849,8 +1841,9 @@ static int mv_u3d_probe(struct platform_device *dev)
                retval = -EBUSY;
                goto err_map_cap_regs;
        } else {
-               dev_dbg(&dev->dev, "cap_regs address: 0x%x/0x%x\n",
-                       (unsigned int)r->start, (unsigned int)u3d->cap_regs);
+               dev_dbg(&dev->dev, "cap_regs address: 0x%lx/0x%lx\n",
+                       (unsigned long) r->start,
+                       (unsigned long) u3d->cap_regs);
        }
 
        /* we will access controller register, so enable the u3d controller */
@@ -1864,10 +1857,10 @@ static int mv_u3d_probe(struct platform_device *dev)
                }
        }
 
-       u3d->op_regs = (struct mv_u3d_op_regs __iomem *)((u32)u3d->cap_regs
+       u3d->op_regs = (struct mv_u3d_op_regs __iomem *)(u3d->cap_regs
                + MV_U3D_USB3_OP_REGS_OFFSET);
 
-       u3d->vuc_regs = (struct mv_u3d_vuc_regs __iomem *)((u32)u3d->cap_regs
+       u3d->vuc_regs = (struct mv_u3d_vuc_regs __iomem *)(u3d->cap_regs
                + ioread32(&u3d->cap_regs->vuoff));
 
        u3d->max_eps = 16;
@@ -1957,16 +1950,8 @@ static int mv_u3d_probe(struct platform_device *dev)
        u3d->gadget.speed = USB_SPEED_UNKNOWN;  /* speed */
 
        /* the "gadget" abstracts/virtualizes the controller */
-       dev_set_name(&u3d->gadget.dev, "gadget");
-       u3d->gadget.dev.parent = &dev->dev;
-       u3d->gadget.dev.dma_mask = dev->dev.dma_mask;
-       u3d->gadget.dev.release = mv_u3d_gadget_release;
        u3d->gadget.name = driver_name;         /* gadget name */
 
-       retval = device_register(&u3d->gadget.dev);
-       if (retval)
-               goto err_register_gadget_device;
-
        mv_u3d_eps_init(u3d);
 
        /* external vbus detection */
@@ -1991,8 +1976,6 @@ static int mv_u3d_probe(struct platform_device *dev)
        return 0;
 
 err_unregister:
-       device_unregister(&u3d->gadget.dev);
-err_register_gadget_device:
        free_irq(u3d->irq, &dev->dev);
 err_request_irq:
 err_get_irq:
@@ -2021,7 +2004,7 @@ err_pdata:
        return retval;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int mv_u3d_suspend(struct device *dev)
 {
        struct mv_u3d *u3d = dev_get_drvdata(dev);
@@ -2064,10 +2047,10 @@ static int mv_u3d_resume(struct device *dev)
 
        return 0;
 }
-
-SIMPLE_DEV_PM_OPS(mv_u3d_pm_ops, mv_u3d_suspend, mv_u3d_resume);
 #endif
 
+static SIMPLE_DEV_PM_OPS(mv_u3d_pm_ops, mv_u3d_suspend, mv_u3d_resume);
+
 static void mv_u3d_shutdown(struct platform_device *dev)
 {
        struct mv_u3d *u3d = dev_get_drvdata(&dev->dev);
@@ -2080,14 +2063,12 @@ static void mv_u3d_shutdown(struct platform_device *dev)
 
 static struct platform_driver mv_u3d_driver = {
        .probe          = mv_u3d_probe,
-       .remove         = __exit_p(mv_u3d_remove),
+       .remove         = mv_u3d_remove,
        .shutdown       = mv_u3d_shutdown,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "mv-u3d",
-#ifdef CONFIG_PM
                .pm     = &mv_u3d_pm_ops,
-#endif
        },
 };
 
index 9073436..be77f20 100644 (file)
@@ -222,8 +222,7 @@ struct mv_udc {
        struct mv_usb_platform_data     *pdata;
 
        /* some SOC has mutiple clock sources for USB*/
-       unsigned int    clknum;
-       struct clk      *clk[0];
+       struct clk      *clk;
 };
 
 /* endpoint data structure */
index c8cf959..c2a5702 100644 (file)
@@ -212,6 +212,8 @@ static int process_ep_req(struct mv_udc *udc, int index,
  * request is still in progress.
  */
 static void done(struct mv_ep *ep, struct mv_req *req, int status)
+       __releases(&ep->udc->lock)
+       __acquires(&ep->udc->lock)
 {
        struct mv_udc *udc = NULL;
        unsigned char stopped = ep->stopped;
@@ -237,18 +239,7 @@ static void done(struct mv_ep *ep, struct mv_req *req, int status)
                dma_pool_free(udc->dtd_pool, curr_td, curr_td->td_dma);
        }
 
-       if (req->mapped) {
-               dma_unmap_single(ep->udc->gadget.dev.parent,
-                       req->req.dma, req->req.length,
-                       ((ep_dir(ep) == EP_DIR_IN) ?
-                               DMA_TO_DEVICE : DMA_FROM_DEVICE));
-               req->req.dma = DMA_ADDR_INVALID;
-               req->mapped = 0;
-       } else
-               dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
-                       req->req.dma, req->req.length,
-                       ((ep_dir(ep) == EP_DIR_IN) ?
-                               DMA_TO_DEVICE : DMA_FROM_DEVICE));
+       usb_gadget_unmap_request(&udc->gadget, &req->req, ep_dir(ep));
 
        if (status && (status != -ESHUTDOWN))
                dev_info(&udc->dev->dev, "complete %s req %p stat %d len %u/%u",
@@ -732,21 +723,9 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
        req->ep = ep;
 
        /* map virtual address to hardware */
-       if (req->req.dma == DMA_ADDR_INVALID) {
-               req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
-                                       req->req.buf,
-                                       req->req.length, ep_dir(ep)
-                                               ? DMA_TO_DEVICE
-                                               : DMA_FROM_DEVICE);
-               req->mapped = 1;
-       } else {
-               dma_sync_single_for_device(ep->udc->gadget.dev.parent,
-                                       req->req.dma, req->req.length,
-                                       ep_dir(ep)
-                                               ? DMA_TO_DEVICE
-                                               : DMA_FROM_DEVICE);
-               req->mapped = 0;
-       }
+       retval = usb_gadget_map_request(&udc->gadget, _req, ep_dir(ep));
+       if (retval)
+               return retval;
 
        req->req.status = -EINPROGRESS;
        req->req.actual = 0;
@@ -780,18 +759,7 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
        return 0;
 
 err_unmap_dma:
-       if (req->mapped) {
-               dma_unmap_single(ep->udc->gadget.dev.parent,
-                               req->req.dma, req->req.length,
-                               ((ep_dir(ep) == EP_DIR_IN) ?
-                               DMA_TO_DEVICE : DMA_FROM_DEVICE));
-               req->req.dma = DMA_ADDR_INVALID;
-               req->mapped = 0;
-       } else
-               dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
-                               req->req.dma, req->req.length,
-                               ((ep_dir(ep) == EP_DIR_IN) ?
-                               DMA_TO_DEVICE : DMA_FROM_DEVICE));
+       usb_gadget_unmap_request(&udc->gadget, _req, ep_dir(ep));
 
        return retval;
 }
@@ -1006,18 +974,12 @@ static struct usb_ep_ops mv_ep_ops = {
 
 static void udc_clock_enable(struct mv_udc *udc)
 {
-       unsigned int i;
-
-       for (i = 0; i < udc->clknum; i++)
-               clk_prepare_enable(udc->clk[i]);
+       clk_prepare_enable(udc->clk);
 }
 
 static void udc_clock_disable(struct mv_udc *udc)
 {
-       unsigned int i;
-
-       for (i = 0; i < udc->clknum; i++)
-               clk_disable_unprepare(udc->clk[i]);
+       clk_disable_unprepare(udc->clk);
 }
 
 static void udc_stop(struct mv_udc *udc)
@@ -1386,7 +1348,6 @@ static int mv_udc_start(struct usb_gadget *gadget,
        /* hook up the driver ... */
        driver->driver.bus = NULL;
        udc->driver = driver;
-       udc->gadget.dev.driver = &driver->driver;
 
        udc->usb_state = USB_STATE_ATTACHED;
        udc->ep0_state = WAIT_FOR_SETUP;
@@ -1401,7 +1362,6 @@ static int mv_udc_start(struct usb_gadget *gadget,
                        dev_err(&udc->dev->dev,
                                "unable to register peripheral to otg\n");
                        udc->driver = NULL;
-                       udc->gadget.dev.driver = NULL;
                        return retval;
                }
        }
@@ -1437,7 +1397,6 @@ static int mv_udc_stop(struct usb_gadget *gadget,
        spin_unlock_irqrestore(&udc->lock, flags);
 
        /* unbind gadget driver */
-       udc->gadget.dev.driver = NULL;
        udc->driver = NULL;
 
        return 0;
@@ -1528,14 +1487,7 @@ udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty)
 
        return 0;
 out:
-       if (req->mapped) {
-               dma_unmap_single(ep->udc->gadget.dev.parent,
-                               req->req.dma, req->req.length,
-                               ((ep_dir(ep) == EP_DIR_IN) ?
-                               DMA_TO_DEVICE : DMA_FROM_DEVICE));
-               req->req.dma = DMA_ADDR_INVALID;
-               req->mapped = 0;
-       }
+       usb_gadget_unmap_request(&udc->gadget, &req->req, ep_dir(ep));
 
        return retval;
 }
@@ -1695,6 +1647,8 @@ out:
 
 static void handle_setup_packet(struct mv_udc *udc, u8 ep_num,
        struct usb_ctrlrequest *setup)
+       __releases(&ep->udc->lock)
+       __acquires(&ep->udc->lock)
 {
        bool delegate = false;
 
@@ -1891,7 +1845,7 @@ static void irq_process_tr_complete(struct mv_udc *udc)
        }
 }
 
-void irq_process_reset(struct mv_udc *udc)
+static void irq_process_reset(struct mv_udc *udc)
 {
        u32 tmp;
        unsigned int loops;
@@ -2138,8 +2092,6 @@ static int mv_udc_remove(struct platform_device *pdev)
 
        mv_udc_disable(udc);
 
-       device_unregister(&udc->gadget.dev);
-
        /* free dev, wait for the release() finished */
        wait_for_completion(udc->done);
 
@@ -2151,7 +2103,6 @@ static int mv_udc_probe(struct platform_device *pdev)
        struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
        struct mv_udc *udc;
        int retval = 0;
-       int clk_i = 0;
        struct resource *r;
        size_t size;
 
@@ -2160,8 +2111,7 @@ static int mv_udc_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       size = sizeof(*udc) + sizeof(struct clk *) * pdata->clknum;
-       udc = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+       udc = devm_kzalloc(&pdev->dev, sizeof(*udc), GFP_KERNEL);
        if (udc == NULL) {
                dev_err(&pdev->dev, "failed to allocate memory for udc\n");
                return -ENOMEM;
@@ -2173,26 +2123,24 @@ static int mv_udc_probe(struct platform_device *pdev)
 
        udc->dev = pdev;
 
-#ifdef CONFIG_USB_OTG_UTILS
        if (pdata->mode == MV_USB_MODE_OTG) {
                udc->transceiver = devm_usb_get_phy(&pdev->dev,
                                        USB_PHY_TYPE_USB2);
-               if (IS_ERR_OR_NULL(udc->transceiver)) {
+               if (IS_ERR(udc->transceiver)) {
+                       retval = PTR_ERR(udc->transceiver);
+
+                       if (retval == -ENXIO)
+                               return retval;
+
                        udc->transceiver = NULL;
-                       return -ENODEV;
+                       return -EPROBE_DEFER;
                }
        }
-#endif
 
-       udc->clknum = pdata->clknum;
-       for (clk_i = 0; clk_i < udc->clknum; clk_i++) {
-               udc->clk[clk_i] = devm_clk_get(&pdev->dev,
-                                       pdata->clkname[clk_i]);
-               if (IS_ERR(udc->clk[clk_i])) {
-                       retval = PTR_ERR(udc->clk[clk_i]);
-                       return retval;
-               }
-       }
+       /* udc only have one sysclk. */
+       udc->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(udc->clk))
+               return PTR_ERR(udc->clk);
 
        r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "capregs");
        if (r == NULL) {
@@ -2311,16 +2259,8 @@ static int mv_udc_probe(struct platform_device *pdev)
        udc->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */
 
        /* the "gadget" abstracts/virtualizes the controller */
-       dev_set_name(&udc->gadget.dev, "gadget");
-       udc->gadget.dev.parent = &pdev->dev;
-       udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
-       udc->gadget.dev.release = gadget_release;
        udc->gadget.name = driver_name;         /* gadget name */
 
-       retval = device_register(&udc->gadget.dev);
-       if (retval)
-               goto err_destroy_dma;
-
        eps_init(udc);
 
        /* VBUS detect: we can disable/enable clock on demand.*/
@@ -2342,7 +2282,7 @@ static int mv_udc_probe(struct platform_device *pdev)
                if (!udc->qwork) {
                        dev_err(&pdev->dev, "cannot create workqueue\n");
                        retval = -ENOMEM;
-                       goto err_unregister;
+                       goto err_destroy_dma;
                }
 
                INIT_WORK(&udc->vbus_work, mv_udc_vbus_work);
@@ -2358,7 +2298,8 @@ static int mv_udc_probe(struct platform_device *pdev)
        else
                udc->vbus_active = 1;
 
-       retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
+       retval = usb_add_gadget_udc_release(&pdev->dev, &udc->gadget,
+                       gadget_release);
        if (retval)
                goto err_create_workqueue;
 
@@ -2370,8 +2311,6 @@ static int mv_udc_probe(struct platform_device *pdev)
 
 err_create_workqueue:
        destroy_workqueue(udc->qwork);
-err_unregister:
-       device_unregister(&udc->gadget.dev);
 err_destroy_dma:
        dma_pool_destroy(udc->dtd_pool);
 err_free_dma:
index a22ad9a..3b02fd4 100644 (file)
@@ -111,6 +111,7 @@ static struct usb_gadget_strings *dev_strings[] = {
        NULL,
 };
 
+struct eth_dev *the_dev;
 static u8 hostaddr[ETH_ALEN];
 
 /*-------------------------------------------------------------------------*/
@@ -124,7 +125,7 @@ static int __init ncm_do_config(struct usb_configuration *c)
                c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
        }
 
-       return ncm_bind_config(c, hostaddr);
+       return ncm_bind_config(c, hostaddr, the_dev);
 }
 
 static struct usb_configuration ncm_config_driver = {
@@ -143,9 +144,9 @@ static int __init gncm_bind(struct usb_composite_dev *cdev)
        int                     status;
 
        /* set up network link layer */
-       status = gether_setup(cdev->gadget, hostaddr);
-       if (status < 0)
-               return status;
+       the_dev = gether_setup(cdev->gadget, hostaddr);
+       if (IS_ERR(the_dev))
+               return PTR_ERR(the_dev);
 
        /* Allocate string descriptor numbers ... note that string
         * contents can be overridden by the composite_dev glue.
@@ -168,13 +169,13 @@ static int __init gncm_bind(struct usb_composite_dev *cdev)
        return 0;
 
 fail:
-       gether_cleanup();
+       gether_cleanup(the_dev);
        return status;
 }
 
 static int __exit gncm_unbind(struct usb_composite_dev *cdev)
 {
-       gether_cleanup();
+       gether_cleanup(the_dev);
        return 0;
 }
 
index 32524b6..f1e50a3 100644 (file)
@@ -58,7 +58,6 @@ static const char * const ep_name[] = {
        "ep-a", "ep-b", "ep-c",
 };
 
-#define DMA_ADDR_INVALID       (~(dma_addr_t)0)
 #ifdef CONFIG_USB_NET2272_DMA
 /*
  * use_dma: the NET2272 can use an external DMA controller.
@@ -341,7 +340,6 @@ net2272_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
        if (!req)
                return NULL;
 
-       req->req.dma = DMA_ADDR_INVALID;
        INIT_LIST_HEAD(&req->queue);
 
        return &req->req;
@@ -913,7 +911,7 @@ net2272_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
                        }
                }
        }
-       if (likely(req != 0))
+       if (likely(req))
                list_add_tail(&req->queue, &ep->queue);
 
        if (likely(!list_empty(&ep->queue)))
@@ -1467,7 +1465,6 @@ static int net2272_start(struct usb_gadget *_gadget,
        dev->softconnect = 1;
        driver->driver.bus = NULL;
        dev->driver = driver;
-       dev->gadget.dev.driver = &driver->driver;
 
        /* ... then enable host detection and ep0; and we're ready
         * for set_configuration as well as eventual disconnect.
@@ -1517,7 +1514,6 @@ static int net2272_stop(struct usb_gadget *_gadget,
        stop_activity(dev, driver);
        spin_unlock_irqrestore(&dev->lock, flags);
 
-       dev->gadget.dev.driver = NULL;
        dev->driver = NULL;
 
        dev_dbg(dev->dev, "unregistered driver '%s'\n", driver->driver.name);
@@ -1549,7 +1545,7 @@ net2272_handle_dma(struct net2272_ep *ep)
              | (ep->dev->dma_eot_polarity << EOT_POLARITY)
              | (ep->dev->dma_dack_polarity << DACK_POLARITY)
              | (ep->dev->dma_dreq_polarity << DREQ_POLARITY)
-             | ((ep->dma >> 1) << DMA_ENDPOINT_SELECT));
+             | (ep->dma << DMA_ENDPOINT_SELECT));
 
        ep->dev->dma_busy = 0;
 
@@ -1622,7 +1618,7 @@ net2272_handle_ep(struct net2272_ep *ep)
        ep->irqs++;
 
        dev_vdbg(ep->dev->dev, "%s ack ep_stat0 %02x, ep_stat1 %02x, req %p\n",
-               ep->ep.name, stat0, stat1, req ? &req->req : 0);
+               ep->ep.name, stat0, stat1, req ? &req->req : NULL);
 
        net2272_ep_write(ep, EP_STAT0, stat0 &
                ~((1 << NAK_OUT_PACKETS)
@@ -2216,7 +2212,6 @@ net2272_remove(struct net2272 *dev)
        free_irq(dev->irq, dev);
        iounmap(dev->base_addr);
 
-       device_unregister(&dev->gadget.dev);
        device_remove_file(dev->dev, &dev_attr_registers);
 
        dev_info(dev->dev, "unbind\n");
@@ -2243,10 +2238,6 @@ static struct net2272 *net2272_probe_init(struct device *dev, unsigned int irq)
        ret->gadget.max_speed = USB_SPEED_HIGH;
 
        /* the "gadget" abstracts/virtualizes the controller */
-       dev_set_name(&ret->gadget.dev, "gadget");
-       ret->gadget.dev.parent = dev;
-       ret->gadget.dev.dma_mask = dev->dma_mask;
-       ret->gadget.dev.release = net2272_gadget_release;
        ret->gadget.name = driver_name;
 
        return ret;
@@ -2282,14 +2273,12 @@ net2272_probe_fin(struct net2272 *dev, unsigned int irqflags)
                dma_mode_string());
        dev_info(dev->dev, "version: %s\n", driver_vers);
 
-       ret = device_register(&dev->gadget.dev);
-       if (ret)
-               goto err_irq;
        ret = device_create_file(dev->dev, &dev_attr_registers);
        if (ret)
-               goto err_dev_reg;
+               goto err_irq;
 
-       ret = usb_add_gadget_udc(dev->dev, &dev->gadget);
+       ret = usb_add_gadget_udc_release(dev->dev, &dev->gadget,
+                       net2272_gadget_release);
        if (ret)
                goto err_add_udc;
 
@@ -2297,8 +2286,6 @@ net2272_probe_fin(struct net2272 *dev, unsigned int irqflags)
 
 err_add_udc:
        device_remove_file(dev->dev, &dev_attr_registers);
- err_dev_reg:
-       device_unregister(&dev->gadget.dev);
  err_irq:
        free_irq(dev->irq, dev);
  err:
index 3bd0f99..fbd006a 100644 (file)
@@ -65,7 +65,6 @@
 #define        DRIVER_DESC             "PLX NET228x USB Peripheral Controller"
 #define        DRIVER_VERSION          "2005 Sept 27"
 
-#define        DMA_ADDR_INVALID        (~(dma_addr_t)0)
 #define        EP_DONTUSE              13      /* nonzero */
 
 #define USE_RDK_LEDS           /* GPIO pins control three LEDs */
@@ -406,7 +405,6 @@ net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
        if (!req)
                return NULL;
 
-       req->req.dma = DMA_ADDR_INVALID;
        INIT_LIST_HEAD (&req->queue);
 
        /* this dma descriptor may be swapped with the previous dummy */
@@ -420,7 +418,6 @@ net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
                        return NULL;
                }
                td->dmacount = 0;       /* not VALID */
-               td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID);
                td->dmadesc = td->dmaaddr;
                req->td = td;
        }
@@ -1896,7 +1893,6 @@ static int net2280_start(struct usb_gadget *_gadget,
        dev->softconnect = 1;
        driver->driver.bus = NULL;
        dev->driver = driver;
-       dev->gadget.dev.driver = &driver->driver;
 
        retval = device_create_file (&dev->pdev->dev, &dev_attr_function);
        if (retval) goto err_unbind;
@@ -1924,7 +1920,6 @@ static int net2280_start(struct usb_gadget *_gadget,
 err_func:
        device_remove_file (&dev->pdev->dev, &dev_attr_function);
 err_unbind:
-       dev->gadget.dev.driver = NULL;
        dev->driver = NULL;
        return retval;
 }
@@ -1967,7 +1962,6 @@ static int net2280_stop(struct usb_gadget *_gadget,
        stop_activity (dev, driver);
        spin_unlock_irqrestore (&dev->lock, flags);
 
-       dev->gadget.dev.driver = NULL;
        dev->driver = NULL;
 
        net2280_led_active (dev, 0);
@@ -2072,7 +2066,7 @@ static void handle_ep_small (struct net2280_ep *ep)
                return;
 
        /* manual DMA queue advance after short OUT */
-       if (likely (ep->dma != 0)) {
+       if (likely (ep->dma)) {
                if (t & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) {
                        u32     count;
                        int     stopped = ep->stopped;
@@ -2330,7 +2324,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
                        /* hw handles device and interface status */
                        if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT))
                                goto delegate;
-                       if ((e = get_ep_by_addr (dev, w_index)) == 0
+                       if ((e = get_ep_by_addr (dev, w_index)) == NULL
                                        || w_length > 2)
                                goto do_stall;
 
@@ -2358,7 +2352,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
                        if (w_value != USB_ENDPOINT_HALT
                                        || w_length != 0)
                                goto do_stall;
-                       if ((e = get_ep_by_addr (dev, w_index)) == 0)
+                       if ((e = get_ep_by_addr (dev, w_index)) == NULL)
                                goto do_stall;
                        if (e->wedged) {
                                VDEBUG(dev, "%s wedged, halt not cleared\n",
@@ -2380,7 +2374,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
                        if (w_value != USB_ENDPOINT_HALT
                                        || w_length != 0)
                                goto do_stall;
-                       if ((e = get_ep_by_addr (dev, w_index)) == 0)
+                       if ((e = get_ep_by_addr (dev, w_index)) == NULL)
                                goto do_stall;
                        if (e->ep.name == ep0name)
                                goto do_stall;
@@ -2685,7 +2679,6 @@ static void net2280_remove (struct pci_dev *pdev)
                                pci_resource_len (pdev, 0));
        if (dev->enabled)
                pci_disable_device (pdev);
-       device_unregister (&dev->gadget.dev);
        device_remove_file (&pdev->dev, &dev_attr_registers);
        pci_set_drvdata (pdev, NULL);
 
@@ -2717,10 +2710,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
        dev->gadget.max_speed = USB_SPEED_HIGH;
 
        /* the "gadget" abstracts/virtualizes the controller */
-       dev_set_name(&dev->gadget.dev, "gadget");
-       dev->gadget.dev.parent = &pdev->dev;
-       dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
-       dev->gadget.dev.release = gadget_release;
        dev->gadget.name = driver_name;
 
        /* now all the pci goodies ... */
@@ -2802,7 +2791,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
                        goto done;
                }
                td->dmacount = 0;       /* not VALID */
-               td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID);
                td->dmadesc = td->dmaaddr;
                dev->ep [i].dummy = td;
        }
@@ -2829,12 +2817,11 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
                        use_dma
                                ? (use_dma_chaining ? "chaining" : "enabled")
                                : "disabled");
-       retval = device_register (&dev->gadget.dev);
-       if (retval) goto done;
        retval = device_create_file (&pdev->dev, &dev_attr_registers);
        if (retval) goto done;
 
-       retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+       retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
+                       gadget_release);
        if (retval)
                goto done;
        return 0;
index def3740..3b344b4 100644 (file)
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-#define USB_FACM_INCLUDED
-#include "f_acm.c"
+#define USBF_OBEX_INCLUDED
 #include "f_ecm.c"
 #include "f_obex.c"
-#include "f_serial.c"
 #include "f_phonet.c"
 #include "u_ether.c"
 
@@ -98,20 +96,40 @@ MODULE_AUTHOR("Felipe Balbi");
 MODULE_LICENSE("GPL");
 
 /*-------------------------------------------------------------------------*/
-
+static struct usb_function *f_acm_cfg1;
+static struct usb_function *f_acm_cfg2;
 static u8 hostaddr[ETH_ALEN];
+static struct eth_dev *the_dev;
 
 enum {
        TTY_PORT_OBEX0,
        TTY_PORT_OBEX1,
-       TTY_PORT_ACM,
        TTY_PORTS_MAX,
 };
 
 static unsigned char tty_lines[TTY_PORTS_MAX];
 
+static struct usb_configuration nokia_config_500ma_driver = {
+       .label          = "Bus Powered",
+       .bConfigurationValue = 1,
+       /* .iConfiguration = DYNAMIC */
+       .bmAttributes   = USB_CONFIG_ATT_ONE,
+       .MaxPower       = 500,
+};
+
+static struct usb_configuration nokia_config_100ma_driver = {
+       .label          = "Self Powered",
+       .bConfigurationValue = 2,
+       /* .iConfiguration = DYNAMIC */
+       .bmAttributes   = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+       .MaxPower       = 100,
+};
+
+static struct usb_function_instance *fi_acm;
+
 static int __init nokia_bind_config(struct usb_configuration *c)
 {
+       struct usb_function *f_acm;
        int status = 0;
 
        status = phonet_bind_config(c);
@@ -126,33 +144,32 @@ static int __init nokia_bind_config(struct usb_configuration *c)
        if (status)
                printk(KERN_DEBUG "could not bind obex config %d\n", 0);
 
-       status = acm_bind_config(c, tty_lines[TTY_PORT_ACM]);
-       if (status)
-               printk(KERN_DEBUG "could not bind acm config\n");
+       f_acm = usb_get_function(fi_acm);
+       if (IS_ERR(f_acm))
+               return PTR_ERR(f_acm);
 
-       status = ecm_bind_config(c, hostaddr);
+       status = usb_add_function(c, f_acm);
        if (status)
-               printk(KERN_DEBUG "could not bind ecm config\n");
+               goto err_conf;
+
+       status = ecm_bind_config(c, hostaddr, the_dev);
+       if (status) {
+               pr_debug("could not bind ecm config %d\n", status);
+               goto err_ecm;
+       }
+       if (c == &nokia_config_500ma_driver)
+               f_acm_cfg1 = f_acm;
+       else
+               f_acm_cfg2 = f_acm;
 
        return status;
+err_ecm:
+       usb_remove_function(c, f_acm);
+err_conf:
+       usb_put_function(f_acm);
+       return status;
 }
 
-static struct usb_configuration nokia_config_500ma_driver = {
-       .label          = "Bus Powered",
-       .bConfigurationValue = 1,
-       /* .iConfiguration = DYNAMIC */
-       .bmAttributes   = USB_CONFIG_ATT_ONE,
-       .MaxPower       = 500,
-};
-
-static struct usb_configuration nokia_config_100ma_driver = {
-       .label          = "Self Powered",
-       .bConfigurationValue = 2,
-       /* .iConfiguration = DYNAMIC */
-       .bmAttributes   = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
-       .MaxPower       = 100,
-};
-
 static int __init nokia_bind(struct usb_composite_dev *cdev)
 {
        struct usb_gadget       *gadget = cdev->gadget;
@@ -169,9 +186,11 @@ static int __init nokia_bind(struct usb_composite_dev *cdev)
                        goto err_ether;
        }
 
-       status = gether_setup(cdev->gadget, hostaddr);
-       if (status < 0)
+       the_dev = gether_setup(cdev->gadget, hostaddr);
+       if (IS_ERR(the_dev)) {
+               status = PTR_ERR(the_dev);
                goto err_ether;
+       }
 
        status = usb_string_ids_tab(cdev, strings_dev);
        if (status < 0)
@@ -185,24 +204,32 @@ static int __init nokia_bind(struct usb_composite_dev *cdev)
        if (!gadget_supports_altsettings(gadget))
                goto err_usb;
 
+       fi_acm = usb_get_function_instance("acm");
+       if (IS_ERR(fi_acm))
+               goto err_usb;
+
        /* finally register the configuration */
        status = usb_add_config(cdev, &nokia_config_500ma_driver,
                        nokia_bind_config);
        if (status < 0)
-               goto err_usb;
+               goto err_acm_inst;
 
        status = usb_add_config(cdev, &nokia_config_100ma_driver,
                        nokia_bind_config);
        if (status < 0)
-               goto err_usb;
+               goto err_put_cfg1;
 
        usb_composite_overwrite_options(cdev, &coverwrite);
        dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME);
 
        return 0;
 
+err_put_cfg1:
+       usb_put_function(f_acm_cfg1);
+err_acm_inst:
+       usb_put_function_instance(fi_acm);
 err_usb:
-       gether_cleanup();
+       gether_cleanup(the_dev);
 err_ether:
        cur_line--;
        while (cur_line >= 0)
@@ -217,12 +244,15 @@ static int __exit nokia_unbind(struct usb_composite_dev *cdev)
 {
        int i;
 
+       usb_put_function(f_acm_cfg1);
+       usb_put_function(f_acm_cfg2);
+       usb_put_function_instance(fi_acm);
        gphonet_cleanup();
 
        for (i = 0; i < TTY_PORTS_MAX; i++)
                gserial_free_line(tty_lines[i]);
 
-       gether_cleanup();
+       gether_cleanup(the_dev);
 
        return 0;
 }
@@ -247,4 +277,3 @@ static void __exit nokia_cleanup(void)
        usb_composite_unregister(&nokia_driver);
 }
 module_exit(nokia_cleanup);
-
index f844565..b8ed74a 100644 (file)
@@ -2067,7 +2067,6 @@ static int omap_udc_start(struct usb_gadget *g,
        /* hook up the driver */
        driver->driver.bus = NULL;
        udc->driver = driver;
-       udc->gadget.dev.driver = &driver->driver;
        spin_unlock_irqrestore(&udc->lock, flags);
 
        if (udc->dc_clk != NULL)
@@ -2083,7 +2082,6 @@ static int omap_udc_start(struct usb_gadget *g,
                        ERR("can't bind to transceiver\n");
                        if (driver->unbind) {
                                driver->unbind(&udc->gadget);
-                               udc->gadget.dev.driver = NULL;
                                udc->driver = NULL;
                        }
                        goto done;
@@ -2129,7 +2127,6 @@ static int omap_udc_stop(struct usb_gadget *g,
        udc_quiesce(udc);
        spin_unlock_irqrestore(&udc->lock, flags);
 
-       udc->gadget.dev.driver = NULL;
        udc->driver = NULL;
 
        if (udc->dc_clk != NULL)
@@ -2631,14 +2628,6 @@ omap_udc_setup(struct platform_device *odev, struct usb_phy *xceiv)
        udc->gadget.speed = USB_SPEED_UNKNOWN;
        udc->gadget.max_speed = USB_SPEED_FULL;
        udc->gadget.name = driver_name;
-
-       device_initialize(&udc->gadget.dev);
-       dev_set_name(&udc->gadget.dev, "gadget");
-       udc->gadget.dev.release = omap_udc_release;
-       udc->gadget.dev.parent = &odev->dev;
-       if (use_dma)
-               udc->gadget.dev.dma_mask = odev->dev.dma_mask;
-
        udc->transceiver = xceiv;
 
        /* ep0 is special; put it right after the SETUP buffer */
@@ -2912,14 +2901,13 @@ bad_on_1710:
        }
 
        create_proc_file();
-       status = device_add(&udc->gadget.dev);
+       status = usb_add_gadget_udc_release(&pdev->dev, &udc->gadget,
+                       omap_udc_release);
        if (status)
                goto cleanup4;
 
-       status = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
-       if (!status)
-               return status;
-       /* If fail, fall through */
+       return 0;
+
 cleanup4:
        remove_proc_file();
 
@@ -2990,7 +2978,6 @@ static int omap_udc_remove(struct platform_device *pdev)
        release_mem_region(pdev->resource[0].start,
                        pdev->resource[0].end - pdev->resource[0].start + 1);
 
-       device_unregister(&udc->gadget.dev);
        wait_for_completion(&done);
 
        return 0;
index a787a8e..24174e1 100644 (file)
@@ -358,7 +358,6 @@ struct pch_udc_dev {
                        prot_stall:1,
                        irq_registered:1,
                        mem_region:1,
-                       registered:1,
                        suspended:1,
                        connected:1,
                        vbus_session:1,
@@ -1441,6 +1440,8 @@ static void pch_vbus_gpio_free(struct pch_udc_dev *dev)
  */
 static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req,
                                                                 int status)
+       __releases(&dev->lock)
+       __acquires(&dev->lock)
 {
        struct pch_udc_dev      *dev;
        unsigned halted = ep->halted;
@@ -2382,6 +2383,8 @@ static void pch_udc_svc_control_in(struct pch_udc_dev *dev)
  * @dev:       Reference to the device structure
  */
 static void pch_udc_svc_control_out(struct pch_udc_dev *dev)
+       __releases(&dev->lock)
+       __acquires(&dev->lock)
 {
        u32     stat;
        int setup_supported;
@@ -2989,7 +2992,6 @@ static int pch_udc_start(struct usb_gadget *g,
 
        driver->driver.bus = NULL;
        dev->driver = driver;
-       dev->gadget.dev.driver = &driver->driver;
 
        /* get ready for ep0 traffic */
        pch_udc_setup_ep0(dev);
@@ -3010,7 +3012,6 @@ static int pch_udc_stop(struct usb_gadget *g,
        pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK);
 
        /* Assures that there are no pending requests with this driver */
-       dev->gadget.dev.driver = NULL;
        dev->driver = NULL;
        dev->connected = 0;
 
@@ -3078,8 +3079,6 @@ static void pch_udc_remove(struct pci_dev *pdev)
                                   pci_resource_len(pdev, PCH_UDC_PCI_BAR));
        if (dev->active)
                pci_disable_device(pdev);
-       if (dev->registered)
-               device_unregister(&dev->gadget.dev);
        kfree(dev);
        pci_set_drvdata(pdev, NULL);
 }
@@ -3196,21 +3195,13 @@ static int pch_udc_probe(struct pci_dev *pdev,
        if (retval)
                goto finished;
 
-       dev_set_name(&dev->gadget.dev, "gadget");
-       dev->gadget.dev.parent = &pdev->dev;
-       dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
-       dev->gadget.dev.release = gadget_release;
        dev->gadget.name = KBUILD_MODNAME;
        dev->gadget.max_speed = USB_SPEED_HIGH;
 
-       retval = device_register(&dev->gadget.dev);
-       if (retval)
-               goto finished;
-       dev->registered = 1;
-
        /* Put the device in disconnected state till a driver is bound */
        pch_udc_set_disconnect(dev);
-       retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+       retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
+                       gadget_release);
        if (retval)
                goto finished;
        return 0;
index d0f3748..ef47495 100644 (file)
@@ -1263,7 +1263,6 @@ static int pxa25x_udc_start(struct usb_gadget *g,
 
        /* first hook up the driver ... */
        dev->driver = driver;
-       dev->gadget.dev.driver = &driver->driver;
        dev->pullup = 1;
 
        /* ... then enable host detection and ep0; and we're ready
@@ -1325,7 +1324,6 @@ static int pxa25x_udc_stop(struct usb_gadget*g,
        if (!IS_ERR_OR_NULL(dev->transceiver))
                (void) otg_set_peripheral(dev->transceiver->otg, NULL);
 
-       dev->gadget.dev.driver = NULL;
        dev->driver = NULL;
 
        dump_state(dev);
@@ -2138,17 +2136,6 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
        dev->timer.function = udc_watchdog;
        dev->timer.data = (unsigned long) dev;
 
-       device_initialize(&dev->gadget.dev);
-       dev->gadget.dev.parent = &pdev->dev;
-       dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
-
-       retval = device_add(&dev->gadget.dev);
-       if (retval) {
-               dev->driver = NULL;
-               dev->gadget.dev.driver = NULL;
-               goto err_device_add;
-       }
-
        the_controller = dev;
        platform_set_drvdata(pdev, dev);
 
@@ -2199,8 +2186,6 @@ lubbock_fail0:
        free_irq(irq, dev);
 #endif
  err_irq1:
-       device_unregister(&dev->gadget.dev);
- err_device_add:
        if (gpio_is_valid(dev->mach->gpio_pullup))
                gpio_free(dev->mach->gpio_pullup);
  err_gpio_pullup:
@@ -2226,7 +2211,6 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev)
                return -EBUSY;
 
        usb_del_gadget_udc(&dev->gadget);
-       device_unregister(&dev->gadget.dev);
        dev->pullup = 0;
        pullup(dev);
 
index 2fc8676..6b4c7d9 100644 (file)
 #include <linux/gpio.h>
 #include <linux/slab.h>
 #include <linux/prefetch.h>
-
-#include <asm/byteorder.h>
-#include <mach/hardware.h>
+#include <linux/byteorder/generic.h>
+#include <linux/platform_data/pxa2xx_udc.h>
 
 #include <linux/usb.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
-#include <mach/udc.h>
 
 #include "pxa27x_udc.h"
 
@@ -611,7 +609,7 @@ static void inc_ep_stats_bytes(struct pxa_ep *ep, int count, int is_in)
  *
  * Find the physical pxa27x ep, and setup its UDCCR
  */
-static __init void pxa_ep_setup(struct pxa_ep *ep)
+static void pxa_ep_setup(struct pxa_ep *ep)
 {
        u32 new_udccr;
 
@@ -633,7 +631,7 @@ static __init void pxa_ep_setup(struct pxa_ep *ep)
  *
  * Setup all pxa physical endpoints, except ep0
  */
-static __init void pxa_eps_setup(struct pxa_udc *dev)
+static void pxa_eps_setup(struct pxa_udc *dev)
 {
        unsigned int i;
 
@@ -1718,7 +1716,7 @@ static void udc_disable(struct pxa_udc *udc)
  * Initializes gadget endpoint list, endpoints locks. No action is taken
  * on the hardware.
  */
-static __init void udc_init_data(struct pxa_udc *dev)
+static void udc_init_data(struct pxa_udc *dev)
 {
        int i;
        struct pxa_ep *ep;
@@ -1811,7 +1809,6 @@ static int pxa27x_udc_start(struct usb_gadget *g,
 
        /* first hook up the driver ... */
        udc->driver = driver;
-       udc->gadget.dev.driver = &driver->driver;
        dplus_pullup(udc, 1);
 
        if (!IS_ERR_OR_NULL(udc->transceiver)) {
@@ -1829,7 +1826,6 @@ static int pxa27x_udc_start(struct usb_gadget *g,
 
 fail:
        udc->driver = NULL;
-       udc->gadget.dev.driver = NULL;
        return retval;
 }
 
@@ -1871,7 +1867,6 @@ static int pxa27x_udc_stop(struct usb_gadget *g,
 
        udc->driver = NULL;
 
-
        if (!IS_ERR_OR_NULL(udc->transceiver))
                return otg_set_peripheral(udc->transceiver->otg, NULL);
        return 0;
@@ -2413,7 +2408,7 @@ static struct pxa_udc memory = {
  * Perform basic init : allocates udc clock, creates sysfs files, requests
  * irq.
  */
-static int __init pxa_udc_probe(struct platform_device *pdev)
+static int pxa_udc_probe(struct platform_device *pdev)
 {
        struct resource *regs;
        struct pxa_udc *udc = &memory;
@@ -2456,9 +2451,6 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
                goto err_map;
        }
 
-       device_initialize(&udc->gadget.dev);
-       udc->gadget.dev.parent = &pdev->dev;
-       udc->gadget.dev.dma_mask = NULL;
        udc->vbus_sensed = 0;
 
        the_controller = udc;
@@ -2475,12 +2467,6 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
                goto err_irq;
        }
 
-       retval = device_add(&udc->gadget.dev);
-       if (retval) {
-               dev_err(udc->dev, "device_add error %d\n", retval);
-               goto err_dev_add;
-       }
-
        retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
        if (retval)
                goto err_add_udc;
@@ -2490,8 +2476,6 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
        return 0;
 
 err_add_udc:
-       device_unregister(&udc->gadget.dev);
-err_dev_add:
        free_irq(udc->irq, udc);
 err_irq:
        iounmap(udc->regs);
@@ -2506,13 +2490,12 @@ err_clk:
  * pxa_udc_remove - removes the udc device driver
  * @_dev: platform device
  */
-static int __exit pxa_udc_remove(struct platform_device *_dev)
+static int pxa_udc_remove(struct platform_device *_dev)
 {
        struct pxa_udc *udc = platform_get_drvdata(_dev);
        int gpio = udc->mach->gpio_pullup;
 
        usb_del_gadget_udc(&udc->gadget);
-       device_del(&udc->gadget.dev);
        usb_gadget_unregister_driver(udc->driver);
        free_irq(udc->irq, udc);
        pxa_cleanup_debugfs(udc);
@@ -2625,7 +2608,8 @@ static struct platform_driver udc_driver = {
                .name   = "pxa27x-udc",
                .owner  = THIS_MODULE,
        },
-       .remove         = __exit_p(pxa_udc_remove),
+       .probe          = pxa_udc_probe,
+       .remove         = pxa_udc_remove,
        .shutdown       = pxa_udc_shutdown,
 #ifdef CONFIG_PM
        .suspend        = pxa_udc_suspend,
@@ -2633,22 +2617,7 @@ static struct platform_driver udc_driver = {
 #endif
 };
 
-static int __init udc_init(void)
-{
-       if (!cpu_is_pxa27x() && !cpu_is_pxa3xx())
-               return -ENODEV;
-
-       printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);
-       return platform_driver_probe(&udc_driver, pxa_udc_probe);
-}
-module_init(udc_init);
-
-
-static void __exit udc_exit(void)
-{
-       platform_driver_unregister(&udc_driver);
-}
-module_exit(udc_exit);
+module_platform_driver(udc_driver);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_AUTHOR("Robert Jarzmik");
index f46a1b7..0b742d1 100644 (file)
@@ -1837,7 +1837,6 @@ static int __exit r8a66597_remove(struct platform_device *pdev)
                clk_put(r8a66597->clk);
        }
 
-       device_unregister(&r8a66597->gadget.dev);
        kfree(r8a66597);
        return 0;
 }
@@ -1915,17 +1914,8 @@ static int __init r8a66597_probe(struct platform_device *pdev)
        r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW;
 
        r8a66597->gadget.ops = &r8a66597_gadget_ops;
-       dev_set_name(&r8a66597->gadget.dev, "gadget");
        r8a66597->gadget.max_speed = USB_SPEED_HIGH;
-       r8a66597->gadget.dev.parent = &pdev->dev;
-       r8a66597->gadget.dev.dma_mask = pdev->dev.dma_mask;
-       r8a66597->gadget.dev.release = pdev->dev.release;
        r8a66597->gadget.name = udc_name;
-       ret = device_register(&r8a66597->gadget.dev);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "device_register failed\n");
-               goto clean_up;
-       }
 
        init_timer(&r8a66597->timer);
        r8a66597->timer.function = r8a66597_timer;
@@ -1939,7 +1929,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)
                        dev_err(&pdev->dev, "cannot get clock \"%s\"\n",
                                clk_name);
                        ret = PTR_ERR(r8a66597->clk);
-                       goto clean_up_dev;
+                       goto clean_up;
                }
                clk_enable(r8a66597->clk);
        }
@@ -2007,8 +1997,6 @@ clean_up2:
                clk_disable(r8a66597->clk);
                clk_put(r8a66597->clk);
        }
-clean_up_dev:
-       device_unregister(&r8a66597->gadget.dev);
 clean_up:
        if (r8a66597) {
                if (r8a66597->sudmac_reg)
index c26564f..a3cdc32 100644 (file)
@@ -39,8 +39,6 @@
 
 #include "s3c-hsotg.h"
 
-#define DMA_ADDR_INVALID (~((dma_addr_t)0))
-
 static const char * const s3c_hsotg_supply_names[] = {
        "vusb_d",               /* digital USB supply, 1.2V */
        "vusb_a",               /* analog USB supply, 1.1V */
@@ -405,7 +403,6 @@ static struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep,
 
        INIT_LIST_HEAD(&req->queue);
 
-       req->req.dma = DMA_ADDR_INVALID;
        return &req->req;
 }
 
@@ -435,24 +432,12 @@ static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg,
                                struct s3c_hsotg_req *hs_req)
 {
        struct usb_request *req = &hs_req->req;
-       enum dma_data_direction dir;
-
-       dir = hs_ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
 
        /* ignore this if we're not moving any data */
        if (hs_req->req.length == 0)
                return;
 
-       if (hs_req->mapped) {
-               /* we mapped this, so unmap and remove the dma */
-
-               dma_unmap_single(hsotg->dev, req->dma, req->length, dir);
-
-               req->dma = DMA_ADDR_INVALID;
-               hs_req->mapped = 0;
-       } else {
-               dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir);
-       }
+       usb_gadget_unmap_request(&hsotg->gadget, hs_req, hs_ep->dir_in);
 }
 
 /**
@@ -852,37 +837,16 @@ static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg,
                             struct s3c_hsotg_ep *hs_ep,
                             struct usb_request *req)
 {
-       enum dma_data_direction dir;
        struct s3c_hsotg_req *hs_req = our_req(req);
-
-       dir = hs_ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+       int ret;
 
        /* if the length is zero, ignore the DMA data */
        if (hs_req->req.length == 0)
                return 0;
 
-       if (req->dma == DMA_ADDR_INVALID) {
-               dma_addr_t dma;
-
-               dma = dma_map_single(hsotg->dev, req->buf, req->length, dir);
-
-               if (unlikely(dma_mapping_error(hsotg->dev, dma)))
-                       goto dma_error;
-
-               if (dma & 3) {
-                       dev_err(hsotg->dev, "%s: unaligned dma buffer\n",
-                               __func__);
-
-                       dma_unmap_single(hsotg->dev, dma, req->length, dir);
-                       return -EINVAL;
-               }
-
-               hs_req->mapped = 1;
-               req->dma = dma;
-       } else {
-               dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir);
-               hs_req->mapped = 0;
-       }
+       ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in);
+       if (ret)
+               goto dma_error;
 
        return 0;
 
@@ -2961,9 +2925,7 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
 
        driver->driver.bus = NULL;
        hsotg->driver = driver;
-       hsotg->gadget.dev.driver = &driver->driver;
        hsotg->gadget.dev.of_node = hsotg->dev->of_node;
-       hsotg->gadget.dev.dma_mask = hsotg->dev->dma_mask;
        hsotg->gadget.speed = USB_SPEED_UNKNOWN;
 
        ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
@@ -2979,7 +2941,6 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
 
 err:
        hsotg->driver = NULL;
-       hsotg->gadget.dev.driver = NULL;
        return ret;
 }
 
@@ -3014,7 +2975,6 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,
 
        hsotg->driver = NULL;
        hsotg->gadget.speed = USB_SPEED_UNKNOWN;
-       hsotg->gadget.dev.driver = NULL;
 
        spin_unlock_irqrestore(&hsotg->lock, flags);
 
@@ -3483,16 +3443,6 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
        debugfs_remove(hsotg->debug_root);
 }
 
-/**
- * s3c_hsotg_release - release callback for hsotg device
- * @dev: Device to for which release is called
- *
- * Nothing to do as the resource is allocated using devm_ API.
- */
-static void s3c_hsotg_release(struct device *dev)
-{
-}
-
 /**
  * s3c_hsotg_probe - probe function for hsotg driver
  * @pdev: The platform information for the driver
@@ -3517,7 +3467,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
        }
 
        phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
-       if (IS_ERR_OR_NULL(phy)) {
+       if (IS_ERR(phy)) {
                /* Fallback for pdata */
                plat = pdev->dev.platform_data;
                if (!plat) {
@@ -3567,18 +3517,10 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
 
        dev_info(dev, "regs %p, irq %d\n", hsotg->regs, hsotg->irq);
 
-       device_initialize(&hsotg->gadget.dev);
-
-       dev_set_name(&hsotg->gadget.dev, "gadget");
-
        hsotg->gadget.max_speed = USB_SPEED_HIGH;
        hsotg->gadget.ops = &s3c_hsotg_gadget_ops;
        hsotg->gadget.name = dev_name(dev);
 
-       hsotg->gadget.dev.parent = dev;
-       hsotg->gadget.dev.dma_mask = dev->dma_mask;
-       hsotg->gadget.dev.release = s3c_hsotg_release;
-
        /* reset the system */
 
        clk_prepare_enable(hsotg->clk);
@@ -3658,12 +3600,6 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
 
        s3c_hsotg_phy_disable(hsotg);
 
-       ret = device_add(&hsotg->gadget.dev);
-       if (ret) {
-               put_device(&hsotg->gadget.dev);
-               goto err_ep_mem;
-       }
-
        ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget);
        if (ret)
                goto err_ep_mem;
@@ -3702,10 +3638,8 @@ static int s3c_hsotg_remove(struct platform_device *pdev)
        }
 
        s3c_hsotg_phy_disable(hsotg);
-
        clk_disable_unprepare(hsotg->clk);
 
-       device_unregister(&hsotg->gadget.dev);
        return 0;
 }
 
index 458965a..b1f0771 100644 (file)
@@ -283,7 +283,6 @@ static void s3c_hsudc_nuke_ep(struct s3c_hsudc_ep *hsep, int status)
 /**
  * s3c_hsudc_stop_activity - Stop activity on all endpoints.
  * @hsudc: Device controller for which EP activity is to be stopped.
- * @driver: Reference to the gadget driver which is currently active.
  *
  * All the endpoints are stopped and any pending transfer requests if any on
  * the endpoint are terminated.
@@ -1154,7 +1153,6 @@ static int s3c_hsudc_start(struct usb_gadget *gadget,
                return -EBUSY;
 
        hsudc->driver = driver;
-       hsudc->gadget.dev.driver = &driver->driver;
 
        ret = regulator_bulk_enable(ARRAY_SIZE(hsudc->supplies),
                                    hsudc->supplies);
@@ -1190,7 +1188,6 @@ err_otg:
        regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
 err_supplies:
        hsudc->driver = NULL;
-       hsudc->gadget.dev.driver = NULL;
        return ret;
 }
 
@@ -1208,7 +1205,6 @@ static int s3c_hsudc_stop(struct usb_gadget *gadget,
 
        spin_lock_irqsave(&hsudc->lock, flags);
        hsudc->driver = NULL;
-       hsudc->gadget.dev.driver = NULL;
        hsudc->gadget.speed = USB_SPEED_UNKNOWN;
        s3c_hsudc_uninit_phy();
 
@@ -1303,15 +1299,10 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
 
        spin_lock_init(&hsudc->lock);
 
-       dev_set_name(&hsudc->gadget.dev, "gadget");
-
        hsudc->gadget.max_speed = USB_SPEED_HIGH;
        hsudc->gadget.ops = &s3c_hsudc_gadget_ops;
        hsudc->gadget.name = dev_name(dev);
-       hsudc->gadget.dev.parent = dev;
-       hsudc->gadget.dev.dma_mask = dev->dma_mask;
        hsudc->gadget.ep0 = &hsudc->ep[0].ep;
-
        hsudc->gadget.is_otg = 0;
        hsudc->gadget.is_a_peripheral = 0;
        hsudc->gadget.speed = USB_SPEED_UNKNOWN;
@@ -1345,12 +1336,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
        disable_irq(hsudc->irq);
        local_irq_enable();
 
-       ret = device_register(&hsudc->gadget.dev);
-       if (ret) {
-               put_device(&hsudc->gadget.dev);
-               goto err_add_device;
-       }
-
        ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget);
        if (ret)
                goto err_add_udc;
@@ -1359,7 +1344,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
 
        return 0;
 err_add_udc:
-       device_unregister(&hsudc->gadget.dev);
 err_add_device:
        clk_disable(hsudc->uclk);
 err_res:
index 08f8965..d0e75e1 100644 (file)
@@ -1674,7 +1674,6 @@ static int s3c2410_udc_start(struct usb_gadget *g,
 
        /* Hook the driver */
        udc->driver = driver;
-       udc->gadget.dev.driver = &driver->driver;
 
        /* Enable udc */
        s3c2410_udc_enable(udc);
@@ -1824,17 +1823,6 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
                goto err_mem;
        }
 
-       device_initialize(&udc->gadget.dev);
-       udc->gadget.dev.parent = &pdev->dev;
-       udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
-
-       /* Bind the driver */
-       retval = device_add(&udc->gadget.dev);
-       if (retval) {
-               dev_err(&udc->gadget.dev, "Error in device_add() : %d\n", retval);
-               goto err_device_add;
-       }
-
        the_controller = udc;
        platform_set_drvdata(pdev, udc);
 
@@ -1923,8 +1911,6 @@ err_gpio_claim:
 err_int:
        free_irq(IRQ_USBD, udc);
 err_map:
-       device_unregister(&udc->gadget.dev);
-err_device_add:
        iounmap(base_addr);
 err_mem:
        release_mem_region(rsrc_start, rsrc_len);
@@ -1946,7 +1932,6 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
                return -EBUSY;
 
        usb_del_gadget_udc(&udc->gadget);
-       device_unregister(&udc->gadget.dev);
        debugfs_remove(udc->regs_info);
 
        if (udc_info && !udc_info->udc_command &&
index 68d7bb0..1f5f978 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/kernel.h>
 #include <linux/device.h>
+#include <linux/module.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 
 #define GS_LONG_NAME                   "Gadget Serial"
 #define GS_VERSION_NAME                        GS_LONG_NAME " " GS_VERSION_STR
 
-/*-------------------------------------------------------------------------*/
-
-/*
- * Kbuild is not very cooperative with respect to linking separately
- * compiled library objects into one module.  So for now we won't use
- * separate compilation ... ensuring init/exit sections work to shrink
- * the runtime footprint, and giving us at least some parts of what
- * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
- */
-#include "f_obex.c"
-#include "f_serial.c"
-
 /*-------------------------------------------------------------------------*/
 USB_GADGET_COMPOSITE_OPTIONS();
 
@@ -126,27 +115,6 @@ module_param(n_ports, uint, 0);
 MODULE_PARM_DESC(n_ports, "number of ports to create, default=1");
 
 /*-------------------------------------------------------------------------*/
-static unsigned char tty_lines[MAX_U_SERIAL_PORTS];
-
-static int __init serial_bind_obex_config(struct usb_configuration *c)
-{
-       unsigned i;
-       int status = 0;
-
-       for (i = 0; i < n_ports && status == 0; i++)
-               status = obex_bind_config(c, tty_lines[i]);
-       return status;
-}
-
-static int __init serial_bind_gser_config(struct usb_configuration *c)
-{
-       unsigned i;
-       int status = 0;
-
-       for (i = 0; i < n_ports && status == 0; i++)
-               status = gser_bind_config(c, tty_lines[i]);
-       return status;
-}
 
 static struct usb_configuration serial_config_driver = {
        /* .label = f(use_acm) */
@@ -169,15 +137,12 @@ static int serial_register_ports(struct usb_composite_dev *cdev,
                goto out;
 
        for (i = 0; i < n_ports; i++) {
-               struct f_serial_opts *opts;
 
                fi_serial[i] = usb_get_function_instance(f_name);
                if (IS_ERR(fi_serial[i])) {
                        ret = PTR_ERR(fi_serial[i]);
                        goto fail;
                }
-               opts = container_of(fi_serial[i], struct f_serial_opts, func_inst);
-               opts->port_num = tty_lines[i];
 
                f_serial[i] = usb_get_function(fi_serial[i]);
                if (IS_ERR(f_serial[i])) {
@@ -212,13 +177,6 @@ out:
 static int __init gs_bind(struct usb_composite_dev *cdev)
 {
        int                     status;
-       int                     cur_line;
-
-       for (cur_line = 0; cur_line < n_ports; cur_line++) {
-               status = gserial_alloc_line(&tty_lines[cur_line]);
-               if (status)
-                       goto fail;
-       }
 
        /* Allocate string descriptor numbers ... note that string
         * contents can be overridden by the composite_dev glue.
@@ -243,11 +201,12 @@ static int __init gs_bind(struct usb_composite_dev *cdev)
                                "acm");
                usb_ep_autoconfig_reset(cdev->gadget);
        } else if (use_obex)
-               status = usb_add_config(cdev, &serial_config_driver,
-                               serial_bind_obex_config);
-       else
-               status = usb_add_config(cdev, &serial_config_driver,
-                               serial_bind_gser_config);
+               status = serial_register_ports(cdev, &serial_config_driver,
+                               "obex");
+       else {
+               status = serial_register_ports(cdev, &serial_config_driver,
+                               "gser");
+       }
        if (status < 0)
                goto fail;
 
@@ -257,9 +216,6 @@ static int __init gs_bind(struct usb_composite_dev *cdev)
        return 0;
 
 fail:
-       cur_line--;
-       while (cur_line >= 0)
-               gserial_free_line(tty_lines[cur_line--]);
        return status;
 }
 
@@ -270,7 +226,6 @@ static int gs_unbind(struct usb_composite_dev *cdev)
        for (i = 0; i < n_ports; i++) {
                usb_put_function(f_serial[i]);
                usb_put_function_instance(fi_serial[i]);
-               gserial_free_line(tty_lines[i]);
        }
        return 0;
 }
index a0aa721..4b76124 100644 (file)
@@ -50,7 +50,6 @@
 
 struct eth_dev {
        /* lock is held while accessing port_usb
-        * or updating its backlink port_usb->ioport
         */
        spinlock_t              lock;
        struct gether           *port_usb;
@@ -729,8 +728,6 @@ static int get_ether_addr(const char *str, u8 *dev_addr)
        return 1;
 }
 
-static struct eth_dev *the_dev;
-
 static const struct net_device_ops eth_netdev_ops = {
        .ndo_open               = eth_open,
        .ndo_stop               = eth_stop,
@@ -758,19 +755,16 @@ static struct device_type gadget_type = {
  *
  * Returns negative errno, or zero on success
  */
-int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
+struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
                const char *netname)
 {
        struct eth_dev          *dev;
        struct net_device       *net;
        int                     status;
 
-       if (the_dev)
-               return -EBUSY;
-
        net = alloc_etherdev(sizeof *dev);
        if (!net)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
 
        dev = netdev_priv(net);
        spin_lock_init(&dev->lock);
@@ -807,12 +801,11 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
        if (status < 0) {
                dev_dbg(&g->dev, "register_netdev failed, %d\n", status);
                free_netdev(net);
+               dev = ERR_PTR(status);
        } else {
                INFO(dev, "MAC %pM\n", net->dev_addr);
                INFO(dev, "HOST MAC %pM\n", dev->host_mac);
 
-               the_dev = dev;
-
                /* two kinds of host-initiated state changes:
                 *  - iff DATA transfer is active, carrier is "on"
                 *  - tx queueing enabled if open *and* carrier is "on"
@@ -820,7 +813,7 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
                netif_carrier_off(net);
        }
 
-       return status;
+       return dev;
 }
 
 /**
@@ -829,19 +822,16 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
  *
  * This is called to free all resources allocated by @gether_setup().
  */
-void gether_cleanup(void)
+void gether_cleanup(struct eth_dev *dev)
 {
-       if (!the_dev)
+       if (!dev)
                return;
 
-       unregister_netdev(the_dev->net);
-       flush_work(&the_dev->work);
-       free_netdev(the_dev->net);
-
-       the_dev = NULL;
+       unregister_netdev(dev->net);
+       flush_work(&dev->work);
+       free_netdev(dev->net);
 }
 
-
 /**
  * gether_connect - notify network layer that USB link is active
  * @link: the USB link, set up with endpoints, descriptors matching
@@ -860,7 +850,7 @@ void gether_cleanup(void)
  */
 struct net_device *gether_connect(struct gether *link)
 {
-       struct eth_dev          *dev = the_dev;
+       struct eth_dev          *dev = link->ioport;
        int                     result = 0;
 
        if (!dev)
@@ -895,7 +885,6 @@ struct net_device *gether_connect(struct gether *link)
 
                spin_lock(&dev->lock);
                dev->port_usb = link;
-               link->ioport = dev;
                if (netif_running(dev->net)) {
                        if (link->open)
                                link->open(link);
@@ -989,6 +978,5 @@ void gether_disconnect(struct gether *link)
 
        spin_lock(&dev->lock);
        dev->port_usb = NULL;
-       link->ioport = NULL;
        spin_unlock(&dev->lock);
 }
index 6f4a162..0252233 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "gadget_chips.h"
 
+struct eth_dev;
 
 /*
  * This represents the USB side of an "ethernet" link, managed by a USB
@@ -70,7 +71,7 @@ struct gether {
                        |USB_CDC_PACKET_TYPE_DIRECTED)
 
 /* variant of gether_setup that allows customizing network device name */
-int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
+struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
                const char *netname);
 
 /* netdev setup/teardown as directed by the gadget driver */
@@ -86,12 +87,13 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
  *
  * Returns negative errno, or zero on success
  */
-static inline int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
+static inline struct eth_dev *gether_setup(struct usb_gadget *g,
+               u8 ethaddr[ETH_ALEN])
 {
        return gether_setup_name(g, ethaddr, "usb");
 }
 
-void gether_cleanup(void);
+void gether_cleanup(struct eth_dev *dev);
 
 /* connect/disconnect is handled by individual functions */
 struct net_device *gether_connect(struct gether *);
@@ -111,21 +113,24 @@ static inline bool can_support_ecm(struct usb_gadget *gadget)
 }
 
 /* each configuration may bind one instance of an ethernet link */
-int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
-int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
-int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
-int eem_bind_config(struct usb_configuration *c);
+int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+               struct eth_dev *dev);
+int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+               struct eth_dev *dev);
+int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+               struct eth_dev *dev);
+int eem_bind_config(struct usb_configuration *c, struct eth_dev *dev);
 
 #ifdef USB_ETH_RNDIS
 
 int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
-                               u32 vendorID, const char *manufacturer);
+               u32 vendorID, const char *manufacturer, struct eth_dev *dev);
 
 #else
 
 static inline int
 rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
-                               u32 vendorID, const char *manufacturer)
+               u32 vendorID, const char *manufacturer, struct eth_dev *dev)
 {
        return 0;
 }
@@ -145,9 +150,9 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
  * for calling @gether_cleanup() before module unload.
  */
 static inline int rndis_bind_config(struct usb_configuration *c,
-                                   u8 ethaddr[ETH_ALEN])
+               u8 ethaddr[ETH_ALEN], struct eth_dev *dev)
 {
-       return rndis_bind_config_vendor(c, ethaddr, 0, NULL);
+       return rndis_bind_config_vendor(c, ethaddr, 0, NULL, dev);
 }
 
 
index 66ce73a..c20210c 100644 (file)
@@ -65,7 +65,6 @@ int gserial_connect(struct gserial *, u8 port_num);
 void gserial_disconnect(struct gserial *);
 
 /* functions are bound to configurations by a config or gadget driver */
-int acm_bind_config(struct usb_configuration *c, u8 port_num);
 int gser_bind_config(struct usb_configuration *c, u8 port_num);
 int obex_bind_config(struct usb_configuration *c, u8 port_num);
 
index f8f62c3..ffd8fa5 100644 (file)
@@ -101,6 +101,16 @@ EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
 
 /* ------------------------------------------------------------------------- */
 
+void usb_gadget_set_state(struct usb_gadget *gadget,
+               enum usb_device_state state)
+{
+       gadget->state = state;
+       sysfs_notify(&gadget->dev.kobj, NULL, "status");
+}
+EXPORT_SYMBOL_GPL(usb_gadget_set_state);
+
+/* ------------------------------------------------------------------------- */
+
 /**
  * usb_gadget_udc_start - tells usb device controller to start up
  * @gadget: The gadget we want to get started
@@ -156,15 +166,23 @@ static void usb_udc_release(struct device *dev)
 }
 
 static const struct attribute_group *usb_udc_attr_groups[];
+
+static void usb_udc_nop_release(struct device *dev)
+{
+       dev_vdbg(dev, "%s\n", __func__);
+}
+
 /**
- * usb_add_gadget_udc - adds a new gadget to the udc class driver list
- * @parent: the parent device to this udc. Usually the controller
- * driver's device.
- * @gadget: the gadget to be added to the list
+ * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
+ * @parent: the parent device to this udc. Usually the controller driver's
+ * device.
+ * @gadget: the gadget to be added to the list.
+ * @release: a gadget release function.
  *
  * Returns zero on success, negative errno otherwise.
  */
-int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
+int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
+               void (*release)(struct device *dev))
 {
        struct usb_udc          *udc;
        int                     ret = -ENOMEM;
@@ -173,6 +191,22 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
        if (!udc)
                goto err1;
 
+       dev_set_name(&gadget->dev, "gadget");
+       gadget->dev.parent = parent;
+
+       dma_set_coherent_mask(&gadget->dev, parent->coherent_dma_mask);
+       gadget->dev.dma_parms = parent->dma_parms;
+       gadget->dev.dma_mask = parent->dma_mask;
+
+       if (release)
+               gadget->dev.release = release;
+       else
+               gadget->dev.release = usb_udc_nop_release;
+
+       ret = device_register(&gadget->dev);
+       if (ret)
+               goto err2;
+
        device_initialize(&udc->dev);
        udc->dev.release = usb_udc_release;
        udc->dev.class = udc_class;
@@ -180,7 +214,7 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
        udc->dev.parent = parent;
        ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj));
        if (ret)
-               goto err2;
+               goto err3;
 
        udc->gadget = gadget;
 
@@ -189,21 +223,42 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
 
        ret = device_add(&udc->dev);
        if (ret)
-               goto err3;
+               goto err4;
+
+       usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
 
        mutex_unlock(&udc_lock);
 
        return 0;
-err3:
+
+err4:
        list_del(&udc->list);
        mutex_unlock(&udc_lock);
 
-err2:
+err3:
        put_device(&udc->dev);
 
+err2:
+       put_device(&gadget->dev);
+       kfree(udc);
+
 err1:
        return ret;
 }
+EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release);
+
+/**
+ * usb_add_gadget_udc - adds a new gadget to the udc class driver list
+ * @parent: the parent device to this udc. Usually the controller
+ * driver's device.
+ * @gadget: the gadget to be added to the list
+ *
+ * Returns zero on success, negative errno otherwise.
+ */
+int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
+{
+       return usb_add_gadget_udc_release(parent, gadget, NULL);
+}
 EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
 
 static void usb_gadget_remove_driver(struct usb_udc *udc)
@@ -220,6 +275,7 @@ static void usb_gadget_remove_driver(struct usb_udc *udc)
 
        udc->driver = NULL;
        udc->dev.driver = NULL;
+       udc->gadget->dev.driver = NULL;
 }
 
 /**
@@ -254,6 +310,7 @@ found:
 
        kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
        device_unregister(&udc->dev);
+       device_unregister(&gadget->dev);
 }
 EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
 
@@ -268,6 +325,7 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri
 
        udc->driver = driver;
        udc->dev.driver = &driver->driver;
+       udc->gadget->dev.driver = &driver->driver;
 
        ret = driver->bind(udc->gadget, driver);
        if (ret)
@@ -286,6 +344,7 @@ err1:
                        udc->driver->function, ret);
        udc->driver = NULL;
        udc->dev.driver = NULL;
+       udc->gadget->dev.driver = NULL;
        return ret;
 }
 
@@ -395,6 +454,16 @@ static ssize_t usb_udc_softconn_store(struct device *dev,
 }
 static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store);
 
+static ssize_t usb_gadget_state_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct usb_udc          *udc = container_of(dev, struct usb_udc, dev);
+       struct usb_gadget       *gadget = udc->gadget;
+
+       return sprintf(buf, "%s\n", usb_state_string(gadget->state));
+}
+static DEVICE_ATTR(state, S_IRUGO, usb_gadget_state_show, NULL);
+
 #define USB_UDC_SPEED_ATTR(name, param)                                        \
 ssize_t usb_udc_##param##_show(struct device *dev,                     \
                struct device_attribute *attr, char *buf)               \
@@ -403,7 +472,7 @@ ssize_t usb_udc_##param##_show(struct device *dev,                  \
        return snprintf(buf, PAGE_SIZE, "%s\n",                         \
                        usb_speed_string(udc->gadget->param));          \
 }                                                                      \
-static DEVICE_ATTR(name, S_IRUSR, usb_udc_##param##_show, NULL)
+static DEVICE_ATTR(name, S_IRUGO, usb_udc_##param##_show, NULL)
 
 static USB_UDC_SPEED_ATTR(current_speed, speed);
 static USB_UDC_SPEED_ATTR(maximum_speed, max_speed);
@@ -428,6 +497,7 @@ static USB_UDC_ATTR(a_alt_hnp_support);
 static struct attribute *usb_udc_attrs[] = {
        &dev_attr_srp.attr,
        &dev_attr_soft_connect.attr,
+       &dev_attr_state.attr,
        &dev_attr_current_speed.attr,
        &dev_attr_maximum_speed.attr,
 
index 93b0c11..817e9e1 100644 (file)
@@ -98,8 +98,6 @@ extern unsigned int uvc_gadget_trace_param;
 #define DRIVER_VERSION                         "0.1.0"
 #define DRIVER_VERSION_NUMBER                  KERNEL_VERSION(0, 1, 0)
 
-#define DMA_ADDR_INVALID                       (~(dma_addr_t)0)
-
 #define UVC_NUM_REQUESTS                       4
 #define UVC_MAX_REQUEST_SIZE                   64
 #define UVC_MAX_EVENTS                         4
@@ -190,6 +188,7 @@ struct uvc_file_handle
  * Functions
  */
 
+extern void uvc_function_setup_continue(struct uvc_device *uvc);
 extern void uvc_endpoint_stream(struct uvc_device *dev);
 
 extern void uvc_function_connect(struct uvc_device *uvc);
index 104ae9c..7ce27e3 100644 (file)
@@ -10,6 +10,7 @@
  *     (at your option) any later version.
  */
 
+#include <linux/atomic.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/list.h>
@@ -18,7 +19,8 @@
 #include <linux/videodev2.h>
 #include <linux/vmalloc.h>
 #include <linux/wait.h>
-#include <linux/atomic.h>
+
+#include <media/videobuf2-vmalloc.h>
 
 #include "uvc.h"
 
  * Video queues is initialized by uvc_queue_init(). The function performs
  * basic initialization of the uvc_video_queue struct and never fails.
  *
- * Video buffer allocation and freeing are performed by uvc_alloc_buffers and
- * uvc_free_buffers respectively. The former acquires the video queue lock,
- * while the later must be called with the lock held (so that allocation can
- * free previously allocated buffers). Trying to free buffers that are mapped
- * to user space will return -EBUSY.
- *
- * Video buffers are managed using two queues. However, unlike most USB video
- * drivers that use an in queue and an out queue, we use a main queue to hold
- * all queued buffers (both 'empty' and 'done' buffers), and an irq queue to
- * hold empty buffers. This design (copied from video-buf) minimizes locking
- * in interrupt, as only one queue is shared between interrupt and user
- * contexts.
- *
- * Use cases
- * ---------
- *
- * Unless stated otherwise, all operations that modify the irq buffers queue
- * are protected by the irq spinlock.
- *
- * 1. The user queues the buffers, starts streaming and dequeues a buffer.
- *
- *    The buffers are added to the main and irq queues. Both operations are
- *    protected by the queue lock, and the later is protected by the irq
- *    spinlock as well.
- *
- *    The completion handler fetches a buffer from the irq queue and fills it
- *    with video data. If no buffer is available (irq queue empty), the handler
- *    returns immediately.
- *
- *    When the buffer is full, the completion handler removes it from the irq
- *    queue, marks it as ready (UVC_BUF_STATE_DONE) and wakes its wait queue.
- *    At that point, any process waiting on the buffer will be woken up. If a
- *    process tries to dequeue a buffer after it has been marked ready, the
- *    dequeing will succeed immediately.
- *
- * 2. Buffers are queued, user is waiting on a buffer and the device gets
- *    disconnected.
- *
- *    When the device is disconnected, the kernel calls the completion handler
- *    with an appropriate status code. The handler marks all buffers in the
- *    irq queue as being erroneous (UVC_BUF_STATE_ERROR) and wakes them up so
- *    that any process waiting on a buffer gets woken up.
- *
- *    Waking up up the first buffer on the irq list is not enough, as the
- *    process waiting on the buffer might restart the dequeue operation
- *    immediately.
- *
+ * Video buffers are managed by videobuf2. The driver uses a mutex to protect
+ * the videobuf2 queue operations by serializing calls to videobuf2 and a
+ * spinlock to protect the IRQ queue that holds the buffers to be processed by
+ * the driver.
  */
 
-static void
-uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type)
-{
-       mutex_init(&queue->mutex);
-       spin_lock_init(&queue->irqlock);
-       INIT_LIST_HEAD(&queue->mainqueue);
-       INIT_LIST_HEAD(&queue->irqqueue);
-       queue->type = type;
-}
-
-/*
- * Free the video buffers.
- *
- * This function must be called with the queue lock held.
+/* -----------------------------------------------------------------------------
+ * videobuf2 queue operations
  */
-static int uvc_free_buffers(struct uvc_video_queue *queue)
+
+static int uvc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+                          unsigned int *nbuffers, unsigned int *nplanes,
+                          unsigned int sizes[], void *alloc_ctxs[])
 {
-       unsigned int i;
+       struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
+       struct uvc_video *video = container_of(queue, struct uvc_video, queue);
 
-       for (i = 0; i < queue->count; ++i) {
-               if (queue->buffer[i].vma_use_count != 0)
-                       return -EBUSY;
-       }
+       if (*nbuffers > UVC_MAX_VIDEO_BUFFERS)
+               *nbuffers = UVC_MAX_VIDEO_BUFFERS;
 
-       if (queue->count) {
-               vfree(queue->mem);
-               queue->count = 0;
-       }
+       *nplanes = 1;
+
+       sizes[0] = video->imagesize;
 
        return 0;
 }
 
-/*
- * Allocate the video buffers.
- *
- * Pages are reserved to make sure they will not be swapped, as they will be
- * filled in the URB completion handler.
- *
- * Buffers will be individually mapped, so they must all be page aligned.
- */
-static int
-uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
-                 unsigned int buflength)
+static int uvc_buffer_prepare(struct vb2_buffer *vb)
 {
-       unsigned int bufsize = PAGE_ALIGN(buflength);
-       unsigned int i;
-       void *mem = NULL;
-       int ret;
+       struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
+       struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
 
-       if (nbuffers > UVC_MAX_VIDEO_BUFFERS)
-               nbuffers = UVC_MAX_VIDEO_BUFFERS;
+       if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+           vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
+               uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
+               return -EINVAL;
+       }
 
-       mutex_lock(&queue->mutex);
+       if (unlikely(queue->flags & UVC_QUEUE_DISCONNECTED))
+               return -ENODEV;
 
-       if ((ret = uvc_free_buffers(queue)) < 0)
-               goto done;
+       buf->state = UVC_BUF_STATE_QUEUED;
+       buf->mem = vb2_plane_vaddr(vb, 0);
+       buf->length = vb2_plane_size(vb, 0);
+       if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               buf->bytesused = 0;
+       else
+               buf->bytesused = vb2_get_plane_payload(vb, 0);
 
-       /* Bail out if no buffers should be allocated. */
-       if (nbuffers == 0)
-               goto done;
+       return 0;
+}
 
-       /* Decrement the number of buffers until allocation succeeds. */
-       for (; nbuffers > 0; --nbuffers) {
-               mem = vmalloc_32(nbuffers * bufsize);
-               if (mem != NULL)
-                       break;
-       }
+static void uvc_buffer_queue(struct vb2_buffer *vb)
+{
+       struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
+       struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
+       unsigned long flags;
 
-       if (mem == NULL) {
-               ret = -ENOMEM;
-               goto done;
-       }
+       spin_lock_irqsave(&queue->irqlock, flags);
 
-       for (i = 0; i < nbuffers; ++i) {
-               memset(&queue->buffer[i], 0, sizeof queue->buffer[i]);
-               queue->buffer[i].buf.index = i;
-               queue->buffer[i].buf.m.offset = i * bufsize;
-               queue->buffer[i].buf.length = buflength;
-               queue->buffer[i].buf.type = queue->type;
-               queue->buffer[i].buf.sequence = 0;
-               queue->buffer[i].buf.field = V4L2_FIELD_NONE;
-               queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP;
-               queue->buffer[i].buf.flags = 0;
-               init_waitqueue_head(&queue->buffer[i].wait);
+       if (likely(!(queue->flags & UVC_QUEUE_DISCONNECTED))) {
+               list_add_tail(&buf->queue, &queue->irqqueue);
+       } else {
+               /* If the device is disconnected return the buffer to userspace
+                * directly. The next QBUF call will fail with -ENODEV.
+                */
+               buf->state = UVC_BUF_STATE_ERROR;
+               vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
        }
 
-       queue->mem = mem;
-       queue->count = nbuffers;
-       queue->buf_size = bufsize;
-       ret = nbuffers;
-
-done:
-       mutex_unlock(&queue->mutex);
-       return ret;
+       spin_unlock_irqrestore(&queue->irqlock, flags);
 }
 
-static void __uvc_query_buffer(struct uvc_buffer *buf,
-               struct v4l2_buffer *v4l2_buf)
-{
-       memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf);
-
-       if (buf->vma_use_count)
-               v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED;
-
-       switch (buf->state) {
-       case UVC_BUF_STATE_ERROR:
-       case UVC_BUF_STATE_DONE:
-               v4l2_buf->flags |= V4L2_BUF_FLAG_DONE;
-               break;
-       case UVC_BUF_STATE_QUEUED:
-       case UVC_BUF_STATE_ACTIVE:
-               v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
-               break;
-       case UVC_BUF_STATE_IDLE:
-       default:
-               break;
-       }
-}
+static struct vb2_ops uvc_queue_qops = {
+       .queue_setup = uvc_queue_setup,
+       .buf_prepare = uvc_buffer_prepare,
+       .buf_queue = uvc_buffer_queue,
+};
 
-static int
-uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf)
+static int uvc_queue_init(struct uvc_video_queue *queue,
+                         enum v4l2_buf_type type)
 {
-       int ret = 0;
+       int ret;
 
-       mutex_lock(&queue->mutex);
-       if (v4l2_buf->index >= queue->count) {
-               ret = -EINVAL;
-               goto done;
-       }
+       queue->queue.type = type;
+       queue->queue.io_modes = VB2_MMAP | VB2_USERPTR;
+       queue->queue.drv_priv = queue;
+       queue->queue.buf_struct_size = sizeof(struct uvc_buffer);
+       queue->queue.ops = &uvc_queue_qops;
+       queue->queue.mem_ops = &vb2_vmalloc_memops;
+       ret = vb2_queue_init(&queue->queue);
+       if (ret)
+               return ret;
+
+       mutex_init(&queue->mutex);
+       spin_lock_init(&queue->irqlock);
+       INIT_LIST_HEAD(&queue->irqqueue);
+       queue->flags = 0;
 
-       __uvc_query_buffer(&queue->buffer[v4l2_buf->index], v4l2_buf);
+       return 0;
+}
 
-done:
+/*
+ * Free the video buffers.
+ */
+static void uvc_free_buffers(struct uvc_video_queue *queue)
+{
+       mutex_lock(&queue->mutex);
+       vb2_queue_release(&queue->queue);
        mutex_unlock(&queue->mutex);
-       return ret;
 }
 
 /*
- * Queue a video buffer. Attempting to queue a buffer that has already been
- * queued will return -EINVAL.
+ * Allocate the video buffers.
  */
-static int
-uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf)
+static int uvc_alloc_buffers(struct uvc_video_queue *queue,
+                            struct v4l2_requestbuffers *rb)
 {
-       struct uvc_buffer *buf;
-       unsigned long flags;
-       int ret = 0;
+       int ret;
 
-       uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index);
+       mutex_lock(&queue->mutex);
+       ret = vb2_reqbufs(&queue->queue, rb);
+       mutex_unlock(&queue->mutex);
 
-       if (v4l2_buf->type != queue->type ||
-           v4l2_buf->memory != V4L2_MEMORY_MMAP) {
-               uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
-                       "and/or memory (%u).\n", v4l2_buf->type,
-                       v4l2_buf->memory);
-               return -EINVAL;
-       }
+       return ret ? ret : rb->count;
+}
 
-       mutex_lock(&queue->mutex);
-       if (v4l2_buf->index >= queue->count) {
-               uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n");
-               ret = -EINVAL;
-               goto done;
-       }
+static int uvc_query_buffer(struct uvc_video_queue *queue,
+                           struct v4l2_buffer *buf)
+{
+       int ret;
 
-       buf = &queue->buffer[v4l2_buf->index];
-       if (buf->state != UVC_BUF_STATE_IDLE) {
-               uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state "
-                       "(%u).\n", buf->state);
-               ret = -EINVAL;
-               goto done;
-       }
+       mutex_lock(&queue->mutex);
+       ret = vb2_querybuf(&queue->queue, buf);
+       mutex_unlock(&queue->mutex);
 
-       if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
-           v4l2_buf->bytesused > buf->buf.length) {
-               uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
-               ret = -EINVAL;
-               goto done;
-       }
+       return ret;
+}
 
-       if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               buf->buf.bytesused = 0;
-       else
-               buf->buf.bytesused = v4l2_buf->bytesused;
+static int uvc_queue_buffer(struct uvc_video_queue *queue,
+                           struct v4l2_buffer *buf)
+{
+       unsigned long flags;
+       int ret;
 
+       mutex_lock(&queue->mutex);
+       ret = vb2_qbuf(&queue->queue, buf);
        spin_lock_irqsave(&queue->irqlock, flags);
-       if (queue->flags & UVC_QUEUE_DISCONNECTED) {
-               spin_unlock_irqrestore(&queue->irqlock, flags);
-               ret = -ENODEV;
-               goto done;
-       }
-       buf->state = UVC_BUF_STATE_QUEUED;
-
        ret = (queue->flags & UVC_QUEUE_PAUSED) != 0;
        queue->flags &= ~UVC_QUEUE_PAUSED;
-
-       list_add_tail(&buf->stream, &queue->mainqueue);
-       list_add_tail(&buf->queue, &queue->irqqueue);
        spin_unlock_irqrestore(&queue->irqlock, flags);
-
-done:
        mutex_unlock(&queue->mutex);
-       return ret;
-}
 
-static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking)
-{
-       if (nonblocking) {
-               return (buf->state != UVC_BUF_STATE_QUEUED &&
-                       buf->state != UVC_BUF_STATE_ACTIVE)
-                       ? 0 : -EAGAIN;
-       }
-
-       return wait_event_interruptible(buf->wait,
-               buf->state != UVC_BUF_STATE_QUEUED &&
-               buf->state != UVC_BUF_STATE_ACTIVE);
+       return ret;
 }
 
 /*
  * Dequeue a video buffer. If nonblocking is false, block until a buffer is
  * available.
  */
-static int
-uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf,
-                  int nonblocking)
+static int uvc_dequeue_buffer(struct uvc_video_queue *queue,
+                             struct v4l2_buffer *buf, int nonblocking)
 {
-       struct uvc_buffer *buf;
-       int ret = 0;
-
-       if (v4l2_buf->type != queue->type ||
-           v4l2_buf->memory != V4L2_MEMORY_MMAP) {
-               uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
-                       "and/or memory (%u).\n", v4l2_buf->type,
-                       v4l2_buf->memory);
-               return -EINVAL;
-       }
+       int ret;
 
        mutex_lock(&queue->mutex);
-       if (list_empty(&queue->mainqueue)) {
-               uvc_trace(UVC_TRACE_CAPTURE, "[E] Empty buffer queue.\n");
-               ret = -EINVAL;
-               goto done;
-       }
-
-       buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
-       if ((ret = uvc_queue_waiton(buf, nonblocking)) < 0)
-               goto done;
-
-       uvc_trace(UVC_TRACE_CAPTURE, "Dequeuing buffer %u (%u, %u bytes).\n",
-               buf->buf.index, buf->state, buf->buf.bytesused);
-
-       switch (buf->state) {
-       case UVC_BUF_STATE_ERROR:
-               uvc_trace(UVC_TRACE_CAPTURE, "[W] Corrupted data "
-                       "(transmission error).\n");
-               ret = -EIO;
-       case UVC_BUF_STATE_DONE:
-               buf->state = UVC_BUF_STATE_IDLE;
-               break;
-
-       case UVC_BUF_STATE_IDLE:
-       case UVC_BUF_STATE_QUEUED:
-       case UVC_BUF_STATE_ACTIVE:
-       default:
-               uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u "
-                       "(driver bug?).\n", buf->state);
-               ret = -EINVAL;
-               goto done;
-       }
-
-       list_del(&buf->stream);
-       __uvc_query_buffer(buf, v4l2_buf);
-
-done:
+       ret = vb2_dqbuf(&queue->queue, buf, nonblocking);
        mutex_unlock(&queue->mutex);
+
        return ret;
 }
 
@@ -361,105 +208,47 @@ done:
  * This function implements video queue polling and is intended to be used by
  * the device poll handler.
  */
-static unsigned int
-uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
-              poll_table *wait)
+static unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
+                                  struct file *file, poll_table *wait)
 {
-       struct uvc_buffer *buf;
-       unsigned int mask = 0;
+       unsigned int ret;
 
        mutex_lock(&queue->mutex);
-       if (list_empty(&queue->mainqueue))
-               goto done;
-
-       buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
-
-       poll_wait(file, &buf->wait, wait);
-       if (buf->state == UVC_BUF_STATE_DONE ||
-           buf->state == UVC_BUF_STATE_ERROR)
-               mask |= POLLOUT | POLLWRNORM;
-
-done:
+       ret = vb2_poll(&queue->queue, file, wait);
        mutex_unlock(&queue->mutex);
-       return mask;
-}
 
-/*
- * VMA operations.
- */
-static void uvc_vm_open(struct vm_area_struct *vma)
-{
-       struct uvc_buffer *buffer = vma->vm_private_data;
-       buffer->vma_use_count++;
+       return ret;
 }
 
-static void uvc_vm_close(struct vm_area_struct *vma)
+static int uvc_queue_mmap(struct uvc_video_queue *queue,
+                         struct vm_area_struct *vma)
 {
-       struct uvc_buffer *buffer = vma->vm_private_data;
-       buffer->vma_use_count--;
-}
+       int ret;
 
-static struct vm_operations_struct uvc_vm_ops = {
-       .open           = uvc_vm_open,
-       .close          = uvc_vm_close,
-};
+       mutex_lock(&queue->mutex);
+       ret = vb2_mmap(&queue->queue, vma);
+       mutex_unlock(&queue->mutex);
+
+       return ret;
+}
 
+#ifndef CONFIG_MMU
 /*
- * Memory-map a buffer.
+ * Get unmapped area.
  *
- * This function implements video buffer memory mapping and is intended to be
- * used by the device mmap handler.
+ * NO-MMU arch need this function to make mmap() work correctly.
  */
-static int
-uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
+static unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
+               unsigned long pgoff)
 {
-       struct uvc_buffer *uninitialized_var(buffer);
-       struct page *page;
-       unsigned long addr, start, size;
-       unsigned int i;
-       int ret = 0;
-
-       start = vma->vm_start;
-       size = vma->vm_end - vma->vm_start;
+       unsigned long ret;
 
        mutex_lock(&queue->mutex);
-
-       for (i = 0; i < queue->count; ++i) {
-               buffer = &queue->buffer[i];
-               if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
-                       break;
-       }
-
-       if (i == queue->count || size != queue->buf_size) {
-               ret = -EINVAL;
-               goto done;
-       }
-
-       /*
-        * VM_IO marks the area as being an mmaped region for I/O to a
-        * device. It also prevents the region from being core dumped.
-        */
-       vma->vm_flags |= VM_IO;
-
-       addr = (unsigned long)queue->mem + buffer->buf.m.offset;
-       while (size > 0) {
-               page = vmalloc_to_page((void *)addr);
-               if ((ret = vm_insert_page(vma, start, page)) < 0)
-                       goto done;
-
-               start += PAGE_SIZE;
-               addr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       vma->vm_ops = &uvc_vm_ops;
-       vma->vm_private_data = buffer;
-       uvc_vm_open(vma);
-
-done:
+       ret = vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0);
        mutex_unlock(&queue->mutex);
        return ret;
 }
+#endif
 
 /*
  * Cancel the video buffers queue.
@@ -484,7 +273,7 @@ static void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
                                       queue);
                list_del(&buf->queue);
                buf->state = UVC_BUF_STATE_ERROR;
-               wake_up(&buf->wait);
+               vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
        }
        /* This must be protected by the irqlock spinlock to avoid race
         * conditions between uvc_queue_buffer and the disconnection event that
@@ -516,26 +305,33 @@ static void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
  */
 static int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
 {
-       unsigned int i;
+       unsigned long flags;
        int ret = 0;
 
        mutex_lock(&queue->mutex);
        if (enable) {
-               if (uvc_queue_streaming(queue)) {
-                       ret = -EBUSY;
+               ret = vb2_streamon(&queue->queue, queue->queue.type);
+               if (ret < 0)
                        goto done;
-               }
+
                queue->sequence = 0;
-               queue->flags |= UVC_QUEUE_STREAMING;
                queue->buf_used = 0;
        } else {
-               uvc_queue_cancel(queue, 0);
-               INIT_LIST_HEAD(&queue->mainqueue);
+               ret = vb2_streamoff(&queue->queue, queue->queue.type);
+               if (ret < 0)
+                       goto done;
 
-               for (i = 0; i < queue->count; ++i)
-                       queue->buffer[i].state = UVC_BUF_STATE_IDLE;
+               spin_lock_irqsave(&queue->irqlock, flags);
+               INIT_LIST_HEAD(&queue->irqqueue);
 
-               queue->flags &= ~UVC_QUEUE_STREAMING;
+               /*
+                * FIXME: We need to clear the DISCONNECTED flag to ensure that
+                * applications will be able to queue buffers for the next
+                * streaming run. However, clearing it here doesn't guarantee
+                * that the device will be reconnected in the meantime.
+                */
+               queue->flags &= ~UVC_QUEUE_DISCONNECTED;
+               spin_unlock_irqrestore(&queue->irqlock, flags);
        }
 
 done:
@@ -544,15 +340,15 @@ done:
 }
 
 /* called with &queue_irqlock held.. */
-static struct uvc_buffer *
-uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf)
+static struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
+                                               struct uvc_buffer *buf)
 {
        struct uvc_buffer *nextbuf;
 
        if ((queue->flags & UVC_QUEUE_DROP_INCOMPLETE) &&
-           buf->buf.length != buf->buf.bytesused) {
+            buf->length != buf->bytesused) {
                buf->state = UVC_BUF_STATE_QUEUED;
-               buf->buf.bytesused = 0;
+               vb2_set_plane_payload(&buf->buf, 0, 0);
                return buf;
        }
 
@@ -563,10 +359,18 @@ uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf)
        else
                nextbuf = NULL;
 
-       buf->buf.sequence = queue->sequence++;
-       do_gettimeofday(&buf->buf.timestamp);
+       /*
+        * FIXME: with videobuf2, the sequence number or timestamp fields
+        * are valid only for video capture devices and the UVC gadget usually
+        * is a video output device. Keeping these until the specs are clear on
+        * this aspect.
+        */
+       buf->buf.v4l2_buf.sequence = queue->sequence++;
+       do_gettimeofday(&buf->buf.v4l2_buf.timestamp);
+
+       vb2_set_plane_payload(&buf->buf, 0, buf->bytesused);
+       vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE);
 
-       wake_up(&buf->wait);
        return nextbuf;
 }
 
index 1812a8e..8e76ce9 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/kernel.h>
 #include <linux/poll.h>
 #include <linux/videodev2.h>
+#include <media/videobuf2-core.h>
 
 /* Maximum frame size in bytes, for sanity checking. */
 #define UVC_MAX_FRAME_SIZE     (16*1024*1024)
@@ -25,42 +26,35 @@ enum uvc_buffer_state {
 };
 
 struct uvc_buffer {
-       unsigned long vma_use_count;
-       struct list_head stream;
-
-       /* Touched by interrupt handler. */
-       struct v4l2_buffer buf;
+       struct vb2_buffer buf;
        struct list_head queue;
-       wait_queue_head_t wait;
+
        enum uvc_buffer_state state;
+       void *mem;
+       unsigned int length;
+       unsigned int bytesused;
 };
 
-#define UVC_QUEUE_STREAMING            (1 << 0)
-#define UVC_QUEUE_DISCONNECTED         (1 << 1)
-#define UVC_QUEUE_DROP_INCOMPLETE      (1 << 2)
-#define UVC_QUEUE_PAUSED               (1 << 3)
+#define UVC_QUEUE_DISCONNECTED         (1 << 0)
+#define UVC_QUEUE_DROP_INCOMPLETE      (1 << 1)
+#define UVC_QUEUE_PAUSED               (1 << 2)
 
 struct uvc_video_queue {
-       enum v4l2_buf_type type;
+       struct vb2_queue queue;
+       struct mutex mutex;     /* Protects queue */
 
-       void *mem;
        unsigned int flags;
        __u32 sequence;
 
-       unsigned int count;
-       unsigned int buf_size;
        unsigned int buf_used;
-       struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS];
-       struct mutex mutex;     /* protects buffers and mainqueue */
-       spinlock_t irqlock;     /* protects irqqueue */
 
-       struct list_head mainqueue;
+       spinlock_t irqlock;     /* Protects flags and irqqueue */
        struct list_head irqqueue;
 };
 
 static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
 {
-       return queue->flags & UVC_QUEUE_STREAMING;
+       return vb2_is_streaming(&queue->queue);
 }
 
 #endif /* __KERNEL__ */
index 2ca9386..ad48e81 100644 (file)
@@ -41,9 +41,8 @@ uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data)
 
        req->length = min_t(unsigned int, uvc->event_length, data->length);
        req->zero = data->length < uvc->event_length;
-       req->dma = DMA_ADDR_INVALID;
 
-       memcpy(req->buf, data->data, data->length);
+       memcpy(req->buf, data->data, req->length);
 
        return usb_ep_queue(cdev->gadget->ep0, req, GFP_KERNEL);
 }
@@ -148,16 +147,13 @@ uvc_v4l2_release(struct file *file)
        uvc_function_disconnect(uvc);
 
        uvc_video_enable(video, 0);
-       mutex_lock(&video->queue.mutex);
-       if (uvc_free_buffers(&video->queue) < 0)
-               printk(KERN_ERR "uvc_v4l2_release: Unable to free "
-                               "buffers.\n");
-       mutex_unlock(&video->queue.mutex);
+       uvc_free_buffers(&video->queue);
 
        file->private_data = NULL;
        v4l2_fh_del(&handle->vfh);
        v4l2_fh_exit(&handle->vfh);
        kfree(handle);
+
        return 0;
 }
 
@@ -178,9 +174,9 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                struct v4l2_capability *cap = arg;
 
                memset(cap, 0, sizeof *cap);
-               strncpy(cap->driver, "g_uvc", sizeof(cap->driver));
-               strncpy(cap->card, cdev->gadget->name, sizeof(cap->card));
-               strncpy(cap->bus_info, dev_name(&cdev->gadget->dev),
+               strlcpy(cap->driver, "g_uvc", sizeof(cap->driver));
+               strlcpy(cap->card, cdev->gadget->name, sizeof(cap->card));
+               strlcpy(cap->bus_info, dev_name(&cdev->gadget->dev),
                        sizeof cap->bus_info);
                cap->version = DRIVER_VERSION_NUMBER;
                cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
@@ -192,7 +188,7 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        {
                struct v4l2_format *fmt = arg;
 
-               if (fmt->type != video->queue.type)
+               if (fmt->type != video->queue.queue.type)
                        return -EINVAL;
 
                return uvc_v4l2_get_format(video, fmt);
@@ -202,7 +198,7 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        {
                struct v4l2_format *fmt = arg;
 
-               if (fmt->type != video->queue.type)
+               if (fmt->type != video->queue.queue.type)
                        return -EINVAL;
 
                return uvc_v4l2_set_format(video, fmt);
@@ -213,16 +209,13 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        {
                struct v4l2_requestbuffers *rb = arg;
 
-               if (rb->type != video->queue.type ||
-                   rb->memory != V4L2_MEMORY_MMAP)
+               if (rb->type != video->queue.queue.type)
                        return -EINVAL;
 
-               ret = uvc_alloc_buffers(&video->queue, rb->count,
-                                       video->imagesize);
+               ret = uvc_alloc_buffers(&video->queue, rb);
                if (ret < 0)
                        return ret;
 
-               rb->count = ret;
                ret = 0;
                break;
        }
@@ -231,9 +224,6 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        {
                struct v4l2_buffer *buf = arg;
 
-               if (buf->type != video->queue.type)
-                       return -EINVAL;
-
                return uvc_query_buffer(&video->queue, buf);
        }
 
@@ -251,24 +241,36 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        {
                int *type = arg;
 
-               if (*type != video->queue.type)
+               if (*type != video->queue.queue.type)
                        return -EINVAL;
 
-               return uvc_video_enable(video, 1);
+               /* Enable UVC video. */
+               ret = uvc_video_enable(video, 1);
+               if (ret < 0)
+                       return ret;
+
+               /*
+                * Complete the alternate setting selection setup phase now that
+                * userspace is ready to provide video frames.
+                */
+               uvc_function_setup_continue(uvc);
+               uvc->state = UVC_STATE_STREAMING;
+
+               return 0;
        }
 
        case VIDIOC_STREAMOFF:
        {
                int *type = arg;
 
-               if (*type != video->queue.type)
+               if (*type != video->queue.queue.type)
                        return -EINVAL;
 
                return uvc_video_enable(video, 0);
        }
 
        /* Events */
-        case VIDIOC_DQEVENT:
+       case VIDIOC_DQEVENT:
        {
                struct v4l2_event *event = arg;
 
@@ -333,17 +335,21 @@ uvc_v4l2_poll(struct file *file, poll_table *wait)
 {
        struct video_device *vdev = video_devdata(file);
        struct uvc_device *uvc = video_get_drvdata(vdev);
-       struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);
-       unsigned int mask = 0;
 
-       poll_wait(file, &handle->vfh.wait, wait);
-       if (v4l2_event_pending(&handle->vfh))
-               mask |= POLLPRI;
+       return uvc_queue_poll(&uvc->video.queue, file, wait);
+}
 
-       mask |= uvc_queue_poll(&uvc->video.queue, file, wait);
+#ifndef CONFIG_MMU
+static unsigned long uvc_v4l2_get_unmapped_area(struct file *file,
+               unsigned long addr, unsigned long len, unsigned long pgoff,
+               unsigned long flags)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct uvc_device *uvc = video_get_drvdata(vdev);
 
-       return mask;
+       return uvc_queue_get_unmapped_area(&uvc->video.queue, pgoff);
 }
+#endif
 
 static struct v4l2_file_operations uvc_v4l2_fops = {
        .owner          = THIS_MODULE,
@@ -352,5 +358,8 @@ static struct v4l2_file_operations uvc_v4l2_fops = {
        .ioctl          = uvc_v4l2_ioctl,
        .mmap           = uvc_v4l2_mmap,
        .poll           = uvc_v4l2_poll,
+#ifndef CONFIG_MMU
+       .get_unmapped_area = uvc_v4l2_get_unmapped_area,
+#endif
 };
 
index b0e53a8..71e896d 100644 (file)
@@ -32,7 +32,7 @@ uvc_video_encode_header(struct uvc_video *video, struct uvc_buffer *buf,
        data[0] = 2;
        data[1] = UVC_STREAM_EOH | video->fid;
 
-       if (buf->buf.bytesused - video->queue.buf_used <= len - 2)
+       if (buf->bytesused - video->queue.buf_used <= len - 2)
                data[1] |= UVC_STREAM_EOF;
 
        return 2;
@@ -47,8 +47,8 @@ uvc_video_encode_data(struct uvc_video *video, struct uvc_buffer *buf,
        void *mem;
 
        /* Copy video data to the USB buffer. */
-       mem = queue->mem + buf->buf.m.offset + queue->buf_used;
-       nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used);
+       mem = buf->mem + queue->buf_used;
+       nbytes = min((unsigned int)len, buf->bytesused - queue->buf_used);
 
        memcpy(data, mem, nbytes);
        queue->buf_used += nbytes;
@@ -82,7 +82,7 @@ uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video,
        req->length = video->req_size - len;
        req->zero = video->payload_size == video->max_payload_size;
 
-       if (buf->buf.bytesused == video->queue.buf_used) {
+       if (buf->bytesused == video->queue.buf_used) {
                video->queue.buf_used = 0;
                buf->state = UVC_BUF_STATE_DONE;
                uvc_queue_next_buffer(&video->queue, buf);
@@ -92,7 +92,7 @@ uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video,
        }
 
        if (video->payload_size == video->max_payload_size ||
-           buf->buf.bytesused == video->queue.buf_used)
+           buf->bytesused == video->queue.buf_used)
                video->payload_size = 0;
 }
 
@@ -115,7 +115,7 @@ uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video,
 
        req->length = video->req_size - len;
 
-       if (buf->buf.bytesused == video->queue.buf_used) {
+       if (buf->bytesused == video->queue.buf_used) {
                video->queue.buf_used = 0;
                buf->state = UVC_BUF_STATE_DONE;
                uvc_queue_next_buffer(&video->queue, buf);
@@ -161,6 +161,7 @@ static void
 uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
 {
        struct uvc_video *video = req->context;
+       struct uvc_video_queue *queue = &video->queue;
        struct uvc_buffer *buf;
        unsigned long flags;
        int ret;
@@ -169,13 +170,15 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
        case 0:
                break;
 
-       case -ESHUTDOWN:
+       case -ESHUTDOWN:        /* disconnect from host. */
                printk(KERN_INFO "VS request cancelled.\n");
+               uvc_queue_cancel(queue, 1);
                goto requeue;
 
        default:
                printk(KERN_INFO "VS request completed with status %d.\n",
                        req->status);
+               uvc_queue_cancel(queue, 0);
                goto requeue;
        }
 
@@ -229,13 +232,18 @@ uvc_video_free_requests(struct uvc_video *video)
 static int
 uvc_video_alloc_requests(struct uvc_video *video)
 {
+       unsigned int req_size;
        unsigned int i;
        int ret = -ENOMEM;
 
        BUG_ON(video->req_size);
 
+       req_size = video->ep->maxpacket
+                * max_t(unsigned int, video->ep->maxburst, 1)
+                * (video->ep->mult + 1);
+
        for (i = 0; i < UVC_NUM_REQUESTS; ++i) {
-               video->req_buffer[i] = kmalloc(video->ep->maxpacket, GFP_KERNEL);
+               video->req_buffer[i] = kmalloc(req_size, GFP_KERNEL);
                if (video->req_buffer[i] == NULL)
                        goto error;
 
@@ -245,14 +253,14 @@ uvc_video_alloc_requests(struct uvc_video *video)
 
                video->req[i]->buf = video->req_buffer[i];
                video->req[i]->length = 0;
-               video->req[i]->dma = DMA_ADDR_INVALID;
                video->req[i]->complete = uvc_video_complete;
                video->req[i]->context = video;
 
                list_add_tail(&video->req[i]->list, &video->req_free);
        }
 
-       video->req_size = video->ep->maxpacket;
+       video->req_size = req_size;
+
        return 0;
 
 error:
@@ -309,7 +317,8 @@ uvc_video_pump(struct uvc_video *video)
                video->encode(req, video, buf);
 
                /* Queue the USB request */
-               if ((ret = usb_ep_queue(video->ep, req, GFP_KERNEL)) < 0) {
+               ret = usb_ep_queue(video->ep, req, GFP_ATOMIC);
+               if (ret < 0) {
                        printk(KERN_INFO "Failed to queue request (%d)\n", ret);
                        usb_ep_set_halt(video->ep);
                        spin_unlock_irqrestore(&video->queue.irqlock, flags);
index 2f68221..f7af098 100644 (file)
@@ -180,6 +180,7 @@ config USB_EHCI_TEGRA
        boolean "NVIDIA Tegra HCD support"
        depends on USB_EHCI_HCD && ARCH_TEGRA
        select USB_EHCI_ROOT_HUB_TT
+       select USB_PHY
        help
          This driver enables support for the internal USB Host Controllers
          found in NVIDIA Tegra SoCs. The controllers are EHCI compliant.
@@ -301,7 +302,6 @@ config USB_OHCI_HCD
        tristate "OHCI HCD support"
        depends on USB && USB_ARCH_HAS_OHCI
        select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
-       select USB_OTG_UTILS if ARCH_OMAP
        depends on USB_ISP1301 || !ARCH_LPC32XX
        ---help---
          The Open Host Controller Interface (OHCI) is a standard for accessing
index 88a49c8..ebf4103 100644 (file)
@@ -145,7 +145,7 @@ static int ehci_msm_probe(struct platform_device *pdev)
         * management.
         */
        phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
-       if (IS_ERR_OR_NULL(phy)) {
+       if (IS_ERR(phy)) {
                dev_err(&pdev->dev, "unable to find transceiver\n");
                ret = -ENODEV;
                goto put_hcd;
index 5cd9f96..4020629 100644 (file)
@@ -33,25 +33,17 @@ struct ehci_hcd_mv {
 
        struct mv_usb_platform_data *pdata;
 
-       /* clock source and total clock number */
-       unsigned int clknum;
-       struct clk *clk[0];
+       struct clk *clk;
 };
 
 static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv)
 {
-       unsigned int i;
-
-       for (i = 0; i < ehci_mv->clknum; i++)
-               clk_prepare_enable(ehci_mv->clk[i]);
+       clk_prepare_enable(ehci_mv->clk);
 }
 
 static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv)
 {
-       unsigned int i;
-
-       for (i = 0; i < ehci_mv->clknum; i++)
-               clk_disable_unprepare(ehci_mv->clk[i]);
+       clk_disable_unprepare(ehci_mv->clk);
 }
 
 static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv)
@@ -144,9 +136,8 @@ static int mv_ehci_probe(struct platform_device *pdev)
        struct ehci_hcd *ehci;
        struct ehci_hcd_mv *ehci_mv;
        struct resource *r;
-       int clk_i, retval = -ENODEV;
+       int retval = -ENODEV;
        u32 offset;
-       size_t size;
 
        if (!pdata) {
                dev_err(&pdev->dev, "missing platform_data\n");
@@ -160,8 +151,7 @@ static int mv_ehci_probe(struct platform_device *pdev)
        if (!hcd)
                return -ENOMEM;
 
-       size = sizeof(*ehci_mv) + sizeof(struct clk *) * pdata->clknum;
-       ehci_mv = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+       ehci_mv = devm_kzalloc(&pdev->dev, sizeof(*ehci_mv), GFP_KERNEL);
        if (ehci_mv == NULL) {
                dev_err(&pdev->dev, "cannot allocate ehci_hcd_mv\n");
                retval = -ENOMEM;
@@ -172,16 +162,11 @@ static int mv_ehci_probe(struct platform_device *pdev)
        ehci_mv->pdata = pdata;
        ehci_mv->hcd = hcd;
 
-       ehci_mv->clknum = pdata->clknum;
-       for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++) {
-               ehci_mv->clk[clk_i] =
-                   devm_clk_get(&pdev->dev, pdata->clkname[clk_i]);
-               if (IS_ERR(ehci_mv->clk[clk_i])) {
-                       dev_err(&pdev->dev, "error get clck \"%s\"\n",
-                               pdata->clkname[clk_i]);
-                       retval = PTR_ERR(ehci_mv->clk[clk_i]);
-                       goto err_clear_drvdata;
-               }
+       ehci_mv->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(ehci_mv->clk)) {
+               dev_err(&pdev->dev, "error getting clock\n");
+               retval = PTR_ERR(ehci_mv->clk);
+               goto err_clear_drvdata;
        }
 
        r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs");
@@ -240,12 +225,16 @@ static int mv_ehci_probe(struct platform_device *pdev)
 
        ehci_mv->mode = pdata->mode;
        if (ehci_mv->mode == MV_USB_MODE_OTG) {
-#ifdef CONFIG_USB_OTG_UTILS
                ehci_mv->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
-               if (IS_ERR_OR_NULL(ehci_mv->otg)) {
-                       dev_err(&pdev->dev,
-                               "unable to find transceiver\n");
-                       retval = -ENODEV;
+               if (IS_ERR(ehci_mv->otg)) {
+                       retval = PTR_ERR(ehci_mv->otg);
+
+                       if (retval == -ENXIO)
+                               dev_info(&pdev->dev, "MV_USB_MODE_OTG "
+                                               "must have CONFIG_USB_PHY enabled\n");
+                       else
+                               dev_err(&pdev->dev,
+                                               "unable to find transceiver\n");
                        goto err_disable_clk;
                }
 
@@ -258,11 +247,6 @@ static int mv_ehci_probe(struct platform_device *pdev)
                }
                /* otg will enable clock before use as host */
                mv_ehci_disable(ehci_mv);
-#else
-               dev_info(&pdev->dev, "MV_USB_MODE_OTG "
-                        "must have CONFIG_USB_OTG_UTILS enabled\n");
-               goto err_disable_clk;
-#endif
        } else {
                if (pdata->set_vbus)
                        pdata->set_vbus(1);
index 738490e..43a2a16 100644 (file)
@@ -140,7 +140,7 @@ static int s5p_ehci_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
-       if (IS_ERR_OR_NULL(phy)) {
+       if (IS_ERR(phy)) {
                /* Fallback to pdata */
                if (!pdata) {
                        dev_warn(&pdev->dev, "no platform data or transceiver defined\n");
index 4f3cfb8..ed201ae 100644 (file)
@@ -773,16 +773,14 @@ static int tegra_ehci_probe(struct platform_device *pdev)
                goto fail_phy;
        }
 
-#ifdef CONFIG_USB_OTG_UTILS
        if (pdata->operating_mode == TEGRA_USB_OTG) {
                tegra->transceiver =
                        devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
-               if (!IS_ERR_OR_NULL(tegra->transceiver))
+               if (!IS_ERR(tegra->transceiver))
                        otg_set_host(tegra->transceiver->otg, &hcd->self);
        } else {
                tegra->transceiver = ERR_PTR(-ENODEV);
        }
-#endif
 
        err = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (err) {
@@ -801,10 +799,8 @@ static int tegra_ehci_probe(struct platform_device *pdev)
        return err;
 
 fail:
-#ifdef CONFIG_USB_OTG_UTILS
-       if (!IS_ERR_OR_NULL(tegra->transceiver))
+       if (!IS_ERR(tegra->transceiver))
                otg_set_host(tegra->transceiver->otg, NULL);
-#endif
 fail_phy:
        usb_phy_shutdown(hcd->phy);
 fail_io:
@@ -823,10 +819,8 @@ static int tegra_ehci_remove(struct platform_device *pdev)
        pm_runtime_disable(&pdev->dev);
        pm_runtime_put_noidle(&pdev->dev);
 
-#ifdef CONFIG_USB_OTG_UTILS
-       if (!IS_ERR_OR_NULL(tegra->transceiver))
+       if (!IS_ERR(tegra->transceiver))
                otg_set_host(tegra->transceiver->otg, NULL);
-#endif
 
        usb_phy_shutdown(hcd->phy);
        usb_remove_hcd(hcd);
index e3b7e85..4b469e0 100644 (file)
@@ -128,7 +128,7 @@ static int exynos_ohci_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
-       if (IS_ERR_OR_NULL(phy)) {
+       if (IS_ERR(phy)) {
                /* Fallback to pdata */
                if (!pdata) {
                        dev_warn(&pdev->dev, "no platform data or transceiver defined\n");
index 05e5143..47442d3 100644 (file)
@@ -7,7 +7,6 @@
 config USB_MUSB_HDRC
        tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
        depends on USB && USB_GADGET
-       select USB_OTG_UTILS
        help
          Say Y here if your system has a dual role high speed USB
          controller based on the Mentor Graphics silicon IP.  Then
@@ -34,10 +33,12 @@ choice
 config USB_MUSB_DAVINCI
        tristate "DaVinci"
        depends on ARCH_DAVINCI_DMx
+       depends on BROKEN
 
 config USB_MUSB_DA8XX
        tristate "DA8xx/OMAP-L1x"
        depends on ARCH_DAVINCI_DA8XX
+       depends on BROKEN
 
 config USB_MUSB_TUSB6010
        tristate "TUSB6010"
@@ -53,7 +54,6 @@ config USB_MUSB_AM35X
 
 config USB_MUSB_DSPS
        tristate "TI DSPS platforms"
-       depends on SOC_TI81XX || SOC_AM33XX
 
 config USB_MUSB_BLACKFIN
        tristate "Blackfin"
@@ -61,12 +61,12 @@ config USB_MUSB_BLACKFIN
 
 config USB_MUSB_UX500
        tristate "U8500 and U5500"
-       depends on (ARCH_U8500 && AB8500_USB)
 
 endchoice
 
 choice
        prompt 'MUSB DMA mode'
+       default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM
        default USB_UX500_DMA if USB_MUSB_UX500
        default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN
        default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI
index 59eea21..2231850 100644 (file)
@@ -149,7 +149,7 @@ static void otg_timer(unsigned long _musb)
         */
        devctl = musb_readb(mregs, MUSB_DEVCTL);
        dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
-               otg_state_string(musb->xceiv->state));
+               usb_otg_state_string(musb->xceiv->state));
 
        spin_lock_irqsave(&musb->lock, flags);
        switch (musb->xceiv->state) {
@@ -195,7 +195,7 @@ static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout)
        if (musb->is_active || (musb->a_wait_bcon == 0 &&
                                musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
                dev_dbg(musb->controller, "%s active, deleting timer\n",
-                       otg_state_string(musb->xceiv->state));
+                       usb_otg_state_string(musb->xceiv->state));
                del_timer(&otg_workaround);
                last_timer = jiffies;
                return;
@@ -208,7 +208,7 @@ static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout)
        last_timer = timeout;
 
        dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
-               otg_state_string(musb->xceiv->state),
+               usb_otg_state_string(musb->xceiv->state),
                jiffies_to_msecs(timeout - jiffies));
        mod_timer(&otg_workaround, timeout);
 }
@@ -298,7 +298,7 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci)
                /* NOTE: this must complete power-on within 100 ms. */
                dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
                                drvvbus ? "on" : "off",
-                               otg_state_string(musb->xceiv->state),
+                               usb_otg_state_string(musb->xceiv->state),
                                err ? " ERROR" : "",
                                devctl);
                ret = IRQ_HANDLED;
index dbb31b3..5e63b16 100644 (file)
@@ -280,13 +280,13 @@ static void musb_conn_timer_handler(unsigned long _musb)
                break;
        default:
                dev_dbg(musb->controller, "%s state not handled\n",
-                       otg_state_string(musb->xceiv->state));
+                       usb_otg_state_string(musb->xceiv->state));
                break;
        }
        spin_unlock_irqrestore(&musb->lock, flags);
 
        dev_dbg(musb->controller, "state is %s\n",
-               otg_state_string(musb->xceiv->state));
+               usb_otg_state_string(musb->xceiv->state));
 }
 
 static void bfin_musb_enable(struct musb *musb)
@@ -307,7 +307,7 @@ static void bfin_musb_set_vbus(struct musb *musb, int is_on)
 
        dev_dbg(musb->controller, "VBUS %s, devctl %02x "
                /* otg %3x conf %08x prcm %08x */ "\n",
-               otg_state_string(musb->xceiv->state),
+               usb_otg_state_string(musb->xceiv->state),
                musb_readb(musb->mregs, MUSB_DEVCTL));
 }
 
index f522000..9db211e 100644 (file)
@@ -435,7 +435,6 @@ cppi_rndis_update(struct cppi_channel *c, int is_rx,
        }
 }
 
-#ifdef CONFIG_USB_MUSB_DEBUG
 static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd)
 {
        pr_debug("RXBD/%s %08x: "
@@ -444,21 +443,16 @@ static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd)
                        bd->hw_next, bd->hw_bufp, bd->hw_off_len,
                        bd->hw_options);
 }
-#endif
 
 static void cppi_dump_rxq(int level, const char *tag, struct cppi_channel *rx)
 {
-#ifdef CONFIG_USB_MUSB_DEBUG
        struct cppi_descriptor  *bd;
 
-       if (!_dbg_level(level))
-               return;
        cppi_dump_rx(level, rx, tag);
        if (rx->last_processed)
                cppi_dump_rxbd("last", rx->last_processed);
        for (bd = rx->head; bd; bd = bd->next)
                cppi_dump_rxbd("active", bd);
-#endif
 }
 
 
@@ -784,6 +778,7 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
        void __iomem            *tibase = musb->ctrl_base;
        int                     is_rndis = 0;
        struct cppi_rx_stateram __iomem *rx_ram = rx->state_ram;
+       struct cppi_descriptor  *d;
 
        if (onepacket) {
                /* almost every USB driver, host or peripheral side */
@@ -897,14 +892,8 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
        bd->hw_options |= CPPI_SOP_SET;
        tail->hw_options |= CPPI_EOP_SET;
 
-#ifdef CONFIG_USB_MUSB_DEBUG
-       if (_dbg_level(5)) {
-               struct cppi_descriptor  *d;
-
-               for (d = rx->head; d; d = d->next)
-                       cppi_dump_rxbd("S", d);
-       }
-#endif
+       for (d = rx->head; d; d = d->next)
+               cppi_dump_rxbd("S", d);
 
        /* in case the preceding transfer left some state... */
        tail = rx->last_processed;
index 41613a2..b903b74 100644 (file)
@@ -198,7 +198,7 @@ static void otg_timer(unsigned long _musb)
         */
        devctl = musb_readb(mregs, MUSB_DEVCTL);
        dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
-               otg_state_string(musb->xceiv->state));
+               usb_otg_state_string(musb->xceiv->state));
 
        spin_lock_irqsave(&musb->lock, flags);
        switch (musb->xceiv->state) {
@@ -267,7 +267,7 @@ static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout)
        if (musb->is_active || (musb->a_wait_bcon == 0 &&
                                musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
                dev_dbg(musb->controller, "%s active, deleting timer\n",
-                       otg_state_string(musb->xceiv->state));
+                       usb_otg_state_string(musb->xceiv->state));
                del_timer(&otg_workaround);
                last_timer = jiffies;
                return;
@@ -280,7 +280,7 @@ static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout)
        last_timer = timeout;
 
        dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
-               otg_state_string(musb->xceiv->state),
+               usb_otg_state_string(musb->xceiv->state),
                jiffies_to_msecs(timeout - jiffies));
        mod_timer(&otg_workaround, timeout);
 }
@@ -360,7 +360,7 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
 
                dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
                                drvvbus ? "on" : "off",
-                               otg_state_string(musb->xceiv->state),
+                               usb_otg_state_string(musb->xceiv->state),
                                err ? " ERROR" : "",
                                devctl);
                ret = IRQ_HANDLED;
index e040d91..bea6cc3 100644 (file)
@@ -215,7 +215,7 @@ static void otg_timer(unsigned long _musb)
         */
        devctl = musb_readb(mregs, MUSB_DEVCTL);
        dev_dbg(musb->controller, "poll devctl %02x (%s)\n", devctl,
-               otg_state_string(musb->xceiv->state));
+               usb_otg_state_string(musb->xceiv->state));
 
        spin_lock_irqsave(&musb->lock, flags);
        switch (musb->xceiv->state) {
@@ -349,7 +349,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
                davinci_musb_source_power(musb, drvvbus, 0);
                dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
                                drvvbus ? "on" : "off",
-                               otg_state_string(musb->xceiv->state),
+                               usb_otg_state_string(musb->xceiv->state),
                                err ? " ERROR" : "",
                                devctl);
                retval = IRQ_HANDLED;
index daec6e0..37a261a 100644 (file)
@@ -372,13 +372,13 @@ static void musb_otg_timer_func(unsigned long data)
        case OTG_STATE_A_SUSPEND:
        case OTG_STATE_A_WAIT_BCON:
                dev_dbg(musb->controller, "HNP: %s timeout\n",
-                       otg_state_string(musb->xceiv->state));
+                       usb_otg_state_string(musb->xceiv->state));
                musb_platform_set_vbus(musb, 0);
                musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
                break;
        default:
                dev_dbg(musb->controller, "HNP: Unhandled mode %s\n",
-                       otg_state_string(musb->xceiv->state));
+                       usb_otg_state_string(musb->xceiv->state));
        }
        musb->ignore_disconnect = 0;
        spin_unlock_irqrestore(&musb->lock, flags);
@@ -393,13 +393,14 @@ void musb_hnp_stop(struct musb *musb)
        void __iomem    *mbase = musb->mregs;
        u8      reg;
 
-       dev_dbg(musb->controller, "HNP: stop from %s\n", otg_state_string(musb->xceiv->state));
+       dev_dbg(musb->controller, "HNP: stop from %s\n",
+                       usb_otg_state_string(musb->xceiv->state));
 
        switch (musb->xceiv->state) {
        case OTG_STATE_A_PERIPHERAL:
                musb_g_disconnect(musb);
                dev_dbg(musb->controller, "HNP: back to %s\n",
-                       otg_state_string(musb->xceiv->state));
+                       usb_otg_state_string(musb->xceiv->state));
                break;
        case OTG_STATE_B_HOST:
                dev_dbg(musb->controller, "HNP: Disabling HR\n");
@@ -413,7 +414,7 @@ void musb_hnp_stop(struct musb *musb)
                break;
        default:
                dev_dbg(musb->controller, "HNP: Stopping in unknown state %s\n",
-                       otg_state_string(musb->xceiv->state));
+                       usb_otg_state_string(musb->xceiv->state));
        }
 
        /*
@@ -451,7 +452,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
         */
        if (int_usb & MUSB_INTR_RESUME) {
                handled = IRQ_HANDLED;
-               dev_dbg(musb->controller, "RESUME (%s)\n", otg_state_string(musb->xceiv->state));
+               dev_dbg(musb->controller, "RESUME (%s)\n", usb_otg_state_string(musb->xceiv->state));
 
                if (devctl & MUSB_DEVCTL_HM) {
                        void __iomem *mbase = musb->mregs;
@@ -493,7 +494,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                        default:
                                WARNING("bogus %s RESUME (%s)\n",
                                        "host",
-                                       otg_state_string(musb->xceiv->state));
+                                       usb_otg_state_string(musb->xceiv->state));
                        }
                } else {
                        switch (musb->xceiv->state) {
@@ -522,7 +523,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                        default:
                                WARNING("bogus %s RESUME (%s)\n",
                                        "peripheral",
-                                       otg_state_string(musb->xceiv->state));
+                                       usb_otg_state_string(musb->xceiv->state));
                        }
                }
        }
@@ -538,7 +539,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                }
 
                dev_dbg(musb->controller, "SESSION_REQUEST (%s)\n",
-                       otg_state_string(musb->xceiv->state));
+                       usb_otg_state_string(musb->xceiv->state));
 
                /* IRQ arrives from ID pin sense or (later, if VBUS power
                 * is removed) SRP.  responses are time critical:
@@ -602,8 +603,9 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                        break;
                }
 
-               dev_dbg(musb->controller, "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n",
-                               otg_state_string(musb->xceiv->state),
+               dev_printk(ignore ? KERN_DEBUG : KERN_ERR, musb->controller,
+                               "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n",
+                               usb_otg_state_string(musb->xceiv->state),
                                devctl,
                                ({ char *s;
                                switch (devctl & MUSB_DEVCTL_VBUS) {
@@ -628,7 +630,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
 
        if (int_usb & MUSB_INTR_SUSPEND) {
                dev_dbg(musb->controller, "SUSPEND (%s) devctl %02x\n",
-                       otg_state_string(musb->xceiv->state), devctl);
+                       usb_otg_state_string(musb->xceiv->state), devctl);
                handled = IRQ_HANDLED;
 
                switch (musb->xceiv->state) {
@@ -745,12 +747,12 @@ b_host:
                        usb_hcd_resume_root_hub(hcd);
 
                dev_dbg(musb->controller, "CONNECT (%s) devctl %02x\n",
-                               otg_state_string(musb->xceiv->state), devctl);
+                               usb_otg_state_string(musb->xceiv->state), devctl);
        }
 
        if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) {
                dev_dbg(musb->controller, "DISCONNECT (%s) as %s, devctl %02x\n",
-                               otg_state_string(musb->xceiv->state),
+                               usb_otg_state_string(musb->xceiv->state),
                                MUSB_MODE(musb), devctl);
                handled = IRQ_HANDLED;
 
@@ -787,7 +789,7 @@ b_host:
                        break;
                default:
                        WARNING("unhandled DISCONNECT transition (%s)\n",
-                               otg_state_string(musb->xceiv->state));
+                               usb_otg_state_string(musb->xceiv->state));
                        break;
                }
        }
@@ -813,7 +815,7 @@ b_host:
                        }
                } else {
                        dev_dbg(musb->controller, "BUS RESET as %s\n",
-                               otg_state_string(musb->xceiv->state));
+                               usb_otg_state_string(musb->xceiv->state));
                        switch (musb->xceiv->state) {
                        case OTG_STATE_A_SUSPEND:
                                /* We need to ignore disconnect on suspend
@@ -826,7 +828,7 @@ b_host:
                        case OTG_STATE_A_WAIT_BCON:     /* OPT TD.4.7-900ms */
                                /* never use invalid T(a_wait_bcon) */
                                dev_dbg(musb->controller, "HNP: in %s, %d msec timeout\n",
-                                       otg_state_string(musb->xceiv->state),
+                                       usb_otg_state_string(musb->xceiv->state),
                                        TA_WAIT_BCON(musb));
                                mod_timer(&musb->otg_timer, jiffies
                                        + msecs_to_jiffies(TA_WAIT_BCON(musb)));
@@ -838,7 +840,7 @@ b_host:
                                break;
                        case OTG_STATE_B_WAIT_ACON:
                                dev_dbg(musb->controller, "HNP: RESET (%s), to b_peripheral\n",
-                                       otg_state_string(musb->xceiv->state));
+                                       usb_otg_state_string(musb->xceiv->state));
                                musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
                                musb_g_reset(musb);
                                break;
@@ -850,7 +852,7 @@ b_host:
                                break;
                        default:
                                dev_dbg(musb->controller, "Unhandled BUS RESET as %s\n",
-                                       otg_state_string(musb->xceiv->state));
+                                       usb_otg_state_string(musb->xceiv->state));
                        }
                }
        }
@@ -1632,7 +1634,7 @@ musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
        int ret = -EINVAL;
 
        spin_lock_irqsave(&musb->lock, flags);
-       ret = sprintf(buf, "%s\n", otg_state_string(musb->xceiv->state));
+       ret = sprintf(buf, "%s\n", usb_otg_state_string(musb->xceiv->state));
        spin_unlock_irqrestore(&musb->lock, flags);
 
        return ret;
@@ -1951,9 +1953,13 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
                musb_write_ulpi_buscontrol(musb->mregs, busctl);
        }
 
-       MUSB_DEV_MODE(musb);
-       musb->xceiv->otg->default_a = 0;
-       musb->xceiv->state = OTG_STATE_B_IDLE;
+       if (musb->xceiv->otg->default_a) {
+               MUSB_HST_MODE(musb);
+               musb->xceiv->state = OTG_STATE_A_IDLE;
+       } else {
+               MUSB_DEV_MODE(musb);
+               musb->xceiv->state = OTG_STATE_B_IDLE;
+       }
 
        status = musb_gadget_setup(musb);
 
@@ -2008,7 +2014,6 @@ static int musb_probe(struct platform_device *pdev)
 {
        struct device   *dev = &pdev->dev;
        int             irq = platform_get_irq_byname(pdev, "mc");
-       int             status;
        struct resource *iomem;
        void __iomem    *base;
 
@@ -2016,24 +2021,17 @@ static int musb_probe(struct platform_device *pdev)
        if (!iomem || irq <= 0)
                return -ENODEV;
 
-       base = ioremap(iomem->start, resource_size(iomem));
-       if (!base) {
-               dev_err(dev, "ioremap failed\n");
-               return -ENOMEM;
-       }
+       base = devm_ioremap_resource(dev, iomem);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
 
-       status = musb_init_controller(dev, irq, base);
-       if (status < 0)
-               iounmap(base);
-
-       return status;
+       return musb_init_controller(dev, irq, base);
 }
 
 static int musb_remove(struct platform_device *pdev)
 {
        struct device   *dev = &pdev->dev;
        struct musb     *musb = dev_to_musb(dev);
-       void __iomem    *ctrl_base = musb->ctrl_base;
 
        /* this gets called on rmmod.
         *  - Host mode: host may still be active
@@ -2044,7 +2042,6 @@ static int musb_remove(struct platform_device *pdev)
        musb_shutdown(pdev);
 
        musb_free(musb);
-       iounmap(ctrl_base);
        device_init_wakeup(dev, 0);
 #ifndef CONFIG_MUSB_PIO_ONLY
        dma_set_mask(dev, *dev->parent->dma_mask);
@@ -2293,8 +2290,6 @@ static int __init musb_init(void)
        if (usb_disabled())
                return 0;
 
-       pr_info("%s: version " MUSB_VERSION ", ?dma?, otg (peripheral+host)\n",
-               musb_driver_name);
        return platform_driver_register(&musb_driver);
 }
 module_init(musb_init);
index 6bb8971..3a18e44 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/module.h>
 #include <linux/usb/nop-usb-xceiv.h>
 #include <linux/platform_data/usb-omap.h>
+#include <linux/sizes.h>
 
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -224,7 +225,7 @@ static void otg_timer(unsigned long _musb)
         */
        devctl = dsps_readb(mregs, MUSB_DEVCTL);
        dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
-                               otg_state_string(musb->xceiv->state));
+                               usb_otg_state_string(musb->xceiv->state));
 
        spin_lock_irqsave(&musb->lock, flags);
        switch (musb->xceiv->state) {
@@ -273,7 +274,7 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
        if (musb->is_active || (musb->a_wait_bcon == 0 &&
                                musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
                dev_dbg(musb->controller, "%s active, deleting timer\n",
-                               otg_state_string(musb->xceiv->state));
+                               usb_otg_state_string(musb->xceiv->state));
                del_timer(&glue->timer[pdev->id]);
                glue->last_timer[pdev->id] = jiffies;
                return;
@@ -288,7 +289,7 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
        glue->last_timer[pdev->id] = timeout;
 
        dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
-               otg_state_string(musb->xceiv->state),
+               usb_otg_state_string(musb->xceiv->state),
                        jiffies_to_msecs(timeout - jiffies));
        mod_timer(&glue->timer[pdev->id], timeout);
 }
@@ -334,7 +335,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
         * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
         * Also, DRVVBUS pulses for SRP (but not at 5V) ...
         */
-       if (usbintr & MUSB_INTR_BABBLE)
+       if (is_host_active(musb) && usbintr & MUSB_INTR_BABBLE)
                pr_info("CAUTION: musb: Babble Interrupt Occurred\n");
 
        if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) {
@@ -377,7 +378,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
                /* NOTE: this must complete power-on within 100 ms. */
                dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
                                drvvbus ? "on" : "off",
-                               otg_state_string(musb->xceiv->state),
+                               usb_otg_state_string(musb->xceiv->state),
                                err ? " ERROR" : "",
                                devctl);
                ret = IRQ_HANDLED;
@@ -596,14 +597,13 @@ err0:
 
 static int dsps_probe(struct platform_device *pdev)
 {
-       struct device_node *np = pdev->dev.of_node;
        const struct of_device_id *match;
        const struct dsps_musb_wrapper *wrp;
        struct dsps_glue *glue;
        struct resource *iomem;
        int ret, i;
 
-       match = of_match_node(musb_dsps_of_match, np);
+       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;
index 83edded..ba70923 100644 (file)
 #include "musb_core.h"
 
 
-/* MUSB PERIPHERAL status 3-mar-2006:
- *
- * - EP0 seems solid.  It passes both USBCV and usbtest control cases.
- *   Minor glitches:
- *
- *     + remote wakeup to Linux hosts work, but saw USBCV failures;
- *       in one test run (operator error?)
- *     + endpoint halt tests -- in both usbtest and usbcv -- seem
- *       to break when dma is enabled ... is something wrongly
- *       clearing SENDSTALL?
- *
- * - Mass storage behaved ok when last tested.  Network traffic patterns
- *   (with lots of short transfers etc) need retesting; they turn up the
- *   worst cases of the DMA, since short packets are typical but are not
- *   required.
- *
- * - TX/IN
- *     + both pio and dma behave in with network and g_zero tests
- *     + no cppi throughput issues other than no-hw-queueing
- *     + failed with FLAT_REG (DaVinci)
- *     + seems to behave with double buffering, PIO -and- CPPI
- *     + with gadgetfs + AIO, requests got lost?
- *
- * - RX/OUT
- *     + both pio and dma behave in with network and g_zero tests
- *     + dma is slow in typical case (short_not_ok is clear)
- *     + double buffering ok with PIO
- *     + double buffering *FAILS* with CPPI, wrong data bytes sometimes
- *     + request lossage observed with gadgetfs
- *
- * - ISO not tested ... might work, but only weakly isochronous
- *
- * - Gadget driver disabling of softconnect during bind() is ignored; so
- *   drivers can't hold off host requests until userspace is ready.
- *   (Workaround:  they can turn it off later.)
- *
- * - PORTABILITY (assumes PIO works):
- *     + DaVinci, basically works with cppi dma
- *     + OMAP 2430, ditto with mentor dma
- *     + TUSB 6010, platform-specific dma in the works
- */
-
 /* ----------------------------------------------------------------------- */
 
 #define is_buffer_mapped(req) (is_dma_capable() && \
@@ -280,41 +238,6 @@ static inline int max_ep_writesize(struct musb *musb, struct musb_ep *ep)
                return ep->packet_sz;
 }
 
-
-#ifdef CONFIG_USB_INVENTRA_DMA
-
-/* Peripheral tx (IN) using Mentor DMA works as follows:
-       Only mode 0 is used for transfers <= wPktSize,
-       mode 1 is used for larger transfers,
-
-       One of the following happens:
-       - Host sends IN token which causes an endpoint interrupt
-               -> TxAvail
-                       -> if DMA is currently busy, exit.
-                       -> if queue is non-empty, txstate().
-
-       - Request is queued by the gadget driver.
-               -> if queue was previously empty, txstate()
-
-       txstate()
-               -> start
-                 /\    -> setup DMA
-                 |     (data is transferred to the FIFO, then sent out when
-                 |     IN token(s) are recd from Host.
-                 |             -> DMA interrupt on completion
-                 |                calls TxAvail.
-                 |                   -> stop DMA, ~DMAENAB,
-                 |                   -> set TxPktRdy for last short pkt or zlp
-                 |                   -> Complete Request
-                 |                   -> Continue next request (call txstate)
-                 |___________________________________|
-
- * Non-Mentor DMA engines can of course work differently, such as by
- * upleveling from irq-per-packet to irq-per-buffer.
- */
-
-#endif
-
 /*
  * An endpoint is transmitting data. This can be called either from
  * the IRQ routine or from ep.queue() to kickstart a request on an
@@ -621,37 +544,6 @@ void musb_g_tx(struct musb *musb, u8 epnum)
 
 /* ------------------------------------------------------------ */
 
-#ifdef CONFIG_USB_INVENTRA_DMA
-
-/* Peripheral rx (OUT) using Mentor DMA works as follows:
-       - Only mode 0 is used.
-
-       - Request is queued by the gadget class driver.
-               -> if queue was previously empty, rxstate()
-
-       - Host sends OUT token which causes an endpoint interrupt
-         /\      -> RxReady
-         |           -> if request queued, call rxstate
-         |             /\      -> setup DMA
-         |             |            -> DMA interrupt on completion
-         |             |               -> RxReady
-         |             |                     -> stop DMA
-         |             |                     -> ack the read
-         |             |                     -> if data recd = max expected
-         |             |                               by the request, or host
-         |             |                               sent a short packet,
-         |             |                               complete the request,
-         |             |                               and start the next one.
-         |             |_____________________________________|
-         |                                      else just wait for the host
-         |                                         to send the next OUT token.
-         |__________________________________________________|
-
- * Non-Mentor DMA engines can of course work differently.
- */
-
-#endif
-
 /*
  * Context: controller locked, IRQs blocked, endpoint selected
  */
@@ -740,7 +632,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                                struct dma_controller   *c;
                                struct dma_channel      *channel;
                                int                     use_dma = 0;
-                               int transfer_size;
+                               unsigned int transfer_size;
 
                                c = musb->dma_controller;
                                channel = musb_ep->dma;
@@ -782,10 +674,11 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                                                csr | MUSB_RXCSR_DMAMODE);
                                        musb_writew(epio, MUSB_RXCSR, csr);
 
-                                       transfer_size = min(request->length - request->actual,
+                                       transfer_size = min_t(unsigned int,
+                                                       request->length -
+                                                       request->actual,
                                                        channel->max_len);
                                        musb_ep->dma->desired_mode = 1;
-
                                } else {
                                        if (!musb_ep->hb_mult &&
                                                musb_ep->hw_ep->rx_double_buffered)
@@ -815,7 +708,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
 
                                struct dma_controller *c;
                                struct dma_channel *channel;
-                               int transfer_size = 0;
+                               unsigned int transfer_size = 0;
 
                                c = musb->dma_controller;
                                channel = musb_ep->dma;
@@ -824,11 +717,13 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                                if (fifo_count < musb_ep->packet_sz)
                                        transfer_size = fifo_count;
                                else if (request->short_not_ok)
-                                       transfer_size = min(request->length -
+                                       transfer_size = min_t(unsigned int,
+                                                       request->length -
                                                        request->actual,
                                                        channel->max_len);
                                else
-                                       transfer_size = min(request->length -
+                                       transfer_size = min_t(unsigned int,
+                                                       request->length -
                                                        request->actual,
                                                        (unsigned)fifo_count);
 
@@ -1681,7 +1576,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
                goto done;
        default:
                dev_dbg(musb->controller, "Unhandled wake: %s\n",
-                       otg_state_string(musb->xceiv->state));
+                       usb_otg_state_string(musb->xceiv->state));
                goto done;
        }
 
@@ -1801,13 +1696,6 @@ static const struct usb_gadget_ops musb_gadget_operations = {
  * all peripheral ports are external...
  */
 
-static void musb_gadget_release(struct device *dev)
-{
-       /* kref_put(WHAT) */
-       dev_dbg(dev, "%s\n", __func__);
-}
-
-
 static void
 init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in)
 {
@@ -1892,12 +1780,7 @@ int musb_gadget_setup(struct musb *musb)
        musb->g.speed = USB_SPEED_UNKNOWN;
 
        /* this "gadget" abstracts/virtualizes the controller */
-       dev_set_name(&musb->g.dev, "gadget");
-       musb->g.dev.parent = musb->controller;
-       musb->g.dev.dma_mask = musb->controller->dma_mask;
-       musb->g.dev.release = musb_gadget_release;
        musb->g.name = musb_driver_name;
-
        musb->g.is_otg = 1;
 
        musb_g_init_endpoints(musb);
@@ -1905,11 +1788,6 @@ int musb_gadget_setup(struct musb *musb)
        musb->is_active = 0;
        musb_platform_try_idle(musb, 0);
 
-       status = device_register(&musb->g.dev);
-       if (status != 0) {
-               put_device(&musb->g.dev);
-               return status;
-       }
        status = usb_add_gadget_udc(musb->controller, &musb->g);
        if (status)
                goto err;
@@ -1924,8 +1802,6 @@ err:
 void musb_gadget_cleanup(struct musb *musb)
 {
        usb_del_gadget_udc(&musb->g);
-       if (musb->g.dev.parent)
-               device_unregister(&musb->g.dev);
 }
 
 /*
@@ -1977,9 +1853,8 @@ static int musb_gadget_start(struct usb_gadget *g,
                goto err;
        }
 
-       if ((musb->xceiv->last_event == USB_EVENT_ID)
-                               && otg->set_vbus)
-               otg_set_vbus(otg, 1);
+       if (musb->xceiv->last_event == USB_EVENT_ID)
+               musb_platform_set_vbus(musb, 1);
 
        hcd->self.uses_pio_for_control = 1;
 
@@ -2063,6 +1938,7 @@ static int musb_gadget_stop(struct usb_gadget *g,
        dev_dbg(musb->controller, "unregistering driver %s\n", driver->function);
 
        musb->is_active = 0;
+       musb->gadget_driver = NULL;
        musb_platform_try_idle(musb, 0);
        spin_unlock_irqrestore(&musb->lock, flags);
 
@@ -2099,7 +1975,7 @@ void musb_g_resume(struct musb *musb)
                break;
        default:
                WARNING("unhandled RESUME transition (%s)\n",
-                               otg_state_string(musb->xceiv->state));
+                               usb_otg_state_string(musb->xceiv->state));
        }
 }
 
@@ -2129,7 +2005,7 @@ void musb_g_suspend(struct musb *musb)
                 * A_PERIPHERAL may need care too
                 */
                WARNING("unhandled SUSPEND transition (%s)\n",
-                               otg_state_string(musb->xceiv->state));
+                               usb_otg_state_string(musb->xceiv->state));
        }
 }
 
@@ -2163,7 +2039,7 @@ void musb_g_disconnect(struct musb *musb)
        switch (musb->xceiv->state) {
        default:
                dev_dbg(musb->controller, "Unhandled disconnect %s, setting a_idle\n",
-                       otg_state_string(musb->xceiv->state));
+                       usb_otg_state_string(musb->xceiv->state));
                musb->xceiv->state = OTG_STATE_A_IDLE;
                MUSB_HST_MODE(musb);
                break;
index c9c1ac4..2af45a0 100644 (file)
@@ -505,8 +505,10 @@ static void ep0_rxstate(struct musb *musb)
                        req->status = -EOVERFLOW;
                        count = len;
                }
-               musb_read_fifo(&musb->endpoints[0], count, buf);
-               req->actual += count;
+               if (count > 0) {
+                       musb_read_fifo(&musb->endpoints[0], count, buf);
+                       req->actual += count;
+               }
                csr = MUSB_CSR0_P_SVDRXPKTRDY;
                if (count < 64 || req->actual == req->length) {
                        musb->ep0_state = MUSB_EP0_STAGE_STATUSIN;
index 1ce1fcf..8914dec 100644 (file)
@@ -2453,7 +2453,7 @@ static int musb_bus_suspend(struct usb_hcd *hcd)
 
        if (musb->is_active) {
                WARNING("trying to suspend as %s while active\n",
-                               otg_state_string(musb->xceiv->state));
+                               usb_otg_state_string(musb->xceiv->state));
                return -EBUSY;
        } else
                return 0;
@@ -2465,6 +2465,118 @@ static int musb_bus_resume(struct usb_hcd *hcd)
        return 0;
 }
 
+
+#ifndef CONFIG_MUSB_PIO_ONLY
+
+#define MUSB_USB_DMA_ALIGN 4
+
+struct musb_temp_buffer {
+       void *kmalloc_ptr;
+       void *old_xfer_buffer;
+       u8 data[0];
+};
+
+static void musb_free_temp_buffer(struct urb *urb)
+{
+       enum dma_data_direction dir;
+       struct musb_temp_buffer *temp;
+
+       if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
+               return;
+
+       dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+       temp = container_of(urb->transfer_buffer, struct musb_temp_buffer,
+                           data);
+
+       if (dir == DMA_FROM_DEVICE) {
+               memcpy(temp->old_xfer_buffer, temp->data,
+                      urb->transfer_buffer_length);
+       }
+       urb->transfer_buffer = temp->old_xfer_buffer;
+       kfree(temp->kmalloc_ptr);
+
+       urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER;
+}
+
+static int musb_alloc_temp_buffer(struct urb *urb, gfp_t mem_flags)
+{
+       enum dma_data_direction dir;
+       struct musb_temp_buffer *temp;
+       void *kmalloc_ptr;
+       size_t kmalloc_size;
+
+       if (urb->num_sgs || urb->sg ||
+           urb->transfer_buffer_length == 0 ||
+           !((uintptr_t)urb->transfer_buffer & (MUSB_USB_DMA_ALIGN - 1)))
+               return 0;
+
+       dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+       /* Allocate a buffer with enough padding for alignment */
+       kmalloc_size = urb->transfer_buffer_length +
+               sizeof(struct musb_temp_buffer) + MUSB_USB_DMA_ALIGN - 1;
+
+       kmalloc_ptr = kmalloc(kmalloc_size, mem_flags);
+       if (!kmalloc_ptr)
+               return -ENOMEM;
+
+       /* Position our struct temp_buffer such that data is aligned */
+       temp = PTR_ALIGN(kmalloc_ptr, MUSB_USB_DMA_ALIGN);
+
+
+       temp->kmalloc_ptr = kmalloc_ptr;
+       temp->old_xfer_buffer = urb->transfer_buffer;
+       if (dir == DMA_TO_DEVICE)
+               memcpy(temp->data, urb->transfer_buffer,
+                      urb->transfer_buffer_length);
+       urb->transfer_buffer = temp->data;
+
+       urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER;
+
+       return 0;
+}
+
+static int musb_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
+                                     gfp_t mem_flags)
+{
+       struct musb     *musb = hcd_to_musb(hcd);
+       int ret;
+
+       /*
+        * The DMA engine in RTL1.8 and above cannot handle
+        * DMA addresses that are not aligned to a 4 byte boundary.
+        * For such engine implemented (un)map_urb_for_dma hooks.
+        * Do not use these hooks for RTL<1.8
+        */
+       if (musb->hwvers < MUSB_HWVERS_1800)
+               return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
+
+       ret = musb_alloc_temp_buffer(urb, mem_flags);
+       if (ret)
+               return ret;
+
+       ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
+       if (ret)
+               musb_free_temp_buffer(urb);
+
+       return ret;
+}
+
+static void musb_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+       struct musb     *musb = hcd_to_musb(hcd);
+
+       usb_hcd_unmap_urb_for_dma(hcd, urb);
+
+       /* Do not use this hook for RTL<1.8 (see description above) */
+       if (musb->hwvers < MUSB_HWVERS_1800)
+               return;
+
+       musb_free_temp_buffer(urb);
+}
+#endif /* !CONFIG_MUSB_PIO_ONLY */
+
 const struct hc_driver musb_hc_driver = {
        .description            = "musb-hcd",
        .product_desc           = "MUSB HDRC host driver",
@@ -2484,6 +2596,11 @@ const struct hc_driver musb_hc_driver = {
        .urb_dequeue            = musb_urb_dequeue,
        .endpoint_disable       = musb_h_disable,
 
+#ifndef CONFIG_MUSB_PIO_ONLY
+       .map_urb_for_dma        = musb_map_urb_for_dma,
+       .unmap_urb_for_dma      = musb_unmap_urb_for_dma,
+#endif
+
        .hub_status_data        = musb_hub_status_data,
        .hub_control            = musb_hub_control,
        .bus_suspend            = musb_bus_suspend,
index f705791..ef7d110 100644 (file)
@@ -95,7 +95,7 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend)
                        break;
                default:
                        dev_dbg(musb->controller, "bogus rh suspend? %s\n",
-                               otg_state_string(musb->xceiv->state));
+                               usb_otg_state_string(musb->xceiv->state));
                }
        } else if (power & MUSB_POWER_SUSPENDM) {
                power &= ~MUSB_POWER_SUSPENDM;
@@ -203,7 +203,7 @@ void musb_root_disconnect(struct musb *musb)
                break;
        default:
                dev_dbg(musb->controller, "host disconnect (%s)\n",
-                       otg_state_string(musb->xceiv->state));
+                       usb_otg_state_string(musb->xceiv->state));
        }
 }
 
index 1a42a45..3551f1a 100644 (file)
@@ -117,7 +117,7 @@ static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)
        if (musb->is_active || ((musb->a_wait_bcon == 0)
                        && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
                dev_dbg(musb->controller, "%s active, deleting timer\n",
-                       otg_state_string(musb->xceiv->state));
+                       usb_otg_state_string(musb->xceiv->state));
                del_timer(&musb_idle_timer);
                last_timer = jiffies;
                return;
@@ -134,7 +134,7 @@ static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)
        last_timer = timeout;
 
        dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n",
-               otg_state_string(musb->xceiv->state),
+               usb_otg_state_string(musb->xceiv->state),
                (unsigned long)jiffies_to_msecs(timeout - jiffies));
        mod_timer(&musb_idle_timer, timeout);
 }
@@ -174,8 +174,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
                                }
                        }
 
-                       if (otg->set_vbus)
-                               otg_set_vbus(otg, 1);
+                       otg_set_vbus(otg, 1);
                } else {
                        musb->is_active = 1;
                        otg->default_a = 1;
@@ -200,7 +199,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
 
        dev_dbg(musb->controller, "VBUS %s, devctl %02x "
                /* otg %3x conf %08x prcm %08x */ "\n",
-               otg_state_string(musb->xceiv->state),
+               usb_otg_state_string(musb->xceiv->state),
                musb_readb(musb->mregs, MUSB_DEVCTL));
 }
 
@@ -292,14 +291,14 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
 
                musb->xceiv->last_event = USB_EVENT_NONE;
                if (musb->gadget_driver) {
+                       omap2430_musb_set_vbus(musb, 0);
                        pm_runtime_mark_last_busy(dev);
                        pm_runtime_put_autosuspend(dev);
                }
 
-               if (data->interface_type == MUSB_INTERFACE_UTMI) {
-                       if (musb->xceiv->otg->set_vbus)
-                               otg_set_vbus(musb->xceiv->otg, 0);
-               }
+               if (data->interface_type == MUSB_INTERFACE_UTMI)
+                       otg_set_vbus(musb->xceiv->otg, 0);
+
                omap_control_usb_set_mode(glue->control_otghs,
                        USB_MODE_DISCONNECT);
                break;
@@ -355,7 +354,12 @@ static int omap2430_musb_init(struct musb *musb)
        else
                musb->xceiv = devm_usb_get_phy_dev(dev, 0);
 
-       if (IS_ERR_OR_NULL(musb->xceiv)) {
+       if (IS_ERR(musb->xceiv)) {
+               status = PTR_ERR(musb->xceiv);
+
+               if (status == -ENXIO)
+                       return status;
+
                pr_err("HS USB OTG: no transceiver configured\n");
                return -EPROBE_DEFER;
        }
@@ -393,6 +397,8 @@ static int omap2430_musb_init(struct musb *musb)
        if (glue->status != OMAP_MUSB_UNKNOWN)
                omap_musb_set_mailbox(glue);
 
+       usb_phy_init(musb->xceiv);
+
        pm_runtime_put_noidle(musb->controller);
        return 0;
 
@@ -526,10 +532,10 @@ static int omap2430_probe(struct platform_device *pdev)
                }
 
                of_property_read_u32(np, "mode", (u32 *)&pdata->mode);
-               of_property_read_u32(np, "interface_type",
+               of_property_read_u32(np, "interface-type",
                                                (u32 *)&data->interface_type);
-               of_property_read_u32(np, "num_eps", (u32 *)&config->num_eps);
-               of_property_read_u32(np, "ram_bits", (u32 *)&config->ram_bits);
+               of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps);
+               of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);
                of_property_read_u32(np, "power", (u32 *)&pdata->power);
                config->multipoint = of_property_read_bool(np, "multipoint");
                pdata->has_mailbox = of_property_read_bool(np,
index 464bd23..7369ba3 100644 (file)
@@ -423,7 +423,7 @@ static void musb_do_idle(unsigned long _musb)
                        && (musb->idle_timeout == 0
                                || time_after(jiffies, musb->idle_timeout))) {
                        dev_dbg(musb->controller, "Nothing connected %s, turning off VBUS\n",
-                                       otg_state_string(musb->xceiv->state));
+                                       usb_otg_state_string(musb->xceiv->state));
                }
                /* FALLTHROUGH */
        case OTG_STATE_A_IDLE:
@@ -478,7 +478,7 @@ static void tusb_musb_try_idle(struct musb *musb, unsigned long timeout)
        if (musb->is_active || ((musb->a_wait_bcon == 0)
                        && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
                dev_dbg(musb->controller, "%s active, deleting timer\n",
-                       otg_state_string(musb->xceiv->state));
+                       usb_otg_state_string(musb->xceiv->state));
                del_timer(&musb_idle_timer);
                last_timer = jiffies;
                return;
@@ -495,7 +495,7 @@ static void tusb_musb_try_idle(struct musb *musb, unsigned long timeout)
        last_timer = timeout;
 
        dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n",
-               otg_state_string(musb->xceiv->state),
+               usb_otg_state_string(musb->xceiv->state),
                (unsigned long)jiffies_to_msecs(timeout - jiffies));
        mod_timer(&musb_idle_timer, timeout);
 }
@@ -571,7 +571,7 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on)
        musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
 
        dev_dbg(musb->controller, "VBUS %s, devctl %02x otg %3x conf %08x prcm %08x\n",
-               otg_state_string(musb->xceiv->state),
+               usb_otg_state_string(musb->xceiv->state),
                musb_readb(musb->mregs, MUSB_DEVCTL),
                musb_readl(tbase, TUSB_DEV_OTG_STAT),
                conf, prcm);
@@ -678,13 +678,13 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
                                musb->is_active = 0;
                        }
                        dev_dbg(musb->controller, "vbus change, %s, otg %03x\n",
-                               otg_state_string(musb->xceiv->state), otg_stat);
+                               usb_otg_state_string(musb->xceiv->state), otg_stat);
                        idle_timeout = jiffies + (1 * HZ);
                        schedule_work(&musb->irq_work);
 
                } else /* A-dev state machine */ {
                        dev_dbg(musb->controller, "vbus change, %s, otg %03x\n",
-                               otg_state_string(musb->xceiv->state), otg_stat);
+                               usb_otg_state_string(musb->xceiv->state), otg_stat);
 
                        switch (musb->xceiv->state) {
                        case OTG_STATE_A_IDLE:
@@ -733,7 +733,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
                u8      devctl;
 
                dev_dbg(musb->controller, "%s timer, %03x\n",
-                       otg_state_string(musb->xceiv->state), otg_stat);
+                       usb_otg_state_string(musb->xceiv->state), otg_stat);
 
                switch (musb->xceiv->state) {
                case OTG_STATE_A_WAIT_VRISE:
index 13a3929..2c80004 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
+#include <linux/usb/musb-ux500.h>
 
 #include "musb_core.h"
 
@@ -36,6 +37,98 @@ struct ux500_glue {
 };
 #define glue_to_musb(g)        platform_get_drvdata(g->musb)
 
+static void ux500_musb_set_vbus(struct musb *musb, int is_on)
+{
+       u8            devctl;
+       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+       /* HDRC controls CPEN, but beware current surges during device
+        * connect.  They can trigger transient overcurrent conditions
+        * that must be ignored.
+        */
+
+       devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+
+       if (is_on) {
+               if (musb->xceiv->state == OTG_STATE_A_IDLE) {
+                       /* start the session */
+                       devctl |= MUSB_DEVCTL_SESSION;
+                       musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+                       /*
+                        * Wait for the musb to set as A device to enable the
+                        * VBUS
+                        */
+                       while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {
+
+                               if (time_after(jiffies, timeout)) {
+                                       dev_err(musb->controller,
+                                       "configured as A device timeout");
+                                       break;
+                               }
+                       }
+
+               } else {
+                       musb->is_active = 1;
+                       musb->xceiv->otg->default_a = 1;
+                       musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+                       devctl |= MUSB_DEVCTL_SESSION;
+                       MUSB_HST_MODE(musb);
+               }
+       } else {
+               musb->is_active = 0;
+
+               /* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and jumping
+                * right to B_IDLE...
+                */
+               musb->xceiv->otg->default_a = 0;
+               devctl &= ~MUSB_DEVCTL_SESSION;
+               MUSB_DEV_MODE(musb);
+       }
+       musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+       /*
+        * Devctl values will be updated after vbus goes below
+        * session_valid. The time taken depends on the capacitance
+        * on VBUS line. The max discharge time can be upto 1 sec
+        * as per the spec. Typically on our platform, it is 200ms
+        */
+       if (!is_on)
+               mdelay(200);
+
+       dev_dbg(musb->controller, "VBUS %s, devctl %02x\n",
+               usb_otg_state_string(musb->xceiv->state),
+               musb_readb(musb->mregs, MUSB_DEVCTL));
+}
+
+static int musb_otg_notifications(struct notifier_block *nb,
+               unsigned long event, void *unused)
+{
+       struct musb *musb = container_of(nb, struct musb, nb);
+
+       dev_dbg(musb->controller, "musb_otg_notifications %ld %s\n",
+                       event, usb_otg_state_string(musb->xceiv->state));
+
+       switch (event) {
+       case UX500_MUSB_ID:
+               dev_dbg(musb->controller, "ID GND\n");
+               ux500_musb_set_vbus(musb, 1);
+               break;
+       case UX500_MUSB_VBUS:
+               dev_dbg(musb->controller, "VBUS Connect\n");
+               break;
+       case UX500_MUSB_NONE:
+               dev_dbg(musb->controller, "VBUS Disconnect\n");
+               if (is_host_active(musb))
+                       ux500_musb_set_vbus(musb, 0);
+               else
+                       musb->xceiv->state = OTG_STATE_B_IDLE;
+               break;
+       default:
+               dev_dbg(musb->controller, "ID float\n");
+               return NOTIFY_DONE;
+       }
+       return NOTIFY_OK;
+}
+
 static irqreturn_t ux500_musb_interrupt(int irq, void *__hci)
 {
        unsigned long   flags;
@@ -58,12 +151,21 @@ static irqreturn_t ux500_musb_interrupt(int irq, void *__hci)
 
 static int ux500_musb_init(struct musb *musb)
 {
+       int status;
+
        musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
        if (IS_ERR_OR_NULL(musb->xceiv)) {
                pr_err("HS USB OTG: no transceiver configured\n");
                return -EPROBE_DEFER;
        }
 
+       musb->nb.notifier_call = musb_otg_notifications;
+       status = usb_register_notifier(musb->xceiv, &musb->nb);
+       if (status < 0) {
+               dev_dbg(musb->controller, "notification register failed\n");
+               return status;
+       }
+
        musb->isr = ux500_musb_interrupt;
 
        return 0;
@@ -71,6 +173,8 @@ static int ux500_musb_init(struct musb *musb)
 
 static int ux500_musb_exit(struct musb *musb)
 {
+       usb_unregister_notifier(musb->xceiv, &musb->nb);
+
        usb_put_phy(musb->xceiv);
 
        return 0;
@@ -79,6 +183,8 @@ static int ux500_musb_exit(struct musb *musb)
 static const struct musb_platform_ops ux500_ops = {
        .init           = ux500_musb_init,
        .exit           = ux500_musb_exit,
+
+       .set_vbus       = ux500_musb_set_vbus,
 };
 
 static int ux500_probe(struct platform_device *pdev)
index 039e567..3381206 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * drivers/usb/musb/ux500_dma.c
  *
- * U8500 and U5500 DMA support code
+ * U8500 DMA support code
  *
  * Copyright (C) 2009 STMicroelectronics
  * Copyright (C) 2011 ST-Ericsson SA
@@ -30,6 +30,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
 #include <linux/pfn.h>
+#include <linux/sizes.h>
 #include <linux/platform_data/usb-musb-ux500.h>
 #include "musb_core.h"
 
@@ -56,7 +57,7 @@ struct ux500_dma_controller {
 };
 
 /* Work function invoked from DMA callback to handle rx transfers. */
-void ux500_dma_callback(void *private_data)
+static void ux500_dma_callback(void *private_data)
 {
        struct dma_channel *channel = private_data;
        struct ux500_dma_channel *ux500_channel = channel->private_data;
@@ -93,8 +94,9 @@ static bool ux500_configure_channel(struct dma_channel *channel,
        struct musb *musb = ux500_channel->controller->private_data;
 
        dev_dbg(musb->controller,
-               "packet_sz=%d, mode=%d, dma_addr=0x%x, len=%d is_tx=%d\n",
-               packet_sz, mode, dma_addr, len, ux500_channel->is_tx);
+               "packet_sz=%d, mode=%d, dma_addr=0x%llu, len=%d is_tx=%d\n",
+               packet_sz, mode, (unsigned long long) dma_addr,
+               len, ux500_channel->is_tx);
 
        ux500_channel->cur_len = len;
 
@@ -191,7 +193,7 @@ static int ux500_dma_is_compatible(struct dma_channel *channel,
                u16 maxpacket, void *buf, u32 length)
 {
        if ((maxpacket & 0x3)           ||
-               ((int)buf & 0x3)        ||
+               ((unsigned long int) buf & 0x3) ||
                (length < 512)          ||
                (length & 0x3))
                return false;
@@ -372,12 +374,17 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba
 
        controller = kzalloc(sizeof(*controller), GFP_KERNEL);
        if (!controller)
-               return NULL;
+               goto kzalloc_fail;
 
        controller->private_data = musb;
 
        /* Save physical address for DMA controller. */
        iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!iomem) {
+               dev_err(musb->controller, "no memory resource defined\n");
+               goto plat_get_fail;
+       }
+
        controller->phy_base = (dma_addr_t) iomem->start;
 
        controller->controller.start = ux500_dma_controller_start;
@@ -389,4 +396,9 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba
        controller->controller.is_compatible = ux500_dma_is_compatible;
 
        return &controller->controller;
+
+plat_get_fail:
+       kfree(controller);
+kzalloc_fail:
+       return NULL;
 }
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
deleted file mode 100644 (file)
index 37962c9..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-#
-# USB OTG infrastructure may be needed for peripheral-only, host-only,
-# or OTG-capable configurations when OTG transceivers or controllers
-# are used.
-#
-
-comment "OTG and related infrastructure"
-
-config USB_OTG_UTILS
-       bool
-       help
-         Select this to make sure the build includes objects from
-         the OTG infrastructure directory.
-
-if USB || USB_GADGET
-
-#
-# USB Transceiver Drivers
-#
-config USB_GPIO_VBUS
-       tristate "GPIO based peripheral-only VBUS sensing 'transceiver'"
-       depends on GENERIC_GPIO
-       select USB_OTG_UTILS
-       help
-         Provides simple GPIO VBUS sensing for controllers with an
-         internal transceiver via the usb_phy interface, and
-         optionally control of a D+ pullup GPIO as well as a VBUS
-         current limit regulator.
-
-config ISP1301_OMAP
-       tristate "Philips ISP1301 with OMAP OTG"
-       depends on I2C && ARCH_OMAP_OTG
-       select USB_OTG_UTILS
-       help
-         If you say yes here you get support for the Philips ISP1301
-         USB-On-The-Go transceiver working with the OMAP OTG controller.
-         The ISP1301 is a full speed USB  transceiver which is used in
-         products including H2, H3, and H4 development boards for Texas
-         Instruments OMAP processors.
-
-         This driver can also be built as a module.  If so, the module
-         will be called isp1301_omap.
-
-config USB_ULPI
-       bool "Generic ULPI Transceiver Driver"
-       depends on ARM
-       select USB_OTG_UTILS
-       help
-         Enable this to support ULPI connected USB OTG transceivers which
-         are likely found on embedded boards.
-
-config USB_ULPI_VIEWPORT
-       bool
-       depends on USB_ULPI
-       help
-         Provides read/write operations to the ULPI phy register set for
-         controllers with a viewport register (e.g. Chipidea/ARC controllers).
-
-config TWL4030_USB
-       tristate "TWL4030 USB Transceiver Driver"
-       depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS
-       select USB_OTG_UTILS
-       help
-         Enable this to support the USB OTG transceiver on TWL4030
-         family chips (including the TWL5030 and TPS659x0 devices).
-         This transceiver supports high and full speed devices plus,
-         in host mode, low speed.
-
-config TWL6030_USB
-       tristate "TWL6030 USB Transceiver Driver"
-       depends on TWL4030_CORE && OMAP_USB2 && USB_MUSB_OMAP2PLUS
-       select USB_OTG_UTILS
-       help
-         Enable this to support the USB OTG transceiver on TWL6030
-         family chips. This TWL6030 transceiver has the VBUS and ID GND
-         and OTG SRP events capabilities. For all other transceiver functionality
-         UTMI PHY is embedded in OMAP4430. The internal PHY configurations APIs
-         are hooked to this driver through platform_data structure.
-         The definition of internal PHY APIs are in the mach-omap2 layer.
-
-config NOP_USB_XCEIV
-       tristate "NOP USB Transceiver Driver"
-       select USB_OTG_UTILS
-       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
-         phy programming such as ISP1x04 etc.
-
-config USB_MSM_OTG
-       tristate "OTG support for Qualcomm on-chip USB controller"
-       depends on (USB || USB_GADGET) && ARCH_MSM
-       select USB_OTG_UTILS
-       help
-         Enable this to support the USB OTG transceiver on MSM chips. It
-         handles PHY initialization, clock management, and workarounds
-         required after resetting the hardware and power management.
-         This driver is required even for peripheral only or host only
-         mode configurations.
-         This driver is not supported on boards like trout which
-         has an external PHY.
-
-config AB8500_USB
-       tristate "AB8500 USB Transceiver Driver"
-       depends on AB8500_CORE
-       select USB_OTG_UTILS
-       help
-         Enable this to support the USB OTG transceiver in AB8500 chip.
-         This transceiver supports high and full speed devices plus,
-         in host mode, low speed.
-
-config FSL_USB2_OTG
-       bool "Freescale USB OTG Transceiver Driver"
-       depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_SUSPEND
-       select USB_OTG
-       select USB_OTG_UTILS
-       help
-         Enable this to support Freescale USB OTG transceiver.
-
-config USB_MXS_PHY
-       tristate "Freescale MXS USB PHY support"
-       depends on ARCH_MXC || ARCH_MXS
-       select STMP_DEVICE
-       select USB_OTG_UTILS
-       help
-         Enable this to support the Freescale MXS USB PHY.
-
-         MXS Phy is used by some of the i.MX SoCs, for example imx23/28/6x.
-
-config USB_MV_OTG
-       tristate "Marvell USB OTG support"
-       depends on USB_EHCI_MV && USB_MV_UDC && USB_SUSPEND
-       select USB_OTG
-       select USB_OTG_UTILS
-       help
-         Say Y here if you want to build Marvell USB OTG transciever
-         driver in kernel (including PXA and MMP series). This driver
-         implements role switch between EHCI host driver and gadget driver.
-
-         To compile this driver as a module, choose M here.
-
-endif # USB || OTG
diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile
deleted file mode 100644 (file)
index a844b8d..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# OTG infrastructure and transceiver drivers
-#
-
-ccflags-$(CONFIG_USB_DEBUG)            := -DDEBUG
-ccflags-$(CONFIG_USB_GADGET_DEBUG)     += -DDEBUG
-
-# infrastructure
-obj-$(CONFIG_USB_OTG_UTILS)    += otg.o
-
-# transceiver drivers
-obj-$(CONFIG_USB_GPIO_VBUS)    += gpio_vbus.o
-obj-$(CONFIG_ISP1301_OMAP)     += isp1301_omap.o
-obj-$(CONFIG_TWL4030_USB)      += twl4030-usb.o
-obj-$(CONFIG_TWL6030_USB)      += twl6030-usb.o
-obj-$(CONFIG_NOP_USB_XCEIV)    += nop-usb-xceiv.o
-obj-$(CONFIG_USB_ULPI)         += ulpi.o
-obj-$(CONFIG_USB_ULPI_VIEWPORT)        += ulpi_viewport.o
-obj-$(CONFIG_USB_MSM_OTG)      += msm_otg.o
-obj-$(CONFIG_AB8500_USB)       += ab8500-usb.o
-fsl_usb2_otg-objs              := fsl_otg.o otg_fsm.o
-obj-$(CONFIG_FSL_USB2_OTG)     += fsl_usb2_otg.o
-obj-$(CONFIG_USB_MXS_PHY)      += mxs-phy.o
-obj-$(CONFIG_USB_MV_OTG)       += mv_otg.o
diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c
deleted file mode 100644 (file)
index 2d86f26..0000000
+++ /dev/null
@@ -1,596 +0,0 @@
-/*
- * drivers/usb/otg/ab8500_usb.c
- *
- * USB transceiver driver for AB8500 chip
- *
- * Copyright (C) 2010 ST-Ericsson AB
- * Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/usb/otg.h>
-#include <linux/slab.h>
-#include <linux/notifier.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/mfd/abx500.h>
-#include <linux/mfd/abx500/ab8500.h>
-
-#define AB8500_MAIN_WD_CTRL_REG 0x01
-#define AB8500_USB_LINE_STAT_REG 0x80
-#define AB8500_USB_PHY_CTRL_REG 0x8A
-
-#define AB8500_BIT_OTG_STAT_ID (1 << 0)
-#define AB8500_BIT_PHY_CTRL_HOST_EN (1 << 0)
-#define AB8500_BIT_PHY_CTRL_DEVICE_EN (1 << 1)
-#define AB8500_BIT_WD_CTRL_ENABLE (1 << 0)
-#define AB8500_BIT_WD_CTRL_KICK (1 << 1)
-
-#define AB8500_V1x_LINK_STAT_WAIT (HZ/10)
-#define AB8500_WD_KICK_DELAY_US 100 /* usec */
-#define AB8500_WD_V11_DISABLE_DELAY_US 100 /* usec */
-#define AB8500_WD_V10_DISABLE_DELAY_MS 100 /* ms */
-
-/* Usb line status register */
-enum ab8500_usb_link_status {
-       USB_LINK_NOT_CONFIGURED = 0,
-       USB_LINK_STD_HOST_NC,
-       USB_LINK_STD_HOST_C_NS,
-       USB_LINK_STD_HOST_C_S,
-       USB_LINK_HOST_CHG_NM,
-       USB_LINK_HOST_CHG_HS,
-       USB_LINK_HOST_CHG_HS_CHIRP,
-       USB_LINK_DEDICATED_CHG,
-       USB_LINK_ACA_RID_A,
-       USB_LINK_ACA_RID_B,
-       USB_LINK_ACA_RID_C_NM,
-       USB_LINK_ACA_RID_C_HS,
-       USB_LINK_ACA_RID_C_HS_CHIRP,
-       USB_LINK_HM_IDGND,
-       USB_LINK_RESERVED,
-       USB_LINK_NOT_VALID_LINK
-};
-
-struct ab8500_usb {
-       struct usb_phy phy;
-       struct device *dev;
-       int irq_num_id_rise;
-       int irq_num_id_fall;
-       int irq_num_vbus_rise;
-       int irq_num_vbus_fall;
-       int irq_num_link_status;
-       unsigned vbus_draw;
-       struct delayed_work dwork;
-       struct work_struct phy_dis_work;
-       unsigned long link_status_wait;
-       int rev;
-};
-
-static inline struct ab8500_usb *phy_to_ab(struct usb_phy *x)
-{
-       return container_of(x, struct ab8500_usb, phy);
-}
-
-static void ab8500_usb_wd_workaround(struct ab8500_usb *ab)
-{
-       abx500_set_register_interruptible(ab->dev,
-               AB8500_SYS_CTRL2_BLOCK,
-               AB8500_MAIN_WD_CTRL_REG,
-               AB8500_BIT_WD_CTRL_ENABLE);
-
-       udelay(AB8500_WD_KICK_DELAY_US);
-
-       abx500_set_register_interruptible(ab->dev,
-               AB8500_SYS_CTRL2_BLOCK,
-               AB8500_MAIN_WD_CTRL_REG,
-               (AB8500_BIT_WD_CTRL_ENABLE
-               | AB8500_BIT_WD_CTRL_KICK));
-
-       if (ab->rev > 0x10) /* v1.1 v2.0 */
-               udelay(AB8500_WD_V11_DISABLE_DELAY_US);
-       else /* v1.0 */
-               msleep(AB8500_WD_V10_DISABLE_DELAY_MS);
-
-       abx500_set_register_interruptible(ab->dev,
-               AB8500_SYS_CTRL2_BLOCK,
-               AB8500_MAIN_WD_CTRL_REG,
-               0);
-}
-
-static void ab8500_usb_phy_ctrl(struct ab8500_usb *ab, bool sel_host,
-                                       bool enable)
-{
-       u8 ctrl_reg;
-       abx500_get_register_interruptible(ab->dev,
-                               AB8500_USB,
-                               AB8500_USB_PHY_CTRL_REG,
-                               &ctrl_reg);
-       if (sel_host) {
-               if (enable)
-                       ctrl_reg |= AB8500_BIT_PHY_CTRL_HOST_EN;
-               else
-                       ctrl_reg &= ~AB8500_BIT_PHY_CTRL_HOST_EN;
-       } else {
-               if (enable)
-                       ctrl_reg |= AB8500_BIT_PHY_CTRL_DEVICE_EN;
-               else
-                       ctrl_reg &= ~AB8500_BIT_PHY_CTRL_DEVICE_EN;
-       }
-
-       abx500_set_register_interruptible(ab->dev,
-                               AB8500_USB,
-                               AB8500_USB_PHY_CTRL_REG,
-                               ctrl_reg);
-
-       /* Needed to enable the phy.*/
-       if (enable)
-               ab8500_usb_wd_workaround(ab);
-}
-
-#define ab8500_usb_host_phy_en(ab)     ab8500_usb_phy_ctrl(ab, true, true)
-#define ab8500_usb_host_phy_dis(ab)    ab8500_usb_phy_ctrl(ab, true, false)
-#define ab8500_usb_peri_phy_en(ab)     ab8500_usb_phy_ctrl(ab, false, true)
-#define ab8500_usb_peri_phy_dis(ab)    ab8500_usb_phy_ctrl(ab, false, false)
-
-static int ab8500_usb_link_status_update(struct ab8500_usb *ab)
-{
-       u8 reg;
-       enum ab8500_usb_link_status lsts;
-       void *v = NULL;
-       enum usb_phy_events event;
-
-       abx500_get_register_interruptible(ab->dev,
-                       AB8500_USB,
-                       AB8500_USB_LINE_STAT_REG,
-                       &reg);
-
-       lsts = (reg >> 3) & 0x0F;
-
-       switch (lsts) {
-       case USB_LINK_NOT_CONFIGURED:
-       case USB_LINK_RESERVED:
-       case USB_LINK_NOT_VALID_LINK:
-               /* TODO: Disable regulators. */
-               ab8500_usb_host_phy_dis(ab);
-               ab8500_usb_peri_phy_dis(ab);
-               ab->phy.state = OTG_STATE_B_IDLE;
-               ab->phy.otg->default_a = false;
-               ab->vbus_draw = 0;
-               event = USB_EVENT_NONE;
-               break;
-
-       case USB_LINK_STD_HOST_NC:
-       case USB_LINK_STD_HOST_C_NS:
-       case USB_LINK_STD_HOST_C_S:
-       case USB_LINK_HOST_CHG_NM:
-       case USB_LINK_HOST_CHG_HS:
-       case USB_LINK_HOST_CHG_HS_CHIRP:
-               if (ab->phy.otg->gadget) {
-                       /* TODO: Enable regulators. */
-                       ab8500_usb_peri_phy_en(ab);
-                       v = ab->phy.otg->gadget;
-               }
-               event = USB_EVENT_VBUS;
-               break;
-
-       case USB_LINK_HM_IDGND:
-               if (ab->phy.otg->host) {
-                       /* TODO: Enable regulators. */
-                       ab8500_usb_host_phy_en(ab);
-                       v = ab->phy.otg->host;
-               }
-               ab->phy.state = OTG_STATE_A_IDLE;
-               ab->phy.otg->default_a = true;
-               event = USB_EVENT_ID;
-               break;
-
-       case USB_LINK_ACA_RID_A:
-       case USB_LINK_ACA_RID_B:
-               /* TODO */
-       case USB_LINK_ACA_RID_C_NM:
-       case USB_LINK_ACA_RID_C_HS:
-       case USB_LINK_ACA_RID_C_HS_CHIRP:
-       case USB_LINK_DEDICATED_CHG:
-               /* TODO: vbus_draw */
-               event = USB_EVENT_CHARGER;
-               break;
-       }
-
-       atomic_notifier_call_chain(&ab->phy.notifier, event, v);
-
-       return 0;
-}
-
-static void ab8500_usb_delayed_work(struct work_struct *work)
-{
-       struct ab8500_usb *ab = container_of(work, struct ab8500_usb,
-                                               dwork.work);
-
-       ab8500_usb_link_status_update(ab);
-}
-
-static irqreturn_t ab8500_usb_v1x_common_irq(int irq, void *data)
-{
-       struct ab8500_usb *ab = (struct ab8500_usb *) data;
-
-       /* Wait for link status to become stable. */
-       schedule_delayed_work(&ab->dwork, ab->link_status_wait);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t ab8500_usb_v1x_vbus_fall_irq(int irq, void *data)
-{
-       struct ab8500_usb *ab = (struct ab8500_usb *) data;
-
-       /* Link status will not be updated till phy is disabled. */
-       ab8500_usb_peri_phy_dis(ab);
-
-       /* Wait for link status to become stable. */
-       schedule_delayed_work(&ab->dwork, ab->link_status_wait);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t ab8500_usb_v20_irq(int irq, void *data)
-{
-       struct ab8500_usb *ab = (struct ab8500_usb *) data;
-
-       ab8500_usb_link_status_update(ab);
-
-       return IRQ_HANDLED;
-}
-
-static void ab8500_usb_phy_disable_work(struct work_struct *work)
-{
-       struct ab8500_usb *ab = container_of(work, struct ab8500_usb,
-                                               phy_dis_work);
-
-       if (!ab->phy.otg->host)
-               ab8500_usb_host_phy_dis(ab);
-
-       if (!ab->phy.otg->gadget)
-               ab8500_usb_peri_phy_dis(ab);
-}
-
-static int ab8500_usb_set_power(struct usb_phy *phy, unsigned mA)
-{
-       struct ab8500_usb *ab;
-
-       if (!phy)
-               return -ENODEV;
-
-       ab = phy_to_ab(phy);
-
-       ab->vbus_draw = mA;
-
-       if (mA)
-               atomic_notifier_call_chain(&ab->phy.notifier,
-                               USB_EVENT_ENUMERATED, ab->phy.otg->gadget);
-       return 0;
-}
-
-/* TODO: Implement some way for charging or other drivers to read
- * ab->vbus_draw.
- */
-
-static int ab8500_usb_set_suspend(struct usb_phy *x, int suspend)
-{
-       /* TODO */
-       return 0;
-}
-
-static int ab8500_usb_set_peripheral(struct usb_otg *otg,
-                                       struct usb_gadget *gadget)
-{
-       struct ab8500_usb *ab;
-
-       if (!otg)
-               return -ENODEV;
-
-       ab = phy_to_ab(otg->phy);
-
-       /* Some drivers call this function in atomic context.
-        * Do not update ab8500 registers directly till this
-        * is fixed.
-        */
-
-       if (!gadget) {
-               /* TODO: Disable regulators. */
-               otg->gadget = NULL;
-               schedule_work(&ab->phy_dis_work);
-       } else {
-               otg->gadget = gadget;
-               otg->phy->state = OTG_STATE_B_IDLE;
-
-               /* Phy will not be enabled if cable is already
-                * plugged-in. Schedule to enable phy.
-                * Use same delay to avoid any race condition.
-                */
-               schedule_delayed_work(&ab->dwork, ab->link_status_wait);
-       }
-
-       return 0;
-}
-
-static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
-{
-       struct ab8500_usb *ab;
-
-       if (!otg)
-               return -ENODEV;
-
-       ab = phy_to_ab(otg->phy);
-
-       /* Some drivers call this function in atomic context.
-        * Do not update ab8500 registers directly till this
-        * is fixed.
-        */
-
-       if (!host) {
-               /* TODO: Disable regulators. */
-               otg->host = NULL;
-               schedule_work(&ab->phy_dis_work);
-       } else {
-               otg->host = host;
-               /* Phy will not be enabled if cable is already
-                * plugged-in. Schedule to enable phy.
-                * Use same delay to avoid any race condition.
-                */
-               schedule_delayed_work(&ab->dwork, ab->link_status_wait);
-       }
-
-       return 0;
-}
-
-static void ab8500_usb_irq_free(struct ab8500_usb *ab)
-{
-       if (ab->rev < 0x20) {
-               free_irq(ab->irq_num_id_rise, ab);
-               free_irq(ab->irq_num_id_fall, ab);
-               free_irq(ab->irq_num_vbus_rise, ab);
-               free_irq(ab->irq_num_vbus_fall, ab);
-       } else {
-               free_irq(ab->irq_num_link_status, ab);
-       }
-}
-
-static int ab8500_usb_v1x_res_setup(struct platform_device *pdev,
-                               struct ab8500_usb *ab)
-{
-       int err;
-
-       ab->irq_num_id_rise = platform_get_irq_byname(pdev, "ID_WAKEUP_R");
-       if (ab->irq_num_id_rise < 0) {
-               dev_err(&pdev->dev, "ID rise irq not found\n");
-               return ab->irq_num_id_rise;
-       }
-       err = request_threaded_irq(ab->irq_num_id_rise, NULL,
-               ab8500_usb_v1x_common_irq,
-               IRQF_NO_SUSPEND | IRQF_SHARED,
-               "usb-id-rise", ab);
-       if (err < 0) {
-               dev_err(ab->dev, "request_irq failed for ID rise irq\n");
-               goto fail0;
-       }
-
-       ab->irq_num_id_fall = platform_get_irq_byname(pdev, "ID_WAKEUP_F");
-       if (ab->irq_num_id_fall < 0) {
-               dev_err(&pdev->dev, "ID fall irq not found\n");
-               return ab->irq_num_id_fall;
-       }
-       err = request_threaded_irq(ab->irq_num_id_fall, NULL,
-               ab8500_usb_v1x_common_irq,
-               IRQF_NO_SUSPEND | IRQF_SHARED,
-               "usb-id-fall", ab);
-       if (err < 0) {
-               dev_err(ab->dev, "request_irq failed for ID fall irq\n");
-               goto fail1;
-       }
-
-       ab->irq_num_vbus_rise = platform_get_irq_byname(pdev, "VBUS_DET_R");
-       if (ab->irq_num_vbus_rise < 0) {
-               dev_err(&pdev->dev, "VBUS rise irq not found\n");
-               return ab->irq_num_vbus_rise;
-       }
-       err = request_threaded_irq(ab->irq_num_vbus_rise, NULL,
-               ab8500_usb_v1x_common_irq,
-               IRQF_NO_SUSPEND | IRQF_SHARED,
-               "usb-vbus-rise", ab);
-       if (err < 0) {
-               dev_err(ab->dev, "request_irq failed for Vbus rise irq\n");
-               goto fail2;
-       }
-
-       ab->irq_num_vbus_fall = platform_get_irq_byname(pdev, "VBUS_DET_F");
-       if (ab->irq_num_vbus_fall < 0) {
-               dev_err(&pdev->dev, "VBUS fall irq not found\n");
-               return ab->irq_num_vbus_fall;
-       }
-       err = request_threaded_irq(ab->irq_num_vbus_fall, NULL,
-               ab8500_usb_v1x_vbus_fall_irq,
-               IRQF_NO_SUSPEND | IRQF_SHARED,
-               "usb-vbus-fall", ab);
-       if (err < 0) {
-               dev_err(ab->dev, "request_irq failed for Vbus fall irq\n");
-               goto fail3;
-       }
-
-       return 0;
-fail3:
-       free_irq(ab->irq_num_vbus_rise, ab);
-fail2:
-       free_irq(ab->irq_num_id_fall, ab);
-fail1:
-       free_irq(ab->irq_num_id_rise, ab);
-fail0:
-       return err;
-}
-
-static int ab8500_usb_v2_res_setup(struct platform_device *pdev,
-                               struct ab8500_usb *ab)
-{
-       int err;
-
-       ab->irq_num_link_status = platform_get_irq_byname(pdev,
-                                               "USB_LINK_STATUS");
-       if (ab->irq_num_link_status < 0) {
-               dev_err(&pdev->dev, "Link status irq not found\n");
-               return ab->irq_num_link_status;
-       }
-
-       err = request_threaded_irq(ab->irq_num_link_status, NULL,
-               ab8500_usb_v20_irq,
-               IRQF_NO_SUSPEND | IRQF_SHARED,
-               "usb-link-status", ab);
-       if (err < 0) {
-               dev_err(ab->dev,
-                       "request_irq failed for link status irq\n");
-               return err;
-       }
-
-       return 0;
-}
-
-static int ab8500_usb_probe(struct platform_device *pdev)
-{
-       struct ab8500_usb       *ab;
-       struct usb_otg          *otg;
-       int err;
-       int rev;
-
-       rev = abx500_get_chip_id(&pdev->dev);
-       if (rev < 0) {
-               dev_err(&pdev->dev, "Chip id read failed\n");
-               return rev;
-       } else if (rev < 0x10) {
-               dev_err(&pdev->dev, "Unsupported AB8500 chip\n");
-               return -ENODEV;
-       }
-
-       ab = kzalloc(sizeof *ab, GFP_KERNEL);
-       if (!ab)
-               return -ENOMEM;
-
-       otg = kzalloc(sizeof *otg, GFP_KERNEL);
-       if (!otg) {
-               kfree(ab);
-               return -ENOMEM;
-       }
-
-       ab->dev                 = &pdev->dev;
-       ab->rev                 = rev;
-       ab->phy.dev             = ab->dev;
-       ab->phy.otg             = otg;
-       ab->phy.label           = "ab8500";
-       ab->phy.set_suspend     = ab8500_usb_set_suspend;
-       ab->phy.set_power       = ab8500_usb_set_power;
-       ab->phy.state           = OTG_STATE_UNDEFINED;
-
-       otg->phy                = &ab->phy;
-       otg->set_host           = ab8500_usb_set_host;
-       otg->set_peripheral     = ab8500_usb_set_peripheral;
-
-       platform_set_drvdata(pdev, ab);
-
-       ATOMIC_INIT_NOTIFIER_HEAD(&ab->phy.notifier);
-
-       /* v1: Wait for link status to become stable.
-        * all: Updates form set_host and set_peripheral as they are atomic.
-        */
-       INIT_DELAYED_WORK(&ab->dwork, ab8500_usb_delayed_work);
-
-       /* all: Disable phy when called from set_host and set_peripheral */
-       INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work);
-
-       if (ab->rev < 0x20) {
-               err = ab8500_usb_v1x_res_setup(pdev, ab);
-               ab->link_status_wait = AB8500_V1x_LINK_STAT_WAIT;
-       } else {
-               err = ab8500_usb_v2_res_setup(pdev, ab);
-       }
-
-       if (err < 0)
-               goto fail0;
-
-       err = usb_add_phy(&ab->phy, USB_PHY_TYPE_USB2);
-       if (err) {
-               dev_err(&pdev->dev, "Can't register transceiver\n");
-               goto fail1;
-       }
-
-       dev_info(&pdev->dev, "AB8500 usb driver initialized\n");
-
-       return 0;
-fail1:
-       ab8500_usb_irq_free(ab);
-fail0:
-       kfree(otg);
-       kfree(ab);
-       return err;
-}
-
-static int ab8500_usb_remove(struct platform_device *pdev)
-{
-       struct ab8500_usb *ab = platform_get_drvdata(pdev);
-
-       ab8500_usb_irq_free(ab);
-
-       cancel_delayed_work_sync(&ab->dwork);
-
-       cancel_work_sync(&ab->phy_dis_work);
-
-       usb_remove_phy(&ab->phy);
-
-       ab8500_usb_host_phy_dis(ab);
-       ab8500_usb_peri_phy_dis(ab);
-
-       platform_set_drvdata(pdev, NULL);
-
-       kfree(ab->phy.otg);
-       kfree(ab);
-
-       return 0;
-}
-
-static struct platform_driver ab8500_usb_driver = {
-       .probe          = ab8500_usb_probe,
-       .remove         = ab8500_usb_remove,
-       .driver         = {
-               .name   = "ab8500-usb",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init ab8500_usb_init(void)
-{
-       return platform_driver_register(&ab8500_usb_driver);
-}
-subsys_initcall(ab8500_usb_init);
-
-static void __exit ab8500_usb_exit(void)
-{
-       platform_driver_unregister(&ab8500_usb_driver);
-}
-module_exit(ab8500_usb_exit);
-
-MODULE_ALIAS("platform:ab8500_usb");
-MODULE_AUTHOR("ST-Ericsson AB");
-MODULE_DESCRIPTION("AB8500 usb transceiver driver");
-MODULE_LICENSE("GPL");
index 9054938..3a7fec9 100644 (file)
@@ -1,13 +1,74 @@
 #
 # Physical Layer USB driver configuration
 #
-comment "USB Physical Layer drivers"
-       depends on USB || USB_GADGET
+menuconfig USB_PHY
+       tristate "USB Physical Layer drivers"
+       help
+         USB controllers (those which are host, device or DRD) need a
+         device to handle the physical layer signalling, commonly called
+         a PHY.
+
+         The following drivers add support for such PHY devices.
+
+if USB_PHY
+
+#
+# USB Transceiver Drivers
+#
+config AB8500_USB
+       tristate "AB8500 USB Transceiver Driver"
+       depends on AB8500_CORE
+       help
+         Enable this to support the USB OTG transceiver in AB8500 chip.
+         This transceiver supports high and full speed devices plus,
+         in host mode, low speed.
+
+config FSL_USB2_OTG
+       bool "Freescale USB OTG Transceiver Driver"
+       depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_SUSPEND
+       select USB_OTG
+       help
+         Enable this to support Freescale USB OTG transceiver.
+
+config ISP1301_OMAP
+       tristate "Philips ISP1301 with OMAP OTG"
+       depends on I2C && ARCH_OMAP_OTG
+       help
+         If you say yes here you get support for the Philips ISP1301
+         USB-On-The-Go transceiver working with the OMAP OTG controller.
+         The ISP1301 is a full speed USB  transceiver which is used in
+         products including H2, H3, and H4 development boards for Texas
+         Instruments OMAP processors.
+
+         This driver can also be built as a module.  If so, the module
+         will be called isp1301_omap.
+
+config MV_U3D_PHY
+       bool "Marvell USB 3.0 PHY controller Driver"
+       depends on CPU_MMP3
+       help
+         Enable this to support Marvell USB 3.0 phy controller for Marvell
+         SoC.
+
+config NOP_USB_XCEIV
+       tristate "NOP USB Transceiver Driver"
+       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
+         phy programming such as ISP1x04 etc.
+
+config OMAP_CONTROL_USB
+       tristate "OMAP CONTROL USB Driver"
+       help
+         Enable this to add support for the USB part present in the control
+         module. This driver has API to power on the USB2 PHY and to write to
+         the mailbox. The mailbox is present only in omap4 and the register to
+         power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an
+         additional register to power on USB3 PHY.
 
 config OMAP_USB2
        tristate "OMAP USB2 PHY Driver"
        depends on ARCH_OMAP2PLUS
-       select USB_OTG_UTILS
        select OMAP_CONTROL_USB
        help
          Enable this to support the transceiver that is part of SOC. This
@@ -17,7 +78,6 @@ config OMAP_USB2
 
 config OMAP_USB3
        tristate "OMAP USB3 PHY Driver"
-       select USB_OTG_UTILS
        select OMAP_CONTROL_USB
        help
          Enable this to support the USB3 PHY that is part of SOC. This
@@ -25,14 +85,55 @@ config OMAP_USB3
          This driver interacts with the "OMAP Control USB Driver" to power
          on/off the PHY.
 
-config OMAP_CONTROL_USB
-       tristate "OMAP CONTROL USB Driver"
+config SAMSUNG_USBPHY
+       tristate "Samsung USB PHY Driver"
        help
-         Enable this to add support for the USB part present in the control
-         module. This driver has API to power on the USB2 PHY and to write to
-         the mailbox. The mailbox is present only in omap4 and the register to
-         power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an
-         additional register to power on USB3 PHY.
+         Enable this to support Samsung USB phy helper driver for Samsung SoCs.
+         This driver provides common interface to interact, for Samsung USB 2.0 PHY
+         driver and later for Samsung USB 3.0 PHY driver.
+
+config SAMSUNG_USB2PHY
+       tristate "Samsung USB 2.0 PHY controller Driver"
+       select SAMSUNG_USBPHY
+       help
+         Enable this to support Samsung USB 2.0 (High Speed) PHY controller
+         driver for Samsung SoCs.
+
+config SAMSUNG_USB3PHY
+       tristate "Samsung USB 3.0 PHY controller Driver"
+       select SAMSUNG_USBPHY
+       help
+         Enable this to support Samsung USB 3.0 (Super Speed) phy controller
+         for samsung SoCs.
+
+config TWL4030_USB
+       tristate "TWL4030 USB Transceiver Driver"
+       depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS
+       help
+         Enable this to support the USB OTG transceiver on TWL4030
+         family chips (including the TWL5030 and TPS659x0 devices).
+         This transceiver supports high and full speed devices plus,
+         in host mode, low speed.
+
+config TWL6030_USB
+       tristate "TWL6030 USB Transceiver Driver"
+       depends on TWL4030_CORE && OMAP_USB2 && USB_MUSB_OMAP2PLUS
+       help
+         Enable this to support the USB OTG transceiver on TWL6030
+         family chips. This TWL6030 transceiver has the VBUS and ID GND
+         and OTG SRP events capabilities. For all other transceiver functionality
+         UTMI PHY is embedded in OMAP4430. The internal PHY configurations APIs
+         are hooked to this driver through platform_data structure.
+         The definition of internal PHY APIs are in the mach-omap2 layer.
+
+config USB_GPIO_VBUS
+       tristate "GPIO based peripheral-only VBUS sensing 'transceiver'"
+       depends on GENERIC_GPIO
+       help
+         Provides simple GPIO VBUS sensing for controllers with an
+         internal transceiver via the usb_phy interface, and
+         optionally control of a D+ pullup GPIO as well as a VBUS
+         current limit regulator.
 
 config USB_ISP1301
        tristate "NXP ISP1301 USB transceiver support"
@@ -47,18 +148,41 @@ config USB_ISP1301
          To compile this driver as a module, choose M here: the
          module will be called isp1301.
 
-config MV_U3D_PHY
-       bool "Marvell USB 3.0 PHY controller Driver"
-       depends on USB_MV_U3D
-       select USB_OTG_UTILS
+config USB_MSM_OTG
+       tristate "OTG support for Qualcomm on-chip USB controller"
+       depends on (USB || USB_GADGET) && ARCH_MSM
        help
-         Enable this to support Marvell USB 3.0 phy controller for Marvell
-         SoC.
+         Enable this to support the USB OTG transceiver on MSM chips. It
+         handles PHY initialization, clock management, and workarounds
+         required after resetting the hardware and power management.
+         This driver is required even for peripheral only or host only
+         mode configurations.
+         This driver is not supported on boards like trout which
+         has an external PHY.
+
+config USB_MV_OTG
+       tristate "Marvell USB OTG support"
+       depends on USB_EHCI_MV && USB_MV_UDC && USB_SUSPEND
+       select USB_OTG
+       help
+         Say Y here if you want to build Marvell USB OTG transciever
+         driver in kernel (including PXA and MMP series). This driver
+         implements role switch between EHCI host driver and gadget driver.
+
+         To compile this driver as a module, choose M here.
+
+config USB_MXS_PHY
+       tristate "Freescale MXS USB PHY support"
+       depends on ARCH_MXC || ARCH_MXS
+       select STMP_DEVICE
+       help
+         Enable this to support the Freescale MXS USB PHY.
+
+         MXS Phy is used by some of the i.MX SoCs, for example imx23/28/6x.
 
 config USB_RCAR_PHY
        tristate "Renesas R-Car USB phy support"
        depends on USB || USB_GADGET
-       select USB_OTG_UTILS
        help
          Say Y here to add support for the Renesas R-Car USB phy driver.
          This chip is typically used as USB phy for USB host, gadget.
@@ -67,10 +191,18 @@ config USB_RCAR_PHY
          To compile this driver as a module, choose M here: the
          module will be called rcar-phy.
 
-config SAMSUNG_USBPHY
-       bool "Samsung USB PHY controller Driver"
-       depends on USB_S3C_HSOTG || USB_EHCI_S5P || USB_OHCI_EXYNOS
-       select USB_OTG_UTILS
+config USB_ULPI
+       bool "Generic ULPI Transceiver Driver"
+       depends on ARM
+       help
+         Enable this to support ULPI connected USB OTG transceivers which
+         are likely found on embedded boards.
+
+config USB_ULPI_VIEWPORT
+       bool
+       depends on USB_ULPI
        help
-         Enable this to support Samsung USB phy controller for samsung
-         SoCs.
+         Provides read/write operations to the ULPI phy register set for
+         controllers with a viewport register (e.g. Chipidea/ARC controllers).
+
+endif # USB_PHY
index b13faa1..33863c0 100644 (file)
@@ -4,11 +4,30 @@
 
 ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
 
-obj-$(CONFIG_OMAP_USB2)                        += omap-usb2.o
-obj-$(CONFIG_OMAP_USB3)                        += omap-usb3.o
-obj-$(CONFIG_OMAP_CONTROL_USB)         += omap-control-usb.o
-obj-$(CONFIG_USB_ISP1301)              += isp1301.o
-obj-$(CONFIG_MV_U3D_PHY)               += mv_u3d_phy.o
-obj-$(CONFIG_USB_EHCI_TEGRA)   += tegra_usb_phy.o
-obj-$(CONFIG_USB_RCAR_PHY)             += rcar-phy.o
-obj-$(CONFIG_SAMSUNG_USBPHY)           += samsung-usbphy.o
+obj-$(CONFIG_USB_PHY)                  += phy.o
+
+# transceiver drivers, keep the list sorted
+
+obj-$(CONFIG_AB8500_USB)               += phy-ab8500-usb.o
+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_OMAP_CONTROL_USB)         += phy-omap-control.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
+obj-$(CONFIG_SAMSUNG_USB2PHY)          += phy-samsung-usb2.o
+obj-$(CONFIG_SAMSUNG_USB3PHY)          += phy-samsung-usb3.o
+obj-$(CONFIG_TWL4030_USB)              += phy-twl4030-usb.o
+obj-$(CONFIG_TWL6030_USB)              += phy-twl6030-usb.o
+obj-$(CONFIG_USB_EHCI_TEGRA)           += phy-tegra-usb.o
+obj-$(CONFIG_USB_GPIO_VBUS)            += phy-gpio-vbus-usb.o
+obj-$(CONFIG_USB_ISP1301)              += phy-isp1301.o
+obj-$(CONFIG_USB_MSM_OTG)              += phy-msm-usb.o
+obj-$(CONFIG_USB_MV_OTG)               += phy-mv-usb.o
+obj-$(CONFIG_USB_MXS_PHY)              += phy-mxs-usb.o
+obj-$(CONFIG_USB_RCAR_PHY)             += phy-rcar-usb.o
+obj-$(CONFIG_USB_ULPI)                 += phy-ulpi.o
+obj-$(CONFIG_USB_ULPI_VIEWPORT)                += phy-ulpi-viewport.o
diff --git a/drivers/usb/phy/isp1301.c b/drivers/usb/phy/isp1301.c
deleted file mode 100644 (file)
index 18dbf7e..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * NXP ISP1301 USB transceiver driver
- *
- * Copyright (C) 2012 Roland Stigge
- *
- * Author: Roland Stigge <stigge@antcom.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/i2c.h>
-
-#define DRV_NAME               "isp1301"
-
-static const struct i2c_device_id isp1301_id[] = {
-       { "isp1301", 0 },
-       { }
-};
-
-static struct i2c_client *isp1301_i2c_client;
-
-static int isp1301_probe(struct i2c_client *client,
-                        const struct i2c_device_id *i2c_id)
-{
-       isp1301_i2c_client = client;
-       return 0;
-}
-
-static int isp1301_remove(struct i2c_client *client)
-{
-       return 0;
-}
-
-static struct i2c_driver isp1301_driver = {
-       .driver = {
-               .name = DRV_NAME,
-       },
-       .probe = isp1301_probe,
-       .remove = isp1301_remove,
-       .id_table = isp1301_id,
-};
-
-module_i2c_driver(isp1301_driver);
-
-static int match(struct device *dev, void *data)
-{
-       struct device_node *node = (struct device_node *)data;
-       return (dev->of_node == node) &&
-               (dev->driver == &isp1301_driver.driver);
-}
-
-struct i2c_client *isp1301_get_client(struct device_node *node)
-{
-       if (node) { /* reference of ISP1301 I2C node via DT */
-               struct device *dev = bus_find_device(&i2c_bus_type, NULL,
-                                                    node, match);
-               if (!dev)
-                       return NULL;
-               return to_i2c_client(dev);
-       } else { /* non-DT: only one ISP1301 chip supported */
-               return isp1301_i2c_client;
-       }
-}
-EXPORT_SYMBOL_GPL(isp1301_get_client);
-
-MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
-MODULE_DESCRIPTION("NXP ISP1301 USB transceiver driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c
new file mode 100644 (file)
index 0000000..4acef26
--- /dev/null
@@ -0,0 +1,924 @@
+/*
+ * drivers/usb/otg/ab8500_usb.c
+ *
+ * USB transceiver driver for AB8500 chip
+ *
+ * Copyright (C) 2010 ST-Ericsson AB
+ * Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/usb/otg.h>
+#include <linux/slab.h>
+#include <linux/notifier.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/usb/musb-ux500.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pinctrl/consumer.h>
+
+/* Bank AB8500_SYS_CTRL2_BLOCK */
+#define AB8500_MAIN_WD_CTRL_REG 0x01
+
+/* Bank AB8500_USB */
+#define AB8500_USB_LINE_STAT_REG 0x80
+#define AB8505_USB_LINE_STAT_REG 0x94
+#define AB8500_USB_PHY_CTRL_REG 0x8A
+
+/* Bank AB8500_DEVELOPMENT */
+#define AB8500_BANK12_ACCESS 0x00
+
+/* Bank AB8500_DEBUG */
+#define AB8500_USB_PHY_TUNE1 0x05
+#define AB8500_USB_PHY_TUNE2 0x06
+#define AB8500_USB_PHY_TUNE3 0x07
+
+#define AB8500_BIT_OTG_STAT_ID (1 << 0)
+#define AB8500_BIT_PHY_CTRL_HOST_EN (1 << 0)
+#define AB8500_BIT_PHY_CTRL_DEVICE_EN (1 << 1)
+#define AB8500_BIT_WD_CTRL_ENABLE (1 << 0)
+#define AB8500_BIT_WD_CTRL_KICK (1 << 1)
+
+#define AB8500_WD_KICK_DELAY_US 100 /* usec */
+#define AB8500_WD_V11_DISABLE_DELAY_US 100 /* usec */
+#define AB8500_V20_31952_DISABLE_DELAY_US 100 /* usec */
+
+/* Usb line status register */
+enum ab8500_usb_link_status {
+       USB_LINK_NOT_CONFIGURED_8500 = 0,
+       USB_LINK_STD_HOST_NC_8500,
+       USB_LINK_STD_HOST_C_NS_8500,
+       USB_LINK_STD_HOST_C_S_8500,
+       USB_LINK_HOST_CHG_NM_8500,
+       USB_LINK_HOST_CHG_HS_8500,
+       USB_LINK_HOST_CHG_HS_CHIRP_8500,
+       USB_LINK_DEDICATED_CHG_8500,
+       USB_LINK_ACA_RID_A_8500,
+       USB_LINK_ACA_RID_B_8500,
+       USB_LINK_ACA_RID_C_NM_8500,
+       USB_LINK_ACA_RID_C_HS_8500,
+       USB_LINK_ACA_RID_C_HS_CHIRP_8500,
+       USB_LINK_HM_IDGND_8500,
+       USB_LINK_RESERVED_8500,
+       USB_LINK_NOT_VALID_LINK_8500,
+};
+
+enum ab8505_usb_link_status {
+       USB_LINK_NOT_CONFIGURED_8505 = 0,
+       USB_LINK_STD_HOST_NC_8505,
+       USB_LINK_STD_HOST_C_NS_8505,
+       USB_LINK_STD_HOST_C_S_8505,
+       USB_LINK_CDP_8505,
+       USB_LINK_RESERVED0_8505,
+       USB_LINK_RESERVED1_8505,
+       USB_LINK_DEDICATED_CHG_8505,
+       USB_LINK_ACA_RID_A_8505,
+       USB_LINK_ACA_RID_B_8505,
+       USB_LINK_ACA_RID_C_NM_8505,
+       USB_LINK_RESERVED2_8505,
+       USB_LINK_RESERVED3_8505,
+       USB_LINK_HM_IDGND_8505,
+       USB_LINK_CHARGERPORT_NOT_OK_8505,
+       USB_LINK_CHARGER_DM_HIGH_8505,
+       USB_LINK_PHYEN_NO_VBUS_NO_IDGND_8505,
+       USB_LINK_STD_UPSTREAM_NO_IDGNG_NO_VBUS_8505,
+       USB_LINK_STD_UPSTREAM_8505,
+       USB_LINK_CHARGER_SE1_8505,
+       USB_LINK_CARKIT_CHGR_1_8505,
+       USB_LINK_CARKIT_CHGR_2_8505,
+       USB_LINK_ACA_DOCK_CHGR_8505,
+       USB_LINK_SAMSUNG_BOOT_CBL_PHY_EN_8505,
+       USB_LINK_SAMSUNG_BOOT_CBL_PHY_DISB_8505,
+       USB_LINK_SAMSUNG_UART_CBL_PHY_EN_8505,
+       USB_LINK_SAMSUNG_UART_CBL_PHY_DISB_8505,
+       USB_LINK_MOTOROLA_FACTORY_CBL_PHY_EN_8505,
+};
+
+enum ab8500_usb_mode {
+       USB_IDLE = 0,
+       USB_PERIPHERAL,
+       USB_HOST,
+       USB_DEDICATED_CHG
+};
+
+struct ab8500_usb {
+       struct usb_phy phy;
+       struct device *dev;
+       struct ab8500 *ab8500;
+       unsigned vbus_draw;
+       struct work_struct phy_dis_work;
+       enum ab8500_usb_mode mode;
+       struct regulator *v_ape;
+       struct regulator *v_musb;
+       struct regulator *v_ulpi;
+       int saved_v_ulpi;
+       int previous_link_status_state;
+       struct pinctrl *pinctrl;
+       struct pinctrl_state *pins_sleep;
+};
+
+static inline struct ab8500_usb *phy_to_ab(struct usb_phy *x)
+{
+       return container_of(x, struct ab8500_usb, phy);
+}
+
+static void ab8500_usb_wd_workaround(struct ab8500_usb *ab)
+{
+       abx500_set_register_interruptible(ab->dev,
+               AB8500_SYS_CTRL2_BLOCK,
+               AB8500_MAIN_WD_CTRL_REG,
+               AB8500_BIT_WD_CTRL_ENABLE);
+
+       udelay(AB8500_WD_KICK_DELAY_US);
+
+       abx500_set_register_interruptible(ab->dev,
+               AB8500_SYS_CTRL2_BLOCK,
+               AB8500_MAIN_WD_CTRL_REG,
+               (AB8500_BIT_WD_CTRL_ENABLE
+               | AB8500_BIT_WD_CTRL_KICK));
+
+       udelay(AB8500_WD_V11_DISABLE_DELAY_US);
+
+       abx500_set_register_interruptible(ab->dev,
+               AB8500_SYS_CTRL2_BLOCK,
+               AB8500_MAIN_WD_CTRL_REG,
+               0);
+}
+
+static void ab8500_usb_regulator_enable(struct ab8500_usb *ab)
+{
+       int ret, volt;
+
+       ret = regulator_enable(ab->v_ape);
+       if (ret)
+               dev_err(ab->dev, "Failed to enable v-ape\n");
+
+       if (!is_ab8500_2p0_or_earlier(ab->ab8500)) {
+               ab->saved_v_ulpi = regulator_get_voltage(ab->v_ulpi);
+               if (ab->saved_v_ulpi < 0)
+                       dev_err(ab->dev, "Failed to get v_ulpi voltage\n");
+
+               ret = regulator_set_voltage(ab->v_ulpi, 1300000, 1350000);
+               if (ret < 0)
+                       dev_err(ab->dev, "Failed to set the Vintcore to 1.3V, ret=%d\n",
+                                       ret);
+
+               ret = regulator_set_optimum_mode(ab->v_ulpi, 28000);
+               if (ret < 0)
+                       dev_err(ab->dev, "Failed to set optimum mode (ret=%d)\n",
+                                       ret);
+       }
+
+       ret = regulator_enable(ab->v_ulpi);
+       if (ret)
+               dev_err(ab->dev, "Failed to enable vddulpivio18\n");
+
+       if (!is_ab8500_2p0_or_earlier(ab->ab8500)) {
+               volt = regulator_get_voltage(ab->v_ulpi);
+               if ((volt != 1300000) && (volt != 1350000))
+                       dev_err(ab->dev, "Vintcore is not set to 1.3V volt=%d\n",
+                                       volt);
+       }
+
+       ret = regulator_enable(ab->v_musb);
+       if (ret)
+               dev_err(ab->dev, "Failed to enable musb_1v8\n");
+}
+
+static void ab8500_usb_regulator_disable(struct ab8500_usb *ab)
+{
+       int ret;
+
+       regulator_disable(ab->v_musb);
+
+       regulator_disable(ab->v_ulpi);
+
+       /* USB is not the only consumer of Vintcore, restore old settings */
+       if (!is_ab8500_2p0_or_earlier(ab->ab8500)) {
+               if (ab->saved_v_ulpi > 0) {
+                       ret = regulator_set_voltage(ab->v_ulpi,
+                                       ab->saved_v_ulpi, ab->saved_v_ulpi);
+                       if (ret < 0)
+                               dev_err(ab->dev, "Failed to set the Vintcore to %duV, ret=%d\n",
+                                               ab->saved_v_ulpi, ret);
+               }
+
+               ret = regulator_set_optimum_mode(ab->v_ulpi, 0);
+               if (ret < 0)
+                       dev_err(ab->dev, "Failed to set optimum mode (ret=%d)\n",
+                                       ret);
+       }
+
+       regulator_disable(ab->v_ape);
+}
+
+static void ab8500_usb_wd_linkstatus(struct ab8500_usb *ab, u8 bit)
+{
+       /* Workaround for v2.0 bug # 31952 */
+       if (is_ab8500_2p0(ab->ab8500)) {
+               abx500_mask_and_set_register_interruptible(ab->dev,
+                               AB8500_USB, AB8500_USB_PHY_CTRL_REG,
+                               bit, bit);
+               udelay(AB8500_V20_31952_DISABLE_DELAY_US);
+       }
+}
+
+static void ab8500_usb_phy_enable(struct ab8500_usb *ab, bool sel_host)
+{
+       u8 bit;
+       bit = sel_host ? AB8500_BIT_PHY_CTRL_HOST_EN :
+               AB8500_BIT_PHY_CTRL_DEVICE_EN;
+
+       /* mux and configure USB pins to DEFAULT state */
+       ab->pinctrl = pinctrl_get_select(ab->dev, PINCTRL_STATE_DEFAULT);
+       if (IS_ERR(ab->pinctrl))
+               dev_err(ab->dev, "could not get/set default pinstate\n");
+
+       ab8500_usb_regulator_enable(ab);
+
+       abx500_mask_and_set_register_interruptible(ab->dev,
+                       AB8500_USB, AB8500_USB_PHY_CTRL_REG,
+                       bit, bit);
+}
+
+static void ab8500_usb_phy_disable(struct ab8500_usb *ab, bool sel_host)
+{
+       u8 bit;
+       bit = sel_host ? AB8500_BIT_PHY_CTRL_HOST_EN :
+               AB8500_BIT_PHY_CTRL_DEVICE_EN;
+
+       ab8500_usb_wd_linkstatus(ab, bit);
+
+       abx500_mask_and_set_register_interruptible(ab->dev,
+                       AB8500_USB, AB8500_USB_PHY_CTRL_REG,
+                       bit, 0);
+
+       /* Needed to disable the phy.*/
+       ab8500_usb_wd_workaround(ab);
+
+       ab8500_usb_regulator_disable(ab);
+
+       if (!IS_ERR(ab->pinctrl)) {
+               /* configure USB pins to SLEEP state */
+               ab->pins_sleep = pinctrl_lookup_state(ab->pinctrl,
+                               PINCTRL_STATE_SLEEP);
+
+               if (IS_ERR(ab->pins_sleep))
+                       dev_dbg(ab->dev, "could not get sleep pinstate\n");
+               else if (pinctrl_select_state(ab->pinctrl, ab->pins_sleep))
+                       dev_err(ab->dev, "could not set pins to sleep state\n");
+
+               /* as USB pins are shared with idddet, release them to allow
+                * iddet to request them
+                */
+               pinctrl_put(ab->pinctrl);
+       }
+}
+
+#define ab8500_usb_host_phy_en(ab)     ab8500_usb_phy_enable(ab, true)
+#define ab8500_usb_host_phy_dis(ab)    ab8500_usb_phy_disable(ab, true)
+#define ab8500_usb_peri_phy_en(ab)     ab8500_usb_phy_enable(ab, false)
+#define ab8500_usb_peri_phy_dis(ab)    ab8500_usb_phy_disable(ab, false)
+
+static int ab8505_usb_link_status_update(struct ab8500_usb *ab,
+               enum ab8505_usb_link_status lsts)
+{
+       enum ux500_musb_vbus_id_status event = 0;
+
+       dev_dbg(ab->dev, "ab8505_usb_link_status_update %d\n", lsts);
+
+       /*
+        * Spurious link_status interrupts are seen at the time of
+        * disconnection of a device in RIDA state
+        */
+       if (ab->previous_link_status_state == USB_LINK_ACA_RID_A_8505 &&
+                       (lsts == USB_LINK_STD_HOST_NC_8505))
+               return 0;
+
+       ab->previous_link_status_state = lsts;
+
+       switch (lsts) {
+       case USB_LINK_ACA_RID_B_8505:
+               event = UX500_MUSB_RIDB;
+       case USB_LINK_NOT_CONFIGURED_8505:
+       case USB_LINK_RESERVED0_8505:
+       case USB_LINK_RESERVED1_8505:
+       case USB_LINK_RESERVED2_8505:
+       case USB_LINK_RESERVED3_8505:
+               ab->mode = USB_IDLE;
+               ab->phy.otg->default_a = false;
+               ab->vbus_draw = 0;
+               if (event != UX500_MUSB_RIDB)
+                       event = UX500_MUSB_NONE;
+               /*
+                * Fallback to default B_IDLE as nothing
+                * is connected
+                */
+               ab->phy.state = OTG_STATE_B_IDLE;
+               break;
+
+       case USB_LINK_ACA_RID_C_NM_8505:
+               event = UX500_MUSB_RIDC;
+       case USB_LINK_STD_HOST_NC_8505:
+       case USB_LINK_STD_HOST_C_NS_8505:
+       case USB_LINK_STD_HOST_C_S_8505:
+       case USB_LINK_CDP_8505:
+               if (ab->mode == USB_IDLE) {
+                       ab->mode = USB_PERIPHERAL;
+                       ab8500_usb_peri_phy_en(ab);
+                       atomic_notifier_call_chain(&ab->phy.notifier,
+                                       UX500_MUSB_PREPARE, &ab->vbus_draw);
+               }
+               if (event != UX500_MUSB_RIDC)
+                       event = UX500_MUSB_VBUS;
+               break;
+
+       case USB_LINK_ACA_RID_A_8505:
+       case USB_LINK_ACA_DOCK_CHGR_8505:
+               event = UX500_MUSB_RIDA;
+       case USB_LINK_HM_IDGND_8505:
+               if (ab->mode == USB_IDLE) {
+                       ab->mode = USB_HOST;
+                       ab8500_usb_host_phy_en(ab);
+                       atomic_notifier_call_chain(&ab->phy.notifier,
+                                       UX500_MUSB_PREPARE, &ab->vbus_draw);
+               }
+               ab->phy.otg->default_a = true;
+               if (event != UX500_MUSB_RIDA)
+                       event = UX500_MUSB_ID;
+               atomic_notifier_call_chain(&ab->phy.notifier,
+                               event, &ab->vbus_draw);
+               break;
+
+       case USB_LINK_DEDICATED_CHG_8505:
+               ab->mode = USB_DEDICATED_CHG;
+               event = UX500_MUSB_CHARGER;
+               atomic_notifier_call_chain(&ab->phy.notifier,
+                               event, &ab->vbus_draw);
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int ab8500_usb_link_status_update(struct ab8500_usb *ab,
+               enum ab8500_usb_link_status lsts)
+{
+       enum ux500_musb_vbus_id_status event = 0;
+
+       dev_dbg(ab->dev, "ab8500_usb_link_status_update %d\n", lsts);
+
+       /*
+        * Spurious link_status interrupts are seen in case of a
+        * disconnection of a device in IDGND and RIDA stage
+        */
+       if (ab->previous_link_status_state == USB_LINK_HM_IDGND_8500 &&
+                       (lsts == USB_LINK_STD_HOST_C_NS_8500 ||
+                        lsts == USB_LINK_STD_HOST_NC_8500))
+               return 0;
+
+       if (ab->previous_link_status_state == USB_LINK_ACA_RID_A_8500 &&
+                       lsts == USB_LINK_STD_HOST_NC_8500)
+               return 0;
+
+       ab->previous_link_status_state = lsts;
+
+       switch (lsts) {
+       case USB_LINK_ACA_RID_B_8500:
+               event = UX500_MUSB_RIDB;
+       case USB_LINK_NOT_CONFIGURED_8500:
+       case USB_LINK_NOT_VALID_LINK_8500:
+               ab->mode = USB_IDLE;
+               ab->phy.otg->default_a = false;
+               ab->vbus_draw = 0;
+               if (event != UX500_MUSB_RIDB)
+                       event = UX500_MUSB_NONE;
+               /* Fallback to default B_IDLE as nothing is connected */
+               ab->phy.state = OTG_STATE_B_IDLE;
+               break;
+
+       case USB_LINK_ACA_RID_C_NM_8500:
+       case USB_LINK_ACA_RID_C_HS_8500:
+       case USB_LINK_ACA_RID_C_HS_CHIRP_8500:
+               event = UX500_MUSB_RIDC;
+       case USB_LINK_STD_HOST_NC_8500:
+       case USB_LINK_STD_HOST_C_NS_8500:
+       case USB_LINK_STD_HOST_C_S_8500:
+       case USB_LINK_HOST_CHG_NM_8500:
+       case USB_LINK_HOST_CHG_HS_8500:
+       case USB_LINK_HOST_CHG_HS_CHIRP_8500:
+               if (ab->mode == USB_IDLE) {
+                       ab->mode = USB_PERIPHERAL;
+                       ab8500_usb_peri_phy_en(ab);
+                       atomic_notifier_call_chain(&ab->phy.notifier,
+                                       UX500_MUSB_PREPARE, &ab->vbus_draw);
+               }
+               if (event != UX500_MUSB_RIDC)
+                       event = UX500_MUSB_VBUS;
+               break;
+
+       case USB_LINK_ACA_RID_A_8500:
+               event = UX500_MUSB_RIDA;
+       case USB_LINK_HM_IDGND_8500:
+               if (ab->mode == USB_IDLE) {
+                       ab->mode = USB_HOST;
+                       ab8500_usb_host_phy_en(ab);
+                       atomic_notifier_call_chain(&ab->phy.notifier,
+                                       UX500_MUSB_PREPARE, &ab->vbus_draw);
+               }
+               ab->phy.otg->default_a = true;
+               if (event != UX500_MUSB_RIDA)
+                       event = UX500_MUSB_ID;
+               atomic_notifier_call_chain(&ab->phy.notifier,
+                               event, &ab->vbus_draw);
+               break;
+
+       case USB_LINK_DEDICATED_CHG_8500:
+               ab->mode = USB_DEDICATED_CHG;
+               event = UX500_MUSB_CHARGER;
+               atomic_notifier_call_chain(&ab->phy.notifier,
+                               event, &ab->vbus_draw);
+               break;
+
+       case USB_LINK_RESERVED_8500:
+               break;
+       }
+
+       return 0;
+}
+
+/*
+ * Connection Sequence:
+ *   1. Link Status Interrupt
+ *   2. Enable AB clock
+ *   3. Enable AB regulators
+ *   4. Enable USB phy
+ *   5. Reset the musb controller
+ *   6. Switch the ULPI GPIO pins to fucntion mode
+ *   7. Enable the musb Peripheral5 clock
+ *   8. Restore MUSB context
+ */
+static int abx500_usb_link_status_update(struct ab8500_usb *ab)
+{
+       u8 reg;
+       int ret = 0;
+
+       if (is_ab8500(ab->ab8500)) {
+               enum ab8500_usb_link_status lsts;
+
+               abx500_get_register_interruptible(ab->dev,
+                               AB8500_USB, AB8500_USB_LINE_STAT_REG, &reg);
+               lsts = (reg >> 3) & 0x0F;
+               ret = ab8500_usb_link_status_update(ab, lsts);
+       } else if (is_ab8505(ab->ab8500)) {
+               enum ab8505_usb_link_status lsts;
+
+               abx500_get_register_interruptible(ab->dev,
+                               AB8500_USB, AB8505_USB_LINE_STAT_REG, &reg);
+               lsts = (reg >> 3) & 0x1F;
+               ret = ab8505_usb_link_status_update(ab, lsts);
+       }
+
+       return ret;
+}
+
+/*
+ * Disconnection Sequence:
+ *   1. Disconect Interrupt
+ *   2. Disable regulators
+ *   3. Disable AB clock
+ *   4. Disable the Phy
+ *   5. Link Status Interrupt
+ *   6. Disable Musb Clock
+ */
+static irqreturn_t ab8500_usb_disconnect_irq(int irq, void *data)
+{
+       struct ab8500_usb *ab = (struct ab8500_usb *) data;
+       enum usb_phy_events event = UX500_MUSB_NONE;
+
+       /* Link status will not be updated till phy is disabled. */
+       if (ab->mode == USB_HOST) {
+               ab->phy.otg->default_a = false;
+               ab->vbus_draw = 0;
+               atomic_notifier_call_chain(&ab->phy.notifier,
+                               event, &ab->vbus_draw);
+               ab8500_usb_host_phy_dis(ab);
+               ab->mode = USB_IDLE;
+       }
+
+       if (ab->mode == USB_PERIPHERAL) {
+               atomic_notifier_call_chain(&ab->phy.notifier,
+                               event, &ab->vbus_draw);
+               ab8500_usb_peri_phy_dis(ab);
+               atomic_notifier_call_chain(&ab->phy.notifier,
+                               UX500_MUSB_CLEAN, &ab->vbus_draw);
+               ab->mode = USB_IDLE;
+               ab->phy.otg->default_a = false;
+               ab->vbus_draw = 0;
+       }
+
+       if (is_ab8500_2p0(ab->ab8500)) {
+               if (ab->mode == USB_DEDICATED_CHG) {
+                       ab8500_usb_wd_linkstatus(ab,
+                                       AB8500_BIT_PHY_CTRL_DEVICE_EN);
+                       abx500_mask_and_set_register_interruptible(ab->dev,
+                                       AB8500_USB, AB8500_USB_PHY_CTRL_REG,
+                                       AB8500_BIT_PHY_CTRL_DEVICE_EN, 0);
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t ab8500_usb_link_status_irq(int irq, void *data)
+{
+       struct ab8500_usb *ab = (struct ab8500_usb *) data;
+
+       abx500_usb_link_status_update(ab);
+
+       return IRQ_HANDLED;
+}
+
+static void ab8500_usb_phy_disable_work(struct work_struct *work)
+{
+       struct ab8500_usb *ab = container_of(work, struct ab8500_usb,
+                                               phy_dis_work);
+
+       if (!ab->phy.otg->host)
+               ab8500_usb_host_phy_dis(ab);
+
+       if (!ab->phy.otg->gadget)
+               ab8500_usb_peri_phy_dis(ab);
+}
+
+static unsigned ab8500_eyediagram_workaroud(struct ab8500_usb *ab, unsigned mA)
+{
+       /*
+        * AB8500 V2 has eye diagram issues when drawing more than 100mA from
+        * VBUS.  Set charging current to 100mA in case of standard host
+        */
+       if (is_ab8500_2p0_or_earlier(ab->ab8500))
+               if (mA > 100)
+                       mA = 100;
+
+       return mA;
+}
+
+static int ab8500_usb_set_power(struct usb_phy *phy, unsigned mA)
+{
+       struct ab8500_usb *ab;
+
+       if (!phy)
+               return -ENODEV;
+
+       ab = phy_to_ab(phy);
+
+       mA = ab8500_eyediagram_workaroud(ab, mA);
+
+       ab->vbus_draw = mA;
+
+       atomic_notifier_call_chain(&ab->phy.notifier,
+                       UX500_MUSB_VBUS, &ab->vbus_draw);
+
+       return 0;
+}
+
+static int ab8500_usb_set_suspend(struct usb_phy *x, int suspend)
+{
+       /* TODO */
+       return 0;
+}
+
+static int ab8500_usb_set_peripheral(struct usb_otg *otg,
+                                       struct usb_gadget *gadget)
+{
+       struct ab8500_usb *ab;
+
+       if (!otg)
+               return -ENODEV;
+
+       ab = phy_to_ab(otg->phy);
+
+       ab->phy.otg->gadget = gadget;
+
+       /* Some drivers call this function in atomic context.
+        * Do not update ab8500 registers directly till this
+        * is fixed.
+        */
+
+       if ((ab->mode != USB_IDLE) && (!gadget)) {
+               ab->mode = USB_IDLE;
+               schedule_work(&ab->phy_dis_work);
+       }
+
+       return 0;
+}
+
+static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+       struct ab8500_usb *ab;
+
+       if (!otg)
+               return -ENODEV;
+
+       ab = phy_to_ab(otg->phy);
+
+       ab->phy.otg->host = host;
+
+       /* Some drivers call this function in atomic context.
+        * Do not update ab8500 registers directly till this
+        * is fixed.
+        */
+
+       if ((ab->mode != USB_IDLE) && (!host)) {
+               ab->mode = USB_IDLE;
+               schedule_work(&ab->phy_dis_work);
+       }
+
+       return 0;
+}
+
+static int ab8500_usb_regulator_get(struct ab8500_usb *ab)
+{
+       int err;
+
+       ab->v_ape = devm_regulator_get(ab->dev, "v-ape");
+       if (IS_ERR(ab->v_ape)) {
+               dev_err(ab->dev, "Could not get v-ape supply\n");
+               err = PTR_ERR(ab->v_ape);
+               return err;
+       }
+
+       ab->v_ulpi = devm_regulator_get(ab->dev, "vddulpivio18");
+       if (IS_ERR(ab->v_ulpi)) {
+               dev_err(ab->dev, "Could not get vddulpivio18 supply\n");
+               err = PTR_ERR(ab->v_ulpi);
+               return err;
+       }
+
+       ab->v_musb = devm_regulator_get(ab->dev, "musb_1v8");
+       if (IS_ERR(ab->v_musb)) {
+               dev_err(ab->dev, "Could not get musb_1v8 supply\n");
+               err = PTR_ERR(ab->v_musb);
+               return err;
+       }
+
+       return 0;
+}
+
+static int ab8500_usb_irq_setup(struct platform_device *pdev,
+               struct ab8500_usb *ab)
+{
+       int err;
+       int irq;
+
+       irq = platform_get_irq_byname(pdev, "USB_LINK_STATUS");
+       if (irq < 0) {
+               dev_err(&pdev->dev, "Link status irq not found\n");
+               return irq;
+       }
+       err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+                       ab8500_usb_link_status_irq,
+                       IRQF_NO_SUSPEND | IRQF_SHARED, "usb-link-status", ab);
+       if (err < 0) {
+               dev_err(ab->dev, "request_irq failed for link status irq\n");
+               return err;
+       }
+
+       irq = platform_get_irq_byname(pdev, "ID_WAKEUP_F");
+       if (irq < 0) {
+               dev_err(&pdev->dev, "ID fall irq not found\n");
+               return irq;
+       }
+       err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+                       ab8500_usb_disconnect_irq,
+                       IRQF_NO_SUSPEND | IRQF_SHARED, "usb-id-fall", ab);
+       if (err < 0) {
+               dev_err(ab->dev, "request_irq failed for ID fall irq\n");
+               return err;
+       }
+
+       irq = platform_get_irq_byname(pdev, "VBUS_DET_F");
+       if (irq < 0) {
+               dev_err(&pdev->dev, "VBUS fall irq not found\n");
+               return irq;
+       }
+       err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+                       ab8500_usb_disconnect_irq,
+                       IRQF_NO_SUSPEND | IRQF_SHARED, "usb-vbus-fall", ab);
+       if (err < 0) {
+               dev_err(ab->dev, "request_irq failed for Vbus fall irq\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static int ab8500_usb_probe(struct platform_device *pdev)
+{
+       struct ab8500_usb       *ab;
+       struct ab8500           *ab8500;
+       struct usb_otg          *otg;
+       int err;
+       int rev;
+
+       ab8500 = dev_get_drvdata(pdev->dev.parent);
+       rev = abx500_get_chip_id(&pdev->dev);
+
+       if (is_ab8500_1p1_or_earlier(ab8500)) {
+               dev_err(&pdev->dev, "Unsupported AB8500 chip rev=%d\n", rev);
+               return -ENODEV;
+       }
+
+       ab = devm_kzalloc(&pdev->dev, sizeof(*ab), GFP_KERNEL);
+       if (!ab)
+               return -ENOMEM;
+
+       otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL);
+       if (!otg)
+               return -ENOMEM;
+
+       ab->dev                 = &pdev->dev;
+       ab->ab8500              = ab8500;
+       ab->phy.dev             = ab->dev;
+       ab->phy.otg             = otg;
+       ab->phy.label           = "ab8500";
+       ab->phy.set_suspend     = ab8500_usb_set_suspend;
+       ab->phy.set_power       = ab8500_usb_set_power;
+       ab->phy.state           = OTG_STATE_UNDEFINED;
+
+       otg->phy                = &ab->phy;
+       otg->set_host           = ab8500_usb_set_host;
+       otg->set_peripheral     = ab8500_usb_set_peripheral;
+
+       platform_set_drvdata(pdev, ab);
+
+       ATOMIC_INIT_NOTIFIER_HEAD(&ab->phy.notifier);
+
+       /* all: Disable phy when called from set_host and set_peripheral */
+       INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work);
+
+       err = ab8500_usb_regulator_get(ab);
+       if (err)
+               return err;
+
+       err = ab8500_usb_irq_setup(pdev, ab);
+       if (err < 0)
+               return err;
+
+       err = usb_add_phy(&ab->phy, USB_PHY_TYPE_USB2);
+       if (err) {
+               dev_err(&pdev->dev, "Can't register transceiver\n");
+               return err;
+       }
+
+       /* Phy tuning values for AB8500 */
+       if (!is_ab8500_2p0_or_earlier(ab->ab8500)) {
+               /* Enable the PBT/Bank 0x12 access */
+               err = abx500_set_register_interruptible(ab->dev,
+                               AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS, 0x01);
+               if (err < 0)
+                       dev_err(ab->dev, "Failed to enable bank12 access err=%d\n",
+                                       err);
+
+               err = abx500_set_register_interruptible(ab->dev,
+                               AB8500_DEBUG, AB8500_USB_PHY_TUNE1, 0xC8);
+               if (err < 0)
+                       dev_err(ab->dev, "Failed to set PHY_TUNE1 register err=%d\n",
+                                       err);
+
+               err = abx500_set_register_interruptible(ab->dev,
+                               AB8500_DEBUG, AB8500_USB_PHY_TUNE2, 0x00);
+               if (err < 0)
+                       dev_err(ab->dev, "Failed to set PHY_TUNE2 register err=%d\n",
+                                       err);
+
+               err = abx500_set_register_interruptible(ab->dev,
+                               AB8500_DEBUG, AB8500_USB_PHY_TUNE3, 0x78);
+               if (err < 0)
+                       dev_err(ab->dev, "Failed to set PHY_TUNE3 regester err=%d\n",
+                                       err);
+
+               /* Switch to normal mode/disable Bank 0x12 access */
+               err = abx500_set_register_interruptible(ab->dev,
+                               AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS, 0x00);
+               if (err < 0)
+                       dev_err(ab->dev, "Failed to switch bank12 access err=%d\n",
+                                       err);
+       }
+
+       /* Phy tuning values for AB8505 */
+       if (is_ab8505(ab->ab8500)) {
+               /* Enable the PBT/Bank 0x12 access */
+               err = abx500_mask_and_set_register_interruptible(ab->dev,
+                               AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS,
+                               0x01, 0x01);
+               if (err < 0)
+                       dev_err(ab->dev, "Failed to enable bank12 access err=%d\n",
+                                       err);
+
+               err = abx500_mask_and_set_register_interruptible(ab->dev,
+                               AB8500_DEBUG, AB8500_USB_PHY_TUNE1,
+                               0xC8, 0xC8);
+               if (err < 0)
+                       dev_err(ab->dev, "Failed to set PHY_TUNE1 register err=%d\n",
+                                       err);
+
+               err = abx500_mask_and_set_register_interruptible(ab->dev,
+                               AB8500_DEBUG, AB8500_USB_PHY_TUNE2,
+                               0x60, 0x60);
+               if (err < 0)
+                       dev_err(ab->dev, "Failed to set PHY_TUNE2 register err=%d\n",
+                                       err);
+
+               err = abx500_mask_and_set_register_interruptible(ab->dev,
+                               AB8500_DEBUG, AB8500_USB_PHY_TUNE3,
+                               0xFC, 0x80);
+
+               if (err < 0)
+                       dev_err(ab->dev, "Failed to set PHY_TUNE3 regester err=%d\n",
+                                       err);
+
+               /* Switch to normal mode/disable Bank 0x12 access */
+               err = abx500_mask_and_set_register_interruptible(ab->dev,
+                               AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS,
+                               0x00, 0x00);
+               if (err < 0)
+                       dev_err(ab->dev, "Failed to switch bank12 access err=%d\n",
+                                       err);
+       }
+
+       /* Needed to enable ID detection. */
+       ab8500_usb_wd_workaround(ab);
+
+       abx500_usb_link_status_update(ab);
+
+       dev_info(&pdev->dev, "revision 0x%2x driver initialized\n", rev);
+
+       return 0;
+}
+
+static int ab8500_usb_remove(struct platform_device *pdev)
+{
+       struct ab8500_usb *ab = platform_get_drvdata(pdev);
+
+       cancel_work_sync(&ab->phy_dis_work);
+
+       usb_remove_phy(&ab->phy);
+
+       if (ab->mode == USB_HOST)
+               ab8500_usb_host_phy_dis(ab);
+       else if (ab->mode == USB_PERIPHERAL)
+               ab8500_usb_peri_phy_dis(ab);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver ab8500_usb_driver = {
+       .probe          = ab8500_usb_probe,
+       .remove         = ab8500_usb_remove,
+       .driver         = {
+               .name   = "ab8500-usb",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init ab8500_usb_init(void)
+{
+       return platform_driver_register(&ab8500_usb_driver);
+}
+subsys_initcall(ab8500_usb_init);
+
+static void __exit ab8500_usb_exit(void)
+{
+       platform_driver_unregister(&ab8500_usb_driver);
+}
+module_exit(ab8500_usb_exit);
+
+MODULE_ALIAS("platform:ab8500_usb");
+MODULE_AUTHOR("ST-Ericsson AB");
+MODULE_DESCRIPTION("AB8500 usb transceiver driver");
+MODULE_LICENSE("GPL");
similarity index 97%
rename from drivers/usb/otg/fsl_otg.c
rename to drivers/usb/phy/phy-fsl-usb.c
index d16adb4..97b9308 100644 (file)
@@ -43,7 +43,7 @@
 
 #include <asm/unaligned.h>
 
-#include "fsl_otg.h"
+#include "phy-fsl-usb.h"
 
 #define DRIVER_VERSION "Rev. 1.55"
 #define DRIVER_AUTHOR "Jerry Huang/Li Yang"
@@ -361,28 +361,18 @@ int fsl_otg_init_timers(struct otg_fsm *fsm)
 void fsl_otg_uninit_timers(void)
 {
        /* FSM used timers */
-       if (a_wait_vrise_tmr != NULL)
-               kfree(a_wait_vrise_tmr);
-       if (a_wait_bcon_tmr != NULL)
-               kfree(a_wait_bcon_tmr);
-       if (a_aidl_bdis_tmr != NULL)
-               kfree(a_aidl_bdis_tmr);
-       if (b_ase0_brst_tmr != NULL)
-               kfree(b_ase0_brst_tmr);
-       if (b_se0_srp_tmr != NULL)
-               kfree(b_se0_srp_tmr);
-       if (b_srp_fail_tmr != NULL)
-               kfree(b_srp_fail_tmr);
-       if (a_wait_enum_tmr != NULL)
-               kfree(a_wait_enum_tmr);
+       kfree(a_wait_vrise_tmr);
+       kfree(a_wait_bcon_tmr);
+       kfree(a_aidl_bdis_tmr);
+       kfree(b_ase0_brst_tmr);
+       kfree(b_se0_srp_tmr);
+       kfree(b_srp_fail_tmr);
+       kfree(a_wait_enum_tmr);
 
        /* device driver used timers */
-       if (b_srp_wait_tmr != NULL)
-               kfree(b_srp_wait_tmr);
-       if (b_data_pulse_tmr != NULL)
-               kfree(b_data_pulse_tmr);
-       if (b_vbus_pulse_tmr != NULL)
-               kfree(b_vbus_pulse_tmr);
+       kfree(b_srp_wait_tmr);
+       kfree(b_data_pulse_tmr);
+       kfree(b_vbus_pulse_tmr);
 }
 
 /* Add timer to timer list */
@@ -1002,7 +992,7 @@ static int show_fsl_usb2_otg_state(struct device *dev,
        /* State */
        t = scnprintf(next, size,
                      "OTG state: %s\n\n",
-                     otg_state_string(fsl_otg_dev->phy.state));
+                     usb_otg_state_string(fsl_otg_dev->phy.state));
        size -= t;
        next += t;
 
similarity index 99%
rename from drivers/usb/otg/otg_fsm.c
rename to drivers/usb/phy/phy-fsm-usb.c
index ade131a..c520b35 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 
-#include "otg_fsm.h"
+#include "phy-otg-fsm.h"
 
 /* Change USB protocol when there is a protocol change */
 static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
@@ -119,7 +119,7 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
        state_changed = 1;
        if (fsm->otg->phy->state == new_state)
                return 0;
-       VDBG("Set state: %s\n", otg_state_string(new_state));
+       VDBG("Set state: %s\n", usb_otg_state_string(new_state));
        otg_leave_state(fsm, fsm->otg->phy->state);
        switch (new_state) {
        case OTG_STATE_B_IDLE:
similarity index 98%
rename from drivers/usb/otg/gpio_vbus.c
rename to drivers/usb/phy/phy-gpio-vbus-usb.c
index a7d4ac5..4c76074 100644 (file)
@@ -61,6 +61,7 @@ static void set_vbus_draw(struct gpio_vbus_data *gpio_vbus, unsigned mA)
 {
        struct regulator *vbus_draw = gpio_vbus->vbus_draw;
        int enabled;
+       int ret;
 
        if (!vbus_draw)
                return;
@@ -69,12 +70,16 @@ static void set_vbus_draw(struct gpio_vbus_data *gpio_vbus, unsigned mA)
        if (mA) {
                regulator_set_current_limit(vbus_draw, 0, 1000 * mA);
                if (!enabled) {
-                       regulator_enable(vbus_draw);
+                       ret = regulator_enable(vbus_draw);
+                       if (ret < 0)
+                               return;
                        gpio_vbus->vbus_draw_enabled = 1;
                }
        } else {
                if (enabled) {
-                       regulator_disable(vbus_draw);
+                       ret = regulator_disable(vbus_draw);
+                       if (ret < 0)
+                               return;
                        gpio_vbus->vbus_draw_enabled = 0;
                }
        }
similarity index 99%
rename from drivers/usb/otg/isp1301_omap.c
rename to drivers/usb/phy/phy-isp1301-omap.c
index 8b9de95..ae481af 100644 (file)
@@ -236,7 +236,7 @@ isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits)
 
 static inline const char *state_name(struct isp1301 *isp)
 {
-       return otg_state_string(isp->phy.state);
+       return usb_otg_state_string(isp->phy.state);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -481,7 +481,7 @@ static void check_state(struct isp1301 *isp, const char *tag)
        if (isp->phy.state == state && !extra)
                return;
        pr_debug("otg: %s FSM %s/%02x, %s, %06x\n", tag,
-               otg_state_string(state), fsm, state_name(isp),
+               usb_otg_state_string(state), fsm, state_name(isp),
                omap_readl(OTG_CTRL));
 }
 
@@ -1077,7 +1077,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
 
        if (state != isp->phy.state)
                pr_debug("  isp, %s -> %s\n",
-                               otg_state_string(state), state_name(isp));
+                               usb_otg_state_string(state), state_name(isp));
 
 #ifdef CONFIG_USB_OTG
        /* update the OTG controller state to match the isp1301; may
diff --git a/drivers/usb/phy/phy-isp1301.c b/drivers/usb/phy/phy-isp1301.c
new file mode 100644 (file)
index 0000000..225ae6c
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * NXP ISP1301 USB transceiver driver
+ *
+ * Copyright (C) 2012 Roland Stigge
+ *
+ * Author: Roland Stigge <stigge@antcom.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/i2c.h>
+#include <linux/usb/phy.h>
+#include <linux/usb/isp1301.h>
+
+#define DRV_NAME               "isp1301"
+
+struct isp1301 {
+       struct usb_phy          phy;
+       struct mutex            mutex;
+
+       struct i2c_client       *client;
+};
+
+#define phy_to_isp(p)          (container_of((p), struct isp1301, phy))
+
+static const struct i2c_device_id isp1301_id[] = {
+       { "isp1301", 0 },
+       { }
+};
+
+static struct i2c_client *isp1301_i2c_client;
+
+static int __isp1301_write(struct isp1301 *isp, u8 reg, u8 value, u8 clear)
+{
+       return i2c_smbus_write_byte_data(isp->client, reg | clear, value);
+}
+
+static int isp1301_write(struct isp1301 *isp, u8 reg, u8 value)
+{
+       return __isp1301_write(isp, reg, value, 0);
+}
+
+static int isp1301_clear(struct isp1301 *isp, u8 reg, u8 value)
+{
+       return __isp1301_write(isp, reg, value, ISP1301_I2C_REG_CLEAR_ADDR);
+}
+
+static int isp1301_phy_init(struct usb_phy *phy)
+{
+       struct isp1301 *isp = phy_to_isp(phy);
+
+       /* Disable transparent UART mode first */
+       isp1301_clear(isp, ISP1301_I2C_MODE_CONTROL_1, MC1_UART_EN);
+       isp1301_clear(isp, ISP1301_I2C_MODE_CONTROL_1, ~MC1_SPEED_REG);
+       isp1301_write(isp, ISP1301_I2C_MODE_CONTROL_1, MC1_SPEED_REG);
+       isp1301_clear(isp, ISP1301_I2C_MODE_CONTROL_2, ~0);
+       isp1301_write(isp, ISP1301_I2C_MODE_CONTROL_2, (MC2_BI_DI | MC2_PSW_EN
+                               | MC2_SPD_SUSP_CTRL));
+
+       isp1301_clear(isp, ISP1301_I2C_OTG_CONTROL_1, ~0);
+       isp1301_write(isp, ISP1301_I2C_MODE_CONTROL_1, MC1_DAT_SE0);
+       isp1301_write(isp, ISP1301_I2C_OTG_CONTROL_1, (OTG1_DM_PULLDOWN
+                               | OTG1_DP_PULLDOWN));
+       isp1301_clear(isp, ISP1301_I2C_OTG_CONTROL_1, (OTG1_DM_PULLUP
+                               | OTG1_DP_PULLUP));
+
+       /* mask all interrupts */
+       isp1301_clear(isp, ISP1301_I2C_INTERRUPT_LATCH, ~0);
+       isp1301_clear(isp, ISP1301_I2C_INTERRUPT_FALLING, ~0);
+       isp1301_clear(isp, ISP1301_I2C_INTERRUPT_RISING, ~0);
+
+       return 0;
+}
+
+static int isp1301_phy_set_vbus(struct usb_phy *phy, int on)
+{
+       struct isp1301 *isp = phy_to_isp(phy);
+
+       if (on)
+               isp1301_write(isp, ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DRV);
+       else
+               isp1301_clear(isp, ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DRV);
+
+       return 0;
+}
+
+static int isp1301_probe(struct i2c_client *client,
+                        const struct i2c_device_id *i2c_id)
+{
+       struct isp1301 *isp;
+       struct usb_phy *phy;
+
+       isp = devm_kzalloc(&client->dev, sizeof(*isp), GFP_KERNEL);
+       if (!isp)
+               return -ENOMEM;
+
+       isp->client = client;
+       mutex_init(&isp->mutex);
+
+       phy = &isp->phy;
+       phy->label = DRV_NAME;
+       phy->init = isp1301_phy_init;
+       phy->set_vbus = isp1301_phy_set_vbus;
+       phy->type = USB_PHY_TYPE_USB2;
+
+       i2c_set_clientdata(client, isp);
+       usb_add_phy_dev(phy);
+
+       isp1301_i2c_client = client;
+
+       return 0;
+}
+
+static int isp1301_remove(struct i2c_client *client)
+{
+       struct isp1301 *isp = i2c_get_clientdata(client);
+
+       usb_remove_phy(&isp->phy);
+       isp1301_i2c_client = NULL;
+
+       return 0;
+}
+
+static struct i2c_driver isp1301_driver = {
+       .driver = {
+               .name = DRV_NAME,
+       },
+       .probe = isp1301_probe,
+       .remove = isp1301_remove,
+       .id_table = isp1301_id,
+};
+
+module_i2c_driver(isp1301_driver);
+
+static int match(struct device *dev, void *data)
+{
+       struct device_node *node = (struct device_node *)data;
+       return (dev->of_node == node) &&
+               (dev->driver == &isp1301_driver.driver);
+}
+
+struct i2c_client *isp1301_get_client(struct device_node *node)
+{
+       if (node) { /* reference of ISP1301 I2C node via DT */
+               struct device *dev = bus_find_device(&i2c_bus_type, NULL,
+                                                    node, match);
+               if (!dev)
+                       return NULL;
+               return to_i2c_client(dev);
+       } else { /* non-DT: only one ISP1301 chip supported */
+               return isp1301_i2c_client;
+       }
+}
+EXPORT_SYMBOL_GPL(isp1301_get_client);
+
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("NXP ISP1301 USB transceiver driver");
+MODULE_LICENSE("GPL");
similarity index 99%
rename from drivers/usb/phy/mv_u3d_phy.c
rename to drivers/usb/phy/phy-mv-u3d-usb.c
index bafd67f..f7838a4 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/usb/otg.h>
 #include <linux/platform_data/mv_usb.h>
 
-#include "mv_u3d_phy.h"
+#include "phy-mv-u3d-usb.h"
 
 /*
  * struct mv_u3d_phy - transceiver driver state
similarity index 97%
rename from drivers/usb/otg/mv_otg.c
rename to drivers/usb/phy/phy-mv-usb.c
index b6a9be3..c987bbe 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/usb/hcd.h>
 #include <linux/platform_data/mv_usb.h>
 
-#include "mv_otg.h"
+#include "phy-mv-usb.h"
 
 #define        DRIVER_DESC     "Marvell USB OTG transceiver driver"
 #define        DRIVER_VERSION  "Jan 20, 2010"
@@ -237,18 +237,12 @@ static void mv_otg_start_periphrals(struct mv_otg *mvotg, int on)
 
 static void otg_clock_enable(struct mv_otg *mvotg)
 {
-       unsigned int i;
-
-       for (i = 0; i < mvotg->clknum; i++)
-               clk_prepare_enable(mvotg->clk[i]);
+       clk_prepare_enable(mvotg->clk);
 }
 
 static void otg_clock_disable(struct mv_otg *mvotg)
 {
-       unsigned int i;
-
-       for (i = 0; i < mvotg->clknum; i++)
-               clk_disable_unprepare(mvotg->clk[i]);
+       clk_disable_unprepare(mvotg->clk);
 }
 
 static int mv_otg_enable_internal(struct mv_otg *mvotg)
@@ -684,16 +678,14 @@ static int mv_otg_probe(struct platform_device *pdev)
        struct mv_otg *mvotg;
        struct usb_otg *otg;
        struct resource *r;
-       int retval = 0, clk_i, i;
-       size_t size;
+       int retval = 0, i;
 
        if (pdata == NULL) {
                dev_err(&pdev->dev, "failed to get platform data\n");
                return -ENODEV;
        }
 
-       size = sizeof(*mvotg) + sizeof(struct clk *) * pdata->clknum;
-       mvotg = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+       mvotg = devm_kzalloc(&pdev->dev, sizeof(*mvotg), GFP_KERNEL);
        if (!mvotg) {
                dev_err(&pdev->dev, "failed to allocate memory!\n");
                return -ENOMEM;
@@ -708,15 +700,9 @@ static int mv_otg_probe(struct platform_device *pdev)
        mvotg->pdev = pdev;
        mvotg->pdata = pdata;
 
-       mvotg->clknum = pdata->clknum;
-       for (clk_i = 0; clk_i < mvotg->clknum; clk_i++) {
-               mvotg->clk[clk_i] = devm_clk_get(&pdev->dev,
-                                               pdata->clkname[clk_i]);
-               if (IS_ERR(mvotg->clk[clk_i])) {
-                       retval = PTR_ERR(mvotg->clk[clk_i]);
-                       return retval;
-               }
-       }
+       mvotg->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(mvotg->clk))
+               return PTR_ERR(mvotg->clk);
 
        mvotg->qwork = create_singlethread_workqueue("mv_otg_queue");
        if (!mvotg->qwork) {
similarity index 99%
rename from drivers/usb/otg/mv_otg.h
rename to drivers/usb/phy/phy-mv-usb.h
index 8a9e351..551da6e 100644 (file)
@@ -158,8 +158,7 @@ struct mv_otg {
 
        unsigned int active;
        unsigned int clock_gating;
-       unsigned int clknum;
-       struct clk *clk[0];
+       struct clk *clk;
 };
 
 #endif
similarity index 84%
rename from drivers/usb/otg/mxs-phy.c
rename to drivers/usb/phy/phy-mxs-usb.c
index b0d9f11..9d4381e 100644 (file)
@@ -48,12 +48,12 @@ static void mxs_phy_hw_init(struct mxs_phy *mxs_phy)
        stmp_reset_block(base + HW_USBPHY_CTRL);
 
        /* Power up the PHY */
-       writel_relaxed(0, base + HW_USBPHY_PWD);
+       writel(0, base + HW_USBPHY_PWD);
 
        /* enable FS/LS device */
-       writel_relaxed(BM_USBPHY_CTRL_ENUTMILEVEL2 |
-                       BM_USBPHY_CTRL_ENUTMILEVEL3,
-                       base + HW_USBPHY_CTRL_SET);
+       writel(BM_USBPHY_CTRL_ENUTMILEVEL2 |
+              BM_USBPHY_CTRL_ENUTMILEVEL3,
+              base + HW_USBPHY_CTRL_SET);
 }
 
 static int mxs_phy_init(struct usb_phy *phy)
@@ -70,8 +70,8 @@ static void mxs_phy_shutdown(struct usb_phy *phy)
 {
        struct mxs_phy *mxs_phy = to_mxs_phy(phy);
 
-       writel_relaxed(BM_USBPHY_CTRL_CLKGATE,
-                       phy->io_priv + HW_USBPHY_CTRL_SET);
+       writel(BM_USBPHY_CTRL_CLKGATE,
+              phy->io_priv + HW_USBPHY_CTRL_SET);
 
        clk_disable_unprepare(mxs_phy->clk);
 }
@@ -81,15 +81,15 @@ static int mxs_phy_suspend(struct usb_phy *x, int suspend)
        struct mxs_phy *mxs_phy = to_mxs_phy(x);
 
        if (suspend) {
-               writel_relaxed(0xffffffff, x->io_priv + HW_USBPHY_PWD);
-               writel_relaxed(BM_USBPHY_CTRL_CLKGATE,
-                       x->io_priv + HW_USBPHY_CTRL_SET);
+               writel(0xffffffff, x->io_priv + HW_USBPHY_PWD);
+               writel(BM_USBPHY_CTRL_CLKGATE,
+                      x->io_priv + HW_USBPHY_CTRL_SET);
                clk_disable_unprepare(mxs_phy->clk);
        } else {
                clk_prepare_enable(mxs_phy->clk);
-               writel_relaxed(BM_USBPHY_CTRL_CLKGATE,
-                       x->io_priv + HW_USBPHY_CTRL_CLR);
-               writel_relaxed(0, x->io_priv + HW_USBPHY_PWD);
+               writel(BM_USBPHY_CTRL_CLKGATE,
+                      x->io_priv + HW_USBPHY_CTRL_CLR);
+               writel(0, x->io_priv + HW_USBPHY_PWD);
        }
 
        return 0;
@@ -102,8 +102,8 @@ static int mxs_phy_on_connect(struct usb_phy *phy,
                (speed == USB_SPEED_HIGH) ? "high" : "non-high");
 
        if (speed == USB_SPEED_HIGH)
-               writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
-                               phy->io_priv + HW_USBPHY_CTRL_SET);
+               writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+                      phy->io_priv + HW_USBPHY_CTRL_SET);
 
        return 0;
 }
@@ -115,8 +115,8 @@ static int mxs_phy_on_disconnect(struct usb_phy *phy,
                (speed == USB_SPEED_HIGH) ? "high" : "non-high");
 
        if (speed == USB_SPEED_HIGH)
-               writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
-                               phy->io_priv + HW_USBPHY_CTRL_CLR);
+               writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+                      phy->io_priv + HW_USBPHY_CTRL_CLR);
 
        return 0;
 }
@@ -127,6 +127,7 @@ static int mxs_phy_probe(struct platform_device *pdev)
        void __iomem *base;
        struct clk *clk;
        struct mxs_phy *mxs_phy;
+       int ret;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
@@ -166,11 +167,19 @@ static int mxs_phy_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, &mxs_phy->phy);
 
+       ret = usb_add_phy_dev(&mxs_phy->phy);
+       if (ret)
+               return ret;
+
        return 0;
 }
 
 static int mxs_phy_remove(struct platform_device *pdev)
 {
+       struct mxs_phy *mxs_phy = platform_get_drvdata(pdev);
+
+       usb_remove_phy(&mxs_phy->phy);
+
        platform_set_drvdata(pdev, NULL);
 
        return 0;
similarity index 55%
rename from drivers/usb/otg/nop-usb-xceiv.c
rename to drivers/usb/phy/phy-nop.c
index a3ce24b..2b10cc9 100644 (file)
 #include <linux/usb/otg.h>
 #include <linux/usb/nop-usb-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 usb_phy phy;
+       struct device *dev;
+       struct clk *clk;
+       struct regulator *vcc;
+       struct regulator *reset;
 };
 
 static struct platform_device *pd;
@@ -64,6 +70,46 @@ static int nop_set_suspend(struct usb_phy *x, int suspend)
        return 0;
 }
 
+static int nop_init(struct usb_phy *phy)
+{
+       struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
+
+       if (!IS_ERR(nop->vcc)) {
+               if (regulator_enable(nop->vcc))
+                       dev_err(phy->dev, "Failed to enable power\n");
+       }
+
+       if (!IS_ERR(nop->clk))
+               clk_enable(nop->clk);
+
+       if (!IS_ERR(nop->reset)) {
+               /* De-assert RESET */
+               if (regulator_enable(nop->reset))
+                       dev_err(phy->dev, "Failed to de-assert reset\n");
+       }
+
+       return 0;
+}
+
+static void nop_shutdown(struct usb_phy *phy)
+{
+       struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
+
+       if (!IS_ERR(nop->reset)) {
+               /* Assert RESET */
+               if (regulator_disable(nop->reset))
+                       dev_err(phy->dev, "Failed to assert reset\n");
+       }
+
+       if (!IS_ERR(nop->clk))
+               clk_disable(nop->clk);
+
+       if (!IS_ERR(nop->vcc)) {
+               if (regulator_disable(nop->vcc))
+                       dev_err(phy->dev, "Failed to disable power\n");
+       }
+}
+
 static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
 {
        if (!otg)
@@ -95,39 +141,96 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)
 
 static int nop_usb_xceiv_probe(struct platform_device *pdev)
 {
+       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 = kzalloc(sizeof *nop, GFP_KERNEL);
+       nop = devm_kzalloc(&pdev->dev, sizeof(*nop), GFP_KERNEL);
        if (!nop)
                return -ENOMEM;
 
-       nop->phy.otg = kzalloc(sizeof *nop->phy.otg, GFP_KERNEL);
-       if (!nop->phy.otg) {
-               kfree(nop);
+       nop->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*nop->phy.otg),
+                                                       GFP_KERNEL);
+       if (!nop->phy.otg)
                return -ENOMEM;
-       }
 
-       if (pdata)
+       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");
+       if (IS_ERR(nop->clk)) {
+               dev_dbg(&pdev->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");
+                       return err;
+               }
+       }
+
+       if (!IS_ERR(nop->clk)) {
+               err = clk_prepare(nop->clk);
+               if (err) {
+                       dev_err(&pdev->dev, "Error preparing clock\n");
+                       return err;
+               }
+       }
+
+       nop->vcc = devm_regulator_get(&pdev->dev, "vcc");
+       if (IS_ERR(nop->vcc)) {
+               dev_dbg(&pdev->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");
+       if (IS_ERR(nop->reset)) {
+               dev_dbg(&pdev->dev, "Error getting reset regulator: %ld\n",
+                                       PTR_ERR(nop->reset));
+               if (needs_reset)
+                       return -EPROBE_DEFER;
+       }
 
        nop->dev                = &pdev->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;
 
        nop->phy.otg->phy               = &nop->phy;
        nop->phy.otg->set_host          = nop_set_host;
        nop->phy.otg->set_peripheral    = nop_set_peripheral;
 
-       err = usb_add_phy(&nop->phy, type);
+       err = usb_add_phy_dev(&nop->phy);
        if (err) {
                dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
                        err);
-               goto exit;
+               goto err_add;
        }
 
        platform_set_drvdata(pdev, nop);
@@ -135,9 +238,10 @@ static int nop_usb_xceiv_probe(struct platform_device *pdev)
        ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);
 
        return 0;
-exit:
-       kfree(nop->phy.otg);
-       kfree(nop);
+
+err_add:
+       if (!IS_ERR(nop->clk))
+               clk_unprepare(nop->clk);
        return err;
 }
 
@@ -145,21 +249,30 @@ static int nop_usb_xceiv_remove(struct platform_device *pdev)
 {
        struct nop_usb_xceiv *nop = platform_get_drvdata(pdev);
 
+       if (!IS_ERR(nop->clk))
+               clk_unprepare(nop->clk);
+
        usb_remove_phy(&nop->phy);
 
        platform_set_drvdata(pdev, NULL);
-       kfree(nop->phy.otg);
-       kfree(nop);
 
        return 0;
 }
 
+static const struct of_device_id nop_xceiv_dt_ids[] = {
+       { .compatible = "usb-nop-xceiv" },
+       { }
+};
+
+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,
        .driver         = {
                .name   = "nop_usb_xceiv",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(nop_xceiv_dt_ids),
        },
 };
 
diff --git a/drivers/usb/phy/phy-samsung-usb.c b/drivers/usb/phy/phy-samsung-usb.c
new file mode 100644 (file)
index 0000000..7b118ee
--- /dev/null
@@ -0,0 +1,236 @@
+/* linux/drivers/usb/phy/phy-samsung-usb.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Praveen Paneri <p.paneri@samsung.com>
+ *
+ * Samsung USB-PHY helper driver with common function calls;
+ * interacts with Samsung USB 2.0 PHY controller driver and later
+ * with Samsung USB 3.0 PHY driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/usb/samsung_usb_phy.h>
+
+#include "phy-samsung-usb.h"
+
+int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy)
+{
+       struct device_node *usbphy_sys;
+
+       /* Getting node for system controller interface for usb-phy */
+       usbphy_sys = of_get_child_by_name(sphy->dev->of_node, "usbphy-sys");
+       if (!usbphy_sys) {
+               dev_err(sphy->dev, "No sys-controller interface for usb-phy\n");
+               return -ENODEV;
+       }
+
+       sphy->pmuregs = of_iomap(usbphy_sys, 0);
+
+       if (sphy->pmuregs == NULL) {
+               dev_err(sphy->dev, "Can't get usb-phy pmu control register\n");
+               goto err0;
+       }
+
+       sphy->sysreg = of_iomap(usbphy_sys, 1);
+
+       /*
+        * Not returning error code here, since this situation is not fatal.
+        * Few SoCs may not have this switch available
+        */
+       if (sphy->sysreg == NULL)
+               dev_warn(sphy->dev, "Can't get usb-phy sysreg cfg register\n");
+
+       of_node_put(usbphy_sys);
+
+       return 0;
+
+err0:
+       of_node_put(usbphy_sys);
+       return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(samsung_usbphy_parse_dt);
+
+/*
+ * Set isolation here for phy.
+ * Here 'on = true' would mean USB PHY block is isolated, hence
+ * de-activated and vice-versa.
+ */
+void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on)
+{
+       void __iomem *reg = NULL;
+       u32 reg_val;
+       u32 en_mask = 0;
+
+       if (!sphy->pmuregs) {
+               dev_warn(sphy->dev, "Can't set pmu isolation\n");
+               return;
+       }
+
+       switch (sphy->drv_data->cpu_type) {
+       case TYPE_S3C64XX:
+               /*
+                * Do nothing: We will add here once S3C64xx goes for DT support
+                */
+               break;
+       case TYPE_EXYNOS4210:
+               /*
+                * Fall through since exynos4210 and exynos5250 have similar
+                * register architecture: two separate registers for host and
+                * device phy control with enable bit at position 0.
+                */
+       case TYPE_EXYNOS5250:
+               if (sphy->phy_type == USB_PHY_TYPE_DEVICE) {
+                       reg = sphy->pmuregs +
+                               sphy->drv_data->devphy_reg_offset;
+                       en_mask = sphy->drv_data->devphy_en_mask;
+               } else if (sphy->phy_type == USB_PHY_TYPE_HOST) {
+                       reg = sphy->pmuregs +
+                               sphy->drv_data->hostphy_reg_offset;
+                       en_mask = sphy->drv_data->hostphy_en_mask;
+               }
+               break;
+       default:
+               dev_err(sphy->dev, "Invalid SoC type\n");
+               return;
+       }
+
+       reg_val = readl(reg);
+
+       if (on)
+               reg_val &= ~en_mask;
+       else
+               reg_val |= en_mask;
+
+       writel(reg_val, reg);
+}
+EXPORT_SYMBOL_GPL(samsung_usbphy_set_isolation);
+
+/*
+ * Configure the mode of working of usb-phy here: HOST/DEVICE.
+ */
+void samsung_usbphy_cfg_sel(struct samsung_usbphy *sphy)
+{
+       u32 reg;
+
+       if (!sphy->sysreg) {
+               dev_warn(sphy->dev, "Can't configure specified phy mode\n");
+               return;
+       }
+
+       reg = readl(sphy->sysreg);
+
+       if (sphy->phy_type == USB_PHY_TYPE_DEVICE)
+               reg &= ~EXYNOS_USB20PHY_CFG_HOST_LINK;
+       else if (sphy->phy_type == USB_PHY_TYPE_HOST)
+               reg |= EXYNOS_USB20PHY_CFG_HOST_LINK;
+
+       writel(reg, sphy->sysreg);
+}
+EXPORT_SYMBOL_GPL(samsung_usbphy_cfg_sel);
+
+/*
+ * PHYs are different for USB Device and USB Host.
+ * This make sure that correct PHY type is selected before
+ * any operation on PHY.
+ */
+int samsung_usbphy_set_type(struct usb_phy *phy,
+                               enum samsung_usb_phy_type phy_type)
+{
+       struct samsung_usbphy *sphy = phy_to_sphy(phy);
+
+       sphy->phy_type = phy_type;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(samsung_usbphy_set_type);
+
+/*
+ * Returns reference clock frequency selection value
+ */
+int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
+{
+       struct clk *ref_clk;
+       int refclk_freq = 0;
+
+       /*
+        * In exynos5250 USB host and device PHY use
+        * external crystal clock XXTI
+        */
+       if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
+               ref_clk = devm_clk_get(sphy->dev, "ext_xtal");
+       else
+               ref_clk = devm_clk_get(sphy->dev, "xusbxti");
+       if (IS_ERR(ref_clk)) {
+               dev_err(sphy->dev, "Failed to get reference clock\n");
+               return PTR_ERR(ref_clk);
+       }
+
+       if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) {
+               /* set clock frequency for PLL */
+               switch (clk_get_rate(ref_clk)) {
+               case 9600 * KHZ:
+                       refclk_freq = FSEL_CLKSEL_9600K;
+                       break;
+               case 10 * MHZ:
+                       refclk_freq = FSEL_CLKSEL_10M;
+                       break;
+               case 12 * MHZ:
+                       refclk_freq = FSEL_CLKSEL_12M;
+                       break;
+               case 19200 * KHZ:
+                       refclk_freq = FSEL_CLKSEL_19200K;
+                       break;
+               case 20 * MHZ:
+                       refclk_freq = FSEL_CLKSEL_20M;
+                       break;
+               case 50 * MHZ:
+                       refclk_freq = FSEL_CLKSEL_50M;
+                       break;
+               case 24 * MHZ:
+               default:
+                       /* default reference clock */
+                       refclk_freq = FSEL_CLKSEL_24M;
+                       break;
+               }
+       } else {
+               switch (clk_get_rate(ref_clk)) {
+               case 12 * MHZ:
+                       refclk_freq = PHYCLK_CLKSEL_12M;
+                       break;
+               case 24 * MHZ:
+                       refclk_freq = PHYCLK_CLKSEL_24M;
+                       break;
+               case 48 * MHZ:
+                       refclk_freq = PHYCLK_CLKSEL_48M;
+                       break;
+               default:
+                       if (sphy->drv_data->cpu_type == TYPE_S3C64XX)
+                               refclk_freq = PHYCLK_CLKSEL_48M;
+                       else
+                               refclk_freq = PHYCLK_CLKSEL_24M;
+                       break;
+               }
+       }
+       clk_put(ref_clk);
+
+       return refclk_freq;
+}
+EXPORT_SYMBOL_GPL(samsung_usbphy_get_refclk_freq);
diff --git a/drivers/usb/phy/phy-samsung-usb.h b/drivers/usb/phy/phy-samsung-usb.h
new file mode 100644 (file)
index 0000000..70a9cae
--- /dev/null
@@ -0,0 +1,327 @@
+/* linux/drivers/usb/phy/phy-samsung-usb.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Samsung USB-PHY transceiver; talks to S3C HS OTG controller, EHCI-S5P and
+ * OHCI-EXYNOS controllers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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/usb/phy.h>
+
+/* Register definitions */
+
+#define SAMSUNG_PHYPWR                         (0x00)
+
+#define PHYPWR_NORMAL_MASK                     (0x19 << 0)
+#define PHYPWR_OTG_DISABLE                     (0x1 << 4)
+#define PHYPWR_ANALOG_POWERDOWN                        (0x1 << 3)
+#define PHYPWR_FORCE_SUSPEND                   (0x1 << 1)
+/* For Exynos4 */
+#define PHYPWR_NORMAL_MASK_PHY0                        (0x39 << 0)
+#define PHYPWR_SLEEP_PHY0                      (0x1 << 5)
+
+#define SAMSUNG_PHYCLK                         (0x04)
+
+#define PHYCLK_MODE_USB11                      (0x1 << 6)
+#define PHYCLK_EXT_OSC                         (0x1 << 5)
+#define PHYCLK_COMMON_ON_N                     (0x1 << 4)
+#define PHYCLK_ID_PULL                         (0x1 << 2)
+#define PHYCLK_CLKSEL_MASK                     (0x3 << 0)
+#define PHYCLK_CLKSEL_48M                      (0x0 << 0)
+#define PHYCLK_CLKSEL_12M                      (0x2 << 0)
+#define PHYCLK_CLKSEL_24M                      (0x3 << 0)
+
+#define SAMSUNG_RSTCON                         (0x08)
+
+#define RSTCON_PHYLINK_SWRST                   (0x1 << 2)
+#define RSTCON_HLINK_SWRST                     (0x1 << 1)
+#define RSTCON_SWRST                           (0x1 << 0)
+
+/* EXYNOS5 */
+#define EXYNOS5_PHY_HOST_CTRL0                 (0x00)
+
+#define HOST_CTRL0_PHYSWRSTALL                 (0x1 << 31)
+
+#define HOST_CTRL0_REFCLKSEL_MASK              (0x3 << 19)
+#define HOST_CTRL0_REFCLKSEL_XTAL              (0x0 << 19)
+#define HOST_CTRL0_REFCLKSEL_EXTL              (0x1 << 19)
+#define HOST_CTRL0_REFCLKSEL_CLKCORE           (0x2 << 19)
+
+#define HOST_CTRL0_FSEL_MASK                   (0x7 << 16)
+#define HOST_CTRL0_FSEL(_x)                    ((_x) << 16)
+
+#define FSEL_CLKSEL_50M                                (0x7)
+#define FSEL_CLKSEL_24M                                (0x5)
+#define FSEL_CLKSEL_20M                                (0x4)
+#define FSEL_CLKSEL_19200K                     (0x3)
+#define FSEL_CLKSEL_12M                                (0x2)
+#define FSEL_CLKSEL_10M                                (0x1)
+#define FSEL_CLKSEL_9600K                      (0x0)
+
+#define HOST_CTRL0_TESTBURNIN                  (0x1 << 11)
+#define HOST_CTRL0_RETENABLE                   (0x1 << 10)
+#define HOST_CTRL0_COMMONON_N                  (0x1 << 9)
+#define HOST_CTRL0_SIDDQ                       (0x1 << 6)
+#define HOST_CTRL0_FORCESLEEP                  (0x1 << 5)
+#define HOST_CTRL0_FORCESUSPEND                        (0x1 << 4)
+#define HOST_CTRL0_WORDINTERFACE               (0x1 << 3)
+#define HOST_CTRL0_UTMISWRST                   (0x1 << 2)
+#define HOST_CTRL0_LINKSWRST                   (0x1 << 1)
+#define HOST_CTRL0_PHYSWRST                    (0x1 << 0)
+
+#define EXYNOS5_PHY_HOST_TUNE0                 (0x04)
+
+#define EXYNOS5_PHY_HSIC_CTRL1                 (0x10)
+
+#define EXYNOS5_PHY_HSIC_TUNE1                 (0x14)
+
+#define EXYNOS5_PHY_HSIC_CTRL2                 (0x20)
+
+#define EXYNOS5_PHY_HSIC_TUNE2                 (0x24)
+
+#define HSIC_CTRL_REFCLKSEL_MASK               (0x3 << 23)
+#define HSIC_CTRL_REFCLKSEL                    (0x2 << 23)
+
+#define HSIC_CTRL_REFCLKDIV_MASK               (0x7f << 16)
+#define HSIC_CTRL_REFCLKDIV(_x)                        ((_x) << 16)
+#define HSIC_CTRL_REFCLKDIV_12                 (0x24 << 16)
+#define HSIC_CTRL_REFCLKDIV_15                 (0x1c << 16)
+#define HSIC_CTRL_REFCLKDIV_16                 (0x1a << 16)
+#define HSIC_CTRL_REFCLKDIV_19_2               (0x15 << 16)
+#define HSIC_CTRL_REFCLKDIV_20                 (0x14 << 16)
+
+#define HSIC_CTRL_SIDDQ                                (0x1 << 6)
+#define HSIC_CTRL_FORCESLEEP                   (0x1 << 5)
+#define HSIC_CTRL_FORCESUSPEND                 (0x1 << 4)
+#define HSIC_CTRL_WORDINTERFACE                        (0x1 << 3)
+#define HSIC_CTRL_UTMISWRST                    (0x1 << 2)
+#define HSIC_CTRL_PHYSWRST                     (0x1 << 0)
+
+#define EXYNOS5_PHY_HOST_EHCICTRL              (0x30)
+
+#define HOST_EHCICTRL_ENAINCRXALIGN            (0x1 << 29)
+#define HOST_EHCICTRL_ENAINCR4                 (0x1 << 28)
+#define HOST_EHCICTRL_ENAINCR8                 (0x1 << 27)
+#define HOST_EHCICTRL_ENAINCR16                        (0x1 << 26)
+
+#define EXYNOS5_PHY_HOST_OHCICTRL              (0x34)
+
+#define HOST_OHCICTRL_SUSPLGCY                 (0x1 << 3)
+#define HOST_OHCICTRL_APPSTARTCLK              (0x1 << 2)
+#define HOST_OHCICTRL_CNTSEL                   (0x1 << 1)
+#define HOST_OHCICTRL_CLKCKTRST                        (0x1 << 0)
+
+#define EXYNOS5_PHY_OTG_SYS                    (0x38)
+
+#define OTG_SYS_PHYLINK_SWRESET                        (0x1 << 14)
+#define OTG_SYS_LINKSWRST_UOTG                 (0x1 << 13)
+#define OTG_SYS_PHY0_SWRST                     (0x1 << 12)
+
+#define OTG_SYS_REFCLKSEL_MASK                 (0x3 << 9)
+#define OTG_SYS_REFCLKSEL_XTAL                 (0x0 << 9)
+#define OTG_SYS_REFCLKSEL_EXTL                 (0x1 << 9)
+#define OTG_SYS_REFCLKSEL_CLKCORE              (0x2 << 9)
+
+#define OTG_SYS_IDPULLUP_UOTG                  (0x1 << 8)
+#define OTG_SYS_COMMON_ON                      (0x1 << 7)
+
+#define OTG_SYS_FSEL_MASK                      (0x7 << 4)
+#define OTG_SYS_FSEL(_x)                       ((_x) << 4)
+
+#define OTG_SYS_FORCESLEEP                     (0x1 << 3)
+#define OTG_SYS_OTGDISABLE                     (0x1 << 2)
+#define OTG_SYS_SIDDQ_UOTG                     (0x1 << 1)
+#define OTG_SYS_FORCESUSPEND                   (0x1 << 0)
+
+#define EXYNOS5_PHY_OTG_TUNE                   (0x40)
+
+/* EXYNOS5: USB 3.0 DRD */
+#define EXYNOS5_DRD_LINKSYSTEM                 (0x04)
+
+#define LINKSYSTEM_FLADJ_MASK                  (0x3f << 1)
+#define LINKSYSTEM_FLADJ(_x)                   ((_x) << 1)
+#define LINKSYSTEM_XHCI_VERSION_CONTROL                (0x1 << 27)
+
+#define EXYNOS5_DRD_PHYUTMI                    (0x08)
+
+#define PHYUTMI_OTGDISABLE                     (0x1 << 6)
+#define PHYUTMI_FORCESUSPEND                   (0x1 << 1)
+#define PHYUTMI_FORCESLEEP                     (0x1 << 0)
+
+#define EXYNOS5_DRD_PHYPIPE                    (0x0c)
+
+#define EXYNOS5_DRD_PHYCLKRST                  (0x10)
+
+#define PHYCLKRST_SSC_REFCLKSEL_MASK           (0xff << 23)
+#define PHYCLKRST_SSC_REFCLKSEL(_x)            ((_x) << 23)
+
+#define PHYCLKRST_SSC_RANGE_MASK               (0x03 << 21)
+#define PHYCLKRST_SSC_RANGE(_x)                        ((_x) << 21)
+
+#define PHYCLKRST_SSC_EN                       (0x1 << 20)
+#define PHYCLKRST_REF_SSP_EN                   (0x1 << 19)
+#define PHYCLKRST_REF_CLKDIV2                  (0x1 << 18)
+
+#define PHYCLKRST_MPLL_MULTIPLIER_MASK         (0x7f << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER_100MHZ_REF   (0x19 << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER_50M_REF      (0x02 << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF    (0x68 << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF    (0x7d << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF (0x02 << 11)
+
+#define PHYCLKRST_FSEL_MASK                    (0x3f << 5)
+#define PHYCLKRST_FSEL(_x)                     ((_x) << 5)
+#define PHYCLKRST_FSEL_PAD_100MHZ              (0x27 << 5)
+#define PHYCLKRST_FSEL_PAD_24MHZ               (0x2a << 5)
+#define PHYCLKRST_FSEL_PAD_20MHZ               (0x31 << 5)
+#define PHYCLKRST_FSEL_PAD_19_2MHZ             (0x38 << 5)
+
+#define PHYCLKRST_RETENABLEN                   (0x1 << 4)
+
+#define PHYCLKRST_REFCLKSEL_MASK               (0x03 << 2)
+#define PHYCLKRST_REFCLKSEL_PAD_REFCLK         (0x2 << 2)
+#define PHYCLKRST_REFCLKSEL_EXT_REFCLK         (0x3 << 2)
+
+#define PHYCLKRST_PORTRESET                    (0x1 << 1)
+#define PHYCLKRST_COMMONONN                    (0x1 << 0)
+
+#define EXYNOS5_DRD_PHYREG0                    (0x14)
+#define EXYNOS5_DRD_PHYREG1                    (0x18)
+
+#define EXYNOS5_DRD_PHYPARAM0                  (0x1c)
+
+#define PHYPARAM0_REF_USE_PAD                  (0x1 << 31)
+#define PHYPARAM0_REF_LOSLEVEL_MASK            (0x1f << 26)
+#define PHYPARAM0_REF_LOSLEVEL                 (0x9 << 26)
+
+#define EXYNOS5_DRD_PHYPARAM1                  (0x20)
+
+#define PHYPARAM1_PCS_TXDEEMPH_MASK            (0x1f << 0)
+#define PHYPARAM1_PCS_TXDEEMPH                 (0x1c)
+
+#define EXYNOS5_DRD_PHYTERM                    (0x24)
+
+#define EXYNOS5_DRD_PHYTEST                    (0x28)
+
+#define PHYTEST_POWERDOWN_SSP                  (0x1 << 3)
+#define PHYTEST_POWERDOWN_HSP                  (0x1 << 2)
+
+#define EXYNOS5_DRD_PHYADP                     (0x2c)
+
+#define EXYNOS5_DRD_PHYBATCHG                  (0x30)
+
+#define PHYBATCHG_UTMI_CLKSEL                  (0x1 << 2)
+
+#define EXYNOS5_DRD_PHYRESUME                  (0x34)
+#define EXYNOS5_DRD_LINKPORT                   (0x44)
+
+#ifndef MHZ
+#define MHZ (1000*1000)
+#endif
+
+#ifndef KHZ
+#define KHZ (1000)
+#endif
+
+#define EXYNOS_USBHOST_PHY_CTRL_OFFSET         (0x4)
+#define S3C64XX_USBPHY_ENABLE                  (0x1 << 16)
+#define EXYNOS_USBPHY_ENABLE                   (0x1 << 0)
+#define EXYNOS_USB20PHY_CFG_HOST_LINK          (0x1 << 0)
+
+enum samsung_cpu_type {
+       TYPE_S3C64XX,
+       TYPE_EXYNOS4210,
+       TYPE_EXYNOS5250,
+};
+
+/*
+ * struct samsung_usbphy_drvdata - driver data for various SoC variants
+ * @cpu_type: machine identifier
+ * @devphy_en_mask: device phy enable mask for PHY CONTROL register
+ * @hostphy_en_mask: host phy enable mask for PHY CONTROL register
+ * @devphy_reg_offset: offset to DEVICE PHY CONTROL register from
+ *                    mapped address of system controller.
+ * @hostphy_reg_offset: offset to HOST PHY CONTROL register from
+ *                    mapped address of system controller.
+ *
+ *     Here we have a separate mask for device type phy.
+ *     Having different masks for host and device type phy helps
+ *     in setting independent masks in case of SoCs like S5PV210,
+ *     in which PHY0 and PHY1 enable bits belong to same register
+ *     placed at position 0 and 1 respectively.
+ *     Although for newer SoCs like exynos these bits belong to
+ *     different registers altogether placed at position 0.
+ */
+struct samsung_usbphy_drvdata {
+       int cpu_type;
+       int devphy_en_mask;
+       int hostphy_en_mask;
+       u32 devphy_reg_offset;
+       u32 hostphy_reg_offset;
+};
+
+/*
+ * struct samsung_usbphy - transceiver driver state
+ * @phy: transceiver structure
+ * @plat: platform data
+ * @dev: The parent device supplied to the probe function
+ * @clk: usb phy clock
+ * @regs: usb phy controller registers memory base
+ * @pmuregs: USB device PHY_CONTROL register memory base
+ * @sysreg: USB2.0 PHY_CFG register memory base
+ * @ref_clk_freq: reference clock frequency selection
+ * @drv_data: driver data available for different SoCs
+ * @phy_type: Samsung SoCs specific phy types: #HOST
+ *                                             #DEVICE
+ * @phy_usage: usage count for phy
+ * @lock: lock for phy operations
+ */
+struct samsung_usbphy {
+       struct usb_phy  phy;
+       struct samsung_usbphy_data *plat;
+       struct device   *dev;
+       struct clk      *clk;
+       void __iomem    *regs;
+       void __iomem    *pmuregs;
+       void __iomem    *sysreg;
+       int             ref_clk_freq;
+       const struct samsung_usbphy_drvdata *drv_data;
+       enum samsung_usb_phy_type phy_type;
+       atomic_t        phy_usage;
+       spinlock_t      lock;
+};
+
+#define phy_to_sphy(x)         container_of((x), struct samsung_usbphy, phy)
+
+static const struct of_device_id samsung_usbphy_dt_match[];
+
+static inline const struct samsung_usbphy_drvdata
+*samsung_usbphy_get_driver_data(struct platform_device *pdev)
+{
+       if (pdev->dev.of_node) {
+               const struct of_device_id *match;
+               match = of_match_node(samsung_usbphy_dt_match,
+                                                       pdev->dev.of_node);
+               return match->data;
+       }
+
+       return (struct samsung_usbphy_drvdata *)
+                               platform_get_device_id(pdev)->driver_data;
+}
+
+extern int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy);
+extern void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on);
+extern void samsung_usbphy_cfg_sel(struct samsung_usbphy *sphy);
+extern int samsung_usbphy_set_type(struct usb_phy *phy,
+                                       enum samsung_usb_phy_type phy_type);
+extern int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy);
diff --git a/drivers/usb/phy/phy-samsung-usb2.c b/drivers/usb/phy/phy-samsung-usb2.c
new file mode 100644 (file)
index 0000000..45ffe03
--- /dev/null
@@ -0,0 +1,509 @@
+/* linux/drivers/usb/phy/phy-samsung-usb2.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Praveen Paneri <p.paneri@samsung.com>
+ *
+ * Samsung USB2.0 PHY transceiver; talks to S3C HS OTG controller, EHCI-S5P and
+ * OHCI-EXYNOS controllers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/samsung_usb_phy.h>
+#include <linux/platform_data/samsung-usbphy.h>
+
+#include "phy-samsung-usb.h"
+
+static int samsung_usbphy_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+       if (!otg)
+               return -ENODEV;
+
+       if (!otg->host)
+               otg->host = host;
+
+       return 0;
+}
+
+static bool exynos5_phyhost_is_on(void __iomem *regs)
+{
+       u32 reg;
+
+       reg = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
+
+       return !(reg & HOST_CTRL0_SIDDQ);
+}
+
+static void samsung_exynos5_usb2phy_enable(struct samsung_usbphy *sphy)
+{
+       void __iomem *regs = sphy->regs;
+       u32 phyclk = sphy->ref_clk_freq;
+       u32 phyhost;
+       u32 phyotg;
+       u32 phyhsic;
+       u32 ehcictrl;
+       u32 ohcictrl;
+
+       /*
+        * phy_usage helps in keeping usage count for phy
+        * so that the first consumer enabling the phy is also
+        * the last consumer to disable it.
+        */
+
+       atomic_inc(&sphy->phy_usage);
+
+       if (exynos5_phyhost_is_on(regs)) {
+               dev_info(sphy->dev, "Already power on PHY\n");
+               return;
+       }
+
+       /* Host configuration */
+       phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
+
+       /* phy reference clock configuration */
+       phyhost &= ~HOST_CTRL0_FSEL_MASK;
+       phyhost |= HOST_CTRL0_FSEL(phyclk);
+
+       /* host phy reset */
+       phyhost &= ~(HOST_CTRL0_PHYSWRST |
+                       HOST_CTRL0_PHYSWRSTALL |
+                       HOST_CTRL0_SIDDQ |
+                       /* Enable normal mode of operation */
+                       HOST_CTRL0_FORCESUSPEND |
+                       HOST_CTRL0_FORCESLEEP);
+
+       /* Link reset */
+       phyhost |= (HOST_CTRL0_LINKSWRST |
+                       HOST_CTRL0_UTMISWRST |
+                       /* COMMON Block configuration during suspend */
+                       HOST_CTRL0_COMMONON_N);
+       writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
+       udelay(10);
+       phyhost &= ~(HOST_CTRL0_LINKSWRST |
+                       HOST_CTRL0_UTMISWRST);
+       writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
+
+       /* OTG configuration */
+       phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS);
+
+       /* phy reference clock configuration */
+       phyotg &= ~OTG_SYS_FSEL_MASK;
+       phyotg |= OTG_SYS_FSEL(phyclk);
+
+       /* Enable normal mode of operation */
+       phyotg &= ~(OTG_SYS_FORCESUSPEND |
+                       OTG_SYS_SIDDQ_UOTG |
+                       OTG_SYS_FORCESLEEP |
+                       OTG_SYS_REFCLKSEL_MASK |
+                       /* COMMON Block configuration during suspend */
+                       OTG_SYS_COMMON_ON);
+
+       /* OTG phy & link reset */
+       phyotg |= (OTG_SYS_PHY0_SWRST |
+                       OTG_SYS_LINKSWRST_UOTG |
+                       OTG_SYS_PHYLINK_SWRESET |
+                       OTG_SYS_OTGDISABLE |
+                       /* Set phy refclk */
+                       OTG_SYS_REFCLKSEL_CLKCORE);
+
+       writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
+       udelay(10);
+       phyotg &= ~(OTG_SYS_PHY0_SWRST |
+                       OTG_SYS_LINKSWRST_UOTG |
+                       OTG_SYS_PHYLINK_SWRESET);
+       writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
+
+       /* HSIC phy configuration */
+       phyhsic = (HSIC_CTRL_REFCLKDIV_12 |
+                       HSIC_CTRL_REFCLKSEL |
+                       HSIC_CTRL_PHYSWRST);
+       writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
+       writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
+       udelay(10);
+       phyhsic &= ~HSIC_CTRL_PHYSWRST;
+       writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
+       writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
+
+       udelay(80);
+
+       /* enable EHCI DMA burst */
+       ehcictrl = readl(regs + EXYNOS5_PHY_HOST_EHCICTRL);
+       ehcictrl |= (HOST_EHCICTRL_ENAINCRXALIGN |
+                               HOST_EHCICTRL_ENAINCR4 |
+                               HOST_EHCICTRL_ENAINCR8 |
+                               HOST_EHCICTRL_ENAINCR16);
+       writel(ehcictrl, regs + EXYNOS5_PHY_HOST_EHCICTRL);
+
+       /* set ohci_suspend_on_n */
+       ohcictrl = readl(regs + EXYNOS5_PHY_HOST_OHCICTRL);
+       ohcictrl |= HOST_OHCICTRL_SUSPLGCY;
+       writel(ohcictrl, regs + EXYNOS5_PHY_HOST_OHCICTRL);
+}
+
+static void samsung_usb2phy_enable(struct samsung_usbphy *sphy)
+{
+       void __iomem *regs = sphy->regs;
+       u32 phypwr;
+       u32 phyclk;
+       u32 rstcon;
+
+       /* set clock frequency for PLL */
+       phyclk = sphy->ref_clk_freq;
+       phypwr = readl(regs + SAMSUNG_PHYPWR);
+       rstcon = readl(regs + SAMSUNG_RSTCON);
+
+       switch (sphy->drv_data->cpu_type) {
+       case TYPE_S3C64XX:
+               phyclk &= ~PHYCLK_COMMON_ON_N;
+               phypwr &= ~PHYPWR_NORMAL_MASK;
+               rstcon |= RSTCON_SWRST;
+               break;
+       case TYPE_EXYNOS4210:
+               phypwr &= ~PHYPWR_NORMAL_MASK_PHY0;
+               rstcon |= RSTCON_SWRST;
+       default:
+               break;
+       }
+
+       writel(phyclk, regs + SAMSUNG_PHYCLK);
+       /* Configure PHY0 for normal operation*/
+       writel(phypwr, regs + SAMSUNG_PHYPWR);
+       /* reset all ports of PHY and Link */
+       writel(rstcon, regs + SAMSUNG_RSTCON);
+       udelay(10);
+       rstcon &= ~RSTCON_SWRST;
+       writel(rstcon, regs + SAMSUNG_RSTCON);
+}
+
+static void samsung_exynos5_usb2phy_disable(struct samsung_usbphy *sphy)
+{
+       void __iomem *regs = sphy->regs;
+       u32 phyhost;
+       u32 phyotg;
+       u32 phyhsic;
+
+       if (atomic_dec_return(&sphy->phy_usage) > 0) {
+               dev_info(sphy->dev, "still being used\n");
+               return;
+       }
+
+       phyhsic = (HSIC_CTRL_REFCLKDIV_12 |
+                       HSIC_CTRL_REFCLKSEL |
+                       HSIC_CTRL_SIDDQ |
+                       HSIC_CTRL_FORCESLEEP |
+                       HSIC_CTRL_FORCESUSPEND);
+       writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
+       writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
+
+       phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
+       phyhost |= (HOST_CTRL0_SIDDQ |
+                       HOST_CTRL0_FORCESUSPEND |
+                       HOST_CTRL0_FORCESLEEP |
+                       HOST_CTRL0_PHYSWRST |
+                       HOST_CTRL0_PHYSWRSTALL);
+       writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
+
+       phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS);
+       phyotg |= (OTG_SYS_FORCESUSPEND |
+                       OTG_SYS_SIDDQ_UOTG |
+                       OTG_SYS_FORCESLEEP);
+       writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
+}
+
+static void samsung_usb2phy_disable(struct samsung_usbphy *sphy)
+{
+       void __iomem *regs = sphy->regs;
+       u32 phypwr;
+
+       phypwr = readl(regs + SAMSUNG_PHYPWR);
+
+       switch (sphy->drv_data->cpu_type) {
+       case TYPE_S3C64XX:
+               phypwr |= PHYPWR_NORMAL_MASK;
+               break;
+       case TYPE_EXYNOS4210:
+               phypwr |= PHYPWR_NORMAL_MASK_PHY0;
+       default:
+               break;
+       }
+
+       /* Disable analog and otg block power */
+       writel(phypwr, regs + SAMSUNG_PHYPWR);
+}
+
+/*
+ * The function passed to the usb driver for phy initialization
+ */
+static int samsung_usb2phy_init(struct usb_phy *phy)
+{
+       struct samsung_usbphy *sphy;
+       struct usb_bus *host = NULL;
+       unsigned long flags;
+       int ret = 0;
+
+       sphy = phy_to_sphy(phy);
+
+       host = phy->otg->host;
+
+       /* Enable the phy clock */
+       ret = clk_prepare_enable(sphy->clk);
+       if (ret) {
+               dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+               return ret;
+       }
+
+       spin_lock_irqsave(&sphy->lock, flags);
+
+       if (host) {
+               /* setting default phy-type for USB 2.0 */
+               if (!strstr(dev_name(host->controller), "ehci") ||
+                               !strstr(dev_name(host->controller), "ohci"))
+                       samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_HOST);
+       } else {
+               samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE);
+       }
+
+       /* Disable phy isolation */
+       if (sphy->plat && sphy->plat->pmu_isolation)
+               sphy->plat->pmu_isolation(false);
+       else
+               samsung_usbphy_set_isolation(sphy, false);
+
+       /* Selecting Host/OTG mode; After reset USB2.0PHY_CFG: HOST */
+       samsung_usbphy_cfg_sel(sphy);
+
+       /* Initialize usb phy registers */
+       if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
+               samsung_exynos5_usb2phy_enable(sphy);
+       else
+               samsung_usb2phy_enable(sphy);
+
+       spin_unlock_irqrestore(&sphy->lock, flags);
+
+       /* Disable the phy clock */
+       clk_disable_unprepare(sphy->clk);
+
+       return ret;
+}
+
+/*
+ * The function passed to the usb driver for phy shutdown
+ */
+static void samsung_usb2phy_shutdown(struct usb_phy *phy)
+{
+       struct samsung_usbphy *sphy;
+       struct usb_bus *host = NULL;
+       unsigned long flags;
+
+       sphy = phy_to_sphy(phy);
+
+       host = phy->otg->host;
+
+       if (clk_prepare_enable(sphy->clk)) {
+               dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+               return;
+       }
+
+       spin_lock_irqsave(&sphy->lock, flags);
+
+       if (host) {
+               /* setting default phy-type for USB 2.0 */
+               if (!strstr(dev_name(host->controller), "ehci") ||
+                               !strstr(dev_name(host->controller), "ohci"))
+                       samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_HOST);
+       } else {
+               samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE);
+       }
+
+       /* De-initialize usb phy registers */
+       if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
+               samsung_exynos5_usb2phy_disable(sphy);
+       else
+               samsung_usb2phy_disable(sphy);
+
+       /* Enable phy isolation */
+       if (sphy->plat && sphy->plat->pmu_isolation)
+               sphy->plat->pmu_isolation(true);
+       else
+               samsung_usbphy_set_isolation(sphy, true);
+
+       spin_unlock_irqrestore(&sphy->lock, flags);
+
+       clk_disable_unprepare(sphy->clk);
+}
+
+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;
+       const struct samsung_usbphy_drvdata *drv_data;
+       struct device *dev = &pdev->dev;
+       struct resource *phy_mem;
+       void __iomem    *phy_base;
+       struct clk *clk;
+       int ret;
+
+       phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!phy_mem) {
+               dev_err(dev, "%s: missing mem resource\n", __func__);
+               return -ENODEV;
+       }
+
+       phy_base = devm_ioremap_resource(dev, phy_mem);
+       if (IS_ERR(phy_base))
+               return PTR_ERR(phy_base);
+
+       sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
+       if (!sphy)
+               return -ENOMEM;
+
+       otg = devm_kzalloc(dev, sizeof(*otg), GFP_KERNEL);
+       if (!otg)
+               return -ENOMEM;
+
+       drv_data = samsung_usbphy_get_driver_data(pdev);
+
+       if (drv_data->cpu_type == TYPE_EXYNOS5250)
+               clk = devm_clk_get(dev, "usbhost");
+       else
+               clk = devm_clk_get(dev, "otg");
+
+       if (IS_ERR(clk)) {
+               dev_err(dev, "Failed to get otg clock\n");
+               return PTR_ERR(clk);
+       }
+
+       sphy->dev = dev;
+
+       if (dev->of_node) {
+               ret = samsung_usbphy_parse_dt(sphy);
+               if (ret < 0)
+                       return ret;
+       } else {
+               if (!pdata) {
+                       dev_err(dev, "no platform data specified\n");
+                       return -EINVAL;
+               }
+       }
+
+       sphy->plat              = pdata;
+       sphy->regs              = phy_base;
+       sphy->clk               = clk;
+       sphy->drv_data          = drv_data;
+       sphy->phy.dev           = sphy->dev;
+       sphy->phy.label         = "samsung-usb2phy";
+       sphy->phy.init          = samsung_usb2phy_init;
+       sphy->phy.shutdown      = samsung_usb2phy_shutdown;
+       sphy->ref_clk_freq      = samsung_usbphy_get_refclk_freq(sphy);
+
+       sphy->phy.otg           = otg;
+       sphy->phy.otg->phy      = &sphy->phy;
+       sphy->phy.otg->set_host = samsung_usbphy_set_host;
+
+       spin_lock_init(&sphy->lock);
+
+       platform_set_drvdata(pdev, sphy);
+
+       return usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2);
+}
+
+static int samsung_usb2phy_remove(struct platform_device *pdev)
+{
+       struct samsung_usbphy *sphy = platform_get_drvdata(pdev);
+
+       usb_remove_phy(&sphy->phy);
+
+       if (sphy->pmuregs)
+               iounmap(sphy->pmuregs);
+       if (sphy->sysreg)
+               iounmap(sphy->sysreg);
+
+       return 0;
+}
+
+static const struct samsung_usbphy_drvdata usb2phy_s3c64xx = {
+       .cpu_type               = TYPE_S3C64XX,
+       .devphy_en_mask         = S3C64XX_USBPHY_ENABLE,
+};
+
+static const struct samsung_usbphy_drvdata usb2phy_exynos4 = {
+       .cpu_type               = TYPE_EXYNOS4210,
+       .devphy_en_mask         = EXYNOS_USBPHY_ENABLE,
+       .hostphy_en_mask        = EXYNOS_USBPHY_ENABLE,
+};
+
+static struct samsung_usbphy_drvdata usb2phy_exynos5 = {
+       .cpu_type               = TYPE_EXYNOS5250,
+       .hostphy_en_mask        = EXYNOS_USBPHY_ENABLE,
+       .hostphy_reg_offset     = EXYNOS_USBHOST_PHY_CTRL_OFFSET,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id samsung_usbphy_dt_match[] = {
+       {
+               .compatible = "samsung,s3c64xx-usb2phy",
+               .data = &usb2phy_s3c64xx,
+       }, {
+               .compatible = "samsung,exynos4210-usb2phy",
+               .data = &usb2phy_exynos4,
+       }, {
+               .compatible = "samsung,exynos5250-usb2phy",
+               .data = &usb2phy_exynos5
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match);
+#endif
+
+static struct platform_device_id samsung_usbphy_driver_ids[] = {
+       {
+               .name           = "s3c64xx-usb2phy",
+               .driver_data    = (unsigned long)&usb2phy_s3c64xx,
+       }, {
+               .name           = "exynos4210-usb2phy",
+               .driver_data    = (unsigned long)&usb2phy_exynos4,
+       }, {
+               .name           = "exynos5250-usb2phy",
+               .driver_data    = (unsigned long)&usb2phy_exynos5,
+       },
+       {},
+};
+
+MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids);
+
+static struct platform_driver samsung_usb2phy_driver = {
+       .probe          = samsung_usb2phy_probe,
+       .remove         = samsung_usb2phy_remove,
+       .id_table       = samsung_usbphy_driver_ids,
+       .driver         = {
+               .name   = "samsung-usb2phy",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(samsung_usbphy_dt_match),
+       },
+};
+
+module_platform_driver(samsung_usb2phy_driver);
+
+MODULE_DESCRIPTION("Samsung USB 2.0 phy controller");
+MODULE_AUTHOR("Praveen Paneri <p.paneri@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-usb2phy");
diff --git a/drivers/usb/phy/phy-samsung-usb3.c b/drivers/usb/phy/phy-samsung-usb3.c
new file mode 100644 (file)
index 0000000..133f3d0
--- /dev/null
@@ -0,0 +1,347 @@
+/* linux/drivers/usb/phy/phy-samsung-usb3.c
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Vivek Gautam <gautam.vivek@samsung.com>
+ *
+ * Samsung USB 3.0 PHY transceiver; talks to DWC3 controller.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/usb/samsung_usb_phy.h>
+#include <linux/platform_data/samsung-usbphy.h>
+
+#include "phy-samsung-usb.h"
+
+/*
+ * Sets the phy clk as EXTREFCLK (XXTI) which is internal clock from clock core.
+ */
+static u32 samsung_usb3phy_set_refclk(struct samsung_usbphy *sphy)
+{
+       u32 reg;
+       u32 refclk;
+
+       refclk = sphy->ref_clk_freq;
+
+       reg = PHYCLKRST_REFCLKSEL_EXT_REFCLK |
+               PHYCLKRST_FSEL(refclk);
+
+       switch (refclk) {
+       case FSEL_CLKSEL_50M:
+               reg |= (PHYCLKRST_MPLL_MULTIPLIER_50M_REF |
+                       PHYCLKRST_SSC_REFCLKSEL(0x00));
+               break;
+       case FSEL_CLKSEL_20M:
+               reg |= (PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF |
+                       PHYCLKRST_SSC_REFCLKSEL(0x00));
+               break;
+       case FSEL_CLKSEL_19200K:
+               reg |= (PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF |
+                       PHYCLKRST_SSC_REFCLKSEL(0x88));
+               break;
+       case FSEL_CLKSEL_24M:
+       default:
+               reg |= (PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF |
+                       PHYCLKRST_SSC_REFCLKSEL(0x88));
+               break;
+       }
+
+       return reg;
+}
+
+static int samsung_exynos5_usb3phy_enable(struct samsung_usbphy *sphy)
+{
+       void __iomem *regs = sphy->regs;
+       u32 phyparam0;
+       u32 phyparam1;
+       u32 linksystem;
+       u32 phybatchg;
+       u32 phytest;
+       u32 phyclkrst;
+
+       /* Reset USB 3.0 PHY */
+       writel(0x0, regs + EXYNOS5_DRD_PHYREG0);
+
+       phyparam0 = readl(regs + EXYNOS5_DRD_PHYPARAM0);
+       /* Select PHY CLK source */
+       phyparam0 &= ~PHYPARAM0_REF_USE_PAD;
+       /* Set Loss-of-Signal Detector sensitivity */
+       phyparam0 &= ~PHYPARAM0_REF_LOSLEVEL_MASK;
+       phyparam0 |= PHYPARAM0_REF_LOSLEVEL;
+       writel(phyparam0, regs + EXYNOS5_DRD_PHYPARAM0);
+
+       writel(0x0, regs + EXYNOS5_DRD_PHYRESUME);
+
+       /*
+        * Setting the Frame length Adj value[6:1] to default 0x20
+        * See xHCI 1.0 spec, 5.2.4
+        */
+       linksystem = LINKSYSTEM_XHCI_VERSION_CONTROL |
+                       LINKSYSTEM_FLADJ(0x20);
+       writel(linksystem, regs + EXYNOS5_DRD_LINKSYSTEM);
+
+       phyparam1 = readl(regs + EXYNOS5_DRD_PHYPARAM1);
+       /* Set Tx De-Emphasis level */
+       phyparam1 &= ~PHYPARAM1_PCS_TXDEEMPH_MASK;
+       phyparam1 |= PHYPARAM1_PCS_TXDEEMPH;
+       writel(phyparam1, regs + EXYNOS5_DRD_PHYPARAM1);
+
+       phybatchg = readl(regs + EXYNOS5_DRD_PHYBATCHG);
+       phybatchg |= PHYBATCHG_UTMI_CLKSEL;
+       writel(phybatchg, regs + EXYNOS5_DRD_PHYBATCHG);
+
+       /* PHYTEST POWERDOWN Control */
+       phytest = readl(regs + EXYNOS5_DRD_PHYTEST);
+       phytest &= ~(PHYTEST_POWERDOWN_SSP |
+                       PHYTEST_POWERDOWN_HSP);
+       writel(phytest, regs + EXYNOS5_DRD_PHYTEST);
+
+       /* UTMI Power Control */
+       writel(PHYUTMI_OTGDISABLE, regs + EXYNOS5_DRD_PHYUTMI);
+
+       phyclkrst = samsung_usb3phy_set_refclk(sphy);
+
+       phyclkrst |= PHYCLKRST_PORTRESET |
+                       /* Digital power supply in normal operating mode */
+                       PHYCLKRST_RETENABLEN |
+                       /* Enable ref clock for SS function */
+                       PHYCLKRST_REF_SSP_EN |
+                       /* Enable spread spectrum */
+                       PHYCLKRST_SSC_EN |
+                       /* Power down HS Bias and PLL blocks in suspend mode */
+                       PHYCLKRST_COMMONONN;
+
+       writel(phyclkrst, regs + EXYNOS5_DRD_PHYCLKRST);
+
+       udelay(10);
+
+       phyclkrst &= ~(PHYCLKRST_PORTRESET);
+       writel(phyclkrst, regs + EXYNOS5_DRD_PHYCLKRST);
+
+       return 0;
+}
+
+static void samsung_exynos5_usb3phy_disable(struct samsung_usbphy *sphy)
+{
+       u32 phyutmi;
+       u32 phyclkrst;
+       u32 phytest;
+       void __iomem *regs = sphy->regs;
+
+       phyutmi = PHYUTMI_OTGDISABLE |
+                       PHYUTMI_FORCESUSPEND |
+                       PHYUTMI_FORCESLEEP;
+       writel(phyutmi, regs + EXYNOS5_DRD_PHYUTMI);
+
+       /* Resetting the PHYCLKRST enable bits to reduce leakage current */
+       phyclkrst = readl(regs + EXYNOS5_DRD_PHYCLKRST);
+       phyclkrst &= ~(PHYCLKRST_REF_SSP_EN |
+                       PHYCLKRST_SSC_EN |
+                       PHYCLKRST_COMMONONN);
+       writel(phyclkrst, regs + EXYNOS5_DRD_PHYCLKRST);
+
+       /* Control PHYTEST to remove leakage current */
+       phytest = readl(regs + EXYNOS5_DRD_PHYTEST);
+       phytest |= (PHYTEST_POWERDOWN_SSP |
+                       PHYTEST_POWERDOWN_HSP);
+       writel(phytest, regs + EXYNOS5_DRD_PHYTEST);
+}
+
+static int samsung_usb3phy_init(struct usb_phy *phy)
+{
+       struct samsung_usbphy *sphy;
+       unsigned long flags;
+       int ret = 0;
+
+       sphy = phy_to_sphy(phy);
+
+       /* Enable the phy clock */
+       ret = clk_prepare_enable(sphy->clk);
+       if (ret) {
+               dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+               return ret;
+       }
+
+       spin_lock_irqsave(&sphy->lock, flags);
+
+       /* setting default phy-type for USB 3.0 */
+       samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE);
+
+       /* Disable phy isolation */
+       samsung_usbphy_set_isolation(sphy, false);
+
+       /* Initialize usb phy registers */
+       samsung_exynos5_usb3phy_enable(sphy);
+
+       spin_unlock_irqrestore(&sphy->lock, flags);
+
+       /* Disable the phy clock */
+       clk_disable_unprepare(sphy->clk);
+
+       return ret;
+}
+
+/*
+ * The function passed to the usb driver for phy shutdown
+ */
+static void samsung_usb3phy_shutdown(struct usb_phy *phy)
+{
+       struct samsung_usbphy *sphy;
+       unsigned long flags;
+
+       sphy = phy_to_sphy(phy);
+
+       if (clk_prepare_enable(sphy->clk)) {
+               dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+               return;
+       }
+
+       spin_lock_irqsave(&sphy->lock, flags);
+
+       /* setting default phy-type for USB 3.0 */
+       samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE);
+
+       /* De-initialize usb phy registers */
+       samsung_exynos5_usb3phy_disable(sphy);
+
+       /* Enable phy isolation */
+       samsung_usbphy_set_isolation(sphy, true);
+
+       spin_unlock_irqrestore(&sphy->lock, flags);
+
+       clk_disable_unprepare(sphy->clk);
+}
+
+static int samsung_usb3phy_probe(struct platform_device *pdev)
+{
+       struct samsung_usbphy *sphy;
+       struct samsung_usbphy_data *pdata = pdev->dev.platform_data;
+       struct device *dev = &pdev->dev;
+       struct resource *phy_mem;
+       void __iomem    *phy_base;
+       struct clk *clk;
+       int ret;
+
+       phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!phy_mem) {
+               dev_err(dev, "%s: missing mem resource\n", __func__);
+               return -ENODEV;
+       }
+
+       phy_base = devm_ioremap_resource(dev, phy_mem);
+       if (IS_ERR(phy_base))
+               return PTR_ERR(phy_base);
+
+       sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
+       if (!sphy)
+               return -ENOMEM;
+
+       clk = devm_clk_get(dev, "usbdrd30");
+       if (IS_ERR(clk)) {
+               dev_err(dev, "Failed to get device clock\n");
+               return PTR_ERR(clk);
+       }
+
+       sphy->dev = dev;
+
+       if (dev->of_node) {
+               ret = samsung_usbphy_parse_dt(sphy);
+               if (ret < 0)
+                       return ret;
+       } else {
+               if (!pdata) {
+                       dev_err(dev, "no platform data specified\n");
+                       return -EINVAL;
+               }
+       }
+
+       sphy->plat              = pdata;
+       sphy->regs              = phy_base;
+       sphy->clk               = clk;
+       sphy->phy.dev           = sphy->dev;
+       sphy->phy.label         = "samsung-usb3phy";
+       sphy->phy.init          = samsung_usb3phy_init;
+       sphy->phy.shutdown      = samsung_usb3phy_shutdown;
+       sphy->drv_data          = samsung_usbphy_get_driver_data(pdev);
+       sphy->ref_clk_freq      = samsung_usbphy_get_refclk_freq(sphy);
+
+       spin_lock_init(&sphy->lock);
+
+       platform_set_drvdata(pdev, sphy);
+
+       return usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB3);
+}
+
+static int samsung_usb3phy_remove(struct platform_device *pdev)
+{
+       struct samsung_usbphy *sphy = platform_get_drvdata(pdev);
+
+       usb_remove_phy(&sphy->phy);
+
+       if (sphy->pmuregs)
+               iounmap(sphy->pmuregs);
+       if (sphy->sysreg)
+               iounmap(sphy->sysreg);
+
+       return 0;
+}
+
+static struct samsung_usbphy_drvdata usb3phy_exynos5 = {
+       .cpu_type               = TYPE_EXYNOS5250,
+       .devphy_en_mask         = EXYNOS_USBPHY_ENABLE,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id samsung_usbphy_dt_match[] = {
+       {
+               .compatible = "samsung,exynos5250-usb3phy",
+               .data = &usb3phy_exynos5
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match);
+#endif
+
+static struct platform_device_id samsung_usbphy_driver_ids[] = {
+       {
+               .name           = "exynos5250-usb3phy",
+               .driver_data    = (unsigned long)&usb3phy_exynos5,
+       },
+       {},
+};
+
+MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids);
+
+static struct platform_driver samsung_usb3phy_driver = {
+       .probe          = samsung_usb3phy_probe,
+       .remove         = samsung_usb3phy_remove,
+       .id_table       = samsung_usbphy_driver_ids,
+       .driver         = {
+               .name   = "samsung-usb3phy",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(samsung_usbphy_dt_match),
+       },
+};
+
+module_platform_driver(samsung_usb3phy_driver);
+
+MODULE_DESCRIPTION("Samsung USB 3.0 phy controller");
+MODULE_AUTHOR("Vivek Gautam <gautam.vivek@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-usb3phy");
similarity index 85%
rename from drivers/usb/otg/twl4030-usb.c
rename to drivers/usb/phy/phy-twl4030-usb.c
index 24d573a..8f78d2d 100644 (file)
@@ -163,6 +163,8 @@ struct twl4030_usb {
        bool                    vbus_supplied;
        u8                      asleep;
        bool                    irq_enabled;
+
+       struct delayed_work     id_workaround_work;
 };
 
 /* internal define on top of container_of */
@@ -246,6 +248,25 @@ twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
 
 /*-------------------------------------------------------------------------*/
 
+static bool twl4030_is_driving_vbus(struct twl4030_usb *twl)
+{
+       int ret;
+
+       ret = twl4030_usb_read(twl, PHY_CLK_CTRL_STS);
+       if (ret < 0 || !(ret & PHY_DPLL_CLK))
+               /*
+                * if clocks are off, registers are not updated,
+                * but we can assume we don't drive VBUS in this case
+                */
+               return false;
+
+       ret = twl4030_usb_read(twl, ULPI_OTG_CTRL);
+       if (ret < 0)
+               return false;
+
+       return (ret & (ULPI_OTG_DRVVBUS | ULPI_OTG_CHRGVBUS)) ? true : false;
+}
+
 static enum omap_musb_vbus_id_status
        twl4030_usb_linkstat(struct twl4030_usb *twl)
 {
@@ -268,13 +289,19 @@ static enum omap_musb_vbus_id_status
        if (status < 0)
                dev_err(twl->dev, "USB link status err %d\n", status);
        else if (status & (BIT(7) | BIT(2))) {
-               if (status & (BIT(7)))
-                        twl->vbus_supplied = true;
+               if (status & BIT(7)) {
+                       if (twl4030_is_driving_vbus(twl))
+                               status &= ~BIT(7);
+                       else
+                               twl->vbus_supplied = true;
+               }
 
                if (status & BIT(2))
                        linkstat = OMAP_MUSB_ID_GROUND;
-               else
+               else if (status & BIT(7))
                        linkstat = OMAP_MUSB_VBUS_VALID;
+               else
+                       linkstat = OMAP_MUSB_VBUS_OFF;
        } else {
                if (twl->linkstat != OMAP_MUSB_UNKNOWN)
                        linkstat = OMAP_MUSB_VBUS_OFF;
@@ -287,10 +314,6 @@ static enum omap_musb_vbus_id_status
         * are registered, and that both are active...
         */
 
-       spin_lock_irq(&twl->lock);
-       twl->linkstat = linkstat;
-       spin_unlock_irq(&twl->lock);
-
        return linkstat;
 }
 
@@ -361,9 +384,17 @@ static void __twl4030_phy_power(struct twl4030_usb *twl, int on)
 
 static void twl4030_phy_power(struct twl4030_usb *twl, int on)
 {
+       int ret;
+
        if (on) {
-               regulator_enable(twl->usb3v1);
-               regulator_enable(twl->usb1v8);
+               ret = regulator_enable(twl->usb3v1);
+               if (ret)
+                       dev_err(twl->dev, "Failed to enable usb3v1\n");
+
+               ret = regulator_enable(twl->usb1v8);
+               if (ret)
+                       dev_err(twl->dev, "Failed to enable usb1v8\n");
+
                /*
                 * Disabling usb3v1 regulator (= writing 0 to VUSB3V1_DEV_GRP
                 * in twl4030) resets the VUSB_DEDICATED2 register. This reset
@@ -372,7 +403,11 @@ static void twl4030_phy_power(struct twl4030_usb *twl, int on)
                 * is re-activated. This ensures that VUSB3V1 is really active.
                 */
                twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);
-               regulator_enable(twl->usb1v5);
+
+               ret = regulator_enable(twl->usb1v5);
+               if (ret)
+                       dev_err(twl->dev, "Failed to enable usb1v5\n");
+
                __twl4030_phy_power(twl, 1);
                twl4030_usb_write(twl, PHY_CLK_CTRL,
                                  twl4030_usb_read(twl, PHY_CLK_CTRL) |
@@ -412,6 +447,16 @@ static void twl4030_phy_resume(struct twl4030_usb *twl)
        __twl4030_phy_resume(twl);
        twl->asleep = 0;
        dev_dbg(twl->dev, "%s\n", __func__);
+
+       /*
+        * XXX When VBUS gets driven after musb goes to A mode,
+        * ID_PRES related interrupts no longer arrive, why?
+        * Register itself is updated fine though, so we must poll.
+        */
+       if (twl->linkstat == OMAP_MUSB_ID_GROUND) {
+               cancel_delayed_work(&twl->id_workaround_work);
+               schedule_delayed_work(&twl->id_workaround_work, HZ);
+       }
 }
 
 static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
@@ -432,7 +477,7 @@ static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
        /* Initialize 3.1V regulator */
        twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP);
 
-       twl->usb3v1 = regulator_get(twl->dev, "usb3v1");
+       twl->usb3v1 = devm_regulator_get(twl->dev, "usb3v1");
        if (IS_ERR(twl->usb3v1))
                return -ENODEV;
 
@@ -441,18 +486,18 @@ static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
        /* Initialize 1.5V regulator */
        twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP);
 
-       twl->usb1v5 = regulator_get(twl->dev, "usb1v5");
+       twl->usb1v5 = devm_regulator_get(twl->dev, "usb1v5");
        if (IS_ERR(twl->usb1v5))
-               goto fail1;
+               return -ENODEV;
 
        twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE);
 
        /* Initialize 1.8V regulator */
        twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP);
 
-       twl->usb1v8 = regulator_get(twl->dev, "usb1v8");
+       twl->usb1v8 = devm_regulator_get(twl->dev, "usb1v8");
        if (IS_ERR(twl->usb1v8))
-               goto fail2;
+               return -ENODEV;
 
        twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE);
 
@@ -461,14 +506,6 @@ static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
                         TWL4030_PM_MASTER_PROTECT_KEY);
 
        return 0;
-
-fail2:
-       regulator_put(twl->usb1v5);
-       twl->usb1v5 = NULL;
-fail1:
-       regulator_put(twl->usb3v1);
-       twl->usb3v1 = NULL;
-       return -ENODEV;
 }
 
 static ssize_t twl4030_usb_vbus_show(struct device *dev,
@@ -491,9 +528,18 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
 {
        struct twl4030_usb *twl = _twl;
        enum omap_musb_vbus_id_status status;
+       bool status_changed = false;
 
        status = twl4030_usb_linkstat(twl);
-       if (status > 0) {
+
+       spin_lock_irq(&twl->lock);
+       if (status >= 0 && status != twl->linkstat) {
+               twl->linkstat = status;
+               status_changed = true;
+       }
+       spin_unlock_irq(&twl->lock);
+
+       if (status_changed) {
                /* FIXME add a set_power() method so that B-devices can
                 * configure the charger appropriately.  It's not always
                 * correct to consume VBUS power, and how much current to
@@ -505,37 +551,62 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
                 * USB_LINK_VBUS state.  musb_hdrc won't care until it
                 * starts to handle softconnect right.
                 */
-               if (status == OMAP_MUSB_VBUS_OFF ||
-                               status == OMAP_MUSB_ID_FLOAT)
-                       twl4030_phy_suspend(twl, 0);
-               else
-                       twl4030_phy_resume(twl);
-
-               omap_musb_mailbox(twl->linkstat);
+               omap_musb_mailbox(status);
        }
        sysfs_notify(&twl->dev->kobj, NULL, "vbus");
 
        return IRQ_HANDLED;
 }
 
-static void twl4030_usb_phy_init(struct twl4030_usb *twl)
+static void twl4030_id_workaround_work(struct work_struct *work)
 {
+       struct twl4030_usb *twl = container_of(work, struct twl4030_usb,
+               id_workaround_work.work);
        enum omap_musb_vbus_id_status status;
+       bool status_changed = false;
 
        status = twl4030_usb_linkstat(twl);
-       if (status > 0) {
-               if (status == OMAP_MUSB_VBUS_OFF ||
-                               status == OMAP_MUSB_ID_FLOAT) {
-                       __twl4030_phy_power(twl, 0);
-                       twl->asleep = 1;
-               } else {
-                       __twl4030_phy_resume(twl);
-                       twl->asleep = 0;
-               }
 
-               omap_musb_mailbox(twl->linkstat);
+       spin_lock_irq(&twl->lock);
+       if (status >= 0 && status != twl->linkstat) {
+               twl->linkstat = status;
+               status_changed = true;
+       }
+       spin_unlock_irq(&twl->lock);
+
+       if (status_changed) {
+               dev_dbg(twl->dev, "handle missing status change to %d\n",
+                               status);
+               omap_musb_mailbox(status);
        }
+
+       /* don't schedule during sleep - irq works right then */
+       if (status == OMAP_MUSB_ID_GROUND && !twl->asleep) {
+               cancel_delayed_work(&twl->id_workaround_work);
+               schedule_delayed_work(&twl->id_workaround_work, HZ);
+       }
+}
+
+static int twl4030_usb_phy_init(struct usb_phy *phy)
+{
+       struct twl4030_usb *twl = phy_to_twl(phy);
+       enum omap_musb_vbus_id_status status;
+
+       /*
+        * Start in sleep state, we'll get called through set_suspend()
+        * callback when musb is runtime resumed and it's time to start.
+        */
+       __twl4030_phy_power(twl, 0);
+       twl->asleep = 1;
+
+       status = twl4030_usb_linkstat(twl);
+       twl->linkstat = status;
+
+       if (status == OMAP_MUSB_ID_GROUND || status == OMAP_MUSB_VBUS_VALID)
+               omap_musb_mailbox(twl->linkstat);
+
        sysfs_notify(&twl->dev->kobj, NULL, "vbus");
+       return 0;
 }
 
 static int twl4030_set_suspend(struct usb_phy *x, int suspend)
@@ -612,6 +683,7 @@ static int twl4030_usb_probe(struct platform_device *pdev)
        twl->phy.otg            = otg;
        twl->phy.type           = USB_PHY_TYPE_USB2;
        twl->phy.set_suspend    = twl4030_set_suspend;
+       twl->phy.init           = twl4030_usb_phy_init;
 
        otg->phy                = &twl->phy;
        otg->set_host           = twl4030_set_host;
@@ -620,6 +692,8 @@ static int twl4030_usb_probe(struct platform_device *pdev)
        /* init spinlock for workqueue */
        spin_lock_init(&twl->lock);
 
+       INIT_DELAYED_WORK(&twl->id_workaround_work, twl4030_id_workaround_work);
+
        err = twl4030_usb_ldo_init(twl);
        if (err) {
                dev_err(&pdev->dev, "ldo init failed\n");
@@ -640,20 +714,15 @@ static int twl4030_usb_probe(struct platform_device *pdev)
         * need both handles, otherwise just one suffices.
         */
        twl->irq_enabled = true;
-       status = request_threaded_irq(twl->irq, NULL, twl4030_usb_irq,
-                       IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
-                       IRQF_ONESHOT, "twl4030_usb", twl);
+       status = devm_request_threaded_irq(twl->dev, twl->irq, NULL,
+                       twl4030_usb_irq, IRQF_TRIGGER_FALLING |
+                       IRQF_TRIGGER_RISING | IRQF_ONESHOT, "twl4030_usb", twl);
        if (status < 0) {
                dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n",
                        twl->irq, status);
                return status;
        }
 
-       /* Power down phy or make it work according to
-        * current link state.
-        */
-       twl4030_usb_phy_init(twl);
-
        dev_info(&pdev->dev, "Initialized TWL4030 USB module\n");
        return 0;
 }
@@ -663,7 +732,7 @@ static int twl4030_usb_remove(struct platform_device *pdev)
        struct twl4030_usb *twl = platform_get_drvdata(pdev);
        int val;
 
-       free_irq(twl->irq, twl);
+       cancel_delayed_work(&twl->id_workaround_work);
        device_remove_file(twl->dev, &dev_attr_vbus);
 
        /* set transceiver mode to power on defaults */
@@ -685,9 +754,6 @@ static int twl4030_usb_remove(struct platform_device *pdev)
 
        if (!twl->asleep)
                twl4030_phy_power(twl, 0);
-       regulator_put(twl->usb1v5);
-       regulator_put(twl->usb1v8);
-       regulator_put(twl->usb3v1);
 
        return 0;
 }
similarity index 98%
rename from drivers/usb/otg/twl6030-usb.c
rename to drivers/usb/phy/phy-twl6030-usb.c
index 7f3c5b0..9de7ada 100644 (file)
@@ -211,6 +211,7 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
        struct twl6030_usb *twl = _twl;
        enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN;
        u8 vbus_state, hw_state;
+       int ret;
 
        hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
 
@@ -218,7 +219,10 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
                                                CONTROLLER_STAT1);
        if (!(hw_state & STS_USB_ID)) {
                if (vbus_state & VBUS_DET) {
-                       regulator_enable(twl->usb3v3);
+                       ret = regulator_enable(twl->usb3v3);
+                       if (ret)
+                               dev_err(twl->dev, "Failed to enable usb3v3\n");
+
                        twl->asleep = 1;
                        status = OMAP_MUSB_VBUS_VALID;
                        twl->linkstat = status;
@@ -245,12 +249,15 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
        struct twl6030_usb *twl = _twl;
        enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN;
        u8 hw_state;
+       int ret;
 
        hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
 
        if (hw_state & STS_USB_ID) {
+               ret = regulator_enable(twl->usb3v3);
+               if (ret)
+                       dev_err(twl->dev, "Failed to enable usb3v3\n");
 
-               regulator_enable(twl->usb3v3);
                twl->asleep = 1;
                twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_CLR);
                twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET);
similarity index 89%
rename from drivers/usb/otg/otg.c
rename to drivers/usb/phy/phy.c
index 2bd03d2..f52c006 100644 (file)
@@ -1,14 +1,13 @@
 /*
- * otg.c -- USB OTG utility code
+ * phy.c -- USB phy handling
  *
- * Copyright (C) 2004 Texas Instruments
+ * Copyright (C) 2004-2013 Texas Instruments
  *
  * 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.
  */
-
 #include <linux/kernel.h>
 #include <linux/export.h>
 #include <linux/err.h>
@@ -17,7 +16,7 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 
-#include <linux/usb/otg.h>
+#include <linux/usb/phy.h>
 
 static LIST_HEAD(phy_list);
 static LIST_HEAD(phy_bind_list);
@@ -110,7 +109,7 @@ struct usb_phy *devm_usb_get_phy(struct device *dev, enum usb_phy_type type)
 
        return phy;
 }
-EXPORT_SYMBOL(devm_usb_get_phy);
+EXPORT_SYMBOL_GPL(devm_usb_get_phy);
 
 /**
  * usb_get_phy - find the USB PHY
@@ -143,7 +142,7 @@ err0:
 
        return phy;
 }
-EXPORT_SYMBOL(usb_get_phy);
+EXPORT_SYMBOL_GPL(usb_get_phy);
 
  /**
  * devm_usb_get_phy_by_phandle - find the USB PHY by phandle
@@ -207,7 +206,7 @@ err0:
 
        return phy;
 }
-EXPORT_SYMBOL(devm_usb_get_phy_by_phandle);
+EXPORT_SYMBOL_GPL(devm_usb_get_phy_by_phandle);
 
 /**
  * usb_get_phy_dev - find the USB PHY
@@ -240,7 +239,7 @@ err0:
 
        return phy;
 }
-EXPORT_SYMBOL(usb_get_phy_dev);
+EXPORT_SYMBOL_GPL(usb_get_phy_dev);
 
 /**
  * devm_usb_get_phy_dev - find the USB PHY using device ptr and index
@@ -270,7 +269,7 @@ struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index)
 
        return phy;
 }
-EXPORT_SYMBOL(devm_usb_get_phy_dev);
+EXPORT_SYMBOL_GPL(devm_usb_get_phy_dev);
 
 /**
  * devm_usb_put_phy - release the USB PHY
@@ -289,7 +288,7 @@ void devm_usb_put_phy(struct device *dev, struct usb_phy *phy)
        r = devres_destroy(dev, devm_usb_phy_release, devm_usb_phy_match, phy);
        dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n");
 }
-EXPORT_SYMBOL(devm_usb_put_phy);
+EXPORT_SYMBOL_GPL(devm_usb_put_phy);
 
 /**
  * usb_put_phy - release the USB PHY
@@ -308,7 +307,7 @@ void usb_put_phy(struct usb_phy *x)
                module_put(owner);
        }
 }
-EXPORT_SYMBOL(usb_put_phy);
+EXPORT_SYMBOL_GPL(usb_put_phy);
 
 /**
  * usb_add_phy - declare the USB PHY
@@ -348,7 +347,7 @@ out:
        spin_unlock_irqrestore(&phy_lock, flags);
        return ret;
 }
-EXPORT_SYMBOL(usb_add_phy);
+EXPORT_SYMBOL_GPL(usb_add_phy);
 
 /**
  * usb_add_phy_dev - declare the USB PHY
@@ -378,7 +377,7 @@ int usb_add_phy_dev(struct usb_phy *x)
        spin_unlock_irqrestore(&phy_lock, flags);
        return 0;
 }
-EXPORT_SYMBOL(usb_add_phy_dev);
+EXPORT_SYMBOL_GPL(usb_add_phy_dev);
 
 /**
  * usb_remove_phy - remove the OTG PHY
@@ -400,7 +399,7 @@ void usb_remove_phy(struct usb_phy *x)
        }
        spin_unlock_irqrestore(&phy_lock, flags);
 }
-EXPORT_SYMBOL(usb_remove_phy);
+EXPORT_SYMBOL_GPL(usb_remove_phy);
 
 /**
  * usb_bind_phy - bind the phy and the controller that uses the phy
@@ -437,38 +436,3 @@ int __init usb_bind_phy(const char *dev_name, u8 index,
        return 0;
 }
 EXPORT_SYMBOL_GPL(usb_bind_phy);
-
-const char *otg_state_string(enum usb_otg_state state)
-{
-       switch (state) {
-       case OTG_STATE_A_IDLE:
-               return "a_idle";
-       case OTG_STATE_A_WAIT_VRISE:
-               return "a_wait_vrise";
-       case OTG_STATE_A_WAIT_BCON:
-               return "a_wait_bcon";
-       case OTG_STATE_A_HOST:
-               return "a_host";
-       case OTG_STATE_A_SUSPEND:
-               return "a_suspend";
-       case OTG_STATE_A_PERIPHERAL:
-               return "a_peripheral";
-       case OTG_STATE_A_WAIT_VFALL:
-               return "a_wait_vfall";
-       case OTG_STATE_A_VBUS_ERR:
-               return "a_vbus_err";
-       case OTG_STATE_B_IDLE:
-               return "b_idle";
-       case OTG_STATE_B_SRP_INIT:
-               return "b_srp_init";
-       case OTG_STATE_B_PERIPHERAL:
-               return "b_peripheral";
-       case OTG_STATE_B_WAIT_ACON:
-               return "b_wait_acon";
-       case OTG_STATE_B_HOST:
-               return "b_host";
-       default:
-               return "UNDEFINED";
-       }
-}
-EXPORT_SYMBOL(otg_state_string);
diff --git a/drivers/usb/phy/samsung-usbphy.c b/drivers/usb/phy/samsung-usbphy.c
deleted file mode 100644 (file)
index 967101e..0000000
+++ /dev/null
@@ -1,928 +0,0 @@
-/* linux/drivers/usb/phy/samsung-usbphy.c
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- *              http://www.samsung.com
- *
- * Author: Praveen Paneri <p.paneri@samsung.com>
- *
- * Samsung USB2.0 PHY transceiver; talks to S3C HS OTG controller, EHCI-S5P and
- * OHCI-EXYNOS controllers.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/samsung_usb_phy.h>
-#include <linux/platform_data/samsung-usbphy.h>
-
-/* Register definitions */
-
-#define SAMSUNG_PHYPWR                         (0x00)
-
-#define PHYPWR_NORMAL_MASK                     (0x19 << 0)
-#define PHYPWR_OTG_DISABLE                     (0x1 << 4)
-#define PHYPWR_ANALOG_POWERDOWN                        (0x1 << 3)
-#define PHYPWR_FORCE_SUSPEND                   (0x1 << 1)
-/* For Exynos4 */
-#define PHYPWR_NORMAL_MASK_PHY0                        (0x39 << 0)
-#define PHYPWR_SLEEP_PHY0                      (0x1 << 5)
-
-#define SAMSUNG_PHYCLK                         (0x04)
-
-#define PHYCLK_MODE_USB11                      (0x1 << 6)
-#define PHYCLK_EXT_OSC                         (0x1 << 5)
-#define PHYCLK_COMMON_ON_N                     (0x1 << 4)
-#define PHYCLK_ID_PULL                         (0x1 << 2)
-#define PHYCLK_CLKSEL_MASK                     (0x3 << 0)
-#define PHYCLK_CLKSEL_48M                      (0x0 << 0)
-#define PHYCLK_CLKSEL_12M                      (0x2 << 0)
-#define PHYCLK_CLKSEL_24M                      (0x3 << 0)
-
-#define SAMSUNG_RSTCON                         (0x08)
-
-#define RSTCON_PHYLINK_SWRST                   (0x1 << 2)
-#define RSTCON_HLINK_SWRST                     (0x1 << 1)
-#define RSTCON_SWRST                           (0x1 << 0)
-
-/* EXYNOS5 */
-#define EXYNOS5_PHY_HOST_CTRL0                 (0x00)
-
-#define HOST_CTRL0_PHYSWRSTALL                 (0x1 << 31)
-
-#define HOST_CTRL0_REFCLKSEL_MASK              (0x3 << 19)
-#define HOST_CTRL0_REFCLKSEL_XTAL              (0x0 << 19)
-#define HOST_CTRL0_REFCLKSEL_EXTL              (0x1 << 19)
-#define HOST_CTRL0_REFCLKSEL_CLKCORE           (0x2 << 19)
-
-#define HOST_CTRL0_FSEL_MASK                   (0x7 << 16)
-#define HOST_CTRL0_FSEL(_x)                    ((_x) << 16)
-
-#define FSEL_CLKSEL_50M                                (0x7)
-#define FSEL_CLKSEL_24M                                (0x5)
-#define FSEL_CLKSEL_20M                                (0x4)
-#define FSEL_CLKSEL_19200K                     (0x3)
-#define FSEL_CLKSEL_12M                                (0x2)
-#define FSEL_CLKSEL_10M                                (0x1)
-#define FSEL_CLKSEL_9600K                      (0x0)
-
-#define HOST_CTRL0_TESTBURNIN                  (0x1 << 11)
-#define HOST_CTRL0_RETENABLE                   (0x1 << 10)
-#define HOST_CTRL0_COMMONON_N                  (0x1 << 9)
-#define HOST_CTRL0_SIDDQ                       (0x1 << 6)
-#define HOST_CTRL0_FORCESLEEP                  (0x1 << 5)
-#define HOST_CTRL0_FORCESUSPEND                        (0x1 << 4)
-#define HOST_CTRL0_WORDINTERFACE               (0x1 << 3)
-#define HOST_CTRL0_UTMISWRST                   (0x1 << 2)
-#define HOST_CTRL0_LINKSWRST                   (0x1 << 1)
-#define HOST_CTRL0_PHYSWRST                    (0x1 << 0)
-
-#define EXYNOS5_PHY_HOST_TUNE0                 (0x04)
-
-#define EXYNOS5_PHY_HSIC_CTRL1                 (0x10)
-
-#define EXYNOS5_PHY_HSIC_TUNE1                 (0x14)
-
-#define EXYNOS5_PHY_HSIC_CTRL2                 (0x20)
-
-#define EXYNOS5_PHY_HSIC_TUNE2                 (0x24)
-
-#define HSIC_CTRL_REFCLKSEL_MASK               (0x3 << 23)
-#define HSIC_CTRL_REFCLKSEL                    (0x2 << 23)
-
-#define HSIC_CTRL_REFCLKDIV_MASK               (0x7f << 16)
-#define HSIC_CTRL_REFCLKDIV(_x)                        ((_x) << 16)
-#define HSIC_CTRL_REFCLKDIV_12                 (0x24 << 16)
-#define HSIC_CTRL_REFCLKDIV_15                 (0x1c << 16)
-#define HSIC_CTRL_REFCLKDIV_16                 (0x1a << 16)
-#define HSIC_CTRL_REFCLKDIV_19_2               (0x15 << 16)
-#define HSIC_CTRL_REFCLKDIV_20                 (0x14 << 16)
-
-#define HSIC_CTRL_SIDDQ                                (0x1 << 6)
-#define HSIC_CTRL_FORCESLEEP                   (0x1 << 5)
-#define HSIC_CTRL_FORCESUSPEND                 (0x1 << 4)
-#define HSIC_CTRL_WORDINTERFACE                        (0x1 << 3)
-#define HSIC_CTRL_UTMISWRST                    (0x1 << 2)
-#define HSIC_CTRL_PHYSWRST                     (0x1 << 0)
-
-#define EXYNOS5_PHY_HOST_EHCICTRL              (0x30)
-
-#define HOST_EHCICTRL_ENAINCRXALIGN            (0x1 << 29)
-#define HOST_EHCICTRL_ENAINCR4                 (0x1 << 28)
-#define HOST_EHCICTRL_ENAINCR8                 (0x1 << 27)
-#define HOST_EHCICTRL_ENAINCR16                        (0x1 << 26)
-
-#define EXYNOS5_PHY_HOST_OHCICTRL              (0x34)
-
-#define HOST_OHCICTRL_SUSPLGCY                 (0x1 << 3)
-#define HOST_OHCICTRL_APPSTARTCLK              (0x1 << 2)
-#define HOST_OHCICTRL_CNTSEL                   (0x1 << 1)
-#define HOST_OHCICTRL_CLKCKTRST                        (0x1 << 0)
-
-#define EXYNOS5_PHY_OTG_SYS                    (0x38)
-
-#define OTG_SYS_PHYLINK_SWRESET                        (0x1 << 14)
-#define OTG_SYS_LINKSWRST_UOTG                 (0x1 << 13)
-#define OTG_SYS_PHY0_SWRST                     (0x1 << 12)
-
-#define OTG_SYS_REFCLKSEL_MASK                 (0x3 << 9)
-#define OTG_SYS_REFCLKSEL_XTAL                 (0x0 << 9)
-#define OTG_SYS_REFCLKSEL_EXTL                 (0x1 << 9)
-#define OTG_SYS_REFCLKSEL_CLKCORE              (0x2 << 9)
-
-#define OTG_SYS_IDPULLUP_UOTG                  (0x1 << 8)
-#define OTG_SYS_COMMON_ON                      (0x1 << 7)
-
-#define OTG_SYS_FSEL_MASK                      (0x7 << 4)
-#define OTG_SYS_FSEL(_x)                       ((_x) << 4)
-
-#define OTG_SYS_FORCESLEEP                     (0x1 << 3)
-#define OTG_SYS_OTGDISABLE                     (0x1 << 2)
-#define OTG_SYS_SIDDQ_UOTG                     (0x1 << 1)
-#define OTG_SYS_FORCESUSPEND                   (0x1 << 0)
-
-#define EXYNOS5_PHY_OTG_TUNE                   (0x40)
-
-#ifndef MHZ
-#define MHZ (1000*1000)
-#endif
-
-#ifndef KHZ
-#define KHZ (1000)
-#endif
-
-#define EXYNOS_USBHOST_PHY_CTRL_OFFSET         (0x4)
-#define S3C64XX_USBPHY_ENABLE                  (0x1 << 16)
-#define EXYNOS_USBPHY_ENABLE                   (0x1 << 0)
-#define EXYNOS_USB20PHY_CFG_HOST_LINK          (0x1 << 0)
-
-enum samsung_cpu_type {
-       TYPE_S3C64XX,
-       TYPE_EXYNOS4210,
-       TYPE_EXYNOS5250,
-};
-
-/*
- * struct samsung_usbphy_drvdata - driver data for various SoC variants
- * @cpu_type: machine identifier
- * @devphy_en_mask: device phy enable mask for PHY CONTROL register
- * @hostphy_en_mask: host phy enable mask for PHY CONTROL register
- * @devphy_reg_offset: offset to DEVICE PHY CONTROL register from
- *                    mapped address of system controller.
- * @hostphy_reg_offset: offset to HOST PHY CONTROL register from
- *                    mapped address of system controller.
- *
- *     Here we have a separate mask for device type phy.
- *     Having different masks for host and device type phy helps
- *     in setting independent masks in case of SoCs like S5PV210,
- *     in which PHY0 and PHY1 enable bits belong to same register
- *     placed at position 0 and 1 respectively.
- *     Although for newer SoCs like exynos these bits belong to
- *     different registers altogether placed at position 0.
- */
-struct samsung_usbphy_drvdata {
-       int cpu_type;
-       int devphy_en_mask;
-       int hostphy_en_mask;
-       u32 devphy_reg_offset;
-       u32 hostphy_reg_offset;
-};
-
-/*
- * struct samsung_usbphy - transceiver driver state
- * @phy: transceiver structure
- * @plat: platform data
- * @dev: The parent device supplied to the probe function
- * @clk: usb phy clock
- * @regs: usb phy controller registers memory base
- * @pmuregs: USB device PHY_CONTROL register memory base
- * @sysreg: USB2.0 PHY_CFG register memory base
- * @ref_clk_freq: reference clock frequency selection
- * @drv_data: driver data available for different SoCs
- * @phy_type: Samsung SoCs specific phy types: #HOST
- *                                             #DEVICE
- * @phy_usage: usage count for phy
- * @lock: lock for phy operations
- */
-struct samsung_usbphy {
-       struct usb_phy  phy;
-       struct samsung_usbphy_data *plat;
-       struct device   *dev;
-       struct clk      *clk;
-       void __iomem    *regs;
-       void __iomem    *pmuregs;
-       void __iomem    *sysreg;
-       int             ref_clk_freq;
-       const struct samsung_usbphy_drvdata *drv_data;
-       enum samsung_usb_phy_type phy_type;
-       atomic_t        phy_usage;
-       spinlock_t      lock;
-};
-
-#define phy_to_sphy(x)         container_of((x), struct samsung_usbphy, phy)
-
-int samsung_usbphy_set_host(struct usb_otg *otg, struct usb_bus *host)
-{
-       if (!otg)
-               return -ENODEV;
-
-       if (!otg->host)
-               otg->host = host;
-
-       return 0;
-}
-
-static int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy)
-{
-       struct device_node *usbphy_sys;
-
-       /* Getting node for system controller interface for usb-phy */
-       usbphy_sys = of_get_child_by_name(sphy->dev->of_node, "usbphy-sys");
-       if (!usbphy_sys) {
-               dev_err(sphy->dev, "No sys-controller interface for usb-phy\n");
-               return -ENODEV;
-       }
-
-       sphy->pmuregs = of_iomap(usbphy_sys, 0);
-
-       if (sphy->pmuregs == NULL) {
-               dev_err(sphy->dev, "Can't get usb-phy pmu control register\n");
-               goto err0;
-       }
-
-       sphy->sysreg = of_iomap(usbphy_sys, 1);
-
-       /*
-        * Not returning error code here, since this situation is not fatal.
-        * Few SoCs may not have this switch available
-        */
-       if (sphy->sysreg == NULL)
-               dev_warn(sphy->dev, "Can't get usb-phy sysreg cfg register\n");
-
-       of_node_put(usbphy_sys);
-
-       return 0;
-
-err0:
-       of_node_put(usbphy_sys);
-       return -ENXIO;
-}
-
-/*
- * Set isolation here for phy.
- * Here 'on = true' would mean USB PHY block is isolated, hence
- * de-activated and vice-versa.
- */
-static void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on)
-{
-       void __iomem *reg = NULL;
-       u32 reg_val;
-       u32 en_mask = 0;
-
-       if (!sphy->pmuregs) {
-               dev_warn(sphy->dev, "Can't set pmu isolation\n");
-               return;
-       }
-
-       switch (sphy->drv_data->cpu_type) {
-       case TYPE_S3C64XX:
-               /*
-                * Do nothing: We will add here once S3C64xx goes for DT support
-                */
-               break;
-       case TYPE_EXYNOS4210:
-               /*
-                * Fall through since exynos4210 and exynos5250 have similar
-                * register architecture: two separate registers for host and
-                * device phy control with enable bit at position 0.
-                */
-       case TYPE_EXYNOS5250:
-               if (sphy->phy_type == USB_PHY_TYPE_DEVICE) {
-                       reg = sphy->pmuregs +
-                               sphy->drv_data->devphy_reg_offset;
-                       en_mask = sphy->drv_data->devphy_en_mask;
-               } else if (sphy->phy_type == USB_PHY_TYPE_HOST) {
-                       reg = sphy->pmuregs +
-                               sphy->drv_data->hostphy_reg_offset;
-                       en_mask = sphy->drv_data->hostphy_en_mask;
-               }
-               break;
-       default:
-               dev_err(sphy->dev, "Invalid SoC type\n");
-               return;
-       }
-
-       reg_val = readl(reg);
-
-       if (on)
-               reg_val &= ~en_mask;
-       else
-               reg_val |= en_mask;
-
-       writel(reg_val, reg);
-}
-
-/*
- * Configure the mode of working of usb-phy here: HOST/DEVICE.
- */
-static void samsung_usbphy_cfg_sel(struct samsung_usbphy *sphy)
-{
-       u32 reg;
-
-       if (!sphy->sysreg) {
-               dev_warn(sphy->dev, "Can't configure specified phy mode\n");
-               return;
-       }
-
-       reg = readl(sphy->sysreg);
-
-       if (sphy->phy_type == USB_PHY_TYPE_DEVICE)
-               reg &= ~EXYNOS_USB20PHY_CFG_HOST_LINK;
-       else if (sphy->phy_type == USB_PHY_TYPE_HOST)
-               reg |= EXYNOS_USB20PHY_CFG_HOST_LINK;
-
-       writel(reg, sphy->sysreg);
-}
-
-/*
- * PHYs are different for USB Device and USB Host.
- * This make sure that correct PHY type is selected before
- * any operation on PHY.
- */
-static int samsung_usbphy_set_type(struct usb_phy *phy,
-                               enum samsung_usb_phy_type phy_type)
-{
-       struct samsung_usbphy *sphy = phy_to_sphy(phy);
-
-       sphy->phy_type = phy_type;
-
-       return 0;
-}
-
-/*
- * Returns reference clock frequency selection value
- */
-static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
-{
-       struct clk *ref_clk;
-       int refclk_freq = 0;
-
-       /*
-        * In exynos5250 USB host and device PHY use
-        * external crystal clock XXTI
-        */
-       if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
-               ref_clk = clk_get(sphy->dev, "ext_xtal");
-       else
-               ref_clk = clk_get(sphy->dev, "xusbxti");
-       if (IS_ERR(ref_clk)) {
-               dev_err(sphy->dev, "Failed to get reference clock\n");
-               return PTR_ERR(ref_clk);
-       }
-
-       if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) {
-               /* set clock frequency for PLL */
-               switch (clk_get_rate(ref_clk)) {
-               case 9600 * KHZ:
-                       refclk_freq = FSEL_CLKSEL_9600K;
-                       break;
-               case 10 * MHZ:
-                       refclk_freq = FSEL_CLKSEL_10M;
-                       break;
-               case 12 * MHZ:
-                       refclk_freq = FSEL_CLKSEL_12M;
-                       break;
-               case 19200 * KHZ:
-                       refclk_freq = FSEL_CLKSEL_19200K;
-                       break;
-               case 20 * MHZ:
-                       refclk_freq = FSEL_CLKSEL_20M;
-                       break;
-               case 50 * MHZ:
-                       refclk_freq = FSEL_CLKSEL_50M;
-                       break;
-               case 24 * MHZ:
-               default:
-                       /* default reference clock */
-                       refclk_freq = FSEL_CLKSEL_24M;
-                       break;
-               }
-       } else {
-               switch (clk_get_rate(ref_clk)) {
-               case 12 * MHZ:
-                       refclk_freq = PHYCLK_CLKSEL_12M;
-                       break;
-               case 24 * MHZ:
-                       refclk_freq = PHYCLK_CLKSEL_24M;
-                       break;
-               case 48 * MHZ:
-                       refclk_freq = PHYCLK_CLKSEL_48M;
-                       break;
-               default:
-                       if (sphy->drv_data->cpu_type == TYPE_S3C64XX)
-                               refclk_freq = PHYCLK_CLKSEL_48M;
-                       else
-                               refclk_freq = PHYCLK_CLKSEL_24M;
-                       break;
-               }
-       }
-       clk_put(ref_clk);
-
-       return refclk_freq;
-}
-
-static bool exynos5_phyhost_is_on(void *regs)
-{
-       u32 reg;
-
-       reg = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
-
-       return !(reg & HOST_CTRL0_SIDDQ);
-}
-
-static void samsung_exynos5_usbphy_enable(struct samsung_usbphy *sphy)
-{
-       void __iomem *regs = sphy->regs;
-       u32 phyclk = sphy->ref_clk_freq;
-       u32 phyhost;
-       u32 phyotg;
-       u32 phyhsic;
-       u32 ehcictrl;
-       u32 ohcictrl;
-
-       /*
-        * phy_usage helps in keeping usage count for phy
-        * so that the first consumer enabling the phy is also
-        * the last consumer to disable it.
-        */
-
-       atomic_inc(&sphy->phy_usage);
-
-       if (exynos5_phyhost_is_on(regs)) {
-               dev_info(sphy->dev, "Already power on PHY\n");
-               return;
-       }
-
-       /* Host configuration */
-       phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
-
-       /* phy reference clock configuration */
-       phyhost &= ~HOST_CTRL0_FSEL_MASK;
-       phyhost |= HOST_CTRL0_FSEL(phyclk);
-
-       /* host phy reset */
-       phyhost &= ~(HOST_CTRL0_PHYSWRST |
-                       HOST_CTRL0_PHYSWRSTALL |
-                       HOST_CTRL0_SIDDQ |
-                       /* Enable normal mode of operation */
-                       HOST_CTRL0_FORCESUSPEND |
-                       HOST_CTRL0_FORCESLEEP);
-
-       /* Link reset */
-       phyhost |= (HOST_CTRL0_LINKSWRST |
-                       HOST_CTRL0_UTMISWRST |
-                       /* COMMON Block configuration during suspend */
-                       HOST_CTRL0_COMMONON_N);
-       writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
-       udelay(10);
-       phyhost &= ~(HOST_CTRL0_LINKSWRST |
-                       HOST_CTRL0_UTMISWRST);
-       writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
-
-       /* OTG configuration */
-       phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS);
-
-       /* phy reference clock configuration */
-       phyotg &= ~OTG_SYS_FSEL_MASK;
-       phyotg |= OTG_SYS_FSEL(phyclk);
-
-       /* Enable normal mode of operation */
-       phyotg &= ~(OTG_SYS_FORCESUSPEND |
-                       OTG_SYS_SIDDQ_UOTG |
-                       OTG_SYS_FORCESLEEP |
-                       OTG_SYS_REFCLKSEL_MASK |
-                       /* COMMON Block configuration during suspend */
-                       OTG_SYS_COMMON_ON);
-
-       /* OTG phy & link reset */
-       phyotg |= (OTG_SYS_PHY0_SWRST |
-                       OTG_SYS_LINKSWRST_UOTG |
-                       OTG_SYS_PHYLINK_SWRESET |
-                       OTG_SYS_OTGDISABLE |
-                       /* Set phy refclk */
-                       OTG_SYS_REFCLKSEL_CLKCORE);
-
-       writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
-       udelay(10);
-       phyotg &= ~(OTG_SYS_PHY0_SWRST |
-                       OTG_SYS_LINKSWRST_UOTG |
-                       OTG_SYS_PHYLINK_SWRESET);
-       writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
-
-       /* HSIC phy configuration */
-       phyhsic = (HSIC_CTRL_REFCLKDIV_12 |
-                       HSIC_CTRL_REFCLKSEL |
-                       HSIC_CTRL_PHYSWRST);
-       writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
-       writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
-       udelay(10);
-       phyhsic &= ~HSIC_CTRL_PHYSWRST;
-       writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
-       writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
-
-       udelay(80);
-
-       /* enable EHCI DMA burst */
-       ehcictrl = readl(regs + EXYNOS5_PHY_HOST_EHCICTRL);
-       ehcictrl |= (HOST_EHCICTRL_ENAINCRXALIGN |
-                               HOST_EHCICTRL_ENAINCR4 |
-                               HOST_EHCICTRL_ENAINCR8 |
-                               HOST_EHCICTRL_ENAINCR16);
-       writel(ehcictrl, regs + EXYNOS5_PHY_HOST_EHCICTRL);
-
-       /* set ohci_suspend_on_n */
-       ohcictrl = readl(regs + EXYNOS5_PHY_HOST_OHCICTRL);
-       ohcictrl |= HOST_OHCICTRL_SUSPLGCY;
-       writel(ohcictrl, regs + EXYNOS5_PHY_HOST_OHCICTRL);
-}
-
-static void samsung_usbphy_enable(struct samsung_usbphy *sphy)
-{
-       void __iomem *regs = sphy->regs;
-       u32 phypwr;
-       u32 phyclk;
-       u32 rstcon;
-
-       /* set clock frequency for PLL */
-       phyclk = sphy->ref_clk_freq;
-       phypwr = readl(regs + SAMSUNG_PHYPWR);
-       rstcon = readl(regs + SAMSUNG_RSTCON);
-
-       switch (sphy->drv_data->cpu_type) {
-       case TYPE_S3C64XX:
-               phyclk &= ~PHYCLK_COMMON_ON_N;
-               phypwr &= ~PHYPWR_NORMAL_MASK;
-               rstcon |= RSTCON_SWRST;
-               break;
-       case TYPE_EXYNOS4210:
-               phypwr &= ~PHYPWR_NORMAL_MASK_PHY0;
-               rstcon |= RSTCON_SWRST;
-       default:
-               break;
-       }
-
-       writel(phyclk, regs + SAMSUNG_PHYCLK);
-       /* Configure PHY0 for normal operation*/
-       writel(phypwr, regs + SAMSUNG_PHYPWR);
-       /* reset all ports of PHY and Link */
-       writel(rstcon, regs + SAMSUNG_RSTCON);
-       udelay(10);
-       rstcon &= ~RSTCON_SWRST;
-       writel(rstcon, regs + SAMSUNG_RSTCON);
-}
-
-static void samsung_exynos5_usbphy_disable(struct samsung_usbphy *sphy)
-{
-       void __iomem *regs = sphy->regs;
-       u32 phyhost;
-       u32 phyotg;
-       u32 phyhsic;
-
-       if (atomic_dec_return(&sphy->phy_usage) > 0) {
-               dev_info(sphy->dev, "still being used\n");
-               return;
-       }
-
-       phyhsic = (HSIC_CTRL_REFCLKDIV_12 |
-                       HSIC_CTRL_REFCLKSEL |
-                       HSIC_CTRL_SIDDQ |
-                       HSIC_CTRL_FORCESLEEP |
-                       HSIC_CTRL_FORCESUSPEND);
-       writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
-       writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
-
-       phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
-       phyhost |= (HOST_CTRL0_SIDDQ |
-                       HOST_CTRL0_FORCESUSPEND |
-                       HOST_CTRL0_FORCESLEEP |
-                       HOST_CTRL0_PHYSWRST |
-                       HOST_CTRL0_PHYSWRSTALL);
-       writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
-
-       phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS);
-       phyotg |= (OTG_SYS_FORCESUSPEND |
-                       OTG_SYS_SIDDQ_UOTG |
-                       OTG_SYS_FORCESLEEP);
-       writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
-}
-
-static void samsung_usbphy_disable(struct samsung_usbphy *sphy)
-{
-       void __iomem *regs = sphy->regs;
-       u32 phypwr;
-
-       phypwr = readl(regs + SAMSUNG_PHYPWR);
-
-       switch (sphy->drv_data->cpu_type) {
-       case TYPE_S3C64XX:
-               phypwr |= PHYPWR_NORMAL_MASK;
-               break;
-       case TYPE_EXYNOS4210:
-               phypwr |= PHYPWR_NORMAL_MASK_PHY0;
-       default:
-               break;
-       }
-
-       /* Disable analog and otg block power */
-       writel(phypwr, regs + SAMSUNG_PHYPWR);
-}
-
-/*
- * The function passed to the usb driver for phy initialization
- */
-static int samsung_usbphy_init(struct usb_phy *phy)
-{
-       struct samsung_usbphy *sphy;
-       struct usb_bus *host = NULL;
-       unsigned long flags;
-       int ret = 0;
-
-       sphy = phy_to_sphy(phy);
-
-       host = phy->otg->host;
-
-       /* Enable the phy clock */
-       ret = clk_prepare_enable(sphy->clk);
-       if (ret) {
-               dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
-               return ret;
-       }
-
-       spin_lock_irqsave(&sphy->lock, flags);
-
-       if (host) {
-               /* setting default phy-type for USB 2.0 */
-               if (!strstr(dev_name(host->controller), "ehci") ||
-                               !strstr(dev_name(host->controller), "ohci"))
-                       samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_HOST);
-       } else {
-               samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE);
-       }
-
-       /* Disable phy isolation */
-       if (sphy->plat && sphy->plat->pmu_isolation)
-               sphy->plat->pmu_isolation(false);
-       else
-               samsung_usbphy_set_isolation(sphy, false);
-
-       /* Selecting Host/OTG mode; After reset USB2.0PHY_CFG: HOST */
-       samsung_usbphy_cfg_sel(sphy);
-
-       /* Initialize usb phy registers */
-       if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
-               samsung_exynos5_usbphy_enable(sphy);
-       else
-               samsung_usbphy_enable(sphy);
-
-       spin_unlock_irqrestore(&sphy->lock, flags);
-
-       /* Disable the phy clock */
-       clk_disable_unprepare(sphy->clk);
-
-       return ret;
-}
-
-/*
- * The function passed to the usb driver for phy shutdown
- */
-static void samsung_usbphy_shutdown(struct usb_phy *phy)
-{
-       struct samsung_usbphy *sphy;
-       struct usb_bus *host = NULL;
-       unsigned long flags;
-
-       sphy = phy_to_sphy(phy);
-
-       host = phy->otg->host;
-
-       if (clk_prepare_enable(sphy->clk)) {
-               dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
-               return;
-       }
-
-       spin_lock_irqsave(&sphy->lock, flags);
-
-       if (host) {
-               /* setting default phy-type for USB 2.0 */
-               if (!strstr(dev_name(host->controller), "ehci") ||
-                               !strstr(dev_name(host->controller), "ohci"))
-                       samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_HOST);
-       } else {
-               samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE);
-       }
-
-       /* De-initialize usb phy registers */
-       if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
-               samsung_exynos5_usbphy_disable(sphy);
-       else
-               samsung_usbphy_disable(sphy);
-
-       /* Enable phy isolation */
-       if (sphy->plat && sphy->plat->pmu_isolation)
-               sphy->plat->pmu_isolation(true);
-       else
-               samsung_usbphy_set_isolation(sphy, true);
-
-       spin_unlock_irqrestore(&sphy->lock, flags);
-
-       clk_disable_unprepare(sphy->clk);
-}
-
-static const struct of_device_id samsung_usbphy_dt_match[];
-
-static inline const struct samsung_usbphy_drvdata
-*samsung_usbphy_get_driver_data(struct platform_device *pdev)
-{
-       if (pdev->dev.of_node) {
-               const struct of_device_id *match;
-               match = of_match_node(samsung_usbphy_dt_match,
-                                                       pdev->dev.of_node);
-               return match->data;
-       }
-
-       return (struct samsung_usbphy_drvdata *)
-                               platform_get_device_id(pdev)->driver_data;
-}
-
-static int samsung_usbphy_probe(struct platform_device *pdev)
-{
-       struct samsung_usbphy *sphy;
-       struct usb_otg *otg;
-       struct samsung_usbphy_data *pdata = pdev->dev.platform_data;
-       const struct samsung_usbphy_drvdata *drv_data;
-       struct device *dev = &pdev->dev;
-       struct resource *phy_mem;
-       void __iomem    *phy_base;
-       struct clk *clk;
-       int ret;
-
-       phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!phy_mem) {
-               dev_err(dev, "%s: missing mem resource\n", __func__);
-               return -ENODEV;
-       }
-
-       phy_base = devm_ioremap_resource(dev, phy_mem);
-       if (IS_ERR(phy_base))
-               return PTR_ERR(phy_base);
-
-       sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
-       if (!sphy)
-               return -ENOMEM;
-
-       otg = devm_kzalloc(dev, sizeof(*otg), GFP_KERNEL);
-       if (!otg)
-               return -ENOMEM;
-
-       drv_data = samsung_usbphy_get_driver_data(pdev);
-
-       if (drv_data->cpu_type == TYPE_EXYNOS5250)
-               clk = devm_clk_get(dev, "usbhost");
-       else
-               clk = devm_clk_get(dev, "otg");
-
-       if (IS_ERR(clk)) {
-               dev_err(dev, "Failed to get otg clock\n");
-               return PTR_ERR(clk);
-       }
-
-       sphy->dev = dev;
-
-       if (dev->of_node) {
-               ret = samsung_usbphy_parse_dt(sphy);
-               if (ret < 0)
-                       return ret;
-       } else {
-               if (!pdata) {
-                       dev_err(dev, "no platform data specified\n");
-                       return -EINVAL;
-               }
-       }
-
-       sphy->plat              = pdata;
-       sphy->regs              = phy_base;
-       sphy->clk               = clk;
-       sphy->drv_data          = drv_data;
-       sphy->phy.dev           = sphy->dev;
-       sphy->phy.label         = "samsung-usbphy";
-       sphy->phy.init          = samsung_usbphy_init;
-       sphy->phy.shutdown      = samsung_usbphy_shutdown;
-       sphy->ref_clk_freq      = samsung_usbphy_get_refclk_freq(sphy);
-
-       sphy->phy.otg           = otg;
-       sphy->phy.otg->phy      = &sphy->phy;
-       sphy->phy.otg->set_host = samsung_usbphy_set_host;
-
-       spin_lock_init(&sphy->lock);
-
-       platform_set_drvdata(pdev, sphy);
-
-       return usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2);
-}
-
-static int samsung_usbphy_remove(struct platform_device *pdev)
-{
-       struct samsung_usbphy *sphy = platform_get_drvdata(pdev);
-
-       usb_remove_phy(&sphy->phy);
-
-       if (sphy->pmuregs)
-               iounmap(sphy->pmuregs);
-       if (sphy->sysreg)
-               iounmap(sphy->sysreg);
-
-       return 0;
-}
-
-static const struct samsung_usbphy_drvdata usbphy_s3c64xx = {
-       .cpu_type               = TYPE_S3C64XX,
-       .devphy_en_mask         = S3C64XX_USBPHY_ENABLE,
-};
-
-static const struct samsung_usbphy_drvdata usbphy_exynos4 = {
-       .cpu_type               = TYPE_EXYNOS4210,
-       .devphy_en_mask         = EXYNOS_USBPHY_ENABLE,
-       .hostphy_en_mask        = EXYNOS_USBPHY_ENABLE,
-};
-
-static struct samsung_usbphy_drvdata usbphy_exynos5 = {
-       .cpu_type               = TYPE_EXYNOS5250,
-       .hostphy_en_mask        = EXYNOS_USBPHY_ENABLE,
-       .hostphy_reg_offset     = EXYNOS_USBHOST_PHY_CTRL_OFFSET,
-};
-
-#ifdef CONFIG_OF
-static const struct of_device_id samsung_usbphy_dt_match[] = {
-       {
-               .compatible = "samsung,s3c64xx-usbphy",
-               .data = &usbphy_s3c64xx,
-       }, {
-               .compatible = "samsung,exynos4210-usbphy",
-               .data = &usbphy_exynos4,
-       }, {
-               .compatible = "samsung,exynos5250-usbphy",
-               .data = &usbphy_exynos5
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match);
-#endif
-
-static struct platform_device_id samsung_usbphy_driver_ids[] = {
-       {
-               .name           = "s3c64xx-usbphy",
-               .driver_data    = (unsigned long)&usbphy_s3c64xx,
-       }, {
-               .name           = "exynos4210-usbphy",
-               .driver_data    = (unsigned long)&usbphy_exynos4,
-       }, {
-               .name           = "exynos5250-usbphy",
-               .driver_data    = (unsigned long)&usbphy_exynos5,
-       },
-       {},
-};
-
-MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids);
-
-static struct platform_driver samsung_usbphy_driver = {
-       .probe          = samsung_usbphy_probe,
-       .remove         = samsung_usbphy_remove,
-       .id_table       = samsung_usbphy_driver_ids,
-       .driver         = {
-               .name   = "samsung-usbphy",
-               .owner  = THIS_MODULE,
-               .of_match_table = of_match_ptr(samsung_usbphy_dt_match),
-       },
-};
-
-module_platform_driver(samsung_usbphy_driver);
-
-MODULE_DESCRIPTION("Samsung USB phy controller");
-MODULE_AUTHOR("Praveen Paneri <p.paneri@samsung.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:samsung-usbphy");
index 9538f0f..45b9401 100644 (file)
@@ -32,7 +32,6 @@
  */
 void usbhs_pkt_init(struct usbhs_pkt *pkt)
 {
-       pkt->dma = DMA_ADDR_INVALID;
        INIT_LIST_HEAD(&pkt->node);
 }
 
index c31731a..a168a17 100644 (file)
@@ -23,8 +23,6 @@
 #include <asm/dma.h>
 #include "pipe.h"
 
-#define        DMA_ADDR_INVALID        (~(dma_addr_t)0)
-
 struct usbhs_fifo {
        char *name;
        u32 port;       /* xFIFO */
index 78fca97..ed4949f 100644 (file)
@@ -230,7 +230,7 @@ static int usbhsg_recip_handler_std_clear_endpoint(struct usbhs_priv *priv,
        return 0;
 }
 
-struct usbhsg_recip_handle req_clear_feature = {
+static struct usbhsg_recip_handle req_clear_feature = {
        .name           = "clear feature",
        .device         = usbhsg_recip_handler_std_control_done,
        .interface      = usbhsg_recip_handler_std_control_done,
@@ -271,7 +271,7 @@ static int usbhsg_recip_handler_std_set_endpoint(struct usbhs_priv *priv,
        return 0;
 }
 
-struct usbhsg_recip_handle req_set_feature = {
+static struct usbhsg_recip_handle req_set_feature = {
        .name           = "set feature",
        .device         = usbhsg_recip_handler_std_set_device,
        .interface      = usbhsg_recip_handler_std_control_done,
@@ -372,7 +372,7 @@ static int usbhsg_recip_handler_std_get_endpoint(struct usbhs_priv *priv,
        return 0;
 }
 
-struct usbhsg_recip_handle req_get_status = {
+static struct usbhsg_recip_handle req_get_status = {
        .name           = "get status",
        .device         = usbhsg_recip_handler_std_get_device,
        .interface      = usbhsg_recip_handler_std_get_interface,
@@ -845,7 +845,6 @@ static int usbhsg_gadget_start(struct usb_gadget *gadget,
 
        /* first hook up the driver ... */
        gpriv->driver = driver;
-       gpriv->gadget.dev.driver = &driver->driver;
 
        return usbhsg_try_start(priv, USBHSG_STATUS_REGISTERD);
 }
@@ -861,7 +860,6 @@ static int usbhsg_gadget_stop(struct usb_gadget *gadget,
                return -EINVAL;
 
        usbhsg_try_stop(priv, USBHSG_STATUS_REGISTERD);
-       gpriv->gadget.dev.driver = NULL;
        gpriv->driver = NULL;
 
        return 0;
@@ -925,11 +923,6 @@ static int usbhsg_stop(struct usbhs_priv *priv)
        return usbhsg_try_stop(priv, USBHSG_STATUS_STARTED);
 }
 
-static void usbhs_mod_gadget_release(struct device *pdev)
-{
-       /* do nothing */
-}
-
 int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
 {
        struct usbhsg_gpriv *gpriv;
@@ -976,15 +969,10 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
        /*
         * init gadget
         */
-       dev_set_name(&gpriv->gadget.dev, "gadget");
        gpriv->gadget.dev.parent        = dev;
-       gpriv->gadget.dev.release       = usbhs_mod_gadget_release;
        gpriv->gadget.name              = "renesas_usbhs_udc";
        gpriv->gadget.ops               = &usbhsg_gadget_ops;
        gpriv->gadget.max_speed         = USB_SPEED_HIGH;
-       ret = device_register(&gpriv->gadget.dev);
-       if (ret < 0)
-               goto err_add_udc;
 
        INIT_LIST_HEAD(&gpriv->gadget.ep_list);
 
@@ -1014,15 +1002,13 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
 
        ret = usb_add_gadget_udc(dev, &gpriv->gadget);
        if (ret)
-               goto err_register;
+               goto err_add_udc;
 
 
        dev_info(dev, "gadget probed\n");
 
        return 0;
 
-err_register:
-       device_unregister(&gpriv->gadget.dev);
 err_add_udc:
        kfree(gpriv->uep);
 
@@ -1038,8 +1024,6 @@ void usbhs_mod_gadget_remove(struct usbhs_priv *priv)
 
        usb_del_gadget_udc(&gpriv->gadget);
 
-       device_unregister(&gpriv->gadget.dev);
-
        kfree(gpriv->uep);
        kfree(gpriv);
 }
index d29503e..0db0a91 100644 (file)
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/usb/ch9.h>
+#include <linux/usb/otg.h>
+
+const char *usb_otg_state_string(enum usb_otg_state state)
+{
+       static const char *const names[] = {
+               [OTG_STATE_A_IDLE] = "a_idle",
+               [OTG_STATE_A_WAIT_VRISE] = "a_wait_vrise",
+               [OTG_STATE_A_WAIT_BCON] = "a_wait_bcon",
+               [OTG_STATE_A_HOST] = "a_host",
+               [OTG_STATE_A_SUSPEND] = "a_suspend",
+               [OTG_STATE_A_PERIPHERAL] = "a_peripheral",
+               [OTG_STATE_A_WAIT_VFALL] = "a_wait_vfall",
+               [OTG_STATE_A_VBUS_ERR] = "a_vbus_err",
+               [OTG_STATE_B_IDLE] = "b_idle",
+               [OTG_STATE_B_SRP_INIT] = "b_srp_init",
+               [OTG_STATE_B_PERIPHERAL] = "b_peripheral",
+               [OTG_STATE_B_WAIT_ACON] = "b_wait_acon",
+               [OTG_STATE_B_HOST] = "b_host",
+       };
+
+       if (state < 0 || state >= ARRAY_SIZE(names))
+               return "UNDEFINED";
+
+       return names[state];
+}
+EXPORT_SYMBOL_GPL(usb_otg_state_string);
 
 const char *usb_speed_string(enum usb_device_speed speed)
 {
@@ -32,4 +58,25 @@ const char *usb_speed_string(enum usb_device_speed speed)
 }
 EXPORT_SYMBOL_GPL(usb_speed_string);
 
+const char *usb_state_string(enum usb_device_state state)
+{
+       static const char *const names[] = {
+               [USB_STATE_NOTATTACHED] = "not attached",
+               [USB_STATE_ATTACHED] = "attached",
+               [USB_STATE_POWERED] = "powered",
+               [USB_STATE_RECONNECTING] = "reconnecting",
+               [USB_STATE_UNAUTHENTICATED] = "unauthenticated",
+               [USB_STATE_DEFAULT] = "default",
+               [USB_STATE_ADDRESS] = "addresssed",
+               [USB_STATE_CONFIGURED] = "configured",
+               [USB_STATE_SUSPENDED] = "suspended",
+       };
+
+       if (state < 0 || state >= ARRAY_SIZE(names))
+               return "UNKNOWN";
+
+       return names[state];
+}
+EXPORT_SYMBOL_GPL(usb_state_string);
+
 MODULE_LICENSE("GPL");
index ada4012..1d36ca8 100644 (file)
@@ -41,7 +41,3 @@ enum dwc3_omap_utmi_mode {
        DWC3_OMAP_UTMI_MODE_HW,
        DWC3_OMAP_UTMI_MODE_SW,
 };
-
-struct dwc3_omap_data {
-       enum dwc3_omap_utmi_mode        utmi_mode;
-};
index 944b01d..98b7925 100644 (file)
@@ -34,8 +34,6 @@ struct mv_usb_addon_irq {
 };
 
 struct mv_usb_platform_data {
-       unsigned int            clknum;
-       char                    **clkname;
        struct mv_usb_addon_irq *id;    /* Only valid for OTG. ID pin change*/
        struct mv_usb_addon_irq *vbus;  /* valid for OTG/UDC. VBUS change*/
 
index 9c210f2..27603bc 100644 (file)
  */
 extern const char *usb_speed_string(enum usb_device_speed speed);
 
+
+/**
+ * usb_state_string - Returns human readable name for the state.
+ * @state: The state to return a human-readable name for. If it's not
+ *     any of the states devices in usb_device_state_string enum,
+ *     the string UNKNOWN will be returned.
+ */
+extern const char *usb_state_string(enum usb_device_state state);
+
 #endif /* __LINUX_USB_CH9_H */
index 8860594..5e61589 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/log2.h>
+#include <linux/configfs.h>
 
 /*
  * USB function drivers should return USB_GADGET_DELAYED_STATUS if they
@@ -464,6 +465,8 @@ struct usb_function_driver {
 };
 
 struct usb_function_instance {
+       struct config_group group;
+       struct list_head cfs_list;
        struct usb_function_driver *fd;
        void (*free_func_inst)(struct usb_function_instance *inst);
 };
index 51eae14..5615f4d 100644 (file)
@@ -19,11 +19,11 @@ enum omap_dwc3_vbus_id_status {
 };
 
 #if (defined(CONFIG_USB_DWC3) || defined(CONFIG_USB_DWC3_MODULE))
-extern void dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status);
+extern int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status);
 #else
-static inline void dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
+static inline int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
 {
-       return;
+       return -ENODEV;
 }
 #endif
 
index 2e297e8..c454a88 100644 (file)
@@ -482,6 +482,7 @@ struct usb_gadget_ops {
  * @speed: Speed of current connection to USB host.
  * @max_speed: Maximal speed the UDC can handle.  UDC must support this
  *      and all slower speeds.
+ * @state: the state we are now (attached, suspended, configured, etc)
  * @sg_supported: true if we can handle scatter-gather
  * @is_otg: True if the USB device port uses a Mini-AB jack, so that the
  *     gadget driver must provide a USB OTG descriptor.
@@ -525,6 +526,7 @@ struct usb_gadget {
        struct list_head                ep_list;        /* of usb_ep */
        enum usb_device_speed           speed;
        enum usb_device_speed           max_speed;
+       enum usb_device_state           state;
        unsigned                        sg_supported:1;
        unsigned                        is_otg:1;
        unsigned                        is_a_peripheral:1;
@@ -872,6 +874,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver);
  */
 int usb_gadget_unregister_driver(struct usb_gadget_driver *driver);
 
+extern int usb_add_gadget_udc_release(struct device *parent,
+               struct usb_gadget *gadget, void (*release)(struct device *dev));
 extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget);
 extern void usb_del_gadget_udc(struct usb_gadget *gadget);
 extern int udc_attach_driver(const char *name,
@@ -959,6 +963,13 @@ extern void usb_gadget_unmap_request(struct usb_gadget *gadget,
 
 /*-------------------------------------------------------------------------*/
 
+/* utility to set gadget state properly */
+
+extern void usb_gadget_set_state(struct usb_gadget *gadget,
+               enum usb_device_state state);
+
+/*-------------------------------------------------------------------------*/
+
 /* utility wrapping a simple endpoint selection policy */
 
 extern struct usb_ep *usb_ep_autoconfig(struct usb_gadget *,
diff --git a/include/linux/usb/gadget_configfs.h b/include/linux/usb/gadget_configfs.h
new file mode 100644 (file)
index 0000000..d74c0ae
--- /dev/null
@@ -0,0 +1,110 @@
+#ifndef __GADGET_CONFIGFS__
+#define __GADGET_CONFIGFS__
+
+#include <linux/configfs.h>
+
+int check_user_usb_string(const char *name,
+               struct usb_gadget_strings *stringtab_dev);
+
+#define GS_STRINGS_W(__struct, __name) \
+       static ssize_t __struct##_##__name##_store(struct __struct *gs, \
+               const char *page, size_t len)           \
+{                                                      \
+       int ret;                                        \
+                                                       \
+       ret = usb_string_copy(page, &gs->__name);       \
+       if (ret)                                        \
+               return ret;                             \
+       return len;                                     \
+}
+
+#define GS_STRINGS_R(__struct, __name) \
+       static ssize_t __struct##_##__name##_show(struct __struct *gs, \
+                       char *page)     \
+{      \
+       return sprintf(page, "%s\n", gs->__name ?: ""); \
+}
+
+#define GS_STRING_ITEM_ATTR(struct_name, name) \
+       static struct struct_name##_attribute struct_name##_##name = \
+               __CONFIGFS_ATTR(name,  S_IRUGO | S_IWUSR,               \
+                               struct_name##_##name##_show,            \
+                               struct_name##_##name##_store)
+
+#define GS_STRINGS_RW(struct_name, _name)      \
+       GS_STRINGS_R(struct_name, _name)        \
+       GS_STRINGS_W(struct_name, _name)        \
+       GS_STRING_ITEM_ATTR(struct_name, _name)
+
+#define USB_CONFIG_STRING_RW_OPS(struct_in)                            \
+       CONFIGFS_ATTR_OPS(struct_in);                                   \
+                                                                       \
+static struct configfs_item_operations struct_in##_langid_item_ops = { \
+       .release                = struct_in##_attr_release,             \
+       .show_attribute         = struct_in##_attr_show,                \
+       .store_attribute        = struct_in##_attr_store,               \
+};                                                                     \
+                                                                       \
+static struct config_item_type struct_in##_langid_type = {             \
+       .ct_item_ops    = &struct_in##_langid_item_ops,                 \
+       .ct_attrs       = struct_in##_langid_attrs,                     \
+       .ct_owner       = THIS_MODULE,                                  \
+}
+
+#define USB_CONFIG_STRINGS_LANG(struct_in, struct_member)      \
+       static struct config_group *struct_in##_strings_make(           \
+                       struct config_group *group,                     \
+                       const char *name)                               \
+       {                                                               \
+       struct struct_member *gi;                                       \
+       struct struct_in *gs;                                           \
+       struct struct_in *new;                                          \
+       int langs = 0;                                                  \
+       int ret;                                                        \
+                                                                       \
+       new = kzalloc(sizeof(*new), GFP_KERNEL);                        \
+       if (!new)                                                       \
+               return ERR_PTR(-ENOMEM);                                \
+                                                                       \
+       ret = check_user_usb_string(name, &new->stringtab_dev);         \
+       if (ret)                                                        \
+               goto err;                                               \
+       config_group_init_type_name(&new->group, name,                  \
+                       &struct_in##_langid_type);                      \
+                                                                       \
+       gi = container_of(group, struct struct_member, strings_group);  \
+       ret = -EEXIST;                                                  \
+       list_for_each_entry(gs, &gi->string_list, list) {               \
+               if (gs->stringtab_dev.language == new->stringtab_dev.language) \
+                       goto err;                                       \
+               langs++;                                                \
+       }                                                               \
+       ret = -EOVERFLOW;                                               \
+       if (langs >= MAX_USB_STRING_LANGS)                              \
+               goto err;                                               \
+                                                                       \
+       list_add_tail(&new->list, &gi->string_list);                    \
+       return &new->group;                                             \
+err:                                                                   \
+       kfree(new);                                                     \
+       return ERR_PTR(ret);                                            \
+}                                                                      \
+                                                                       \
+static void struct_in##_strings_drop(                                  \
+               struct config_group *group,                             \
+               struct config_item *item)                               \
+{                                                                      \
+       config_item_put(item);                                          \
+}                                                                      \
+                                                                       \
+static struct configfs_group_operations struct_in##_strings_ops = {    \
+       .make_group     = &struct_in##_strings_make,                    \
+       .drop_item      = &struct_in##_strings_drop,                    \
+};                                                                     \
+                                                                       \
+static struct config_item_type struct_in##_strings_type = {            \
+       .ct_group_ops   = &struct_in##_strings_ops,                     \
+       .ct_owner       = THIS_MODULE,                                  \
+}
+
+#endif
diff --git a/include/linux/usb/musb-ux500.h b/include/linux/usb/musb-ux500.h
new file mode 100644 (file)
index 0000000..1e2c713
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013 ST-Ericsson AB
+ *
+ * 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.
+ */
+
+#ifndef __MUSB_UX500_H__
+#define __MUSB_UX500_H__
+
+enum ux500_musb_vbus_id_status {
+       UX500_MUSB_NONE = 0,
+       UX500_MUSB_VBUS,
+       UX500_MUSB_ID,
+       UX500_MUSB_CHARGER,
+       UX500_MUSB_ENUMERATED,
+       UX500_MUSB_RIDA,
+       UX500_MUSB_RIDB,
+       UX500_MUSB_RIDC,
+       UX500_MUSB_PREPARE,
+       UX500_MUSB_CLEAN,
+};
+
+#endif /* __MUSB_UX500_H__ */
index 28884c7..148d351 100644 (file)
@@ -5,6 +5,11 @@
 
 struct nop_usb_xceiv_platform_data {
        enum usb_phy_type type;
+       unsigned long clk_rate;
+
+       /* if set fails with -EPROBE_DEFER if can't get regulator */
+       unsigned int needs_vcc:1;
+       unsigned int needs_reset:1;
 };
 
 #if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE))
index e8a5fe8..291e01b 100644 (file)
@@ -36,14 +36,7 @@ struct usb_otg {
 
 };
 
-#ifdef CONFIG_USB_OTG_UTILS
-extern const char *otg_state_string(enum usb_otg_state state);
-#else
-static inline const char *otg_state_string(enum usb_otg_state state)
-{
-       return NULL;
-}
-#endif
+extern const char *usb_otg_state_string(enum usb_otg_state state);
 
 /* Context: can sleep */
 static inline int
index 15847cb..6b5978f 100644 (file)
@@ -91,6 +91,9 @@ struct usb_phy {
        int     (*init)(struct usb_phy *x);
        void    (*shutdown)(struct usb_phy *x);
 
+       /* enable/disable VBUS */
+       int     (*set_vbus)(struct usb_phy *x, int on);
+
        /* effective for B devices, ignored for A-peripheral */
        int     (*set_power)(struct usb_phy *x,
                                unsigned mA);
@@ -160,8 +163,26 @@ usb_phy_shutdown(struct usb_phy *x)
                x->shutdown(x);
 }
 
+static inline int
+usb_phy_vbus_on(struct usb_phy *x)
+{
+       if (!x->set_vbus)
+               return 0;
+
+       return x->set_vbus(x, true);
+}
+
+static inline int
+usb_phy_vbus_off(struct usb_phy *x)
+{
+       if (!x->set_vbus)
+               return 0;
+
+       return x->set_vbus(x, false);
+}
+
 /* for usb host and peripheral controller drivers */
-#ifdef CONFIG_USB_OTG_UTILS
+#if IS_ENABLED(CONFIG_USB_PHY)
 extern struct usb_phy *usb_get_phy(enum usb_phy_type type);
 extern struct usb_phy *devm_usb_get_phy(struct device *dev,
        enum usb_phy_type type);
@@ -176,29 +197,29 @@ extern int usb_bind_phy(const char *dev_name, u8 index,
 #else
 static inline struct usb_phy *usb_get_phy(enum usb_phy_type type)
 {
-       return NULL;
+       return ERR_PTR(-ENXIO);
 }
 
 static inline struct usb_phy *devm_usb_get_phy(struct device *dev,
        enum usb_phy_type type)
 {
-       return NULL;
+       return ERR_PTR(-ENXIO);
 }
 
 static inline struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index)
 {
-       return NULL;
+       return ERR_PTR(-ENXIO);
 }
 
 static inline struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index)
 {
-       return NULL;
+       return ERR_PTR(-ENXIO);
 }
 
 static inline struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev,
        const char *phandle, u8 index)
 {
-       return NULL;
+       return ERR_PTR(-ENXIO);
 }
 
 static inline void usb_put_phy(struct usb_phy *x)
index c5d36c6..e452ba6 100644 (file)
@@ -62,14 +62,14 @@ struct renesas_usbhs_platform_callback {
         * Hardware exit function for platform.
         * it is called when driver was removed
         */
-       void (*hardware_exit)(struct platform_device *pdev);
+       int (*hardware_exit)(struct platform_device *pdev);
 
        /*
         * option:
         *
         * for board specific clock control
         */
-       void (*power_ctrl)(struct platform_device *pdev,
+       int (*power_ctrl)(struct platform_device *pdev,
                           void __iomem *base, int enable);
 
        /*
@@ -77,7 +77,7 @@ struct renesas_usbhs_platform_callback {
         *
         * Phy reset for platform
         */
-       void (*phy_reset)(struct platform_device *pdev);
+       int (*phy_reset)(struct platform_device *pdev);
 
        /*
         * get USB ID function