diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/i2c/busses/i2c-s3c2410.c | 37 |
1 files changed, 33 insertions, 4 deletions
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 8162901ff753..ae4491062e41 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c | |||
@@ -601,6 +601,31 @@ static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id) | |||
601 | return IRQ_HANDLED; | 601 | return IRQ_HANDLED; |
602 | } | 602 | } |
603 | 603 | ||
604 | /* | ||
605 | * Disable the bus so that we won't get any interrupts from now on, or try | ||
606 | * to drive any lines. This is the default state when we don't have | ||
607 | * anything to send/receive. | ||
608 | * | ||
609 | * If there is an event on the bus, or we have a pre-existing event at | ||
610 | * kernel boot time, we may not notice the event and the I2C controller | ||
611 | * will lock the bus with the I2C clock line low indefinitely. | ||
612 | */ | ||
613 | static inline void s3c24xx_i2c_disable_bus(struct s3c24xx_i2c *i2c) | ||
614 | { | ||
615 | unsigned long tmp; | ||
616 | |||
617 | /* Stop driving the I2C pins */ | ||
618 | tmp = readl(i2c->regs + S3C2410_IICSTAT); | ||
619 | tmp &= ~S3C2410_IICSTAT_TXRXEN; | ||
620 | writel(tmp, i2c->regs + S3C2410_IICSTAT); | ||
621 | |||
622 | /* We don't expect any interrupts now, and don't want send acks */ | ||
623 | tmp = readl(i2c->regs + S3C2410_IICCON); | ||
624 | tmp &= ~(S3C2410_IICCON_IRQEN | S3C2410_IICCON_IRQPEND | | ||
625 | S3C2410_IICCON_ACKEN); | ||
626 | writel(tmp, i2c->regs + S3C2410_IICCON); | ||
627 | } | ||
628 | |||
604 | 629 | ||
605 | /* s3c24xx_i2c_set_master | 630 | /* s3c24xx_i2c_set_master |
606 | * | 631 | * |
@@ -735,7 +760,11 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, | |||
735 | 760 | ||
736 | s3c24xx_i2c_wait_idle(i2c); | 761 | s3c24xx_i2c_wait_idle(i2c); |
737 | 762 | ||
763 | s3c24xx_i2c_disable_bus(i2c); | ||
764 | |||
738 | out: | 765 | out: |
766 | i2c->state = STATE_IDLE; | ||
767 | |||
739 | return ret; | 768 | return ret; |
740 | } | 769 | } |
741 | 770 | ||
@@ -1004,7 +1033,6 @@ static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c) | |||
1004 | 1033 | ||
1005 | static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) | 1034 | static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) |
1006 | { | 1035 | { |
1007 | unsigned long iicon = S3C2410_IICCON_IRQEN | S3C2410_IICCON_ACKEN; | ||
1008 | struct s3c2410_platform_i2c *pdata; | 1036 | struct s3c2410_platform_i2c *pdata; |
1009 | unsigned int freq; | 1037 | unsigned int freq; |
1010 | 1038 | ||
@@ -1018,12 +1046,12 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) | |||
1018 | 1046 | ||
1019 | dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr); | 1047 | dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr); |
1020 | 1048 | ||
1021 | writel(iicon, i2c->regs + S3C2410_IICCON); | 1049 | writel(0, i2c->regs + S3C2410_IICCON); |
1050 | writel(0, i2c->regs + S3C2410_IICSTAT); | ||
1022 | 1051 | ||
1023 | /* we need to work out the divisors for the clock... */ | 1052 | /* we need to work out the divisors for the clock... */ |
1024 | 1053 | ||
1025 | if (s3c24xx_i2c_clockrate(i2c, &freq) != 0) { | 1054 | if (s3c24xx_i2c_clockrate(i2c, &freq) != 0) { |
1026 | writel(0, i2c->regs + S3C2410_IICCON); | ||
1027 | dev_err(i2c->dev, "cannot meet bus frequency required\n"); | 1055 | dev_err(i2c->dev, "cannot meet bus frequency required\n"); |
1028 | return -EINVAL; | 1056 | return -EINVAL; |
1029 | } | 1057 | } |
@@ -1031,7 +1059,8 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) | |||
1031 | /* todo - check that the i2c lines aren't being dragged anywhere */ | 1059 | /* todo - check that the i2c lines aren't being dragged anywhere */ |
1032 | 1060 | ||
1033 | dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq); | 1061 | dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq); |
1034 | dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon); | 1062 | dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02x\n", |
1063 | readl(i2c->regs + S3C2410_IICCON)); | ||
1035 | 1064 | ||
1036 | return 0; | 1065 | return 0; |
1037 | } | 1066 | } |