diff options
author | Naveen Krishna Ch <ch.naveen@samsung.com> | 2014-04-28 04:59:58 -0400 |
---|---|---|
committer | Wolfram Sang <wsa@the-dreams.de> | 2014-05-22 04:09:22 -0400 |
commit | 218e1496135e94e901bf1c136d81ede7e2b418b8 (patch) | |
tree | 201d6039862e875ee922370bf50cc1b8523176e8 | |
parent | a83bea7c1170ad8c68d65ed2fff6a533e68f67a4 (diff) |
i2c: exynos5: add support for HSI2C on Exynos5260 SoC
HSI2C module on Exynos5260 differs from current modules in
following ways:
1. HSI2C on Exynos5260 has fifo_depth of 16bytes
2. Module needs to be reset as a part of init sequence.
Hence, Following changes are involved.
1. Add a new compatible string and Updates the Documentation dt bindings.
2. Introduce a variant struct to support the changes in H/W
3. Reset the module during init. Thus, bringing the module back
to default state irrespective of what firmware did with it.
Signed-off-by: Naveen Krishna Chatradhi <ch.naveen@samsung.com>
Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
-rw-r--r-- | Documentation/devicetree/bindings/i2c/i2c-exynos5.txt | 11 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-exynos5.c | 67 |
2 files changed, 64 insertions, 14 deletions
diff --git a/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt b/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt index 056732cfdcee..d4745e31f5c6 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt | |||
@@ -5,7 +5,14 @@ at various speeds ranging from 100khz to 3.4Mhz. | |||
5 | 5 | ||
6 | Required properties: | 6 | Required properties: |
7 | - compatible: value should be. | 7 | - compatible: value should be. |
8 | -> "samsung,exynos5-hsi2c", for i2c compatible with exynos5 hsi2c. | 8 | -> "samsung,exynos5-hsi2c", (DEPRECATED) |
9 | for i2c compatible with HSI2C available | ||
10 | on Exynos5250 and Exynos5420 SoCs. | ||
11 | -> "samsung,exynos5250-hsi2c", for i2c compatible with HSI2C available | ||
12 | on Exynos5250 and Exynos5420 SoCs. | ||
13 | -> "samsung,exynos5260-hsi2c", for i2c compatible with HSI2C available | ||
14 | on Exynos5260 SoCs. | ||
15 | |||
9 | - reg: physical base address of the controller and length of memory mapped | 16 | - reg: physical base address of the controller and length of memory mapped |
10 | region. | 17 | region. |
11 | - interrupts: interrupt number to the cpu. | 18 | - interrupts: interrupt number to the cpu. |
@@ -26,7 +33,7 @@ Optional properties: | |||
26 | Example: | 33 | Example: |
27 | 34 | ||
28 | hsi2c@12ca0000 { | 35 | hsi2c@12ca0000 { |
29 | compatible = "samsung,exynos5-hsi2c"; | 36 | compatible = "samsung,exynos5250-hsi2c"; |
30 | reg = <0x12ca0000 0x100>; | 37 | reg = <0x12ca0000 0x100>; |
31 | interrupts = <56>; | 38 | interrupts = <56>; |
32 | clock-frequency = <100000>; | 39 | clock-frequency = <100000>; |
diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 00af0a0a3361..ba1faf0ef96f 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c | |||
@@ -76,12 +76,6 @@ | |||
76 | #define HSI2C_RXFIFO_TRIGGER_LEVEL(x) ((x) << 4) | 76 | #define HSI2C_RXFIFO_TRIGGER_LEVEL(x) ((x) << 4) |
77 | #define HSI2C_TXFIFO_TRIGGER_LEVEL(x) ((x) << 16) | 77 | #define HSI2C_TXFIFO_TRIGGER_LEVEL(x) ((x) << 16) |
78 | 78 | ||
79 | /* As per user manual FIFO max depth is 64bytes */ | ||
80 | #define HSI2C_FIFO_MAX 0x40 | ||
81 | /* default trigger levels for Tx and Rx FIFOs */ | ||
82 | #define HSI2C_DEF_TXFIFO_LVL (HSI2C_FIFO_MAX - 0x30) | ||
83 | #define HSI2C_DEF_RXFIFO_LVL (HSI2C_FIFO_MAX - 0x10) | ||
84 | |||
85 | /* I2C_TRAILING_CTL Register bits */ | 79 | /* I2C_TRAILING_CTL Register bits */ |
86 | #define HSI2C_TRAILING_COUNT (0xf) | 80 | #define HSI2C_TRAILING_COUNT (0xf) |
87 | 81 | ||
@@ -183,14 +177,54 @@ struct exynos5_i2c { | |||
183 | * 2. Fast speed upto 1Mbps | 177 | * 2. Fast speed upto 1Mbps |
184 | */ | 178 | */ |
185 | int speed_mode; | 179 | int speed_mode; |
180 | |||
181 | /* Version of HS-I2C Hardware */ | ||
182 | struct exynos_hsi2c_variant *variant; | ||
183 | }; | ||
184 | |||
185 | /** | ||
186 | * struct exynos_hsi2c_variant - platform specific HSI2C driver data | ||
187 | * @fifo_depth: the fifo depth supported by the HSI2C module | ||
188 | * | ||
189 | * Specifies platform specific configuration of HSI2C module. | ||
190 | * Note: A structure for driver specific platform data is used for future | ||
191 | * expansion of its usage. | ||
192 | */ | ||
193 | struct exynos_hsi2c_variant { | ||
194 | unsigned int fifo_depth; | ||
195 | }; | ||
196 | |||
197 | static const struct exynos_hsi2c_variant exynos5250_hsi2c_data = { | ||
198 | .fifo_depth = 64, | ||
199 | }; | ||
200 | |||
201 | static const struct exynos_hsi2c_variant exynos5260_hsi2c_data = { | ||
202 | .fifo_depth = 16, | ||
186 | }; | 203 | }; |
187 | 204 | ||
188 | static const struct of_device_id exynos5_i2c_match[] = { | 205 | static const struct of_device_id exynos5_i2c_match[] = { |
189 | { .compatible = "samsung,exynos5-hsi2c" }, | 206 | { |
190 | {}, | 207 | .compatible = "samsung,exynos5-hsi2c", |
208 | .data = &exynos5250_hsi2c_data | ||
209 | }, { | ||
210 | .compatible = "samsung,exynos5250-hsi2c", | ||
211 | .data = &exynos5250_hsi2c_data | ||
212 | }, { | ||
213 | .compatible = "samsung,exynos5260-hsi2c", | ||
214 | .data = &exynos5260_hsi2c_data | ||
215 | }, {}, | ||
191 | }; | 216 | }; |
192 | MODULE_DEVICE_TABLE(of, exynos5_i2c_match); | 217 | MODULE_DEVICE_TABLE(of, exynos5_i2c_match); |
193 | 218 | ||
219 | static inline struct exynos_hsi2c_variant *exynos5_i2c_get_variant | ||
220 | (struct platform_device *pdev) | ||
221 | { | ||
222 | const struct of_device_id *match; | ||
223 | |||
224 | match = of_match_node(exynos5_i2c_match, pdev->dev.of_node); | ||
225 | return (struct exynos_hsi2c_variant *)match->data; | ||
226 | } | ||
227 | |||
194 | static void exynos5_i2c_clr_pend_irq(struct exynos5_i2c *i2c) | 228 | static void exynos5_i2c_clr_pend_irq(struct exynos5_i2c *i2c) |
195 | { | 229 | { |
196 | writel(readl(i2c->regs + HSI2C_INT_STATUS), | 230 | writel(readl(i2c->regs + HSI2C_INT_STATUS), |
@@ -415,7 +449,7 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) | |||
415 | fifo_status = readl(i2c->regs + HSI2C_FIFO_STATUS); | 449 | fifo_status = readl(i2c->regs + HSI2C_FIFO_STATUS); |
416 | fifo_level = HSI2C_TX_FIFO_LVL(fifo_status); | 450 | fifo_level = HSI2C_TX_FIFO_LVL(fifo_status); |
417 | 451 | ||
418 | len = HSI2C_FIFO_MAX - fifo_level; | 452 | len = i2c->variant->fifo_depth - fifo_level; |
419 | if (len > (i2c->msg->len - i2c->msg_ptr)) | 453 | if (len > (i2c->msg->len - i2c->msg_ptr)) |
420 | len = i2c->msg->len - i2c->msg_ptr; | 454 | len = i2c->msg->len - i2c->msg_ptr; |
421 | 455 | ||
@@ -483,6 +517,7 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop) | |||
483 | u32 i2c_auto_conf = 0; | 517 | u32 i2c_auto_conf = 0; |
484 | u32 fifo_ctl; | 518 | u32 fifo_ctl; |
485 | unsigned long flags; | 519 | unsigned long flags; |
520 | unsigned short trig_lvl; | ||
486 | 521 | ||
487 | i2c_ctl = readl(i2c->regs + HSI2C_CTL); | 522 | i2c_ctl = readl(i2c->regs + HSI2C_CTL); |
488 | i2c_ctl &= ~(HSI2C_TXCHON | HSI2C_RXCHON); | 523 | i2c_ctl &= ~(HSI2C_TXCHON | HSI2C_RXCHON); |
@@ -493,13 +528,19 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop) | |||
493 | 528 | ||
494 | i2c_auto_conf = HSI2C_READ_WRITE; | 529 | i2c_auto_conf = HSI2C_READ_WRITE; |
495 | 530 | ||
496 | fifo_ctl |= HSI2C_RXFIFO_TRIGGER_LEVEL(HSI2C_DEF_TXFIFO_LVL); | 531 | trig_lvl = (i2c->msg->len > i2c->variant->fifo_depth) ? |
532 | (i2c->variant->fifo_depth * 3 / 4) : i2c->msg->len; | ||
533 | fifo_ctl |= HSI2C_RXFIFO_TRIGGER_LEVEL(trig_lvl); | ||
534 | |||
497 | int_en |= (HSI2C_INT_RX_ALMOSTFULL_EN | | 535 | int_en |= (HSI2C_INT_RX_ALMOSTFULL_EN | |
498 | HSI2C_INT_TRAILING_EN); | 536 | HSI2C_INT_TRAILING_EN); |
499 | } else { | 537 | } else { |
500 | i2c_ctl |= HSI2C_TXCHON; | 538 | i2c_ctl |= HSI2C_TXCHON; |
501 | 539 | ||
502 | fifo_ctl |= HSI2C_TXFIFO_TRIGGER_LEVEL(HSI2C_DEF_RXFIFO_LVL); | 540 | trig_lvl = (i2c->msg->len > i2c->variant->fifo_depth) ? |
541 | (i2c->variant->fifo_depth * 1 / 4) : i2c->msg->len; | ||
542 | fifo_ctl |= HSI2C_TXFIFO_TRIGGER_LEVEL(trig_lvl); | ||
543 | |||
503 | int_en |= HSI2C_INT_TX_ALMOSTEMPTY_EN; | 544 | int_en |= HSI2C_INT_TX_ALMOSTEMPTY_EN; |
504 | } | 545 | } |
505 | 546 | ||
@@ -691,7 +732,9 @@ static int exynos5_i2c_probe(struct platform_device *pdev) | |||
691 | if (ret) | 732 | if (ret) |
692 | goto err_clk; | 733 | goto err_clk; |
693 | 734 | ||
694 | exynos5_i2c_init(i2c); | 735 | i2c->variant = exynos5_i2c_get_variant(pdev); |
736 | |||
737 | exynos5_i2c_reset(i2c); | ||
695 | 738 | ||
696 | ret = i2c_add_adapter(&i2c->adap); | 739 | ret = i2c_add_adapter(&i2c->adap); |
697 | if (ret < 0) { | 740 | if (ret < 0) { |