usb: gadget: Add link power management support

Link Power Management (a.k.a. L1) is similar to the existing usb bus
suspend/resume/remote-wakeup, but has transitional latencies of tens
of microseconds between power states (instead of three to greater than
20 millisecond latencies of the USB 2.0 suspend/resume).

Change-Id: I8ae493534702e658c24f384a6b705b08e9ea9d05
Signed-off-by: Shimrit Malichi <smalichi@codeaurora.org>
Signed-off-by: Tarun Gupta <tarung@codeaurora.org>
This commit is contained in:
Shimrit Malichi 2013-06-20 19:04:28 +03:00 committed by David Keitel
parent f67850e9f0
commit 37648e8eb6
2 changed files with 37 additions and 29 deletions

View file

@ -653,7 +653,8 @@ static int bos_desc(struct usb_composite_dev *cdev)
/* /*
* A SuperSpeed device shall include the USB2.0 extension descriptor * A SuperSpeed device shall include the USB2.0 extension descriptor
* and shall support LPM when operating in USB2.0 HS mode. * and shall support LPM when operating in USB2.0 HS mode, as well as
* a HS device when operating in USB2.1 HS mode.
*/ */
usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength); usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
bos->bNumDeviceCaps++; bos->bNumDeviceCaps++;
@ -663,9 +664,10 @@ static int bos_desc(struct usb_composite_dev *cdev)
usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT; usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT); usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT);
if (gadget_is_superspeed(cdev->gadget)) {
/* /*
* The Superspeed USB Capability descriptor shall be implemented by all * The Superspeed USB Capability descriptor shall be
* SuperSpeed devices. * implemented by all SuperSpeed devices.
*/ */
ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength); ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
bos->bNumDeviceCaps++; bos->bNumDeviceCaps++;
@ -682,14 +684,17 @@ static int bos_desc(struct usb_composite_dev *cdev)
/* Get Controller configuration */ /* Get Controller configuration */
if (cdev->gadget->ops->get_config_params) if (cdev->gadget->ops->get_config_params)
cdev->gadget->ops->get_config_params(&dcd_config_params); cdev->gadget->ops->get_config_params
(&dcd_config_params);
else { else {
dcd_config_params.bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT; dcd_config_params.bU1devExitLat =
USB_DEFAULT_U1_DEV_EXIT_LAT;
dcd_config_params.bU2DevExitLat = dcd_config_params.bU2DevExitLat =
cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT); cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
} }
ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat; ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat; ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
}
return le16_to_cpu(bos->wTotalLength); return le16_to_cpu(bos->wTotalLength);
} }
@ -1623,8 +1628,9 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
} else { } else {
cdev->desc.bcdUSB = cpu_to_le16(0x0210); cdev->desc.bcdUSB = cpu_to_le16(0x0210);
} }
} else { } else if (gadget->l1_supported) {
cdev->desc.bcdUSB = cpu_to_le16(0x0200); cdev->desc.bcdUSB = cpu_to_le16(0x0210);
DBG(cdev, "Config HS device with LPM(L1)\n");
} }
value = min(w_length, (u16) sizeof cdev->desc); value = min(w_length, (u16) sizeof cdev->desc);
@ -1655,7 +1661,8 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
value = min(w_length, (u16) value); value = min(w_length, (u16) value);
break; break;
case USB_DT_BOS: case USB_DT_BOS:
if (gadget_is_superspeed(gadget)) { if (gadget_is_superspeed(gadget) ||
gadget->l1_supported) {
value = bos_desc(cdev); value = bos_desc(cdev);
value = min(w_length, (u16) value); value = min(w_length, (u16) value);
} }

View file

@ -647,6 +647,7 @@ struct usb_gadget {
unsigned is_selfpowered:1; unsigned is_selfpowered:1;
unsigned deactivated:1; unsigned deactivated:1;
unsigned connected:1; unsigned connected:1;
bool l1_supported;
}; };
#define work_to_gadget(w) (container_of((w), struct usb_gadget, work)) #define work_to_gadget(w) (container_of((w), struct usb_gadget, work))