Message ID | 20180618150450.13723-1-thierry.reding@gmail.com |
---|---|
State | Deferred |
Headers | show |
Series | i2c: tegra: Add support for Tegra194 | expand |
On Monday, 18 June 2018 18:04:50 MSK Thierry Reding wrote: > From: Thierry Reding <treding@nvidia.com> > > 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. > > Signed-off-by: Thierry Reding <treding@nvidia.com> > --- > drivers/i2c/busses/i2c-tegra.c | 99 +++++++++++++++++++++++++++++----- > 1 file changed, 85 insertions(+), 14 deletions(-) > > diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c > index 5fccd1f1bca8..a2779e9af1ff 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,16 @@ 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; > + > + /* > + * All bytes received, mask RX_FIFO_DATA_REQ to prevent more > + * interrupts from FIFO. > + */ > + /* > + if (i2c_dev->msg_buf_remaining == 0) > + tegra_i2c_mask_irq(i2c_dev, I2C_INT_RX_FIFO_DATA_REQ); > + */ Is it a deliberately commented out code? -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 18/06/18 17:59, Dmitry Osipenko wrote: > On Monday, 18 June 2018 18:04:50 MSK Thierry Reding wrote: >> From: Thierry Reding <treding@nvidia.com> >> >> 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. >> >> Signed-off-by: Thierry Reding <treding@nvidia.com> >> --- >> drivers/i2c/busses/i2c-tegra.c | 99 +++++++++++++++++++++++++++++----- >> 1 file changed, 85 insertions(+), 14 deletions(-) >> >> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c >> index 5fccd1f1bca8..a2779e9af1ff 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,16 @@ 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; >> + >> + /* >> + * All bytes received, mask RX_FIFO_DATA_REQ to prevent more >> + * interrupts from FIFO. >> + */ >> + /* >> + if (i2c_dev->msg_buf_remaining == 0) >> + tegra_i2c_mask_irq(i2c_dev, I2C_INT_RX_FIFO_DATA_REQ); >> + */ > > Is it a deliberately commented out code? This does look odd and I am guessing it was not meant to be part of this patch. If so and you drop the above snippet, as it looks like it should be a separate patch if uncommented, then for the rest of the patch ... Acked-by: Jon Hunter <jonathanh@nvidia.com> Cheers Jon
On Mon, Jun 18, 2018 at 07:59:51PM +0300, Dmitry Osipenko wrote: > On Monday, 18 June 2018 18:04:50 MSK Thierry Reding wrote: > > From: Thierry Reding <treding@nvidia.com> > > > > 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. > > > > Signed-off-by: Thierry Reding <treding@nvidia.com> > > --- > > drivers/i2c/busses/i2c-tegra.c | 99 +++++++++++++++++++++++++++++----- > > 1 file changed, 85 insertions(+), 14 deletions(-) > > > > diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c > > index 5fccd1f1bca8..a2779e9af1ff 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,16 @@ 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; > > + > > + /* > > + * All bytes received, mask RX_FIFO_DATA_REQ to prevent more > > + * interrupts from FIFO. > > + */ > > + /* > > + if (i2c_dev->msg_buf_remaining == 0) > > + tegra_i2c_mask_irq(i2c_dev, I2C_INT_RX_FIFO_DATA_REQ); > > + */ > > Is it a deliberately commented out code? I think I left this in by mistake. The code certainly did work the last time I tried with the above commented out, so I'll just remove it. Thierry
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 5fccd1f1bca8..a2779e9af1ff 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,16 @@ 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; + + /* + * All bytes received, mask RX_FIFO_DATA_REQ to prevent more + * interrupts from FIFO. + */ + /* + if (i2c_dev->msg_buf_remaining == 0) + tegra_i2c_mask_irq(i2c_dev, I2C_INT_RX_FIFO_DATA_REQ); + */ + return 0; } @@ -332,9 +372,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 +562,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 +855,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 +868,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 +881,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 +894,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 +907,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, },