diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-tegra.c')
-rw-r--r-- | drivers/i2c/busses/i2c-tegra.c | 132 |
1 files changed, 93 insertions, 39 deletions
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 66eb53fac202..f981ac4e6783 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/i2c-tegra.h> | 28 | #include <linux/i2c-tegra.h> |
29 | #include <linux/of_i2c.h> | 29 | #include <linux/of_i2c.h> |
30 | #include <linux/of_device.h> | ||
30 | #include <linux/module.h> | 31 | #include <linux/module.h> |
31 | 32 | ||
32 | #include <asm/unaligned.h> | 33 | #include <asm/unaligned.h> |
@@ -114,11 +115,21 @@ enum msg_end_type { | |||
114 | }; | 115 | }; |
115 | 116 | ||
116 | /** | 117 | /** |
118 | * struct tegra_i2c_hw_feature : Different HW support on Tegra | ||
119 | * @has_continue_xfer_support: Continue transfer supports. | ||
120 | */ | ||
121 | |||
122 | struct tegra_i2c_hw_feature { | ||
123 | bool has_continue_xfer_support; | ||
124 | }; | ||
125 | |||
126 | /** | ||
117 | * struct tegra_i2c_dev - per device i2c context | 127 | * struct tegra_i2c_dev - per device i2c context |
118 | * @dev: device reference for power management | 128 | * @dev: device reference for power management |
129 | * @hw: Tegra i2c hw feature. | ||
119 | * @adapter: core i2c layer adapter information | 130 | * @adapter: core i2c layer adapter information |
120 | * @clk: clock reference for i2c controller | 131 | * @div_clk: clock reference for div clock of i2c controller. |
121 | * @i2c_clk: clock reference for i2c bus | 132 | * @fast_clk: clock reference for fast clock of i2c controller. |
122 | * @base: ioremapped registers cookie | 133 | * @base: ioremapped registers cookie |
123 | * @cont_id: i2c controller id, used for for packet header | 134 | * @cont_id: i2c controller id, used for for packet header |
124 | * @irq: irq number of transfer complete interrupt | 135 | * @irq: irq number of transfer complete interrupt |
@@ -133,9 +144,10 @@ enum msg_end_type { | |||
133 | */ | 144 | */ |
134 | struct tegra_i2c_dev { | 145 | struct tegra_i2c_dev { |
135 | struct device *dev; | 146 | struct device *dev; |
147 | const struct tegra_i2c_hw_feature *hw; | ||
136 | struct i2c_adapter adapter; | 148 | struct i2c_adapter adapter; |
137 | struct clk *clk; | 149 | struct clk *div_clk; |
138 | struct clk *i2c_clk; | 150 | struct clk *fast_clk; |
139 | void __iomem *base; | 151 | void __iomem *base; |
140 | int cont_id; | 152 | int cont_id; |
141 | int irq; | 153 | int irq; |
@@ -351,16 +363,40 @@ static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev) | |||
351 | dvc_writel(i2c_dev, val, DVC_CTRL_REG1); | 363 | dvc_writel(i2c_dev, val, DVC_CTRL_REG1); |
352 | } | 364 | } |
353 | 365 | ||
366 | static inline int tegra_i2c_clock_enable(struct tegra_i2c_dev *i2c_dev) | ||
367 | { | ||
368 | int ret; | ||
369 | ret = clk_prepare_enable(i2c_dev->fast_clk); | ||
370 | if (ret < 0) { | ||
371 | dev_err(i2c_dev->dev, | ||
372 | "Enabling fast clk failed, err %d\n", ret); | ||
373 | return ret; | ||
374 | } | ||
375 | ret = clk_prepare_enable(i2c_dev->div_clk); | ||
376 | if (ret < 0) { | ||
377 | dev_err(i2c_dev->dev, | ||
378 | "Enabling div clk failed, err %d\n", ret); | ||
379 | clk_disable_unprepare(i2c_dev->fast_clk); | ||
380 | } | ||
381 | return ret; | ||
382 | } | ||
383 | |||
384 | static inline void tegra_i2c_clock_disable(struct tegra_i2c_dev *i2c_dev) | ||
385 | { | ||
386 | clk_disable_unprepare(i2c_dev->div_clk); | ||
387 | clk_disable_unprepare(i2c_dev->fast_clk); | ||
388 | } | ||
389 | |||
354 | static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) | 390 | static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) |
355 | { | 391 | { |
356 | u32 val; | 392 | u32 val; |
357 | int err = 0; | 393 | int err = 0; |
358 | 394 | ||
359 | clk_prepare_enable(i2c_dev->clk); | 395 | tegra_i2c_clock_enable(i2c_dev); |
360 | 396 | ||
361 | tegra_periph_reset_assert(i2c_dev->clk); | 397 | tegra_periph_reset_assert(i2c_dev->div_clk); |
362 | udelay(2); | 398 | udelay(2); |
363 | tegra_periph_reset_deassert(i2c_dev->clk); | 399 | tegra_periph_reset_deassert(i2c_dev->div_clk); |
364 | 400 | ||
365 | if (i2c_dev->is_dvc) | 401 | if (i2c_dev->is_dvc) |
366 | tegra_dvc_init(i2c_dev); | 402 | tegra_dvc_init(i2c_dev); |
@@ -369,7 +405,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) | |||
369 | (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT); | 405 | (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT); |
370 | i2c_writel(i2c_dev, val, I2C_CNFG); | 406 | i2c_writel(i2c_dev, val, I2C_CNFG); |
371 | i2c_writel(i2c_dev, 0, I2C_INT_MASK); | 407 | i2c_writel(i2c_dev, 0, I2C_INT_MASK); |
372 | clk_set_rate(i2c_dev->clk, i2c_dev->bus_clk_rate * 8); | 408 | clk_set_rate(i2c_dev->div_clk, i2c_dev->bus_clk_rate * 8); |
373 | 409 | ||
374 | if (!i2c_dev->is_dvc) { | 410 | if (!i2c_dev->is_dvc) { |
375 | u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG); | 411 | u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG); |
@@ -387,7 +423,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) | |||
387 | if (tegra_i2c_flush_fifos(i2c_dev)) | 423 | if (tegra_i2c_flush_fifos(i2c_dev)) |
388 | err = -ETIMEDOUT; | 424 | err = -ETIMEDOUT; |
389 | 425 | ||
390 | clk_disable_unprepare(i2c_dev->clk); | 426 | tegra_i2c_clock_disable(i2c_dev); |
391 | 427 | ||
392 | if (i2c_dev->irq_disabled) { | 428 | if (i2c_dev->irq_disabled) { |
393 | i2c_dev->irq_disabled = 0; | 429 | i2c_dev->irq_disabled = 0; |
@@ -563,7 +599,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], | |||
563 | if (i2c_dev->is_suspended) | 599 | if (i2c_dev->is_suspended) |
564 | return -EBUSY; | 600 | return -EBUSY; |
565 | 601 | ||
566 | clk_prepare_enable(i2c_dev->clk); | 602 | tegra_i2c_clock_enable(i2c_dev); |
567 | for (i = 0; i < num; i++) { | 603 | for (i = 0; i < num; i++) { |
568 | enum msg_end_type end_type = MSG_END_STOP; | 604 | enum msg_end_type end_type = MSG_END_STOP; |
569 | if (i < (num - 1)) { | 605 | if (i < (num - 1)) { |
@@ -576,14 +612,19 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], | |||
576 | if (ret) | 612 | if (ret) |
577 | break; | 613 | break; |
578 | } | 614 | } |
579 | clk_disable_unprepare(i2c_dev->clk); | 615 | tegra_i2c_clock_disable(i2c_dev); |
580 | return ret ?: i; | 616 | return ret ?: i; |
581 | } | 617 | } |
582 | 618 | ||
583 | static u32 tegra_i2c_func(struct i2c_adapter *adap) | 619 | static u32 tegra_i2c_func(struct i2c_adapter *adap) |
584 | { | 620 | { |
585 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | | 621 | struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap); |
586 | I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_NOSTART; | 622 | u32 ret = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | |
623 | I2C_FUNC_PROTOCOL_MANGLING; | ||
624 | |||
625 | if (i2c_dev->hw->has_continue_xfer_support) | ||
626 | ret |= I2C_FUNC_NOSTART; | ||
627 | return ret; | ||
587 | } | 628 | } |
588 | 629 | ||
589 | static const struct i2c_algorithm tegra_i2c_algo = { | 630 | static const struct i2c_algorithm tegra_i2c_algo = { |
@@ -591,13 +632,32 @@ static const struct i2c_algorithm tegra_i2c_algo = { | |||
591 | .functionality = tegra_i2c_func, | 632 | .functionality = tegra_i2c_func, |
592 | }; | 633 | }; |
593 | 634 | ||
635 | static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { | ||
636 | .has_continue_xfer_support = false, | ||
637 | }; | ||
638 | |||
639 | static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { | ||
640 | .has_continue_xfer_support = true, | ||
641 | }; | ||
642 | |||
643 | #if defined(CONFIG_OF) | ||
644 | /* Match table for of_platform binding */ | ||
645 | static const struct of_device_id tegra_i2c_of_match[] __devinitconst = { | ||
646 | { .compatible = "nvidia,tegra30-i2c", .data = &tegra30_i2c_hw, }, | ||
647 | { .compatible = "nvidia,tegra20-i2c", .data = &tegra20_i2c_hw, }, | ||
648 | { .compatible = "nvidia,tegra20-i2c-dvc", .data = &tegra20_i2c_hw, }, | ||
649 | {}, | ||
650 | }; | ||
651 | MODULE_DEVICE_TABLE(of, tegra_i2c_of_match); | ||
652 | #endif | ||
653 | |||
594 | static int __devinit tegra_i2c_probe(struct platform_device *pdev) | 654 | static int __devinit tegra_i2c_probe(struct platform_device *pdev) |
595 | { | 655 | { |
596 | struct tegra_i2c_dev *i2c_dev; | 656 | struct tegra_i2c_dev *i2c_dev; |
597 | struct tegra_i2c_platform_data *pdata = pdev->dev.platform_data; | 657 | struct tegra_i2c_platform_data *pdata = pdev->dev.platform_data; |
598 | struct resource *res; | 658 | struct resource *res; |
599 | struct clk *clk; | 659 | struct clk *div_clk; |
600 | struct clk *i2c_clk; | 660 | struct clk *fast_clk; |
601 | const unsigned int *prop; | 661 | const unsigned int *prop; |
602 | void __iomem *base; | 662 | void __iomem *base; |
603 | int irq; | 663 | int irq; |
@@ -622,16 +682,16 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) | |||
622 | } | 682 | } |
623 | irq = res->start; | 683 | irq = res->start; |
624 | 684 | ||
625 | clk = devm_clk_get(&pdev->dev, NULL); | 685 | div_clk = devm_clk_get(&pdev->dev, "div-clk"); |
626 | if (IS_ERR(clk)) { | 686 | if (IS_ERR(div_clk)) { |
627 | dev_err(&pdev->dev, "missing controller clock"); | 687 | dev_err(&pdev->dev, "missing controller clock"); |
628 | return PTR_ERR(clk); | 688 | return PTR_ERR(div_clk); |
629 | } | 689 | } |
630 | 690 | ||
631 | i2c_clk = devm_clk_get(&pdev->dev, "i2c"); | 691 | fast_clk = devm_clk_get(&pdev->dev, "fast-clk"); |
632 | if (IS_ERR(i2c_clk)) { | 692 | if (IS_ERR(fast_clk)) { |
633 | dev_err(&pdev->dev, "missing bus clock"); | 693 | dev_err(&pdev->dev, "missing bus clock"); |
634 | return PTR_ERR(i2c_clk); | 694 | return PTR_ERR(fast_clk); |
635 | } | 695 | } |
636 | 696 | ||
637 | i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); | 697 | i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); |
@@ -641,8 +701,8 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) | |||
641 | } | 701 | } |
642 | 702 | ||
643 | i2c_dev->base = base; | 703 | i2c_dev->base = base; |
644 | i2c_dev->clk = clk; | 704 | i2c_dev->div_clk = div_clk; |
645 | i2c_dev->i2c_clk = i2c_clk; | 705 | i2c_dev->fast_clk = fast_clk; |
646 | i2c_dev->adapter.algo = &tegra_i2c_algo; | 706 | i2c_dev->adapter.algo = &tegra_i2c_algo; |
647 | i2c_dev->irq = irq; | 707 | i2c_dev->irq = irq; |
648 | i2c_dev->cont_id = pdev->id; | 708 | i2c_dev->cont_id = pdev->id; |
@@ -659,11 +719,18 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) | |||
659 | i2c_dev->bus_clk_rate = be32_to_cpup(prop); | 719 | i2c_dev->bus_clk_rate = be32_to_cpup(prop); |
660 | } | 720 | } |
661 | 721 | ||
662 | if (pdev->dev.of_node) | 722 | i2c_dev->hw = &tegra20_i2c_hw; |
723 | |||
724 | if (pdev->dev.of_node) { | ||
725 | const struct of_device_id *match; | ||
726 | match = of_match_device(of_match_ptr(tegra_i2c_of_match), | ||
727 | &pdev->dev); | ||
728 | i2c_dev->hw = match->data; | ||
663 | i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node, | 729 | i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node, |
664 | "nvidia,tegra20-i2c-dvc"); | 730 | "nvidia,tegra20-i2c-dvc"); |
665 | else if (pdev->id == 3) | 731 | } else if (pdev->id == 3) { |
666 | i2c_dev->is_dvc = 1; | 732 | i2c_dev->is_dvc = 1; |
733 | } | ||
667 | init_completion(&i2c_dev->msg_complete); | 734 | init_completion(&i2c_dev->msg_complete); |
668 | 735 | ||
669 | platform_set_drvdata(pdev, i2c_dev); | 736 | platform_set_drvdata(pdev, i2c_dev); |
@@ -681,8 +748,6 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) | |||
681 | return ret; | 748 | return ret; |
682 | } | 749 | } |
683 | 750 | ||
684 | clk_prepare_enable(i2c_dev->i2c_clk); | ||
685 | |||
686 | i2c_set_adapdata(&i2c_dev->adapter, i2c_dev); | 751 | i2c_set_adapdata(&i2c_dev->adapter, i2c_dev); |
687 | i2c_dev->adapter.owner = THIS_MODULE; | 752 | i2c_dev->adapter.owner = THIS_MODULE; |
688 | i2c_dev->adapter.class = I2C_CLASS_HWMON; | 753 | i2c_dev->adapter.class = I2C_CLASS_HWMON; |
@@ -696,7 +761,6 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) | |||
696 | ret = i2c_add_numbered_adapter(&i2c_dev->adapter); | 761 | ret = i2c_add_numbered_adapter(&i2c_dev->adapter); |
697 | if (ret) { | 762 | if (ret) { |
698 | dev_err(&pdev->dev, "Failed to add I2C adapter\n"); | 763 | dev_err(&pdev->dev, "Failed to add I2C adapter\n"); |
699 | clk_disable_unprepare(i2c_dev->i2c_clk); | ||
700 | return ret; | 764 | return ret; |
701 | } | 765 | } |
702 | 766 | ||
@@ -712,7 +776,7 @@ static int __devexit tegra_i2c_remove(struct platform_device *pdev) | |||
712 | return 0; | 776 | return 0; |
713 | } | 777 | } |
714 | 778 | ||
715 | #ifdef CONFIG_PM | 779 | #ifdef CONFIG_PM_SLEEP |
716 | static int tegra_i2c_suspend(struct device *dev) | 780 | static int tegra_i2c_suspend(struct device *dev) |
717 | { | 781 | { |
718 | struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); | 782 | struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); |
@@ -751,16 +815,6 @@ static SIMPLE_DEV_PM_OPS(tegra_i2c_pm, tegra_i2c_suspend, tegra_i2c_resume); | |||
751 | #define TEGRA_I2C_PM NULL | 815 | #define TEGRA_I2C_PM NULL |
752 | #endif | 816 | #endif |
753 | 817 | ||
754 | #if defined(CONFIG_OF) | ||
755 | /* Match table for of_platform binding */ | ||
756 | static const struct of_device_id tegra_i2c_of_match[] __devinitconst = { | ||
757 | { .compatible = "nvidia,tegra20-i2c", }, | ||
758 | { .compatible = "nvidia,tegra20-i2c-dvc", }, | ||
759 | {}, | ||
760 | }; | ||
761 | MODULE_DEVICE_TABLE(of, tegra_i2c_of_match); | ||
762 | #endif | ||
763 | |||
764 | static struct platform_driver tegra_i2c_driver = { | 818 | static struct platform_driver tegra_i2c_driver = { |
765 | .probe = tegra_i2c_probe, | 819 | .probe = tegra_i2c_probe, |
766 | .remove = __devexit_p(tegra_i2c_remove), | 820 | .remove = __devexit_p(tegra_i2c_remove), |