i2c: rk3x: sync with i2c-next branch
authorDavid Wu <david.wu@rock-chips.com>
Fri, 17 Jun 2016 21:34:02 +0000 (05:34 +0800)
committerGerrit Code Review <gerrit@rock-chips.com>
Mon, 20 Jun 2016 10:38:19 +0000 (18:38 +0800)
Change-Id: Id698758616934b8816f0b8be12ea45887dc0aca9
Signed-off-by: David Wu <david.wu@rock-chips.com>
Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
drivers/i2c/busses/i2c-rk3x.c

index 7a5d98890bd2eb0b436041210885a3e6161c1f64..bbc5a1ed5fa188557a4c45828ea8ba5d65f46893 100644 (file)
@@ -6,16 +6,20 @@ RK3xxx SoCs.
 Required properties :
 
  - reg : Offset and length of the register set for the device
 Required properties :
 
  - reg : Offset and length of the register set for the device
- - compatible: should be one of the followings
+ - compatible: should be one of the following:
    - "rockchip,rk3066-i2c": for rk3066
    - "rockchip,rk3188-i2c": for rk3188
    - "rockchip,rk3066-i2c": for rk3066
    - "rockchip,rk3188-i2c": for rk3188
+   - "rockchip,rk3228-i2c": for rk3228
    - "rockchip,rk3288-i2c": for rk3288
    - "rockchip,rk3399-i2c": for rk3399
  - interrupts : interrupt number
    - "rockchip,rk3288-i2c": for rk3288
    - "rockchip,rk3399-i2c": for rk3399
  - interrupts : interrupt number
- - clocks:
-   - clk(function): APB clock and function clock is the same clock for rk3066,
-                   rk3188 and rk3288. but separated at rk3399.
-   - pclk(APB): It is just required for rk3399.
+ - clocks: See ../clock/clock-bindings.txt
+   - For older hardware (rk3066, rk3188, rk3228, rk3288):
+     - There is one clock that's used both to derive the functional clock
+       for the device and as the bus clock.
+   - For newer hardware (rk3399): specified by name
+     - "i2c": This is used to derive the functional clock.
+     - "pclk": This is the bus clock.
 
 Required on RK3066, RK3188 :
 
 
 Required on RK3066, RK3188 :
 
@@ -38,8 +42,6 @@ Optional properties :
  - i2c-sda-falling-time-ns : Number of nanoseconds the SDA signal takes to fall
        (t(f) in the I2C specification). If not specified we'll use the SCL
        value since they are the same in nearly all cases.
  - i2c-sda-falling-time-ns : Number of nanoseconds the SDA signal takes to fall
        (t(f) in the I2C specification). If not specified we'll use the SCL
        value since they are the same in nearly all cases.
- - input-clk-rate : frequency rate of function clock used(in Hz). If omitted,
-       the default clock rate is used. It is just used at rk3399 soc.
 
 Example:
 
 
 Example:
 
@@ -47,7 +49,6 @@ aliases {
        i2c0 = &i2c0;
 }
 
        i2c0 = &i2c0;
 }
 
-rk3066, rk3188 and rk3288:
 i2c0: i2c@2002d000 {
        compatible = "rockchip,rk3188-i2c";
        reg = <0x2002d000 0x1000>;
 i2c0: i2c@2002d000 {
        compatible = "rockchip,rk3188-i2c";
        reg = <0x2002d000 0x1000>;
@@ -63,20 +64,3 @@ i2c0: i2c@2002d000 {
        i2c-scl-rising-time-ns = <800>;
        i2c-scl-falling-time-ns = <100>;
 };
        i2c-scl-rising-time-ns = <800>;
        i2c-scl-falling-time-ns = <100>;
 };
-
-rk3399:
-i2c0: i2c@2002d000 {
-       compatible = "rockchip,rk3399-i2c";
-       reg = <0x2002d000 0x1000>;
-       interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
-       #address-cells = <1>;
-       #size-cells = <0>;
-
-       clock-names = "i2c", "pclk";
-       clocks = <&cru SCLK_I2C0_PMU>, <&cru PCLK_I2C0_PMU>;
-       input-clk-rate = <200000000>;
-
-       i2c-scl-rising-time-ns = <50>;
-       i2c-scl-falling-time-ns = <20>;
-       clock-frequency = <1700000>;
-};
index fd28df1f71e40c83c15d336660d165e7c32d0583..2bc8b01153d61985814591a962851b19bb0bb2b1 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
 #include <linux/math64.h>
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
 #include <linux/math64.h>
-#include <linux/property.h>
 
 
 /* Register Map */
 
 
 /* Register Map */
@@ -59,9 +58,11 @@ enum {
 #define REG_CON_LASTACK   BIT(5) /* 1: send NACK after last received byte */
 #define REG_CON_ACTACK    BIT(6) /* 1: stop if NACK is received */
 
 #define REG_CON_LASTACK   BIT(5) /* 1: send NACK after last received byte */
 #define REG_CON_ACTACK    BIT(6) /* 1: stop if NACK is received */
 
-#define REG_CON_SDA_CNT(cnt)  ((cnt) << 8)
-#define REG_CON_STA_CNT(cnt)  ((cnt) << 12)
-#define REG_CON_STO_CNT(cnt)  ((cnt) << 14)
+#define REG_CON_TUNING_MASK GENMASK(15, 8)
+
+#define REG_CON_SDA_CFG(cfg) ((cfg) << 8)
+#define REG_CON_STA_CFG(cfg) ((cfg) << 12)
+#define REG_CON_STO_CFG(cfg) ((cfg) << 14)
 
 /* REG_MRXADDR bits */
 #define REG_MRXADDR_VALID(x) BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */
 
 /* REG_MRXADDR bits */
 #define REG_MRXADDR_VALID(x) BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */
@@ -80,44 +81,116 @@ enum {
 #define WAIT_TIMEOUT      1000 /* ms */
 #define DEFAULT_SCL_RATE  (100 * 1000) /* Hz */
 
 #define WAIT_TIMEOUT      1000 /* ms */
 #define DEFAULT_SCL_RATE  (100 * 1000) /* Hz */
 
-enum rk3x_i2c_state {
-       STATE_IDLE,
-       STATE_START,
-       STATE_READ,
-       STATE_WRITE,
-       STATE_STOP
+/**
+ * struct i2c_spec_values:
+ * @min_hold_start_ns: min hold time (repeated) START condition
+ * @min_low_ns: min LOW period of the SCL clock
+ * @min_high_ns: min HIGH period of the SCL cloc
+ * @min_setup_start_ns: min set-up time for a repeated START conditio
+ * @max_data_hold_ns: max data hold time
+ * @min_data_setup_ns: min data set-up time
+ * @min_setup_stop_ns: min set-up time for STOP condition
+ * @min_hold_buffer_ns: min bus free time between a STOP and
+ * START condition
+ */
+struct i2c_spec_values {
+       unsigned long min_hold_start_ns;
+       unsigned long min_low_ns;
+       unsigned long min_high_ns;
+       unsigned long min_setup_start_ns;
+       unsigned long max_data_hold_ns;
+       unsigned long min_data_setup_ns;
+       unsigned long min_setup_stop_ns;
+       unsigned long min_hold_buffer_ns;
+};
+
+static const struct i2c_spec_values standard_mode_spec = {
+       .min_hold_start_ns = 4000,
+       .min_low_ns = 4700,
+       .min_high_ns = 4000,
+       .min_setup_start_ns = 4700,
+       .max_data_hold_ns = 3450,
+       .min_data_setup_ns = 250,
+       .min_setup_stop_ns = 4000,
+       .min_hold_buffer_ns = 4700,
 };
 
 };
 
-struct rk3x_i2c;
+static const struct i2c_spec_values fast_mode_spec = {
+       .min_hold_start_ns = 600,
+       .min_low_ns = 1300,
+       .min_high_ns = 600,
+       .min_setup_start_ns = 600,
+       .max_data_hold_ns = 900,
+       .min_data_setup_ns = 100,
+       .min_setup_stop_ns = 600,
+       .min_hold_buffer_ns = 1300,
+};
+
+static const struct i2c_spec_values fast_mode_plus_spec = {
+       .min_hold_start_ns = 260,
+       .min_low_ns = 500,
+       .min_high_ns = 260,
+       .min_setup_start_ns = 260,
+       .max_data_hold_ns = 400,
+       .min_data_setup_ns = 50,
+       .min_setup_stop_ns = 260,
+       .min_hold_buffer_ns = 500,
+};
 
 /**
  * struct rk3x_i2c_calced_timings:
  * @div_low: Divider output for low
  * @div_high: Divider output for high
 
 /**
  * struct rk3x_i2c_calced_timings:
  * @div_low: Divider output for low
  * @div_high: Divider output for high
- * @sda_update_cfg: Used to config sda change state when scl is low,
- * used to adjust setup/hold time
- * @stp_sta_cfg: Start setup config for setup start time and hold start time
- * @stp_sto_cfg: Stop setup config for setup stop time
+ * @tuning: Used to adjust setup/hold data time,
+ * setup/hold start time and setup stop time for
+ * v1's calc_timings, the tuning should all be 0
+ * for old hardware anyone using v0's calc_timings.
  */
 struct rk3x_i2c_calced_timings {
        unsigned long div_low;
        unsigned long div_high;
  */
 struct rk3x_i2c_calced_timings {
        unsigned long div_low;
        unsigned long div_high;
-       unsigned int sda_update_cfg;
-       unsigned int stp_sta_cfg;
-       unsigned int stp_sto_cfg;
+       unsigned int tuning;
+};
+
+enum rk3x_i2c_state {
+       STATE_IDLE,
+       STATE_START,
+       STATE_READ,
+       STATE_WRITE,
+       STATE_STOP
 };
 
 /**
  * @grf_offset: offset inside the grf regmap for setting the i2c type
 };
 
 /**
  * @grf_offset: offset inside the grf regmap for setting the i2c type
+ * @calc_timings: Callback function for i2c timing information calculated
  */
 struct rk3x_i2c_soc_data {
        int grf_offset;
  */
 struct rk3x_i2c_soc_data {
        int grf_offset;
-
-       int (*clk_init)(struct rk3x_i2c *, unsigned long *);
        int (*calc_timings)(unsigned long, struct i2c_timings *,
                            struct rk3x_i2c_calced_timings *);
 };
 
        int (*calc_timings)(unsigned long, struct i2c_timings *,
                            struct rk3x_i2c_calced_timings *);
 };
 
+/**
+ * struct rk3x_i2c - private data of the controller
+ * @adap: corresponding I2C adapter
+ * @dev: device for this controller
+ * @soc_data: related soc data struct
+ * @regs: virtual memory area
+ * @clk: function clk for rk3399 or function & Bus clks for others
+ * @pclk: Bus clk for rk3399
+ * @clk_rate_nb: i2c clk rate change notify
+ * @t: I2C known timing information
+ * @lock: spinlock for the i2c bus
+ * @wait: the waitqueue to wait for i2c transfer
+ * @busy: the condition for the event to wait for
+ * @msg: current i2c message
+ * @addr: addr of i2c slave device
+ * @mode: mode of i2c transfer
+ * @is_last_msg: flag determines whether it is the last msg in this transfer
+ * @state: state of i2c transfer
+ * @processed: byte length which has been send or received
+ * @error: error code for i2c transfer
+ */
 struct rk3x_i2c {
        struct i2c_adapter adap;
        struct device *dev;
 struct rk3x_i2c {
        struct i2c_adapter adap;
        struct device *dev;
@@ -125,13 +198,12 @@ struct rk3x_i2c {
 
        /* Hardware resources */
        void __iomem *regs;
 
        /* Hardware resources */
        void __iomem *regs;
-       struct clk *pclk; /* APB clock */
-       struct clk *clk; /* Func clk for rk3399 or Func & APB clks for others */
+       struct clk *clk;
+       struct clk *pclk;
        struct notifier_block clk_rate_nb;
 
        /* Settings */
        struct i2c_timings t;
        struct notifier_block clk_rate_nb;
 
        /* Settings */
        struct i2c_timings t;
-       struct rk3x_i2c_calced_timings t_calc;
 
        /* Synchronization & notification */
        spinlock_t lock;
 
        /* Synchronization & notification */
        spinlock_t lock;
@@ -146,7 +218,7 @@ struct rk3x_i2c {
 
        /* I2C state machine */
        enum rk3x_i2c_state state;
 
        /* I2C state machine */
        enum rk3x_i2c_state state;
-       unsigned int processed; /* sent/received bytes */
+       unsigned int processed;
        int error;
 };
 
        int error;
 };
 
@@ -161,13 +233,6 @@ static inline u32 i2c_readl(struct rk3x_i2c *i2c, unsigned int offset)
        return readl(i2c->regs + offset);
 }
 
        return readl(i2c->regs + offset);
 }
 
-static inline u32 rk3x_i2c_get_con_count(struct rk3x_i2c *i2c)
-{
-       return REG_CON_SDA_CNT(i2c->t_calc.sda_update_cfg) |
-              REG_CON_STA_CNT(i2c->t_calc.stp_sta_cfg) |
-              REG_CON_STO_CNT(i2c->t_calc.stp_sto_cfg);
-}
-
 /* Reset all interrupt pending bits */
 static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c)
 {
 /* Reset all interrupt pending bits */
 static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c)
 {
@@ -179,13 +244,12 @@ static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c)
  */
 static void rk3x_i2c_start(struct rk3x_i2c *i2c)
 {
  */
 static void rk3x_i2c_start(struct rk3x_i2c *i2c)
 {
-       u32 val = rk3x_i2c_get_con_count(i2c);
+       u32 val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
 
 
-       rk3x_i2c_clean_ipd(i2c);
        i2c_writel(i2c, REG_INT_START, REG_IEN);
 
        /* enable adapter with correct mode, send START condition */
        i2c_writel(i2c, REG_INT_START, REG_IEN);
 
        /* enable adapter with correct mode, send START condition */
-       val = val | REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START;
+       val |= REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START;
 
        /* if we want to react to NACK, set ACTACK bit */
        if (!(i2c->msg->flags & I2C_M_IGNORE_NAK))
 
        /* if we want to react to NACK, set ACTACK bit */
        if (!(i2c->msg->flags & I2C_M_IGNORE_NAK))
@@ -226,7 +290,8 @@ static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error)
                 * get the intended effect by resetting its internal state
                 * and issuing an ordinary START.
                 */
                 * get the intended effect by resetting its internal state
                 * and issuing an ordinary START.
                 */
-               i2c_writel(i2c, rk3x_i2c_get_con_count(i2c), REG_CON);
+               ctrl = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
+               i2c_writel(i2c, ctrl, REG_CON);
 
                /* signal that we are finished with the current msg */
                wake_up(&i2c->wait);
 
                /* signal that we are finished with the current msg */
                wake_up(&i2c->wait);
@@ -468,14 +533,28 @@ out:
 }
 
 /**
 }
 
 /**
- * Calculate timing values for desired SCL frequency
+ * Get timing values of I2C specification
+ *
+ * @speed: Desired SCL frequency
+ *
+ * Returns: Matched i2c spec values.
+ */
+static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
+{
+       if (speed <= 100000)
+               return &standard_mode_spec;
+       else if (speed <= 400000)
+               return &fast_mode_spec;
+       else
+               return &fast_mode_plus_spec;
+}
+
+/**
+ * Calculate divider values for desired SCL frequency
  *
  * @clk_rate: I2C input clock rate
  *
  * @clk_rate: I2C input clock rate
- * @t: Known I2C timing information.
- * @div_low: Divider output for low
- * @div_high: Divider output for high
- * @t_calc: Caculated rk3x private timings  that would
- * be written into regs
+ * @t: Known I2C timing information
+ * @t_calc: Caculated rk3x private timings that would be written into regs
  *
  * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
  * a best-effort divider value is returned in divs. If the target rate is
  *
  * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
  * a best-effort divider value is returned in divs. If the target rate is
@@ -485,10 +564,6 @@ static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate,
                                    struct i2c_timings *t,
                                    struct rk3x_i2c_calced_timings *t_calc)
 {
                                    struct i2c_timings *t,
                                    struct rk3x_i2c_calced_timings *t_calc)
 {
-       unsigned long spec_min_low_ns, spec_min_high_ns;
-       unsigned long spec_setup_start, spec_max_data_hold_ns;
-       unsigned long data_hold_buffer_ns;
-
        unsigned long min_low_ns, min_high_ns;
        unsigned long max_low_ns, min_total_ns;
 
        unsigned long min_low_ns, min_high_ns;
        unsigned long max_low_ns, min_total_ns;
 
@@ -500,6 +575,8 @@ static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate,
        unsigned long min_div_for_hold, min_total_div;
        unsigned long extra_div, extra_low_div, ideal_low_div;
 
        unsigned long min_div_for_hold, min_total_div;
        unsigned long extra_div, extra_low_div, ideal_low_div;
 
+       unsigned long data_hold_buffer_ns = 50;
+       const struct i2c_spec_values *spec;
        int ret = 0;
 
        /* Only support standard-mode and fast-mode */
        int ret = 0;
 
        /* Only support standard-mode and fast-mode */
@@ -522,22 +599,8 @@ static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate,
         *       This is because the i2c host on Rockchip holds the data line
         *       for half the low time.
         */
         *       This is because the i2c host on Rockchip holds the data line
         *       for half the low time.
         */
-       if (t->bus_freq_hz <= 100000) {
-               /* Standard-mode */
-               spec_min_low_ns = 4700;
-               spec_setup_start = 4700;
-               spec_min_high_ns = 4000;
-               spec_max_data_hold_ns = 3450;
-               data_hold_buffer_ns = 50;
-       } else {
-               /* Fast-mode */
-               spec_min_low_ns = 1300;
-               spec_setup_start = 600;
-               spec_min_high_ns = 600;
-               spec_max_data_hold_ns = 900;
-               data_hold_buffer_ns = 50;
-       }
-       min_high_ns = t->scl_rise_ns + spec_min_high_ns;
+       spec = rk3x_i2c_get_spec(t->bus_freq_hz);
+       min_high_ns = t->scl_rise_ns + spec->min_high_ns;
 
        /*
         * Timings for repeated start:
 
        /*
         * Timings for repeated start:
@@ -547,14 +610,14 @@ static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate,
         * We need to account for those rules in picking our "high" time so
         * we meet tSU;STA and tHD;STA times.
         */
         * We need to account for those rules in picking our "high" time so
         * we meet tSU;STA and tHD;STA times.
         */
-       min_high_ns = max(min_high_ns,
-               DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start) * 1000, 875));
-       min_high_ns = max(min_high_ns,
-               DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start +
-                             t->sda_fall_ns + spec_min_high_ns), 2));
-
-       min_low_ns = t->scl_fall_ns + spec_min_low_ns;
-       max_low_ns = spec_max_data_hold_ns * 2 - data_hold_buffer_ns;
+       min_high_ns = max(min_high_ns, DIV_ROUND_UP(
+               (t->scl_rise_ns + spec->min_setup_start_ns) * 1000, 875));
+       min_high_ns = max(min_high_ns, DIV_ROUND_UP(
+               (t->scl_rise_ns + spec->min_setup_start_ns + t->sda_fall_ns +
+               spec->min_high_ns), 2));
+
+       min_low_ns = t->scl_fall_ns + spec->min_low_ns;
+       max_low_ns =  spec->max_data_hold_ns * 2 - data_hold_buffer_ns;
        min_total_ns = min_low_ns + min_high_ns;
 
        /* Adjust to avoid overflow */
        min_total_ns = min_low_ns + min_high_ns;
 
        /* Adjust to avoid overflow */
@@ -628,8 +691,8 @@ static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate,
         * Adjust to the fact that the hardware has an implicit "+1".
         * NOTE: Above calculations always produce div_low > 0 and div_high > 0.
         */
         * Adjust to the fact that the hardware has an implicit "+1".
         * NOTE: Above calculations always produce div_low > 0 and div_high > 0.
         */
-       t_calc->div_low -= 1;
-       t_calc->div_high -=  1;
+       t_calc->div_low--;
+       t_calc->div_high--;
 
        /* Maximum divider supported by hw is 0xffff */
        if (t_calc->div_low > 0xffff) {
 
        /* Maximum divider supported by hw is 0xffff */
        if (t_calc->div_low > 0xffff) {
@@ -650,8 +713,8 @@ static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate,
  *
  * @clk_rate: I2C input clock rate
  * @t: Known I2C timing information
  *
  * @clk_rate: I2C input clock rate
  * @t: Known I2C timing information
- * @t_calc: Caculated rk3x private timings that would
- * be written into regs
+ * @t_calc: Caculated rk3x private timings that would be written into regs
+ *
  * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
  * a best-effort divider value is returned in divs. If the target rate is
  * too high, we silently use the highest possible rate.
  * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
  * a best-effort divider value is returned in divs. If the target rate is
  * too high, we silently use the highest possible rate.
@@ -663,14 +726,14 @@ static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate,
  * u = start_setup_config + 1;
  * p = stop_setup_config + 1;
  * T = Tclk_i2c;
  * u = start_setup_config + 1;
  * p = stop_setup_config + 1;
  * T = Tclk_i2c;
-
+ *
  * tHigh = 8 * h * T;
  * tLow = 8 * l * T;
  * tHigh = 8 * h * T;
  * tLow = 8 * l * T;
-
+ *
  * tHD;sda = (l * s + 1) * T;
  * tSU;sda = [(8 - s) * l + 1] * T;
  * tI2C = 8 * (l + h) * T;
  * tHD;sda = (l * s + 1) * T;
  * tSU;sda = [(8 - s) * l + 1] * T;
  * tI2C = 8 * (l + h) * T;
-
+ *
  * tSU;sta = (8h * u + 1) * T;
  * tHD;sta = [8h * (u + 1) - 1] * T;
  * tSU;sto = (8h * p + 1) * T;
  * tSU;sta = (8h * u + 1) * T;
  * tHD;sta = [8h * (u + 1) - 1] * T;
  * tSU;sto = (8h * p + 1) * T;
@@ -679,13 +742,9 @@ static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
                                    struct i2c_timings *t,
                                    struct rk3x_i2c_calced_timings *t_calc)
 {
                                    struct i2c_timings *t,
                                    struct rk3x_i2c_calced_timings *t_calc)
 {
-       unsigned long spec_min_low_ns, spec_min_high_ns;
-       unsigned long spec_min_setup_start_ns, spec_min_stop_setup_ns;
-       unsigned long spec_min_data_setup_ns, spec_max_data_hold_ns;
-
        unsigned long min_low_ns, min_high_ns, min_total_ns;
        unsigned long min_setup_start_ns, min_setup_data_ns;
        unsigned long min_low_ns, min_high_ns, min_total_ns;
        unsigned long min_setup_start_ns, min_setup_data_ns;
-       unsigned long min_stop_setup_ns, max_hold_data_ns;
+       unsigned long min_setup_stop_ns, max_hold_data_ns;
 
        unsigned long clk_rate_khz, scl_rate_khz;
 
 
        unsigned long clk_rate_khz, scl_rate_khz;
 
@@ -693,13 +752,14 @@ static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
 
        unsigned long min_div_for_hold, min_total_div;
        unsigned long extra_div, extra_low_div;
 
        unsigned long min_div_for_hold, min_total_div;
        unsigned long extra_div, extra_low_div;
-       unsigned long sda_update_cfg;
+       unsigned long sda_update_cfg, stp_sta_cfg, stp_sto_cfg;
 
 
+       const struct i2c_spec_values *spec;
        int ret = 0;
 
        int ret = 0;
 
-       /* Support standard-mode, fast-mode and highspeed-mode */
-       if (WARN_ON(t->bus_freq_hz > 3400000))
-               t->bus_freq_hz = 3400000;
+       /* Support standard-mode, fast-mode and fast-mode plus */
+       if (WARN_ON(t->bus_freq_hz > 1000000))
+               t->bus_freq_hz = 1000000;
 
        /* prevent scl_rate_khz from becoming 0 */
        if (WARN_ON(t->bus_freq_hz < 1000))
 
        /* prevent scl_rate_khz from becoming 0 */
        if (WARN_ON(t->bus_freq_hz < 1000))
@@ -711,56 +771,21 @@ static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
         * min_high_ns: The minimum number of ns we need to hold high to
         *              meet I2C specification, should include rise time.
         */
         * min_high_ns: The minimum number of ns we need to hold high to
         *              meet I2C specification, should include rise time.
         */
-       if (t->bus_freq_hz <= 100000) {
-               spec_min_low_ns = 4700;
-               spec_min_high_ns = 4000;
-
-               spec_min_setup_start_ns = 4700;
-               spec_min_stop_setup_ns = 4000;
-
-               spec_min_data_setup_ns = 250;
-                spec_max_data_hold_ns = 3450;
-       } else if (t->bus_freq_hz <= 400000) {
-               spec_min_low_ns = 1300;
-               spec_min_high_ns = 600;
-
-               spec_min_setup_start_ns = 600;
-               spec_min_stop_setup_ns = 600;
-
-               spec_min_data_setup_ns = 100;
-               spec_max_data_hold_ns = 900;
-       } else if (t->bus_freq_hz <= 1700000) {
-               spec_min_low_ns = 320;
-               spec_min_high_ns = 120;
-
-               spec_min_setup_start_ns = 160;
-               spec_min_stop_setup_ns = 160;
-
-               spec_min_data_setup_ns = 10;
-               spec_max_data_hold_ns = 150;
-       } else {
-               spec_min_low_ns = 160;
-               spec_min_high_ns = 60;
+       spec = rk3x_i2c_get_spec(t->bus_freq_hz);
 
 
-               spec_min_setup_start_ns = 160;
-               spec_min_stop_setup_ns = 160;
-
-               spec_min_data_setup_ns = 10;
-               spec_max_data_hold_ns = 70;
-       }
-
-       /* caculate min-divh and min-divl */
+       /* calculate min-divh and min-divl */
        clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000);
        scl_rate_khz = t->bus_freq_hz / 1000;
        min_total_div = DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8);
 
        clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000);
        scl_rate_khz = t->bus_freq_hz / 1000;
        min_total_div = DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8);
 
-       min_high_ns = t->scl_rise_ns + spec_min_high_ns;
+       min_high_ns = t->scl_rise_ns + spec->min_high_ns;
        min_high_div = DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000);
 
        min_high_div = DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000);
 
-       min_low_ns = t->scl_fall_ns + spec_min_low_ns;
+       min_low_ns = t->scl_fall_ns + spec->min_low_ns;
        min_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000);
 
        min_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000);
 
-       /* Final divh and divl must be greater than 0, otherwise the
+       /*
+        * Final divh and divl must be greater than 0, otherwise the
         * hardware would not output the i2c clk.
         */
        min_high_div = (min_high_div < 1) ? 2 : min_high_div;
         * hardware would not output the i2c clk.
         */
        min_high_div = (min_high_div < 1) ? 2 : min_high_div;
@@ -774,7 +799,7 @@ static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
         * This is the maximum divider so we don't go over the maximum.
         * We don't round up here (we round down) since this is a maximum.
         */
         * This is the maximum divider so we don't go over the maximum.
         * We don't round up here (we round down) since this is a maximum.
         */
-        if (min_div_for_hold >= min_total_div) {
+       if (min_div_for_hold >= min_total_div) {
                /*
                 * Time needed to meet hold requirements is important.
                 * Just use that.
                /*
                 * Time needed to meet hold requirements is important.
                 * Just use that.
@@ -808,33 +833,35 @@ static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
                min_setup_data_ns =  DIV_ROUND_UP(((8 - sda_update_cfg)
                                                 * (t_calc->div_low) + 1)
                                                 * 1000000, clk_rate_khz);
                min_setup_data_ns =  DIV_ROUND_UP(((8 - sda_update_cfg)
                                                 * (t_calc->div_low) + 1)
                                                 * 1000000, clk_rate_khz);
-               if ((max_hold_data_ns < spec_max_data_hold_ns) &&
-                   (min_setup_data_ns > spec_min_data_setup_ns)) {
-                       t_calc->sda_update_cfg = sda_update_cfg;
+               if ((max_hold_data_ns < spec->max_data_hold_ns) &&
+                   (min_setup_data_ns > spec->min_data_setup_ns))
                        break;
                        break;
-               }
        }
 
        }
 
-       /* caculate setup start config */
-       min_setup_start_ns = t->scl_rise_ns + spec_min_setup_start_ns;
-       t_calc->stp_sta_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_start_ns
+       /* calculate setup start config */
+       min_setup_start_ns = t->scl_rise_ns + spec->min_setup_start_ns;
+       stp_sta_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_start_ns
                           - 1000000, 8 * 1000000 * (t_calc->div_high));
 
                           - 1000000, 8 * 1000000 * (t_calc->div_high));
 
-       /* caculate setup stop config */
-       min_stop_setup_ns = t->scl_rise_ns + spec_min_stop_setup_ns;
-       t_calc->stp_sto_cfg = DIV_ROUND_UP(clk_rate_khz * min_stop_setup_ns
+       /* calculate setup stop config */
+       min_setup_stop_ns = t->scl_rise_ns + spec->min_setup_stop_ns;
+       stp_sto_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_stop_ns
                           - 1000000, 8 * 1000000 * (t_calc->div_high));
 
                           - 1000000, 8 * 1000000 * (t_calc->div_high));
 
-       t_calc->stp_sta_cfg -= 1;
-       t_calc->stp_sto_cfg -= 1;
-       t_calc->sda_update_cfg -= 1;
+       t_calc->tuning = REG_CON_SDA_CFG(--sda_update_cfg) |
+                        REG_CON_STA_CFG(--stp_sta_cfg) |
+                        REG_CON_STO_CFG(--stp_sto_cfg);
 
 
-       t_calc->div_low -= 1;
-       t_calc->div_high -= 1;
+       t_calc->div_low--;
+       t_calc->div_high--;
 
        /* Maximum divider supported by hw is 0xffff */
 
        /* Maximum divider supported by hw is 0xffff */
-       if ((t_calc->div_low > 0xffff) || (t_calc->div_high > 0xffff)) {
+       if (t_calc->div_low > 0xffff) {
                t_calc->div_low = 0xffff;
                t_calc->div_low = 0xffff;
+               ret = -EINVAL;
+       }
+
+       if (t_calc->div_high > 0xffff) {
                t_calc->div_high = 0xffff;
                ret = -EINVAL;
        }
                t_calc->div_high = 0xffff;
                ret = -EINVAL;
        }
@@ -845,30 +872,30 @@ static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
 static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
 {
        struct i2c_timings *t = &i2c->t;
 static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
 {
        struct i2c_timings *t = &i2c->t;
-       struct rk3x_i2c_calced_timings *t_calc = &i2c->t_calc;
+       struct rk3x_i2c_calced_timings calc;
        u64 t_low_ns, t_high_ns;
        u64 t_low_ns, t_high_ns;
-       int ret = 0;
+       unsigned long flags;
+       u32 val;
+       int ret;
 
 
-       if (i2c->soc_data->calc_timings)
-               ret = i2c->soc_data->calc_timings(clk_rate, t, t_calc);
+       ret = i2c->soc_data->calc_timings(clk_rate, t, &calc);
        WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
 
        WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
 
-       if (i2c->pclk)
-               clk_enable(i2c->pclk);
-       else
-               clk_enable(i2c->clk);
+       clk_enable(i2c->pclk);
 
 
-       i2c_writel(i2c, (t_calc->div_high << 16) |
-                 (t_calc->div_low & 0xffff), REG_CLKDIV);
+       spin_lock_irqsave(&i2c->lock, flags);
+       val = i2c_readl(i2c, REG_CON);
+       val &= ~REG_CON_TUNING_MASK;
+       val |= calc.tuning;
+       i2c_writel(i2c, val, REG_CON);
+       i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff),
+                  REG_CLKDIV);
+       spin_unlock_irqrestore(&i2c->lock, flags);
 
 
-       if (i2c->pclk)
-               clk_disable(i2c->pclk);
-       else
-               clk_disable(i2c->clk);
+       clk_disable(i2c->pclk);
 
 
-       t_low_ns = div_u64(((u64)t_calc->div_low + 1) * 8 * 1000000000,
-                          clk_rate);
-       t_high_ns = div_u64(((u64)t_calc->div_high + 1) * 8 * 1000000000,
+       t_low_ns = div_u64(((u64)calc.div_low + 1) * 8 * 1000000000, clk_rate);
+       t_high_ns = div_u64(((u64)calc.div_high + 1) * 8 * 1000000000,
                            clk_rate);
        dev_dbg(i2c->dev,
                "CLK %lukhz, Req %uns, Act low %lluns high %lluns\n",
                            clk_rate);
        dev_dbg(i2c->dev,
                "CLK %lukhz, Req %uns, Act low %lluns high %lluns\n",
@@ -899,13 +926,17 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
 {
        struct clk_notifier_data *ndata = data;
        struct rk3x_i2c *i2c = container_of(nb, struct rk3x_i2c, clk_rate_nb);
 {
        struct clk_notifier_data *ndata = data;
        struct rk3x_i2c *i2c = container_of(nb, struct rk3x_i2c, clk_rate_nb);
-       struct i2c_timings *t = &i2c->t;
-       struct rk3x_i2c_calced_timings *t_calc = &i2c->t_calc;
+       struct rk3x_i2c_calced_timings calc;
 
        switch (event) {
        case PRE_RATE_CHANGE:
 
        switch (event) {
        case PRE_RATE_CHANGE:
-               if (i2c->soc_data->calc_timings(ndata->new_rate,
-                                               t, t_calc) != 0)
+               /*
+                * Try the calculation (but don't store the result) ahead of
+                * time to see if we need to block the clock change.  Timings
+                * shouldn't actually take effect until rk3x_i2c_adapt_div().
+                */
+               if (i2c->soc_data->calc_timings(ndata->new_rate, &i2c->t,
+                                               &calc) != 0)
                        return NOTIFY_STOP;
 
                /* scale up */
                        return NOTIFY_STOP;
 
                /* scale up */
@@ -1015,14 +1046,14 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
 {
        struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data;
        unsigned long timeout, flags;
 {
        struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data;
        unsigned long timeout, flags;
+       u32 val;
        int ret = 0;
        int i;
 
        spin_lock_irqsave(&i2c->lock, flags);
 
        int ret = 0;
        int i;
 
        spin_lock_irqsave(&i2c->lock, flags);
 
-       if (i2c->pclk)
-               clk_enable(i2c->pclk);
        clk_enable(i2c->clk);
        clk_enable(i2c->clk);
+       clk_enable(i2c->pclk);
 
        i2c->is_last_msg = false;
 
 
        i2c->is_last_msg = false;
 
@@ -1056,8 +1087,9 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
 
                        /* Force a STOP condition without interrupt */
                        i2c_writel(i2c, 0, REG_IEN);
 
                        /* Force a STOP condition without interrupt */
                        i2c_writel(i2c, 0, REG_IEN);
-                       i2c_writel(i2c, rk3x_i2c_get_con_count(i2c) |
-                                  REG_CON_EN | REG_CON_STOP, REG_CON);
+                       val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
+                       val |= REG_CON_EN | REG_CON_STOP;
+                       i2c_writel(i2c, val, REG_CON);
 
                        i2c->state = STATE_IDLE;
 
 
                        i2c->state = STATE_IDLE;
 
@@ -1071,9 +1103,9 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
                }
        }
 
                }
        }
 
+       clk_disable(i2c->pclk);
        clk_disable(i2c->clk);
        clk_disable(i2c->clk);
-       if (i2c->pclk)
-               clk_disable(i2c->pclk);
+
        spin_unlock_irqrestore(&i2c->lock, flags);
 
        return ret < 0 ? ret : num;
        spin_unlock_irqrestore(&i2c->lock, flags);
 
        return ret < 0 ? ret : num;
@@ -1089,110 +1121,52 @@ static const struct i2c_algorithm rk3x_i2c_algorithm = {
        .functionality          = rk3x_i2c_func,
 };
 
        .functionality          = rk3x_i2c_func,
 };
 
-static int rk3x_i2c_v0_clock_init(struct rk3x_i2c *i2c, unsigned long *clk_rate)
-{
-       int ret = 0;
-
-       i2c->clk = devm_clk_get(i2c->dev, "i2c");
-       if (IS_ERR(i2c->clk)) {
-               dev_err(i2c->dev, "Could not get i2c clk\n");
-               return PTR_ERR(i2c->clk);
-       }
-
-       ret = clk_prepare(i2c->clk);
-       if (ret < 0) {
-               dev_err(i2c->dev, "Could not prepare i2c clk\n");
-               return ret;
-       }
-
-       *clk_rate = clk_get_rate(i2c->clk);
-
-       i2c->clk_rate_nb.notifier_call = rk3x_i2c_clk_notifier_cb;
-       ret = clk_notifier_register(i2c->clk, &i2c->clk_rate_nb);
-       if (ret != 0) {
-               dev_err(i2c->dev, "Unable to register clk notifier\n");
-               clk_unprepare(i2c->clk);
-       }
-
-       return ret;
-}
-
-static int rk3x_i2c_v1_clock_init(struct rk3x_i2c *i2c, unsigned long *clk_rate)
-{
-       int ret = 0;
-       u32 rate = 0;
-
-       /* sclk and pclk need to do individually*/
-       i2c->pclk = devm_clk_get(i2c->dev, "pclk");
-       if (IS_ERR(i2c->pclk)) {
-               dev_err(i2c->dev, "Could not get i2c pclk\n");
-               return PTR_ERR(i2c->pclk);
-       }
+static const struct rk3x_i2c_soc_data rk3066_soc_data = {
+       .grf_offset = 0x154,
+       .calc_timings = rk3x_i2c_v0_calc_timings,
+};
 
 
-       ret = clk_prepare(i2c->pclk);
-       if (ret < 0) {
-               dev_err(i2c->dev, "Could not prepare pclk\n");
-               return ret;
-       }
+static const struct rk3x_i2c_soc_data rk3188_soc_data = {
+       .grf_offset = 0x0a4,
+       .calc_timings = rk3x_i2c_v0_calc_timings,
+};
 
 
-       i2c->clk = devm_clk_get(i2c->dev, "i2c");
-       if (IS_ERR(i2c->clk)) {
-               dev_err(i2c->dev, "cannot get i2c clk\n");
-               clk_unprepare(i2c->pclk);
-               return PTR_ERR(i2c->clk);
-       }
-       ret = clk_prepare(i2c->clk);
-       if (ret) {
-               dev_err(i2c->dev, "Could not prepare i2c clk\n");
-               clk_unprepare(i2c->pclk);
-               return ret;
-       }
+static const struct rk3x_i2c_soc_data rk3228_soc_data = {
+       .grf_offset = -1,
+       .calc_timings = rk3x_i2c_v0_calc_timings,
+};
 
 
-       if (!device_property_read_u32(i2c->dev, "input-clk-rate", &rate)) {
-               *clk_rate = rate;
-               ret = clk_set_rate(i2c->clk, *clk_rate);
-               if (ret) {
-                       dev_err(i2c->dev, "i2c clk set rate failed\n");
-                       clk_unprepare(i2c->clk);
-                       clk_unprepare(i2c->pclk);
-                       return ret;
-               }
-       } else {
-               /* use default input clock rate */
-               *clk_rate = clk_get_rate(i2c->clk);
-       }
+static const struct rk3x_i2c_soc_data rk3288_soc_data = {
+       .grf_offset = -1,
+       .calc_timings = rk3x_i2c_v0_calc_timings,
+};
 
 
-       return ret;
-}
+static const struct rk3x_i2c_soc_data rk3399_soc_data = {
+       .grf_offset = -1,
+       .calc_timings = rk3x_i2c_v1_calc_timings,
+};
 
 
-static struct rk3x_i2c_soc_data soc_data[] = {
+static const struct of_device_id rk3x_i2c_match[] = {
        {
        {
-               .grf_offset = 0x154,
-               .clk_init = rk3x_i2c_v0_clock_init,
-               .calc_timings = rk3x_i2c_v0_calc_timings,
+               .compatible = "rockchip,rk3066-i2c",
+               .data = (void *)&rk3066_soc_data
        },
        {
        },
        {
-               .grf_offset = 0x0a4,
-               .clk_init = rk3x_i2c_v0_clock_init,
-               .calc_timings = rk3x_i2c_v0_calc_timings,
+               .compatible = "rockchip,rk3188-i2c",
+               .data = (void *)&rk3188_soc_data
        },
        {
        },
        {
-               .grf_offset = -1,
-               .clk_init = rk3x_i2c_v0_clock_init,
-               .calc_timings = rk3x_i2c_v0_calc_timings,
+               .compatible = "rockchip,rk3228-i2c",
+               .data = (void *)&rk3228_soc_data
        },
        {
        },
        {
-               .grf_offset = -1,
-               .clk_init = rk3x_i2c_v1_clock_init,
-               .calc_timings = rk3x_i2c_v1_calc_timings,
+               .compatible = "rockchip,rk3288-i2c",
+               .data = (void *)&rk3288_soc_data
+       },
+       {
+               .compatible = "rockchip,rk3399-i2c",
+               .data = (void *)&rk3399_soc_data
        },
        },
-};
-
-static const struct of_device_id rk3x_i2c_match[] = {
-       { .compatible = "rockchip,rk3066-i2c", .data = (void *)&soc_data[0] },
-       { .compatible = "rockchip,rk3188-i2c", .data = (void *)&soc_data[1] },
-       { .compatible = "rockchip,rk3288-i2c", .data = (void *)&soc_data[2] },
-       { .compatible = "rockchip,rk3399-i2c", .data = (void *)&soc_data[3] },
        {},
 };
 MODULE_DEVICE_TABLE(of, rk3x_i2c_match);
        {},
 };
 MODULE_DEVICE_TABLE(of, rk3x_i2c_match);
@@ -1226,6 +1200,7 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
        i2c->adap.dev.of_node = np;
        i2c->adap.algo_data = i2c;
        i2c->adap.dev.parent = &pdev->dev;
        i2c->adap.dev.of_node = np;
        i2c->adap.algo_data = i2c;
        i2c->adap.dev.parent = &pdev->dev;
+
        i2c->dev = &pdev->dev;
 
        spin_lock_init(&i2c->lock);
        i2c->dev = &pdev->dev;
 
        spin_lock_init(&i2c->lock);
@@ -1284,15 +1259,49 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, i2c);
 
 
        platform_set_drvdata(pdev, i2c);
 
-       if (i2c->soc_data->clk_init) {
-               ret = i2c->soc_data->clk_init(i2c, &clk_rate);
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "clock init failed\n");
-                       return ret;
-               }
+       if (i2c->soc_data->calc_timings == rk3x_i2c_v0_calc_timings) {
+               /* Only one clock to use for bus clock and peripheral clock */
+               i2c->clk = devm_clk_get(&pdev->dev, NULL);
+               i2c->pclk = i2c->clk;
+       } else {
+               i2c->clk = devm_clk_get(&pdev->dev, "i2c");
+               i2c->pclk = devm_clk_get(&pdev->dev, "pclk");
+       }
+
+       if (IS_ERR(i2c->clk)) {
+               ret = PTR_ERR(i2c->clk);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "Can't get bus clk: %d\n", ret);
+               return ret;
+       }
+       if (IS_ERR(i2c->pclk)) {
+               ret = PTR_ERR(i2c->pclk);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "Can't get periph clk: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_prepare(i2c->clk);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Can't prepare bus clk: %d\n", ret);
+               return ret;
+       }
+       ret = clk_prepare(i2c->pclk);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Can't prepare periph clock: %d\n", ret);
+               goto err_clk;
+       }
+
+       i2c->clk_rate_nb.notifier_call = rk3x_i2c_clk_notifier_cb;
+       ret = clk_notifier_register(i2c->clk, &i2c->clk_rate_nb);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "Unable to register clock notifier\n");
+               goto err_pclk;
        }
 
        }
 
+       clk_rate = clk_get_rate(i2c->clk);
        rk3x_i2c_adapt_div(i2c, clk_rate);
        rk3x_i2c_adapt_div(i2c, clk_rate);
+
        ret = i2c_add_adapter(&i2c->adap);
        if (ret < 0) {
                dev_err(&pdev->dev, "Could not register adapter\n");
        ret = i2c_add_adapter(&i2c->adap);
        if (ret < 0) {
                dev_err(&pdev->dev, "Could not register adapter\n");
@@ -1305,10 +1314,10 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
 
 err_clk_notifier:
        clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
 
 err_clk_notifier:
        clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
+err_pclk:
+       clk_unprepare(i2c->pclk);
+err_clk:
        clk_unprepare(i2c->clk);
        clk_unprepare(i2c->clk);
-       if (i2c->pclk)
-               clk_unprepare(i2c->pclk);
-
        return ret;
 }
 
        return ret;
 }
 
@@ -1319,9 +1328,8 @@ static int rk3x_i2c_remove(struct platform_device *pdev)
        i2c_del_adapter(&i2c->adap);
 
        clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
        i2c_del_adapter(&i2c->adap);
 
        clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
+       clk_unprepare(i2c->pclk);
        clk_unprepare(i2c->clk);
        clk_unprepare(i2c->clk);
-       if (i2c->pclk)
-               clk_unprepare(i2c->pclk);
 
        return 0;
 }
 
        return 0;
 }