Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4dd39bb1 authored by Sonic Zhang's avatar Sonic Zhang Committed by Jean Delvare
Browse files

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: default avatarSonic Zhang <sonic.zhang@analog.com>
Signed-off-by: default avatarBryan Wu <cooloney@kernel.org>
Signed-off-by: default avatarJean Delvare <khali@linux-fr.org>
parent 4c03f68f
Loading
Loading
Loading
Loading
+114 −71
Original line number Diff line number Diff line
@@ -39,9 +39,10 @@
#define POLL_TIMEOUT       (2 * HZ)

/* SMBus mode*/
#define TWI_I2C_MODE_STANDARD		0x01
#define TWI_I2C_MODE_STANDARDSUB	0x02
#define TWI_I2C_MODE_COMBINED		0x04
#define TWI_I2C_MODE_STANDARD		1
#define TWI_I2C_MODE_STANDARDSUB	2
#define TWI_I2C_MODE_COMBINED		3
#define TWI_I2C_MODE_REPEAT		4

struct bfin_twi_iface {
	int			irq;
@@ -58,6 +59,9 @@ struct bfin_twi_iface {
	struct timer_list	timeout_timer;
	struct i2c_adapter	adap;
	struct completion	complete;
	struct i2c_msg 		*pmsg;
	int			msg_num;
	int			cur_msg;
};

static struct bfin_twi_iface twi_iface;
@@ -76,12 +80,16 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
		/* start receive immediately after complete sending in
		 * combine mode.
		 */
		else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
		else if (iface->cur_mode == TWI_I2C_MODE_COMBINED)
			bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
				| MDIR | RSTART);
		} else if (iface->manual_stop)
		else if (iface->manual_stop)
			bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
				| STOP);
		else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
				iface->cur_msg+1 < iface->msg_num)
			bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
				| RSTART);
		SSYNC();
		/* Clear status */
		bfin_write_TWI_INT_STAT(XMTSERV);
@@ -108,6 +116,11 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
			bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
				| STOP);
			SSYNC();
		} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
				iface->cur_msg+1 < iface->msg_num) {
			bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
				| RSTART);
			SSYNC();
		}
		/* Clear interrupt source */
		bfin_write_TWI_INT_STAT(RCVSERV);
@@ -119,7 +132,7 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
		bfin_write_TWI_MASTER_STAT(0x3e);
		bfin_write_TWI_MASTER_CTL(0);
		SSYNC();
		iface->result = -1;
		iface->result = -EIO;
		/* if both err and complete int stats are set, return proper
		 * results.
		 */
@@ -170,6 +183,42 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
			bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() |
				MEN | MDIR);
			SSYNC();
		} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
				iface->cur_msg+1 < iface->msg_num) {
			iface->cur_msg++;
			iface->transPtr = iface->pmsg[iface->cur_msg].buf;
			iface->writeNum = iface->readNum =
				iface->pmsg[iface->cur_msg].len;
			/* Set Transmit device address */
			bfin_write_TWI_MASTER_ADDR(
				iface->pmsg[iface->cur_msg].addr);
			if (iface->pmsg[iface->cur_msg].flags & I2C_M_RD)
				iface->read_write = I2C_SMBUS_READ;
			else {
				iface->read_write = I2C_SMBUS_WRITE;
				/* Transmit first data */
				if (iface->writeNum > 0) {
					bfin_write_TWI_XMT_DATA8(
						*(iface->transPtr++));
					iface->writeNum--;
					SSYNC();
				}
			}

			if (iface->pmsg[iface->cur_msg].len <= 255)
				bfin_write_TWI_MASTER_CTL(
				iface->pmsg[iface->cur_msg].len << 6);
			else {
				bfin_write_TWI_MASTER_CTL(0xff << 6);
				iface->manual_stop = 1;
			}
			/* remove restart bit and enable master receive */
			bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() &
				~RSTART);
			bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() |
				MEN | ((iface->read_write == I2C_SMBUS_READ) ?
				MDIR : 0));
			SSYNC();
		} else {
			iface->result = 1;
			bfin_write_TWI_INT_MASK(0);
@@ -221,7 +270,6 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap,
{
	struct bfin_twi_iface *iface = adap->algo_data;
	struct i2c_msg *pmsg;
	int i, ret;
	int rc = 0;

	if (!(bfin_read_TWI_CONTROL() & TWI_ENA))
@@ -231,17 +279,17 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap,
		yield();
	}

	ret = 0;
	for (i = 0; rc >= 0 && i < num; i++) {
		pmsg = &msgs[i];
	iface->pmsg = msgs;
	iface->msg_num = num;
	iface->cur_msg = 0;

	pmsg = &msgs[0];
	if (pmsg->flags & I2C_M_TEN) {
			dev_err(&(adap->dev), "i2c-bfin-twi: 10 bits addr "
				"not supported !\n");
			rc = -EINVAL;
			break;
		dev_err(&adap->dev, "10 bits addr not supported!\n");
		return -EINVAL;
	}

		iface->cur_mode = TWI_I2C_MODE_STANDARD;
	iface->cur_mode = TWI_I2C_MODE_REPEAT;
	iface->manual_stop = 0;
	iface->transPtr = pmsg->buf;
	iface->writeNum = iface->readNum = pmsg->len;
@@ -274,18 +322,15 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap,
	bfin_write_TWI_INT_STAT(MERR | MCOMP | XMTSERV | RCVSERV);

	/* Interrupt mask . Enable XMT, RCV interrupt */
		bfin_write_TWI_INT_MASK(MCOMP | MERR |
			((iface->read_write == I2C_SMBUS_READ)?
			RCVSERV : XMTSERV));
	bfin_write_TWI_INT_MASK(MCOMP | MERR | RCVSERV | XMTSERV);
	SSYNC();

		if (pmsg->len > 0 && pmsg->len <= 255)
	if (pmsg->len <= 255)
		bfin_write_TWI_MASTER_CTL(pmsg->len << 6);
		else if (pmsg->len > 255) {
	else {
		bfin_write_TWI_MASTER_CTL(0xff << 6);
		iface->manual_stop = 1;
		} else
			break;
	}

	iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
	add_timer(&iface->timeout_timer);
@@ -299,13 +344,11 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap,
	wait_for_completion(&iface->complete);

	rc = iface->result;
		if (rc == 1)
			ret++;
		else if (rc == -1)
			break;
	}

	return ret;
	if (rc == 1)
		return num;
	else
		return rc;
}

/*