aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland Stigge <stigge@antcom.de>2012-08-08 03:42:32 -0400
committerWolfram Sang <w.sang@pengutronix.de>2012-09-12 11:52:44 -0400
commitc076ada4e4aaf45e1a31ad6de7c6cce36081e045 (patch)
tree0c1676608ef8316d271ed0a54f275c21feb3008e
parentb3aafe80c83097403d2b5edccfc440fac3d5f028 (diff)
i2c: pnx: Fix read transactions of >= 2 bytes
On transactions with n>=2 bytes, the controller actually wrongly clocks in n+1 bytes. This is caused by the (wrong) assumption that RFE in the Status Register is 1 iff there is no byte already ordered (via a dummy TX byte). This lead to the implementation of synchronized byte ordering, e.g.: Dummy-TX - RX - Dummy-TX - RX - ... But since RFE actually stays high after some Dummy-TX, it rather looks like: Dummy-TX - Dummy-TX - RX - Dummy-TX - RX - (RX) The last RX byte is clocked in by the bus controller, but ignored by the kernel when filling the userspace buffer. This patch fixes the issue by asking for RX via Dummy-TX asynchronously. Introducing a separate counter for TX bytes. Signed-off-by: Roland Stigge <stigge@antcom.de> Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
-rw-r--r--drivers/i2c/busses/i2c-pnx.c48
-rw-r--r--include/linux/i2c-pnx.h1
2 files changed, 29 insertions, 20 deletions
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c
index b36e21f9fd5..8488bddfe46 100644
--- a/drivers/i2c/busses/i2c-pnx.c
+++ b/drivers/i2c/busses/i2c-pnx.c
@@ -291,31 +291,37 @@ static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data)
291 * or we didn't 'ask' for it yet. 291 * or we didn't 'ask' for it yet.
292 */ 292 */
293 if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) { 293 if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) {
294 dev_dbg(&alg_data->adapter.dev, 294 /* 'Asking' is done asynchronously, e.g. dummy TX of several
295 "%s(): Write dummy data to fill Rx-fifo...\n", 295 * bytes is done before the first actual RX arrives in FIFO.
296 __func__); 296 * Therefore, ordered bytes (via TX) are counted separately.
297 */
298 if (alg_data->mif.order) {
299 dev_dbg(&alg_data->adapter.dev,
300 "%s(): Write dummy data to fill Rx-fifo...\n",
301 __func__);
297 302
298 if (alg_data->mif.len == 1) { 303 if (alg_data->mif.order == 1) {
299 /* Last byte, do not acknowledge next rcv. */ 304 /* Last byte, do not acknowledge next rcv. */
300 val |= stop_bit; 305 val |= stop_bit;
306
307 /*
308 * Enable interrupt RFDAIE (data in Rx fifo),
309 * and disable DRMIE (need data for Tx)
310 */
311 ctl = ioread32(I2C_REG_CTL(alg_data));
312 ctl |= mcntrl_rffie | mcntrl_daie;
313 ctl &= ~mcntrl_drmie;
314 iowrite32(ctl, I2C_REG_CTL(alg_data));
315 }
301 316
302 /* 317 /*
303 * Enable interrupt RFDAIE (data in Rx fifo), 318 * Now we'll 'ask' for data:
304 * and disable DRMIE (need data for Tx) 319 * For each byte we want to receive, we must
320 * write a (dummy) byte to the Tx-FIFO.
305 */ 321 */
306 ctl = ioread32(I2C_REG_CTL(alg_data)); 322 iowrite32(val, I2C_REG_TX(alg_data));
307 ctl |= mcntrl_rffie | mcntrl_daie; 323 alg_data->mif.order--;
308 ctl &= ~mcntrl_drmie;
309 iowrite32(ctl, I2C_REG_CTL(alg_data));
310 } 324 }
311
312 /*
313 * Now we'll 'ask' for data:
314 * For each byte we want to receive, we must
315 * write a (dummy) byte to the Tx-FIFO.
316 */
317 iowrite32(val, I2C_REG_TX(alg_data));
318
319 return 0; 325 return 0;
320 } 326 }
321 327
@@ -515,6 +521,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
515 521
516 alg_data->mif.buf = pmsg->buf; 522 alg_data->mif.buf = pmsg->buf;
517 alg_data->mif.len = pmsg->len; 523 alg_data->mif.len = pmsg->len;
524 alg_data->mif.order = pmsg->len;
518 alg_data->mif.mode = (pmsg->flags & I2C_M_RD) ? 525 alg_data->mif.mode = (pmsg->flags & I2C_M_RD) ?
519 I2C_SMBUS_READ : I2C_SMBUS_WRITE; 526 I2C_SMBUS_READ : I2C_SMBUS_WRITE;
520 alg_data->mif.ret = 0; 527 alg_data->mif.ret = 0;
@@ -567,6 +574,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
567 /* Cleanup to be sure... */ 574 /* Cleanup to be sure... */
568 alg_data->mif.buf = NULL; 575 alg_data->mif.buf = NULL;
569 alg_data->mif.len = 0; 576 alg_data->mif.len = 0;
577 alg_data->mif.order = 0;
570 578
571 dev_dbg(&alg_data->adapter.dev, "%s(): exiting, stat = %x\n", 579 dev_dbg(&alg_data->adapter.dev, "%s(): exiting, stat = %x\n",
572 __func__, ioread32(I2C_REG_STS(alg_data))); 580 __func__, ioread32(I2C_REG_STS(alg_data)));
diff --git a/include/linux/i2c-pnx.h b/include/linux/i2c-pnx.h
index 1bc74afe7a3..49ed17fdf05 100644
--- a/include/linux/i2c-pnx.h
+++ b/include/linux/i2c-pnx.h
@@ -22,6 +22,7 @@ struct i2c_pnx_mif {
22 struct timer_list timer; /* Timeout */ 22 struct timer_list timer; /* Timeout */
23 u8 * buf; /* Data buffer */ 23 u8 * buf; /* Data buffer */
24 int len; /* Length of data buffer */ 24 int len; /* Length of data buffer */
25 int order; /* RX Bytes to order via TX */
25}; 26};
26 27
27struct i2c_pnx_algo_data { 28struct i2c_pnx_algo_data {