diff options
author | mkarthik <mkarthik@nvidia.com> | 2018-08-16 05:13:16 -0400 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2018-08-27 09:22:31 -0400 |
commit | 5276e80d92d168243b7c348fa921e7c8d68eccda (patch) | |
tree | fb3b8a1454adb13263a73941b8ef0acb7f7e53bf | |
parent | e0b3e59770dfaf8cdd4c1e5a6ea92cdea6afbc2b (diff) |
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 <mkarthik@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1800968
Reviewed-by: Shardar Mohammed <smohammed@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Bibek Basu <bbasu@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
-rw-r--r-- | drivers/i2c/busses/i2c-tegra194-slave.c | 24 |
1 files changed, 23 insertions, 1 deletions
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 @@ | |||
29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
30 | #include <linux/i2c.h> | 30 | #include <linux/i2c.h> |
31 | #include <linux/iopoll.h> | 31 | #include <linux/iopoll.h> |
32 | #include <linux/workqueue.h> | ||
32 | 33 | ||
34 | #define I2C_SLV_TIMEOUT (msecs_to_jiffies(10000)) | ||
33 | #define I2C_SL_CNFG 0x20 | 35 | #define I2C_SL_CNFG 0x20 |
34 | #define I2C_SL_CNFG_RESP BIT(0) | 36 | #define I2C_SL_CNFG_RESP BIT(0) |
35 | #define I2C_SL_CNFG_NACK BIT(1) | 37 | #define I2C_SL_CNFG_NACK BIT(1) |
@@ -144,6 +146,7 @@ struct tegra_i2cslv_dev { | |||
144 | bool rx_in_progress; | 146 | bool rx_in_progress; |
145 | bool tx_in_progress; | 147 | bool tx_in_progress; |
146 | u32 buffer_size; | 148 | u32 buffer_size; |
149 | struct delayed_work work; | ||
147 | }; | 150 | }; |
148 | 151 | ||
149 | static inline u32 tegra_i2cslv_readl(struct tegra_i2cslv_dev *i2cslv_dev, | 152 | 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) | |||
442 | i2cslv_dev->buffer_size = i2cslv_dev->slave->buffer_size; | 445 | i2cslv_dev->buffer_size = i2cslv_dev->slave->buffer_size; |
443 | i2cslv_dev->rx_count = 0; | 446 | i2cslv_dev->rx_count = 0; |
444 | 447 | ||
445 | |||
446 | if (i2cslv_dev->slave->flags & I2C_CLIENT_TEN) { | 448 | if (i2cslv_dev->slave->flags & I2C_CLIENT_TEN) { |
447 | /* Program the 10-bit slave address */ | 449 | /* Program the 10-bit slave address */ |
448 | tegra_i2cslv_writel(i2cslv_dev, i2cslv_dev->slave->addr & | 450 | tegra_i2cslv_writel(i2cslv_dev, i2cslv_dev->slave->addr & |
@@ -488,6 +490,22 @@ static int tegra_i2cslv_init(struct tegra_i2cslv_dev *i2cslv_dev) | |||
488 | return tegra_i2cslv_load_config(i2cslv_dev); | 490 | return tegra_i2cslv_load_config(i2cslv_dev); |
489 | } | 491 | } |
490 | 492 | ||
493 | static void tegra_i2cslv_handle_timeout(struct work_struct *work) | ||
494 | { | ||
495 | struct tegra_i2cslv_dev *i2cslv_dev = container_of(work, | ||
496 | struct tegra_i2cslv_dev, work.work); | ||
497 | unsigned long flags; | ||
498 | |||
499 | dev_err(i2cslv_dev->dev, "Slave Xfer timeout\n"); | ||
500 | |||
501 | raw_spin_lock_irqsave(&i2cslv_dev->xfer_lock, flags); | ||
502 | tegra_i2cslv_dump_reg(i2cslv_dev); | ||
503 | raw_spin_unlock_irqrestore(&i2cslv_dev->xfer_lock, flags); | ||
504 | |||
505 | reset_control_reset(i2cslv_dev->rstc); | ||
506 | tegra_i2cslv_init(i2cslv_dev); | ||
507 | } | ||
508 | |||
491 | static irqreturn_t tegra_i2cslv_isr(int irq, void *dev_id) | 509 | static irqreturn_t tegra_i2cslv_isr(int irq, void *dev_id) |
492 | { | 510 | { |
493 | struct tegra_i2cslv_dev *i2cslv_dev = dev_id; | 511 | struct tegra_i2cslv_dev *i2cslv_dev = dev_id; |
@@ -512,6 +530,7 @@ static irqreturn_t tegra_i2cslv_isr(int irq, void *dev_id) | |||
512 | } | 530 | } |
513 | 531 | ||
514 | if (i2c_int_src & I2C_INTERRUPT_SLV_TX_BUFFER_REQ) { | 532 | if (i2c_int_src & I2C_INTERRUPT_SLV_TX_BUFFER_REQ) { |
533 | schedule_delayed_work(&i2cslv_dev->work, I2C_SLV_TIMEOUT); | ||
515 | tegra_i2cslv_handle_tx(i2cslv_dev, i2c_int_src, i2c_slv_sts); | 534 | tegra_i2cslv_handle_tx(i2cslv_dev, i2c_int_src, i2c_slv_sts); |
516 | goto done; | 535 | goto done; |
517 | } | 536 | } |
@@ -529,6 +548,7 @@ static irqreturn_t tegra_i2cslv_isr(int irq, void *dev_id) | |||
529 | /* STOP: End of transfer */ | 548 | /* STOP: End of transfer */ |
530 | if (i2c_slv_sts & I2C_SL_STATUS_END_TRANS) { | 549 | if (i2c_slv_sts & I2C_SL_STATUS_END_TRANS) { |
531 | tegra_i2cslv_handle_stop(i2cslv_dev, i2c_int_src, i2c_slv_sts); | 550 | tegra_i2cslv_handle_stop(i2cslv_dev, i2c_int_src, i2c_slv_sts); |
551 | cancel_delayed_work(&i2cslv_dev->work); | ||
532 | goto done; | 552 | goto done; |
533 | } | 553 | } |
534 | 554 | ||
@@ -693,6 +713,8 @@ static int tegra_i2cslv_probe(struct platform_device *pdev) | |||
693 | return ret; | 713 | return ret; |
694 | } | 714 | } |
695 | 715 | ||
716 | INIT_DELAYED_WORK(&i2cslv_dev->work, tegra_i2cslv_handle_timeout); | ||
717 | |||
696 | return 0; | 718 | return 0; |
697 | } | 719 | } |
698 | 720 | ||