aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNaveen Krishna Ch <ch.naveen@samsung.com>2014-09-16 05:33:17 -0400
committerWolfram Sang <wsa@the-dreams.de>2014-10-02 21:35:49 -0400
commit2374a5399b7263eb1afc6b5522a56ebf9f0b8636 (patch)
treebd920d59a3d9cc198c52311058d6a004e4f91f64
parent030f940a535433605e6b4ee43f36189e5cace022 (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.txt2
-rw-r--r--drivers/i2c/busses/Kconfig2
-rw-r--r--drivers/i2c/busses/i2c-exynos5.c71
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
466config I2C_EXYNOS5 466config 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
146struct exynos5_i2c { 158struct 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 */
193struct exynos_hsi2c_variant { 205struct exynos_hsi2c_variant {
194 unsigned int fifo_depth; 206 unsigned int fifo_depth;
207 unsigned int hw;
195}; 208};
196 209
197static const struct exynos_hsi2c_variant exynos5250_hsi2c_data = { 210static 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
218static const struct exynos_hsi2c_variant exynos7_hsi2c_data = {
219 .fifo_depth = 16,
220 .hw = HSI2C_EXYNOS7,
221};
222
205static const struct of_device_id exynos5_i2c_match[] = { 223static 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};
217MODULE_DEVICE_TABLE(of, exynos5_i2c_match); 238MODULE_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)
512static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop) 565static 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);