summaryrefslogtreecommitdiff
path: root/drivers/i2c/busses/i2c-designware-master.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c/busses/i2c-designware-master.c')
-rw-r--r--drivers/i2c/busses/i2c-designware-master.c115
1 files changed, 95 insertions, 20 deletions
diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index c7e56002809a..2569bf1a72e0 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -8,6 +8,9 @@
* Copyright (C) 2007 MontaVista Software Inc.
* Copyright (C) 2009 Provigent Ltd.
*/
+
+#define DEFAULT_SYMBOL_NAMESPACE "I2C_DW"
+
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/errno.h>
@@ -64,13 +67,16 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
if (!dev->ss_hcnt || !dev->ss_lcnt) {
ic_clk = i2c_dw_clk_rate(dev);
dev->ss_hcnt =
- i2c_dw_scl_hcnt(ic_clk,
+ i2c_dw_scl_hcnt(dev,
+ DW_IC_SS_SCL_HCNT,
+ ic_clk,
4000, /* tHD;STA = tHIGH = 4.0 us */
sda_falling_time,
- 0, /* 0: DW default, 1: Ideal */
0); /* No offset */
dev->ss_lcnt =
- i2c_dw_scl_lcnt(ic_clk,
+ i2c_dw_scl_lcnt(dev,
+ DW_IC_SS_SCL_LCNT,
+ ic_clk,
4700, /* tLOW = 4.7 us */
scl_falling_time,
0); /* No offset */
@@ -94,13 +100,16 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
} else {
ic_clk = i2c_dw_clk_rate(dev);
dev->fs_hcnt =
- i2c_dw_scl_hcnt(ic_clk,
+ i2c_dw_scl_hcnt(dev,
+ DW_IC_FS_SCL_HCNT,
+ ic_clk,
260, /* tHIGH = 260 ns */
sda_falling_time,
- 0, /* DW default */
0); /* No offset */
dev->fs_lcnt =
- i2c_dw_scl_lcnt(ic_clk,
+ i2c_dw_scl_lcnt(dev,
+ DW_IC_FS_SCL_LCNT,
+ ic_clk,
500, /* tLOW = 500 ns */
scl_falling_time,
0); /* No offset */
@@ -114,13 +123,16 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
if (!dev->fs_hcnt || !dev->fs_lcnt) {
ic_clk = i2c_dw_clk_rate(dev);
dev->fs_hcnt =
- i2c_dw_scl_hcnt(ic_clk,
+ i2c_dw_scl_hcnt(dev,
+ DW_IC_FS_SCL_HCNT,
+ ic_clk,
600, /* tHD;STA = tHIGH = 0.6 us */
sda_falling_time,
- 0, /* 0: DW default, 1: Ideal */
0); /* No offset */
dev->fs_lcnt =
- i2c_dw_scl_lcnt(ic_clk,
+ i2c_dw_scl_lcnt(dev,
+ DW_IC_FS_SCL_LCNT,
+ ic_clk,
1300, /* tLOW = 1.3 us */
scl_falling_time,
0); /* No offset */
@@ -140,16 +152,38 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
dev->hs_hcnt = 0;
dev->hs_lcnt = 0;
} else if (!dev->hs_hcnt || !dev->hs_lcnt) {
+ u32 t_high, t_low;
+
+ /*
+ * The legal values stated in the databook for bus
+ * capacitance are only 100pF and 400pF.
+ * If dev->bus_capacitance_pF is greater than or equals
+ * to 400, t_high and t_low are assumed to be
+ * appropriate values for 400pF, otherwise 100pF.
+ */
+ if (dev->bus_capacitance_pF >= 400) {
+ /* assume bus capacitance is 400pF */
+ t_high = dev->clk_freq_optimized ? 160 : 120;
+ t_low = 320;
+ } else {
+ /* assume bus capacitance is 100pF */
+ t_high = 60;
+ t_low = dev->clk_freq_optimized ? 120 : 160;
+ }
+
ic_clk = i2c_dw_clk_rate(dev);
dev->hs_hcnt =
- i2c_dw_scl_hcnt(ic_clk,
- 160, /* tHIGH = 160 ns */
+ i2c_dw_scl_hcnt(dev,
+ DW_IC_HS_SCL_HCNT,
+ ic_clk,
+ t_high,
sda_falling_time,
- 0, /* DW default */
0); /* No offset */
dev->hs_lcnt =
- i2c_dw_scl_lcnt(ic_clk,
- 320, /* tLOW = 320 ns */
+ i2c_dw_scl_lcnt(dev,
+ DW_IC_HS_SCL_LCNT,
+ ic_clk,
+ t_low,
scl_falling_time,
0); /* No offset */
}
@@ -166,12 +200,14 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
}
/**
- * i2c_dw_init_master() - Initialize the designware I2C master hardware
+ * i2c_dw_init_master() - 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.
+ *
+ * Return: 0 on success, or negative errno otherwise.
*/
static int i2c_dw_init_master(struct dw_i2c_dev *dev)
{
@@ -253,6 +289,34 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
__i2c_dw_write_intr_mask(dev, DW_IC_INTR_MASTER_MASK);
}
+/*
+ * This function waits for the controller to be idle before disabling I2C
+ * When the controller is not in the IDLE state, the MST_ACTIVITY bit
+ * (IC_STATUS[5]) is set.
+ *
+ * Values:
+ * 0x1 (ACTIVE): Controller not idle
+ * 0x0 (IDLE): Controller is idle
+ *
+ * The function is called after completing the current transfer.
+ *
+ * Returns:
+ * False when the controller is in the IDLE state.
+ * True when the controller is in the ACTIVE state.
+ */
+static bool i2c_dw_is_controller_active(struct dw_i2c_dev *dev)
+{
+ u32 status;
+
+ regmap_read(dev->map, DW_IC_STATUS, &status);
+ if (!(status & DW_IC_STATUS_MASTER_ACTIVITY))
+ return false;
+
+ return regmap_read_poll_timeout(dev->map, DW_IC_STATUS, status,
+ !(status & DW_IC_STATUS_MASTER_ACTIVITY),
+ 1100, 20000) != 0;
+}
+
static int i2c_dw_check_stopbit(struct dw_i2c_dev *dev)
{
u32 val;
@@ -311,7 +375,7 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs,
/*
* Initiate the i2c read/write transaction of buffer length,
* and poll for bus busy status. For the last message transfer,
- * update the command with stopbit enable.
+ * update the command with stop bit enable.
*/
for (msg_itr_lmt = buf_len; msg_itr_lmt > 0; msg_itr_lmt--) {
if (msg_wrt_idx == num_msgs - 1 && msg_itr_lmt == 1)
@@ -356,7 +420,7 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs,
/*
* Initiate (and continue) low level master read/write transaction.
- * This function is only called from i2c_dw_isr, and pumping i2c_msg
+ * This function is only called from i2c_dw_isr(), and pumping i2c_msg
* messages into the tx buffer. Even if the size of i2c_msg data is
* longer than the size of the tx buffer, it handles everything.
*/
@@ -394,7 +458,8 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
buf = msgs[dev->msg_write_idx].buf;
buf_len = msgs[dev->msg_write_idx].len;
- /* If both IC_EMPTYFIFO_HOLD_MASTER_EN and
+ /*
+ * If both IC_EMPTYFIFO_HOLD_MASTER_EN and
* IC_RESTART_EN are set, we must manually
* set restart bit between messages.
*/
@@ -789,6 +854,16 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
}
/*
+ * This happens rarely (~1:500) and is hard to reproduce. Debug trace
+ * showed that IC_STATUS had value of 0x23 when STOP_DET occurred,
+ * if disable IC_ENABLE.ENABLE immediately that can result in
+ * IC_RAW_INTR_STAT.MASTER_ON_HOLD holding SCL low. Check if
+ * controller is still ACTIVE before disabling I2C.
+ */
+ if (i2c_dw_is_controller_active(dev))
+ dev_err(dev->dev, "controller active\n");
+
+ /*
* We must disable the adapter before returning and signaling the end
* of the current transfer. Otherwise the hardware might continue
* generating interrupts which in turn causes a race condition with
@@ -915,7 +990,7 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev)
rinfo->unprepare_recovery = i2c_dw_unprepare_recovery;
adap->bus_recovery_info = rinfo;
- dev_info(dev->dev, "running with gpio recovery mode! scl%s",
+ dev_info(dev->dev, "running with GPIO recovery mode! scl%s",
rinfo->sda_gpiod ? ",sda" : "");
return 0;
@@ -931,7 +1006,6 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
init_completion(&dev->cmd_complete);
dev->init = i2c_dw_init_master;
- dev->disable = i2c_dw_disable;
ret = i2c_dw_init_regmap(dev);
if (ret)
@@ -1021,3 +1095,4 @@ EXPORT_SYMBOL_GPL(i2c_dw_probe_master);
MODULE_DESCRIPTION("Synopsys DesignWare I2C bus master adapter");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("I2C_DW_COMMON");