summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Agner <stefan.agner@toradex.com>2014-07-11 14:32:15 +0200
committerStefan Agner <stefan.agner@toradex.com>2014-07-11 14:32:15 +0200
commit9ff665d55bfd273042cb25e92b18bfaae0b8a0a6 (patch)
tree2297bc332ae702edeae356d7ed20e7c8158fe9bf
parent8079d9137048fce1114b29fda2d1854d49599068 (diff)
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
-rw-r--r--drivers/net/can/flexcan.c19
1 files changed, 18 insertions, 1 deletions
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(&regs->mcr);
reg &= ~FLEXCAN_MCR_MDIS;
writel(reg, &regs->mcr);
- udelay(10);
+ while (timeout-- && (readl(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+ usleep_range(10, 20);
+
+ if (readl(&regs->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(&regs->mcr);
reg |= FLEXCAN_MCR_MDIS;
writel(reg, &regs->mcr);
+
+
+ while (timeout-- && !(readl(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+ usleep_range(10, 20);
+
+ if (!(readl(&regs->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,