Author: David Brownell
Last Modified:
1 September 2004
The new USB "On-The-Go" (OTG) capabilities are not yet widely understood, or even generally available. The most visible feature of OTG is that it defines the behavior of intelligent "Dual-Role" USB devices, such as cameras or wireless handsets, which act either as USB host or as USB peripheral. That role choice is made each time the device is used, rather than once when it's designed, giving a flexibility previously unknown with USB. Using a new kind of USB connector, OTG lets USB support more "peer to peer" style application models. You could
This document should be useful to developers investigating the use of Linux to implement OTG-capable products. It presents the USB OTG support contributed by Texas Instruments for the OMAP H2 software development platform running an Linux 2.6 kernel. That builds on the standard Linux USB host and peripheral side driver frameworks, making small additions as described here. It also includes drivers implementing OTG support on OMAP platforms.
The H2 software development platform includes a Texas Instruments OMAP 5912/16xx series processor, with an ARM 926TEJ cpu, a DSP, battery power management, and a wealth of other features often used in cell phones. USB support includes:
The "Mini-AB" connector is compatible with standard USB 2.0 "Mini-B" connectors, which appear in some new USB peripherals.
Most OMAP processors support this and similar product designs. Register interfaces to the different USB controllers are largely source-compatible, although older chips don't support OTG.
It's reasonable to think about OTG support as revolving around that "Mini-AB" connector, since that's what demands the highly visible "dual-role" capability implemented by the OTG drivers. OTG uses two methods to chose device role:
That dynamic role selection is the most procedurally visible aspect of OTG, but there's more to OTG than that; see the OTG specification (and errata). The primary target of OTG is battery powered devices, so several aspects of the specification support reduced power usage. These include a new Session Request Protocol (SRP), which may be supported even by single-role USB devices.
To someone providing hardware-level drivers, an OTG solution starts with support for the standard Linux-USB host side and peripheral side driver stacks. Add protocol support for SRP and HNP, match the state machines in the OTG specification well enough to pass OTG hardware and software compliance testing, and then your product can use the OTG logo.
USB OTG Logo full-speed version |
The current Linux kernel updates for OTG support break down as follows:
These points are addressed in the rest of this document, in that same order.
It was a goal to keep these interface changes small, and to have them be useful outside of OTG support where possible. That way the new code paths can get better testing, rather than being used only for (currently uncommon) OTG devices.
In particular, this doesn't change the existing programming models or calls for host side USB (still uses urb and usb_device) or for peripheral side USB (still uses usb_request and usb_gadget). At some point it might become desirable to move away from "URB" to a lighter weight model like "usb_request", and maybe to a more symmetric programming interface; but that's not necessary at this time.
Several OTG state flags, and a few new usb_gadget_*() calls, are all the changes needed in the gadget programming interfaces. The flags support user interface reporting requirements for OTG devices, and the calls support new USB state transitions (some of which are also useful for non-OTG systems). Except for the flag reporting whether the gadget is_otg, the state flags are current only when the gadget driver could participate in HNP: after it receives the SET_CONFIGURATION request, or before it suspends. In addition, if HNP is ever enabled, it can't be disabled without re-enumerating the device.
struct usb_gadget { ... unsigned is_otg:1; unsigned is_a_peripheral:1; unsigned b_hnp_enable:1; unsigned a_hnp_support:1; unsigned a_alt_hnp_support:1; ... }; /* used by external USB transceiver */ int usb_gadget_vbus_connect(struct usb_gadget *gadget); int usb_gadget_vbus_disconnect(struct usb_gadget *gadget); /* call this during SET_CONFIGURATION */ int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA); /* these logically control the USB D+ pullup */ int usb_gadget_connect(struct usb_gadget *gadget); int usb_gadget_disconnect(struct usb_gadget *gadget); |
In addition, usb_gadget_wakeup() is now defined as the way SRP may be invoked. If the device is in a USB suspend state, remote wakeup is used (and OTG peripherals don't always need hosts to enable wakeup). If there's no VBUS power, SRP may be used instead.
There's kerneldoc for all of those, and many of the symbols have the same meaning as in the OTG specification. For example, b_hnp_enable is the device feature flag that may be set by the USB A-Host; if it's set, the B-Peripheral device may be well into an HNP-driven role switch when suspend() is called.
To see how those are used in drivers, see the small changes to Gadget Zero which, using omap_udc, were sufficient to pass the USBCV OTG tests. All USB gadget drivers that will be used on OTG-capable hardware should have corresponding changes; at this writing, some of the gadget drivers still haven't been modified to know about OTG.
This framework is currently not set up to handle the SRP-only subset of OTG; that would need another gadget flag. Also, so far there's no gadgetfs support for OTG: OTG feature flags aren't exported to user mode drivers, though user mode drivers can certainly provide OTG descriptors if they know (out of band) that they're appropriate.
There are several updates that affect host side support for OTG dual-role devices.
USB enumeration (khubd and usb_new_device) needed updates:
So that the updated enumeration code can set OTG device features appropriately, the usb_bus interface reports which port has the Mini-AB connector. It also provides more visibility of key HNP protocol state, reporting if this is a B-Host rather than an A-Host (so that it shouldn't set OTG device features during enumeration); and whether the A-Host has set b_hnp_enable on the B-Peripheral (needed by OTG controllers and drivers). (This information is not currently visible in sysfs.)
struct usb_bus { ... u8 otg_port; /* 0, or index of OTG/HNP port */ unsigned is_b_host:1; /* true during some HNP roleswitches */ unsigned b_hnp_enable:1; /* OTG: did A-Host enable HNP? */ ... }; |
The CONFIG_USB_SUSPEND patch adds generic experimental support for USB suspend/resume to Linux, as needed to implement HNP.
/* selective suspend/resume */ extern int usb_suspend_device(struct usb_device *dev, u32 state); extern int usb_resume_device(struct usb_device *dev); |
Normal device-specific suspend processing may be triggered by calling usb_suspend_device(), either directly or by updating the sysfs power/state attribute. That involves suspending the driver for each active interface before suspending the device. When the device is a USB hub, any child devices are suspended as part of suspending the hub's interface. When HNP is not enabled, that's all that happens.
When HNP is enabled, suspend also triggers a role switch between the two linked devices. The A-Host becomes A-Peripheral; or the B-Host returns to being a B-peripheral. The host's root hub tells the OTG controller to talk HNP, through some implementation specific mechanism such as the otg_transceiver interface presented later.
Linux 2.6 power management still has a number of issues. Most of the work in that area is addressing system suspend issues, although some APIs do support the per-device suspend operations. Those device power management APIs have problems though, including: the presence of more than one "legacy" power management framework, lack of APIs to perform bottom-up suspend (or top-town resume) of a proper subtree of the new 2.6 driver model tree, ease of self-deadlocking the PM core, and more. (For example, in USB these power management operations need to interact with other concurrent operations; locking in usbcore is an ongoing issue.)
Since OTG products will normally be battery powered, and will need to aggressively leverage per-device suspend modes to extend battery life, this area needs much more work. (This is a general issue, not limited to OTG or USB.)
At this writing, usbcore has the notion of a hub power budget, and the hub driver will warn if the power budget for a hub port is exceeded, but it will try to continue. Root hubs can specify their power budget, such as the minimum 8mA for the OTG root port. Host side SRP support is not currently visible to usbcore, but the lower level OTG controllers handle it nonetheless. This means that the hub driver doesn't have a fully accurate view of the power status of the OTG port; it's not yet controlled through root hub operations. This may eventually need to be fixed, making the hub driver be SRP-aware.
No host side USB device drivers have yet been modified for OTG support in the 2.6.8 kernel. Drivers intended for use with "targeted" peripherals should be modified to behave with USB suspend, which will trigger either HNP or power savings (or both). At the moment, few USB device drivers implement the callbacks used for USB suspend processing. Eventually that shouldn't be a problem, but currently it often is one.
Also, something should suspend devices that aren't in active use. Some drivers could self-suspend, others might work better if signaled through sysfs power/state writes.
Each OTG product will customize "otg_whitelist.h" so it includes the Targeted Peripherals List to match its supported product interoperability goals.
In Linux 2.4 versions of H2 board support, both the OHCI and UDC drivers had private "mini-drivers" to talk to the isp1301 chip and initialize OMAP USB registers. That meant only one role (host or peripheral) could be active, and also that lots of board-specific (and chip-specific) information was mixed into the controller drivers.
Linux 2.6 support, to also support the OTG controller, needed get rid of those private mini-drivers. The USB drivers now interact with each other through abstract interfaces, so that it's easier to change the implementations to work with a new board. One of those interfaces is OMAP-specific: omap_usb_config, used to set up the right board-specific pin multiplexing and controller mode, and report that setup to USB drivers. The other interface is relatively generic: otg_transceiver, used to coordinate the different drivers.
Also, an omap_udc driver was written, using the "USB Gadget" framework to expose essentially all functionality of this USB peripheral controller. This driver is significantly more functional than the previous one (on Linux 2.4), which used a non-gadget driver framework.
This initialization now uses Linux 2.6 board-specific MACHINE_INIT hooks to set up the right pin multiplexing and controller setup. On 2.4 kernels, analogous board-specific logic was part of each controller driver; Linux 2.6 makes it easy to keep such code out of drivers, and group it with other board-specific initialization. The initialization is now done in arch/arm/mach-omap/usb.c, creating the platform devices used by USB. It's driven by passing a board-specific struct omap_usb_info to the initialization logic, which creates the relevant platform devices and passes that configuration/wiring information to the drivers that need it using platform_data.
Contents of this structure should be easy to define with the aid of board schematics and chip specifications, although there might be more than one HMC mode to choose from (mapping USB ports to pin groups and controllers). Some board-aware bootloader will provide this information; simple board revisions can trigger substantial behavior changes. For example, that information might say the board is wired:
Hundreds of potential board configurations are encapsulated in that board-specific descriptor, following options that are extensively described in the relevant OMAP processor technical reference manual. This platform_data setup should handle the kinds of options designed into current OMAP chips and boards. If not, it's easy to change (at least the non-bootloader portions), and most of the changes should stay out of the controller drivers.
On H2, the OTG controller integrates two major logical parts: an external Philips ISP1301 OTG transceiver, and OTG controller silicon on the OMAP chip. On other OTG systems, a different transceiver might be used; or the internal transceiver might be used for some tasks. The OTG controller could also change. Such implementation choices are abstracted using an otg_transceiver interface, so that the implementation behind that interface can change without forcing changes to the OHCI or UDC drivers.
Testing this involves the USB "OTG Protocol Tester" (OPT), a programmable Windows-based test harness. At this writing, the Linux-OMAP implementation passes essentially all of these software compliance tests.
Only developers interacting directly with USB controller hardware should need to know about this interface, and it's expected to be in flux for a while. No interface is "generic enough" until it's got at least three very implementations, but isp1301_omap currently has no sibling OTG implementations. Its members currently include:
// from <linux/usb_otg.h> struct otg_transceiver { struct device *dev; const char *label; u8 default_a; enum usb_otg_state state; struct usb_bus *host; struct usb_gadget *gadget; /* to pass extra port status to the root hub */ u16 port_status; u16 port_change; /* bind/unbind the host controller */ int (*set_host)(struct otg_transceiver *otg, struct usb_bus *host); /* bind/unbind the peripheral controller */ int (*set_peripheral)(struct otg_transceiver *otg, struct usb_gadget *gadget); /* effective for B devices, ignored for A-peripheral */ int (*set_power)(struct otg_transceiver *otg, unsigned mA); /* for B devices only: start session with A-Host */ int (*start_srp)(struct otg_transceiver *otg); /* start or continue HNP role switch */ int (*start_hnp)(struct otg_transceiver *otg); }; |
The enum usb_otg_state is one of about a dozen states described in the USB OTG 1.0a specification, most of which will be invisible to USB Device or Gadget drivers because they are enumeration states which appear before USB reset. Those are also defined in <linux/usb_otg.h>, along with inlined functions to invoke each of the methods on the transceiver.
When an A-Host puts an OTG device into a configuration, that device may use the specified amount of current for any purpose, such as battery charging or normal operation; that information is passed through the gadget driver to the OTG transceiver driver using the set_power method.
This OTG driver needs to know the two USB controllers (host, gadget) it's working with, since it needs to be able to activate one of them at a time. It's also responsible for initializing the usb_bus.is_b_host and usb_gadget.is_a_peripheral flags, making HNP-switched roles visible to drivers that may need to report them through user interface code.
A new drivers/i2c/chips/isp1301_omap.c driver was written, implementing the otg_transceiver API. This driver holds the core of the OTG protocol support, but it also supports simplified host-only and peripheral-only modes. On H2 and similar platforms, as part of implementing the full otg_transceiver interface, this driver can also talk to the driver for the TPS65010 chip, controlling how much current to draw from USB VBUS (from 0-500mA) for recharging the battery.
To support OTG, the isp1301 driver needs to be very tightly coupled to the OMAP OTG controller; it's OMAP-specific, and needs some board-specific knowledge. The basic structure of this driver is a work queue entry (currently using keventd) taking signal comparator state from the ISP1301 chip and feeding it to the OMAP OTG controller, or going the other way and feeding controller commands from the OMAP OTG controller to the ISP1301. The driver watches the information it feeds back and forth, driven by IRQs from each controller, and detects OTG state machine transitions which call for various actions. Parts of it are timing-sensitive; a deadline-scheduled work queue might be necessary in certain systems. Better yet, this driver would be much improved by being able to issue asynchronous I2C requests from its IRQ handlers. (That's not yet supported by the Linux I2C framework. Asynchronous operation could eliminate CPU scheduling latencies, leaving only lower IRQ and bus access latencies.)
In order to meet HNP protocol timing requirements, OTG controller drivers switching to host mode during HNP need to start resetting the OTG port within a millisecond of device connect. That probably means it starts in an IRQ handler; khubd will start handling the rest of enumeration in a few tens of milliseconds. Such drivers can use this routine, passing bus->otg_port:
int usb_bus_start_enum(struct usb_bus *root, unsigned port_num); |
OHCI has a generic implementation of that, which also knows to re-issue reset signaling to make sure the reset lasts long enough.
The drivers/usb/gadget/omap_udc.c driver can support dozens of full speed USB endpoints, and works with all USB transfer types. The hardware seems pleasantly free of quirks that would affect its ability to properly support composite or multi-configuration devices. The structure of the driver for this UDC is like other recent gadget-framework UDC drivers. OTG support involves only a few new OTG-specific features beyond registering with the OTG controller driver.
A few things of interest came up during the implementation:
The drivers/usb/host/ohci-omap.c driver needed few changes specifically for OTG support. The port reset changes described earlier were also needed, but those changes were not OMAP-specific.
Some important OHCI changes were merged earlier, with Linux 2.6.6 patches. These included OHCI power management changes which made the OHCI driver suspend the controller's root hub when it's not in use, and more carefully manage schedule re-activation. That code was previously PCI-specific, and is now abstract enough to easily re-use on non-PCI systems, like OMAP. When added to the the CONFIG_USB_SUSPEND patch, this also makes USB Remote Wakeup work with OHCI; both mechanisms are necessary for full HNP support.
It seems like some USB devices may not like being driven with only 8mA of VBUS power, even if the devices themselves are self-powered. One USB 2.0 hub produced some very strange failure modes, which the Linux-USB "usbcore" support is now hardened against. Other USB devices may have similar issues; development of the "targeted peripheral list" might be able to turn up similar issues with other products.
Linux 2.6 supported USB OTG with only minor additions to the driver programming interfaces. It's working now on OMAP hardware. Some device and gadget drivers will need small changes to use those new interfaces, and host side drivers may need more changes to fully support USB suspend/resume. Other power management changes are needed, too. The most complex OTG-specific changes are at the level of USB controller drivers, implementing the new SRP and HNP protocols; they are hidden from normal USB drivers, which never touch hardware directly.
USB and OTG specifications are available at http://www.usb.org/developers/docs/ in PDF form.