Skip to content

Commit 8ce8c0a

Browse files
Timo Schlüßlermarckleinebudde
authored andcommitted
can: mcp251x: only reset hardware as required
This prevents unwanted glitches on the outputs when changing the link state of the can interface or when resuming from suspend. Only if the device is powered off during suspend it needs to be resetted as required by the specs. Signed-off-by: Timo Schlüßler <[email protected]> Signed-off-by: Marc Kleine-Budde <[email protected]>
1 parent 877a902 commit 8ce8c0a

File tree

1 file changed

+44
-7
lines changed

1 file changed

+44
-7
lines changed

drivers/net/can/spi/mcp251x.c

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,39 @@ static void mcp251x_hw_sleep(struct spi_device *spi)
468468
mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_SLEEP);
469469
}
470470

471+
/* May only be called when device is sleeping! */
472+
static int mcp251x_hw_wake(struct spi_device *spi)
473+
{
474+
unsigned long timeout;
475+
476+
/* Force wakeup interrupt to wake device, but don't execute IST */
477+
disable_irq(spi->irq);
478+
mcp251x_write_2regs(spi, CANINTE, CANINTE_WAKIE, CANINTF_WAKIF);
479+
480+
/* Wait for oscillator startup timer after wake up */
481+
mdelay(MCP251X_OST_DELAY_MS);
482+
483+
/* Put device into config mode */
484+
mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_CONF);
485+
486+
/* Wait for the device to enter config mode */
487+
timeout = jiffies + HZ;
488+
while ((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK) !=
489+
CANCTRL_REQOP_CONF) {
490+
schedule();
491+
if (time_after(jiffies, timeout)) {
492+
dev_err(&spi->dev, "MCP251x didn't enter in config mode\n");
493+
return -EBUSY;
494+
}
495+
}
496+
497+
/* Disable and clear pending interrupts */
498+
mcp251x_write_2regs(spi, CANINTE, 0x00, 0x00);
499+
enable_irq(spi->irq);
500+
501+
return 0;
502+
}
503+
471504
static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb,
472505
struct net_device *net)
473506
{
@@ -725,8 +758,12 @@ static void mcp251x_restart_work_handler(struct work_struct *ws)
725758

726759
mutex_lock(&priv->mcp_lock);
727760
if (priv->after_suspend) {
728-
mcp251x_hw_reset(spi);
729-
mcp251x_setup(net, spi);
761+
if (priv->after_suspend & AFTER_SUSPEND_POWER) {
762+
mcp251x_hw_reset(spi);
763+
mcp251x_setup(net, spi);
764+
} else {
765+
mcp251x_hw_wake(spi);
766+
}
730767
priv->force_quit = 0;
731768
if (priv->after_suspend & AFTER_SUSPEND_RESTART) {
732769
mcp251x_set_normal_mode(spi);
@@ -923,7 +960,7 @@ static int mcp251x_open(struct net_device *net)
923960
INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);
924961
INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler);
925962

926-
ret = mcp251x_hw_reset(spi);
963+
ret = mcp251x_hw_wake(spi);
927964
if (ret)
928965
goto out_free_wq;
929966
ret = mcp251x_setup(net, spi);
@@ -1165,13 +1202,13 @@ static int __maybe_unused mcp251x_can_resume(struct device *dev)
11651202

11661203
if (priv->after_suspend & AFTER_SUSPEND_POWER)
11671204
mcp251x_power_enable(priv->power, 1);
1168-
1169-
if (priv->after_suspend & AFTER_SUSPEND_UP) {
1205+
if (priv->after_suspend & AFTER_SUSPEND_UP)
11701206
mcp251x_power_enable(priv->transceiver, 1);
1207+
1208+
if (priv->after_suspend & (AFTER_SUSPEND_POWER | AFTER_SUSPEND_UP))
11711209
queue_work(priv->wq, &priv->restart_work);
1172-
} else {
1210+
else
11731211
priv->after_suspend = 0;
1174-
}
11751212

11761213
priv->force_quit = 0;
11771214
enable_irq(spi->irq);

0 commit comments

Comments
 (0)