i2c: designware: Add debug print for bus speed
[platform/kernel/linux-rpi.git] / drivers / i2c / busses / i2c-designware-master.c
index 27436a9..fc7c255 100644 (file)
@@ -45,90 +45,78 @@ static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev)
        dw_writel(dev, dev->master_cfg, DW_IC_CON);
 }
 
-/**
- * i2c_dw_init() - Initialize the designware I2C master hardware
- * @dev: device private data
- *
- * This functions configures and enables the I2C master.
- * This function is called during I2C init function, and in case of timeout at
- * run time.
- */
-static int i2c_dw_init_master(struct dw_i2c_dev *dev)
+static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
 {
-       u32 hcnt, lcnt;
-       u32 reg, comp_param1;
+       u32 ic_clk = i2c_dw_clk_rate(dev);
+       const char *mode_str, *fp_str = "";
+       u32 comp_param1;
        u32 sda_falling_time, scl_falling_time;
        int ret;
 
        ret = i2c_dw_acquire_lock(dev);
        if (ret)
                return ret;
-
-       reg = dw_readl(dev, DW_IC_COMP_TYPE);
-       if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) {
-               /* Configure register endianess access */
-               dev->flags |= ACCESS_SWAP;
-       } else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) {
-               /* Configure register access mode 16bit */
-               dev->flags |= ACCESS_16BIT;
-       } else if (reg != DW_IC_COMP_TYPE_VALUE) {
-               dev_err(dev->dev,
-                       "Unknown Synopsys component type: 0x%08x\n", reg);
-               i2c_dw_release_lock(dev);
-               return -ENODEV;
-       }
-
        comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1);
+       i2c_dw_release_lock(dev);
 
-       /* Disable the adapter */
-       __i2c_dw_disable(dev);
-
-       /* Set standard and fast speed deviders for high/low periods */
-
+       /* Set standard and fast speed dividers for high/low periods */
        sda_falling_time = dev->sda_falling_time ?: 300; /* ns */
        scl_falling_time = dev->scl_falling_time ?: 300; /* ns */
 
-       /* Set SCL timing parameters for standard-mode */
-       if (dev->ss_hcnt && dev->ss_lcnt) {
-               hcnt = dev->ss_hcnt;
-               lcnt = dev->ss_lcnt;
-       } else {
-               hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev),
+       /* Calculate SCL timing parameters for standard mode if not set */
+       if (!dev->ss_hcnt || !dev->ss_lcnt) {
+               dev->ss_hcnt =
+                       i2c_dw_scl_hcnt(ic_clk,
                                        4000,   /* tHD;STA = tHIGH = 4.0 us */
                                        sda_falling_time,
                                        0,      /* 0: DW default, 1: Ideal */
                                        0);     /* No offset */
-               lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev),
+               dev->ss_lcnt =
+                       i2c_dw_scl_lcnt(ic_clk,
                                        4700,   /* tLOW = 4.7 us */
                                        scl_falling_time,
                                        0);     /* No offset */
        }
-       dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT);
-       dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT);
-       dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
-
-       /* Set SCL timing parameters for fast-mode or fast-mode plus */
-       if ((dev->clk_freq == 1000000) && dev->fp_hcnt && dev->fp_lcnt) {
-               hcnt = dev->fp_hcnt;
-               lcnt = dev->fp_lcnt;
-       } else if (dev->fs_hcnt && dev->fs_lcnt) {
-               hcnt = dev->fs_hcnt;
-               lcnt = dev->fs_lcnt;
-       } else {
-               hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev),
+       dev_dbg(dev->dev, "Standard Mode HCNT:LCNT = %d:%d\n",
+               dev->ss_hcnt, dev->ss_lcnt);
+
+       /*
+        * Set SCL timing parameters for fast mode or fast mode plus. Only
+        * difference is the timing parameter values since the registers are
+        * the same.
+        */
+       if (dev->clk_freq == 1000000) {
+               /*
+                * Check are fast mode plus parameters available and use
+                * fast mode if not.
+                */
+               if (dev->fp_hcnt && dev->fp_lcnt) {
+                       dev->fs_hcnt = dev->fp_hcnt;
+                       dev->fs_lcnt = dev->fp_lcnt;
+                       fp_str = " Plus";
+               }
+       }
+       /*
+        * Calculate SCL timing parameters for fast mode if not set. They are
+        * needed also in high speed mode.
+        */
+       if (!dev->fs_hcnt || !dev->fs_lcnt) {
+               dev->fs_hcnt =
+                       i2c_dw_scl_hcnt(ic_clk,
                                        600,    /* tHD;STA = tHIGH = 0.6 us */
                                        sda_falling_time,
                                        0,      /* 0: DW default, 1: Ideal */
                                        0);     /* No offset */
-               lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev),
+               dev->fs_lcnt =
+                       i2c_dw_scl_lcnt(ic_clk,
                                        1300,   /* tLOW = 1.3 us */
                                        scl_falling_time,
                                        0);     /* No offset */
        }
-       dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT);
-       dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
-       dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
+       dev_dbg(dev->dev, "Fast Mode%s HCNT:LCNT = %d:%d\n",
+               fp_str, dev->fs_hcnt, dev->fs_lcnt);
 
+       /* Check is high speed possible and fall back to fast mode if not */
        if ((dev->master_cfg & DW_IC_CON_SPEED_MASK) ==
                DW_IC_CON_SPEED_HIGH) {
                if ((comp_param1 & DW_IC_COMP_PARAM_1_SPEED_MODE_MASK)
@@ -136,37 +124,70 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev)
                        dev_err(dev->dev, "High Speed not supported!\n");
                        dev->master_cfg &= ~DW_IC_CON_SPEED_MASK;
                        dev->master_cfg |= DW_IC_CON_SPEED_FAST;
+                       dev->hs_hcnt = 0;
+                       dev->hs_lcnt = 0;
                } else if (dev->hs_hcnt && dev->hs_lcnt) {
-                       hcnt = dev->hs_hcnt;
-                       lcnt = dev->hs_lcnt;
-                       dw_writel(dev, hcnt, DW_IC_HS_SCL_HCNT);
-                       dw_writel(dev, lcnt, DW_IC_HS_SCL_LCNT);
-                       dev_dbg(dev->dev, "HighSpeed-mode HCNT:LCNT = %d:%d\n",
-                               hcnt, lcnt);
+                       dev_dbg(dev->dev, "High Speed Mode HCNT:LCNT = %d:%d\n",
+                               dev->hs_hcnt, dev->hs_lcnt);
                }
        }
 
-       /* Configure SDA Hold Time if required */
-       reg = dw_readl(dev, DW_IC_COMP_VERSION);
-       if (reg >= DW_IC_SDA_HOLD_MIN_VERS) {
-               if (!dev->sda_hold_time) {
-                       /* Keep previous hold time setting if no one set it */
-                       dev->sda_hold_time = dw_readl(dev, DW_IC_SDA_HOLD);
-               }
-               /*
-                * Workaround for avoiding TX arbitration lost in case I2C
-                * slave pulls SDA down "too quickly" after falling egde of
-                * SCL by enabling non-zero SDA RX hold. Specification says it
-                * extends incoming SDA low to high transition while SCL is
-                * high but it apprears to help also above issue.
-                */
-               if (!(dev->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK))
-                       dev->sda_hold_time |= 1 << DW_IC_SDA_HOLD_RX_SHIFT;
-               dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
-       } else if (dev->sda_hold_time) {
-               dev_warn(dev->dev,
-                       "Hardware too old to adjust SDA hold time.\n");
+       ret = i2c_dw_set_sda_hold(dev);
+       if (ret)
+               goto out;
+
+       switch (dev->master_cfg & DW_IC_CON_SPEED_MASK) {
+       case DW_IC_CON_SPEED_STD:
+               mode_str = "Standard Mode";
+               break;
+       case DW_IC_CON_SPEED_HIGH:
+               mode_str = "High Speed Mode";
+               break;
+       default:
+               mode_str = "Fast Mode";
        }
+       dev_dbg(dev->dev, "Bus speed: %s%s\n", mode_str, fp_str);
+
+out:
+       return ret;
+}
+
+/**
+ * i2c_dw_init() - Initialize the designware I2C master hardware
+ * @dev: device private data
+ *
+ * This functions configures and enables the I2C master.
+ * This function is called during I2C init function, and in case of timeout at
+ * run time.
+ */
+static int i2c_dw_init_master(struct dw_i2c_dev *dev)
+{
+       int ret;
+
+       ret = i2c_dw_acquire_lock(dev);
+       if (ret)
+               return ret;
+
+       /* Disable the adapter */
+       __i2c_dw_disable(dev);
+
+       /* Write standard speed timing parameters */
+       dw_writel(dev, dev->ss_hcnt, DW_IC_SS_SCL_HCNT);
+       dw_writel(dev, dev->ss_lcnt, DW_IC_SS_SCL_LCNT);
+
+       /* Write fast mode/fast mode plus timing parameters */
+       dw_writel(dev, dev->fs_hcnt, DW_IC_FS_SCL_HCNT);
+       dw_writel(dev, dev->fs_lcnt, DW_IC_FS_SCL_LCNT);
+
+       /* Write high speed timing parameters if supported */
+       if (dev->hs_hcnt && dev->hs_lcnt) {
+               dw_writel(dev, dev->hs_hcnt, DW_IC_HS_SCL_HCNT);
+               dw_writel(dev, dev->hs_lcnt, DW_IC_HS_SCL_LCNT);
+       }
+
+       /* Write SDA hold time if supported */
+       if (dev->sda_hold_time)
+               dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
 
        i2c_dw_configure_fifo_master(dev);
        i2c_dw_release_lock(dev);
@@ -681,6 +702,14 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
        dev->disable = i2c_dw_disable;
        dev->disable_int = i2c_dw_disable_int;
 
+       ret = i2c_dw_set_reg_access(dev);
+       if (ret)
+               return ret;
+
+       ret = i2c_dw_set_timings_master(dev);
+       if (ret)
+               return ret;
+
        ret = dev->init(dev);
        if (ret)
                return ret;