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