Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Timo Schlüßler and committed by
Marc Kleine-Budde
8ce8c0ab 877a9021

+44 -7
+44 -7
drivers/net/can/spi/mcp251x.c
··· 468 468 mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_SLEEP); 469 469 } 470 470 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 + 471 504 static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb, 472 505 struct net_device *net) 473 506 { ··· 758 725 759 726 mutex_lock(&priv->mcp_lock); 760 727 if (priv->after_suspend) { 761 - mcp251x_hw_reset(spi); 762 - mcp251x_setup(net, spi); 728 + if (priv->after_suspend & AFTER_SUSPEND_POWER) { 729 + mcp251x_hw_reset(spi); 730 + mcp251x_setup(net, spi); 731 + } else { 732 + mcp251x_hw_wake(spi); 733 + } 763 734 priv->force_quit = 0; 764 735 if (priv->after_suspend & AFTER_SUSPEND_RESTART) { 765 736 mcp251x_set_normal_mode(spi); ··· 960 923 INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler); 961 924 INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler); 962 925 963 - ret = mcp251x_hw_reset(spi); 926 + ret = mcp251x_hw_wake(spi); 964 927 if (ret) 965 928 goto out_free_wq; 966 929 ret = mcp251x_setup(net, spi); ··· 1202 1165 1203 1166 if (priv->after_suspend & AFTER_SUSPEND_POWER) 1204 1167 mcp251x_power_enable(priv->power, 1); 1205 - 1206 - if (priv->after_suspend & AFTER_SUSPEND_UP) { 1168 + if (priv->after_suspend & AFTER_SUSPEND_UP) 1207 1169 mcp251x_power_enable(priv->transceiver, 1); 1170 + 1171 + if (priv->after_suspend & (AFTER_SUSPEND_POWER | AFTER_SUSPEND_UP)) 1208 1172 queue_work(priv->wq, &priv->restart_work); 1209 - } else { 1173 + else 1210 1174 priv->after_suspend = 0; 1211 - } 1212 1175 1213 1176 priv->force_quit = 0; 1214 1177 enable_irq(spi->irq);