Skip to content

Commit c73178b

Browse files
committed
i2c: tegra: Add support for the VI I2C on Tegra210
Tegra210 has an extra instance of the I2C controller that is in the domain of host1x and usually used for camera use-cases. The programming model for the VI variant of the controller is roughly the same as for the other variants, except that the I2C registers start at an offset and are spaced further apart. VI I2C also doesn't support slave mode. Signed-off-by: Thierry Reding <[email protected]>
1 parent 82dd45f commit c73178b

File tree

1 file changed

+95
-2
lines changed

1 file changed

+95
-2
lines changed

drivers/i2c/busses/i2c-tegra.c

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#define I2C_SL_CNFG_NEWSL BIT(2)
4141
#define I2C_SL_ADDR1 0x02c
4242
#define I2C_SL_ADDR2 0x030
43+
#define I2C_TLOW_SEXT 0x034
4344
#define I2C_TX_FIFO 0x050
4445
#define I2C_RX_FIFO 0x054
4546
#define I2C_PACKET_TRANSFER_STATUS 0x058
@@ -109,6 +110,18 @@
109110
#define I2C_INTERFACE_TIMING_THIGH GENMASK(13, 8)
110111
#define I2C_INTERFACE_TIMING_TLOW GENMASK(5, 0)
111112
#define I2C_INTERFACE_TIMING_1 0x098
113+
#define I2C_INTERFACE_TIMING_TBUF GENMASK(29, 24)
114+
#define I2C_INTERFACE_TIMING_TSU_STO GENMASK(21, 16)
115+
#define I2C_INTERFACE_TIMING_THD_STA GENMASK(13, 8)
116+
#define I2C_INTERFACE_TIMING_TSU_STA GENMASK(5, 0)
117+
118+
#define I2C_HS_INTERFACE_TIMING_0 0x09c
119+
#define I2C_HS_INTERFACE_TIMING_THIGH GENMASK(13, 8)
120+
#define I2C_HS_INTERFACE_TIMING_TLOW GENMASK(5, 0)
121+
#define I2C_HS_INTERFACE_TIMING_1 0x0a0
122+
#define I2C_HS_INTERFACE_TIMING_TSU_STO GENMASK(21, 16)
123+
#define I2C_HS_INTERFACE_TIMING_THD_STA GENMASK(13, 8)
124+
#define I2C_HS_INTERFACE_TIMING_TSU_STA GENMASK(5, 0)
112125

113126
#define I2C_MST_FIFO_CONTROL 0x0b4
114127
#define I2C_MST_FIFO_CONTROL_RX_FLUSH BIT(0)
@@ -230,6 +243,7 @@ struct tegra_i2c_hw_feature {
230243
* @cont_id: I2C controller ID, used for packet header
231244
* @irq: IRQ number of transfer complete interrupt
232245
* @is_dvc: identifies the DVC I2C controller, has a different register layout
246+
* @is_vi: identifies the VI I2C controller, has a different register layout
233247
* @msg_complete: transfer completion notifier
234248
* @msg_err: error code for completed message
235249
* @msg_buf: pointer to current message data
@@ -253,12 +267,14 @@ struct tegra_i2c_dev {
253267
struct i2c_adapter adapter;
254268
struct clk *div_clk;
255269
struct clk *fast_clk;
270+
struct clk *slow_clk;
256271
struct reset_control *rst;
257272
void __iomem *base;
258273
phys_addr_t base_phys;
259274
int cont_id;
260275
int irq;
261276
int is_dvc;
277+
bool is_vi;
262278
struct completion msg_complete;
263279
int msg_err;
264280
u8 *msg_buf;
@@ -297,6 +313,8 @@ static unsigned long tegra_i2c_reg_addr(struct tegra_i2c_dev *i2c_dev,
297313
{
298314
if (i2c_dev->is_dvc)
299315
reg += (reg >= I2C_TX_FIFO) ? 0x10 : 0x40;
316+
else if (i2c_dev->is_vi)
317+
reg = 0xc00 + (reg << 2);
300318
return reg;
301319
}
302320

@@ -646,6 +664,14 @@ static int __maybe_unused tegra_i2c_runtime_resume(struct device *dev)
646664
}
647665
}
648666

667+
if (i2c_dev->slow_clk) {
668+
ret = clk_enable(i2c_dev->slow_clk);
669+
if (ret < 0) {
670+
dev_err(dev, "failed to enable slow clock: %d\n", ret);
671+
return ret;
672+
}
673+
}
674+
649675
ret = clk_enable(i2c_dev->div_clk);
650676
if (ret < 0) {
651677
dev_err(i2c_dev->dev,
@@ -662,6 +688,10 @@ static int __maybe_unused tegra_i2c_runtime_suspend(struct device *dev)
662688
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
663689

664690
clk_disable(i2c_dev->div_clk);
691+
692+
if (i2c_dev->slow_clk)
693+
clk_disable(i2c_dev->slow_clk);
694+
665695
if (!i2c_dev->hw->has_single_clk_source)
666696
clk_disable(i2c_dev->fast_clk);
667697

@@ -699,6 +729,35 @@ static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev)
699729
return 0;
700730
}
701731

732+
static void tegra_i2c_vi_init(struct tegra_i2c_dev *i2c_dev)
733+
{
734+
u32 value;
735+
736+
value = FIELD_PREP(I2C_INTERFACE_TIMING_THIGH, 2) |
737+
FIELD_PREP(I2C_INTERFACE_TIMING_TLOW, 4);
738+
i2c_writel(i2c_dev, value, I2C_INTERFACE_TIMING_0);
739+
740+
value = FIELD_PREP(I2C_INTERFACE_TIMING_TBUF, 4) |
741+
FIELD_PREP(I2C_INTERFACE_TIMING_TSU_STO, 7) |
742+
FIELD_PREP(I2C_INTERFACE_TIMING_THD_STA, 4) |
743+
FIELD_PREP(I2C_INTERFACE_TIMING_TSU_STA, 4);
744+
i2c_writel(i2c_dev, value, I2C_INTERFACE_TIMING_1);
745+
746+
value = FIELD_PREP(I2C_HS_INTERFACE_TIMING_THIGH, 3) |
747+
FIELD_PREP(I2C_HS_INTERFACE_TIMING_TLOW, 8);
748+
i2c_writel(i2c_dev, value, I2C_HS_INTERFACE_TIMING_0);
749+
750+
value = FIELD_PREP(I2C_HS_INTERFACE_TIMING_TSU_STO, 11) |
751+
FIELD_PREP(I2C_HS_INTERFACE_TIMING_THD_STA, 11) |
752+
FIELD_PREP(I2C_HS_INTERFACE_TIMING_TSU_STA, 11);
753+
i2c_writel(i2c_dev, value, I2C_HS_INTERFACE_TIMING_1);
754+
755+
value = FIELD_PREP(I2C_BC_SCLK_THRESHOLD, 9) | I2C_BC_STOP_COND;
756+
i2c_writel(i2c_dev, value, I2C_BUS_CLEAR_CNFG);
757+
758+
i2c_writel(i2c_dev, 0x0, I2C_TLOW_SEXT);
759+
}
760+
702761
static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
703762
{
704763
u32 val;
@@ -723,6 +782,9 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
723782
i2c_writel(i2c_dev, val, I2C_CNFG);
724783
i2c_writel(i2c_dev, 0, I2C_INT_MASK);
725784

785+
if (i2c_dev->is_vi)
786+
tegra_i2c_vi_init(i2c_dev);
787+
726788
/* Make sure clock divisor programmed correctly */
727789
clk_divisor = FIELD_PREP(I2C_CLK_DIVISOR_HSMODE,
728790
i2c_dev->hw->clk_divisor_hs_mode) |
@@ -766,7 +828,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
766828
}
767829
}
768830

769-
if (!i2c_dev->is_dvc) {
831+
if (!i2c_dev->is_dvc && !i2c_dev->is_vi) {
770832
u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG);
771833

772834
sl_cfg |= I2C_SL_CNFG_NACK | I2C_SL_CNFG_NEWSL;
@@ -1555,6 +1617,7 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
15551617
static const struct of_device_id tegra_i2c_of_match[] = {
15561618
{ .compatible = "nvidia,tegra194-i2c", .data = &tegra194_i2c_hw, },
15571619
{ .compatible = "nvidia,tegra186-i2c", .data = &tegra186_i2c_hw, },
1620+
{ .compatible = "nvidia,tegra210-i2c-vi", .data = &tegra210_i2c_hw, },
15581621
{ .compatible = "nvidia,tegra210-i2c", .data = &tegra210_i2c_hw, },
15591622
{ .compatible = "nvidia,tegra124-i2c", .data = &tegra124_i2c_hw, },
15601623
{ .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, },
@@ -1567,6 +1630,7 @@ MODULE_DEVICE_TABLE(of, tegra_i2c_of_match);
15671630

15681631
static int tegra_i2c_probe(struct platform_device *pdev)
15691632
{
1633+
struct device *dev = &pdev->dev;
15701634
struct tegra_i2c_dev *i2c_dev;
15711635
struct resource *res;
15721636
struct clk *div_clk;
@@ -1622,6 +1686,8 @@ static int tegra_i2c_probe(struct platform_device *pdev)
16221686
i2c_dev->hw = of_device_get_match_data(&pdev->dev);
16231687
i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node,
16241688
"nvidia,tegra20-i2c-dvc");
1689+
i2c_dev->is_vi = of_device_is_compatible(dev->of_node,
1690+
"nvidia,tegra210-i2c-vi");
16251691
i2c_dev->adapter.quirks = i2c_dev->hw->quirks;
16261692
i2c_dev->dma_buf_size = i2c_dev->adapter.quirks->max_write_len +
16271693
I2C_PACKET_HEADER_SIZE;
@@ -1637,6 +1703,17 @@ static int tegra_i2c_probe(struct platform_device *pdev)
16371703
i2c_dev->fast_clk = fast_clk;
16381704
}
16391705

1706+
if (i2c_dev->is_vi) {
1707+
i2c_dev->slow_clk = devm_clk_get(dev, "slow");
1708+
if (IS_ERR(i2c_dev->slow_clk)) {
1709+
if (PTR_ERR(i2c_dev->slow_clk) != -EPROBE_DEFER)
1710+
dev_err(dev, "failed to get slow clock: %ld\n",
1711+
PTR_ERR(i2c_dev->slow_clk));
1712+
1713+
return PTR_ERR(i2c_dev->slow_clk);
1714+
}
1715+
}
1716+
16401717
platform_set_drvdata(pdev, i2c_dev);
16411718

16421719
if (!i2c_dev->hw->has_single_clk_source) {
@@ -1647,6 +1724,14 @@ static int tegra_i2c_probe(struct platform_device *pdev)
16471724
}
16481725
}
16491726

1727+
if (i2c_dev->slow_clk) {
1728+
ret = clk_prepare(i2c_dev->slow_clk);
1729+
if (ret < 0) {
1730+
dev_err(dev, "failed to prepare slow clock: %d\n", ret);
1731+
goto unprepare_fast_clk;
1732+
}
1733+
}
1734+
16501735
if (i2c_dev->bus_clk_rate > I2C_MAX_FAST_MODE_FREQ &&
16511736
i2c_dev->bus_clk_rate <= I2C_MAX_FAST_MODE_PLUS_FREQ)
16521737
i2c_dev->clk_divisor_non_hs_mode =
@@ -1662,7 +1747,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
16621747
ret = clk_prepare(i2c_dev->div_clk);
16631748
if (ret < 0) {
16641749
dev_err(i2c_dev->dev, "Clock prepare failed %d\n", ret);
1665-
goto unprepare_fast_clk;
1750+
goto unprepare_slow_clk;
16661751
}
16671752

16681753
pm_runtime_irq_safe(&pdev->dev);
@@ -1749,6 +1834,10 @@ static int tegra_i2c_probe(struct platform_device *pdev)
17491834
unprepare_div_clk:
17501835
clk_unprepare(i2c_dev->div_clk);
17511836

1837+
unprepare_slow_clk:
1838+
if (i2c_dev->is_vi)
1839+
clk_unprepare(i2c_dev->slow_clk);
1840+
17521841
unprepare_fast_clk:
17531842
if (!i2c_dev->hw->has_single_clk_source)
17541843
clk_unprepare(i2c_dev->fast_clk);
@@ -1770,6 +1859,10 @@ static int tegra_i2c_remove(struct platform_device *pdev)
17701859
tegra_i2c_runtime_suspend(&pdev->dev);
17711860

17721861
clk_unprepare(i2c_dev->div_clk);
1862+
1863+
if (i2c_dev->slow_clk)
1864+
clk_unprepare(i2c_dev->slow_clk);
1865+
17731866
if (!i2c_dev->hw->has_single_clk_source)
17741867
clk_unprepare(i2c_dev->fast_clk);
17751868

0 commit comments

Comments
 (0)