874 lines
		
	
	
	
		
			32 KiB
			
		
	
	
	
		
			Cheetah
		
	
	
	
	
	
		
		
			
		
	
	
			874 lines
		
	
	
	
		
			32 KiB
			
		
	
	
	
		
			Cheetah
		
	
	
	
	
	
| 
								 | 
							
								<?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>
							 |