diff options
author | Chunfeng Yun <chunfeng.yun@mediatek.com> | 2021-07-15 17:07:57 +0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2021-07-27 15:58:37 +0200 |
commit | 427c66422e14b8468ee005aa6edf76ef0c2a8fc2 (patch) | |
tree | 67b8054585d58c8c06f69f47fd2107a5b341c51a /drivers/usb/mtu3/mtu3_core.c | |
parent | 6244831543ec269f40ed9032bb8194c089049718 (diff) | |
download | linux-next-427c66422e14b8468ee005aa6edf76ef0c2a8fc2.tar.gz |
usb: mtu3: support suspend/resume for device mode
Support suspend/resume for device mode if the device is not
connected with a host, otherwise reject to suspend.
Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
Link: https://lore.kernel.org/r/1626340078-29111-13-git-send-email-chunfeng.yun@mediatek.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/mtu3/mtu3_core.c')
-rw-r--r-- | drivers/usb/mtu3/mtu3_core.c | 68 |
1 files changed, 66 insertions, 2 deletions
diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c index 648e970d77ba..a800920d38b9 100644 --- a/drivers/usb/mtu3/mtu3_core.c +++ b/drivers/usb/mtu3/mtu3_core.c @@ -9,6 +9,7 @@ */ #include <linux/dma-mapping.h> +#include <linux/iopoll.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of_address.h> @@ -380,6 +381,24 @@ void mtu3_stop(struct mtu3 *mtu) mtu3_dev_power_down(mtu); } +static void mtu3_dev_suspend(struct mtu3 *mtu) +{ + if (!mtu->is_active) + return; + + mtu3_intr_disable(mtu); + mtu3_dev_power_down(mtu); +} + +static void mtu3_dev_resume(struct mtu3 *mtu) +{ + if (!mtu->is_active) + return; + + mtu3_dev_power_on(mtu); + mtu3_intr_enable(mtu); +} + /* for non-ep0 */ int mtu3_config_ep(struct mtu3 *mtu, struct mtu3_ep *mep, int interval, int burst, int mult) @@ -700,11 +719,15 @@ static irqreturn_t mtu3_link_isr(struct mtu3 *mtu) mtu->g.speed = udev_speed; mtu->g.ep0->maxpacket = maxpkt; mtu->ep0_state = MU3D_EP0_STATE_SETUP; + mtu->connected = !!(udev_speed != USB_SPEED_UNKNOWN); - if (udev_speed == USB_SPEED_UNKNOWN) + if (udev_speed == USB_SPEED_UNKNOWN) { mtu3_gadget_disconnect(mtu); - else + pm_runtime_put(mtu->dev); + } else { + pm_runtime_get(mtu->dev); mtu3_ep0_setup(mtu); + } return IRQ_HANDLED; } @@ -984,3 +1007,44 @@ void ssusb_gadget_exit(struct ssusb_mtk *ssusb) device_init_wakeup(ssusb->dev, false); mtu3_hw_exit(mtu); } + +int ssusb_gadget_suspend(struct ssusb_mtk *ssusb, pm_message_t msg) +{ + struct mtu3 *mtu = ssusb->u3d; + void __iomem *ibase = mtu->ippc_base; + u32 value; + int ret = 0; + + if (!mtu->gadget_driver) + return 0; + + if (mtu->connected) + return -EBUSY; + + mtu3_dev_suspend(mtu); + synchronize_irq(mtu->irq); + + /* wait for ip to sleep */ + if (mtu->is_active && mtu->softconnect) { + ret = readl_poll_timeout(ibase + U3D_SSUSB_IP_PW_STS1, + value, (value & SSUSB_IP_SLEEP_STS), 100, 100000); + if (ret) { + dev_err(mtu->dev, "ip sleep failed!!!\n"); + ret = -EBUSY; + } + } + + return ret; +} + +int ssusb_gadget_resume(struct ssusb_mtk *ssusb, pm_message_t msg) +{ + struct mtu3 *mtu = ssusb->u3d; + + if (!mtu->gadget_driver) + return 0; + + mtu3_dev_resume(mtu); + + return 0; +} |