From: Stefan Agner Date: Mon, 18 May 2015 16:33:27 +0000 (+0200) Subject: can: mcp251x: fix resume when device is down X-Git-Tag: v3.4.111~77 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=45ceb60e13119ead510fb76882e5744a5802c5e1;p=thirdparty%2Fkernel%2Fstable.git can: mcp251x: fix resume when device is down commit 25b401c1816ae64bcc5dcb1d39ab41812522a0ce upstream. If a valid power regulator or a dummy regulator is used (which happens to be the case when no regulator is specified), restart_work is queued no matter whether the device was running or not at suspend time. Since work queues get initialized in the ndo_open callback, resuming leads to a NULL pointer exception. Reverse exactly the steps executed at suspend time: - Enable the power regulator in any case - Enable the transceiver regulator if the device was running, even in case we have a power regulator - Queue restart_work only in case the device was running Fixes: bf66f3736a94 ("can: mcp251x: Move to threaded interrupts instead of workqueues.") Signed-off-by: Stefan Agner Signed-off-by: Marc Kleine-Budde [lizf: Backported to 3.4: - adjust filename - adjust context] Signed-off-by: Zefan Li --- diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index 9d6074273caa5..d07426d007d05 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -1161,18 +1161,17 @@ static int mcp251x_can_resume(struct spi_device *spi) struct mcp251x_platform_data *pdata = spi->dev.platform_data; struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); - if (priv->after_suspend & AFTER_SUSPEND_POWER) { + if (priv->after_suspend & AFTER_SUSPEND_POWER) pdata->power_enable(1); + + if (priv->after_suspend & AFTER_SUSPEND_UP) { + if (pdata->transceiver_enable) + pdata->transceiver_enable(1); queue_work(priv->wq, &priv->restart_work); } else { - if (priv->after_suspend & AFTER_SUSPEND_UP) { - if (pdata->transceiver_enable) - pdata->transceiver_enable(1); - queue_work(priv->wq, &priv->restart_work); - } else { - priv->after_suspend = 0; - } + priv->after_suspend = 0; } + priv->force_quit = 0; enable_irq(spi->irq); return 0;