Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

i2c-algo-pca: Use timeout for checking the state machine

We now timeout also if the state machine does not change within the
given time. For that, the driver-specific completion-functions are
extended to return true or false depending on the timeout. This then
gets checked in the algorithm.

Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Signed-off-by: Jean Delvare <khali@linux-fr.org>

authored by

Wolfram Sang and committed by
Jean Delvare
2378bc09 8e99ada8

+46 -33
+23 -18
drivers/i2c/algos/i2c-algo-pca.c
··· 60 60 * 61 61 * returns after the start condition has occurred 62 62 */ 63 - static void pca_start(struct i2c_algo_pca_data *adap) 63 + static int pca_start(struct i2c_algo_pca_data *adap) 64 64 { 65 65 int sta = pca_get_con(adap); 66 66 DEB2("=== START\n"); 67 67 sta |= I2C_PCA_CON_STA; 68 68 sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_SI); 69 69 pca_set_con(adap, sta); 70 - pca_wait(adap); 70 + return pca_wait(adap); 71 71 } 72 72 73 73 /* ··· 75 75 * 76 76 * return after the repeated start condition has occurred 77 77 */ 78 - static void pca_repeated_start(struct i2c_algo_pca_data *adap) 78 + static int pca_repeated_start(struct i2c_algo_pca_data *adap) 79 79 { 80 80 int sta = pca_get_con(adap); 81 81 DEB2("=== REPEATED START\n"); 82 82 sta |= I2C_PCA_CON_STA; 83 83 sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_SI); 84 84 pca_set_con(adap, sta); 85 - pca_wait(adap); 85 + return pca_wait(adap); 86 86 } 87 87 88 88 /* ··· 108 108 * 109 109 * returns after the address has been sent 110 110 */ 111 - static void pca_address(struct i2c_algo_pca_data *adap, 111 + static int pca_address(struct i2c_algo_pca_data *adap, 112 112 struct i2c_msg *msg) 113 113 { 114 114 int sta = pca_get_con(adap); ··· 125 125 sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI); 126 126 pca_set_con(adap, sta); 127 127 128 - pca_wait(adap); 128 + return pca_wait(adap); 129 129 } 130 130 131 131 /* ··· 133 133 * 134 134 * Returns after the byte has been transmitted 135 135 */ 136 - static void pca_tx_byte(struct i2c_algo_pca_data *adap, 136 + static int pca_tx_byte(struct i2c_algo_pca_data *adap, 137 137 __u8 b) 138 138 { 139 139 int sta = pca_get_con(adap); ··· 143 143 sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI); 144 144 pca_set_con(adap, sta); 145 145 146 - pca_wait(adap); 146 + return pca_wait(adap); 147 147 } 148 148 149 149 /* ··· 163 163 * 164 164 * Returns after next byte has arrived. 165 165 */ 166 - static void pca_rx_ack(struct i2c_algo_pca_data *adap, 166 + static int pca_rx_ack(struct i2c_algo_pca_data *adap, 167 167 int ack) 168 168 { 169 169 int sta = pca_get_con(adap); ··· 174 174 sta |= I2C_PCA_CON_AA; 175 175 176 176 pca_set_con(adap, sta); 177 - pca_wait(adap); 177 + return pca_wait(adap); 178 178 } 179 179 180 180 static int pca_xfer(struct i2c_adapter *i2c_adap, ··· 187 187 int numbytes = 0; 188 188 int state; 189 189 int ret; 190 + int completed = 1; 190 191 unsigned long timeout = jiffies + i2c_adap->timeout; 191 192 192 193 while (pca_status(adap) != 0xf8) { ··· 233 232 234 233 switch (state) { 235 234 case 0xf8: /* On reset or stop the bus is idle */ 236 - pca_start(adap); 235 + completed = pca_start(adap); 237 236 break; 238 237 239 238 case 0x08: /* A START condition has been transmitted */ 240 239 case 0x10: /* A repeated start condition has been transmitted */ 241 - pca_address(adap, msg); 240 + completed = pca_address(adap, msg); 242 241 break; 243 242 244 243 case 0x18: /* SLA+W has been transmitted; ACK has been received */ 245 244 case 0x28: /* Data byte in I2CDAT has been transmitted; ACK has been received */ 246 245 if (numbytes < msg->len) { 247 - pca_tx_byte(adap, msg->buf[numbytes]); 246 + completed = pca_tx_byte(adap, 247 + msg->buf[numbytes]); 248 248 numbytes++; 249 249 break; 250 250 } ··· 253 251 if (curmsg == num) 254 252 pca_stop(adap); 255 253 else 256 - pca_repeated_start(adap); 254 + completed = pca_repeated_start(adap); 257 255 break; 258 256 259 257 case 0x20: /* SLA+W has been transmitted; NOT ACK has been received */ ··· 262 260 goto out; 263 261 264 262 case 0x40: /* SLA+R has been transmitted; ACK has been received */ 265 - pca_rx_ack(adap, msg->len > 1); 263 + completed = pca_rx_ack(adap, msg->len > 1); 266 264 break; 267 265 268 266 case 0x50: /* Data bytes has been received; ACK has been returned */ 269 267 if (numbytes < msg->len) { 270 268 pca_rx_byte(adap, &msg->buf[numbytes], 1); 271 269 numbytes++; 272 - pca_rx_ack(adap, numbytes < msg->len - 1); 270 + completed = pca_rx_ack(adap, 271 + numbytes < msg->len - 1); 273 272 break; 274 273 } 275 274 curmsg++; numbytes = 0; 276 275 if (curmsg == num) 277 276 pca_stop(adap); 278 277 else 279 - pca_repeated_start(adap); 278 + completed = pca_repeated_start(adap); 280 279 break; 281 280 282 281 case 0x48: /* SLA+R has been transmitted; NOT ACK has been received */ ··· 300 297 if (curmsg == num) 301 298 pca_stop(adap); 302 299 else 303 - pca_repeated_start(adap); 300 + completed = pca_repeated_start(adap); 304 301 } else { 305 302 DEB2("NOT ACK sent after data byte received. " 306 303 "Not final byte. numbytes %d. len %d\n", ··· 326 323 break; 327 324 } 328 325 326 + if (!completed) 327 + goto out; 329 328 } 330 329 331 330 ret = curmsg;
+13 -5
drivers/i2c/busses/i2c-pca-isa.c
··· 23 23 #include <linux/module.h> 24 24 #include <linux/moduleparam.h> 25 25 #include <linux/delay.h> 26 + #include <linux/jiffies.h> 26 27 #include <linux/init.h> 27 28 #include <linux/interrupt.h> 28 29 #include <linux/wait.h> ··· 44 43 * in the actual clock rate */ 45 44 static int clock = 59000; 46 45 46 + static struct i2c_adapter pca_isa_ops; 47 47 static wait_queue_head_t pca_wait; 48 48 49 49 static void pca_isa_writebyte(void *pd, int reg, int val) ··· 71 69 72 70 static int pca_isa_waitforcompletion(void *pd) 73 71 { 74 - int ret = 0; 72 + long ret = ~0; 73 + unsigned long timeout; 75 74 76 75 if (irq > -1) { 77 - ret = wait_event_interruptible(pca_wait, 78 - pca_isa_readbyte(pd, I2C_PCA_CON) & I2C_PCA_CON_SI); 76 + ret = wait_event_interruptible_timeout(pca_wait, 77 + pca_isa_readbyte(pd, I2C_PCA_CON) 78 + & I2C_PCA_CON_SI, pca_isa_ops.timeout); 79 79 } else { 80 - while ((pca_isa_readbyte(pd, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0) 80 + /* Do polling */ 81 + timeout = jiffies + pca_isa_ops.timeout; 82 + while (((pca_isa_readbyte(pd, I2C_PCA_CON) 83 + & I2C_PCA_CON_SI) == 0) 84 + && (ret = time_before(jiffies, timeout))) 81 85 udelay(100); 82 86 } 83 - return ret; 87 + return ret > 0; 84 88 } 85 89 86 90 static void pca_isa_resetchip(void *pd)
+10 -10
drivers/i2c/busses/i2c-pca-platform.c
··· 15 15 #include <linux/init.h> 16 16 #include <linux/slab.h> 17 17 #include <linux/delay.h> 18 + #include <linux/jiffies.h> 18 19 #include <linux/errno.h> 19 20 #include <linux/i2c.h> 20 21 #include <linux/interrupt.h> ··· 82 81 static int i2c_pca_pf_waitforcompletion(void *pd) 83 82 { 84 83 struct i2c_pca_pf_data *i2c = pd; 85 - int ret = 0; 84 + long ret = ~0; 85 + unsigned long timeout; 86 86 87 87 if (i2c->irq) { 88 - ret = wait_event_interruptible(i2c->wait, 88 + ret = wait_event_interruptible_timeout(i2c->wait, 89 89 i2c->algo_data.read_byte(i2c, I2C_PCA_CON) 90 - & I2C_PCA_CON_SI); 90 + & I2C_PCA_CON_SI, i2c->adap.timeout); 91 91 } else { 92 - /* 93 - * Do polling... 94 - * XXX: Could get stuck in extreme cases! 95 - * Maybe add timeout, but using irqs is preferred anyhow. 96 - */ 97 - while ((i2c->algo_data.read_byte(i2c, I2C_PCA_CON) 92 + /* Do polling */ 93 + timeout = jiffies + i2c->adap.timeout; 94 + while (((i2c->algo_data.read_byte(i2c, I2C_PCA_CON) 98 95 & I2C_PCA_CON_SI) == 0) 96 + && (ret = time_before(jiffies, timeout))) 99 97 udelay(100); 100 98 } 101 99 102 - return ret; 100 + return ret > 0; 103 101 } 104 102 105 103 static void i2c_pca_pf_dummyreset(void *pd)