diff options
author | Sonic Zhang <sonic.zhang@analog.com> | 2008-04-22 16:16:47 -0400 |
---|---|---|
committer | Jean Delvare <khali@hyperion.delvare> | 2008-04-22 16:16:47 -0400 |
commit | 4dd39bb12f5b9f0d9a98f29071dc1c51e9306954 (patch) | |
tree | 0cab698b36a97a4a73211d6f6370efd2296337ca /drivers/i2c | |
parent | 4c03f68fc4ab902353336b6b0c6933617821cf70 (diff) |
i2c-bfin-twi: Add repeat start feature to avoid break of a bundle of i2c master xfer operation
- Create a new mode TWI_I2C_MODE_REPEAT.
- No change to smbus operation.
Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
Signed-off-by: Bryan Wu <cooloney@kernel.org>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-bfin-twi.c | 185 |
1 files changed, 114 insertions, 71 deletions
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 7dbdaeb707a9..86956a8f0ae5 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c | |||
@@ -39,9 +39,10 @@ | |||
39 | #define POLL_TIMEOUT (2 * HZ) | 39 | #define POLL_TIMEOUT (2 * HZ) |
40 | 40 | ||
41 | /* SMBus mode*/ | 41 | /* SMBus mode*/ |
42 | #define TWI_I2C_MODE_STANDARD 0x01 | 42 | #define TWI_I2C_MODE_STANDARD 1 |
43 | #define TWI_I2C_MODE_STANDARDSUB 0x02 | 43 | #define TWI_I2C_MODE_STANDARDSUB 2 |
44 | #define TWI_I2C_MODE_COMBINED 0x04 | 44 | #define TWI_I2C_MODE_COMBINED 3 |
45 | #define TWI_I2C_MODE_REPEAT 4 | ||
45 | 46 | ||
46 | struct bfin_twi_iface { | 47 | struct bfin_twi_iface { |
47 | int irq; | 48 | int irq; |
@@ -58,6 +59,9 @@ struct bfin_twi_iface { | |||
58 | struct timer_list timeout_timer; | 59 | struct timer_list timeout_timer; |
59 | struct i2c_adapter adap; | 60 | struct i2c_adapter adap; |
60 | struct completion complete; | 61 | struct completion complete; |
62 | struct i2c_msg *pmsg; | ||
63 | int msg_num; | ||
64 | int cur_msg; | ||
61 | }; | 65 | }; |
62 | 66 | ||
63 | static struct bfin_twi_iface twi_iface; | 67 | static struct bfin_twi_iface twi_iface; |
@@ -76,12 +80,16 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) | |||
76 | /* start receive immediately after complete sending in | 80 | /* start receive immediately after complete sending in |
77 | * combine mode. | 81 | * combine mode. |
78 | */ | 82 | */ |
79 | else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { | 83 | else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) |
80 | bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | 84 | bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() |
81 | | MDIR | RSTART); | 85 | | MDIR | RSTART); |
82 | } else if (iface->manual_stop) | 86 | else if (iface->manual_stop) |
83 | bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | 87 | bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() |
84 | | STOP); | 88 | | STOP); |
89 | else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && | ||
90 | iface->cur_msg+1 < iface->msg_num) | ||
91 | bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | ||
92 | | RSTART); | ||
85 | SSYNC(); | 93 | SSYNC(); |
86 | /* Clear status */ | 94 | /* Clear status */ |
87 | bfin_write_TWI_INT_STAT(XMTSERV); | 95 | bfin_write_TWI_INT_STAT(XMTSERV); |
@@ -108,6 +116,11 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) | |||
108 | bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | 116 | bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() |
109 | | STOP); | 117 | | STOP); |
110 | SSYNC(); | 118 | SSYNC(); |
119 | } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && | ||
120 | iface->cur_msg+1 < iface->msg_num) { | ||
121 | bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | ||
122 | | RSTART); | ||
123 | SSYNC(); | ||
111 | } | 124 | } |
112 | /* Clear interrupt source */ | 125 | /* Clear interrupt source */ |
113 | bfin_write_TWI_INT_STAT(RCVSERV); | 126 | bfin_write_TWI_INT_STAT(RCVSERV); |
@@ -119,7 +132,7 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) | |||
119 | bfin_write_TWI_MASTER_STAT(0x3e); | 132 | bfin_write_TWI_MASTER_STAT(0x3e); |
120 | bfin_write_TWI_MASTER_CTL(0); | 133 | bfin_write_TWI_MASTER_CTL(0); |
121 | SSYNC(); | 134 | SSYNC(); |
122 | iface->result = -1; | 135 | iface->result = -EIO; |
123 | /* if both err and complete int stats are set, return proper | 136 | /* if both err and complete int stats are set, return proper |
124 | * results. | 137 | * results. |
125 | */ | 138 | */ |
@@ -170,6 +183,42 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) | |||
170 | bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | | 183 | bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | |
171 | MEN | MDIR); | 184 | MEN | MDIR); |
172 | SSYNC(); | 185 | SSYNC(); |
186 | } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && | ||
187 | iface->cur_msg+1 < iface->msg_num) { | ||
188 | iface->cur_msg++; | ||
189 | iface->transPtr = iface->pmsg[iface->cur_msg].buf; | ||
190 | iface->writeNum = iface->readNum = | ||
191 | iface->pmsg[iface->cur_msg].len; | ||
192 | /* Set Transmit device address */ | ||
193 | bfin_write_TWI_MASTER_ADDR( | ||
194 | iface->pmsg[iface->cur_msg].addr); | ||
195 | if (iface->pmsg[iface->cur_msg].flags & I2C_M_RD) | ||
196 | iface->read_write = I2C_SMBUS_READ; | ||
197 | else { | ||
198 | iface->read_write = I2C_SMBUS_WRITE; | ||
199 | /* Transmit first data */ | ||
200 | if (iface->writeNum > 0) { | ||
201 | bfin_write_TWI_XMT_DATA8( | ||
202 | *(iface->transPtr++)); | ||
203 | iface->writeNum--; | ||
204 | SSYNC(); | ||
205 | } | ||
206 | } | ||
207 | |||
208 | if (iface->pmsg[iface->cur_msg].len <= 255) | ||
209 | bfin_write_TWI_MASTER_CTL( | ||
210 | iface->pmsg[iface->cur_msg].len << 6); | ||
211 | else { | ||
212 | bfin_write_TWI_MASTER_CTL(0xff << 6); | ||
213 | iface->manual_stop = 1; | ||
214 | } | ||
215 | /* remove restart bit and enable master receive */ | ||
216 | bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() & | ||
217 | ~RSTART); | ||
218 | bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | | ||
219 | MEN | ((iface->read_write == I2C_SMBUS_READ) ? | ||
220 | MDIR : 0)); | ||
221 | SSYNC(); | ||
173 | } else { | 222 | } else { |
174 | iface->result = 1; | 223 | iface->result = 1; |
175 | bfin_write_TWI_INT_MASK(0); | 224 | bfin_write_TWI_INT_MASK(0); |
@@ -221,7 +270,6 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap, | |||
221 | { | 270 | { |
222 | struct bfin_twi_iface *iface = adap->algo_data; | 271 | struct bfin_twi_iface *iface = adap->algo_data; |
223 | struct i2c_msg *pmsg; | 272 | struct i2c_msg *pmsg; |
224 | int i, ret; | ||
225 | int rc = 0; | 273 | int rc = 0; |
226 | 274 | ||
227 | if (!(bfin_read_TWI_CONTROL() & TWI_ENA)) | 275 | if (!(bfin_read_TWI_CONTROL() & TWI_ENA)) |
@@ -231,81 +279,76 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap, | |||
231 | yield(); | 279 | yield(); |
232 | } | 280 | } |
233 | 281 | ||
234 | ret = 0; | 282 | iface->pmsg = msgs; |
235 | for (i = 0; rc >= 0 && i < num; i++) { | 283 | iface->msg_num = num; |
236 | pmsg = &msgs[i]; | 284 | iface->cur_msg = 0; |
237 | if (pmsg->flags & I2C_M_TEN) { | ||
238 | dev_err(&(adap->dev), "i2c-bfin-twi: 10 bits addr " | ||
239 | "not supported !\n"); | ||
240 | rc = -EINVAL; | ||
241 | break; | ||
242 | } | ||
243 | 285 | ||
244 | iface->cur_mode = TWI_I2C_MODE_STANDARD; | 286 | pmsg = &msgs[0]; |
245 | iface->manual_stop = 0; | 287 | if (pmsg->flags & I2C_M_TEN) { |
246 | iface->transPtr = pmsg->buf; | 288 | dev_err(&adap->dev, "10 bits addr not supported!\n"); |
247 | iface->writeNum = iface->readNum = pmsg->len; | 289 | return -EINVAL; |
248 | iface->result = 0; | 290 | } |
249 | iface->timeout_count = 10; | ||
250 | /* Set Transmit device address */ | ||
251 | bfin_write_TWI_MASTER_ADDR(pmsg->addr); | ||
252 | |||
253 | /* FIFO Initiation. Data in FIFO should be | ||
254 | * discarded before start a new operation. | ||
255 | */ | ||
256 | bfin_write_TWI_FIFO_CTL(0x3); | ||
257 | SSYNC(); | ||
258 | bfin_write_TWI_FIFO_CTL(0); | ||
259 | SSYNC(); | ||
260 | 291 | ||
261 | if (pmsg->flags & I2C_M_RD) | 292 | iface->cur_mode = TWI_I2C_MODE_REPEAT; |
262 | iface->read_write = I2C_SMBUS_READ; | 293 | iface->manual_stop = 0; |
263 | else { | 294 | iface->transPtr = pmsg->buf; |
264 | iface->read_write = I2C_SMBUS_WRITE; | 295 | iface->writeNum = iface->readNum = pmsg->len; |
265 | /* Transmit first data */ | 296 | iface->result = 0; |
266 | if (iface->writeNum > 0) { | 297 | iface->timeout_count = 10; |
267 | bfin_write_TWI_XMT_DATA8(*(iface->transPtr++)); | 298 | /* Set Transmit device address */ |
268 | iface->writeNum--; | 299 | bfin_write_TWI_MASTER_ADDR(pmsg->addr); |
269 | SSYNC(); | 300 | |
270 | } | 301 | /* FIFO Initiation. Data in FIFO should be |
302 | * discarded before start a new operation. | ||
303 | */ | ||
304 | bfin_write_TWI_FIFO_CTL(0x3); | ||
305 | SSYNC(); | ||
306 | bfin_write_TWI_FIFO_CTL(0); | ||
307 | SSYNC(); | ||
308 | |||
309 | if (pmsg->flags & I2C_M_RD) | ||
310 | iface->read_write = I2C_SMBUS_READ; | ||
311 | else { | ||
312 | iface->read_write = I2C_SMBUS_WRITE; | ||
313 | /* Transmit first data */ | ||
314 | if (iface->writeNum > 0) { | ||
315 | bfin_write_TWI_XMT_DATA8(*(iface->transPtr++)); | ||
316 | iface->writeNum--; | ||
317 | SSYNC(); | ||
271 | } | 318 | } |
319 | } | ||
272 | 320 | ||
273 | /* clear int stat */ | 321 | /* clear int stat */ |
274 | bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV); | 322 | bfin_write_TWI_INT_STAT(MERR | MCOMP | XMTSERV | RCVSERV); |
275 | 323 | ||
276 | /* Interrupt mask . Enable XMT, RCV interrupt */ | 324 | /* Interrupt mask . Enable XMT, RCV interrupt */ |
277 | bfin_write_TWI_INT_MASK(MCOMP | MERR | | 325 | bfin_write_TWI_INT_MASK(MCOMP | MERR | RCVSERV | XMTSERV); |
278 | ((iface->read_write == I2C_SMBUS_READ)? | 326 | SSYNC(); |
279 | RCVSERV : XMTSERV)); | ||
280 | SSYNC(); | ||
281 | 327 | ||
282 | if (pmsg->len > 0 && pmsg->len <= 255) | 328 | if (pmsg->len <= 255) |
283 | bfin_write_TWI_MASTER_CTL(pmsg->len << 6); | 329 | bfin_write_TWI_MASTER_CTL(pmsg->len << 6); |
284 | else if (pmsg->len > 255) { | 330 | else { |
285 | bfin_write_TWI_MASTER_CTL(0xff << 6); | 331 | bfin_write_TWI_MASTER_CTL(0xff << 6); |
286 | iface->manual_stop = 1; | 332 | iface->manual_stop = 1; |
287 | } else | 333 | } |
288 | break; | ||
289 | 334 | ||
290 | iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; | 335 | iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; |
291 | add_timer(&iface->timeout_timer); | 336 | add_timer(&iface->timeout_timer); |
292 | 337 | ||
293 | /* Master enable */ | 338 | /* Master enable */ |
294 | bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN | | 339 | bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN | |
295 | ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) | | 340 | ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) | |
296 | ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0)); | 341 | ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0)); |
297 | SSYNC(); | 342 | SSYNC(); |
298 | 343 | ||
299 | wait_for_completion(&iface->complete); | 344 | wait_for_completion(&iface->complete); |
300 | 345 | ||
301 | rc = iface->result; | 346 | rc = iface->result; |
302 | if (rc == 1) | ||
303 | ret++; | ||
304 | else if (rc == -1) | ||
305 | break; | ||
306 | } | ||
307 | 347 | ||
308 | return ret; | 348 | if (rc == 1) |
349 | return num; | ||
350 | else | ||
351 | return rc; | ||
309 | } | 352 | } |
310 | 353 | ||
311 | /* | 354 | /* |