Commit | Line | Data |
---|---|---|
74ba9207 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
e0d3bafd SD |
2 | /* |
3 | cx231xx-i2c.c - driver for Conexant Cx23100/101/102 USB video capture devices | |
4 | ||
5 | Copyright (C) 2008 <srinivasa.deevi at conexant dot com> | |
b9255176 SD |
6 | Based on em28xx driver |
7 | Based on Cx23885 driver | |
e0d3bafd | 8 | |
e0d3bafd SD |
9 | */ |
10 | ||
589dadf2 | 11 | #include "cx231xx.h" |
e0d3bafd SD |
12 | #include <linux/module.h> |
13 | #include <linux/kernel.h> | |
e0d3bafd | 14 | #include <linux/i2c.h> |
15c212dd | 15 | #include <linux/i2c-mux.h> |
e0d3bafd SD |
16 | #include <media/v4l2-common.h> |
17 | #include <media/tuner.h> | |
18 | ||
e0d3bafd | 19 | |
e0d3bafd SD |
20 | /* ----------------------------------------------------------- */ |
21 | ||
22 | static unsigned int i2c_scan; | |
23 | module_param(i2c_scan, int, 0444); | |
24 | MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); | |
25 | ||
26 | static unsigned int i2c_debug; | |
27 | module_param(i2c_debug, int, 0644); | |
28 | MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); | |
29 | ||
e0d3bafd SD |
30 | #define dprintk1(lvl, fmt, args...) \ |
31 | do { \ | |
32 | if (i2c_debug >= lvl) { \ | |
6e4f574b SD |
33 | printk(fmt, ##args); \ |
34 | } \ | |
e0d3bafd SD |
35 | } while (0) |
36 | ||
37 | #define dprintk2(lvl, fmt, args...) \ | |
38 | do { \ | |
39 | if (i2c_debug >= lvl) { \ | |
40 | printk(KERN_DEBUG "%s at %s: " fmt, \ | |
41 | dev->name, __func__ , ##args); \ | |
6e6a8b5a | 42 | } \ |
e0d3bafd SD |
43 | } while (0) |
44 | ||
8a025348 MS |
45 | static inline int get_real_i2c_port(struct cx231xx *dev, int bus_nr) |
46 | { | |
47 | if (bus_nr == 1) | |
48 | return dev->port_3_switch_enabled ? I2C_1_MUX_3 : I2C_1_MUX_1; | |
49 | return bus_nr; | |
50 | } | |
51 | ||
3f25ffa2 MCC |
52 | static inline bool is_tuner(struct cx231xx *dev, struct cx231xx_i2c *bus, |
53 | const struct i2c_msg *msg, int tuner_type) | |
54 | { | |
8a025348 MS |
55 | int i2c_port = get_real_i2c_port(dev, bus->nr); |
56 | ||
57 | if (i2c_port != dev->board.tuner_i2c_master) | |
3f25ffa2 MCC |
58 | return false; |
59 | ||
60 | if (msg->addr != dev->board.tuner_addr) | |
61 | return false; | |
62 | ||
63 | if (dev->tuner_type != tuner_type) | |
64 | return false; | |
65 | ||
66 | return true; | |
67 | } | |
68 | ||
e0d3bafd SD |
69 | /* |
70 | * cx231xx_i2c_send_bytes() | |
71 | */ | |
d4c06133 MCC |
72 | static int cx231xx_i2c_send_bytes(struct i2c_adapter *i2c_adap, |
73 | const struct i2c_msg *msg) | |
e0d3bafd SD |
74 | { |
75 | struct cx231xx_i2c *bus = i2c_adap->algo_data; | |
76 | struct cx231xx *dev = bus->dev; | |
84b5dbf3 MCC |
77 | struct cx231xx_i2c_xfer_data req_data; |
78 | int status = 0; | |
79 | u16 size = 0; | |
80 | u8 loop = 0; | |
81 | u8 saddr_len = 1; | |
82 | u8 *buf_ptr = NULL; | |
83 | u16 saddr = 0; | |
84 | u8 need_gpio = 0; | |
85 | ||
3f25ffa2 | 86 | if (is_tuner(dev, bus, msg, TUNER_XC5000)) { |
84b5dbf3 MCC |
87 | size = msg->len; |
88 | ||
89 | if (size == 2) { /* register write sub addr */ | |
6e4f574b SD |
90 | /* Just writing sub address will cause problem |
91 | * to XC5000. So ignore the request */ | |
84b5dbf3 | 92 | return 0; |
84b5dbf3 | 93 | } else if (size == 4) { /* register write with sub addr */ |
84b5dbf3 MCC |
94 | if (msg->len >= 2) |
95 | saddr = msg->buf[0] << 8 | msg->buf[1]; | |
96 | else if (msg->len == 1) | |
97 | saddr = msg->buf[0]; | |
98 | ||
99 | switch (saddr) { | |
100 | case 0x0000: /* start tuner calibration mode */ | |
101 | need_gpio = 1; | |
b9255176 SD |
102 | /* FW Loading is done */ |
103 | dev->xc_fw_load_done = 1; | |
84b5dbf3 MCC |
104 | break; |
105 | case 0x000D: /* Set signal source */ | |
106 | case 0x0001: /* Set TV standard - Video */ | |
107 | case 0x0002: /* Set TV standard - Audio */ | |
108 | case 0x0003: /* Set RF Frequency */ | |
109 | need_gpio = 1; | |
110 | break; | |
111 | default: | |
112 | if (dev->xc_fw_load_done) | |
113 | need_gpio = 1; | |
114 | break; | |
115 | } | |
116 | ||
117 | if (need_gpio) { | |
118 | dprintk1(1, | |
b9255176 SD |
119 | "GPIO WRITE: addr 0x%x, len %d, saddr 0x%x\n", |
120 | msg->addr, msg->len, saddr); | |
84b5dbf3 MCC |
121 | |
122 | return dev->cx231xx_gpio_i2c_write(dev, | |
123 | msg->addr, | |
124 | msg->buf, | |
125 | msg->len); | |
126 | } | |
84b5dbf3 MCC |
127 | } |
128 | ||
129 | /* special case for Xc5000 tuner case */ | |
130 | saddr_len = 1; | |
131 | ||
132 | /* adjust the length to correct length */ | |
133 | size -= saddr_len; | |
134 | buf_ptr = (u8 *) (msg->buf + 1); | |
135 | ||
136 | do { | |
137 | /* prepare xfer_data struct */ | |
138 | req_data.dev_addr = msg->addr; | |
139 | req_data.direction = msg->flags; | |
140 | req_data.saddr_len = saddr_len; | |
141 | req_data.saddr_dat = msg->buf[0]; | |
142 | req_data.buf_size = size > 16 ? 16 : size; | |
143 | req_data.p_buffer = (u8 *) (buf_ptr + loop * 16); | |
144 | ||
145 | bus->i2c_nostop = (size > 16) ? 1 : 0; | |
146 | bus->i2c_reserve = (loop == 0) ? 0 : 1; | |
147 | ||
148 | /* usb send command */ | |
149 | status = dev->cx231xx_send_usb_command(bus, &req_data); | |
150 | loop++; | |
151 | ||
152 | if (size >= 16) | |
153 | size -= 16; | |
154 | else | |
155 | size = 0; | |
156 | ||
157 | } while (size > 0); | |
158 | ||
159 | bus->i2c_nostop = 0; | |
160 | bus->i2c_reserve = 0; | |
161 | ||
162 | } else { /* regular case */ | |
163 | ||
164 | /* prepare xfer_data struct */ | |
165 | req_data.dev_addr = msg->addr; | |
166 | req_data.direction = msg->flags; | |
167 | req_data.saddr_len = 0; | |
168 | req_data.saddr_dat = 0; | |
169 | req_data.buf_size = msg->len; | |
170 | req_data.p_buffer = msg->buf; | |
171 | ||
172 | /* usb send command */ | |
173 | status = dev->cx231xx_send_usb_command(bus, &req_data); | |
174 | } | |
175 | ||
176 | return status < 0 ? status : 0; | |
e0d3bafd SD |
177 | } |
178 | ||
179 | /* | |
180 | * cx231xx_i2c_recv_bytes() | |
181 | * read a byte from the i2c device | |
182 | */ | |
183 | static int cx231xx_i2c_recv_bytes(struct i2c_adapter *i2c_adap, | |
84b5dbf3 | 184 | const struct i2c_msg *msg) |
e0d3bafd | 185 | { |
84b5dbf3 | 186 | struct cx231xx_i2c *bus = i2c_adap->algo_data; |
e0d3bafd | 187 | struct cx231xx *dev = bus->dev; |
84b5dbf3 MCC |
188 | struct cx231xx_i2c_xfer_data req_data; |
189 | int status = 0; | |
190 | u16 saddr = 0; | |
191 | u8 need_gpio = 0; | |
192 | ||
3f25ffa2 | 193 | if (is_tuner(dev, bus, msg, TUNER_XC5000)) { |
84b5dbf3 MCC |
194 | if (msg->len == 2) |
195 | saddr = msg->buf[0] << 8 | msg->buf[1]; | |
196 | else if (msg->len == 1) | |
197 | saddr = msg->buf[0]; | |
198 | ||
199 | if (dev->xc_fw_load_done) { | |
200 | ||
201 | switch (saddr) { | |
202 | case 0x0009: /* BUSY check */ | |
203 | dprintk1(1, | |
b9255176 SD |
204 | "GPIO R E A D: Special case BUSY check \n"); |
205 | /*Try read BUSY register, just set it to zero*/ | |
84b5dbf3 MCC |
206 | msg->buf[0] = 0; |
207 | if (msg->len == 2) | |
208 | msg->buf[1] = 0; | |
209 | return 0; | |
210 | case 0x0004: /* read Lock status */ | |
211 | need_gpio = 1; | |
212 | break; | |
213 | ||
214 | } | |
215 | ||
216 | if (need_gpio) { | |
b9255176 SD |
217 | /* this is a special case to handle Xceive tuner |
218 | clock stretch issue with gpio based I2C */ | |
219 | ||
84b5dbf3 | 220 | dprintk1(1, |
b9255176 SD |
221 | "GPIO R E A D: addr 0x%x, len %d, saddr 0x%x\n", |
222 | msg->addr, msg->len, | |
223 | msg->buf[0] << 8 | msg->buf[1]); | |
224 | ||
84b5dbf3 MCC |
225 | status = |
226 | dev->cx231xx_gpio_i2c_write(dev, msg->addr, | |
227 | msg->buf, | |
228 | msg->len); | |
229 | status = | |
230 | dev->cx231xx_gpio_i2c_read(dev, msg->addr, | |
231 | msg->buf, | |
232 | msg->len); | |
233 | return status; | |
234 | } | |
235 | } | |
236 | ||
237 | /* prepare xfer_data struct */ | |
238 | req_data.dev_addr = msg->addr; | |
239 | req_data.direction = msg->flags; | |
240 | req_data.saddr_len = msg->len; | |
241 | req_data.saddr_dat = msg->buf[0] << 8 | msg->buf[1]; | |
242 | req_data.buf_size = msg->len; | |
243 | req_data.p_buffer = msg->buf; | |
244 | ||
245 | /* usb send command */ | |
246 | status = dev->cx231xx_send_usb_command(bus, &req_data); | |
247 | ||
248 | } else { | |
249 | ||
250 | /* prepare xfer_data struct */ | |
251 | req_data.dev_addr = msg->addr; | |
252 | req_data.direction = msg->flags; | |
253 | req_data.saddr_len = 0; | |
254 | req_data.saddr_dat = 0; | |
255 | req_data.buf_size = msg->len; | |
256 | req_data.p_buffer = msg->buf; | |
257 | ||
258 | /* usb send command */ | |
259 | status = dev->cx231xx_send_usb_command(bus, &req_data); | |
260 | } | |
261 | ||
262 | return status < 0 ? status : 0; | |
e0d3bafd SD |
263 | } |
264 | ||
265 | /* | |
266 | * cx231xx_i2c_recv_bytes_with_saddr() | |
267 | * read a byte from the i2c device | |
268 | */ | |
269 | static int cx231xx_i2c_recv_bytes_with_saddr(struct i2c_adapter *i2c_adap, | |
84b5dbf3 MCC |
270 | const struct i2c_msg *msg1, |
271 | const struct i2c_msg *msg2) | |
e0d3bafd | 272 | { |
84b5dbf3 | 273 | struct cx231xx_i2c *bus = i2c_adap->algo_data; |
e0d3bafd | 274 | struct cx231xx *dev = bus->dev; |
84b5dbf3 MCC |
275 | struct cx231xx_i2c_xfer_data req_data; |
276 | int status = 0; | |
277 | u16 saddr = 0; | |
278 | u8 need_gpio = 0; | |
279 | ||
280 | if (msg1->len == 2) | |
281 | saddr = msg1->buf[0] << 8 | msg1->buf[1]; | |
282 | else if (msg1->len == 1) | |
283 | saddr = msg1->buf[0]; | |
284 | ||
3f25ffa2 | 285 | if (is_tuner(dev, bus, msg2, TUNER_XC5000)) { |
84b5dbf3 MCC |
286 | if ((msg2->len < 16)) { |
287 | ||
288 | dprintk1(1, | |
b9255176 SD |
289 | "i2c_read: addr 0x%x, len %d, saddr 0x%x, len %d\n", |
290 | msg2->addr, msg2->len, saddr, msg1->len); | |
84b5dbf3 MCC |
291 | |
292 | switch (saddr) { | |
293 | case 0x0008: /* read FW load status */ | |
294 | need_gpio = 1; | |
295 | break; | |
296 | case 0x0004: /* read Lock status */ | |
297 | need_gpio = 1; | |
298 | break; | |
299 | } | |
300 | ||
301 | if (need_gpio) { | |
302 | status = | |
303 | dev->cx231xx_gpio_i2c_write(dev, msg1->addr, | |
304 | msg1->buf, | |
305 | msg1->len); | |
306 | status = | |
307 | dev->cx231xx_gpio_i2c_read(dev, msg2->addr, | |
308 | msg2->buf, | |
309 | msg2->len); | |
310 | return status; | |
311 | } | |
312 | } | |
313 | } | |
314 | ||
315 | /* prepare xfer_data struct */ | |
316 | req_data.dev_addr = msg2->addr; | |
317 | req_data.direction = msg2->flags; | |
318 | req_data.saddr_len = msg1->len; | |
319 | req_data.saddr_dat = saddr; | |
320 | req_data.buf_size = msg2->len; | |
321 | req_data.p_buffer = msg2->buf; | |
322 | ||
323 | /* usb send command */ | |
324 | status = dev->cx231xx_send_usb_command(bus, &req_data); | |
325 | ||
326 | return status < 0 ? status : 0; | |
e0d3bafd SD |
327 | } |
328 | ||
329 | /* | |
330 | * cx231xx_i2c_check_for_device() | |
331 | * check if there is a i2c_device at the supplied address | |
332 | */ | |
333 | static int cx231xx_i2c_check_for_device(struct i2c_adapter *i2c_adap, | |
84b5dbf3 | 334 | const struct i2c_msg *msg) |
e0d3bafd | 335 | { |
84b5dbf3 | 336 | struct cx231xx_i2c *bus = i2c_adap->algo_data; |
e0d3bafd | 337 | struct cx231xx *dev = bus->dev; |
84b5dbf3 MCC |
338 | struct cx231xx_i2c_xfer_data req_data; |
339 | int status = 0; | |
0d88d091 | 340 | u8 buf[1]; |
e0d3bafd | 341 | |
84b5dbf3 MCC |
342 | /* prepare xfer_data struct */ |
343 | req_data.dev_addr = msg->addr; | |
0d88d091 | 344 | req_data.direction = I2C_M_RD; |
84b5dbf3 MCC |
345 | req_data.saddr_len = 0; |
346 | req_data.saddr_dat = 0; | |
0d88d091 MS |
347 | req_data.buf_size = 1; |
348 | req_data.p_buffer = buf; | |
e0d3bafd | 349 | |
84b5dbf3 MCC |
350 | /* usb send command */ |
351 | status = dev->cx231xx_send_usb_command(bus, &req_data); | |
e0d3bafd | 352 | |
84b5dbf3 | 353 | return status < 0 ? status : 0; |
e0d3bafd SD |
354 | } |
355 | ||
356 | /* | |
357 | * cx231xx_i2c_xfer() | |
358 | * the main i2c transfer function | |
359 | */ | |
360 | static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap, | |
84b5dbf3 | 361 | struct i2c_msg msgs[], int num) |
e0d3bafd SD |
362 | { |
363 | struct cx231xx_i2c *bus = i2c_adap->algo_data; | |
364 | struct cx231xx *dev = bus->dev; | |
365 | int addr, rc, i, byte; | |
366 | ||
64fbf444 | 367 | mutex_lock(&dev->i2c_lock); |
e0d3bafd SD |
368 | for (i = 0; i < num; i++) { |
369 | ||
1134e9d1 | 370 | addr = msgs[i].addr; |
e0d3bafd | 371 | |
1134e9d1 | 372 | dprintk2(2, "%s %s addr=0x%x len=%d:", |
e0d3bafd SD |
373 | (msgs[i].flags & I2C_M_RD) ? "read" : "write", |
374 | i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); | |
b9255176 SD |
375 | if (!msgs[i].len) { |
376 | /* no len: check only for device presence */ | |
e0d3bafd SD |
377 | rc = cx231xx_i2c_check_for_device(i2c_adap, &msgs[i]); |
378 | if (rc < 0) { | |
379 | dprintk2(2, " no device\n"); | |
b8383962 | 380 | mutex_unlock(&dev->i2c_lock); |
e0d3bafd SD |
381 | return rc; |
382 | } | |
383 | ||
384 | } else if (msgs[i].flags & I2C_M_RD) { | |
385 | /* read bytes */ | |
386 | rc = cx231xx_i2c_recv_bytes(i2c_adap, &msgs[i]); | |
387 | if (i2c_debug >= 2) { | |
388 | for (byte = 0; byte < msgs[i].len; byte++) | |
6f64eb0e | 389 | printk(KERN_CONT " %02x", msgs[i].buf[byte]); |
e0d3bafd SD |
390 | } |
391 | } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && | |
84b5dbf3 | 392 | msgs[i].addr == msgs[i + 1].addr |
64fbf444 | 393 | && (msgs[i].len <= 2) && (bus->nr < 3)) { |
1134e9d1 MS |
394 | /* write bytes */ |
395 | if (i2c_debug >= 2) { | |
396 | for (byte = 0; byte < msgs[i].len; byte++) | |
6f64eb0e MS |
397 | printk(KERN_CONT " %02x", msgs[i].buf[byte]); |
398 | printk(KERN_CONT "\n"); | |
1134e9d1 | 399 | } |
e0d3bafd | 400 | /* read bytes */ |
1134e9d1 MS |
401 | dprintk2(2, "plus %s %s addr=0x%x len=%d:", |
402 | (msgs[i+1].flags & I2C_M_RD) ? "read" : "write", | |
403 | i+1 == num - 1 ? "stop" : "nonstop", addr, msgs[i+1].len); | |
84b5dbf3 MCC |
404 | rc = cx231xx_i2c_recv_bytes_with_saddr(i2c_adap, |
405 | &msgs[i], | |
406 | &msgs[i + 1]); | |
e0d3bafd | 407 | if (i2c_debug >= 2) { |
1134e9d1 | 408 | for (byte = 0; byte < msgs[i+1].len; byte++) |
6f64eb0e | 409 | printk(KERN_CONT " %02x", msgs[i+1].buf[byte]); |
e0d3bafd | 410 | } |
84b5dbf3 | 411 | i++; |
e0d3bafd SD |
412 | } else { |
413 | /* write bytes */ | |
414 | if (i2c_debug >= 2) { | |
415 | for (byte = 0; byte < msgs[i].len; byte++) | |
6f64eb0e | 416 | printk(KERN_CONT " %02x", msgs[i].buf[byte]); |
e0d3bafd | 417 | } |
84b5dbf3 | 418 | rc = cx231xx_i2c_send_bytes(i2c_adap, &msgs[i]); |
e0d3bafd SD |
419 | } |
420 | if (rc < 0) | |
421 | goto err; | |
422 | if (i2c_debug >= 2) | |
6f64eb0e | 423 | printk(KERN_CONT "\n"); |
e0d3bafd | 424 | } |
64fbf444 | 425 | mutex_unlock(&dev->i2c_lock); |
e0d3bafd | 426 | return num; |
b9255176 | 427 | err: |
e0d3bafd | 428 | dprintk2(2, " ERROR: %i\n", rc); |
64fbf444 | 429 | mutex_unlock(&dev->i2c_lock); |
e0d3bafd SD |
430 | return rc; |
431 | } | |
432 | ||
433 | /* ----------------------------------------------------------- */ | |
434 | ||
435 | /* | |
436 | * functionality() | |
437 | */ | |
438 | static u32 functionality(struct i2c_adapter *adap) | |
439 | { | |
440 | return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; | |
441 | } | |
442 | ||
78f2c50b | 443 | static const struct i2c_algorithm cx231xx_algo = { |
84b5dbf3 | 444 | .master_xfer = cx231xx_i2c_xfer, |
e0d3bafd SD |
445 | .functionality = functionality, |
446 | }; | |
447 | ||
6843868f | 448 | static const struct i2c_adapter cx231xx_adap_template = { |
e0d3bafd | 449 | .owner = THIS_MODULE, |
e0d3bafd | 450 | .name = "cx231xx", |
e0d3bafd | 451 | .algo = &cx231xx_algo, |
e0d3bafd SD |
452 | }; |
453 | ||
e0d3bafd SD |
454 | /* ----------------------------------------------------------- */ |
455 | ||
456 | /* | |
457 | * i2c_devs | |
458 | * incomplete list of known devices | |
459 | */ | |
ec2a387e MCC |
460 | static const char *i2c_devs[128] = { |
461 | [0x20 >> 1] = "demod", | |
e0d3bafd SD |
462 | [0x60 >> 1] = "colibri", |
463 | [0x88 >> 1] = "hammerhead", | |
84b5dbf3 | 464 | [0x8e >> 1] = "CIR", |
e0d3bafd | 465 | [0x32 >> 1] = "GeminiIII", |
84b5dbf3 | 466 | [0x02 >> 1] = "Aquarius", |
e0d3bafd | 467 | [0xa0 >> 1] = "eeprom", |
3f25ffa2 MCC |
468 | [0xc0 >> 1] = "tuner", |
469 | [0xc2 >> 1] = "tuner", | |
e0d3bafd SD |
470 | }; |
471 | ||
472 | /* | |
473 | * cx231xx_do_i2c_scan() | |
474 | * check i2c address range for devices | |
475 | */ | |
7c894a3b | 476 | void cx231xx_do_i2c_scan(struct cx231xx *dev, int i2c_port) |
e0d3bafd SD |
477 | { |
478 | unsigned char buf; | |
479 | int i, rc; | |
4063987c AB |
480 | struct i2c_adapter *adap; |
481 | struct i2c_msg msg = { | |
482 | .flags = I2C_M_RD, | |
483 | .len = 1, | |
484 | .buf = &buf, | |
485 | }; | |
e0d3bafd | 486 | |
e4de03f2 MS |
487 | if (!i2c_scan) |
488 | return; | |
489 | ||
77e97ba2 MCC |
490 | /* Don't generate I2C errors during scan */ |
491 | dev->i2c_scan_running = true; | |
4063987c | 492 | adap = cx231xx_get_i2c_adap(dev, i2c_port); |
7c894a3b | 493 | |
e0d3bafd | 494 | for (i = 0; i < 128; i++) { |
4063987c AB |
495 | msg.addr = i; |
496 | rc = i2c_transfer(adap, &msg, 1); | |
497 | ||
e0d3bafd SD |
498 | if (rc < 0) |
499 | continue; | |
336fea92 | 500 | dev_info(dev->dev, |
ac550faa MCC |
501 | "i2c scan: found device @ port %d addr 0x%x [%s]\n", |
502 | i2c_port, | |
b7085c08 MCC |
503 | i << 1, |
504 | i2c_devs[i] ? i2c_devs[i] : "???"); | |
e0d3bafd | 505 | } |
77e97ba2 MCC |
506 | |
507 | dev->i2c_scan_running = false; | |
e0d3bafd SD |
508 | } |
509 | ||
e0d3bafd SD |
510 | /* |
511 | * cx231xx_i2c_register() | |
512 | * register i2c bus | |
513 | */ | |
514 | int cx231xx_i2c_register(struct cx231xx_i2c *bus) | |
515 | { | |
84b5dbf3 | 516 | struct cx231xx *dev = bus->dev; |
e0d3bafd | 517 | |
93a24578 AP |
518 | if (!dev->cx231xx_send_usb_command) |
519 | return -EINVAL; | |
e0d3bafd | 520 | |
23ba641a | 521 | bus->i2c_adap = cx231xx_adap_template; |
336fea92 | 522 | bus->i2c_adap.dev.parent = dev->dev; |
e0d3bafd | 523 | |
8da4f2d5 | 524 | snprintf(bus->i2c_adap.name, sizeof(bus->i2c_adap.name), "%s-%d", bus->dev->name, bus->nr); |
e0d3bafd | 525 | |
e0d3bafd | 526 | bus->i2c_adap.algo_data = bus; |
b1196126 | 527 | i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev); |
54b1b41f | 528 | bus->i2c_rc = i2c_add_adapter(&bus->i2c_adap); |
e0d3bafd | 529 | |
e4de03f2 | 530 | if (0 != bus->i2c_rc) |
336fea92 | 531 | dev_warn(dev->dev, |
b7085c08 | 532 | "i2c bus %d register FAILED\n", bus->nr); |
e0d3bafd SD |
533 | |
534 | return bus->i2c_rc; | |
535 | } | |
536 | ||
537 | /* | |
538 | * cx231xx_i2c_unregister() | |
539 | * unregister i2c_bus | |
540 | */ | |
22469022 | 541 | void cx231xx_i2c_unregister(struct cx231xx_i2c *bus) |
e0d3bafd | 542 | { |
8e2803ff PR |
543 | if (!bus->i2c_rc) |
544 | i2c_del_adapter(&bus->i2c_adap); | |
e0d3bafd | 545 | } |
c3c3f1ae | 546 | |
15c212dd MS |
547 | /* |
548 | * cx231xx_i2c_mux_select() | |
549 | * switch i2c master number 1 between port1 and port3 | |
550 | */ | |
05e0dfd0 | 551 | static int cx231xx_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan_id) |
15c212dd | 552 | { |
05e0dfd0 | 553 | struct cx231xx *dev = i2c_mux_priv(muxc); |
15c212dd MS |
554 | |
555 | return cx231xx_enable_i2c_port_3(dev, chan_id); | |
556 | } | |
557 | ||
05e0dfd0 PR |
558 | int cx231xx_i2c_mux_create(struct cx231xx *dev) |
559 | { | |
560 | dev->muxc = i2c_mux_alloc(&dev->i2c_bus[1].i2c_adap, dev->dev, 2, 0, 0, | |
561 | cx231xx_i2c_mux_select, NULL); | |
562 | if (!dev->muxc) | |
563 | return -ENOMEM; | |
564 | dev->muxc->priv = dev; | |
565 | return 0; | |
566 | } | |
567 | ||
15c212dd MS |
568 | int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no) |
569 | { | |
fec1982d | 570 | return i2c_mux_add_adapter(dev->muxc, 0, mux_no); |
15c212dd MS |
571 | } |
572 | ||
05e0dfd0 | 573 | void cx231xx_i2c_mux_unregister(struct cx231xx *dev) |
15c212dd | 574 | { |
05e0dfd0 | 575 | i2c_mux_del_adapters(dev->muxc); |
15c212dd MS |
576 | } |
577 | ||
c3c3f1ae MS |
578 | struct i2c_adapter *cx231xx_get_i2c_adap(struct cx231xx *dev, int i2c_port) |
579 | { | |
580 | switch (i2c_port) { | |
581 | case I2C_0: | |
582 | return &dev->i2c_bus[0].i2c_adap; | |
583 | case I2C_1: | |
584 | return &dev->i2c_bus[1].i2c_adap; | |
585 | case I2C_2: | |
586 | return &dev->i2c_bus[2].i2c_adap; | |
587 | case I2C_1_MUX_1: | |
05e0dfd0 | 588 | return dev->muxc->adapter[0]; |
c3c3f1ae | 589 | case I2C_1_MUX_3: |
05e0dfd0 | 590 | return dev->muxc->adapter[1]; |
c3c3f1ae | 591 | default: |
4001dfb4 | 592 | BUG(); |
c3c3f1ae MS |
593 | } |
594 | } | |
595 | EXPORT_SYMBOL_GPL(cx231xx_get_i2c_adap); |