diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-exynos5.c')
-rw-r--r-- | drivers/i2c/busses/i2c-exynos5.c | 71 |
1 files changed, 65 insertions, 6 deletions
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); |