i2c: tegra: Factor out hardware initialization into separate function
[linux-2.6-block.git] / drivers / i2c / busses / i2c-tegra.c
index 15772964a05f12847605b24c9b1d87812b01e436..d8fc5cdcc310117c12b3eddf68178976330ec53f 100644 (file)
@@ -165,9 +165,6 @@ enum msg_end_type {
  * @has_continue_xfer_support: Continue transfer supports.
  * @has_per_pkt_xfer_complete_irq: Has enable/disable capability for transfer
  *             complete interrupt per packet basis.
- * @has_single_clk_source: The I2C controller has single clock source. Tegra30
- *             and earlier SoCs have two clock sources i.e. div-clk and
- *             fast-clk.
  * @has_config_load_reg: Has the config load register to load the new
  *             configuration.
  * @clk_divisor_hs_mode: Clock divisor in HS mode.
@@ -208,22 +205,21 @@ enum msg_end_type {
 struct tegra_i2c_hw_feature {
        bool has_continue_xfer_support;
        bool has_per_pkt_xfer_complete_irq;
-       bool has_single_clk_source;
        bool has_config_load_reg;
-       int clk_divisor_hs_mode;
-       int clk_divisor_std_mode;
-       int clk_divisor_fast_mode;
-       u16 clk_divisor_fast_plus_mode;
+       u32 clk_divisor_hs_mode;
+       u32 clk_divisor_std_mode;
+       u32 clk_divisor_fast_mode;
+       u32 clk_divisor_fast_plus_mode;
        bool has_multi_master_mode;
        bool has_slcg_override_reg;
        bool has_mst_fifo;
        const struct i2c_adapter_quirks *quirks;
        bool supports_bus_clear;
        bool has_apb_dma;
-       u8 tlow_std_mode;
-       u8 thigh_std_mode;
-       u8 tlow_fast_fastplus_mode;
-       u8 thigh_fast_fastplus_mode;
+       u32 tlow_std_mode;
+       u32 thigh_std_mode;
+       u32 tlow_fast_fastplus_mode;
+       u32 thigh_fast_fastplus_mode;
        u32 setup_hold_time_std_mode;
        u32 setup_hold_time_fast_fast_plus_mode;
        u32 setup_hold_time_hs_mode;
@@ -236,7 +232,8 @@ struct tegra_i2c_hw_feature {
  * @hw: Tegra I2C HW feature
  * @adapter: core I2C layer adapter information
  * @div_clk: clock reference for div clock of I2C controller
- * @fast_clk: clock reference for fast clock of I2C controller
+ * @clocks: array of I2C controller clocks
+ * @nclocks: number of clocks in the array
  * @rst: reset control for the I2C controller
  * @base: ioremapped registers cookie
  * @base_phys: physical base address of the I2C controller
@@ -250,7 +247,6 @@ struct tegra_i2c_hw_feature {
  * @msg_buf_remaining: size of unsent data in the message buffer
  * @msg_read: identifies read transfers
  * @bus_clk_rate: current I2C bus clock rate
- * @clk_divisor_non_hs_mode: clock divider for non-high-speed modes
  * @is_multimaster_mode: track if I2C controller is in multi-master mode
  * @tx_dma_chan: DMA transmit channel
  * @rx_dma_chan: DMA receive channel
@@ -266,27 +262,26 @@ struct tegra_i2c_dev {
        const struct tegra_i2c_hw_feature *hw;
        struct i2c_adapter adapter;
        struct clk *div_clk;
-       struct clk *fast_clk;
-       struct clk *slow_clk;
+       struct clk_bulk_data clocks[2];
+       unsigned int nclocks;
        struct reset_control *rst;
        void __iomem *base;
        phys_addr_t base_phys;
-       int cont_id;
-       int irq;
-       int is_dvc;
+       unsigned int cont_id;
+       unsigned int irq;
+       bool is_dvc;
        bool is_vi;
        struct completion msg_complete;
        int msg_err;
        u8 *msg_buf;
        size_t msg_buf_remaining;
-       int msg_read;
+       bool msg_read;
        u32 bus_clk_rate;
-       u16 clk_divisor_non_hs_mode;
        bool is_multimaster_mode;
        struct dma_chan *tx_dma_chan;
        struct dma_chan *rx_dma_chan;
        dma_addr_t dma_phys;
-       u32 *dma_buf;
+       void *dma_buf;
        unsigned int dma_buf_size;
        bool is_curr_dma_xfer;
        struct completion dma_complete;
@@ -334,13 +329,13 @@ static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
 }
 
 static void i2c_writesl(struct tegra_i2c_dev *i2c_dev, void *data,
-                       unsigned long reg, int len)
+                       unsigned long reg, unsigned int len)
 {
        writesl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len);
 }
 
 static void i2c_readsl(struct tegra_i2c_dev *i2c_dev, void *data,
-                      unsigned long reg, int len)
+                      unsigned long reg, unsigned int len)
 {
        readsl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len);
 }
@@ -419,7 +414,7 @@ static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev)
        dma_addr_t dma_phys;
        int err;
 
-       if (!i2c_dev->hw->has_apb_dma)
+       if (!i2c_dev->hw->has_apb_dma || i2c_dev->is_vi)
                return 0;
 
        if (!IS_ENABLED(CONFIG_TEGRA20_APB_DMA)) {
@@ -443,6 +438,9 @@ static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev)
 
        i2c_dev->tx_dma_chan = chan;
 
+       i2c_dev->dma_buf_size = i2c_dev->hw->quirks->max_write_len +
+                               I2C_PACKET_HEADER_SIZE;
+
        dma_buf = dma_alloc_coherent(i2c_dev->dev, i2c_dev->dma_buf_size,
                                     &dma_phys, GFP_KERNEL | __GFP_NOWARN);
        if (!dma_buf) {
@@ -466,165 +464,6 @@ err_out:
        return err;
 }
 
-static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev)
-{
-       unsigned long timeout = jiffies + HZ;
-       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_readl(i2c_dev, offset);
-       val |= mask;
-       i2c_writel(i2c_dev, val, offset);
-
-       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;
-               }
-               usleep_range(1000, 2000);
-       }
-       return 0;
-}
-
-static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
-{
-       u32 val;
-       int rx_fifo_avail;
-       u8 *buf = i2c_dev->msg_buf;
-       size_t buf_remaining = i2c_dev->msg_buf_remaining;
-       int words_to_transfer;
-
-       /*
-        * Catch overflow due to message fully sent
-        * before the check for RX FIFO availability.
-        */
-       if (WARN_ON_ONCE(!(i2c_dev->msg_buf_remaining)))
-               return -EINVAL;
-
-       if (i2c_dev->hw->has_mst_fifo) {
-               val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS);
-               rx_fifo_avail = FIELD_GET(I2C_MST_FIFO_STATUS_RX, val);
-       } else {
-               val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
-               rx_fifo_avail = FIELD_GET(I2C_FIFO_STATUS_RX, val);
-       }
-
-       /* Rounds down to not include partial word at the end of buf */
-       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);
-
-       buf += words_to_transfer * BYTES_PER_FIFO_WORD;
-       buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD;
-       rx_fifo_avail -= words_to_transfer;
-
-       /*
-        * If there is a partial word at the end of buf, handle it manually to
-        * prevent overwriting past the end of buf
-        */
-       if (rx_fifo_avail > 0 && buf_remaining > 0) {
-               /*
-                * buf_remaining > 3 check not needed as rx_fifo_avail == 0
-                * when (words_to_transfer was > rx_fifo_avail) earlier
-                * in this function.
-                */
-               val = i2c_readl(i2c_dev, I2C_RX_FIFO);
-               val = cpu_to_le32(val);
-               memcpy(buf, &val, buf_remaining);
-               buf_remaining = 0;
-               rx_fifo_avail--;
-       }
-
-       /* RX FIFO must be drained, otherwise it's an Overflow case. */
-       if (WARN_ON_ONCE(rx_fifo_avail))
-               return -EINVAL;
-
-       i2c_dev->msg_buf_remaining = buf_remaining;
-       i2c_dev->msg_buf = buf;
-
-       return 0;
-}
-
-static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
-{
-       u32 val;
-       int tx_fifo_avail;
-       u8 *buf = i2c_dev->msg_buf;
-       size_t buf_remaining = i2c_dev->msg_buf_remaining;
-       int words_to_transfer;
-
-       if (i2c_dev->hw->has_mst_fifo) {
-               val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS);
-               tx_fifo_avail = FIELD_GET(I2C_MST_FIFO_STATUS_TX, val);
-       } else {
-               val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
-               tx_fifo_avail = FIELD_GET(I2C_FIFO_STATUS_TX, val);
-       }
-
-       /* Rounds down to not include partial word at the end of buf */
-       words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD;
-
-       /* It's very common to have < 4 bytes, so optimize that case. */
-       if (words_to_transfer) {
-               if (words_to_transfer > tx_fifo_avail)
-                       words_to_transfer = tx_fifo_avail;
-
-               /*
-                * Update state before writing to FIFO.  If this casues us
-                * to finish writing all bytes (AKA buf_remaining goes to 0) we
-                * have a potential for an interrupt (PACKET_XFER_COMPLETE is
-                * not maskable).  We need to make sure that the isr sees
-                * buf_remaining as 0 and doesn't call us back re-entrantly.
-                */
-               buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD;
-               tx_fifo_avail -= words_to_transfer;
-               i2c_dev->msg_buf_remaining = buf_remaining;
-               i2c_dev->msg_buf = buf +
-                       words_to_transfer * BYTES_PER_FIFO_WORD;
-               barrier();
-
-               i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer);
-
-               buf += words_to_transfer * BYTES_PER_FIFO_WORD;
-       }
-
-       /*
-        * If there is a partial word at the end of buf, handle it manually to
-        * prevent reading past the end of buf, which could cross a page
-        * boundary and fault.
-        */
-       if (tx_fifo_avail > 0 && buf_remaining > 0) {
-               /*
-                * buf_remaining > 3 check not needed as tx_fifo_avail == 0
-                * when (words_to_transfer was > tx_fifo_avail) earlier
-                * in this function for non-zero words_to_transfer.
-                */
-               memcpy(&val, buf, buf_remaining);
-               val = le32_to_cpu(val);
-
-               /* Again update before writing to FIFO to make sure isr sees. */
-               i2c_dev->msg_buf_remaining = 0;
-               i2c_dev->msg_buf = NULL;
-               barrier();
-
-               i2c_writel(i2c_dev, val, I2C_TX_FIFO);
-       }
-
-       return 0;
-}
-
 /*
  * One of the Tegra I2C blocks is inside the DVC (Digital Voltage Controller)
  * block.  This block is identical to the rest of the I2C blocks, except that
@@ -646,89 +485,6 @@ static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev)
        dvc_writel(i2c_dev, val, DVC_CTRL_REG1);
 }
 
-static int __maybe_unused tegra_i2c_runtime_resume(struct device *dev)
-{
-       struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
-       int ret;
-
-       ret = pinctrl_pm_select_default_state(i2c_dev->dev);
-       if (ret)
-               return ret;
-
-       if (!i2c_dev->hw->has_single_clk_source) {
-               ret = clk_enable(i2c_dev->fast_clk);
-               if (ret < 0) {
-                       dev_err(i2c_dev->dev,
-                               "Enabling fast clk failed, err %d\n", ret);
-                       return ret;
-               }
-       }
-
-       if (i2c_dev->slow_clk) {
-               ret = clk_enable(i2c_dev->slow_clk);
-               if (ret < 0) {
-                       dev_err(dev, "failed to enable slow clock: %d\n", ret);
-                       return ret;
-               }
-       }
-
-       ret = clk_enable(i2c_dev->div_clk);
-       if (ret < 0) {
-               dev_err(i2c_dev->dev,
-                       "Enabling div clk failed, err %d\n", ret);
-               clk_disable(i2c_dev->fast_clk);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int __maybe_unused tegra_i2c_runtime_suspend(struct device *dev)
-{
-       struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
-
-       clk_disable(i2c_dev->div_clk);
-
-       if (i2c_dev->slow_clk)
-               clk_disable(i2c_dev->slow_clk);
-
-       if (!i2c_dev->hw->has_single_clk_source)
-               clk_disable(i2c_dev->fast_clk);
-
-       return pinctrl_pm_select_idle_state(i2c_dev->dev);
-}
-
-static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev)
-{
-       unsigned long reg_offset;
-       void __iomem *addr;
-       u32 val;
-       int err;
-
-       if (i2c_dev->hw->has_config_load_reg) {
-               reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_CONFIG_LOAD);
-               addr = i2c_dev->base + reg_offset;
-               i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD);
-
-               if (i2c_dev->is_curr_atomic_xfer)
-                       err = readl_relaxed_poll_timeout_atomic(
-                                               addr, val, val == 0, 1000,
-                                               I2C_CONFIG_LOAD_TIMEOUT);
-               else
-                       err = readl_relaxed_poll_timeout(
-                                               addr, val, val == 0, 1000,
-                                               I2C_CONFIG_LOAD_TIMEOUT);
-
-               if (err) {
-                       dev_warn(i2c_dev->dev,
-                                "timeout waiting for config load\n");
-                       return err;
-               }
-       }
-
-       return 0;
-}
-
 static void tegra_i2c_vi_init(struct tegra_i2c_dev *i2c_dev)
 {
        u32 value;
@@ -758,17 +514,86 @@ static void tegra_i2c_vi_init(struct tegra_i2c_dev *i2c_dev)
        i2c_writel(i2c_dev, 0x0, I2C_TLOW_SEXT);
 }
 
-static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
+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);
+       u32 val;
+
+       if (!i2c_dev->is_curr_atomic_xfer)
+               return readl_relaxed_poll_timeout(addr, val, !(val & mask),
+                                                 delay_us, timeout_us);
+
+       return readl_relaxed_poll_timeout_atomic(addr, val, !(val & mask),
+                                                delay_us, timeout_us);
+}
+
+static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev)
+{
+       u32 mask, val, offset;
+       int err;
+
+       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_readl(i2c_dev, offset);
+       val |= mask;
+       i2c_writel(i2c_dev, val, offset);
+
+       err = tegra_i2c_poll_register(i2c_dev, offset, mask, 1000, 1000000);
+       if (err) {
+               dev_err(i2c_dev->dev, "failed to flush FIFO\n");
+               return err;
+       }
+       return 0;
+}
+
+static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev)
+{
+       int err;
+
+       if (!i2c_dev->hw->has_config_load_reg)
+               return 0;
+
+       i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD);
+
+       err = tegra_i2c_poll_register(i2c_dev, I2C_CONFIG_LOAD, 0xffffffff,
+                                     1000, I2C_CONFIG_LOAD_TIMEOUT);
+       if (err) {
+               dev_warn(i2c_dev->dev, "timeout waiting for config load\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
 {
        u32 val;
        int err;
        u32 clk_divisor, clk_multiplier;
+       u32 non_hs_mode;
        u32 tsu_thd;
        u8 tlow, thigh;
 
-       reset_control_assert(i2c_dev->rst);
-       udelay(2);
-       reset_control_deassert(i2c_dev->rst);
+       /*
+        * The reset shouldn't ever fail in practice. The failure will be a
+        * sign of a severe problem that needs to be resolved. Still we don't
+        * want to fail the initialization completely because this may break
+        * kernel boot up since voltage regulators use I2C. Hence, we will
+        * emit a noisy warning on error, which won't stay unnoticed and
+        * won't hose machine entirely.
+        */
+       err = reset_control_reset(i2c_dev->rst);
+       WARN_ON_ONCE(err);
 
        if (i2c_dev->is_dvc)
                tegra_dvc_init(i2c_dev);
@@ -785,24 +610,33 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
        if (i2c_dev->is_vi)
                tegra_i2c_vi_init(i2c_dev);
 
-       /* Make sure clock divisor programmed correctly */
-       clk_divisor = FIELD_PREP(I2C_CLK_DIVISOR_HSMODE,
-                                i2c_dev->hw->clk_divisor_hs_mode) |
-                     FIELD_PREP(I2C_CLK_DIVISOR_STD_FAST_MODE,
-                                i2c_dev->clk_divisor_non_hs_mode);
-       i2c_writel(i2c_dev, clk_divisor, I2C_CLK_DIVISOR);
-
-       if (i2c_dev->bus_clk_rate > I2C_MAX_STANDARD_MODE_FREQ &&
-           i2c_dev->bus_clk_rate <= I2C_MAX_FAST_MODE_PLUS_FREQ) {
+       switch (i2c_dev->bus_clk_rate) {
+       case I2C_MAX_STANDARD_MODE_FREQ + 1 ... I2C_MAX_FAST_MODE_PLUS_FREQ:
+       default:
                tlow = i2c_dev->hw->tlow_fast_fastplus_mode;
                thigh = i2c_dev->hw->thigh_fast_fastplus_mode;
                tsu_thd = i2c_dev->hw->setup_hold_time_fast_fast_plus_mode;
-       } else {
+
+               if (i2c_dev->bus_clk_rate > I2C_MAX_FAST_MODE_FREQ)
+                       non_hs_mode = i2c_dev->hw->clk_divisor_fast_plus_mode;
+               else
+                       non_hs_mode = i2c_dev->hw->clk_divisor_fast_mode;
+               break;
+
+       case 0 ... I2C_MAX_STANDARD_MODE_FREQ:
                tlow = i2c_dev->hw->tlow_std_mode;
                thigh = i2c_dev->hw->thigh_std_mode;
                tsu_thd = i2c_dev->hw->setup_hold_time_std_mode;
+               non_hs_mode = i2c_dev->hw->clk_divisor_std_mode;
+               break;
        }
 
+       /* Make sure clock divisor programmed correctly */
+       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);
+
        if (i2c_dev->hw->has_interface_timing_reg) {
                val = FIELD_PREP(I2C_INTERFACE_TIMING_THIGH, thigh) |
                      FIELD_PREP(I2C_INTERFACE_TIMING_TLOW, tlow);
@@ -816,16 +650,14 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
        if (i2c_dev->hw->has_interface_timing_reg && tsu_thd)
                i2c_writel(i2c_dev, tsu_thd, I2C_INTERFACE_TIMING_1);
 
-       if (!clk_reinit) {
-               clk_multiplier = (tlow + thigh + 2);
-               clk_multiplier *= (i2c_dev->clk_divisor_non_hs_mode + 1);
-               err = clk_set_rate(i2c_dev->div_clk,
-                                  i2c_dev->bus_clk_rate * clk_multiplier);
-               if (err) {
-                       dev_err(i2c_dev->dev,
-                               "failed changing clock rate: %d\n", err);
-                       return err;
-               }
+       clk_multiplier  = tlow + thigh + 2;
+       clk_multiplier *= non_hs_mode + 1;
+
+       err = clk_set_rate(i2c_dev->div_clk,
+                          i2c_dev->bus_clk_rate * clk_multiplier);
+       if (err) {
+               dev_err(i2c_dev->dev, "failed to set div-clk rate: %d\n", err);
+               return err;
        }
 
        if (!i2c_dev->is_dvc && !i2c_dev->is_vi) {
@@ -870,6 +702,132 @@ static int tegra_i2c_disable_packet_mode(struct tegra_i2c_dev *i2c_dev)
        return tegra_i2c_wait_for_config_load(i2c_dev);
 }
 
+static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
+{
+       u32 val;
+       unsigned int rx_fifo_avail;
+       u8 *buf = i2c_dev->msg_buf;
+       size_t buf_remaining = i2c_dev->msg_buf_remaining;
+       unsigned int words_to_transfer;
+
+       /*
+        * Catch overflow due to message fully sent
+        * before the check for RX FIFO availability.
+        */
+       if (WARN_ON_ONCE(!(i2c_dev->msg_buf_remaining)))
+               return -EINVAL;
+
+       if (i2c_dev->hw->has_mst_fifo) {
+               val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS);
+               rx_fifo_avail = FIELD_GET(I2C_MST_FIFO_STATUS_RX, val);
+       } else {
+               val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
+               rx_fifo_avail = FIELD_GET(I2C_FIFO_STATUS_RX, val);
+       }
+
+       /* Rounds down to not include partial word at the end of buf */
+       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);
+
+       buf += words_to_transfer * BYTES_PER_FIFO_WORD;
+       buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD;
+       rx_fifo_avail -= words_to_transfer;
+
+       /*
+        * If there is a partial word at the end of buf, handle it manually to
+        * prevent overwriting past the end of buf
+        */
+       if (rx_fifo_avail > 0 && buf_remaining > 0) {
+               /*
+                * buf_remaining > 3 check not needed as rx_fifo_avail == 0
+                * when (words_to_transfer was > rx_fifo_avail) earlier
+                * in this function.
+                */
+               val = i2c_readl(i2c_dev, I2C_RX_FIFO);
+               val = cpu_to_le32(val);
+               memcpy(buf, &val, buf_remaining);
+               buf_remaining = 0;
+               rx_fifo_avail--;
+       }
+
+       /* RX FIFO must be drained, otherwise it's an Overflow case. */
+       if (WARN_ON_ONCE(rx_fifo_avail))
+               return -EINVAL;
+
+       i2c_dev->msg_buf_remaining = buf_remaining;
+       i2c_dev->msg_buf = buf;
+
+       return 0;
+}
+
+static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
+{
+       u32 val;
+       unsigned int tx_fifo_avail;
+       u8 *buf = i2c_dev->msg_buf;
+       size_t buf_remaining = i2c_dev->msg_buf_remaining;
+       unsigned int words_to_transfer;
+
+       if (i2c_dev->hw->has_mst_fifo) {
+               val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS);
+               tx_fifo_avail = FIELD_GET(I2C_MST_FIFO_STATUS_TX, val);
+       } else {
+               val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
+               tx_fifo_avail = FIELD_GET(I2C_FIFO_STATUS_TX, val);
+       }
+
+       /* Rounds down to not include partial word at the end of buf */
+       words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD;
+
+       /* It's very common to have < 4 bytes, so optimize that case. */
+       if (words_to_transfer) {
+               if (words_to_transfer > tx_fifo_avail)
+                       words_to_transfer = tx_fifo_avail;
+
+               /*
+                * Update state before writing to FIFO.  Note that this may
+                * cause us to finish writing all bytes (AKA buf_remaining
+                * goes to 0), hence we have a potential for an interrupt
+                * (PACKET_XFER_COMPLETE is not maskable), but GIC interrupt
+                * is disabled at this point.
+                */
+               buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD;
+               tx_fifo_avail -= words_to_transfer;
+               i2c_dev->msg_buf_remaining = buf_remaining;
+               i2c_dev->msg_buf = buf +
+                       words_to_transfer * BYTES_PER_FIFO_WORD;
+
+               i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer);
+
+               buf += words_to_transfer * BYTES_PER_FIFO_WORD;
+       }
+
+       /*
+        * If there is a partial word at the end of buf, handle it manually to
+        * prevent reading past the end of buf, which could cross a page
+        * boundary and fault.
+        */
+       if (tx_fifo_avail > 0 && buf_remaining > 0) {
+               /*
+                * buf_remaining > 3 check not needed as tx_fifo_avail == 0
+                * when (words_to_transfer was > tx_fifo_avail) earlier
+                * in this function for non-zero words_to_transfer.
+                */
+               memcpy(&val, buf, buf_remaining);
+               val = le32_to_cpu(val);
+
+               i2c_dev->msg_buf_remaining = 0;
+               i2c_dev->msg_buf = NULL;
+
+               i2c_writel(i2c_dev, val, I2C_TX_FIFO);
+       }
+
+       return 0;
+}
+
 static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
 {
        u32 status;
@@ -887,7 +845,7 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
                goto err;
        }
 
-       if (unlikely(status & status_err)) {
+       if (status & status_err) {
                tegra_i2c_disable_packet_mode(i2c_dev);
                if (status & I2C_INT_NO_ACK)
                        i2c_dev->msg_err |= I2C_ERR_NO_ACK;
@@ -1045,10 +1003,9 @@ out:
        i2c_writel(i2c_dev, val, reg);
 }
 
-static unsigned long
-tegra_i2c_poll_completion_timeout(struct tegra_i2c_dev *i2c_dev,
-                                 struct completion *complete,
-                                 unsigned int timeout_ms)
+static unsigned long tegra_i2c_poll_completion(struct tegra_i2c_dev *i2c_dev,
+                                              struct completion *complete,
+                                              unsigned int timeout_ms)
 {
        ktime_t ktime = ktime_get();
        ktime_t ktimeout = ktime_add_ms(ktime, timeout_ms);
@@ -1072,16 +1029,14 @@ tegra_i2c_poll_completion_timeout(struct tegra_i2c_dev *i2c_dev,
        return 0;
 }
 
-static unsigned long
-tegra_i2c_wait_completion_timeout(struct tegra_i2c_dev *i2c_dev,
-                                 struct completion *complete,
-                                 unsigned int timeout_ms)
+static unsigned long tegra_i2c_wait_completion(struct tegra_i2c_dev *i2c_dev,
+                                              struct completion *complete,
+                                              unsigned int timeout_ms)
 {
        unsigned long ret;
 
        if (i2c_dev->is_curr_atomic_xfer) {
-               ret = tegra_i2c_poll_completion_timeout(i2c_dev, complete,
-                                                       timeout_ms);
+               ret = tegra_i2c_poll_completion(i2c_dev, complete, timeout_ms);
        } else {
                enable_irq(i2c_dev->irq);
                ret = wait_for_completion_timeout(complete,
@@ -1099,8 +1054,7 @@ tegra_i2c_wait_completion_timeout(struct tegra_i2c_dev *i2c_dev,
                 * needs to be checked after timeout.
                 */
                if (ret == 0)
-                       ret = tegra_i2c_poll_completion_timeout(i2c_dev,
-                                                               complete, 0);
+                       ret = tegra_i2c_poll_completion(i2c_dev, complete, 0);
        }
 
        return ret;
@@ -1117,18 +1071,18 @@ static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
        reg = FIELD_PREP(I2C_BC_SCLK_THRESHOLD, 9) | I2C_BC_STOP_COND |
              I2C_BC_TERMINATE;
        i2c_writel(i2c_dev, reg, I2C_BUS_CLEAR_CNFG);
-       if (i2c_dev->hw->has_config_load_reg) {
-               err = tegra_i2c_wait_for_config_load(i2c_dev);
-               if (err)
-                       return err;
-       }
+
+       err = tegra_i2c_wait_for_config_load(i2c_dev);
+       if (err)
+               return err;
 
        reg |= I2C_BC_ENABLE;
        i2c_writel(i2c_dev, reg, I2C_BUS_CLEAR_CNFG);
        tegra_i2c_unmask_irq(i2c_dev, I2C_INT_BUS_CLR_DONE);
 
-       time_left = tegra_i2c_wait_completion_timeout(
-                       i2c_dev, &i2c_dev->msg_complete, 50);
+       time_left = tegra_i2c_wait_completion(i2c_dev, &i2c_dev->msg_complete, 50);
+       tegra_i2c_mask_irq(i2c_dev, I2C_INT_BUS_CLR_DONE);
+
        if (time_left == 0) {
                dev_err(i2c_dev->dev, "timed out for bus clear\n");
                return -ETIMEDOUT;
@@ -1144,25 +1098,101 @@ static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
        return -EAGAIN;
 }
 
+static void tegra_i2c_push_packet_header(struct tegra_i2c_dev *i2c_dev,
+                                        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) |
+                       FIELD_PREP(PACKET_HEADER0_CONT_ID, i2c_dev->cont_id) |
+                       FIELD_PREP(PACKET_HEADER0_PACKET_ID, 1);
+
+       if (i2c_dev->is_curr_dma_xfer && !i2c_dev->msg_read)
+               *dma_buf++ = packet_header;
+       else
+               i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+
+       packet_header = msg->len - 1;
+
+       if (i2c_dev->is_curr_dma_xfer && !i2c_dev->msg_read)
+               *dma_buf++ = packet_header;
+       else
+               i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+
+       packet_header = I2C_HEADER_IE_ENABLE;
+
+       if (end_state == MSG_END_CONTINUE)
+               packet_header |= I2C_HEADER_CONTINUE_XFER;
+       else if (end_state == MSG_END_REPEAT_START)
+               packet_header |= I2C_HEADER_REPEAT_START;
+
+       if (msg->flags & I2C_M_TEN) {
+               packet_header |= msg->addr;
+               packet_header |= I2C_HEADER_10BIT_ADDR;
+       } else {
+               packet_header |= msg->addr << I2C_HEADER_SLAVE_ADDR_SHIFT;
+       }
+
+       if (msg->flags & I2C_M_IGNORE_NAK)
+               packet_header |= I2C_HEADER_CONT_ON_NAK;
+
+       if (msg->flags & I2C_M_RD)
+               packet_header |= I2C_HEADER_READ;
+
+       if (i2c_dev->is_curr_dma_xfer && !i2c_dev->msg_read)
+               *dma_buf++ = packet_header;
+       else
+               i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+}
+
+static int tegra_i2c_error_recover(struct tegra_i2c_dev *i2c_dev,
+                                  struct i2c_msg *msg)
+{
+       if (i2c_dev->msg_err == I2C_ERR_NONE)
+               return 0;
+
+       tegra_i2c_init(i2c_dev);
+
+       /* start recovery upon arbitration loss in single master mode */
+       if (i2c_dev->msg_err == I2C_ERR_ARBITRATION_LOST) {
+               if (!i2c_dev->is_multimaster_mode)
+                       return i2c_recover_bus(&i2c_dev->adapter);
+
+               return -EAGAIN;
+       }
+
+       if (i2c_dev->msg_err == I2C_ERR_NO_ACK) {
+               if (msg->flags & I2C_M_IGNORE_NAK)
+                       return 0;
+
+               return -EREMOTEIO;
+       }
+
+       return -EIO;
+}
+
 static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
                              struct i2c_msg *msg,
                              enum msg_end_type end_state)
 {
-       u32 packet_header;
        u32 int_mask;
        unsigned long time_left;
        size_t xfer_size;
-       u32 *buffer = NULL;
        int err = 0;
-       bool dma;
        u16 xfer_time = 100;
 
-       tegra_i2c_flush_fifos(i2c_dev);
+       err = tegra_i2c_flush_fifos(i2c_dev);
+       if (err)
+               return err;
 
        i2c_dev->msg_buf = msg->buf;
        i2c_dev->msg_buf_remaining = msg->len;
        i2c_dev->msg_err = I2C_ERR_NONE;
-       i2c_dev->msg_read = (msg->flags & I2C_M_RD);
+       i2c_dev->msg_read = !!(msg->flags & I2C_M_RD);
        reinit_completion(&i2c_dev->msg_complete);
 
        if (i2c_dev->msg_read)
@@ -1175,7 +1205,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
                                    i2c_dev->dma_buf &&
                                    !i2c_dev->is_curr_atomic_xfer;
        tegra_i2c_config_fifo_trig(i2c_dev, xfer_size);
-       dma = i2c_dev->is_curr_dma_xfer;
+
        /*
         * Transfer time in mSec = Total bits / transfer rate
         * Total bits = 9 bits per byte (including ACK bit) + Start & stop bits
@@ -1185,7 +1215,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 
        int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
        tegra_i2c_unmask_irq(i2c_dev, int_mask);
-       if (dma) {
+       if (i2c_dev->is_curr_dma_xfer) {
                if (i2c_dev->msg_read) {
                        dma_sync_single_for_device(i2c_dev->dev,
                                                   i2c_dev->dma_phys,
@@ -1204,49 +1234,15 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
                                                i2c_dev->dma_phys,
                                                xfer_size,
                                                DMA_TO_DEVICE);
-                       buffer = i2c_dev->dma_buf;
                }
        }
 
-       packet_header = FIELD_PREP(PACKET_HEADER0_HEADER_SIZE, 0) |
-                       FIELD_PREP(PACKET_HEADER0_PROTOCOL,
-                                  PACKET_HEADER0_PROTOCOL_I2C) |
-                       FIELD_PREP(PACKET_HEADER0_CONT_ID, i2c_dev->cont_id) |
-                       FIELD_PREP(PACKET_HEADER0_PACKET_ID, 1);
-       if (dma && !i2c_dev->msg_read)
-               *buffer++ = packet_header;
-       else
-               i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
-
-       packet_header = msg->len - 1;
-       if (dma && !i2c_dev->msg_read)
-               *buffer++ = packet_header;
-       else
-               i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
-
-       packet_header = I2C_HEADER_IE_ENABLE;
-       if (end_state == MSG_END_CONTINUE)
-               packet_header |= I2C_HEADER_CONTINUE_XFER;
-       else if (end_state == MSG_END_REPEAT_START)
-               packet_header |= I2C_HEADER_REPEAT_START;
-       if (msg->flags & I2C_M_TEN) {
-               packet_header |= msg->addr;
-               packet_header |= I2C_HEADER_10BIT_ADDR;
-       } else {
-               packet_header |= msg->addr << I2C_HEADER_SLAVE_ADDR_SHIFT;
-       }
-       if (msg->flags & I2C_M_IGNORE_NAK)
-               packet_header |= I2C_HEADER_CONT_ON_NAK;
-       if (msg->flags & I2C_M_RD)
-               packet_header |= I2C_HEADER_READ;
-       if (dma && !i2c_dev->msg_read)
-               *buffer++ = packet_header;
-       else
-               i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+       tegra_i2c_push_packet_header(i2c_dev, msg, end_state);
 
        if (!i2c_dev->msg_read) {
-               if (dma) {
-                       memcpy(buffer, msg->buf, msg->len);
+               if (i2c_dev->is_curr_dma_xfer) {
+                       memcpy(i2c_dev->dma_buf + I2C_PACKET_HEADER_SIZE,
+                              msg->buf, msg->len);
                        dma_sync_single_for_device(i2c_dev->dev,
                                                   i2c_dev->dma_phys,
                                                   xfer_size,
@@ -1265,7 +1261,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 
        if (i2c_dev->hw->has_per_pkt_xfer_complete_irq)
                int_mask |= I2C_INT_PACKET_XFER_COMPLETE;
-       if (!dma) {
+       if (!i2c_dev->is_curr_dma_xfer) {
                if (msg->flags & I2C_M_RD)
                        int_mask |= I2C_INT_RX_FIFO_DATA_REQ;
                else if (i2c_dev->msg_buf_remaining)
@@ -1276,9 +1272,10 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
        dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n",
                i2c_readl(i2c_dev, I2C_INT_MASK));
 
-       if (dma) {
-               time_left = tegra_i2c_wait_completion_timeout(
-                               i2c_dev, &i2c_dev->dma_complete, xfer_time);
+       if (i2c_dev->is_curr_dma_xfer) {
+               time_left = tegra_i2c_wait_completion(i2c_dev,
+                                                     &i2c_dev->dma_complete,
+                                                     xfer_time);
 
                /*
                 * Synchronize DMA first, since dmaengine_terminate_sync()
@@ -1295,7 +1292,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 
                if (!time_left && !completion_done(&i2c_dev->dma_complete)) {
                        dev_err(i2c_dev->dev, "DMA transfer timeout\n");
-                       tegra_i2c_init(i2c_dev, true);
+                       tegra_i2c_init(i2c_dev);
                        return -ETIMEDOUT;
                }
 
@@ -1309,14 +1306,14 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
                }
        }
 
-       time_left = tegra_i2c_wait_completion_timeout(
-                       i2c_dev, &i2c_dev->msg_complete, xfer_time);
+       time_left = tegra_i2c_wait_completion(i2c_dev, &i2c_dev->msg_complete,
+                                             xfer_time);
 
        tegra_i2c_mask_irq(i2c_dev, int_mask);
 
        if (time_left == 0) {
                dev_err(i2c_dev->dev, "i2c transfer timed out\n");
-               tegra_i2c_init(i2c_dev, true);
+               tegra_i2c_init(i2c_dev);
                return -ETIMEDOUT;
        }
 
@@ -1325,24 +1322,12 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
                i2c_dev->msg_err);
 
        i2c_dev->is_curr_dma_xfer = false;
-       if (likely(i2c_dev->msg_err == I2C_ERR_NONE))
-               return 0;
-
-       tegra_i2c_init(i2c_dev, true);
-       /* start recovery upon arbitration loss in single master mode */
-       if (i2c_dev->msg_err == I2C_ERR_ARBITRATION_LOST) {
-               if (!i2c_dev->is_multimaster_mode)
-                       return i2c_recover_bus(&i2c_dev->adapter);
-               return -EAGAIN;
-       }
 
-       if (i2c_dev->msg_err == I2C_ERR_NO_ACK) {
-               if (msg->flags & I2C_M_IGNORE_NAK)
-                       return 0;
-               return -EREMOTEIO;
-       }
+       err = tegra_i2c_error_recover(i2c_dev, msg);
+       if (err)
+               return err;
 
-       return -EIO;
+       return 0;
 }
 
 static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
@@ -1355,6 +1340,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
        ret = pm_runtime_get_sync(i2c_dev->dev);
        if (ret < 0) {
                dev_err(i2c_dev->dev, "runtime resume failed %d\n", ret);
+               pm_runtime_put_noidle(i2c_dev->dev);
                return ret;
        }
 
@@ -1401,21 +1387,6 @@ static u32 tegra_i2c_func(struct i2c_adapter *adap)
        return ret;
 }
 
-static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev)
-{
-       struct device_node *np = i2c_dev->dev->of_node;
-       int ret;
-       bool multi_mode;
-
-       ret = of_property_read_u32(np, "clock-frequency",
-                                  &i2c_dev->bus_clk_rate);
-       if (ret)
-               i2c_dev->bus_clk_rate = I2C_MAX_STANDARD_MODE_FREQ; /* default clock rate */
-
-       multi_mode = of_property_read_bool(np, "multi-master");
-       i2c_dev->is_multimaster_mode = multi_mode;
-}
-
 static const struct i2c_algorithm tegra_i2c_algo = {
        .master_xfer            = tegra_i2c_xfer,
        .master_xfer_atomic     = tegra_i2c_xfer_atomic,
@@ -1441,7 +1412,6 @@ static struct i2c_bus_recovery_info tegra_i2c_recovery_info = {
 static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
        .has_continue_xfer_support = false,
        .has_per_pkt_xfer_complete_irq = false,
-       .has_single_clk_source = false,
        .clk_divisor_hs_mode = 3,
        .clk_divisor_std_mode = 0,
        .clk_divisor_fast_mode = 0,
@@ -1466,7 +1436,6 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
 static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
        .has_continue_xfer_support = true,
        .has_per_pkt_xfer_complete_irq = false,
-       .has_single_clk_source = false,
        .clk_divisor_hs_mode = 3,
        .clk_divisor_std_mode = 0,
        .clk_divisor_fast_mode = 0,
@@ -1491,7 +1460,6 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
 static const struct tegra_i2c_hw_feature tegra114_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_mode = 0x19,
        .clk_divisor_fast_mode = 0x19,
@@ -1516,7 +1484,6 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
 static const struct tegra_i2c_hw_feature tegra124_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_mode = 0x19,
        .clk_divisor_fast_mode = 0x19,
@@ -1541,7 +1508,6 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
 static const struct tegra_i2c_hw_feature tegra210_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_mode = 0x19,
        .clk_divisor_fast_mode = 0x19,
@@ -1566,7 +1532,6 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
 static const struct tegra_i2c_hw_feature tegra186_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_mode = 0x16,
        .clk_divisor_fast_mode = 0x19,
@@ -1591,7 +1556,6 @@ static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
 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_mode = 0x4f,
        .clk_divisor_fast_mode = 0x3c,
@@ -1628,219 +1592,191 @@ static const struct of_device_id tegra_i2c_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, tegra_i2c_of_match);
 
-static int tegra_i2c_probe(struct platform_device *pdev)
+static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev)
 {
-       struct device *dev = &pdev->dev;
-       struct tegra_i2c_dev *i2c_dev;
-       struct resource *res;
-       struct clk *div_clk;
-       struct clk *fast_clk;
-       void __iomem *base;
-       phys_addr_t base_phys;
-       int irq;
+       struct device_node *np = i2c_dev->dev->of_node;
        int ret;
+       bool multi_mode;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base_phys = res->start;
-       base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(base))
-               return PTR_ERR(base);
+       ret = of_property_read_u32(np, "clock-frequency",
+                                  &i2c_dev->bus_clk_rate);
+       if (ret)
+               i2c_dev->bus_clk_rate = I2C_MAX_STANDARD_MODE_FREQ; /* default clock rate */
 
-       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "no irq resource\n");
-               return -EINVAL;
-       }
-       irq = res->start;
+       multi_mode = of_property_read_bool(np, "multi-master");
+       i2c_dev->is_multimaster_mode = multi_mode;
 
-       div_clk = devm_clk_get(&pdev->dev, "div-clk");
-       if (IS_ERR(div_clk)) {
-               if (PTR_ERR(div_clk) != -EPROBE_DEFER)
-                       dev_err(&pdev->dev, "missing controller clock\n");
+       if (of_device_is_compatible(np, "nvidia,tegra20-i2c-dvc"))
+               i2c_dev->is_dvc = true;
 
-               return PTR_ERR(div_clk);
-       }
+       if (of_device_is_compatible(np, "nvidia,tegra210-i2c-vi"))
+               i2c_dev->is_vi = true;
+}
 
-       i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-       if (!i2c_dev)
-               return -ENOMEM;
+static int tegra_i2c_init_clocks(struct tegra_i2c_dev *i2c_dev)
+{
+       int err;
 
-       i2c_dev->base = base;
-       i2c_dev->base_phys = base_phys;
-       i2c_dev->div_clk = div_clk;
-       i2c_dev->adapter.algo = &tegra_i2c_algo;
-       i2c_dev->adapter.retries = 1;
-       i2c_dev->adapter.timeout = 6 * HZ;
-       i2c_dev->irq = irq;
-       i2c_dev->cont_id = pdev->id;
-       i2c_dev->dev = &pdev->dev;
+       i2c_dev->clocks[i2c_dev->nclocks++].id = "div-clk";
 
-       i2c_dev->rst = devm_reset_control_get_exclusive(&pdev->dev, "i2c");
-       if (IS_ERR(i2c_dev->rst)) {
-               dev_err(&pdev->dev, "missing controller reset\n");
-               return PTR_ERR(i2c_dev->rst);
-       }
+       if (i2c_dev->hw == &tegra20_i2c_hw || i2c_dev->hw == &tegra30_i2c_hw)
+               i2c_dev->clocks[i2c_dev->nclocks++].id = "fast-clk";
 
-       tegra_i2c_parse_dt(i2c_dev);
+       if (i2c_dev->is_vi)
+               i2c_dev->clocks[i2c_dev->nclocks++].id = "slow";
 
-       i2c_dev->hw = of_device_get_match_data(&pdev->dev);
-       i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node,
-                                                 "nvidia,tegra20-i2c-dvc");
-       i2c_dev->is_vi = of_device_is_compatible(dev->of_node,
-                                                "nvidia,tegra210-i2c-vi");
-       i2c_dev->adapter.quirks = i2c_dev->hw->quirks;
-       i2c_dev->dma_buf_size = i2c_dev->adapter.quirks->max_write_len +
-                               I2C_PACKET_HEADER_SIZE;
-       init_completion(&i2c_dev->msg_complete);
-       init_completion(&i2c_dev->dma_complete);
+       err = devm_clk_bulk_get(i2c_dev->dev, i2c_dev->nclocks,
+                               i2c_dev->clocks);
+       if (err)
+               return err;
 
-       if (!i2c_dev->hw->has_single_clk_source) {
-               fast_clk = devm_clk_get(&pdev->dev, "fast-clk");
-               if (IS_ERR(fast_clk)) {
-                       dev_err(&pdev->dev, "missing fast clock\n");
-                       return PTR_ERR(fast_clk);
-               }
-               i2c_dev->fast_clk = fast_clk;
-       }
+       err = clk_bulk_prepare(i2c_dev->nclocks, i2c_dev->clocks);
+       if (err)
+               return err;
 
-       if (i2c_dev->is_vi) {
-               i2c_dev->slow_clk = devm_clk_get(dev, "slow");
-               if (IS_ERR(i2c_dev->slow_clk)) {
-                       if (PTR_ERR(i2c_dev->slow_clk) != -EPROBE_DEFER)
-                               dev_err(dev, "failed to get slow clock: %ld\n",
-                                       PTR_ERR(i2c_dev->slow_clk));
+       i2c_dev->div_clk = i2c_dev->clocks[0].clk;
 
-                       return PTR_ERR(i2c_dev->slow_clk);
-               }
+       if (!i2c_dev->is_multimaster_mode)
+               return 0;
+
+       err = clk_enable(i2c_dev->div_clk);
+       if (err) {
+               dev_err(i2c_dev->dev, "failed to enable div-clk: %d\n", err);
+               goto unprepare_clocks;
        }
 
-       platform_set_drvdata(pdev, i2c_dev);
+       return 0;
 
-       if (!i2c_dev->hw->has_single_clk_source) {
-               ret = clk_prepare(i2c_dev->fast_clk);
-               if (ret < 0) {
-                       dev_err(i2c_dev->dev, "Clock prepare failed %d\n", ret);
-                       return ret;
-               }
-       }
+unprepare_clocks:
+       clk_bulk_unprepare(i2c_dev->nclocks, i2c_dev->clocks);
 
-       if (i2c_dev->slow_clk) {
-               ret = clk_prepare(i2c_dev->slow_clk);
-               if (ret < 0) {
-                       dev_err(dev, "failed to prepare slow clock: %d\n", ret);
-                       goto unprepare_fast_clk;
-               }
-       }
+       return err;
+}
+
+static void tegra_i2c_release_clocks(struct tegra_i2c_dev *i2c_dev)
+{
+       if (i2c_dev->is_multimaster_mode)
+               clk_disable(i2c_dev->div_clk);
 
-       if (i2c_dev->bus_clk_rate > I2C_MAX_FAST_MODE_FREQ &&
-           i2c_dev->bus_clk_rate <= I2C_MAX_FAST_MODE_PLUS_FREQ)
-               i2c_dev->clk_divisor_non_hs_mode =
-                               i2c_dev->hw->clk_divisor_fast_plus_mode;
-       else if (i2c_dev->bus_clk_rate > I2C_MAX_STANDARD_MODE_FREQ &&
-                i2c_dev->bus_clk_rate <= I2C_MAX_FAST_MODE_FREQ)
-               i2c_dev->clk_divisor_non_hs_mode =
-                               i2c_dev->hw->clk_divisor_fast_mode;
+       clk_bulk_unprepare(i2c_dev->nclocks, i2c_dev->clocks);
+}
+
+static int tegra_i2c_init_hardware(struct tegra_i2c_dev *i2c_dev)
+{
+       int ret;
+
+       ret = pm_runtime_get_sync(i2c_dev->dev);
+       if (ret < 0)
+               dev_err(i2c_dev->dev, "runtime resume failed: %d\n", ret);
        else
-               i2c_dev->clk_divisor_non_hs_mode =
-                               i2c_dev->hw->clk_divisor_std_mode;
+               ret = tegra_i2c_init(i2c_dev);
 
-       ret = clk_prepare(i2c_dev->div_clk);
-       if (ret < 0) {
-               dev_err(i2c_dev->dev, "Clock prepare failed %d\n", ret);
-               goto unprepare_slow_clk;
-       }
+       pm_runtime_put(i2c_dev->dev);
 
-       pm_runtime_irq_safe(&pdev->dev);
-       pm_runtime_enable(&pdev->dev);
-       if (!pm_runtime_enabled(&pdev->dev)) {
-               ret = tegra_i2c_runtime_resume(&pdev->dev);
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "runtime resume failed\n");
-                       goto unprepare_div_clk;
-               }
-       } else {
-               ret = pm_runtime_get_sync(i2c_dev->dev);
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "runtime resume failed\n");
-                       goto disable_rpm;
-               }
-       }
+       return ret;
+}
 
-       if (i2c_dev->is_multimaster_mode) {
-               ret = clk_enable(i2c_dev->div_clk);
-               if (ret < 0) {
-                       dev_err(i2c_dev->dev, "div_clk enable failed %d\n",
-                               ret);
-                       goto put_rpm;
-               }
-       }
+static int tegra_i2c_probe(struct platform_device *pdev)
+{
+       struct tegra_i2c_dev *i2c_dev;
+       struct resource *res;
+       int ret;
 
-       if (i2c_dev->hw->supports_bus_clear)
-               i2c_dev->adapter.bus_recovery_info = &tegra_i2c_recovery_info;
+       i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
+       if (!i2c_dev)
+               return -ENOMEM;
 
-       ret = tegra_i2c_init_dma(i2c_dev);
+       platform_set_drvdata(pdev, i2c_dev);
+
+       init_completion(&i2c_dev->msg_complete);
+       init_completion(&i2c_dev->dma_complete);
+
+       i2c_dev->hw = of_device_get_match_data(&pdev->dev);
+       i2c_dev->cont_id = pdev->id;
+       i2c_dev->dev = &pdev->dev;
+
+       i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+       if (IS_ERR(i2c_dev->base))
+               return PTR_ERR(i2c_dev->base);
+
+       i2c_dev->base_phys = res->start;
+
+       ret = platform_get_irq(pdev, 0);
        if (ret < 0)
-               goto disable_div_clk;
+               return ret;
 
-       ret = tegra_i2c_init(i2c_dev, false);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to initialize i2c controller\n");
-               goto release_dma;
-       }
+       i2c_dev->irq = ret;
 
+       /* interrupt will be enabled during of transfer time */
        irq_set_status_flags(i2c_dev->irq, IRQ_NOAUTOEN);
 
        ret = devm_request_irq(&pdev->dev, i2c_dev->irq, tegra_i2c_isr,
-                              IRQF_NO_SUSPEND, dev_name(&pdev->dev), i2c_dev);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
-               goto release_dma;
+                              IRQF_NO_SUSPEND, dev_name(&pdev->dev),
+                              i2c_dev);
+       if (ret)
+               return ret;
+
+       i2c_dev->rst = devm_reset_control_get_exclusive(&pdev->dev, "i2c");
+       if (IS_ERR(i2c_dev->rst)) {
+               dev_err_probe(&pdev->dev, PTR_ERR(i2c_dev->rst),
+                             "failed to get reset control\n");
+               return PTR_ERR(i2c_dev->rst);
        }
 
+       tegra_i2c_parse_dt(i2c_dev);
+
+       ret = tegra_i2c_init_clocks(i2c_dev);
+       if (ret)
+               return ret;
+
+       ret = tegra_i2c_init_dma(i2c_dev);
+       if (ret)
+               goto release_clocks;
+
+       /*
+        * VI I2C is in VE power domain which is not always on and not
+        * an IRQ safe. So, IRQ safe device can't be attached to a non-IRQ
+        * safe domain as it prevents powering off the PM domain.
+        * Also, VI I2C device don't need to use runtime IRQ safe as it will
+        * not be used for atomic transfers.
+        */
+       if (!i2c_dev->is_vi)
+               pm_runtime_irq_safe(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+
+       ret = tegra_i2c_init_hardware(i2c_dev);
+       if (ret)
+               goto release_rpm;
+
        i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
+       i2c_dev->adapter.dev.of_node = pdev->dev.of_node;
+       i2c_dev->adapter.dev.parent = &pdev->dev;
+       i2c_dev->adapter.retries = 1;
+       i2c_dev->adapter.timeout = 6 * HZ;
+       i2c_dev->adapter.quirks = i2c_dev->hw->quirks;
        i2c_dev->adapter.owner = THIS_MODULE;
        i2c_dev->adapter.class = I2C_CLASS_DEPRECATED;
+       i2c_dev->adapter.algo = &tegra_i2c_algo;
+       i2c_dev->adapter.nr = pdev->id;
+
+       if (i2c_dev->hw->supports_bus_clear)
+               i2c_dev->adapter.bus_recovery_info = &tegra_i2c_recovery_info;
+
        strlcpy(i2c_dev->adapter.name, dev_name(&pdev->dev),
                sizeof(i2c_dev->adapter.name));
-       i2c_dev->adapter.dev.parent = &pdev->dev;
-       i2c_dev->adapter.nr = pdev->id;
-       i2c_dev->adapter.dev.of_node = pdev->dev.of_node;
 
        ret = i2c_add_numbered_adapter(&i2c_dev->adapter);
        if (ret)
-               goto release_dma;
-
-       pm_runtime_put(&pdev->dev);
+               goto release_rpm;
 
        return 0;
 
-release_dma:
-       tegra_i2c_release_dma(i2c_dev);
-
-disable_div_clk:
-       if (i2c_dev->is_multimaster_mode)
-               clk_disable(i2c_dev->div_clk);
-
-put_rpm:
-       if (pm_runtime_enabled(&pdev->dev))
-               pm_runtime_put_sync(&pdev->dev);
-       else
-               tegra_i2c_runtime_suspend(&pdev->dev);
-
-disable_rpm:
-       if (pm_runtime_enabled(&pdev->dev))
-               pm_runtime_disable(&pdev->dev);
-
-unprepare_div_clk:
-       clk_unprepare(i2c_dev->div_clk);
-
-unprepare_slow_clk:
-       if (i2c_dev->is_vi)
-               clk_unprepare(i2c_dev->slow_clk);
+release_rpm:
+       pm_runtime_disable(&pdev->dev);
 
-unprepare_fast_clk:
-       if (!i2c_dev->hw->has_single_clk_source)
-               clk_unprepare(i2c_dev->fast_clk);
+       tegra_i2c_release_dma(i2c_dev);
+release_clocks:
+       tegra_i2c_release_clocks(i2c_dev);
 
        return ret;
 }
@@ -1851,23 +1787,53 @@ static int tegra_i2c_remove(struct platform_device *pdev)
 
        i2c_del_adapter(&i2c_dev->adapter);
 
-       if (i2c_dev->is_multimaster_mode)
-               clk_disable(i2c_dev->div_clk);
-
        pm_runtime_disable(&pdev->dev);
-       if (!pm_runtime_status_suspended(&pdev->dev))
-               tegra_i2c_runtime_suspend(&pdev->dev);
 
-       clk_unprepare(i2c_dev->div_clk);
+       tegra_i2c_release_dma(i2c_dev);
+       tegra_i2c_release_clocks(i2c_dev);
+       return 0;
+}
+
+static int __maybe_unused tegra_i2c_runtime_resume(struct device *dev)
+{
+       struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+       int ret;
 
-       if (i2c_dev->slow_clk)
-               clk_unprepare(i2c_dev->slow_clk);
+       ret = pinctrl_pm_select_default_state(i2c_dev->dev);
+       if (ret)
+               return ret;
 
-       if (!i2c_dev->hw->has_single_clk_source)
-               clk_unprepare(i2c_dev->fast_clk);
+       ret = clk_bulk_enable(i2c_dev->nclocks, i2c_dev->clocks);
+       if (ret)
+               return ret;
+
+       /*
+        * VI I2C device is attached to VE power domain which goes through
+        * power ON/OFF during PM runtime resume/suspend. So, controller
+        * should go through reset and need to re-initialize after power
+        * domain ON.
+        */
+       if (i2c_dev->is_vi) {
+               ret = tegra_i2c_init(i2c_dev);
+               if (ret)
+                       goto disable_clocks;
+       }
 
-       tegra_i2c_release_dma(i2c_dev);
        return 0;
+
+disable_clocks:
+       clk_bulk_disable(i2c_dev->nclocks, i2c_dev->clocks);
+
+       return ret;
+}
+
+static int __maybe_unused tegra_i2c_runtime_suspend(struct device *dev)
+{
+       struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+
+       clk_bulk_disable(i2c_dev->nclocks, i2c_dev->clocks);
+
+       return pinctrl_pm_select_idle_state(i2c_dev->dev);
 }
 
 static int __maybe_unused tegra_i2c_suspend(struct device *dev)
@@ -1896,7 +1862,7 @@ static int __maybe_unused tegra_i2c_resume(struct device *dev)
        if (err)
                return err;
 
-       err = tegra_i2c_init(i2c_dev, false);
+       err = tegra_i2c_init(i2c_dev);
        if (err)
                return err;