aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorLaxman Dewangan <ldewangan@nvidia.com>2013-01-05 07:04:46 -0500
committerWolfram Sang <w.sang@pengutronix.de>2013-01-27 23:26:43 -0500
commit2a2897bab2d3d50ab466cf908f03b62801f1ff56 (patch)
treeacd8aa07d9a33368e5bd3223d8d9207b5447f9ae /drivers/i2c
parentb61b14154b19e1ef1da9c1e283f0cf93470e0c70 (diff)
i2c: tegra: add support for Tegra114 SoC
NVIDIA's Tegra114 has following enhanced feature in i2c controller: - Enable/disable control for per packet transfer complete interrupt. Earlier SoCs could not disable this. - Single clock source for standard/fast and HS mode clock speed. The clock divisor for fast/standard mode is added into the i2c controller to meet the HS and standard/fast mode of clock speed from single source. Add support for the above feature to make it functional on T114 SOCs. Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com> Reviewed-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-tegra.c77
1 files changed, 63 insertions, 14 deletions
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 7b38877ffec1..2dadb964c464 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -71,6 +71,8 @@
71#define I2C_INT_TX_FIFO_DATA_REQ (1<<1) 71#define I2C_INT_TX_FIFO_DATA_REQ (1<<1)
72#define I2C_INT_RX_FIFO_DATA_REQ (1<<0) 72#define I2C_INT_RX_FIFO_DATA_REQ (1<<0)
73#define I2C_CLK_DIVISOR 0x06c 73#define I2C_CLK_DIVISOR 0x06c
74#define I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT 16
75#define I2C_CLK_MULTIPLIER_STD_FAST_MODE 8
74 76
75#define DVC_CTRL_REG1 0x000 77#define DVC_CTRL_REG1 0x000
76#define DVC_CTRL_REG1_INTR_EN (1<<10) 78#define DVC_CTRL_REG1_INTR_EN (1<<10)
@@ -117,10 +119,23 @@ enum msg_end_type {
117/** 119/**
118 * struct tegra_i2c_hw_feature : Different HW support on Tegra 120 * struct tegra_i2c_hw_feature : Different HW support on Tegra
119 * @has_continue_xfer_support: Continue transfer supports. 121 * @has_continue_xfer_support: Continue transfer supports.
122 * @has_per_pkt_xfer_complete_irq: Has enable/disable capability for transfer
123 * complete interrupt per packet basis.
124 * @has_single_clk_source: The i2c controller has single clock source. Tegra30
125 * and earlier Socs has two clock sources i.e. div-clk and
126 * fast-clk.
127 * @clk_divisor_hs_mode: Clock divisor in HS mode.
128 * @clk_divisor_std_fast_mode: Clock divisor in standard/fast mode. It is
129 * applicable if there is no fast clock source i.e. single clock
130 * source.
120 */ 131 */
121 132
122struct tegra_i2c_hw_feature { 133struct tegra_i2c_hw_feature {
123 bool has_continue_xfer_support; 134 bool has_continue_xfer_support;
135 bool has_per_pkt_xfer_complete_irq;
136 bool has_single_clk_source;
137 int clk_divisor_hs_mode;
138 int clk_divisor_std_fast_mode;
124}; 139};
125 140
126/** 141/**
@@ -366,11 +381,13 @@ static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev)
366static inline int tegra_i2c_clock_enable(struct tegra_i2c_dev *i2c_dev) 381static inline int tegra_i2c_clock_enable(struct tegra_i2c_dev *i2c_dev)
367{ 382{
368 int ret; 383 int ret;
369 ret = clk_prepare_enable(i2c_dev->fast_clk); 384 if (!i2c_dev->hw->has_single_clk_source) {
370 if (ret < 0) { 385 ret = clk_prepare_enable(i2c_dev->fast_clk);
371 dev_err(i2c_dev->dev, 386 if (ret < 0) {
372 "Enabling fast clk failed, err %d\n", ret); 387 dev_err(i2c_dev->dev,
373 return ret; 388 "Enabling fast clk failed, err %d\n", ret);
389 return ret;
390 }
374 } 391 }
375 ret = clk_prepare_enable(i2c_dev->div_clk); 392 ret = clk_prepare_enable(i2c_dev->div_clk);
376 if (ret < 0) { 393 if (ret < 0) {
@@ -384,13 +401,16 @@ static inline int tegra_i2c_clock_enable(struct tegra_i2c_dev *i2c_dev)
384static inline void tegra_i2c_clock_disable(struct tegra_i2c_dev *i2c_dev) 401static inline void tegra_i2c_clock_disable(struct tegra_i2c_dev *i2c_dev)
385{ 402{
386 clk_disable_unprepare(i2c_dev->div_clk); 403 clk_disable_unprepare(i2c_dev->div_clk);
387 clk_disable_unprepare(i2c_dev->fast_clk); 404 if (!i2c_dev->hw->has_single_clk_source)
405 clk_disable_unprepare(i2c_dev->fast_clk);
388} 406}
389 407
390static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) 408static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
391{ 409{
392 u32 val; 410 u32 val;
393 int err = 0; 411 int err = 0;
412 int clk_multiplier = I2C_CLK_MULTIPLIER_STD_FAST_MODE;
413 u32 clk_divisor;
394 414
395 tegra_i2c_clock_enable(i2c_dev); 415 tegra_i2c_clock_enable(i2c_dev);
396 416
@@ -405,7 +425,15 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
405 (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT); 425 (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
406 i2c_writel(i2c_dev, val, I2C_CNFG); 426 i2c_writel(i2c_dev, val, I2C_CNFG);
407 i2c_writel(i2c_dev, 0, I2C_INT_MASK); 427 i2c_writel(i2c_dev, 0, I2C_INT_MASK);
408 clk_set_rate(i2c_dev->div_clk, i2c_dev->bus_clk_rate * 8); 428
429 clk_multiplier *= (i2c_dev->hw->clk_divisor_std_fast_mode + 1);
430 clk_set_rate(i2c_dev->div_clk, i2c_dev->bus_clk_rate * clk_multiplier);
431
432 /* Make sure clock divisor programmed correctly */
433 clk_divisor = i2c_dev->hw->clk_divisor_hs_mode;
434 clk_divisor |= i2c_dev->hw->clk_divisor_std_fast_mode <<
435 I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT;
436 i2c_writel(i2c_dev, clk_divisor, I2C_CLK_DIVISOR);
409 437
410 if (!i2c_dev->is_dvc) { 438 if (!i2c_dev->is_dvc) {
411 u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG); 439 u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG);
@@ -547,6 +575,8 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
547 tegra_i2c_fill_tx_fifo(i2c_dev); 575 tegra_i2c_fill_tx_fifo(i2c_dev);
548 576
549 int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST; 577 int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
578 if (i2c_dev->hw->has_per_pkt_xfer_complete_irq)
579 int_mask |= I2C_INT_PACKET_XFER_COMPLETE;
550 if (msg->flags & I2C_M_RD) 580 if (msg->flags & I2C_M_RD)
551 int_mask |= I2C_INT_RX_FIFO_DATA_REQ; 581 int_mask |= I2C_INT_RX_FIFO_DATA_REQ;
552 else if (i2c_dev->msg_buf_remaining) 582 else if (i2c_dev->msg_buf_remaining)
@@ -634,15 +664,32 @@ static const struct i2c_algorithm tegra_i2c_algo = {
634 664
635static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { 665static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
636 .has_continue_xfer_support = false, 666 .has_continue_xfer_support = false,
667 .has_per_pkt_xfer_complete_irq = false,
668 .has_single_clk_source = false,
669 .clk_divisor_hs_mode = 3,
670 .clk_divisor_std_fast_mode = 0,
637}; 671};
638 672
639static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { 673static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
640 .has_continue_xfer_support = true, 674 .has_continue_xfer_support = true,
675 .has_per_pkt_xfer_complete_irq = false,
676 .has_single_clk_source = false,
677 .clk_divisor_hs_mode = 3,
678 .clk_divisor_std_fast_mode = 0,
679};
680
681static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
682 .has_continue_xfer_support = true,
683 .has_per_pkt_xfer_complete_irq = true,
684 .has_single_clk_source = true,
685 .clk_divisor_hs_mode = 1,
686 .clk_divisor_std_fast_mode = 0x19,
641}; 687};
642 688
643#if defined(CONFIG_OF) 689#if defined(CONFIG_OF)
644/* Match table for of_platform binding */ 690/* Match table for of_platform binding */
645static const struct of_device_id tegra_i2c_of_match[] = { 691static const struct of_device_id tegra_i2c_of_match[] = {
692 { .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, },
646 { .compatible = "nvidia,tegra30-i2c", .data = &tegra30_i2c_hw, }, 693 { .compatible = "nvidia,tegra30-i2c", .data = &tegra30_i2c_hw, },
647 { .compatible = "nvidia,tegra20-i2c", .data = &tegra20_i2c_hw, }, 694 { .compatible = "nvidia,tegra20-i2c", .data = &tegra20_i2c_hw, },
648 { .compatible = "nvidia,tegra20-i2c-dvc", .data = &tegra20_i2c_hw, }, 695 { .compatible = "nvidia,tegra20-i2c-dvc", .data = &tegra20_i2c_hw, },
@@ -688,12 +735,6 @@ static int tegra_i2c_probe(struct platform_device *pdev)
688 return PTR_ERR(div_clk); 735 return PTR_ERR(div_clk);
689 } 736 }
690 737
691 fast_clk = devm_clk_get(&pdev->dev, "fast-clk");
692 if (IS_ERR(fast_clk)) {
693 dev_err(&pdev->dev, "missing bus clock");
694 return PTR_ERR(fast_clk);
695 }
696
697 i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); 738 i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
698 if (!i2c_dev) { 739 if (!i2c_dev) {
699 dev_err(&pdev->dev, "Could not allocate struct tegra_i2c_dev"); 740 dev_err(&pdev->dev, "Could not allocate struct tegra_i2c_dev");
@@ -702,7 +743,6 @@ static int tegra_i2c_probe(struct platform_device *pdev)
702 743
703 i2c_dev->base = base; 744 i2c_dev->base = base;
704 i2c_dev->div_clk = div_clk; 745 i2c_dev->div_clk = div_clk;
705 i2c_dev->fast_clk = fast_clk;
706 i2c_dev->adapter.algo = &tegra_i2c_algo; 746 i2c_dev->adapter.algo = &tegra_i2c_algo;
707 i2c_dev->irq = irq; 747 i2c_dev->irq = irq;
708 i2c_dev->cont_id = pdev->id; 748 i2c_dev->cont_id = pdev->id;
@@ -733,6 +773,15 @@ static int tegra_i2c_probe(struct platform_device *pdev)
733 } 773 }
734 init_completion(&i2c_dev->msg_complete); 774 init_completion(&i2c_dev->msg_complete);
735 775
776 if (!i2c_dev->hw->has_single_clk_source) {
777 fast_clk = devm_clk_get(&pdev->dev, "fast-clk");
778 if (IS_ERR(fast_clk)) {
779 dev_err(&pdev->dev, "missing fast clock");
780 return PTR_ERR(fast_clk);
781 }
782 i2c_dev->fast_clk = fast_clk;
783 }
784
736 platform_set_drvdata(pdev, i2c_dev); 785 platform_set_drvdata(pdev, i2c_dev);
737 786
738 ret = tegra_i2c_init(i2c_dev); 787 ret = tegra_i2c_init(i2c_dev);