summaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
authorChristian Ruppert <christian.ruppert@abilis.com>2013-06-26 10:55:06 +0200
committerWolfram Sang <wsa@the-dreams.de>2013-06-26 16:02:06 +0200
commit9803f868944e879c4623c0d910e81f1ae89ccfb4 (patch)
tree1dc609539e707c857b7a3e38104a6b0063847a41 /drivers/i2c
parent4c730a06c19bb83d2fa4308ee4cbb23abc84c9ca (diff)
i2c-designware: make SDA hold time configurable
This patch makes the SDA hold time configurable through device tree. Signed-off-by: Christian Ruppert <christian.ruppert@abilis.com> Signed-off-by: Pierrick Hascoet <pierrick.hascoet@abilis.com> Acked-by: Vineet Gupta <vgupta@synopsys.com> for arch/arc bits Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-designware-core.c13
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h1
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c10
3 files changed, 24 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index 3de549436992..ad46616de29e 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -67,9 +67,12 @@
#define DW_IC_STATUS 0x70
#define DW_IC_TXFLR 0x74
#define DW_IC_RXFLR 0x78
+#define DW_IC_SDA_HOLD 0x7c
#define DW_IC_TX_ABRT_SOURCE 0x80
#define DW_IC_ENABLE_STATUS 0x9c
#define DW_IC_COMP_PARAM_1 0xf4
+#define DW_IC_COMP_VERSION 0xf8
+#define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A
#define DW_IC_COMP_TYPE 0xfc
#define DW_IC_COMP_TYPE_VALUE 0x44570140
@@ -332,6 +335,16 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
+ /* Configure SDA Hold Time if required */
+ if (dev->sda_hold_time) {
+ reg = dw_readl(dev, DW_IC_COMP_VERSION);
+ if (reg >= DW_IC_SDA_HOLD_MIN_VERS)
+ dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
+ else
+ dev_warn(dev->dev,
+ "Hardware too old to adjust SDA hold time.");
+ }
+
/* Configure Tx/Rx FIFO threshold levels */
dw_writel(dev, dev->tx_fifo_depth - 1, DW_IC_TX_TL);
dw_writel(dev, 0, DW_IC_RX_TL);
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index e761ad18dd61..912aa2262866 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -90,6 +90,7 @@ struct dw_i2c_dev {
unsigned int tx_fifo_depth;
unsigned int rx_fifo_depth;
int rx_outstanding;
+ u32 sda_hold_time;
};
#define ACCESS_SWAP 0x00000001
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index ee46c92d7e3c..def79b5fd4c8 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -34,6 +34,7 @@
#include <linux/sched.h>
#include <linux/err.h>
#include <linux/interrupt.h>
+#include <linux/of.h>
#include <linux/of_i2c.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
@@ -115,6 +116,15 @@ static int dw_i2c_probe(struct platform_device *pdev)
return PTR_ERR(dev->clk);
clk_prepare_enable(dev->clk);
+ if (pdev->dev.of_node) {
+ u32 ht = 0;
+ u32 ic_clk = dev->get_clk_rate_khz(dev);
+
+ of_property_read_u32(pdev->dev.of_node,
+ "i2c-sda-hold-time-ns", &ht);
+ dev->sda_hold_time = ((u64)ic_clk * ht + 500000) / 1000000;
+ }
+
dev->functionality =
I2C_FUNC_I2C |
I2C_FUNC_10BIT_ADDR |