summaryrefslogtreecommitdiff
path: root/drivers/net/can/flexcan.c
diff options
context:
space:
mode:
authorFugang Duan <fugang.duan@nxp.com>2018-11-06 13:09:42 +0800
committerJason Liu <jason.hui.liu@nxp.com>2019-02-12 10:35:24 +0800
commit498e58731a8b38778581d24ca9cdee3d94c13c41 (patch)
tree360db4c88aa7267b0bd9ba6e7612b97795e4a9f1 /drivers/net/can/flexcan.c
parentc624150aa781fb3d578a1cb983ae5ddc85fb3dd4 (diff)
MLK-20131 can: flexcan: fix CAN can't suspend/resume when CAN is only capable of wakeup
When dev->power.can_wakeup set to true, device_prepare() may runtime resume the device: dpm_suspend_start() dpm_prepare(state); dev->driver->pm->prepare() pm_genpd_prepare() if (resume_needed(dev, genpd)) pm_runtime_resume(dev); And imx8qm/qxp power domain driver don't implement the active_wakeup() callback, then resume_needed() always return "true" when dev->power.can_wakeup is true. Once CAN device is runtime active status, then CAN's clock's count is 1 during system suspend. And CAN0/CAN1/CAN2 share the same module clock, so we can say all CAN's module clock is enabled during system suspended. flexcan_runtime_resume() flexcan_clks_enable(priv); i.MX8QM/QXP SCU code clock logic requires linux kernel clocks should be disabled during suspend, otherwise SCU don't enable them after system resume back. There are two ways to fix the issue: 1. CAN driver should check the runtime status to ensure all clocks are disabled during system suspend. 2. Don't set CAN wakeup capability during probe, move it into flexcan_open(). Signed-off-by: Fugang Duan <fugang.duan@nxp.com> Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
Diffstat (limited to 'drivers/net/can/flexcan.c')
-rw-r--r--drivers/net/can/flexcan.c13
1 files changed, 8 insertions, 5 deletions
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index b0fac6364b53..7be8da8694d2 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -366,6 +366,7 @@ struct flexcan_priv {
#ifdef CONFIG_ARCH_MXC_ARM64
sc_ipc_t ipc_handle;
#endif
+ bool wakeup;
u32 mb_size;
u32 mb_num;
@@ -1434,6 +1435,8 @@ static int flexcan_open(struct net_device *dev)
if (err)
goto out_free_irq;
+ device_set_wakeup_capable(priv->dev, priv->wakeup);
+
can_led_event(dev, CAN_LED_EVENT_OPEN);
can_rx_offload_enable(&priv->offload);
@@ -1464,6 +1467,8 @@ static int flexcan_close(struct net_device *dev)
close_candev(dev);
+ device_set_wakeup_capable(priv->dev, false);
+
can_led_event(dev, CAN_LED_EVENT_STOP);
pm_runtime_put(priv->dev);
@@ -1659,7 +1664,6 @@ static int flexcan_probe(struct platform_device *pdev)
int err, irq;
u32 clock_freq = 0;
u32 clk_src = 1;
- int wakeup = 1;
reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver");
if (PTR_ERR(reg_xceiver) == -EPROBE_DEFER)
@@ -1808,22 +1812,21 @@ static int flexcan_probe(struct platform_device *pdev)
devm_can_led_init(dev);
+ priv->wakeup = true;
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD) {
err = imx8_sc_ipc_fetch(pdev);
if (err) {
- wakeup = 0;
+ priv->wakeup = false;
dev_dbg(&pdev->dev, "failed to fetch scu ipc\n");
}
} else if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_RXFG) {
err = flexcan_of_parse_stop_mode(pdev);
if (err) {
- wakeup = 0;
+ priv->wakeup = false;;
dev_dbg(&pdev->dev, "failed to parse stop-mode\n");
}
}
- device_set_wakeup_capable(&pdev->dev, wakeup);
-
pm_runtime_put(&pdev->dev);
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",