Add a flag to the suspend class function that leaves the chip in a running state with rx interrupt enabled, so that m_can device driver can configure and use the interrupt as a wakeup source. Signed-off-by: Martin Hundebøll <martin@xxxxxxxxxx> --- Changes since v1: * Fixed comment formatting * Updated m_can_class_{suspend,resume} calls in m_can_pci.c too * Skipped calling m_can_start() when resuming a wake-source device drivers/net/can/m_can/m_can.c | 26 +++++++++++++++++++------- drivers/net/can/m_can/m_can.h | 4 ++-- drivers/net/can/m_can/m_can_pci.c | 4 ++-- drivers/net/can/m_can/m_can_platform.c | 4 ++-- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 16ecc11c7f62..ec345f6fd6b0 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -2113,7 +2113,7 @@ void m_can_class_unregister(struct m_can_classdev *cdev) } EXPORT_SYMBOL_GPL(m_can_class_unregister); -int m_can_class_suspend(struct device *dev) +int m_can_class_suspend(struct device *dev, bool is_wake_source) { struct m_can_classdev *cdev = dev_get_drvdata(dev); struct net_device *ndev = cdev->net; @@ -2121,7 +2121,15 @@ int m_can_class_suspend(struct device *dev) if (netif_running(ndev)) { netif_stop_queue(ndev); netif_device_detach(ndev); - m_can_stop(ndev); + + /* leave the chip running with rx interrupt enabled if it used + * as a wake-up source. + */ + if (is_wake_source) + m_can_write(cdev, M_CAN_IE, IR_RF0N); + else + m_can_stop(ndev); + m_can_clk_stop(cdev); } @@ -2133,7 +2141,7 @@ int m_can_class_suspend(struct device *dev) } EXPORT_SYMBOL_GPL(m_can_class_suspend); -int m_can_class_resume(struct device *dev) +int m_can_class_resume(struct device *dev, bool is_wake_source) { struct m_can_classdev *cdev = dev_get_drvdata(dev); struct net_device *ndev = cdev->net; @@ -2148,11 +2156,15 @@ int m_can_class_resume(struct device *dev) ret = m_can_clk_start(cdev); if (ret) return ret; - ret = m_can_start(ndev); - if (ret) { - m_can_clk_stop(cdev); - return ret; + if (is_wake_source) { + m_can_write(cdev, M_CAN_IE, cdev->active_interrupts); + } else { + ret = m_can_start(ndev); + if (ret) { + m_can_clk_stop(cdev); + return ret; + } } netif_device_attach(ndev); diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h index 520e14277dff..5d86bcf66e83 100644 --- a/drivers/net/can/m_can/m_can.h +++ b/drivers/net/can/m_can/m_can.h @@ -105,6 +105,6 @@ int m_can_class_get_clocks(struct m_can_classdev *cdev); int m_can_init_ram(struct m_can_classdev *priv); int m_can_check_mram_cfg(struct m_can_classdev *cdev, u32 mram_max_size); -int m_can_class_suspend(struct device *dev); -int m_can_class_resume(struct device *dev); +int m_can_class_suspend(struct device *dev, bool is_wake_source); +int m_can_class_resume(struct device *dev, bool is_wake_source); #endif /* _CAN_M_H_ */ diff --git a/drivers/net/can/m_can/m_can_pci.c b/drivers/net/can/m_can/m_can_pci.c index f2219aa2824b..7ffbe06d96d0 100644 --- a/drivers/net/can/m_can/m_can_pci.c +++ b/drivers/net/can/m_can/m_can_pci.c @@ -169,12 +169,12 @@ static void m_can_pci_remove(struct pci_dev *pci) static __maybe_unused int m_can_pci_suspend(struct device *dev) { - return m_can_class_suspend(dev); + return m_can_class_suspend(dev, false); } static __maybe_unused int m_can_pci_resume(struct device *dev) { - return m_can_class_resume(dev); + return m_can_class_resume(dev, false); } static SIMPLE_DEV_PM_OPS(m_can_pci_pm_ops, diff --git a/drivers/net/can/m_can/m_can_platform.c b/drivers/net/can/m_can/m_can_platform.c index cdb28d6a092c..e49bef50d52c 100644 --- a/drivers/net/can/m_can/m_can_platform.c +++ b/drivers/net/can/m_can/m_can_platform.c @@ -169,12 +169,12 @@ static int m_can_plat_probe(struct platform_device *pdev) static __maybe_unused int m_can_suspend(struct device *dev) { - return m_can_class_suspend(dev); + return m_can_class_suspend(dev, false); } static __maybe_unused int m_can_resume(struct device *dev) { - return m_can_class_resume(dev); + return m_can_class_resume(dev, false); } static void m_can_plat_remove(struct platform_device *pdev) -- 2.42.0