summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2017-08-14 22:17:26 +0200
committerWolfram Sang <wsa@the-dreams.de>2017-08-17 21:53:03 +0200
commited1094012ae82798de33bad0ba1cc5f19a005e68 (patch)
tree07b614eb567bb550cbc6a7f3b75c77418adc3244
parent8de60c636e353806d43be6313987f36b03cdbf86 (diff)
downloadlwn-ed1094012ae82798de33bad0ba1cc5f19a005e68.tar.gz
lwn-ed1094012ae82798de33bad0ba1cc5f19a005e68.zip
i2c-cht-wc: Workaround CHT GPIO controller IRQ issues
The Cherry Trail Whiskey Cove PMIC's IRQ line is attached to one of the GPIOs of the Cherry Trail SoC. The CHT GPIO controller sometimes fails to deliver IRQs (seen when there is an IRQ storm on another pin). This commit works around this by reducing the long timeout which was a poor attempt to workaround this from 3s to 30ms and after that manually checking the status register for transfer completion by calling the threaded IRQ handler directly. This is safe todo as the entire threaded IRQ handler is protected by a mutex. Note 30ms should be more then long enough, at 100KHz any smbus single byte transaction should be finished in 4ms. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
-rw-r--r--drivers/i2c/busses/i2c-cht-wc.c14
1 files changed, 10 insertions, 4 deletions
diff --git a/drivers/i2c/busses/i2c-cht-wc.c b/drivers/i2c/busses/i2c-cht-wc.c
index 11f7e516f1b1..21312eed09e4 100644
--- a/drivers/i2c/busses/i2c-cht-wc.c
+++ b/drivers/i2c/busses/i2c-cht-wc.c
@@ -158,10 +158,16 @@ static int cht_wc_i2c_adap_smbus_xfer(struct i2c_adapter *_adap, u16 addr,
if (ret)
return ret;
- /* 3 second timeout, during cable plug the PMIC responds quite slow */
- ret = wait_event_timeout(adap->wait, adap->done, 3 * HZ);
- if (ret == 0)
- return -ETIMEDOUT;
+ ret = wait_event_timeout(adap->wait, adap->done, msecs_to_jiffies(30));
+ if (ret == 0) {
+ /*
+ * The CHT GPIO controller serializes all IRQs, sometimes
+ * causing significant delays, check status manually.
+ */
+ cht_wc_i2c_adap_thread_handler(0, adap);
+ if (!adap->done)
+ return -ETIMEDOUT;
+ }
ret = 0;
mutex_lock(&adap->adap_lock);