diff options
author | Naveen Krishna Ch <ch.naveen@samsung.com> | 2014-09-16 05:33:17 -0400 |
---|---|---|
committer | Wolfram Sang <wsa@the-dreams.de> | 2014-10-02 21:35:49 -0400 |
commit | 2374a5399b7263eb1afc6b5522a56ebf9f0b8636 (patch) | |
tree | bd920d59a3d9cc198c52311058d6a004e4f91f64 | |
parent | 030f940a535433605e6b4ee43f36189e5cace022 (diff) |
i2c: exynos: add support for HSI2C module on Exynos7
The HSI2C module on Exynos7 differs in the transfer status
bits. Transfer status bits were moved to INT_ENABLE and
INT_STATUS registers
This patch adds support for the HSI2C module on Exynos7.
1. Implementes a "hw" field in the variant struct to distinguish
the hardware.
2. Updates the dt-new compatible in dt-binding documenation
Signed-off-by: Naveen Krishna Chatradhi <ch.naveen@samsung.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
-rw-r--r-- | Documentation/devicetree/bindings/i2c/i2c-exynos5.txt | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/Kconfig | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-exynos5.c | 71 |
3 files changed, 68 insertions, 7 deletions
diff --git a/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt b/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt index d4745e31f5c6..2dbc0b62daa6 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt | |||
@@ -12,6 +12,8 @@ Required properties: | |||
12 | on Exynos5250 and Exynos5420 SoCs. | 12 | on Exynos5250 and Exynos5420 SoCs. |
13 | -> "samsung,exynos5260-hsi2c", for i2c compatible with HSI2C available | 13 | -> "samsung,exynos5260-hsi2c", for i2c compatible with HSI2C available |
14 | on Exynos5260 SoCs. | 14 | on Exynos5260 SoCs. |
15 | -> "samsung,exynos7-hsi2c", for i2c compatible with HSI2C available | ||
16 | on Exynos7 SoCs. | ||
15 | 17 | ||
16 | - reg: physical base address of the controller and length of memory mapped | 18 | - reg: physical base address of the controller and length of memory mapped |
17 | region. | 19 | region. |
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 2ac87fa3058d..1f3b9cb1faa7 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig | |||
@@ -465,7 +465,7 @@ config I2C_EG20T | |||
465 | 465 | ||
466 | config I2C_EXYNOS5 | 466 | config I2C_EXYNOS5 |
467 | tristate "Exynos5 high-speed I2C driver" | 467 | tristate "Exynos5 high-speed I2C driver" |
468 | depends on ARCH_EXYNOS5 && OF | 468 | depends on ARCH_EXYNOS && OF |
469 | default y | 469 | default y |
470 | help | 470 | help |
471 | High-speed I2C controller on Exynos5 based Samsung SoCs. | 471 | High-speed I2C controller on Exynos5 based Samsung SoCs. |
diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 28073f1d6d47..81e6263cd7da 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c | |||
@@ -83,7 +83,6 @@ | |||
83 | #define HSI2C_INT_TX_ALMOSTEMPTY_EN (1u << 0) | 83 | #define HSI2C_INT_TX_ALMOSTEMPTY_EN (1u << 0) |
84 | #define HSI2C_INT_RX_ALMOSTFULL_EN (1u << 1) | 84 | #define HSI2C_INT_RX_ALMOSTFULL_EN (1u << 1) |
85 | #define HSI2C_INT_TRAILING_EN (1u << 6) | 85 | #define HSI2C_INT_TRAILING_EN (1u << 6) |
86 | #define HSI2C_INT_I2C_EN (1u << 9) | ||
87 | 86 | ||
88 | /* I2C_INT_STAT Register bits */ | 87 | /* I2C_INT_STAT Register bits */ |
89 | #define HSI2C_INT_TX_ALMOSTEMPTY (1u << 0) | 88 | #define HSI2C_INT_TX_ALMOSTEMPTY (1u << 0) |
@@ -95,6 +94,17 @@ | |||
95 | #define HSI2C_INT_TRAILING (1u << 6) | 94 | #define HSI2C_INT_TRAILING (1u << 6) |
96 | #define HSI2C_INT_I2C (1u << 9) | 95 | #define HSI2C_INT_I2C (1u << 9) |
97 | 96 | ||
97 | #define HSI2C_INT_TRANS_DONE (1u << 7) | ||
98 | #define HSI2C_INT_TRANS_ABORT (1u << 8) | ||
99 | #define HSI2C_INT_NO_DEV_ACK (1u << 9) | ||
100 | #define HSI2C_INT_NO_DEV (1u << 10) | ||
101 | #define HSI2C_INT_TIMEOUT (1u << 11) | ||
102 | #define HSI2C_INT_I2C_TRANS (HSI2C_INT_TRANS_DONE | \ | ||
103 | HSI2C_INT_TRANS_ABORT | \ | ||
104 | HSI2C_INT_NO_DEV_ACK | \ | ||
105 | HSI2C_INT_NO_DEV | \ | ||
106 | HSI2C_INT_TIMEOUT) | ||
107 | |||
98 | /* I2C_FIFO_STAT Register bits */ | 108 | /* I2C_FIFO_STAT Register bits */ |
99 | #define HSI2C_RX_FIFO_EMPTY (1u << 24) | 109 | #define HSI2C_RX_FIFO_EMPTY (1u << 24) |
100 | #define HSI2C_RX_FIFO_FULL (1u << 23) | 110 | #define HSI2C_RX_FIFO_FULL (1u << 23) |
@@ -143,6 +153,8 @@ | |||
143 | 153 | ||
144 | #define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(1000)) | 154 | #define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(1000)) |
145 | 155 | ||
156 | #define HSI2C_EXYNOS7 BIT(0) | ||
157 | |||
146 | struct exynos5_i2c { | 158 | struct exynos5_i2c { |
147 | struct i2c_adapter adap; | 159 | struct i2c_adapter adap; |
148 | unsigned int suspended:1; | 160 | unsigned int suspended:1; |
@@ -192,6 +204,7 @@ struct exynos5_i2c { | |||
192 | */ | 204 | */ |
193 | struct exynos_hsi2c_variant { | 205 | struct exynos_hsi2c_variant { |
194 | unsigned int fifo_depth; | 206 | unsigned int fifo_depth; |
207 | unsigned int hw; | ||
195 | }; | 208 | }; |
196 | 209 | ||
197 | static const struct exynos_hsi2c_variant exynos5250_hsi2c_data = { | 210 | static const struct exynos_hsi2c_variant exynos5250_hsi2c_data = { |
@@ -202,6 +215,11 @@ static const struct exynos_hsi2c_variant exynos5260_hsi2c_data = { | |||
202 | .fifo_depth = 16, | 215 | .fifo_depth = 16, |
203 | }; | 216 | }; |
204 | 217 | ||
218 | static const struct exynos_hsi2c_variant exynos7_hsi2c_data = { | ||
219 | .fifo_depth = 16, | ||
220 | .hw = HSI2C_EXYNOS7, | ||
221 | }; | ||
222 | |||
205 | static const struct of_device_id exynos5_i2c_match[] = { | 223 | static const struct of_device_id exynos5_i2c_match[] = { |
206 | { | 224 | { |
207 | .compatible = "samsung,exynos5-hsi2c", | 225 | .compatible = "samsung,exynos5-hsi2c", |
@@ -212,6 +230,9 @@ static const struct of_device_id exynos5_i2c_match[] = { | |||
212 | }, { | 230 | }, { |
213 | .compatible = "samsung,exynos5260-hsi2c", | 231 | .compatible = "samsung,exynos5260-hsi2c", |
214 | .data = &exynos5260_hsi2c_data | 232 | .data = &exynos5260_hsi2c_data |
233 | }, { | ||
234 | .compatible = "samsung,exynos7-hsi2c", | ||
235 | .data = &exynos7_hsi2c_data | ||
215 | }, {}, | 236 | }, {}, |
216 | }; | 237 | }; |
217 | MODULE_DEVICE_TABLE(of, exynos5_i2c_match); | 238 | MODULE_DEVICE_TABLE(of, exynos5_i2c_match); |
@@ -256,13 +277,24 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode) | |||
256 | i2c->hs_clock : i2c->fs_clock; | 277 | i2c->hs_clock : i2c->fs_clock; |
257 | 278 | ||
258 | /* | 279 | /* |
280 | * In case of HSI2C controller in Exynos5 series | ||
259 | * FPCLK / FI2C = | 281 | * FPCLK / FI2C = |
260 | * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + 2 * FLT_CYCLE | 282 | * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + 2 * FLT_CYCLE |
283 | * | ||
284 | * In case of HSI2C controllers in Exynos7 series | ||
285 | * FPCLK / FI2C = | ||
286 | * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + FLT_CYCLE | ||
287 | * | ||
261 | * utemp0 = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) | 288 | * utemp0 = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) |
262 | * utemp1 = (TSCLK_L + TSCLK_H + 2) | 289 | * utemp1 = (TSCLK_L + TSCLK_H + 2) |
263 | */ | 290 | */ |
264 | t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7; | 291 | t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7; |
265 | utemp0 = (clkin / op_clk) - 8 - 2 * t_ftl_cycle; | 292 | utemp0 = (clkin / op_clk) - 8; |
293 | |||
294 | if (i2c->variant->hw == HSI2C_EXYNOS7) | ||
295 | utemp0 -= t_ftl_cycle; | ||
296 | else | ||
297 | utemp0 -= 2 * t_ftl_cycle; | ||
266 | 298 | ||
267 | /* CLK_DIV max is 256 */ | 299 | /* CLK_DIV max is 256 */ |
268 | for (div = 0; div < 256; div++) { | 300 | for (div = 0; div < 256; div++) { |
@@ -407,7 +439,28 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) | |||
407 | writel(int_status, i2c->regs + HSI2C_INT_STATUS); | 439 | writel(int_status, i2c->regs + HSI2C_INT_STATUS); |
408 | 440 | ||
409 | /* handle interrupt related to the transfer status */ | 441 | /* handle interrupt related to the transfer status */ |
410 | if (int_status & HSI2C_INT_I2C) { | 442 | if (i2c->variant->hw == HSI2C_EXYNOS7) { |
443 | if (int_status & HSI2C_INT_TRANS_DONE) { | ||
444 | i2c->trans_done = 1; | ||
445 | i2c->state = 0; | ||
446 | } else if (int_status & HSI2C_INT_TRANS_ABORT) { | ||
447 | dev_dbg(i2c->dev, "Deal with arbitration lose\n"); | ||
448 | i2c->state = -EAGAIN; | ||
449 | goto stop; | ||
450 | } else if (int_status & HSI2C_INT_NO_DEV_ACK) { | ||
451 | dev_dbg(i2c->dev, "No ACK from device\n"); | ||
452 | i2c->state = -ENXIO; | ||
453 | goto stop; | ||
454 | } else if (int_status & HSI2C_INT_NO_DEV) { | ||
455 | dev_dbg(i2c->dev, "No device\n"); | ||
456 | i2c->state = -ENXIO; | ||
457 | goto stop; | ||
458 | } else if (int_status & HSI2C_INT_TIMEOUT) { | ||
459 | dev_dbg(i2c->dev, "Accessing device timed out\n"); | ||
460 | i2c->state = -EAGAIN; | ||
461 | goto stop; | ||
462 | } | ||
463 | } else if (int_status & HSI2C_INT_I2C) { | ||
411 | trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS); | 464 | trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS); |
412 | if (trans_status & HSI2C_NO_DEV_ACK) { | 465 | if (trans_status & HSI2C_NO_DEV_ACK) { |
413 | dev_dbg(i2c->dev, "No ACK from device\n"); | 466 | dev_dbg(i2c->dev, "No ACK from device\n"); |
@@ -512,12 +565,17 @@ static int exynos5_i2c_wait_bus_idle(struct exynos5_i2c *i2c) | |||
512 | static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop) | 565 | static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop) |
513 | { | 566 | { |
514 | u32 i2c_ctl; | 567 | u32 i2c_ctl; |
515 | u32 int_en = HSI2C_INT_I2C_EN; | 568 | u32 int_en = 0; |
516 | u32 i2c_auto_conf = 0; | 569 | u32 i2c_auto_conf = 0; |
517 | u32 fifo_ctl; | 570 | u32 fifo_ctl; |
518 | unsigned long flags; | 571 | unsigned long flags; |
519 | unsigned short trig_lvl; | 572 | unsigned short trig_lvl; |
520 | 573 | ||
574 | if (i2c->variant->hw == HSI2C_EXYNOS7) | ||
575 | int_en |= HSI2C_INT_I2C_TRANS; | ||
576 | else | ||
577 | int_en |= HSI2C_INT_I2C; | ||
578 | |||
521 | i2c_ctl = readl(i2c->regs + HSI2C_CTL); | 579 | i2c_ctl = readl(i2c->regs + HSI2C_CTL); |
522 | i2c_ctl &= ~(HSI2C_TXCHON | HSI2C_RXCHON); | 580 | i2c_ctl &= ~(HSI2C_TXCHON | HSI2C_RXCHON); |
523 | fifo_ctl = HSI2C_RXFIFO_EN | HSI2C_TXFIFO_EN; | 581 | fifo_ctl = HSI2C_RXFIFO_EN | HSI2C_TXFIFO_EN; |
@@ -724,12 +782,13 @@ static int exynos5_i2c_probe(struct platform_device *pdev) | |||
724 | goto err_clk; | 782 | goto err_clk; |
725 | } | 783 | } |
726 | 784 | ||
785 | /* Need to check the variant before setting up. */ | ||
786 | i2c->variant = exynos5_i2c_get_variant(pdev); | ||
787 | |||
727 | ret = exynos5_hsi2c_clock_setup(i2c); | 788 | ret = exynos5_hsi2c_clock_setup(i2c); |
728 | if (ret) | 789 | if (ret) |
729 | goto err_clk; | 790 | goto err_clk; |
730 | 791 | ||
731 | i2c->variant = exynos5_i2c_get_variant(pdev); | ||
732 | |||
733 | exynos5_i2c_reset(i2c); | 792 | exynos5_i2c_reset(i2c); |
734 | 793 | ||
735 | ret = i2c_add_adapter(&i2c->adap); | 794 | ret = i2c_add_adapter(&i2c->adap); |