Process device remote wakeup set/clear feature requests and implement wakeup method of usb_gadget_ops. This patch also provides a sysfs file to initiate remote wakeup from user space. Remote wakeup can be generated by poking into /sys/devices/platform/msm_hsusb/gadget/wakeup file. Signed-off-by: Pavankumar Kondeti <pkondeti@xxxxxxxxxxxxxx> Signed-off-by: Vamsi Krishna <vskrishn@xxxxxxxxxxxxxx> --- drivers/usb/gadget/msm72k_udc.c | 57 ++++++++++++++++++++++++++++++++++++++ include/linux/usb/msm_hsusb_hw.h | 3 ++ 2 files changed, 60 insertions(+), 0 deletions(-) diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c index 84315a2..9922d3d 100644 --- a/drivers/usb/gadget/msm72k_udc.c +++ b/drivers/usb/gadget/msm72k_udc.c @@ -167,6 +167,7 @@ struct usb_info { struct clk *pclk; unsigned int ep0_dir; + u8 remote_wakeup; }; static const struct usb_ep_ops msm72k_ep_ops; @@ -585,6 +586,8 @@ static void handle_setup(struct usb_info *ui) u16 temp = 0; temp = 1 << USB_DEVICE_SELF_POWERED; + temp |= (ui->remote_wakeup << + USB_DEVICE_REMOTE_WAKEUP); memcpy(req->buf, &temp, 2); break; } @@ -630,6 +633,16 @@ static void handle_setup(struct usb_info *ui) */ writel((ctl.wValue << 25) | (1 << 24), USB_DEVICEADDR); goto ack; + } else if (ctl.bRequest == USB_REQ_SET_FEATURE) { + switch (ctl.wValue) { + case USB_DEVICE_REMOTE_WAKEUP: + ui->remote_wakeup = 1; + goto ack; + } + } else if ((ctl.bRequest == USB_REQ_CLEAR_FEATURE) && + (ctl.wValue == USB_DEVICE_REMOTE_WAKEUP)) { + ui->remote_wakeup = 0; + goto ack; } } @@ -1538,12 +1551,49 @@ static int msm72k_pullup(struct usb_gadget *_gadget, int is_active) return 0; } +static int msm72k_wakeup(struct usb_gadget *_gadget) +{ + struct usb_info *ui = container_of(_gadget, struct usb_info, gadget); + unsigned long flags; + + if (!ui->remote_wakeup) { + ERROR("%s: remote wakeup not supported\n", __func__); + return -ENOTSUPP; + } + + if (!ui->online) { + ERROR("%s: device is not configured\n", __func__); + return -ENODEV; + } + + spin_lock_irqsave(&ui->lock, flags); + if ((readl(USB_PORTSC) & PORTSC_SUSP) == PORTSC_SUSP) { + INFO("%s: enabling force resume\n", __func__); + writel(readl(USB_PORTSC) | PORTSC_FPR, USB_PORTSC); + } + spin_unlock_irqrestore(&ui->lock, flags); + + return 0; +} + static const struct usb_gadget_ops msm72k_ops = { .get_frame = msm72k_get_frame, .vbus_session = msm72k_udc_vbus_session, .pullup = msm72k_pullup, + .wakeup = msm72k_wakeup, }; +static ssize_t usb_remote_wakeup(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_info *ui = the_usb_info; + + msm72k_wakeup(&ui->gadget); + + return count; +} +static DEVICE_ATTR(wakeup, S_IWUSR, 0, usb_remote_wakeup); + static int msm72k_probe(struct platform_device *pdev) { struct resource *res; @@ -1673,6 +1723,12 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) INFO("registered gadget driver '%s'\n", driver->driver.name); + /* create sysfs node for remote wakeup */ + retval = device_create_file(&ui->gadget.dev, &dev_attr_wakeup); + if (retval != 0) + INFO("failed to create sysfs entry: (wakeup) error: (%d)\n", + retval); + usb_start(ui); return 0; @@ -1693,6 +1749,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) if (!driver || driver != dev->driver || !driver->unbind) return -EINVAL; + device_remove_file(&dev->gadget.dev, &dev_attr_wakeup); driver->unbind(&dev->gadget); dev->gadget.dev.driver = NULL; dev->driver = NULL; diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h index ab28be6..ae13342 100644 --- a/include/linux/usb/msm_hsusb_hw.h +++ b/include/linux/usb/msm_hsusb_hw.h @@ -200,6 +200,9 @@ struct ept_queue_item { #define PORTSC_PSPD_LS (1 << 26) #define PORTSC_PSPD_HS (2 << 26) #define PORTSC_PSPD_MASK (3 << 26) +/* suspend and remote wakeup */ +#define PORTSC_FPR (1 << 6) +#define PORTSC_SUSP (1 << 7) #define PORTSC_PTS_MASK (3 << 30) #define PORTSC_PTS_ULPI (2 << 30) -- 1.7.1 -- Sent by a consultant of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html