Skip to content

Commit 978b3cc

Browse files
akhilr-nvWolfram Sang
authored andcommitted
i2c: tegra: Add HS mode support
Add support for High Speed (HS) mode transfers for Tegra194 and later chips. While HS mode has been documented in the technical reference manuals since Tegra20, the hardware implementation appears to be broken on all chips prior to Tegra194. When HS mode is not supported, set the frequency to FM+ instead. Signed-off-by: Akhil R <akhilrajeev@nvidia.com> Signed-off-by: Kartik Rajput <kkartik@nvidia.com> Reviewed-by: Jon Hunter <jonathanh@nvidia.com> Acked-by: Thierry Reding <treding@nvidia.com> Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
1 parent 81d4c53 commit 978b3cc

1 file changed

Lines changed: 57 additions & 2 deletions

File tree

drivers/i2c/busses/i2c-tegra.c

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
#define PACKET_HEADER0_PROTOCOL GENMASK(7, 4)
8686
#define PACKET_HEADER0_PROTOCOL_I2C 1
8787

88+
#define I2C_HEADER_HS_MODE BIT(22)
8889
#define I2C_HEADER_CONT_ON_NAK BIT(21)
8990
#define I2C_HEADER_READ BIT(19)
9091
#define I2C_HEADER_10BIT_ADDR BIT(18)
@@ -200,6 +201,8 @@ enum msg_end_type {
200201
* @thigh_fast_mode: High period of the clock in fast mode.
201202
* @tlow_fastplus_mode: Low period of the clock in fast-plus mode.
202203
* @thigh_fastplus_mode: High period of the clock in fast-plus mode.
204+
* @tlow_hs_mode: Low period of the clock in HS mode.
205+
* @thigh_hs_mode: High period of the clock in HS mode.
203206
* @setup_hold_time_std_mode: Setup and hold time for start and stop conditions
204207
* in standard mode.
205208
* @setup_hold_time_fast_mode: Setup and hold time for start and stop
@@ -210,6 +213,7 @@ enum msg_end_type {
210213
* in HS mode.
211214
* @has_interface_timing_reg: Has interface timing register to program the tuned
212215
* timing settings.
216+
* @enable_hs_mode_support: Enable support for high speed (HS) mode transfers.
213217
*/
214218
struct tegra_i2c_hw_feature {
215219
bool has_continue_xfer_support;
@@ -232,11 +236,14 @@ struct tegra_i2c_hw_feature {
232236
u32 thigh_fast_mode;
233237
u32 tlow_fastplus_mode;
234238
u32 thigh_fastplus_mode;
239+
u32 tlow_hs_mode;
240+
u32 thigh_hs_mode;
235241
u32 setup_hold_time_std_mode;
236242
u32 setup_hold_time_fast_mode;
237243
u32 setup_hold_time_fastplus_mode;
238244
u32 setup_hold_time_hs_mode;
239245
bool has_interface_timing_reg;
246+
bool enable_hs_mode_support;
240247
};
241248

242249
/**
@@ -646,6 +653,7 @@ static int tegra_i2c_master_reset(struct tegra_i2c_dev *i2c_dev)
646653
static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
647654
{
648655
u32 val, clk_divisor, clk_multiplier, tsu_thd, tlow, thigh, non_hs_mode;
656+
u32 max_bus_freq_hz;
649657
struct i2c_timings *t = &i2c_dev->timings;
650658
int err;
651659

@@ -684,6 +692,14 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
684692
if (IS_VI(i2c_dev))
685693
tegra_i2c_vi_init(i2c_dev);
686694

695+
if (i2c_dev->hw->enable_hs_mode_support)
696+
max_bus_freq_hz = I2C_MAX_HIGH_SPEED_MODE_FREQ;
697+
else
698+
max_bus_freq_hz = I2C_MAX_FAST_MODE_PLUS_FREQ;
699+
700+
if (WARN_ON(t->bus_freq_hz > max_bus_freq_hz))
701+
t->bus_freq_hz = max_bus_freq_hz;
702+
687703
if (t->bus_freq_hz <= I2C_MAX_STANDARD_MODE_FREQ) {
688704
tlow = i2c_dev->hw->tlow_std_mode;
689705
thigh = i2c_dev->hw->thigh_std_mode;
@@ -694,11 +710,22 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
694710
thigh = i2c_dev->hw->thigh_fast_mode;
695711
tsu_thd = i2c_dev->hw->setup_hold_time_fast_mode;
696712
non_hs_mode = i2c_dev->hw->clk_divisor_fast_mode;
697-
} else {
713+
} else if (t->bus_freq_hz <= I2C_MAX_FAST_MODE_PLUS_FREQ) {
698714
tlow = i2c_dev->hw->tlow_fastplus_mode;
699715
thigh = i2c_dev->hw->thigh_fastplus_mode;
700716
tsu_thd = i2c_dev->hw->setup_hold_time_fastplus_mode;
701717
non_hs_mode = i2c_dev->hw->clk_divisor_fast_plus_mode;
718+
} else {
719+
/*
720+
* When using HS mode, i.e. when the bus frequency is greater than fast plus mode,
721+
* the non-hs timing registers will be used for sending the master code byte for
722+
* transition to HS mode. Configure the non-hs timing registers for Fast Mode to
723+
* send the master code byte at 400kHz.
724+
*/
725+
tlow = i2c_dev->hw->tlow_fast_mode;
726+
thigh = i2c_dev->hw->thigh_fast_mode;
727+
tsu_thd = i2c_dev->hw->setup_hold_time_fast_mode;
728+
non_hs_mode = i2c_dev->hw->clk_divisor_fast_mode;
702729
}
703730

704731
/* make sure clock divisor programmed correctly */
@@ -720,6 +747,18 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
720747
if (i2c_dev->hw->has_interface_timing_reg && tsu_thd)
721748
i2c_writel(i2c_dev, tsu_thd, I2C_INTERFACE_TIMING_1);
722749

750+
/* Write HS mode registers. These will get used only for HS mode*/
751+
if (i2c_dev->hw->enable_hs_mode_support) {
752+
tlow = i2c_dev->hw->tlow_hs_mode;
753+
thigh = i2c_dev->hw->thigh_hs_mode;
754+
tsu_thd = i2c_dev->hw->setup_hold_time_hs_mode;
755+
756+
val = FIELD_PREP(I2C_HS_INTERFACE_TIMING_THIGH, thigh) |
757+
FIELD_PREP(I2C_HS_INTERFACE_TIMING_TLOW, tlow);
758+
i2c_writel(i2c_dev, val, I2C_HS_INTERFACE_TIMING_0);
759+
i2c_writel(i2c_dev, tsu_thd, I2C_HS_INTERFACE_TIMING_1);
760+
}
761+
723762
clk_multiplier = (tlow + thigh + 2) * (non_hs_mode + 1);
724763

725764
err = clk_set_rate(i2c_dev->div_clk,
@@ -1217,6 +1256,9 @@ static void tegra_i2c_push_packet_header(struct tegra_i2c_dev *i2c_dev,
12171256
if (msg->flags & I2C_M_RD)
12181257
packet_header |= I2C_HEADER_READ;
12191258

1259+
if (i2c_dev->timings.bus_freq_hz > I2C_MAX_FAST_MODE_PLUS_FREQ)
1260+
packet_header |= I2C_HEADER_HS_MODE;
1261+
12201262
if (i2c_dev->dma_mode && !i2c_dev->msg_read)
12211263
*dma_buf++ = packet_header;
12221264
else
@@ -1508,6 +1550,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
15081550
.setup_hold_time_fastplus_mode = 0x0,
15091551
.setup_hold_time_hs_mode = 0x0,
15101552
.has_interface_timing_reg = false,
1553+
.enable_hs_mode_support = false,
15111554
};
15121555

15131556
static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
@@ -1536,6 +1579,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
15361579
.setup_hold_time_fastplus_mode = 0x0,
15371580
.setup_hold_time_hs_mode = 0x0,
15381581
.has_interface_timing_reg = false,
1582+
.enable_hs_mode_support = false,
15391583
};
15401584

15411585
static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
@@ -1564,6 +1608,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
15641608
.setup_hold_time_fastplus_mode = 0x0,
15651609
.setup_hold_time_hs_mode = 0x0,
15661610
.has_interface_timing_reg = false,
1611+
.enable_hs_mode_support = false,
15671612
};
15681613

15691614
static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
@@ -1592,6 +1637,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
15921637
.setup_hold_time_fastplus_mode = 0x0,
15931638
.setup_hold_time_hs_mode = 0x0,
15941639
.has_interface_timing_reg = true,
1640+
.enable_hs_mode_support = false,
15951641
};
15961642

15971643
static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
@@ -1620,6 +1666,7 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
16201666
.setup_hold_time_fastplus_mode = 0,
16211667
.setup_hold_time_hs_mode = 0,
16221668
.has_interface_timing_reg = true,
1669+
.enable_hs_mode_support = false,
16231670
};
16241671

16251672
static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
@@ -1648,6 +1695,7 @@ static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
16481695
.setup_hold_time_fastplus_mode = 0,
16491696
.setup_hold_time_hs_mode = 0,
16501697
.has_interface_timing_reg = true,
1698+
.enable_hs_mode_support = false,
16511699
};
16521700

16531701
static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
@@ -1671,17 +1719,20 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
16711719
.thigh_fast_mode = 0x2,
16721720
.tlow_fastplus_mode = 0x2,
16731721
.thigh_fastplus_mode = 0x2,
1722+
.tlow_hs_mode = 0x8,
1723+
.thigh_hs_mode = 0x3,
16741724
.setup_hold_time_std_mode = 0x08080808,
16751725
.setup_hold_time_fast_mode = 0x02020202,
16761726
.setup_hold_time_fastplus_mode = 0x02020202,
16771727
.setup_hold_time_hs_mode = 0x090909,
16781728
.has_interface_timing_reg = true,
1729+
.enable_hs_mode_support = true,
16791730
};
16801731

16811732
static const struct tegra_i2c_hw_feature tegra256_i2c_hw = {
16821733
.has_continue_xfer_support = true,
16831734
.has_per_pkt_xfer_complete_irq = true,
1684-
.clk_divisor_hs_mode = 7,
1735+
.clk_divisor_hs_mode = 9,
16851736
.clk_divisor_std_mode = 0x7a,
16861737
.clk_divisor_fast_mode = 0x40,
16871738
.clk_divisor_fast_plus_mode = 0x14,
@@ -1699,10 +1750,14 @@ static const struct tegra_i2c_hw_feature tegra256_i2c_hw = {
16991750
.thigh_fast_mode = 0x2,
17001751
.tlow_fastplus_mode = 0x4,
17011752
.thigh_fastplus_mode = 0x4,
1753+
.tlow_hs_mode = 0x3,
1754+
.thigh_hs_mode = 0x2,
17021755
.setup_hold_time_std_mode = 0x08080808,
17031756
.setup_hold_time_fast_mode = 0x04010101,
17041757
.setup_hold_time_fastplus_mode = 0x04020202,
1758+
.setup_hold_time_hs_mode = 0x030303,
17051759
.has_interface_timing_reg = true,
1760+
.enable_hs_mode_support = true,
17061761
};
17071762

17081763
static const struct of_device_id tegra_i2c_of_match[] = {

0 commit comments

Comments
 (0)