Commit 9803f868 authored by Christian Ruppert's avatar Christian Ruppert Committed by Wolfram Sang

i2c-designware: make SDA hold time configurable

This patch makes the SDA hold time configurable through device tree.
Signed-off-by: default avatarChristian Ruppert <christian.ruppert@abilis.com>
Signed-off-by: default avatarPierrick Hascoet <pierrick.hascoet@abilis.com>
Acked-by: Vineet Gupta <vgupta@synopsys.com> for arch/arc bits
Signed-off-by: default avatarWolfram Sang <wsa@the-dreams.de>
parent 4c730a06
...@@ -10,6 +10,10 @@ Recommended properties : ...@@ -10,6 +10,10 @@ Recommended properties :
- clock-frequency : desired I2C bus clock frequency in Hz. - clock-frequency : desired I2C bus clock frequency in Hz.
Optional properties :
- i2c-sda-hold-time-ns : should contain the SDA hold time in nanoseconds.
This option is only supported in hardware blocks version 1.11a or newer.
Example : Example :
i2c@f0000 { i2c@f0000 {
...@@ -20,3 +24,14 @@ Example : ...@@ -20,3 +24,14 @@ Example :
interrupts = <11>; interrupts = <11>;
clock-frequency = <400000>; clock-frequency = <400000>;
}; };
i2c@1120000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "snps,designware-i2c";
reg = <0x1120000 0x1000>;
interrupt-parent = <&ictl>;
interrupts = <12 1>;
clock-frequency = <400000>;
i2c-sda-hold-time-ns = <300>;
};
...@@ -45,19 +45,19 @@ ethernet@FE100000 { ...@@ -45,19 +45,19 @@ ethernet@FE100000 {
}; };
i2c0: i2c@FF120000 { i2c0: i2c@FF120000 {
sda-hold-time = <432>; i2c-sda-hold-time-ns = <432>;
}; };
i2c1: i2c@FF121000 { i2c1: i2c@FF121000 {
sda-hold-time = <432>; i2c-sda-hold-time-ns = <432>;
}; };
i2c2: i2c@FF122000 { i2c2: i2c@FF122000 {
sda-hold-time = <432>; i2c-sda-hold-time-ns = <432>;
}; };
i2c3: i2c@FF123000 { i2c3: i2c@FF123000 {
sda-hold-time = <432>; i2c-sda-hold-time-ns = <432>;
}; };
i2c4: i2c@FF124000 { i2c4: i2c@FF124000 {
sda-hold-time = <432>; i2c-sda-hold-time-ns = <432>;
}; };
leds { leds {
......
...@@ -45,19 +45,19 @@ ethernet@FE100000 { ...@@ -45,19 +45,19 @@ ethernet@FE100000 {
}; };
i2c0: i2c@FF120000 { i2c0: i2c@FF120000 {
sda-hold-time = <432>; i2c-sda-hold-time-ns = <432>;
}; };
i2c1: i2c@FF121000 { i2c1: i2c@FF121000 {
sda-hold-time = <432>; i2c-sda-hold-time-ns = <432>;
}; };
i2c2: i2c@FF122000 { i2c2: i2c@FF122000 {
sda-hold-time = <432>; i2c-sda-hold-time-ns = <432>;
}; };
i2c3: i2c@FF123000 { i2c3: i2c@FF123000 {
sda-hold-time = <432>; i2c-sda-hold-time-ns = <432>;
}; };
i2c4: i2c@FF124000 { i2c4: i2c@FF124000 {
sda-hold-time = <432>; i2c-sda-hold-time-ns = <432>;
}; };
leds { leds {
......
...@@ -67,9 +67,12 @@ ...@@ -67,9 +67,12 @@
#define DW_IC_STATUS 0x70 #define DW_IC_STATUS 0x70
#define DW_IC_TXFLR 0x74 #define DW_IC_TXFLR 0x74
#define DW_IC_RXFLR 0x78 #define DW_IC_RXFLR 0x78
#define DW_IC_SDA_HOLD 0x7c
#define DW_IC_TX_ABRT_SOURCE 0x80 #define DW_IC_TX_ABRT_SOURCE 0x80
#define DW_IC_ENABLE_STATUS 0x9c #define DW_IC_ENABLE_STATUS 0x9c
#define DW_IC_COMP_PARAM_1 0xf4 #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 0xfc
#define DW_IC_COMP_TYPE_VALUE 0x44570140 #define DW_IC_COMP_TYPE_VALUE 0x44570140
...@@ -332,6 +335,16 @@ int i2c_dw_init(struct dw_i2c_dev *dev) ...@@ -332,6 +335,16 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT); 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 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 */ /* Configure Tx/Rx FIFO threshold levels */
dw_writel(dev, dev->tx_fifo_depth - 1, DW_IC_TX_TL); dw_writel(dev, dev->tx_fifo_depth - 1, DW_IC_TX_TL);
dw_writel(dev, 0, DW_IC_RX_TL); dw_writel(dev, 0, DW_IC_RX_TL);
......
...@@ -90,6 +90,7 @@ struct dw_i2c_dev { ...@@ -90,6 +90,7 @@ struct dw_i2c_dev {
unsigned int tx_fifo_depth; unsigned int tx_fifo_depth;
unsigned int rx_fifo_depth; unsigned int rx_fifo_depth;
int rx_outstanding; int rx_outstanding;
u32 sda_hold_time;
}; };
#define ACCESS_SWAP 0x00000001 #define ACCESS_SWAP 0x00000001
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_i2c.h> #include <linux/of_i2c.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm.h> #include <linux/pm.h>
...@@ -115,6 +116,15 @@ static int dw_i2c_probe(struct platform_device *pdev) ...@@ -115,6 +116,15 @@ static int dw_i2c_probe(struct platform_device *pdev)
return PTR_ERR(dev->clk); return PTR_ERR(dev->clk);
clk_prepare_enable(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 = dev->functionality =
I2C_FUNC_I2C | I2C_FUNC_I2C |
I2C_FUNC_10BIT_ADDR | I2C_FUNC_10BIT_ADDR |
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment