* [PATCH 0/2] Add I2C support for Tegra410
@ 2025-10-01 15:36 Kartik Rajput
2025-10-01 15:36 ` [PATCH 1/2] i2c: tegra: Add logic to support different register offsets Kartik Rajput
2025-10-01 15:36 ` [PATCH 2/2] i2c: tegra: Add support for Tegra410 Kartik Rajput
0 siblings, 2 replies; 12+ messages in thread
From: Kartik Rajput @ 2025-10-01 15:36 UTC (permalink / raw)
To: akhilrajeev, andi.shyti, robh, krzk+dt, conor+dt, thierry.reding,
jonathanh, ldewangan, digetx, smangipudi, linux-i2c, devicetree,
linux-tegra, linux-kernel
Cc: kkartik
Add support for the Tegra410 SoC, which has 4 I2C controllers. The
controllers are feature-equivalent to Tegra264; only the register
offsets differ.
Please note that this series is rebased on:
https://lore.kernel.org/linux-tegra/20251001064759.664630-1-kkartik@nvidia.com/T/#t
Kartik Rajput (2):
i2c: tegra: Add logic to support different register offsets
i2c: tegra: Add support for Tegra410
drivers/i2c/busses/i2c-tegra.c | 563 +++++++++++++++++++++++----------
1 file changed, 398 insertions(+), 165 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 1/2] i2c: tegra: Add logic to support different register offsets
2025-10-01 15:36 [PATCH 0/2] Add I2C support for Tegra410 Kartik Rajput
@ 2025-10-01 15:36 ` Kartik Rajput
2025-10-24 15:11 ` Jon Hunter
` (3 more replies)
2025-10-01 15:36 ` [PATCH 2/2] i2c: tegra: Add support for Tegra410 Kartik Rajput
1 sibling, 4 replies; 12+ messages in thread
From: Kartik Rajput @ 2025-10-01 15:36 UTC (permalink / raw)
To: akhilrajeev, andi.shyti, robh, krzk+dt, conor+dt, thierry.reding,
jonathanh, ldewangan, digetx, smangipudi, linux-i2c, devicetree,
linux-tegra, linux-kernel
Cc: kkartik
Tegra410 use different offsets for existing I2C registers, update
the logic to use appropriate offsets per SoC.
Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
---
drivers/i2c/busses/i2c-tegra.c | 499 ++++++++++++++++++++++-----------
1 file changed, 334 insertions(+), 165 deletions(-)
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 038809264526..1e26d67cbd30 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -30,47 +30,35 @@
#define BYTES_PER_FIFO_WORD 4
-#define I2C_CNFG 0x000
#define I2C_CNFG_DEBOUNCE_CNT GENMASK(14, 12)
#define I2C_CNFG_PACKET_MODE_EN BIT(10)
#define I2C_CNFG_NEW_MASTER_FSM BIT(11)
#define I2C_CNFG_MULTI_MASTER_MODE BIT(17)
-#define I2C_STATUS 0x01c
-#define I2C_SL_CNFG 0x020
+
#define I2C_SL_CNFG_NACK BIT(1)
#define I2C_SL_CNFG_NEWSL BIT(2)
-#define I2C_SL_ADDR1 0x02c
-#define I2C_SL_ADDR2 0x030
-#define I2C_TLOW_SEXT 0x034
-#define I2C_TX_FIFO 0x050
-#define I2C_RX_FIFO 0x054
-#define I2C_PACKET_TRANSFER_STATUS 0x058
-#define I2C_FIFO_CONTROL 0x05c
+
#define I2C_FIFO_CONTROL_TX_FLUSH BIT(1)
#define I2C_FIFO_CONTROL_RX_FLUSH BIT(0)
#define I2C_FIFO_CONTROL_TX_TRIG(x) (((x) - 1) << 5)
#define I2C_FIFO_CONTROL_RX_TRIG(x) (((x) - 1) << 2)
-#define I2C_FIFO_STATUS 0x060
#define I2C_FIFO_STATUS_TX GENMASK(7, 4)
#define I2C_FIFO_STATUS_RX GENMASK(3, 0)
-#define I2C_INT_MASK 0x064
-#define I2C_INT_STATUS 0x068
+
#define I2C_INT_BUS_CLR_DONE BIT(11)
#define I2C_INT_PACKET_XFER_COMPLETE BIT(7)
#define I2C_INT_NO_ACK BIT(3)
#define I2C_INT_ARBITRATION_LOST BIT(2)
#define I2C_INT_TX_FIFO_DATA_REQ BIT(1)
#define I2C_INT_RX_FIFO_DATA_REQ BIT(0)
-#define I2C_CLK_DIVISOR 0x06c
+
#define I2C_CLK_DIVISOR_STD_FAST_MODE GENMASK(31, 16)
#define I2C_CLK_DIVISOR_HSMODE GENMASK(15, 0)
-#define DVC_CTRL_REG1 0x000
#define DVC_CTRL_REG1_INTR_EN BIT(10)
-#define DVC_CTRL_REG3 0x008
#define DVC_CTRL_REG3_SW_PROG BIT(26)
#define DVC_CTRL_REG3_I2C_DONE_INTR_EN BIT(30)
-#define DVC_STATUS 0x00c
+
#define DVC_STATUS_I2C_DONE_INTR BIT(30)
#define I2C_ERR_NONE 0x00
@@ -94,50 +82,37 @@
#define I2C_HEADER_HS_MODE BIT(22)
#define I2C_HEADER_SLAVE_ADDR_SHIFT 1
-#define I2C_BUS_CLEAR_CNFG 0x084
#define I2C_BC_SCLK_THRESHOLD GENMASK(23, 16)
#define I2C_BC_STOP_COND BIT(2)
#define I2C_BC_TERMINATE BIT(1)
#define I2C_BC_ENABLE BIT(0)
-#define I2C_BUS_CLEAR_STATUS 0x088
#define I2C_BC_STATUS BIT(0)
-#define I2C_CONFIG_LOAD 0x08c
#define I2C_MSTR_CONFIG_LOAD BIT(0)
-#define I2C_CLKEN_OVERRIDE 0x090
#define I2C_MST_CORE_CLKEN_OVR BIT(0)
-#define I2C_INTERFACE_TIMING_0 0x094
-#define I2C_INTERFACE_TIMING_THIGH GENMASK(13, 8)
-#define I2C_INTERFACE_TIMING_TLOW GENMASK(5, 0)
-#define I2C_INTERFACE_TIMING_1 0x098
-#define I2C_INTERFACE_TIMING_TBUF GENMASK(29, 24)
-#define I2C_INTERFACE_TIMING_TSU_STO GENMASK(21, 16)
-#define I2C_INTERFACE_TIMING_THD_STA GENMASK(13, 8)
-#define I2C_INTERFACE_TIMING_TSU_STA GENMASK(5, 0)
-
-#define I2C_HS_INTERFACE_TIMING_0 0x09c
-#define I2C_HS_INTERFACE_TIMING_THIGH GENMASK(13, 8)
-#define I2C_HS_INTERFACE_TIMING_TLOW GENMASK(5, 0)
-#define I2C_HS_INTERFACE_TIMING_1 0x0a0
-#define I2C_HS_INTERFACE_TIMING_TSU_STO GENMASK(21, 16)
-#define I2C_HS_INTERFACE_TIMING_THD_STA GENMASK(13, 8)
-#define I2C_HS_INTERFACE_TIMING_TSU_STA GENMASK(5, 0)
-
-#define I2C_MST_FIFO_CONTROL 0x0b4
+#define I2C_INTERFACE_TIMING_THIGH GENMASK(13, 8)
+#define I2C_INTERFACE_TIMING_TLOW GENMASK(5, 0)
+#define I2C_INTERFACE_TIMING_TBUF GENMASK(29, 24)
+#define I2C_INTERFACE_TIMING_TSU_STO GENMASK(21, 16)
+#define I2C_INTERFACE_TIMING_THD_STA GENMASK(13, 8)
+#define I2C_INTERFACE_TIMING_TSU_STA GENMASK(5, 0)
+
+#define I2C_HS_INTERFACE_TIMING_THIGH GENMASK(13, 8)
+#define I2C_HS_INTERFACE_TIMING_TLOW GENMASK(5, 0)
+#define I2C_HS_INTERFACE_TIMING_TSU_STO GENMASK(21, 16)
+#define I2C_HS_INTERFACE_TIMING_THD_STA GENMASK(13, 8)
+#define I2C_HS_INTERFACE_TIMING_TSU_STA GENMASK(5, 0)
+
#define I2C_MST_FIFO_CONTROL_RX_FLUSH BIT(0)
#define I2C_MST_FIFO_CONTROL_TX_FLUSH BIT(1)
#define I2C_MST_FIFO_CONTROL_RX_TRIG(x) (((x) - 1) << 4)
#define I2C_MST_FIFO_CONTROL_TX_TRIG(x) (((x) - 1) << 16)
-#define I2C_MST_FIFO_STATUS 0x0b8
#define I2C_MST_FIFO_STATUS_TX GENMASK(23, 16)
#define I2C_MST_FIFO_STATUS_RX GENMASK(7, 0)
-#define I2C_MASTER_RESET_CNTRL 0x0a8
-
-#define I2C_SW_MUTEX 0x0ec
#define I2C_SW_MUTEX_REQUEST GENMASK(3, 0)
#define I2C_SW_MUTEX_GRANT GENMASK(7, 4)
#define I2C_SW_MUTEX_ID_CCPLEX 9
@@ -159,6 +134,134 @@
*/
#define I2C_PIO_MODE_PREFERRED_LEN 32
+struct tegra_i2c_regs {
+ unsigned int cnfg;
+ unsigned int status;
+ unsigned int sl_cnfg;
+ unsigned int sl_addr1;
+ unsigned int sl_addr2;
+ unsigned int tlow_sext;
+ unsigned int tx_fifo;
+ unsigned int rx_fifo;
+ unsigned int packet_transfer_status;
+ unsigned int fifo_control;
+ unsigned int fifo_status;
+ unsigned int int_mask;
+ unsigned int int_status;
+ unsigned int clk_divisor;
+ unsigned int bus_clear_cnfg;
+ unsigned int bus_clear_status;
+ unsigned int config_load;
+ unsigned int clken_override;
+ unsigned int interface_timing_0;
+ unsigned int interface_timing_1;
+ unsigned int hs_interface_timing_0;
+ unsigned int hs_interface_timing_1;
+ unsigned int master_reset_cntrl;
+ unsigned int mst_fifo_control;
+ unsigned int mst_fifo_status;
+ unsigned int sw_mutex;
+ unsigned int dvc_ctrl_reg1;
+ unsigned int dvc_ctrl_reg3;
+ unsigned int dvc_status;
+};
+
+static const struct tegra_i2c_regs tegra20_i2c_regs = {
+ .cnfg = 0x000,
+ .status = 0x01c,
+ .sl_cnfg = 0x020,
+ .sl_addr1 = 0x02c,
+ .sl_addr2 = 0x030,
+ .tlow_sext = 0x034,
+ .tx_fifo = 0x050,
+ .rx_fifo = 0x054,
+ .packet_transfer_status = 0x058,
+ .fifo_control = 0x05c,
+ .fifo_status = 0x060,
+ .int_mask = 0x064,
+ .int_status = 0x068,
+ .clk_divisor = 0x06c,
+ .bus_clear_cnfg = 0x084,
+ .bus_clear_status = 0x088,
+ .config_load = 0x08c,
+ .clken_override = 0x090,
+ .interface_timing_0 = 0x094,
+ .interface_timing_1 = 0x098,
+ .hs_interface_timing_0 = 0x09c,
+ .hs_interface_timing_1 = 0x0a0,
+ .master_reset_cntrl = 0x0a8,
+ .mst_fifo_control = 0x0b4,
+ .mst_fifo_status = 0x0b8,
+ .sw_mutex = 0x0ec,
+ .dvc_ctrl_reg1 = 0x000,
+ .dvc_ctrl_reg3 = 0x008,
+ .dvc_status = 0x00c,
+};
+
+static const struct tegra_i2c_regs tegra20_i2c_regs_dvc = {
+ .cnfg = 0x000 + 0x40,
+ .status = 0x01c + 0x40,
+ .sl_cnfg = 0x020 + 0x40,
+ .sl_addr1 = 0x02c + 0x40,
+ .sl_addr2 = 0x030 + 0x40,
+ .tlow_sext = 0x034 + 0x40,
+ .tx_fifo = 0x050 + 0x10,
+ .rx_fifo = 0x054 + 0x10,
+ .packet_transfer_status = 0x058 + 0x10,
+ .fifo_control = 0x05c + 0x10,
+ .fifo_status = 0x060 + 0x10,
+ .int_mask = 0x064 + 0x10,
+ .int_status = 0x068 + 0x10,
+ .clk_divisor = 0x06c + 0x10,
+ .bus_clear_cnfg = 0x084 + 0x40,
+ .bus_clear_status = 0x088 + 0x40,
+ .config_load = 0x08c + 0x40,
+ .clken_override = 0x090 + 0x40,
+ .interface_timing_0 = 0x094 + 0x40,
+ .interface_timing_1 = 0x098 + 0x40,
+ .hs_interface_timing_0 = 0x09c + 0x40,
+ .hs_interface_timing_1 = 0x0a0 + 0x40,
+ .master_reset_cntrl = 0x0a8 + 0x40,
+ .mst_fifo_control = 0x0b4 + 0x10,
+ .mst_fifo_status = 0x0b8 + 0x10,
+ .sw_mutex = 0x0ec + 0x40,
+ .dvc_ctrl_reg1 = 0x000,
+ .dvc_ctrl_reg3 = 0x008,
+ .dvc_status = 0x00c,
+};
+
+static const struct tegra_i2c_regs tegra20_i2c_regs_vi = {
+ .cnfg = 0x0c00 + (0x000 << 2),
+ .status = 0x0c00 + (0x01c << 2),
+ .sl_cnfg = 0x0c00 + (0x020 << 2),
+ .sl_addr1 = 0x0c00 + (0x02c << 2),
+ .sl_addr2 = 0x0c00 + (0x030 << 2),
+ .tlow_sext = 0x0c00 + (0x034 << 2),
+ .tx_fifo = 0x0c00 + (0x050 << 2),
+ .rx_fifo = 0x0c00 + (0x054 << 2),
+ .packet_transfer_status = 0x0c00 + (0x058 << 2),
+ .fifo_control = 0x0c00 + (0x05c << 2),
+ .fifo_status = 0x0c00 + (0x060 << 2),
+ .int_mask = 0x0c00 + (0x064 << 2),
+ .int_status = 0x0c00 + (0x068 << 2),
+ .clk_divisor = 0x0c00 + (0x06c << 2),
+ .bus_clear_cnfg = 0x0c00 + (0x084 << 2),
+ .bus_clear_status = 0x0c00 + (0x088 << 2),
+ .config_load = 0x0c00 + (0x08c << 2),
+ .clken_override = 0x0c00 + (0x090 << 2),
+ .interface_timing_0 = 0x0c00 + (0x094 << 2),
+ .interface_timing_1 = 0x0c00 + (0x098 << 2),
+ .hs_interface_timing_0 = 0x0c00 + (0x09c << 2),
+ .hs_interface_timing_1 = 0x0c00 + (0x0a0 << 2),
+ .master_reset_cntrl = 0x0c00 + (0x0a8 << 2),
+ .mst_fifo_control = 0x0c00 + (0x0b4 << 2),
+ .mst_fifo_status = 0x0c00 + (0x0b8 << 2),
+ .sw_mutex = 0x0c00 + (0x0ec << 2),
+ .dvc_ctrl_reg1 = 0x000,
+ .dvc_ctrl_reg3 = 0x008,
+ .dvc_status = 0x00c,
+};
+
/*
* msg_end_type: The bus control which needs to be sent at end of transfer.
* @MSG_END_STOP: Send stop pulse.
@@ -219,6 +322,9 @@ enum msg_end_type {
* timing settings.
* @has_hs_mode_support: Has support for high speed (HS) mode transfers.
* @has_mutex: Has mutex register for mutual exclusion with other firmwares or VMs.
+ * @is_dvc: This instance represents the DVC I2C controller variant.
+ * @is_vi: This instance represents the VI I2C controller variant.
+ * @regs: Register offsets for the specific SoC variant.
*/
struct tegra_i2c_hw_feature {
bool has_continue_xfer_support;
@@ -247,6 +353,9 @@ struct tegra_i2c_hw_feature {
bool has_interface_timing_reg;
bool has_hs_mode_support;
bool has_mutex;
+ bool is_dvc;
+ bool is_vi;
+ const struct tegra_i2c_regs *regs;
};
/**
@@ -262,8 +371,6 @@ struct tegra_i2c_hw_feature {
* @base_phys: physical base address of the I2C controller
* @cont_id: I2C controller ID, used for packet header
* @irq: IRQ number of transfer complete interrupt
- * @is_dvc: identifies the DVC I2C controller, has a different register layout
- * @is_vi: identifies the VI I2C controller, has a different register layout
* @msg_complete: transfer completion notifier
* @msg_buf_remaining: size of unsent data in the message buffer
* @msg_len: length of message in current transfer
@@ -316,12 +423,10 @@ struct tegra_i2c_dev {
bool atomic_mode;
bool dma_mode;
bool msg_read;
- bool is_dvc;
- bool is_vi;
};
-#define IS_DVC(dev) (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && (dev)->is_dvc)
-#define IS_VI(dev) (IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) && (dev)->is_vi)
+#define IS_DVC(dev) (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && (dev)->hw->is_dvc)
+#define IS_VI(dev) (IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) && (dev)->hw->is_vi)
static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
unsigned int reg)
@@ -334,40 +439,26 @@ static u32 dvc_readl(struct tegra_i2c_dev *i2c_dev, unsigned int reg)
return readl_relaxed(i2c_dev->base + reg);
}
-/*
- * If necessary, i2c_writel() and i2c_readl() will offset the register
- * in order to talk to the I2C block inside the DVC block.
- */
-static u32 tegra_i2c_reg_addr(struct tegra_i2c_dev *i2c_dev, unsigned int reg)
-{
- if (IS_DVC(i2c_dev))
- reg += (reg >= I2C_TX_FIFO) ? 0x10 : 0x40;
- else if (IS_VI(i2c_dev))
- reg = 0xc00 + (reg << 2);
-
- return reg;
-}
-
static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned int reg)
{
- writel_relaxed(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
+ writel_relaxed(val, i2c_dev->base + reg);
/* read back register to make sure that register writes completed */
- if (reg != I2C_TX_FIFO)
- readl_relaxed(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
+ if (reg != i2c_dev->hw->regs->tx_fifo)
+ readl_relaxed(i2c_dev->base + reg);
else if (IS_VI(i2c_dev))
- readl_relaxed(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, I2C_INT_STATUS));
+ readl_relaxed(i2c_dev->base + i2c_dev->hw->regs->int_status);
}
static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned int reg)
{
- return readl_relaxed(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
+ return readl_relaxed(i2c_dev->base + reg);
}
static void i2c_writesl(struct tegra_i2c_dev *i2c_dev, void *data,
unsigned int reg, unsigned int len)
{
- writesl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len);
+ writesl(i2c_dev->base + reg, data, len);
}
static void i2c_writesl_vi(struct tegra_i2c_dev *i2c_dev, void *data,
@@ -388,12 +479,12 @@ static void i2c_writesl_vi(struct tegra_i2c_dev *i2c_dev, void *data,
static void i2c_readsl(struct tegra_i2c_dev *i2c_dev, void *data,
unsigned int reg, unsigned int len)
{
- readsl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len);
+ readsl(i2c_dev->base + reg, data, len);
}
static bool tegra_i2c_mutex_acquired(struct tegra_i2c_dev *i2c_dev)
{
- unsigned int reg = tegra_i2c_reg_addr(i2c_dev, I2C_SW_MUTEX);
+ unsigned int reg = i2c_dev->hw->regs->sw_mutex;
u32 val, id;
val = readl(i2c_dev->base + reg);
@@ -404,7 +495,7 @@ static bool tegra_i2c_mutex_acquired(struct tegra_i2c_dev *i2c_dev)
static bool tegra_i2c_mutex_trylock(struct tegra_i2c_dev *i2c_dev)
{
- unsigned int reg = tegra_i2c_reg_addr(i2c_dev, I2C_SW_MUTEX);
+ unsigned int reg = i2c_dev->hw->regs->sw_mutex;
u32 val, id;
val = readl(i2c_dev->base + reg);
@@ -428,8 +519,8 @@ static int tegra_i2c_mutex_lock(struct tegra_i2c_dev *i2c_dev)
if (i2c_dev->atomic_mode)
ret = read_poll_timeout_atomic(tegra_i2c_mutex_trylock, locked, locked,
- USEC_PER_MSEC, I2C_SW_MUTEX_TIMEOUT_US,
- false, i2c_dev);
+ USEC_PER_MSEC, I2C_SW_MUTEX_TIMEOUT_US,
+ false, i2c_dev);
else
ret = read_poll_timeout(tegra_i2c_mutex_trylock, locked, locked, USEC_PER_MSEC,
I2C_SW_MUTEX_TIMEOUT_US, false, i2c_dev);
@@ -442,7 +533,7 @@ static int tegra_i2c_mutex_lock(struct tegra_i2c_dev *i2c_dev)
static int tegra_i2c_mutex_unlock(struct tegra_i2c_dev *i2c_dev)
{
- unsigned int reg = tegra_i2c_reg_addr(i2c_dev, I2C_SW_MUTEX);
+ unsigned int reg = i2c_dev->hw->regs->sw_mutex;
u32 val, id;
if (!i2c_dev->hw->has_mutex)
@@ -465,16 +556,16 @@ static void tegra_i2c_mask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask)
{
u32 int_mask;
- int_mask = i2c_readl(i2c_dev, I2C_INT_MASK) & ~mask;
- i2c_writel(i2c_dev, int_mask, I2C_INT_MASK);
+ int_mask = i2c_readl(i2c_dev, i2c_dev->hw->regs->int_mask) & ~mask;
+ i2c_writel(i2c_dev, int_mask, i2c_dev->hw->regs->int_mask);
}
static void tegra_i2c_unmask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask)
{
u32 int_mask;
- int_mask = i2c_readl(i2c_dev, I2C_INT_MASK) | mask;
- i2c_writel(i2c_dev, int_mask, I2C_INT_MASK);
+ int_mask = i2c_readl(i2c_dev, i2c_dev->hw->regs->int_mask) | mask;
+ i2c_writel(i2c_dev, int_mask, i2c_dev->hw->regs->int_mask);
}
static void tegra_i2c_dma_complete(void *args)
@@ -602,14 +693,14 @@ static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev)
{
u32 val;
- val = dvc_readl(i2c_dev, DVC_CTRL_REG3);
+ val = dvc_readl(i2c_dev, i2c_dev->hw->regs->dvc_ctrl_reg3);
val |= DVC_CTRL_REG3_SW_PROG;
val |= DVC_CTRL_REG3_I2C_DONE_INTR_EN;
- dvc_writel(i2c_dev, val, DVC_CTRL_REG3);
+ dvc_writel(i2c_dev, val, i2c_dev->hw->regs->dvc_ctrl_reg3);
- val = dvc_readl(i2c_dev, DVC_CTRL_REG1);
+ val = dvc_readl(i2c_dev, i2c_dev->hw->regs->dvc_ctrl_reg1);
val |= DVC_CTRL_REG1_INTR_EN;
- dvc_writel(i2c_dev, val, DVC_CTRL_REG1);
+ dvc_writel(i2c_dev, val, i2c_dev->hw->regs->dvc_ctrl_reg1);
}
static void tegra_i2c_vi_init(struct tegra_i2c_dev *i2c_dev)
@@ -618,34 +709,34 @@ static void tegra_i2c_vi_init(struct tegra_i2c_dev *i2c_dev)
value = FIELD_PREP(I2C_INTERFACE_TIMING_THIGH, 2) |
FIELD_PREP(I2C_INTERFACE_TIMING_TLOW, 4);
- i2c_writel(i2c_dev, value, I2C_INTERFACE_TIMING_0);
+ i2c_writel(i2c_dev, value, i2c_dev->hw->regs->interface_timing_0);
value = FIELD_PREP(I2C_INTERFACE_TIMING_TBUF, 4) |
FIELD_PREP(I2C_INTERFACE_TIMING_TSU_STO, 7) |
FIELD_PREP(I2C_INTERFACE_TIMING_THD_STA, 4) |
FIELD_PREP(I2C_INTERFACE_TIMING_TSU_STA, 4);
- i2c_writel(i2c_dev, value, I2C_INTERFACE_TIMING_1);
+ i2c_writel(i2c_dev, value, i2c_dev->hw->regs->interface_timing_1);
value = FIELD_PREP(I2C_HS_INTERFACE_TIMING_THIGH, 3) |
FIELD_PREP(I2C_HS_INTERFACE_TIMING_TLOW, 8);
- i2c_writel(i2c_dev, value, I2C_HS_INTERFACE_TIMING_0);
+ i2c_writel(i2c_dev, value, i2c_dev->hw->regs->hs_interface_timing_0);
value = FIELD_PREP(I2C_HS_INTERFACE_TIMING_TSU_STO, 11) |
FIELD_PREP(I2C_HS_INTERFACE_TIMING_THD_STA, 11) |
FIELD_PREP(I2C_HS_INTERFACE_TIMING_TSU_STA, 11);
- i2c_writel(i2c_dev, value, I2C_HS_INTERFACE_TIMING_1);
+ i2c_writel(i2c_dev, value, i2c_dev->hw->regs->hs_interface_timing_1);
value = FIELD_PREP(I2C_BC_SCLK_THRESHOLD, 9) | I2C_BC_STOP_COND;
- i2c_writel(i2c_dev, value, I2C_BUS_CLEAR_CNFG);
+ i2c_writel(i2c_dev, value, i2c_dev->hw->regs->bus_clear_cnfg);
- i2c_writel(i2c_dev, 0x0, I2C_TLOW_SEXT);
+ i2c_writel(i2c_dev, 0x0, i2c_dev->hw->regs->tlow_sext);
}
static int tegra_i2c_poll_register(struct tegra_i2c_dev *i2c_dev,
u32 reg, u32 mask, u32 delay_us,
u32 timeout_us)
{
- void __iomem *addr = i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg);
+ void __iomem *addr = i2c_dev->base + reg;
u32 val;
if (!i2c_dev->atomic_mode)
@@ -664,11 +755,11 @@ static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev)
if (i2c_dev->hw->has_mst_fifo) {
mask = I2C_MST_FIFO_CONTROL_TX_FLUSH |
I2C_MST_FIFO_CONTROL_RX_FLUSH;
- offset = I2C_MST_FIFO_CONTROL;
+ offset = i2c_dev->hw->regs->mst_fifo_control;
} else {
mask = I2C_FIFO_CONTROL_TX_FLUSH |
I2C_FIFO_CONTROL_RX_FLUSH;
- offset = I2C_FIFO_CONTROL;
+ offset = i2c_dev->hw->regs->fifo_control;
}
val = i2c_readl(i2c_dev, offset);
@@ -691,9 +782,9 @@ static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev)
if (!i2c_dev->hw->has_config_load_reg)
return 0;
- i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD);
+ i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, i2c_dev->hw->regs->config_load);
- err = tegra_i2c_poll_register(i2c_dev, I2C_CONFIG_LOAD, 0xffffffff,
+ err = tegra_i2c_poll_register(i2c_dev, i2c_dev->hw->regs->config_load, 0xffffffff,
1000, I2C_CONFIG_LOAD_TIMEOUT);
if (err) {
dev_err(i2c_dev->dev, "failed to load config\n");
@@ -714,10 +805,10 @@ static int tegra_i2c_master_reset(struct tegra_i2c_dev *i2c_dev)
* SW needs to wait for 2us after assertion and de-assertion of this soft
* reset.
*/
- i2c_writel(i2c_dev, 0x1, I2C_MASTER_RESET_CNTRL);
+ i2c_writel(i2c_dev, 0x1, i2c_dev->hw->regs->master_reset_cntrl);
fsleep(2);
- i2c_writel(i2c_dev, 0x0, I2C_MASTER_RESET_CNTRL);
+ i2c_writel(i2c_dev, 0x0, i2c_dev->hw->regs->master_reset_cntrl);
fsleep(2);
return 0;
@@ -758,8 +849,8 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
if (i2c_dev->hw->has_multi_master_mode)
val |= I2C_CNFG_MULTI_MASTER_MODE;
- i2c_writel(i2c_dev, val, I2C_CNFG);
- i2c_writel(i2c_dev, 0, I2C_INT_MASK);
+ i2c_writel(i2c_dev, val, i2c_dev->hw->regs->cnfg);
+ i2c_writel(i2c_dev, 0, i2c_dev->hw->regs->int_mask);
if (IS_VI(i2c_dev))
tegra_i2c_vi_init(i2c_dev);
@@ -801,12 +892,12 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
clk_divisor = FIELD_PREP(I2C_CLK_DIVISOR_HSMODE,
i2c_dev->hw->clk_divisor_hs_mode) |
FIELD_PREP(I2C_CLK_DIVISOR_STD_FAST_MODE, non_hs_mode);
- i2c_writel(i2c_dev, clk_divisor, I2C_CLK_DIVISOR);
+ i2c_writel(i2c_dev, clk_divisor, i2c_dev->hw->regs->clk_divisor);
if (i2c_dev->hw->has_interface_timing_reg) {
val = FIELD_PREP(I2C_INTERFACE_TIMING_THIGH, thigh) |
FIELD_PREP(I2C_INTERFACE_TIMING_TLOW, tlow);
- i2c_writel(i2c_dev, val, I2C_INTERFACE_TIMING_0);
+ i2c_writel(i2c_dev, val, i2c_dev->hw->regs->interface_timing_0);
}
/*
@@ -814,9 +905,8 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
* Otherwise, preserve the chip default values.
*/
if (i2c_dev->hw->has_interface_timing_reg && tsu_thd)
- i2c_writel(i2c_dev, tsu_thd, I2C_INTERFACE_TIMING_1);
+ i2c_writel(i2c_dev, tsu_thd, i2c_dev->hw->regs->interface_timing_1);
- /* Write HS mode registers. These will get used only for HS mode*/
if (i2c_dev->hw->has_hs_mode_support) {
tlow = i2c_dev->hw->tlow_hs_mode;
thigh = i2c_dev->hw->thigh_hs_mode;
@@ -824,8 +914,8 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
val = FIELD_PREP(I2C_HS_INTERFACE_TIMING_THIGH, thigh) |
FIELD_PREP(I2C_HS_INTERFACE_TIMING_TLOW, tlow);
- i2c_writel(i2c_dev, val, I2C_HS_INTERFACE_TIMING_0);
- i2c_writel(i2c_dev, tsu_thd, I2C_HS_INTERFACE_TIMING_1);
+ i2c_writel(i2c_dev, val, i2c_dev->hw->regs->hs_interface_timing_0);
+ i2c_writel(i2c_dev, tsu_thd, i2c_dev->hw->regs->hs_interface_timing_1);
}
clk_multiplier = (tlow + thigh + 2) * (non_hs_mode + 1);
@@ -838,12 +928,12 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
}
if (!IS_DVC(i2c_dev) && !IS_VI(i2c_dev)) {
- u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG);
+ u32 sl_cfg = i2c_readl(i2c_dev, i2c_dev->hw->regs->sl_cnfg);
sl_cfg |= I2C_SL_CNFG_NACK | I2C_SL_CNFG_NEWSL;
- i2c_writel(i2c_dev, sl_cfg, I2C_SL_CNFG);
- i2c_writel(i2c_dev, 0xfc, I2C_SL_ADDR1);
- i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2);
+ i2c_writel(i2c_dev, sl_cfg, i2c_dev->hw->regs->sl_cnfg);
+ i2c_writel(i2c_dev, 0xfc, i2c_dev->hw->regs->sl_addr1);
+ i2c_writel(i2c_dev, 0x00, i2c_dev->hw->regs->sl_addr2);
}
err = tegra_i2c_flush_fifos(i2c_dev);
@@ -851,7 +941,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
return err;
if (i2c_dev->multimaster_mode && i2c_dev->hw->has_slcg_override_reg)
- i2c_writel(i2c_dev, I2C_MST_CORE_CLKEN_OVR, I2C_CLKEN_OVERRIDE);
+ i2c_writel(i2c_dev, I2C_MST_CORE_CLKEN_OVR, i2c_dev->hw->regs->clken_override);
err = tegra_i2c_wait_for_config_load(i2c_dev);
if (err)
@@ -872,9 +962,9 @@ static int tegra_i2c_disable_packet_mode(struct tegra_i2c_dev *i2c_dev)
*/
udelay(DIV_ROUND_UP(2 * 1000000, i2c_dev->timings.bus_freq_hz));
- cnfg = i2c_readl(i2c_dev, I2C_CNFG);
+ cnfg = i2c_readl(i2c_dev, i2c_dev->hw->regs->cnfg);
if (cnfg & I2C_CNFG_PACKET_MODE_EN)
- i2c_writel(i2c_dev, cnfg & ~I2C_CNFG_PACKET_MODE_EN, I2C_CNFG);
+ i2c_writel(i2c_dev, cnfg & ~I2C_CNFG_PACKET_MODE_EN, i2c_dev->hw->regs->cnfg);
return tegra_i2c_wait_for_config_load(i2c_dev);
}
@@ -894,19 +984,18 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
return -EINVAL;
if (i2c_dev->hw->has_mst_fifo) {
- val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS);
+ val = i2c_readl(i2c_dev, i2c_dev->hw->regs->mst_fifo_status);
rx_fifo_avail = FIELD_GET(I2C_MST_FIFO_STATUS_RX, val);
} else {
- val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
+ val = i2c_readl(i2c_dev, i2c_dev->hw->regs->fifo_status);
rx_fifo_avail = FIELD_GET(I2C_FIFO_STATUS_RX, val);
}
- /* round down to exclude partial word at the end of buffer */
words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD;
if (words_to_transfer > rx_fifo_avail)
words_to_transfer = rx_fifo_avail;
- i2c_readsl(i2c_dev, buf, I2C_RX_FIFO, words_to_transfer);
+ i2c_readsl(i2c_dev, buf, i2c_dev->hw->regs->rx_fifo, words_to_transfer);
buf += words_to_transfer * BYTES_PER_FIFO_WORD;
buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD;
@@ -922,7 +1011,7 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
* when (words_to_transfer was > rx_fifo_avail) earlier
* in this function.
*/
- val = i2c_readl(i2c_dev, I2C_RX_FIFO);
+ val = i2c_readl(i2c_dev, i2c_dev->hw->regs->rx_fifo);
val = cpu_to_le32(val);
memcpy(buf, &val, buf_remaining);
buf_remaining = 0;
@@ -947,10 +1036,10 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
u32 val;
if (i2c_dev->hw->has_mst_fifo) {
- val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS);
+ val = i2c_readl(i2c_dev, i2c_dev->hw->regs->mst_fifo_status);
tx_fifo_avail = FIELD_GET(I2C_MST_FIFO_STATUS_TX, val);
} else {
- val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
+ val = i2c_readl(i2c_dev, i2c_dev->hw->regs->fifo_status);
tx_fifo_avail = FIELD_GET(I2C_FIFO_STATUS_TX, val);
}
@@ -981,9 +1070,9 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
i2c_dev->msg_buf = buf + words_to_transfer * BYTES_PER_FIFO_WORD;
if (IS_VI(i2c_dev))
- i2c_writesl_vi(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer);
+ i2c_writesl_vi(i2c_dev, buf, i2c_dev->hw->regs->tx_fifo, words_to_transfer);
else
- i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer);
+ i2c_writesl(i2c_dev, buf, i2c_dev->hw->regs->tx_fifo, words_to_transfer);
buf += words_to_transfer * BYTES_PER_FIFO_WORD;
}
@@ -1005,7 +1094,7 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
i2c_dev->msg_buf_remaining = 0;
i2c_dev->msg_buf = NULL;
- i2c_writel(i2c_dev, val, I2C_TX_FIFO);
+ i2c_writel(i2c_dev, val, i2c_dev->hw->regs->tx_fifo);
}
return 0;
@@ -1017,13 +1106,13 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
struct tegra_i2c_dev *i2c_dev = dev_id;
u32 status;
- status = i2c_readl(i2c_dev, I2C_INT_STATUS);
+ status = i2c_readl(i2c_dev, i2c_dev->hw->regs->int_status);
if (status == 0) {
dev_warn(i2c_dev->dev, "IRQ status 0 %08x %08x %08x\n",
- i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS),
- i2c_readl(i2c_dev, I2C_STATUS),
- i2c_readl(i2c_dev, I2C_CNFG));
+ i2c_readl(i2c_dev, i2c_dev->hw->regs->packet_transfer_status),
+ i2c_readl(i2c_dev, i2c_dev->hw->regs->status),
+ i2c_readl(i2c_dev, i2c_dev->hw->regs->cnfg));
i2c_dev->msg_err |= I2C_ERR_UNKNOWN_INTERRUPT;
goto err;
}
@@ -1062,13 +1151,13 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
tegra_i2c_fill_tx_fifo(i2c_dev);
else
tegra_i2c_mask_irq(i2c_dev,
- I2C_INT_TX_FIFO_DATA_REQ);
+ I2C_INT_TX_FIFO_DATA_REQ);
}
}
- i2c_writel(i2c_dev, status, I2C_INT_STATUS);
+ i2c_writel(i2c_dev, status, i2c_dev->hw->regs->int_status);
if (IS_DVC(i2c_dev))
- dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
+ dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, i2c_dev->hw->regs->dvc_status);
/*
* During message read XFER_COMPLETE interrupt is triggered prior to
@@ -1104,10 +1193,10 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
if (i2c_dev->hw->supports_bus_clear)
tegra_i2c_mask_irq(i2c_dev, I2C_INT_BUS_CLR_DONE);
- i2c_writel(i2c_dev, status, I2C_INT_STATUS);
+ i2c_writel(i2c_dev, status, i2c_dev->hw->regs->int_status);
if (IS_DVC(i2c_dev))
- dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
+ dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, i2c_dev->hw->regs->dvc_status);
if (i2c_dev->dma_mode) {
dmaengine_terminate_async(i2c_dev->dma_chan);
@@ -1120,16 +1209,16 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
}
static void tegra_i2c_config_fifo_trig(struct tegra_i2c_dev *i2c_dev,
- size_t len)
+ size_t len)
{
struct dma_slave_config slv_config = {0};
u32 val, reg, dma_burst, reg_offset;
int err;
if (i2c_dev->hw->has_mst_fifo)
- reg = I2C_MST_FIFO_CONTROL;
+ reg = i2c_dev->hw->regs->mst_fifo_control;
else
- reg = I2C_FIFO_CONTROL;
+ reg = i2c_dev->hw->regs->fifo_control;
if (i2c_dev->dma_mode) {
if (len & 0xF)
@@ -1140,7 +1229,7 @@ static void tegra_i2c_config_fifo_trig(struct tegra_i2c_dev *i2c_dev,
dma_burst = 8;
if (i2c_dev->msg_read) {
- reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_RX_FIFO);
+ reg_offset = i2c_dev->hw->regs->rx_fifo;
slv_config.src_addr = i2c_dev->base_phys + reg_offset;
slv_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
@@ -1151,7 +1240,7 @@ static void tegra_i2c_config_fifo_trig(struct tegra_i2c_dev *i2c_dev,
else
val = I2C_FIFO_CONTROL_RX_TRIG(dma_burst);
} else {
- reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_TX_FIFO);
+ reg_offset = i2c_dev->hw->regs->tx_fifo;
slv_config.dst_addr = i2c_dev->base_phys + reg_offset;
slv_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
@@ -1187,14 +1276,14 @@ static void tegra_i2c_config_fifo_trig(struct tegra_i2c_dev *i2c_dev,
}
static unsigned long tegra_i2c_poll_completion(struct tegra_i2c_dev *i2c_dev,
- struct completion *complete,
- unsigned int timeout_ms)
+ struct completion *complete,
+ unsigned int timeout_ms)
{
ktime_t ktime = ktime_get();
ktime_t ktimeout = ktime_add_ms(ktime, timeout_ms);
do {
- u32 status = i2c_readl(i2c_dev, I2C_INT_STATUS);
+ u32 status = i2c_readl(i2c_dev, i2c_dev->hw->regs->int_status);
if (status)
tegra_i2c_isr(i2c_dev->irq, i2c_dev);
@@ -1253,14 +1342,14 @@ static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
val = FIELD_PREP(I2C_BC_SCLK_THRESHOLD, 9) | I2C_BC_STOP_COND |
I2C_BC_TERMINATE;
- i2c_writel(i2c_dev, val, I2C_BUS_CLEAR_CNFG);
+ i2c_writel(i2c_dev, val, i2c_dev->hw->regs->bus_clear_cnfg);
err = tegra_i2c_wait_for_config_load(i2c_dev);
if (err)
return err;
val |= I2C_BC_ENABLE;
- i2c_writel(i2c_dev, val, I2C_BUS_CLEAR_CNFG);
+ i2c_writel(i2c_dev, val, i2c_dev->hw->regs->bus_clear_cnfg);
tegra_i2c_unmask_irq(i2c_dev, I2C_INT_BUS_CLR_DONE);
time_left = tegra_i2c_wait_completion(i2c_dev, &i2c_dev->msg_complete, 50);
@@ -1271,7 +1360,7 @@ static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
return -ETIMEDOUT;
}
- val = i2c_readl(i2c_dev, I2C_BUS_CLEAR_STATUS);
+ val = i2c_readl(i2c_dev, i2c_dev->hw->regs->bus_clear_status);
if (!(val & I2C_BC_STATUS)) {
dev_err(i2c_dev->dev, "un-recovered arbitration lost\n");
return -EIO;
@@ -1281,29 +1370,29 @@ static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
}
static void tegra_i2c_push_packet_header(struct tegra_i2c_dev *i2c_dev,
- struct i2c_msg *msg,
- enum msg_end_type end_state)
+ struct i2c_msg *msg,
+ enum msg_end_type end_state)
{
u32 *dma_buf = i2c_dev->dma_buf;
u32 packet_header;
packet_header = FIELD_PREP(PACKET_HEADER0_HEADER_SIZE, 0) |
FIELD_PREP(PACKET_HEADER0_PROTOCOL,
- PACKET_HEADER0_PROTOCOL_I2C) |
+ PACKET_HEADER0_PROTOCOL_I2C) |
FIELD_PREP(PACKET_HEADER0_CONT_ID, i2c_dev->cont_id) |
FIELD_PREP(PACKET_HEADER0_PACKET_ID, 1);
if (i2c_dev->dma_mode && !i2c_dev->msg_read)
*dma_buf++ = packet_header;
else
- i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+ i2c_writel(i2c_dev, packet_header, i2c_dev->hw->regs->tx_fifo);
packet_header = i2c_dev->msg_len - 1;
if (i2c_dev->dma_mode && !i2c_dev->msg_read)
*dma_buf++ = packet_header;
else
- i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+ i2c_writel(i2c_dev, packet_header, i2c_dev->hw->regs->tx_fifo);
packet_header = I2C_HEADER_IE_ENABLE;
@@ -1331,7 +1420,7 @@ static void tegra_i2c_push_packet_header(struct tegra_i2c_dev *i2c_dev,
if (i2c_dev->dma_mode && !i2c_dev->msg_read)
*dma_buf++ = packet_header;
else
- i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+ i2c_writel(i2c_dev, packet_header, i2c_dev->hw->regs->tx_fifo);
}
static int tegra_i2c_error_recover(struct tegra_i2c_dev *i2c_dev,
@@ -1361,8 +1450,8 @@ static int tegra_i2c_error_recover(struct tegra_i2c_dev *i2c_dev,
}
static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
- struct i2c_msg *msg,
- enum msg_end_type end_state)
+ struct i2c_msg *msg,
+ enum msg_end_type end_state)
{
unsigned long time_left, xfer_time = 100;
size_t xfer_size;
@@ -1413,7 +1502,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
* Total bits = 9 bits per byte (including ACK bit) + Start & stop bits
*/
xfer_time += DIV_ROUND_CLOSEST(((xfer_size * 9) + 2) * MSEC_PER_SEC,
- i2c_dev->timings.bus_freq_hz);
+ i2c_dev->timings.bus_freq_hz);
int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
tegra_i2c_unmask_irq(i2c_dev, int_mask);
@@ -1452,12 +1541,12 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
tegra_i2c_unmask_irq(i2c_dev, int_mask);
dev_dbg(i2c_dev->dev, "unmasked IRQ: %02x\n",
- i2c_readl(i2c_dev, I2C_INT_MASK));
+ i2c_readl(i2c_dev, i2c_dev->hw->regs->int_mask));
if (i2c_dev->dma_mode) {
time_left = tegra_i2c_wait_completion(i2c_dev,
- &i2c_dev->dma_complete,
- xfer_time);
+ &i2c_dev->dma_complete,
+ xfer_time);
/*
* Synchronize DMA first, since dmaengine_terminate_sync()
@@ -1477,7 +1566,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
}
time_left = tegra_i2c_wait_completion(i2c_dev, &i2c_dev->msg_complete,
- xfer_time);
+ xfer_time);
tegra_i2c_mask_irq(i2c_dev, int_mask);
@@ -1623,7 +1712,75 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
.has_interface_timing_reg = false,
.has_hs_mode_support = false,
.has_mutex = false,
+ .is_dvc = false,
+ .is_vi = false,
+ .regs = &tegra20_i2c_regs,
+};
+
+#if IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)
+static const struct tegra_i2c_hw_feature tegra20_dvc_i2c_hw = {
+ .has_continue_xfer_support = false,
+ .has_per_pkt_xfer_complete_irq = false,
+ .clk_divisor_hs_mode = 3,
+ .clk_divisor_std_mode = 0,
+ .clk_divisor_fast_mode = 0,
+ .clk_divisor_fast_plus_mode = 0,
+ .has_config_load_reg = false,
+ .has_multi_master_mode = false,
+ .has_slcg_override_reg = false,
+ .has_mst_fifo = false,
+ .has_mst_reset = false,
+ .quirks = &tegra_i2c_quirks,
+ .supports_bus_clear = false,
+ .has_apb_dma = true,
+ .tlow_std_mode = 0x4,
+ .thigh_std_mode = 0x2,
+ .tlow_fast_fastplus_mode = 0x4,
+ .thigh_fast_fastplus_mode = 0x2,
+ .setup_hold_time_std_mode = 0x0,
+ .setup_hold_time_fast_fast_plus_mode = 0x0,
+ .setup_hold_time_hs_mode = 0x0,
+ .has_interface_timing_reg = false,
+ .has_hs_mode_support = false,
+ .has_mutex = false,
+ .is_dvc = true,
+ .is_vi = false,
+ .regs = &tegra20_i2c_regs_dvc,
+};
+#endif
+
+#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
+static const struct tegra_i2c_hw_feature tegra210_vi_i2c_hw = {
+ .has_continue_xfer_support = true,
+ .has_per_pkt_xfer_complete_irq = true,
+ .clk_divisor_hs_mode = 1,
+ .clk_divisor_std_mode = 0x19,
+ .clk_divisor_fast_mode = 0x19,
+ .clk_divisor_fast_plus_mode = 0x10,
+ .has_config_load_reg = true,
+ .has_multi_master_mode = false,
+ .has_slcg_override_reg = true,
+ .has_mst_fifo = false,
+ .has_mst_reset = false,
+ .quirks = &tegra_i2c_quirks,
+ .supports_bus_clear = true,
+ .has_apb_dma = true,
+ .tlow_std_mode = 0x4,
+ .thigh_std_mode = 0x2,
+ .tlow_fast_fastplus_mode = 0x4,
+ .thigh_fast_fastplus_mode = 0x2,
+ .setup_hold_time_std_mode = 0,
+ .setup_hold_time_fast_fast_plus_mode = 0,
+ .setup_hold_time_hs_mode = 0,
+ .has_interface_timing_reg = true,
+ .has_hs_mode_support = false,
+ .has_mutex = false,
+ .is_dvc = false,
+ .is_vi = true,
+ .regs = &tegra20_i2c_regs_vi,
};
+#endif
+
static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
.has_continue_xfer_support = true,
@@ -1650,6 +1807,9 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
.has_interface_timing_reg = false,
.has_hs_mode_support = false,
.has_mutex = false,
+ .is_dvc = false,
+ .is_vi = false,
+ .regs = &tegra20_i2c_regs,
};
static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
@@ -1677,6 +1837,9 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
.has_interface_timing_reg = false,
.has_hs_mode_support = false,
.has_mutex = false,
+ .is_dvc = false,
+ .is_vi = false,
+ .regs = &tegra20_i2c_regs,
};
static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
@@ -1704,6 +1867,9 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
.has_interface_timing_reg = true,
.has_hs_mode_support = false,
.has_mutex = false,
+ .is_dvc = false,
+ .is_vi = false,
+ .regs = &tegra20_i2c_regs,
};
static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
@@ -1731,6 +1897,9 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
.has_interface_timing_reg = true,
.has_hs_mode_support = false,
.has_mutex = false,
+ .is_dvc = false,
+ .is_vi = false,
+ .regs = &tegra20_i2c_regs,
};
static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
@@ -1758,6 +1927,9 @@ static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
.has_interface_timing_reg = true,
.has_hs_mode_support = false,
.has_mutex = false,
+ .is_dvc = false,
+ .is_vi = false,
+ .regs = &tegra20_i2c_regs,
};
static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
@@ -1787,6 +1959,9 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
.has_interface_timing_reg = true,
.has_hs_mode_support = true,
.has_mutex = false,
+ .is_dvc = false,
+ .is_vi = false,
+ .regs = &tegra20_i2c_regs,
};
static const struct tegra_i2c_hw_feature tegra256_i2c_hw = {
@@ -1840,6 +2015,9 @@ static const struct tegra_i2c_hw_feature tegra264_i2c_hw = {
.has_interface_timing_reg = true,
.has_hs_mode_support = true,
.has_mutex = true,
+ .is_dvc = false,
+ .is_vi = false,
+ .regs = &tegra20_i2c_regs,
};
static const struct of_device_id tegra_i2c_of_match[] = {
@@ -1848,7 +2026,7 @@ static const struct of_device_id tegra_i2c_of_match[] = {
{ .compatible = "nvidia,tegra194-i2c", .data = &tegra194_i2c_hw, },
{ .compatible = "nvidia,tegra186-i2c", .data = &tegra186_i2c_hw, },
#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
- { .compatible = "nvidia,tegra210-i2c-vi", .data = &tegra210_i2c_hw, },
+ { .compatible = "nvidia,tegra210-i2c-vi", .data = &tegra210_vi_i2c_hw, },
#endif
{ .compatible = "nvidia,tegra210-i2c", .data = &tegra210_i2c_hw, },
{ .compatible = "nvidia,tegra124-i2c", .data = &tegra124_i2c_hw, },
@@ -1856,7 +2034,7 @@ static const struct of_device_id tegra_i2c_of_match[] = {
{ .compatible = "nvidia,tegra30-i2c", .data = &tegra30_i2c_hw, },
{ .compatible = "nvidia,tegra20-i2c", .data = &tegra20_i2c_hw, },
#if IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)
- { .compatible = "nvidia,tegra20-i2c-dvc", .data = &tegra20_i2c_hw, },
+ { .compatible = "nvidia,tegra20-i2c-dvc", .data = &tegra20_dvc_i2c_hw, },
#endif
{},
};
@@ -1864,21 +2042,12 @@ MODULE_DEVICE_TABLE(of, tegra_i2c_of_match);
static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev)
{
- struct device_node *np = i2c_dev->dev->of_node;
bool multi_mode;
i2c_parse_fw_timings(i2c_dev->dev, &i2c_dev->timings, true);
multi_mode = device_property_read_bool(i2c_dev->dev, "multi-master");
i2c_dev->multimaster_mode = multi_mode;
-
- if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) &&
- of_device_is_compatible(np, "nvidia,tegra20-i2c-dvc"))
- i2c_dev->is_dvc = true;
-
- if (IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) &&
- of_device_is_compatible(np, "nvidia,tegra210-i2c-vi"))
- i2c_dev->is_vi = true;
}
static int tegra_i2c_init_clocks(struct tegra_i2c_dev *i2c_dev)
--
2.43.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 2/2] i2c: tegra: Add support for Tegra410
2025-10-01 15:36 [PATCH 0/2] Add I2C support for Tegra410 Kartik Rajput
2025-10-01 15:36 ` [PATCH 1/2] i2c: tegra: Add logic to support different register offsets Kartik Rajput
@ 2025-10-01 15:36 ` Kartik Rajput
2025-10-24 15:17 ` Jon Hunter
1 sibling, 1 reply; 12+ messages in thread
From: Kartik Rajput @ 2025-10-01 15:36 UTC (permalink / raw)
To: akhilrajeev, andi.shyti, robh, krzk+dt, conor+dt, thierry.reding,
jonathanh, ldewangan, digetx, smangipudi, linux-i2c, devicetree,
linux-tegra, linux-kernel
Cc: kkartik
Add support for the Tegra410 SoC, which has 4 I2C controllers. The
controllers are feature-equivalent to Tegra264; only the register
offsets differ.
Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
---
drivers/i2c/busses/i2c-tegra.c | 64 ++++++++++++++++++++++++++++++++++
1 file changed, 64 insertions(+)
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 1e26d67cbd30..bc9f60b69020 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -262,6 +262,38 @@ static const struct tegra_i2c_regs tegra20_i2c_regs_vi = {
.dvc_status = 0x00c,
};
+static const struct tegra_i2c_regs tegra410_i2c_regs = {
+ .cnfg = 0x000,
+ .status = 0x01c,
+ .sl_cnfg = 0x020,
+ .sl_addr1 = 0x02c,
+ .sl_addr2 = 0x030,
+ .tlow_sext = 0x034,
+ .tx_fifo = 0x054,
+ .rx_fifo = 0x058,
+ .packet_transfer_status = 0x05c,
+ .fifo_control = 0x060,
+ .fifo_status = 0x064,
+ .int_mask = 0x068,
+ .int_status = 0x06c,
+ .clk_divisor = 0x070,
+ .bus_clear_cnfg = 0x088,
+ .bus_clear_status = 0x08c,
+ .config_load = 0x090,
+ .clken_override = 0x094,
+ .interface_timing_0 = 0x098,
+ .interface_timing_1 = 0x09c,
+ .hs_interface_timing_0 = 0x0a0,
+ .hs_interface_timing_1 = 0x0a4,
+ .master_reset_cntrl = 0x0ac,
+ .mst_fifo_control = 0x0b8,
+ .mst_fifo_status = 0x0bc,
+ .sw_mutex = 0x0f0,
+ .dvc_ctrl_reg1 = 0x000,
+ .dvc_ctrl_reg3 = 0x008,
+ .dvc_status = 0x00c,
+};
+
/*
* msg_end_type: The bus control which needs to be sent at end of transfer.
* @MSG_END_STOP: Send stop pulse.
@@ -2020,6 +2052,37 @@ static const struct tegra_i2c_hw_feature tegra264_i2c_hw = {
.regs = &tegra20_i2c_regs,
};
+static const struct tegra_i2c_hw_feature tegra410_i2c_hw = {
+ .has_continue_xfer_support = true,
+ .has_per_pkt_xfer_complete_irq = true,
+ .clk_divisor_hs_mode = 1,
+ .clk_divisor_std_mode = 0x1d,
+ .clk_divisor_fast_mode = 0x15,
+ .clk_divisor_fast_plus_mode = 0x8,
+ .has_config_load_reg = true,
+ .has_multi_master_mode = true,
+ .has_slcg_override_reg = true,
+ .has_mst_fifo = true,
+ .quirks = &tegra194_i2c_quirks,
+ .supports_bus_clear = true,
+ .has_apb_dma = false,
+ .tlow_std_mode = 0x8,
+ .thigh_std_mode = 0x7,
+ .tlow_fast_fastplus_mode = 0x2,
+ .thigh_fast_fastplus_mode = 0x2,
+ .tlow_hs_mode = 0x4,
+ .thigh_hs_mode = 0x2,
+ .setup_hold_time_std_mode = 0x08080808,
+ .setup_hold_time_fast_fast_plus_mode = 0x02020202,
+ .setup_hold_time_hs_mode = 0x090909,
+ .has_interface_timing_reg = true,
+ .has_hs_mode_support = true,
+ .has_mutex = true,
+ .is_dvc = false,
+ .is_vi = false,
+ .regs = &tegra410_i2c_regs,
+};
+
static const struct of_device_id tegra_i2c_of_match[] = {
{ .compatible = "nvidia,tegra264-i2c", .data = &tegra264_i2c_hw, },
{ .compatible = "nvidia,tegra256-i2c", .data = &tegra256_i2c_hw, },
@@ -2330,6 +2393,7 @@ static const struct acpi_device_id tegra_i2c_acpi_match[] = {
{.id = "NVDA0101", .driver_data = (kernel_ulong_t)&tegra210_i2c_hw},
{.id = "NVDA0201", .driver_data = (kernel_ulong_t)&tegra186_i2c_hw},
{.id = "NVDA0301", .driver_data = (kernel_ulong_t)&tegra194_i2c_hw},
+ {.id = "NVDA2017", .driver_data = (kernel_ulong_t)&tegra410_i2c_hw},
{ }
};
MODULE_DEVICE_TABLE(acpi, tegra_i2c_acpi_match);
--
2.43.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 1/2] i2c: tegra: Add logic to support different register offsets
2025-10-01 15:36 ` [PATCH 1/2] i2c: tegra: Add logic to support different register offsets Kartik Rajput
@ 2025-10-24 15:11 ` Jon Hunter
2025-10-24 15:13 ` Jon Hunter
` (2 subsequent siblings)
3 siblings, 0 replies; 12+ messages in thread
From: Jon Hunter @ 2025-10-24 15:11 UTC (permalink / raw)
To: Kartik Rajput, akhilrajeev, andi.shyti, robh, krzk+dt, conor+dt,
thierry.reding, ldewangan, digetx, smangipudi, linux-i2c,
devicetree, linux-tegra, linux-kernel
On 01/10/2025 16:36, Kartik Rajput wrote:
> Tegra410 use different offsets for existing I2C registers, update
> the logic to use appropriate offsets per SoC.
>
> Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
> ---
> drivers/i2c/busses/i2c-tegra.c | 499 ++++++++++++++++++++++-----------
> 1 file changed, 334 insertions(+), 165 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
> index 038809264526..1e26d67cbd30 100644
> --- a/drivers/i2c/busses/i2c-tegra.c
> +++ b/drivers/i2c/busses/i2c-tegra.c
...
> @@ -428,8 +519,8 @@ static int tegra_i2c_mutex_lock(struct tegra_i2c_dev *i2c_dev)
>
> if (i2c_dev->atomic_mode)
> ret = read_poll_timeout_atomic(tegra_i2c_mutex_trylock, locked, locked,
> - USEC_PER_MSEC, I2C_SW_MUTEX_TIMEOUT_US,
> - false, i2c_dev);
> + USEC_PER_MSEC, I2C_SW_MUTEX_TIMEOUT_US,
> + false, i2c_dev);
The above appears to be changed accidently?
> @@ -1062,13 +1151,13 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
> tegra_i2c_fill_tx_fifo(i2c_dev);
> else
> tegra_i2c_mask_irq(i2c_dev,
> - I2C_INT_TX_FIFO_DATA_REQ);
> + I2C_INT_TX_FIFO_DATA_REQ);
Same here.
> }
> }
>
> - i2c_writel(i2c_dev, status, I2C_INT_STATUS);
> + i2c_writel(i2c_dev, status, i2c_dev->hw->regs->int_status);
> if (IS_DVC(i2c_dev))
> - dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
> + dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, i2c_dev->hw->regs->dvc_status);
>
> /*
> * During message read XFER_COMPLETE interrupt is triggered prior to
> @@ -1104,10 +1193,10 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
> if (i2c_dev->hw->supports_bus_clear)
> tegra_i2c_mask_irq(i2c_dev, I2C_INT_BUS_CLR_DONE);
>
> - i2c_writel(i2c_dev, status, I2C_INT_STATUS);
> + i2c_writel(i2c_dev, status, i2c_dev->hw->regs->int_status);
>
> if (IS_DVC(i2c_dev))
> - dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
> + dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, i2c_dev->hw->regs->dvc_status);
>
> if (i2c_dev->dma_mode) {
> dmaengine_terminate_async(i2c_dev->dma_chan);
> @@ -1120,16 +1209,16 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
> }
>
> static void tegra_i2c_config_fifo_trig(struct tegra_i2c_dev *i2c_dev,
> - size_t len)
> + size_t len)
And here.
> {
> struct dma_slave_config slv_config = {0};
> u32 val, reg, dma_burst, reg_offset;
> int err;
>
> if (i2c_dev->hw->has_mst_fifo)
> - reg = I2C_MST_FIFO_CONTROL;
> + reg = i2c_dev->hw->regs->mst_fifo_control;
> else
> - reg = I2C_FIFO_CONTROL;
> + reg = i2c_dev->hw->regs->fifo_control;
>
> if (i2c_dev->dma_mode) {
> if (len & 0xF)
> @@ -1140,7 +1229,7 @@ static void tegra_i2c_config_fifo_trig(struct tegra_i2c_dev *i2c_dev,
> dma_burst = 8;
>
> if (i2c_dev->msg_read) {
> - reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_RX_FIFO);
> + reg_offset = i2c_dev->hw->regs->rx_fifo;
>
> slv_config.src_addr = i2c_dev->base_phys + reg_offset;
> slv_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> @@ -1151,7 +1240,7 @@ static void tegra_i2c_config_fifo_trig(struct tegra_i2c_dev *i2c_dev,
> else
> val = I2C_FIFO_CONTROL_RX_TRIG(dma_burst);
> } else {
> - reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_TX_FIFO);
> + reg_offset = i2c_dev->hw->regs->tx_fifo;
>
> slv_config.dst_addr = i2c_dev->base_phys + reg_offset;
> slv_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> @@ -1187,14 +1276,14 @@ static void tegra_i2c_config_fifo_trig(struct tegra_i2c_dev *i2c_dev,
> }
>
> static unsigned long tegra_i2c_poll_completion(struct tegra_i2c_dev *i2c_dev,
> - struct completion *complete,
> - unsigned int timeout_ms)
> + struct completion *complete,
> + unsigned int timeout_ms)
And here.
> {
> ktime_t ktime = ktime_get();
> ktime_t ktimeout = ktime_add_ms(ktime, timeout_ms);
>
> do {
> - u32 status = i2c_readl(i2c_dev, I2C_INT_STATUS);
> + u32 status = i2c_readl(i2c_dev, i2c_dev->hw->regs->int_status);
>
> if (status)
> tegra_i2c_isr(i2c_dev->irq, i2c_dev);
> @@ -1253,14 +1342,14 @@ static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
>
> val = FIELD_PREP(I2C_BC_SCLK_THRESHOLD, 9) | I2C_BC_STOP_COND |
> I2C_BC_TERMINATE;
> - i2c_writel(i2c_dev, val, I2C_BUS_CLEAR_CNFG);
> + i2c_writel(i2c_dev, val, i2c_dev->hw->regs->bus_clear_cnfg);
>
> err = tegra_i2c_wait_for_config_load(i2c_dev);
> if (err)
> return err;
>
> val |= I2C_BC_ENABLE;
> - i2c_writel(i2c_dev, val, I2C_BUS_CLEAR_CNFG);
> + i2c_writel(i2c_dev, val, i2c_dev->hw->regs->bus_clear_cnfg);
> tegra_i2c_unmask_irq(i2c_dev, I2C_INT_BUS_CLR_DONE);
>
> time_left = tegra_i2c_wait_completion(i2c_dev, &i2c_dev->msg_complete, 50);
> @@ -1271,7 +1360,7 @@ static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
> return -ETIMEDOUT;
> }
>
> - val = i2c_readl(i2c_dev, I2C_BUS_CLEAR_STATUS);
> + val = i2c_readl(i2c_dev, i2c_dev->hw->regs->bus_clear_status);
> if (!(val & I2C_BC_STATUS)) {
> dev_err(i2c_dev->dev, "un-recovered arbitration lost\n");
> return -EIO;
> @@ -1281,29 +1370,29 @@ static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
> }
>
> static void tegra_i2c_push_packet_header(struct tegra_i2c_dev *i2c_dev,
> - struct i2c_msg *msg,
> - enum msg_end_type end_state)
> + struct i2c_msg *msg,
> + enum msg_end_type end_state)
And here.
> {
> u32 *dma_buf = i2c_dev->dma_buf;
> u32 packet_header;
>
> packet_header = FIELD_PREP(PACKET_HEADER0_HEADER_SIZE, 0) |
> FIELD_PREP(PACKET_HEADER0_PROTOCOL,
> - PACKET_HEADER0_PROTOCOL_I2C) |
> + PACKET_HEADER0_PROTOCOL_I2C) |
And here.
> FIELD_PREP(PACKET_HEADER0_CONT_ID, i2c_dev->cont_id) |
> FIELD_PREP(PACKET_HEADER0_PACKET_ID, 1);
>
> if (i2c_dev->dma_mode && !i2c_dev->msg_read)
> *dma_buf++ = packet_header;
> else
> - i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
> + i2c_writel(i2c_dev, packet_header, i2c_dev->hw->regs->tx_fifo);
>
> packet_header = i2c_dev->msg_len - 1;
>
> if (i2c_dev->dma_mode && !i2c_dev->msg_read)
> *dma_buf++ = packet_header;
> else
> - i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
> + i2c_writel(i2c_dev, packet_header, i2c_dev->hw->regs->tx_fifo);
>
> packet_header = I2C_HEADER_IE_ENABLE;
>
> @@ -1331,7 +1420,7 @@ static void tegra_i2c_push_packet_header(struct tegra_i2c_dev *i2c_dev,
> if (i2c_dev->dma_mode && !i2c_dev->msg_read)
> *dma_buf++ = packet_header;
> else
> - i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
> + i2c_writel(i2c_dev, packet_header, i2c_dev->hw->regs->tx_fifo);
> }
>
> static int tegra_i2c_error_recover(struct tegra_i2c_dev *i2c_dev,
> @@ -1361,8 +1450,8 @@ static int tegra_i2c_error_recover(struct tegra_i2c_dev *i2c_dev,
> }
>
> static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
> - struct i2c_msg *msg,
> - enum msg_end_type end_state)
> + struct i2c_msg *msg,
> + enum msg_end_type end_state)
And here.
> {
> unsigned long time_left, xfer_time = 100;
> size_t xfer_size;
> @@ -1413,7 +1502,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
> * Total bits = 9 bits per byte (including ACK bit) + Start & stop bits
> */
> xfer_time += DIV_ROUND_CLOSEST(((xfer_size * 9) + 2) * MSEC_PER_SEC,
> - i2c_dev->timings.bus_freq_hz);
> + i2c_dev->timings.bus_freq_hz);
And here.
>
> int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
> tegra_i2c_unmask_irq(i2c_dev, int_mask);
> @@ -1452,12 +1541,12 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
>
> tegra_i2c_unmask_irq(i2c_dev, int_mask);
> dev_dbg(i2c_dev->dev, "unmasked IRQ: %02x\n",
> - i2c_readl(i2c_dev, I2C_INT_MASK));
> + i2c_readl(i2c_dev, i2c_dev->hw->regs->int_mask));
>
> if (i2c_dev->dma_mode) {
> time_left = tegra_i2c_wait_completion(i2c_dev,
> - &i2c_dev->dma_complete,
> - xfer_time);
> + &i2c_dev->dma_complete,
> + xfer_time);
And here.
>
> /*
> * Synchronize DMA first, since dmaengine_terminate_sync()
> @@ -1477,7 +1566,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
> }
>
> time_left = tegra_i2c_wait_completion(i2c_dev, &i2c_dev->msg_complete,
> - xfer_time);
> + xfer_time);
And here.
>
> tegra_i2c_mask_irq(i2c_dev, int_mask);
>
> @@ -1623,7 +1712,75 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
> .has_interface_timing_reg = false,
> .has_hs_mode_support = false,
> .has_mutex = false,
> + .is_dvc = false,
> + .is_vi = false,
> + .regs = &tegra20_i2c_regs,
> +};
> +
> +#if IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)
> +static const struct tegra_i2c_hw_feature tegra20_dvc_i2c_hw = {
> + .has_continue_xfer_support = false,
> + .has_per_pkt_xfer_complete_irq = false,
> + .clk_divisor_hs_mode = 3,
> + .clk_divisor_std_mode = 0,
> + .clk_divisor_fast_mode = 0,
> + .clk_divisor_fast_plus_mode = 0,
> + .has_config_load_reg = false,
> + .has_multi_master_mode = false,
> + .has_slcg_override_reg = false,
> + .has_mst_fifo = false,
> + .has_mst_reset = false,
> + .quirks = &tegra_i2c_quirks,
> + .supports_bus_clear = false,
> + .has_apb_dma = true,
> + .tlow_std_mode = 0x4,
> + .thigh_std_mode = 0x2,
> + .tlow_fast_fastplus_mode = 0x4,
> + .thigh_fast_fastplus_mode = 0x2,
> + .setup_hold_time_std_mode = 0x0,
> + .setup_hold_time_fast_fast_plus_mode = 0x0,
> + .setup_hold_time_hs_mode = 0x0,
> + .has_interface_timing_reg = false,
> + .has_hs_mode_support = false,
> + .has_mutex = false,
> + .is_dvc = true,
> + .is_vi = false,
> + .regs = &tegra20_i2c_regs_dvc,
> +};
> +#endif
Seems like we are duplicating a lot of the above. I am not sure if it
would be better to have a higher level struct so that the common
features bit is not duplicated? I guess that we are only adding two more
of these structures so may be not a big deal?
Also, I would prefer this adding the above tegra20_dvc_i2c_hw was a
separate patch to this because this is a large patch and it would be
clear to add these in their own patch.
> static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev)
> {
> - struct device_node *np = i2c_dev->dev->of_node;
> bool multi_mode;
>
> i2c_parse_fw_timings(i2c_dev->dev, &i2c_dev->timings, true);
>
> multi_mode = device_property_read_bool(i2c_dev->dev, "multi-master");
> i2c_dev->multimaster_mode = multi_mode;
> -
> - if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) &&
> - of_device_is_compatible(np, "nvidia,tegra20-i2c-dvc"))
> - i2c_dev->is_dvc = true;
> -
> - if (IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) &&
> - of_device_is_compatible(np, "nvidia,tegra210-i2c-vi"))
> - i2c_dev->is_vi = true;
> }
Thinking about it, wouldn't it be simpler to keep the above? We could
also populate the regs offset dynamically too. Would this save the
duplication? May be we could only do this for Tegra20 and Tegra210 devices?
Jon
--
nvpublic
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/2] i2c: tegra: Add logic to support different register offsets
2025-10-01 15:36 ` [PATCH 1/2] i2c: tegra: Add logic to support different register offsets Kartik Rajput
2025-10-24 15:11 ` Jon Hunter
@ 2025-10-24 15:13 ` Jon Hunter
2025-10-28 5:47 ` Kartik Rajput
2025-10-24 15:33 ` Jon Hunter
2025-11-06 7:59 ` Jon Hunter
3 siblings, 1 reply; 12+ messages in thread
From: Jon Hunter @ 2025-10-24 15:13 UTC (permalink / raw)
To: Kartik Rajput, akhilrajeev, andi.shyti, robh, krzk+dt, conor+dt,
thierry.reding, ldewangan, digetx, smangipudi, linux-i2c,
devicetree, linux-tegra, linux-kernel
On 01/10/2025 16:36, Kartik Rajput wrote:
> Tegra410 use different offsets for existing I2C registers, update
> the logic to use appropriate offsets per SoC.
>
> Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
> ---
> drivers/i2c/busses/i2c-tegra.c | 499 ++++++++++++++++++++++-----------
> 1 file changed, 334 insertions(+), 165 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
> index 038809264526..1e26d67cbd30 100644
> --- a/drivers/i2c/busses/i2c-tegra.c
> +++ b/drivers/i2c/busses/i2c-tegra.c
...
> +static const struct tegra_i2c_regs tegra20_i2c_regs_vi = {
> + .cnfg = 0x0c00 + (0x000 << 2),
> + .status = 0x0c00 + (0x01c << 2),
> + .sl_cnfg = 0x0c00 + (0x020 << 2),
> + .sl_addr1 = 0x0c00 + (0x02c << 2),
> + .sl_addr2 = 0x0c00 + (0x030 << 2),
> + .tlow_sext = 0x0c00 + (0x034 << 2),
> + .tx_fifo = 0x0c00 + (0x050 << 2),
> + .rx_fifo = 0x0c00 + (0x054 << 2),
> + .packet_transfer_status = 0x0c00 + (0x058 << 2),
> + .fifo_control = 0x0c00 + (0x05c << 2),
> + .fifo_status = 0x0c00 + (0x060 << 2),
> + .int_mask = 0x0c00 + (0x064 << 2),
> + .int_status = 0x0c00 + (0x068 << 2),
> + .clk_divisor = 0x0c00 + (0x06c << 2),
> + .bus_clear_cnfg = 0x0c00 + (0x084 << 2),
> + .bus_clear_status = 0x0c00 + (0x088 << 2),
> + .config_load = 0x0c00 + (0x08c << 2),
> + .clken_override = 0x0c00 + (0x090 << 2),
> + .interface_timing_0 = 0x0c00 + (0x094 << 2),
> + .interface_timing_1 = 0x0c00 + (0x098 << 2),
> + .hs_interface_timing_0 = 0x0c00 + (0x09c << 2),
> + .hs_interface_timing_1 = 0x0c00 + (0x0a0 << 2),
> + .master_reset_cntrl = 0x0c00 + (0x0a8 << 2),
> + .mst_fifo_control = 0x0c00 + (0x0b4 << 2),
> + .mst_fifo_status = 0x0c00 + (0x0b8 << 2),
> + .sw_mutex = 0x0c00 + (0x0ec << 2),
Why do we define all the above with '<< 2'? Seems odd.
Jon
--
nvpublic
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/2] i2c: tegra: Add support for Tegra410
2025-10-01 15:36 ` [PATCH 2/2] i2c: tegra: Add support for Tegra410 Kartik Rajput
@ 2025-10-24 15:17 ` Jon Hunter
2025-10-28 5:44 ` Kartik Rajput
0 siblings, 1 reply; 12+ messages in thread
From: Jon Hunter @ 2025-10-24 15:17 UTC (permalink / raw)
To: Kartik Rajput, akhilrajeev, andi.shyti, robh, krzk+dt, conor+dt,
thierry.reding, ldewangan, digetx, smangipudi, linux-i2c,
devicetree, linux-tegra, linux-kernel
On 01/10/2025 16:36, Kartik Rajput wrote:
> Add support for the Tegra410 SoC, which has 4 I2C controllers. The
> controllers are feature-equivalent to Tegra264; only the register
> offsets differ.
>
> Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
> ---
> drivers/i2c/busses/i2c-tegra.c | 64 ++++++++++++++++++++++++++++++++++
> 1 file changed, 64 insertions(+)
>
> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
> index 1e26d67cbd30..bc9f60b69020 100644
> --- a/drivers/i2c/busses/i2c-tegra.c
> +++ b/drivers/i2c/busses/i2c-tegra.c
> @@ -262,6 +262,38 @@ static const struct tegra_i2c_regs tegra20_i2c_regs_vi = {
> .dvc_status = 0x00c,
> };
>
> +static const struct tegra_i2c_regs tegra410_i2c_regs = {
> + .cnfg = 0x000,
> + .status = 0x01c,
> + .sl_cnfg = 0x020,
> + .sl_addr1 = 0x02c,
> + .sl_addr2 = 0x030,
> + .tlow_sext = 0x034,
> + .tx_fifo = 0x054,
> + .rx_fifo = 0x058,
> + .packet_transfer_status = 0x05c,
> + .fifo_control = 0x060,
> + .fifo_status = 0x064,
> + .int_mask = 0x068,
> + .int_status = 0x06c,
> + .clk_divisor = 0x070,
> + .bus_clear_cnfg = 0x088,
> + .bus_clear_status = 0x08c,
> + .config_load = 0x090,
> + .clken_override = 0x094,
> + .interface_timing_0 = 0x098,
> + .interface_timing_1 = 0x09c,
> + .hs_interface_timing_0 = 0x0a0,
> + .hs_interface_timing_1 = 0x0a4,
> + .master_reset_cntrl = 0x0ac,
> + .mst_fifo_control = 0x0b8,
> + .mst_fifo_status = 0x0bc,
> + .sw_mutex = 0x0f0,
> + .dvc_ctrl_reg1 = 0x000,
> + .dvc_ctrl_reg3 = 0x008,
> + .dvc_status = 0x00c,
We define dvc regs here but ...
> +};
> +
> /*
> * msg_end_type: The bus control which needs to be sent at end of transfer.
> * @MSG_END_STOP: Send stop pulse.
> @@ -2020,6 +2052,37 @@ static const struct tegra_i2c_hw_feature tegra264_i2c_hw = {
> .regs = &tegra20_i2c_regs,
> };
>
> +static const struct tegra_i2c_hw_feature tegra410_i2c_hw = {
> + .has_continue_xfer_support = true,
> + .has_per_pkt_xfer_complete_irq = true,
> + .clk_divisor_hs_mode = 1,
> + .clk_divisor_std_mode = 0x1d,
> + .clk_divisor_fast_mode = 0x15,
> + .clk_divisor_fast_plus_mode = 0x8,
> + .has_config_load_reg = true,
> + .has_multi_master_mode = true,
> + .has_slcg_override_reg = true,
> + .has_mst_fifo = true,
> + .quirks = &tegra194_i2c_quirks,
> + .supports_bus_clear = true,
> + .has_apb_dma = false,
> + .tlow_std_mode = 0x8,
> + .thigh_std_mode = 0x7,
> + .tlow_fast_fastplus_mode = 0x2,
> + .thigh_fast_fastplus_mode = 0x2,
> + .tlow_hs_mode = 0x4,
> + .thigh_hs_mode = 0x2,
> + .setup_hold_time_std_mode = 0x08080808,
> + .setup_hold_time_fast_fast_plus_mode = 0x02020202,
> + .setup_hold_time_hs_mode = 0x090909,
> + .has_interface_timing_reg = true,
> + .has_hs_mode_support = true,
> + .has_mutex = true,
> + .is_dvc = false,
dvc is not supported.
> + .is_vi = false,
> + .regs = &tegra410_i2c_regs,
> +};
> +
> static const struct of_device_id tegra_i2c_of_match[] = {
> { .compatible = "nvidia,tegra264-i2c", .data = &tegra264_i2c_hw, },
> { .compatible = "nvidia,tegra256-i2c", .data = &tegra256_i2c_hw, },
> @@ -2330,6 +2393,7 @@ static const struct acpi_device_id tegra_i2c_acpi_match[] = {
> {.id = "NVDA0101", .driver_data = (kernel_ulong_t)&tegra210_i2c_hw},
> {.id = "NVDA0201", .driver_data = (kernel_ulong_t)&tegra186_i2c_hw},
> {.id = "NVDA0301", .driver_data = (kernel_ulong_t)&tegra194_i2c_hw},
> + {.id = "NVDA2017", .driver_data = (kernel_ulong_t)&tegra410_i2c_hw},
> { }
> };
> MODULE_DEVICE_TABLE(acpi, tegra_i2c_acpi_match);
--
nvpublic
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/2] i2c: tegra: Add logic to support different register offsets
2025-10-01 15:36 ` [PATCH 1/2] i2c: tegra: Add logic to support different register offsets Kartik Rajput
2025-10-24 15:11 ` Jon Hunter
2025-10-24 15:13 ` Jon Hunter
@ 2025-10-24 15:33 ` Jon Hunter
2025-10-28 5:42 ` Kartik Rajput
2025-11-06 7:59 ` Jon Hunter
3 siblings, 1 reply; 12+ messages in thread
From: Jon Hunter @ 2025-10-24 15:33 UTC (permalink / raw)
To: Kartik Rajput, akhilrajeev, andi.shyti, robh, krzk+dt, conor+dt,
thierry.reding, ldewangan, digetx, smangipudi, linux-i2c,
devicetree, linux-tegra, linux-kernel
On 01/10/2025 16:36, Kartik Rajput wrote:
> Tegra410 use different offsets for existing I2C registers, update
> the logic to use appropriate offsets per SoC.
>
> Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
> ---
> drivers/i2c/busses/i2c-tegra.c | 499 ++++++++++++++++++++++-----------
> 1 file changed, 334 insertions(+), 165 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
> index 038809264526..1e26d67cbd30 100644
> --- a/drivers/i2c/busses/i2c-tegra.c
> +++ b/drivers/i2c/busses/i2c-tegra.c
...
> +static const struct tegra_i2c_regs tegra20_i2c_regs_dvc = {
> + .cnfg = 0x000 + 0x40,
> + .status = 0x01c + 0x40,
> + .sl_cnfg = 0x020 + 0x40,
> + .sl_addr1 = 0x02c + 0x40,
> + .sl_addr2 = 0x030 + 0x40,
> + .tlow_sext = 0x034 + 0x40,
> + .tx_fifo = 0x050 + 0x10,
> + .rx_fifo = 0x054 + 0x10,
> + .packet_transfer_status = 0x058 + 0x10,
> + .fifo_control = 0x05c + 0x10,
> + .fifo_status = 0x060 + 0x10,
> + .int_mask = 0x064 + 0x10,
> + .int_status = 0x068 + 0x10,
> + .clk_divisor = 0x06c + 0x10,
> + .bus_clear_cnfg = 0x084 + 0x40,
> + .bus_clear_status = 0x088 + 0x40,
> + .config_load = 0x08c + 0x40,
> + .clken_override = 0x090 + 0x40,
> + .interface_timing_0 = 0x094 + 0x40,
> + .interface_timing_1 = 0x098 + 0x40,
> + .hs_interface_timing_0 = 0x09c + 0x40,
> + .hs_interface_timing_1 = 0x0a0 + 0x40,
> + .master_reset_cntrl = 0x0a8 + 0x40,
> + .mst_fifo_control = 0x0b4 + 0x10,
> + .mst_fifo_status = 0x0b8 + 0x10,
> + .sw_mutex = 0x0ec + 0x40,
sw_mutex is not supported for Tegra20 or anything before Tegra264.
Jon
--
nvpublic
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/2] i2c: tegra: Add logic to support different register offsets
2025-10-24 15:33 ` Jon Hunter
@ 2025-10-28 5:42 ` Kartik Rajput
0 siblings, 0 replies; 12+ messages in thread
From: Kartik Rajput @ 2025-10-28 5:42 UTC (permalink / raw)
To: Jon Hunter, akhilrajeev, andi.shyti, robh, krzk+dt, conor+dt,
thierry.reding, ldewangan, digetx, smangipudi, linux-i2c,
devicetree, linux-tegra, linux-kernel
Hi Jon,
Thanks for reviewing the patch!
On 24/10/25 21:03, Jon Hunter wrote:
>
> On 01/10/2025 16:36, Kartik Rajput wrote:
>> Tegra410 use different offsets for existing I2C registers, update
>> the logic to use appropriate offsets per SoC.
>>
>> Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
>> ---
>> drivers/i2c/busses/i2c-tegra.c | 499 ++++++++++++++++++++++-----------
>> 1 file changed, 334 insertions(+), 165 deletions(-)
>>
>> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
>> index 038809264526..1e26d67cbd30 100644
>> --- a/drivers/i2c/busses/i2c-tegra.c
>> +++ b/drivers/i2c/busses/i2c-tegra.c
>
> ...
>
>> +static const struct tegra_i2c_regs tegra20_i2c_regs_dvc = {
>> + .cnfg = 0x000 + 0x40,
>> + .status = 0x01c + 0x40,
>> + .sl_cnfg = 0x020 + 0x40,
>> + .sl_addr1 = 0x02c + 0x40,
>> + .sl_addr2 = 0x030 + 0x40,
>> + .tlow_sext = 0x034 + 0x40,
>> + .tx_fifo = 0x050 + 0x10,
>> + .rx_fifo = 0x054 + 0x10,
>> + .packet_transfer_status = 0x058 + 0x10,
>> + .fifo_control = 0x05c + 0x10,
>> + .fifo_status = 0x060 + 0x10,
>> + .int_mask = 0x064 + 0x10,
>> + .int_status = 0x068 + 0x10,
>> + .clk_divisor = 0x06c + 0x10,
>> + .bus_clear_cnfg = 0x084 + 0x40,
>> + .bus_clear_status = 0x088 + 0x40,
>> + .config_load = 0x08c + 0x40,
>> + .clken_override = 0x090 + 0x40,
>> + .interface_timing_0 = 0x094 + 0x40,
>> + .interface_timing_1 = 0x098 + 0x40,
>> + .hs_interface_timing_0 = 0x09c + 0x40,
>> + .hs_interface_timing_1 = 0x0a0 + 0x40,
>> + .master_reset_cntrl = 0x0a8 + 0x40,
>> + .mst_fifo_control = 0x0b4 + 0x10,
>> + .mst_fifo_status = 0x0b8 + 0x10,
>> + .sw_mutex = 0x0ec + 0x40,
>
> sw_mutex is not supported for Tegra20 or anything before Tegra264.
>
> Jon
>
Ack.
Thanks,
Kartik
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/2] i2c: tegra: Add support for Tegra410
2025-10-24 15:17 ` Jon Hunter
@ 2025-10-28 5:44 ` Kartik Rajput
0 siblings, 0 replies; 12+ messages in thread
From: Kartik Rajput @ 2025-10-28 5:44 UTC (permalink / raw)
To: Jon Hunter, akhilrajeev, andi.shyti, robh, krzk+dt, conor+dt,
thierry.reding, ldewangan, digetx, smangipudi, linux-i2c,
devicetree, linux-tegra, linux-kernel
On 24/10/25 20:47, Jon Hunter wrote:
>
>
> On 01/10/2025 16:36, Kartik Rajput wrote:
>> Add support for the Tegra410 SoC, which has 4 I2C controllers. The
>> controllers are feature-equivalent to Tegra264; only the register
>> offsets differ.
>>
>> Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
>> ---
>> drivers/i2c/busses/i2c-tegra.c | 64 ++++++++++++++++++++++++++++++++++
>> 1 file changed, 64 insertions(+)
>>
>> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
>> index 1e26d67cbd30..bc9f60b69020 100644
>> --- a/drivers/i2c/busses/i2c-tegra.c
>> +++ b/drivers/i2c/busses/i2c-tegra.c
>> @@ -262,6 +262,38 @@ static const struct tegra_i2c_regs tegra20_i2c_regs_vi = {
>> .dvc_status = 0x00c,
>> };
>> +static const struct tegra_i2c_regs tegra410_i2c_regs = {
>> + .cnfg = 0x000,
>> + .status = 0x01c,
>> + .sl_cnfg = 0x020,
>> + .sl_addr1 = 0x02c,
>> + .sl_addr2 = 0x030,
>> + .tlow_sext = 0x034,
>> + .tx_fifo = 0x054,
>> + .rx_fifo = 0x058,
>> + .packet_transfer_status = 0x05c,
>> + .fifo_control = 0x060,
>> + .fifo_status = 0x064,
>> + .int_mask = 0x068,
>> + .int_status = 0x06c,
>> + .clk_divisor = 0x070,
>> + .bus_clear_cnfg = 0x088,
>> + .bus_clear_status = 0x08c,
>> + .config_load = 0x090,
>> + .clken_override = 0x094,
>> + .interface_timing_0 = 0x098,
>> + .interface_timing_1 = 0x09c,
>> + .hs_interface_timing_0 = 0x0a0,
>> + .hs_interface_timing_1 = 0x0a4,
>> + .master_reset_cntrl = 0x0ac,
>> + .mst_fifo_control = 0x0b8,
>> + .mst_fifo_status = 0x0bc,
>> + .sw_mutex = 0x0f0,
>> + .dvc_ctrl_reg1 = 0x000,
>> + .dvc_ctrl_reg3 = 0x008,
>> + .dvc_status = 0x00c,
>
> We define dvc regs here but ...
>
Ack, I will remove dvc related regs from here.
>> +};
>> +
>> /*
>> * msg_end_type: The bus control which needs to be sent at end of transfer.
>> * @MSG_END_STOP: Send stop pulse.
>> @@ -2020,6 +2052,37 @@ static const struct tegra_i2c_hw_feature tegra264_i2c_hw = {
>> .regs = &tegra20_i2c_regs,
>> };
>> +static const struct tegra_i2c_hw_feature tegra410_i2c_hw = {
>> + .has_continue_xfer_support = true,
>> + .has_per_pkt_xfer_complete_irq = true,
>> + .clk_divisor_hs_mode = 1,
>> + .clk_divisor_std_mode = 0x1d,
>> + .clk_divisor_fast_mode = 0x15,
>> + .clk_divisor_fast_plus_mode = 0x8,
>> + .has_config_load_reg = true,
>> + .has_multi_master_mode = true,
>> + .has_slcg_override_reg = true,
>> + .has_mst_fifo = true,
>> + .quirks = &tegra194_i2c_quirks,
>> + .supports_bus_clear = true,
>> + .has_apb_dma = false,
>> + .tlow_std_mode = 0x8,
>> + .thigh_std_mode = 0x7,
>> + .tlow_fast_fastplus_mode = 0x2,
>> + .thigh_fast_fastplus_mode = 0x2,
>> + .tlow_hs_mode = 0x4,
>> + .thigh_hs_mode = 0x2,
>> + .setup_hold_time_std_mode = 0x08080808,
>> + .setup_hold_time_fast_fast_plus_mode = 0x02020202,
>> + .setup_hold_time_hs_mode = 0x090909,
>> + .has_interface_timing_reg = true,
>> + .has_hs_mode_support = true,
>> + .has_mutex = true,
>> + .is_dvc = false,
>
> dvc is not supported.
>
>> + .is_vi = false,
>> + .regs = &tegra410_i2c_regs,
>> +};
>> +
>> static const struct of_device_id tegra_i2c_of_match[] = {
>> { .compatible = "nvidia,tegra264-i2c", .data = &tegra264_i2c_hw, },
>> { .compatible = "nvidia,tegra256-i2c", .data = &tegra256_i2c_hw, },
>> @@ -2330,6 +2393,7 @@ static const struct acpi_device_id tegra_i2c_acpi_match[] = {
>> {.id = "NVDA0101", .driver_data = (kernel_ulong_t)&tegra210_i2c_hw},
>> {.id = "NVDA0201", .driver_data = (kernel_ulong_t)&tegra186_i2c_hw},
>> {.id = "NVDA0301", .driver_data = (kernel_ulong_t)&tegra194_i2c_hw},
>> + {.id = "NVDA2017", .driver_data = (kernel_ulong_t)&tegra410_i2c_hw},
>> { }
>> };
>> MODULE_DEVICE_TABLE(acpi, tegra_i2c_acpi_match);
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/2] i2c: tegra: Add logic to support different register offsets
2025-10-24 15:13 ` Jon Hunter
@ 2025-10-28 5:47 ` Kartik Rajput
0 siblings, 0 replies; 12+ messages in thread
From: Kartik Rajput @ 2025-10-28 5:47 UTC (permalink / raw)
To: Jon Hunter, akhilrajeev, andi.shyti, robh, krzk+dt, conor+dt,
thierry.reding, ldewangan, digetx, smangipudi, linux-i2c,
devicetree, linux-tegra, linux-kernel
On 24/10/25 20:43, Jon Hunter wrote:
>
> On 01/10/2025 16:36, Kartik Rajput wrote:
>> Tegra410 use different offsets for existing I2C registers, update
>> the logic to use appropriate offsets per SoC.
>>
>> Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
>> ---
>> drivers/i2c/busses/i2c-tegra.c | 499 ++++++++++++++++++++++-----------
>> 1 file changed, 334 insertions(+), 165 deletions(-)
>>
>> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
>> index 038809264526..1e26d67cbd30 100644
>> --- a/drivers/i2c/busses/i2c-tegra.c
>> +++ b/drivers/i2c/busses/i2c-tegra.c
>
> ...
>
>> +static const struct tegra_i2c_regs tegra20_i2c_regs_vi = {
>> + .cnfg = 0x0c00 + (0x000 << 2),
>> + .status = 0x0c00 + (0x01c << 2),
>> + .sl_cnfg = 0x0c00 + (0x020 << 2),
>> + .sl_addr1 = 0x0c00 + (0x02c << 2),
>> + .sl_addr2 = 0x0c00 + (0x030 << 2),
>> + .tlow_sext = 0x0c00 + (0x034 << 2),
>> + .tx_fifo = 0x0c00 + (0x050 << 2),
>> + .rx_fifo = 0x0c00 + (0x054 << 2),
>> + .packet_transfer_status = 0x0c00 + (0x058 << 2),
>> + .fifo_control = 0x0c00 + (0x05c << 2),
>> + .fifo_status = 0x0c00 + (0x060 << 2),
>> + .int_mask = 0x0c00 + (0x064 << 2),
>> + .int_status = 0x0c00 + (0x068 << 2),
>> + .clk_divisor = 0x0c00 + (0x06c << 2),
>> + .bus_clear_cnfg = 0x0c00 + (0x084 << 2),
>> + .bus_clear_status = 0x0c00 + (0x088 << 2),
>> + .config_load = 0x0c00 + (0x08c << 2),
>> + .clken_override = 0x0c00 + (0x090 << 2),
>> + .interface_timing_0 = 0x0c00 + (0x094 << 2),
>> + .interface_timing_1 = 0x0c00 + (0x098 << 2),
>> + .hs_interface_timing_0 = 0x0c00 + (0x09c << 2),
>> + .hs_interface_timing_1 = 0x0c00 + (0x0a0 << 2),
>> + .master_reset_cntrl = 0x0c00 + (0x0a8 << 2),
>> + .mst_fifo_control = 0x0c00 + (0x0b4 << 2),
>> + .mst_fifo_status = 0x0c00 + (0x0b8 << 2),
>> + .sw_mutex = 0x0c00 + (0x0ec << 2),
>
> Why do we define all the above with '<< 2'? Seems odd.
>
> Jon
>
Ack. I will update this with the calculated values.
Thanks,
Kartik
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/2] i2c: tegra: Add logic to support different register offsets
2025-10-01 15:36 ` [PATCH 1/2] i2c: tegra: Add logic to support different register offsets Kartik Rajput
` (2 preceding siblings ...)
2025-10-24 15:33 ` Jon Hunter
@ 2025-11-06 7:59 ` Jon Hunter
2025-11-06 8:06 ` Kartik Rajput
3 siblings, 1 reply; 12+ messages in thread
From: Jon Hunter @ 2025-11-06 7:59 UTC (permalink / raw)
To: Kartik Rajput, akhilrajeev, andi.shyti, robh, krzk+dt, conor+dt,
thierry.reding, ldewangan, digetx, smangipudi, linux-i2c,
devicetree, linux-tegra, linux-kernel
On 01/10/2025 16:36, Kartik Rajput wrote:
> Tegra410 use different offsets for existing I2C registers, update
> the logic to use appropriate offsets per SoC.
>
> Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
> ---
> drivers/i2c/busses/i2c-tegra.c | 499 ++++++++++++++++++++++-----------
> 1 file changed, 334 insertions(+), 165 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
> index 038809264526..1e26d67cbd30 100644
> --- a/drivers/i2c/busses/i2c-tegra.c
> +++ b/drivers/i2c/busses/i2c-tegra.c
...
> /*
> * msg_end_type: The bus control which needs to be sent at end of transfer.
> * @MSG_END_STOP: Send stop pulse.
> @@ -219,6 +322,9 @@ enum msg_end_type {
> * timing settings.
> * @has_hs_mode_support: Has support for high speed (HS) mode transfers.
> * @has_mutex: Has mutex register for mutual exclusion with other firmwares or VMs.
> + * @is_dvc: This instance represents the DVC I2C controller variant.
> + * @is_vi: This instance represents the VI I2C controller variant.
> + * @regs: Register offsets for the specific SoC variant.
> */
> struct tegra_i2c_hw_feature {
> bool has_continue_xfer_support;
> @@ -247,6 +353,9 @@ struct tegra_i2c_hw_feature {
> bool has_interface_timing_reg;
> bool has_hs_mode_support;
> bool has_mutex;
> + bool is_dvc;
> + bool is_vi;
> + const struct tegra_i2c_regs *regs;
> };
I think it could be better to have a 'variant' flag for these is_dvc and
is_vi variables because they are mutually exclusive.
Jon
--
nvpublic
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/2] i2c: tegra: Add logic to support different register offsets
2025-11-06 7:59 ` Jon Hunter
@ 2025-11-06 8:06 ` Kartik Rajput
0 siblings, 0 replies; 12+ messages in thread
From: Kartik Rajput @ 2025-11-06 8:06 UTC (permalink / raw)
To: Jon Hunter, akhilrajeev, andi.shyti, robh, krzk+dt, conor+dt,
thierry.reding, ldewangan, digetx, smangipudi, linux-i2c,
devicetree, linux-tegra, linux-kernel
On 06/11/25 13:29, Jon Hunter wrote:
>
> On 01/10/2025 16:36, Kartik Rajput wrote:
>> Tegra410 use different offsets for existing I2C registers, update
>> the logic to use appropriate offsets per SoC.
>>
>> Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
>> ---
>> drivers/i2c/busses/i2c-tegra.c | 499 ++++++++++++++++++++++-----------
>> 1 file changed, 334 insertions(+), 165 deletions(-)
>>
>> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
>> index 038809264526..1e26d67cbd30 100644
>> --- a/drivers/i2c/busses/i2c-tegra.c
>> +++ b/drivers/i2c/busses/i2c-tegra.c
>
> ...
>
>> /*
>> * msg_end_type: The bus control which needs to be sent at end of transfer.
>> * @MSG_END_STOP: Send stop pulse.
>> @@ -219,6 +322,9 @@ enum msg_end_type {
>> * timing settings.
>> * @has_hs_mode_support: Has support for high speed (HS) mode transfers.
>> * @has_mutex: Has mutex register for mutual exclusion with other firmwares or VMs.
>> + * @is_dvc: This instance represents the DVC I2C controller variant.
>> + * @is_vi: This instance represents the VI I2C controller variant.
>> + * @regs: Register offsets for the specific SoC variant.
>> */
>> struct tegra_i2c_hw_feature {
>> bool has_continue_xfer_support;
>> @@ -247,6 +353,9 @@ struct tegra_i2c_hw_feature {
>> bool has_interface_timing_reg;
>> bool has_hs_mode_support;
>> bool has_mutex;
>> + bool is_dvc;
>> + bool is_vi;
>> + const struct tegra_i2c_regs *regs;
>> };
>
>
> I think it could be better to have a 'variant' flag for these is_dvc and is_vi variables because they are mutually exclusive.
>
> Jon
>
Ack, I will use a flag for 'is_dvc' and 'is_vi' in the next version.
Thanks,
Kartik
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2025-11-06 8:06 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-01 15:36 [PATCH 0/2] Add I2C support for Tegra410 Kartik Rajput
2025-10-01 15:36 ` [PATCH 1/2] i2c: tegra: Add logic to support different register offsets Kartik Rajput
2025-10-24 15:11 ` Jon Hunter
2025-10-24 15:13 ` Jon Hunter
2025-10-28 5:47 ` Kartik Rajput
2025-10-24 15:33 ` Jon Hunter
2025-10-28 5:42 ` Kartik Rajput
2025-11-06 7:59 ` Jon Hunter
2025-11-06 8:06 ` Kartik Rajput
2025-10-01 15:36 ` [PATCH 2/2] i2c: tegra: Add support for Tegra410 Kartik Rajput
2025-10-24 15:17 ` Jon Hunter
2025-10-28 5:44 ` Kartik Rajput
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).