diff options
291 files changed, 14364 insertions, 6800 deletions
diff --git a/Documentation/ABI/testing/configfs-usb-gadget b/Documentation/ABI/testing/configfs-usb-gadget index 37559a06393b..95a36589a66b 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget +++ b/Documentation/ABI/testing/configfs-usb-gadget @@ -62,6 +62,40 @@ KernelVersion: 3.11 Description: This group contains functions available to this USB gadget. +What: /config/usb-gadget/gadget/functions/<func>.<inst>/interface.<n> +Date: May 2014 +KernelVersion: 3.16 +Description: + This group contains "Feature Descriptors" specific for one + gadget's USB interface or one interface group described + by an IAD. + + The attributes: + + compatible_id - 8-byte string for "Compatible ID" + sub_compatible_id - 8-byte string for "Sub Compatible ID" + +What: /config/usb-gadget/gadget/functions/<func>.<inst>/interface.<n>/<property> +Date: May 2014 +KernelVersion: 3.16 +Description: + This group contains "Extended Property Descriptors" specific for one + gadget's USB interface or one interface group described + by an IAD. + + The attributes: + + type - value 1..7 for interpreting the data + 1: unicode string + 2: unicode string with environment variable + 3: binary + 4: little-endian 32-bit + 5: big-endian 32-bit + 6: unicode string with a symbolic link + 7: multiple unicode strings + data - blob of data to be interpreted depending on + type + What: /config/usb-gadget/gadget/strings Date: Jun 2013 KernelVersion: 3.11 @@ -79,3 +113,14 @@ Description: product - gadget's product description manufacturer - gadget's manufacturer description +What: /config/usb-gadget/gadget/os_desc +Date: May 2014 +KernelVersion: 3.16 +Description: + This group contains "OS String" extension handling attributes. + + use - flag turning "OS Desctiptors" support on/off + b_vendor_code - one-byte value used for custom per-device and + per-interface requests + qw_sign - an identifier to be reported as "OS String" + proper diff --git a/Documentation/ABI/testing/sysfs-platform-chipidea-usb-otg b/Documentation/ABI/testing/sysfs-platform-chipidea-usb-otg new file mode 100644 index 000000000000..151c59578db4 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-chipidea-usb-otg @@ -0,0 +1,56 @@ +What: /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req +Date: Feb 2014 +Contact: Li Jun <b47624@freescale.com> +Description: + Can be set and read. + Set a_bus_req(A-device bus request) input to be 1 if + the application running on the A-device wants to use the bus, + and to be 0 when the application no longer wants to use + the bus(or wants to work as peripheral). a_bus_req can also + be set to 1 by kernel in response to remote wakeup signaling + from the B-device, the A-device should decide to resume the bus. + + Valid values are "1" and "0". + + Reading: returns 1 if the application running on the A-device + is using the bus as host role, otherwise 0. + +What: /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_drop +Date: Feb 2014 +Contact: Li Jun <b47624@freescale.com> +Description: + Can be set and read + The a_bus_drop(A-device bus drop) input is 1 when the + application running on the A-device wants to power down + the bus, and is 0 otherwise, When a_bus_drop is 1, then + the a_bus_req shall be 0. + + Valid values are "1" and "0". + + Reading: returns 1 if the bus is off(vbus is turned off) by + A-device, otherwise 0. + +What: /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req +Date: Feb 2014 +Contact: Li Jun <b47624@freescale.com> +Description: + Can be set and read. + The b_bus_req(B-device bus request) input is 1 during the time + that the application running on the B-device wants to use the + bus as host, and is 0 when the application no longer wants to + work as host and decides to switch back to be peripheral. + + Valid values are "1" and "0". + + Reading: returns if the application running on the B device + is using the bus as host role, otherwise 0. + +What: /sys/bus/platform/devices/ci_hdrc.0/inputs/a_clr_err +Date: Feb 2014 +Contact: Li Jun <b47624@freescale.com> +Description: + Only can be set. + The a_clr_err(A-device Vbus error clear) input is used to clear + vbus error, then A-device will power down the bus. + + Valid value is "1" diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index b444f2e8fe32..bec06659e0eb 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -14,7 +14,8 @@ DOCBOOKS := z8530book.xml device-drivers.xml \ genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \ 80211.xml debugobjects.xml sh.xml regulator.xml \ alsa-driver-api.xml writing-an-alsa-driver.xml \ - tracepoint.xml drm.xml media_api.xml w1.xml + tracepoint.xml drm.xml media_api.xml w1.xml \ + writing_musb_glue_layer.xml include Documentation/DocBook/media/Makefile diff --git a/Documentation/DocBook/writing_musb_glue_layer.tmpl b/Documentation/DocBook/writing_musb_glue_layer.tmpl new file mode 100644 index 000000000000..837eca77f274 --- /dev/null +++ b/Documentation/DocBook/writing_musb_glue_layer.tmpl @@ -0,0 +1,873 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" + "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []> + +<book id="Writing-MUSB-Glue-Layer"> + <bookinfo> + <title>Writing an MUSB Glue Layer</title> + + <authorgroup> + <author> + <firstname>Apelete</firstname> + <surname>Seketeli</surname> + <affiliation> + <address> + <email>apelete at seketeli.net</email> + </address> + </affiliation> + </author> + </authorgroup> + + <copyright> + <year>2014</year> + <holder>Apelete Seketeli</holder> + </copyright> + + <legalnotice> + <para> + This documentation 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. + </para> + + <para> + This documentation 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. + </para> + + <para> + You should have received a copy of the GNU General Public License + along with this documentation; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA + </para> + + <para> + For more details see the file COPYING in the Linux kernel source + tree. + </para> + </legalnotice> + </bookinfo> + +<toc></toc> + + <chapter id="introduction"> + <title>Introduction</title> + <para> + The Linux MUSB subsystem is part of the larger Linux USB + subsystem. It provides support for embedded USB Device Controllers + (UDC) that do not use Universal Host Controller Interface (UHCI) + or Open Host Controller Interface (OHCI). + </para> + <para> + Instead, these embedded UDC rely on the USB On-the-Go (OTG) + specification which they implement at least partially. The silicon + reference design used in most cases is the Multipoint USB + Highspeed Dual-Role Controller (MUSB HDRC) found in the Mentor + Graphics Inventra™ design. + </para> + <para> + As a self-taught exercise I have written an MUSB glue layer for + the Ingenic JZ4740 SoC, modelled after the many MUSB glue layers + in the kernel source tree. This layer can be found at + drivers/usb/musb/jz4740.c. In this documentation I will walk + through the basics of the jz4740.c glue layer, explaining the + different pieces and what needs to be done in order to write your + own device glue layer. + </para> + </chapter> + + <chapter id="linux-musb-basics"> + <title>Linux MUSB Basics</title> + <para> + To get started on the topic, please read USB On-the-Go Basics (see + Resources) which provides an introduction of USB OTG operation at + the hardware level. A couple of wiki pages by Texas Instruments + and Analog Devices also provide an overview of the Linux kernel + MUSB configuration, albeit focused on some specific devices + provided by these companies. Finally, getting acquainted with the + USB specification at USB home page may come in handy, with + practical instance provided through the Writing USB Device Drivers + documentation (again, see Resources). + </para> + <para> + Linux USB stack is a layered architecture in which the MUSB + controller hardware sits at the lowest. The MUSB controller driver + abstract the MUSB controller hardware to the Linux USB stack. + </para> + <programlisting> + ------------------------ + | | <------- drivers/usb/gadget + | Linux USB Core Stack | <------- drivers/usb/host + | | <------- drivers/usb/core + ------------------------ + ⬍ + -------------------------- + | | <------ drivers/usb/musb/musb_gadget.c + | MUSB Controller driver | <------ drivers/usb/musb/musb_host.c + | | <------ drivers/usb/musb/musb_core.c + -------------------------- + ⬍ + --------------------------------- + | MUSB Platform Specific Driver | + | | <-- drivers/usb/musb/jz4740.c + | aka "Glue Layer" | + --------------------------------- + ⬍ + --------------------------------- + | MUSB Controller Hardware | + --------------------------------- + </programlisting> + <para> + As outlined above, the glue layer is actually the platform + specific code sitting in between the controller driver and the + controller hardware. + </para> + <para> + Just like a Linux USB driver needs to register itself with the + Linux USB subsystem, the MUSB glue layer needs first to register + itself with the MUSB controller driver. This will allow the + controller driver to know about which device the glue layer + supports and which functions to call when a supported device is + detected or released; remember we are talking about an embedded + controller chip here, so no insertion or removal at run-time. + </para> + <para> + All of this information is passed to the MUSB controller driver + through a platform_driver structure defined in the glue layer as: + </para> + <programlisting linenumbering="numbered"> +static struct platform_driver jz4740_driver = { + .probe = jz4740_probe, + .remove = jz4740_remove, + .driver = { + .name = "musb-jz4740", + }, +}; + </programlisting> + <para> + The probe and remove function pointers are called when a matching + device is detected and, respectively, released. The name string + describes the device supported by this glue layer. In the current + case it matches a platform_device structure declared in + arch/mips/jz4740/platform.c. Note that we are not using device + tree bindings here. + </para> + <para> + In order to register itself to the controller driver, the glue + layer goes through a few steps, basically allocating the + controller hardware resources and initialising a couple of + circuits. To do so, it needs to keep track of the information used + throughout these steps. This is done by defining a private + jz4740_glue structure: + </para> + <programlisting linenumbering="numbered"> +struct jz4740_glue { + struct device *dev; + struct platform_device *musb; + struct clk *clk; +}; + </programlisting> + <para> + The dev and musb members are both device structure variables. The + first one holds generic information about the device, since it's + the basic device structure, and the latter holds information more + closely related to the subsystem the device is registered to. The + clk variable keeps information related to the device clock + operation. + </para> + <para> + Let's go through the steps of the probe function that leads the + glue layer to register itself to the controller driver. + </para> + <para> + N.B.: For the sake of readability each function will be split in + logical parts, each part being shown as if it was independent from + the others. + </para> + <programlisting linenumbering="numbered"> +static int jz4740_probe(struct platform_device *pdev) +{ + struct platform_device *musb; + struct jz4740_glue *glue; + struct clk *clk; + int ret; + + glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); + if (!glue) + return -ENOMEM; + + musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); + if (!musb) { + dev_err(&pdev->dev, "failed to allocate musb device\n"); + return -ENOMEM; + } + + clk = devm_clk_get(&pdev->dev, "udc"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "failed to get clock\n"); + ret = PTR_ERR(clk); + goto err_platform_device_put; + } + + ret = clk_prepare_enable(clk); + if (ret) { + dev_err(&pdev->dev, "failed to enable clock\n"); + goto err_platform_device_put; + } + + musb->dev.parent = &pdev->dev; + + glue->dev = &pdev->dev; + glue->musb = musb; + glue->clk = clk; + + return 0; + +err_platform_device_put: + platform_device_put(musb); + return ret; +} + </programlisting> + <para> + The first few lines of the probe function allocate and assign the + glue, musb and clk variables. The GFP_KERNEL flag (line 8) allows + the allocation process to sleep and wait for memory, thus being + usable in a blocking situation. The PLATFORM_DEVID_AUTO flag (line + 12) allows automatic allocation and management of device IDs in + order to avoid device namespace collisions with explicit IDs. With + devm_clk_get() (line 18) the glue layer allocates the clock -- the + <literal>devm_</literal> prefix indicates that clk_get() is + managed: it automatically frees the allocated clock resource data + when the device is released -- and enable it. + </para> + <para> + Then comes the registration steps: + </para> + <programlisting linenumbering="numbered"> +static int jz4740_probe(struct platform_device *pdev) +{ + struct musb_hdrc_platform_data *pdata = &jz4740_musb_platform_data; + + pdata->platform_ops = &jz4740_musb_ops; + + platform_set_drvdata(pdev, glue); + + ret = platform_device_add_resources(musb, pdev->resource, + pdev->num_resources); + if (ret) { + dev_err(&pdev->dev, "failed to add resources\n"); + goto err_clk_disable; + } + + ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); + if (ret) { + dev_err(&pdev->dev, "failed to add platform_data\n"); + goto err_clk_disable; + } + + return 0; + +err_clk_disable: + clk_disable_unprepare(clk); +err_platform_device_put: + platform_device_put(musb); + return ret; +} + </programlisting> + <para> + The first step is to pass the device data privately held by the + glue layer on to the controller driver through + platform_set_drvdata() (line 7). Next is passing on the device + resources information, also privately held at that point, through + platform_device_add_resources() (line 9). + </para> + <para> + Finally comes passing on the platform specific data to the + controller driver (line 16). Platform data will be discussed in + <link linkend="device-platform-data">Chapter 4</link>, but here + we are looking at the platform_ops function pointer (line 5) in + musb_hdrc_platform_data structure (line 3). This function + pointer allows the MUSB controller driver to know which function + to call for device operation: + </para> + <programlisting linenumbering="numbered"> +static const struct musb_platform_ops jz4740_musb_ops = { + .init = jz4740_musb_init, + .exit = jz4740_musb_exit, +}; + </programlisting> + <para> + Here we have the minimal case where only init and exit functions + are called by the controller driver when needed. Fact is the + JZ4740 MUSB controller is a basic controller, lacking some + features found in other controllers, otherwise we may also have + pointers to a few other functions like a power management function + or a function to switch between OTG and non-OTG modes, for + instance. + </para> + <para> + At that point of the registration process, the controller driver + actually calls the init function: + </para> + <programlisting linenumbering="numbered"> +static int jz4740_musb_init(struct musb *musb) +{ + musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); + if (!musb->xceiv) { + pr_err("HS UDC: no transceiver configured\n"); + return -ENODEV; + } + + /* Silicon does not implement ConfigData register. + * Set dyn_fifo to avoid reading EP config from hardware. + */ + musb->dyn_fifo = true; + + musb->isr = jz4740_musb_interrupt; + + return 0; +} + </programlisting> + <para> + The goal of jz4740_musb_init() is to get hold of the transceiver + driver data of the MUSB controller hardware and pass it on to the + MUSB controller driver, as usual. The transceiver is the circuitry + inside the controller hardware responsible for sending/receiving + the USB data. Since it is an implementation of the physical layer + of the OSI model, the transceiver is also referred to as PHY. + </para> + <para> + Getting hold of the MUSB PHY driver data is done with + usb_get_phy() which returns a pointer to the structure + containing the driver instance data. The next couple of + instructions (line 12 and 14) are used as a quirk and to setup + IRQ handling respectively. Quirks and IRQ handling will be + discussed later in <link linkend="device-quirks">Chapter + 5</link> and <link linkend="handling-irqs">Chapter 3</link>. + </para> + <programlisting linenumbering="numbered"> +static int jz4740_musb_exit(struct musb *musb) +{ + usb_put_phy(musb->xceiv); + + return 0; +} + </programlisting> + <para> + Acting as the counterpart of init, the exit function releases the + MUSB PHY driver when the controller hardware itself is about to be + released. + </para> + <para> + Again, note that init and exit are fairly simple in this case due + to the basic set of features of the JZ4740 controller hardware. + When writing an musb glue layer for a more complex controller + hardware, you might need to take care of more processing in those + two functions. + </para> + <para> + Returning from the init function, the MUSB controller driver jumps + back into the probe function: + </para> + <programlisting linenumbering="numbered"> +static int jz4740_probe(struct platform_device *pdev) +{ + ret = platform_device_add(musb); + if (ret) { + dev_err(&pdev->dev, "failed to register musb device\n"); + goto err_clk_disable; + } + + return 0; + +err_clk_disable: + clk_disable_unprepare(clk); +err_platform_device_put: + platform_device_put(musb); + return ret; +} + </programlisting> + <para> + This is the last part of the device registration process where the + glue layer adds the controller hardware device to Linux kernel + device hierarchy: at this stage, all known information about the + device is passed on to the Linux USB core stack. + </para> + <programlisting linenumbering="numbered"> +static int jz4740_remove(struct platform_device *pdev) +{ + struct jz4740_glue *glue = platform_get_drvdata(pdev); + + platform_device_unregister(glue->musb); + clk_disable_unprepare(glue->clk); + + return 0; +} + </programlisting> + <para> + Acting as the counterpart of probe, the remove function unregister + the MUSB controller hardware (line 5) and disable the clock (line + 6), allowing it to be gated. + </para> + </chapter> + + <chapter id="handling-irqs"> + <title>Handling IRQs</title> + <para> + Additionally to the MUSB controller hardware basic setup and + registration, the glue layer is also responsible for handling the + IRQs: + </para> + <programlisting linenumbering="numbered"> +static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci) +{ + unsigned long flags; + irqreturn_t retval = IRQ_NONE; + struct musb *musb = __hci; + + spin_lock_irqsave(&musb->lock, flags); + + musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); + musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); + musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); + + /* + * The controller is gadget only, the state of the host mode IRQ bits is + * undefined. Mask them to make sure that the musb driver core will + * never see them set + */ + musb->int_usb &= MUSB_INTR_SUSPEND | MUSB_INTR_RESUME | + MUSB_INTR_RESET | MUSB_INTR_SOF; + + if (musb->int_usb || musb->int_tx || musb->int_rx) + retval = musb_interrupt(musb); + + spin_unlock_irqrestore(&musb->lock, flags); + + return retval; +} + </programlisting> + <para> + Here the glue layer mostly has to read the relevant hardware + registers and pass their values on to the controller driver which + will handle the actual event that triggered the IRQ. + </para> + <para> + The interrupt handler critical section is protected by the + spin_lock_irqsave() and counterpart spin_unlock_irqrestore() + functions (line 7 and 24 respectively), which prevent the + interrupt handler code to be run by two different threads at the + same time. + </para> + <para> + Then the relevant interrupt registers are read (line 9 to 11): + </para> + <itemizedlist> + <listitem> + <para> + MUSB_INTRUSB: indicates which USB interrupts are currently + active, + </para> + </listitem> + <listitem> + <para> + MUSB_INTRTX: indicates which of the interrupts for TX + endpoints are currently active, + </para> + </listitem> + <listitem> + <para> + MUSB_INTRRX: indicates which of the interrupts for TX + endpoints are currently active. + </para> + </listitem> + </itemizedlist> + <para> + Note that musb_readb() is used to read 8-bit registers at most, + while musb_readw() allows us to read at most 16-bit registers. + There are other functions that can be used depending on the size + of your device registers. See musb_io.h for more information. + </para> + <para> + Instruction on line 18 is another quirk specific to the JZ4740 + USB device controller, which will be discussed later in <link + linkend="device-quirks">Chapter 5</link>. + </para> + <para> + The glue layer still needs to register the IRQ handler though. + Remember the instruction on line 14 of the init function: + </para> + <programlisting linenumbering="numbered"> +static int jz4740_musb_init(struct musb *musb) +{ + musb->isr = jz4740_musb_interrupt; + + return 0; +} + </programlisting> + <para> + This instruction sets a pointer to the glue layer IRQ handler + function, in order for the controller hardware to call the handler + back when an IRQ comes from the controller hardware. The interrupt + handler is now implemented and registered. + </para> + </chapter> + + <chapter id="device-platform-data"> + <title>Device Platform Data</title> + <para> + In order to write an MUSB glue layer, you need to have some data + describing the hardware capabilities of your controller hardware, + which is called the platform data. + </para> + <para> + Platform data is specific to your hardware, though it may cover a + broad range of devices, and is generally found somewhere in the + arch/ directory, depending on your device architecture. + </para> + <para> + For instance, platform data for the JZ4740 SoC is found in + arch/mips/jz4740/platform.c. In the platform.c file each device of + the JZ4740 SoC is described through a set of structures. + </para> + <para> + Here is the part of arch/mips/jz4740/platform.c that covers the + USB Device Controller (UDC): + </para> + <programlisting linenumbering="numbered"> +/* USB Device Controller */ +struct platform_device jz4740_udc_xceiv_device = { + .name = "usb_phy_gen_xceiv", + .id = 0, +}; + +static struct resource jz4740_udc_resources[] = { + [0] = { + .start = JZ4740_UDC_BASE_ADDR, + .end = JZ4740_UDC_BASE_ADDR + 0x10000 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = JZ4740_IRQ_UDC, + .end = JZ4740_IRQ_UDC, + .flags = IORESOURCE_IRQ, + .name = "mc", + }, +}; + +struct platform_device jz4740_udc_device = { + .name = "musb-jz4740", + .id = -1, + .dev = { + .dma_mask = &jz4740_udc_device.dev.coherent_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .num_resources = ARRAY_SIZE(jz4740_udc_resources), + .resource = jz4740_udc_resources, +}; + </programlisting> + <para> + The jz4740_udc_xceiv_device platform device structure (line 2) + describes the UDC transceiver with a name and id number. + </para> + <para> + At the time of this writing, note that + "usb_phy_gen_xceiv" is the specific name to be used for + all transceivers that are either built-in with reference USB IP or + autonomous and doesn't require any PHY programming. You will need + to set CONFIG_NOP_USB_XCEIV=y in the kernel configuration to make + use of the corresponding transceiver driver. The id field could be + set to -1 (equivalent to PLATFORM_DEVID_NONE), -2 (equivalent to + PLATFORM_DEVID_AUTO) or start with 0 for the first device of this + kind if we want a specific id number. + </para> + <para> + The jz4740_udc_resources resource structure (line 7) defines the + UDC registers base addresses. + </para> + <para> + The first array (line 9 to 11) defines the UDC registers base + memory addresses: start points to the first register memory + address, end points to the last register memory address and the + flags member defines the type of resource we are dealing with. So + IORESOURCE_MEM is used to define the registers memory addresses. + The second array (line 14 to 17) defines the UDC IRQ registers + addresses. Since there is only one IRQ register available for the + JZ4740 UDC, start and end point at the same address. The + IORESOURCE_IRQ flag tells that we are dealing with IRQ resources, + and the name "mc" is in fact hard-coded in the MUSB core + in order for the controller driver to retrieve this IRQ resource + by querying it by its name. + </para> + <para> + Finally, the jz4740_udc_device platform device structure (line 21) + describes the UDC itself. + </para> + <para> + The "musb-jz4740" name (line 22) defines the MUSB + driver that is used for this device; remember this is in fact + the name that we used in the jz4740_driver platform driver + structure in <link linkend="linux-musb-basics">Chapter + 2</link>. The id field (line 23) is set to -1 (equivalent to + PLATFORM_DEVID_NONE) since we do not need an id for the device: + the MUSB controller driver was already set to allocate an + automatic id in <link linkend="linux-musb-basics">Chapter + 2</link>. In the dev field we care for DMA related information + here. The dma_mask field (line 25) defines the width of the DMA + mask that is going to be used, and coherent_dma_mask (line 26) + has the same purpose but for the alloc_coherent DMA mappings: in + both cases we are using a 32 bits mask. Then the resource field + (line 29) is simply a pointer to the resource structure defined + before, while the num_resources field (line 28) keeps track of + the number of arrays defined in the resource structure (in this + case there were two resource arrays defined before). + </para> + <para> + With this quick overview of the UDC platform data at the arch/ + level now done, let's get back to the MUSB glue layer specific + platform data in drivers/usb/musb/jz4740.c: + </para> + <programlisting linenumbering="numbered"> +static struct musb_hdrc_config jz4740_musb_config = { + /* Silicon does not implement USB OTG. */ + .multipoint = 0, + /* Max EPs scanned, driver will decide which EP can be used. */ + .num_eps = 4, + /* RAMbits needed to configure EPs from table */ + .ram_bits = 9, + .fifo_cfg = jz4740_musb_fifo_cfg, + .fifo_cfg_size = ARRAY_SIZE(jz4740_musb_fifo_cfg), +}; + +static struct musb_hdrc_platform_data jz4740_musb_platform_data = { + .mode = MUSB_PERIPHERAL, + .config = &jz4740_musb_config, +}; + </programlisting> + <para> + First the glue layer configures some aspects of the controller + driver operation related to the controller hardware specifics. + This is done through the jz4740_musb_config musb_hdrc_config + structure. + </para> + <para> + Defining the OTG capability of the controller hardware, the + multipoint member (line 3) is set to 0 (equivalent to false) + since the JZ4740 UDC is not OTG compatible. Then num_eps (line + 5) defines the number of USB endpoints of the controller + hardware, including endpoint 0: here we have 3 endpoints + + endpoint 0. Next is ram_bits (line 7) which is the width of the + RAM address bus for the MUSB controller hardware. This + information is needed when the controller driver cannot + automatically configure endpoints by reading the relevant + controller hardware registers. This issue will be discussed when + we get to device quirks in <link linkend="device-quirks">Chapter + 5</link>. Last two fields (line 8 and 9) are also about device + quirks: fifo_cfg points to the USB endpoints configuration table + and fifo_cfg_size keeps track of the size of the number of + entries in that configuration table. More on that later in <link + linkend="device-quirks">Chapter 5</link>. + </para> + <para> + Then this configuration is embedded inside + jz4740_musb_platform_data musb_hdrc_platform_data structure (line + 11): config is a pointer to the configuration structure itself, + and mode tells the controller driver if the controller hardware + may be used as MUSB_HOST only, MUSB_PERIPHERAL only or MUSB_OTG + which is a dual mode. + </para> + <para> + Remember that jz4740_musb_platform_data is then used to convey + platform data information as we have seen in the probe function + in <link linkend="linux-musb-basics">Chapter 2</link> + </para> + </chapter> + + <chapter id="device-quirks"> + <title>Device Quirks</title> + <para> + Completing the platform data specific to your device, you may also + need to write some code in the glue layer to work around some + device specific limitations. These quirks may be due to some + hardware bugs, or simply be the result of an incomplete + implementation of the USB On-the-Go specification. + </para> + <para> + The JZ4740 UDC exhibits such quirks, some of which we will discuss + here for the sake of insight even though these might not be found + in the controller hardware you are working on. + </para> + <para> + Let's get back to the init function first: + </para> + <programlisting linenumbering="numbered"> +static int jz4740_musb_init(struct musb *musb) +{ + musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); + if (!musb->xceiv) { + pr_err("HS UDC: no transceiver configured\n"); + return -ENODEV; + } + + /* Silicon does not implement ConfigData register. + * Set dyn_fifo to avoid reading EP config from hardware. + */ + musb->dyn_fifo = true; + + musb->isr = jz4740_musb_interrupt; + + return 0; +} + </programlisting> + <para> + Instruction on line 12 helps the MUSB controller driver to work + around the fact that the controller hardware is missing registers + that are used for USB endpoints configuration. + </para> + <para> + Without these registers, the controller driver is unable to read + the endpoints configuration from the hardware, so we use line 12 + instruction to bypass reading the configuration from silicon, and + rely on a hard-coded table that describes the endpoints + configuration instead: + </para> + <programlisting linenumbering="numbered"> +static struct musb_fifo_cfg jz4740_musb_fifo_cfg[] = { +{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 64, }, +}; + </programlisting> + <para> + Looking at the configuration table above, we see that each + endpoints is described by three fields: hw_ep_num is the endpoint + number, style is its direction (either FIFO_TX for the controller + driver to send packets in the controller hardware, or FIFO_RX to + receive packets from hardware), and maxpacket defines the maximum + size of each data packet that can be transmitted over that + endpoint. Reading from the table, the controller driver knows that + endpoint 1 can be used to send and receive USB data packets of 512 + bytes at once (this is in fact a bulk in/out endpoint), and + endpoint 2 can be used to send data packets of 64 bytes at once + (this is in fact an interrupt endpoint). + </para> + <para> + Note that there is no information about endpoint 0 here: that one + is implemented by default in every silicon design, with a + predefined configuration according to the USB specification. For + more examples of endpoint configuration tables, see musb_core.c. + </para> + <para> + Let's now get back to the interrupt handler function: + </para> + <programlisting linenumbering="numbered"> +static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci) +{ + unsigned long flags; + irqreturn_t retval = IRQ_NONE; + struct musb *musb = __hci; + + spin_lock_irqsave(&musb->lock, flags); + + musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); + musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); + musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); + + /* + * The controller is gadget only, the state of the host mode IRQ bits is + * undefined. Mask them to make sure that the musb driver core will + * never see them set + */ + musb->int_usb &= MUSB_INTR_SUSPEND | MUSB_INTR_RESUME | + MUSB_INTR_RESET | MUSB_INTR_SOF; + + if (musb->int_usb || musb->int_tx || musb->int_rx) + retval = musb_interrupt(musb); + + spin_unlock_irqrestore(&musb->lock, flags); + + return retval; +} + </programlisting> + <para> + Instruction on line 18 above is a way for the controller driver to + work around the fact that some interrupt bits used for USB host + mode operation are missing in the MUSB_INTRUSB register, thus left + in an undefined hardware state, since this MUSB controller + hardware is used in peripheral mode only. As a consequence, the + glue layer masks these missing bits out to avoid parasite + interrupts by doing a logical AND operation between the value read + from MUSB_INTRUSB and the bits that are actually implemented in + the register. + </para> + <para> + These are only a couple of the quirks found in the JZ4740 USB + device controller. Some others were directly addressed in the MUSB + core since the fixes were generic enough to provide a better + handling of the issues for others controller hardware eventually. + </para> + </chapter> + + <chapter id="conclusion"> + <title>Conclusion</title> + <para> + Writing a Linux MUSB glue layer should be a more accessible task, + as this documentation tries to show the ins and outs of this + exercise. + </para> + <para> + The JZ4740 USB device controller being fairly simple, I hope its + glue layer serves as a good example for the curious mind. Used + with the current MUSB glue layers, this documentation should + provide enough guidance to get started; should anything gets out + of hand, the linux-usb mailing list archive is another helpful + resource to browse through. + </para> + </chapter> + + <chapter id="acknowledgements"> + <title>Acknowledgements</title> + <para> + Many thanks to Lars-Peter Clausen and Maarten ter Huurne for + answering my questions while I was writing the JZ4740 glue layer + and for helping me out getting the code in good shape. + </para> + <para> + I would also like to thank the Qi-Hardware community at large for + its cheerful guidance and support. + </para> + </chapter> + + <chapter id="resources"> + <title>Resources</title> + <para> + USB Home Page: + <ulink url="http://www.usb.org">http://www.usb.org</ulink> + </para> + <para> + linux-usb Mailing List Archives: + <ulink url="http://marc.info/?l=linux-usb">http://marc.info/?l=linux-usb</ulink> + </para> + <para> + USB On-the-Go Basics: + <ulink url="http://www.maximintegrated.com/app-notes/index.mvp/id/1822">http://www.maximintegrated.com/app-notes/index.mvp/id/1822</ulink> + </para> + <para> + Writing USB Device Drivers: + <ulink url="https://www.kernel.org/doc/htmldocs/writing_usb_driver/index.html">https://www.kernel.org/doc/htmldocs/writing_usb_driver/index.html</ulink> + </para> + <para> + Texas Instruments USB Configuration Wiki Page: + <ulink url="http://processors.wiki.ti.com/index.php/Usbgeneralpage">http://processors.wiki.ti.com/index.php/Usbgeneralpage</ulink> + </para> + <para> + Analog Devices Blackfin MUSB Configuration: + <ulink url="http://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:drivers:musb">http://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:drivers:musb</ulink> + </para> + </chapter> + +</book> diff --git a/Documentation/devicetree/bindings/phy/samsung-phy.txt b/Documentation/devicetree/bindings/phy/samsung-phy.txt index b422e38946d7..2049261d8c31 100644 --- a/Documentation/devicetree/bindings/phy/samsung-phy.txt +++ b/Documentation/devicetree/bindings/phy/samsung-phy.txt @@ -114,3 +114,50 @@ Example: compatible = "samsung,exynos-sataphy-i2c"; reg = <0x38>; }; + +Samsung Exynos5 SoC series USB DRD PHY controller +-------------------------------------------------- + +Required properties: +- compatible : Should be set to one of the following supported values: + - "samsung,exynos5250-usbdrd-phy" - for exynos5250 SoC, + - "samsung,exynos5420-usbdrd-phy" - for exynos5420 SoC. +- reg : Register offset and length of USB DRD PHY register set; +- clocks: Clock IDs array as required by the controller +- clock-names: names of clocks correseponding to IDs in the clock property; + Required clocks: + - phy: main PHY clock (same as USB DRD controller i.e. DWC3 IP clock), + used for register access. + - ref: PHY's reference clock (usually crystal clock), used for + PHY operations, associated by phy name. It is used to + determine bit values for clock settings register. + For Exynos5420 this is given as 'sclk_usbphy30' in CMU. +- samsung,pmu-syscon: phandle for PMU system controller interface, used to + control pmu registers for power isolation. +- #phy-cells : from the generic PHY bindings, must be 1; + +For "samsung,exynos5250-usbdrd-phy" and "samsung,exynos5420-usbdrd-phy" +compatible PHYs, the second cell in the PHY specifier identifies the +PHY id, which is interpreted as follows: + 0 - UTMI+ type phy, + 1 - PIPE3 type phy, + +Example: + usbdrd_phy: usbphy@12100000 { + compatible = "samsung,exynos5250-usbdrd-phy"; + reg = <0x12100000 0x100>; + clocks = <&clock 286>, <&clock 1>; + clock-names = "phy", "ref"; + samsung,pmu-syscon = <&pmu_system_controller>; + #phy-cells = <1>; + }; + +- aliases: For SoCs like Exynos5420 having multiple USB 3.0 DRD PHY controllers, + 'usbdrd_phy' nodes should have numbered alias in the aliases node, + in the form of usbdrdphyN, N = 0, 1... (depending on number of + controllers). +Example: + aliases { + usbdrdphy0 = &usb3_phy0; + usbdrdphy1 = &usb3_phy1; + }; diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt index a82361b62015..16528b9eb561 100644 --- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt @@ -2,15 +2,26 @@ Allwinner sun4i USB PHY ----------------------- Required properties: -- compatible : should be one of "allwinner,sun4i-a10-usb-phy", - "allwinner,sun5i-a13-usb-phy" or "allwinner,sun7i-a20-usb-phy" +- compatible : should be one of + * allwinner,sun4i-a10-usb-phy + * allwinner,sun5i-a13-usb-phy + * allwinner,sun6i-a31-usb-phy + * allwinner,sun7i-a20-usb-phy - reg : a list of offset + length pairs -- reg-names : "phy_ctrl", "pmu1" and for sun4i or sun7i "pmu2" +- reg-names : + * "phy_ctrl" + * "pmu1" + * "pmu2" for sun4i, sun6i or sun7i - #phy-cells : from the generic phy bindings, must be 1 -- clocks : phandle + clock specifier for the phy clock -- clock-names : "usb_phy" +- clocks : phandle + clock specifier for the phy clocks +- clock-names : + * "usb_phy" for sun4i, sun5i or sun7i + * "usb0_phy", "usb1_phy" and "usb2_phy" for sun6i - resets : a list of phandle + reset specifier pairs -- reset-names : "usb0_reset", "usb1_reset" and for sun4i or sun7i "usb2_reset" +- reset-names : + * "usb0_reset" + * "usb1_reset" + * "usb2_reset" for sun4i, sun6i or sun7i Example: usbphy: phy@0x01c13400 { diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt b/Documentation/devicetree/bindings/phy/ti-phy.txt index 788fb0fa3762..9ce458f32945 100644 --- a/Documentation/devicetree/bindings/phy/ti-phy.txt +++ b/Documentation/devicetree/bindings/phy/ti-phy.txt @@ -32,6 +32,11 @@ Required properties: - reg : Address and length of the register set for the device. - #phy-cells: determine the number of cells that should be given in the phandle while referencing this phy. + - clocks: a list of phandles and clock-specifier pairs, one for each entry in + clock-names. + - clock-names: should include: + * "wkupclk" - wakeup clock. + * "refclk" - reference clock (optional). Optional properties: - ctrl-module : phandle of the control module used by PHY driver to power on @@ -44,6 +49,8 @@ usb2phy@4a0ad080 { reg = <0x4a0ad080 0x58>; ctrl-module = <&omap_control_usb>; #phy-cells = <0>; + clocks = <&usb_phy_cm_clk32k>, <&usb_otg_ss_refclk960m>; + clock-names = "wkupclk", "refclk"; }; TI PIPE3 PHY diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-qcom.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-qcom.txt new file mode 100644 index 000000000000..f2899b550939 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-qcom.txt @@ -0,0 +1,17 @@ +Qualcomm CI13xxx (Chipidea) USB controllers + +Required properties: +- compatible: should contain "qcom,ci-hdrc" +- reg: offset and length of the register set in the memory map +- interrupts: interrupt-specifier for the controller interrupt. +- usb-phy: phandle for the PHY device +- dr_mode: Should be "peripheral" + +Examples: + gadget@f9a55000 { + compatible = "qcom,ci-hdrc"; + reg = <0xf9a55000 0x400>; + dr_mode = "peripheral"; + interrupts = <0 134 0>; + usb-phy = <&usbphy0>; + }; diff --git a/Documentation/devicetree/bindings/usb/ehci-orion.txt b/Documentation/devicetree/bindings/usb/ehci-orion.txt index 6bc09ec14c4d..17c3bc858b86 100644 --- a/Documentation/devicetree/bindings/usb/ehci-orion.txt +++ b/Documentation/devicetree/bindings/usb/ehci-orion.txt @@ -6,6 +6,11 @@ Required properties: region. - interrupts: The EHCI interrupt +Optional properties: +- clocks: reference to the clock +- phys: reference to the USB PHY +- phy-names: name of the USB PHY, should be "usb" + Example: ehci@50000 { diff --git a/Documentation/devicetree/bindings/usb/exynos-usb.txt b/Documentation/devicetree/bindings/usb/exynos-usb.txt index d967ba16de60..a3b5990d0f2c 100644 --- a/Documentation/devicetree/bindings/usb/exynos-usb.txt +++ b/Documentation/devicetree/bindings/usb/exynos-usb.txt @@ -12,6 +12,13 @@ Required properties: - interrupts: interrupt number to the cpu. - clocks: from common clock binding: handle to usb clock. - clock-names: from common clock binding: Shall be "usbhost". + - port: if in the SoC there are EHCI phys, they should be listed here. + One phy per port. Each port should have following entries: + - reg: port number on EHCI controller, e.g + On Exynos5250, port 0 is USB2.0 otg phy + port 1 is HSIC phy0 + port 2 is HSIC phy1 + - phys: from the *Generic PHY* bindings; specifying phy used by port. Optional properties: - samsung,vbus-gpio: if present, specifies the GPIO that @@ -27,6 +34,14 @@ Example: clocks = <&clock 285>; clock-names = "usbhost"; + + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + phys = <&usb2phy 1>; + status = "disabled"; + }; }; OHCI @@ -38,6 +53,13 @@ Required properties: - interrupts: interrupt number to the cpu. - clocks: from common clock binding: handle to usb clock. - clock-names: from common clock binding: Shall be "usbhost". + - port: if in the SoC there are OHCI phys, they should be listed here. + One phy per port. Each port should have following entries: + - reg: port number on OHCI controller, e.g + On Exynos5250, port 0 is USB2.0 otg phy + port 1 is HSIC phy0 + port 2 is HSIC phy1 + - phys: from the *Generic PHY* bindings, specifying phy used by port. Example: usb@12120000 { @@ -47,6 +69,15 @@ Example: clocks = <&clock 285>; clock-names = "usbhost"; + + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + phys = <&usb2phy 1>; + status = "disabled"; + }; + }; DWC3 diff --git a/Documentation/devicetree/bindings/usb/gr-udc.txt b/Documentation/devicetree/bindings/usb/gr-udc.txt index 0c5118f7a916..e9445224fabd 100644 --- a/Documentation/devicetree/bindings/usb/gr-udc.txt +++ b/Documentation/devicetree/bindings/usb/gr-udc.txt @@ -12,17 +12,23 @@ Required properties: - reg : Address and length of the register set for the device -- interrupts : Interrupt numbers for this device +- interrupts : Interrupt numbers for this device. Either one interrupt number + for all interrupts, or one for status related interrupts, one for IN + endpoint related interrupts and one for OUT endpoint related interrupts. Optional properties: -- epobufsizes : An array of buffer sizes for OUT endpoints. If the property is - not present, or for endpoints outside of the array, 1024 is assumed by - the driver. - -- epibufsizes : An array of buffer sizes for IN endpoints. If the property is - not present, or for endpoints outside of the array, 1024 is assumed by - the driver. +- epobufsizes : Array of buffer sizes for OUT endpoints when they differ + from the default size of 1024. The array is indexed by the OUT endpoint + number. If the property is present it typically contains one entry for + each OUT endpoint of the core. Fewer entries overrides the default sizes + only for as many endpoints as the array contains. + +- epibufsizes : Array of buffer sizes for IN endpoints when they differ + from the default size of 1024. The array is indexed by the IN endpoint + number. If the property is present it typically contains one entry for + each IN endpoint of the core. Fewer entries overrides the default sizes + only for as many endpoints as the array contains. For further information look in the documentation for the GLIB IP core library: http://www.gaisler.com/products/grlib/grip.pdf diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt index 5ea26c631e3a..2826f2af503a 100644 --- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt @@ -15,3 +15,81 @@ Example EHCI controller device node: usb-phy = <&usb_otg>; }; +USB PHY with optional OTG: + +Required properties: +- compatible: Should contain: + "qcom,usb-otg-ci" for chipsets with ChipIdea 45nm PHY + "qcom,usb-otg-snps" for chipsets with Synopsys 28nm PHY + +- regs: Offset and length of the register set in the memory map +- interrupts: interrupt-specifier for the OTG interrupt. + +- clocks: A list of phandle + clock-specifier pairs for the + clocks listed in clock-names +- clock-names: Should contain the following: + "phy" USB PHY reference clock + "core" Protocol engine clock + "iface" Interface bus clock + "alt_core" Protocol engine clock for targets with asynchronous + reset methodology. (optional) + +- vdccx-supply: phandle to the regulator for the vdd supply for + digital circuit operation. +- v1p8-supply: phandle to the regulator for the 1.8V supply +- v3p3-supply: phandle to the regulator for the 3.3V supply + +- resets: A list of phandle + reset-specifier pairs for the + resets listed in reset-names +- reset-names: Should contain the following: + "phy" USB PHY controller reset + "link" USB LINK controller reset + +- qcom,otg-control: OTG control (VBUS and ID notifications) can be one of + 1 - PHY control + 2 - PMIC control + +Optional properties: +- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg" + +- qcom,phy-init-sequence: PHY configuration sequence values. This is related to Device + Mode Eye Diagram test. Start address at which these values will be + written is ULPI_EXT_VENDOR_SPECIFIC. Value of -1 is reserved as + "do not overwrite default value at this address". + For example: qcom,phy-init-sequence = < -1 0x63 >; + Will update only value at address ULPI_EXT_VENDOR_SPECIFIC + 1. + +- qcom,phy-num: Select number of pyco-phy to use, can be one of + 0 - PHY one, default + 1 - Second PHY + Some platforms may have configuration to allow USB + controller work with any of the two HSPHYs present. + +- qcom,vdd-levels: This property must be a list of three integer values + (no, min, max) where each value represents either a voltage + in microvolts or a value corresponding to voltage corner. + +Example HSUSB OTG controller device node: + + usb@f9a55000 { + compatible = "qcom,usb-otg-snps"; + reg = <0xf9a55000 0x400>; + interrupts = <0 134 0>; + dr_mode = "peripheral"; + + clocks = <&gcc GCC_XO_CLK>, <&gcc GCC_USB_HS_SYSTEM_CLK>, + <&gcc GCC_USB_HS_AHB_CLK>; + + clock-names = "phy", "core", "iface"; + + vddcx-supply = <&pm8841_s2_corner>; + v1p8-supply = <&pm8941_l6>; + v3p3-supply = <&pm8941_l24>; + + resets = <&gcc GCC_USB2A_PHY_BCR>, <&gcc GCC_USB_HS_BCR>; + reset-names = "phy", "link"; + + qcom,otg-control = <1>; + qcom,phy-init-sequence = < -1 0x63 >; + qcom,vdd-levels = <1 5 7>; + }; diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt index ff151ec084c4..43c1a4e06767 100644 --- a/Documentation/devicetree/bindings/usb/usb-ehci.txt +++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt @@ -15,6 +15,7 @@ Optional properties: - clocks : a list of phandle + clock specifier pairs - phys : phandle + phy specifier pair - phy-names : "usb" + - resets : phandle + reset specifier pair Example (Sequoia 440EPx): ehci@e0000300 { diff --git a/Documentation/devicetree/bindings/usb/usb-ohci.txt b/Documentation/devicetree/bindings/usb/usb-ohci.txt index 45f67d91e888..b968a1aea995 100644 --- a/Documentation/devicetree/bindings/usb/usb-ohci.txt +++ b/Documentation/devicetree/bindings/usb/usb-ohci.txt @@ -12,6 +12,7 @@ Optional properties: - clocks : a list of phandle + clock specifier pairs - phys : phandle + phy specifier pair - phy-names : "usb" +- resets : phandle + reset specifier pair Example: diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt index 90f8f607d125..5a79377c6a96 100644 --- a/Documentation/devicetree/bindings/usb/usb-xhci.txt +++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt @@ -1,11 +1,17 @@ USB xHCI controllers Required properties: - - compatible: should be "generic-xhci" (deprecated: "xhci-platform"). + - compatible: should be one of "generic-xhci", + "marvell,armada-375-xhci", "marvell,armada-380-xhci", + "renesas,xhci-r8a7790", "renesas,xhci-r8a7791" (deprecated: + "xhci-platform"). - reg: should contain address and length of the standard XHCI register set for the device. - interrupts: one XHCI interrupt should be described here. +Optional property: + - clocks: reference to a clock + Example: usb@f0931000 { compatible = "generic-xhci"; diff --git a/Documentation/devicetree/bindings/usb/usb3503.txt b/Documentation/devicetree/bindings/usb/usb3503.txt index a018da4a7ad7..221ac0dbc678 100644 --- a/Documentation/devicetree/bindings/usb/usb3503.txt +++ b/Documentation/devicetree/bindings/usb/usb3503.txt @@ -15,6 +15,14 @@ Optional properties: - reset-gpios: Should specify GPIO for reset. - initial-mode: Should specify initial mode. (1 for HUB mode, 2 for STANDBY mode) +- refclk: Clock used for driving REFCLK signal (optional, if not provided + the driver assumes that clock signal is always available, its + rate is specified by REF_SEL pins and a value from the primary + reference clock frequencies table is used) +- refclk-frequency: Frequency of the REFCLK signal as defined by REF_SEL + pins (optional, if not provided, driver will not set rate of the + REFCLK signal and assume that a value from the primary reference + clock frequencies table is used) Examples: usb3503@08 { diff --git a/Documentation/usb/chipidea.txt b/Documentation/usb/chipidea.txt new file mode 100644 index 000000000000..995c8bca40e2 --- /dev/null +++ b/Documentation/usb/chipidea.txt @@ -0,0 +1,71 @@ +1. How to test OTG FSM(HNP and SRP) +----------------------------------- +To show how to demo OTG HNP and SRP functions via sys input files +with 2 Freescale i.MX6Q sabre SD boards. + +1.1 How to enable OTG FSM in menuconfig +--------------------------------------- +Select CONFIG_USB_OTG_FSM, rebuild kernel Image and modules. +If you want to check some internal variables for otg fsm, +select CONFIG_USB_CHIPIDEA_DEBUG, there are 2 files which +can show otg fsm variables and some controller registers value: +cat /sys/kernel/debug/ci_hdrc.0/otg +cat /sys/kernel/debug/ci_hdrc.0/registers + +1.2 Test operations +------------------- +1) Power up 2 Freescale i.MX6Q sabre SD boards with gadget class driver loaded + (e.g. g_mass_storage). + +2) Connect 2 boards with usb cable with one end is micro A plug, the other end + is micro B plug. + + The A-device(with micro A plug inserted) should enumrate B-device. + +3) Role switch + On B-device: + echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req + + if HNP polling is not supported, also need: + On A-device: + echo 0 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req + + B-device should take host role and enumrate A-device. + +4) A-device switch back to host. + On B-device: + echo 0 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req + + A-device should switch back to host and enumrate B-device. + +5) Remove B-device(unplug micro B plug) and insert again in 10 seconds, + A-device should enumrate B-device again. + +6) Remove B-device(unplug micro B plug) and insert again after 10 seconds, + A-device should NOT enumrate B-device. + + if A-device wants to use bus: + On A-device: + echo 0 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_drop + echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req + + if B-device wants to use bus: + On B-device: + echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req + +7) A-device power down the bus. + On A-device: + echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_drop + + A-device should disconnect with B-device and power down the bus. + +8) B-device does data pulse for SRP. + On B-device: + echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req + + A-device should resume usb bus and enumrate B-device. + +1.3 Reference document +---------------------- +"On-The-Go and Embedded Host Supplement to the USB Revision 2.0 Specification +July 27, 2012 Revision 2.0 version 1.1a" diff --git a/arch/arm/configs/badge4_defconfig b/arch/arm/configs/badge4_defconfig index 5b54abbeb0b3..0494c8f229a2 100644 --- a/arch/arm/configs/badge4_defconfig +++ b/arch/arm/configs/badge4_defconfig @@ -73,8 +73,6 @@ CONFIG_SA1100_WATCHDOG=m CONFIG_SOUND=y CONFIG_SOUND_PRIME=y CONFIG_USB=y -CONFIG_USB_DEBUG=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_ACM=m CONFIG_USB_PRINTER=m diff --git a/arch/arm/configs/cm_x2xx_defconfig b/arch/arm/configs/cm_x2xx_defconfig index a93ff8da5bab..dc01c049a520 100644 --- a/arch/arm/configs/cm_x2xx_defconfig +++ b/arch/arm/configs/cm_x2xx_defconfig @@ -144,7 +144,6 @@ CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=y CONFIG_USB_OHCI_HCD=y diff --git a/arch/arm/configs/cm_x300_defconfig b/arch/arm/configs/cm_x300_defconfig index f4b767256f95..7df040e91c1c 100644 --- a/arch/arm/configs/cm_x300_defconfig +++ b/arch/arm/configs/cm_x300_defconfig @@ -129,7 +129,6 @@ CONFIG_HID_TOPSEED=y CONFIG_HID_THRUSTMASTER=y CONFIG_HID_ZEROPLUS=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=y CONFIG_USB_OHCI_HCD=y diff --git a/arch/arm/configs/colibri_pxa270_defconfig b/arch/arm/configs/colibri_pxa270_defconfig index 2ef2c5e8aaec..18c311ae1113 100644 --- a/arch/arm/configs/colibri_pxa270_defconfig +++ b/arch/arm/configs/colibri_pxa270_defconfig @@ -124,7 +124,6 @@ CONFIG_FONT_8x16=y CONFIG_LOGO=y # CONFIG_USB_HID is not set CONFIG_USB=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_SERIAL=m CONFIG_USB_GADGET=m diff --git a/arch/arm/configs/colibri_pxa300_defconfig b/arch/arm/configs/colibri_pxa300_defconfig index b985334e42dd..be02fe2b14cb 100644 --- a/arch/arm/configs/colibri_pxa300_defconfig +++ b/arch/arm/configs/colibri_pxa300_defconfig @@ -47,9 +47,7 @@ CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_LOGO=y # CONFIG_HID_SUPPORT is not set CONFIG_USB=y -CONFIG_USB_DEBUG=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_STORAGE=y CONFIG_MMC=y diff --git a/arch/arm/configs/corgi_defconfig b/arch/arm/configs/corgi_defconfig index 1fd1d1de3220..c1470a00f55a 100644 --- a/arch/arm/configs/corgi_defconfig +++ b/arch/arm/configs/corgi_defconfig @@ -172,7 +172,6 @@ CONFIG_HID_SAMSUNG=m CONFIG_HID_SONY=m CONFIG_HID_SUNPLUS=m CONFIG_USB=m -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=m CONFIG_USB_SL811_HCD=m CONFIG_USB_SL811_CS=m diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig index 2f8ff65e3ef1..f95f72d62db7 100644 --- a/arch/arm/configs/davinci_all_defconfig +++ b/arch/arm/configs/davinci_all_defconfig @@ -157,7 +157,6 @@ CONFIG_HID_SAMSUNG=m CONFIG_HID_SONY=m CONFIG_HID_SUNPLUS=m CONFIG_USB=m -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=m CONFIG_USB_MUSB_HDRC=m CONFIG_USB_GADGET_MUSB_HDRC=y diff --git a/arch/arm/configs/em_x270_defconfig b/arch/arm/configs/em_x270_defconfig index 60a21e01eb70..4560c9ca6636 100644 --- a/arch/arm/configs/em_x270_defconfig +++ b/arch/arm/configs/em_x270_defconfig @@ -144,7 +144,6 @@ CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=y CONFIG_USB_OHCI_HCD=y diff --git a/arch/arm/configs/ep93xx_defconfig b/arch/arm/configs/ep93xx_defconfig index 6ac5ea73bd0a..1b650c85bdd0 100644 --- a/arch/arm/configs/ep93xx_defconfig +++ b/arch/arm/configs/ep93xx_defconfig @@ -80,7 +80,6 @@ CONFIG_I2C_DEBUG_BUS=y CONFIG_WATCHDOG=y CONFIG_EP93XX_WATCHDOG=y CONFIG_USB=y -CONFIG_USB_DEBUG=y CONFIG_USB_DYNAMIC_MINORS=y CONFIG_USB_OHCI_HCD=y CONFIG_USB_OHCI_HCD_PLATFORM=y diff --git a/arch/arm/configs/footbridge_defconfig b/arch/arm/configs/footbridge_defconfig index 038518ab39a8..87e020f303ab 100644 --- a/arch/arm/configs/footbridge_defconfig +++ b/arch/arm/configs/footbridge_defconfig @@ -100,8 +100,6 @@ CONFIG_FB_CYBER2000=y CONFIG_SOUND=m # CONFIG_USB_HID is not set CONFIG_USB=m -CONFIG_USB_DEBUG=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=m CONFIG_USB_PRINTER=m CONFIG_EXT2_FS=y diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig index 063e2ab2c8f1..1af665e847d1 100644 --- a/arch/arm/configs/ixp4xx_defconfig +++ b/arch/arm/configs/ixp4xx_defconfig @@ -169,7 +169,6 @@ CONFIG_SENSORS_W83781D=y CONFIG_WATCHDOG=y CONFIG_IXP4XX_WATCHDOG=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y diff --git a/arch/arm/configs/keystone_defconfig b/arch/arm/configs/keystone_defconfig index ec9a41d50680..095bb52671f6 100644 --- a/arch/arm/configs/keystone_defconfig +++ b/arch/arm/configs/keystone_defconfig @@ -135,7 +135,6 @@ CONFIG_WATCHDOG=y CONFIG_WATCHDOG_CORE=y CONFIG_DAVINCI_WATCHDOG=y CONFIG_USB=y -CONFIG_USB_DEBUG=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_MON=y CONFIG_USB_XHCI_HCD=y diff --git a/arch/arm/configs/kzm9g_defconfig b/arch/arm/configs/kzm9g_defconfig index 12bd1f63c399..bd097d455f87 100644 --- a/arch/arm/configs/kzm9g_defconfig +++ b/arch/arm/configs/kzm9g_defconfig @@ -106,7 +106,6 @@ CONFIG_SND_SOC=y CONFIG_SND_SOC_SH4_FSI=y # CONFIG_HID_SUPPORT is not set CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_R8A66597_HCD=y CONFIG_USB_RENESAS_USBHS=y CONFIG_USB_STORAGE=y diff --git a/arch/arm/configs/mini2440_defconfig b/arch/arm/configs/mini2440_defconfig index a07948a87caa..9c93f5655248 100644 --- a/arch/arm/configs/mini2440_defconfig +++ b/arch/arm/configs/mini2440_defconfig @@ -217,7 +217,6 @@ CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_HID_TOPSEED=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_OHCI_HCD=y CONFIG_USB_ACM=m diff --git a/arch/arm/configs/mv78xx0_defconfig b/arch/arm/configs/mv78xx0_defconfig index 1f08219c1b3c..0dae1c1f007a 100644 --- a/arch/arm/configs/mv78xx0_defconfig +++ b/arch/arm/configs/mv78xx0_defconfig @@ -80,7 +80,6 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MV64XXX=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y diff --git a/arch/arm/configs/neponset_defconfig b/arch/arm/configs/neponset_defconfig index d7dc9922cfff..460dca4a4f98 100644 --- a/arch/arm/configs/neponset_defconfig +++ b/arch/arm/configs/neponset_defconfig @@ -68,8 +68,6 @@ CONFIG_SOUND=y CONFIG_SOUND_PRIME=y # CONFIG_USB_HID is not set CONFIG_USB=m -CONFIG_USB_DEBUG=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=m CONFIG_USB_OHCI_HCD=m CONFIG_USB_STORAGE=m diff --git a/arch/arm/configs/omap1_defconfig b/arch/arm/configs/omap1_defconfig index d74edbad18fc..ce541bb3c2de 100644 --- a/arch/arm/configs/omap1_defconfig +++ b/arch/arm/configs/omap1_defconfig @@ -197,8 +197,6 @@ CONFIG_SND_OMAP_SOC=y # CONFIG_USB_HID is not set CONFIG_USB=y CONFIG_USB_PHY=y -CONFIG_USB_DEBUG=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=y CONFIG_USB_OHCI_HCD=y diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index 28f3b6e3b589..59066cf0271a 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -224,7 +224,6 @@ CONFIG_SND_OMAP_SOC_OMAP_TWL4030=m CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040=m CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=m CONFIG_USB=y -CONFIG_USB_DEBUG=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_MON=y CONFIG_USB_WDM=y diff --git a/arch/arm/configs/pcm027_defconfig b/arch/arm/configs/pcm027_defconfig index 2f136c30a989..0a847d04ddc1 100644 --- a/arch/arm/configs/pcm027_defconfig +++ b/arch/arm/configs/pcm027_defconfig @@ -76,7 +76,6 @@ CONFIG_SND_PCM_OSS=y CONFIG_SND_PXA2XX_AC97=y # CONFIG_HID_SUPPORT is not set CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_OHCI_HCD=y CONFIG_USB_STORAGE=y CONFIG_MMC=y diff --git a/arch/arm/configs/raumfeld_defconfig b/arch/arm/configs/raumfeld_defconfig index f7caa909b40d..3d833aea545a 100644 --- a/arch/arm/configs/raumfeld_defconfig +++ b/arch/arm/configs/raumfeld_defconfig @@ -122,7 +122,6 @@ CONFIG_HID_TOPSEED=y CONFIG_HID_THRUSTMASTER=y CONFIG_HID_ZEROPLUS=y CONFIG_USB=y -CONFIG_USB_DEBUG=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_MON=y CONFIG_USB_OHCI_HCD=y diff --git a/arch/arm/configs/s3c2410_defconfig b/arch/arm/configs/s3c2410_defconfig index 193448f31284..eb4d204bff47 100644 --- a/arch/arm/configs/s3c2410_defconfig +++ b/arch/arm/configs/s3c2410_defconfig @@ -324,7 +324,6 @@ CONFIG_SND_USB_CAIAQ=m CONFIG_SND_SOC=y # CONFIG_USB_HID is not set CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_OHCI_HCD=y CONFIG_USB_ACM=m diff --git a/arch/arm/configs/s3c6400_defconfig b/arch/arm/configs/s3c6400_defconfig index 3a186d653dac..e2f9fa5bb54b 100644 --- a/arch/arm/configs/s3c6400_defconfig +++ b/arch/arm/configs/s3c6400_defconfig @@ -56,7 +56,6 @@ CONFIG_SND_S3C24XX_SOC=m CONFIG_SND_SOC_SMDK_WM9713=m CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_OHCI_HCD=y CONFIG_USB_ACM=m CONFIG_USB_PRINTER=m diff --git a/arch/arm/configs/spitz_defconfig b/arch/arm/configs/spitz_defconfig index 2e0419d1b964..a1ede1966baf 100644 --- a/arch/arm/configs/spitz_defconfig +++ b/arch/arm/configs/spitz_defconfig @@ -166,7 +166,6 @@ CONFIG_HID_SAMSUNG=m CONFIG_HID_SONY=m CONFIG_HID_SUNPLUS=m CONFIG_USB=m -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=m CONFIG_USB_OHCI_HCD=m CONFIG_USB_SL811_HCD=m diff --git a/arch/arm/configs/tct_hammer_defconfig b/arch/arm/configs/tct_hammer_defconfig index 71277a1591ba..7209a2caefcf 100644 --- a/arch/arm/configs/tct_hammer_defconfig +++ b/arch/arm/configs/tct_hammer_defconfig @@ -47,7 +47,6 @@ CONFIG_BLK_DEV_RAM_SIZE=10240 # CONFIG_VGA_CONSOLE is not set # CONFIG_HID_SUPPORT is not set CONFIG_USB=y -CONFIG_USB_DEBUG=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=y CONFIG_USB_OHCI_HCD=y diff --git a/arch/arm/configs/trizeps4_defconfig b/arch/arm/configs/trizeps4_defconfig index 3162173fa75a..932ee4e4a13a 100644 --- a/arch/arm/configs/trizeps4_defconfig +++ b/arch/arm/configs/trizeps4_defconfig @@ -165,7 +165,6 @@ CONFIG_SND_PXA2XX_AC97=y CONFIG_SND_USB_AUDIO=m # CONFIG_USB_HID is not set CONFIG_USB=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_OHCI_HCD=y CONFIG_USB_STORAGE=m diff --git a/arch/arm/configs/viper_defconfig b/arch/arm/configs/viper_defconfig index d36e0d3c86ec..0d717a5eff29 100644 --- a/arch/arm/configs/viper_defconfig +++ b/arch/arm/configs/viper_defconfig @@ -127,7 +127,6 @@ CONFIG_SND_MIXER_OSS=m CONFIG_SND_PCM_OSS=m CONFIG_SND_PXA2XX_AC97=m CONFIG_USB=m -CONFIG_USB_DEVICEFS=y CONFIG_USB_ISP116X_HCD=m CONFIG_USB_SL811_HCD=m CONFIG_USB_R8A66597_HCD=m diff --git a/arch/arm/configs/zeus_defconfig b/arch/arm/configs/zeus_defconfig index 731d4f985310..cd11da8b5123 100644 --- a/arch/arm/configs/zeus_defconfig +++ b/arch/arm/configs/zeus_defconfig @@ -132,7 +132,6 @@ CONFIG_SND_SOC=m CONFIG_SND_PXA2XX_SOC=m # CONFIG_HID_SUPPORT is not set CONFIG_USB=m -CONFIG_USB_DEVICEFS=y CONFIG_USB_OHCI_HCD=m CONFIG_USB_ACM=m CONFIG_USB_STORAGE=m diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c index 46de789ad3ae..0c4c200e1221 100644 --- a/arch/arm/mach-msm/board-msm7x30.c +++ b/arch/arm/mach-msm/board-msm7x30.c @@ -95,7 +95,7 @@ static int hsusb_phy_clk_reset(struct clk *phy_clk) static struct msm_otg_platform_data msm_otg_pdata = { .phy_init_seq = hsusb_phy_init_seq, - .mode = USB_PERIPHERAL, + .mode = USB_DR_MODE_PERIPHERAL, .otg_control = OTG_PHY_CONTROL, .link_clk_reset = hsusb_link_clk_reset, .phy_clk_reset = hsusb_phy_clk_reset, diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index 9169ec324a43..4c748616ef47 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -116,7 +116,7 @@ static int hsusb_phy_clk_reset(struct clk *phy_clk) static struct msm_otg_platform_data msm_otg_pdata = { .phy_init_seq = hsusb_phy_init_seq, - .mode = USB_PERIPHERAL, + .mode = USB_DR_MODE_PERIPHERAL, .otg_control = OTG_PHY_CONTROL, .link_clk_reset = hsusb_link_clk_reset, .phy_clk_reset = hsusb_phy_clk_reset, diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index d6ed819ff15c..660bfc5a70d7 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -33,7 +33,6 @@ #include <linux/mtd/nand.h> #include <linux/mmc/host.h> #include <linux/usb/phy.h> -#include <linux/usb/usb_phy_gen_xceiv.h> #include <linux/regulator/machine.h> #include <linux/i2c/twl.h> diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c index 10855eb4ccc1..745367c0c2bb 100644 --- a/arch/arm/mach-omap2/usb-host.c +++ b/arch/arm/mach-omap2/usb-host.c @@ -28,7 +28,7 @@ #include <linux/io.h> #include <linux/gpio.h> #include <linux/usb/phy.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h> #include "soc.h" #include "omap_device.h" @@ -349,7 +349,7 @@ static struct fixed_voltage_config hsusb_reg_config = { /* .init_data filled later */ }; -static const char *nop_name = "usb_phy_gen_xceiv"; /* NOP PHY driver */ +static const char *nop_name = "usb_phy_generic"; /* NOP PHY driver */ static const char *reg_name = "reg-fixed-voltage"; /* Regulator driver */ /** @@ -435,7 +435,7 @@ int usbhs_init_phys(struct usbhs_phy_data *phy, int num_phys) struct platform_device *pdev; char *phy_id; struct platform_device_info pdevinfo; - struct usb_phy_gen_xceiv_platform_data nop_pdata; + struct usb_phy_generic_platform_data nop_pdata; for (i = 0; i < num_phys; i++) { @@ -469,8 +469,8 @@ int usbhs_init_phys(struct usbhs_phy_data *phy, int num_phys) pdevinfo.id = phy->port; pdevinfo.data = &nop_pdata; pdevinfo.size_data = - sizeof(struct usb_phy_gen_xceiv_platform_data); - scnprintf(phy_id, MAX_STR, "usb_phy_gen_xceiv.%d", + sizeof(struct usb_phy_generic_platform_data); + scnprintf(phy_id, MAX_STR, "usb_phy_generic.%d", phy->port); pdev = platform_device_register_full(&pdevinfo); if (IS_ERR(pdev)) { diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c index b19d1c361cab..205f9bf3821e 100644 --- a/arch/arm/mach-pxa/zeus.c +++ b/arch/arm/mach-pxa/zeus.c @@ -413,7 +413,7 @@ static struct fixed_voltage_config can_regulator_pdata = { static struct platform_device can_regulator_device = { .name = "reg-fixed-volage", - .id = -1, + .id = 0, .dev = { .platform_data = &can_regulator_pdata, }, @@ -510,18 +510,6 @@ struct platform_device zeus_max6369_device = { .num_resources = 1, }; -static struct platform_device *zeus_devices[] __initdata = { - &zeus_serial_device, - &zeus_mtd_devices[0], - &zeus_dm9k0_device, - &zeus_dm9k1_device, - &zeus_sram_device, - &zeus_leds_device, - &zeus_pcmcia_device, - &zeus_max6369_device, - &can_regulator_device, -}; - /* AC'97 */ static pxa2xx_audio_ops_t zeus_ac97_info = { .reset_gpio = 95, @@ -532,44 +520,50 @@ static pxa2xx_audio_ops_t zeus_ac97_info = { * USB host */ -static int zeus_ohci_init(struct device *dev) -{ - int err; - - /* Switch on port 2. */ - if ((err = gpio_request(ZEUS_USB2_PWREN_GPIO, "USB2_PWREN"))) { - dev_err(dev, "Can't request USB2_PWREN\n"); - return err; - } - - if ((err = gpio_direction_output(ZEUS_USB2_PWREN_GPIO, 1))) { - gpio_free(ZEUS_USB2_PWREN_GPIO); - dev_err(dev, "Can't enable USB2_PWREN\n"); - return err; - } +static struct regulator_consumer_supply zeus_ohci_regulator_supplies[] = { + REGULATOR_SUPPLY("vbus2", "pxa27x-ohci"), +}; - /* Port 2 is shared between host and client interface. */ - UP2OCR = UP2OCR_HXOE | UP2OCR_HXS | UP2OCR_DMPDE | UP2OCR_DPPDE; +static struct regulator_init_data zeus_ohci_regulator_data = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(zeus_ohci_regulator_supplies), + .consumer_supplies = zeus_ohci_regulator_supplies, +}; - return 0; -} +static struct fixed_voltage_config zeus_ohci_regulator_config = { + .supply_name = "vbus2", + .microvolts = 5000000, /* 5.0V */ + .gpio = ZEUS_USB2_PWREN_GPIO, + .enable_high = 1, + .startup_delay = 0, + .init_data = &zeus_ohci_regulator_data, +}; -static void zeus_ohci_exit(struct device *dev) -{ - /* Power-off port 2 */ - gpio_direction_output(ZEUS_USB2_PWREN_GPIO, 0); - gpio_free(ZEUS_USB2_PWREN_GPIO); -} +static struct platform_device zeus_ohci_regulator_device = { + .name = "reg-fixed-voltage", + .id = 1, + .dev = { + .platform_data = &zeus_ohci_regulator_config, + }, +}; static struct pxaohci_platform_data zeus_ohci_platform_data = { .port_mode = PMM_NPS_MODE, /* Clear Power Control Polarity Low and set Power Sense * Polarity Low. Supply power to USB ports. */ .flags = ENABLE_PORT_ALL | POWER_SENSE_LOW, - .init = zeus_ohci_init, - .exit = zeus_ohci_exit, }; +static void zeus_register_ohci(void) +{ + /* Port 2 is shared between host and client interface. */ + UP2OCR = UP2OCR_HXOE | UP2OCR_HXS | UP2OCR_DMPDE | UP2OCR_DPPDE; + + pxa_set_ohci_info(&zeus_ohci_platform_data); +} + /* * Flat Panel */ @@ -677,6 +671,19 @@ static struct pxa2xx_udc_mach_info zeus_udc_info = { .udc_command = zeus_udc_command, }; +static struct platform_device *zeus_devices[] __initdata = { + &zeus_serial_device, + &zeus_mtd_devices[0], + &zeus_dm9k0_device, + &zeus_dm9k1_device, + &zeus_sram_device, + &zeus_leds_device, + &zeus_pcmcia_device, + &zeus_max6369_device, + &can_regulator_device, + &zeus_ohci_regulator_device, +}; + #ifdef CONFIG_PM static void zeus_power_off(void) { @@ -847,7 +854,7 @@ static void __init zeus_init(void) platform_add_devices(zeus_devices, ARRAY_SIZE(zeus_devices)); - pxa_set_ohci_info(&zeus_ohci_platform_data); + zeus_register_ohci(); if (zeus_setup_fb_gpios()) pr_err("Failed to setup fb gpios\n"); diff --git a/arch/avr32/configs/hammerhead_defconfig b/arch/avr32/configs/hammerhead_defconfig index 18db853386c8..4912f0aadaa1 100644 --- a/arch/avr32/configs/hammerhead_defconfig +++ b/arch/avr32/configs/hammerhead_defconfig @@ -117,7 +117,6 @@ CONFIG_HID_SAMSUNG=m CONFIG_HID_SONY=m CONFIG_HID_SUNPLUS=m CONFIG_USB=m -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=m CONFIG_USB_ISP116X_HCD=m diff --git a/arch/blackfin/configs/BF526-EZBRD_defconfig b/arch/blackfin/configs/BF526-EZBRD_defconfig index 2f2c6acf210c..1759fad54017 100644 --- a/arch/blackfin/configs/BF526-EZBRD_defconfig +++ b/arch/blackfin/configs/BF526-EZBRD_defconfig @@ -123,7 +123,6 @@ CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_OTG_BLACKLIST_HUB=y CONFIG_USB_MON=y diff --git a/arch/blackfin/configs/BF527-EZKIT-V2_defconfig b/arch/blackfin/configs/BF527-EZKIT-V2_defconfig index 91535c38e7f2..357729682c00 100644 --- a/arch/blackfin/configs/BF527-EZKIT-V2_defconfig +++ b/arch/blackfin/configs/BF527-EZKIT-V2_defconfig @@ -147,7 +147,6 @@ CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_OTG_BLACKLIST_HUB=y CONFIG_USB_MON=y diff --git a/arch/blackfin/configs/BF527-EZKIT_defconfig b/arch/blackfin/configs/BF527-EZKIT_defconfig index af2738c7441b..2e73a5d33da8 100644 --- a/arch/blackfin/configs/BF527-EZKIT_defconfig +++ b/arch/blackfin/configs/BF527-EZKIT_defconfig @@ -141,7 +141,6 @@ CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_OTG_BLACKLIST_HUB=y CONFIG_USB_MON=y diff --git a/arch/blackfin/configs/BF548-EZKIT_defconfig b/arch/blackfin/configs/BF548-EZKIT_defconfig index e716fdfd2cf2..f0a2ddf5de46 100644 --- a/arch/blackfin/configs/BF548-EZKIT_defconfig +++ b/arch/blackfin/configs/BF548-EZKIT_defconfig @@ -159,7 +159,6 @@ CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_OTG_BLACKLIST_HUB=y CONFIG_USB_MON=y diff --git a/arch/blackfin/configs/CM-BF527_defconfig b/arch/blackfin/configs/CM-BF527_defconfig index f59c80ee78e3..05108b85ab12 100644 --- a/arch/blackfin/configs/CM-BF527_defconfig +++ b/arch/blackfin/configs/CM-BF527_defconfig @@ -95,7 +95,6 @@ CONFIG_WATCHDOG=y CONFIG_BFIN_WDT=y CONFIG_USB=m CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_OTG_BLACKLIST_HUB=y CONFIG_USB_MON=m diff --git a/arch/blackfin/configs/CM-BF548_defconfig b/arch/blackfin/configs/CM-BF548_defconfig index b9af4fa69984..9ff79df6825c 100644 --- a/arch/blackfin/configs/CM-BF548_defconfig +++ b/arch/blackfin/configs/CM-BF548_defconfig @@ -94,7 +94,6 @@ CONFIG_WATCHDOG=y CONFIG_BFIN_WDT=y # CONFIG_HID_SUPPORT is not set CONFIG_USB=m -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=m CONFIG_USB_MUSB_HDRC=m diff --git a/arch/blackfin/configs/IP0X_defconfig b/arch/blackfin/configs/IP0X_defconfig index 629516578760..5adf0da58499 100644 --- a/arch/blackfin/configs/IP0X_defconfig +++ b/arch/blackfin/configs/IP0X_defconfig @@ -73,7 +73,6 @@ CONFIG_SPI_BFIN5XX=y # CONFIG_HWMON is not set CONFIG_WATCHDOG=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_OTG_WHITELIST=y CONFIG_USB_MON=y CONFIG_USB_ISP1362_HCD=y diff --git a/arch/ia64/configs/bigsur_defconfig b/arch/ia64/configs/bigsur_defconfig index cf5993f05d4f..4c4ac163c600 100644 --- a/arch/ia64/configs/bigsur_defconfig +++ b/arch/ia64/configs/bigsur_defconfig @@ -75,7 +75,6 @@ CONFIG_SND_PCM_OSS=m CONFIG_SND_CS4281=m CONFIG_USB_HIDDEV=y CONFIG_USB=m -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=m CONFIG_USB_UHCI_HCD=m CONFIG_USB_ACM=m diff --git a/arch/ia64/configs/generic_defconfig b/arch/ia64/configs/generic_defconfig index b4efaf2bc13e..e8ed3ae70aae 100644 --- a/arch/ia64/configs/generic_defconfig +++ b/arch/ia64/configs/generic_defconfig @@ -143,7 +143,6 @@ CONFIG_HID_SAMSUNG=m CONFIG_HID_SONY=m CONFIG_HID_SUNPLUS=m CONFIG_USB=m -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=m CONFIG_USB_EHCI_HCD=m CONFIG_USB_OHCI_HCD=m diff --git a/arch/ia64/configs/gensparse_defconfig b/arch/ia64/configs/gensparse_defconfig index f64980dd20c3..d663efd1e4db 100644 --- a/arch/ia64/configs/gensparse_defconfig +++ b/arch/ia64/configs/gensparse_defconfig @@ -126,7 +126,6 @@ CONFIG_SND_CS46XX=m CONFIG_SND_EMU10K1=m CONFIG_SND_FM801=m CONFIG_USB=m -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=m CONFIG_USB_EHCI_HCD=m CONFIG_USB_OHCI_HCD=m diff --git a/arch/ia64/configs/tiger_defconfig b/arch/ia64/configs/tiger_defconfig index 0fed9ae5a42a..c8a3f40e77f6 100644 --- a/arch/ia64/configs/tiger_defconfig +++ b/arch/ia64/configs/tiger_defconfig @@ -102,7 +102,6 @@ CONFIG_DRM_RADEON=m CONFIG_DRM_MGA=m CONFIG_DRM_SIS=m CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_EHCI_HCD=m CONFIG_USB_OHCI_HCD=m CONFIG_USB_UHCI_HCD=y diff --git a/arch/mips/configs/fuloong2e_defconfig b/arch/mips/configs/fuloong2e_defconfig index e5b73de08fc5..002680648dcb 100644 --- a/arch/mips/configs/fuloong2e_defconfig +++ b/arch/mips/configs/fuloong2e_defconfig @@ -188,7 +188,6 @@ CONFIG_USB_KBD=y CONFIG_USB_MOUSE=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_OTG_WHITELIST=y CONFIG_USB_WUSB_CBAF=m diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig index 343bebc4b63b..227a9de32246 100644 --- a/arch/mips/configs/lemote2f_defconfig +++ b/arch/mips/configs/lemote2f_defconfig @@ -297,7 +297,6 @@ CONFIG_HID_WACOM=m CONFIG_HID_ZEROPLUS=m CONFIG_ZEROPLUS_FF=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_DYNAMIC_MINORS=y CONFIG_USB_OTG_WHITELIST=y diff --git a/arch/mips/configs/mpc30x_defconfig b/arch/mips/configs/mpc30x_defconfig index c16de9812920..7a346605c498 100644 --- a/arch/mips/configs/mpc30x_defconfig +++ b/arch/mips/configs/mpc30x_defconfig @@ -47,7 +47,6 @@ CONFIG_GPIO_VR41XX=y # CONFIG_VGA_CONSOLE is not set # CONFIG_HID_SUPPORT is not set CONFIG_USB=m -CONFIG_USB_DEVICEFS=y CONFIG_USB_OHCI_HCD=m CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_VR41XX=y diff --git a/arch/mips/configs/msp71xx_defconfig b/arch/mips/configs/msp71xx_defconfig index d1142e9cd9a1..201edfb2637d 100644 --- a/arch/mips/configs/msp71xx_defconfig +++ b/arch/mips/configs/msp71xx_defconfig @@ -67,7 +67,6 @@ CONFIG_I2C_CHARDEV=y CONFIG_I2C_PMCMSP=y # CONFIG_USB_HID is not set CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_ROOT_HUB_TT=y diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index 593946afc483..d269a5326a30 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -575,7 +575,6 @@ CONFIG_USB_HIDDEV=y CONFIG_USB_KBD=m CONFIG_USB_MOUSE=m CONFIG_USB=m -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=m CONFIG_USB_EHCI_HCD=m CONFIG_USB_EHCI_ROOT_HUB_TT=y diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig index 59d9d2fdcd48..73e7bf49461c 100644 --- a/arch/mips/configs/rm200_defconfig +++ b/arch/mips/configs/rm200_defconfig @@ -301,7 +301,6 @@ CONFIG_USB_HIDDEV=y CONFIG_USB_KBD=m CONFIG_USB_MOUSE=m CONFIG_USB=m -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=m CONFIG_USB_EHCI_HCD=m # CONFIG_USB_EHCI_TT_NEWSCHED is not set diff --git a/arch/mips/configs/sb1250_swarm_defconfig b/arch/mips/configs/sb1250_swarm_defconfig index 5b0463ef9389..51bab13ef6f8 100644 --- a/arch/mips/configs/sb1250_swarm_defconfig +++ b/arch/mips/configs/sb1250_swarm_defconfig @@ -72,7 +72,6 @@ CONFIG_SERIO_RAW=m # CONFIG_HW_RANDOM is not set # CONFIG_HWMON is not set CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_OHCI_HCD=y CONFIG_EXT2_FS=y diff --git a/arch/mips/configs/tb0219_defconfig b/arch/mips/configs/tb0219_defconfig index 30036b4cbeb1..11f51505d562 100644 --- a/arch/mips/configs/tb0219_defconfig +++ b/arch/mips/configs/tb0219_defconfig @@ -72,7 +72,6 @@ CONFIG_GPIO_TB0219=y # CONFIG_VGA_CONSOLE is not set # CONFIG_HID_SUPPORT is not set CONFIG_USB=m -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=m CONFIG_USB_EHCI_HCD=m # CONFIG_USB_EHCI_TT_NEWSCHED is not set diff --git a/arch/mips/configs/tb0226_defconfig b/arch/mips/configs/tb0226_defconfig index 81bfa1d4d8e3..d99b1905a1ba 100644 --- a/arch/mips/configs/tb0226_defconfig +++ b/arch/mips/configs/tb0226_defconfig @@ -69,7 +69,6 @@ CONFIG_SERIAL_VR41XX_CONSOLE=y # CONFIG_VGA_CONSOLE is not set # CONFIG_HID_SUPPORT is not set CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_EHCI_HCD=y # CONFIG_USB_EHCI_TT_NEWSCHED is not set CONFIG_USB_OHCI_HCD=y diff --git a/arch/parisc/configs/c3000_defconfig b/arch/parisc/configs/c3000_defconfig index acacd348df89..fb92b8920785 100644 --- a/arch/parisc/configs/c3000_defconfig +++ b/arch/parisc/configs/c3000_defconfig @@ -127,8 +127,6 @@ CONFIG_SND_SEQUENCER_OSS=y CONFIG_SND_AD1889=y CONFIG_USB_HIDDEV=y CONFIG_USB=y -CONFIG_USB_DEBUG=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_OHCI_HCD=y CONFIG_USB_PRINTER=m CONFIG_USB_STORAGE=m diff --git a/arch/parisc/configs/default_defconfig b/arch/parisc/configs/default_defconfig index ba61495e1fa4..4d8127e8428a 100644 --- a/arch/parisc/configs/default_defconfig +++ b/arch/parisc/configs/default_defconfig @@ -145,7 +145,6 @@ CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_HID_TOPSEED=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_OHCI_HCD=y CONFIG_USB_UHCI_HCD=y diff --git a/arch/parisc/configs/generic-64bit_defconfig b/arch/parisc/configs/generic-64bit_defconfig index 28c1b5de044e..dc0d7ce71ea7 100644 --- a/arch/parisc/configs/generic-64bit_defconfig +++ b/arch/parisc/configs/generic-64bit_defconfig @@ -219,7 +219,6 @@ CONFIG_HIDRAW=y CONFIG_HID_PID=y CONFIG_USB_HIDDEV=y CONFIG_USB=y -CONFIG_USB_DEBUG=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_DYNAMIC_MINORS=y CONFIG_USB_MON=m diff --git a/arch/powerpc/configs/40x/ep405_defconfig b/arch/powerpc/configs/40x/ep405_defconfig index cf06d42f2c03..e9d84b5d0ab6 100644 --- a/arch/powerpc/configs/40x/ep405_defconfig +++ b/arch/powerpc/configs/40x/ep405_defconfig @@ -57,7 +57,6 @@ CONFIG_SERIAL_OF_PLATFORM=y CONFIG_THERMAL=y CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_OHCI_HCD=y CONFIG_USB_OHCI_HCD_PPC_OF_BE=y diff --git a/arch/powerpc/configs/44x/canyonlands_defconfig b/arch/powerpc/configs/44x/canyonlands_defconfig index 7b8abd1b88b0..9919a91add12 100644 --- a/arch/powerpc/configs/44x/canyonlands_defconfig +++ b/arch/powerpc/configs/44x/canyonlands_defconfig @@ -71,7 +71,6 @@ CONFIG_I2C_IBM_IIC=y CONFIG_SENSORS_AD7414=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=m CONFIG_USB_OHCI_HCD=y diff --git a/arch/powerpc/configs/44x/currituck_defconfig b/arch/powerpc/configs/44x/currituck_defconfig index 4192322f8a7f..47de68261443 100644 --- a/arch/powerpc/configs/44x/currituck_defconfig +++ b/arch/powerpc/configs/44x/currituck_defconfig @@ -71,7 +71,6 @@ CONFIG_I2C_IBM_IIC=y # CONFIG_HWMON is not set CONFIG_THERMAL=y CONFIG_USB=y -CONFIG_USB_DEBUG=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y CONFIG_RTC_CLASS=y diff --git a/arch/powerpc/configs/44x/sam440ep_defconfig b/arch/powerpc/configs/44x/sam440ep_defconfig index ca088cd581af..9622eb2a3e37 100644 --- a/arch/powerpc/configs/44x/sam440ep_defconfig +++ b/arch/powerpc/configs/44x/sam440ep_defconfig @@ -83,7 +83,6 @@ CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_EHCI_HCD=m CONFIG_USB_OHCI_HCD=y diff --git a/arch/powerpc/configs/52xx/cm5200_defconfig b/arch/powerpc/configs/52xx/cm5200_defconfig index 4f84a0b2fbf3..0dc99e141035 100644 --- a/arch/powerpc/configs/52xx/cm5200_defconfig +++ b/arch/powerpc/configs/52xx/cm5200_defconfig @@ -64,7 +64,6 @@ CONFIG_I2C_MPC=y # CONFIG_HWMON is not set CONFIG_WATCHDOG=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_OHCI_HCD=y CONFIG_USB_OHCI_HCD_PPC_OF_BE=y diff --git a/arch/powerpc/configs/52xx/pcm030_defconfig b/arch/powerpc/configs/52xx/pcm030_defconfig index 2401e2554329..1d03c35540c7 100644 --- a/arch/powerpc/configs/52xx/pcm030_defconfig +++ b/arch/powerpc/configs/52xx/pcm030_defconfig @@ -76,7 +76,6 @@ CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y # CONFIG_HWMON is not set CONFIG_USB=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_OHCI_HCD=m # CONFIG_USB_OHCI_HCD_PPC_SOC is not set diff --git a/arch/powerpc/configs/52xx/tqm5200_defconfig b/arch/powerpc/configs/52xx/tqm5200_defconfig index 21c841e0f482..ca83ec88b114 100644 --- a/arch/powerpc/configs/52xx/tqm5200_defconfig +++ b/arch/powerpc/configs/52xx/tqm5200_defconfig @@ -75,7 +75,6 @@ CONFIG_FB_FOREIGN_ENDIAN=y CONFIG_FB_SM501=y CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=y CONFIG_USB_OHCI_HCD=y diff --git a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig index 0b73b7f9d112..4b4a2a9133a5 100644 --- a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig +++ b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig @@ -74,7 +74,6 @@ CONFIG_WATCHDOG=y CONFIG_VIDEO_OUTPUT_CONTROL=m # CONFIG_USB_HID is not set CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_FSL=y diff --git a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig index 97ac3b993cb6..5871395573c5 100644 --- a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig +++ b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig @@ -71,7 +71,6 @@ CONFIG_WATCHDOG=y CONFIG_VIDEO_OUTPUT_CONTROL=m # CONFIG_USB_HID is not set CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_FSL=y diff --git a/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig b/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig index b4da1a7e6449..5adc4cea42d3 100644 --- a/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig +++ b/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig @@ -61,7 +61,6 @@ CONFIG_WATCHDOG=y CONFIG_VIDEO_OUTPUT_CONTROL=m # CONFIG_USB_HID is not set CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y diff --git a/arch/powerpc/configs/83xx/mpc834x_itx_defconfig b/arch/powerpc/configs/83xx/mpc834x_itx_defconfig index 291f8221d5a6..82b6b6c88d6a 100644 --- a/arch/powerpc/configs/83xx/mpc834x_itx_defconfig +++ b/arch/powerpc/configs/83xx/mpc834x_itx_defconfig @@ -71,7 +71,6 @@ CONFIG_SPI_BITBANG=y CONFIG_WATCHDOG=y CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_FSL=y diff --git a/arch/powerpc/configs/83xx/sbc834x_defconfig b/arch/powerpc/configs/83xx/sbc834x_defconfig index a3bcda67d2d9..4ae385894c64 100644 --- a/arch/powerpc/configs/83xx/sbc834x_defconfig +++ b/arch/powerpc/configs/83xx/sbc834x_defconfig @@ -70,7 +70,6 @@ CONFIG_I2C_MPC=y CONFIG_WATCHDOG=y # CONFIG_USB_HID is not set CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_FSL=y diff --git a/arch/powerpc/configs/85xx/ge_imp3a_defconfig b/arch/powerpc/configs/85xx/ge_imp3a_defconfig index c9765b54dd1a..dc939de9b5b0 100644 --- a/arch/powerpc/configs/85xx/ge_imp3a_defconfig +++ b/arch/powerpc/configs/85xx/ge_imp3a_defconfig @@ -158,7 +158,6 @@ CONFIG_HID_TOPSEED=y CONFIG_HID_THRUSTMASTER=y CONFIG_HID_ZEROPLUS=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_EHCI_HCD=y # CONFIG_USB_EHCI_TT_NEWSCHED is not set CONFIG_USB_EHCI_FSL=y diff --git a/arch/powerpc/configs/85xx/socrates_defconfig b/arch/powerpc/configs/85xx/socrates_defconfig index e5147488c000..435fd408eef1 100644 --- a/arch/powerpc/configs/85xx/socrates_defconfig +++ b/arch/powerpc/configs/85xx/socrates_defconfig @@ -86,7 +86,6 @@ CONFIG_FONTS=y CONFIG_FONT_8x16=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y diff --git a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig index 07bb81df27e0..72df8ab8449e 100644 --- a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig +++ b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig @@ -125,7 +125,6 @@ CONFIG_SENSORS_LM90=y CONFIG_WATCHDOG=y CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=y CONFIG_USB_ISP1760_HCD=y diff --git a/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig b/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig index f51c7ebc181e..76f43df3dec7 100644 --- a/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig +++ b/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig @@ -123,7 +123,6 @@ CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y diff --git a/arch/powerpc/configs/amigaone_defconfig b/arch/powerpc/configs/amigaone_defconfig index b6d49da9c82c..8c66b13e59fc 100644 --- a/arch/powerpc/configs/amigaone_defconfig +++ b/arch/powerpc/configs/amigaone_defconfig @@ -108,7 +108,6 @@ CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_HID_TOPSEED=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_OHCI_HCD=y CONFIG_USB_UHCI_HCD=y diff --git a/arch/powerpc/configs/c2k_defconfig b/arch/powerpc/configs/c2k_defconfig index c69f61620908..5e2aa43562b5 100644 --- a/arch/powerpc/configs/c2k_defconfig +++ b/arch/powerpc/configs/c2k_defconfig @@ -261,7 +261,6 @@ CONFIG_USBPCWATCHDOG=m # CONFIG_VGA_CONSOLE is not set # CONFIG_HID_SUPPORT is not set CONFIG_USB=m -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=m CONFIG_USB_EHCI_HCD=m diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig index 22a403d78d34..4bee1a6d41d0 100644 --- a/arch/powerpc/configs/cell_defconfig +++ b/arch/powerpc/configs/cell_defconfig @@ -179,7 +179,6 @@ CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_HID=m # CONFIG_USB_HID is not set CONFIG_USB=m -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=m CONFIG_USB_EHCI_HCD=m # CONFIG_USB_EHCI_HCD_PPC_OF is not set diff --git a/arch/powerpc/configs/celleb_defconfig b/arch/powerpc/configs/celleb_defconfig index 895449ed971e..6d7b22f41b50 100644 --- a/arch/powerpc/configs/celleb_defconfig +++ b/arch/powerpc/configs/celleb_defconfig @@ -87,7 +87,6 @@ CONFIG_WATCHDOG=y # CONFIG_VGA_CONSOLE is not set CONFIG_USB_HIDDEV=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=m diff --git a/arch/powerpc/configs/chrp32_defconfig b/arch/powerpc/configs/chrp32_defconfig index b20554efddcc..db5b30857e1c 100644 --- a/arch/powerpc/configs/chrp32_defconfig +++ b/arch/powerpc/configs/chrp32_defconfig @@ -111,7 +111,6 @@ CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=m # CONFIG_USB_EHCI_HCD_PPC_OF is not set diff --git a/arch/powerpc/configs/g5_defconfig b/arch/powerpc/configs/g5_defconfig index 1ea22fc24ea8..3c72fa615bd9 100644 --- a/arch/powerpc/configs/g5_defconfig +++ b/arch/powerpc/configs/g5_defconfig @@ -175,7 +175,6 @@ CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y # CONFIG_USB_EHCI_HCD_PPC_OF is not set diff --git a/arch/powerpc/configs/linkstation_defconfig b/arch/powerpc/configs/linkstation_defconfig index 353435256f4c..b5e684640fdf 100644 --- a/arch/powerpc/configs/linkstation_defconfig +++ b/arch/powerpc/configs/linkstation_defconfig @@ -111,7 +111,6 @@ CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_HID=m # CONFIG_USB_HID is not set CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y diff --git a/arch/powerpc/configs/maple_defconfig b/arch/powerpc/configs/maple_defconfig index 2a5afac29861..95e545d9f25c 100644 --- a/arch/powerpc/configs/maple_defconfig +++ b/arch/powerpc/configs/maple_defconfig @@ -79,7 +79,6 @@ CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_ROOT_HUB_TT=y diff --git a/arch/powerpc/configs/mpc5200_defconfig b/arch/powerpc/configs/mpc5200_defconfig index 8b682d1cf4d6..530601e8ccfe 100644 --- a/arch/powerpc/configs/mpc5200_defconfig +++ b/arch/powerpc/configs/mpc5200_defconfig @@ -113,7 +113,6 @@ CONFIG_HID_TOPSEED=y CONFIG_HID_THRUSTMASTER=y CONFIG_HID_ZEROPLUS=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=y CONFIG_USB_OHCI_HCD=y diff --git a/arch/powerpc/configs/mpc86xx_defconfig b/arch/powerpc/configs/mpc86xx_defconfig index a1cc8179e9fd..35595ea74ff4 100644 --- a/arch/powerpc/configs/mpc86xx_defconfig +++ b/arch/powerpc/configs/mpc86xx_defconfig @@ -126,7 +126,6 @@ CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y diff --git a/arch/powerpc/configs/pmac32_defconfig b/arch/powerpc/configs/pmac32_defconfig index a73626b09051..553e66278010 100644 --- a/arch/powerpc/configs/pmac32_defconfig +++ b/arch/powerpc/configs/pmac32_defconfig @@ -279,7 +279,6 @@ CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_HID_TOPSEED=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_DYNAMIC_MINORS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=m diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index 175a8b99c196..c91066944842 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -964,9 +964,7 @@ CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -CONFIG_USB_DEBUG=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=m diff --git a/arch/powerpc/configs/storcenter_defconfig b/arch/powerpc/configs/storcenter_defconfig index ba39c785445d..60ad2c08caa6 100644 --- a/arch/powerpc/configs/storcenter_defconfig +++ b/arch/powerpc/configs/storcenter_defconfig @@ -72,7 +72,6 @@ CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y # CONFIG_HWMON is not set CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y CONFIG_USB_STORAGE=y diff --git a/arch/sh/configs/apsh4ad0a_defconfig b/arch/sh/configs/apsh4ad0a_defconfig index 95ae23fcfdd6..ec70475da890 100644 --- a/arch/sh/configs/apsh4ad0a_defconfig +++ b/arch/sh/configs/apsh4ad0a_defconfig @@ -93,7 +93,6 @@ CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y CONFIG_LOGO=y CONFIG_USB=y -CONFIG_USB_DEBUG=y CONFIG_USB_MON=y CONFIG_USB_OHCI_HCD=y CONFIG_USB_STORAGE=y diff --git a/arch/sh/configs/ecovec24_defconfig b/arch/sh/configs/ecovec24_defconfig index c6c2becdc8ab..0b364e3b0ff8 100644 --- a/arch/sh/configs/ecovec24_defconfig +++ b/arch/sh/configs/ecovec24_defconfig @@ -107,7 +107,6 @@ CONFIG_SND_SOC=y CONFIG_SND_SOC_SH4_FSI=y CONFIG_SND_FSI_DA7210=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_R8A66597_HCD=y CONFIG_USB_STORAGE=y diff --git a/arch/sh/configs/landisk_defconfig b/arch/sh/configs/landisk_defconfig index 3670e937f2b7..6783f31315c7 100644 --- a/arch/sh/configs/landisk_defconfig +++ b/arch/sh/configs/landisk_defconfig @@ -80,7 +80,6 @@ CONFIG_HID_SAMSUNG=m CONFIG_HID_SONY=m CONFIG_HID_SUNPLUS=m CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y # CONFIG_USB_EHCI_TT_NEWSCHED is not set diff --git a/arch/sh/configs/rsk7203_defconfig b/arch/sh/configs/rsk7203_defconfig index 47236573db83..3c4f6f4d52b0 100644 --- a/arch/sh/configs/rsk7203_defconfig +++ b/arch/sh/configs/rsk7203_defconfig @@ -100,7 +100,6 @@ CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_R8A66597_HCD=y CONFIG_NEW_LEDS=y diff --git a/arch/sh/configs/rsk7264_defconfig b/arch/sh/configs/rsk7264_defconfig index 1600426224c2..eecdf65bb789 100644 --- a/arch/sh/configs/rsk7264_defconfig +++ b/arch/sh/configs/rsk7264_defconfig @@ -60,7 +60,6 @@ CONFIG_SERIAL_SH_SCI_NR_UARTS=8 CONFIG_SERIAL_SH_SCI_CONSOLE=y # CONFIG_HWMON is not set CONFIG_USB=y -CONFIG_USB_DEBUG=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_R8A66597_HCD=y diff --git a/arch/sh/configs/rsk7269_defconfig b/arch/sh/configs/rsk7269_defconfig index 9f062b5837d7..8370b10df357 100644 --- a/arch/sh/configs/rsk7269_defconfig +++ b/arch/sh/configs/rsk7269_defconfig @@ -43,7 +43,6 @@ CONFIG_SERIAL_SH_SCI_NR_UARTS=8 CONFIG_SERIAL_SH_SCI_CONSOLE=y # CONFIG_HWMON is not set CONFIG_USB=y -CONFIG_USB_DEBUG=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_R8A66597_HCD=y diff --git a/arch/sh/configs/sdk7780_defconfig b/arch/sh/configs/sdk7780_defconfig index ae1115849dda..6a96b9a2f7a5 100644 --- a/arch/sh/configs/sdk7780_defconfig +++ b/arch/sh/configs/sdk7780_defconfig @@ -100,8 +100,6 @@ CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -CONFIG_USB_DEBUG=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y diff --git a/arch/sh/configs/se7343_defconfig b/arch/sh/configs/se7343_defconfig index be9c474197b3..201acb4652f7 100644 --- a/arch/sh/configs/se7343_defconfig +++ b/arch/sh/configs/se7343_defconfig @@ -92,9 +92,7 @@ CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -CONFIG_USB_DEBUG=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_ISP116X_HCD=y CONFIG_UIO=y CONFIG_EXT2_FS=y diff --git a/arch/sh/configs/se7780_defconfig b/arch/sh/configs/se7780_defconfig index c8c5e7f7a68d..b0ef63ce525a 100644 --- a/arch/sh/configs/se7780_defconfig +++ b/arch/sh/configs/se7780_defconfig @@ -94,7 +94,6 @@ CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y diff --git a/arch/sh/configs/sh2007_defconfig b/arch/sh/configs/sh2007_defconfig index 0d2f41472a19..0c08d9244c97 100644 --- a/arch/sh/configs/sh2007_defconfig +++ b/arch/sh/configs/sh2007_defconfig @@ -97,7 +97,6 @@ CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y CONFIG_LOGO=y # CONFIG_HID_SUPPORT is not set CONFIG_USB=y -CONFIG_USB_DEVICEFS=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=y CONFIG_NEW_LEDS=y diff --git a/arch/sh/configs/sh7785lcr_defconfig b/arch/sh/configs/sh7785lcr_defconfig index 51561f5677d8..d29da4a0f6c2 100644 --- a/arch/sh/configs/sh7785lcr_defconfig +++ b/arch/sh/configs/sh7785lcr_defconfig @@ -88,7 +88,6 @@ CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=m # CONFIG_USB_EHCI_TT_NEWSCHED is not set diff --git a/arch/sh/configs/titan_defconfig b/arch/sh/configs/titan_defconfig index e2cbd92d520b..a77b778c745b 100644 --- a/arch/sh/configs/titan_defconfig +++ b/arch/sh/configs/titan_defconfig @@ -215,7 +215,6 @@ CONFIG_WATCHDOG=y CONFIG_SH_WDT=m # CONFIG_USB_HID is not set CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_ROOT_HUB_TT=y diff --git a/arch/sh/configs/urquell_defconfig b/arch/sh/configs/urquell_defconfig index d7f89be9f474..1e843dbed5f0 100644 --- a/arch/sh/configs/urquell_defconfig +++ b/arch/sh/configs/urquell_defconfig @@ -117,7 +117,6 @@ CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_OHCI_HCD=y CONFIG_USB_STORAGE=y diff --git a/arch/unicore32/configs/unicore32_defconfig b/arch/unicore32/configs/unicore32_defconfig index c9dd3198b6f7..45f47f88d86a 100644 --- a/arch/unicore32/configs/unicore32_defconfig +++ b/arch/unicore32/configs/unicore32_defconfig @@ -149,7 +149,6 @@ CONFIG_SND_PCM_OSS=m # USB support CONFIG_USB_ARCH_HAS_HCD=n CONFIG_USB=n -CONFIG_USB_DEVICEFS=n CONFIG_USB_PRINTER=n CONFIG_USB_STORAGE=n # Inventra Highspeed Dual Role Controller diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig index 619e7f7426c6..32d2e7056c87 100644 --- a/arch/x86/configs/i386_defconfig +++ b/arch/x86/configs/i386_defconfig @@ -244,7 +244,6 @@ CONFIG_HID_TOPSEED=y CONFIG_HID_PID=y CONFIG_USB_HIDDEV=y CONFIG_USB=y -CONFIG_USB_DEBUG=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig index 6181c69b786b..a481dd4755d5 100644 --- a/arch/x86/configs/x86_64_defconfig +++ b/arch/x86/configs/x86_64_defconfig @@ -239,7 +239,6 @@ CONFIG_HID_TOPSEED=y CONFIG_HID_PID=y CONFIG_USB_HIDDEV=y CONFIG_USB=y -CONFIG_USB_DEBUG=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index f5ae57406f34..afdf383f630a 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -283,7 +283,7 @@ int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len) int udl_driver_load(struct drm_device *dev, unsigned long flags) { struct udl_device *udl; - int ret; + int ret = -ENOMEM; DRM_DEBUG("\n"); udl = kzalloc(sizeof(struct udl_device), GFP_KERNEL); @@ -299,7 +299,6 @@ int udl_driver_load(struct drm_device *dev, unsigned long flags) } if (!udl_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) { - ret = -ENOMEM; DRM_ERROR("udl_alloc_urb_list failed\n"); goto err; } diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 47cd373e2295..79abbc8d9600 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -60,28 +60,6 @@ #define DRIVER_DESC "RedRat3 USB IR Transceiver Driver" #define DRIVER_NAME "redrat3" -/* module parameters */ -#ifdef CONFIG_USB_DEBUG -static int debug = 1; -#else -static int debug; -#endif - -#define RR3_DEBUG_STANDARD 0x1 -#define RR3_DEBUG_FUNCTION_TRACE 0x2 - -#define rr3_dbg(dev, fmt, ...) \ - do { \ - if (debug & RR3_DEBUG_STANDARD) \ - dev_info(dev, fmt, ## __VA_ARGS__); \ - } while (0) - -#define rr3_ftr(dev, fmt, ...) \ - do { \ - if (debug & RR3_DEBUG_FUNCTION_TRACE) \ - dev_info(dev, fmt, ## __VA_ARGS__); \ - } while (0) - /* bulk data transfer types */ #define RR3_ERROR 0x01 #define RR3_MOD_SIGNAL_IN 0x20 @@ -237,13 +215,11 @@ static void redrat3_issue_async(struct redrat3_dev *rr3) { int res; - rr3_ftr(rr3->dev, "Entering %s\n", __func__); - res = usb_submit_urb(rr3->read_urb, GFP_ATOMIC); if (res) - rr3_dbg(rr3->dev, "%s: receive request FAILED! " - "(res %d, len %d)\n", __func__, res, - rr3->read_urb->transfer_buffer_length); + dev_dbg(rr3->dev, + "%s: receive request FAILED! (res %d, len %d)\n", + __func__, res, rr3->read_urb->transfer_buffer_length); } static void redrat3_dump_fw_error(struct redrat3_dev *rr3, int code) @@ -359,7 +335,7 @@ static void redrat3_rx_timeout(unsigned long data) { struct redrat3_dev *rr3 = (struct redrat3_dev *)data; - rr3_dbg(rr3->dev, "calling ir_raw_event_reset\n"); + dev_dbg(rr3->dev, "calling ir_raw_event_reset\n"); ir_raw_event_reset(rr3->rc); } @@ -377,8 +353,6 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) return; } - rr3_ftr(rr3->dev, "Entered %s\n", __func__); - dev = rr3->dev; /* Make sure we reset the IR kfifo after a bit of inactivity */ @@ -386,7 +360,7 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) mod_timer(&rr3->rx_timeout, jiffies + delay); mod_freq = redrat3_val_to_mod_freq(&rr3->irdata); - rr3_dbg(dev, "Got mod_freq of %u\n", mod_freq); + dev_dbg(dev, "Got mod_freq of %u\n", mod_freq); /* process each rr3 encoded byte into an int */ sig_size = be16_to_cpu(rr3->irdata.sig_size); @@ -408,7 +382,7 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) /* cap the value to IR_MAX_DURATION */ rawir.duration &= IR_MAX_DURATION; - rr3_dbg(dev, "storing %s with duration %d (i: %d)\n", + dev_dbg(dev, "storing %s with duration %d (i: %d)\n", rawir.pulse ? "pulse" : "space", rawir.duration, i); ir_raw_event_store_with_filter(rr3->rc, &rawir); } @@ -421,12 +395,12 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) rawir.duration = US_TO_NS(2800); else rawir.duration = trailer; - rr3_dbg(dev, "storing trailing space with duration %d\n", + dev_dbg(dev, "storing trailing space with duration %d\n", rawir.duration); ir_raw_event_store_with_filter(rr3->rc, &rawir); } - rr3_dbg(dev, "calling ir_raw_event_handle\n"); + dev_dbg(dev, "calling ir_raw_event_handle\n"); ir_raw_event_handle(rr3->rc); } @@ -464,8 +438,6 @@ static int redrat3_enable_detector(struct redrat3_dev *rr3) struct device *dev = rr3->dev; u8 ret; - rr3_ftr(dev, "Entering %s\n", __func__); - ret = redrat3_send_cmd(RR3_RC_DET_ENABLE, rr3); if (ret != 0) dev_dbg(dev, "%s: unexpected ret of %d\n", @@ -486,7 +458,6 @@ static int redrat3_enable_detector(struct redrat3_dev *rr3) static inline void redrat3_delete(struct redrat3_dev *rr3, struct usb_device *udev) { - rr3_ftr(rr3->dev, "%s cleaning up\n", __func__); usb_kill_urb(rr3->read_urb); usb_kill_urb(rr3->flash_urb); usb_free_urb(rr3->read_urb); @@ -519,7 +490,7 @@ static u32 redrat3_get_timeout(struct redrat3_dev *rr3) else { timeout = redrat3_len_to_us(be32_to_cpup(tmp)); - rr3_dbg(rr3->dev, "Got timeout of %d ms\n", timeout / 1000); + dev_dbg(rr3->dev, "Got timeout of %d ms\n", timeout / 1000); } kfree(tmp); @@ -535,8 +506,6 @@ static void redrat3_reset(struct redrat3_dev *rr3) u8 *val; int len = sizeof(u8); - rr3_ftr(dev, "Entering %s\n", __func__); - rxpipe = usb_rcvctrlpipe(udev, 0); txpipe = usb_sndctrlpipe(udev, 0); @@ -550,19 +519,19 @@ static void redrat3_reset(struct redrat3_dev *rr3) rc = usb_control_msg(udev, rxpipe, RR3_RESET, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, RR3_CPUCS_REG_ADDR, 0, val, len, HZ * 25); - rr3_dbg(dev, "reset returned 0x%02x\n", rc); + dev_dbg(dev, "reset returned 0x%02x\n", rc); *val = 5; rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, RR3_IR_IO_LENGTH_FUZZ, 0, val, len, HZ * 25); - rr3_dbg(dev, "set ir parm len fuzz %d rc 0x%02x\n", *val, rc); + dev_dbg(dev, "set ir parm len fuzz %d rc 0x%02x\n", *val, rc); *val = RR3_DRIVER_MAXLENS; rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, RR3_IR_IO_MAX_LENGTHS, 0, val, len, HZ * 25); - rr3_dbg(dev, "set ir parm max lens %d rc 0x%02x\n", *val, rc); + dev_dbg(dev, "set ir parm max lens %d rc 0x%02x\n", *val, rc); kfree(val); } @@ -572,8 +541,6 @@ static void redrat3_get_firmware_rev(struct redrat3_dev *rr3) int rc = 0; char *buffer; - rr3_ftr(rr3->dev, "Entering %s\n", __func__); - buffer = kzalloc(sizeof(char) * (RR3_FW_VERSION_LEN + 1), GFP_KERNEL); if (!buffer) { dev_err(rr3->dev, "Memory allocation failure\n"); @@ -591,7 +558,6 @@ static void redrat3_get_firmware_rev(struct redrat3_dev *rr3) dev_err(rr3->dev, "Problem fetching firmware ID\n"); kfree(buffer); - rr3_ftr(rr3->dev, "Exiting %s\n", __func__); } static void redrat3_read_packet_start(struct redrat3_dev *rr3, unsigned len) @@ -599,8 +565,6 @@ static void redrat3_read_packet_start(struct redrat3_dev *rr3, unsigned len) struct redrat3_header *header = rr3->bulk_in_buf; unsigned pktlen, pkttype; - rr3_ftr(rr3->dev, "Entering %s\n", __func__); - /* grab the Length and type of transfer */ pktlen = be16_to_cpu(header->length); pkttype = be16_to_cpu(header->transfer_type); @@ -622,12 +586,12 @@ static void redrat3_read_packet_start(struct redrat3_dev *rr3, unsigned len) case RR3_MOD_SIGNAL_IN: memcpy(&rr3->irdata, rr3->bulk_in_buf, len); rr3->bytes_read = len; - rr3_dbg(rr3->dev, "bytes_read %d, pktlen %d\n", + dev_dbg(rr3->dev, "bytes_read %d, pktlen %d\n", rr3->bytes_read, pktlen); break; default: - rr3_dbg(rr3->dev, "ignoring packet with type 0x%02x, len of %d, 0x%02x\n", + dev_dbg(rr3->dev, "ignoring packet with type 0x%02x, len of %d, 0x%02x\n", pkttype, len, pktlen); break; } @@ -637,8 +601,6 @@ static void redrat3_read_packet_continue(struct redrat3_dev *rr3, unsigned len) { void *irdata = &rr3->irdata; - rr3_ftr(rr3->dev, "Entering %s\n", __func__); - if (len + rr3->bytes_read > sizeof(rr3->irdata)) { dev_warn(rr3->dev, "too much data for packet\n"); rr3->bytes_read = 0; @@ -648,7 +610,7 @@ static void redrat3_read_packet_continue(struct redrat3_dev *rr3, unsigned len) memcpy(irdata + rr3->bytes_read, rr3->bulk_in_buf, len); rr3->bytes_read += len; - rr3_dbg(rr3->dev, "bytes_read %d, pktlen %d\n", rr3->bytes_read, + dev_dbg(rr3->dev, "bytes_read %d, pktlen %d\n", rr3->bytes_read, be16_to_cpu(rr3->irdata.header.length)); } @@ -659,8 +621,6 @@ static int redrat3_get_ir_data(struct redrat3_dev *rr3, unsigned len) unsigned pkttype; int ret = 0; - rr3_ftr(dev, "Entering %s\n", __func__); - if (rr3->bytes_read == 0 && len >= sizeof(struct redrat3_header)) { redrat3_read_packet_start(rr3, len); } else if (rr3->bytes_read != 0) { @@ -681,7 +641,7 @@ static int redrat3_get_ir_data(struct redrat3_dev *rr3, unsigned len) if (pkttype == RR3_MOD_SIGNAL_IN) redrat3_process_ir_data(rr3); else - rr3_dbg(dev, "discarding non-signal data packet (type 0x%02x)\n", + dev_dbg(dev, "discarding non-signal data packet (type 0x%02x)\n", pkttype); out: @@ -705,8 +665,6 @@ static void redrat3_handle_async(struct urb *urb) return; } - rr3_ftr(rr3->dev, "Entering %s\n", __func__); - switch (urb->status) { case 0: ret = redrat3_get_ir_data(rr3, urb->actual_length); @@ -743,7 +701,7 @@ static int redrat3_set_tx_carrier(struct rc_dev *rcdev, u32 carrier) struct redrat3_dev *rr3 = rcdev->priv; struct device *dev = rr3->dev; - rr3_dbg(dev, "Setting modulation frequency to %u", carrier); + dev_dbg(dev, "Setting modulation frequency to %u", carrier); if (carrier == 0) return -EINVAL; @@ -764,8 +722,6 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, u8 curlencheck = 0; unsigned i, sendbuf_len; - rr3_ftr(dev, "Entering %s\n", __func__); - if (rr3->transmitting) { dev_warn(dev, "%s: transmitter already in use\n", __func__); return -EAGAIN; @@ -801,7 +757,7 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, break; } if (lencheck == curlencheck) { - rr3_dbg(dev, "txbuf[%d]=%u, pos %d, enc %u\n", + dev_dbg(dev, "txbuf[%d]=%u, pos %d, enc %u\n", i, txbuf[i], curlencheck, cur_sample_len); if (curlencheck < RR3_DRIVER_MAXLENS) { /* now convert the value to a proper @@ -835,7 +791,7 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, pipe = usb_sndbulkpipe(rr3->udev, rr3->ep_out->bEndpointAddress); ret = usb_bulk_msg(rr3->udev, pipe, irdata, sendbuf_len, &ret_len, 10 * HZ); - rr3_dbg(dev, "sent %d bytes, (ret %d)\n", ret_len, ret); + dev_dbg(dev, "sent %d bytes, (ret %d)\n", ret_len, ret); /* now tell the hardware to transmit what we sent it */ pipe = usb_rcvctrlpipe(rr3->udev, 0); @@ -957,8 +913,6 @@ static int redrat3_dev_probe(struct usb_interface *intf, int pipe, i; int retval = -ENOMEM; - rr3_ftr(dev, "%s called\n", __func__); - uhi = intf->cur_altsetting; /* find our bulk-in and bulk-out endpoints */ @@ -971,7 +925,7 @@ static int redrat3_dev_probe(struct usb_interface *intf, ((addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) && ((attrs & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) { - rr3_dbg(dev, "found bulk-in endpoint at 0x%02x\n", + dev_dbg(dev, "found bulk-in endpoint at 0x%02x\n", ep->bEndpointAddress); /* data comes in on 0x82, 0x81 is for other data... */ if (ep->bEndpointAddress == RR3_BULK_IN_EP_ADDR) @@ -982,7 +936,7 @@ static int redrat3_dev_probe(struct usb_interface *intf, ((addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) && ((attrs & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) { - rr3_dbg(dev, "found bulk-out endpoint at 0x%02x\n", + dev_dbg(dev, "found bulk-out endpoint at 0x%02x\n", ep->bEndpointAddress); ep_out = ep; } @@ -1074,7 +1028,6 @@ static int redrat3_dev_probe(struct usb_interface *intf, /* we can register the device now, as it is ready */ usb_set_intfdata(intf, rr3); - rr3_ftr(dev, "Exiting %s\n", __func__); return 0; led_free_error: @@ -1093,8 +1046,6 @@ static void redrat3_dev_disconnect(struct usb_interface *intf) struct usb_device *udev = interface_to_usbdev(intf); struct redrat3_dev *rr3 = usb_get_intfdata(intf); - rr3_ftr(&intf->dev, "Entering %s\n", __func__); - if (!rr3) return; @@ -1103,14 +1054,12 @@ static void redrat3_dev_disconnect(struct usb_interface *intf) led_classdev_unregister(&rr3->led); del_timer_sync(&rr3->rx_timeout); redrat3_delete(rr3, udev); - - rr3_ftr(&intf->dev, "RedRat3 IR Transceiver now disconnected\n"); } static int redrat3_dev_suspend(struct usb_interface *intf, pm_message_t message) { struct redrat3_dev *rr3 = usb_get_intfdata(intf); - rr3_ftr(rr3->dev, "suspend\n"); + led_classdev_suspend(&rr3->led); usb_kill_urb(rr3->read_urb); usb_kill_urb(rr3->flash_urb); @@ -1120,7 +1069,7 @@ static int redrat3_dev_suspend(struct usb_interface *intf, pm_message_t message) static int redrat3_dev_resume(struct usb_interface *intf) { struct redrat3_dev *rr3 = usb_get_intfdata(intf); - rr3_ftr(rr3->dev, "resume\n"); + if (usb_submit_urb(rr3->read_urb, GFP_ATOMIC)) return -EIO; led_classdev_resume(&rr3->led); @@ -1144,8 +1093,3 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_AUTHOR(DRIVER_AUTHOR2); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(usb, redrat3_dev_table); - -module_param(debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable module debug spew. 0 = no debugging (default) " - "0x1 = standard debug messages, 0x2 = function tracing debug. " - "Flag bits are addative (i.e., 0x3 for both debug types)."); diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c index f4e0bc3d382c..bd5e4ff9e0ba 100644 --- a/drivers/media/rc/streamzap.c +++ b/drivers/media/rc/streamzap.c @@ -42,12 +42,6 @@ #define DRIVER_NAME "streamzap" #define DRIVER_DESC "Streamzap Remote Control driver" -#ifdef CONFIG_USB_DEBUG -static bool debug = 1; -#else -static bool debug; -#endif - #define USB_STREAMZAP_VENDOR_ID 0x0e9c #define USB_STREAMZAP_PRODUCT_ID 0x0000 @@ -528,6 +522,3 @@ module_usb_driver(streamzap_driver); MODULE_AUTHOR("Jarod Wilson <jarod@wilsonet.com>"); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debugging messages"); diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c index f9805c9353d2..3ac71339d040 100644 --- a/drivers/net/wireless/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/orinoco/orinoco_usb.c @@ -100,25 +100,11 @@ static struct ez_usb_fw firmware = { .code = NULL, }; -#ifdef CONFIG_USB_DEBUG -static int debug = 1; -#else -static int debug; -#endif - /* Debugging macros */ -#undef dbg -#define dbg(format, arg...) \ - do { if (debug) printk(KERN_DEBUG PFX "%s: " format "\n", \ - __func__ , ## arg); } while (0) #undef err #define err(format, arg...) \ do { printk(KERN_ERR PFX format "\n", ## arg); } while (0) -/* Module paramaters */ -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - MODULE_FIRMWARE("orinoco_ezusb_fw"); /* @@ -341,7 +327,7 @@ static void ezusb_request_timerfn(u_long _ctx) ctx->state = EZUSB_CTX_REQ_TIMEOUT; } else { ctx->state = EZUSB_CTX_RESP_TIMEOUT; - dbg("couldn't unlink"); + dev_dbg(&ctx->outurb->dev->dev, "couldn't unlink\n"); atomic_inc(&ctx->refcount); ctx->killed = 1; ezusb_ctx_complete(ctx); @@ -634,9 +620,9 @@ static void ezusb_request_in_callback(struct ezusb_priv *upriv, ctx = c; break; } - dbg("Skipped (0x%x/0x%x) (%d/%d)", - le16_to_cpu(ans->hermes_rid), - c->in_rid, ans->ans_reply_count, reply_count); + netdev_dbg(upriv->dev, "Skipped (0x%x/0x%x) (%d/%d)\n", + le16_to_cpu(ans->hermes_rid), c->in_rid, + ans->ans_reply_count, reply_count); } } @@ -768,7 +754,7 @@ static int ezusb_submit_in_urb(struct ezusb_priv *upriv) void *cur_buf = upriv->read_urb->transfer_buffer; if (upriv->read_urb->status == -EINPROGRESS) { - dbg("urb busy, not resubmiting"); + netdev_dbg(upriv->dev, "urb busy, not resubmiting\n"); retval = -EBUSY; goto exit; } @@ -838,8 +824,9 @@ static int ezusb_firmware_download(struct ezusb_priv *upriv, memcpy(fw_buffer, &fw->code[addr], FW_BUF_SIZE); if (variant_offset >= addr && variant_offset < addr + FW_BUF_SIZE) { - dbg("Patching card_variant byte at 0x%04X", - variant_offset); + netdev_dbg(upriv->dev, + "Patching card_variant byte at 0x%04X\n", + variant_offset); fw_buffer[variant_offset - addr] = FW_VAR_VALUE; } retval = usb_control_msg(upriv->udev, @@ -879,7 +866,6 @@ static int ezusb_access_ltv(struct ezusb_priv *upriv, BUG_ON(in_irq()); if (!upriv->udev) { - dbg("Device disconnected"); retval = -ENODEV; goto exit; } @@ -1023,8 +1009,9 @@ static int ezusb_doicmd_wait(struct hermes *hw, u16 cmd, u16 parm0, u16 parm1, cpu_to_le16(parm1), cpu_to_le16(parm2), }; - dbg("0x%04X, parm0 0x%04X, parm1 0x%04X, parm2 0x%04X", - cmd, parm0, parm1, parm2); + netdev_dbg(upriv->dev, + "0x%04X, parm0 0x%04X, parm1 0x%04X, parm2 0x%04X\n", cmd, + parm0, parm1, parm2); ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_DOCMD, EZUSB_RID_ACK); if (!ctx) return -ENOMEM; @@ -1045,7 +1032,7 @@ static int ezusb_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0, 0, 0, }; - dbg("0x%04X, parm0 0x%04X", cmd, parm0); + netdev_dbg(upriv->dev, "0x%04X, parm0 0x%04X\n", cmd, parm0); ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_DOCMD, EZUSB_RID_ACK); if (!ctx) return -ENOMEM; @@ -1332,7 +1319,7 @@ static int ezusb_hard_reset(struct orinoco_private *priv) return retval; } - dbg("sending control message"); + netdev_dbg(upriv->dev, "sending control message\n"); retval = usb_control_msg(upriv->udev, usb_sndctrlpipe(upriv->udev, 0), EZUSB_REQUEST_TRIGER, @@ -1401,10 +1388,8 @@ static void ezusb_bulk_in_callback(struct urb *urb) u16 crc; u16 hermes_rid; - if (upriv->udev == NULL) { - dbg("disconnected"); + if (upriv->udev == NULL) return; - } if (urb->status == -ETIMEDOUT) { /* When a device gets unplugged we get this every time @@ -1421,12 +1406,13 @@ static void ezusb_bulk_in_callback(struct urb *urb) if ((urb->status == -EILSEQ) || (urb->status == -ENOENT) || (urb->status == -ECONNRESET)) { - dbg("status %d, not resubmiting", urb->status); + netdev_dbg(upriv->dev, "status %d, not resubmiting\n", + urb->status); return; } if (urb->status) - dbg("status: %d length: %d", - urb->status, urb->actual_length); + netdev_dbg(upriv->dev, "status: %d length: %d\n", + urb->status, urb->actual_length); if (urb->actual_length < sizeof(*ans)) { err("%s: short read, ignoring", __func__); goto resubmit; diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 4906c27fa3bd..16a2f067c242 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -89,8 +89,8 @@ config PHY_EXYNOS_DP_VIDEO config BCM_KONA_USB2_PHY tristate "Broadcom Kona USB2 PHY Driver" - depends on GENERIC_PHY depends on HAS_IOMEM + select GENERIC_PHY help Enable this to support the Broadcom Kona USB 2.0 PHY. @@ -160,6 +160,17 @@ config PHY_EXYNOS5250_USB2 particular SoC is compiled in the driver. In case of Exynos 5250 four phys are available - device, host, HSIC0 and HSIC. +config PHY_EXYNOS5_USBDRD + tristate "Exynos5 SoC series USB DRD PHY driver" + depends on ARCH_EXYNOS5 && OF + depends on HAS_IOMEM + select GENERIC_PHY + select MFD_SYSCON + help + Enable USB DRD PHY support for Exynos 5 SoC series. + This driver provides PHY interface for USB 3.0 DRD controller + present on Exynos5 SoC series. + config PHY_XGENE tristate "APM X-Gene 15Gbps PHY support" depends on HAS_IOMEM && OF && (ARM64 || COMPILE_TEST) diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 7728518572a4..b4f1d5770601 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -18,4 +18,5 @@ phy-exynos-usb2-y += phy-samsung-usb2.o phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2) += phy-exynos4x12-usb2.o phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2) += phy-exynos5250-usb2.o +obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o obj-$(CONFIG_PHY_XGENE) += phy-xgene.o diff --git a/drivers/phy/phy-exynos-mipi-video.c b/drivers/phy/phy-exynos-mipi-video.c index 7f139326a642..ff026689358c 100644 --- a/drivers/phy/phy-exynos-mipi-video.c +++ b/drivers/phy/phy-exynos-mipi-video.c @@ -101,7 +101,7 @@ static struct phy *exynos_mipi_video_phy_xlate(struct device *dev, { struct exynos_mipi_video_phy *state = dev_get_drvdata(dev); - if (WARN_ON(args->args[0] > EXYNOS_MIPI_PHYS_NUM)) + if (WARN_ON(args->args[0] >= EXYNOS_MIPI_PHYS_NUM)) return ERR_PTR(-ENODEV); return state->phys[args->args[0]].phy; diff --git a/drivers/phy/phy-exynos5-usbdrd.c b/drivers/phy/phy-exynos5-usbdrd.c new file mode 100644 index 000000000000..76d862b2202f --- /dev/null +++ b/drivers/phy/phy-exynos5-usbdrd.c @@ -0,0 +1,676 @@ +/* + * Samsung EXYNOS5 SoC series USB DRD PHY driver + * + * Phy provider for USB 3.0 DRD controller on Exynos5 SoC series + * + * Copyright (C) 2014 Samsung Electronics Co., Ltd. + * Author: Vivek Gautam <gautam.vivek@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/mutex.h> +#include <linux/mfd/syscon.h> +#include <linux/mfd/syscon/exynos5-pmu.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + +/* Exynos USB PHY registers */ +#define EXYNOS5_FSEL_9MHZ6 0x0 +#define EXYNOS5_FSEL_10MHZ 0x1 +#define EXYNOS5_FSEL_12MHZ 0x2 +#define EXYNOS5_FSEL_19MHZ2 0x3 +#define EXYNOS5_FSEL_20MHZ 0x4 +#define EXYNOS5_FSEL_24MHZ 0x5 +#define EXYNOS5_FSEL_50MHZ 0x7 + +/* EXYNOS5: USB 3.0 DRD PHY registers */ +#define EXYNOS5_DRD_LINKSYSTEM 0x04 + +#define LINKSYSTEM_FLADJ_MASK (0x3f << 1) +#define LINKSYSTEM_FLADJ(_x) ((_x) << 1) +#define LINKSYSTEM_XHCI_VERSION_CONTROL BIT(27) + +#define EXYNOS5_DRD_PHYUTMI 0x08 + +#define PHYUTMI_OTGDISABLE BIT(6) +#define PHYUTMI_FORCESUSPEND BIT(1) +#define PHYUTMI_FORCESLEEP BIT(0) + +#define EXYNOS5_DRD_PHYPIPE 0x0c + +#define EXYNOS5_DRD_PHYCLKRST 0x10 + +#define PHYCLKRST_EN_UTMISUSPEND BIT(31) + +#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 BIT(20) +#define PHYCLKRST_REF_SSP_EN BIT(19) +#define PHYCLKRST_REF_CLKDIV2 BIT(18) + +#define PHYCLKRST_MPLL_MULTIPLIER_MASK (0x7f << 11) +#define PHYCLKRST_MPLL_MULTIPLIER_100MHZ_REF (0x19 << 11) +#define PHYCLKRST_MPLL_MULTIPLIER_50M_REF (0x32 << 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_UTMI_MASK (0x7 << 5) +#define PHYCLKRST_FSEL_PIPE_MASK (0x7 << 8) +#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 BIT(4) + +#define PHYCLKRST_REFCLKSEL_MASK (0x03 << 2) +#define PHYCLKRST_REFCLKSEL_PAD_REFCLK (0x2 << 2) +#define PHYCLKRST_REFCLKSEL_EXT_REFCLK (0x3 << 2) + +#define PHYCLKRST_PORTRESET BIT(1) +#define PHYCLKRST_COMMONONN BIT(0) + +#define EXYNOS5_DRD_PHYREG0 0x14 +#define EXYNOS5_DRD_PHYREG1 0x18 + +#define EXYNOS5_DRD_PHYPARAM0 0x1c + +#define PHYPARAM0_REF_USE_PAD BIT(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 BIT(3) +#define PHYTEST_POWERDOWN_HSP BIT(2) + +#define EXYNOS5_DRD_PHYADP 0x2c + +#define EXYNOS5_DRD_PHYUTMICLKSEL 0x30 + +#define PHYUTMICLKSEL_UTMI_CLKSEL BIT(2) + +#define EXYNOS5_DRD_PHYRESUME 0x34 +#define EXYNOS5_DRD_LINKPORT 0x44 + +#define KHZ 1000 +#define MHZ (KHZ * KHZ) + +enum exynos5_usbdrd_phy_id { + EXYNOS5_DRDPHY_UTMI, + EXYNOS5_DRDPHY_PIPE3, + EXYNOS5_DRDPHYS_NUM, +}; + +struct phy_usb_instance; +struct exynos5_usbdrd_phy; + +struct exynos5_usbdrd_phy_config { + u32 id; + void (*phy_isol)(struct phy_usb_instance *inst, u32 on); + void (*phy_init)(struct exynos5_usbdrd_phy *phy_drd); + unsigned int (*set_refclk)(struct phy_usb_instance *inst); +}; + +struct exynos5_usbdrd_phy_drvdata { + const struct exynos5_usbdrd_phy_config *phy_cfg; + u32 pmu_offset_usbdrd0_phy; + u32 pmu_offset_usbdrd1_phy; +}; + +/** + * struct exynos5_usbdrd_phy - driver data for USB 3.0 PHY + * @dev: pointer to device instance of this platform device + * @reg_phy: usb phy controller register memory base + * @clk: phy clock for register access + * @drv_data: pointer to SoC level driver data structure + * @phys[]: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY + * instances each with its 'phy' and 'phy_cfg'. + * @extrefclk: frequency select settings when using 'separate + * reference clocks' for SS and HS operations + * @ref_clk: reference clock to PHY block from which PHY's + * operational clocks are derived + * @ref_rate: rate of above reference clock + */ +struct exynos5_usbdrd_phy { + struct device *dev; + void __iomem *reg_phy; + struct clk *clk; + const struct exynos5_usbdrd_phy_drvdata *drv_data; + struct phy_usb_instance { + struct phy *phy; + u32 index; + struct regmap *reg_pmu; + u32 pmu_offset; + const struct exynos5_usbdrd_phy_config *phy_cfg; + } phys[EXYNOS5_DRDPHYS_NUM]; + u32 extrefclk; + struct clk *ref_clk; + struct regulator *vbus; +}; + +static inline +struct exynos5_usbdrd_phy *to_usbdrd_phy(struct phy_usb_instance *inst) +{ + return container_of((inst), struct exynos5_usbdrd_phy, + phys[(inst)->index]); +} + +/* + * exynos5_rate_to_clk() converts the supplied clock rate to the value that + * can be written to the phy register. + */ +static unsigned int exynos5_rate_to_clk(unsigned long rate, u32 *reg) +{ + /* EXYNOS5_FSEL_MASK */ + + switch (rate) { + case 9600 * KHZ: + *reg = EXYNOS5_FSEL_9MHZ6; + break; + case 10 * MHZ: + *reg = EXYNOS5_FSEL_10MHZ; + break; + case 12 * MHZ: + *reg = EXYNOS5_FSEL_12MHZ; + break; + case 19200 * KHZ: + *reg = EXYNOS5_FSEL_19MHZ2; + break; + case 20 * MHZ: + *reg = EXYNOS5_FSEL_20MHZ; + break; + case 24 * MHZ: + *reg = EXYNOS5_FSEL_24MHZ; + break; + case 50 * MHZ: + *reg = EXYNOS5_FSEL_50MHZ; + break; + default: + return -EINVAL; + } + + return 0; +} + +static void exynos5_usbdrd_phy_isol(struct phy_usb_instance *inst, + unsigned int on) +{ + unsigned int val; + + if (!inst->reg_pmu) + return; + + val = on ? 0 : EXYNOS5_PHY_ENABLE; + + regmap_update_bits(inst->reg_pmu, inst->pmu_offset, + EXYNOS5_PHY_ENABLE, val); +} + +/* + * Sets the pipe3 phy's clk as EXTREFCLK (XXTI) which is internal clock + * from clock core. Further sets multiplier values and spread spectrum + * clock settings for SuperSpeed operations. + */ +static unsigned int +exynos5_usbdrd_pipe3_set_refclk(struct phy_usb_instance *inst) +{ + static u32 reg; + struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); + + /* restore any previous reference clock settings */ + reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST); + + /* Use EXTREFCLK as ref clock */ + reg &= ~PHYCLKRST_REFCLKSEL_MASK; + reg |= PHYCLKRST_REFCLKSEL_EXT_REFCLK; + + /* FSEL settings corresponding to reference clock */ + reg &= ~PHYCLKRST_FSEL_PIPE_MASK | + PHYCLKRST_MPLL_MULTIPLIER_MASK | + PHYCLKRST_SSC_REFCLKSEL_MASK; + switch (phy_drd->extrefclk) { + case EXYNOS5_FSEL_50MHZ: + reg |= (PHYCLKRST_MPLL_MULTIPLIER_50M_REF | + PHYCLKRST_SSC_REFCLKSEL(0x00)); + break; + case EXYNOS5_FSEL_24MHZ: + reg |= (PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF | + PHYCLKRST_SSC_REFCLKSEL(0x88)); + break; + case EXYNOS5_FSEL_20MHZ: + reg |= (PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF | + PHYCLKRST_SSC_REFCLKSEL(0x00)); + break; + case EXYNOS5_FSEL_19MHZ2: + reg |= (PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF | + PHYCLKRST_SSC_REFCLKSEL(0x88)); + break; + default: + dev_dbg(phy_drd->dev, "unsupported ref clk\n"); + break; + } + + return reg; +} + +/* + * Sets the utmi phy's clk as EXTREFCLK (XXTI) which is internal clock + * from clock core. Further sets the FSEL values for HighSpeed operations. + */ +static unsigned int +exynos5_usbdrd_utmi_set_refclk(struct phy_usb_instance *inst) +{ + static u32 reg; + struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); + + /* restore any previous reference clock settings */ + reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST); + + reg &= ~PHYCLKRST_REFCLKSEL_MASK; + reg |= PHYCLKRST_REFCLKSEL_EXT_REFCLK; + + reg &= ~PHYCLKRST_FSEL_UTMI_MASK | + PHYCLKRST_MPLL_MULTIPLIER_MASK | + PHYCLKRST_SSC_REFCLKSEL_MASK; + reg |= PHYCLKRST_FSEL(phy_drd->extrefclk); + + return reg; +} + +static void exynos5_usbdrd_pipe3_init(struct exynos5_usbdrd_phy *phy_drd) +{ + u32 reg; + + reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1); + /* Set Tx De-Emphasis level */ + reg &= ~PHYPARAM1_PCS_TXDEEMPH_MASK; + reg |= PHYPARAM1_PCS_TXDEEMPH; + writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1); + + reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST); + reg &= ~PHYTEST_POWERDOWN_SSP; + writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST); +} + +static void exynos5_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd) +{ + u32 reg; + + reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0); + /* Set Loss-of-Signal Detector sensitivity */ + reg &= ~PHYPARAM0_REF_LOSLEVEL_MASK; + reg |= PHYPARAM0_REF_LOSLEVEL; + writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0); + + reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1); + /* Set Tx De-Emphasis level */ + reg &= ~PHYPARAM1_PCS_TXDEEMPH_MASK; + reg |= PHYPARAM1_PCS_TXDEEMPH; + writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1); + + /* UTMI Power Control */ + writel(PHYUTMI_OTGDISABLE, phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMI); + + reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST); + reg &= ~PHYTEST_POWERDOWN_HSP; + writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST); +} + +static int exynos5_usbdrd_phy_init(struct phy *phy) +{ + int ret; + u32 reg; + struct phy_usb_instance *inst = phy_get_drvdata(phy); + struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); + + ret = clk_prepare_enable(phy_drd->clk); + if (ret) + return ret; + + /* Reset USB 3.0 PHY */ + writel(0x0, phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0); + writel(0x0, phy_drd->reg_phy + EXYNOS5_DRD_PHYRESUME); + + /* + * Setting the Frame length Adj value[6:1] to default 0x20 + * See xHCI 1.0 spec, 5.2.4 + */ + reg = LINKSYSTEM_XHCI_VERSION_CONTROL | + LINKSYSTEM_FLADJ(0x20); + writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_LINKSYSTEM); + + reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0); + /* Select PHY CLK source */ + reg &= ~PHYPARAM0_REF_USE_PAD; + writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0); + + /* This bit must be set for both HS and SS operations */ + reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMICLKSEL); + reg |= PHYUTMICLKSEL_UTMI_CLKSEL; + writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMICLKSEL); + + /* UTMI or PIPE3 specific init */ + inst->phy_cfg->phy_init(phy_drd); + + /* reference clock settings */ + reg = inst->phy_cfg->set_refclk(inst); + + /* Digital power supply in normal operating mode */ + reg |= 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 | + /* Reset the port */ + PHYCLKRST_PORTRESET; + + writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST); + + udelay(10); + + reg &= ~PHYCLKRST_PORTRESET; + writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST); + + clk_disable_unprepare(phy_drd->clk); + + return 0; +} + +static int exynos5_usbdrd_phy_exit(struct phy *phy) +{ + int ret; + u32 reg; + struct phy_usb_instance *inst = phy_get_drvdata(phy); + struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); + + ret = clk_prepare_enable(phy_drd->clk); + if (ret) + return ret; + + reg = PHYUTMI_OTGDISABLE | + PHYUTMI_FORCESUSPEND | + PHYUTMI_FORCESLEEP; + writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMI); + + /* Resetting the PHYCLKRST enable bits to reduce leakage current */ + reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST); + reg &= ~(PHYCLKRST_REF_SSP_EN | + PHYCLKRST_SSC_EN | + PHYCLKRST_COMMONONN); + writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST); + + /* Control PHYTEST to remove leakage current */ + reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST); + reg |= PHYTEST_POWERDOWN_SSP | + PHYTEST_POWERDOWN_HSP; + writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST); + + clk_disable_unprepare(phy_drd->clk); + + return 0; +} + +static int exynos5_usbdrd_phy_power_on(struct phy *phy) +{ + int ret; + struct phy_usb_instance *inst = phy_get_drvdata(phy); + struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); + + dev_dbg(phy_drd->dev, "Request to power_on usbdrd_phy phy\n"); + + clk_prepare_enable(phy_drd->ref_clk); + + /* Enable VBUS supply */ + if (phy_drd->vbus) { + ret = regulator_enable(phy_drd->vbus); + if (ret) { + dev_err(phy_drd->dev, "Failed to enable VBUS supply\n"); + goto fail_vbus; + } + } + + /* Power-on PHY*/ + inst->phy_cfg->phy_isol(inst, 0); + + return 0; + +fail_vbus: + clk_disable_unprepare(phy_drd->ref_clk); + + return ret; +} + +static int exynos5_usbdrd_phy_power_off(struct phy *phy) +{ + struct phy_usb_instance *inst = phy_get_drvdata(phy); + struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); + + dev_dbg(phy_drd->dev, "Request to power_off usbdrd_phy phy\n"); + + /* Power-off the PHY */ + inst->phy_cfg->phy_isol(inst, 1); + + /* Disable VBUS supply */ + if (phy_drd->vbus) + regulator_disable(phy_drd->vbus); + + clk_disable_unprepare(phy_drd->ref_clk); + + return 0; +} + +static struct phy *exynos5_usbdrd_phy_xlate(struct device *dev, + struct of_phandle_args *args) +{ + struct exynos5_usbdrd_phy *phy_drd = dev_get_drvdata(dev); + + if (WARN_ON(args->args[0] > EXYNOS5_DRDPHYS_NUM)) + return ERR_PTR(-ENODEV); + + return phy_drd->phys[args->args[0]].phy; +} + +static struct phy_ops exynos5_usbdrd_phy_ops = { + .init = exynos5_usbdrd_phy_init, + .exit = exynos5_usbdrd_phy_exit, + .power_on = exynos5_usbdrd_phy_power_on, + .power_off = exynos5_usbdrd_phy_power_off, + .owner = THIS_MODULE, +}; + +const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = { + { + .id = EXYNOS5_DRDPHY_UTMI, + .phy_isol = exynos5_usbdrd_phy_isol, + .phy_init = exynos5_usbdrd_utmi_init, + .set_refclk = exynos5_usbdrd_utmi_set_refclk, + }, + { + .id = EXYNOS5_DRDPHY_PIPE3, + .phy_isol = exynos5_usbdrd_phy_isol, + .phy_init = exynos5_usbdrd_pipe3_init, + .set_refclk = exynos5_usbdrd_pipe3_set_refclk, + }, +}; + +const struct exynos5_usbdrd_phy_drvdata exynos5420_usbdrd_phy = { + .phy_cfg = phy_cfg_exynos5, + .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, + .pmu_offset_usbdrd1_phy = EXYNOS5420_USBDRD1_PHY_CONTROL, +}; + +const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = { + .phy_cfg = phy_cfg_exynos5, + .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, +}; + +static const struct of_device_id exynos5_usbdrd_phy_of_match[] = { + { + .compatible = "samsung,exynos5250-usbdrd-phy", + .data = &exynos5250_usbdrd_phy + }, { + .compatible = "samsung,exynos5420-usbdrd-phy", + .data = &exynos5420_usbdrd_phy + }, + { }, +}; + +static int exynos5_usbdrd_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct exynos5_usbdrd_phy *phy_drd; + struct phy_provider *phy_provider; + struct resource *res; + const struct of_device_id *match; + const struct exynos5_usbdrd_phy_drvdata *drv_data; + struct regmap *reg_pmu; + u32 pmu_offset; + unsigned long ref_rate; + int i, ret; + int channel; + + phy_drd = devm_kzalloc(dev, sizeof(*phy_drd), GFP_KERNEL); + if (!phy_drd) + return -ENOMEM; + + dev_set_drvdata(dev, phy_drd); + phy_drd->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + phy_drd->reg_phy = devm_ioremap_resource(dev, res); + if (IS_ERR(phy_drd->reg_phy)) + return PTR_ERR(phy_drd->reg_phy); + + match = of_match_node(exynos5_usbdrd_phy_of_match, pdev->dev.of_node); + + drv_data = match->data; + phy_drd->drv_data = drv_data; + + phy_drd->clk = devm_clk_get(dev, "phy"); + if (IS_ERR(phy_drd->clk)) { + dev_err(dev, "Failed to get clock of phy controller\n"); + return PTR_ERR(phy_drd->clk); + } + + phy_drd->ref_clk = devm_clk_get(dev, "ref"); + if (IS_ERR(phy_drd->ref_clk)) { + dev_err(dev, "Failed to get reference clock of usbdrd phy\n"); + return PTR_ERR(phy_drd->ref_clk); + } + ref_rate = clk_get_rate(phy_drd->ref_clk); + + ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk); + if (ret) { + dev_err(phy_drd->dev, "Clock rate (%ld) not supported\n", + ref_rate); + return ret; + } + + reg_pmu = syscon_regmap_lookup_by_phandle(dev->of_node, + "samsung,pmu-syscon"); + if (IS_ERR(reg_pmu)) { + dev_err(dev, "Failed to lookup PMU regmap\n"); + return PTR_ERR(reg_pmu); + } + + /* + * Exynos5420 SoC has multiple channels for USB 3.0 PHY, with + * each having separate power control registers. + * 'channel' facilitates to set such registers. + */ + channel = of_alias_get_id(node, "usbdrdphy"); + if (channel < 0) + dev_dbg(dev, "Not a multi-controller usbdrd phy\n"); + + switch (channel) { + case 1: + pmu_offset = phy_drd->drv_data->pmu_offset_usbdrd1_phy; + break; + case 0: + default: + pmu_offset = phy_drd->drv_data->pmu_offset_usbdrd0_phy; + break; + } + + /* Get Vbus regulator */ + phy_drd->vbus = devm_regulator_get(dev, "vbus"); + if (IS_ERR(phy_drd->vbus)) { + ret = PTR_ERR(phy_drd->vbus); + if (ret == -EPROBE_DEFER) + return ret; + + dev_warn(dev, "Failed to get VBUS supply regulator\n"); + phy_drd->vbus = NULL; + } + + dev_vdbg(dev, "Creating usbdrd_phy phy\n"); + + for (i = 0; i < EXYNOS5_DRDPHYS_NUM; i++) { + struct phy *phy = devm_phy_create(dev, &exynos5_usbdrd_phy_ops, + NULL); + if (IS_ERR(phy)) { + dev_err(dev, "Failed to create usbdrd_phy phy\n"); + return PTR_ERR(phy); + } + + phy_drd->phys[i].phy = phy; + phy_drd->phys[i].index = i; + phy_drd->phys[i].reg_pmu = reg_pmu; + phy_drd->phys[i].pmu_offset = pmu_offset; + phy_drd->phys[i].phy_cfg = &drv_data->phy_cfg[i]; + phy_set_drvdata(phy, &phy_drd->phys[i]); + } + + phy_provider = devm_of_phy_provider_register(dev, + exynos5_usbdrd_phy_xlate); + if (IS_ERR(phy_provider)) { + dev_err(phy_drd->dev, "Failed to register phy provider\n"); + return PTR_ERR(phy_provider); + } + + return 0; +} + +static struct platform_driver exynos5_usb3drd_phy = { + .probe = exynos5_usbdrd_phy_probe, + .driver = { + .of_match_table = exynos5_usbdrd_phy_of_match, + .name = "exynos5_usb3drd_phy", + .owner = THIS_MODULE, + } +}; + +module_platform_driver(exynos5_usb3drd_phy); +MODULE_DESCRIPTION("Samsung EXYNOS5 SoCs USB 3.0 DRD controller PHY driver"); +MODULE_AUTHOR("Vivek Gautam <gautam.vivek@samsung.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:exynos5_usb3drd_phy"); diff --git a/drivers/phy/phy-exynos5250-sata.c b/drivers/phy/phy-exynos5250-sata.c index c9361b731fa6..05689450f93b 100644 --- a/drivers/phy/phy-exynos5250-sata.c +++ b/drivers/phy/phy-exynos5250-sata.c @@ -246,6 +246,6 @@ static struct platform_driver exynos_sata_phy_driver = { module_platform_driver(exynos_sata_phy_driver); MODULE_DESCRIPTION("Samsung SerDes PHY driver"); -MODULE_LICENSE("GPL V2"); +MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Girish K S <ks.giri@samsung.com>"); MODULE_AUTHOR("Yuvaraj C D <yuvaraj.cd@samsung.com>"); diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c index a2205a841e5e..7007c11fe07d 100644 --- a/drivers/phy/phy-omap-usb2.c +++ b/drivers/phy/phy-omap-usb2.c @@ -275,18 +275,34 @@ static int omap_usb2_probe(struct platform_device *pdev) if (IS_ERR(phy_provider)) return PTR_ERR(phy_provider); - phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k"); + phy->wkupclk = devm_clk_get(phy->dev, "wkupclk"); if (IS_ERR(phy->wkupclk)) { - dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n"); - return PTR_ERR(phy->wkupclk); + dev_warn(&pdev->dev, "unable to get wkupclk, trying old name\n"); + phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k"); + if (IS_ERR(phy->wkupclk)) { + dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n"); + return PTR_ERR(phy->wkupclk); + } else { + dev_warn(&pdev->dev, + "found usb_phy_cm_clk32k, please fix DTS\n"); + } } clk_prepare(phy->wkupclk); - phy->optclk = devm_clk_get(phy->dev, "usb_otg_ss_refclk960m"); - if (IS_ERR(phy->optclk)) - dev_vdbg(&pdev->dev, "unable to get refclk960m\n"); - else + phy->optclk = devm_clk_get(phy->dev, "refclk"); + if (IS_ERR(phy->optclk)) { + dev_dbg(&pdev->dev, "unable to get refclk, trying old name\n"); + phy->optclk = devm_clk_get(phy->dev, "usb_otg_ss_refclk960m"); + if (IS_ERR(phy->optclk)) { + dev_dbg(&pdev->dev, + "unable to get usb_otg_ss_refclk960m\n"); + } else { + dev_warn(&pdev->dev, + "found usb_otg_ss_refclk960m, please fix DTS\n"); + } + } else { clk_prepare(phy->optclk); + } usb_add_phy_dev(&phy->phy); diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index e6e6c4ba7145..115d8d5190d5 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -61,7 +61,6 @@ #define MAX_PHYS 3 struct sun4i_usb_phy_data { - struct clk *clk; void __iomem *base; struct mutex mutex; int num_phys; @@ -71,6 +70,7 @@ struct sun4i_usb_phy_data { void __iomem *pmu; struct regulator *vbus; struct reset_control *reset; + struct clk *clk; int index; } phys[MAX_PHYS]; }; @@ -146,13 +146,13 @@ static int sun4i_usb_phy_init(struct phy *_phy) struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy); int ret; - ret = clk_prepare_enable(data->clk); + ret = clk_prepare_enable(phy->clk); if (ret) return ret; ret = reset_control_deassert(phy->reset); if (ret) { - clk_disable_unprepare(data->clk); + clk_disable_unprepare(phy->clk); return ret; } @@ -170,11 +170,10 @@ static int sun4i_usb_phy_init(struct phy *_phy) static int sun4i_usb_phy_exit(struct phy *_phy) { struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); - struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy); sun4i_usb_phy_passby(phy, 0); reset_control_assert(phy->reset); - clk_disable_unprepare(data->clk); + clk_disable_unprepare(phy->clk); return 0; } @@ -224,13 +223,9 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) struct sun4i_usb_phy_data *data; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - void __iomem *pmu = NULL; struct phy_provider *phy_provider; - struct reset_control *reset; - struct regulator *vbus; + bool dedicated_clocks; struct resource *res; - struct phy *phy; - char name[16]; int i; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); @@ -249,55 +244,64 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) else data->disc_thresh = 2; + if (of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy")) + dedicated_clocks = true; + else + dedicated_clocks = false; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl"); data->base = devm_ioremap_resource(dev, res); if (IS_ERR(data->base)) return PTR_ERR(data->base); - data->clk = devm_clk_get(dev, "usb_phy"); - if (IS_ERR(data->clk)) { - dev_err(dev, "could not get usb_phy clock\n"); - return PTR_ERR(data->clk); - } - /* Skip 0, 0 is the phy for otg which is not yet supported. */ for (i = 1; i < data->num_phys; i++) { + struct sun4i_usb_phy *phy = data->phys + i; + char name[16]; + snprintf(name, sizeof(name), "usb%d_vbus", i); - vbus = devm_regulator_get_optional(dev, name); - if (IS_ERR(vbus)) { - if (PTR_ERR(vbus) == -EPROBE_DEFER) + phy->vbus = devm_regulator_get_optional(dev, name); + if (IS_ERR(phy->vbus)) { + if (PTR_ERR(phy->vbus) == -EPROBE_DEFER) return -EPROBE_DEFER; - vbus = NULL; + phy->vbus = NULL; + } + + if (dedicated_clocks) + snprintf(name, sizeof(name), "usb%d_phy", i); + else + strlcpy(name, "usb_phy", sizeof(name)); + + phy->clk = devm_clk_get(dev, name); + if (IS_ERR(phy->clk)) { + dev_err(dev, "failed to get clock %s\n", name); + return PTR_ERR(phy->clk); } snprintf(name, sizeof(name), "usb%d_reset", i); - reset = devm_reset_control_get(dev, name); - if (IS_ERR(reset)) { + phy->reset = devm_reset_control_get(dev, name); + if (IS_ERR(phy->reset)) { dev_err(dev, "failed to get reset %s\n", name); - return PTR_ERR(reset); + return PTR_ERR(phy->reset); } if (i) { /* No pmu for usbc0 */ snprintf(name, sizeof(name), "pmu%d", i); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); - pmu = devm_ioremap_resource(dev, res); - if (IS_ERR(pmu)) - return PTR_ERR(pmu); + phy->pmu = devm_ioremap_resource(dev, res); + if (IS_ERR(phy->pmu)) + return PTR_ERR(phy->pmu); } - phy = devm_phy_create(dev, &sun4i_usb_phy_ops, NULL); - if (IS_ERR(phy)) { + phy->phy = devm_phy_create(dev, &sun4i_usb_phy_ops, NULL); + if (IS_ERR(phy->phy)) { dev_err(dev, "failed to create PHY %d\n", i); - return PTR_ERR(phy); + return PTR_ERR(phy->phy); } - data->phys[i].phy = phy; - data->phys[i].pmu = pmu; - data->phys[i].vbus = vbus; - data->phys[i].reset = reset; - data->phys[i].index = i; - phy_set_drvdata(phy, &data->phys[i]); + phy->index = i; + phy_set_drvdata(phy->phy, &data->phys[i]); } dev_set_drvdata(dev, data); @@ -311,6 +315,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) static const struct of_device_id sun4i_usb_phy_of_match[] = { { .compatible = "allwinner,sun4i-a10-usb-phy" }, { .compatible = "allwinner,sun5i-a13-usb-phy" }, + { .compatible = "allwinner,sun6i-a31-usb-phy" }, { .compatible = "allwinner,sun7i-a20-usb-phy" }, { }, }; diff --git a/drivers/staging/media/lirc/lirc_igorplugusb.c b/drivers/staging/media/lirc/lirc_igorplugusb.c index f508a1372ad8..44b0d0766084 100644 --- a/drivers/staging/media/lirc/lirc_igorplugusb.c +++ b/drivers/staging/media/lirc/lirc_igorplugusb.c @@ -60,19 +60,6 @@ #define DRIVER_DESC "Igorplug USB remote driver for LIRC" #define DRIVER_NAME "lirc_igorplugusb" -/* debugging support */ -#ifdef CONFIG_USB_DEBUG -static bool debug = true; -#else -static bool debug; -#endif - -#define dprintk(fmt, args...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG fmt, ## args); \ - } while (0) - /* One mode2 pulse/space has 4 bytes. */ #define CODE_LENGTH sizeof(int) @@ -237,7 +224,7 @@ static int unregister_from_lirc(struct igorplug *ir) return -EINVAL; } - dprintk(DRIVER_NAME "[%d]: calling lirc_unregister_driver\n", devnum); + dev_dbg(&ir->usbdev->dev, "calling lirc_unregister_driver\n"); lirc_unregister_driver(d->minor); return devnum; @@ -252,7 +239,7 @@ static int set_use_inc(void *data) return -EIO; } - dprintk(DRIVER_NAME "[%d]: set use inc\n", ir->devnum); + dev_dbg(&ir->usbdev->dev, "set use inc\n"); if (!ir->usbdev) return -ENODEV; @@ -269,7 +256,7 @@ static void set_use_dec(void *data) return; } - dprintk(DRIVER_NAME "[%d]: set use dec\n", ir->devnum); + dev_dbg(&ir->usbdev->dev, "set use dec\n"); } static void send_fragment(struct igorplug *ir, struct lirc_buffer *buf, @@ -321,7 +308,7 @@ static int igorplugusb_remote_poll(void *data, struct lirc_buffer *buf) if (ret < DEVICE_HEADERLEN) return -ENODATA; - dprintk(DRIVER_NAME ": Got %d bytes. Header: %*ph\n", + dev_dbg(&ir->usbdev->dev, "Got %d bytes. Header: %*ph\n", ret, 3, ir->buf_in); do_gettimeofday(&now); @@ -385,7 +372,7 @@ static int igorplugusb_remote_probe(struct usb_interface *intf, char buf[63], name[128] = ""; int ret; - dprintk(DRIVER_NAME ": usb probe called.\n"); + dev_dbg(&intf->dev, "%s: usb probe called.\n", __func__); dev = interface_to_usbdev(intf); @@ -405,8 +392,8 @@ static int igorplugusb_remote_probe(struct usb_interface *intf, devnum = dev->devnum; maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); - dprintk(DRIVER_NAME "[%d]: bytes_in_key=%zu maxp=%d\n", - devnum, CODE_LENGTH, maxp); + dev_dbg(&intf->dev, "%s: bytes_in_key=%zu maxp=%d\n", + __func__, CODE_LENGTH, maxp); ir = devm_kzalloc(&intf->dev, sizeof(*ir), GFP_KERNEL); if (!ir) @@ -525,6 +512,3 @@ MODULE_DEVICE_TABLE(usb, igorplugusb_remote_id_table); module_param(sample_rate, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(sample_rate, "Sampling rate in Hz (default: 100)"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/staging/usbip/userspace/README b/drivers/staging/usbip/userspace/README index f528ba462b5f..831f49fea3ce 100644 --- a/drivers/staging/usbip/userspace/README +++ b/drivers/staging/usbip/userspace/README @@ -195,7 +195,6 @@ Detach the imported device: - Shutdown firewall. - usbip now uses TCP port 3240. - Disable SELinux. - - If possible, compile your kernel with CONFIG_USB_DEBUG flag and try again. - Check the kernel and daemon messages. diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 1ae2bf39d84b..3cba892b83a2 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_USB_IMX21_HCD) += host/ obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/ obj-$(CONFIG_USB_FUSBH200_HCD) += host/ obj-$(CONFIG_USB_FOTG210_HCD) += host/ +obj-$(CONFIG_USB_MAX3421_HCD) += host/ obj-$(CONFIG_USB_C67X00_HCD) += c67x00/ @@ -58,4 +59,4 @@ obj-$(CONFIG_USB_CHIPIDEA) += chipidea/ obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/ obj-$(CONFIG_USB_GADGET) += gadget/ -obj-$(CONFIG_USB_COMMON) += usb-common.o +obj-$(CONFIG_USB_COMMON) += common/ diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index 480bd4d5710a..2f099c7df7b5 100644 --- a/drivers/usb/chipidea/Makefile +++ b/drivers/usb/chipidea/Makefile @@ -6,6 +6,7 @@ ci_hdrc-y := core.o otg.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC) += udc.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST) += host.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG) += debug.o +ci_hdrc-$(CONFIG_USB_OTG_FSM) += otg_fsm.o # Glue/Bridge layers go here diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h index 83d06c1455b7..ca57e3dcd3d5 100644 --- a/drivers/usb/chipidea/bits.h +++ b/drivers/usb/chipidea/bits.h @@ -44,9 +44,14 @@ #define DEVICEADDR_USBADR (0x7FUL << 25) /* PORTSC */ +#define PORTSC_CCS BIT(0) +#define PORTSC_CSC BIT(1) +#define PORTSC_PEC BIT(3) +#define PORTSC_OCC BIT(5) #define PORTSC_FPR BIT(6) #define PORTSC_SUSP BIT(7) #define PORTSC_HSP BIT(9) +#define PORTSC_PP BIT(12) #define PORTSC_PTC (0x0FUL << 16) #define PORTSC_PHCD(d) ((d) ? BIT(22) : BIT(23)) /* PTS and PTW for non lpm version only */ @@ -56,6 +61,9 @@ #define PORTSC_PTW BIT(28) #define PORTSC_STS BIT(29) +#define PORTSC_W1C_BITS \ + (PORTSC_CSC | PORTSC_PEC | PORTSC_OCC) + /* DEVLC */ #define DEVLC_PFSC BIT(23) #define DEVLC_PSPD (0x03UL << 25) @@ -72,6 +80,8 @@ /* OTGSC */ #define OTGSC_IDPU BIT(5) +#define OTGSC_HADP BIT(6) +#define OTGSC_HABA BIT(7) #define OTGSC_ID BIT(8) #define OTGSC_AVV BIT(9) #define OTGSC_ASV BIT(10) diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index e206406ae1d9..9563cb56d564 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -17,6 +17,7 @@ #include <linux/irqreturn.h> #include <linux/usb.h> #include <linux/usb/gadget.h> +#include <linux/usb/otg-fsm.h> /****************************************************************************** * DEFINE @@ -139,6 +140,8 @@ struct hw_bank { * @roles: array of supported roles for this controller * @role: current role * @is_otg: if the device is otg-capable + * @fsm: otg finite state machine + * @fsm_timer: pointer to timer list of otg fsm * @work: work for role changing * @wq: workqueue thread * @qh_pool: allocation pool for queue heads @@ -174,6 +177,8 @@ struct ci_hdrc { struct ci_role_driver *roles[CI_ROLE_END]; enum ci_role role; bool is_otg; + struct otg_fsm fsm; + struct ci_otg_fsm_timer_list *fsm_timer; struct work_struct work; struct workqueue_struct *wq; @@ -319,6 +324,24 @@ static inline u32 hw_test_and_write(struct ci_hdrc *ci, enum ci_hw_regs reg, return (val & mask) >> __ffs(mask); } +/** + * ci_otg_is_fsm_mode: runtime check if otg controller + * is in otg fsm mode. + */ +static inline bool ci_otg_is_fsm_mode(struct ci_hdrc *ci) +{ +#ifdef CONFIG_USB_OTG_FSM + return ci->is_otg && ci->roles[CI_ROLE_HOST] && + ci->roles[CI_ROLE_GADGET]; +#else + return false; +#endif +} + +u32 hw_read_intr_enable(struct ci_hdrc *ci); + +u32 hw_read_intr_status(struct ci_hdrc *ci); + int hw_device_reset(struct ci_hdrc *ci, u32 mode); int hw_port_test_set(struct ci_hdrc *ci, u8 mode); diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c index 2d51d852b474..d72b9d2de2c5 100644 --- a/drivers/usb/chipidea/ci_hdrc_msm.c +++ b/drivers/usb/chipidea/ci_hdrc_msm.c @@ -47,6 +47,7 @@ static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event) static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = { .name = "ci_hdrc_msm", + .capoffset = DEF_CAPOFFSET, .flags = CI_HDRC_REGS_SHARED | CI_HDRC_REQUIRE_TRANSCEIVER | CI_HDRC_DISABLE_STREAMING, @@ -57,9 +58,21 @@ static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = { static int ci_hdrc_msm_probe(struct platform_device *pdev) { struct platform_device *plat_ci; + struct usb_phy *phy; dev_dbg(&pdev->dev, "ci_hdrc_msm_probe\n"); + /* + * OTG(PHY) driver takes care of PHY initialization, clock management, + * powering up VBUS, mapping of registers address space and power + * management. + */ + phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); + if (IS_ERR(phy)) + return PTR_ERR(phy); + + ci_hdrc_msm_platdata.phy = phy; + plat_ci = ci_hdrc_add_device(&pdev->dev, pdev->resource, pdev->num_resources, &ci_hdrc_msm_platdata); @@ -86,10 +99,19 @@ static int ci_hdrc_msm_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id msm_ci_dt_match[] = { + { .compatible = "qcom,ci-hdrc", }, + { } +}; +MODULE_DEVICE_TABLE(of, msm_ci_dt_match); + static struct platform_driver ci_hdrc_msm_driver = { .probe = ci_hdrc_msm_probe, .remove = ci_hdrc_msm_remove, - .driver = { .name = "msm_hsusb", }, + .driver = { + .name = "msm_hsusb", + .of_match_table = msm_ci_dt_match, + }, }; module_platform_driver(ci_hdrc_msm_driver); diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 1cd5d0ba587c..619d13e29995 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -23,7 +23,7 @@ * - BUS: bus glue code, bus abstraction layer * * Compile Options - * - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities + * - CONFIG_USB_CHIPIDEA_DEBUG: enable debug facilities * - STALL_IN: non-empty bulk-in pipes cannot be halted * if defined mass storage compliance succeeds but with warnings * => case 4: Hi > Dn @@ -42,10 +42,6 @@ * - Not Supported: 15 & 16 (ISO) * * TODO List - * - OTG - * - Interrupt Traffic - * - GET_STATUS(device) - always reports 0 - * - Gadget API (majority of optional features) * - Suspend & Remote Wakeup */ #include <linux/delay.h> @@ -74,6 +70,7 @@ #include "host.h" #include "debug.h" #include "otg.h" +#include "otg_fsm.h" /* Controller register map */ static const u8 ci_regs_nolpm[] = { @@ -140,6 +137,26 @@ static int hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm) } /** + * hw_read_intr_enable: returns interrupt enable register + * + * This function returns register data + */ +u32 hw_read_intr_enable(struct ci_hdrc *ci) +{ + return hw_read(ci, OP_USBINTR, ~0); +} + +/** + * hw_read_intr_status: returns interrupt status register + * + * This function returns register data + */ +u32 hw_read_intr_status(struct ci_hdrc *ci) +{ + return hw_read(ci, OP_USBSTS, ~0); +} + +/** * hw_port_test_set: writes port test mode (execute without interruption) * @mode: new value * @@ -179,11 +196,10 @@ static void ci_hdrc_enter_lpm(struct ci_hdrc *ci, bool enable) hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm), 0); /* - * The controller needs at least 1ms to reflect - * PHY's status, the PHY also needs some time (less + * the PHY needs some time (less * than 1ms) to leave low power mode. */ - usleep_range(1500, 2000); + usleep_range(1000, 1100); } } @@ -392,8 +408,14 @@ static irqreturn_t ci_irq(int irq, void *data) irqreturn_t ret = IRQ_NONE; u32 otgsc = 0; - if (ci->is_otg) - otgsc = hw_read(ci, OP_OTGSC, ~0); + if (ci->is_otg) { + otgsc = hw_read_otgsc(ci, ~0); + if (ci_otg_is_fsm_mode(ci)) { + ret = ci_otg_fsm_irq(ci); + if (ret == IRQ_HANDLED) + return ret; + } + } /* * Handle id change interrupt, it indicates device/host function @@ -401,9 +423,9 @@ static irqreturn_t ci_irq(int irq, void *data) */ if (ci->is_otg && (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) { ci->id_event = true; - ci_clear_otg_interrupt(ci, OTGSC_IDIS); - disable_irq_nosync(ci->irq); - queue_work(ci->wq, &ci->work); + /* Clear ID change irq status */ + hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS); + ci_otg_queue_work(ci); return IRQ_HANDLED; } @@ -413,9 +435,9 @@ static irqreturn_t ci_irq(int irq, void *data) */ if (ci->is_otg && (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) { ci->b_sess_valid_event = true; - ci_clear_otg_interrupt(ci, OTGSC_BSVIS); - disable_irq_nosync(ci->irq); - queue_work(ci->wq, &ci->work); + /* Clear BSV irq */ + hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS); + ci_otg_queue_work(ci); return IRQ_HANDLED; } @@ -533,11 +555,8 @@ static void ci_get_otg_capable(struct ci_hdrc *ci) ci->is_otg = (hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DC | DCCPARAMS_HC) == (DCCPARAMS_DC | DCCPARAMS_HC)); - if (ci->is_otg) { + if (ci->is_otg) dev_dbg(ci->dev, "It is OTG capable controller\n"); - ci_disable_otg_interrupt(ci, OTGSC_INT_EN_BITS); - ci_clear_otg_interrupt(ci, OTGSC_INT_STATUS_BITS); - } } static int ci_hdrc_probe(struct platform_device *pdev) @@ -599,6 +618,13 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (ret) { dev_err(dev, "unable to init phy: %d\n", ret); return ret; + } else { + /* + * The delay to sync PHY's status, the maximum delay is + * 2ms since the otgsc uses 1ms timer to debounce the + * PHY's input + */ + usleep_range(2000, 2500); } ci->hw_bank.phys = res->start; @@ -633,6 +659,9 @@ static int ci_hdrc_probe(struct platform_device *pdev) } if (ci->is_otg) { + /* Disable and clear all OTG irq */ + hw_write_otgsc(ci, OTGSC_INT_EN_BITS | OTGSC_INT_STATUS_BITS, + OTGSC_INT_STATUS_BITS); ret = ci_hdrc_otg_init(ci); if (ret) { dev_err(dev, "init otg fails, ret = %d\n", ret); @@ -642,13 +671,9 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) { if (ci->is_otg) { - /* - * ID pin needs 1ms debouce time, - * we delay 2ms for safe. - */ - mdelay(2); ci->role = ci_otg_role(ci); - ci_enable_otg_interrupt(ci, OTGSC_IDIE); + /* Enable ID change irq */ + hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE); } else { /* * If the controller is not OTG capable, but support @@ -667,10 +692,13 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (ci->role == CI_ROLE_GADGET) ci_handle_vbus_change(ci); - ret = ci_role_start(ci, ci->role); - if (ret) { - dev_err(dev, "can't start %s role\n", ci_role(ci)->name); - goto stop; + if (!ci_otg_is_fsm_mode(ci)) { + ret = ci_role_start(ci, ci->role); + if (ret) { + dev_err(dev, "can't start %s role\n", + ci_role(ci)->name); + goto stop; + } } platform_set_drvdata(pdev, ci); @@ -679,6 +707,9 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (ret) goto stop; + if (ci_otg_is_fsm_mode(ci)) + ci_hdrc_otg_fsm_start(ci); + ret = dbg_create_files(ci); if (!ret) return 0; @@ -711,6 +742,7 @@ static struct platform_driver ci_hdrc_driver = { .remove = ci_hdrc_remove, .driver = { .name = "ci_hdrc", + .owner = THIS_MODULE, }, }; diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index 96d899aee473..7cccab6ff308 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -7,11 +7,15 @@ #include <linux/uaccess.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> +#include <linux/usb/phy.h> +#include <linux/usb/otg.h> +#include <linux/usb/otg-fsm.h> #include "ci.h" #include "udc.h" #include "bits.h" #include "debug.h" +#include "otg.h" /** * ci_device_show: prints information about device capabilities and status @@ -204,6 +208,80 @@ static const struct file_operations ci_requests_fops = { .release = single_release, }; +int ci_otg_show(struct seq_file *s, void *unused) +{ + struct ci_hdrc *ci = s->private; + struct otg_fsm *fsm; + + if (!ci || !ci_otg_is_fsm_mode(ci)) + return 0; + + fsm = &ci->fsm; + + /* ------ State ----- */ + seq_printf(s, "OTG state: %s\n\n", + usb_otg_state_string(ci->transceiver->state)); + + /* ------ State Machine Variables ----- */ + seq_printf(s, "a_bus_drop: %d\n", fsm->a_bus_drop); + + seq_printf(s, "a_bus_req: %d\n", fsm->a_bus_req); + + seq_printf(s, "a_srp_det: %d\n", fsm->a_srp_det); + + seq_printf(s, "a_vbus_vld: %d\n", fsm->a_vbus_vld); + + seq_printf(s, "b_conn: %d\n", fsm->b_conn); + + seq_printf(s, "adp_change: %d\n", fsm->adp_change); + + seq_printf(s, "power_up: %d\n", fsm->power_up); + + seq_printf(s, "a_bus_resume: %d\n", fsm->a_bus_resume); + + seq_printf(s, "a_bus_suspend: %d\n", fsm->a_bus_suspend); + + seq_printf(s, "a_conn: %d\n", fsm->a_conn); + + seq_printf(s, "b_bus_req: %d\n", fsm->b_bus_req); + + seq_printf(s, "b_bus_suspend: %d\n", fsm->b_bus_suspend); + + seq_printf(s, "b_se0_srp: %d\n", fsm->b_se0_srp); + + seq_printf(s, "b_ssend_srp: %d\n", fsm->b_ssend_srp); + + seq_printf(s, "b_sess_vld: %d\n", fsm->b_sess_vld); + + seq_printf(s, "b_srp_done: %d\n", fsm->b_srp_done); + + seq_printf(s, "drv_vbus: %d\n", fsm->drv_vbus); + + seq_printf(s, "loc_conn: %d\n", fsm->loc_conn); + + seq_printf(s, "loc_sof: %d\n", fsm->loc_sof); + + seq_printf(s, "adp_prb: %d\n", fsm->adp_prb); + + seq_printf(s, "id: %d\n", fsm->id); + + seq_printf(s, "protocol: %d\n", fsm->protocol); + + return 0; +} + +static int ci_otg_open(struct inode *inode, struct file *file) +{ + return single_open(file, ci_otg_show, inode->i_private); +} + +static const struct file_operations ci_otg_fops = { + .open = ci_otg_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int ci_role_show(struct seq_file *s, void *data) { struct ci_hdrc *ci = s->private; @@ -253,6 +331,50 @@ static const struct file_operations ci_role_fops = { .release = single_release, }; +int ci_registers_show(struct seq_file *s, void *unused) +{ + struct ci_hdrc *ci = s->private; + u32 tmp_reg; + + if (!ci) + return 0; + + /* ------ Registers ----- */ + tmp_reg = hw_read_intr_enable(ci); + seq_printf(s, "USBINTR reg: %08x\n", tmp_reg); + + tmp_reg = hw_read_intr_status(ci); + seq_printf(s, "USBSTS reg: %08x\n", tmp_reg); + + tmp_reg = hw_read(ci, OP_USBMODE, ~0); + seq_printf(s, "USBMODE reg: %08x\n", tmp_reg); + + tmp_reg = hw_read(ci, OP_USBCMD, ~0); + seq_printf(s, "USBCMD reg: %08x\n", tmp_reg); + + tmp_reg = hw_read(ci, OP_PORTSC, ~0); + seq_printf(s, "PORTSC reg: %08x\n", tmp_reg); + + if (ci->is_otg) { + tmp_reg = hw_read_otgsc(ci, ~0); + seq_printf(s, "OTGSC reg: %08x\n", tmp_reg); + } + + return 0; +} + +static int ci_registers_open(struct inode *inode, struct file *file) +{ + return single_open(file, ci_registers_show, inode->i_private); +} + +static const struct file_operations ci_registers_fops = { + .open = ci_registers_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /** * dbg_create_files: initializes the attribute interface * @ci: device @@ -287,8 +409,21 @@ int dbg_create_files(struct ci_hdrc *ci) if (!dent) goto err; + if (ci_otg_is_fsm_mode(ci)) { + dent = debugfs_create_file("otg", S_IRUGO, ci->debugfs, ci, + &ci_otg_fops); + if (!dent) + goto err; + } + dent = debugfs_create_file("role", S_IRUGO | S_IWUSR, ci->debugfs, ci, &ci_role_fops); + if (!dent) + goto err; + + dent = debugfs_create_file("registers", S_IRUGO, ci->debugfs, ci, + &ci_registers_fops); + if (dent) return 0; err: diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index a8ac6c16dac9..a93d950e9468 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -67,7 +67,11 @@ static int host_start(struct ci_hdrc *ci) ehci->has_tdi_phy_lpm = ci->hw_bank.lpm; ehci->imx28_write_fix = ci->imx28_write_fix; - if (ci->platdata->reg_vbus) { + /* + * vbus is always on if host is not in OTG FSM mode, + * otherwise should be controlled by OTG FSM + */ + if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) { ret = regulator_enable(ci->platdata->reg_vbus); if (ret) { dev_err(ci->dev, @@ -78,10 +82,17 @@ static int host_start(struct ci_hdrc *ci) } ret = usb_add_hcd(hcd, 0, 0); - if (ret) + if (ret) { goto disable_reg; - else + } else { + struct usb_otg *otg = ci->transceiver->otg; + ci->hcd = hcd; + if (otg) { + otg->host = &hcd->self; + hcd->self.otg_port = 1; + } + } if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING) hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); @@ -89,7 +100,7 @@ static int host_start(struct ci_hdrc *ci) return ret; disable_reg: - if (ci->platdata->reg_vbus) + if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) regulator_disable(ci->platdata->reg_vbus); put_hcd: @@ -105,7 +116,7 @@ static void host_stop(struct ci_hdrc *ci) if (hcd) { usb_remove_hcd(hcd); usb_put_hcd(hcd); - if (ci->platdata->reg_vbus) + if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) regulator_disable(ci->platdata->reg_vbus); } } diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index 39bd7ec8bf75..a048b08b9d4d 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -11,8 +11,8 @@ */ /* - * This file mainly handles otgsc register, it may include OTG operation - * in the future. + * This file mainly handles otgsc register, OTG fsm operations for HNP and SRP + * are also included. */ #include <linux/usb/otg.h> @@ -22,6 +22,26 @@ #include "ci.h" #include "bits.h" #include "otg.h" +#include "otg_fsm.h" + +/** + * hw_read_otgsc returns otgsc register bits value. + * @mask: bitfield mask + */ +u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask) +{ + return hw_read(ci, OP_OTGSC, mask); +} + +/** + * hw_write_otgsc updates target bits of OTGSC register. + * @mask: bitfield mask + * @data: to be written + */ +void hw_write_otgsc(struct ci_hdrc *ci, u32 mask, u32 data) +{ + hw_write(ci, OP_OTGSC, mask | OTGSC_INT_STATUS_BITS, data); +} /** * ci_otg_role - pick role based on ID pin state @@ -29,8 +49,7 @@ */ enum ci_role ci_otg_role(struct ci_hdrc *ci) { - u32 sts = hw_read(ci, OP_OTGSC, ~0); - enum ci_role role = sts & OTGSC_ID + enum ci_role role = hw_read_otgsc(ci, OTGSC_ID) ? CI_ROLE_GADGET : CI_ROLE_HOST; @@ -39,14 +58,10 @@ enum ci_role ci_otg_role(struct ci_hdrc *ci) void ci_handle_vbus_change(struct ci_hdrc *ci) { - u32 otgsc; - if (!ci->is_otg) return; - otgsc = hw_read(ci, OP_OTGSC, ~0); - - if (otgsc & OTGSC_BSV) + if (hw_read_otgsc(ci, OTGSC_BSV)) usb_gadget_vbus_connect(&ci->gadget); else usb_gadget_vbus_disconnect(&ci->gadget); @@ -76,6 +91,11 @@ static void ci_otg_work(struct work_struct *work) { struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work); + if (ci_otg_is_fsm_mode(ci) && !ci_otg_fsm_work(ci)) { + enable_irq(ci->irq); + return; + } + if (ci->id_event) { ci->id_event = false; ci_handle_id_switch(ci); @@ -102,6 +122,9 @@ int ci_hdrc_otg_init(struct ci_hdrc *ci) return -ENODEV; } + if (ci_otg_is_fsm_mode(ci)) + return ci_hdrc_otg_fsm_init(ci); + return 0; } @@ -115,6 +138,9 @@ void ci_hdrc_otg_destroy(struct ci_hdrc *ci) flush_workqueue(ci->wq); destroy_workqueue(ci->wq); } - ci_disable_otg_interrupt(ci, OTGSC_INT_EN_BITS); - ci_clear_otg_interrupt(ci, OTGSC_INT_STATUS_BITS); + /* Disable all OTG irq and clear status */ + hw_write_otgsc(ci, OTGSC_INT_EN_BITS | OTGSC_INT_STATUS_BITS, + OTGSC_INT_STATUS_BITS); + if (ci_otg_is_fsm_mode(ci)) + ci_hdrc_otg_fsm_remove(ci); } diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h index 449bee07f4fe..9ecb598e48f0 100644 --- a/drivers/usb/chipidea/otg.h +++ b/drivers/usb/chipidea/otg.h @@ -11,25 +11,16 @@ #ifndef __DRIVERS_USB_CHIPIDEA_OTG_H #define __DRIVERS_USB_CHIPIDEA_OTG_H -static inline void ci_clear_otg_interrupt(struct ci_hdrc *ci, u32 bits) -{ - /* Only clear request bits */ - hw_write(ci, OP_OTGSC, OTGSC_INT_STATUS_BITS, bits); -} - -static inline void ci_enable_otg_interrupt(struct ci_hdrc *ci, u32 bits) -{ - hw_write(ci, OP_OTGSC, bits | OTGSC_INT_STATUS_BITS, bits); -} - -static inline void ci_disable_otg_interrupt(struct ci_hdrc *ci, u32 bits) -{ - hw_write(ci, OP_OTGSC, bits | OTGSC_INT_STATUS_BITS, 0); -} - +u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask); +void hw_write_otgsc(struct ci_hdrc *ci, u32 mask, u32 data); int ci_hdrc_otg_init(struct ci_hdrc *ci); void ci_hdrc_otg_destroy(struct ci_hdrc *ci); enum ci_role ci_otg_role(struct ci_hdrc *ci); void ci_handle_vbus_change(struct ci_hdrc *ci); +static inline void ci_otg_queue_work(struct ci_hdrc *ci) +{ + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); +} #endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */ diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c new file mode 100644 index 000000000000..caaabc58021e --- /dev/null +++ b/drivers/usb/chipidea/otg_fsm.c @@ -0,0 +1,842 @@ +/* + * otg_fsm.c - ChipIdea USB IP core OTG FSM driver + * + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * Author: Jun Li + * + * 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 file mainly handles OTG fsm, it includes OTG fsm operations + * for HNP and SRP. + * + * TODO List + * - ADP + * - OTG test device + */ + +#include <linux/usb/otg.h> +#include <linux/usb/gadget.h> +#include <linux/usb/hcd.h> +#include <linux/usb/chipidea.h> +#include <linux/regulator/consumer.h> + +#include "ci.h" +#include "bits.h" +#include "otg.h" +#include "otg_fsm.h" + +static struct ci_otg_fsm_timer *otg_timer_initializer +(struct ci_hdrc *ci, void (*function)(void *, unsigned long), + unsigned long expires, unsigned long data) +{ + struct ci_otg_fsm_timer *timer; + + timer = devm_kzalloc(ci->dev, sizeof(struct ci_otg_fsm_timer), + GFP_KERNEL); + if (!timer) + return NULL; + timer->function = function; + timer->expires = expires; + timer->data = data; + return timer; +} + +/* Add for otg: interact with user space app */ +static ssize_t +get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf) +{ + char *next; + unsigned size, t; + struct ci_hdrc *ci = dev_get_drvdata(dev); + + next = buf; + size = PAGE_SIZE; + t = scnprintf(next, size, "%d\n", ci->fsm.a_bus_req); + size -= t; + next += t; + + return PAGE_SIZE - size; +} + +static ssize_t +set_a_bus_req(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ci_hdrc *ci = dev_get_drvdata(dev); + + if (count > 2) + return -1; + + mutex_lock(&ci->fsm.lock); + if (buf[0] == '0') { + ci->fsm.a_bus_req = 0; + } else if (buf[0] == '1') { + /* If a_bus_drop is TRUE, a_bus_req can't be set */ + if (ci->fsm.a_bus_drop) { + mutex_unlock(&ci->fsm.lock); + return count; + } + ci->fsm.a_bus_req = 1; + } + + ci_otg_queue_work(ci); + mutex_unlock(&ci->fsm.lock); + + return count; +} +static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req, set_a_bus_req); + +static ssize_t +get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf) +{ + char *next; + unsigned size, t; + struct ci_hdrc *ci = dev_get_drvdata(dev); + + next = buf; + size = PAGE_SIZE; + t = scnprintf(next, size, "%d\n", ci->fsm.a_bus_drop); + size -= t; + next += t; + + return PAGE_SIZE - size; +} + +static ssize_t +set_a_bus_drop(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ci_hdrc *ci = dev_get_drvdata(dev); + + if (count > 2) + return -1; + + mutex_lock(&ci->fsm.lock); + if (buf[0] == '0') { + ci->fsm.a_bus_drop = 0; + } else if (buf[0] == '1') { + ci->fsm.a_bus_drop = 1; + ci->fsm.a_bus_req = 0; + } + + ci_otg_queue_work(ci); + mutex_unlock(&ci->fsm.lock); + + return count; +} +static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR, get_a_bus_drop, + set_a_bus_drop); + +static ssize_t +get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf) +{ + char *next; + unsigned size, t; + struct ci_hdrc *ci = dev_get_drvdata(dev); + + next = buf; + size = PAGE_SIZE; + t = scnprintf(next, size, "%d\n", ci->fsm.b_bus_req); + size -= t; + next += t; + + return PAGE_SIZE - size; +} + +static ssize_t +set_b_bus_req(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ci_hdrc *ci = dev_get_drvdata(dev); + + if (count > 2) + return -1; + + mutex_lock(&ci->fsm.lock); + if (buf[0] == '0') + ci->fsm.b_bus_req = 0; + else if (buf[0] == '1') + ci->fsm.b_bus_req = 1; + + ci_otg_queue_work(ci); + mutex_unlock(&ci->fsm.lock); + + return count; +} +static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUSR, get_b_bus_req, set_b_bus_req); + +static ssize_t +set_a_clr_err(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ci_hdrc *ci = dev_get_drvdata(dev); + + if (count > 2) + return -1; + + mutex_lock(&ci->fsm.lock); + if (buf[0] == '1') + ci->fsm.a_clr_err = 1; + + ci_otg_queue_work(ci); + mutex_unlock(&ci->fsm.lock); + + return count; +} +static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err); + +static struct attribute *inputs_attrs[] = { + &dev_attr_a_bus_req.attr, + &dev_attr_a_bus_drop.attr, + &dev_attr_b_bus_req.attr, + &dev_attr_a_clr_err.attr, + NULL, +}; + +static struct attribute_group inputs_attr_group = { + .name = "inputs", + .attrs = inputs_attrs, +}; + +/* + * Add timer to active timer list + */ +static void ci_otg_add_timer(struct ci_hdrc *ci, enum ci_otg_fsm_timer_index t) +{ + struct ci_otg_fsm_timer *tmp_timer; + struct ci_otg_fsm_timer *timer = ci->fsm_timer->timer_list[t]; + struct list_head *active_timers = &ci->fsm_timer->active_timers; + + if (t >= NUM_CI_OTG_FSM_TIMERS) + return; + + /* + * Check if the timer is already in the active list, + * if so update timer count + */ + list_for_each_entry(tmp_timer, active_timers, list) + if (tmp_timer == timer) { + timer->count = timer->expires; + return; + } + + timer->count = timer->expires; + list_add_tail(&timer->list, active_timers); + + /* Enable 1ms irq */ + if (!(hw_read_otgsc(ci, OTGSC_1MSIE))) + hw_write_otgsc(ci, OTGSC_1MSIE, OTGSC_1MSIE); +} + +/* + * Remove timer from active timer list + */ +static void ci_otg_del_timer(struct ci_hdrc *ci, enum ci_otg_fsm_timer_index t) +{ + struct ci_otg_fsm_timer *tmp_timer, *del_tmp; + struct ci_otg_fsm_timer *timer = ci->fsm_timer->timer_list[t]; + struct list_head *active_timers = &ci->fsm_timer->active_timers; + + if (t >= NUM_CI_OTG_FSM_TIMERS) + return; + + list_for_each_entry_safe(tmp_timer, del_tmp, active_timers, list) + if (tmp_timer == timer) + list_del(&timer->list); + + /* Disable 1ms irq if there is no any active timer */ + if (list_empty(active_timers)) + hw_write_otgsc(ci, OTGSC_1MSIE, 0); +} + +/* + * Reduce timer count by 1, and find timeout conditions. + * Called by otg 1ms timer interrupt + */ +static inline int ci_otg_tick_timer(struct ci_hdrc *ci) +{ + struct ci_otg_fsm_timer *tmp_timer, *del_tmp; + struct list_head *active_timers = &ci->fsm_timer->active_timers; + int expired = 0; + + list_for_each_entry_safe(tmp_timer, del_tmp, active_timers, list) { + tmp_timer->count--; + /* check if timer expires */ + if (!tmp_timer->count) { + list_del(&tmp_timer->list); + tmp_timer->function(ci, tmp_timer->data); + expired = 1; + } + } + + /* disable 1ms irq if there is no any timer active */ + if ((expired == 1) && list_empty(active_timers)) + hw_write_otgsc(ci, OTGSC_1MSIE, 0); + + return expired; +} + +/* The timeout callback function to set time out bit */ +static void set_tmout(void *ptr, unsigned long indicator) +{ + *(int *)indicator = 1; +} + +static void set_tmout_and_fsm(void *ptr, unsigned long indicator) +{ + struct ci_hdrc *ci = (struct ci_hdrc *)ptr; + + set_tmout(ci, indicator); + + ci_otg_queue_work(ci); +} + +static void a_wait_vfall_tmout_func(void *ptr, unsigned long indicator) +{ + struct ci_hdrc *ci = (struct ci_hdrc *)ptr; + + set_tmout(ci, indicator); + /* Disable port power */ + hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP, 0); + /* Clear exsiting DP irq */ + hw_write_otgsc(ci, OTGSC_DPIS, OTGSC_DPIS); + /* Enable data pulse irq */ + hw_write_otgsc(ci, OTGSC_DPIE, OTGSC_DPIE); + ci_otg_queue_work(ci); +} + +static void b_ase0_brst_tmout_func(void *ptr, unsigned long indicator) +{ + struct ci_hdrc *ci = (struct ci_hdrc *)ptr; + + set_tmout(ci, indicator); + if (!hw_read_otgsc(ci, OTGSC_BSV)) + ci->fsm.b_sess_vld = 0; + + ci_otg_queue_work(ci); +} + +static void b_ssend_srp_tmout_func(void *ptr, unsigned long indicator) +{ + struct ci_hdrc *ci = (struct ci_hdrc *)ptr; + + set_tmout(ci, indicator); + + /* only vbus fall below B_sess_vld in b_idle state */ + if (ci->transceiver->state == OTG_STATE_B_IDLE) + ci_otg_queue_work(ci); +} + +static void b_sess_vld_tmout_func(void *ptr, unsigned long indicator) +{ + struct ci_hdrc *ci = (struct ci_hdrc *)ptr; + + /* Check if A detached */ + if (!(hw_read_otgsc(ci, OTGSC_BSV))) { + ci->fsm.b_sess_vld = 0; + ci_otg_add_timer(ci, B_SSEND_SRP); + ci_otg_queue_work(ci); + } +} + +static void b_data_pulse_end(void *ptr, unsigned long indicator) +{ + struct ci_hdrc *ci = (struct ci_hdrc *)ptr; + + ci->fsm.b_srp_done = 1; + ci->fsm.b_bus_req = 0; + if (ci->fsm.power_up) + ci->fsm.power_up = 0; + + hw_write_otgsc(ci, OTGSC_HABA, 0); + + ci_otg_queue_work(ci); +} + +/* Initialize timers */ +static int ci_otg_init_timers(struct ci_hdrc *ci) +{ + struct otg_fsm *fsm = &ci->fsm; + + /* FSM used timers */ + ci->fsm_timer->timer_list[A_WAIT_VRISE] = + otg_timer_initializer(ci, &set_tmout_and_fsm, TA_WAIT_VRISE, + (unsigned long)&fsm->a_wait_vrise_tmout); + if (ci->fsm_timer->timer_list[A_WAIT_VRISE] == NULL) + return -ENOMEM; + + ci->fsm_timer->timer_list[A_WAIT_VFALL] = + otg_timer_initializer(ci, &a_wait_vfall_tmout_func, + TA_WAIT_VFALL, (unsigned long)&fsm->a_wait_vfall_tmout); + if (ci->fsm_timer->timer_list[A_WAIT_VFALL] == NULL) + return -ENOMEM; + + ci->fsm_timer->timer_list[A_WAIT_BCON] = + otg_timer_initializer(ci, &set_tmout_and_fsm, TA_WAIT_BCON, + (unsigned long)&fsm->a_wait_bcon_tmout); + if (ci->fsm_timer->timer_list[A_WAIT_BCON] == NULL) + return -ENOMEM; + + ci->fsm_timer->timer_list[A_AIDL_BDIS] = + otg_timer_initializer(ci, &set_tmout_and_fsm, TA_AIDL_BDIS, + (unsigned long)&fsm->a_aidl_bdis_tmout); + if (ci->fsm_timer->timer_list[A_AIDL_BDIS] == NULL) + return -ENOMEM; + + ci->fsm_timer->timer_list[A_BIDL_ADIS] = + otg_timer_initializer(ci, &set_tmout_and_fsm, TA_BIDL_ADIS, + (unsigned long)&fsm->a_bidl_adis_tmout); + if (ci->fsm_timer->timer_list[A_BIDL_ADIS] == NULL) + return -ENOMEM; + + ci->fsm_timer->timer_list[B_ASE0_BRST] = + otg_timer_initializer(ci, &b_ase0_brst_tmout_func, TB_ASE0_BRST, + (unsigned long)&fsm->b_ase0_brst_tmout); + if (ci->fsm_timer->timer_list[B_ASE0_BRST] == NULL) + return -ENOMEM; + + ci->fsm_timer->timer_list[B_SE0_SRP] = + otg_timer_initializer(ci, &set_tmout_and_fsm, TB_SE0_SRP, + (unsigned long)&fsm->b_se0_srp); + if (ci->fsm_timer->timer_list[B_SE0_SRP] == NULL) + return -ENOMEM; + + ci->fsm_timer->timer_list[B_SSEND_SRP] = + otg_timer_initializer(ci, &b_ssend_srp_tmout_func, TB_SSEND_SRP, + (unsigned long)&fsm->b_ssend_srp); + if (ci->fsm_timer->timer_list[B_SSEND_SRP] == NULL) + return -ENOMEM; + + ci->fsm_timer->timer_list[B_SRP_FAIL] = + otg_timer_initializer(ci, &set_tmout, TB_SRP_FAIL, + (unsigned long)&fsm->b_srp_done); + if (ci->fsm_timer->timer_list[B_SRP_FAIL] == NULL) + return -ENOMEM; + + ci->fsm_timer->timer_list[B_DATA_PLS] = + otg_timer_initializer(ci, &b_data_pulse_end, TB_DATA_PLS, 0); + if (ci->fsm_timer->timer_list[B_DATA_PLS] == NULL) + return -ENOMEM; + + ci->fsm_timer->timer_list[B_SESS_VLD] = otg_timer_initializer(ci, + &b_sess_vld_tmout_func, TB_SESS_VLD, 0); + if (ci->fsm_timer->timer_list[B_SESS_VLD] == NULL) + return -ENOMEM; + + return 0; +} + +/* -------------------------------------------------------------*/ +/* Operations that will be called from OTG Finite State Machine */ +/* -------------------------------------------------------------*/ +static void ci_otg_fsm_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer t) +{ + struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); + + if (t < NUM_OTG_FSM_TIMERS) + ci_otg_add_timer(ci, t); + return; +} + +static void ci_otg_fsm_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer t) +{ + struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); + + if (t < NUM_OTG_FSM_TIMERS) + ci_otg_del_timer(ci, t); + return; +} + +/* + * A-device drive vbus: turn on vbus regulator and enable port power + * Data pulse irq should be disabled while vbus is on. + */ +static void ci_otg_drv_vbus(struct otg_fsm *fsm, int on) +{ + int ret; + struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); + + if (on) { + /* Enable power power */ + hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP, + PORTSC_PP); + if (ci->platdata->reg_vbus) { + ret = regulator_enable(ci->platdata->reg_vbus); + if (ret) { + dev_err(ci->dev, + "Failed to enable vbus regulator, ret=%d\n", + ret); + return; + } + } + /* Disable data pulse irq */ + hw_write_otgsc(ci, OTGSC_DPIE, 0); + + fsm->a_srp_det = 0; + fsm->power_up = 0; + } else { + if (ci->platdata->reg_vbus) + regulator_disable(ci->platdata->reg_vbus); + + fsm->a_bus_drop = 1; + fsm->a_bus_req = 0; + } +} + +/* + * Control data line by Run Stop bit. + */ +static void ci_otg_loc_conn(struct otg_fsm *fsm, int on) +{ + struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); + + if (on) + hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS); + else + hw_write(ci, OP_USBCMD, USBCMD_RS, 0); +} + +/* + * Generate SOF by host. + * This is controlled through suspend/resume the port. + * In host mode, controller will automatically send SOF. + * Suspend will block the data on the port. + */ +static void ci_otg_loc_sof(struct otg_fsm *fsm, int on) +{ + struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); + + if (on) + hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_FPR, + PORTSC_FPR); + else + hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_SUSP, + PORTSC_SUSP); +} + +/* + * Start SRP pulsing by data-line pulsing, + * no v-bus pulsing followed + */ +static void ci_otg_start_pulse(struct otg_fsm *fsm) +{ + struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); + + /* Hardware Assistant Data pulse */ + hw_write_otgsc(ci, OTGSC_HADP, OTGSC_HADP); + + ci_otg_add_timer(ci, B_DATA_PLS); +} + +static int ci_otg_start_host(struct otg_fsm *fsm, int on) +{ + struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); + + mutex_unlock(&fsm->lock); + if (on) { + ci_role_stop(ci); + ci_role_start(ci, CI_ROLE_HOST); + } else { + ci_role_stop(ci); + hw_device_reset(ci, USBMODE_CM_DC); + ci_role_start(ci, CI_ROLE_GADGET); + } + mutex_lock(&fsm->lock); + return 0; +} + +static int ci_otg_start_gadget(struct otg_fsm *fsm, int on) +{ + struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); + + mutex_unlock(&fsm->lock); + if (on) + usb_gadget_vbus_connect(&ci->gadget); + else + usb_gadget_vbus_disconnect(&ci->gadget); + mutex_lock(&fsm->lock); + + return 0; +} + +static struct otg_fsm_ops ci_otg_ops = { + .drv_vbus = ci_otg_drv_vbus, + .loc_conn = ci_otg_loc_conn, + .loc_sof = ci_otg_loc_sof, + .start_pulse = ci_otg_start_pulse, + .add_timer = ci_otg_fsm_add_timer, + .del_timer = ci_otg_fsm_del_timer, + .start_host = ci_otg_start_host, + .start_gadget = ci_otg_start_gadget, +}; + +int ci_otg_fsm_work(struct ci_hdrc *ci) +{ + /* + * Don't do fsm transition for B device + * when there is no gadget class driver + */ + if (ci->fsm.id && !(ci->driver) && + ci->transceiver->state < OTG_STATE_A_IDLE) + return 0; + + if (otg_statemachine(&ci->fsm)) { + if (ci->transceiver->state == OTG_STATE_A_IDLE) { + /* + * Further state change for cases: + * a_idle to b_idle; or + * a_idle to a_wait_vrise due to ID change(1->0), so + * B-dev becomes A-dev can try to start new session + * consequently; or + * a_idle to a_wait_vrise when power up + */ + if ((ci->fsm.id) || (ci->id_event) || + (ci->fsm.power_up)) + ci_otg_queue_work(ci); + if (ci->id_event) + ci->id_event = false; + } else if (ci->transceiver->state == OTG_STATE_B_IDLE) { + if (ci->fsm.b_sess_vld) { + ci->fsm.power_up = 0; + /* + * Further transite to b_periphearl state + * when register gadget driver with vbus on + */ + ci_otg_queue_work(ci); + } + } + } + return 0; +} + +/* + * Update fsm variables in each state if catching expected interrupts, + * called by otg fsm isr. + */ +static void ci_otg_fsm_event(struct ci_hdrc *ci) +{ + u32 intr_sts, otg_bsess_vld, port_conn; + struct otg_fsm *fsm = &ci->fsm; + + intr_sts = hw_read_intr_status(ci); + otg_bsess_vld = hw_read_otgsc(ci, OTGSC_BSV); + port_conn = hw_read(ci, OP_PORTSC, PORTSC_CCS); + + switch (ci->transceiver->state) { + case OTG_STATE_A_WAIT_BCON: + if (port_conn) { + fsm->b_conn = 1; + fsm->a_bus_req = 1; + ci_otg_queue_work(ci); + } + break; + case OTG_STATE_B_IDLE: + if (otg_bsess_vld && (intr_sts & USBi_PCI) && port_conn) { + fsm->b_sess_vld = 1; + ci_otg_queue_work(ci); + } + break; + case OTG_STATE_B_PERIPHERAL: + if ((intr_sts & USBi_SLI) && port_conn && otg_bsess_vld) { + fsm->a_bus_suspend = 1; + ci_otg_queue_work(ci); + } else if (intr_sts & USBi_PCI) { + if (fsm->a_bus_suspend == 1) + fsm->a_bus_suspend = 0; + } + break; + case OTG_STATE_B_HOST: + if ((intr_sts & USBi_PCI) && !port_conn) { + fsm->a_conn = 0; + fsm->b_bus_req = 0; + ci_otg_queue_work(ci); + ci_otg_add_timer(ci, B_SESS_VLD); + } + break; + case OTG_STATE_A_PERIPHERAL: + if (intr_sts & USBi_SLI) { + fsm->b_bus_suspend = 1; + /* + * Init a timer to know how long this suspend + * will contine, if time out, indicates B no longer + * wants to be host role + */ + ci_otg_add_timer(ci, A_BIDL_ADIS); + } + + if (intr_sts & USBi_URI) + ci_otg_del_timer(ci, A_BIDL_ADIS); + + if (intr_sts & USBi_PCI) { + if (fsm->b_bus_suspend == 1) { + ci_otg_del_timer(ci, A_BIDL_ADIS); + fsm->b_bus_suspend = 0; + } + } + break; + case OTG_STATE_A_SUSPEND: + if ((intr_sts & USBi_PCI) && !port_conn) { + fsm->b_conn = 0; + + /* if gadget driver is binded */ + if (ci->driver) { + /* A device to be peripheral mode */ + ci->gadget.is_a_peripheral = 1; + } + ci_otg_queue_work(ci); + } + break; + case OTG_STATE_A_HOST: + if ((intr_sts & USBi_PCI) && !port_conn) { + fsm->b_conn = 0; + ci_otg_queue_work(ci); + } + break; + case OTG_STATE_B_WAIT_ACON: + if ((intr_sts & USBi_PCI) && port_conn) { + fsm->a_conn = 1; + ci_otg_queue_work(ci); + } + break; + default: + break; + } +} + +/* + * ci_otg_irq - otg fsm related irq handling + * and also update otg fsm variable by monitoring usb host and udc + * state change interrupts. + * @ci: ci_hdrc + */ +irqreturn_t ci_otg_fsm_irq(struct ci_hdrc *ci) +{ + irqreturn_t retval = IRQ_NONE; + u32 otgsc, otg_int_src = 0; + struct otg_fsm *fsm = &ci->fsm; + + otgsc = hw_read_otgsc(ci, ~0); + otg_int_src = otgsc & OTGSC_INT_STATUS_BITS & (otgsc >> 8); + fsm->id = (otgsc & OTGSC_ID) ? 1 : 0; + + if (otg_int_src) { + if (otg_int_src & OTGSC_1MSIS) { + hw_write_otgsc(ci, OTGSC_1MSIS, OTGSC_1MSIS); + retval = ci_otg_tick_timer(ci); + return IRQ_HANDLED; + } else if (otg_int_src & OTGSC_DPIS) { + hw_write_otgsc(ci, OTGSC_DPIS, OTGSC_DPIS); + fsm->a_srp_det = 1; + fsm->a_bus_drop = 0; + } else if (otg_int_src & OTGSC_IDIS) { + hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS); + if (fsm->id == 0) { + fsm->a_bus_drop = 0; + fsm->a_bus_req = 1; + ci->id_event = true; + } + } else if (otg_int_src & OTGSC_BSVIS) { + hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS); + if (otgsc & OTGSC_BSV) { + fsm->b_sess_vld = 1; + ci_otg_del_timer(ci, B_SSEND_SRP); + ci_otg_del_timer(ci, B_SRP_FAIL); + fsm->b_ssend_srp = 0; + } else { + fsm->b_sess_vld = 0; + if (fsm->id) + ci_otg_add_timer(ci, B_SSEND_SRP); + } + } else if (otg_int_src & OTGSC_AVVIS) { + hw_write_otgsc(ci, OTGSC_AVVIS, OTGSC_AVVIS); + if (otgsc & OTGSC_AVV) { + fsm->a_vbus_vld = 1; + } else { + fsm->a_vbus_vld = 0; + fsm->b_conn = 0; + } + } + ci_otg_queue_work(ci); + return IRQ_HANDLED; + } + + ci_otg_fsm_event(ci); + + return retval; +} + +void ci_hdrc_otg_fsm_start(struct ci_hdrc *ci) +{ + ci_otg_queue_work(ci); +} + +int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci) +{ + int retval = 0; + struct usb_otg *otg; + + otg = devm_kzalloc(ci->dev, + sizeof(struct usb_otg), GFP_KERNEL); + if (!otg) { + dev_err(ci->dev, + "Failed to allocate usb_otg structure for ci hdrc otg!\n"); + return -ENOMEM; + } + + otg->phy = ci->transceiver; + otg->gadget = &ci->gadget; + ci->fsm.otg = otg; + ci->transceiver->otg = ci->fsm.otg; + ci->fsm.power_up = 1; + ci->fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0; + ci->transceiver->state = OTG_STATE_UNDEFINED; + ci->fsm.ops = &ci_otg_ops; + + mutex_init(&ci->fsm.lock); + + ci->fsm_timer = devm_kzalloc(ci->dev, + sizeof(struct ci_otg_fsm_timer_list), GFP_KERNEL); + if (!ci->fsm_timer) { + dev_err(ci->dev, + "Failed to allocate timer structure for ci hdrc otg!\n"); + return -ENOMEM; + } + + INIT_LIST_HEAD(&ci->fsm_timer->active_timers); + retval = ci_otg_init_timers(ci); + if (retval) { + dev_err(ci->dev, "Couldn't init OTG timers\n"); + return retval; + } + + retval = sysfs_create_group(&ci->dev->kobj, &inputs_attr_group); + if (retval < 0) { + dev_dbg(ci->dev, + "Can't register sysfs attr group: %d\n", retval); + return retval; + } + + /* Enable A vbus valid irq */ + hw_write_otgsc(ci, OTGSC_AVVIE, OTGSC_AVVIE); + + if (ci->fsm.id) { + ci->fsm.b_ssend_srp = + hw_read_otgsc(ci, OTGSC_BSV) ? 0 : 1; + ci->fsm.b_sess_vld = + hw_read_otgsc(ci, OTGSC_BSV) ? 1 : 0; + /* Enable BSV irq */ + hw_write_otgsc(ci, OTGSC_BSVIE, OTGSC_BSVIE); + } + + return 0; +} + +void ci_hdrc_otg_fsm_remove(struct ci_hdrc *ci) +{ + sysfs_remove_group(&ci->dev->kobj, &inputs_attr_group); +} diff --git a/drivers/usb/chipidea/otg_fsm.h b/drivers/usb/chipidea/otg_fsm.h new file mode 100644 index 000000000000..94c085f456a9 --- /dev/null +++ b/drivers/usb/chipidea/otg_fsm.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * Author: Jun Li + * + * 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. + */ + +#ifndef __DRIVERS_USB_CHIPIDEA_OTG_FSM_H +#define __DRIVERS_USB_CHIPIDEA_OTG_FSM_H + +#include <linux/usb/otg-fsm.h> + +/* + * A-DEVICE timing constants + */ + +/* Wait for VBUS Rise */ +#define TA_WAIT_VRISE (100) /* a_wait_vrise: section 7.1.2 + * a_wait_vrise_tmr: section 7.4.5.1 + * TA_VBUS_RISE <= 100ms, section 4.4 + * Table 4-1: Electrical Characteristics + * ->DC Electrical Timing + */ +/* Wait for VBUS Fall */ +#define TA_WAIT_VFALL (1000) /* a_wait_vfall: section 7.1.7 + * a_wait_vfall_tmr: section: 7.4.5.2 + */ +/* Wait for B-Connect */ +#define TA_WAIT_BCON (10000) /* a_wait_bcon: section 7.1.3 + * TA_WAIT_BCON: should be between 1100 + * and 30000 ms, section 5.5, Table 5-1 + */ +/* A-Idle to B-Disconnect */ +#define TA_AIDL_BDIS (5000) /* a_suspend min 200 ms, section 5.2.1 + * TA_AIDL_BDIS: section 5.5, Table 5-1 + */ +/* B-Idle to A-Disconnect */ +#define TA_BIDL_ADIS (500) /* TA_BIDL_ADIS: section 5.2.1 + * 500ms is used for B switch to host + * for safe + */ + +/* + * B-device timing constants + */ + +/* Data-Line Pulse Time*/ +#define TB_DATA_PLS (10) /* b_srp_init,continue 5~10ms + * section:5.1.3 + */ +/* SRP Fail Time */ +#define TB_SRP_FAIL (6000) /* b_srp_init,fail time 5~6s + * section:5.1.6 + */ +/* A-SE0 to B-Reset */ +#define TB_ASE0_BRST (155) /* minimum 155 ms, section:5.3.1 */ +/* SE0 Time Before SRP */ +#define TB_SE0_SRP (1000) /* b_idle,minimum 1s, section:5.1.2 */ +/* SSEND time before SRP */ +#define TB_SSEND_SRP (1500) /* minimum 1.5 sec, section:5.1.2 */ + +#define TB_SESS_VLD (1000) + +enum ci_otg_fsm_timer_index { + /* + * CI specific timers, start from the end + * of standard and auxiliary OTG timers + */ + B_DATA_PLS = NUM_OTG_FSM_TIMERS, + B_SSEND_SRP, + B_SESS_VLD, + + NUM_CI_OTG_FSM_TIMERS, +}; + +struct ci_otg_fsm_timer { + unsigned long expires; /* Number of count increase to timeout */ + unsigned long count; /* Tick counter */ + void (*function)(void *, unsigned long); /* Timeout function */ + unsigned long data; /* Data passed to function */ + struct list_head list; +}; + +struct ci_otg_fsm_timer_list { + struct ci_otg_fsm_timer *timer_list[NUM_CI_OTG_FSM_TIMERS]; + struct list_head active_timers; +}; + +#ifdef CONFIG_USB_OTG_FSM + +int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci); +int ci_otg_fsm_work(struct ci_hdrc *ci); +irqreturn_t ci_otg_fsm_irq(struct ci_hdrc *ci); +void ci_hdrc_otg_fsm_start(struct ci_hdrc *ci); +void ci_hdrc_otg_fsm_remove(struct ci_hdrc *ci); + +#else + +static inline int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci) +{ + return 0; +} + +static inline int ci_otg_fsm_work(struct ci_hdrc *ci) +{ + return -ENXIO; +} + +static inline irqreturn_t ci_otg_fsm_irq(struct ci_hdrc *ci) +{ + return IRQ_NONE; +} + +static inline void ci_hdrc_otg_fsm_start(struct ci_hdrc *ci) +{ + +} + +static inline void ci_hdrc_otg_fsm_remove(struct ci_hdrc *ci) +{ + +} + +#endif + +#endif /* __DRIVERS_USB_CHIPIDEA_OTG_FSM_H */ diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 7739c64ef259..69425b3cb6b7 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -20,6 +20,7 @@ #include <linux/pm_runtime.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> +#include <linux/usb/otg-fsm.h> #include <linux/usb/chipidea.h> #include "ci.h" @@ -27,6 +28,7 @@ #include "bits.h" #include "debug.h" #include "otg.h" +#include "otg_fsm.h" /* control endpoint description */ static const struct usb_endpoint_descriptor @@ -242,26 +244,6 @@ static int hw_port_is_high_speed(struct ci_hdrc *ci) } /** - * hw_read_intr_enable: returns interrupt enable register - * - * This function returns register data - */ -static u32 hw_read_intr_enable(struct ci_hdrc *ci) -{ - return hw_read(ci, OP_USBINTR, ~0); -} - -/** - * hw_read_intr_status: returns interrupt status register - * - * This function returns register data - */ -static u32 hw_read_intr_status(struct ci_hdrc *ci) -{ - return hw_read(ci, OP_USBSTS, ~0); -} - -/** * hw_test_and_clear_complete: test & clear complete status (execute without * interruption) * @n: endpoint number @@ -727,6 +709,8 @@ __acquires(ci->lock) if (ci->status == NULL) retval = -ENOMEM; + usb_gadget_set_state(&ci->gadget, USB_STATE_DEFAULT); + done: spin_lock(&ci->lock); @@ -841,7 +825,6 @@ __acquires(hwep->lock) if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) { /* Assume that device is bus powered for now. */ *(u16 *)req->buf = ci->remote_wakeup << 1; - retval = 0; } else if ((setup->bRequestType & USB_RECIP_MASK) \ == USB_RECIP_ENDPOINT) { dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ? @@ -883,6 +866,8 @@ isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req) if (ci->setaddr) { hw_usb_set_address(ci, ci->address); ci->setaddr = false; + if (ci->address) + usb_gadget_set_state(&ci->gadget, USB_STATE_ADDRESS); } spin_lock_irqsave(&ci->lock, flags); @@ -1072,6 +1057,14 @@ __acquires(ci->lock) default: break; } + break; + case USB_DEVICE_B_HNP_ENABLE: + if (ci_otg_is_fsm_mode(ci)) { + ci->gadget.b_hnp_enable = 1; + err = isr_setup_status_phase( + ci); + } + break; default: goto delegate; } @@ -1477,7 +1470,7 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active) pm_runtime_get_sync(&_gadget->dev); hw_device_reset(ci, USBMODE_CM_DC); hw_device_state(ci, ci->ep0out->qh.dma); - dev_dbg(ci->dev, "Connected to host\n"); + usb_gadget_set_state(_gadget, USB_STATE_POWERED); } else { if (ci->driver) ci->driver->disconnect(&ci->gadget); @@ -1487,7 +1480,7 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active) CI_HDRC_CONTROLLER_STOPPED_EVENT); _gadget_stop_activity(&ci->gadget); pm_runtime_put_sync(&_gadget->dev); - dev_dbg(ci->dev, "Disconnected from host\n"); + usb_gadget_set_state(_gadget, USB_STATE_NOTATTACHED); } } @@ -1655,6 +1648,13 @@ static int ci_udc_start(struct usb_gadget *gadget, return retval; ci->driver = driver; + + /* Start otg fsm for B-device */ + if (ci_otg_is_fsm_mode(ci) && ci->fsm.id) { + ci_hdrc_otg_fsm_start(ci); + return retval; + } + pm_runtime_get_sync(&ci->gadget.dev); if (ci->vbus_active) { spin_lock_irqsave(&ci->lock, flags); @@ -1753,6 +1753,8 @@ static irqreturn_t udc_irq(struct ci_hdrc *ci) ci->suspended = 1; spin_unlock(&ci->lock); ci->driver->suspend(&ci->gadget); + usb_gadget_set_state(&ci->gadget, + USB_STATE_SUSPENDED); spin_lock(&ci->lock); } } @@ -1779,7 +1781,7 @@ static int udc_start(struct ci_hdrc *ci) ci->gadget.ops = &usb_gadget_ops; ci->gadget.speed = USB_SPEED_UNKNOWN; ci->gadget.max_speed = USB_SPEED_HIGH; - ci->gadget.is_otg = 0; + ci->gadget.is_otg = ci->is_otg ? 1 : 0; ci->gadget.name = ci->platdata->name; INIT_LIST_HEAD(&ci->gadget.ep_list); @@ -1843,21 +1845,22 @@ void ci_hdrc_gadget_destroy(struct ci_hdrc *ci) static int udc_id_switch_for_device(struct ci_hdrc *ci) { - if (ci->is_otg) { - ci_clear_otg_interrupt(ci, OTGSC_BSVIS); - ci_enable_otg_interrupt(ci, OTGSC_BSVIE); - } + if (ci->is_otg) + /* Clear and enable BSV irq */ + hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE, + OTGSC_BSVIS | OTGSC_BSVIE); return 0; } static void udc_id_switch_for_host(struct ci_hdrc *ci) { - if (ci->is_otg) { - /* host doesn't care B_SESSION_VALID event */ - ci_clear_otg_interrupt(ci, OTGSC_BSVIS); - ci_disable_otg_interrupt(ci, OTGSC_BSVIE); - } + /* + * host doesn't care B_SESSION_VALID event + * so clear and disbale BSV irq + */ + if (ci->is_otg) + hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS); } /** diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index cd061abe3507..85293b8b1df9 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -21,16 +21,39 @@ #define MX25_USB_PHY_CTRL_OFFSET 0x08 #define MX25_BM_EXTERNAL_VBUS_DIVIDER BIT(23) +#define MX25_EHCI_INTERFACE_SINGLE_UNI (2 << 0) +#define MX25_EHCI_INTERFACE_DIFF_UNI (0 << 0) +#define MX25_EHCI_INTERFACE_MASK (0xf) + +#define MX25_OTG_SIC_SHIFT 29 +#define MX25_OTG_SIC_MASK (0x3 << MX25_OTG_SIC_SHIFT) +#define MX25_OTG_PM_BIT BIT(24) +#define MX25_OTG_PP_BIT BIT(11) +#define MX25_OTG_OCPOL_BIT BIT(3) + +#define MX25_H1_SIC_SHIFT 21 +#define MX25_H1_SIC_MASK (0x3 << MX25_H1_SIC_SHIFT) +#define MX25_H1_PP_BIT BIT(18) +#define MX25_H1_PM_BIT BIT(16) +#define MX25_H1_IPPUE_UP_BIT BIT(7) +#define MX25_H1_IPPUE_DOWN_BIT BIT(6) +#define MX25_H1_TLL_BIT BIT(5) +#define MX25_H1_USBTE_BIT BIT(4) +#define MX25_H1_OCPOL_BIT BIT(2) + #define MX27_H1_PM_BIT BIT(8) #define MX27_H2_PM_BIT BIT(16) #define MX27_OTG_PM_BIT BIT(24) #define MX53_USB_OTG_PHY_CTRL_0_OFFSET 0x08 +#define MX53_USB_OTG_PHY_CTRL_1_OFFSET 0x0c #define MX53_USB_UH2_CTRL_OFFSET 0x14 #define MX53_USB_UH3_CTRL_OFFSET 0x18 #define MX53_BM_OVER_CUR_DIS_H1 BIT(5) #define MX53_BM_OVER_CUR_DIS_OTG BIT(8) #define MX53_BM_OVER_CUR_DIS_UHx BIT(30) +#define MX53_USB_PHYCTRL1_PLLDIV_MASK 0x3 +#define MX53_USB_PLL_DIV_24_MHZ 0x01 #define MX6_BM_OVER_CUR_DIS BIT(7) @@ -50,6 +73,39 @@ struct imx_usbmisc { static struct imx_usbmisc *usbmisc; +static int usbmisc_imx25_init(struct imx_usbmisc_data *data) +{ + unsigned long flags; + u32 val = 0; + + if (data->index > 1) + return -EINVAL; + + spin_lock_irqsave(&usbmisc->lock, flags); + switch (data->index) { + case 0: + val = readl(usbmisc->base); + val &= ~(MX25_OTG_SIC_MASK | MX25_OTG_PP_BIT); + val |= (MX25_EHCI_INTERFACE_DIFF_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_OTG_SIC_SHIFT; + val |= (MX25_OTG_PM_BIT | MX25_OTG_OCPOL_BIT); + writel(val, usbmisc->base); + break; + case 1: + val = readl(usbmisc->base); + val &= ~(MX25_H1_SIC_MASK | MX25_H1_PP_BIT | MX25_H1_IPPUE_UP_BIT); + val |= (MX25_EHCI_INTERFACE_SINGLE_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_H1_SIC_SHIFT; + val |= (MX25_H1_PM_BIT | MX25_H1_OCPOL_BIT | MX25_H1_TLL_BIT | + MX25_H1_USBTE_BIT | MX25_H1_IPPUE_DOWN_BIT); + + writel(val, usbmisc->base); + + break; + } + spin_unlock_irqrestore(&usbmisc->lock, flags); + + return 0; +} + static int usbmisc_imx25_post(struct imx_usbmisc_data *data) { void __iomem *reg; @@ -111,6 +167,13 @@ static int usbmisc_imx53_init(struct imx_usbmisc_data *data) if (data->index > 3) return -EINVAL; + /* Select a 24 MHz reference clock for the PHY */ + reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET; + val = readl(reg); + val &= ~MX53_USB_PHYCTRL1_PLLDIV_MASK; + val |= MX53_USB_PLL_DIV_24_MHZ; + writel(val, usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET); + if (data->disable_oc) { spin_lock_irqsave(&usbmisc->lock, flags); switch (data->index) { @@ -159,6 +222,7 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data) } static const struct usbmisc_ops imx25_usbmisc_ops = { + .init = usbmisc_imx25_init, .post = usbmisc_imx25_post, }; @@ -200,6 +264,10 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = { .data = &imx25_usbmisc_ops, }, { + .compatible = "fsl,imx35-usbmisc", + .data = &imx25_usbmisc_ops, + }, + { .compatible = "fsl,imx27-usbmisc", .data = &imx27_usbmisc_ops, }, diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 904efb6035b0..e934e19f49f5 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -122,13 +122,23 @@ static void acm_release_minor(struct acm *acm) static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int len) { - int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), + int retval; + + retval = usb_autopm_get_interface(acm->control); + if (retval) + return retval; + + retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), request, USB_RT_ACM, value, acm->control->altsetting[0].desc.bInterfaceNumber, buf, len, 5000); + dev_dbg(&acm->control->dev, "%s - rq 0x%02x, val %#x, len %#x, result %d\n", __func__, request, value, len, retval); + + usb_autopm_put_interface(acm->control); + return retval < 0 ? retval : 0; } @@ -406,19 +416,21 @@ static void acm_read_bulk_callback(struct urb *urb) dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__); return; } - usb_mark_last_busy(acm->dev); if (urb->status) { dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n", __func__, urb->status); return; } + + usb_mark_last_busy(acm->dev); + acm_process_read_urb(acm, urb); /* throttle device if requested by tty */ spin_lock_irqsave(&acm->read_lock, flags); acm->throttled = acm->throttle_req; - if (!acm->throttled && !acm->susp_count) { + if (!acm->throttled) { spin_unlock_irqrestore(&acm->read_lock, flags); acm_submit_read_urb(acm, rb->index, GFP_ATOMIC); } else { @@ -492,10 +504,30 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) return tty_port_open(&acm->port, tty, filp); } +static void acm_port_dtr_rts(struct tty_port *port, int raise) +{ + struct acm *acm = container_of(port, struct acm, port); + int val; + int res; + + if (raise) + val = ACM_CTRL_DTR | ACM_CTRL_RTS; + else + val = 0; + + /* FIXME: add missing ctrlout locking throughout driver */ + acm->ctrlout = val; + + res = acm_set_control(acm, val); + if (res && (acm->ctrl_caps & USB_CDC_CAP_LINE)) + dev_err(&acm->control->dev, "failed to set dtr/rts\n"); +} + static int acm_port_activate(struct tty_port *port, struct tty_struct *tty) { struct acm *acm = container_of(port, struct acm, port); int retval = -ENODEV; + int i; dev_dbg(&acm->control->dev, "%s\n", __func__); @@ -515,22 +547,13 @@ static int acm_port_activate(struct tty_port *port, struct tty_struct *tty) acm->control->needs_remote_wakeup = 1; acm->ctrlurb->dev = acm->dev; - if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { + retval = usb_submit_urb(acm->ctrlurb, GFP_KERNEL); + if (retval) { dev_err(&acm->control->dev, "%s - usb_submit_urb(ctrl irq) failed\n", __func__); - usb_autopm_put_interface(acm->control); goto error_submit_urb; } - acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS; - if (acm_set_control(acm, acm->ctrlout) < 0 && - (acm->ctrl_caps & USB_CDC_CAP_LINE)) { - usb_autopm_put_interface(acm->control); - goto error_set_control; - } - - usb_autopm_put_interface(acm->control); - /* * Unthrottle device in case the TTY was closed while throttled. */ @@ -539,23 +562,27 @@ static int acm_port_activate(struct tty_port *port, struct tty_struct *tty) acm->throttle_req = 0; spin_unlock_irq(&acm->read_lock); - if (acm_submit_read_urbs(acm, GFP_KERNEL)) + retval = acm_submit_read_urbs(acm, GFP_KERNEL); + if (retval) goto error_submit_read_urbs; + usb_autopm_put_interface(acm->control); + mutex_unlock(&acm->mutex); return 0; error_submit_read_urbs: - acm->ctrlout = 0; - acm_set_control(acm, acm->ctrlout); -error_set_control: + for (i = 0; i < acm->rx_buflimit; i++) + usb_kill_urb(acm->read_urbs[i]); usb_kill_urb(acm->ctrlurb); error_submit_urb: + usb_autopm_put_interface(acm->control); error_get_interface: disconnected: mutex_unlock(&acm->mutex); - return retval; + + return usb_translate_errors(retval); } static void acm_port_destruct(struct tty_port *port) @@ -573,23 +600,37 @@ static void acm_port_destruct(struct tty_port *port) static void acm_port_shutdown(struct tty_port *port) { struct acm *acm = container_of(port, struct acm, port); + struct urb *urb; + struct acm_wb *wb; int i; dev_dbg(&acm->control->dev, "%s\n", __func__); - mutex_lock(&acm->mutex); - if (!acm->disconnected) { - usb_autopm_get_interface(acm->control); - acm_set_control(acm, acm->ctrlout = 0); - usb_kill_urb(acm->ctrlurb); - for (i = 0; i < ACM_NW; i++) - usb_kill_urb(acm->wb[i].urb); - for (i = 0; i < acm->rx_buflimit; i++) - usb_kill_urb(acm->read_urbs[i]); - acm->control->needs_remote_wakeup = 0; - usb_autopm_put_interface(acm->control); + /* + * Need to grab write_lock to prevent race with resume, but no need to + * hold it due to the tty-port initialised flag. + */ + spin_lock_irq(&acm->write_lock); + spin_unlock_irq(&acm->write_lock); + + usb_autopm_get_interface_no_resume(acm->control); + acm->control->needs_remote_wakeup = 0; + usb_autopm_put_interface(acm->control); + + for (;;) { + urb = usb_get_from_anchor(&acm->delayed); + if (!urb) + break; + wb = urb->context; + wb->use = 0; + usb_autopm_put_interface_async(acm->control); } - mutex_unlock(&acm->mutex); + + usb_kill_urb(acm->ctrlurb); + for (i = 0; i < ACM_NW; i++) + usb_kill_urb(acm->wb[i].urb); + for (i = 0; i < acm->rx_buflimit; i++) + usb_kill_urb(acm->read_urbs[i]); } static void acm_tty_cleanup(struct tty_struct *tty) @@ -646,16 +687,18 @@ static int acm_tty_write(struct tty_struct *tty, memcpy(wb->buf, buf, count); wb->len = count; - usb_autopm_get_interface_async(acm->control); + stat = usb_autopm_get_interface_async(acm->control); + if (stat) { + wb->use = 0; + spin_unlock_irqrestore(&acm->write_lock, flags); + return stat; + } + if (acm->susp_count) { - if (!acm->delayed_wb) - acm->delayed_wb = wb; - else - usb_autopm_put_interface_async(acm->control); + usb_anchor_urb(wb->urb, &acm->delayed); spin_unlock_irqrestore(&acm->write_lock, flags); - return count; /* A white lie */ + return count; } - usb_mark_last_busy(acm->dev); stat = acm_start_wb(acm, wb); spin_unlock_irqrestore(&acm->write_lock, flags); @@ -958,6 +1001,7 @@ static void acm_tty_set_termios(struct tty_struct *tty, } static const struct tty_port_operations acm_port_ops = { + .dtr_rts = acm_port_dtr_rts, .shutdown = acm_port_shutdown, .activate = acm_port_activate, .destruct = acm_port_destruct, @@ -1269,6 +1313,7 @@ made_compressed_probe: acm->bInterval = epread->bInterval; tty_port_init(&acm->port); acm->port.ops = &acm_port_ops; + init_usb_anchor(&acm->delayed); buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); if (!buf) { @@ -1394,8 +1439,6 @@ skip_countries: dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); - acm_set_control(acm, acm->ctrlout); - acm->line.dwDTERate = cpu_to_le32(9600); acm->line.bDataBits = 8; acm_set_line(acm, &acm->line); @@ -1514,27 +1557,20 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message) struct acm *acm = usb_get_intfdata(intf); int cnt; + spin_lock_irq(&acm->write_lock); if (PMSG_IS_AUTO(message)) { - int b; - - spin_lock_irq(&acm->write_lock); - b = acm->transmitting; - spin_unlock_irq(&acm->write_lock); - if (b) + if (acm->transmitting) { + spin_unlock_irq(&acm->write_lock); return -EBUSY; + } } - - spin_lock_irq(&acm->read_lock); - spin_lock(&acm->write_lock); cnt = acm->susp_count++; - spin_unlock(&acm->write_lock); - spin_unlock_irq(&acm->read_lock); + spin_unlock_irq(&acm->write_lock); if (cnt) return 0; - if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) - stop_data_traffic(acm); + stop_data_traffic(acm); return 0; } @@ -1542,29 +1578,23 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message) static int acm_resume(struct usb_interface *intf) { struct acm *acm = usb_get_intfdata(intf); - struct acm_wb *wb; + struct urb *urb; int rv = 0; - int cnt; - spin_lock_irq(&acm->read_lock); - acm->susp_count -= 1; - cnt = acm->susp_count; - spin_unlock_irq(&acm->read_lock); + spin_lock_irq(&acm->write_lock); - if (cnt) - return 0; + if (--acm->susp_count) + goto out; if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) { - rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); + rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC); - spin_lock_irq(&acm->write_lock); - if (acm->delayed_wb) { - wb = acm->delayed_wb; - acm->delayed_wb = NULL; - spin_unlock_irq(&acm->write_lock); - acm_start_wb(acm, wb); - } else { - spin_unlock_irq(&acm->write_lock); + for (;;) { + urb = usb_get_from_anchor(&acm->delayed); + if (!urb) + break; + + acm_start_wb(acm, urb->context); } /* @@ -1572,12 +1602,13 @@ static int acm_resume(struct usb_interface *intf) * do the write path at all cost */ if (rv < 0) - goto err_out; + goto out; - rv = acm_submit_read_urbs(acm, GFP_NOIO); + rv = acm_submit_read_urbs(acm, GFP_ATOMIC); } +out: + spin_unlock_irq(&acm->write_lock); -err_out: return rv; } diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index e38dc785808f..fc75651afe1c 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -120,15 +120,15 @@ struct acm { unsigned int throttled:1; /* actually throttled */ unsigned int throttle_req:1; /* throttle requested */ u8 bInterval; - struct acm_wb *delayed_wb; /* write queued for a device about to be woken */ + struct usb_anchor delayed; /* writes queued for a device about to be woken */ }; #define CDC_DATA_INTERFACE_TYPE 0x0a /* constants describing various quirks and errors */ -#define NO_UNION_NORMAL 1 -#define SINGLE_RX_URB 2 -#define NO_CAP_LINE 4 -#define NOT_A_MODEM 8 -#define NO_DATA_INTERFACE 16 -#define IGNORE_DEVICE 32 +#define NO_UNION_NORMAL BIT(0) +#define SINGLE_RX_URB BIT(1) +#define NO_CAP_LINE BIT(2) +#define NOT_A_MODEM BIT(3) +#define NO_DATA_INTERFACE BIT(4) +#define IGNORE_DEVICE BIT(5) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index cfbec9c7e09e..103a6e9ee49d 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -383,9 +383,12 @@ exit: static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t transfer_size) { int retval; - u8 buffer[USBTMC_HEADER_SIZE]; + u8 *buffer; int actual; + buffer = kmalloc(USBTMC_HEADER_SIZE, GFP_KERNEL); + if (!buffer) + return -ENOMEM; /* Setup IO buffer for REQUEST_DEV_DEP_MSG_IN message * Refer to class specs for details */ @@ -417,6 +420,7 @@ static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t t if (!data->bTag) data->bTag++; + kfree(buffer); if (retval < 0) { dev_err(&data->intf->dev, "usb_bulk_msg in send_request_dev_dep_msg_in() returned %d\n", retval); return retval; diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile new file mode 100644 index 000000000000..752646167e1e --- /dev/null +++ b/drivers/usb/common/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the usb common parts. +# + +obj-$(CONFIG_USB_COMMON) += usb-common.o +obj-$(CONFIG_USB_OTG_FSM) += usb-otg-fsm.o diff --git a/drivers/usb/usb-common.c b/drivers/usb/common/usb-common.c index 6dfd30a863c7..6dfd30a863c7 100644 --- a/drivers/usb/usb-common.c +++ b/drivers/usb/common/usb-common.c diff --git a/drivers/usb/phy/phy-fsm-usb.c b/drivers/usb/common/usb-otg-fsm.c index d03fadd2629f..98e8340a5bb1 100644 --- a/drivers/usb/phy/phy-fsm-usb.c +++ b/drivers/usb/common/usb-otg-fsm.c @@ -364,3 +364,4 @@ int otg_statemachine(struct otg_fsm *fsm) VDBG("quit statemachine, changed = %d\n", state_changed); return state_changed; } +EXPORT_SYMBOL_GPL(otg_statemachine); diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index cb8e99156f5a..1060657ca1b0 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -1,13 +1,6 @@ # # USB Core configuration # -config USB_DEBUG - bool "USB verbose debug messages" - help - Say Y here if you want the USB core & hub drivers to produce a bunch - of debug messages to the system log. Select this if you are having a - problem with USB support and want to see more of what is going on. - config USB_ANNOUNCE_NEW_DEVICES bool "USB announce new devices" help @@ -88,3 +81,12 @@ config USB_OTG_BLACKLIST_HUB and software costs by not supporting external hubs. So are "Embedded Hosts" that don't offer OTG support. +config USB_OTG_FSM + tristate "USB 2.0 OTG FSM implementation" + depends on USB + select USB_OTG + select USB_PHY + help + Implements OTG Finite State Machine as specified in On-The-Go + and Embedded Host Supplement to the USB Revision 2.0 Specification. + diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 1f02e65fe305..82044b5d6113 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -192,7 +192,6 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) if (pci_enable_device(dev) < 0) return -ENODEV; - dev->current_state = PCI_D0; /* * The xHCI driver has its own irq management diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 9c4e2922b04d..bec31e2efb88 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -918,6 +918,7 @@ static void usb_bus_init (struct usb_bus *bus) bus->bandwidth_allocated = 0; bus->bandwidth_int_reqs = 0; bus->bandwidth_isoc_reqs = 0; + mutex_init(&bus->usb_address0_mutex); INIT_LIST_HEAD (&bus->bus_list); } @@ -1502,6 +1503,9 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, ret = -EAGAIN; else urb->transfer_flags |= URB_DMA_MAP_PAGE; + } else if (is_vmalloc_addr(urb->transfer_buffer)) { + WARN_ONCE(1, "transfer buffer not dma capable\n"); + ret = -EAGAIN; } else { urb->transfer_dma = dma_map_single( hcd->self.controller, @@ -2263,9 +2267,7 @@ static void hcd_resume_work(struct work_struct *work) struct usb_hcd *hcd = container_of(work, struct usb_hcd, wakeup_work); struct usb_device *udev = hcd->self.root_hub; - usb_lock_device(udev); usb_remote_wakeup(udev); - usb_unlock_device(udev); } /** @@ -2454,11 +2456,13 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver, mutex_init(hcd->bandwidth_mutex); dev_set_drvdata(dev, hcd); } else { + mutex_lock(&usb_port_peer_mutex); hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex; hcd->primary_hcd = primary_hcd; primary_hcd->primary_hcd = primary_hcd; hcd->shared_hcd = primary_hcd; primary_hcd->shared_hcd = hcd; + mutex_unlock(&usb_port_peer_mutex); } kref_init(&hcd->kref); @@ -2510,18 +2514,25 @@ EXPORT_SYMBOL_GPL(usb_create_hcd); * deallocated. * * Make sure to only deallocate the bandwidth_mutex when the primary HCD is - * freed. When hcd_release() is called for the non-primary HCD, set the - * primary_hcd's shared_hcd pointer to null (since the non-primary HCD will be - * freed shortly). + * freed. When hcd_release() is called for either hcd in a peer set + * invalidate the peer's ->shared_hcd and ->primary_hcd pointers to + * block new peering attempts */ -static void hcd_release (struct kref *kref) +static void hcd_release(struct kref *kref) { struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref); + mutex_lock(&usb_port_peer_mutex); if (usb_hcd_is_primary_hcd(hcd)) kfree(hcd->bandwidth_mutex); - else - hcd->shared_hcd->shared_hcd = NULL; + if (hcd->shared_hcd) { + struct usb_hcd *peer = hcd->shared_hcd; + + peer->shared_hcd = NULL; + if (peer->primary_hcd == hcd) + peer->primary_hcd = NULL; + } + mutex_unlock(&usb_port_peer_mutex); kfree(hcd); } @@ -2589,6 +2600,21 @@ static int usb_hcd_request_irqs(struct usb_hcd *hcd, return 0; } +/* + * Before we free this root hub, flush in-flight peering attempts + * and disable peer lookups + */ +static void usb_put_invalidate_rhdev(struct usb_hcd *hcd) +{ + struct usb_device *rhdev; + + mutex_lock(&usb_port_peer_mutex); + rhdev = hcd->self.root_hub; + hcd->self.root_hub = NULL; + mutex_unlock(&usb_port_peer_mutex); + usb_put_dev(rhdev); +} + /** * usb_add_hcd - finish generic HCD structure initialization and register * @hcd: the usb_hcd structure to initialize @@ -2649,7 +2675,9 @@ int usb_add_hcd(struct usb_hcd *hcd, retval = -ENOMEM; goto err_allocate_root_hub; } + mutex_lock(&usb_port_peer_mutex); hcd->self.root_hub = rhdev; + mutex_unlock(&usb_port_peer_mutex); switch (hcd->speed) { case HCD_USB11: @@ -2758,7 +2786,7 @@ err_hcd_driver_start: err_request_irq: err_hcd_driver_setup: err_set_rh_speed: - usb_put_dev(hcd->self.root_hub); + usb_put_invalidate_rhdev(hcd); err_allocate_root_hub: usb_deregister_bus(&hcd->self); err_register_bus: @@ -2838,7 +2866,6 @@ void usb_remove_hcd(struct usb_hcd *hcd) free_irq(hcd->irq, hcd); } - usb_put_dev(hcd->self.root_hub); usb_deregister_bus(&hcd->self); hcd_buffer_destroy(hcd); if (hcd->remove_phy && hcd->phy) { @@ -2846,6 +2873,8 @@ void usb_remove_hcd(struct usb_hcd *hcd) usb_put_phy(hcd->phy); hcd->phy = NULL; } + + usb_put_invalidate_rhdev(hcd); } EXPORT_SYMBOL_GPL(usb_remove_hcd); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 090469ebfcff..db6287025c06 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -36,11 +36,6 @@ #define USB_VENDOR_GENESYS_LOGIC 0x05e3 #define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND 0x01 -static inline int hub_is_superspeed(struct usb_device *hdev) -{ - return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS); -} - /* Protect struct usb_device->state and ->children members * Note: Both are also protected by ->dev.sem, except that ->state can * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */ @@ -55,6 +50,9 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait); static struct task_struct *khubd_task; +/* synchronize hub-port add/remove and peering operations */ +DEFINE_MUTEX(usb_port_peer_mutex); + /* cycle leds on hubs that aren't blinking for attention */ static bool blinkenlights = 0; module_param (blinkenlights, bool, S_IRUGO); @@ -412,30 +410,35 @@ static int set_port_feature(struct usb_device *hdev, int port1, int feature) NULL, 0, 1000); } +static char *to_led_name(int selector) +{ + switch (selector) { + case HUB_LED_AMBER: + return "amber"; + case HUB_LED_GREEN: + return "green"; + case HUB_LED_OFF: + return "off"; + case HUB_LED_AUTO: + return "auto"; + default: + return "??"; + } +} + /* * USB 2.0 spec Section 11.24.2.7.1.10 and table 11-7 * for info about using port indicators */ -static void set_port_led( - struct usb_hub *hub, - int port1, - int selector -) +static void set_port_led(struct usb_hub *hub, int port1, int selector) { - int status = set_port_feature(hub->hdev, (selector << 8) | port1, + struct usb_port *port_dev = hub->ports[port1 - 1]; + int status; + + status = set_port_feature(hub->hdev, (selector << 8) | port1, USB_PORT_FEAT_INDICATOR); - if (status < 0) - dev_dbg (hub->intfdev, - "port %d indicator %s status %d\n", - port1, - ({ char *s; switch (selector) { - case HUB_LED_AMBER: s = "amber"; break; - case HUB_LED_GREEN: s = "green"; break; - case HUB_LED_OFF: s = "off"; break; - case HUB_LED_AUTO: s = "auto"; break; - default: s = "??"; break; - } s; }), - status); + dev_dbg(&port_dev->dev, "indicator %s status %d\n", + to_led_name(selector), status); } #define LED_CYCLE_PERIOD ((2*HZ)/3) @@ -743,16 +746,20 @@ int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub, int port1, bool set) { int ret; - struct usb_port *port_dev = hub->ports[port1 - 1]; if (set) ret = set_port_feature(hdev, port1, USB_PORT_FEAT_POWER); else ret = usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_POWER); - if (!ret) - port_dev->power_is_on = set; - return ret; + if (ret) + return ret; + + if (set) + set_bit(port1, hub->power_bits); + else + clear_bit(port1, hub->power_bits); + return 0; } /** @@ -810,16 +817,9 @@ int usb_hub_clear_tt_buffer(struct urb *urb) } EXPORT_SYMBOL_GPL(usb_hub_clear_tt_buffer); -/* If do_delay is false, return the number of milliseconds the caller - * needs to delay. - */ -static unsigned hub_power_on(struct usb_hub *hub, bool do_delay) +static void hub_power_on(struct usb_hub *hub, bool do_delay) { int port1; - unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2; - unsigned delay; - u16 wHubCharacteristics = - le16_to_cpu(hub->descriptor->wHubCharacteristics); /* Enable power on each port. Some hubs have reserved values * of LPSM (> 2) in their descriptors, even though they are @@ -827,23 +827,19 @@ static unsigned hub_power_on(struct usb_hub *hub, bool do_delay) * but only emulate it. In all cases, the ports won't work * unless we send these messages to the hub. */ - if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2) + if (hub_is_port_power_switchable(hub)) dev_dbg(hub->intfdev, "enabling power on all ports\n"); else dev_dbg(hub->intfdev, "trying to enable port power on " "non-switchable hub\n"); for (port1 = 1; port1 <= hub->hdev->maxchild; port1++) - if (hub->ports[port1 - 1]->power_is_on) + if (test_bit(port1, hub->power_bits)) set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER); else usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER); - - /* Wait at least 100 msec for power to become stable */ - delay = max(pgood_delay, (unsigned) 100); if (do_delay) - msleep(delay); - return delay; + msleep(hub_power_on_good_delay(hub)); } static int hub_hub_status(struct usb_hub *hub, @@ -911,20 +907,20 @@ static int hub_usb3_port_disable(struct usb_hub *hub, int port1) msleep(HUB_DEBOUNCE_STEP); } if (total_time >= HUB_DEBOUNCE_TIMEOUT) - dev_warn(hub->intfdev, "Could not disable port %d after %d ms\n", - port1, total_time); + dev_warn(&hub->ports[port1 - 1]->dev, + "Could not disable after %d ms\n", total_time); return hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_RX_DETECT); } static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) { + struct usb_port *port_dev = hub->ports[port1 - 1]; struct usb_device *hdev = hub->hdev; int ret = 0; - if (hub->ports[port1 - 1]->child && set_state) - usb_set_device_state(hub->ports[port1 - 1]->child, - USB_STATE_NOTATTACHED); + if (port_dev->child && set_state) + usb_set_device_state(port_dev->child, USB_STATE_NOTATTACHED); if (!hub->error) { if (hub_is_superspeed(hub->hdev)) ret = hub_usb3_port_disable(hub, port1); @@ -933,8 +929,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) USB_PORT_FEAT_ENABLE); } if (ret && ret != -ENODEV) - dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", - port1, ret); + dev_err(&port_dev->dev, "cannot disable (err = %d)\n", ret); return ret; } @@ -945,7 +940,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) */ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1) { - dev_dbg(hub->intfdev, "logical disconnect on port %d\n", port1); + dev_dbg(&hub->ports[port1 - 1]->dev, "logical disconnect\n"); hub_port_disable(hub, port1, 1); /* FIXME let caller ask to power down the port: @@ -1048,7 +1043,9 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) * for HUB_POST_RESET, but it's easier not to. */ if (type == HUB_INIT) { - delay = hub_power_on(hub, false); + unsigned delay = hub_power_on_good_delay(hub); + + hub_power_on(hub, false); INIT_DELAYED_WORK(&hub->init_work, hub_init_func2); queue_delayed_work(system_power_efficient_wq, &hub->init_work, @@ -1083,21 +1080,23 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) } init2: - /* Check each port and set hub->change_bits to let khubd know + /* + * Check each port and set hub->change_bits to let khubd know * which ports need attention. */ for (port1 = 1; port1 <= hdev->maxchild; ++port1) { - struct usb_device *udev = hub->ports[port1 - 1]->child; + struct usb_port *port_dev = hub->ports[port1 - 1]; + struct usb_device *udev = port_dev->child; u16 portstatus, portchange; portstatus = portchange = 0; status = hub_port_status(hub, port1, &portstatus, &portchange); if (udev || (portstatus & USB_PORT_STAT_CONNECTION)) - dev_dbg(hub->intfdev, - "port %d: status %04x change %04x\n", - port1, portstatus, portchange); + dev_dbg(&port_dev->dev, "status %04x change %04x\n", + portstatus, portchange); - /* After anything other than HUB_RESUME (i.e., initialization + /* + * After anything other than HUB_RESUME (i.e., initialization * or any sort of reset), every port should be disabled. * Unconnected ports should likewise be disabled (paranoia), * and so should ports for which we have no usb_device. @@ -1173,15 +1172,13 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) set_bit(port1, hub->change_bits); } else if (udev->persist_enabled) { - struct usb_port *port_dev = hub->ports[port1 - 1]; - #ifdef CONFIG_PM udev->reset_resume = 1; #endif /* Don't set the change_bits when the device * was powered off. */ - if (port_dev->power_is_on) + if (test_bit(port1, hub->power_bits)) set_bit(port1, hub->change_bits); } else { @@ -1276,12 +1273,22 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type) flush_work(&hub->tt.clear_work); } +static void hub_pm_barrier_for_all_ports(struct usb_hub *hub) +{ + int i; + + for (i = 0; i < hub->hdev->maxchild; ++i) + pm_runtime_barrier(&hub->ports[i]->dev); +} + /* caller has locked the hub device */ static int hub_pre_reset(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata(intf); hub_quiesce(hub, HUB_PRE_RESET); + hub->in_reset = 1; + hub_pm_barrier_for_all_ports(hub); return 0; } @@ -1290,6 +1297,8 @@ static int hub_post_reset(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata(intf); + hub->in_reset = 0; + hub_pm_barrier_for_all_ports(hub); hub_activate(hub, HUB_POST_RESET); return 0; } @@ -1307,6 +1316,7 @@ static int hub_configure(struct usb_hub *hub, char *message = "out of memory"; unsigned unit_load; unsigned full_load; + unsigned maxchild; hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL); if (!hub->buffer) { @@ -1345,12 +1355,11 @@ static int hub_configure(struct usb_hub *hub, goto fail; } - hdev->maxchild = hub->descriptor->bNbrPorts; - dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild, - (hdev->maxchild == 1) ? "" : "s"); + maxchild = hub->descriptor->bNbrPorts; + dev_info(hub_dev, "%d port%s detected\n", maxchild, + (maxchild == 1) ? "" : "s"); - hub->ports = kzalloc(hdev->maxchild * sizeof(struct usb_port *), - GFP_KERNEL); + hub->ports = kzalloc(maxchild * sizeof(struct usb_port *), GFP_KERNEL); if (!hub->ports) { ret = -ENOMEM; goto fail; @@ -1371,11 +1380,11 @@ static int hub_configure(struct usb_hub *hub, int i; char portstr[USB_MAXCHILDREN + 1]; - for (i = 0; i < hdev->maxchild; i++) + for (i = 0; i < maxchild; i++) portstr[i] = hub->descriptor->u.hs.DeviceRemovable [((i + 1) / 8)] & (1 << ((i + 1) % 8)) ? 'F' : 'R'; - portstr[hdev->maxchild] = 0; + portstr[maxchild] = 0; dev_dbg(hub_dev, "compound device; port removable status: %s\n", portstr); } else dev_dbg(hub_dev, "standalone hub\n"); @@ -1487,7 +1496,7 @@ static int hub_configure(struct usb_hub *hub, if (hcd->power_budget > 0) hdev->bus_mA = hcd->power_budget; else - hdev->bus_mA = full_load * hdev->maxchild; + hdev->bus_mA = full_load * maxchild; if (hdev->bus_mA >= full_load) hub->mA_per_port = full_load; else { @@ -1502,7 +1511,7 @@ static int hub_configure(struct usb_hub *hub, hub->descriptor->bHubContrCurrent); hub->limited_power = 1; - if (remaining < hdev->maxchild * unit_load) + if (remaining < maxchild * unit_load) dev_warn(hub_dev, "insufficient power available " "to use all downstream ports\n"); @@ -1570,15 +1579,19 @@ static int hub_configure(struct usb_hub *hub, if (hub->has_indicators && blinkenlights) hub->indicator[0] = INDICATOR_CYCLE; - for (i = 0; i < hdev->maxchild; i++) { + mutex_lock(&usb_port_peer_mutex); + for (i = 0; i < maxchild; i++) { ret = usb_hub_create_port_device(hub, i + 1); if (ret < 0) { dev_err(hub->intfdev, "couldn't create port%d device.\n", i + 1); - hdev->maxchild = i; - goto fail_keep_maxchild; + break; } } + hdev->maxchild = i; + mutex_unlock(&usb_port_peer_mutex); + if (ret < 0) + goto fail; usb_hub_adjust_deviceremovable(hdev, hub->descriptor); @@ -1586,8 +1599,6 @@ static int hub_configure(struct usb_hub *hub, return 0; fail: - hdev->maxchild = 0; -fail_keep_maxchild: dev_err (hub_dev, "config failed, %s (err %d)\n", message, ret); /* hub_disconnect() frees urb and descriptor */ @@ -1623,6 +1634,8 @@ static void hub_disconnect(struct usb_interface *intf) hub->error = 0; hub_quiesce(hub, HUB_DISCONNECT); + mutex_lock(&usb_port_peer_mutex); + /* Avoid races with recursively_mark_NOTATTACHED() */ spin_lock_irq(&device_state_lock); port1 = hdev->maxchild; @@ -1633,6 +1646,8 @@ static void hub_disconnect(struct usb_interface *intf) for (; port1 > 0; --port1) usb_hub_remove_port_device(hub, port1); + mutex_unlock(&usb_port_peer_mutex); + if (hub->hdev->speed == USB_SPEED_HIGH) highspeed_hubs--; @@ -2024,6 +2039,18 @@ static void hub_free_dev(struct usb_device *udev) hcd->driver->free_dev(hcd, udev); } +static void hub_disconnect_children(struct usb_device *udev) +{ + struct usb_hub *hub = usb_hub_to_struct_hub(udev); + int i; + + /* Free up all the children before we remove this device */ + for (i = 0; i < udev->maxchild; i++) { + if (hub->ports[i]->child) + usb_disconnect(&hub->ports[i]->child); + } +} + /** * usb_disconnect - disconnect a device (usbcore-internal) * @pdev: pointer to device being disconnected @@ -2042,9 +2069,10 @@ static void hub_free_dev(struct usb_device *udev) */ void usb_disconnect(struct usb_device **pdev) { - struct usb_device *udev = *pdev; - struct usb_hub *hub = usb_hub_to_struct_hub(udev); - int i; + struct usb_port *port_dev = NULL; + struct usb_device *udev = *pdev; + struct usb_hub *hub; + int port1; /* mark the device as inactive, so any further urb submissions for * this device (and any of its children) will fail immediately. @@ -2056,11 +2084,7 @@ void usb_disconnect(struct usb_device **pdev) usb_lock_device(udev); - /* Free up all the children before we remove this device */ - for (i = 0; i < udev->maxchild; i++) { - if (hub->ports[i]->child) - usb_disconnect(&hub->ports[i]->child); - } + hub_disconnect_children(udev); /* deallocate hcd/hardware state ... nuking all pending urbs and * cleaning up all state associated with the current configuration @@ -2071,16 +2095,19 @@ void usb_disconnect(struct usb_device **pdev) usb_hcd_synchronize_unlinks(udev); if (udev->parent) { - struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); - struct usb_port *port_dev = hub->ports[udev->portnum - 1]; + port1 = udev->portnum; + hub = usb_hub_to_struct_hub(udev->parent); + port_dev = hub->ports[port1 - 1]; sysfs_remove_link(&udev->dev.kobj, "port"); sysfs_remove_link(&port_dev->dev.kobj, "device"); - if (!port_dev->did_runtime_put) - pm_runtime_put(&port_dev->dev); - else - port_dev->did_runtime_put = false; + /* + * As usb_port_runtime_resume() de-references udev, make + * sure no resumes occur during removal + */ + if (!test_and_set_bit(port1, hub->child_usage_bits)) + pm_runtime_get_sync(&port_dev->dev); } usb_remove_ep_devs(&udev->ep0); @@ -2102,6 +2129,9 @@ void usb_disconnect(struct usb_device **pdev) *pdev = NULL; spin_unlock_irq(&device_state_lock); + if (port_dev && test_and_clear_bit(port1, hub->child_usage_bits)) + pm_runtime_put(&port_dev->dev); + hub_free_dev(udev); put_device(&udev->dev); @@ -2289,6 +2319,22 @@ static void set_usb_port_removable(struct usb_device *udev) udev->removable = USB_DEVICE_REMOVABLE; else udev->removable = USB_DEVICE_FIXED; + + /* + * Platform firmware may have populated an alternative value for + * removable. If the parent port has a known connect_type use + * that instead. + */ + switch (hub->ports[udev->portnum - 1]->connect_type) { + case USB_PORT_CONNECT_TYPE_HOT_PLUG: + udev->removable = USB_DEVICE_REMOVABLE; + break; + case USB_PORT_CONNECT_TYPE_HARD_WIRED: + udev->removable = USB_DEVICE_FIXED; + break; + default: /* use what was set above */ + break; + } } /** @@ -2358,11 +2404,7 @@ int usb_new_device(struct usb_device *udev) device_enable_async_suspend(&udev->dev); - /* - * check whether the hub marks this port as non-removable. Do it - * now so that platform-specific data can override it in - * device_add() - */ + /* check whether the hub or firmware marks this port as non-removable */ if (udev->parent) set_usb_port_removable(udev); @@ -2379,7 +2421,8 @@ int usb_new_device(struct usb_device *udev) /* Create link files between child device and usb port device. */ if (udev->parent) { struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); - struct usb_port *port_dev = hub->ports[udev->portnum - 1]; + int port1 = udev->portnum; + struct usb_port *port_dev = hub->ports[port1 - 1]; err = sysfs_create_link(&udev->dev.kobj, &port_dev->dev.kobj, "port"); @@ -2393,7 +2436,8 @@ int usb_new_device(struct usb_device *udev) goto fail; } - pm_runtime_get_sync(&port_dev->dev); + if (!test_and_set_bit(port1, hub->child_usage_bits)) + pm_runtime_get_sync(&port_dev->dev); } (void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev); @@ -2561,9 +2605,9 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, if (delay_time >= 2 * HUB_SHORT_RESET_TIME) delay = HUB_LONG_RESET_TIME; - dev_dbg (hub->intfdev, - "port %d not %sreset yet, waiting %dms\n", - port1, warm ? "warm " : "", delay); + dev_dbg(&hub->ports[port1 - 1]->dev, + "not %sreset yet, waiting %dms\n", + warm ? "warm " : "", delay); } if ((portstatus & USB_PORT_STAT_RESET)) @@ -2647,6 +2691,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1, { int i, status; u16 portchange, portstatus; + struct usb_port *port_dev = hub->ports[port1 - 1]; if (!hub_is_superspeed(hub->hdev)) { if (warm) { @@ -2680,9 +2725,9 @@ static int hub_port_reset(struct usb_hub *hub, int port1, if (status == -ENODEV) { ; /* The hub is gone */ } else if (status) { - dev_err(hub->intfdev, - "cannot %sreset port %d (err = %d)\n", - warm ? "warm " : "", port1, status); + dev_err(&port_dev->dev, + "cannot %sreset (err = %d)\n", + warm ? "warm " : "", status); } else { status = hub_port_wait_reset(hub, port1, udev, delay, warm); @@ -2715,21 +2760,19 @@ static int hub_port_reset(struct usb_hub *hub, int port1, * hot or warm reset failed. Try another warm reset. */ if (!warm) { - dev_dbg(hub->intfdev, "hot reset failed, warm reset port %d\n", - port1); + dev_dbg(&port_dev->dev, + "hot reset failed, warm reset\n"); warm = true; } } - dev_dbg (hub->intfdev, - "port %d not enabled, trying %sreset again...\n", - port1, warm ? "warm " : ""); + dev_dbg(&port_dev->dev, + "not enabled, trying %sreset again...\n", + warm ? "warm " : ""); delay = HUB_LONG_RESET_TIME; } - dev_err (hub->intfdev, - "Cannot enable port %i. Maybe the USB cable is bad?\n", - port1); + dev_err(&port_dev->dev, "Cannot enable. Maybe the USB cable is bad?\n"); done: if (!hub_is_superspeed(hub->hdev)) @@ -2754,6 +2797,20 @@ static int port_is_power_on(struct usb_hub *hub, unsigned portstatus) return ret; } +static void usb_lock_port(struct usb_port *port_dev) + __acquires(&port_dev->status_lock) +{ + mutex_lock(&port_dev->status_lock); + __acquire(&port_dev->status_lock); +} + +static void usb_unlock_port(struct usb_port *port_dev) + __releases(&port_dev->status_lock) +{ + mutex_unlock(&port_dev->status_lock); + __release(&port_dev->status_lock); +} + #ifdef CONFIG_PM /* Check if a port is suspended(USB2.0 port) or in U3 state(USB3.0 port) */ @@ -2780,6 +2837,8 @@ static int check_port_resume_type(struct usb_device *udev, struct usb_hub *hub, int port1, int status, unsigned portchange, unsigned portstatus) { + struct usb_port *port_dev = hub->ports[port1 - 1]; + /* Is the device still present? */ if (status || port_is_suspended(hub, portstatus) || !port_is_power_on(hub, portstatus) || @@ -2799,9 +2858,8 @@ static int check_port_resume_type(struct usb_device *udev, } if (status) { - dev_dbg(hub->intfdev, - "port %d status %04x.%04x after resume, %d\n", - port1, portchange, portstatus, status); + dev_dbg(&port_dev->dev, "status %04x.%04x after resume, %d\n", + portchange, portstatus, status); } else if (udev->reset_resume) { /* Late port handoff can set status-change bits */ @@ -2975,6 +3033,8 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) int status; bool really_suspend = true; + usb_lock_port(port_dev); + /* enable remote wakeup when appropriate; this lets the device * wake up the upstream hub (including maybe the root hub). * @@ -3032,8 +3092,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) status = 0; } if (status) { - dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n", - port1, status); + dev_dbg(&port_dev->dev, "can't suspend, status %d\n", status); /* Try to enable USB3 LPM and LTM again */ usb_unlocked_enable_lpm(udev); @@ -3064,12 +3123,13 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) usb_set_device_state(udev, USB_STATE_SUSPENDED); } - if (status == 0 && !udev->do_remote_wakeup && udev->persist_enabled) { + if (status == 0 && !udev->do_remote_wakeup && udev->persist_enabled + && test_and_clear_bit(port1, hub->child_usage_bits)) pm_runtime_put_sync(&port_dev->dev); - port_dev->did_runtime_put = true; - } usb_mark_last_busy(hub->hdev); + + usb_unlock_port(port_dev); return status; } @@ -3209,9 +3269,8 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) int status; u16 portchange, portstatus; - if (port_dev->did_runtime_put) { + if (!test_and_set_bit(port1, hub->child_usage_bits)) { status = pm_runtime_get_sync(&port_dev->dev); - port_dev->did_runtime_put = false; if (status < 0) { dev_dbg(&udev->dev, "can't resume usb port, status %d\n", status); @@ -3219,15 +3278,13 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) } } + usb_lock_port(port_dev); + /* Skip the initial Clear-Suspend step for a remote wakeup */ status = hub_port_status(hub, port1, &portstatus, &portchange); if (status == 0 && !port_is_suspended(hub, portstatus)) goto SuspendCleared; - /* dev_dbg(hub->intfdev, "resume port %d\n", port1); */ - - set_bit(port1, hub->busy_bits); - /* see 7.1.7.7; affects power usage, but not budgeting */ if (hub_is_superspeed(hub->hdev)) status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U0); @@ -3235,8 +3292,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) status = usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_SUSPEND); if (status) { - dev_dbg(hub->intfdev, "can't resume port %d, status %d\n", - port1, status); + dev_dbg(&port_dev->dev, "can't resume, status %d\n", status); } else { /* drive resume for at least 20 msec */ dev_dbg(&udev->dev, "usb %sresume\n", @@ -3267,8 +3323,6 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) } } - clear_bit(port1, hub->busy_bits); - status = check_port_resume_type(udev, hub, port1, status, portchange, portstatus); if (status == 0) @@ -3286,16 +3340,18 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) usb_unlocked_enable_lpm(udev); } + usb_unlock_port(port_dev); + return status; } #ifdef CONFIG_PM_RUNTIME -/* caller has locked udev */ int usb_remote_wakeup(struct usb_device *udev) { int status = 0; + usb_lock_device(udev); if (udev->state == USB_STATE_SUSPENDED) { dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-"); status = usb_autoresume_device(udev); @@ -3304,9 +3360,59 @@ int usb_remote_wakeup(struct usb_device *udev) usb_autosuspend_device(udev); } } + usb_unlock_device(udev); return status; } +/* Returns 1 if there was a remote wakeup and a connect status change. */ +static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, + u16 portstatus, u16 portchange) + __must_hold(&port_dev->status_lock) +{ + struct usb_port *port_dev = hub->ports[port - 1]; + struct usb_device *hdev; + struct usb_device *udev; + int connect_change = 0; + int ret; + + hdev = hub->hdev; + udev = port_dev->child; + if (!hub_is_superspeed(hdev)) { + if (!(portchange & USB_PORT_STAT_C_SUSPEND)) + return 0; + usb_clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND); + } else { + if (!udev || udev->state != USB_STATE_SUSPENDED || + (portstatus & USB_PORT_STAT_LINK_STATE) != + USB_SS_PORT_LS_U0) + return 0; + } + + if (udev) { + /* TRSMRCY = 10 msec */ + msleep(10); + + usb_unlock_port(port_dev); + ret = usb_remote_wakeup(udev); + usb_lock_port(port_dev); + if (ret < 0) + connect_change = 1; + } else { + ret = -ENODEV; + hub_port_disable(hub, port, 1); + } + dev_dbg(&port_dev->dev, "resume, status %d\n", ret); + return connect_change; +} + +#else + +static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, + u16 portstatus, u16 portchange) +{ + return 0; +} + #endif static int check_ports_changed(struct usb_hub *hub) @@ -3337,12 +3443,11 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) */ hub->wakeup_enabled_descendants = 0; for (port1 = 1; port1 <= hdev->maxchild; port1++) { - struct usb_device *udev; + struct usb_port *port_dev = hub->ports[port1 - 1]; + struct usb_device *udev = port_dev->child; - udev = hub->ports[port1 - 1]->child; if (udev && udev->can_submit) { - dev_warn(&intf->dev, "port %d not suspended yet\n", - port1); + dev_warn(&port_dev->dev, "not suspended yet\n"); if (PMSG_IS_AUTO(msg)) return -EBUSY; } @@ -3861,6 +3966,12 @@ EXPORT_SYMBOL_GPL(usb_disable_ltm); void usb_enable_ltm(struct usb_device *udev) { } EXPORT_SYMBOL_GPL(usb_enable_ltm); +static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, + u16 portstatus, u16 portchange) +{ + return 0; +} + #endif /* CONFIG_PM */ @@ -3882,9 +3993,10 @@ EXPORT_SYMBOL_GPL(usb_enable_ltm); int hub_port_debounce(struct usb_hub *hub, int port1, bool must_be_connected) { int ret; - int total_time, stable_time = 0; u16 portchange, portstatus; unsigned connection = 0xffff; + int total_time, stable_time = 0; + struct usb_port *port_dev = hub->ports[port1 - 1]; for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) { ret = hub_port_status(hub, port1, &portstatus, &portchange); @@ -3913,9 +4025,8 @@ int hub_port_debounce(struct usb_hub *hub, int port1, bool must_be_connected) msleep(HUB_DEBOUNCE_STEP); } - dev_dbg (hub->intfdev, - "debounce: port %d: total %dms stable %dms status 0x%x\n", - port1, total_time, stable_time, portstatus); + dev_dbg(&port_dev->dev, "debounce total %dms stable %dms status 0x%x\n", + total_time, stable_time, portstatus); if (stable_time < HUB_DEBOUNCE_STABLE) return -ETIMEDOUT; @@ -3974,13 +4085,14 @@ static int hub_set_address(struct usb_device *udev, int devnum) */ static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev) { - int connect_type; + struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); + int connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN; if (!udev->usb2_hw_lpm_capable) return; - connect_type = usb_get_hub_port_connect_type(udev->parent, - udev->portnum); + if (hub) + connect_type = hub->ports[udev->portnum - 1]->connect_type; if ((udev->bos->ext_cap->bmAttributes & cpu_to_le32(USB_BESL_SUPPORT)) || connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) { @@ -4008,16 +4120,15 @@ static int hub_enable_device(struct usb_device *udev) * Returns device in USB_STATE_ADDRESS, except on error. * * If this is called for an already-existing device (as part of - * usb_reset_and_verify_device), the caller must own the device lock. For a - * newly detected device that is not accessible through any global - * pointers, it's not necessary to lock the device. + * usb_reset_and_verify_device), the caller must own the device lock and + * the port lock. For a newly detected device that is not accessible + * through any global pointers, it's not necessary to lock the device, + * but it is still necessary to lock the port. */ static int hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, int retry_counter) { - static DEFINE_MUTEX(usb_address0_mutex); - struct usb_device *hdev = hub->hdev; struct usb_hcd *hcd = bus_to_hcd(hdev->bus); int i, j, retval; @@ -4040,7 +4151,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, if (oldspeed == USB_SPEED_LOW) delay = HUB_LONG_RESET_TIME; - mutex_lock(&usb_address0_mutex); + mutex_lock(&hdev->bus->usb_address0_mutex); /* Reset the device; full speed may morph to high speed */ /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */ @@ -4317,7 +4428,7 @@ fail: hub_port_disable(hub, port1, 0); update_devnum(udev, devnum); /* for disconnect processing */ } - mutex_unlock(&usb_address0_mutex); + mutex_unlock(&hdev->bus->usb_address0_mutex); return retval; } @@ -4358,9 +4469,10 @@ hub_power_remaining (struct usb_hub *hub) remaining = hdev->bus_mA - hub->descriptor->bHubContrCurrent; for (port1 = 1; port1 <= hdev->maxchild; ++port1) { - struct usb_device *udev = hub->ports[port1 - 1]->child; - int delta; - unsigned unit_load; + struct usb_port *port_dev = hub->ports[port1 - 1]; + struct usb_device *udev = port_dev->child; + unsigned unit_load; + int delta; if (!udev) continue; @@ -4380,9 +4492,8 @@ hub_power_remaining (struct usb_hub *hub) else delta = 8; if (delta > hub->mA_per_port) - dev_warn(&udev->dev, - "%dmA is over %umA budget for port %d!\n", - delta, hub->mA_per_port, port1); + dev_warn(&port_dev->dev, "%dmA is over %umA budget!\n", + delta, hub->mA_per_port); remaining -= delta; } if (remaining < 0) { @@ -4393,78 +4504,23 @@ hub_power_remaining (struct usb_hub *hub) return remaining; } -/* Handle physical or logical connection change events. - * This routine is called when: - * a port connection-change occurs; - * a port enable-change occurs (often caused by EMI); - * usb_reset_and_verify_device() encounters changed descriptors (as from - * a firmware download) - * caller already locked the hub - */ -static void hub_port_connect_change(struct usb_hub *hub, int port1, - u16 portstatus, u16 portchange) +static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, + u16 portchange) { - struct usb_device *hdev = hub->hdev; - struct device *hub_dev = hub->intfdev; - struct usb_hcd *hcd = bus_to_hcd(hdev->bus); - unsigned wHubCharacteristics = - le16_to_cpu(hub->descriptor->wHubCharacteristics); - struct usb_device *udev; int status, i; unsigned unit_load; - - dev_dbg (hub_dev, - "port %d, status %04x, change %04x, %s\n", - port1, portstatus, portchange, portspeed(hub, portstatus)); - - if (hub->has_indicators) { - set_port_led(hub, port1, HUB_LED_AUTO); - hub->indicator[port1-1] = INDICATOR_AUTO; - } - -#ifdef CONFIG_USB_OTG - /* during HNP, don't repeat the debounce */ - if (hdev->bus->is_b_host) - portchange &= ~(USB_PORT_STAT_C_CONNECTION | - USB_PORT_STAT_C_ENABLE); -#endif - - /* Try to resuscitate an existing device */ - udev = hub->ports[port1 - 1]->child; - if ((portstatus & USB_PORT_STAT_CONNECTION) && udev && - udev->state != USB_STATE_NOTATTACHED) { - usb_lock_device(udev); - if (portstatus & USB_PORT_STAT_ENABLE) { - status = 0; /* Nothing to do */ - -#ifdef CONFIG_PM_RUNTIME - } else if (udev->state == USB_STATE_SUSPENDED && - udev->persist_enabled) { - /* For a suspended device, treat this as a - * remote wakeup event. - */ - status = usb_remote_wakeup(udev); -#endif - - } else { - status = -ENODEV; /* Don't resuscitate */ - } - usb_unlock_device(udev); - - if (status == 0) { - clear_bit(port1, hub->change_bits); - return; - } - } + struct usb_device *hdev = hub->hdev; + struct usb_hcd *hcd = bus_to_hcd(hdev->bus); + struct usb_port *port_dev = hub->ports[port1 - 1]; + struct usb_device *udev = port_dev->child; /* Disconnect any existing devices under this port */ if (udev) { if (hcd->phy && !hdev->parent && !(portstatus & USB_PORT_STAT_CONNECTION)) usb_phy_notify_disconnect(hcd->phy, udev->speed); - usb_disconnect(&hub->ports[port1 - 1]->child); + usb_disconnect(&port_dev->child); } - clear_bit(port1, hub->change_bits); /* We can forget about a "removed" device when there's a physical * disconnect or the connect status changes. @@ -4478,8 +4534,8 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, status = hub_port_debounce_be_stable(hub, port1); if (status < 0) { if (status != -ENODEV && printk_ratelimit()) - dev_err(hub_dev, "connect-debounce failed, " - "port %d disabled\n", port1); + dev_err(&port_dev->dev, + "connect-debounce failed\n"); portstatus &= ~USB_PORT_STAT_CONNECTION; } else { portstatus = status; @@ -4493,7 +4549,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, test_bit(port1, hub->removed_bits)) { /* maybe switch power back on (e.g. root hub was reset) */ - if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2 + if (hub_is_port_power_switchable(hub) && !port_is_power_on(hub, portstatus)) set_port_feature(hdev, port1, USB_PORT_FEAT_POWER); @@ -4514,9 +4570,8 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, */ udev = usb_alloc_dev(hdev, hdev->bus, port1); if (!udev) { - dev_err (hub_dev, - "couldn't allocate port %d usb_device\n", - port1); + dev_err(&port_dev->dev, + "couldn't allocate usb_device\n"); goto done; } @@ -4538,7 +4593,9 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, } /* reset (non-USB 3.0 devices) and get descriptor */ + usb_lock_port(port_dev); status = hub_port_init(hub, udev, port1, i); + usb_unlock_port(port_dev); if (status < 0) goto loop; @@ -4590,6 +4647,8 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, */ status = 0; + mutex_lock(&usb_port_peer_mutex); + /* We mustn't add new devices if the parent hub has * been disconnected; we would race with the * recursively_mark_NOTATTACHED() routine. @@ -4598,16 +4657,19 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, if (hdev->state == USB_STATE_NOTATTACHED) status = -ENOTCONN; else - hub->ports[port1 - 1]->child = udev; + port_dev->child = udev; spin_unlock_irq(&device_state_lock); + mutex_unlock(&usb_port_peer_mutex); /* Run it through the hoops (find a driver, etc) */ if (!status) { status = usb_new_device(udev); if (status) { + mutex_lock(&usb_port_peer_mutex); spin_lock_irq(&device_state_lock); - hub->ports[port1 - 1]->child = NULL; + port_dev->child = NULL; spin_unlock_irq(&device_state_lock); + mutex_unlock(&usb_port_peer_mutex); } } @@ -4616,7 +4678,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, status = hub_power_remaining(hub); if (status) - dev_dbg(hub_dev, "%dmA power budget left\n", status); + dev_dbg(hub->intfdev, "%dmA power budget left\n", status); return; @@ -4634,56 +4696,200 @@ loop: !hcd->driver->port_handed_over || !(hcd->driver->port_handed_over)(hcd, port1)) { if (status != -ENOTCONN && status != -ENODEV) - dev_err(hub_dev, "unable to enumerate USB device on port %d\n", - port1); + dev_err(&port_dev->dev, + "unable to enumerate USB device\n"); } done: hub_port_disable(hub, port1, 1); if (hcd->driver->relinquish_port && !hub->hdev->parent) hcd->driver->relinquish_port(hcd, port1); + } -/* Returns 1 if there was a remote wakeup and a connect status change. */ -static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, - u16 portstatus, u16 portchange) +/* Handle physical or logical connection change events. + * This routine is called when: + * a port connection-change occurs; + * a port enable-change occurs (often caused by EMI); + * usb_reset_and_verify_device() encounters changed descriptors (as from + * a firmware download) + * caller already locked the hub + */ +static void hub_port_connect_change(struct usb_hub *hub, int port1, + u16 portstatus, u16 portchange) + __must_hold(&port_dev->status_lock) { - struct usb_device *hdev; - struct usb_device *udev; - int connect_change = 0; - int ret; + struct usb_port *port_dev = hub->ports[port1 - 1]; + struct usb_device *udev = port_dev->child; + int status = -ENODEV; - hdev = hub->hdev; - udev = hub->ports[port - 1]->child; - if (!hub_is_superspeed(hdev)) { - if (!(portchange & USB_PORT_STAT_C_SUSPEND)) - return 0; - usb_clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND); - } else { - if (!udev || udev->state != USB_STATE_SUSPENDED || - (portstatus & USB_PORT_STAT_LINK_STATE) != - USB_SS_PORT_LS_U0) - return 0; + dev_dbg(&port_dev->dev, "status %04x, change %04x, %s\n", portstatus, + portchange, portspeed(hub, portstatus)); + + if (hub->has_indicators) { + set_port_led(hub, port1, HUB_LED_AUTO); + hub->indicator[port1-1] = INDICATOR_AUTO; } - if (udev) { - /* TRSMRCY = 10 msec */ - msleep(10); +#ifdef CONFIG_USB_OTG + /* during HNP, don't repeat the debounce */ + if (hub->hdev->bus->is_b_host) + portchange &= ~(USB_PORT_STAT_C_CONNECTION | + USB_PORT_STAT_C_ENABLE); +#endif + + /* Try to resuscitate an existing device */ + if ((portstatus & USB_PORT_STAT_CONNECTION) && udev && + udev->state != USB_STATE_NOTATTACHED) { + if (portstatus & USB_PORT_STAT_ENABLE) { + status = 0; /* Nothing to do */ +#ifdef CONFIG_PM_RUNTIME + } else if (udev->state == USB_STATE_SUSPENDED && + udev->persist_enabled) { + /* For a suspended device, treat this as a + * remote wakeup event. + */ + usb_unlock_port(port_dev); + status = usb_remote_wakeup(udev); + usb_lock_port(port_dev); +#endif + } else { + /* Don't resuscitate */; + } + } + clear_bit(port1, hub->change_bits); + + /* successfully revalidated the connection */ + if (status == 0) + return; + + usb_unlock_port(port_dev); + hub_port_connect(hub, port1, portstatus, portchange); + usb_lock_port(port_dev); +} + +static void port_event(struct usb_hub *hub, int port1) + __must_hold(&port_dev->status_lock) +{ + int connect_change, reset_device = 0; + struct usb_port *port_dev = hub->ports[port1 - 1]; + struct usb_device *udev = port_dev->child; + struct usb_device *hdev = hub->hdev; + u16 portstatus, portchange; + + connect_change = test_bit(port1, hub->change_bits); + clear_bit(port1, hub->event_bits); + clear_bit(port1, hub->wakeup_bits); + + if (hub_port_status(hub, port1, &portstatus, &portchange) < 0) + return; + + if (portchange & USB_PORT_STAT_C_CONNECTION) { + usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION); + connect_change = 1; + } + + if (portchange & USB_PORT_STAT_C_ENABLE) { + if (!connect_change) + dev_dbg(&port_dev->dev, "enable change, status %08x\n", + portstatus); + usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE); + + /* + * EM interference sometimes causes badly shielded USB devices + * to be shutdown by the hub, this hack enables them again. + * Works at least with mouse driver. + */ + if (!(portstatus & USB_PORT_STAT_ENABLE) + && !connect_change && udev) { + dev_err(&port_dev->dev, "disabled by hub (EMI?), re-enabling...\n"); + connect_change = 1; + } + } + + if (portchange & USB_PORT_STAT_C_OVERCURRENT) { + u16 status = 0, unused; + + dev_dbg(&port_dev->dev, "over-current change\n"); + usb_clear_port_feature(hdev, port1, + USB_PORT_FEAT_C_OVER_CURRENT); + msleep(100); /* Cool down */ + hub_power_on(hub, true); + hub_port_status(hub, port1, &status, &unused); + if (status & USB_PORT_STAT_OVERCURRENT) + dev_err(&port_dev->dev, "over-current condition\n"); + } + + if (portchange & USB_PORT_STAT_C_RESET) { + dev_dbg(&port_dev->dev, "reset change\n"); + usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_RESET); + } + if ((portchange & USB_PORT_STAT_C_BH_RESET) + && hub_is_superspeed(hdev)) { + dev_dbg(&port_dev->dev, "warm reset change\n"); + usb_clear_port_feature(hdev, port1, + USB_PORT_FEAT_C_BH_PORT_RESET); + } + if (portchange & USB_PORT_STAT_C_LINK_STATE) { + dev_dbg(&port_dev->dev, "link state change\n"); + usb_clear_port_feature(hdev, port1, + USB_PORT_FEAT_C_PORT_LINK_STATE); + } + if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) { + dev_warn(&port_dev->dev, "config error\n"); + usb_clear_port_feature(hdev, port1, + USB_PORT_FEAT_C_PORT_CONFIG_ERROR); + } + + /* skip port actions that require the port to be powered on */ + if (!pm_runtime_active(&port_dev->dev)) + return; + if (hub_handle_remote_wakeup(hub, port1, portstatus, portchange)) + connect_change = 1; + + /* + * Warm reset a USB3 protocol port if it's in + * SS.Inactive state. + */ + if (hub_port_warm_reset_required(hub, portstatus)) { + dev_dbg(&port_dev->dev, "do warm reset\n"); + if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION) + || udev->state == USB_STATE_NOTATTACHED) { + if (hub_port_reset(hub, port1, NULL, + HUB_BH_RESET_TIME, true) < 0) + hub_port_disable(hub, port1, 1); + } else + reset_device = 1; + } + + /* + * On disconnect USB3 protocol ports transit from U0 to + * SS.Inactive to Rx.Detect. If this happens a warm- + * reset is not needed, but a (re)connect may happen + * before khubd runs and sees the disconnect, and the + * device may be an unknown state. + * + * If the port went through SS.Inactive without khubd + * seeing it the C_LINK_STATE change flag will be set, + * and we reset the dev to put it in a known state. + */ + if (reset_device || (udev && hub_is_superspeed(hub->hdev) + && (portchange & USB_PORT_STAT_C_LINK_STATE) + && (portstatus & USB_PORT_STAT_CONNECTION))) { + usb_unlock_port(port_dev); usb_lock_device(udev); - ret = usb_remote_wakeup(udev); + usb_reset_device(udev); usb_unlock_device(udev); - if (ret < 0) - connect_change = 1; - } else { - ret = -ENODEV; - hub_port_disable(hub, port, 1); + usb_lock_port(port_dev); + connect_change = 0; } - dev_dbg(hub->intfdev, "resume on port %d, status %d\n", - port, ret); - return connect_change; + + if (connect_change) + hub_port_connect_change(hub, port1, portstatus, portchange); } + static void hub_events(void) { struct list_head *tmp; @@ -4693,10 +4899,7 @@ static void hub_events(void) struct device *hub_dev; u16 hubstatus; u16 hubchange; - u16 portstatus; - u16 portchange; int i, ret; - int connect_change, wakeup_change; /* * We restart the list every time to avoid a deadlock with @@ -4770,146 +4973,28 @@ static void hub_events(void) /* deal with port status changes */ for (i = 1; i <= hdev->maxchild; i++) { - struct usb_device *udev = hub->ports[i - 1]->child; - - if (test_bit(i, hub->busy_bits)) - continue; - connect_change = test_bit(i, hub->change_bits); - wakeup_change = test_and_clear_bit(i, hub->wakeup_bits); - if (!test_and_clear_bit(i, hub->event_bits) && - !connect_change && !wakeup_change) - continue; - - ret = hub_port_status(hub, i, - &portstatus, &portchange); - if (ret < 0) - continue; - - if (portchange & USB_PORT_STAT_C_CONNECTION) { - usb_clear_port_feature(hdev, i, - USB_PORT_FEAT_C_CONNECTION); - connect_change = 1; - } - - if (portchange & USB_PORT_STAT_C_ENABLE) { - if (!connect_change) - dev_dbg (hub_dev, - "port %d enable change, " - "status %08x\n", - i, portstatus); - usb_clear_port_feature(hdev, i, - USB_PORT_FEAT_C_ENABLE); + struct usb_port *port_dev = hub->ports[i - 1]; + if (test_bit(i, hub->event_bits) + || test_bit(i, hub->change_bits) + || test_bit(i, hub->wakeup_bits)) { /* - * EM interference sometimes causes badly - * shielded USB devices to be shutdown by - * the hub, this hack enables them again. - * Works at least with mouse driver. + * The get_noresume and barrier ensure that if + * the port was in the process of resuming, we + * flush that work and keep the port active for + * the duration of the port_event(). However, + * if the port is runtime pm suspended + * (powered-off), we leave it in that state, run + * an abbreviated port_event(), and move on. */ - if (!(portstatus & USB_PORT_STAT_ENABLE) - && !connect_change - && hub->ports[i - 1]->child) { - dev_err (hub_dev, - "port %i " - "disabled by hub (EMI?), " - "re-enabling...\n", - i); - connect_change = 1; - } - } - - if (hub_handle_remote_wakeup(hub, i, - portstatus, portchange)) - connect_change = 1; - - if (portchange & USB_PORT_STAT_C_OVERCURRENT) { - u16 status = 0; - u16 unused; - - dev_dbg(hub_dev, "over-current change on port " - "%d\n", i); - usb_clear_port_feature(hdev, i, - USB_PORT_FEAT_C_OVER_CURRENT); - msleep(100); /* Cool down */ - hub_power_on(hub, true); - hub_port_status(hub, i, &status, &unused); - if (status & USB_PORT_STAT_OVERCURRENT) - dev_err(hub_dev, "over-current " - "condition on port %d\n", i); - } - - if (portchange & USB_PORT_STAT_C_RESET) { - dev_dbg (hub_dev, - "reset change on port %d\n", - i); - usb_clear_port_feature(hdev, i, - USB_PORT_FEAT_C_RESET); - } - if ((portchange & USB_PORT_STAT_C_BH_RESET) && - hub_is_superspeed(hub->hdev)) { - dev_dbg(hub_dev, - "warm reset change on port %d\n", - i); - usb_clear_port_feature(hdev, i, - USB_PORT_FEAT_C_BH_PORT_RESET); - } - if (portchange & USB_PORT_STAT_C_LINK_STATE) { - usb_clear_port_feature(hub->hdev, i, - USB_PORT_FEAT_C_PORT_LINK_STATE); - } - if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) { - dev_warn(hub_dev, - "config error on port %d\n", - i); - usb_clear_port_feature(hub->hdev, i, - USB_PORT_FEAT_C_PORT_CONFIG_ERROR); + pm_runtime_get_noresume(&port_dev->dev); + pm_runtime_barrier(&port_dev->dev); + usb_lock_port(port_dev); + port_event(hub, i); + usb_unlock_port(port_dev); + pm_runtime_put_sync(&port_dev->dev); } - - /* Warm reset a USB3 protocol port if it's in - * SS.Inactive state. - */ - if (hub_port_warm_reset_required(hub, portstatus)) { - int status; - - dev_dbg(hub_dev, "warm reset port %d\n", i); - if (!udev || - !(portstatus & USB_PORT_STAT_CONNECTION) || - udev->state == USB_STATE_NOTATTACHED) { - status = hub_port_reset(hub, i, - NULL, HUB_BH_RESET_TIME, - true); - if (status < 0) - hub_port_disable(hub, i, 1); - } else { - usb_lock_device(udev); - status = usb_reset_device(udev); - usb_unlock_device(udev); - connect_change = 0; - } - /* - * On disconnect USB3 protocol ports transit from U0 to - * SS.Inactive to Rx.Detect. If this happens a warm- - * reset is not needed, but a (re)connect may happen - * before khubd runs and sees the disconnect, and the - * device may be an unknown state. - * - * If the port went through SS.Inactive without khubd - * seeing it the C_LINK_STATE change flag will be set, - * and we reset the dev to put it in a known state. - */ - } else if (udev && hub_is_superspeed(hub->hdev) && - (portchange & USB_PORT_STAT_C_LINK_STATE) && - (portstatus & USB_PORT_STAT_CONNECTION)) { - usb_lock_device(udev); - usb_reset_device(udev); - usb_unlock_device(udev); - connect_change = 0; - } - - if (connect_change) - hub_port_connect_change(hub, i, - portstatus, portchange); - } /* end for i */ + } /* deal with hub status changes */ if (test_and_clear_bit(0, hub->event_bits) == 0) @@ -5144,15 +5229,18 @@ static int descriptors_changed(struct usb_device *udev, * if the reset wasn't even attempted. * * Note: - * The caller must own the device lock. For example, it's safe to use - * this from a driver probe() routine after downloading new firmware. - * For calls that might not occur during probe(), drivers should lock - * the device using usb_lock_device_for_reset(). + * The caller must own the device lock and the port lock, the latter is + * taken by usb_reset_device(). For example, it's safe to use + * usb_reset_device() from a driver probe() routine after downloading + * new firmware. For calls that might not occur during probe(), drivers + * should lock the device using usb_lock_device_for_reset(). * * Locking exception: This routine may also be called from within an * autoresume handler. Such usage won't conflict with other tasks * holding the device lock because these tasks should always call - * usb_autopm_resume_device(), thereby preventing any unwanted autoresume. + * usb_autopm_resume_device(), thereby preventing any unwanted + * autoresume. The autoresume handler is expected to have already + * acquired the port lock before calling this routine. */ static int usb_reset_and_verify_device(struct usb_device *udev) { @@ -5171,11 +5259,9 @@ static int usb_reset_and_verify_device(struct usb_device *udev) return -EINVAL; } - if (!parent_hdev) { - /* this requires hcd-specific logic; see ohci_restart() */ - dev_dbg(&udev->dev, "%s for root hub!\n", __func__); + if (!parent_hdev) return -EISDIR; - } + parent_hub = usb_hub_to_struct_hub(parent_hdev); /* Disable USB2 hardware LPM. @@ -5204,7 +5290,6 @@ static int usb_reset_and_verify_device(struct usb_device *udev) goto re_enumerate; } - set_bit(port1, parent_hub->busy_bits); for (i = 0; i < SET_CONFIG_TRIES; ++i) { /* ep0 maxpacket size may change; let the HCD know about it. @@ -5214,7 +5299,6 @@ static int usb_reset_and_verify_device(struct usb_device *udev) if (ret >= 0 || ret == -ENOTCONN || ret == -ENODEV) break; } - clear_bit(port1, parent_hub->busy_bits); if (ret < 0) goto re_enumerate; @@ -5335,7 +5419,9 @@ int usb_reset_device(struct usb_device *udev) int ret; int i; unsigned int noio_flag; + struct usb_port *port_dev; struct usb_host_config *config = udev->actconfig; + struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); if (udev->state == USB_STATE_NOTATTACHED || udev->state == USB_STATE_SUSPENDED) { @@ -5344,6 +5430,14 @@ int usb_reset_device(struct usb_device *udev) return -EINVAL; } + if (!udev->parent) { + /* this requires hcd-specific logic; see ohci_restart() */ + dev_dbg(&udev->dev, "%s for root hub!\n", __func__); + return -EISDIR; + } + + port_dev = hub->ports[udev->portnum - 1]; + /* * Don't allocate memory with GFP_KERNEL in current * context to avoid possible deadlock if usb mass @@ -5377,7 +5471,9 @@ int usb_reset_device(struct usb_device *udev) } } + usb_lock_port(port_dev); ret = usb_reset_and_verify_device(udev); + usb_unlock_port(port_dev); if (config) { for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) { @@ -5472,56 +5568,26 @@ struct usb_device *usb_hub_find_child(struct usb_device *hdev, } EXPORT_SYMBOL_GPL(usb_hub_find_child); -/** - * usb_set_hub_port_connect_type - set hub port connect type. - * @hdev: USB device belonging to the usb hub - * @port1: port num of the port - * @type: connect type of the port - */ -void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1, - enum usb_port_connect_type type) -{ - struct usb_hub *hub = usb_hub_to_struct_hub(hdev); - - if (hub) - hub->ports[port1 - 1]->connect_type = type; -} - -/** - * usb_get_hub_port_connect_type - Get the port's connect type - * @hdev: USB device belonging to the usb hub - * @port1: port num of the port - * - * Return: The connect type of the port if successful. Or - * USB_PORT_CONNECT_TYPE_UNKNOWN if input params are invalid. - */ -enum usb_port_connect_type -usb_get_hub_port_connect_type(struct usb_device *hdev, int port1) -{ - struct usb_hub *hub = usb_hub_to_struct_hub(hdev); - - if (!hub) - return USB_PORT_CONNECT_TYPE_UNKNOWN; - - return hub->ports[port1 - 1]->connect_type; -} - void usb_hub_adjust_deviceremovable(struct usb_device *hdev, struct usb_hub_descriptor *desc) { + struct usb_hub *hub = usb_hub_to_struct_hub(hdev); enum usb_port_connect_type connect_type; int i; + if (!hub) + return; + if (!hub_is_superspeed(hdev)) { for (i = 1; i <= hdev->maxchild; i++) { - connect_type = usb_get_hub_port_connect_type(hdev, i); + struct usb_port *port_dev = hub->ports[i - 1]; + connect_type = port_dev->connect_type; if (connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) { u8 mask = 1 << (i%8); if (!(desc->u.hs.DeviceRemovable[i/8] & mask)) { - dev_dbg(&hdev->dev, "usb port%d's DeviceRemovable is changed to 1 according to platform information.\n", - i); + dev_dbg(&port_dev->dev, "DeviceRemovable is changed to 1 according to platform information.\n"); desc->u.hs.DeviceRemovable[i/8] |= mask; } } @@ -5530,14 +5596,14 @@ void usb_hub_adjust_deviceremovable(struct usb_device *hdev, u16 port_removable = le16_to_cpu(desc->u.ss.DeviceRemovable); for (i = 1; i <= hdev->maxchild; i++) { - connect_type = usb_get_hub_port_connect_type(hdev, i); + struct usb_port *port_dev = hub->ports[i - 1]; + connect_type = port_dev->connect_type; if (connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) { u16 mask = 1 << i; if (!(port_removable & mask)) { - dev_dbg(&hdev->dev, "usb port%d's DeviceRemovable is changed to 1 according to platform information.\n", - i); + dev_dbg(&port_dev->dev, "DeviceRemovable is changed to 1 according to platform information.\n"); port_removable |= mask; } } diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 33bcb2c6f90a..0a7cdc0ef0a9 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -45,12 +45,13 @@ struct usb_hub { unsigned long event_bits[1]; /* status change bitmask */ unsigned long change_bits[1]; /* ports with logical connect status change */ - unsigned long busy_bits[1]; /* ports being reset or - resumed */ unsigned long removed_bits[1]; /* ports with a "removed" device present */ unsigned long wakeup_bits[1]; /* ports that have signaled remote wakeup */ + unsigned long power_bits[1]; /* ports that are powered */ + unsigned long child_usage_bits[1]; /* ports powered on for + children */ #if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */ #error event_bits[] is too short! #endif @@ -66,6 +67,7 @@ struct usb_hub { unsigned limited_power:1; unsigned quiescing:1; unsigned disconnected:1; + unsigned in_reset:1; unsigned quirk_check_port_auto_suspend:1; @@ -81,19 +83,23 @@ struct usb_hub { * @child: usb device attached to the port * @dev: generic device interface * @port_owner: port's owner + * @peer: related usb2 and usb3 ports (share the same connector) * @connect_type: port's connect type + * @location: opaque representation of platform connector location + * @status_lock: synchronize port_event() vs usb_port_{suspend|resume} * @portnum: port index num based one - * @power_is_on: port's power state - * @did_runtime_put: port has done pm_runtime_put(). + * @is_superspeed cache super-speed status */ struct usb_port { struct usb_device *child; struct device dev; struct usb_dev_state *port_owner; + struct usb_port *peer; enum usb_port_connect_type connect_type; + usb_port_location_t location; + struct mutex status_lock; u8 portnum; - unsigned power_is_on:1; - unsigned did_runtime_put:1; + unsigned int is_superspeed:1; }; #define to_usb_port(_dev) \ @@ -111,6 +117,29 @@ extern int hub_port_debounce(struct usb_hub *hub, int port1, extern int usb_clear_port_feature(struct usb_device *hdev, int port1, int feature); +static inline bool hub_is_port_power_switchable(struct usb_hub *hub) +{ + __le16 hcs; + + if (!hub) + return false; + hcs = hub->descriptor->wHubCharacteristics; + return (le16_to_cpu(hcs) & HUB_CHAR_LPSM) < HUB_CHAR_NO_LPSM; +} + +static inline int hub_is_superspeed(struct usb_device *hdev) +{ + return hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS; +} + +static inline unsigned hub_power_on_good_delay(struct usb_hub *hub) +{ + unsigned delay = hub->descriptor->bPwrOn2PwrGood * 2; + + /* Wait at least 100 msec for power to become stable */ + return max(delay, 100U); +} + static inline int hub_port_debounce_be_connected(struct usb_hub *hub, int port1) { diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 51542f852393..62036faf56c0 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -76,17 +76,29 @@ static int usb_port_runtime_resume(struct device *dev) struct usb_device *hdev = to_usb_device(dev->parent->parent); struct usb_interface *intf = to_usb_interface(dev->parent); struct usb_hub *hub = usb_hub_to_struct_hub(hdev); + struct usb_device *udev = port_dev->child; + struct usb_port *peer = port_dev->peer; int port1 = port_dev->portnum; int retval; if (!hub) return -EINVAL; + if (hub->in_reset) { + set_bit(port1, hub->power_bits); + return 0; + } - usb_autopm_get_interface(intf); - set_bit(port1, hub->busy_bits); + /* + * Power on our usb3 peer before this usb2 port to prevent a usb3 + * device from degrading to its usb2 connection + */ + if (!port_dev->is_superspeed && peer) + pm_runtime_get_sync(&peer->dev); + usb_autopm_get_interface(intf); retval = usb_hub_set_port_power(hdev, hub, port1, true); - if (port_dev->child && !retval) { + msleep(hub_power_on_good_delay(hub)); + if (udev && !retval) { /* * Attempt to wait for usb hub port to be reconnected in order * to make the resume procedure successful. The device may have @@ -97,12 +109,17 @@ static int usb_port_runtime_resume(struct device *dev) if (retval < 0) dev_dbg(&port_dev->dev, "can't get reconnection after setting port power on, status %d\n", retval); - usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE); retval = 0; + + /* Force the child awake to revalidate after the power loss. */ + if (!test_and_set_bit(port1, hub->child_usage_bits)) { + pm_runtime_get_noresume(&port_dev->dev); + pm_request_resume(&udev->dev); + } } - clear_bit(port1, hub->busy_bits); usb_autopm_put_interface(intf); + return retval; } @@ -112,23 +129,34 @@ static int usb_port_runtime_suspend(struct device *dev) struct usb_device *hdev = to_usb_device(dev->parent->parent); struct usb_interface *intf = to_usb_interface(dev->parent); struct usb_hub *hub = usb_hub_to_struct_hub(hdev); + struct usb_port *peer = port_dev->peer; int port1 = port_dev->portnum; int retval; if (!hub) return -EINVAL; + if (hub->in_reset) + return -EBUSY; if (dev_pm_qos_flags(&port_dev->dev, PM_QOS_FLAG_NO_POWER_OFF) == PM_QOS_FLAGS_ALL) return -EAGAIN; usb_autopm_get_interface(intf); - set_bit(port1, hub->busy_bits); retval = usb_hub_set_port_power(hdev, hub, port1, false); usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION); - usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE); - clear_bit(port1, hub->busy_bits); + if (!port_dev->is_superspeed) + usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE); usb_autopm_put_interface(intf); + + /* + * Our peer usb3 port may now be able to suspend, so + * asynchronously queue a suspend request to observe that this + * usb2 port is now off. + */ + if (!port_dev->is_superspeed && peer) + pm_runtime_put(&peer->dev); + return retval; } #endif @@ -146,9 +174,215 @@ struct device_type usb_port_device_type = { .pm = &usb_port_pm_ops, }; +static struct device_driver usb_port_driver = { + .name = "usb", + .owner = THIS_MODULE, +}; + +static int link_peers(struct usb_port *left, struct usb_port *right) +{ + struct usb_port *ss_port, *hs_port; + int rc; + + if (left->peer == right && right->peer == left) + return 0; + + if (left->peer || right->peer) { + struct usb_port *lpeer = left->peer; + struct usb_port *rpeer = right->peer; + + WARN(1, "failed to peer %s and %s (%s -> %p) (%s -> %p)\n", + dev_name(&left->dev), dev_name(&right->dev), + dev_name(&left->dev), lpeer, + dev_name(&right->dev), rpeer); + return -EBUSY; + } + + rc = sysfs_create_link(&left->dev.kobj, &right->dev.kobj, "peer"); + if (rc) + return rc; + rc = sysfs_create_link(&right->dev.kobj, &left->dev.kobj, "peer"); + if (rc) { + sysfs_remove_link(&left->dev.kobj, "peer"); + return rc; + } + + /* + * We need to wake the HiSpeed port to make sure we don't race + * setting ->peer with usb_port_runtime_suspend(). Otherwise we + * may miss a suspend event for the SuperSpeed port. + */ + if (left->is_superspeed) { + ss_port = left; + WARN_ON(right->is_superspeed); + hs_port = right; + } else { + ss_port = right; + WARN_ON(!right->is_superspeed); + hs_port = left; + } + pm_runtime_get_sync(&hs_port->dev); + + left->peer = right; + right->peer = left; + + /* + * The SuperSpeed reference is dropped when the HiSpeed port in + * this relationship suspends, i.e. when it is safe to allow a + * SuperSpeed connection to drop since there is no risk of a + * device degrading to its powered-off HiSpeed connection. + * + * Also, drop the HiSpeed ref taken above. + */ + pm_runtime_get_sync(&ss_port->dev); + pm_runtime_put(&hs_port->dev); + + return 0; +} + +static void link_peers_report(struct usb_port *left, struct usb_port *right) +{ + int rc; + + rc = link_peers(left, right); + if (rc == 0) { + dev_dbg(&left->dev, "peered to %s\n", dev_name(&right->dev)); + } else { + dev_warn(&left->dev, "failed to peer to %s (%d)\n", + dev_name(&right->dev), rc); + pr_warn_once("usb: port power management may be unreliable\n"); + } +} + +static void unlink_peers(struct usb_port *left, struct usb_port *right) +{ + struct usb_port *ss_port, *hs_port; + + WARN(right->peer != left || left->peer != right, + "%s and %s are not peers?\n", + dev_name(&left->dev), dev_name(&right->dev)); + + /* + * We wake the HiSpeed port to make sure we don't race its + * usb_port_runtime_resume() event which takes a SuperSpeed ref + * when ->peer is !NULL. + */ + if (left->is_superspeed) { + ss_port = left; + hs_port = right; + } else { + ss_port = right; + hs_port = left; + } + + pm_runtime_get_sync(&hs_port->dev); + + sysfs_remove_link(&left->dev.kobj, "peer"); + right->peer = NULL; + sysfs_remove_link(&right->dev.kobj, "peer"); + left->peer = NULL; + + /* Drop the SuperSpeed ref held on behalf of the active HiSpeed port */ + pm_runtime_put(&ss_port->dev); + + /* Drop the ref taken above */ + pm_runtime_put(&hs_port->dev); +} + +/* + * For each usb hub device in the system check to see if it is in the + * peer domain of the given port_dev, and if it is check to see if it + * has a port that matches the given port by location + */ +static int match_location(struct usb_device *peer_hdev, void *p) +{ + int port1; + struct usb_hcd *hcd, *peer_hcd; + struct usb_port *port_dev = p, *peer; + struct usb_hub *peer_hub = usb_hub_to_struct_hub(peer_hdev); + struct usb_device *hdev = to_usb_device(port_dev->dev.parent->parent); + + if (!peer_hub) + return 0; + + hcd = bus_to_hcd(hdev->bus); + peer_hcd = bus_to_hcd(peer_hdev->bus); + /* peer_hcd is provisional until we verify it against the known peer */ + if (peer_hcd != hcd->shared_hcd) + return 0; + + for (port1 = 1; port1 <= peer_hdev->maxchild; port1++) { + peer = peer_hub->ports[port1 - 1]; + if (peer && peer->location == port_dev->location) { + link_peers_report(port_dev, peer); + return 1; /* done */ + } + } + + return 0; +} + +/* + * Find the peer port either via explicit platform firmware "location" + * data, the peer hcd for root hubs, or the upstream peer relationship + * for all other hubs. + */ +static void find_and_link_peer(struct usb_hub *hub, int port1) +{ + struct usb_port *port_dev = hub->ports[port1 - 1], *peer; + struct usb_device *hdev = hub->hdev; + struct usb_device *peer_hdev; + struct usb_hub *peer_hub; + + /* + * If location data is available then we can only peer this port + * by a location match, not the default peer (lest we create a + * situation where we need to go back and undo a default peering + * when the port is later peered by location data) + */ + if (port_dev->location) { + /* we link the peer in match_location() if found */ + usb_for_each_dev(port_dev, match_location); + return; + } else if (!hdev->parent) { + struct usb_hcd *hcd = bus_to_hcd(hdev->bus); + struct usb_hcd *peer_hcd = hcd->shared_hcd; + + if (!peer_hcd) + return; + + peer_hdev = peer_hcd->self.root_hub; + } else { + struct usb_port *upstream; + struct usb_device *parent = hdev->parent; + struct usb_hub *parent_hub = usb_hub_to_struct_hub(parent); + + if (!parent_hub) + return; + + upstream = parent_hub->ports[hdev->portnum - 1]; + if (!upstream || !upstream->peer) + return; + + peer_hdev = upstream->peer->child; + } + + peer_hub = usb_hub_to_struct_hub(peer_hdev); + if (!peer_hub || port1 > peer_hdev->maxchild) + return; + + /* + * we found a valid default peer, last check is to make sure it + * does not have location data + */ + peer = peer_hub->ports[port1 - 1]; + if (peer && peer->location == 0) + link_peers_report(port_dev, peer); +} + int usb_hub_create_port_device(struct usb_hub *hub, int port1) { - struct usb_port *port_dev = NULL; + struct usb_port *port_dev; int retval; port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL); @@ -159,24 +393,33 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1) hub->ports[port1 - 1] = port_dev; port_dev->portnum = port1; - port_dev->power_is_on = true; + set_bit(port1, hub->power_bits); port_dev->dev.parent = hub->intfdev; port_dev->dev.groups = port_dev_group; port_dev->dev.type = &usb_port_device_type; - dev_set_name(&port_dev->dev, "port%d", port1); - + port_dev->dev.driver = &usb_port_driver; + if (hub_is_superspeed(hub->hdev)) + port_dev->is_superspeed = 1; + dev_set_name(&port_dev->dev, "%s-port%d", dev_name(&hub->hdev->dev), + port1); + mutex_init(&port_dev->status_lock); retval = device_register(&port_dev->dev); if (retval) goto error_register; + find_and_link_peer(hub, port1); + pm_runtime_set_active(&port_dev->dev); - /* It would be dangerous if user space couldn't - * prevent usb device from being powered off. So don't - * enable port runtime pm if failed to expose port's pm qos. + /* + * Do not enable port runtime pm if the hub does not support + * power switching. Also, userspace must have final say of + * whether a port is permitted to power-off. Do not enable + * runtime pm if we fail to expose pm_qos_no_power_off. */ - if (!dev_pm_qos_expose_flags(&port_dev->dev, - PM_QOS_FLAG_NO_POWER_OFF)) + if (hub_is_port_power_switchable(hub) + && dev_pm_qos_expose_flags(&port_dev->dev, + PM_QOS_FLAG_NO_POWER_OFF) == 0) pm_runtime_enable(&port_dev->dev); device_enable_async_suspend(&port_dev->dev); @@ -188,9 +431,13 @@ exit: return retval; } -void usb_hub_remove_port_device(struct usb_hub *hub, - int port1) +void usb_hub_remove_port_device(struct usb_hub *hub, int port1) { - device_unregister(&hub->ports[port1 - 1]->dev); -} + struct usb_port *port_dev = hub->ports[port1 - 1]; + struct usb_port *peer; + peer = port_dev->peer; + if (peer) + unlink_peers(port_dev, peer); + device_unregister(&port_dev->dev); +} diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index 5ca4070b1f38..2776cfe64c09 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -17,7 +17,7 @@ #include <linux/pci.h> #include <linux/usb/hcd.h> -#include "usb.h" +#include "hub.h" /** * usb_acpi_power_manageable - check whether usb port has @@ -55,13 +55,18 @@ EXPORT_SYMBOL_GPL(usb_acpi_power_manageable); */ int usb_acpi_set_power_state(struct usb_device *hdev, int index, bool enable) { + struct usb_hub *hub = usb_hub_to_struct_hub(hdev); + struct usb_port *port_dev; acpi_handle port_handle; unsigned char state; int port1 = index + 1; int error = -EINVAL; - port_handle = (acpi_handle)usb_get_hub_port_acpi_handle(hdev, - port1); + if (!hub) + return -ENODEV; + port_dev = hub->ports[port1 - 1]; + + port_handle = (acpi_handle) usb_get_hub_port_acpi_handle(hdev, port1); if (!port_handle) return error; @@ -72,23 +77,21 @@ int usb_acpi_set_power_state(struct usb_device *hdev, int index, bool enable) error = acpi_bus_set_power(port_handle, state); if (!error) - dev_dbg(&hdev->dev, "The power of hub port %d was set to %d\n", - port1, enable); + dev_dbg(&port_dev->dev, "acpi: power was set to %d\n", enable); else - dev_dbg(&hdev->dev, "The power of hub port failed to be set\n"); + dev_dbg(&port_dev->dev, "acpi: power failed to be set\n"); return error; } EXPORT_SYMBOL_GPL(usb_acpi_set_power_state); -static int usb_acpi_check_port_connect_type(struct usb_device *hdev, - acpi_handle handle, int port1) +static enum usb_port_connect_type usb_acpi_get_connect_type(acpi_handle handle, + struct acpi_pld_info *pld) { - acpi_status status; + enum usb_port_connect_type connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *upc; - struct acpi_pld_info *pld; - int ret = 0; + acpi_status status; /* * According to ACPI Spec 9.13. PLD indicates whether usb port is @@ -98,39 +101,37 @@ static int usb_acpi_check_port_connect_type(struct usb_device *hdev, * a usb device is directly hard-wired to the port. If no visible and * no connectable, the port would be not used. */ - status = acpi_get_physical_device_location(handle, &pld); - if (ACPI_FAILURE(status)) - return -ENODEV; - status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer); upc = buffer.pointer; if (!upc || (upc->type != ACPI_TYPE_PACKAGE) || upc->package.count != 4) { - ret = -EINVAL; goto out; } if (upc->package.elements[0].integer.value) if (pld->user_visible) - usb_set_hub_port_connect_type(hdev, port1, - USB_PORT_CONNECT_TYPE_HOT_PLUG); + connect_type = USB_PORT_CONNECT_TYPE_HOT_PLUG; else - usb_set_hub_port_connect_type(hdev, port1, - USB_PORT_CONNECT_TYPE_HARD_WIRED); + connect_type = USB_PORT_CONNECT_TYPE_HARD_WIRED; else if (!pld->user_visible) - usb_set_hub_port_connect_type(hdev, port1, USB_PORT_NOT_USED); - + connect_type = USB_PORT_NOT_USED; out: - ACPI_FREE(pld); kfree(upc); - return ret; + return connect_type; } + +/* + * Private to usb-acpi, all the core needs to know is that + * port_dev->location is non-zero when it has been set by the firmware. + */ +#define USB_ACPI_LOCATION_VALID (1 << 31) + static struct acpi_device *usb_acpi_find_companion(struct device *dev) { struct usb_device *udev; + struct acpi_device *adev; acpi_handle *parent_handle; - int port_num; /* * In the ACPI DSDT table, only usb root hub and usb ports are @@ -147,37 +148,19 @@ static struct acpi_device *usb_acpi_find_companion(struct device *dev) */ if (is_usb_device(dev)) { udev = to_usb_device(dev); - if (udev->parent) { - enum usb_port_connect_type type; - - /* - * According usb port's connect type to set usb device's - * removability. - */ - type = usb_get_hub_port_connect_type(udev->parent, - udev->portnum); - switch (type) { - case USB_PORT_CONNECT_TYPE_HOT_PLUG: - udev->removable = USB_DEVICE_REMOVABLE; - break; - case USB_PORT_CONNECT_TYPE_HARD_WIRED: - udev->removable = USB_DEVICE_FIXED; - break; - default: - udev->removable = USB_DEVICE_REMOVABLE_UNKNOWN; - break; - } - + if (udev->parent) return NULL; - } - /* root hub's parent is the usb hcd. */ - return acpi_find_child_device(ACPI_COMPANION(dev->parent), - udev->portnum, false); + /* root hub is only child (_ADR=0) under its parent, the HC */ + adev = ACPI_COMPANION(dev->parent); + return acpi_find_child_device(adev, 0, false); } else if (is_usb_port(dev)) { - struct acpi_device *adev = NULL; + struct usb_port *port_dev = to_usb_port(dev); + int port1 = port_dev->portnum; + struct acpi_pld_info *pld; + acpi_handle *handle; + acpi_status status; - sscanf(dev_name(dev), "port%d", &port_num); /* Get the struct usb_device point of port's hub */ udev = to_usb_device(dev->parent->parent); @@ -188,12 +171,11 @@ static struct acpi_device *usb_acpi_find_companion(struct device *dev) */ if (!udev->parent) { struct usb_hcd *hcd = bus_to_hcd(udev->bus); - int raw_port_num; + int raw; - raw_port_num = usb_hcd_find_raw_port_number(hcd, - port_num); + raw = usb_hcd_find_raw_port_number(hcd, port1); adev = acpi_find_child_device(ACPI_COMPANION(&udev->dev), - raw_port_num, false); + raw, false); if (!adev) return NULL; } else { @@ -204,11 +186,20 @@ static struct acpi_device *usb_acpi_find_companion(struct device *dev) return NULL; acpi_bus_get_device(parent_handle, &adev); - adev = acpi_find_child_device(adev, port_num, false); + adev = acpi_find_child_device(adev, port1, false); if (!adev) return NULL; } - usb_acpi_check_port_connect_type(udev, adev->handle, port_num); + handle = adev->handle; + status = acpi_get_physical_device_location(handle, &pld); + if (ACPI_FAILURE(status) || !pld) + return adev; + + port_dev->location = USB_ACPI_LOCATION_VALID + | pld->group_token << 8 | pld->group_position; + port_dev->connect_type = usb_acpi_get_connect_type(handle, pld); + ACPI_FREE(pld); + return adev; } diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 75bf649da82d..d9d08720c386 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -107,11 +107,6 @@ static inline int usb_autoresume_device(struct usb_device *udev) return 0; } -static inline int usb_remote_wakeup(struct usb_device *udev) -{ - return 0; -} - static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) { return 0; @@ -119,6 +114,7 @@ static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) #endif extern struct bus_type usb_bus_type; +extern struct mutex usb_port_peer_mutex; extern struct device_type usb_device_type; extern struct device_type usb_if_device_type; extern struct device_type usb_ep_device_type; @@ -170,15 +166,17 @@ extern void usbfs_conn_disc_event(void); extern int usb_devio_init(void); extern void usb_devio_cleanup(void); +/* + * Firmware specific cookie identifying a port's location. '0' == no location + * data available + */ +typedef u32 usb_port_location_t; + /* internal notify stuff */ extern void usb_notify_add_device(struct usb_device *udev); extern void usb_notify_remove_device(struct usb_device *udev); extern void usb_notify_add_bus(struct usb_bus *ubus); extern void usb_notify_remove_bus(struct usb_bus *ubus); -extern enum usb_port_connect_type - usb_get_hub_port_connect_type(struct usb_device *hdev, int port1); -extern void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1, - enum usb_port_connect_type type); extern void usb_hub_adjust_deviceremovable(struct usb_device *hdev, struct usb_hub_descriptor *desc); diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig index be947d673844..f93807b3631a 100644 --- a/drivers/usb/dwc2/Kconfig +++ b/drivers/usb/dwc2/Kconfig @@ -1,25 +1,58 @@ config USB_DWC2 - tristate "DesignWare USB2 DRD Core Support" + bool "DesignWare USB2 DRD Core Support" depends on USB help - Say Y or M here if your system has a Dual Role HighSpeed - USB controller based on the DesignWare HSOTG IP Core. + Say Y here if your system has a Dual Role Hi-Speed USB + controller based on the DesignWare HSOTG IP Core. - If you choose to build this driver as dynamically linked - modules, the core module will be called dwc2.ko, the - PCI bus interface module (if you have a PCI bus system) - will be called dwc2_pci.ko and the platform interface module - (for controllers directly connected to the CPU) will be called - dwc2_platform.ko. + For host mode, if you choose to build the driver as dynamically + linked modules, the core module will be called dwc2.ko, the PCI + bus interface module (if you have a PCI bus system) will be + called dwc2_pci.ko, and the platform interface module (for + controllers directly connected to the CPU) will be called + dwc2_platform.ko. For gadget mode, there will be a single + module called dwc2_gadget.ko. - NOTE: This driver at present only implements the Host mode - of the controller. The existing s3c-hsotg driver supports - Peripheral mode, but only for the Samsung S3C platforms. - There are plans to merge the s3c-hsotg driver with this - driver in the near future to create a dual-role driver. + NOTE: The s3c-hsotg driver is now renamed to dwc2_gadget. The + host and gadget drivers are still currently separate drivers. + There are plans to merge the dwc2_gadget driver with the dwc2 + host driver in the near future to create a dual-role driver. if USB_DWC2 +config USB_DWC2_HOST + tristate "Host only mode" + depends on USB + help + The Designware USB2.0 high-speed host controller + integrated into many SoCs. + +config USB_DWC2_PLATFORM + bool "DWC2 Platform" + depends on USB_DWC2_HOST + default USB_DWC2_HOST + help + The Designware USB2.0 platform interface module for + controllers directly connected to the CPU. This is only + used for host mode. + +config USB_DWC2_PCI + bool "DWC2 PCI" + depends on USB_DWC2_HOST && PCI + default USB_DWC2_HOST + help + The Designware USB2.0 PCI interface module for controllers + connected to a PCI bus. This is only used for host mode. + +comment "Gadget mode requires USB Gadget support to be enabled" + +config USB_DWC2_PERIPHERAL + tristate "Gadget only mode" + depends on USB_GADGET + help + The Designware USB2.0 high-speed gadget controller + integrated into many SoCs. + config USB_DWC2_DEBUG bool "Enable Debugging Messages" help diff --git a/drivers/usb/dwc2/Makefile b/drivers/usb/dwc2/Makefile index 11529d3439b0..b73d2a527970 100644 --- a/drivers/usb/dwc2/Makefile +++ b/drivers/usb/dwc2/Makefile @@ -1,25 +1,28 @@ ccflags-$(CONFIG_USB_DWC2_DEBUG) += -DDEBUG ccflags-$(CONFIG_USB_DWC2_VERBOSE) += -DVERBOSE_DEBUG -obj-$(CONFIG_USB_DWC2) += dwc2.o - -dwc2-y += core.o core_intr.o - -# NOTE: This driver at present only implements the Host mode -# of the controller. The existing s3c-hsotg driver supports -# Peripheral mode, but only for the Samsung S3C platforms. -# There are plans to merge the s3c-hsotg driver with this -# driver in the near future to create a dual-role driver. Once -# that is done, Host mode will become an optional feature that -# is selected with a config option. - +obj-$(CONFIG_USB_DWC2_HOST) += dwc2.o +dwc2-y := core.o core_intr.o dwc2-y += hcd.o hcd_intr.o dwc2-y += hcd_queue.o hcd_ddma.o -ifneq ($(CONFIG_PCI),) - obj-$(CONFIG_USB_DWC2) += dwc2_pci.o +# NOTE: The previous s3c-hsotg peripheral mode only driver has been moved to +# this location and renamed gadget.c. When building for dynamically linked +# modules, dwc2_gadget.ko will get built for peripheral mode. For host mode, +# the core module will be dwc2.ko, the PCI bus interface module will called +# dwc2_pci.ko and the platform interface module will be called dwc2_platform.ko. +# At present the host and gadget driver will be separate drivers, but there +# are plans in the near future to create a dual-role driver. + +ifneq ($(CONFIG_USB_DWC2_PCI),) + obj-$(CONFIG_USB_DWC2_HOST) += dwc2_pci.o + dwc2_pci-y := pci.o +endif + +ifneq ($(CONFIG_USB_DWC2_PLATFORM),) + obj-$(CONFIG_USB_DWC2_HOST) += dwc2_platform.o + dwc2_platform-y := platform.o endif -obj-$(CONFIG_USB_DWC2) += dwc2_platform.o -dwc2_pci-y += pci.o -dwc2_platform-y += platform.o +obj-$(CONFIG_USB_DWC2_PERIPHERAL) += dwc2_gadget.o +dwc2_gadget-y := gadget.o diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c index 1d129884cc39..27d2c9b8a034 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -507,6 +507,72 @@ void dwc2_disable_host_interrupts(struct dwc2_hsotg *hsotg) writel(intmsk, hsotg->regs + GINTMSK); } +/* + * dwc2_calculate_dynamic_fifo() - Calculates the default fifo size + * For system that have a total fifo depth that is smaller than the default + * RX + TX fifo size. + * + * @hsotg: Programming view of DWC_otg controller + */ +static void dwc2_calculate_dynamic_fifo(struct dwc2_hsotg *hsotg) +{ + struct dwc2_core_params *params = hsotg->core_params; + struct dwc2_hw_params *hw = &hsotg->hw_params; + u32 rxfsiz, nptxfsiz, ptxfsiz, total_fifo_size; + + total_fifo_size = hw->total_fifo_size; + rxfsiz = params->host_rx_fifo_size; + nptxfsiz = params->host_nperio_tx_fifo_size; + ptxfsiz = params->host_perio_tx_fifo_size; + + /* + * Will use Method 2 defined in the DWC2 spec: minimum FIFO depth + * allocation with support for high bandwidth endpoints. Synopsys + * defines MPS(Max Packet size) for a periodic EP=1024, and for + * non-periodic as 512. + */ + if (total_fifo_size < (rxfsiz + nptxfsiz + ptxfsiz)) { + /* + * For Buffer DMA mode/Scatter Gather DMA mode + * 2 * ((Largest Packet size / 4) + 1 + 1) + n + * with n = number of host channel. + * 2 * ((1024/4) + 2) = 516 + */ + rxfsiz = 516 + hw->host_channels; + + /* + * min non-periodic tx fifo depth + * 2 * (largest non-periodic USB packet used / 4) + * 2 * (512/4) = 256 + */ + nptxfsiz = 256; + + /* + * min periodic tx fifo depth + * (largest packet size*MC)/4 + * (1024 * 3)/4 = 768 + */ + ptxfsiz = 768; + + params->host_rx_fifo_size = rxfsiz; + params->host_nperio_tx_fifo_size = nptxfsiz; + params->host_perio_tx_fifo_size = ptxfsiz; + } + + /* + * If the summation of RX, NPTX and PTX fifo sizes is still + * bigger than the total_fifo_size, then we have a problem. + * + * We won't be able to allocate as many endpoints. Right now, + * we're just printing an error message, but ideally this FIFO + * allocation algorithm would be improved in the future. + * + * FIXME improve this FIFO allocation algorithm. + */ + if (unlikely(total_fifo_size < (rxfsiz + nptxfsiz + ptxfsiz))) + dev_err(hsotg->dev, "invalid fifo sizes\n"); +} + static void dwc2_config_fifos(struct dwc2_hsotg *hsotg) { struct dwc2_core_params *params = hsotg->core_params; @@ -515,6 +581,8 @@ static void dwc2_config_fifos(struct dwc2_hsotg *hsotg) if (!params->enable_dynamic_fifo) return; + dwc2_calculate_dynamic_fifo(hsotg); + /* Rx FIFO */ grxfsiz = readl(hsotg->regs + GRXFSIZ); dev_dbg(hsotg->dev, "initial grxfsiz=%08x\n", grxfsiz); diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 648519c024b5..1efd10cc9629 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -37,6 +37,10 @@ #ifndef __DWC2_CORE_H__ #define __DWC2_CORE_H__ +#include <linux/phy/phy.h> +#include <linux/regulator/consumer.h> +#include <linux/usb/gadget.h> +#include <linux/usb/otg.h> #include <linux/usb/phy.h> #include "hw.h" @@ -54,6 +58,184 @@ static inline void do_write(u32 value, void *addr) /* Maximum number of Endpoints/HostChannels */ #define MAX_EPS_CHANNELS 16 +/* s3c-hsotg declarations */ +static const char * const s3c_hsotg_supply_names[] = { + "vusb_d", /* digital USB supply, 1.2V */ + "vusb_a", /* analog USB supply, 1.1V */ +}; + +/* + * EP0_MPS_LIMIT + * + * Unfortunately there seems to be a limit of the amount of data that can + * be transferred by IN transactions on EP0. This is either 127 bytes or 3 + * packets (which practically means 1 packet and 63 bytes of data) when the + * MPS is set to 64. + * + * This means if we are wanting to move >127 bytes of data, we need to + * split the transactions up, but just doing one packet at a time does + * not work (this may be an implicit DATA0 PID on first packet of the + * transaction) and doing 2 packets is outside the controller's limits. + * + * If we try to lower the MPS size for EP0, then no transfers work properly + * for EP0, and the system will fail basic enumeration. As no cause for this + * has currently been found, we cannot support any large IN transfers for + * EP0. + */ +#define EP0_MPS_LIMIT 64 + +struct s3c_hsotg; +struct s3c_hsotg_req; + +/** + * struct s3c_hsotg_ep - driver endpoint definition. + * @ep: The gadget layer representation of the endpoint. + * @name: The driver generated name for the endpoint. + * @queue: Queue of requests for this endpoint. + * @parent: Reference back to the parent device structure. + * @req: The current request that the endpoint is processing. This is + * used to indicate an request has been loaded onto the endpoint + * and has yet to be completed (maybe due to data move, or simply + * awaiting an ack from the core all the data has been completed). + * @debugfs: File entry for debugfs file for this endpoint. + * @lock: State lock to protect contents of endpoint. + * @dir_in: Set to true if this endpoint is of the IN direction, which + * means that it is sending data to the Host. + * @index: The index for the endpoint registers. + * @mc: Multi Count - number of transactions per microframe + * @interval - Interval for periodic endpoints + * @name: The name array passed to the USB core. + * @halted: Set if the endpoint has been halted. + * @periodic: Set if this is a periodic ep, such as Interrupt + * @isochronous: Set if this is a isochronous ep + * @sent_zlp: Set if we've sent a zero-length packet. + * @total_data: The total number of data bytes done. + * @fifo_size: The size of the FIFO (for periodic IN endpoints) + * @fifo_load: The amount of data loaded into the FIFO (periodic IN) + * @last_load: The offset of data for the last start of request. + * @size_loaded: The last loaded size for DxEPTSIZE for periodic IN + * + * This is the driver's state for each registered enpoint, allowing it + * to keep track of transactions that need doing. Each endpoint has a + * lock to protect the state, to try and avoid using an overall lock + * for the host controller as much as possible. + * + * For periodic IN endpoints, we have fifo_size and fifo_load to try + * and keep track of the amount of data in the periodic FIFO for each + * of these as we don't have a status register that tells us how much + * is in each of them. (note, this may actually be useless information + * as in shared-fifo mode periodic in acts like a single-frame packet + * buffer than a fifo) + */ +struct s3c_hsotg_ep { + struct usb_ep ep; + struct list_head queue; + struct s3c_hsotg *parent; + struct s3c_hsotg_req *req; + struct dentry *debugfs; + + unsigned long total_data; + unsigned int size_loaded; + unsigned int last_load; + unsigned int fifo_load; + unsigned short fifo_size; + + unsigned char dir_in; + unsigned char index; + unsigned char mc; + unsigned char interval; + + unsigned int halted:1; + unsigned int periodic:1; + unsigned int isochronous:1; + unsigned int sent_zlp:1; + + char name[10]; +}; + +/** + * struct s3c_hsotg - driver state. + * @dev: The parent device supplied to the probe function + * @driver: USB gadget driver + * @phy: The otg phy transceiver structure for phy control. + * @uphy: The otg phy transceiver structure for old USB phy control. + * @plat: The platform specific configuration data. This can be removed once + * all SoCs support usb transceiver. + * @regs: The memory area mapped for accessing registers. + * @irq: The IRQ number we are using + * @supplies: Definition of USB power supplies + * @phyif: PHY interface width + * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos. + * @num_of_eps: Number of available EPs (excluding EP0) + * @debug_root: root directrory for debugfs. + * @debug_file: main status file for debugfs. + * @debug_fifo: FIFO status file for debugfs. + * @ep0_reply: Request used for ep0 reply. + * @ep0_buff: Buffer for EP0 reply data, if needed. + * @ctrl_buff: Buffer for EP0 control requests. + * @ctrl_req: Request for EP0 control packets. + * @setup: NAK management for EP0 SETUP + * @last_rst: Time of last reset + * @eps: The endpoints being supplied to the gadget framework + */ +struct s3c_hsotg { + struct device *dev; + struct usb_gadget_driver *driver; + struct phy *phy; + struct usb_phy *uphy; + struct s3c_hsotg_plat *plat; + + spinlock_t lock; + + void __iomem *regs; + int irq; + struct clk *clk; + + struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)]; + + u32 phyif; + unsigned int dedicated_fifos:1; + unsigned char num_of_eps; + + struct dentry *debug_root; + struct dentry *debug_file; + struct dentry *debug_fifo; + + struct usb_request *ep0_reply; + struct usb_request *ctrl_req; + u8 ep0_buff[8]; + u8 ctrl_buff[8]; + + struct usb_gadget gadget; + unsigned int setup; + unsigned long last_rst; + struct s3c_hsotg_ep *eps; +}; + +/** + * struct s3c_hsotg_req - data transfer request + * @req: The USB gadget request + * @queue: The list of requests for the endpoint this is queued for. + * @in_progress: Has already had size/packets written to core + * @mapped: DMA buffer for this request has been mapped via dma_map_single(). + */ +struct s3c_hsotg_req { + struct usb_request req; + struct list_head queue; + unsigned char in_progress; + unsigned char mapped; +}; + +#define call_gadget(_hs, _entry) \ +do { \ + if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN && \ + (_hs)->driver && (_hs)->driver->_entry) { \ + spin_unlock(&_hs->lock); \ + (_hs)->driver->_entry(&(_hs)->gadget); \ + spin_lock(&_hs->lock); \ + } \ +} while (0) + struct dwc2_hsotg; struct dwc2_host_chan; diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/dwc2/gadget.c index 2a9cb674926a..f3c56a2fed5b 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/dwc2/gadget.c @@ -37,175 +37,7 @@ #include <linux/usb/phy.h> #include <linux/platform_data/s3c-hsotg.h> -#include "s3c-hsotg.h" - -static const char * const s3c_hsotg_supply_names[] = { - "vusb_d", /* digital USB supply, 1.2V */ - "vusb_a", /* analog USB supply, 1.1V */ -}; - -/* - * EP0_MPS_LIMIT - * - * Unfortunately there seems to be a limit of the amount of data that can - * be transferred by IN transactions on EP0. This is either 127 bytes or 3 - * packets (which practically means 1 packet and 63 bytes of data) when the - * MPS is set to 64. - * - * This means if we are wanting to move >127 bytes of data, we need to - * split the transactions up, but just doing one packet at a time does - * not work (this may be an implicit DATA0 PID on first packet of the - * transaction) and doing 2 packets is outside the controller's limits. - * - * If we try to lower the MPS size for EP0, then no transfers work properly - * for EP0, and the system will fail basic enumeration. As no cause for this - * has currently been found, we cannot support any large IN transfers for - * EP0. - */ -#define EP0_MPS_LIMIT 64 - -struct s3c_hsotg; -struct s3c_hsotg_req; - -/** - * struct s3c_hsotg_ep - driver endpoint definition. - * @ep: The gadget layer representation of the endpoint. - * @name: The driver generated name for the endpoint. - * @queue: Queue of requests for this endpoint. - * @parent: Reference back to the parent device structure. - * @req: The current request that the endpoint is processing. This is - * used to indicate an request has been loaded onto the endpoint - * and has yet to be completed (maybe due to data move, or simply - * awaiting an ack from the core all the data has been completed). - * @debugfs: File entry for debugfs file for this endpoint. - * @lock: State lock to protect contents of endpoint. - * @dir_in: Set to true if this endpoint is of the IN direction, which - * means that it is sending data to the Host. - * @index: The index for the endpoint registers. - * @mc: Multi Count - number of transactions per microframe - * @interval - Interval for periodic endpoints - * @name: The name array passed to the USB core. - * @halted: Set if the endpoint has been halted. - * @periodic: Set if this is a periodic ep, such as Interrupt - * @isochronous: Set if this is a isochronous ep - * @sent_zlp: Set if we've sent a zero-length packet. - * @total_data: The total number of data bytes done. - * @fifo_size: The size of the FIFO (for periodic IN endpoints) - * @fifo_load: The amount of data loaded into the FIFO (periodic IN) - * @last_load: The offset of data for the last start of request. - * @size_loaded: The last loaded size for DxEPTSIZE for periodic IN - * - * This is the driver's state for each registered enpoint, allowing it - * to keep track of transactions that need doing. Each endpoint has a - * lock to protect the state, to try and avoid using an overall lock - * for the host controller as much as possible. - * - * For periodic IN endpoints, we have fifo_size and fifo_load to try - * and keep track of the amount of data in the periodic FIFO for each - * of these as we don't have a status register that tells us how much - * is in each of them. (note, this may actually be useless information - * as in shared-fifo mode periodic in acts like a single-frame packet - * buffer than a fifo) - */ -struct s3c_hsotg_ep { - struct usb_ep ep; - struct list_head queue; - struct s3c_hsotg *parent; - struct s3c_hsotg_req *req; - struct dentry *debugfs; - - - unsigned long total_data; - unsigned int size_loaded; - unsigned int last_load; - unsigned int fifo_load; - unsigned short fifo_size; - - unsigned char dir_in; - unsigned char index; - unsigned char mc; - unsigned char interval; - - unsigned int halted:1; - unsigned int periodic:1; - unsigned int isochronous:1; - unsigned int sent_zlp:1; - - char name[10]; -}; - -/** - * struct s3c_hsotg - driver state. - * @dev: The parent device supplied to the probe function - * @driver: USB gadget driver - * @phy: The otg phy transceiver structure for phy control. - * @uphy: The otg phy transceiver structure for old USB phy control. - * @plat: The platform specific configuration data. This can be removed once - * all SoCs support usb transceiver. - * @regs: The memory area mapped for accessing registers. - * @irq: The IRQ number we are using - * @supplies: Definition of USB power supplies - * @phyif: PHY interface width - * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos. - * @num_of_eps: Number of available EPs (excluding EP0) - * @debug_root: root directrory for debugfs. - * @debug_file: main status file for debugfs. - * @debug_fifo: FIFO status file for debugfs. - * @ep0_reply: Request used for ep0 reply. - * @ep0_buff: Buffer for EP0 reply data, if needed. - * @ctrl_buff: Buffer for EP0 control requests. - * @ctrl_req: Request for EP0 control packets. - * @setup: NAK management for EP0 SETUP - * @last_rst: Time of last reset - * @eps: The endpoints being supplied to the gadget framework - */ -struct s3c_hsotg { - struct device *dev; - struct usb_gadget_driver *driver; - struct phy *phy; - struct usb_phy *uphy; - struct s3c_hsotg_plat *plat; - - spinlock_t lock; - - void __iomem *regs; - int irq; - struct clk *clk; - - struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)]; - - u32 phyif; - unsigned int dedicated_fifos:1; - unsigned char num_of_eps; - - struct dentry *debug_root; - struct dentry *debug_file; - struct dentry *debug_fifo; - - struct usb_request *ep0_reply; - struct usb_request *ctrl_req; - u8 ep0_buff[8]; - u8 ctrl_buff[8]; - - struct usb_gadget gadget; - unsigned int setup; - unsigned long last_rst; - struct s3c_hsotg_ep *eps; -}; - -/** - * struct s3c_hsotg_req - data transfer request - * @req: The USB gadget request - * @queue: The list of requests for the endpoint this is queued for. - * @in_progress: Has already had size/packets written to core - * @mapped: DMA buffer for this request has been mapped via dma_map_single(). - */ -struct s3c_hsotg_req { - struct usb_request req; - struct list_head queue; - unsigned char in_progress; - unsigned char mapped; -}; +#include "core.h" /* conversion functions */ static inline struct s3c_hsotg_req *our_req(struct usb_request *req) @@ -340,9 +172,8 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) /* set FIFO sizes to 2048/1024 */ writel(2048, hsotg->regs + GRXFSIZ); - writel(GNPTXFSIZ_NPTxFStAddr(2048) | - GNPTXFSIZ_NPTxFDep(1024), - hsotg->regs + GNPTXFSIZ); + writel((2048 << FIFOSIZE_STARTADDR_SHIFT) | + (1024 << FIFOSIZE_DEPTH_SHIFT), hsotg->regs + GNPTXFSIZ); /* * arange all the rest of the TX FIFOs, as some versions of this @@ -362,10 +193,10 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) for (ep = 1; ep <= 15; ep++) { val = addr; - val |= size << DPTXFSIZn_DPTxFSize_SHIFT; + val |= size << FIFOSIZE_DEPTH_SHIFT; addr += size; - writel(val, hsotg->regs + DPTXFSIZn(ep)); + writel(val, hsotg->regs + DPTXFSIZN(ep)); } /* @@ -373,15 +204,15 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) * all fifos are flushed before continuing */ - writel(GRSTCTL_TxFNum(0x10) | GRSTCTL_TxFFlsh | - GRSTCTL_RxFFlsh, hsotg->regs + GRSTCTL); + writel(GRSTCTL_TXFNUM(0x10) | GRSTCTL_TXFFLSH | + GRSTCTL_RXFFLSH, hsotg->regs + GRSTCTL); /* wait until the fifos are both flushed */ timeout = 100; while (1) { val = readl(hsotg->regs + GRSTCTL); - if ((val & (GRSTCTL_TxFFlsh | GRSTCTL_RxFFlsh)) == 0) + if ((val & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH)) == 0) break; if (--timeout == 0) { @@ -495,14 +326,14 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, * how much data is left in the fifo. */ - size_left = DxEPTSIZ_XferSize_GET(epsize); + size_left = DXEPTSIZ_XFERSIZE_GET(epsize); /* * if shared fifo, we cannot write anything until the * previous data has been completely sent. */ if (hs_ep->fifo_load != 0) { - s3c_hsotg_en_gsint(hsotg, GINTSTS_PTxFEmp); + s3c_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); return -ENOSPC; } @@ -523,7 +354,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, __func__, can_write); if (can_write <= 0) { - s3c_hsotg_en_gsint(hsotg, GINTSTS_PTxFEmp); + s3c_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); return -ENOSPC; } } else if (hsotg->dedicated_fifos && hs_ep->index != 0) { @@ -532,16 +363,16 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, can_write &= 0xffff; can_write *= 4; } else { - if (GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) { + if (GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(gnptxsts) == 0) { dev_dbg(hsotg->dev, "%s: no queue slots available (0x%08x)\n", __func__, gnptxsts); - s3c_hsotg_en_gsint(hsotg, GINTSTS_NPTxFEmp); + s3c_hsotg_en_gsint(hsotg, GINTSTS_NPTXFEMP); return -ENOSPC; } - can_write = GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts); + can_write = GNPTXSTS_NP_TXF_SPC_AVAIL_GET(gnptxsts); can_write *= 4; /* fifo size is in 32bit quantities. */ } @@ -569,8 +400,8 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, /* it's needed only when we do not use dedicated fifos */ if (!hsotg->dedicated_fifos) s3c_hsotg_en_gsint(hsotg, - periodic ? GINTSTS_PTxFEmp : - GINTSTS_NPTxFEmp); + periodic ? GINTSTS_PTXFEMP : + GINTSTS_NPTXFEMP); } /* see if we can write data */ @@ -598,8 +429,8 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, /* it's needed only when we do not use dedicated fifos */ if (!hsotg->dedicated_fifos) s3c_hsotg_en_gsint(hsotg, - periodic ? GINTSTS_PTxFEmp : - GINTSTS_NPTxFEmp); + periodic ? GINTSTS_PTXFEMP : + GINTSTS_NPTXFEMP); } dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", @@ -636,12 +467,12 @@ static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep) unsigned maxpkt; if (index != 0) { - maxsize = DxEPTSIZ_XferSize_LIMIT + 1; - maxpkt = DxEPTSIZ_PktCnt_LIMIT + 1; + maxsize = DXEPTSIZ_XFERSIZE_LIMIT + 1; + maxpkt = DXEPTSIZ_PKTCNT_LIMIT + 1; } else { maxsize = 64+64; if (hs_ep->dir_in) - maxpkt = DIEPTSIZ0_PktCnt_LIMIT + 1; + maxpkt = DIEPTSIZ0_PKTCNT_LIMIT + 1; else maxpkt = 2; } @@ -710,7 +541,7 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, /* If endpoint is stalled, we will restart request later */ ctrl = readl(hsotg->regs + epctrl_reg); - if (ctrl & DxEPCTL_Stall) { + if (ctrl & DXEPCTL_STALL) { dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index); return; } @@ -720,7 +551,7 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, ureq->length, ureq->actual); if (0) dev_dbg(hsotg->dev, - "REQ buf %p len %d dma 0x%pad noi=%d zp=%d snok=%d\n", + "REQ buf %p len %d dma %pad noi=%d zp=%d snok=%d\n", ureq->buf, length, &ureq->dma, ureq->no_interrupt, ureq->zero, ureq->short_not_ok); @@ -750,9 +581,9 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, if (dir_in && index != 0) if (hs_ep->isochronous) - epsize = DxEPTSIZ_MC(packets); + epsize = DXEPTSIZ_MC(packets); else - epsize = DxEPTSIZ_MC(1); + epsize = DXEPTSIZ_MC(1); else epsize = 0; @@ -766,8 +597,8 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, packets++; } - epsize |= DxEPTSIZ_PktCnt(packets); - epsize |= DxEPTSIZ_XferSize(length); + epsize |= DXEPTSIZ_PKTCNT(packets); + epsize |= DXEPTSIZ_XFERSIZE(length); dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n", __func__, packets, length, ureq->length, epsize, epsize_reg); @@ -789,12 +620,12 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index); writel(ureq->dma, hsotg->regs + dma_reg); - dev_dbg(hsotg->dev, "%s: 0x%pad => 0x%08x\n", + dev_dbg(hsotg->dev, "%s: %pad => 0x%08x\n", __func__, &ureq->dma, dma_reg); } - ctrl |= DxEPCTL_EPEna; /* ensure ep enabled */ - ctrl |= DxEPCTL_USBActEp; + ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ + ctrl |= DXEPCTL_USBACTEP; dev_dbg(hsotg->dev, "setup req:%d\n", hsotg->setup); @@ -802,7 +633,7 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, if (hsotg->setup && index == 0) hsotg->setup = 0; else - ctrl |= DxEPCTL_CNAK; /* clear NAK set by core */ + ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); @@ -828,7 +659,7 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, * to debugging to see what is going on. */ if (dir_in) - writel(DIEPMSK_INTknTXFEmpMsk, + writel(DIEPMSK_INTKNTXFEMPMSK, hsotg->regs + DIEPINT(index)); /* @@ -837,12 +668,12 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, */ /* check ep is enabled */ - if (!(readl(hsotg->regs + epctrl_reg) & DxEPCTL_EPEna)) + if (!(readl(hsotg->regs + epctrl_reg) & DXEPCTL_EPENA)) dev_warn(hsotg->dev, - "ep%d: failed to become enabled (DxEPCTL=0x%08x)?\n", + "ep%d: failed to become enabled (DXEPCTL=0x%08x)?\n", index, readl(hsotg->regs + epctrl_reg)); - dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", + dev_dbg(hsotg->dev, "%s: DXEPCTL=0x%08x\n", __func__, readl(hsotg->regs + epctrl_reg)); /* enable ep interrupts */ @@ -1205,12 +1036,12 @@ static void s3c_hsotg_stall_ep0(struct s3c_hsotg *hsotg) { */ ctrl = readl(hsotg->regs + reg); - ctrl |= DxEPCTL_Stall; - ctrl |= DxEPCTL_CNAK; + ctrl |= DXEPCTL_STALL; + ctrl |= DXEPCTL_CNAK; writel(ctrl, hsotg->regs + reg); dev_dbg(hsotg->dev, - "written DxEPCTL=0x%08x to %08x (DxEPCTL=0x%08x)\n", + "written DXEPCTL=0x%08x to %08x (DXEPCTL=0x%08x)\n", ctrl, reg, readl(hsotg->regs + reg)); /* @@ -1262,8 +1093,9 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg, case USB_REQ_SET_ADDRESS: s3c_hsotg_disconnect(hsotg); dcfg = readl(hsotg->regs + DCFG); - dcfg &= ~DCFG_DevAddr_MASK; - dcfg |= ctrl->wValue << DCFG_DevAddr_SHIFT; + dcfg &= ~DCFG_DEVADDR_MASK; + dcfg |= (le16_to_cpu(ctrl->wValue) << + DCFG_DEVADDR_SHIFT) & DCFG_DEVADDR_MASK; writel(dcfg, hsotg->regs + DCFG); dev_info(hsotg->dev, "new address %d\n", ctrl->wValue); @@ -1458,7 +1290,7 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size) int ptr; dev_warn(hsotg->dev, - "%s: FIFO %d bytes on ep%d but no req (DxEPCTl=0x%08x)\n", + "%s: FIFO %d bytes on ep%d but no req (DXEPCTl=0x%08x)\n", __func__, size, ep_idx, epctl); /* dump the data from the FIFO, we've nothing we can do */ @@ -1530,13 +1362,13 @@ static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg, dev_dbg(hsotg->dev, "sending zero-length packet\n"); /* issue a zero-sized packet to terminate this */ - writel(DxEPTSIZ_MC(1) | DxEPTSIZ_PktCnt(1) | - DxEPTSIZ_XferSize(0), hsotg->regs + DIEPTSIZ(0)); + writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | + DXEPTSIZ_XFERSIZE(0), hsotg->regs + DIEPTSIZ(0)); ctrl = readl(hsotg->regs + DIEPCTL0); - ctrl |= DxEPCTL_CNAK; /* clear NAK set by core */ - ctrl |= DxEPCTL_EPEna; /* ensure ep enabled */ - ctrl |= DxEPCTL_USBActEp; + ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ + ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ + ctrl |= DXEPCTL_USBACTEP; writel(ctrl, hsotg->regs + DIEPCTL0); } @@ -1557,7 +1389,7 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep = &hsotg->eps[epnum]; struct s3c_hsotg_req *hs_req = hs_ep->req; struct usb_request *req = &hs_req->req; - unsigned size_left = DxEPTSIZ_XferSize_GET(epsize); + unsigned size_left = DXEPTSIZ_XFERSIZE_GET(epsize); int result = 0; if (!hs_req) { @@ -1657,24 +1489,22 @@ static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg) WARN_ON(using_dma(hsotg)); - epnum = grxstsr & GRXSTS_EPNum_MASK; - status = grxstsr & GRXSTS_PktSts_MASK; + epnum = grxstsr & GRXSTS_EPNUM_MASK; + status = grxstsr & GRXSTS_PKTSTS_MASK; - size = grxstsr & GRXSTS_ByteCnt_MASK; - size >>= GRXSTS_ByteCnt_SHIFT; + size = grxstsr & GRXSTS_BYTECNT_MASK; + size >>= GRXSTS_BYTECNT_SHIFT; if (1) dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n", __func__, grxstsr, size, epnum); -#define __status(x) ((x) >> GRXSTS_PktSts_SHIFT) - - switch (status >> GRXSTS_PktSts_SHIFT) { - case __status(GRXSTS_PktSts_GlobalOutNAK): - dev_dbg(hsotg->dev, "GlobalOutNAK\n"); + switch ((status & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT) { + case GRXSTS_PKTSTS_GLOBALOUTNAK: + dev_dbg(hsotg->dev, "GLOBALOUTNAK\n"); break; - case __status(GRXSTS_PktSts_OutDone): + case GRXSTS_PKTSTS_OUTDONE: dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n", s3c_hsotg_read_frameno(hsotg)); @@ -1682,7 +1512,7 @@ static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg) s3c_hsotg_handle_outdone(hsotg, epnum, false); break; - case __status(GRXSTS_PktSts_SetupDone): + case GRXSTS_PKTSTS_SETUPDONE: dev_dbg(hsotg->dev, "SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n", s3c_hsotg_read_frameno(hsotg), @@ -1691,11 +1521,11 @@ static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg) s3c_hsotg_handle_outdone(hsotg, epnum, true); break; - case __status(GRXSTS_PktSts_OutRX): + case GRXSTS_PKTSTS_OUTRX: s3c_hsotg_rx_data(hsotg, epnum, size); break; - case __status(GRXSTS_PktSts_SetupRX): + case GRXSTS_PKTSTS_SETUPRX: dev_dbg(hsotg->dev, "SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n", s3c_hsotg_read_frameno(hsotg), @@ -1761,7 +1591,7 @@ static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg, hs_ep->ep.maxpacket = mps; hs_ep->mc = 1; } else { - mpsval = mps & DxEPCTL_MPS_MASK; + mpsval = mps & DXEPCTL_MPS_MASK; if (mpsval > 1024) goto bad_mps; mcval = ((mps >> 11) & 0x3) + 1; @@ -1777,13 +1607,13 @@ static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg, */ reg = readl(regs + DIEPCTL(ep)); - reg &= ~DxEPCTL_MPS_MASK; + reg &= ~DXEPCTL_MPS_MASK; reg |= mpsval; writel(reg, regs + DIEPCTL(ep)); if (ep) { reg = readl(regs + DOEPCTL(ep)); - reg &= ~DxEPCTL_MPS_MASK; + reg &= ~DXEPCTL_MPS_MASK; reg |= mpsval; writel(reg, regs + DOEPCTL(ep)); } @@ -1804,7 +1634,7 @@ static void s3c_hsotg_txfifo_flush(struct s3c_hsotg *hsotg, unsigned int idx) int timeout; int val; - writel(GRSTCTL_TxFNum(idx) | GRSTCTL_TxFFlsh, + writel(GRSTCTL_TXFNUM(idx) | GRSTCTL_TXFFLSH, hsotg->regs + GRSTCTL); /* wait until the fifo is flushed */ @@ -1813,7 +1643,7 @@ static void s3c_hsotg_txfifo_flush(struct s3c_hsotg *hsotg, unsigned int idx) while (1) { val = readl(hsotg->regs + GRSTCTL); - if ((val & (GRSTCTL_TxFFlsh)) == 0) + if ((val & (GRSTCTL_TXFFLSH)) == 0) break; if (--timeout == 0) { @@ -1896,7 +1726,7 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg, * aligned). */ - size_left = DxEPTSIZ_XferSize_GET(epsize); + size_left = DXEPTSIZ_XFERSIZE_GET(epsize); size_done = hs_ep->size_loaded - size_left; size_done += hs_ep->last_load; @@ -1963,17 +1793,17 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n", __func__, idx, dir_in ? "in" : "out", ints); - if (ints & DxEPINT_XferCompl) { + if (ints & DXEPINT_XFERCOMPL) { if (hs_ep->isochronous && hs_ep->interval == 1) { - if (ctrl & DxEPCTL_EOFrNum) - ctrl |= DxEPCTL_SetEvenFr; + if (ctrl & DXEPCTL_EOFRNUM) + ctrl |= DXEPCTL_SETEVENFR; else - ctrl |= DxEPCTL_SetOddFr; + ctrl |= DXEPCTL_SETODDFR; writel(ctrl, hsotg->regs + epctl_reg); } dev_dbg(hsotg->dev, - "%s: XferCompl: DxEPCTL=0x%08x, DxEPTSIZ=%08x\n", + "%s: XferCompl: DxEPCTL=0x%08x, DXEPTSIZ=%08x\n", __func__, readl(hsotg->regs + epctl_reg), readl(hsotg->regs + epsiz_reg)); @@ -1996,7 +1826,7 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, } } - if (ints & DxEPINT_EPDisbld) { + if (ints & DXEPINT_EPDISBLD) { dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); if (dir_in) { @@ -2004,20 +1834,20 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, s3c_hsotg_txfifo_flush(hsotg, idx); - if ((epctl & DxEPCTL_Stall) && - (epctl & DxEPCTL_EPType_Bulk)) { + if ((epctl & DXEPCTL_STALL) && + (epctl & DXEPCTL_EPTYPE_BULK)) { int dctl = readl(hsotg->regs + DCTL); - dctl |= DCTL_CGNPInNAK; + dctl |= DCTL_CGNPINNAK; writel(dctl, hsotg->regs + DCTL); } } } - if (ints & DxEPINT_AHBErr) + if (ints & DXEPINT_AHBERR) dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); - if (ints & DxEPINT_Setup) { /* Setup or Timeout */ + if (ints & DXEPINT_SETUP) { /* Setup or Timeout */ dev_dbg(hsotg->dev, "%s: Setup/Timeout\n", __func__); if (using_dma(hsotg) && idx == 0) { @@ -2035,25 +1865,25 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, } } - if (ints & DxEPINT_Back2BackSetup) + if (ints & DXEPINT_BACK2BACKSETUP) dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__); if (dir_in && !hs_ep->isochronous) { /* not sure if this is important, but we'll clear it anyway */ - if (ints & DIEPMSK_INTknTXFEmpMsk) { + if (ints & DIEPMSK_INTKNTXFEMPMSK) { dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n", __func__, idx); } /* this probably means something bad is happening */ - if (ints & DIEPMSK_INTknEPMisMsk) { + if (ints & DIEPMSK_INTKNEPMISMSK) { dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n", __func__, idx); } /* FIFO has space or is empty (see GAHBCFG) */ if (hsotg->dedicated_fifos && - ints & DIEPMSK_TxFIFOEmpty) { + ints & DIEPMSK_TXFIFOEMPTY) { dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n", __func__, idx); if (!using_dma(hsotg)) @@ -2089,21 +1919,21 @@ static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg) */ /* catch both EnumSpd_FS and EnumSpd_FS48 */ - switch (dsts & DSTS_EnumSpd_MASK) { - case DSTS_EnumSpd_FS: - case DSTS_EnumSpd_FS48: + switch (dsts & DSTS_ENUMSPD_MASK) { + case DSTS_ENUMSPD_FS: + case DSTS_ENUMSPD_FS48: hsotg->gadget.speed = USB_SPEED_FULL; ep0_mps = EP0_MPS_LIMIT; ep_mps = 1023; break; - case DSTS_EnumSpd_HS: + case DSTS_ENUMSPD_HS: hsotg->gadget.speed = USB_SPEED_HIGH; ep0_mps = EP0_MPS_LIMIT; ep_mps = 1024; break; - case DSTS_EnumSpd_LS: + case DSTS_ENUMSPD_LS: hsotg->gadget.speed = USB_SPEED_LOW; /* * note, we don't actually support LS in this driver at the @@ -2169,16 +1999,6 @@ static void kill_all_requests(struct s3c_hsotg *hsotg, s3c_hsotg_txfifo_flush(hsotg, ep->index); } -#define call_gadget(_hs, _entry) \ -do { \ - if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN && \ - (_hs)->driver && (_hs)->driver->_entry) { \ - spin_unlock(&_hs->lock); \ - (_hs)->driver->_entry(&(_hs)->gadget); \ - spin_lock(&_hs->lock); \ - } \ -} while (0) - /** * s3c_hsotg_disconnect - disconnect service * @hsotg: The device state. @@ -2226,9 +2046,9 @@ static void s3c_hsotg_irq_fifoempty(struct s3c_hsotg *hsotg, bool periodic) } /* IRQ flags which will trigger a retry around the IRQ loop */ -#define IRQ_RETRY_MASK (GINTSTS_NPTxFEmp | \ - GINTSTS_PTxFEmp | \ - GINTSTS_RxFLvl) +#define IRQ_RETRY_MASK (GINTSTS_NPTXFEMP | \ + GINTSTS_PTXFEMP | \ + GINTSTS_RXFLVL) /** * s3c_hsotg_corereset - issue softreset to the core @@ -2244,14 +2064,14 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg) dev_dbg(hsotg->dev, "resetting core\n"); /* issue soft reset */ - writel(GRSTCTL_CSftRst, hsotg->regs + GRSTCTL); + writel(GRSTCTL_CSFTRST, hsotg->regs + GRSTCTL); timeout = 10000; do { grstctl = readl(hsotg->regs + GRSTCTL); - } while ((grstctl & GRSTCTL_CSftRst) && timeout-- > 0); + } while ((grstctl & GRSTCTL_CSFTRST) && timeout-- > 0); - if (grstctl & GRSTCTL_CSftRst) { + if (grstctl & GRSTCTL_CSFTRST) { dev_err(hsotg->dev, "Failed to get CSftRst asserted\n"); return -EINVAL; } @@ -2268,7 +2088,7 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg) return -ETIMEDOUT; } - if (!(grstctl & GRSTCTL_AHBIdle)) + if (!(grstctl & GRSTCTL_AHBIDLE)) continue; break; /* reset done */ @@ -2294,14 +2114,14 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) */ /* set the PLL on, remove the HNP/SRP and set the PHY */ - writel(hsotg->phyif | GUSBCFG_TOutCal(7) | + writel(hsotg->phyif | GUSBCFG_TOUTCAL(7) | (0x5 << 10), hsotg->regs + GUSBCFG); s3c_hsotg_init_fifo(hsotg); - __orr32(hsotg->regs + DCTL, DCTL_SftDiscon); + __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); - writel(1 << 18 | DCFG_DevSpd_HS, hsotg->regs + DCFG); + writel(1 << 18 | DCFG_DEVSPD_HS, hsotg->regs + DCFG); /* Clear any pending OTG interrupts */ writel(0xffffffff, hsotg->regs + GOTGINT); @@ -2309,21 +2129,21 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) /* Clear any pending interrupts */ writel(0xffffffff, hsotg->regs + GINTSTS); - writel(GINTSTS_ErlySusp | GINTSTS_SessReqInt | - GINTSTS_GOUTNakEff | GINTSTS_GINNakEff | - GINTSTS_ConIDStsChng | GINTSTS_USBRst | - GINTSTS_EnumDone | GINTSTS_OTGInt | - GINTSTS_USBSusp | GINTSTS_WkUpInt, - hsotg->regs + GINTMSK); + writel(GINTSTS_ERLYSUSP | GINTSTS_SESSREQINT | + GINTSTS_GOUTNAKEFF | GINTSTS_GINNAKEFF | + GINTSTS_CONIDSTSCHNG | GINTSTS_USBRST | + GINTSTS_ENUMDONE | GINTSTS_OTGINT | + GINTSTS_USBSUSP | GINTSTS_WKUPINT, + hsotg->regs + GINTMSK); if (using_dma(hsotg)) - writel(GAHBCFG_GlblIntrEn | GAHBCFG_DMAEn | - GAHBCFG_HBstLen_Incr4, + writel(GAHBCFG_GLBL_INTR_EN | GAHBCFG_DMA_EN | + GAHBCFG_HBSTLEN_INCR4, hsotg->regs + GAHBCFG); else - writel(((hsotg->dedicated_fifos) ? (GAHBCFG_NPTxFEmpLvl | - GAHBCFG_PTxFEmpLvl) : 0) | - GAHBCFG_GlblIntrEn, + writel(((hsotg->dedicated_fifos) ? (GAHBCFG_NP_TXF_EMP_LVL | + GAHBCFG_P_TXF_EMP_LVL) : 0) | + GAHBCFG_GLBL_INTR_EN, hsotg->regs + GAHBCFG); /* @@ -2332,22 +2152,22 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) * interrupts. */ - writel(((hsotg->dedicated_fifos) ? DIEPMSK_TxFIFOEmpty | - DIEPMSK_INTknTXFEmpMsk : 0) | - DIEPMSK_EPDisbldMsk | DIEPMSK_XferComplMsk | - DIEPMSK_TimeOUTMsk | DIEPMSK_AHBErrMsk | - DIEPMSK_INTknEPMisMsk, - hsotg->regs + DIEPMSK); + writel(((hsotg->dedicated_fifos) ? DIEPMSK_TXFIFOEMPTY | + DIEPMSK_INTKNTXFEMPMSK : 0) | + DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK | + DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | + DIEPMSK_INTKNEPMISMSK, + hsotg->regs + DIEPMSK); /* * don't need XferCompl, we get that from RXFIFO in slave mode. In * DMA mode we may need this. */ - writel((using_dma(hsotg) ? (DIEPMSK_XferComplMsk | - DIEPMSK_TimeOUTMsk) : 0) | - DOEPMSK_EPDisbldMsk | DOEPMSK_AHBErrMsk | - DOEPMSK_SetupMsk, - hsotg->regs + DOEPMSK); + writel((using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK | + DIEPMSK_TIMEOUTMSK) : 0) | + DOEPMSK_EPDISBLDMSK | DOEPMSK_AHBERRMSK | + DOEPMSK_SETUPMSK, + hsotg->regs + DOEPMSK); writel(0, hsotg->regs + DAINTMSK); @@ -2356,7 +2176,7 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) readl(hsotg->regs + DOEPCTL0)); /* enable in and out endpoint interrupts */ - s3c_hsotg_en_gsint(hsotg, GINTSTS_OEPInt | GINTSTS_IEPInt); + s3c_hsotg_en_gsint(hsotg, GINTSTS_OEPINT | GINTSTS_IEPINT); /* * Enable the RXFIFO when in slave mode, as this is how we collect @@ -2364,15 +2184,15 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) * things we cannot process, so do not use it. */ if (!using_dma(hsotg)) - s3c_hsotg_en_gsint(hsotg, GINTSTS_RxFLvl); + s3c_hsotg_en_gsint(hsotg, GINTSTS_RXFLVL); /* Enable interrupts for EP0 in and out */ s3c_hsotg_ctrl_epint(hsotg, 0, 0, 1); s3c_hsotg_ctrl_epint(hsotg, 0, 1, 1); - __orr32(hsotg->regs + DCTL, DCTL_PWROnPrgDone); + __orr32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE); udelay(10); /* see openiboot */ - __bic32(hsotg->regs + DCTL, DCTL_PWROnPrgDone); + __bic32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE); dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + DCTL)); @@ -2382,17 +2202,17 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) */ /* set to read 1 8byte packet */ - writel(DxEPTSIZ_MC(1) | DxEPTSIZ_PktCnt(1) | - DxEPTSIZ_XferSize(8), hsotg->regs + DOEPTSIZ0); + writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | + DXEPTSIZ_XFERSIZE(8), hsotg->regs + DOEPTSIZ0); writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | - DxEPCTL_CNAK | DxEPCTL_EPEna | - DxEPCTL_USBActEp, + DXEPCTL_CNAK | DXEPCTL_EPENA | + DXEPCTL_USBACTEP, hsotg->regs + DOEPCTL0); /* enable, but don't activate EP0in */ writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | - DxEPCTL_USBActEp, hsotg->regs + DIEPCTL0); + DXEPCTL_USBACTEP, hsotg->regs + DIEPCTL0); s3c_hsotg_enqueue_setup(hsotg); @@ -2401,14 +2221,14 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) readl(hsotg->regs + DOEPCTL0)); /* clear global NAKs */ - writel(DCTL_CGOUTNak | DCTL_CGNPInNAK, + writel(DCTL_CGOUTNAK | DCTL_CGNPINNAK, hsotg->regs + DCTL); /* must be at-least 3ms to allow bus to see disconnect */ mdelay(3); /* remove the soft-disconnect and let's go */ - __bic32(hsotg->regs + DCTL, DCTL_SftDiscon); + __bic32(hsotg->regs + DCTL, DCTL_SFTDISCON); } /** @@ -2433,7 +2253,7 @@ irq_retry: gintsts &= gintmsk; - if (gintsts & GINTSTS_OTGInt) { + if (gintsts & GINTSTS_OTGINT) { u32 otgint = readl(hsotg->regs + GOTGINT); dev_info(hsotg->dev, "OTGInt: %08x\n", otgint); @@ -2441,34 +2261,34 @@ irq_retry: writel(otgint, hsotg->regs + GOTGINT); } - if (gintsts & GINTSTS_SessReqInt) { + if (gintsts & GINTSTS_SESSREQINT) { dev_dbg(hsotg->dev, "%s: SessReqInt\n", __func__); - writel(GINTSTS_SessReqInt, hsotg->regs + GINTSTS); + writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS); } - if (gintsts & GINTSTS_EnumDone) { - writel(GINTSTS_EnumDone, hsotg->regs + GINTSTS); + if (gintsts & GINTSTS_ENUMDONE) { + writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS); s3c_hsotg_irq_enumdone(hsotg); } - if (gintsts & GINTSTS_ConIDStsChng) { + if (gintsts & GINTSTS_CONIDSTSCHNG) { dev_dbg(hsotg->dev, "ConIDStsChg (DSTS=0x%08x, GOTCTL=%08x)\n", readl(hsotg->regs + DSTS), readl(hsotg->regs + GOTGCTL)); - writel(GINTSTS_ConIDStsChng, hsotg->regs + GINTSTS); + writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS); } - if (gintsts & (GINTSTS_OEPInt | GINTSTS_IEPInt)) { + if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) { u32 daint = readl(hsotg->regs + DAINT); u32 daintmsk = readl(hsotg->regs + DAINTMSK); u32 daint_out, daint_in; int ep; daint &= daintmsk; - daint_out = daint >> DAINT_OutEP_SHIFT; - daint_in = daint & ~(daint_out << DAINT_OutEP_SHIFT); + daint_out = daint >> DAINT_OUTEP_SHIFT; + daint_in = daint & ~(daint_out << DAINT_OUTEP_SHIFT); dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint); @@ -2483,7 +2303,7 @@ irq_retry: } } - if (gintsts & GINTSTS_USBRst) { + if (gintsts & GINTSTS_USBRST) { u32 usb_status = readl(hsotg->regs + GOTGCTL); @@ -2491,7 +2311,7 @@ irq_retry: dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", readl(hsotg->regs + GNPTXSTS)); - writel(GINTSTS_USBRst, hsotg->regs + GINTSTS); + writel(GINTSTS_USBRST, hsotg->regs + GINTSTS); if (usb_status & GOTGCTL_BSESVLD) { if (time_after(jiffies, hsotg->last_rst + @@ -2508,7 +2328,7 @@ irq_retry: /* check both FIFOs */ - if (gintsts & GINTSTS_NPTxFEmp) { + if (gintsts & GINTSTS_NPTXFEMP) { dev_dbg(hsotg->dev, "NPTxFEmp\n"); /* @@ -2517,20 +2337,20 @@ irq_retry: * it needs re-enabling */ - s3c_hsotg_disable_gsint(hsotg, GINTSTS_NPTxFEmp); + s3c_hsotg_disable_gsint(hsotg, GINTSTS_NPTXFEMP); s3c_hsotg_irq_fifoempty(hsotg, false); } - if (gintsts & GINTSTS_PTxFEmp) { + if (gintsts & GINTSTS_PTXFEMP) { dev_dbg(hsotg->dev, "PTxFEmp\n"); /* See note in GINTSTS_NPTxFEmp */ - s3c_hsotg_disable_gsint(hsotg, GINTSTS_PTxFEmp); + s3c_hsotg_disable_gsint(hsotg, GINTSTS_PTXFEMP); s3c_hsotg_irq_fifoempty(hsotg, true); } - if (gintsts & GINTSTS_RxFLvl) { + if (gintsts & GINTSTS_RXFLVL) { /* * note, since GINTSTS_RxFLvl doubles as FIFO-not-empty, * we need to retry s3c_hsotg_handle_rx if this is still @@ -2540,28 +2360,28 @@ irq_retry: s3c_hsotg_handle_rx(hsotg); } - if (gintsts & GINTSTS_ModeMis) { + if (gintsts & GINTSTS_MODEMIS) { dev_warn(hsotg->dev, "warning, mode mismatch triggered\n"); - writel(GINTSTS_ModeMis, hsotg->regs + GINTSTS); + writel(GINTSTS_MODEMIS, hsotg->regs + GINTSTS); } - if (gintsts & GINTSTS_USBSusp) { + if (gintsts & GINTSTS_USBSUSP) { dev_info(hsotg->dev, "GINTSTS_USBSusp\n"); - writel(GINTSTS_USBSusp, hsotg->regs + GINTSTS); + writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS); call_gadget(hsotg, suspend); } - if (gintsts & GINTSTS_WkUpInt) { + if (gintsts & GINTSTS_WKUPINT) { dev_info(hsotg->dev, "GINTSTS_WkUpIn\n"); - writel(GINTSTS_WkUpInt, hsotg->regs + GINTSTS); + writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS); call_gadget(hsotg, resume); } - if (gintsts & GINTSTS_ErlySusp) { + if (gintsts & GINTSTS_ERLYSUSP) { dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n"); - writel(GINTSTS_ErlySusp, hsotg->regs + GINTSTS); + writel(GINTSTS_ERLYSUSP, hsotg->regs + GINTSTS); } /* @@ -2570,18 +2390,18 @@ irq_retry: * the occurrence. */ - if (gintsts & GINTSTS_GOUTNakEff) { + if (gintsts & GINTSTS_GOUTNAKEFF) { dev_info(hsotg->dev, "GOUTNakEff triggered\n"); - writel(DCTL_CGOUTNak, hsotg->regs + DCTL); + writel(DCTL_CGOUTNAK, hsotg->regs + DCTL); s3c_hsotg_dump(hsotg); } - if (gintsts & GINTSTS_GINNakEff) { + if (gintsts & GINTSTS_GINNAKEFF) { dev_info(hsotg->dev, "GINNakEff triggered\n"); - writel(DCTL_CGNPInNAK, hsotg->regs + DCTL); + writel(DCTL_CGNPINNAK, hsotg->regs + DCTL); s3c_hsotg_dump(hsotg); } @@ -2645,14 +2465,14 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, spin_lock_irqsave(&hsotg->lock, flags); - epctrl &= ~(DxEPCTL_EPType_MASK | DxEPCTL_MPS_MASK); - epctrl |= DxEPCTL_MPS(mps); + epctrl &= ~(DXEPCTL_EPTYPE_MASK | DXEPCTL_MPS_MASK); + epctrl |= DXEPCTL_MPS(mps); /* * mark the endpoint as active, otherwise the core may ignore * transactions entirely for this endpoint */ - epctrl |= DxEPCTL_USBActEp; + epctrl |= DXEPCTL_USBACTEP; /* * set the NAK status on the endpoint, otherwise we might try and @@ -2661,7 +2481,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, * size register hasn't been set. */ - epctrl |= DxEPCTL_SNAK; + epctrl |= DXEPCTL_SNAK; /* update the endpoint state */ s3c_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps); @@ -2677,15 +2497,15 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { case USB_ENDPOINT_XFER_ISOC: - epctrl |= DxEPCTL_EPType_Iso; - epctrl |= DxEPCTL_SetEvenFr; + epctrl |= DXEPCTL_EPTYPE_ISO; + epctrl |= DXEPCTL_SETEVENFR; hs_ep->isochronous = 1; if (dir_in) hs_ep->periodic = 1; break; case USB_ENDPOINT_XFER_BULK: - epctrl |= DxEPCTL_EPType_Bulk; + epctrl |= DXEPCTL_EPTYPE_BULK; break; case USB_ENDPOINT_XFER_INT: @@ -2698,14 +2518,14 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, */ hs_ep->periodic = 1; - epctrl |= DxEPCTL_TxFNum(index); + epctrl |= DXEPCTL_TXFNUM(index); } - epctrl |= DxEPCTL_EPType_Intterupt; + epctrl |= DXEPCTL_EPTYPE_INTERRUPT; break; case USB_ENDPOINT_XFER_CONTROL: - epctrl |= DxEPCTL_EPType_Control; + epctrl |= DXEPCTL_EPTYPE_CONTROL; break; } @@ -2714,11 +2534,11 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, * a unique tx-fifo even if it is non-periodic. */ if (dir_in && hsotg->dedicated_fifos) - epctrl |= DxEPCTL_TxFNum(index); + epctrl |= DXEPCTL_TXFNUM(index); /* for non control endpoints, set PID to D0 */ if (index) - epctrl |= DxEPCTL_SetD0PID; + epctrl |= DXEPCTL_SETD0PID; dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n", __func__, epctrl); @@ -2763,9 +2583,9 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep) ctrl = readl(hsotg->regs + epctrl_reg); - ctrl &= ~DxEPCTL_EPEna; - ctrl &= ~DxEPCTL_USBActEp; - ctrl |= DxEPCTL_SNAK; + ctrl &= ~DXEPCTL_EPENA; + ctrl &= ~DXEPCTL_USBACTEP; + ctrl |= DXEPCTL_SNAK; dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); writel(ctrl, hsotg->regs + epctrl_reg); @@ -2852,15 +2672,15 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) epctl = readl(hs->regs + epreg); if (value) { - epctl |= DxEPCTL_Stall + DxEPCTL_SNAK; - if (epctl & DxEPCTL_EPEna) - epctl |= DxEPCTL_EPDis; + epctl |= DXEPCTL_STALL + DXEPCTL_SNAK; + if (epctl & DXEPCTL_EPENA) + epctl |= DXEPCTL_EPDIS; } else { - epctl &= ~DxEPCTL_Stall; - xfertype = epctl & DxEPCTL_EPType_MASK; - if (xfertype == DxEPCTL_EPType_Bulk || - xfertype == DxEPCTL_EPType_Intterupt) - epctl |= DxEPCTL_SetD0PID; + epctl &= ~DXEPCTL_STALL; + xfertype = epctl & DXEPCTL_EPTYPE_MASK; + if (xfertype == DXEPCTL_EPTYPE_BULK || + xfertype == DXEPCTL_EPTYPE_INTERRUPT) + epctl |= DXEPCTL_SETD0PID; } writel(epctl, hs->regs + epreg); @@ -2869,13 +2689,13 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) epctl = readl(hs->regs + epreg); if (value) - epctl |= DxEPCTL_Stall; + epctl |= DXEPCTL_STALL; else { - epctl &= ~DxEPCTL_Stall; - xfertype = epctl & DxEPCTL_EPType_MASK; - if (xfertype == DxEPCTL_EPType_Bulk || - xfertype == DxEPCTL_EPType_Intterupt) - epctl |= DxEPCTL_SetD0PID; + epctl &= ~DXEPCTL_STALL; + xfertype = epctl & DXEPCTL_EPTYPE_MASK; + if (xfertype == DXEPCTL_EPTYPE_BULK || + xfertype == DXEPCTL_EPTYPE_INTERRUPT) + epctl |= DXEPCTL_SETD0PID; } writel(epctl, hs->regs + epreg); @@ -2965,22 +2785,22 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg) { /* unmask subset of endpoint interrupts */ - writel(DIEPMSK_TimeOUTMsk | DIEPMSK_AHBErrMsk | - DIEPMSK_EPDisbldMsk | DIEPMSK_XferComplMsk, - hsotg->regs + DIEPMSK); + writel(DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | + DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK, + hsotg->regs + DIEPMSK); - writel(DOEPMSK_SetupMsk | DOEPMSK_AHBErrMsk | - DOEPMSK_EPDisbldMsk | DOEPMSK_XferComplMsk, - hsotg->regs + DOEPMSK); + writel(DOEPMSK_SETUPMSK | DOEPMSK_AHBERRMSK | + DOEPMSK_EPDISBLDMSK | DOEPMSK_XFERCOMPLMSK, + hsotg->regs + DOEPMSK); writel(0, hsotg->regs + DAINTMSK); /* Be in disconnected state until gadget is registered */ - __orr32(hsotg->regs + DCTL, DCTL_SftDiscon); + __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); if (0) { /* post global nak until we're ready */ - writel(DCTL_SGNPInNAK | DCTL_SGOUTNak, + writel(DCTL_SGNPINNAK | DCTL_SGOUTNAK, hsotg->regs + DCTL); } @@ -2993,10 +2813,10 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg) s3c_hsotg_init_fifo(hsotg); /* set the PLL on, remove the HNP/SRP and set the PHY */ - writel(GUSBCFG_PHYIf16 | GUSBCFG_TOutCal(7) | (0x5 << 10), + writel(GUSBCFG_PHYIF16 | GUSBCFG_TOUTCAL(7) | (0x5 << 10), hsotg->regs + GUSBCFG); - writel(using_dma(hsotg) ? GAHBCFG_DMAEn : 0x0, + writel(using_dma(hsotg) ? GAHBCFG_DMA_EN : 0x0, hsotg->regs + GAHBCFG); } @@ -3187,8 +3007,8 @@ static void s3c_hsotg_initep(struct s3c_hsotg *hsotg, * code is changed to make each endpoint's direction changeable. */ - ptxfifo = readl(hsotg->regs + DPTXFSIZn(epnum)); - hs_ep->fifo_size = DPTXFSIZn_DPTxFSize_GET(ptxfifo) * 4; + ptxfifo = readl(hsotg->regs + DPTXFSIZN(epnum)); + hs_ep->fifo_size = FIFOSIZE_DEPTH_GET(ptxfifo) * 4; /* * if we're using dma, we need to set the next-endpoint pointer @@ -3196,7 +3016,7 @@ static void s3c_hsotg_initep(struct s3c_hsotg *hsotg, */ if (using_dma(hsotg)) { - u32 next = DxEPCTL_NextEp((epnum + 1) % 15); + u32 next = DXEPCTL_NEXTEP((epnum + 1) % 15); writel(next, hsotg->regs + DIEPCTL(epnum)); writel(next, hsotg->regs + DOEPCTL(epnum)); } @@ -3250,10 +3070,10 @@ static void s3c_hsotg_dump(struct s3c_hsotg *hsotg) /* show periodic fifo settings */ for (idx = 1; idx <= 15; idx++) { - val = readl(regs + DPTXFSIZn(idx)); + val = readl(regs + DPTXFSIZN(idx)); dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx, - val >> DPTXFSIZn_DPTxFSize_SHIFT, - val & DPTXFSIZn_DPTxFStAddr_MASK); + val >> FIFOSIZE_DEPTH_SHIFT, + val & FIFOSIZE_STARTADDR_MASK); } for (idx = 0; idx < 15; idx++) { @@ -3368,17 +3188,17 @@ static int fifo_show(struct seq_file *seq, void *v) val = readl(regs + GNPTXFSIZ); seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n", - val >> GNPTXFSIZ_NPTxFDep_SHIFT, - val & GNPTXFSIZ_NPTxFStAddr_MASK); + val >> FIFOSIZE_DEPTH_SHIFT, + val & FIFOSIZE_DEPTH_MASK); seq_puts(seq, "\nPeriodic TXFIFOs:\n"); for (idx = 1; idx <= 15; idx++) { - val = readl(regs + DPTXFSIZn(idx)); + val = readl(regs + DPTXFSIZN(idx)); seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx, - val >> DPTXFSIZn_DPTxFSize_SHIFT, - val & DPTXFSIZn_DPTxFStAddr_MASK); + val >> FIFOSIZE_DEPTH_SHIFT, + val & FIFOSIZE_STARTADDR_MASK); } return 0; @@ -3662,14 +3482,14 @@ static int s3c_hsotg_probe(struct platform_device *pdev) } /* Set default UTMI width */ - hsotg->phyif = GUSBCFG_PHYIf16; + hsotg->phyif = GUSBCFG_PHYIF16; /* * If using the generic PHY framework, check if the PHY bus * width is 8-bit and set the phyif appropriately. */ if (hsotg->phy && (phy_get_bus_width(phy) == 8)) - hsotg->phyif = GUSBCFG_PHYIf8; + hsotg->phyif = GUSBCFG_PHYIF8; if (hsotg->phy) phy_init(hsotg->phy); diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h index 9c92a3c7588a..51248b935493 100644 --- a/drivers/usb/dwc2/hw.h +++ b/drivers/usb/dwc2/hw.h @@ -109,6 +109,7 @@ #define GUSBCFG_FSINTF (1 << 5) #define GUSBCFG_ULPI_UTMI_SEL (1 << 4) #define GUSBCFG_PHYIF16 (1 << 3) +#define GUSBCFG_PHYIF8 (0 << 3) #define GUSBCFG_TOUTCAL_MASK (0x7 << 0) #define GUSBCFG_TOUTCAL_SHIFT 0 #define GUSBCFG_TOUTCAL_LIMIT 0x7 @@ -403,6 +404,7 @@ #define FIFOSIZE_DEPTH_SHIFT 16 #define FIFOSIZE_STARTADDR_MASK (0xffff << 0) #define FIFOSIZE_STARTADDR_SHIFT 0 +#define FIFOSIZE_DEPTH_GET(_x) (((_x) >> 16) & 0xffff) /* Device mode registers */ @@ -519,11 +521,11 @@ #define DXEPCTL_STALL (1 << 21) #define DXEPCTL_SNP (1 << 20) #define DXEPCTL_EPTYPE_MASK (0x3 << 18) -#define DXEPCTL_EPTYPE_SHIFT 18 -#define DXEPCTL_EPTYPE_CONTROL 0 -#define DXEPCTL_EPTYPE_ISO 1 -#define DXEPCTL_EPTYPE_BULK 2 -#define DXEPCTL_EPTYPE_INTTERUPT 3 +#define DXEPCTL_EPTYPE_CONTROL (0x0 << 18) +#define DXEPCTL_EPTYPE_ISO (0x1 << 18) +#define DXEPCTL_EPTYPE_BULK (0x2 << 18) +#define DXEPCTL_EPTYPE_INTERRUPT (0x3 << 18) + #define DXEPCTL_NAKSTS (1 << 17) #define DXEPCTL_DPID (1 << 16) #define DXEPCTL_EOFRNUM (1 << 16) diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index eaba547ce26b..a10e7a353576 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -134,6 +134,12 @@ static int dwc2_driver_probe(struct platform_device *dev) /* Default all params to autodetect */ dwc2_set_all_params(&defparams, -1); params = &defparams; + + /* + * Disable descriptor dma mode by default as the HW can support + * it, but does not support it for SPLIT transactions. + */ + defparams.dma_desc_enable = 0; } hsotg = devm_kzalloc(&dev->dev, sizeof(*hsotg), GFP_KERNEL); diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index e2c730fc9a90..8eb996e4f058 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -44,7 +44,7 @@ comment "Platform Glue Driver Support" config USB_DWC3_OMAP tristate "Texas Instruments OMAP5 and similar Platforms" - depends on EXTCON + depends on EXTCON && (ARCH_OMAP2PLUS || COMPILE_TEST) default USB_DWC3 help Some platforms from Texas Instruments like OMAP5, DRA7xxx and @@ -54,6 +54,7 @@ config USB_DWC3_OMAP config USB_DWC3_EXYNOS tristate "Samsung Exynos Platform" + depends on ARCH_EXYNOS || COMPILE_TEST default USB_DWC3 help Recent Exynos5 SoCs ship with one DesignWare Core USB3 IP inside, @@ -72,6 +73,7 @@ config USB_DWC3_PCI config USB_DWC3_KEYSTONE tristate "Texas Instruments Keystone2 Platforms" + depends on ARCH_KEYSTONE || COMPILE_TEST default USB_DWC3 help Support of USB2/3 functionality in TI Keystone2 platforms. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 10aaaae9af25..eb69eb9f06c8 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -486,70 +486,20 @@ static void dwc3_core_exit(struct dwc3 *dwc) phy_exit(dwc->usb3_generic_phy); } -#define DWC3_ALIGN_MASK (16 - 1) - -static int dwc3_probe(struct platform_device *pdev) +static int dwc3_core_get_phy(struct dwc3 *dwc) { - struct device *dev = &pdev->dev; - struct dwc3_platform_data *pdata = dev_get_platdata(dev); + struct device *dev = dwc->dev; struct device_node *node = dev->of_node; - struct resource *res; - struct dwc3 *dwc; - - int ret = -ENOMEM; - - void __iomem *regs; - void *mem; - - mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); - if (!mem) { - dev_err(dev, "not enough memory\n"); - return -ENOMEM; - } - dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); - dwc->mem = mem; - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(dev, "missing IRQ\n"); - return -ENODEV; - } - dwc->xhci_resources[1].start = res->start; - dwc->xhci_resources[1].end = res->end; - dwc->xhci_resources[1].flags = res->flags; - dwc->xhci_resources[1].name = res->name; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "missing memory resource\n"); - return -ENODEV; - } + int ret; if (node) { - dwc->maximum_speed = of_usb_get_maximum_speed(node); - dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1); - - dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); - dwc->dr_mode = of_usb_get_dr_mode(node); - } else if (pdata) { - dwc->maximum_speed = pdata->maximum_speed; - - dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); - dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); - - dwc->needs_fifo_resize = pdata->tx_fifo_resize; - dwc->dr_mode = pdata->dr_mode; } else { dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); } - /* default to superspeed if no maximum_speed passed */ - if (dwc->maximum_speed == USB_SPEED_UNKNOWN) - dwc->maximum_speed = USB_SPEED_SUPER; - if (IS_ERR(dwc->usb2_phy)) { ret = PTR_ERR(dwc->usb2_phy); if (ret == -ENXIO || ret == -ENODEV) { @@ -600,6 +550,132 @@ static int dwc3_probe(struct platform_device *pdev) } } + return 0; +} + +static int dwc3_core_init_mode(struct dwc3 *dwc) +{ + struct device *dev = dwc->dev; + int ret; + + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); + ret = dwc3_gadget_init(dwc); + if (ret) { + dev_err(dev, "failed to initialize gadget\n"); + return ret; + } + break; + case USB_DR_MODE_HOST: + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); + ret = dwc3_host_init(dwc); + if (ret) { + dev_err(dev, "failed to initialize host\n"); + return ret; + } + break; + case USB_DR_MODE_OTG: + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); + ret = dwc3_host_init(dwc); + if (ret) { + dev_err(dev, "failed to initialize host\n"); + return ret; + } + + ret = dwc3_gadget_init(dwc); + if (ret) { + dev_err(dev, "failed to initialize gadget\n"); + return ret; + } + break; + default: + dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); + return -EINVAL; + } + + return 0; +} + +static void dwc3_core_exit_mode(struct dwc3 *dwc) +{ + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + dwc3_gadget_exit(dwc); + break; + case USB_DR_MODE_HOST: + dwc3_host_exit(dwc); + break; + case USB_DR_MODE_OTG: + dwc3_host_exit(dwc); + dwc3_gadget_exit(dwc); + break; + default: + /* do nothing */ + break; + } +} + +#define DWC3_ALIGN_MASK (16 - 1) + +static int dwc3_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct dwc3_platform_data *pdata = dev_get_platdata(dev); + struct device_node *node = dev->of_node; + struct resource *res; + struct dwc3 *dwc; + + int ret; + + void __iomem *regs; + void *mem; + + mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); + if (!mem) { + dev_err(dev, "not enough memory\n"); + return -ENOMEM; + } + dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); + dwc->mem = mem; + dwc->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(dev, "missing IRQ\n"); + return -ENODEV; + } + dwc->xhci_resources[1].start = res->start; + dwc->xhci_resources[1].end = res->end; + dwc->xhci_resources[1].flags = res->flags; + dwc->xhci_resources[1].name = res->name; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "missing memory resource\n"); + return -ENODEV; + } + + if (node) { + dwc->maximum_speed = of_usb_get_maximum_speed(node); + + dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); + dwc->dr_mode = of_usb_get_dr_mode(node); + } else if (pdata) { + dwc->maximum_speed = pdata->maximum_speed; + + dwc->needs_fifo_resize = pdata->tx_fifo_resize; + dwc->dr_mode = pdata->dr_mode; + } + + /* default to superspeed if no maximum_speed passed */ + if (dwc->maximum_speed == USB_SPEED_UNKNOWN) + dwc->maximum_speed = USB_SPEED_SUPER; + + ret = dwc3_core_get_phy(dwc); + if (ret) + return ret; + dwc->xhci_resources[0].start = res->start; dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + DWC3_XHCI_REGS_END; @@ -621,7 +697,6 @@ static int dwc3_probe(struct platform_device *pdev) dwc->regs = regs; dwc->regs_size = resource_size(res); - dwc->dev = dev; dev->dma_mask = dev->parent->dma_mask; dev->dma_parms = dev->parent->dma_parms; @@ -670,41 +745,9 @@ static int dwc3_probe(struct platform_device *pdev) goto err_usb3phy_power; } - switch (dwc->dr_mode) { - case USB_DR_MODE_PERIPHERAL: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); - ret = dwc3_gadget_init(dwc); - if (ret) { - dev_err(dev, "failed to initialize gadget\n"); - goto err2; - } - break; - case USB_DR_MODE_HOST: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); - ret = dwc3_host_init(dwc); - if (ret) { - dev_err(dev, "failed to initialize host\n"); - goto err2; - } - break; - case USB_DR_MODE_OTG: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); - ret = dwc3_host_init(dwc); - if (ret) { - dev_err(dev, "failed to initialize host\n"); - goto err2; - } - - ret = dwc3_gadget_init(dwc); - if (ret) { - dev_err(dev, "failed to initialize gadget\n"); - goto err2; - } - break; - default: - dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); + ret = dwc3_core_init_mode(dwc); + if (ret) goto err2; - } ret = dwc3_debugfs_init(dwc); if (ret) { @@ -717,21 +760,7 @@ static int dwc3_probe(struct platform_device *pdev) return 0; err3: - switch (dwc->dr_mode) { - case USB_DR_MODE_PERIPHERAL: - dwc3_gadget_exit(dwc); - break; - case USB_DR_MODE_HOST: - dwc3_host_exit(dwc); - break; - case USB_DR_MODE_OTG: - dwc3_host_exit(dwc); - dwc3_gadget_exit(dwc); - break; - default: - /* do nothing */ - break; - } + dwc3_core_exit_mode(dwc); err2: dwc3_event_buffers_cleanup(dwc); @@ -766,23 +795,7 @@ static int dwc3_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); dwc3_debugfs_exit(dwc); - - switch (dwc->dr_mode) { - case USB_DR_MODE_PERIPHERAL: - dwc3_gadget_exit(dwc); - break; - case USB_DR_MODE_HOST: - dwc3_host_exit(dwc); - break; - case USB_DR_MODE_OTG: - dwc3_host_exit(dwc); - dwc3_gadget_exit(dwc); - break; - default: - /* do nothing */ - break; - } - + dwc3_core_exit_mode(dwc); dwc3_event_buffers_cleanup(dwc); dwc3_free_event_buffers(dwc); dwc3_core_exit(dwc); diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 28c8ad79f5e6..f9fb8adb785b 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -24,9 +24,10 @@ #include <linux/dma-mapping.h> #include <linux/clk.h> #include <linux/usb/otg.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h> #include <linux/of.h> #include <linux/of_platform.h> +#include <linux/regulator/consumer.h> struct dwc3_exynos { struct platform_device *usb2_phy; @@ -34,17 +35,19 @@ struct dwc3_exynos { struct device *dev; struct clk *clk; + struct regulator *vdd33; + struct regulator *vdd10; }; static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos) { - struct usb_phy_gen_xceiv_platform_data pdata; + struct usb_phy_generic_platform_data pdata; struct platform_device *pdev; int ret; memset(&pdata, 0x00, sizeof(pdata)); - pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO); + pdev = platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO); if (!pdev) return -ENOMEM; @@ -56,7 +59,7 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos) if (ret) goto err1; - pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO); + pdev = platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO); if (!pdev) { ret = -ENOMEM; goto err1; @@ -107,12 +110,12 @@ static int dwc3_exynos_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; - int ret = -ENOMEM; + int ret; exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL); if (!exynos) { dev_err(dev, "not enough memory\n"); - goto err1; + return -ENOMEM; } /* @@ -122,21 +125,20 @@ static int dwc3_exynos_probe(struct platform_device *pdev) */ ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); if (ret) - goto err1; + return ret; platform_set_drvdata(pdev, exynos); ret = dwc3_exynos_register_phys(exynos); if (ret) { dev_err(dev, "couldn't register PHYs\n"); - goto err1; + return ret; } clk = devm_clk_get(dev, "usbdrd30"); if (IS_ERR(clk)) { dev_err(dev, "couldn't get clock\n"); - ret = -EINVAL; - goto err1; + return -EINVAL; } exynos->dev = dev; @@ -144,23 +146,48 @@ static int dwc3_exynos_probe(struct platform_device *pdev) clk_prepare_enable(exynos->clk); + exynos->vdd33 = devm_regulator_get(dev, "vdd33"); + if (IS_ERR(exynos->vdd33)) { + ret = PTR_ERR(exynos->vdd33); + goto err2; + } + ret = regulator_enable(exynos->vdd33); + if (ret) { + dev_err(dev, "Failed to enable VDD33 supply\n"); + goto err2; + } + + exynos->vdd10 = devm_regulator_get(dev, "vdd10"); + if (IS_ERR(exynos->vdd10)) { + ret = PTR_ERR(exynos->vdd10); + goto err3; + } + ret = regulator_enable(exynos->vdd10); + if (ret) { + dev_err(dev, "Failed to enable VDD10 supply\n"); + goto err3; + } + if (node) { ret = of_platform_populate(node, NULL, NULL, dev); if (ret) { dev_err(dev, "failed to add dwc3 core\n"); - goto err2; + goto err4; } } else { dev_err(dev, "no device node, failed to add dwc3 core\n"); ret = -ENODEV; - goto err2; + goto err4; } return 0; +err4: + regulator_disable(exynos->vdd10); +err3: + regulator_disable(exynos->vdd33); err2: clk_disable_unprepare(clk); -err1: return ret; } @@ -174,6 +201,9 @@ static int dwc3_exynos_remove(struct platform_device *pdev) clk_disable_unprepare(exynos->clk); + regulator_disable(exynos->vdd33); + regulator_disable(exynos->vdd10); + return 0; } @@ -192,12 +222,27 @@ static int dwc3_exynos_suspend(struct device *dev) clk_disable(exynos->clk); + regulator_disable(exynos->vdd33); + regulator_disable(exynos->vdd10); + return 0; } static int dwc3_exynos_resume(struct device *dev) { struct dwc3_exynos *exynos = dev_get_drvdata(dev); + int ret; + + ret = regulator_enable(exynos->vdd33); + if (ret) { + dev_err(dev, "Failed to enable VDD33 supply\n"); + return ret; + } + ret = regulator_enable(exynos->vdd10); + if (ret) { + dev_err(dev, "Failed to enable VDD10 supply\n"); + return ret; + } clk_enable(exynos->clk); diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 1160ff41bed4..4af4c3567656 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -393,7 +393,7 @@ static int dwc3_omap_probe(struct platform_device *pdev) struct extcon_dev *edev; struct regulator *vbus_reg = NULL; - int ret = -ENOMEM; + int ret; int irq; int utmi_mode = 0; diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index f393c183cc69..a60bab7dfa0a 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -23,7 +23,7 @@ #include <linux/platform_device.h> #include <linux/usb/otg.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h> /* FIXME define these in <linux/pci_ids.h> */ #define PCI_VENDOR_ID_SYNOPSYS 0x16c3 @@ -40,13 +40,13 @@ struct dwc3_pci { static int dwc3_pci_register_phys(struct dwc3_pci *glue) { - struct usb_phy_gen_xceiv_platform_data pdata; + struct usb_phy_generic_platform_data pdata; struct platform_device *pdev; int ret; memset(&pdata, 0x00, sizeof(pdata)); - pdev = platform_device_alloc("usb_phy_gen_xceiv", 0); + pdev = platform_device_alloc("usb_phy_generic", 0); if (!pdev) return -ENOMEM; @@ -58,7 +58,7 @@ static int dwc3_pci_register_phys(struct dwc3_pci *glue) if (ret) goto err1; - pdev = platform_device_alloc("usb_phy_gen_xceiv", 1); + pdev = platform_device_alloc("usb_phy_generic", 1); if (!pdev) { ret = -ENOMEM; goto err1; @@ -99,7 +99,7 @@ static int dwc3_pci_probe(struct pci_dev *pci, struct resource res[2]; struct platform_device *dwc3; struct dwc3_pci *glue; - int ret = -ENOMEM; + int ret; struct device *dev = &pci->dev; glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); @@ -110,7 +110,7 @@ static int dwc3_pci_probe(struct pci_dev *pci, glue->dev = dev; - ret = pci_enable_device(pci); + ret = pcim_enable_device(pci); if (ret) { dev_err(dev, "failed to enable pci device\n"); return -ENODEV; @@ -127,8 +127,7 @@ static int dwc3_pci_probe(struct pci_dev *pci, dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO); if (!dwc3) { dev_err(dev, "couldn't allocate dwc3 device\n"); - ret = -ENOMEM; - goto err1; + return -ENOMEM; } memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res)); @@ -145,7 +144,7 @@ static int dwc3_pci_probe(struct pci_dev *pci, ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res)); if (ret) { dev_err(dev, "couldn't add resources to dwc3 device\n"); - goto err1; + return ret; } pci_set_drvdata(pci, glue); @@ -167,9 +166,6 @@ static int dwc3_pci_probe(struct pci_dev *pci, err3: platform_device_put(dwc3); -err1: - pci_disable_device(pci); - return ret; } @@ -180,7 +176,6 @@ static void dwc3_pci_remove(struct pci_dev *pci) platform_device_unregister(glue->dwc3); platform_device_unregister(glue->usb2_phy); platform_device_unregister(glue->usb3_phy); - pci_disable_device(pci); } static const struct pci_device_id dwc3_pci_id_table[] = { diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 70715eeededd..9d64dd02c57e 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -298,11 +298,76 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd) } } +static const char *dwc3_gadget_generic_cmd_string(u8 cmd) +{ + switch (cmd) { + case DWC3_DGCMD_SET_LMP: + return "Set LMP"; + case DWC3_DGCMD_SET_PERIODIC_PAR: + return "Set Periodic Parameters"; + case DWC3_DGCMD_XMIT_FUNCTION: + return "Transmit Function Wake Device Notification"; + case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO: + return "Set Scratchpad Buffer Array Address Lo"; + case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI: + return "Set Scratchpad Buffer Array Address Hi"; + case DWC3_DGCMD_SELECTED_FIFO_FLUSH: + return "Selected FIFO Flush"; + case DWC3_DGCMD_ALL_FIFO_FLUSH: + return "All FIFO Flush"; + case DWC3_DGCMD_SET_ENDPOINT_NRDY: + return "Set Endpoint NRDY"; + case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK: + return "Run SoC Bus Loopback Test"; + default: + return "UNKNOWN"; + } +} + +static const char *dwc3_gadget_link_string(enum dwc3_link_state link_state) +{ + switch (link_state) { + case DWC3_LINK_STATE_U0: + return "U0"; + case DWC3_LINK_STATE_U1: + return "U1"; + case DWC3_LINK_STATE_U2: + return "U2"; + case DWC3_LINK_STATE_U3: + return "U3"; + case DWC3_LINK_STATE_SS_DIS: + return "SS.Disabled"; + case DWC3_LINK_STATE_RX_DET: + return "RX.Detect"; + case DWC3_LINK_STATE_SS_INACT: + return "SS.Inactive"; + case DWC3_LINK_STATE_POLL: + return "Polling"; + case DWC3_LINK_STATE_RECOV: + return "Recovery"; + case DWC3_LINK_STATE_HRESET: + return "Hot Reset"; + case DWC3_LINK_STATE_CMPLY: + return "Compliance"; + case DWC3_LINK_STATE_LPBK: + return "Loopback"; + case DWC3_LINK_STATE_RESET: + return "Reset"; + case DWC3_LINK_STATE_RESUME: + return "Resume"; + default: + return "UNKNOWN link state\n"; + } +} + int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param) { u32 timeout = 500; u32 reg; + dev_vdbg(dwc->dev, "generic cmd '%s' [%d] param %08x\n", + dwc3_gadget_generic_cmd_string(cmd), cmd, param); + dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param); dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT); @@ -332,9 +397,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, u32 timeout = 500; u32 reg; - dev_vdbg(dwc->dev, "%s: cmd '%s' params %08x %08x %08x\n", + dev_vdbg(dwc->dev, "%s: cmd '%s' [%d] params %08x %08x %08x\n", dep->name, - dwc3_gadget_ep_cmd_string(cmd), params->param0, + dwc3_gadget_ep_cmd_string(cmd), cmd, params->param0, params->param1, params->param2); dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0); @@ -515,7 +580,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, { struct dwc3 *dwc = dep->dwc; u32 reg; - int ret = -ENOMEM; + int ret; dev_vdbg(dwc->dev, "Enabling %s\n", dep->name); @@ -604,6 +669,10 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) dwc3_remove_requests(dwc, dep); + /* make sure HW endpoint isn't stalled */ + if (dep->flags & DWC3_EP_STALL) + __dwc3_gadget_ep_set_halt(dep, 0); + reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); reg &= ~DWC3_DALEPENA_EP(dep->number); dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); @@ -2441,8 +2510,6 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, } } - dwc->link_state = next; - switch (next) { case DWC3_LINK_STATE_U1: if (dwc->speed == USB_SPEED_SUPER) @@ -2460,7 +2527,11 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, break; } - dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state); + dev_vdbg(dwc->dev, "link change: %s [%d] -> %s [%d]\n", + dwc3_gadget_link_string(dwc->link_state), + dwc->link_state, dwc3_gadget_link_string(next), next); + + dwc->link_state = next; } static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc, diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 3557c7e5040d..ba18e9c110cc 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -157,7 +157,7 @@ config USB_AT91 config USB_LPC32XX tristate "LPC32XX USB Peripheral Controller" - depends on ARCH_LPC32XX + depends on ARCH_LPC32XX && I2C select USB_ISP1301 help This option selects the USB device controller in the LPC32xx SoC. @@ -226,7 +226,7 @@ config USB_GR_UDC config USB_OMAP tristate "OMAP USB Device Controller" depends on ARCH_OMAP1 - select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 + depends on ISP1301_OMAP || !(MACH_OMAP_H2 || MACH_OMAP_H3) help Many Texas Instruments OMAP processors have flexible full speed USB device controllers, with support for up to 30 @@ -300,12 +300,6 @@ config USB_PXA27X dynamically linked module called "pxa27x_udc" and force all gadget drivers to also be dynamically linked. -config USB_S3C_HSOTG - tristate "Designware/S3C HS/OtG USB Device controller" - help - The Designware USB2.0 high-speed gadget controller - integrated into many SoCs. - config USB_S3C2410 tristate "S3C2410 USB Device Controller" depends on ARCH_S3C24XX diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 5f150bc1b4bc..49514ea60a98 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -26,7 +26,6 @@ fsl_usb2_udc-$(CONFIG_ARCH_MXC) += fsl_mxc_udc.o obj-$(CONFIG_USB_M66592) += m66592-udc.o obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o -obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o obj-$(CONFIG_USB_LPC32XX) += lpc32xx_udc.o obj-$(CONFIG_USB_EG20T) += pch_udc.o diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 9f65324f9ae0..76023ce449a3 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1686,7 +1686,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) reset_all_endpoints(udc); if (udc->gadget.speed != USB_SPEED_UNKNOWN - && udc->driver->disconnect) { + && udc->driver && udc->driver->disconnect) { udc->gadget.speed = USB_SPEED_UNKNOWN; spin_unlock(&udc->lock); udc->driver->disconnect(&udc->gadget); diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index fab906429b80..f80151932053 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -21,6 +21,24 @@ #include <linux/usb/composite.h> #include <asm/unaligned.h> +#include "u_os_desc.h" + +/** + * struct usb_os_string - represents OS String to be reported by a gadget + * @bLength: total length of the entire descritor, always 0x12 + * @bDescriptorType: USB_DT_STRING + * @qwSignature: the OS String proper + * @bMS_VendorCode: code used by the host for subsequent requests + * @bPad: not used, must be zero + */ +struct usb_os_string { + __u8 bLength; + __u8 bDescriptorType; + __u8 qwSignature[OS_STRING_QW_SIGN_LEN]; + __u8 bMS_VendorCode; + __u8 bPad; +} __packed; + /* * The code in this file is utility code, used to build a gadget driver * from one or more "function" drivers, one or more "configuration" @@ -422,6 +440,7 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value) { struct usb_gadget *gadget = cdev->gadget; struct usb_configuration *c; + struct list_head *pos; u8 type = w_value >> 8; enum usb_device_speed speed = USB_SPEED_UNKNOWN; @@ -440,7 +459,20 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value) /* This is a lookup by config *INDEX* */ w_value &= 0xff; - list_for_each_entry(c, &cdev->configs, list) { + + pos = &cdev->configs; + c = cdev->os_desc_config; + if (c) + goto check_config; + + while ((pos = pos->next) != &cdev->configs) { + c = list_entry(pos, typeof(*c), list); + + /* skip OS Descriptors config which is handled separately */ + if (c == cdev->os_desc_config) + continue; + +check_config: /* ignore configs that won't work at this speed */ switch (speed) { case USB_SPEED_SUPER: @@ -634,6 +666,7 @@ static int set_config(struct usb_composite_dev *cdev, if (!c) goto done; + usb_gadget_set_state(gadget, USB_STATE_CONFIGURED); cdev->config = c; /* Initialize all interfaces by setting them to altsetting zero. */ @@ -960,6 +993,19 @@ static int get_string(struct usb_composite_dev *cdev, return s->bLength; } + if (cdev->use_os_string && language == 0 && id == OS_STRING_IDX) { + struct usb_os_string *b = buf; + b->bLength = sizeof(*b); + b->bDescriptorType = USB_DT_STRING; + compiletime_assert( + sizeof(b->qwSignature) == sizeof(cdev->qw_sign), + "qwSignature size must be equal to qw_sign"); + memcpy(&b->qwSignature, cdev->qw_sign, sizeof(b->qwSignature)); + b->bMS_VendorCode = cdev->b_vendor_code; + b->bPad = 0; + return sizeof(*b); + } + list_for_each_entry(uc, &cdev->gstrings, list) { struct usb_gadget_strings **sp; @@ -1206,6 +1252,156 @@ static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req) req->status, req->actual, req->length); } +static int count_ext_compat(struct usb_configuration *c) +{ + int i, res; + + res = 0; + for (i = 0; i < c->next_interface_id; ++i) { + struct usb_function *f; + int j; + + f = c->interface[i]; + for (j = 0; j < f->os_desc_n; ++j) { + struct usb_os_desc *d; + + if (i != f->os_desc_table[j].if_id) + continue; + d = f->os_desc_table[j].os_desc; + if (d && d->ext_compat_id) + ++res; + } + } + BUG_ON(res > 255); + return res; +} + +static void fill_ext_compat(struct usb_configuration *c, u8 *buf) +{ + int i, count; + + count = 16; + for (i = 0; i < c->next_interface_id; ++i) { + struct usb_function *f; + int j; + + f = c->interface[i]; + for (j = 0; j < f->os_desc_n; ++j) { + struct usb_os_desc *d; + + if (i != f->os_desc_table[j].if_id) + continue; + d = f->os_desc_table[j].os_desc; + if (d && d->ext_compat_id) { + *buf++ = i; + *buf++ = 0x01; + memcpy(buf, d->ext_compat_id, 16); + buf += 22; + } else { + ++buf; + *buf = 0x01; + buf += 23; + } + count += 24; + if (count >= 4096) + return; + } + } +} + +static int count_ext_prop(struct usb_configuration *c, int interface) +{ + struct usb_function *f; + int j; + + f = c->interface[interface]; + for (j = 0; j < f->os_desc_n; ++j) { + struct usb_os_desc *d; + + if (interface != f->os_desc_table[j].if_id) + continue; + d = f->os_desc_table[j].os_desc; + if (d && d->ext_compat_id) + return d->ext_prop_count; + } + return 0; +} + +static int len_ext_prop(struct usb_configuration *c, int interface) +{ + struct usb_function *f; + struct usb_os_desc *d; + int j, res; + + res = 10; /* header length */ + f = c->interface[interface]; + for (j = 0; j < f->os_desc_n; ++j) { + if (interface != f->os_desc_table[j].if_id) + continue; + d = f->os_desc_table[j].os_desc; + if (d) + return min(res + d->ext_prop_len, 4096); + } + return res; +} + +static int fill_ext_prop(struct usb_configuration *c, int interface, u8 *buf) +{ + struct usb_function *f; + struct usb_os_desc *d; + struct usb_os_desc_ext_prop *ext_prop; + int j, count, n, ret; + u8 *start = buf; + + f = c->interface[interface]; + for (j = 0; j < f->os_desc_n; ++j) { + if (interface != f->os_desc_table[j].if_id) + continue; + d = f->os_desc_table[j].os_desc; + if (d) + list_for_each_entry(ext_prop, &d->ext_prop, entry) { + /* 4kB minus header length */ + n = buf - start; + if (n >= 4086) + return 0; + + count = ext_prop->data_len + + ext_prop->name_len + 14; + if (count > 4086 - n) + return -EINVAL; + usb_ext_prop_put_size(buf, count); + usb_ext_prop_put_type(buf, ext_prop->type); + ret = usb_ext_prop_put_name(buf, ext_prop->name, + ext_prop->name_len); + if (ret < 0) + return ret; + switch (ext_prop->type) { + case USB_EXT_PROP_UNICODE: + case USB_EXT_PROP_UNICODE_ENV: + case USB_EXT_PROP_UNICODE_LINK: + usb_ext_prop_put_unicode(buf, ret, + ext_prop->data, + ext_prop->data_len); + break; + case USB_EXT_PROP_BINARY: + usb_ext_prop_put_binary(buf, ret, + ext_prop->data, + ext_prop->data_len); + break; + case USB_EXT_PROP_LE32: + /* not implemented */ + case USB_EXT_PROP_BE32: + /* not implemented */ + default: + return -EINVAL; + } + buf += count; + } + } + + return 0; +} + /* * The setup() callback implements all the ep0 functionality that's * not handled lower down, in hardware or the hardware driver(like @@ -1415,6 +1611,91 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) break; default: unknown: + /* + * OS descriptors handling + */ + if (cdev->use_os_string && cdev->os_desc_config && + (ctrl->bRequest & USB_TYPE_VENDOR) && + ctrl->bRequest == cdev->b_vendor_code) { + struct usb_request *req; + struct usb_configuration *os_desc_cfg; + u8 *buf; + int interface; + int count = 0; + + req = cdev->os_desc_req; + req->complete = composite_setup_complete; + buf = req->buf; + os_desc_cfg = cdev->os_desc_config; + memset(buf, 0, w_length); + buf[5] = 0x01; + switch (ctrl->bRequestType & USB_RECIP_MASK) { + case USB_RECIP_DEVICE: + if (w_index != 0x4 || (w_value >> 8)) + break; + buf[6] = w_index; + if (w_length == 0x10) { + /* Number of ext compat interfaces */ + count = count_ext_compat(os_desc_cfg); + buf[8] = count; + count *= 24; /* 24 B/ext compat desc */ + count += 16; /* header */ + put_unaligned_le32(count, buf); + value = w_length; + } else { + /* "extended compatibility ID"s */ + count = count_ext_compat(os_desc_cfg); + buf[8] = count; + count *= 24; /* 24 B/ext compat desc */ + count += 16; /* header */ + put_unaligned_le32(count, buf); + buf += 16; + fill_ext_compat(os_desc_cfg, buf); + value = w_length; + } + break; + case USB_RECIP_INTERFACE: + if (w_index != 0x5 || (w_value >> 8)) + break; + interface = w_value & 0xFF; + buf[6] = w_index; + if (w_length == 0x0A) { + count = count_ext_prop(os_desc_cfg, + interface); + put_unaligned_le16(count, buf + 8); + count = len_ext_prop(os_desc_cfg, + interface); + put_unaligned_le32(count, buf); + + value = w_length; + } else { + count = count_ext_prop(os_desc_cfg, + interface); + put_unaligned_le16(count, buf + 8); + count = len_ext_prop(os_desc_cfg, + interface); + put_unaligned_le32(count, buf); + buf += 10; + value = fill_ext_prop(os_desc_cfg, + interface, buf); + if (value < 0) + return value; + + value = w_length; + } + break; + } + req->length = value; + req->zero = value < w_length; + value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); + if (value < 0) { + DBG(cdev, "ep_queue --> %d\n", value); + req->status = 0; + composite_setup_complete(gadget->ep0, req); + } + return value; + } + VDBG(cdev, "non-core control req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, @@ -1638,6 +1919,29 @@ fail: return ret; } +int composite_os_desc_req_prepare(struct usb_composite_dev *cdev, + struct usb_ep *ep0) +{ + int ret = 0; + + cdev->os_desc_req = usb_ep_alloc_request(ep0, GFP_KERNEL); + if (!cdev->os_desc_req) { + ret = PTR_ERR(cdev->os_desc_req); + goto end; + } + + /* OS feature descriptor length <= 4kB */ + cdev->os_desc_req->buf = kmalloc(4096, GFP_KERNEL); + if (!cdev->os_desc_req->buf) { + ret = PTR_ERR(cdev->os_desc_req->buf); + kfree(cdev->os_desc_req); + goto end; + } + cdev->os_desc_req->complete = composite_setup_complete; +end: + return ret; +} + void composite_dev_cleanup(struct usb_composite_dev *cdev) { struct usb_gadget_string_container *uc, *tmp; @@ -1646,6 +1950,10 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev) list_del(&uc->list); kfree(uc); } + if (cdev->os_desc_req) { + kfree(cdev->os_desc_req->buf); + usb_ep_free_request(cdev->gadget->ep0, cdev->os_desc_req); + } if (cdev->req) { kfree(cdev->req->buf); usb_ep_free_request(cdev->gadget->ep0, cdev->req); @@ -1683,6 +1991,12 @@ static int composite_bind(struct usb_gadget *gadget, if (status < 0) goto fail; + if (cdev->use_os_string) { + status = composite_os_desc_req_prepare(cdev, gadget->ep0); + if (status) + goto fail; + } + update_unchanged_dev_desc(&cdev->desc, composite->dev); /* has userspace failed to provide a serial number? */ diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 7d1cc01796b6..2ddcd635ca2a 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -2,9 +2,12 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/device.h> +#include <linux/nls.h> #include <linux/usb/composite.h> #include <linux/usb/gadget_configfs.h> #include "configfs.h" +#include "u_f.h" +#include "u_os_desc.h" int check_user_usb_string(const char *name, struct usb_gadget_strings *stringtab_dev) @@ -43,7 +46,8 @@ struct gadget_info { struct config_group functions_group; struct config_group configs_group; struct config_group strings_group; - struct config_group *default_groups[4]; + struct config_group os_desc_group; + struct config_group *default_groups[5]; struct mutex lock; struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1]; @@ -56,6 +60,9 @@ struct gadget_info { #endif struct usb_composite_driver composite; struct usb_composite_dev cdev; + bool use_os_desc; + char b_vendor_code; + char qw_sign[OS_STRING_QW_SIGN_LEN]; }; struct config_usb_cfg { @@ -79,6 +86,10 @@ struct gadget_strings { struct list_head list; }; +struct os_desc { + struct config_group group; +}; + struct gadget_config_name { struct usb_gadget_strings stringtab_dev; struct usb_string strings; @@ -736,6 +747,525 @@ static void gadget_strings_attr_release(struct config_item *item) USB_CONFIG_STRING_RW_OPS(gadget_strings); USB_CONFIG_STRINGS_LANG(gadget_strings, gadget_info); +static inline struct os_desc *to_os_desc(struct config_item *item) +{ + return container_of(to_config_group(item), struct os_desc, group); +} + +CONFIGFS_ATTR_STRUCT(os_desc); +CONFIGFS_ATTR_OPS(os_desc); + +static ssize_t os_desc_use_show(struct os_desc *os_desc, char *page) +{ + struct gadget_info *gi; + + gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + + return sprintf(page, "%d", gi->use_os_desc); +} + +static ssize_t os_desc_use_store(struct os_desc *os_desc, const char *page, + size_t len) +{ + struct gadget_info *gi; + int ret; + bool use; + + gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + + mutex_lock(&gi->lock); + ret = strtobool(page, &use); + if (!ret) { + gi->use_os_desc = use; + ret = len; + } + mutex_unlock(&gi->lock); + + return ret; +} + +static struct os_desc_attribute os_desc_use = + __CONFIGFS_ATTR(use, S_IRUGO | S_IWUSR, + os_desc_use_show, + os_desc_use_store); + +static ssize_t os_desc_b_vendor_code_show(struct os_desc *os_desc, char *page) +{ + struct gadget_info *gi; + + gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + + return sprintf(page, "%d", gi->b_vendor_code); +} + +static ssize_t os_desc_b_vendor_code_store(struct os_desc *os_desc, + const char *page, size_t len) +{ + struct gadget_info *gi; + int ret; + u8 b_vendor_code; + + gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + + mutex_lock(&gi->lock); + ret = kstrtou8(page, 0, &b_vendor_code); + if (!ret) { + gi->b_vendor_code = b_vendor_code; + ret = len; + } + mutex_unlock(&gi->lock); + + return ret; +} + +static struct os_desc_attribute os_desc_b_vendor_code = + __CONFIGFS_ATTR(b_vendor_code, S_IRUGO | S_IWUSR, + os_desc_b_vendor_code_show, + os_desc_b_vendor_code_store); + +static ssize_t os_desc_qw_sign_show(struct os_desc *os_desc, char *page) +{ + struct gadget_info *gi; + + gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + + memcpy(page, gi->qw_sign, OS_STRING_QW_SIGN_LEN); + + return OS_STRING_QW_SIGN_LEN; +} + +static ssize_t os_desc_qw_sign_store(struct os_desc *os_desc, const char *page, + size_t len) +{ + struct gadget_info *gi; + int res, l; + + gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + l = min((int)len, OS_STRING_QW_SIGN_LEN >> 1); + if (page[l - 1] == '\n') + --l; + + mutex_lock(&gi->lock); + res = utf8s_to_utf16s(page, l, + UTF16_LITTLE_ENDIAN, (wchar_t *) gi->qw_sign, + OS_STRING_QW_SIGN_LEN); + if (res > 0) + res = len; + mutex_unlock(&gi->lock); + + return res; +} + +static struct os_desc_attribute os_desc_qw_sign = + __CONFIGFS_ATTR(qw_sign, S_IRUGO | S_IWUSR, + os_desc_qw_sign_show, + os_desc_qw_sign_store); + +static struct configfs_attribute *os_desc_attrs[] = { + &os_desc_use.attr, + &os_desc_b_vendor_code.attr, + &os_desc_qw_sign.attr, + NULL, +}; + +static void os_desc_attr_release(struct config_item *item) +{ + struct os_desc *os_desc = to_os_desc(item); + kfree(os_desc); +} + +static int os_desc_link(struct config_item *os_desc_ci, + struct config_item *usb_cfg_ci) +{ + struct gadget_info *gi = container_of(to_config_group(os_desc_ci), + struct gadget_info, os_desc_group); + struct usb_composite_dev *cdev = &gi->cdev; + struct config_usb_cfg *c_target = + container_of(to_config_group(usb_cfg_ci), + struct config_usb_cfg, group); + struct usb_configuration *c; + int ret; + + mutex_lock(&gi->lock); + list_for_each_entry(c, &cdev->configs, list) { + if (c == &c_target->c) + break; + } + if (c != &c_target->c) { + ret = -EINVAL; + goto out; + } + + if (cdev->os_desc_config) { + ret = -EBUSY; + goto out; + } + + cdev->os_desc_config = &c_target->c; + ret = 0; + +out: + mutex_unlock(&gi->lock); + return ret; +} + +static int os_desc_unlink(struct config_item *os_desc_ci, + struct config_item *usb_cfg_ci) +{ + struct gadget_info *gi = container_of(to_config_group(os_desc_ci), + struct gadget_info, os_desc_group); + struct usb_composite_dev *cdev = &gi->cdev; + + mutex_lock(&gi->lock); + if (gi->udc_name) + unregister_gadget(gi); + cdev->os_desc_config = NULL; + WARN_ON(gi->udc_name); + mutex_unlock(&gi->lock); + return 0; +} + +static struct configfs_item_operations os_desc_ops = { + .release = os_desc_attr_release, + .show_attribute = os_desc_attr_show, + .store_attribute = os_desc_attr_store, + .allow_link = os_desc_link, + .drop_link = os_desc_unlink, +}; + +static struct config_item_type os_desc_type = { + .ct_item_ops = &os_desc_ops, + .ct_attrs = os_desc_attrs, + .ct_owner = THIS_MODULE, +}; + +CONFIGFS_ATTR_STRUCT(usb_os_desc); +CONFIGFS_ATTR_OPS(usb_os_desc); + + +static inline struct usb_os_desc_ext_prop +*to_usb_os_desc_ext_prop(struct config_item *item) +{ + return container_of(item, struct usb_os_desc_ext_prop, item); +} + +CONFIGFS_ATTR_STRUCT(usb_os_desc_ext_prop); +CONFIGFS_ATTR_OPS(usb_os_desc_ext_prop); + +static ssize_t ext_prop_type_show(struct usb_os_desc_ext_prop *ext_prop, + char *page) +{ + return sprintf(page, "%d", ext_prop->type); +} + +static ssize_t ext_prop_type_store(struct usb_os_desc_ext_prop *ext_prop, + const char *page, size_t len) +{ + struct usb_os_desc *desc = to_usb_os_desc(ext_prop->item.ci_parent); + u8 type; + int ret; + + if (desc->opts_mutex) + mutex_lock(desc->opts_mutex); + ret = kstrtou8(page, 0, &type); + if (ret) + goto end; + if (type < USB_EXT_PROP_UNICODE || type > USB_EXT_PROP_UNICODE_MULTI) { + ret = -EINVAL; + goto end; + } + + if ((ext_prop->type == USB_EXT_PROP_BINARY || + ext_prop->type == USB_EXT_PROP_LE32 || + ext_prop->type == USB_EXT_PROP_BE32) && + (type == USB_EXT_PROP_UNICODE || + type == USB_EXT_PROP_UNICODE_ENV || + type == USB_EXT_PROP_UNICODE_LINK)) + ext_prop->data_len <<= 1; + else if ((ext_prop->type == USB_EXT_PROP_UNICODE || + ext_prop->type == USB_EXT_PROP_UNICODE_ENV || + ext_prop->type == USB_EXT_PROP_UNICODE_LINK) && + (type == USB_EXT_PROP_BINARY || + type == USB_EXT_PROP_LE32 || + type == USB_EXT_PROP_BE32)) + ext_prop->data_len >>= 1; + ext_prop->type = type; + ret = len; + +end: + if (desc->opts_mutex) + mutex_unlock(desc->opts_mutex); + return ret; +} + +static ssize_t ext_prop_data_show(struct usb_os_desc_ext_prop *ext_prop, + char *page) +{ + int len = ext_prop->data_len; + + if (ext_prop->type == USB_EXT_PROP_UNICODE || + ext_prop->type == USB_EXT_PROP_UNICODE_ENV || + ext_prop->type == USB_EXT_PROP_UNICODE_LINK) + len >>= 1; + memcpy(page, ext_prop->data, len); + + return len; +} + +static ssize_t ext_prop_data_store(struct usb_os_desc_ext_prop *ext_prop, + const char *page, size_t len) +{ + struct usb_os_desc *desc = to_usb_os_desc(ext_prop->item.ci_parent); + char *new_data; + size_t ret_len = len; + + if (page[len - 1] == '\n' || page[len - 1] == '\0') + --len; + new_data = kzalloc(len, GFP_KERNEL); + if (!new_data) + return -ENOMEM; + + memcpy(new_data, page, len); + + if (desc->opts_mutex) + mutex_lock(desc->opts_mutex); + kfree(ext_prop->data); + ext_prop->data = new_data; + desc->ext_prop_len -= ext_prop->data_len; + ext_prop->data_len = len; + desc->ext_prop_len += ext_prop->data_len; + if (ext_prop->type == USB_EXT_PROP_UNICODE || + ext_prop->type == USB_EXT_PROP_UNICODE_ENV || + ext_prop->type == USB_EXT_PROP_UNICODE_LINK) { + desc->ext_prop_len -= ext_prop->data_len; + ext_prop->data_len <<= 1; + ext_prop->data_len += 2; + desc->ext_prop_len += ext_prop->data_len; + } + if (desc->opts_mutex) + mutex_unlock(desc->opts_mutex); + return ret_len; +} + +static struct usb_os_desc_ext_prop_attribute ext_prop_type = + __CONFIGFS_ATTR(type, S_IRUGO | S_IWUSR, + ext_prop_type_show, ext_prop_type_store); + +static struct usb_os_desc_ext_prop_attribute ext_prop_data = + __CONFIGFS_ATTR(data, S_IRUGO | S_IWUSR, + ext_prop_data_show, ext_prop_data_store); + +static struct configfs_attribute *ext_prop_attrs[] = { + &ext_prop_type.attr, + &ext_prop_data.attr, + NULL, +}; + +static void usb_os_desc_ext_prop_release(struct config_item *item) +{ + struct usb_os_desc_ext_prop *ext_prop = to_usb_os_desc_ext_prop(item); + + kfree(ext_prop); /* frees a whole chunk */ +} + +static struct configfs_item_operations ext_prop_ops = { + .release = usb_os_desc_ext_prop_release, + .show_attribute = usb_os_desc_ext_prop_attr_show, + .store_attribute = usb_os_desc_ext_prop_attr_store, +}; + +static struct config_item *ext_prop_make( + struct config_group *group, + const char *name) +{ + struct usb_os_desc_ext_prop *ext_prop; + struct config_item_type *ext_prop_type; + struct usb_os_desc *desc; + char *vlabuf; + + vla_group(data_chunk); + vla_item(data_chunk, struct usb_os_desc_ext_prop, ext_prop, 1); + vla_item(data_chunk, struct config_item_type, ext_prop_type, 1); + + vlabuf = kzalloc(vla_group_size(data_chunk), GFP_KERNEL); + if (!vlabuf) + return ERR_PTR(-ENOMEM); + + ext_prop = vla_ptr(vlabuf, data_chunk, ext_prop); + ext_prop_type = vla_ptr(vlabuf, data_chunk, ext_prop_type); + + desc = container_of(group, struct usb_os_desc, group); + ext_prop_type->ct_item_ops = &ext_prop_ops; + ext_prop_type->ct_attrs = ext_prop_attrs; + ext_prop_type->ct_owner = desc->owner; + + config_item_init_type_name(&ext_prop->item, name, ext_prop_type); + + ext_prop->name = kstrdup(name, GFP_KERNEL); + if (!ext_prop->name) { + kfree(vlabuf); + return ERR_PTR(-ENOMEM); + } + desc->ext_prop_len += 14; + ext_prop->name_len = 2 * strlen(ext_prop->name) + 2; + if (desc->opts_mutex) + mutex_lock(desc->opts_mutex); + desc->ext_prop_len += ext_prop->name_len; + list_add_tail(&ext_prop->entry, &desc->ext_prop); + ++desc->ext_prop_count; + if (desc->opts_mutex) + mutex_unlock(desc->opts_mutex); + + return &ext_prop->item; +} + +static void ext_prop_drop(struct config_group *group, struct config_item *item) +{ + struct usb_os_desc_ext_prop *ext_prop = to_usb_os_desc_ext_prop(item); + struct usb_os_desc *desc = to_usb_os_desc(&group->cg_item); + + if (desc->opts_mutex) + mutex_lock(desc->opts_mutex); + list_del(&ext_prop->entry); + --desc->ext_prop_count; + kfree(ext_prop->name); + desc->ext_prop_len -= (ext_prop->name_len + ext_prop->data_len + 14); + if (desc->opts_mutex) + mutex_unlock(desc->opts_mutex); + config_item_put(item); +} + +static struct configfs_group_operations interf_grp_ops = { + .make_item = &ext_prop_make, + .drop_item = &ext_prop_drop, +}; + +static struct configfs_item_operations interf_item_ops = { + .show_attribute = usb_os_desc_attr_show, + .store_attribute = usb_os_desc_attr_store, +}; + +static ssize_t rndis_grp_compatible_id_show(struct usb_os_desc *desc, + char *page) +{ + memcpy(page, desc->ext_compat_id, 8); + return 8; +} + +static ssize_t rndis_grp_compatible_id_store(struct usb_os_desc *desc, + const char *page, size_t len) +{ + int l; + + l = min_t(int, 8, len); + if (page[l - 1] == '\n') + --l; + if (desc->opts_mutex) + mutex_lock(desc->opts_mutex); + memcpy(desc->ext_compat_id, page, l); + desc->ext_compat_id[l] = '\0'; + + if (desc->opts_mutex) + mutex_unlock(desc->opts_mutex); + + return len; +} + +static struct usb_os_desc_attribute rndis_grp_attr_compatible_id = + __CONFIGFS_ATTR(compatible_id, S_IRUGO | S_IWUSR, + rndis_grp_compatible_id_show, + rndis_grp_compatible_id_store); + +static ssize_t rndis_grp_sub_compatible_id_show(struct usb_os_desc *desc, + char *page) +{ + memcpy(page, desc->ext_compat_id + 8, 8); + return 8; +} + +static ssize_t rndis_grp_sub_compatible_id_store(struct usb_os_desc *desc, + const char *page, size_t len) +{ + int l; + + l = min_t(int, 8, len); + if (page[l - 1] == '\n') + --l; + if (desc->opts_mutex) + mutex_lock(desc->opts_mutex); + memcpy(desc->ext_compat_id + 8, page, l); + desc->ext_compat_id[l + 8] = '\0'; + + if (desc->opts_mutex) + mutex_unlock(desc->opts_mutex); + + return len; +} + +static struct usb_os_desc_attribute rndis_grp_attr_sub_compatible_id = + __CONFIGFS_ATTR(sub_compatible_id, S_IRUGO | S_IWUSR, + rndis_grp_sub_compatible_id_show, + rndis_grp_sub_compatible_id_store); + +static struct configfs_attribute *interf_grp_attrs[] = { + &rndis_grp_attr_compatible_id.attr, + &rndis_grp_attr_sub_compatible_id.attr, + NULL +}; + +int usb_os_desc_prepare_interf_dir(struct config_group *parent, + int n_interf, + struct usb_os_desc **desc, + struct module *owner) +{ + struct config_group **f_default_groups, *os_desc_group, + **interface_groups; + struct config_item_type *os_desc_type, *interface_type; + + vla_group(data_chunk); + vla_item(data_chunk, struct config_group *, f_default_groups, 2); + vla_item(data_chunk, struct config_group, os_desc_group, 1); + vla_item(data_chunk, struct config_group *, interface_groups, + n_interf + 1); + vla_item(data_chunk, struct config_item_type, os_desc_type, 1); + vla_item(data_chunk, struct config_item_type, interface_type, 1); + + char *vlabuf = kzalloc(vla_group_size(data_chunk), GFP_KERNEL); + if (!vlabuf) + return -ENOMEM; + + f_default_groups = vla_ptr(vlabuf, data_chunk, f_default_groups); + os_desc_group = vla_ptr(vlabuf, data_chunk, os_desc_group); + os_desc_type = vla_ptr(vlabuf, data_chunk, os_desc_type); + interface_groups = vla_ptr(vlabuf, data_chunk, interface_groups); + interface_type = vla_ptr(vlabuf, data_chunk, interface_type); + + parent->default_groups = f_default_groups; + os_desc_type->ct_owner = owner; + config_group_init_type_name(os_desc_group, "os_desc", os_desc_type); + f_default_groups[0] = os_desc_group; + + os_desc_group->default_groups = interface_groups; + interface_type->ct_item_ops = &interf_item_ops; + interface_type->ct_group_ops = &interf_grp_ops; + interface_type->ct_attrs = interf_grp_attrs; + interface_type->ct_owner = owner; + + while (n_interf--) { + struct usb_os_desc *d; + + d = desc[n_interf]; + d->owner = owner; + config_group_init_type_name(&d->group, "", interface_type); + config_item_set_name(&d->group.cg_item, "interface.%d", + n_interf); + interface_groups[n_interf] = &d->group; + } + + return 0; +} +EXPORT_SYMBOL(usb_os_desc_prepare_interf_dir); + static int configfs_do_nothing(struct usb_composite_dev *cdev) { WARN_ON(1); @@ -745,6 +1275,9 @@ static int configfs_do_nothing(struct usb_composite_dev *cdev) int composite_dev_prepare(struct usb_composite_driver *composite, struct usb_composite_dev *dev); +int composite_os_desc_req_prepare(struct usb_composite_dev *cdev, + struct usb_ep *ep0); + static void purge_configs_funcs(struct gadget_info *gi) { struct usb_configuration *c; @@ -793,7 +1326,7 @@ static int configfs_composite_bind(struct usb_gadget *gadget, ret = -EINVAL; if (list_empty(&gi->cdev.configs)) { - pr_err("Need atleast one configuration in %s.\n", + pr_err("Need at least one configuration in %s.\n", gi->composite.name); goto err_comp_cleanup; } @@ -804,7 +1337,7 @@ static int configfs_composite_bind(struct usb_gadget *gadget, 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", + pr_err("Config %s/%d of %s needs at least one function.\n", c->label, c->bConfigurationValue, gi->composite.name); goto err_comp_cleanup; @@ -839,6 +1372,12 @@ static int configfs_composite_bind(struct usb_gadget *gadget, gi->cdev.desc.iSerialNumber = s[USB_GADGET_SERIAL_IDX].id; } + if (gi->use_os_desc) { + cdev->use_os_string = true; + cdev->b_vendor_code = gi->b_vendor_code; + memcpy(cdev->qw_sign, gi->qw_sign, OS_STRING_QW_SIGN_LEN); + } + /* Go through all configs, attach all functions */ list_for_each_entry(c, &gi->cdev.configs, list) { struct config_usb_cfg *cfg; @@ -874,6 +1413,12 @@ static int configfs_composite_bind(struct usb_gadget *gadget, } usb_ep_autoconfig_reset(cdev->gadget); } + if (cdev->use_os_string) { + ret = composite_os_desc_req_prepare(cdev, gadget->ep0); + if (ret) + goto err_purge_funcs; + } + usb_ep_autoconfig_reset(cdev->gadget); return 0; @@ -929,6 +1474,7 @@ static struct config_group *gadgets_make( gi->group.default_groups[0] = &gi->functions_group; gi->group.default_groups[1] = &gi->configs_group; gi->group.default_groups[2] = &gi->strings_group; + gi->group.default_groups[3] = &gi->os_desc_group; config_group_init_type_name(&gi->functions_group, "functions", &functions_type); @@ -936,6 +1482,8 @@ static struct config_group *gadgets_make( &config_desc_type); config_group_init_type_name(&gi->strings_group, "strings", &gadget_strings_strings_type); + config_group_init_type_name(&gi->os_desc_group, "os_desc", + &os_desc_type); gi->composite.bind = configfs_do_nothing; gi->composite.unbind = configfs_do_nothing; @@ -1005,7 +1553,7 @@ void unregister_gadget_item(struct config_item *item) unregister_gadget(gi); } -EXPORT_SYMBOL(unregister_gadget_item); +EXPORT_SYMBOL_GPL(unregister_gadget_item); static int __init gadget_cfs_init(void) { diff --git a/drivers/usb/gadget/configfs.h b/drivers/usb/gadget/configfs.h index a7b564a913d1..a14ac792c698 100644 --- a/drivers/usb/gadget/configfs.h +++ b/drivers/usb/gadget/configfs.h @@ -1,6 +1,18 @@ #ifndef USB__GADGET__CONFIGFS__H #define USB__GADGET__CONFIGFS__H +#include <linux/configfs.h> + void unregister_gadget_item(struct config_item *item); +int usb_os_desc_prepare_interf_dir(struct config_group *parent, + int n_interf, + struct usb_os_desc **desc, + struct module *owner); + +static inline struct usb_os_desc *to_usb_os_desc(struct config_item *item) +{ + return container_of(to_config_group(item), struct usb_os_desc, group); +} + #endif /* USB__GADGET__CONFIGFS__H */ diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 8c06430dcc47..2b54955d3166 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -561,7 +561,6 @@ static int dummy_disable(struct usb_ep *_ep) struct dummy_ep *ep; struct dummy *dum; unsigned long flags; - int retval; ep = usb_ep_to_dummy_ep(_ep); if (!_ep || !ep->desc || _ep->name == ep0name) @@ -571,12 +570,11 @@ static int dummy_disable(struct usb_ep *_ep) spin_lock_irqsave(&dum->lock, flags); ep->desc = NULL; ep->stream_en = 0; - retval = 0; nuke(dum, ep); spin_unlock_irqrestore(&dum->lock, flags); dev_dbg(udc_dev(dum), "disabled %s\n", _ep->name); - return retval; + return 0; } static struct usb_request *dummy_alloc_request(struct usb_ep *_ep, diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 1e12b3ee56fd..74202d67f911 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -33,36 +33,11 @@ #include <linux/poll.h> #include "u_fs.h" +#include "u_f.h" #include "configfs.h" #define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */ -/* Variable Length Array Macros **********************************************/ -#define vla_group(groupname) size_t groupname##__next = 0 -#define vla_group_size(groupname) groupname##__next - -#define vla_item(groupname, type, name, n) \ - size_t groupname##_##name##__offset = ({ \ - size_t align_mask = __alignof__(type) - 1; \ - size_t offset = (groupname##__next + align_mask) & ~align_mask;\ - size_t size = (n) * sizeof(type); \ - groupname##__next = offset + size; \ - offset; \ - }) - -#define vla_item_with_sz(groupname, type, name, n) \ - size_t groupname##_##name##__sz = (n) * sizeof(type); \ - size_t groupname##_##name##__offset = ({ \ - size_t align_mask = __alignof__(type) - 1; \ - size_t offset = (groupname##__next + align_mask) & ~align_mask;\ - size_t size = groupname##_##name##__sz; \ - groupname##__next = offset + size; \ - offset; \ - }) - -#define vla_ptr(ptr, groupname, name) \ - ((void *) ((char *)ptr + groupname##_##name##__offset)) - /* Reference counter handling */ static void ffs_data_get(struct ffs_data *ffs); static void ffs_data_put(struct ffs_data *ffs); @@ -190,7 +165,7 @@ ffs_sb_create_file(struct super_block *sb, const char *name, void *data, /* Devices management *******************************************************/ DEFINE_MUTEX(ffs_lock); -EXPORT_SYMBOL(ffs_lock); +EXPORT_SYMBOL_GPL(ffs_lock); static struct ffs_dev *_ffs_find_dev(const char *name); static struct ffs_dev *_ffs_alloc_dev(void); @@ -2883,7 +2858,7 @@ int ffs_name_dev(struct ffs_dev *dev, const char *name) return ret; } -EXPORT_SYMBOL(ffs_name_dev); +EXPORT_SYMBOL_GPL(ffs_name_dev); int ffs_single_dev(struct ffs_dev *dev) { @@ -2900,7 +2875,7 @@ int ffs_single_dev(struct ffs_dev *dev) ffs_dev_unlock(); return ret; } -EXPORT_SYMBOL(ffs_single_dev); +EXPORT_SYMBOL_GPL(ffs_single_dev); /* * ffs_lock must be taken by the caller of this function diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 9a4f49dc6ac4..eed3ad878047 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -27,6 +27,7 @@ #include "u_ether_configfs.h" #include "u_rndis.h" #include "rndis.h" +#include "configfs.h" /* * This function is an RNDIS Ethernet port -- a Microsoft protocol that's @@ -682,6 +683,15 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst); + if (cdev->use_os_string) { + f->os_desc_table = kzalloc(sizeof(*f->os_desc_table), + GFP_KERNEL); + if (!f->os_desc_table) + return PTR_ERR(f->os_desc_table); + f->os_desc_n = 1; + f->os_desc_table[0].os_desc = &rndis_opts->rndis_os_desc; + } + /* * in drivers/usb/gadget/configfs.c:configfs_composite_bind() * configurations are bound in sequence with list_for_each_entry, @@ -693,14 +703,16 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) gether_set_gadget(rndis_opts->net, cdev->gadget); status = gether_register_netdev(rndis_opts->net); if (status) - return status; + goto fail; rndis_opts->bound = true; } us = usb_gstrings_attach(cdev, rndis_strings, ARRAY_SIZE(rndis_string_defs)); - if (IS_ERR(us)) - return PTR_ERR(us); + if (IS_ERR(us)) { + status = PTR_ERR(us); + goto fail; + } rndis_control_intf.iInterface = us[0].id; rndis_data_intf.iInterface = us[1].id; rndis_iad_descriptor.iFunction = us[2].id; @@ -802,6 +814,8 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) return 0; fail: + kfree(f->os_desc_table); + f->os_desc_n = 0; usb_free_all_descriptors(f); if (rndis->notify_req) { @@ -834,7 +848,7 @@ void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net) opts->borrowed_net = opts->bound = true; opts->net = net; } -EXPORT_SYMBOL(rndis_borrow_net); +EXPORT_SYMBOL_GPL(rndis_borrow_net); static inline struct f_rndis_opts *to_f_rndis_opts(struct config_item *item) { @@ -882,16 +896,21 @@ static void rndis_free_inst(struct usb_function_instance *f) else free_netdev(opts->net); } + + kfree(opts->rndis_os_desc.group.default_groups); /* single VLA chunk */ kfree(opts); } static struct usb_function_instance *rndis_alloc_inst(void) { struct f_rndis_opts *opts; + struct usb_os_desc *descs[1]; opts = kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) return ERR_PTR(-ENOMEM); + opts->rndis_os_desc.ext_compat_id = opts->rndis_ext_compat_id; + mutex_init(&opts->lock); opts->func_inst.free_func_inst = rndis_free_inst; opts->net = gether_setup_default(); @@ -900,7 +919,11 @@ static struct usb_function_instance *rndis_alloc_inst(void) kfree(opts); return ERR_CAST(net); } + INIT_LIST_HEAD(&opts->rndis_os_desc.ext_prop); + descs[0] = &opts->rndis_os_desc; + usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs, + THIS_MODULE); config_group_init_type_name(&opts->func_inst.group, "", &rndis_func_type); @@ -925,6 +948,8 @@ static void rndis_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_rndis *rndis = func_to_rndis(f); + kfree(f->os_desc_table); + f->os_desc_n = 0; usb_free_all_descriptors(f); kfree(rndis->notify_req->buf); diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c index df4a0dcbc993..1ea8baf33333 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c @@ -276,7 +276,7 @@ static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } net = gether_connect(&geth->port); - return PTR_RET(net); + return PTR_ERR_OR_ZERO(net); } static void geth_disable(struct usb_function *f) diff --git a/drivers/usb/gadget/f_uac2.c b/drivers/usb/gadget/f_uac2.c index bc23040c7790..6261db4a9910 100644 --- a/drivers/usb/gadget/f_uac2.c +++ b/drivers/usb/gadget/f_uac2.c @@ -196,7 +196,7 @@ agdev_iso_complete(struct usb_ep *ep, struct usb_request *req) struct snd_uac2_chip *uac2 = prm->uac2; /* i/f shutting down */ - if (!prm->ep_enabled) + if (!prm->ep_enabled || req->status == -ESHUTDOWN) return; /* @@ -974,8 +974,6 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL); if (!prm->rbuf) { prm->max_psize = 0; - dev_err(&uac2->pdev.dev, - "%s:%d Error!\n", __func__, __LINE__); goto err; } @@ -984,8 +982,6 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL); if (!prm->rbuf) { prm->max_psize = 0; - dev_err(&uac2->pdev.dev, - "%s:%d Error!\n", __func__, __LINE__); goto err; } @@ -1298,10 +1294,8 @@ static int audio_bind_config(struct usb_configuration *cfg) int res; agdev_g = kzalloc(sizeof *agdev_g, GFP_KERNEL); - if (agdev_g == NULL) { - printk(KERN_ERR "Unable to allocate audio gadget\n"); + if (agdev_g == NULL) return -ENOMEM; - } res = usb_string_ids_tab(cfg->cdev, strings_fn); if (res) diff --git a/drivers/usb/gadget/fotg210-udc.c b/drivers/usb/gadget/fotg210-udc.c index 2d0305280e8c..e143d69f6017 100644 --- a/drivers/usb/gadget/fotg210-udc.c +++ b/drivers/usb/gadget/fotg210-udc.c @@ -1112,17 +1112,13 @@ static int fotg210_udc_probe(struct platform_device *pdev) /* initialize udc */ fotg210 = kzalloc(sizeof(struct fotg210_udc), GFP_KERNEL); - if (fotg210 == NULL) { - pr_err("kzalloc error\n"); + if (fotg210 == NULL) goto err_alloc; - } for (i = 0; i < FOTG210_MAX_NUM_EP; i++) { _ep[i] = kzalloc(sizeof(struct fotg210_ep), GFP_KERNEL); - if (_ep[i] == NULL) { - pr_err("_ep kzalloc error\n"); + if (_ep[i] == NULL) goto err_alloc; - } fotg210->ep[i] = _ep[i]; } diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index a2f26cdb56fe..28e4fc957026 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -2256,10 +2256,8 @@ static int __init struct_udc_setup(struct fsl_udc *udc, udc->phy_mode = pdata->phy_mode; udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL); - if (!udc->eps) { - ERR("malloc fsl_ep failed\n"); + if (!udc->eps) return -1; - } /* initialized QHs, take care of alignment */ size = udc->max_ep * sizeof(struct ep_queue_head); @@ -2342,10 +2340,8 @@ static int __init fsl_udc_probe(struct platform_device *pdev) u32 dccparams; udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL); - if (udc_controller == NULL) { - ERR("malloc udc failed\n"); + if (udc_controller == NULL) return -ENOMEM; - } pdata = dev_get_platdata(&pdev->dev); udc_controller->pdata = pdata; diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index 6423f1840ed9..3deb4e938071 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -1400,17 +1400,13 @@ static int __init fusb300_probe(struct platform_device *pdev) /* initialize udc */ fusb300 = kzalloc(sizeof(struct fusb300), GFP_KERNEL); - if (fusb300 == NULL) { - pr_err("kzalloc error\n"); + if (fusb300 == NULL) goto clean_up; - } for (i = 0; i < FUSB300_MAX_NUM_EP; i++) { _ep[i] = kzalloc(sizeof(struct fusb300_ep), GFP_KERNEL); - if (_ep[i] == NULL) { - pr_err("_ep kzalloc error\n"); + if (_ep[i] == NULL) goto clean_up; - } fusb300->ep[i] = _ep[i]; } diff --git a/drivers/usb/gadget/gr_udc.c b/drivers/usb/gadget/gr_udc.c index f984ee75324d..99a37ed03e27 100644 --- a/drivers/usb/gadget/gr_udc.c +++ b/drivers/usb/gadget/gr_udc.c @@ -143,6 +143,7 @@ static void gr_seq_ep_show(struct seq_file *seq, struct gr_ep *ep) seq_printf(seq, " wedged = %d\n", ep->wedged); seq_printf(seq, " callback = %d\n", ep->callback); seq_printf(seq, " maxpacket = %d\n", ep->ep.maxpacket); + seq_printf(seq, " maxpacket_limit = %d\n", ep->ep.maxpacket_limit); seq_printf(seq, " bytes_per_buffer = %d\n", ep->bytes_per_buffer); if (mode == 1 || mode == 3) seq_printf(seq, " nt = %d\n", @@ -1541,6 +1542,10 @@ static int gr_ep_enable(struct usb_ep *_ep, } else if (max == 0) { dev_err(dev->dev, "Max payload cannot be set to 0\n"); return -EINVAL; + } else if (max > ep->ep.maxpacket_limit) { + dev_err(dev->dev, "Requested max payload %d > limit %d\n", + max, ep->ep.maxpacket_limit); + return -EINVAL; } spin_lock(&ep->dev->lock); @@ -1679,7 +1684,7 @@ static int gr_queue_ext(struct usb_ep *_ep, struct usb_request *_req, if (ep->is_in) gr_dbgprint_request("EXTERN", ep, req); - ret = gr_queue(ep, req, gfp_flags); + ret = gr_queue(ep, req, GFP_ATOMIC); spin_unlock(&ep->dev->lock); @@ -1985,8 +1990,8 @@ static int gr_ep_init(struct gr_udc *dev, int num, int is_in, u32 maxplimit) INIT_LIST_HEAD(&ep->queue); if (num == 0) { - _req = gr_alloc_request(&ep->ep, GFP_KERNEL); - buf = devm_kzalloc(dev->dev, PAGE_SIZE, GFP_DMA | GFP_KERNEL); + _req = gr_alloc_request(&ep->ep, GFP_ATOMIC); + buf = devm_kzalloc(dev->dev, PAGE_SIZE, GFP_DMA | GFP_ATOMIC); if (!_req || !buf) { /* possible _req freed by gr_probe via gr_remove */ return -ENOMEM; @@ -2020,9 +2025,7 @@ static int gr_udc_init(struct gr_udc *dev) u32 dmactrl_val; int i; int ret = 0; - u32 *bufsizes; u32 bufsize; - int len; gr_set_address(dev, 0); @@ -2033,19 +2036,17 @@ static int gr_udc_init(struct gr_udc *dev) INIT_LIST_HEAD(&dev->ep_list); gr_set_ep0state(dev, GR_EP0_DISCONNECT); - bufsizes = (u32 *)of_get_property(np, "epobufsizes", &len); - len /= sizeof(u32); for (i = 0; i < dev->nepo; i++) { - bufsize = (bufsizes && i < len) ? bufsizes[i] : 1024; + if (of_property_read_u32_index(np, "epobufsizes", i, &bufsize)) + bufsize = 1024; ret = gr_ep_init(dev, i, 0, bufsize); if (ret) return ret; } - bufsizes = (u32 *)of_get_property(np, "epibufsizes", &len); - len /= sizeof(u32); for (i = 0; i < dev->nepi; i++) { - bufsize = (bufsizes && i < len) ? bufsizes[i] : 1024; + if (of_property_read_u32_index(np, "epibufsizes", i, &bufsize)) + bufsize = 1024; ret = gr_ep_init(dev, i, 1, bufsize); if (ret) return ret; @@ -2065,9 +2066,9 @@ static int gr_udc_init(struct gr_udc *dev) return 0; } -static int gr_remove(struct platform_device *ofdev) +static int gr_remove(struct platform_device *pdev) { - struct gr_udc *dev = dev_get_drvdata(&ofdev->dev); + struct gr_udc *dev = platform_get_drvdata(pdev); if (dev->added) usb_del_gadget_udc(&dev->gadget); /* Shuts everything down */ @@ -2077,7 +2078,7 @@ static int gr_remove(struct platform_device *ofdev) gr_dfs_delete(dev); if (dev->desc_pool) dma_pool_destroy(dev->desc_pool); - dev_set_drvdata(&ofdev->dev, NULL); + platform_set_drvdata(pdev, NULL); gr_free_request(&dev->epi[0].ep, &dev->ep0reqi->req); gr_free_request(&dev->epo[0].ep, &dev->ep0reqo->req); @@ -2090,7 +2091,7 @@ static int gr_request_irq(struct gr_udc *dev, int irq) IRQF_SHARED, driver_name, dev); } -static int gr_probe(struct platform_device *ofdev) +static int gr_probe(struct platform_device *pdev) { struct gr_udc *dev; struct resource *res; @@ -2098,30 +2099,32 @@ static int gr_probe(struct platform_device *ofdev) int retval; u32 status; - dev = devm_kzalloc(&ofdev->dev, sizeof(*dev), GFP_KERNEL); + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; - dev->dev = &ofdev->dev; + dev->dev = &pdev->dev; - res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(dev->dev, res); if (IS_ERR(regs)) return PTR_ERR(regs); - dev->irq = irq_of_parse_and_map(dev->dev->of_node, 0); - if (!dev->irq) { + dev->irq = platform_get_irq(pdev, 0); + if (dev->irq <= 0) { dev_err(dev->dev, "No irq found\n"); return -ENODEV; } /* Some core configurations has separate irqs for IN and OUT events */ - dev->irqi = irq_of_parse_and_map(dev->dev->of_node, 1); - if (dev->irqi) { - dev->irqo = irq_of_parse_and_map(dev->dev->of_node, 2); - if (!dev->irqo) { + dev->irqi = platform_get_irq(pdev, 1); + if (dev->irqi > 0) { + dev->irqo = platform_get_irq(pdev, 2); + if (dev->irqo <= 0) { dev_err(dev->dev, "Found irqi but not irqo\n"); return -ENODEV; } + } else { + dev->irqi = 0; } dev->gadget.name = driver_name; @@ -2132,7 +2135,7 @@ static int gr_probe(struct platform_device *ofdev) spin_lock_init(&dev->lock); dev->regs = regs; - dev_set_drvdata(&ofdev->dev, dev); + platform_set_drvdata(pdev, dev); /* Determine number of endpoints and data interface mode */ status = gr_read32(&dev->regs->status); @@ -2204,7 +2207,7 @@ out: spin_unlock(&dev->lock); if (retval) - gr_remove(ofdev); + gr_remove(pdev); return retval; } diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index a925d0cbcd41..ee6c16416c30 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1494,6 +1494,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) */ if (value == 0) { INFO (dev, "configuration #%d\n", dev->current_config); + usb_gadget_set_state(gadget, USB_STATE_CONFIGURED); if (dev->usermode_setup) { dev->setup_can_stall = 0; goto delegate; @@ -1501,7 +1502,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) } break; -#ifndef CONFIG_USB_GADGET_PXA25X +#ifndef CONFIG_USB_PXA25X /* PXA automagically handles this request too */ case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != 0x80) diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 8cae01d88597..0d17174b86f8 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1594,7 +1594,6 @@ static int __init m66592_probe(struct platform_device *pdev) m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL); if (m66592 == NULL) { ret = -ENOMEM; - pr_err("kzalloc error\n"); goto clean_up; } diff --git a/drivers/usb/gadget/mv_u3d_core.c b/drivers/usb/gadget/mv_u3d_core.c index d2ca59e7b477..16248711c152 100644 --- a/drivers/usb/gadget/mv_u3d_core.c +++ b/drivers/usb/gadget/mv_u3d_core.c @@ -297,10 +297,8 @@ static struct mv_u3d_trb *mv_u3d_build_trb_one(struct mv_u3d_req *req, u3d = req->ep->u3d; trb = kzalloc(sizeof(*trb), GFP_ATOMIC); - if (!trb) { - dev_err(u3d->dev, "%s, trb alloc fail\n", __func__); + if (!trb) return NULL; - } /* * Be careful that no _GFP_HIGHMEM is set, @@ -446,17 +444,12 @@ static int mv_u3d_req_to_trb(struct mv_u3d_req *req) trb_num++; trb = kcalloc(trb_num, sizeof(*trb), GFP_ATOMIC); - if (!trb) { - dev_err(u3d->dev, - "%s, trb alloc fail\n", __func__); + if (!trb) return -ENOMEM; - } trb_hw = kcalloc(trb_num, sizeof(*trb_hw), GFP_ATOMIC); if (!trb_hw) { kfree(trb); - dev_err(u3d->dev, - "%s, trb_hw alloc fail\n", __func__); return -ENOMEM; } @@ -1811,7 +1804,6 @@ static int mv_u3d_probe(struct platform_device *dev) u3d = kzalloc(sizeof(*u3d), GFP_KERNEL); if (!u3d) { - dev_err(&dev->dev, "failed to allocate memory for u3d\n"); retval = -ENOMEM; goto err_alloc_private; } @@ -1905,7 +1897,6 @@ static int mv_u3d_probe(struct platform_device *dev) size = u3d->max_eps * sizeof(struct mv_u3d_ep) * 2; u3d->eps = kzalloc(size, GFP_KERNEL); if (!u3d->eps) { - dev_err(&dev->dev, "allocate ep memory failed\n"); retval = -ENOMEM; goto err_alloc_eps; } @@ -1913,7 +1904,6 @@ static int mv_u3d_probe(struct platform_device *dev) /* initialize ep0 status request structure */ u3d->status_req = kzalloc(sizeof(struct mv_u3d_req) + 8, GFP_KERNEL); if (!u3d->status_req) { - dev_err(&dev->dev, "allocate status_req memory failed\n"); retval = -ENOMEM; goto err_alloc_status_req; } diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 43e5e2f9888f..300b3a71383b 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1972,7 +1972,9 @@ static int net2280_stop(struct usb_gadget *_gadget, device_remove_file (&dev->pdev->dev, &dev_attr_function); device_remove_file (&dev->pdev->dev, &dev_attr_queues); - DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name); + DEBUG(dev, "unregistered driver '%s'\n", + driver ? driver->driver.name : ""); + return 0; } diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index aff0a6718bc6..b698a490cc7d 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1904,7 +1904,6 @@ static int __init r8a66597_probe(struct platform_device *pdev) r8a66597 = kzalloc(sizeof(struct r8a66597), GFP_KERNEL); if (r8a66597 == NULL) { ret = -ENOMEM; - dev_err(&pdev->dev, "kzalloc error\n"); goto clean_up; } diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 7ed452d90f4d..95d2324f6977 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -761,7 +761,7 @@ int rndis_signal_connect(int configNr) return rndis_indicate_status_msg(configNr, RNDIS_STATUS_MEDIA_CONNECT); } -EXPORT_SYMBOL(rndis_signal_connect); +EXPORT_SYMBOL_GPL(rndis_signal_connect); int rndis_signal_disconnect(int configNr) { @@ -770,7 +770,7 @@ int rndis_signal_disconnect(int configNr) return rndis_indicate_status_msg(configNr, RNDIS_STATUS_MEDIA_DISCONNECT); } -EXPORT_SYMBOL(rndis_signal_disconnect); +EXPORT_SYMBOL_GPL(rndis_signal_disconnect); void rndis_uninit(int configNr) { @@ -785,13 +785,13 @@ void rndis_uninit(int configNr) while ((buf = rndis_get_next_response(configNr, &length))) rndis_free_response(configNr, buf); } -EXPORT_SYMBOL(rndis_uninit); +EXPORT_SYMBOL_GPL(rndis_uninit); void rndis_set_host_mac(int configNr, const u8 *addr) { rndis_per_dev_params[configNr].host_mac = addr; } -EXPORT_SYMBOL(rndis_set_host_mac); +EXPORT_SYMBOL_GPL(rndis_set_host_mac); /* * Message Parser @@ -874,7 +874,7 @@ int rndis_msg_parser(u8 configNr, u8 *buf) return -ENOTSUPP; } -EXPORT_SYMBOL(rndis_msg_parser); +EXPORT_SYMBOL_GPL(rndis_msg_parser); int rndis_register(void (*resp_avail)(void *v), void *v) { @@ -896,7 +896,7 @@ int rndis_register(void (*resp_avail)(void *v), void *v) return -ENODEV; } -EXPORT_SYMBOL(rndis_register); +EXPORT_SYMBOL_GPL(rndis_register); void rndis_deregister(int configNr) { @@ -905,7 +905,7 @@ void rndis_deregister(int configNr) if (configNr >= RNDIS_MAX_CONFIGS) return; rndis_per_dev_params[configNr].used = 0; } -EXPORT_SYMBOL(rndis_deregister); +EXPORT_SYMBOL_GPL(rndis_deregister); int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter) { @@ -919,7 +919,7 @@ int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter) return 0; } -EXPORT_SYMBOL(rndis_set_param_dev); +EXPORT_SYMBOL_GPL(rndis_set_param_dev); int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr) { @@ -932,7 +932,7 @@ int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr) return 0; } -EXPORT_SYMBOL(rndis_set_param_vendor); +EXPORT_SYMBOL_GPL(rndis_set_param_vendor); int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed) { @@ -944,7 +944,7 @@ int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed) return 0; } -EXPORT_SYMBOL(rndis_set_param_medium); +EXPORT_SYMBOL_GPL(rndis_set_param_medium); void rndis_add_hdr(struct sk_buff *skb) { @@ -959,7 +959,7 @@ void rndis_add_hdr(struct sk_buff *skb) header->DataOffset = cpu_to_le32(36); header->DataLength = cpu_to_le32(skb->len - sizeof(*header)); } -EXPORT_SYMBOL(rndis_add_hdr); +EXPORT_SYMBOL_GPL(rndis_add_hdr); void rndis_free_response(int configNr, u8 *buf) { @@ -976,7 +976,7 @@ void rndis_free_response(int configNr, u8 *buf) } } } -EXPORT_SYMBOL(rndis_free_response); +EXPORT_SYMBOL_GPL(rndis_free_response); u8 *rndis_get_next_response(int configNr, u32 *length) { @@ -998,7 +998,7 @@ u8 *rndis_get_next_response(int configNr, u32 *length) return NULL; } -EXPORT_SYMBOL(rndis_get_next_response); +EXPORT_SYMBOL_GPL(rndis_get_next_response); static rndis_resp_t *rndis_add_response(int configNr, u32 length) { @@ -1042,7 +1042,7 @@ int rndis_rm_hdr(struct gether *port, skb_queue_tail(list, skb); return 0; } -EXPORT_SYMBOL(rndis_rm_hdr); +EXPORT_SYMBOL_GPL(rndis_rm_hdr); #ifdef CONFIG_USB_GADGET_DEBUG_FILES diff --git a/drivers/usb/gadget/s3c-hsotg.h b/drivers/usb/gadget/s3c-hsotg.h deleted file mode 100644 index 85f549ff8c1f..000000000000 --- a/drivers/usb/gadget/s3c-hsotg.h +++ /dev/null @@ -1,378 +0,0 @@ -/* drivers/usb/gadget/s3c-hsotg.h - * - * Copyright 2008 Openmoko, Inc. - * Copyright 2008 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks <ben@simtec.co.uk> - * - * USB2.0 Highspeed/OtG Synopsis DWC2 device block registers - * - * 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. -*/ - -#ifndef __REGS_USB_HSOTG_H -#define __REGS_USB_HSOTG_H __FILE__ - -#define HSOTG_REG(x) (x) - -#define GOTGCTL HSOTG_REG(0x000) -#define GOTGCTL_BSESVLD (1 << 19) -#define GOTGCTL_ASESVLD (1 << 18) -#define GOTGCTL_DBNC_SHORT (1 << 17) -#define GOTGCTL_CONID_B (1 << 16) -#define GOTGCTL_DEVHNPEN (1 << 11) -#define GOTGCTL_HSSETHNPEN (1 << 10) -#define GOTGCTL_HNPREQ (1 << 9) -#define GOTGCTL_HSTNEGSCS (1 << 8) -#define GOTGCTL_SESREQ (1 << 1) -#define GOTGCTL_SESREQSCS (1 << 0) - -#define GOTGINT HSOTG_REG(0x004) -#define GOTGINT_DbnceDone (1 << 19) -#define GOTGINT_ADevTOUTChg (1 << 18) -#define GOTGINT_HstNegDet (1 << 17) -#define GOTGINT_HstnegSucStsChng (1 << 9) -#define GOTGINT_SesReqSucStsChng (1 << 8) -#define GOTGINT_SesEndDet (1 << 2) - -#define GAHBCFG HSOTG_REG(0x008) -#define GAHBCFG_PTxFEmpLvl (1 << 8) -#define GAHBCFG_NPTxFEmpLvl (1 << 7) -#define GAHBCFG_DMAEn (1 << 5) -#define GAHBCFG_HBstLen_MASK (0xf << 1) -#define GAHBCFG_HBstLen_SHIFT (1) -#define GAHBCFG_HBstLen_Single (0x0 << 1) -#define GAHBCFG_HBstLen_Incr (0x1 << 1) -#define GAHBCFG_HBstLen_Incr4 (0x3 << 1) -#define GAHBCFG_HBstLen_Incr8 (0x5 << 1) -#define GAHBCFG_HBstLen_Incr16 (0x7 << 1) -#define GAHBCFG_GlblIntrEn (1 << 0) - -#define GUSBCFG HSOTG_REG(0x00C) -#define GUSBCFG_PHYLPClkSel (1 << 15) -#define GUSBCFG_HNPCap (1 << 9) -#define GUSBCFG_SRPCap (1 << 8) -#define GUSBCFG_PHYIf16 (1 << 3) -#define GUSBCFG_PHYIf8 (0 << 3) -#define GUSBCFG_TOutCal_MASK (0x7 << 0) -#define GUSBCFG_TOutCal_SHIFT (0) -#define GUSBCFG_TOutCal_LIMIT (0x7) -#define GUSBCFG_TOutCal(_x) ((_x) << 0) - -#define GRSTCTL HSOTG_REG(0x010) - -#define GRSTCTL_AHBIdle (1 << 31) -#define GRSTCTL_DMAReq (1 << 30) -#define GRSTCTL_TxFNum_MASK (0x1f << 6) -#define GRSTCTL_TxFNum_SHIFT (6) -#define GRSTCTL_TxFNum_LIMIT (0x1f) -#define GRSTCTL_TxFNum(_x) ((_x) << 6) -#define GRSTCTL_TxFFlsh (1 << 5) -#define GRSTCTL_RxFFlsh (1 << 4) -#define GRSTCTL_INTknQFlsh (1 << 3) -#define GRSTCTL_FrmCntrRst (1 << 2) -#define GRSTCTL_HSftRst (1 << 1) -#define GRSTCTL_CSftRst (1 << 0) - -#define GINTSTS HSOTG_REG(0x014) -#define GINTMSK HSOTG_REG(0x018) - -#define GINTSTS_WkUpInt (1 << 31) -#define GINTSTS_SessReqInt (1 << 30) -#define GINTSTS_DisconnInt (1 << 29) -#define GINTSTS_ConIDStsChng (1 << 28) -#define GINTSTS_PTxFEmp (1 << 26) -#define GINTSTS_HChInt (1 << 25) -#define GINTSTS_PrtInt (1 << 24) -#define GINTSTS_FetSusp (1 << 22) -#define GINTSTS_incompIP (1 << 21) -#define GINTSTS_IncomplSOIN (1 << 20) -#define GINTSTS_OEPInt (1 << 19) -#define GINTSTS_IEPInt (1 << 18) -#define GINTSTS_EPMis (1 << 17) -#define GINTSTS_EOPF (1 << 15) -#define GINTSTS_ISOutDrop (1 << 14) -#define GINTSTS_EnumDone (1 << 13) -#define GINTSTS_USBRst (1 << 12) -#define GINTSTS_USBSusp (1 << 11) -#define GINTSTS_ErlySusp (1 << 10) -#define GINTSTS_GOUTNakEff (1 << 7) -#define GINTSTS_GINNakEff (1 << 6) -#define GINTSTS_NPTxFEmp (1 << 5) -#define GINTSTS_RxFLvl (1 << 4) -#define GINTSTS_SOF (1 << 3) -#define GINTSTS_OTGInt (1 << 2) -#define GINTSTS_ModeMis (1 << 1) -#define GINTSTS_CurMod_Host (1 << 0) - -#define GRXSTSR HSOTG_REG(0x01C) -#define GRXSTSP HSOTG_REG(0x020) - -#define GRXSTS_FN_MASK (0x7f << 25) -#define GRXSTS_FN_SHIFT (25) - -#define GRXSTS_PktSts_MASK (0xf << 17) -#define GRXSTS_PktSts_SHIFT (17) -#define GRXSTS_PktSts_GlobalOutNAK (0x1 << 17) -#define GRXSTS_PktSts_OutRX (0x2 << 17) -#define GRXSTS_PktSts_OutDone (0x3 << 17) -#define GRXSTS_PktSts_SetupDone (0x4 << 17) -#define GRXSTS_PktSts_SetupRX (0x6 << 17) - -#define GRXSTS_DPID_MASK (0x3 << 15) -#define GRXSTS_DPID_SHIFT (15) -#define GRXSTS_ByteCnt_MASK (0x7ff << 4) -#define GRXSTS_ByteCnt_SHIFT (4) -#define GRXSTS_EPNum_MASK (0xf << 0) -#define GRXSTS_EPNum_SHIFT (0) - -#define GRXFSIZ HSOTG_REG(0x024) - -#define GNPTXFSIZ HSOTG_REG(0x028) - -#define GNPTXFSIZ_NPTxFDep_MASK (0xffff << 16) -#define GNPTXFSIZ_NPTxFDep_SHIFT (16) -#define GNPTXFSIZ_NPTxFDep_LIMIT (0xffff) -#define GNPTXFSIZ_NPTxFDep(_x) ((_x) << 16) -#define GNPTXFSIZ_NPTxFStAddr_MASK (0xffff << 0) -#define GNPTXFSIZ_NPTxFStAddr_SHIFT (0) -#define GNPTXFSIZ_NPTxFStAddr_LIMIT (0xffff) -#define GNPTXFSIZ_NPTxFStAddr(_x) ((_x) << 0) - -#define GNPTXSTS HSOTG_REG(0x02C) - -#define GNPTXSTS_NPtxQTop_MASK (0x7f << 24) -#define GNPTXSTS_NPtxQTop_SHIFT (24) - -#define GNPTXSTS_NPTxQSpcAvail_MASK (0xff << 16) -#define GNPTXSTS_NPTxQSpcAvail_SHIFT (16) -#define GNPTXSTS_NPTxQSpcAvail_GET(_v) (((_v) >> 16) & 0xff) - -#define GNPTXSTS_NPTxFSpcAvail_MASK (0xffff << 0) -#define GNPTXSTS_NPTxFSpcAvail_SHIFT (0) -#define GNPTXSTS_NPTxFSpcAvail_GET(_v) (((_v) >> 0) & 0xffff) - - -#define HPTXFSIZ HSOTG_REG(0x100) - -#define DPTXFSIZn(_a) HSOTG_REG(0x104 + (((_a) - 1) * 4)) - -#define DPTXFSIZn_DPTxFSize_MASK (0xffff << 16) -#define DPTXFSIZn_DPTxFSize_SHIFT (16) -#define DPTXFSIZn_DPTxFSize_GET(_v) (((_v) >> 16) & 0xffff) -#define DPTXFSIZn_DPTxFSize_LIMIT (0xffff) -#define DPTXFSIZn_DPTxFSize(_x) ((_x) << 16) - -#define DPTXFSIZn_DPTxFStAddr_MASK (0xffff << 0) -#define DPTXFSIZn_DPTxFStAddr_SHIFT (0) - -/* Device mode registers */ -#define DCFG HSOTG_REG(0x800) - -#define DCFG_EPMisCnt_MASK (0x1f << 18) -#define DCFG_EPMisCnt_SHIFT (18) -#define DCFG_EPMisCnt_LIMIT (0x1f) -#define DCFG_EPMisCnt(_x) ((_x) << 18) - -#define DCFG_PerFrInt_MASK (0x3 << 11) -#define DCFG_PerFrInt_SHIFT (11) -#define DCFG_PerFrInt_LIMIT (0x3) -#define DCFG_PerFrInt(_x) ((_x) << 11) - -#define DCFG_DevAddr_MASK (0x7f << 4) -#define DCFG_DevAddr_SHIFT (4) -#define DCFG_DevAddr_LIMIT (0x7f) -#define DCFG_DevAddr(_x) ((_x) << 4) - -#define DCFG_NZStsOUTHShk (1 << 2) - -#define DCFG_DevSpd_MASK (0x3 << 0) -#define DCFG_DevSpd_SHIFT (0) -#define DCFG_DevSpd_HS (0x0 << 0) -#define DCFG_DevSpd_FS (0x1 << 0) -#define DCFG_DevSpd_LS (0x2 << 0) -#define DCFG_DevSpd_FS48 (0x3 << 0) - -#define DCTL HSOTG_REG(0x804) - -#define DCTL_PWROnPrgDone (1 << 11) -#define DCTL_CGOUTNak (1 << 10) -#define DCTL_SGOUTNak (1 << 9) -#define DCTL_CGNPInNAK (1 << 8) -#define DCTL_SGNPInNAK (1 << 7) -#define DCTL_TstCtl_MASK (0x7 << 4) -#define DCTL_TstCtl_SHIFT (4) -#define DCTL_GOUTNakSts (1 << 3) -#define DCTL_GNPINNakSts (1 << 2) -#define DCTL_SftDiscon (1 << 1) -#define DCTL_RmtWkUpSig (1 << 0) - -#define DSTS HSOTG_REG(0x808) - -#define DSTS_SOFFN_MASK (0x3fff << 8) -#define DSTS_SOFFN_SHIFT (8) -#define DSTS_SOFFN_LIMIT (0x3fff) -#define DSTS_SOFFN(_x) ((_x) << 8) -#define DSTS_ErraticErr (1 << 3) -#define DSTS_EnumSpd_MASK (0x3 << 1) -#define DSTS_EnumSpd_SHIFT (1) -#define DSTS_EnumSpd_HS (0x0 << 1) -#define DSTS_EnumSpd_FS (0x1 << 1) -#define DSTS_EnumSpd_LS (0x2 << 1) -#define DSTS_EnumSpd_FS48 (0x3 << 1) - -#define DSTS_SuspSts (1 << 0) - -#define DIEPMSK HSOTG_REG(0x810) - -#define DIEPMSK_TxFIFOEmpty (1 << 7) -#define DIEPMSK_INEPNakEffMsk (1 << 6) -#define DIEPMSK_INTknEPMisMsk (1 << 5) -#define DIEPMSK_INTknTXFEmpMsk (1 << 4) -#define DIEPMSK_TimeOUTMsk (1 << 3) -#define DIEPMSK_AHBErrMsk (1 << 2) -#define DIEPMSK_EPDisbldMsk (1 << 1) -#define DIEPMSK_XferComplMsk (1 << 0) - -#define DOEPMSK HSOTG_REG(0x814) - -#define DOEPMSK_Back2BackSetup (1 << 6) -#define DOEPMSK_OUTTknEPdisMsk (1 << 4) -#define DOEPMSK_SetupMsk (1 << 3) -#define DOEPMSK_AHBErrMsk (1 << 2) -#define DOEPMSK_EPDisbldMsk (1 << 1) -#define DOEPMSK_XferComplMsk (1 << 0) - -#define DAINT HSOTG_REG(0x818) -#define DAINTMSK HSOTG_REG(0x81C) - -#define DAINT_OutEP_SHIFT (16) -#define DAINT_OutEP(x) (1 << ((x) + 16)) -#define DAINT_InEP(x) (1 << (x)) - -#define DTKNQR1 HSOTG_REG(0x820) -#define DTKNQR2 HSOTG_REG(0x824) -#define DTKNQR3 HSOTG_REG(0x830) -#define DTKNQR4 HSOTG_REG(0x834) - -#define DVBUSDIS HSOTG_REG(0x828) -#define DVBUSPULSE HSOTG_REG(0x82C) - -#define DIEPCTL0 HSOTG_REG(0x900) -#define DOEPCTL0 HSOTG_REG(0xB00) -#define DIEPCTL(_a) HSOTG_REG(0x900 + ((_a) * 0x20)) -#define DOEPCTL(_a) HSOTG_REG(0xB00 + ((_a) * 0x20)) - -/* EP0 specialness: - * bits[29..28] - reserved (no SetD0PID, SetD1PID) - * bits[25..22] - should always be zero, this isn't a periodic endpoint - * bits[10..0] - MPS setting differenct for EP0 - */ -#define D0EPCTL_MPS_MASK (0x3 << 0) -#define D0EPCTL_MPS_SHIFT (0) -#define D0EPCTL_MPS_64 (0x0 << 0) -#define D0EPCTL_MPS_32 (0x1 << 0) -#define D0EPCTL_MPS_16 (0x2 << 0) -#define D0EPCTL_MPS_8 (0x3 << 0) - -#define DxEPCTL_EPEna (1 << 31) -#define DxEPCTL_EPDis (1 << 30) -#define DxEPCTL_SetD1PID (1 << 29) -#define DxEPCTL_SetOddFr (1 << 29) -#define DxEPCTL_SetD0PID (1 << 28) -#define DxEPCTL_SetEvenFr (1 << 28) -#define DxEPCTL_SNAK (1 << 27) -#define DxEPCTL_CNAK (1 << 26) -#define DxEPCTL_TxFNum_MASK (0xf << 22) -#define DxEPCTL_TxFNum_SHIFT (22) -#define DxEPCTL_TxFNum_LIMIT (0xf) -#define DxEPCTL_TxFNum(_x) ((_x) << 22) - -#define DxEPCTL_Stall (1 << 21) -#define DxEPCTL_Snp (1 << 20) -#define DxEPCTL_EPType_MASK (0x3 << 18) -#define DxEPCTL_EPType_SHIFT (18) -#define DxEPCTL_EPType_Control (0x0 << 18) -#define DxEPCTL_EPType_Iso (0x1 << 18) -#define DxEPCTL_EPType_Bulk (0x2 << 18) -#define DxEPCTL_EPType_Intterupt (0x3 << 18) - -#define DxEPCTL_NAKsts (1 << 17) -#define DxEPCTL_DPID (1 << 16) -#define DxEPCTL_EOFrNum (1 << 16) -#define DxEPCTL_USBActEp (1 << 15) -#define DxEPCTL_NextEp_MASK (0xf << 11) -#define DxEPCTL_NextEp_SHIFT (11) -#define DxEPCTL_NextEp_LIMIT (0xf) -#define DxEPCTL_NextEp(_x) ((_x) << 11) - -#define DxEPCTL_MPS_MASK (0x7ff << 0) -#define DxEPCTL_MPS_SHIFT (0) -#define DxEPCTL_MPS_LIMIT (0x7ff) -#define DxEPCTL_MPS(_x) ((_x) << 0) - -#define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20)) -#define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20)) - -#define DxEPINT_INEPNakEff (1 << 6) -#define DxEPINT_Back2BackSetup (1 << 6) -#define DxEPINT_INTknEPMis (1 << 5) -#define DxEPINT_INTknTXFEmp (1 << 4) -#define DxEPINT_OUTTknEPdis (1 << 4) -#define DxEPINT_Timeout (1 << 3) -#define DxEPINT_Setup (1 << 3) -#define DxEPINT_AHBErr (1 << 2) -#define DxEPINT_EPDisbld (1 << 1) -#define DxEPINT_XferCompl (1 << 0) - -#define DIEPTSIZ0 HSOTG_REG(0x910) - -#define DIEPTSIZ0_PktCnt_MASK (0x3 << 19) -#define DIEPTSIZ0_PktCnt_SHIFT (19) -#define DIEPTSIZ0_PktCnt_LIMIT (0x3) -#define DIEPTSIZ0_PktCnt(_x) ((_x) << 19) - -#define DIEPTSIZ0_XferSize_MASK (0x7f << 0) -#define DIEPTSIZ0_XferSize_SHIFT (0) -#define DIEPTSIZ0_XferSize_LIMIT (0x7f) -#define DIEPTSIZ0_XferSize(_x) ((_x) << 0) - -#define DOEPTSIZ0 HSOTG_REG(0xB10) -#define DOEPTSIZ0_SUPCnt_MASK (0x3 << 29) -#define DOEPTSIZ0_SUPCnt_SHIFT (29) -#define DOEPTSIZ0_SUPCnt_LIMIT (0x3) -#define DOEPTSIZ0_SUPCnt(_x) ((_x) << 29) - -#define DOEPTSIZ0_PktCnt (1 << 19) -#define DOEPTSIZ0_XferSize_MASK (0x7f << 0) -#define DOEPTSIZ0_XferSize_SHIFT (0) - -#define DIEPTSIZ(_a) HSOTG_REG(0x910 + ((_a) * 0x20)) -#define DOEPTSIZ(_a) HSOTG_REG(0xB10 + ((_a) * 0x20)) - -#define DxEPTSIZ_MC_MASK (0x3 << 29) -#define DxEPTSIZ_MC_SHIFT (29) -#define DxEPTSIZ_MC_LIMIT (0x3) -#define DxEPTSIZ_MC(_x) ((_x) << 29) - -#define DxEPTSIZ_PktCnt_MASK (0x3ff << 19) -#define DxEPTSIZ_PktCnt_SHIFT (19) -#define DxEPTSIZ_PktCnt_GET(_v) (((_v) >> 19) & 0x3ff) -#define DxEPTSIZ_PktCnt_LIMIT (0x3ff) -#define DxEPTSIZ_PktCnt(_x) ((_x) << 19) - -#define DxEPTSIZ_XferSize_MASK (0x7ffff << 0) -#define DxEPTSIZ_XferSize_SHIFT (0) -#define DxEPTSIZ_XferSize_GET(_v) (((_v) >> 0) & 0x7ffff) -#define DxEPTSIZ_XferSize_LIMIT (0x7ffff) -#define DxEPTSIZ_XferSize(_x) ((_x) << 0) - -#define DIEPDMA(_a) HSOTG_REG(0x914 + ((_a) * 0x20)) -#define DOEPDMA(_a) HSOTG_REG(0xB14 + ((_a) * 0x20)) -#define DTXFSTS(_a) HSOTG_REG(0x918 + ((_a) * 0x20)) - -#define EPFIFO(_a) HSOTG_REG(0x1000 + ((_a) * 0x1000)) - -#endif /* __REGS_USB_HSOTG_H */ diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index dd9678f85c58..7987aa049fab 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -117,7 +117,8 @@ static int dprintk(int level, const char *fmt, ...) sizeof(printk_buf)-len, fmt, args); va_end(args); - return pr_debug("%s", printk_buf); + pr_debug("%s", printk_buf); + return len; } #else static int dprintk(int level, const char *fmt, ...) diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index ec20a1f50c2d..ff205a7bc55c 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -43,7 +43,7 @@ struct usb_interface_descriptor fsg_intf_desc = { .bInterfaceProtocol = USB_PR_BULK, /* Adjusted during fsg_bind() */ .iInterface = FSG_STRING_INTERFACE, }; -EXPORT_SYMBOL(fsg_intf_desc); +EXPORT_SYMBOL_GPL(fsg_intf_desc); /* * Three full-speed endpoint descriptors: bulk-in, bulk-out, and @@ -58,7 +58,7 @@ struct usb_endpoint_descriptor fsg_fs_bulk_in_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, /* wMaxPacketSize set by autoconfiguration */ }; -EXPORT_SYMBOL(fsg_fs_bulk_in_desc); +EXPORT_SYMBOL_GPL(fsg_fs_bulk_in_desc); struct usb_endpoint_descriptor fsg_fs_bulk_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, @@ -68,7 +68,7 @@ struct usb_endpoint_descriptor fsg_fs_bulk_out_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, /* wMaxPacketSize set by autoconfiguration */ }; -EXPORT_SYMBOL(fsg_fs_bulk_out_desc); +EXPORT_SYMBOL_GPL(fsg_fs_bulk_out_desc); struct usb_descriptor_header *fsg_fs_function[] = { (struct usb_descriptor_header *) &fsg_intf_desc, @@ -76,7 +76,7 @@ struct usb_descriptor_header *fsg_fs_function[] = { (struct usb_descriptor_header *) &fsg_fs_bulk_out_desc, NULL, }; -EXPORT_SYMBOL(fsg_fs_function); +EXPORT_SYMBOL_GPL(fsg_fs_function); /* @@ -95,7 +95,7 @@ struct usb_endpoint_descriptor fsg_hs_bulk_in_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(512), }; -EXPORT_SYMBOL(fsg_hs_bulk_in_desc); +EXPORT_SYMBOL_GPL(fsg_hs_bulk_in_desc); struct usb_endpoint_descriptor fsg_hs_bulk_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, @@ -106,7 +106,7 @@ struct usb_endpoint_descriptor fsg_hs_bulk_out_desc = { .wMaxPacketSize = cpu_to_le16(512), .bInterval = 1, /* NAK every 1 uframe */ }; -EXPORT_SYMBOL(fsg_hs_bulk_out_desc); +EXPORT_SYMBOL_GPL(fsg_hs_bulk_out_desc); struct usb_descriptor_header *fsg_hs_function[] = { @@ -115,7 +115,7 @@ struct usb_descriptor_header *fsg_hs_function[] = { (struct usb_descriptor_header *) &fsg_hs_bulk_out_desc, NULL, }; -EXPORT_SYMBOL(fsg_hs_function); +EXPORT_SYMBOL_GPL(fsg_hs_function); struct usb_endpoint_descriptor fsg_ss_bulk_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, @@ -125,7 +125,7 @@ struct usb_endpoint_descriptor fsg_ss_bulk_in_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(1024), }; -EXPORT_SYMBOL(fsg_ss_bulk_in_desc); +EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_desc); struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = { .bLength = sizeof(fsg_ss_bulk_in_comp_desc), @@ -133,7 +133,7 @@ struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = { /*.bMaxBurst = DYNAMIC, */ }; -EXPORT_SYMBOL(fsg_ss_bulk_in_comp_desc); +EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_comp_desc); struct usb_endpoint_descriptor fsg_ss_bulk_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, @@ -143,7 +143,7 @@ struct usb_endpoint_descriptor fsg_ss_bulk_out_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(1024), }; -EXPORT_SYMBOL(fsg_ss_bulk_out_desc); +EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_desc); struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = { .bLength = sizeof(fsg_ss_bulk_in_comp_desc), @@ -151,7 +151,7 @@ struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = { /*.bMaxBurst = DYNAMIC, */ }; -EXPORT_SYMBOL(fsg_ss_bulk_out_comp_desc); +EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_comp_desc); struct usb_descriptor_header *fsg_ss_function[] = { (struct usb_descriptor_header *) &fsg_intf_desc, @@ -161,7 +161,7 @@ struct usb_descriptor_header *fsg_ss_function[] = { (struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc, NULL, }; -EXPORT_SYMBOL(fsg_ss_function); +EXPORT_SYMBOL_GPL(fsg_ss_function); /*-------------------------------------------------------------------------*/ @@ -179,7 +179,7 @@ void fsg_lun_close(struct fsg_lun *curlun) curlun->filp = NULL; } } -EXPORT_SYMBOL(fsg_lun_close); +EXPORT_SYMBOL_GPL(fsg_lun_close); int fsg_lun_open(struct fsg_lun *curlun, const char *filename) { @@ -278,7 +278,7 @@ out: fput(filp); return rc; } -EXPORT_SYMBOL(fsg_lun_open); +EXPORT_SYMBOL_GPL(fsg_lun_open); /*-------------------------------------------------------------------------*/ @@ -295,7 +295,7 @@ int fsg_lun_fsync_sub(struct fsg_lun *curlun) return 0; return vfs_fsync(filp, 1); } -EXPORT_SYMBOL(fsg_lun_fsync_sub); +EXPORT_SYMBOL_GPL(fsg_lun_fsync_sub); void store_cdrom_address(u8 *dest, int msf, u32 addr) { @@ -314,7 +314,7 @@ void store_cdrom_address(u8 *dest, int msf, u32 addr) put_unaligned_be32(addr, dest); } } -EXPORT_SYMBOL(store_cdrom_address); +EXPORT_SYMBOL_GPL(store_cdrom_address); /*-------------------------------------------------------------------------*/ @@ -325,13 +325,13 @@ ssize_t fsg_show_ro(struct fsg_lun *curlun, char *buf) ? curlun->ro : curlun->initially_ro); } -EXPORT_SYMBOL(fsg_show_ro); +EXPORT_SYMBOL_GPL(fsg_show_ro); ssize_t fsg_show_nofua(struct fsg_lun *curlun, char *buf) { return sprintf(buf, "%u\n", curlun->nofua); } -EXPORT_SYMBOL(fsg_show_nofua); +EXPORT_SYMBOL_GPL(fsg_show_nofua); ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, char *buf) @@ -357,19 +357,19 @@ ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, up_read(filesem); return rc; } -EXPORT_SYMBOL(fsg_show_file); +EXPORT_SYMBOL_GPL(fsg_show_file); ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf) { return sprintf(buf, "%u\n", curlun->cdrom); } -EXPORT_SYMBOL(fsg_show_cdrom); +EXPORT_SYMBOL_GPL(fsg_show_cdrom); ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf) { return sprintf(buf, "%u\n", curlun->removable); } -EXPORT_SYMBOL(fsg_show_removable); +EXPORT_SYMBOL_GPL(fsg_show_removable); /* * The caller must hold fsg->filesem for reading when calling this function. @@ -410,7 +410,7 @@ ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem, return rc; } -EXPORT_SYMBOL(fsg_store_ro); +EXPORT_SYMBOL_GPL(fsg_store_ro); ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count) { @@ -429,7 +429,7 @@ ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count) return count; } -EXPORT_SYMBOL(fsg_store_nofua); +EXPORT_SYMBOL_GPL(fsg_store_nofua); ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, const char *buf, size_t count) @@ -460,7 +460,7 @@ ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, up_write(filesem); return (rc < 0 ? rc : count); } -EXPORT_SYMBOL(fsg_store_file); +EXPORT_SYMBOL_GPL(fsg_store_file); ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem, const char *buf, size_t count) @@ -483,7 +483,7 @@ ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem, return ret; } -EXPORT_SYMBOL(fsg_store_cdrom); +EXPORT_SYMBOL_GPL(fsg_store_cdrom); ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf, size_t count) @@ -499,6 +499,6 @@ ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf, return count; } -EXPORT_SYMBOL(fsg_store_removable); +EXPORT_SYMBOL_GPL(fsg_store_removable); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c index f058c0368d61..49481e0a3382 100644 --- a/drivers/usb/gadget/tcm_usb_gadget.c +++ b/drivers/usb/gadget/tcm_usb_gadget.c @@ -1383,10 +1383,8 @@ static struct se_node_acl *usbg_alloc_fabric_acl(struct se_portal_group *se_tpg) struct usbg_nacl *nacl; nacl = kzalloc(sizeof(struct usbg_nacl), GFP_KERNEL); - if (!nacl) { - printk(KERN_ERR "Unable to allocate struct usbg_nacl\n"); + if (!nacl) return NULL; - } return &nacl->se_node_acl; } @@ -1561,10 +1559,8 @@ static struct se_portal_group *usbg_make_tpg( } tpg = kzalloc(sizeof(struct usbg_tpg), GFP_KERNEL); - if (!tpg) { - printk(KERN_ERR "Unable to allocate struct usbg_tpg"); + if (!tpg) return ERR_PTR(-ENOMEM); - } mutex_init(&tpg->tpg_mutex); atomic_set(&tpg->tpg_port_count, 0); tpg->workqueue = alloc_workqueue("tcm_usb_gadget", 0, 1); @@ -1613,10 +1609,8 @@ static struct se_wwn *usbg_make_tport( return ERR_PTR(-EINVAL); tport = kzalloc(sizeof(struct usbg_tport), GFP_KERNEL); - if (!(tport)) { - printk(KERN_ERR "Unable to allocate struct usbg_tport"); + if (!(tport)) return ERR_PTR(-ENOMEM); - } tport->tport_wwpn = wwpn; snprintf(tport->tport_name, sizeof(tport->tport_name), "%s", wnn_name); return &tport->tport_wwn; @@ -1727,10 +1721,8 @@ static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name) ret = -ENOMEM; tv_nexus = kzalloc(sizeof(*tv_nexus), GFP_KERNEL); - if (!tv_nexus) { - pr_err("Unable to allocate struct tcm_vhost_nexus\n"); + if (!tv_nexus) goto err_unlock; - } tv_nexus->tvn_se_sess = transport_init_session(TARGET_PROT_NORMAL); if (IS_ERR(tv_nexus->tvn_se_sess)) goto err_free; diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index b7d4f82872b7..fe0880d0873e 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -818,7 +818,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g, return dev; } -EXPORT_SYMBOL(gether_setup_name); +EXPORT_SYMBOL_GPL(gether_setup_name); struct net_device *gether_setup_name_default(const char *netname) { @@ -855,7 +855,7 @@ struct net_device *gether_setup_name_default(const char *netname) return net; } -EXPORT_SYMBOL(gether_setup_name_default); +EXPORT_SYMBOL_GPL(gether_setup_name_default); int gether_register_netdev(struct net_device *net) { @@ -893,7 +893,7 @@ int gether_register_netdev(struct net_device *net) return status; } -EXPORT_SYMBOL(gether_register_netdev); +EXPORT_SYMBOL_GPL(gether_register_netdev); void gether_set_gadget(struct net_device *net, struct usb_gadget *g) { @@ -903,7 +903,7 @@ void gether_set_gadget(struct net_device *net, struct usb_gadget *g) dev->gadget = g; SET_NETDEV_DEV(net, &g->dev); } -EXPORT_SYMBOL(gether_set_gadget); +EXPORT_SYMBOL_GPL(gether_set_gadget); int gether_set_dev_addr(struct net_device *net, const char *dev_addr) { @@ -916,7 +916,7 @@ int gether_set_dev_addr(struct net_device *net, const char *dev_addr) memcpy(dev->dev_mac, new_addr, ETH_ALEN); return 0; } -EXPORT_SYMBOL(gether_set_dev_addr); +EXPORT_SYMBOL_GPL(gether_set_dev_addr); int gether_get_dev_addr(struct net_device *net, char *dev_addr, int len) { @@ -925,7 +925,7 @@ int gether_get_dev_addr(struct net_device *net, char *dev_addr, int len) dev = netdev_priv(net); return get_ether_addr_str(dev->dev_mac, dev_addr, len); } -EXPORT_SYMBOL(gether_get_dev_addr); +EXPORT_SYMBOL_GPL(gether_get_dev_addr); int gether_set_host_addr(struct net_device *net, const char *host_addr) { @@ -938,7 +938,7 @@ int gether_set_host_addr(struct net_device *net, const char *host_addr) memcpy(dev->host_mac, new_addr, ETH_ALEN); return 0; } -EXPORT_SYMBOL(gether_set_host_addr); +EXPORT_SYMBOL_GPL(gether_set_host_addr); int gether_get_host_addr(struct net_device *net, char *host_addr, int len) { @@ -947,7 +947,7 @@ int gether_get_host_addr(struct net_device *net, char *host_addr, int len) dev = netdev_priv(net); return get_ether_addr_str(dev->host_mac, host_addr, len); } -EXPORT_SYMBOL(gether_get_host_addr); +EXPORT_SYMBOL_GPL(gether_get_host_addr); int gether_get_host_addr_cdc(struct net_device *net, char *host_addr, int len) { @@ -961,7 +961,7 @@ int gether_get_host_addr_cdc(struct net_device *net, char *host_addr, int len) return strlen(host_addr); } -EXPORT_SYMBOL(gether_get_host_addr_cdc); +EXPORT_SYMBOL_GPL(gether_get_host_addr_cdc); void gether_get_host_addr_u8(struct net_device *net, u8 host_mac[ETH_ALEN]) { @@ -970,7 +970,7 @@ void gether_get_host_addr_u8(struct net_device *net, u8 host_mac[ETH_ALEN]) dev = netdev_priv(net); memcpy(host_mac, dev->host_mac, ETH_ALEN); } -EXPORT_SYMBOL(gether_get_host_addr_u8); +EXPORT_SYMBOL_GPL(gether_get_host_addr_u8); void gether_set_qmult(struct net_device *net, unsigned qmult) { @@ -979,7 +979,7 @@ void gether_set_qmult(struct net_device *net, unsigned qmult) dev = netdev_priv(net); dev->qmult = qmult; } -EXPORT_SYMBOL(gether_set_qmult); +EXPORT_SYMBOL_GPL(gether_set_qmult); unsigned gether_get_qmult(struct net_device *net) { @@ -988,7 +988,7 @@ unsigned gether_get_qmult(struct net_device *net) dev = netdev_priv(net); return dev->qmult; } -EXPORT_SYMBOL(gether_get_qmult); +EXPORT_SYMBOL_GPL(gether_get_qmult); int gether_get_ifname(struct net_device *net, char *name, int len) { @@ -997,7 +997,7 @@ int gether_get_ifname(struct net_device *net, char *name, int len) rtnl_unlock(); return strlen(name); } -EXPORT_SYMBOL(gether_get_ifname); +EXPORT_SYMBOL_GPL(gether_get_ifname); /** * gether_cleanup - remove Ethernet-over-USB device @@ -1014,7 +1014,7 @@ void gether_cleanup(struct eth_dev *dev) flush_work(&dev->work); free_netdev(dev->net); } -EXPORT_SYMBOL(gether_cleanup); +EXPORT_SYMBOL_GPL(gether_cleanup); /** * gether_connect - notify network layer that USB link is active @@ -1095,7 +1095,7 @@ fail0: return ERR_PTR(result); return dev->net; } -EXPORT_SYMBOL(gether_connect); +EXPORT_SYMBOL_GPL(gether_connect); /** * gether_disconnect - notify network layer that USB link is inactive @@ -1166,7 +1166,7 @@ void gether_disconnect(struct gether *link) dev->port_usb = NULL; spin_unlock(&dev->lock); } -EXPORT_SYMBOL(gether_disconnect); +EXPORT_SYMBOL_GPL(gether_disconnect); MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Brownell"); diff --git a/drivers/usb/gadget/u_f.c b/drivers/usb/gadget/u_f.c index 63b6642c162b..c6276f0268ae 100644 --- a/drivers/usb/gadget/u_f.c +++ b/drivers/usb/gadget/u_f.c @@ -29,4 +29,4 @@ struct usb_request *alloc_ep_req(struct usb_ep *ep, int len, int default_len) } return req; } -EXPORT_SYMBOL(alloc_ep_req); +EXPORT_SYMBOL_GPL(alloc_ep_req); diff --git a/drivers/usb/gadget/u_f.h b/drivers/usb/gadget/u_f.h index 71034c061fca..1d5f0eb68552 100644 --- a/drivers/usb/gadget/u_f.h +++ b/drivers/usb/gadget/u_f.h @@ -16,6 +16,32 @@ #ifndef __U_F_H__ #define __U_F_H__ +/* Variable Length Array Macros **********************************************/ +#define vla_group(groupname) size_t groupname##__next = 0 +#define vla_group_size(groupname) groupname##__next + +#define vla_item(groupname, type, name, n) \ + size_t groupname##_##name##__offset = ({ \ + size_t align_mask = __alignof__(type) - 1; \ + size_t offset = (groupname##__next + align_mask) & ~align_mask;\ + size_t size = (n) * sizeof(type); \ + groupname##__next = offset + size; \ + offset; \ + }) + +#define vla_item_with_sz(groupname, type, name, n) \ + size_t groupname##_##name##__sz = (n) * sizeof(type); \ + size_t groupname##_##name##__offset = ({ \ + size_t align_mask = __alignof__(type) - 1; \ + size_t offset = (groupname##__next + align_mask) & ~align_mask;\ + size_t size = groupname##_##name##__sz; \ + groupname##__next = offset + size; \ + offset; \ + }) + +#define vla_ptr(ptr, groupname, name) \ + ((void *) ((char *)ptr + groupname##_##name##__offset)) + struct usb_ep; struct usb_request; diff --git a/drivers/usb/gadget/u_os_desc.h b/drivers/usb/gadget/u_os_desc.h new file mode 100644 index 000000000000..ea5cf8c2da28 --- /dev/null +++ b/drivers/usb/gadget/u_os_desc.h @@ -0,0 +1,90 @@ +/* + * u_os_desc.h + * + * Utility definitions for "OS Descriptors" support + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __U_OS_DESC_H__ +#define __U_OS_DESC_H__ + +#include <asm/unaligned.h> +#include <linux/nls.h> + +#define USB_EXT_PROP_DW_SIZE 0 +#define USB_EXT_PROP_DW_PROPERTY_DATA_TYPE 4 +#define USB_EXT_PROP_W_PROPERTY_NAME_LENGTH 8 +#define USB_EXT_PROP_B_PROPERTY_NAME 10 +#define USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH 10 +#define USB_EXT_PROP_B_PROPERTY_DATA 14 + +#define USB_EXT_PROP_RESERVED 0 +#define USB_EXT_PROP_UNICODE 1 +#define USB_EXT_PROP_UNICODE_ENV 2 +#define USB_EXT_PROP_BINARY 3 +#define USB_EXT_PROP_LE32 4 +#define USB_EXT_PROP_BE32 5 +#define USB_EXT_PROP_UNICODE_LINK 6 +#define USB_EXT_PROP_UNICODE_MULTI 7 + +static inline void usb_ext_prop_put_size(u8 *buf, int dw_size) +{ + put_unaligned_le32(dw_size, &buf[USB_EXT_PROP_DW_SIZE]); +} + +static inline void usb_ext_prop_put_type(u8 *buf, int type) +{ + put_unaligned_le32(type, &buf[USB_EXT_PROP_DW_PROPERTY_DATA_TYPE]); +} + +static inline int usb_ext_prop_put_name(u8 *buf, const char *name, int pnl) +{ + int result; + + put_unaligned_le16(pnl, &buf[USB_EXT_PROP_W_PROPERTY_NAME_LENGTH]); + result = utf8s_to_utf16s(name, strlen(name), UTF16_LITTLE_ENDIAN, + (wchar_t *) &buf[USB_EXT_PROP_B_PROPERTY_NAME], pnl - 2); + if (result < 0) + return result; + + put_unaligned_le16(0, &buf[USB_EXT_PROP_B_PROPERTY_NAME + pnl]); + + return pnl; +} + +static inline void usb_ext_prop_put_binary(u8 *buf, int pnl, const u8 *data, + int data_len) +{ + put_unaligned_le32(data_len, + &buf[USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH + pnl]); + memcpy(&buf[USB_EXT_PROP_B_PROPERTY_DATA + pnl], data, data_len); +} + +static inline int usb_ext_prop_put_unicode(u8 *buf, int pnl, const char *string, + int data_len) +{ + int result; + put_unaligned_le32(data_len, + &buf[USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH + pnl]); + + result = utf8s_to_utf16s(string, data_len >> 1, UTF16_LITTLE_ENDIAN, + (wchar_t *) &buf[USB_EXT_PROP_B_PROPERTY_DATA + pnl], + data_len - 2); + if (result < 0) + return result; + + put_unaligned_le16(0, + &buf[USB_EXT_PROP_B_PROPERTY_DATA + pnl + data_len]); + + return data_len; +} + +#endif /* __U_OS_DESC_H__ */ diff --git a/drivers/usb/gadget/u_rndis.h b/drivers/usb/gadget/u_rndis.h index 7291b15c9dce..e902aa42a297 100644 --- a/drivers/usb/gadget/u_rndis.h +++ b/drivers/usb/gadget/u_rndis.h @@ -26,6 +26,9 @@ struct f_rndis_opts { bool bound; bool borrowed_net; + struct usb_os_desc rndis_os_desc; + char rndis_ext_compat_id[16]; + /* * Read/write access to configfs attributes is handled by configfs. * diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index 27768a7d986a..b0d98172bc07 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -428,6 +428,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) list_for_each_entry(udc, &udc_list, list) if (udc->driver == driver) { usb_gadget_remove_driver(udc); + usb_gadget_set_state(udc->gadget, + USB_STATE_NOTATTACHED); ret = 0; break; } diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c index 0bb5d50075de..1c29bc954db9 100644 --- a/drivers/usb/gadget/uvc_queue.c +++ b/drivers/usb/gadget/uvc_queue.c @@ -20,6 +20,7 @@ #include <linux/vmalloc.h> #include <linux/wait.h> +#include <media/v4l2-common.h> #include <media/videobuf2-vmalloc.h> #include "uvc.h" @@ -136,6 +137,8 @@ static int uvc_queue_init(struct uvc_video_queue *queue, queue->queue.buf_struct_size = sizeof(struct uvc_buffer); queue->queue.ops = &uvc_queue_qops; queue->queue.mem_ops = &vb2_vmalloc_memops; + queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC + | V4L2_BUF_FLAG_TSTAMP_SRC_EOF; ret = vb2_queue_init(&queue->queue); if (ret) return ret; @@ -379,14 +382,9 @@ static struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, else nextbuf = NULL; - /* - * 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.field = V4L2_FIELD_NONE; buf->buf.v4l2_buf.sequence = queue->sequence++; - do_gettimeofday(&buf->buf.v4l2_buf.timestamp); + v4l2_get_timestamp(&buf->buf.v4l2_buf.timestamp); vb2_set_plane_payload(&buf->buf, 0, buf->bytesused); vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE); diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 3d9e54062d62..61b7817bd66b 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -29,6 +29,14 @@ if USB_XHCI_HCD config USB_XHCI_PLATFORM tristate +config USB_XHCI_MVEBU + tristate "xHCI support for Marvell Armada 375/38x" + select USB_XHCI_PLATFORM + depends on ARCH_MVEBU || COMPILE_TEST + ---help--- + Say 'Y' to enable the support for the xHCI host controller + found in Marvell Armada 375/38x ARM SOCs. + endif # USB_XHCI_HCD config USB_EHCI_HCD @@ -170,7 +178,6 @@ config USB_EHCI_MSM tristate "Support for Qualcomm QSD/MSM on-chip EHCI USB controller" depends on ARCH_MSM select USB_EHCI_ROOT_HUB_TT - select USB_MSM_OTG ---help--- Enables support for the USB Host controller present on the Qualcomm chipsets. Root Hub has inbuilt TT. @@ -343,10 +350,19 @@ config USB_FOTG210_HCD To compile this driver as a module, choose M here: the module will be called fotg210-hcd. +config USB_MAX3421_HCD + tristate "MAX3421 HCD (USB-over-SPI) support" + depends on USB && SPI + ---help--- + The Maxim MAX3421E chip supports standard USB 2.0-compliant + full-speed devices either in host or peripheral mode. This + driver supports the host-mode of the MAX3421E only. + + To compile this driver as a module, choose M here: the module will + be called max3421-hcd. + config USB_OHCI_HCD tristate "OHCI HCD (USB 1.1) support" - select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 - depends on USB_ISP1301 || !ARCH_LPC32XX ---help--- The Open Host Controller Interface (OHCI) is a standard for accessing USB 1.1 host controller hardware. It does more in hardware than Intel's @@ -365,6 +381,7 @@ if USB_OHCI_HCD config USB_OHCI_HCD_OMAP1 tristate "OHCI support for OMAP1/2 chips" depends on ARCH_OMAP1 + depends on ISP1301_OMAP || !(MACH_OMAP_H2 || MACH_OMAP_H3) default y ---help--- Enables support for the OHCI controller on OMAP1/2 chips. @@ -388,6 +405,7 @@ config USB_OHCI_HCD_S3C2410 config USB_OHCI_HCD_LPC32XX tristate "Support for LPC on-chip OHCI USB controller" depends on USB_OHCI_HCD && ARCH_LPC32XX + depends on USB_ISP1301 default y ---help--- Enables support for the on-chip OHCI controller on @@ -417,6 +435,16 @@ config USB_OHCI_HCD_OMAP3 Enables support for the on-chip OHCI controller on OMAP3 and later chips. +config USB_OHCI_HCD_DAVINCI + bool "OHCI support for TI DaVinci DA8xx" + depends on ARCH_DAVINCI_DA8XX + depends on USB_OHCI_HCD=y + default y + help + Enables support for the DaVinci DA8xx integrated OHCI + controller. This driver cannot currently be a loadable + module because it lacks a proper PHY abstraction. + config USB_OHCI_ATH79 bool "USB OHCI support for the Atheros AR71XX/AR7240 SoCs (DEPRECATED)" depends on (SOC_AR71XX || SOC_AR724X) diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 7530468c9a4f..af89a903d97e 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -19,6 +19,9 @@ xhci-hcd-$(CONFIG_PCI) += xhci-pci.o ifneq ($(CONFIG_USB_XHCI_PLATFORM), ) xhci-hcd-y += xhci-plat.o +ifneq ($(CONFIG_USB_XHCI_MVEBU), ) + xhci-hcd-y += xhci-mvebu.o +endif endif obj-$(CONFIG_USB_WHCI_HCD) += whci/ @@ -70,3 +73,4 @@ obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o obj-$(CONFIG_USB_FUSBH200_HCD) += fusbh200-hcd.o obj-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o +obj-$(CONFIG_USB_MAX3421_HCD) += max3421-hcd.o diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index 7f425acd9be5..d1c76216350f 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -19,6 +19,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_gpio.h> +#include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/usb/phy.h> #include <linux/usb/samsung_usb_phy.h> @@ -42,17 +43,106 @@ static const char hcd_name[] = "ehci-exynos"; static struct hc_driver __read_mostly exynos_ehci_hc_driver; +#define PHY_NUMBER 3 + struct exynos_ehci_hcd { struct clk *clk; struct usb_phy *phy; struct usb_otg *otg; + struct phy *phy_g[PHY_NUMBER]; }; #define to_exynos_ehci(hcd) (struct exynos_ehci_hcd *)(hcd_to_ehci(hcd)->priv) -static void exynos_setup_vbus_gpio(struct platform_device *pdev) +static int exynos_ehci_get_phy(struct device *dev, + struct exynos_ehci_hcd *exynos_ehci) +{ + struct device_node *child; + struct phy *phy; + int phy_number; + int ret = 0; + + exynos_ehci->phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); + if (IS_ERR(exynos_ehci->phy)) { + ret = PTR_ERR(exynos_ehci->phy); + if (ret != -ENXIO && ret != -ENODEV) { + dev_err(dev, "no usb2 phy configured\n"); + return ret; + } + dev_dbg(dev, "Failed to get usb2 phy\n"); + } else { + exynos_ehci->otg = exynos_ehci->phy->otg; + } + + for_each_available_child_of_node(dev->of_node, child) { + ret = of_property_read_u32(child, "reg", &phy_number); + if (ret) { + dev_err(dev, "Failed to parse device tree\n"); + of_node_put(child); + return ret; + } + + if (phy_number >= PHY_NUMBER) { + dev_err(dev, "Invalid number of PHYs\n"); + of_node_put(child); + return -EINVAL; + } + + phy = devm_of_phy_get(dev, child, 0); + of_node_put(child); + if (IS_ERR(phy)) { + ret = PTR_ERR(phy); + if (ret != -ENOSYS && ret != -ENODEV) { + dev_err(dev, "no usb2 phy configured\n"); + return ret; + } + dev_dbg(dev, "Failed to get usb2 phy\n"); + } + exynos_ehci->phy_g[phy_number] = phy; + } + + return ret; +} + +static int exynos_ehci_phy_enable(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd); + int i; + int ret = 0; + + if (!IS_ERR(exynos_ehci->phy)) + return usb_phy_init(exynos_ehci->phy); + + for (i = 0; ret == 0 && i < PHY_NUMBER; i++) + if (!IS_ERR(exynos_ehci->phy_g[i])) + ret = phy_power_on(exynos_ehci->phy_g[i]); + if (ret) + for (i--; i >= 0; i--) + if (!IS_ERR(exynos_ehci->phy_g[i])) + phy_power_off(exynos_ehci->phy_g[i]); + + return ret; +} + +static void exynos_ehci_phy_disable(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd); + int i; + + if (!IS_ERR(exynos_ehci->phy)) { + usb_phy_shutdown(exynos_ehci->phy); + return; + } + + for (i = 0; i < PHY_NUMBER; i++) + if (!IS_ERR(exynos_ehci->phy_g[i])) + phy_power_off(exynos_ehci->phy_g[i]); +} + +static void exynos_setup_vbus_gpio(struct device *dev) { - struct device *dev = &pdev->dev; int err; int gpio; @@ -75,7 +165,6 @@ static int exynos_ehci_probe(struct platform_device *pdev) struct usb_hcd *hcd; struct ehci_hcd *ehci; struct resource *res; - struct usb_phy *phy; int irq; int err; @@ -88,7 +177,7 @@ static int exynos_ehci_probe(struct platform_device *pdev) if (err) return err; - exynos_setup_vbus_gpio(pdev); + exynos_setup_vbus_gpio(&pdev->dev); hcd = usb_create_hcd(&exynos_ehci_hc_driver, &pdev->dev, dev_name(&pdev->dev)); @@ -102,15 +191,9 @@ static int exynos_ehci_probe(struct platform_device *pdev) "samsung,exynos5440-ehci")) goto skip_phy; - phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); - if (IS_ERR(phy)) { - usb_put_hcd(hcd); - dev_warn(&pdev->dev, "no platform data or transceiver defined\n"); - return -EPROBE_DEFER; - } else { - exynos_ehci->phy = phy; - exynos_ehci->otg = phy->otg; - } + err = exynos_ehci_get_phy(&pdev->dev, exynos_ehci); + if (err) + goto fail_clk; skip_phy: @@ -135,10 +218,9 @@ skip_phy: hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - hcd->regs = devm_ioremap(&pdev->dev, res->start, hcd->rsrc_len); - if (!hcd->regs) { - dev_err(&pdev->dev, "Failed to remap I/O memory\n"); - err = -ENOMEM; + hcd->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hcd->regs)) { + err = PTR_ERR(hcd->regs); goto fail_io; } @@ -152,8 +234,11 @@ skip_phy: if (exynos_ehci->otg) exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self); - if (exynos_ehci->phy) - usb_phy_init(exynos_ehci->phy); + err = exynos_ehci_phy_enable(&pdev->dev); + if (err) { + dev_err(&pdev->dev, "Failed to enable USB phy\n"); + goto fail_io; + } ehci = hcd_to_ehci(hcd); ehci->caps = hcd->regs; @@ -173,8 +258,7 @@ skip_phy: return 0; fail_add_hcd: - if (exynos_ehci->phy) - usb_phy_shutdown(exynos_ehci->phy); + exynos_ehci_phy_disable(&pdev->dev); fail_io: clk_disable_unprepare(exynos_ehci->clk); fail_clk: @@ -192,8 +276,7 @@ static int exynos_ehci_remove(struct platform_device *pdev) if (exynos_ehci->otg) exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self); - if (exynos_ehci->phy) - usb_phy_shutdown(exynos_ehci->phy); + exynos_ehci_phy_disable(&pdev->dev); clk_disable_unprepare(exynos_ehci->clk); @@ -218,8 +301,7 @@ static int exynos_ehci_suspend(struct device *dev) if (exynos_ehci->otg) exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self); - if (exynos_ehci->phy) - usb_phy_shutdown(exynos_ehci->phy); + exynos_ehci_phy_disable(dev); clk_disable_unprepare(exynos_ehci->clk); @@ -230,14 +312,19 @@ static int exynos_ehci_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd); + int ret; clk_prepare_enable(exynos_ehci->clk); if (exynos_ehci->otg) exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self); - if (exynos_ehci->phy) - usb_phy_init(exynos_ehci->phy); + ret = exynos_ehci_phy_enable(dev); + if (ret) { + dev_err(dev, "Failed to enable USB phy\n"); + clk_disable_unprepare(exynos_ehci->clk); + return ret; + } /* DMA burst Enable */ writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 7ae0c4d51741..cc305c71ac3d 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -33,15 +33,6 @@ #ifdef CONFIG_PM -static int ehci_hub_control( - struct usb_hcd *hcd, - u16 typeReq, - u16 wValue, - u16 wIndex, - char *buf, - u16 wLength -); - static int persist_enabled_on_companion(struct usb_device *udev, void *unused) { return !udev->maxchild && udev->persist_enabled && @@ -865,7 +856,7 @@ cleanup: #endif /* CONFIG_USB_HCD_TEST_MODE */ /*-------------------------------------------------------------------------*/ -static int ehci_hub_control ( +int ehci_hub_control( struct usb_hcd *hcd, u16 typeReq, u16 wValue, @@ -1285,6 +1276,7 @@ error_exit: spin_unlock_irqrestore (&ehci->lock, flags); return retval; } +EXPORT_SYMBOL_GPL(ehci_hub_control); static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum) { diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index f341651d6f6c..982c09bebe0f 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -96,10 +96,9 @@ static int ehci_msm_probe(struct platform_device *pdev) hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - hcd->regs = devm_ioremap(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; + hcd->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hcd->regs)) { + ret = PTR_ERR(hcd->regs); goto put_hcd; } diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index bd61612a7251..08147c35f836 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c @@ -176,11 +176,9 @@ static int mv_ehci_probe(struct platform_device *pdev) goto err_put_hcd; } - ehci_mv->phy_regs = devm_ioremap(&pdev->dev, r->start, - resource_size(r)); - if (!ehci_mv->phy_regs) { - dev_err(&pdev->dev, "failed to map phy I/O memory\n"); - retval = -EFAULT; + ehci_mv->phy_regs = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(ehci_mv->phy_regs)) { + retval = PTR_ERR(ehci_mv->phy_regs); goto err_put_hcd; } @@ -191,11 +189,9 @@ static int mv_ehci_probe(struct platform_device *pdev) goto err_put_hcd; } - ehci_mv->cap_regs = devm_ioremap(&pdev->dev, r->start, - resource_size(r)); - if (ehci_mv->cap_regs == NULL) { - dev_err(&pdev->dev, "failed to map I/O memory\n"); - retval = -EFAULT; + ehci_mv->cap_regs = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(ehci_mv->cap_regs)) { + retval = PTR_ERR(ehci_mv->cap_regs); goto err_put_hcd; } diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index 30d35e5e503a..22e15cab8ea5 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -15,6 +15,7 @@ #include <linux/clk.h> #include <linux/platform_data/usb-ehci-orion.h> #include <linux/of.h> +#include <linux/phy/phy.h> #include <linux/of_device.h> #include <linux/of_irq.h> #include <linux/usb.h> @@ -42,6 +43,13 @@ #define DRIVER_DESC "EHCI orion driver" +#define hcd_to_orion_priv(h) ((struct orion_ehci_hcd *)hcd_to_ehci(h)->priv) + +struct orion_ehci_hcd { + struct clk *clk; + struct phy *phy; +}; + static const char hcd_name[] = "ehci-orion"; static struct hc_driver __read_mostly ehci_orion_hc_driver; @@ -137,6 +145,10 @@ ehci_orion_conf_mbus_windows(struct usb_hcd *hcd, } } +static const struct ehci_driver_overrides orion_overrides __initconst = { + .extra_priv_size = sizeof(struct orion_ehci_hcd), +}; + static int ehci_orion_drv_probe(struct platform_device *pdev) { struct orion_ehci_data *pd = dev_get_platdata(&pdev->dev); @@ -144,26 +156,23 @@ static int ehci_orion_drv_probe(struct platform_device *pdev) struct resource *res; struct usb_hcd *hcd; struct ehci_hcd *ehci; - struct clk *clk; void __iomem *regs; int irq, err; enum orion_ehci_phy_ver phy_version; + struct orion_ehci_hcd *priv; if (usb_disabled()) return -ENODEV; pr_debug("Initializing Orion-SoC USB Host Controller\n"); - if (pdev->dev.of_node) - irq = irq_of_parse_and_map(pdev->dev.of_node, 0); - else - irq = platform_get_irq(pdev, 0); + irq = platform_get_irq(pdev, 0); if (irq <= 0) { dev_err(&pdev->dev, "Found HC with no IRQ. Check %s setup!\n", dev_name(&pdev->dev)); err = -ENODEV; - goto err1; + goto err; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -172,7 +181,7 @@ static int ehci_orion_drv_probe(struct platform_device *pdev) |