public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Jon Hunter <jonathanh@nvidia.com>
To: Kartik Rajput <kkartik@nvidia.com>,
	akhilrajeev@nvidia.com, andi.shyti@kernel.org, robh@kernel.org,
	krzk+dt@kernel.org, conor+dt@kernel.org,
	thierry.reding@gmail.com, ldewangan@nvidia.com, digetx@gmail.com,
	smangipudi@nvidia.com, linux-i2c@vger.kernel.org,
	devicetree@vger.kernel.org, linux-tegra@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH 1/2] i2c: tegra: Add logic to support different register offsets
Date: Fri, 24 Oct 2025 16:11:07 +0100	[thread overview]
Message-ID: <8cf72af2-8a0c-4a0b-b5d1-77038ce804b3@nvidia.com> (raw)
In-Reply-To: <20251001153648.667036-2-kkartik@nvidia.com>



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


  reply	other threads:[~2025-10-24 15:11 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8cf72af2-8a0c-4a0b-b5d1-77038ce804b3@nvidia.com \
    --to=jonathanh@nvidia.com \
    --cc=akhilrajeev@nvidia.com \
    --cc=andi.shyti@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=digetx@gmail.com \
    --cc=kkartik@nvidia.com \
    --cc=krzk+dt@kernel.org \
    --cc=ldewangan@nvidia.com \
    --cc=linux-i2c@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    --cc=robh@kernel.org \
    --cc=smangipudi@nvidia.com \
    --cc=thierry.reding@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox