162306a36Sopenharmony_ci=========================
262306a36Sopenharmony_ciWriting a MUSB Glue Layer
362306a36Sopenharmony_ci=========================
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci:Author: Apelete Seketeli
662306a36Sopenharmony_ci
762306a36Sopenharmony_ciIntroduction
862306a36Sopenharmony_ci============
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ciThe Linux MUSB subsystem is part of the larger Linux USB subsystem. It
1162306a36Sopenharmony_ciprovides support for embedded USB Device Controllers (UDC) that do not
1262306a36Sopenharmony_ciuse Universal Host Controller Interface (UHCI) or Open Host Controller
1362306a36Sopenharmony_ciInterface (OHCI).
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ciInstead, these embedded UDC rely on the USB On-the-Go (OTG)
1662306a36Sopenharmony_cispecification which they implement at least partially. The silicon
1762306a36Sopenharmony_cireference design used in most cases is the Multipoint USB Highspeed
1862306a36Sopenharmony_ciDual-Role Controller (MUSB HDRC) found in the Mentor Graphics Inventra™
1962306a36Sopenharmony_cidesign.
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ciAs a self-taught exercise I have written an MUSB glue layer for the
2262306a36Sopenharmony_ciIngenic JZ4740 SoC, modelled after the many MUSB glue layers in the
2362306a36Sopenharmony_cikernel source tree. This layer can be found at
2462306a36Sopenharmony_ci``drivers/usb/musb/jz4740.c``. In this documentation I will walk through the
2562306a36Sopenharmony_cibasics of the ``jz4740.c`` glue layer, explaining the different pieces and
2662306a36Sopenharmony_ciwhat needs to be done in order to write your own device glue layer.
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci.. _musb-basics:
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ciLinux MUSB Basics
3162306a36Sopenharmony_ci=================
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ciTo get started on the topic, please read USB On-the-Go Basics (see
3462306a36Sopenharmony_ciResources) which provides an introduction of USB OTG operation at the
3562306a36Sopenharmony_cihardware level. A couple of wiki pages by Texas Instruments and Analog
3662306a36Sopenharmony_ciDevices also provide an overview of the Linux kernel MUSB configuration,
3762306a36Sopenharmony_cialbeit focused on some specific devices provided by these companies.
3862306a36Sopenharmony_ciFinally, getting acquainted with the USB specification at USB home page
3962306a36Sopenharmony_cimay come in handy, with practical instance provided through the Writing
4062306a36Sopenharmony_ciUSB Device Drivers documentation (again, see Resources).
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ciLinux USB stack is a layered architecture in which the MUSB controller
4362306a36Sopenharmony_cihardware sits at the lowest. The MUSB controller driver abstract the
4462306a36Sopenharmony_ciMUSB controller hardware to the Linux USB stack::
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	  ------------------------
4762306a36Sopenharmony_ci	  |                      | <------- drivers/usb/gadget
4862306a36Sopenharmony_ci	  | Linux USB Core Stack | <------- drivers/usb/host
4962306a36Sopenharmony_ci	  |                      | <------- drivers/usb/core
5062306a36Sopenharmony_ci	  ------------------------
5162306a36Sopenharmony_ci5262306a36Sopenharmony_ci	 --------------------------
5362306a36Sopenharmony_ci	 |                        | <------ drivers/usb/musb/musb_gadget.c
5462306a36Sopenharmony_ci	 | MUSB Controller driver | <------ drivers/usb/musb/musb_host.c
5562306a36Sopenharmony_ci	 |                        | <------ drivers/usb/musb/musb_core.c
5662306a36Sopenharmony_ci	 --------------------------
5762306a36Sopenharmony_ci5862306a36Sopenharmony_ci      ---------------------------------
5962306a36Sopenharmony_ci      | MUSB Platform Specific Driver |
6062306a36Sopenharmony_ci      |                               | <-- drivers/usb/musb/jz4740.c
6162306a36Sopenharmony_ci      |       aka "Glue Layer"        |
6262306a36Sopenharmony_ci      ---------------------------------
6362306a36Sopenharmony_ci6462306a36Sopenharmony_ci      ---------------------------------
6562306a36Sopenharmony_ci      |   MUSB Controller Hardware    |
6662306a36Sopenharmony_ci      ---------------------------------
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ciAs outlined above, the glue layer is actually the platform specific code
6962306a36Sopenharmony_cisitting in between the controller driver and the controller hardware.
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ciJust like a Linux USB driver needs to register itself with the Linux USB
7262306a36Sopenharmony_cisubsystem, the MUSB glue layer needs first to register itself with the
7362306a36Sopenharmony_ciMUSB controller driver. This will allow the controller driver to know
7462306a36Sopenharmony_ciabout which device the glue layer supports and which functions to call
7562306a36Sopenharmony_ciwhen a supported device is detected or released; remember we are talking
7662306a36Sopenharmony_ciabout an embedded controller chip here, so no insertion or removal at
7762306a36Sopenharmony_cirun-time.
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ciAll of this information is passed to the MUSB controller driver through
8062306a36Sopenharmony_cia :c:type:`platform_driver` structure defined in the glue layer as::
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci    static struct platform_driver jz4740_driver = {
8362306a36Sopenharmony_ci	.probe      = jz4740_probe,
8462306a36Sopenharmony_ci	.remove     = jz4740_remove,
8562306a36Sopenharmony_ci	.driver     = {
8662306a36Sopenharmony_ci	    .name   = "musb-jz4740",
8762306a36Sopenharmony_ci	},
8862306a36Sopenharmony_ci    };
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ciThe probe and remove function pointers are called when a matching device
9162306a36Sopenharmony_ciis detected and, respectively, released. The name string describes the
9262306a36Sopenharmony_cidevice supported by this glue layer. In the current case it matches a
9362306a36Sopenharmony_ciplatform_device structure declared in ``arch/mips/jz4740/platform.c``. Note
9462306a36Sopenharmony_cithat we are not using device tree bindings here.
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ciIn order to register itself to the controller driver, the glue layer
9762306a36Sopenharmony_cigoes through a few steps, basically allocating the controller hardware
9862306a36Sopenharmony_ciresources and initialising a couple of circuits. To do so, it needs to
9962306a36Sopenharmony_cikeep track of the information used throughout these steps. This is done
10062306a36Sopenharmony_ciby defining a private ``jz4740_glue`` structure::
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci    struct jz4740_glue {
10362306a36Sopenharmony_ci	struct device           *dev;
10462306a36Sopenharmony_ci	struct platform_device  *musb;
10562306a36Sopenharmony_ci	struct clk      *clk;
10662306a36Sopenharmony_ci    };
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ciThe dev and musb members are both device structure variables. The first
11062306a36Sopenharmony_cione holds generic information about the device, since it's the basic
11162306a36Sopenharmony_cidevice structure, and the latter holds information more closely related
11262306a36Sopenharmony_cito the subsystem the device is registered to. The clk variable keeps
11362306a36Sopenharmony_ciinformation related to the device clock operation.
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ciLet's go through the steps of the probe function that leads the glue
11662306a36Sopenharmony_cilayer to register itself to the controller driver.
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci.. note::
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci   For the sake of readability each function will be split in logical
12162306a36Sopenharmony_ci   parts, each part being shown as if it was independent from the others.
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci.. code-block:: c
12462306a36Sopenharmony_ci    :emphasize-lines: 8,12,18
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci    static int jz4740_probe(struct platform_device *pdev)
12762306a36Sopenharmony_ci    {
12862306a36Sopenharmony_ci	struct platform_device      *musb;
12962306a36Sopenharmony_ci	struct jz4740_glue      *glue;
13062306a36Sopenharmony_ci	struct clk                      *clk;
13162306a36Sopenharmony_ci	int             ret;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
13462306a36Sopenharmony_ci	if (!glue)
13562306a36Sopenharmony_ci	    return -ENOMEM;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
13862306a36Sopenharmony_ci	if (!musb) {
13962306a36Sopenharmony_ci	    dev_err(&pdev->dev, "failed to allocate musb device\n");
14062306a36Sopenharmony_ci	    return -ENOMEM;
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	clk = devm_clk_get(&pdev->dev, "udc");
14462306a36Sopenharmony_ci	if (IS_ERR(clk)) {
14562306a36Sopenharmony_ci	    dev_err(&pdev->dev, "failed to get clock\n");
14662306a36Sopenharmony_ci	    ret = PTR_ERR(clk);
14762306a36Sopenharmony_ci	    goto err_platform_device_put;
14862306a36Sopenharmony_ci	}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	ret = clk_prepare_enable(clk);
15162306a36Sopenharmony_ci	if (ret) {
15262306a36Sopenharmony_ci	    dev_err(&pdev->dev, "failed to enable clock\n");
15362306a36Sopenharmony_ci	    goto err_platform_device_put;
15462306a36Sopenharmony_ci	}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	musb->dev.parent        = &pdev->dev;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	glue->dev           = &pdev->dev;
15962306a36Sopenharmony_ci	glue->musb          = musb;
16062306a36Sopenharmony_ci	glue->clk           = clk;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	return 0;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci    err_platform_device_put:
16562306a36Sopenharmony_ci	platform_device_put(musb);
16662306a36Sopenharmony_ci	return ret;
16762306a36Sopenharmony_ci    }
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ciThe first few lines of the probe function allocate and assign the glue,
17062306a36Sopenharmony_cimusb and clk variables. The ``GFP_KERNEL`` flag (line 8) allows the
17162306a36Sopenharmony_ciallocation process to sleep and wait for memory, thus being usable in a
17262306a36Sopenharmony_cilocking situation. The ``PLATFORM_DEVID_AUTO`` flag (line 12) allows
17362306a36Sopenharmony_ciautomatic allocation and management of device IDs in order to avoid
17462306a36Sopenharmony_cidevice namespace collisions with explicit IDs. With :c:func:`devm_clk_get`
17562306a36Sopenharmony_ci(line 18) the glue layer allocates the clock -- the ``devm_`` prefix
17662306a36Sopenharmony_ciindicates that :c:func:`clk_get` is managed: it automatically frees the
17762306a36Sopenharmony_ciallocated clock resource data when the device is released -- and enable
17862306a36Sopenharmony_ciit.
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ciThen comes the registration steps:
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci.. code-block:: c
18562306a36Sopenharmony_ci    :emphasize-lines: 3,5,7,9,16
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci    static int jz4740_probe(struct platform_device *pdev)
18862306a36Sopenharmony_ci    {
18962306a36Sopenharmony_ci	struct musb_hdrc_platform_data  *pdata = &jz4740_musb_platform_data;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	pdata->platform_ops     = &jz4740_musb_ops;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	platform_set_drvdata(pdev, glue);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	ret = platform_device_add_resources(musb, pdev->resource,
19662306a36Sopenharmony_ci			    pdev->num_resources);
19762306a36Sopenharmony_ci	if (ret) {
19862306a36Sopenharmony_ci	    dev_err(&pdev->dev, "failed to add resources\n");
19962306a36Sopenharmony_ci	    goto err_clk_disable;
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
20362306a36Sopenharmony_ci	if (ret) {
20462306a36Sopenharmony_ci	    dev_err(&pdev->dev, "failed to add platform_data\n");
20562306a36Sopenharmony_ci	    goto err_clk_disable;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	return 0;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci    err_clk_disable:
21162306a36Sopenharmony_ci	clk_disable_unprepare(clk);
21262306a36Sopenharmony_ci    err_platform_device_put:
21362306a36Sopenharmony_ci	platform_device_put(musb);
21462306a36Sopenharmony_ci	return ret;
21562306a36Sopenharmony_ci    }
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ciThe first step is to pass the device data privately held by the glue
21862306a36Sopenharmony_cilayer on to the controller driver through :c:func:`platform_set_drvdata`
21962306a36Sopenharmony_ci(line 7). Next is passing on the device resources information, also privately
22062306a36Sopenharmony_ciheld at that point, through :c:func:`platform_device_add_resources` (line 9).
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ciFinally comes passing on the platform specific data to the controller
22362306a36Sopenharmony_cidriver (line 16). Platform data will be discussed in
22462306a36Sopenharmony_ci:ref:`musb-dev-platform-data`, but here we are looking at the
22562306a36Sopenharmony_ci``platform_ops`` function pointer (line 5) in ``musb_hdrc_platform_data``
22662306a36Sopenharmony_cistructure (line 3). This function pointer allows the MUSB controller
22762306a36Sopenharmony_cidriver to know which function to call for device operation::
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci    static const struct musb_platform_ops jz4740_musb_ops = {
23062306a36Sopenharmony_ci	.init       = jz4740_musb_init,
23162306a36Sopenharmony_ci	.exit       = jz4740_musb_exit,
23262306a36Sopenharmony_ci    };
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ciHere we have the minimal case where only init and exit functions are
23562306a36Sopenharmony_cicalled by the controller driver when needed. Fact is the JZ4740 MUSB
23662306a36Sopenharmony_cicontroller is a basic controller, lacking some features found in other
23762306a36Sopenharmony_cicontrollers, otherwise we may also have pointers to a few other
23862306a36Sopenharmony_cifunctions like a power management function or a function to switch
23962306a36Sopenharmony_cibetween OTG and non-OTG modes, for instance.
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ciAt that point of the registration process, the controller driver
24262306a36Sopenharmony_ciactually calls the init function:
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci   .. code-block:: c
24562306a36Sopenharmony_ci    :emphasize-lines: 12,14
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci    static int jz4740_musb_init(struct musb *musb)
24862306a36Sopenharmony_ci    {
24962306a36Sopenharmony_ci	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
25062306a36Sopenharmony_ci	if (!musb->xceiv) {
25162306a36Sopenharmony_ci	    pr_err("HS UDC: no transceiver configured\n");
25262306a36Sopenharmony_ci	    return -ENODEV;
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	/* Silicon does not implement ConfigData register.
25662306a36Sopenharmony_ci	 * Set dyn_fifo to avoid reading EP config from hardware.
25762306a36Sopenharmony_ci	 */
25862306a36Sopenharmony_ci	musb->dyn_fifo = true;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	musb->isr = jz4740_musb_interrupt;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	return 0;
26362306a36Sopenharmony_ci    }
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ciThe goal of ``jz4740_musb_init()`` is to get hold of the transceiver
26662306a36Sopenharmony_cidriver data of the MUSB controller hardware and pass it on to the MUSB
26762306a36Sopenharmony_cicontroller driver, as usual. The transceiver is the circuitry inside the
26862306a36Sopenharmony_cicontroller hardware responsible for sending/receiving the USB data.
26962306a36Sopenharmony_ciSince it is an implementation of the physical layer of the OSI model,
27062306a36Sopenharmony_cithe transceiver is also referred to as PHY.
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ciGetting hold of the ``MUSB PHY`` driver data is done with ``usb_get_phy()``
27362306a36Sopenharmony_ciwhich returns a pointer to the structure containing the driver instance
27462306a36Sopenharmony_cidata. The next couple of instructions (line 12 and 14) are used as a
27562306a36Sopenharmony_ciquirk and to setup IRQ handling respectively. Quirks and IRQ handling
27662306a36Sopenharmony_ciwill be discussed later in :ref:`musb-dev-quirks` and
27762306a36Sopenharmony_ci:ref:`musb-handling-irqs`\ ::
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci    static int jz4740_musb_exit(struct musb *musb)
28062306a36Sopenharmony_ci    {
28162306a36Sopenharmony_ci	usb_put_phy(musb->xceiv);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	return 0;
28462306a36Sopenharmony_ci    }
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ciActing as the counterpart of init, the exit function releases the MUSB
28762306a36Sopenharmony_ciPHY driver when the controller hardware itself is about to be released.
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ciAgain, note that init and exit are fairly simple in this case due to the
29062306a36Sopenharmony_cibasic set of features of the JZ4740 controller hardware. When writing an
29162306a36Sopenharmony_cimusb glue layer for a more complex controller hardware, you might need
29262306a36Sopenharmony_cito take care of more processing in those two functions.
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ciReturning from the init function, the MUSB controller driver jumps back
29562306a36Sopenharmony_ciinto the probe function::
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci    static int jz4740_probe(struct platform_device *pdev)
29862306a36Sopenharmony_ci    {
29962306a36Sopenharmony_ci	ret = platform_device_add(musb);
30062306a36Sopenharmony_ci	if (ret) {
30162306a36Sopenharmony_ci	    dev_err(&pdev->dev, "failed to register musb device\n");
30262306a36Sopenharmony_ci	    goto err_clk_disable;
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	return 0;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci    err_clk_disable:
30862306a36Sopenharmony_ci	clk_disable_unprepare(clk);
30962306a36Sopenharmony_ci    err_platform_device_put:
31062306a36Sopenharmony_ci	platform_device_put(musb);
31162306a36Sopenharmony_ci	return ret;
31262306a36Sopenharmony_ci    }
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ciThis is the last part of the device registration process where the glue
31562306a36Sopenharmony_cilayer adds the controller hardware device to Linux kernel device
31662306a36Sopenharmony_cihierarchy: at this stage, all known information about the device is
31762306a36Sopenharmony_cipassed on to the Linux USB core stack:
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci   .. code-block:: c
32062306a36Sopenharmony_ci    :emphasize-lines: 5,6
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci    static int jz4740_remove(struct platform_device *pdev)
32362306a36Sopenharmony_ci    {
32462306a36Sopenharmony_ci	struct jz4740_glue  *glue = platform_get_drvdata(pdev);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	platform_device_unregister(glue->musb);
32762306a36Sopenharmony_ci	clk_disable_unprepare(glue->clk);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	return 0;
33062306a36Sopenharmony_ci    }
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ciActing as the counterpart of probe, the remove function unregister the
33362306a36Sopenharmony_ciMUSB controller hardware (line 5) and disable the clock (line 6),
33462306a36Sopenharmony_ciallowing it to be gated.
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci.. _musb-handling-irqs:
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ciHandling IRQs
33962306a36Sopenharmony_ci=============
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ciAdditionally to the MUSB controller hardware basic setup and
34262306a36Sopenharmony_ciregistration, the glue layer is also responsible for handling the IRQs:
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci   .. code-block:: c
34562306a36Sopenharmony_ci    :emphasize-lines: 7,9-11,14,24
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci    static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci)
34862306a36Sopenharmony_ci    {
34962306a36Sopenharmony_ci	unsigned long   flags;
35062306a36Sopenharmony_ci	irqreturn_t     retval = IRQ_NONE;
35162306a36Sopenharmony_ci	struct musb     *musb = __hci;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	spin_lock_irqsave(&musb->lock, flags);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
35662306a36Sopenharmony_ci	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
35762306a36Sopenharmony_ci	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	/*
36062306a36Sopenharmony_ci	 * The controller is gadget only, the state of the host mode IRQ bits is
36162306a36Sopenharmony_ci	 * undefined. Mask them to make sure that the musb driver core will
36262306a36Sopenharmony_ci	 * never see them set
36362306a36Sopenharmony_ci	 */
36462306a36Sopenharmony_ci	musb->int_usb &= MUSB_INTR_SUSPEND | MUSB_INTR_RESUME |
36562306a36Sopenharmony_ci	    MUSB_INTR_RESET | MUSB_INTR_SOF;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	if (musb->int_usb || musb->int_tx || musb->int_rx)
36862306a36Sopenharmony_ci	    retval = musb_interrupt(musb);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	spin_unlock_irqrestore(&musb->lock, flags);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	return retval;
37362306a36Sopenharmony_ci    }
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ciHere the glue layer mostly has to read the relevant hardware registers
37662306a36Sopenharmony_ciand pass their values on to the controller driver which will handle the
37762306a36Sopenharmony_ciactual event that triggered the IRQ.
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ciThe interrupt handler critical section is protected by the
38062306a36Sopenharmony_ci:c:func:`spin_lock_irqsave` and counterpart :c:func:`spin_unlock_irqrestore`
38162306a36Sopenharmony_cifunctions (line 7 and 24 respectively), which prevent the interrupt
38262306a36Sopenharmony_cihandler code to be run by two different threads at the same time.
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ciThen the relevant interrupt registers are read (line 9 to 11):
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci-  ``MUSB_INTRUSB``: indicates which USB interrupts are currently active,
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci-  ``MUSB_INTRTX``: indicates which of the interrupts for TX endpoints are
38962306a36Sopenharmony_ci   currently active,
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci-  ``MUSB_INTRRX``: indicates which of the interrupts for TX endpoints are
39262306a36Sopenharmony_ci   currently active.
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ciNote that :c:func:`musb_readb` is used to read 8-bit registers at most, while
39562306a36Sopenharmony_ci:c:func:`musb_readw` allows us to read at most 16-bit registers. There are
39662306a36Sopenharmony_ciother functions that can be used depending on the size of your device
39762306a36Sopenharmony_ciregisters. See ``musb_io.h`` for more information.
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ciInstruction on line 18 is another quirk specific to the JZ4740 USB
40062306a36Sopenharmony_cidevice controller, which will be discussed later in :ref:`musb-dev-quirks`.
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ciThe glue layer still needs to register the IRQ handler though. Remember
40362306a36Sopenharmony_cithe instruction on line 14 of the init function::
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci    static int jz4740_musb_init(struct musb *musb)
40662306a36Sopenharmony_ci    {
40762306a36Sopenharmony_ci	musb->isr = jz4740_musb_interrupt;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	return 0;
41062306a36Sopenharmony_ci    }
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ciThis instruction sets a pointer to the glue layer IRQ handler function,
41362306a36Sopenharmony_ciin order for the controller hardware to call the handler back when an
41462306a36Sopenharmony_ciIRQ comes from the controller hardware. The interrupt handler is now
41562306a36Sopenharmony_ciimplemented and registered.
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci.. _musb-dev-platform-data:
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ciDevice Platform Data
42062306a36Sopenharmony_ci====================
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ciIn order to write an MUSB glue layer, you need to have some data
42362306a36Sopenharmony_cidescribing the hardware capabilities of your controller hardware, which
42462306a36Sopenharmony_ciis called the platform data.
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ciPlatform data is specific to your hardware, though it may cover a broad
42762306a36Sopenharmony_cirange of devices, and is generally found somewhere in the ``arch/``
42862306a36Sopenharmony_cidirectory, depending on your device architecture.
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ciFor instance, platform data for the JZ4740 SoC is found in
43162306a36Sopenharmony_ci``arch/mips/jz4740/platform.c``. In the ``platform.c`` file each device of the
43262306a36Sopenharmony_ciJZ4740 SoC is described through a set of structures.
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ciHere is the part of ``arch/mips/jz4740/platform.c`` that covers the USB
43562306a36Sopenharmony_ciDevice Controller (UDC):
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci   .. code-block:: c
43862306a36Sopenharmony_ci    :emphasize-lines: 2,7,14-17,21,22,25,26,28,29
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci    /* USB Device Controller */
44162306a36Sopenharmony_ci    struct platform_device jz4740_udc_xceiv_device = {
44262306a36Sopenharmony_ci	.name = "usb_phy_gen_xceiv",
44362306a36Sopenharmony_ci	.id   = 0,
44462306a36Sopenharmony_ci    };
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci    static struct resource jz4740_udc_resources[] = {
44762306a36Sopenharmony_ci	[0] = {
44862306a36Sopenharmony_ci	    .start = JZ4740_UDC_BASE_ADDR,
44962306a36Sopenharmony_ci	    .end   = JZ4740_UDC_BASE_ADDR + 0x10000 - 1,
45062306a36Sopenharmony_ci	    .flags = IORESOURCE_MEM,
45162306a36Sopenharmony_ci	},
45262306a36Sopenharmony_ci	[1] = {
45362306a36Sopenharmony_ci	    .start = JZ4740_IRQ_UDC,
45462306a36Sopenharmony_ci	    .end   = JZ4740_IRQ_UDC,
45562306a36Sopenharmony_ci	    .flags = IORESOURCE_IRQ,
45662306a36Sopenharmony_ci	    .name  = "mc",
45762306a36Sopenharmony_ci	},
45862306a36Sopenharmony_ci    };
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci    struct platform_device jz4740_udc_device = {
46162306a36Sopenharmony_ci	.name = "musb-jz4740",
46262306a36Sopenharmony_ci	.id   = -1,
46362306a36Sopenharmony_ci	.dev  = {
46462306a36Sopenharmony_ci	    .dma_mask          = &jz4740_udc_device.dev.coherent_dma_mask,
46562306a36Sopenharmony_ci	    .coherent_dma_mask = DMA_BIT_MASK(32),
46662306a36Sopenharmony_ci	},
46762306a36Sopenharmony_ci	.num_resources = ARRAY_SIZE(jz4740_udc_resources),
46862306a36Sopenharmony_ci	.resource      = jz4740_udc_resources,
46962306a36Sopenharmony_ci    };
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ciThe ``jz4740_udc_xceiv_device`` platform device structure (line 2)
47262306a36Sopenharmony_cidescribes the UDC transceiver with a name and id number.
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ciAt the time of this writing, note that ``usb_phy_gen_xceiv`` is the
47562306a36Sopenharmony_cispecific name to be used for all transceivers that are either built-in
47662306a36Sopenharmony_ciwith reference USB IP or autonomous and doesn't require any PHY
47762306a36Sopenharmony_ciprogramming. You will need to set ``CONFIG_NOP_USB_XCEIV=y`` in the
47862306a36Sopenharmony_cikernel configuration to make use of the corresponding transceiver
47962306a36Sopenharmony_cidriver. The id field could be set to -1 (equivalent to
48062306a36Sopenharmony_ci``PLATFORM_DEVID_NONE``), -2 (equivalent to ``PLATFORM_DEVID_AUTO``) or
48162306a36Sopenharmony_cistart with 0 for the first device of this kind if we want a specific id
48262306a36Sopenharmony_cinumber.
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ciThe ``jz4740_udc_resources`` resource structure (line 7) defines the UDC
48562306a36Sopenharmony_ciregisters base addresses.
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ciThe first array (line 9 to 11) defines the UDC registers base memory
48862306a36Sopenharmony_ciaddresses: start points to the first register memory address, end points
48962306a36Sopenharmony_cito the last register memory address and the flags member defines the
49062306a36Sopenharmony_citype of resource we are dealing with. So ``IORESOURCE_MEM`` is used to
49162306a36Sopenharmony_cidefine the registers memory addresses. The second array (line 14 to 17)
49262306a36Sopenharmony_cidefines the UDC IRQ registers addresses. Since there is only one IRQ
49362306a36Sopenharmony_ciregister available for the JZ4740 UDC, start and end point at the same
49462306a36Sopenharmony_ciaddress. The ``IORESOURCE_IRQ`` flag tells that we are dealing with IRQ
49562306a36Sopenharmony_ciresources, and the name ``mc`` is in fact hard-coded in the MUSB core in
49662306a36Sopenharmony_ciorder for the controller driver to retrieve this IRQ resource by
49762306a36Sopenharmony_ciquerying it by its name.
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ciFinally, the ``jz4740_udc_device`` platform device structure (line 21)
50062306a36Sopenharmony_cidescribes the UDC itself.
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ciThe ``musb-jz4740`` name (line 22) defines the MUSB driver that is used
50362306a36Sopenharmony_cifor this device; remember this is in fact the name that we used in the
50462306a36Sopenharmony_ci``jz4740_driver`` platform driver structure in :ref:`musb-basics`.
50562306a36Sopenharmony_ciThe id field (line 23) is set to -1 (equivalent to ``PLATFORM_DEVID_NONE``)
50662306a36Sopenharmony_cisince we do not need an id for the device: the MUSB controller driver was
50762306a36Sopenharmony_cialready set to allocate an automatic id in :ref:`musb-basics`. In the dev field
50862306a36Sopenharmony_ciwe care for DMA related information here. The ``dma_mask`` field (line 25)
50962306a36Sopenharmony_cidefines the width of the DMA mask that is going to be used, and
51062306a36Sopenharmony_ci``coherent_dma_mask`` (line 26) has the same purpose but for the
51162306a36Sopenharmony_ci``alloc_coherent`` DMA mappings: in both cases we are using a 32 bits mask.
51262306a36Sopenharmony_ciThen the resource field (line 29) is simply a pointer to the resource
51362306a36Sopenharmony_cistructure defined before, while the ``num_resources`` field (line 28) keeps
51462306a36Sopenharmony_citrack of the number of arrays defined in the resource structure (in this
51562306a36Sopenharmony_cicase there were two resource arrays defined before).
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ciWith this quick overview of the UDC platform data at the ``arch/`` level now
51862306a36Sopenharmony_cidone, let's get back to the MUSB glue layer specific platform data in
51962306a36Sopenharmony_ci``drivers/usb/musb/jz4740.c``:
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci   .. code-block:: c
52262306a36Sopenharmony_ci    :emphasize-lines: 3,5,7-9,11
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci    static struct musb_hdrc_config jz4740_musb_config = {
52562306a36Sopenharmony_ci	/* Silicon does not implement USB OTG. */
52662306a36Sopenharmony_ci	.multipoint = 0,
52762306a36Sopenharmony_ci	/* Max EPs scanned, driver will decide which EP can be used. */
52862306a36Sopenharmony_ci	.num_eps    = 4,
52962306a36Sopenharmony_ci	/* RAMbits needed to configure EPs from table */
53062306a36Sopenharmony_ci	.ram_bits   = 9,
53162306a36Sopenharmony_ci	.fifo_cfg = jz4740_musb_fifo_cfg,
53262306a36Sopenharmony_ci	.fifo_cfg_size = ARRAY_SIZE(jz4740_musb_fifo_cfg),
53362306a36Sopenharmony_ci    };
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci    static struct musb_hdrc_platform_data jz4740_musb_platform_data = {
53662306a36Sopenharmony_ci	.mode   = MUSB_PERIPHERAL,
53762306a36Sopenharmony_ci	.config = &jz4740_musb_config,
53862306a36Sopenharmony_ci    };
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ciFirst the glue layer configures some aspects of the controller driver
54162306a36Sopenharmony_cioperation related to the controller hardware specifics. This is done
54262306a36Sopenharmony_cithrough the ``jz4740_musb_config`` :c:type:`musb_hdrc_config` structure.
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ciDefining the OTG capability of the controller hardware, the multipoint
54562306a36Sopenharmony_cimember (line 3) is set to 0 (equivalent to false) since the JZ4740 UDC
54662306a36Sopenharmony_ciis not OTG compatible. Then ``num_eps`` (line 5) defines the number of USB
54762306a36Sopenharmony_ciendpoints of the controller hardware, including endpoint 0: here we have
54862306a36Sopenharmony_ci3 endpoints + endpoint 0. Next is ``ram_bits`` (line 7) which is the width
54962306a36Sopenharmony_ciof the RAM address bus for the MUSB controller hardware. This
55062306a36Sopenharmony_ciinformation is needed when the controller driver cannot automatically
55162306a36Sopenharmony_ciconfigure endpoints by reading the relevant controller hardware
55262306a36Sopenharmony_ciregisters. This issue will be discussed when we get to device quirks in
55362306a36Sopenharmony_ci:ref:`musb-dev-quirks`. Last two fields (line 8 and 9) are also
55462306a36Sopenharmony_ciabout device quirks: ``fifo_cfg`` points to the USB endpoints configuration
55562306a36Sopenharmony_citable and ``fifo_cfg_size`` keeps track of the size of the number of
55662306a36Sopenharmony_cientries in that configuration table. More on that later in
55762306a36Sopenharmony_ci:ref:`musb-dev-quirks`.
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ciThen this configuration is embedded inside ``jz4740_musb_platform_data``
56062306a36Sopenharmony_ci:c:type:`musb_hdrc_platform_data` structure (line 11): config is a pointer to
56162306a36Sopenharmony_cithe configuration structure itself, and mode tells the controller driver
56262306a36Sopenharmony_ciif the controller hardware may be used as ``MUSB_HOST`` only,
56362306a36Sopenharmony_ci``MUSB_PERIPHERAL`` only or ``MUSB_OTG`` which is a dual mode.
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ciRemember that ``jz4740_musb_platform_data`` is then used to convey
56662306a36Sopenharmony_ciplatform data information as we have seen in the probe function in
56762306a36Sopenharmony_ci:ref:`musb-basics`.
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci.. _musb-dev-quirks:
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ciDevice Quirks
57262306a36Sopenharmony_ci=============
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ciCompleting the platform data specific to your device, you may also need
57562306a36Sopenharmony_cito write some code in the glue layer to work around some device specific
57662306a36Sopenharmony_cilimitations. These quirks may be due to some hardware bugs, or simply be
57762306a36Sopenharmony_cithe result of an incomplete implementation of the USB On-the-Go
57862306a36Sopenharmony_cispecification.
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ciThe JZ4740 UDC exhibits such quirks, some of which we will discuss here
58162306a36Sopenharmony_cifor the sake of insight even though these might not be found in the
58262306a36Sopenharmony_cicontroller hardware you are working on.
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ciLet's get back to the init function first:
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci   .. code-block:: c
58762306a36Sopenharmony_ci    :emphasize-lines: 12
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci    static int jz4740_musb_init(struct musb *musb)
59062306a36Sopenharmony_ci    {
59162306a36Sopenharmony_ci	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
59262306a36Sopenharmony_ci	if (!musb->xceiv) {
59362306a36Sopenharmony_ci	    pr_err("HS UDC: no transceiver configured\n");
59462306a36Sopenharmony_ci	    return -ENODEV;
59562306a36Sopenharmony_ci	}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	/* Silicon does not implement ConfigData register.
59862306a36Sopenharmony_ci	 * Set dyn_fifo to avoid reading EP config from hardware.
59962306a36Sopenharmony_ci	 */
60062306a36Sopenharmony_ci	musb->dyn_fifo = true;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	musb->isr = jz4740_musb_interrupt;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	return 0;
60562306a36Sopenharmony_ci    }
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ciInstruction on line 12 helps the MUSB controller driver to work around
60862306a36Sopenharmony_cithe fact that the controller hardware is missing registers that are used
60962306a36Sopenharmony_cifor USB endpoints configuration.
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ciWithout these registers, the controller driver is unable to read the
61262306a36Sopenharmony_ciendpoints configuration from the hardware, so we use line 12 instruction
61362306a36Sopenharmony_cito bypass reading the configuration from silicon, and rely on a
61462306a36Sopenharmony_cihard-coded table that describes the endpoints configuration instead::
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci    static struct musb_fifo_cfg jz4740_musb_fifo_cfg[] = {
61762306a36Sopenharmony_ci	{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
61862306a36Sopenharmony_ci	{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
61962306a36Sopenharmony_ci	{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 64, },
62062306a36Sopenharmony_ci    };
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ciLooking at the configuration table above, we see that each endpoints is
62362306a36Sopenharmony_cidescribed by three fields: ``hw_ep_num`` is the endpoint number, style is
62462306a36Sopenharmony_ciits direction (either ``FIFO_TX`` for the controller driver to send packets
62562306a36Sopenharmony_ciin the controller hardware, or ``FIFO_RX`` to receive packets from
62662306a36Sopenharmony_cihardware), and maxpacket defines the maximum size of each data packet
62762306a36Sopenharmony_cithat can be transmitted over that endpoint. Reading from the table, the
62862306a36Sopenharmony_cicontroller driver knows that endpoint 1 can be used to send and receive
62962306a36Sopenharmony_ciUSB data packets of 512 bytes at once (this is in fact a bulk in/out
63062306a36Sopenharmony_ciendpoint), and endpoint 2 can be used to send data packets of 64 bytes
63162306a36Sopenharmony_ciat once (this is in fact an interrupt endpoint).
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ciNote that there is no information about endpoint 0 here: that one is
63462306a36Sopenharmony_ciimplemented by default in every silicon design, with a predefined
63562306a36Sopenharmony_ciconfiguration according to the USB specification. For more examples of
63662306a36Sopenharmony_ciendpoint configuration tables, see ``musb_core.c``.
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ciLet's now get back to the interrupt handler function:
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci   .. code-block:: c
64162306a36Sopenharmony_ci    :emphasize-lines: 18-19
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci    static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci)
64462306a36Sopenharmony_ci    {
64562306a36Sopenharmony_ci	unsigned long   flags;
64662306a36Sopenharmony_ci	irqreturn_t     retval = IRQ_NONE;
64762306a36Sopenharmony_ci	struct musb     *musb = __hci;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	spin_lock_irqsave(&musb->lock, flags);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
65262306a36Sopenharmony_ci	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
65362306a36Sopenharmony_ci	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	/*
65662306a36Sopenharmony_ci	 * The controller is gadget only, the state of the host mode IRQ bits is
65762306a36Sopenharmony_ci	 * undefined. Mask them to make sure that the musb driver core will
65862306a36Sopenharmony_ci	 * never see them set
65962306a36Sopenharmony_ci	 */
66062306a36Sopenharmony_ci	musb->int_usb &= MUSB_INTR_SUSPEND | MUSB_INTR_RESUME |
66162306a36Sopenharmony_ci	    MUSB_INTR_RESET | MUSB_INTR_SOF;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	if (musb->int_usb || musb->int_tx || musb->int_rx)
66462306a36Sopenharmony_ci	    retval = musb_interrupt(musb);
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	spin_unlock_irqrestore(&musb->lock, flags);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	return retval;
66962306a36Sopenharmony_ci    }
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ciInstruction on line 18 above is a way for the controller driver to work
67262306a36Sopenharmony_ciaround the fact that some interrupt bits used for USB host mode
67362306a36Sopenharmony_cioperation are missing in the ``MUSB_INTRUSB`` register, thus left in an
67462306a36Sopenharmony_ciundefined hardware state, since this MUSB controller hardware is used in
67562306a36Sopenharmony_ciperipheral mode only. As a consequence, the glue layer masks these
67662306a36Sopenharmony_cimissing bits out to avoid parasite interrupts by doing a logical AND
67762306a36Sopenharmony_cioperation between the value read from ``MUSB_INTRUSB`` and the bits that
67862306a36Sopenharmony_ciare actually implemented in the register.
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ciThese are only a couple of the quirks found in the JZ4740 USB device
68162306a36Sopenharmony_cicontroller. Some others were directly addressed in the MUSB core since
68262306a36Sopenharmony_cithe fixes were generic enough to provide a better handling of the issues
68362306a36Sopenharmony_cifor others controller hardware eventually.
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ciConclusion
68662306a36Sopenharmony_ci==========
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ciWriting a Linux MUSB glue layer should be a more accessible task, as
68962306a36Sopenharmony_cithis documentation tries to show the ins and outs of this exercise.
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ciThe JZ4740 USB device controller being fairly simple, I hope its glue
69262306a36Sopenharmony_cilayer serves as a good example for the curious mind. Used with the
69362306a36Sopenharmony_cicurrent MUSB glue layers, this documentation should provide enough
69462306a36Sopenharmony_ciguidance to get started; should anything gets out of hand, the linux-usb
69562306a36Sopenharmony_cimailing list archive is another helpful resource to browse through.
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ciAcknowledgements
69862306a36Sopenharmony_ci================
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ciMany thanks to Lars-Peter Clausen and Maarten ter Huurne for answering
70162306a36Sopenharmony_cimy questions while I was writing the JZ4740 glue layer and for helping
70262306a36Sopenharmony_cime out getting the code in good shape.
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ciI would also like to thank the Qi-Hardware community at large for its
70562306a36Sopenharmony_cicheerful guidance and support.
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ciResources
70862306a36Sopenharmony_ci=========
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ciUSB Home Page: https://www.usb.org
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_cilinux-usb Mailing List Archives: https://marc.info/?l=linux-usb
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ciUSB On-the-Go Basics:
71562306a36Sopenharmony_cihttps://www.maximintegrated.com/app-notes/index.mvp/id/1822
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci:ref:`Writing USB Device Drivers <writing-usb-driver>`
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ciTexas Instruments USB Configuration Wiki Page:
72062306a36Sopenharmony_cihttp://processors.wiki.ti.com/index.php/Usbgeneralpage
721