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:
Родитель
877a902103
Коммит
8ce8c0abcb
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче