i2c: iproc: Add recovery mechanism in error case
Add proper recovery mechanism to the iProc I2C driver in error cases. Signed-off-by: Icarus Chau <ichau@broadcom.com> Signed-off-by: Ray Jui <rjui@broadcom.com> Tested-by: Icarus Chau <ichau@broadcom.com> Reviewed-by: Scott Branden <sbranden@broadcom.com> [wsa: whitespace fixes] Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
This commit is contained in:
parent
61c18aeb05
commit
6ee608c1c9
|
@ -119,6 +119,48 @@ static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev *iproc_i2c)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* put controller in reset */
|
||||
val = readl(iproc_i2c->base + CFG_OFFSET);
|
||||
val |= 1 << CFG_RESET_SHIFT;
|
||||
val &= ~(1 << CFG_EN_SHIFT);
|
||||
writel(val, iproc_i2c->base + CFG_OFFSET);
|
||||
|
||||
/* wait 100 usec per spec */
|
||||
udelay(100);
|
||||
|
||||
/* bring controller out of reset */
|
||||
val &= ~(1 << CFG_RESET_SHIFT);
|
||||
writel(val, iproc_i2c->base + CFG_OFFSET);
|
||||
|
||||
/* flush TX/RX FIFOs and set RX FIFO threshold to zero */
|
||||
val = (1 << M_FIFO_RX_FLUSH_SHIFT) | (1 << M_FIFO_TX_FLUSH_SHIFT);
|
||||
writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
|
||||
/* disable all interrupts */
|
||||
writel(0, iproc_i2c->base + IE_OFFSET);
|
||||
|
||||
/* clear all pending interrupts */
|
||||
writel(0xffffffff, iproc_i2c->base + IS_OFFSET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bcm_iproc_i2c_enable_disable(struct bcm_iproc_i2c_dev *iproc_i2c,
|
||||
bool enable)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(iproc_i2c->base + CFG_OFFSET);
|
||||
if (enable)
|
||||
val |= BIT(CFG_EN_SHIFT);
|
||||
else
|
||||
val &= ~BIT(CFG_EN_SHIFT);
|
||||
writel(val, iproc_i2c->base + CFG_OFFSET);
|
||||
}
|
||||
|
||||
static int bcm_iproc_i2c_check_status(struct bcm_iproc_i2c_dev *iproc_i2c,
|
||||
struct i2c_msg *msg)
|
||||
{
|
||||
|
@ -149,6 +191,12 @@ static int bcm_iproc_i2c_check_status(struct bcm_iproc_i2c_dev *iproc_i2c,
|
|||
|
||||
default:
|
||||
dev_dbg(iproc_i2c->device, "unknown error code=%d\n", val);
|
||||
|
||||
/* re-initialize i2c for recovery */
|
||||
bcm_iproc_i2c_enable_disable(iproc_i2c, false);
|
||||
bcm_iproc_i2c_init(iproc_i2c);
|
||||
bcm_iproc_i2c_enable_disable(iproc_i2c, true);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
@ -321,49 +369,6 @@ static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev *iproc_i2c)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* put controller in reset */
|
||||
val = readl(iproc_i2c->base + CFG_OFFSET);
|
||||
val |= 1 << CFG_RESET_SHIFT;
|
||||
val &= ~(1 << CFG_EN_SHIFT);
|
||||
writel(val, iproc_i2c->base + CFG_OFFSET);
|
||||
|
||||
/* wait 100 usec per spec */
|
||||
udelay(100);
|
||||
|
||||
/* bring controller out of reset */
|
||||
val &= ~(1 << CFG_RESET_SHIFT);
|
||||
writel(val, iproc_i2c->base + CFG_OFFSET);
|
||||
|
||||
/* flush TX/RX FIFOs and set RX FIFO threshold to zero */
|
||||
val = (1 << M_FIFO_RX_FLUSH_SHIFT) | (1 << M_FIFO_TX_FLUSH_SHIFT);
|
||||
writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
|
||||
|
||||
/* disable all interrupts */
|
||||
writel(0, iproc_i2c->base + IE_OFFSET);
|
||||
|
||||
/* clear all pending interrupts */
|
||||
writel(0xffffffff, iproc_i2c->base + IS_OFFSET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bcm_iproc_i2c_enable_disable(struct bcm_iproc_i2c_dev *iproc_i2c,
|
||||
bool enable)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(iproc_i2c->base + CFG_OFFSET);
|
||||
if (enable)
|
||||
val |= BIT(CFG_EN_SHIFT);
|
||||
else
|
||||
val &= ~BIT(CFG_EN_SHIFT);
|
||||
writel(val, iproc_i2c->base + CFG_OFFSET);
|
||||
}
|
||||
|
||||
static int bcm_iproc_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
int irq, ret = 0;
|
||||
|
|
Loading…
Reference in New Issue