diff options
author | Chris Pascoe <c.pascoe@itee.uq.edu.au> | 2007-12-15 01:31:09 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-01-25 16:04:03 -0500 |
commit | 5e3c5967da48b54e5d4ee528b51b565e2f7a3178 (patch) | |
tree | 8adc130fdbc521c9b383f63f70f78757b57e70c0 | |
parent | bc514710889ebb975be9e84ca9c04f698225b656 (diff) |
V4L/DVB (6857): cx23885: correctly join I2C writes and reads from same address
When an I2C message specifies a write then a read from the same I2C address,
we need to tell the chip to not release the bus between the message parts.
Signed-off-by: Chris Pascoe <c.pascoe@itee.uq.edu.au>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r-- | drivers/media/video/cx23885/cx23885-i2c.c | 53 |
1 files changed, 39 insertions, 14 deletions
diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 08e92df33168..20f3fb450f88 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c | |||
@@ -37,8 +37,10 @@ static unsigned int i2c_scan = 0; | |||
37 | module_param(i2c_scan, int, 0444); | 37 | module_param(i2c_scan, int, 0444); |
38 | MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); | 38 | MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); |
39 | 39 | ||
40 | #define dprintk(level,fmt, arg...) if (i2c_debug >= level) \ | 40 | #define dprintk(level, fmt, arg...) do { \ |
41 | printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg) | 41 | if (i2c_debug >= level) \ |
42 | printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg); \ | ||
43 | } while (0) | ||
42 | 44 | ||
43 | #define I2C_WAIT_DELAY 32 | 45 | #define I2C_WAIT_DELAY 32 |
44 | #define I2C_WAIT_RETRY 64 | 46 | #define I2C_WAIT_RETRY 64 |
@@ -77,14 +79,18 @@ static int i2c_wait_done(struct i2c_adapter *i2c_adap) | |||
77 | } | 79 | } |
78 | 80 | ||
79 | static int i2c_sendbytes(struct i2c_adapter *i2c_adap, | 81 | static int i2c_sendbytes(struct i2c_adapter *i2c_adap, |
80 | const struct i2c_msg *msg, int last) | 82 | const struct i2c_msg *msg, int joined_rlen) |
81 | { | 83 | { |
82 | struct cx23885_i2c *bus = i2c_adap->algo_data; | 84 | struct cx23885_i2c *bus = i2c_adap->algo_data; |
83 | struct cx23885_dev *dev = bus->dev; | 85 | struct cx23885_dev *dev = bus->dev; |
84 | u32 wdata, addr, ctrl; | 86 | u32 wdata, addr, ctrl; |
85 | int retval, cnt; | 87 | int retval, cnt; |
86 | 88 | ||
87 | dprintk(1, "%s(msg->len=%d, last=%d)\n", __FUNCTION__, msg->len, last); | 89 | if (joined_rlen) |
90 | dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __FUNCTION__, | ||
91 | msg->len, joined_rlen); | ||
92 | else | ||
93 | dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len); | ||
88 | 94 | ||
89 | /* Deal with i2c probe functions with zero payload */ | 95 | /* Deal with i2c probe functions with zero payload */ |
90 | if (msg->len == 0) { | 96 | if (msg->len == 0) { |
@@ -107,6 +113,8 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, | |||
107 | 113 | ||
108 | if (msg->len > 1) | 114 | if (msg->len > 1) |
109 | ctrl |= I2C_NOSTOP | I2C_EXTEND; | 115 | ctrl |= I2C_NOSTOP | I2C_EXTEND; |
116 | else if (joined_rlen) | ||
117 | ctrl |= I2C_NOSTOP; | ||
110 | 118 | ||
111 | cx_write(bus->reg_addr, addr); | 119 | cx_write(bus->reg_addr, addr); |
112 | cx_write(bus->reg_wdata, wdata); | 120 | cx_write(bus->reg_wdata, wdata); |
@@ -130,6 +138,8 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, | |||
130 | 138 | ||
131 | if (cnt < msg->len - 1) | 139 | if (cnt < msg->len - 1) |
132 | ctrl |= I2C_NOSTOP | I2C_EXTEND; | 140 | ctrl |= I2C_NOSTOP | I2C_EXTEND; |
141 | else if (joined_rlen) | ||
142 | ctrl |= I2C_NOSTOP; | ||
133 | 143 | ||
134 | cx_write(bus->reg_addr, addr); | 144 | cx_write(bus->reg_addr, addr); |
135 | cx_write(bus->reg_wdata, wdata); | 145 | cx_write(bus->reg_wdata, wdata); |
@@ -151,19 +161,22 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, | |||
151 | eio: | 161 | eio: |
152 | retval = -EIO; | 162 | retval = -EIO; |
153 | err: | 163 | err: |
154 | printk(" ERR: %d\n", retval); | 164 | if (i2c_debug) |
165 | printk(" ERR: %d\n", retval); | ||
155 | return retval; | 166 | return retval; |
156 | } | 167 | } |
157 | 168 | ||
158 | static int i2c_readbytes(struct i2c_adapter *i2c_adap, | 169 | static int i2c_readbytes(struct i2c_adapter *i2c_adap, |
159 | const struct i2c_msg *msg, int last) | 170 | const struct i2c_msg *msg, int joined) |
160 | { | 171 | { |
161 | struct cx23885_i2c *bus = i2c_adap->algo_data; | 172 | struct cx23885_i2c *bus = i2c_adap->algo_data; |
162 | struct cx23885_dev *dev = bus->dev; | 173 | struct cx23885_dev *dev = bus->dev; |
163 | u32 ctrl, cnt; | 174 | u32 ctrl, cnt; |
164 | int retval; | 175 | int retval; |
165 | 176 | ||
166 | dprintk(1, "%s(msg->len=%d, last=%d)\n", __FUNCTION__, msg->len, last); | 177 | |
178 | if (i2c_debug && !joined) | ||
179 | dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len); | ||
167 | 180 | ||
168 | /* Deal with i2c probe functions with zero payload */ | 181 | /* Deal with i2c probe functions with zero payload */ |
169 | if (msg->len == 0) { | 182 | if (msg->len == 0) { |
@@ -179,8 +192,12 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, | |||
179 | return 0; | 192 | return 0; |
180 | } | 193 | } |
181 | 194 | ||
182 | if (i2c_debug) | 195 | if (i2c_debug) { |
183 | printk(" <R %02x", (msg->addr << 1) + 1); | 196 | if (joined) |
197 | printk(" R"); | ||
198 | else | ||
199 | printk(" <R %02x", (msg->addr << 1) + 1); | ||
200 | } | ||
184 | 201 | ||
185 | for(cnt = 0; cnt < msg->len; cnt++) { | 202 | for(cnt = 0; cnt < msg->len; cnt++) { |
186 | 203 | ||
@@ -209,7 +226,8 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, | |||
209 | eio: | 226 | eio: |
210 | retval = -EIO; | 227 | retval = -EIO; |
211 | err: | 228 | err: |
212 | printk(" ERR: %d\n", retval); | 229 | if (i2c_debug) |
230 | printk(" ERR: %d\n", retval); | ||
213 | return retval; | 231 | return retval; |
214 | } | 232 | } |
215 | 233 | ||
@@ -227,15 +245,22 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap, | |||
227 | __FUNCTION__, num, msgs[i].addr, msgs[i].len); | 245 | __FUNCTION__, num, msgs[i].addr, msgs[i].len); |
228 | if (msgs[i].flags & I2C_M_RD) { | 246 | if (msgs[i].flags & I2C_M_RD) { |
229 | /* read */ | 247 | /* read */ |
230 | retval = i2c_readbytes(i2c_adap, &msgs[i], i+1 == num); | 248 | retval = i2c_readbytes(i2c_adap, &msgs[i], 0); |
249 | } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && | ||
250 | msgs[i].addr == msgs[i + 1].addr) { | ||
251 | /* write then read from same address */ | ||
252 | retval = i2c_sendbytes(i2c_adap, &msgs[i], | ||
253 | msgs[i + 1].len); | ||
231 | if (retval < 0) | 254 | if (retval < 0) |
232 | goto err; | 255 | goto err; |
256 | i++; | ||
257 | retval = i2c_readbytes(i2c_adap, &msgs[i], 1); | ||
233 | } else { | 258 | } else { |
234 | /* write */ | 259 | /* write */ |
235 | retval = i2c_sendbytes(i2c_adap, &msgs[i], i+1 == num); | 260 | retval = i2c_sendbytes(i2c_adap, &msgs[i], 0); |
236 | if (retval < 0) | ||
237 | goto err; | ||
238 | } | 261 | } |
262 | if (retval < 0) | ||
263 | goto err; | ||
239 | } | 264 | } |
240 | return num; | 265 | return num; |
241 | 266 | ||