Not all implementations of the OCORES i2c bus master support generating interrupts. Add support for polling the interrupt status bit when no interrupt is defined. Signed-off-by: Andrew Lunn <andrew@xxxxxxx> --- drivers/i2c/busses/i2c-ocores.c | 64 ++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index d2730efe6bec..9576e842e557 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -13,6 +13,7 @@ */ #include <linux/clk.h> +#include <linux/delay.h> #include <linux/err.h> #include <linux/kernel.h> #include <linux/module.h> @@ -40,10 +41,14 @@ struct ocores_i2c { struct clk *clk; int ip_clock_khz; int bus_clock_khz; + int flags; void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value); u8 (*getreg)(struct ocores_i2c *i2c, int reg); }; +/* flags */ +#define I2C_FLAG_NOIRQ BIT(0) + /* registers */ #define OCI2C_PRELOW 0 #define OCI2C_PREHIGH 1 @@ -224,6 +229,27 @@ static irqreturn_t ocores_isr(int irq, void *dev_id) return IRQ_HANDLED; } +static void ocores_poll_irq(struct ocores_i2c *i2c) +{ + int timeout = 500; + u8 stat; + + do { + /* delay 2-3 SCL (5-7usec for 400KHz) */ + usleep_range(5, 7); + stat = oc_getreg(i2c, OCI2C_STATUS); + } while ((stat & OCI2C_STAT_TIP) && timeout--); + + + if (!(stat & OCI2C_STAT_TIP)) { + ocores_process(i2c); + } else { + i2c->state = STATE_ERROR; + dev_dbg(&i2c->adap.dev, "Timeout while polling %02x\n", stat); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + } +} + static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct ocores_i2c *i2c = i2c_get_adapdata(adap); @@ -236,11 +262,18 @@ static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) oc_setreg(i2c, OCI2C_DATA, i2c_8bit_addr_from_msg(i2c->msg)); oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); - if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) || - (i2c->state == STATE_DONE), HZ)) + if (i2c->flags & I2C_FLAG_NOIRQ) { + while (!((i2c->state == STATE_DONE) || + (i2c->state == STATE_ERROR))) + ocores_poll_irq(i2c); return (i2c->state == STATE_DONE) ? num : -EIO; - else - return -ETIMEDOUT; + } else { + if (wait_event_timeout(i2c->wait, + (i2c->state == STATE_ERROR) || + (i2c->state == STATE_DONE), HZ)) + return (i2c->state == STATE_DONE) ? num : -EIO; + } + return -ETIMEDOUT; } static int ocores_init(struct device *dev, struct ocores_i2c *i2c) @@ -425,14 +458,17 @@ static int ocores_i2c_probe(struct platform_device *pdev) int ret; int i; - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); if (!i2c) return -ENOMEM; + irq = platform_get_irq(pdev, 0); + if (irq == -ENXIO) + i2c->flags |= I2C_FLAG_NOIRQ; + else + if (irq < 0) + return irq; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res) { i2c->base = devm_ioremap_resource(&pdev->dev, res); @@ -504,11 +540,13 @@ static int ocores_i2c_probe(struct platform_device *pdev) goto err_clk; init_waitqueue_head(&i2c->wait); - ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0, - pdev->name, i2c); - if (ret) { - dev_err(&pdev->dev, "Cannot claim IRQ\n"); - goto err_clk; + if (!(i2c->flags & I2C_FLAG_NOIRQ)) { + ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0, + pdev->name, i2c); + if (ret) { + dev_err(&pdev->dev, "Cannot claim IRQ\n"); + goto err_clk; + } } /* hook up driver to tree */ -- 2.20.1