diff options
| -rw-r--r-- | Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt | 2 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-s3c2410.c | 66 |
2 files changed, 58 insertions, 10 deletions
diff --git a/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt b/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt index 296eb4536129..278de8e64bbf 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt | |||
| @@ -10,6 +10,8 @@ Required properties: | |||
| 10 | inside HDMIPHY block found on several samsung SoCs | 10 | inside HDMIPHY block found on several samsung SoCs |
| 11 | (d) "samsung, exynos5440-i2c", for s3c2440-like i2c used | 11 | (d) "samsung, exynos5440-i2c", for s3c2440-like i2c used |
| 12 | on EXYNOS5440 which does not need GPIO configuration. | 12 | on EXYNOS5440 which does not need GPIO configuration. |
| 13 | (e) "samsung, exynos5-sata-phy-i2c", for s3c2440-like i2c used as | ||
| 14 | a host to SATA PHY controller on an internal bus. | ||
| 13 | - reg: physical base address of the controller and length of memory mapped | 15 | - reg: physical base address of the controller and length of memory mapped |
| 14 | region. | 16 | region. |
| 15 | - interrupts: interrupt number to the cpu. | 17 | - interrupts: interrupt number to the cpu. |
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index bf8fb94ebc5d..09f251d0716f 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c | |||
| @@ -86,6 +86,7 @@ | |||
| 86 | #define QUIRK_S3C2440 (1 << 0) | 86 | #define QUIRK_S3C2440 (1 << 0) |
| 87 | #define QUIRK_HDMIPHY (1 << 1) | 87 | #define QUIRK_HDMIPHY (1 << 1) |
| 88 | #define QUIRK_NO_GPIO (1 << 2) | 88 | #define QUIRK_NO_GPIO (1 << 2) |
| 89 | #define QUIRK_POLL (1 << 3) | ||
| 89 | 90 | ||
| 90 | /* Max time to wait for bus to become idle after a xfer (in us) */ | 91 | /* Max time to wait for bus to become idle after a xfer (in us) */ |
| 91 | #define S3C2410_IDLE_TIMEOUT 5000 | 92 | #define S3C2410_IDLE_TIMEOUT 5000 |
| @@ -142,6 +143,8 @@ static struct platform_device_id s3c24xx_driver_ids[] = { | |||
| 142 | }; | 143 | }; |
| 143 | MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); | 144 | MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); |
| 144 | 145 | ||
| 146 | static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat); | ||
| 147 | |||
| 145 | #ifdef CONFIG_OF | 148 | #ifdef CONFIG_OF |
| 146 | static const struct of_device_id s3c24xx_i2c_match[] = { | 149 | static const struct of_device_id s3c24xx_i2c_match[] = { |
| 147 | { .compatible = "samsung,s3c2410-i2c", .data = (void *)0 }, | 150 | { .compatible = "samsung,s3c2410-i2c", .data = (void *)0 }, |
| @@ -150,6 +153,8 @@ static const struct of_device_id s3c24xx_i2c_match[] = { | |||
| 150 | .data = (void *)(QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO) }, | 153 | .data = (void *)(QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO) }, |
| 151 | { .compatible = "samsung,exynos5440-i2c", | 154 | { .compatible = "samsung,exynos5440-i2c", |
| 152 | .data = (void *)(QUIRK_S3C2440 | QUIRK_NO_GPIO) }, | 155 | .data = (void *)(QUIRK_S3C2440 | QUIRK_NO_GPIO) }, |
| 156 | { .compatible = "samsung,exynos5-sata-phy-i2c", | ||
| 157 | .data = (void *)(QUIRK_S3C2440 | QUIRK_POLL | QUIRK_NO_GPIO) }, | ||
| 153 | {}, | 158 | {}, |
| 154 | }; | 159 | }; |
| 155 | MODULE_DEVICE_TABLE(of, s3c24xx_i2c_match); | 160 | MODULE_DEVICE_TABLE(of, s3c24xx_i2c_match); |
| @@ -188,7 +193,8 @@ static inline void s3c24xx_i2c_master_complete(struct s3c24xx_i2c *i2c, int ret) | |||
| 188 | if (ret) | 193 | if (ret) |
| 189 | i2c->msg_idx = ret; | 194 | i2c->msg_idx = ret; |
| 190 | 195 | ||
| 191 | wake_up(&i2c->wait); | 196 | if (!(i2c->quirks & QUIRK_POLL)) |
| 197 | wake_up(&i2c->wait); | ||
| 192 | } | 198 | } |
| 193 | 199 | ||
| 194 | static inline void s3c24xx_i2c_disable_ack(struct s3c24xx_i2c *i2c) | 200 | static inline void s3c24xx_i2c_disable_ack(struct s3c24xx_i2c *i2c) |
| @@ -225,6 +231,22 @@ static inline void s3c24xx_i2c_enable_irq(struct s3c24xx_i2c *i2c) | |||
| 225 | writel(tmp | S3C2410_IICCON_IRQEN, i2c->regs + S3C2410_IICCON); | 231 | writel(tmp | S3C2410_IICCON_IRQEN, i2c->regs + S3C2410_IICCON); |
| 226 | } | 232 | } |
| 227 | 233 | ||
| 234 | static bool is_ack(struct s3c24xx_i2c *i2c) | ||
| 235 | { | ||
| 236 | int tries; | ||
| 237 | |||
| 238 | for (tries = 50; tries; --tries) { | ||
| 239 | if (readl(i2c->regs + S3C2410_IICCON) | ||
| 240 | & S3C2410_IICCON_IRQPEND) { | ||
| 241 | if (!(readl(i2c->regs + S3C2410_IICSTAT) | ||
| 242 | & S3C2410_IICSTAT_LASTBIT)) | ||
| 243 | return true; | ||
| 244 | } | ||
| 245 | usleep_range(1000, 2000); | ||
| 246 | } | ||
| 247 | dev_err(i2c->dev, "ack was not recieved\n"); | ||
| 248 | return false; | ||
| 249 | } | ||
| 228 | 250 | ||
| 229 | /* s3c24xx_i2c_message_start | 251 | /* s3c24xx_i2c_message_start |
| 230 | * | 252 | * |
| @@ -269,6 +291,16 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c, | |||
| 269 | 291 | ||
| 270 | stat |= S3C2410_IICSTAT_START; | 292 | stat |= S3C2410_IICSTAT_START; |
| 271 | writel(stat, i2c->regs + S3C2410_IICSTAT); | 293 | writel(stat, i2c->regs + S3C2410_IICSTAT); |
| 294 | |||
| 295 | if (i2c->quirks & QUIRK_POLL) { | ||
| 296 | while ((i2c->msg_num != 0) && is_ack(i2c)) { | ||
| 297 | i2c_s3c_irq_nextbyte(i2c, stat); | ||
| 298 | stat = readl(i2c->regs + S3C2410_IICSTAT); | ||
| 299 | |||
| 300 | if (stat & S3C2410_IICSTAT_ARBITR) | ||
| 301 | dev_err(i2c->dev, "deal with arbitration loss\n"); | ||
| 302 | } | ||
| 303 | } | ||
| 272 | } | 304 | } |
| 273 | 305 | ||
| 274 | static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret) | 306 | static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret) |
| @@ -676,6 +708,15 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, | |||
| 676 | s3c24xx_i2c_enable_irq(i2c); | 708 | s3c24xx_i2c_enable_irq(i2c); |
| 677 | s3c24xx_i2c_message_start(i2c, msgs); | 709 | s3c24xx_i2c_message_start(i2c, msgs); |
| 678 | 710 | ||
| 711 | if (i2c->quirks & QUIRK_POLL) { | ||
| 712 | ret = i2c->msg_idx; | ||
| 713 | |||
| 714 | if (ret != num) | ||
| 715 | dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret); | ||
| 716 | |||
| 717 | goto out; | ||
| 718 | } | ||
| 719 | |||
| 679 | timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); | 720 | timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); |
| 680 | 721 | ||
| 681 | ret = i2c->msg_idx; | 722 | ret = i2c->msg_idx; |
| @@ -821,6 +862,9 @@ static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got) | |||
| 821 | if (div1 == 512) | 862 | if (div1 == 512) |
| 822 | iiccon |= S3C2410_IICCON_TXDIV_512; | 863 | iiccon |= S3C2410_IICCON_TXDIV_512; |
| 823 | 864 | ||
| 865 | if (i2c->quirks & QUIRK_POLL) | ||
| 866 | iiccon |= S3C2410_IICCON_SCALE(2); | ||
| 867 | |||
| 824 | writel(iiccon, i2c->regs + S3C2410_IICCON); | 868 | writel(iiccon, i2c->regs + S3C2410_IICCON); |
| 825 | 869 | ||
| 826 | if (i2c->quirks & QUIRK_S3C2440) { | 870 | if (i2c->quirks & QUIRK_S3C2440) { |
| @@ -1118,18 +1162,20 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) | |||
| 1118 | * ensure no current IRQs pending | 1162 | * ensure no current IRQs pending |
| 1119 | */ | 1163 | */ |
| 1120 | 1164 | ||
| 1121 | i2c->irq = ret = platform_get_irq(pdev, 0); | 1165 | if (!(i2c->quirks & QUIRK_POLL)) { |
| 1122 | if (ret <= 0) { | 1166 | i2c->irq = ret = platform_get_irq(pdev, 0); |
| 1123 | dev_err(&pdev->dev, "cannot find IRQ\n"); | 1167 | if (ret <= 0) { |
| 1124 | return ret; | 1168 | dev_err(&pdev->dev, "cannot find IRQ\n"); |
| 1125 | } | 1169 | return ret; |
| 1170 | } | ||
| 1126 | 1171 | ||
| 1127 | ret = devm_request_irq(&pdev->dev, i2c->irq, s3c24xx_i2c_irq, 0, | 1172 | ret = devm_request_irq(&pdev->dev, i2c->irq, s3c24xx_i2c_irq, 0, |
| 1128 | dev_name(&pdev->dev), i2c); | 1173 | dev_name(&pdev->dev), i2c); |
| 1129 | 1174 | ||
| 1130 | if (ret != 0) { | 1175 | if (ret != 0) { |
| 1131 | dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq); | 1176 | dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq); |
| 1132 | return ret; | 1177 | return ret; |
| 1178 | } | ||
| 1133 | } | 1179 | } |
| 1134 | 1180 | ||
| 1135 | ret = s3c24xx_i2c_register_cpufreq(i2c); | 1181 | ret = s3c24xx_i2c_register_cpufreq(i2c); |
