Message ID | 1351612897-14923-5-git-send-email-vasanthananthan@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hi, Missed to include Ben, for I2C patch, including him and copying others. Thanks, Vasanth. On Tue, Oct 30, 2012 at 9:31 PM, Vasanth Ananthan <vasanthananthan@gmail.com> wrote: > This patch adds polling mode support for i2c s3c-2410 driver. > The I2C_SATAPHY controller lacks an interrupt line but the s3c-2410 driver > is interrupt driven. Hence this support is required for functioning > of the I2C_SATAPHY controller. > > Signed-off-by: Vasanth Ananthan <vasanth.a@samsung.com> > --- > drivers/i2c/busses/i2c-s3c2410.c | 79 ++++++++++++++++++++++++++++--------- > 1 files changed, 60 insertions(+), 19 deletions(-) > > diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c > index 3e0335f..5712e40 100644 > --- a/drivers/i2c/busses/i2c-s3c2410.c > +++ b/drivers/i2c/busses/i2c-s3c2410.c > @@ -48,6 +48,7 @@ > #define QUIRK_S3C2440 (1 << 0) > #define QUIRK_HDMIPHY (1 << 1) > #define QUIRK_NO_GPIO (1 << 2) > +#define QUIRK_SATAPHY (1 << 3) > > /* i2c controller state */ > enum s3c24xx_i2c_state { > @@ -102,10 +103,14 @@ static struct platform_device_id s3c24xx_driver_ids[] = { > }; > MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); > > +static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat); > + > #ifdef CONFIG_OF > static const struct of_device_id s3c24xx_i2c_match[] = { > { .compatible = "samsung,s3c2410-i2c", .data = (void *)0 }, > { .compatible = "samsung,s3c2440-i2c", .data = (void *)QUIRK_S3C2440 }, > + { .compatible = "samsung,exynos5-sata-phy-i2c", > + .data = (void *)(QUIRK_S3C2440 | QUIRK_SATAPHY | QUIRK_NO_GPIO) }, > { .compatible = "samsung,s3c2440-hdmiphy-i2c", > .data = (void *)(QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO) }, > {}, > @@ -146,7 +151,8 @@ static inline void s3c24xx_i2c_master_complete(struct s3c24xx_i2c *i2c, int ret) > if (ret) > i2c->msg_idx = ret; > > - wake_up(&i2c->wait); > + if (!(i2c->quirks & QUIRK_SATAPHY)) > + wake_up(&i2c->wait); > } > > static inline void s3c24xx_i2c_disable_ack(struct s3c24xx_i2c *i2c) > @@ -184,6 +190,23 @@ static inline void s3c24xx_i2c_enable_irq(struct s3c24xx_i2c *i2c) > } > > > +static bool is_ack(struct s3c24xx_i2c *i2c) > +{ > + u32 time_out = i2c->tx_setup; > + > + while (--time_out) { > + if (readl(i2c->regs + S3C2410_IICCON) > + & S3C2410_IICCON_IRQPEND) { > + if (!(readl(i2c->regs + S3C2410_IICSTAT) > + & S3C2410_IICSTAT_LASTBIT)) > + return true; > + } > + udelay(time_out); > + } > + > + return false; > +} > + > /* s3c24xx_i2c_message_start > * > * put the start of a message onto the bus > @@ -227,6 +250,15 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c, > > stat |= S3C2410_IICSTAT_START; > writel(stat, i2c->regs + S3C2410_IICSTAT); > + > + if (i2c->quirks & QUIRK_SATAPHY) { > + while ((i2c->msg_num != 0) && is_ack(i2c)) { > + i2c_s3c_irq_nextbyte(i2c, stat); > + stat = readl(i2c->regs + S3C2410_IICSTAT); > + if (stat & S3C2410_IICSTAT_ARBITR) > + dev_err(i2c->dev, "deal with arbitration loss\n"); > + } > + } > } > > static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret) > @@ -552,19 +584,23 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, > s3c24xx_i2c_message_start(i2c, msgs); > spin_unlock_irq(&i2c->lock); > > - timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); > - > ret = i2c->msg_idx; > > - /* having these next two as dev_err() makes life very > - * noisy when doing an i2cdetect */ > + if (!(i2c->quirks & QUIRK_SATAPHY)) { > > - if (timeout == 0) > - dev_dbg(i2c->dev, "timeout\n"); > - else if (ret != num) > - dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret); > + timeout = wait_event_timeout(i2c->wait, > + i2c->msg_num == 0, HZ * 5); > > - /* ensure the stop has been through the bus */ > + /* having these next two as dev_err() makes life very > + * noisy when doing an i2cdetect */ > + > + if (timeout == 0) > + dev_dbg(i2c->dev, "timeout\n"); > + else if (ret != num) > + dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret); > + > + /* ensure the stop has been through the bus */ > + } > > dev_dbg(i2c->dev, "waiting for bus idle\n"); > > @@ -710,6 +746,9 @@ static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got) > if (div1 == 512) > iiccon |= S3C2410_IICCON_TXDIV_512; > > + if (i2c->quirks & QUIRK_SATAPHY) > + iiccon |= S3C2410_IICCON_SCALE(2); > + > writel(iiccon, i2c->regs + S3C2410_IICCON); > > if (i2c->quirks & QUIRK_S3C2440) { > @@ -1023,18 +1062,20 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) > * ensure no current IRQs pending > */ > > - i2c->irq = ret = platform_get_irq(pdev, 0); > - if (ret <= 0) { > - dev_err(&pdev->dev, "cannot find IRQ\n"); > - goto err_iomap; > - } > + if (!(i2c->quirks & QUIRK_SATAPHY)) { > + i2c->irq = ret = platform_get_irq(pdev, 0); > + if (ret <= 0) { > + dev_err(&pdev->dev, "cannot find IRQ\n"); > + goto err_iomap; > + } > > - ret = request_irq(i2c->irq, s3c24xx_i2c_irq, 0, > + ret = request_irq(i2c->irq, s3c24xx_i2c_irq, 0, > dev_name(&pdev->dev), i2c); > > - if (ret != 0) { > - dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq); > - goto err_iomap; > + if (ret != 0) { > + dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq); > + goto err_iomap; > + } > } > > ret = s3c24xx_i2c_register_cpufreq(i2c); > -- > 1.7.4.1 >
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 3e0335f..5712e40 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -48,6 +48,7 @@ #define QUIRK_S3C2440 (1 << 0) #define QUIRK_HDMIPHY (1 << 1) #define QUIRK_NO_GPIO (1 << 2) +#define QUIRK_SATAPHY (1 << 3) /* i2c controller state */ enum s3c24xx_i2c_state { @@ -102,10 +103,14 @@ static struct platform_device_id s3c24xx_driver_ids[] = { }; MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); +static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat); + #ifdef CONFIG_OF static const struct of_device_id s3c24xx_i2c_match[] = { { .compatible = "samsung,s3c2410-i2c", .data = (void *)0 }, { .compatible = "samsung,s3c2440-i2c", .data = (void *)QUIRK_S3C2440 }, + { .compatible = "samsung,exynos5-sata-phy-i2c", + .data = (void *)(QUIRK_S3C2440 | QUIRK_SATAPHY | QUIRK_NO_GPIO) }, { .compatible = "samsung,s3c2440-hdmiphy-i2c", .data = (void *)(QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO) }, {}, @@ -146,7 +151,8 @@ static inline void s3c24xx_i2c_master_complete(struct s3c24xx_i2c *i2c, int ret) if (ret) i2c->msg_idx = ret; - wake_up(&i2c->wait); + if (!(i2c->quirks & QUIRK_SATAPHY)) + wake_up(&i2c->wait); } static inline void s3c24xx_i2c_disable_ack(struct s3c24xx_i2c *i2c) @@ -184,6 +190,23 @@ static inline void s3c24xx_i2c_enable_irq(struct s3c24xx_i2c *i2c) } +static bool is_ack(struct s3c24xx_i2c *i2c) +{ + u32 time_out = i2c->tx_setup; + + while (--time_out) { + if (readl(i2c->regs + S3C2410_IICCON) + & S3C2410_IICCON_IRQPEND) { + if (!(readl(i2c->regs + S3C2410_IICSTAT) + & S3C2410_IICSTAT_LASTBIT)) + return true; + } + udelay(time_out); + } + + return false; +} + /* s3c24xx_i2c_message_start * * put the start of a message onto the bus @@ -227,6 +250,15 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c, stat |= S3C2410_IICSTAT_START; writel(stat, i2c->regs + S3C2410_IICSTAT); + + if (i2c->quirks & QUIRK_SATAPHY) { + while ((i2c->msg_num != 0) && is_ack(i2c)) { + i2c_s3c_irq_nextbyte(i2c, stat); + stat = readl(i2c->regs + S3C2410_IICSTAT); + if (stat & S3C2410_IICSTAT_ARBITR) + dev_err(i2c->dev, "deal with arbitration loss\n"); + } + } } static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret) @@ -552,19 +584,23 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, s3c24xx_i2c_message_start(i2c, msgs); spin_unlock_irq(&i2c->lock); - timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); - ret = i2c->msg_idx; - /* having these next two as dev_err() makes life very - * noisy when doing an i2cdetect */ + if (!(i2c->quirks & QUIRK_SATAPHY)) { - if (timeout == 0) - dev_dbg(i2c->dev, "timeout\n"); - else if (ret != num) - dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret); + timeout = wait_event_timeout(i2c->wait, + i2c->msg_num == 0, HZ * 5); - /* ensure the stop has been through the bus */ + /* having these next two as dev_err() makes life very + * noisy when doing an i2cdetect */ + + if (timeout == 0) + dev_dbg(i2c->dev, "timeout\n"); + else if (ret != num) + dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret); + + /* ensure the stop has been through the bus */ + } dev_dbg(i2c->dev, "waiting for bus idle\n"); @@ -710,6 +746,9 @@ static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got) if (div1 == 512) iiccon |= S3C2410_IICCON_TXDIV_512; + if (i2c->quirks & QUIRK_SATAPHY) + iiccon |= S3C2410_IICCON_SCALE(2); + writel(iiccon, i2c->regs + S3C2410_IICCON); if (i2c->quirks & QUIRK_S3C2440) { @@ -1023,18 +1062,20 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) * ensure no current IRQs pending */ - i2c->irq = ret = platform_get_irq(pdev, 0); - if (ret <= 0) { - dev_err(&pdev->dev, "cannot find IRQ\n"); - goto err_iomap; - } + if (!(i2c->quirks & QUIRK_SATAPHY)) { + i2c->irq = ret = platform_get_irq(pdev, 0); + if (ret <= 0) { + dev_err(&pdev->dev, "cannot find IRQ\n"); + goto err_iomap; + } - ret = request_irq(i2c->irq, s3c24xx_i2c_irq, 0, + ret = request_irq(i2c->irq, s3c24xx_i2c_irq, 0, dev_name(&pdev->dev), i2c); - if (ret != 0) { - dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq); - goto err_iomap; + if (ret != 0) { + dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq); + goto err_iomap; + } } ret = s3c24xx_i2c_register_cpufreq(i2c);
This patch adds polling mode support for i2c s3c-2410 driver. The I2C_SATAPHY controller lacks an interrupt line but the s3c-2410 driver is interrupt driven. Hence this support is required for functioning of the I2C_SATAPHY controller. Signed-off-by: Vasanth Ananthan <vasanth.a@samsung.com> --- drivers/i2c/busses/i2c-s3c2410.c | 79 ++++++++++++++++++++++++++++--------- 1 files changed, 60 insertions(+), 19 deletions(-)