diff options
-rw-r--r-- | drivers/net/can/flexcan.c | 31 |
1 files changed, 27 insertions, 4 deletions
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 33ce45d51e15..fcec8bcb53d6 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -400,9 +400,10 @@ static void flexcan_enable_wakeup_irq(struct flexcan_priv *priv, bool enable) priv->write(reg_mcr, ®s->mcr); } -static inline void flexcan_enter_stop_mode(struct flexcan_priv *priv) +static inline int flexcan_enter_stop_mode(struct flexcan_priv *priv) { struct flexcan_regs __iomem *regs = priv->regs; + unsigned int ackval; u32 reg_mcr; reg_mcr = priv->read(®s->mcr); @@ -412,20 +413,37 @@ static inline void flexcan_enter_stop_mode(struct flexcan_priv *priv) /* enable stop request */ regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, 1 << priv->stm.req_bit, 1 << priv->stm.req_bit); + + /* get stop acknowledgment */ + if (regmap_read_poll_timeout(priv->stm.gpr, priv->stm.ack_gpr, + ackval, ackval & (1 << priv->stm.ack_bit), + 0, FLEXCAN_TIMEOUT_US)) + return -ETIMEDOUT; + + return 0; } -static inline void flexcan_exit_stop_mode(struct flexcan_priv *priv) +static inline int flexcan_exit_stop_mode(struct flexcan_priv *priv) { struct flexcan_regs __iomem *regs = priv->regs; + unsigned int ackval; u32 reg_mcr; /* remove stop request */ regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, 1 << priv->stm.req_bit, 0); + /* get stop acknowledgment */ + if (regmap_read_poll_timeout(priv->stm.gpr, priv->stm.ack_gpr, + ackval, !(ackval & (1 << priv->stm.ack_bit)), + 0, FLEXCAN_TIMEOUT_US)) + return -ETIMEDOUT; + reg_mcr = priv->read(®s->mcr); reg_mcr &= ~FLEXCAN_MCR_SLF_WAK; priv->write(reg_mcr, ®s->mcr); + + return 0; } static inline void flexcan_error_irq_enable(const struct flexcan_priv *priv) @@ -1614,7 +1632,9 @@ static int __maybe_unused flexcan_suspend(struct device *device) */ if (device_may_wakeup(device)) { enable_irq_wake(dev->irq); - flexcan_enter_stop_mode(priv); + err = flexcan_enter_stop_mode(priv); + if (err) + return err; } else { err = flexcan_chip_disable(priv); if (err) @@ -1664,10 +1684,13 @@ static int __maybe_unused flexcan_noirq_resume(struct device *device) { struct net_device *dev = dev_get_drvdata(device); struct flexcan_priv *priv = netdev_priv(dev); + int err; if (netif_running(dev) && device_may_wakeup(device)) { flexcan_enable_wakeup_irq(priv, false); - flexcan_exit_stop_mode(priv); + err = flexcan_exit_stop_mode(priv); + if (err) + return err; } return 0; |