aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/media/dvb/dvb-usb/m920x.c52
-rw-r--r--drivers/media/dvb/dvb-usb/m920x.h28
2 files changed, 47 insertions, 33 deletions
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c
index 621819f6597..08469ccabb7 100644
--- a/drivers/media/dvb/dvb-usb/m920x.c
+++ b/drivers/media/dvb/dvb-usb/m920x.c
@@ -141,43 +141,43 @@ static int m9206_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
int i, j;
int ret = 0;
+ if (!num)
+ return -EINVAL;
+
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
return -EAGAIN;
for (i = 0; i < num; i++) {
- if (msg[i].flags & I2C_M_RD) {
-
- if ((ret = m9206_write(d->udev, M9206_I2C, (msg[i].addr << 1) | 0x01, 0x80)) != 0)
+ if (msg[i].flags & (I2C_M_NO_RD_ACK|I2C_M_IGNORE_NAK|I2C_M_TEN)) {
+ ret = -ENOTSUPP;
+ goto unlock;
+ }
+ /* Send START & address/RW bit */
+ if (!(msg[i].flags & I2C_M_NOSTART)) {
+ if ((ret = m9206_write(d->udev, M9206_I2C, (msg[i].addr<<1)|(msg[i].flags&I2C_M_RD?0x01:00), 0x80)) != 0)
goto unlock;
-
- for(j = 0; j < msg[i].len; j++) {
- if (j + 1 == msg[i].len && i + 1== num) {
- if ((ret = m9206_read(d->udev, M9206_I2C, 0x0, 0x60, &msg[i].buf[j], msg[i].len)) != 0)
- goto unlock;
- } else {
- if ((ret = m9206_read(d->udev, M9206_I2C, 0x0, 0x21, &msg[i].buf[j], msg[i].len)) != 0)
- goto unlock;
- }
+ /* Should check for ack here, if we knew how. */
+ }
+ if (msg[i].flags & I2C_M_RD) {
+ for (j = 0; j < msg[i].len; j++) {
+ /* Last byte of transaction? Send STOP, otherwise send ACK. */
+ int stop = (i+1 == num && j+1 == msg[i].len)?0x40:0x01;
+ if ((ret = m9206_read(d->udev, M9206_I2C, 0x0, 0x20|stop, &msg[i].buf[j], 1)) != 0)
+ goto unlock;
}
-
} else {
- if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].addr << 1, 0x80)) != 0)
- goto unlock;
-
- for(j = 0; j < msg[i].len; j++) {
- if (j + 1 == msg[i].len && i + 1== num) {
- if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[j], 0x40)) != 0)
- goto unlock;
-
- } else {
- if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[j], 0x0)) != 0)
- goto unlock;
- }
+ for (j = 0; j < msg[i].len; j++) {
+ /* Last byte of transaction? Then send STOP. */
+ int stop = (i+1 == num && j+1 == msg[i].len)?0x40:0x00;
+ if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[j], stop)) != 0)
+ goto unlock;
+ /* Should check for ack here too. */
}
}
}
ret = num;
- unlock:
+
+unlock:
mutex_unlock(&d->i2c_mutex);
return ret;
diff --git a/drivers/media/dvb/dvb-usb/m920x.h b/drivers/media/dvb/dvb-usb/m920x.h
index c5ef592cbfe..7dd3db65c80 100644
--- a/drivers/media/dvb/dvb-usb/m920x.h
+++ b/drivers/media/dvb/dvb-usb/m920x.h
@@ -37,13 +37,27 @@ this sequence works:
(0x21 in byte)*
0x60 in byte
-_my guess_:
-0x80: begin i2c transfer using address. value=address<<1|(reading?1:0)
-0x00: write byte
-0x21: read byte, more to follow
-0x40: write last byte of message sequence
-0x60: read last byte of message sequence
- */
+Guess at API of the I2C function:
+I2C operation is done one byte at a time with USB control messages. The
+index the messages is sent to is made up of a set of flags that control
+the I2C bus state:
+0x80: Send START condition. After a START condition, one would normally
+ always send the 7-bit slave I2C address as the 7 MSB, followed by
+ the read/write bit as the LSB.
+0x40: Send STOP condition. This should be set on the last byte of an
+ I2C transaction.
+0x20: Read a byte from the slave. As opposed to writing a byte to the
+ slave. The slave will normally not produce any data unless you
+ set the R/W bit to 1 when sending the slave's address after the
+ START condition.
+0x01: Respond with ACK, as opposed to a NACK. For a multi-byte read,
+ the master should send an ACK, that is pull SDA low during the 9th
+ clock cycle, after every byte but the last. This flags only makes
+ sense when bit 0x20 is set, indicating a read.
+
+What any other bits might mean, or how to get the slave's ACK/NACK
+response to a write, is unknown.
+*/
struct m9206_state {
u16 filters[M9206_MAX_FILTERS];