Re: [PATCH v2] i2c: tegra: Add support for Tegra194

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Jun 19, 2018 at 12:49:42PM +0200, Thierry Reding wrote:
> From: Thierry Reding <treding@xxxxxxxxxx>
> 
> In order to support advanced features, the I2C FIFO interface was
> changed in the version of the Tegra I2C controller found in Tegra194.
> The changes are backwards incompatible, so the driver needs to be
> programmed in a slightly different way on new chips.
> 
> Add support for MST FIFO programming and add an OF match entry for
> Tegra194. At the same time, mark all prior generations of this
> controller as not having the MST FIFO interface.
> 
> Acked-by: Jon Hunter <jonathanh@xxxxxxxxxx>
> Signed-off-by: Thierry Reding <treding@xxxxxxxxxx>
> ---
> Changes in v2:
> - remove commented out code which was left over from debugging
> 
>  drivers/i2c/busses/i2c-tegra.c | 90 ++++++++++++++++++++++++++++------
>  1 file changed, 76 insertions(+), 14 deletions(-)

Hi Wolfram,

do you have any comments on this patch? I'd like to get this merged into
v4.19 so that we can continue enabling more features on Tegra194.

Thanks,
Thierry

> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
> index 5fccd1f1bca8..edde464dfb72 100644
> --- a/drivers/i2c/busses/i2c-tegra.c
> +++ b/drivers/i2c/busses/i2c-tegra.c
> @@ -115,6 +115,18 @@
>  
>  #define I2C_CONFIG_LOAD_TIMEOUT			1000000
>  
> +#define I2C_MST_FIFO_CONTROL			0x0b4
> +#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_RX_MASK		0xff
> +#define I2C_MST_FIFO_STATUS_RX_SHIFT		0
> +#define I2C_MST_FIFO_STATUS_TX_MASK		0xff0000
> +#define I2C_MST_FIFO_STATUS_TX_SHIFT		16
> +
>  /*
>   * msg_end_type: The bus control which need to be send at end of transfer.
>   * @MSG_END_STOP: Send stop pulse at end of transfer.
> @@ -154,6 +166,7 @@ struct tegra_i2c_hw_feature {
>  	u16 clk_divisor_fast_plus_mode;
>  	bool has_multi_master_mode;
>  	bool has_slcg_override_reg;
> +	bool has_mst_fifo;
>  };
>  
>  /**
> @@ -266,13 +279,24 @@ static void tegra_i2c_unmask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask)
>  static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev)
>  {
>  	unsigned long timeout = jiffies + HZ;
> -	u32 val = i2c_readl(i2c_dev, I2C_FIFO_CONTROL);
> +	unsigned int offset;
> +	u32 mask, val;
> +
> +	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;
> +	} else {
> +		mask = I2C_FIFO_CONTROL_TX_FLUSH |
> +		       I2C_FIFO_CONTROL_RX_FLUSH;
> +		offset = I2C_FIFO_CONTROL;
> +	}
>  
> -	val |= I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH;
> -	i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL);
> +	val = i2c_readl(i2c_dev, offset);
> +	val |= mask;
> +	i2c_writel(i2c_dev, val, offset);
>  
> -	while (i2c_readl(i2c_dev, I2C_FIFO_CONTROL) &
> -		(I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH)) {
> +	while (i2c_readl(i2c_dev, offset) & mask) {
>  		if (time_after(jiffies, timeout)) {
>  			dev_warn(i2c_dev->dev, "timeout waiting for fifo flush\n");
>  			return -ETIMEDOUT;
> @@ -290,9 +314,15 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
>  	size_t buf_remaining = i2c_dev->msg_buf_remaining;
>  	int words_to_transfer;
>  
> -	val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
> -	rx_fifo_avail = (val & I2C_FIFO_STATUS_RX_MASK) >>
> -		I2C_FIFO_STATUS_RX_SHIFT;
> +	if (i2c_dev->hw->has_mst_fifo) {
> +		val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS);
> +		rx_fifo_avail = (val & I2C_MST_FIFO_STATUS_RX_MASK) >>
> +			I2C_MST_FIFO_STATUS_RX_SHIFT;
> +	} else {
> +		val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
> +		rx_fifo_avail = (val & I2C_FIFO_STATUS_RX_MASK) >>
> +			I2C_FIFO_STATUS_RX_SHIFT;
> +	}
>  
>  	/* Rounds down to not include partial word at the end of buf */
>  	words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD;
> @@ -321,6 +351,7 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
>  	BUG_ON(rx_fifo_avail > 0 && buf_remaining > 0);
>  	i2c_dev->msg_buf_remaining = buf_remaining;
>  	i2c_dev->msg_buf = buf;
> +
>  	return 0;
>  }
>  
> @@ -332,9 +363,15 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
>  	size_t buf_remaining = i2c_dev->msg_buf_remaining;
>  	int words_to_transfer;
>  
> -	val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
> -	tx_fifo_avail = (val & I2C_FIFO_STATUS_TX_MASK) >>
> -		I2C_FIFO_STATUS_TX_SHIFT;
> +	if (i2c_dev->hw->has_mst_fifo) {
> +		val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS);
> +		tx_fifo_avail = (val & I2C_MST_FIFO_STATUS_TX_MASK) >>
> +			I2C_MST_FIFO_STATUS_TX_SHIFT;
> +	} else {
> +		val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
> +		tx_fifo_avail = (val & I2C_FIFO_STATUS_TX_MASK) >>
> +			I2C_FIFO_STATUS_TX_SHIFT;
> +	}
>  
>  	/* Rounds down to not include partial word at the end of buf */
>  	words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD;
> @@ -516,9 +553,15 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
>  		i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2);
>  	}
>  
> -	val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT |
> -		0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT;
> -	i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL);
> +	if (i2c_dev->hw->has_mst_fifo) {
> +		val = I2C_MST_FIFO_CONTROL_TX_TRIG(8) |
> +		      I2C_MST_FIFO_CONTROL_RX_TRIG(1);
> +		i2c_writel(i2c_dev, val, I2C_MST_FIFO_CONTROL);
> +	} else {
> +		val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT |
> +			0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT;
> +		i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL);
> +	}
>  
>  	err = tegra_i2c_flush_fifos(i2c_dev);
>  	if (err)
> @@ -803,6 +846,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
>  	.has_config_load_reg = false,
>  	.has_multi_master_mode = false,
>  	.has_slcg_override_reg = false,
> +	.has_mst_fifo = false,
>  };
>  
>  static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
> @@ -815,6 +859,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
>  	.has_config_load_reg = false,
>  	.has_multi_master_mode = false,
>  	.has_slcg_override_reg = false,
> +	.has_mst_fifo = false,
>  };
>  
>  static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
> @@ -827,6 +872,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
>  	.has_config_load_reg = false,
>  	.has_multi_master_mode = false,
>  	.has_slcg_override_reg = false,
> +	.has_mst_fifo = false,
>  };
>  
>  static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
> @@ -839,6 +885,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
>  	.has_config_load_reg = true,
>  	.has_multi_master_mode = false,
>  	.has_slcg_override_reg = true,
> +	.has_mst_fifo = false,
>  };
>  
>  static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
> @@ -851,10 +898,25 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
>  	.has_config_load_reg = true,
>  	.has_multi_master_mode = true,
>  	.has_slcg_override_reg = true,
> +	.has_mst_fifo = false,
> +};
> +
> +static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
> +	.has_continue_xfer_support = true,
> +	.has_per_pkt_xfer_complete_irq = true,
> +	.has_single_clk_source = true,
> +	.clk_divisor_hs_mode = 1,
> +	.clk_divisor_std_fast_mode = 0x19,
> +	.clk_divisor_fast_plus_mode = 0x10,
> +	.has_config_load_reg = true,
> +	.has_multi_master_mode = true,
> +	.has_slcg_override_reg = true,
> +	.has_mst_fifo = true,
>  };
>  
>  /* Match table for of_platform binding */
>  static const struct of_device_id tegra_i2c_of_match[] = {
> +	{ .compatible = "nvidia,tegra194-i2c", .data = &tegra194_i2c_hw, },
>  	{ .compatible = "nvidia,tegra210-i2c", .data = &tegra210_i2c_hw, },
>  	{ .compatible = "nvidia,tegra124-i2c", .data = &tegra124_i2c_hw, },
>  	{ .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, },
> -- 
> 2.17.0
> 

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [Linux GPIO]     [Linux SPI]     [Linux Hardward Monitoring]     [LM Sensors]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux