i2c: sh_mobile: don't send a stop condition by default inside transfers
By default there should be no stop bit on I2C between single messages within transfers. Fix the driver to comply and only send a stop bit at the end of transfers or if I2C_M_STOP is set. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Wolfram Sang <wolfram@the-dreams.de>
This commit is contained in:
parent
4b3823184f
commit
e789029761
@ -38,21 +38,21 @@
|
|||||||
/* Transmit operation: */
|
/* Transmit operation: */
|
||||||
/* */
|
/* */
|
||||||
/* 0 byte transmit */
|
/* 0 byte transmit */
|
||||||
/* BUS: S A8 ACK P */
|
/* BUS: S A8 ACK P(*) */
|
||||||
/* IRQ: DTE WAIT */
|
/* IRQ: DTE WAIT */
|
||||||
/* ICIC: */
|
/* ICIC: */
|
||||||
/* ICCR: 0x94 0x90 */
|
/* ICCR: 0x94 0x90 */
|
||||||
/* ICDR: A8 */
|
/* ICDR: A8 */
|
||||||
/* */
|
/* */
|
||||||
/* 1 byte transmit */
|
/* 1 byte transmit */
|
||||||
/* BUS: S A8 ACK D8(1) ACK P */
|
/* BUS: S A8 ACK D8(1) ACK P(*) */
|
||||||
/* IRQ: DTE WAIT WAIT */
|
/* IRQ: DTE WAIT WAIT */
|
||||||
/* ICIC: -DTE */
|
/* ICIC: -DTE */
|
||||||
/* ICCR: 0x94 0x90 */
|
/* ICCR: 0x94 0x90 */
|
||||||
/* ICDR: A8 D8(1) */
|
/* ICDR: A8 D8(1) */
|
||||||
/* */
|
/* */
|
||||||
/* 2 byte transmit */
|
/* 2 byte transmit */
|
||||||
/* BUS: S A8 ACK D8(1) ACK D8(2) ACK P */
|
/* BUS: S A8 ACK D8(1) ACK D8(2) ACK P(*) */
|
||||||
/* IRQ: DTE WAIT WAIT WAIT */
|
/* IRQ: DTE WAIT WAIT WAIT */
|
||||||
/* ICIC: -DTE */
|
/* ICIC: -DTE */
|
||||||
/* ICCR: 0x94 0x90 */
|
/* ICCR: 0x94 0x90 */
|
||||||
@ -66,20 +66,20 @@
|
|||||||
/* 0 byte receive - not supported since slave may hold SDA low */
|
/* 0 byte receive - not supported since slave may hold SDA low */
|
||||||
/* */
|
/* */
|
||||||
/* 1 byte receive [TX] | [RX] */
|
/* 1 byte receive [TX] | [RX] */
|
||||||
/* BUS: S A8 ACK | D8(1) ACK P */
|
/* BUS: S A8 ACK | D8(1) ACK P(*) */
|
||||||
/* IRQ: DTE WAIT | WAIT DTE */
|
/* IRQ: DTE WAIT | WAIT DTE */
|
||||||
/* ICIC: -DTE | +DTE */
|
/* ICIC: -DTE | +DTE */
|
||||||
/* ICCR: 0x94 0x81 | 0xc0 */
|
/* ICCR: 0x94 0x81 | 0xc0 */
|
||||||
/* ICDR: A8 | D8(1) */
|
/* ICDR: A8 | D8(1) */
|
||||||
/* */
|
/* */
|
||||||
/* 2 byte receive [TX]| [RX] */
|
/* 2 byte receive [TX]| [RX] */
|
||||||
/* BUS: S A8 ACK | D8(1) ACK D8(2) ACK P */
|
/* BUS: S A8 ACK | D8(1) ACK D8(2) ACK P(*) */
|
||||||
/* IRQ: DTE WAIT | WAIT WAIT DTE */
|
/* IRQ: DTE WAIT | WAIT WAIT DTE */
|
||||||
/* ICIC: -DTE | +DTE */
|
/* ICIC: -DTE | +DTE */
|
||||||
/* ICCR: 0x94 0x81 | 0xc0 */
|
/* ICCR: 0x94 0x81 | 0xc0 */
|
||||||
/* ICDR: A8 | D8(1) D8(2) */
|
/* ICDR: A8 | D8(1) D8(2) */
|
||||||
/* */
|
/* */
|
||||||
/* 3 byte receive [TX] | [RX] */
|
/* 3 byte receive [TX] | [RX] (*) */
|
||||||
/* BUS: S A8 ACK | D8(1) ACK D8(2) ACK D8(3) ACK P */
|
/* BUS: S A8 ACK | D8(1) ACK D8(2) ACK D8(3) ACK P */
|
||||||
/* IRQ: DTE WAIT | WAIT WAIT WAIT DTE */
|
/* IRQ: DTE WAIT | WAIT WAIT WAIT DTE */
|
||||||
/* ICIC: -DTE | +DTE */
|
/* ICIC: -DTE | +DTE */
|
||||||
@ -94,7 +94,7 @@
|
|||||||
/* SDA ___\___XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAAAAAAAAA___/ */
|
/* SDA ___\___XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAAAAAAAAA___/ */
|
||||||
/* SCL \_/1\_/2\_/3\_/4\_/5\_/6\_/7\_/8\___/9\_____/ */
|
/* SCL \_/1\_/2\_/3\_/4\_/5\_/6\_/7\_/8\___/9\_____/ */
|
||||||
/* */
|
/* */
|
||||||
/* S D7 D6 D5 D4 D3 D2 D1 D0 P */
|
/* S D7 D6 D5 D4 D3 D2 D1 D0 P(*) */
|
||||||
/* ___ */
|
/* ___ */
|
||||||
/* WAIT IRQ ________________________________/ \___________ */
|
/* WAIT IRQ ________________________________/ \___________ */
|
||||||
/* TACK IRQ ____________________________________/ \_______ */
|
/* TACK IRQ ____________________________________/ \_______ */
|
||||||
@ -103,6 +103,11 @@
|
|||||||
/* _______________________________________________ */
|
/* _______________________________________________ */
|
||||||
/* BUSY __/ \_ */
|
/* BUSY __/ \_ */
|
||||||
/* */
|
/* */
|
||||||
|
/* (*) The STOP condition is only sent by the master at the end of the last */
|
||||||
|
/* I2C message or if the I2C_M_STOP flag is set. Similarly, the BUSY bit is */
|
||||||
|
/* only cleared after the STOP condition, so, between messages we have to */
|
||||||
|
/* poll for the DTE bit. */
|
||||||
|
/* */
|
||||||
|
|
||||||
enum sh_mobile_i2c_op {
|
enum sh_mobile_i2c_op {
|
||||||
OP_START = 0,
|
OP_START = 0,
|
||||||
@ -132,6 +137,7 @@ struct sh_mobile_i2c_data {
|
|||||||
struct i2c_msg *msg;
|
struct i2c_msg *msg;
|
||||||
int pos;
|
int pos;
|
||||||
int sr;
|
int sr;
|
||||||
|
bool send_stop;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IIC_FLAG_HAS_ICIC67 (1 << 0)
|
#define IIC_FLAG_HAS_ICIC67 (1 << 0)
|
||||||
@ -322,7 +328,7 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
|
|||||||
break;
|
break;
|
||||||
case OP_TX_STOP: /* write data and issue a stop afterwards */
|
case OP_TX_STOP: /* write data and issue a stop afterwards */
|
||||||
iic_wr(pd, ICDR, data);
|
iic_wr(pd, ICDR, data);
|
||||||
iic_wr(pd, ICCR, 0x90);
|
iic_wr(pd, ICCR, pd->send_stop ? 0x90 : 0x94);
|
||||||
break;
|
break;
|
||||||
case OP_TX_TO_RX: /* select read mode */
|
case OP_TX_TO_RX: /* select read mode */
|
||||||
iic_wr(pd, ICCR, 0x81);
|
iic_wr(pd, ICCR, 0x81);
|
||||||
@ -469,13 +475,15 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
|
|||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg)
|
static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
|
||||||
|
bool do_init)
|
||||||
{
|
{
|
||||||
if (usr_msg->len == 0 && (usr_msg->flags & I2C_M_RD)) {
|
if (usr_msg->len == 0 && (usr_msg->flags & I2C_M_RD)) {
|
||||||
dev_err(pd->dev, "Unsupported zero length i2c read\n");
|
dev_err(pd->dev, "Unsupported zero length i2c read\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (do_init) {
|
||||||
/* Initialize channel registers */
|
/* Initialize channel registers */
|
||||||
iic_set_clr(pd, ICCR, 0, ICCR_ICE);
|
iic_set_clr(pd, ICCR, 0, ICCR_ICE);
|
||||||
|
|
||||||
@ -485,6 +493,7 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg)
|
|||||||
/* Set the clock */
|
/* Set the clock */
|
||||||
iic_wr(pd, ICCL, pd->iccl & 0xff);
|
iic_wr(pd, ICCL, pd->iccl & 0xff);
|
||||||
iic_wr(pd, ICCH, pd->icch & 0xff);
|
iic_wr(pd, ICCH, pd->icch & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
pd->msg = usr_msg;
|
pd->msg = usr_msg;
|
||||||
pd->pos = -1;
|
pd->pos = -1;
|
||||||
@ -495,6 +504,30 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int poll_dte(struct sh_mobile_i2c_data *pd)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 1000; i; i--) {
|
||||||
|
u_int8_t val = iic_rd(pd, ICSR);
|
||||||
|
|
||||||
|
if (val & ICSR_DTE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (val & ICSR_TACK)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
udelay(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!i) {
|
||||||
|
dev_warn(pd->dev, "Timeout polling for DTE!\n");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int poll_busy(struct sh_mobile_i2c_data *pd)
|
static int poll_busy(struct sh_mobile_i2c_data *pd)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -539,12 +572,15 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
|
|||||||
|
|
||||||
/* Process all messages */
|
/* Process all messages */
|
||||||
for (i = 0; i < num; i++) {
|
for (i = 0; i < num; i++) {
|
||||||
|
bool do_start = pd->send_stop || !i;
|
||||||
msg = &msgs[i];
|
msg = &msgs[i];
|
||||||
|
pd->send_stop = i == num - 1 || msg->flags & I2C_M_STOP;
|
||||||
|
|
||||||
err = start_ch(pd, msg);
|
err = start_ch(pd, msg, do_start);
|
||||||
if (err)
|
if (err)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (do_start)
|
||||||
i2c_op(pd, OP_START, 0);
|
i2c_op(pd, OP_START, 0);
|
||||||
|
|
||||||
/* The interrupt handler takes care of the rest... */
|
/* The interrupt handler takes care of the rest... */
|
||||||
@ -557,7 +593,10 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pd->send_stop)
|
||||||
err = poll_busy(pd);
|
err = poll_busy(pd);
|
||||||
|
else
|
||||||
|
err = poll_dte(pd);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -571,7 +610,7 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
|
|||||||
|
|
||||||
static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter)
|
static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter)
|
||||||
{
|
{
|
||||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct i2c_algorithm sh_mobile_i2c_algorithm = {
|
static struct i2c_algorithm sh_mobile_i2c_algorithm = {
|
||||||
|
Loading…
Reference in New Issue
Block a user