Linux USB "On-The-Go" (OTG)

on OMAP H2

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.

OMAP H2 Platform

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.

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

Outline

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.

Programming Interface Updates

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.

Peripheral Side: USB Device Controller

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.

Peripheral Side: Gadget Drivers

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.

Host Side: usbcore

There are several updates that affect host side support for OTG dual-role devices.

OTG Enumeration and the Targeted Peripherals List

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? */
    	...
};

CONFIG_USB_SUSPEND

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.

Other Power Management Issues

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.

Host Side: USB Device Drivers

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.

USB Controller Drivers

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.

OMAP USB Initialization

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.

OTG Controller

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.

struct otg_transceiver

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.

isp1301_omap

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.)

OHCI Port Reset

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.

omap_udc

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.

Probe/release
This uses the board-specific platform_data to determine whether the board provides OTG support, and passes that to the gadget driver using the new is_otg flag. When the board is configured to use an external OTG transceiver, this also finds the OTG controller driver and registers with it.
OTG Device Feature Flags
OMAP hardware manages these; it turns out to be easy to keep them more up-to-date than required, since the UDC issues an interrupt when the host changes a value.
Remote Wakeup calls
These must talk to the OTG controller driver to initiate SRP, when no VBUS session is resumable. These can also be triggered from user mode by writing the sysfs .../power/state file.
VBUS connect/disconnect calls (from the OTG/transceiver driver)
Such external controllers will update the D+ pullup, which conveniently gates the UDC clock to save power whenever there's no host connected. (Useful even for non-OTG systems.)
VBUS draw call (from the gadget driver)
This passes the new usb_gadget_vbus_draw() call right down to any OTG controller it's got, overriding the defaults that apply except for B-peripheral configurations. Boards without an OTG controller might instead talk directly to power management software, such as a TPS65010 driver, instead of delegating this responsibility.
/proc/driver/udc
When debugging, this optional file can be useful since it gives an overview of the whole driver's state, making it easy to notice problems like a blocked I/O queue or other broken state.

A few things of interest came up during the implementation:

ohci_omap

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.

Summary

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.

References

USB and OTG specifications are available at http://www.usb.org/developers/docs/ in PDF form.

  1. Texas Instruments OMAP 5912 has the USB controllers discussed here.
  2. Universal Serial Bus Specification, Revision 2.0
  3. On-The-Go Supplement to the USB 2.0 Specification, Revision 1.0a
  4. OTG Compliance Plan for the USB 2.0 Specification, Revision 1.0
  5. OTG 1.0a errata, January 2004
  6. OpenHCI - Open Host Controller Interface Specification for USB, Revision 1.0a
  7. Philips ISP 1301 (external OTG transceiver)
  8. http://www.muru.com/linux/omap/ (Linux-OMAP info page)