From 9ff665d55bfd273042cb25e92b18bfaae0b8a0a6 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 11 Jul 2014 14:32:15 +0200 Subject: can: flexcan: dynamically sleep for chip_{en,dis}able In flexcan_chip_enable() and flexcan_chip_disable() fixed delays are used. Experiments have shown that the transition from and to low power mode may take several microseconds. This patch adds a while loop which polls the Low Power Mode ACK bit (LPM_ACK) that indicates a successfull mode change. If the function runs into a timeout a error value is returned. This is a simpliefied backport of can: flexcan: fix transition from and to low power mode in chip_{en,dis}able 9b00b300e7bce032c467c36ca47fe2a776887fc2 --- drivers/net/can/flexcan.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 886905db1396..d0b8e8ed275b 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -145,6 +145,8 @@ #define FLEXCAN_MB_CODE_MASK (0xf0ffffff) +#define FLEXCAN_TIMEOUT_US 50 + /* Structure of the message buffer */ struct flexcan_mb { u32 can_ctrl; @@ -249,23 +251,38 @@ static inline void flexcan_exit_stop(struct flexcan_priv *priv) static inline void flexcan_chip_enable(struct flexcan_priv *priv) { struct flexcan_regs __iomem *regs = priv->base; + unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; u32 reg; reg = readl(®s->mcr); reg &= ~FLEXCAN_MCR_MDIS; writel(reg, ®s->mcr); - udelay(10); + while (timeout-- && (readl(®s->mcr) & FLEXCAN_MCR_LPM_ACK)) + usleep_range(10, 20); + + if (readl(®s->mcr) & FLEXCAN_MCR_LPM_ACK) + dev_err(priv->dev->dev.parent, + "flexcan_chip_disable timed out\n"); } static inline void flexcan_chip_disable(struct flexcan_priv *priv) { struct flexcan_regs __iomem *regs = priv->base; + unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; u32 reg; reg = readl(®s->mcr); reg |= FLEXCAN_MCR_MDIS; writel(reg, ®s->mcr); + + + while (timeout-- && !(readl(®s->mcr) & FLEXCAN_MCR_LPM_ACK)) + usleep_range(10, 20); + + if (!(readl(®s->mcr) & FLEXCAN_MCR_LPM_ACK)) + dev_err(priv->dev->dev.parent, + "flexcan_chip_disable timed out\n"); } static int flexcan_get_berr_counter(const struct net_device *dev, -- cgit v1.2.3