From: Shardar Shariff Md <[email protected]>
When I2C_HEADER_CONT_ON_NAK bit in IO header is set then “No ACK
from slave” error is not reported (NACK is considered as ACK
and transfer is continued). So if I2C_ERR_NO_ACK is set, it would
imply I2C_M_IGNORE_NAK is not set and hence this code will never
execute. When I2C_HEADER_CONT_ON_NAK bit in IO header is set then
“No ACK from slave” error is not reported.
Condition (msg->flags & I2C_M_IGNORE_NAK) will never be hit
Signed-off-by: Shardar Shariff Md <[email protected]>
Signed-off-by: Krishna Yarlagadda <[email protected]>
---
drivers/i2c/busses/i2c-tegra.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 1577296..c6c870c 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -1336,11 +1336,8 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
return -EAGAIN;
}
- if (i2c_dev->msg_err == I2C_ERR_NO_ACK) {
- if (msg->flags & I2C_M_IGNORE_NAK)
- return 0;
+ if (i2c_dev->msg_err == I2C_ERR_NO_ACK)
return -EREMOTEIO;
- }
return -EIO;
}
--
2.7.4
From: Shardar Shariff Md <[email protected]>
Assign controller id with adapter number as it (cont_id) is passed
through DT(through alias). Mask with controller id mask to avoid
overflow other fields when single device is present and id is -1.
Signed-off-by: Shardar Shariff Md <[email protected]>
Signed-off-by: Krishna Yarlagadda <[email protected]>
---
drivers/i2c/busses/i2c-tegra.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index c6c870c..a841d6c 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -83,6 +83,7 @@
#define PACKET_HEADER0_CONT_ID GENMASK(15, 12)
#define PACKET_HEADER0_PROTOCOL GENMASK(7, 4)
#define PACKET_HEADER0_PROTOCOL_I2C 1
+#define PACKET_HEADER0_CONT_ID_MASK 0xF
#define I2C_HEADER_CONT_ON_NAK BIT(21)
#define I2C_HEADER_READ BIT(19)
@@ -1669,7 +1670,6 @@ static int tegra_i2c_probe(struct platform_device *pdev)
i2c_dev->adapter.retries = 1;
i2c_dev->adapter.timeout = 6 * HZ;
i2c_dev->irq = irq;
- i2c_dev->cont_id = pdev->id;
i2c_dev->dev = &pdev->dev;
i2c_dev->rst = devm_reset_control_get_exclusive(&pdev->dev, "i2c");
@@ -1807,6 +1807,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
if (ret)
goto release_dma;
+ i2c_dev->cont_id = i2c_dev->adapter.nr & PACKET_HEADER0_CONT_ID_MASK;
pm_runtime_put(&pdev->dev);
return 0;
--
2.7.4
In chips earlier to Tegra186, register write gets buffered. So to make
sure register writes are completed, there is need to readback the
register. Adding flag to disable this readback for Tegra186 and later
chips.
Signed-off-by: Krishna Yarlagadda <[email protected]>
---
drivers/i2c/busses/i2c-tegra.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index a841d6c..bdbbca0 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -220,6 +220,7 @@ struct tegra_i2c_hw_feature {
bool has_mst_fifo;
const struct i2c_adapter_quirks *quirks;
bool supports_bus_clear;
+ bool has_reg_write_buffering;
bool has_apb_dma;
u8 tlow_std_mode;
u8 thigh_std_mode;
@@ -325,8 +326,11 @@ static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
writel_relaxed(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
/* Read back register to make sure that register writes completed */
- if (reg != I2C_TX_FIFO)
- readl_relaxed(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
+ if (i2c_dev->hw->has_reg_write_buffering) {
+ if (reg != I2C_TX_FIFO)
+ readl_relaxed(i2c_dev->base +
+ tegra_i2c_reg_addr(i2c_dev, reg));
+ }
}
static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
@@ -1450,6 +1454,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
.has_mst_fifo = false,
.quirks = &tegra_i2c_quirks,
.supports_bus_clear = false,
+ .has_reg_write_buffering = true,
.has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
@@ -1475,6 +1480,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
.has_mst_fifo = false,
.quirks = &tegra_i2c_quirks,
.supports_bus_clear = false,
+ .has_reg_write_buffering = true,
.has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
@@ -1500,6 +1506,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
.has_mst_fifo = false,
.quirks = &tegra_i2c_quirks,
.supports_bus_clear = true,
+ .has_reg_write_buffering = true,
.has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
@@ -1525,6 +1532,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
.has_mst_fifo = false,
.quirks = &tegra_i2c_quirks,
.supports_bus_clear = true,
+ .has_reg_write_buffering = true,
.has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
@@ -1550,6 +1558,7 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
.has_mst_fifo = false,
.quirks = &tegra_i2c_quirks,
.supports_bus_clear = true,
+ .has_reg_write_buffering = true,
.has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
@@ -1575,6 +1584,7 @@ static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
.has_mst_fifo = false,
.quirks = &tegra_i2c_quirks,
.supports_bus_clear = true,
+ .has_reg_write_buffering = false,
.has_apb_dma = false,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x3,
@@ -1600,6 +1610,7 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
.has_mst_fifo = true,
.quirks = &tegra194_i2c_quirks,
.supports_bus_clear = true,
+ .has_reg_write_buffering = false,
.has_apb_dma = false,
.tlow_std_mode = 0x8,
.thigh_std_mode = 0x7,
--
2.7.4
Enable Second Level Clock Gating feature for supported chips.
With SLCG enabled, software need not control clocks anymore
and leave clocks enabled always on.
Signed-off-by: Shardar Shariff Md <[email protected]>
Signed-off-by: Laxman Dewangan <[email protected]>
Signed-off-by: Krishna Yarlagadda <[email protected]>
---
drivers/i2c/busses/i2c-tegra.c | 32 ++++++++++++++++++++++++++++----
1 file changed, 28 insertions(+), 4 deletions(-)
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 2f654ed..8ab968e 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -235,6 +235,7 @@ struct tegra_i2c_hw_feature {
u32 setup_hold_time_fast_fast_plus_mode;
u32 setup_hold_time_hs_mode;
bool has_interface_timing_reg;
+ bool has_slcg_support;
};
/**
@@ -299,6 +300,7 @@ struct tegra_i2c_dev {
struct completion dma_complete;
bool is_curr_atomic_xfer;
int clk_divisor_hs_mode;
+ bool is_clkon_always;
};
static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
@@ -1478,6 +1480,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
.supports_bus_clear = false,
.has_reg_write_buffering = true,
.has_hs_mode_support = false,
+ .has_slcg_support = false,
.has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
@@ -1506,6 +1509,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
.supports_bus_clear = false,
.has_reg_write_buffering = true,
.has_hs_mode_support = false,
+ .has_slcg_support = false,
.has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
@@ -1534,6 +1538,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
.supports_bus_clear = true,
.has_reg_write_buffering = true,
.has_hs_mode_support = false,
+ .has_slcg_support = false,
.has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
@@ -1562,6 +1567,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
.supports_bus_clear = true,
.has_reg_write_buffering = true,
.has_hs_mode_support = false,
+ .has_slcg_support = false,
.has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
@@ -1590,6 +1596,7 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
.supports_bus_clear = true,
.has_reg_write_buffering = true,
.has_hs_mode_support = false,
+ .has_slcg_support = false,
.has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
@@ -1618,6 +1625,7 @@ static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
.supports_bus_clear = true,
.has_reg_write_buffering = false,
.has_hs_mode_support = false,
+ .has_slcg_support = true,
.has_apb_dma = false,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x3,
@@ -1646,6 +1654,7 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
.supports_bus_clear = true,
.has_reg_write_buffering = false,
.has_hs_mode_support = true,
+ .has_slcg_support = true,
.has_apb_dma = false,
.tlow_std_mode = 0x8,
.thigh_std_mode = 0x7,
@@ -1822,7 +1831,12 @@ static int tegra_i2c_probe(struct platform_device *pdev)
}
}
- if (i2c_dev->is_multimaster_mode) {
+ if (i2c_dev->is_multimaster_mode || i2c_dev->hw->has_slcg_support)
+ i2c_dev->is_clkon_always = true;
+ else
+ i2c_dev->is_clkon_always = false;
+
+ if (i2c_dev->is_clkon_always) {
ret = clk_enable(i2c_dev->div_clk);
if (ret < 0) {
dev_err(i2c_dev->dev, "div_clk enable failed %d\n",
@@ -1875,7 +1889,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
tegra_i2c_release_dma(i2c_dev);
disable_div_clk:
- if (i2c_dev->is_multimaster_mode)
+ if (i2c_dev->is_clkon_always)
clk_disable(i2c_dev->div_clk);
put_rpm:
@@ -1908,7 +1922,7 @@ static int tegra_i2c_remove(struct platform_device *pdev)
i2c_del_adapter(&i2c_dev->adapter);
- if (i2c_dev->is_multimaster_mode)
+ if (i2c_dev->is_clkon_always)
clk_disable(i2c_dev->div_clk);
pm_runtime_disable(&pdev->dev);
@@ -1932,7 +1946,8 @@ static int __maybe_unused tegra_i2c_suspend(struct device *dev)
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
int err = 0;
- i2c_mark_adapter_suspended(&i2c_dev->adapter);
+ if (i2c_dev->is_clkon_always)
+ clk_disable(i2c_dev->div_clk);
if (!pm_runtime_status_suspended(dev))
err = tegra_i2c_runtime_suspend(dev);
@@ -1968,6 +1983,15 @@ static int __maybe_unused tegra_i2c_resume(struct device *dev)
return err;
}
+ if (i2c_dev->is_clkon_always) {
+ err = clk_enable(i2c_dev->div_clk);
+ if (err < 0) {
+ dev_err(i2c_dev->dev, "clock enable failed %d\n",
+ err);
+ return err;
+ }
+ }
+
i2c_mark_adapter_resumed(&i2c_dev->adapter);
return 0;
--
2.7.4
From: Shardar Shariff Md <[email protected]>
Add high speed mode support
Signed-off-by: Shardar Shariff Md <[email protected]>
Signed-off-by: Laxman Dewangan <[email protected]>
Signed-off-by: Krishna Yarlagadda <[email protected]>
---
drivers/i2c/busses/i2c-tegra.c | 64 ++++++++++++++++++++++++++++++++++++------
1 file changed, 56 insertions(+), 8 deletions(-)
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index bdbbca0..2f654ed 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -85,12 +85,14 @@
#define PACKET_HEADER0_PROTOCOL_I2C 1
#define PACKET_HEADER0_CONT_ID_MASK 0xF
+#define I2C_HEADER_HIGHSPEED_MODE BIT(22)
#define I2C_HEADER_CONT_ON_NAK BIT(21)
#define I2C_HEADER_READ BIT(19)
#define I2C_HEADER_10BIT_ADDR BIT(18)
#define I2C_HEADER_IE_ENABLE BIT(17)
#define I2C_HEADER_REPEAT_START BIT(16)
#define I2C_HEADER_CONTINUE_XFER BIT(15)
+#define I2C_HEADER_MASTER_ADDR_SHIFT 12
#define I2C_HEADER_SLAVE_ADDR_SHIFT 1
#define I2C_BUS_CLEAR_CNFG 0x084
@@ -136,6 +138,7 @@
/* configuration load timeout in microseconds */
#define I2C_CONFIG_LOAD_TIMEOUT 1000000
+#define I2C_HS_MODE 3500000
/* Packet header size in bytes */
#define I2C_PACKET_HEADER_SIZE 12
@@ -215,12 +218,14 @@ struct tegra_i2c_hw_feature {
int clk_divisor_std_mode;
int clk_divisor_fast_mode;
u16 clk_divisor_fast_plus_mode;
+ int clk_multiplier_hs_mode;
bool has_multi_master_mode;
bool has_slcg_override_reg;
bool has_mst_fifo;
const struct i2c_adapter_quirks *quirks;
bool supports_bus_clear;
bool has_reg_write_buffering;
+ bool has_hs_mode_support;
bool has_apb_dma;
u8 tlow_std_mode;
u8 thigh_std_mode;
@@ -293,6 +298,7 @@ struct tegra_i2c_dev {
bool is_curr_dma_xfer;
struct completion dma_complete;
bool is_curr_atomic_xfer;
+ int clk_divisor_hs_mode;
};
static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
@@ -778,8 +784,9 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
if (i2c_dev->is_dvc)
tegra_dvc_init(i2c_dev);
- val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN |
- FIELD_PREP(I2C_CNFG_DEBOUNCE_CNT, 2);
+ val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN;
+ if (i2c_dev->bus_clk_rate != I2C_HS_MODE)
+ val |= FIELD_PREP(I2C_CNFG_DEBOUNCE_CNT, 0x2);
if (i2c_dev->hw->has_multi_master_mode)
val |= I2C_CNFG_MULTI_MASTER_MODE;
@@ -791,6 +798,13 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
tegra_i2c_vi_init(i2c_dev);
/* Make sure clock divisor programmed correctly */
+ if (i2c_dev->bus_clk_rate == I2C_HS_MODE) {
+ i2c_dev->clk_divisor_hs_mode = i2c_dev->hw->clk_divisor_hs_mode;
+ } else {
+ val = i2c_readl(i2c_dev, I2C_CLK_DIVISOR);
+ i2c_dev->clk_divisor_hs_mode = FIELD_PREP(I2C_CLK_DIVISOR_HSMODE, val);
+ }
+
clk_divisor = FIELD_PREP(I2C_CLK_DIVISOR_HSMODE,
i2c_dev->hw->clk_divisor_hs_mode) |
FIELD_PREP(I2C_CLK_DIVISOR_STD_FAST_MODE,
@@ -822,8 +836,13 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
i2c_writel(i2c_dev, tsu_thd, I2C_INTERFACE_TIMING_1);
if (!clk_reinit) {
- clk_multiplier = (tlow + thigh + 2);
- clk_multiplier *= (i2c_dev->clk_divisor_non_hs_mode + 1);
+ if (i2c_dev->bus_clk_rate == I2C_HS_MODE) {
+ clk_multiplier = i2c_dev->hw->clk_multiplier_hs_mode;
+ clk_multiplier *= (i2c_dev->clk_divisor_hs_mode + 1);
+ } else {
+ clk_multiplier = (tlow + thigh + 2);
+ clk_multiplier *= (i2c_dev->clk_divisor_non_hs_mode + 1);
+ }
err = clk_set_rate(i2c_dev->div_clk,
i2c_dev->bus_clk_rate * clk_multiplier);
if (err) {
@@ -1244,6 +1263,8 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
packet_header |= I2C_HEADER_CONT_ON_NAK;
if (msg->flags & I2C_M_RD)
packet_header |= I2C_HEADER_READ;
+ if (i2c_dev->bus_clk_rate == I2C_HS_MODE)
+ packet_header |= I2C_HEADER_HIGHSPEED_MODE;
if (dma && !i2c_dev->msg_read)
*buffer++ = packet_header;
else
@@ -1448,6 +1469,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
.clk_divisor_std_mode = 0,
.clk_divisor_fast_mode = 0,
.clk_divisor_fast_plus_mode = 0,
+ .clk_multiplier_hs_mode = 12,
.has_config_load_reg = false,
.has_multi_master_mode = false,
.has_slcg_override_reg = false,
@@ -1455,6 +1477,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
.quirks = &tegra_i2c_quirks,
.supports_bus_clear = false,
.has_reg_write_buffering = true,
+ .has_hs_mode_support = false,
.has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
@@ -1474,6 +1497,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
.clk_divisor_std_mode = 0,
.clk_divisor_fast_mode = 0,
.clk_divisor_fast_plus_mode = 0,
+ .clk_multiplier_hs_mode = 12,
.has_config_load_reg = false,
.has_multi_master_mode = false,
.has_slcg_override_reg = false,
@@ -1481,6 +1505,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
.quirks = &tegra_i2c_quirks,
.supports_bus_clear = false,
.has_reg_write_buffering = true,
+ .has_hs_mode_support = false,
.has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
@@ -1500,6 +1525,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
.clk_divisor_std_mode = 0x19,
.clk_divisor_fast_mode = 0x19,
.clk_divisor_fast_plus_mode = 0x10,
+ .clk_multiplier_hs_mode = 3,
.has_config_load_reg = false,
.has_multi_master_mode = false,
.has_slcg_override_reg = false,
@@ -1507,6 +1533,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
.quirks = &tegra_i2c_quirks,
.supports_bus_clear = true,
.has_reg_write_buffering = true,
+ .has_hs_mode_support = false,
.has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
@@ -1522,10 +1549,11 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
.has_continue_xfer_support = true,
.has_per_pkt_xfer_complete_irq = true,
.has_single_clk_source = true,
- .clk_divisor_hs_mode = 1,
+ .clk_divisor_hs_mode = 2,
.clk_divisor_std_mode = 0x19,
.clk_divisor_fast_mode = 0x19,
.clk_divisor_fast_plus_mode = 0x10,
+ .clk_multiplier_hs_mode = 13,
.has_config_load_reg = true,
.has_multi_master_mode = false,
.has_slcg_override_reg = true,
@@ -1533,6 +1561,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
.quirks = &tegra_i2c_quirks,
.supports_bus_clear = true,
.has_reg_write_buffering = true,
+ .has_hs_mode_support = false,
.has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
@@ -1548,10 +1577,11 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
.has_continue_xfer_support = true,
.has_per_pkt_xfer_complete_irq = true,
.has_single_clk_source = true,
- .clk_divisor_hs_mode = 1,
+ .clk_divisor_hs_mode = 2,
.clk_divisor_std_mode = 0x19,
.clk_divisor_fast_mode = 0x19,
.clk_divisor_fast_plus_mode = 0x10,
+ .clk_multiplier_hs_mode = 13,
.has_config_load_reg = true,
.has_multi_master_mode = false,
.has_slcg_override_reg = true,
@@ -1559,6 +1589,7 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
.quirks = &tegra_i2c_quirks,
.supports_bus_clear = true,
.has_reg_write_buffering = true,
+ .has_hs_mode_support = false,
.has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
@@ -1574,10 +1605,11 @@ static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
.has_continue_xfer_support = true,
.has_per_pkt_xfer_complete_irq = true,
.has_single_clk_source = true,
- .clk_divisor_hs_mode = 1,
+ .clk_divisor_hs_mode = 2,
.clk_divisor_std_mode = 0x16,
.clk_divisor_fast_mode = 0x19,
.clk_divisor_fast_plus_mode = 0x10,
+ .clk_multiplier_hs_mode = 13,
.has_config_load_reg = true,
.has_multi_master_mode = false,
.has_slcg_override_reg = true,
@@ -1585,6 +1617,7 @@ static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
.quirks = &tegra_i2c_quirks,
.supports_bus_clear = true,
.has_reg_write_buffering = false,
+ .has_hs_mode_support = false,
.has_apb_dma = false,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x3,
@@ -1600,10 +1633,11 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
.has_continue_xfer_support = true,
.has_per_pkt_xfer_complete_irq = true,
.has_single_clk_source = true,
- .clk_divisor_hs_mode = 1,
+ .clk_divisor_hs_mode = 2,
.clk_divisor_std_mode = 0x4f,
.clk_divisor_fast_mode = 0x3c,
.clk_divisor_fast_plus_mode = 0x16,
+ .clk_multiplier_hs_mode = 13,
.has_config_load_reg = true,
.has_multi_master_mode = true,
.has_slcg_override_reg = true,
@@ -1611,6 +1645,7 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
.quirks = &tegra194_i2c_quirks,
.supports_bus_clear = true,
.has_reg_write_buffering = false,
+ .has_hs_mode_support = true,
.has_apb_dma = false,
.tlow_std_mode = 0x8,
.thigh_std_mode = 0x7,
@@ -1694,8 +1729,21 @@ static int tegra_i2c_probe(struct platform_device *pdev)
i2c_dev->hw = of_device_get_match_data(&pdev->dev);
i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node,
"nvidia,tegra20-i2c-dvc");
+
+ i2c_dev->hw = of_device_get_match_data(&pdev->dev);
i2c_dev->is_vi = of_device_is_compatible(dev->of_node,
"nvidia,tegra210-i2c-vi");
+ if (i2c_dev->bus_clk_rate == I2C_HS_MODE &&
+ !i2c_dev->hw->has_hs_mode_support) {
+ dev_info(i2c_dev->dev, "HS mode not supported\n");
+ i2c_dev->bus_clk_rate = 100000; /* default clock rate */
+ }
+
+ if (i2c_dev->is_multimaster_mode &&
+ !i2c_dev->hw->has_multi_master_mode) {
+ dev_info(i2c_dev->dev, "multi-master mode not supported\n");
+ i2c_dev->is_multimaster_mode = false;
+ }
i2c_dev->adapter.quirks = i2c_dev->hw->quirks;
i2c_dev->dma_buf_size = i2c_dev->adapter.quirks->max_write_len +
I2C_PACKET_HEADER_SIZE;
--
2.7.4
Enable GPC DMA support for Tegra186 and Tegra194
Signed-off-by: Rajesh Gumasta <[email protected]>
Signed-off-by: Krishna Yarlagadda <[email protected]>
---
drivers/i2c/busses/i2c-tegra.c | 25 ++++++++++++++++++++-----
1 file changed, 20 insertions(+), 5 deletions(-)
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 8ab968e..77198fc 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -236,6 +236,7 @@ struct tegra_i2c_hw_feature {
u32 setup_hold_time_hs_mode;
bool has_interface_timing_reg;
bool has_slcg_support;
+ bool has_gpc_dma;
};
/**
@@ -432,11 +433,18 @@ static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev)
dma_addr_t dma_phys;
int err;
- if (!i2c_dev->hw->has_apb_dma)
- return 0;
-
- if (!IS_ENABLED(CONFIG_TEGRA20_APB_DMA)) {
- dev_dbg(i2c_dev->dev, "Support for APB DMA not enabled!\n");
+ if (i2c_dev->hw->has_gpc_dma) {
+ if (!IS_ENABLED(CONFIG_TEGRA_GPC_DMA)) {
+ dev_dbg(i2c_dev->dev, "Support for GPC DMA not enabled!\n");
+ return 0;
+ }
+ } else if (i2c_dev->hw->has_apb_dma) {
+ if (!IS_ENABLED(CONFIG_TEGRA20_APB_DMA)) {
+ dev_dbg(i2c_dev->dev, "Support for APB DMA not enabled!\n");
+ return 0;
+ }
+ } else {
+ dev_dbg(i2c_dev->dev, "DMA is not enabled!\n");
return 0;
}
@@ -1490,6 +1498,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
.setup_hold_time_fast_fast_plus_mode = 0x0,
.setup_hold_time_hs_mode = 0x0,
.has_interface_timing_reg = false,
+ .has_gpc_dma = false,
};
static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
@@ -1519,6 +1528,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
.setup_hold_time_fast_fast_plus_mode = 0x0,
.setup_hold_time_hs_mode = 0x0,
.has_interface_timing_reg = false,
+ .has_gpc_dma = false,
};
static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
@@ -1548,6 +1558,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
.setup_hold_time_fast_fast_plus_mode = 0x0,
.setup_hold_time_hs_mode = 0x0,
.has_interface_timing_reg = false,
+ .has_gpc_dma = false,
};
static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
@@ -1577,6 +1588,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
.setup_hold_time_fast_fast_plus_mode = 0x0,
.setup_hold_time_hs_mode = 0x0,
.has_interface_timing_reg = true,
+ .has_gpc_dma = false,
};
static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
@@ -1606,6 +1618,7 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
.setup_hold_time_fast_fast_plus_mode = 0,
.setup_hold_time_hs_mode = 0,
.has_interface_timing_reg = true,
+ .has_gpc_dma = true,
};
static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
@@ -1635,6 +1648,7 @@ static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
.setup_hold_time_fast_fast_plus_mode = 0,
.setup_hold_time_hs_mode = 0,
.has_interface_timing_reg = true,
+ .has_gpc_dma = true,
};
static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
@@ -1664,6 +1678,7 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
.setup_hold_time_fast_fast_plus_mode = 0x02020202,
.setup_hold_time_hs_mode = 0x090909,
.has_interface_timing_reg = true,
+ .has_gpc_dma = true,
};
/* Match table for of_platform binding */
--
2.7.4
From: Rajesh Gumasta <[email protected]>
Dump I2C regsiters for debug when transfer timeout occurs.
Signed-off-by: Rajesh Gumasta <[email protected]>
Signed-off-by: Krishna Yarlagadda <[email protected]>
---
drivers/i2c/busses/i2c-tegra.c | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 77198fc..cdc8664 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -126,6 +126,8 @@
#define I2C_HS_INTERFACE_TIMING_THD_STA GENMASK(13, 8)
#define I2C_HS_INTERFACE_TIMING_TSU_STA GENMASK(5, 0)
+#define I2C_MST_PACKET_TRANSFER_CNT_STATUS 0x0b0
+
#define I2C_MST_FIFO_CONTROL 0x0b4
#define I2C_MST_FIFO_CONTROL_RX_FLUSH BIT(0)
#define I2C_MST_FIFO_CONTROL_TX_FLUSH BIT(1)
@@ -1178,6 +1180,33 @@ static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
return -EAGAIN;
}
+static void tegra_i2c_reg_dump(struct tegra_i2c_dev *i2c_dev)
+{
+ dev_dbg(i2c_dev->dev, "--- register dump for debugging ----\n");
+ dev_dbg(i2c_dev->dev, "I2C_CNFG - 0x%x\n",
+ i2c_readl(i2c_dev, I2C_CNFG));
+ dev_dbg(i2c_dev->dev, "I2C_PACKET_TRANSFER_STATUS - 0x%x\n",
+ i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS));
+ dev_dbg(i2c_dev->dev, "I2C_FIFO_CONTROL - 0x%x\n",
+ i2c_readl(i2c_dev, I2C_FIFO_CONTROL));
+ dev_dbg(i2c_dev->dev, "I2C_FIFO_STATUS - 0x%x\n",
+ i2c_readl(i2c_dev, I2C_FIFO_STATUS));
+
+ if (i2c_dev->hw->has_mst_fifo) {
+ dev_dbg(i2c_dev->dev, "I2C_MST_FIFO_CONTROL - 0x%x\n",
+ i2c_readl(i2c_dev, I2C_MST_FIFO_CONTROL));
+ dev_dbg(i2c_dev->dev, "I2C_MST_FIFO_STATUS - 0x%x\n",
+ i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS));
+ dev_dbg(i2c_dev->dev, "I2C_MST_PACKET_TRANSFER_CNT - 0x%x\n",
+ i2c_readl(i2c_dev,
+ I2C_MST_PACKET_TRANSFER_CNT_STATUS));
+ }
+ dev_dbg(i2c_dev->dev, "I2C_INT_MASK - 0x%x\n",
+ i2c_readl(i2c_dev, I2C_INT_MASK));
+ dev_dbg(i2c_dev->dev, "I2C_INT_STATUS - 0x%x\n",
+ i2c_readl(i2c_dev, I2C_INT_STATUS));
+}
+
static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
struct i2c_msg *msg,
enum msg_end_type end_state)
@@ -1331,6 +1360,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
if (!time_left && !completion_done(&i2c_dev->dma_complete)) {
dev_err(i2c_dev->dev, "DMA transfer timeout\n");
+ tegra_i2c_reg_dump(i2c_dev);
tegra_i2c_init(i2c_dev, true);
return -ETIMEDOUT;
}
@@ -1352,6 +1382,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
if (time_left == 0) {
dev_err(i2c_dev->dev, "i2c transfer timed out\n");
+ tegra_i2c_reg_dump(i2c_dev);
tegra_i2c_init(i2c_dev, true);
return -ETIMEDOUT;
}
--
2.7.4
Hello Krishna,
23.07.2020 15:18, Krishna Yarlagadda пишет:
...
> static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
> @@ -1606,6 +1618,7 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
> .setup_hold_time_fast_fast_plus_mode = 0,
> .setup_hold_time_hs_mode = 0,
> .has_interface_timing_reg = true,
> + .has_gpc_dma = true,
false
> };
23.07.2020 15:18, Krishna Yarlagadda пишет:
> In chips earlier to Tegra186, register write gets buffered. So to make
> sure register writes are completed, there is need to readback the
> register. Adding flag to disable this readback for Tegra186 and later
> chips.
>
> Signed-off-by: Krishna Yarlagadda <[email protected]>
> ---
> drivers/i2c/busses/i2c-tegra.c | 15 +++++++++++++--
> 1 file changed, 13 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
> index a841d6c..bdbbca0 100644
> --- a/drivers/i2c/busses/i2c-tegra.c
> +++ b/drivers/i2c/busses/i2c-tegra.c
> @@ -220,6 +220,7 @@ struct tegra_i2c_hw_feature {
> bool has_mst_fifo;
> const struct i2c_adapter_quirks *quirks;
> bool supports_bus_clear;
> + bool has_reg_write_buffering;
> bool has_apb_dma;
> u8 tlow_std_mode;
> u8 thigh_std_mode;
> @@ -325,8 +326,11 @@ static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
> writel_relaxed(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
>
> /* Read back register to make sure that register writes completed */
> - if (reg != I2C_TX_FIFO)
> - readl_relaxed(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
> + if (i2c_dev->hw->has_reg_write_buffering) {
> + if (reg != I2C_TX_FIFO)
Should be single line.
What problem does this solve? If there is no visible effect, then please
drop this patch.
> + readl_relaxed(i2c_dev->base +
> + tegra_i2c_reg_addr(i2c_dev, reg));
> + }
23.07.2020 15:18, Krishna Yarlagadda пишет:
> From: Shardar Shariff Md <[email protected]>
>
> Add high speed mode support
>
> Signed-off-by: Shardar Shariff Md <[email protected]>
> Signed-off-by: Laxman Dewangan <[email protected]>
> Signed-off-by: Krishna Yarlagadda <[email protected]>
> ---
> drivers/i2c/busses/i2c-tegra.c | 64 ++++++++++++++++++++++++++++++++++++------
> 1 file changed, 56 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
> index bdbbca0..2f654ed 100644
> --- a/drivers/i2c/busses/i2c-tegra.c
> +++ b/drivers/i2c/busses/i2c-tegra.c
> @@ -85,12 +85,14 @@
> #define PACKET_HEADER0_PROTOCOL_I2C 1
> #define PACKET_HEADER0_CONT_ID_MASK 0xF
>
> +#define I2C_HEADER_HIGHSPEED_MODE BIT(22)
> #define I2C_HEADER_CONT_ON_NAK BIT(21)
> #define I2C_HEADER_READ BIT(19)
> #define I2C_HEADER_10BIT_ADDR BIT(18)
> #define I2C_HEADER_IE_ENABLE BIT(17)
> #define I2C_HEADER_REPEAT_START BIT(16)
> #define I2C_HEADER_CONTINUE_XFER BIT(15)
> +#define I2C_HEADER_MASTER_ADDR_SHIFT 12
> #define I2C_HEADER_SLAVE_ADDR_SHIFT 1
>
> #define I2C_BUS_CLEAR_CNFG 0x084
> @@ -136,6 +138,7 @@
>
> /* configuration load timeout in microseconds */
> #define I2C_CONFIG_LOAD_TIMEOUT 1000000
> +#define I2C_HS_MODE 3500000
The I2C_MAX_HIGH_SPEED_MODE_FREQ is 3400000, what is 3500000 then?
https://elixir.bootlin.com/linux/v5.8-rc4/source/include/linux/i2c.h#L42
> /* Packet header size in bytes */
> #define I2C_PACKET_HEADER_SIZE 12
> @@ -215,12 +218,14 @@ struct tegra_i2c_hw_feature {
> int clk_divisor_std_mode;
> int clk_divisor_fast_mode;
> u16 clk_divisor_fast_plus_mode;
> + int clk_multiplier_hs_mode;
> bool has_multi_master_mode;
> bool has_slcg_override_reg;
> bool has_mst_fifo;
> const struct i2c_adapter_quirks *quirks;
> bool supports_bus_clear;
> bool has_reg_write_buffering;
> + bool has_hs_mode_support;
> bool has_apb_dma;
> u8 tlow_std_mode;
> u8 thigh_std_mode;
> @@ -293,6 +298,7 @@ struct tegra_i2c_dev {
> bool is_curr_dma_xfer;
> struct completion dma_complete;
> bool is_curr_atomic_xfer;
> + int clk_divisor_hs_mode;
> };
>
> static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
> @@ -778,8 +784,9 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
> if (i2c_dev->is_dvc)
> tegra_dvc_init(i2c_dev);
>
> - val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN |
> - FIELD_PREP(I2C_CNFG_DEBOUNCE_CNT, 2);
> + val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN;
> + if (i2c_dev->bus_clk_rate != I2C_HS_MODE)
> + val |= FIELD_PREP(I2C_CNFG_DEBOUNCE_CNT, 0x2);
>
> if (i2c_dev->hw->has_multi_master_mode)
> val |= I2C_CNFG_MULTI_MASTER_MODE;
> @@ -791,6 +798,13 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
> tegra_i2c_vi_init(i2c_dev);
>
> /* Make sure clock divisor programmed correctly */
> + if (i2c_dev->bus_clk_rate == I2C_HS_MODE) {
> + i2c_dev->clk_divisor_hs_mode = i2c_dev->hw->clk_divisor_hs_mode;
> + } else {
> + val = i2c_readl(i2c_dev, I2C_CLK_DIVISOR);
> + i2c_dev->clk_divisor_hs_mode = FIELD_PREP(I2C_CLK_DIVISOR_HSMODE, val);
FIELD_PREP?
clk_divisor_hs_mode should be a local variable and I don't think its
value needs to be read out from hardware.
> + }
> +
> clk_divisor = FIELD_PREP(I2C_CLK_DIVISOR_HSMODE,
> i2c_dev->hw->clk_divisor_hs_mode) |
> FIELD_PREP(I2C_CLK_DIVISOR_STD_FAST_MODE,
> @@ -822,8 +836,13 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
> i2c_writel(i2c_dev, tsu_thd, I2C_INTERFACE_TIMING_1);
>
> if (!clk_reinit) {
> - clk_multiplier = (tlow + thigh + 2);
> - clk_multiplier *= (i2c_dev->clk_divisor_non_hs_mode + 1);
> + if (i2c_dev->bus_clk_rate == I2C_HS_MODE) {
> + clk_multiplier = i2c_dev->hw->clk_multiplier_hs_mode;
> + clk_multiplier *= (i2c_dev->clk_divisor_hs_mode + 1);
Actually, clk_divisor_hs_mode variable shouldn't be needed at all, use
hw->clk_divisor_hs_mode directly.
> + } else {
> + clk_multiplier = (tlow + thigh + 2);
> + clk_multiplier *= (i2c_dev->clk_divisor_non_hs_mode + 1);
> + }
> err = clk_set_rate(i2c_dev->div_clk,
> i2c_dev->bus_clk_rate * clk_multiplier);
> if (err) {
> @@ -1244,6 +1263,8 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
> packet_header |= I2C_HEADER_CONT_ON_NAK;
> if (msg->flags & I2C_M_RD)
> packet_header |= I2C_HEADER_READ;
> + if (i2c_dev->bus_clk_rate == I2C_HS_MODE)
> + packet_header |= I2C_HEADER_HIGHSPEED_MODE;
> if (dma && !i2c_dev->msg_read)
> *buffer++ = packet_header;
> else
> @@ -1448,6 +1469,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
> .clk_divisor_std_mode = 0,
> .clk_divisor_fast_mode = 0,
> .clk_divisor_fast_plus_mode = 0,
> + .clk_multiplier_hs_mode = 12,
> .has_config_load_reg = false,
> .has_multi_master_mode = false,
> .has_slcg_override_reg = false,
> @@ -1455,6 +1477,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
> .quirks = &tegra_i2c_quirks,
> .supports_bus_clear = false,
> .has_reg_write_buffering = true,
> + .has_hs_mode_support = false,
> .has_apb_dma = true,
> .tlow_std_mode = 0x4,
> .thigh_std_mode = 0x2,
> @@ -1474,6 +1497,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
> .clk_divisor_std_mode = 0,
> .clk_divisor_fast_mode = 0,
> .clk_divisor_fast_plus_mode = 0,
> + .clk_multiplier_hs_mode = 12,
> .has_config_load_reg = false,
> .has_multi_master_mode = false,
> .has_slcg_override_reg = false,
> @@ -1481,6 +1505,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
> .quirks = &tegra_i2c_quirks,
> .supports_bus_clear = false,
> .has_reg_write_buffering = true,
> + .has_hs_mode_support = false,
> .has_apb_dma = true,
> .tlow_std_mode = 0x4,
> .thigh_std_mode = 0x2,
> @@ -1500,6 +1525,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
> .clk_divisor_std_mode = 0x19,
> .clk_divisor_fast_mode = 0x19,
> .clk_divisor_fast_plus_mode = 0x10,
> + .clk_multiplier_hs_mode = 3,
3?
> .has_config_load_reg = false,
> .has_multi_master_mode = false,
> .has_slcg_override_reg = false,
> @@ -1507,6 +1533,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
> .quirks = &tegra_i2c_quirks,
> .supports_bus_clear = true,
> .has_reg_write_buffering = true,
> + .has_hs_mode_support = false,
> .has_apb_dma = true,
> .tlow_std_mode = 0x4,
> .thigh_std_mode = 0x2,
> @@ -1522,10 +1549,11 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
> .has_continue_xfer_support = true,
> .has_per_pkt_xfer_complete_irq = true,
> .has_single_clk_source = true,
> - .clk_divisor_hs_mode = 1,
> + .clk_divisor_hs_mode = 2,
Why are you changing this?
...
> + if (i2c_dev->bus_clk_rate == I2C_HS_MODE &&
> + !i2c_dev->hw->has_hs_mode_support) {
> + dev_info(i2c_dev->dev, "HS mode not supported\n");
> + i2c_dev->bus_clk_rate = 100000; /* default clock rate */
I2C_MAX_STANDARD_MODE_FREQ
23.07.2020 15:18, Krishna Yarlagadda пишет:
> Enable GPC DMA support for Tegra186 and Tegra194
>
> Signed-off-by: Rajesh Gumasta <[email protected]>
> Signed-off-by: Krishna Yarlagadda <[email protected]>
> ---
> drivers/i2c/busses/i2c-tegra.c | 25 ++++++++++++++++++++-----
> 1 file changed, 20 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
> index 8ab968e..77198fc 100644
> --- a/drivers/i2c/busses/i2c-tegra.c
> +++ b/drivers/i2c/busses/i2c-tegra.c
> @@ -236,6 +236,7 @@ struct tegra_i2c_hw_feature {
> u32 setup_hold_time_hs_mode;
> bool has_interface_timing_reg;
> bool has_slcg_support;
> + bool has_gpc_dma;
> };
>
> /**
> @@ -432,11 +433,18 @@ static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev)
> dma_addr_t dma_phys;
> int err;
>
> - if (!i2c_dev->hw->has_apb_dma)
> - return 0;
> -
> - if (!IS_ENABLED(CONFIG_TEGRA20_APB_DMA)) {
> - dev_dbg(i2c_dev->dev, "Support for APB DMA not enabled!\n");
> + if (i2c_dev->hw->has_gpc_dma) {
> + if (!IS_ENABLED(CONFIG_TEGRA_GPC_DMA)) {
Single line, please.
> + dev_dbg(i2c_dev->dev, "Support for GPC DMA not enabled!\n");
> + return 0;
> + }
> + } else if (i2c_dev->hw->has_apb_dma) {
> + if (!IS_ENABLED(CONFIG_TEGRA20_APB_DMA)) {
Here too.
> + dev_dbg(i2c_dev->dev, "Support for APB DMA not enabled!\n");
> + return 0;
> + }
> + } else {
> + dev_dbg(i2c_dev->dev, "DMA is not enabled!\n");
Also, please drop all the exclamation marks.
23.07.2020 15:18, Krishna Yarlagadda пишет:
> Enable Second Level Clock Gating feature for supported chips.
> With SLCG enabled, software need not control clocks anymore
> and leave clocks enabled always on.
What problem is solved by this patch? If there is no real problem, then
I'm not sure that this is a worthwhile patch. Please explain.
...
> @@ -1932,7 +1946,8 @@ static int __maybe_unused tegra_i2c_suspend(struct device *dev)
> struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
> int err = 0;
>
> - i2c_mark_adapter_suspended(&i2c_dev->adapter);
Why i2c_mark_adapter_suspended() is removed?
> + if (i2c_dev->is_clkon_always)
> + clk_disable(i2c_dev->div_clk);
Why clk needs to be disabled on suspend?
> if (!pm_runtime_status_suspended(dev))
> err = tegra_i2c_runtime_suspend(dev);
> @@ -1968,6 +1983,15 @@ static int __maybe_unused tegra_i2c_resume(struct device *dev)
> return err;
> }
>
> + if (i2c_dev->is_clkon_always) {
> + err = clk_enable(i2c_dev->div_clk);
> + if (err < 0) {
> + dev_err(i2c_dev->dev, "clock enable failed %d\n",
> + err);
> + return err;
> + }
> + }
Would be nice if it all could be wrapped into
tegra_i2c_div_clk_enable/disable() helpers.
> i2c_mark_adapter_resumed(&i2c_dev->adapter);
>
> return 0;
>
On Thu, Jul 23, 2020 at 05:48:50PM +0530, Krishna Yarlagadda wrote:
> From: Shardar Shariff Md <[email protected]>
>
> Add high speed mode support
[...]
> --- a/drivers/i2c/busses/i2c-tegra.c
> +++ b/drivers/i2c/busses/i2c-tegra.c
[...]
> @@ -215,12 +218,14 @@ struct tegra_i2c_hw_feature {
> int clk_divisor_std_mode;
> int clk_divisor_fast_mode;
> u16 clk_divisor_fast_plus_mode;
> + int clk_multiplier_hs_mode;
> bool has_multi_master_mode;
> bool has_slcg_override_reg;
> bool has_mst_fifo;
> const struct i2c_adapter_quirks *quirks;
> bool supports_bus_clear;
> bool has_reg_write_buffering;
> + bool has_hs_mode_support;
This field seems redundant: == !clk_multiplier_hs_mode ?
Best Regards,
Micha? Miros?aw