From 5276e80d92d168243b7c348fa921e7c8d68eccda Mon Sep 17 00:00:00 2001 From: mkarthik Date: Thu, 16 Aug 2018 14:43:16 +0530 Subject: i2c: tegra-slave: Add support for timeout during read Add the support for timeout in slave driver during read from slave to master Bug 200376118 Change-Id: I87f93890d4b121b4d966bc20e4fea5dfef84362c Signed-off-by: mkarthik Reviewed-on: https://git-master.nvidia.com/r/1800968 Reviewed-by: Shardar Mohammed GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/i2c/busses/i2c-tegra194-slave.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-tegra194-slave.c b/drivers/i2c/busses/i2c-tegra194-slave.c index 5381f51b9..60d6d61ea 100644 --- a/drivers/i2c/busses/i2c-tegra194-slave.c +++ b/drivers/i2c/busses/i2c-tegra194-slave.c @@ -29,7 +29,9 @@ #include #include #include +#include +#define I2C_SLV_TIMEOUT (msecs_to_jiffies(10000)) #define I2C_SL_CNFG 0x20 #define I2C_SL_CNFG_RESP BIT(0) #define I2C_SL_CNFG_NACK BIT(1) @@ -144,6 +146,7 @@ struct tegra_i2cslv_dev { bool rx_in_progress; bool tx_in_progress; u32 buffer_size; + struct delayed_work work; }; static inline u32 tegra_i2cslv_readl(struct tegra_i2cslv_dev *i2cslv_dev, @@ -442,7 +445,6 @@ static int tegra_i2cslv_init(struct tegra_i2cslv_dev *i2cslv_dev) i2cslv_dev->buffer_size = i2cslv_dev->slave->buffer_size; i2cslv_dev->rx_count = 0; - if (i2cslv_dev->slave->flags & I2C_CLIENT_TEN) { /* Program the 10-bit slave address */ tegra_i2cslv_writel(i2cslv_dev, i2cslv_dev->slave->addr & @@ -488,6 +490,22 @@ static int tegra_i2cslv_init(struct tegra_i2cslv_dev *i2cslv_dev) return tegra_i2cslv_load_config(i2cslv_dev); } +static void tegra_i2cslv_handle_timeout(struct work_struct *work) +{ + struct tegra_i2cslv_dev *i2cslv_dev = container_of(work, + struct tegra_i2cslv_dev, work.work); + unsigned long flags; + + dev_err(i2cslv_dev->dev, "Slave Xfer timeout\n"); + + raw_spin_lock_irqsave(&i2cslv_dev->xfer_lock, flags); + tegra_i2cslv_dump_reg(i2cslv_dev); + raw_spin_unlock_irqrestore(&i2cslv_dev->xfer_lock, flags); + + reset_control_reset(i2cslv_dev->rstc); + tegra_i2cslv_init(i2cslv_dev); +} + static irqreturn_t tegra_i2cslv_isr(int irq, void *dev_id) { struct tegra_i2cslv_dev *i2cslv_dev = dev_id; @@ -512,6 +530,7 @@ static irqreturn_t tegra_i2cslv_isr(int irq, void *dev_id) } if (i2c_int_src & I2C_INTERRUPT_SLV_TX_BUFFER_REQ) { + schedule_delayed_work(&i2cslv_dev->work, I2C_SLV_TIMEOUT); tegra_i2cslv_handle_tx(i2cslv_dev, i2c_int_src, i2c_slv_sts); goto done; } @@ -529,6 +548,7 @@ static irqreturn_t tegra_i2cslv_isr(int irq, void *dev_id) /* STOP: End of transfer */ if (i2c_slv_sts & I2C_SL_STATUS_END_TRANS) { tegra_i2cslv_handle_stop(i2cslv_dev, i2c_int_src, i2c_slv_sts); + cancel_delayed_work(&i2cslv_dev->work); goto done; } @@ -693,6 +713,8 @@ static int tegra_i2cslv_probe(struct platform_device *pdev) return ret; } + INIT_DELAYED_WORK(&i2cslv_dev->work, tegra_i2cslv_handle_timeout); + return 0; } -- cgit v1.2.2