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 <schluessler@krause.de>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
This commit is contained in:
Timo Schlüßler 2019-10-11 15:38:20 +02:00 коммит произвёл Marc Kleine-Budde
Родитель 877a902103
Коммит 8ce8c0abcb
1 изменённых файлов: 44 добавлений и 7 удалений

Просмотреть файл

@ -468,6 +468,39 @@ static void mcp251x_hw_sleep(struct spi_device *spi)
mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_SLEEP);
}
/* May only be called when device is sleeping! */
static int mcp251x_hw_wake(struct spi_device *spi)
{
unsigned long timeout;
/* Force wakeup interrupt to wake device, but don't execute IST */
disable_irq(spi->irq);
mcp251x_write_2regs(spi, CANINTE, CANINTE_WAKIE, CANINTF_WAKIF);
/* Wait for oscillator startup timer after wake up */
mdelay(MCP251X_OST_DELAY_MS);
/* Put device into config mode */
mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_CONF);
/* Wait for the device to enter config mode */
timeout = jiffies + HZ;
while ((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK) !=
CANCTRL_REQOP_CONF) {
schedule();
if (time_after(jiffies, timeout)) {
dev_err(&spi->dev, "MCP251x didn't enter in config mode\n");
return -EBUSY;
}
}
/* Disable and clear pending interrupts */
mcp251x_write_2regs(spi, CANINTE, 0x00, 0x00);
enable_irq(spi->irq);
return 0;
}
static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb,
struct net_device *net)
{
@ -725,8 +758,12 @@ static void mcp251x_restart_work_handler(struct work_struct *ws)
mutex_lock(&priv->mcp_lock);
if (priv->after_suspend) {
mcp251x_hw_reset(spi);
mcp251x_setup(net, spi);
if (priv->after_suspend & AFTER_SUSPEND_POWER) {
mcp251x_hw_reset(spi);
mcp251x_setup(net, spi);
} else {
mcp251x_hw_wake(spi);
}
priv->force_quit = 0;
if (priv->after_suspend & AFTER_SUSPEND_RESTART) {
mcp251x_set_normal_mode(spi);
@ -923,7 +960,7 @@ static int mcp251x_open(struct net_device *net)
INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);
INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler);
ret = mcp251x_hw_reset(spi);
ret = mcp251x_hw_wake(spi);
if (ret)
goto out_free_wq;
ret = mcp251x_setup(net, spi);
@ -1165,13 +1202,13 @@ static int __maybe_unused mcp251x_can_resume(struct device *dev)
if (priv->after_suspend & AFTER_SUSPEND_POWER)
mcp251x_power_enable(priv->power, 1);
if (priv->after_suspend & AFTER_SUSPEND_UP) {
if (priv->after_suspend & AFTER_SUSPEND_UP)
mcp251x_power_enable(priv->transceiver, 1);
if (priv->after_suspend & (AFTER_SUSPEND_POWER | AFTER_SUSPEND_UP))
queue_work(priv->wq, &priv->restart_work);
} else {
else
priv->after_suspend = 0;
}
priv->force_quit = 0;
enable_irq(spi->irq);