aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorWolfram Sang <w.sang@pengutronix.de>2009-03-28 16:34:45 -0400
committerJean Delvare <khali@linux-fr.org>2009-03-28 16:34:45 -0400
commit2378bc09b91b0702fac7823828a614fd8016a29f (patch)
tree26539b17077028baba2741cf0e78fc01225a7d36 /drivers/i2c
parent8e99ada8deaa9033600cd2c7d0a9366b0e99ab68 (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/i2c')
-rw-r--r--drivers/i2c/algos/i2c-algo-pca.c41
-rw-r--r--drivers/i2c/busses/i2c-pca-isa.c18
-rw-r--r--drivers/i2c/busses/i2c-pca-platform.c20
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 */
63static void pca_start(struct i2c_algo_pca_data *adap) 63static 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 */
78static void pca_repeated_start(struct i2c_algo_pca_data *adap) 78static 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 */
111static void pca_address(struct i2c_algo_pca_data *adap, 111static 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 */
136static void pca_tx_byte(struct i2c_algo_pca_data *adap, 136static 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 */
166static void pca_rx_ack(struct i2c_algo_pca_data *adap, 166static 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
180static int pca_xfer(struct i2c_adapter *i2c_adap, 180static 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 */
44static int clock = 59000; 45static int clock = 59000;
45 46
47static struct i2c_adapter pca_isa_ops;
46static wait_queue_head_t pca_wait; 48static wait_queue_head_t pca_wait;
47 49
48static void pca_isa_writebyte(void *pd, int reg, int val) 50static 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
70static int pca_isa_waitforcompletion(void *pd) 72static 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
84static void pca_isa_resetchip(void *pd) 92static 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)
81static int i2c_pca_pf_waitforcompletion(void *pd) 82static 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
104static void i2c_pca_pf_dummyreset(void *pd) 104static void i2c_pca_pf_dummyreset(void *pd)