diff options
Diffstat (limited to 'drivers/net/can/c_can/c_can_platform.c')
-rw-r--r-- | drivers/net/can/c_can/c_can_platform.c | 47 |
1 files changed, 37 insertions, 10 deletions
diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c index d66ac265269c..806d92753427 100644 --- a/drivers/net/can/c_can/c_can_platform.c +++ b/drivers/net/can/c_can/c_can_platform.c @@ -37,8 +37,10 @@ #include "c_can.h" -#define CAN_RAMINIT_START_MASK(i) (1 << (i)) - +#define CAN_RAMINIT_START_MASK(i) (0x001 << (i)) +#define CAN_RAMINIT_DONE_MASK(i) (0x100 << (i)) +#define CAN_RAMINIT_ALL_MASK(i) (0x101 << (i)) +static DEFINE_SPINLOCK(raminit_lock); /* * 16-bit c_can registers can be arranged differently in the memory * architecture of different implementations. For example: 16-bit @@ -69,16 +71,41 @@ static void c_can_plat_write_reg_aligned_to_32bit(struct c_can_priv *priv, writew(val, priv->base + 2 * priv->regs[index]); } +static void c_can_hw_raminit_wait(const struct c_can_priv *priv, u32 mask, + u32 val) +{ + /* We look only at the bits of our instance. */ + val &= mask; + while ((readl(priv->raminit_ctrlreg) & mask) != val) + udelay(1); +} + static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable) { - u32 val; - - val = readl(priv->raminit_ctrlreg); - if (enable) - val |= CAN_RAMINIT_START_MASK(priv->instance); - else - val &= ~CAN_RAMINIT_START_MASK(priv->instance); - writel(val, priv->raminit_ctrlreg); + u32 mask = CAN_RAMINIT_ALL_MASK(priv->instance); + u32 ctrl; + + spin_lock(&raminit_lock); + + ctrl = readl(priv->raminit_ctrlreg); + /* We clear the done and start bit first. The start bit is + * looking at the 0 -> transition, but is not self clearing; + * And we clear the init done bit as well. + */ + ctrl &= ~CAN_RAMINIT_START_MASK(priv->instance); + ctrl |= CAN_RAMINIT_DONE_MASK(priv->instance); + writel(ctrl, priv->raminit_ctrlreg); + ctrl &= ~CAN_RAMINIT_DONE_MASK(priv->instance); + c_can_hw_raminit_wait(priv, ctrl, mask); + + if (enable) { + /* Set start bit and wait for the done bit. */ + ctrl |= CAN_RAMINIT_START_MASK(priv->instance); + writel(ctrl, priv->raminit_ctrlreg); + ctrl |= CAN_RAMINIT_DONE_MASK(priv->instance); + c_can_hw_raminit_wait(priv, ctrl, mask); + } + spin_unlock(&raminit_lock); } static struct platform_device_id c_can_id_table[] = { |