usb: xilinx: Add suspend resume support
authorShubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
Thu, 18 Nov 2021 12:01:43 +0000 (17:31 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 23 Nov 2021 13:12:40 +0000 (14:12 +0100)
Add suspend resume support. In the suspend udc is suspended
and it is set to ready at resume for it to be functional.

Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
Link: https://lore.kernel.org/r/20211118120143.1079-1-shubhrajyoti.datta@xilinx.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/gadget/udc/udc-xilinx.c

index f5ca670..d8585f4 100644 (file)
@@ -2176,6 +2176,61 @@ static int xudc_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int xudc_suspend(struct device *dev)
+{
+       struct xusb_udc *udc;
+       u32 crtlreg;
+       unsigned long flags;
+
+       udc = dev_get_drvdata(dev);
+
+       spin_lock_irqsave(&udc->lock, flags);
+
+       crtlreg = udc->read_fn(udc->addr + XUSB_CONTROL_OFFSET);
+       crtlreg &= ~XUSB_CONTROL_USB_READY_MASK;
+
+       udc->write_fn(udc->addr, XUSB_CONTROL_OFFSET, crtlreg);
+
+       spin_unlock_irqrestore(&udc->lock, flags);
+       if (udc->driver && udc->driver->suspend)
+               udc->driver->suspend(&udc->gadget);
+
+       clk_disable(udc->clk);
+
+       return 0;
+}
+
+static int xudc_resume(struct device *dev)
+{
+       struct xusb_udc *udc;
+       u32 crtlreg;
+       unsigned long flags;
+       int ret;
+
+       udc = dev_get_drvdata(dev);
+
+       ret = clk_enable(udc->clk);
+       if (ret < 0)
+               return ret;
+
+       spin_lock_irqsave(&udc->lock, flags);
+
+       crtlreg = udc->read_fn(udc->addr + XUSB_CONTROL_OFFSET);
+       crtlreg |= XUSB_CONTROL_USB_READY_MASK;
+
+       udc->write_fn(udc->addr, XUSB_CONTROL_OFFSET, crtlreg);
+
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops xudc_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(xudc_suspend, xudc_resume)
+};
+
 /* Match table for of_platform binding */
 static const struct of_device_id usb_of_match[] = {
        { .compatible = "xlnx,usb2-device-4.00.a", },
@@ -2187,6 +2242,7 @@ static struct platform_driver xudc_driver = {
        .driver = {
                .name = driver_name,
                .of_match_table = usb_of_match,
+               .pm     = &xudc_pm_ops,
        },
        .probe = xudc_probe,
        .remove = xudc_remove,