|  | <?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> |