Commit | Line | Data |
---|---|---|
e0d3bafd SD |
1 | /* |
2 | cx231xx-i2c.c - driver for Conexant Cx23100/101/102 USB video capture devices | |
3 | ||
4 | Copyright (C) 2008 <srinivasa.deevi at conexant dot com> | |
b9255176 SD |
5 | Based on em28xx driver |
6 | Based on Cx23885 driver | |
e0d3bafd SD |
7 | |
8 | This program is free software; you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation; either version 2 of the License, or | |
11 | (at your option) any later version. | |
12 | ||
13 | This program is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with this program; if not, write to the Free Software | |
20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
21 | */ | |
22 | ||
23 | #include <linux/module.h> | |
24 | #include <linux/kernel.h> | |
25 | #include <linux/usb.h> | |
26 | #include <linux/i2c.h> | |
27 | #include <media/v4l2-common.h> | |
28 | #include <media/tuner.h> | |
29 | ||
30 | #include "cx231xx.h" | |
31 | ||
e0d3bafd SD |
32 | /* ----------------------------------------------------------- */ |
33 | ||
34 | static unsigned int i2c_scan; | |
35 | module_param(i2c_scan, int, 0444); | |
36 | MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); | |
37 | ||
38 | static unsigned int i2c_debug; | |
39 | module_param(i2c_debug, int, 0644); | |
40 | MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); | |
41 | ||
e0d3bafd SD |
42 | #define dprintk1(lvl, fmt, args...) \ |
43 | do { \ | |
44 | if (i2c_debug >= lvl) { \ | |
6e4f574b SD |
45 | printk(fmt, ##args); \ |
46 | } \ | |
e0d3bafd SD |
47 | } while (0) |
48 | ||
49 | #define dprintk2(lvl, fmt, args...) \ | |
50 | do { \ | |
51 | if (i2c_debug >= lvl) { \ | |
52 | printk(KERN_DEBUG "%s at %s: " fmt, \ | |
53 | dev->name, __func__ , ##args); \ | |
54 | } \ | |
55 | } while (0) | |
56 | ||
3f25ffa2 MCC |
57 | static inline bool is_tuner(struct cx231xx *dev, struct cx231xx_i2c *bus, |
58 | const struct i2c_msg *msg, int tuner_type) | |
59 | { | |
60 | if (bus->nr != dev->board.tuner_i2c_master) | |
61 | return false; | |
62 | ||
63 | if (msg->addr != dev->board.tuner_addr) | |
64 | return false; | |
65 | ||
66 | if (dev->tuner_type != tuner_type) | |
67 | return false; | |
68 | ||
69 | return true; | |
70 | } | |
71 | ||
e0d3bafd SD |
72 | /* |
73 | * cx231xx_i2c_send_bytes() | |
74 | */ | |
75 | int cx231xx_i2c_send_bytes(struct i2c_adapter *i2c_adap, | |
84b5dbf3 | 76 | const struct i2c_msg *msg) |
e0d3bafd SD |
77 | { |
78 | struct cx231xx_i2c *bus = i2c_adap->algo_data; | |
79 | struct cx231xx *dev = bus->dev; | |
84b5dbf3 MCC |
80 | struct cx231xx_i2c_xfer_data req_data; |
81 | int status = 0; | |
82 | u16 size = 0; | |
83 | u8 loop = 0; | |
84 | u8 saddr_len = 1; | |
85 | u8 *buf_ptr = NULL; | |
86 | u16 saddr = 0; | |
87 | u8 need_gpio = 0; | |
88 | ||
3f25ffa2 | 89 | if (is_tuner(dev, bus, msg, TUNER_XC5000)) { |
84b5dbf3 MCC |
90 | size = msg->len; |
91 | ||
92 | if (size == 2) { /* register write sub addr */ | |
6e4f574b SD |
93 | /* Just writing sub address will cause problem |
94 | * to XC5000. So ignore the request */ | |
84b5dbf3 | 95 | return 0; |
84b5dbf3 | 96 | } else if (size == 4) { /* register write with sub addr */ |
84b5dbf3 MCC |
97 | if (msg->len >= 2) |
98 | saddr = msg->buf[0] << 8 | msg->buf[1]; | |
99 | else if (msg->len == 1) | |
100 | saddr = msg->buf[0]; | |
101 | ||
102 | switch (saddr) { | |
103 | case 0x0000: /* start tuner calibration mode */ | |
104 | need_gpio = 1; | |
b9255176 SD |
105 | /* FW Loading is done */ |
106 | dev->xc_fw_load_done = 1; | |
84b5dbf3 MCC |
107 | break; |
108 | case 0x000D: /* Set signal source */ | |
109 | case 0x0001: /* Set TV standard - Video */ | |
110 | case 0x0002: /* Set TV standard - Audio */ | |
111 | case 0x0003: /* Set RF Frequency */ | |
112 | need_gpio = 1; | |
113 | break; | |
114 | default: | |
115 | if (dev->xc_fw_load_done) | |
116 | need_gpio = 1; | |
117 | break; | |
118 | } | |
119 | ||
120 | if (need_gpio) { | |
121 | dprintk1(1, | |
b9255176 SD |
122 | "GPIO WRITE: addr 0x%x, len %d, saddr 0x%x\n", |
123 | msg->addr, msg->len, saddr); | |
84b5dbf3 MCC |
124 | |
125 | return dev->cx231xx_gpio_i2c_write(dev, | |
126 | msg->addr, | |
127 | msg->buf, | |
128 | msg->len); | |
129 | } | |
84b5dbf3 MCC |
130 | } |
131 | ||
132 | /* special case for Xc5000 tuner case */ | |
133 | saddr_len = 1; | |
134 | ||
135 | /* adjust the length to correct length */ | |
136 | size -= saddr_len; | |
137 | buf_ptr = (u8 *) (msg->buf + 1); | |
138 | ||
139 | do { | |
140 | /* prepare xfer_data struct */ | |
141 | req_data.dev_addr = msg->addr; | |
142 | req_data.direction = msg->flags; | |
143 | req_data.saddr_len = saddr_len; | |
144 | req_data.saddr_dat = msg->buf[0]; | |
145 | req_data.buf_size = size > 16 ? 16 : size; | |
146 | req_data.p_buffer = (u8 *) (buf_ptr + loop * 16); | |
147 | ||
148 | bus->i2c_nostop = (size > 16) ? 1 : 0; | |
149 | bus->i2c_reserve = (loop == 0) ? 0 : 1; | |
150 | ||
151 | /* usb send command */ | |
152 | status = dev->cx231xx_send_usb_command(bus, &req_data); | |
153 | loop++; | |
154 | ||
155 | if (size >= 16) | |
156 | size -= 16; | |
157 | else | |
158 | size = 0; | |
159 | ||
160 | } while (size > 0); | |
161 | ||
162 | bus->i2c_nostop = 0; | |
163 | bus->i2c_reserve = 0; | |
164 | ||
165 | } else { /* regular case */ | |
166 | ||
167 | /* prepare xfer_data struct */ | |
168 | req_data.dev_addr = msg->addr; | |
169 | req_data.direction = msg->flags; | |
170 | req_data.saddr_len = 0; | |
171 | req_data.saddr_dat = 0; | |
172 | req_data.buf_size = msg->len; | |
173 | req_data.p_buffer = msg->buf; | |
174 | ||
175 | /* usb send command */ | |
176 | status = dev->cx231xx_send_usb_command(bus, &req_data); | |
177 | } | |
178 | ||
179 | return status < 0 ? status : 0; | |
e0d3bafd SD |
180 | } |
181 | ||
182 | /* | |
183 | * cx231xx_i2c_recv_bytes() | |
184 | * read a byte from the i2c device | |
185 | */ | |
186 | static int cx231xx_i2c_recv_bytes(struct i2c_adapter *i2c_adap, | |
84b5dbf3 | 187 | const struct i2c_msg *msg) |
e0d3bafd | 188 | { |
84b5dbf3 | 189 | struct cx231xx_i2c *bus = i2c_adap->algo_data; |
e0d3bafd | 190 | struct cx231xx *dev = bus->dev; |
84b5dbf3 MCC |
191 | struct cx231xx_i2c_xfer_data req_data; |
192 | int status = 0; | |
193 | u16 saddr = 0; | |
194 | u8 need_gpio = 0; | |
195 | ||
3f25ffa2 | 196 | if (is_tuner(dev, bus, msg, TUNER_XC5000)) { |
84b5dbf3 MCC |
197 | if (msg->len == 2) |
198 | saddr = msg->buf[0] << 8 | msg->buf[1]; | |
199 | else if (msg->len == 1) | |
200 | saddr = msg->buf[0]; | |
201 | ||
202 | if (dev->xc_fw_load_done) { | |
203 | ||
204 | switch (saddr) { | |
205 | case 0x0009: /* BUSY check */ | |
206 | dprintk1(1, | |
b9255176 SD |
207 | "GPIO R E A D: Special case BUSY check \n"); |
208 | /*Try read BUSY register, just set it to zero*/ | |
84b5dbf3 MCC |
209 | msg->buf[0] = 0; |
210 | if (msg->len == 2) | |
211 | msg->buf[1] = 0; | |
212 | return 0; | |
213 | case 0x0004: /* read Lock status */ | |
214 | need_gpio = 1; | |
215 | break; | |
216 | ||
217 | } | |
218 | ||
219 | if (need_gpio) { | |
b9255176 SD |
220 | /* this is a special case to handle Xceive tuner |
221 | clock stretch issue with gpio based I2C */ | |
222 | ||
84b5dbf3 | 223 | dprintk1(1, |
b9255176 SD |
224 | "GPIO R E A D: addr 0x%x, len %d, saddr 0x%x\n", |
225 | msg->addr, msg->len, | |
226 | msg->buf[0] << 8 | msg->buf[1]); | |
227 | ||
84b5dbf3 MCC |
228 | status = |
229 | dev->cx231xx_gpio_i2c_write(dev, msg->addr, | |
230 | msg->buf, | |
231 | msg->len); | |
232 | status = | |
233 | dev->cx231xx_gpio_i2c_read(dev, msg->addr, | |
234 | msg->buf, | |
235 | msg->len); | |
236 | return status; | |
237 | } | |
238 | } | |
239 | ||
240 | /* prepare xfer_data struct */ | |
241 | req_data.dev_addr = msg->addr; | |
242 | req_data.direction = msg->flags; | |
243 | req_data.saddr_len = msg->len; | |
244 | req_data.saddr_dat = msg->buf[0] << 8 | msg->buf[1]; | |
245 | req_data.buf_size = msg->len; | |
246 | req_data.p_buffer = msg->buf; | |
247 | ||
248 | /* usb send command */ | |
249 | status = dev->cx231xx_send_usb_command(bus, &req_data); | |
250 | ||
251 | } else { | |
252 | ||
253 | /* prepare xfer_data struct */ | |
254 | req_data.dev_addr = msg->addr; | |
255 | req_data.direction = msg->flags; | |
256 | req_data.saddr_len = 0; | |
257 | req_data.saddr_dat = 0; | |
258 | req_data.buf_size = msg->len; | |
259 | req_data.p_buffer = msg->buf; | |
260 | ||
261 | /* usb send command */ | |
262 | status = dev->cx231xx_send_usb_command(bus, &req_data); | |
263 | } | |
264 | ||
265 | return status < 0 ? status : 0; | |
e0d3bafd SD |
266 | } |
267 | ||
268 | /* | |
269 | * cx231xx_i2c_recv_bytes_with_saddr() | |
270 | * read a byte from the i2c device | |
271 | */ | |
272 | static int cx231xx_i2c_recv_bytes_with_saddr(struct i2c_adapter *i2c_adap, | |
84b5dbf3 MCC |
273 | const struct i2c_msg *msg1, |
274 | const struct i2c_msg *msg2) | |
e0d3bafd | 275 | { |
84b5dbf3 | 276 | struct cx231xx_i2c *bus = i2c_adap->algo_data; |
e0d3bafd | 277 | struct cx231xx *dev = bus->dev; |
84b5dbf3 MCC |
278 | struct cx231xx_i2c_xfer_data req_data; |
279 | int status = 0; | |
280 | u16 saddr = 0; | |
281 | u8 need_gpio = 0; | |
282 | ||
283 | if (msg1->len == 2) | |
284 | saddr = msg1->buf[0] << 8 | msg1->buf[1]; | |
285 | else if (msg1->len == 1) | |
286 | saddr = msg1->buf[0]; | |
287 | ||
3f25ffa2 | 288 | if (is_tuner(dev, bus, msg2, TUNER_XC5000)) { |
84b5dbf3 MCC |
289 | if ((msg2->len < 16)) { |
290 | ||
291 | dprintk1(1, | |
b9255176 SD |
292 | "i2c_read: addr 0x%x, len %d, saddr 0x%x, len %d\n", |
293 | msg2->addr, msg2->len, saddr, msg1->len); | |
84b5dbf3 MCC |
294 | |
295 | switch (saddr) { | |
296 | case 0x0008: /* read FW load status */ | |
297 | need_gpio = 1; | |
298 | break; | |
299 | case 0x0004: /* read Lock status */ | |
300 | need_gpio = 1; | |
301 | break; | |
302 | } | |
303 | ||
304 | if (need_gpio) { | |
305 | status = | |
306 | dev->cx231xx_gpio_i2c_write(dev, msg1->addr, | |
307 | msg1->buf, | |
308 | msg1->len); | |
309 | status = | |
310 | dev->cx231xx_gpio_i2c_read(dev, msg2->addr, | |
311 | msg2->buf, | |
312 | msg2->len); | |
313 | return status; | |
314 | } | |
315 | } | |
316 | } | |
317 | ||
318 | /* prepare xfer_data struct */ | |
319 | req_data.dev_addr = msg2->addr; | |
320 | req_data.direction = msg2->flags; | |
321 | req_data.saddr_len = msg1->len; | |
322 | req_data.saddr_dat = saddr; | |
323 | req_data.buf_size = msg2->len; | |
324 | req_data.p_buffer = msg2->buf; | |
325 | ||
326 | /* usb send command */ | |
327 | status = dev->cx231xx_send_usb_command(bus, &req_data); | |
328 | ||
329 | return status < 0 ? status : 0; | |
e0d3bafd SD |
330 | } |
331 | ||
332 | /* | |
333 | * cx231xx_i2c_check_for_device() | |
334 | * check if there is a i2c_device at the supplied address | |
335 | */ | |
336 | static int cx231xx_i2c_check_for_device(struct i2c_adapter *i2c_adap, | |
84b5dbf3 | 337 | const struct i2c_msg *msg) |
e0d3bafd | 338 | { |
84b5dbf3 | 339 | struct cx231xx_i2c *bus = i2c_adap->algo_data; |
e0d3bafd | 340 | struct cx231xx *dev = bus->dev; |
84b5dbf3 MCC |
341 | struct cx231xx_i2c_xfer_data req_data; |
342 | int status = 0; | |
e0d3bafd | 343 | |
84b5dbf3 MCC |
344 | /* prepare xfer_data struct */ |
345 | req_data.dev_addr = msg->addr; | |
346 | req_data.direction = msg->flags; | |
347 | req_data.saddr_len = 0; | |
348 | req_data.saddr_dat = 0; | |
349 | req_data.buf_size = 0; | |
350 | req_data.p_buffer = NULL; | |
e0d3bafd | 351 | |
84b5dbf3 MCC |
352 | /* usb send command */ |
353 | status = dev->cx231xx_send_usb_command(bus, &req_data); | |
e0d3bafd | 354 | |
84b5dbf3 | 355 | return status < 0 ? status : 0; |
e0d3bafd SD |
356 | } |
357 | ||
358 | /* | |
359 | * cx231xx_i2c_xfer() | |
360 | * the main i2c transfer function | |
361 | */ | |
362 | static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap, | |
84b5dbf3 | 363 | struct i2c_msg msgs[], int num) |
e0d3bafd SD |
364 | { |
365 | struct cx231xx_i2c *bus = i2c_adap->algo_data; | |
366 | struct cx231xx *dev = bus->dev; | |
367 | int addr, rc, i, byte; | |
368 | ||
369 | if (num <= 0) | |
370 | return 0; | |
64fbf444 | 371 | mutex_lock(&dev->i2c_lock); |
e0d3bafd SD |
372 | for (i = 0; i < num; i++) { |
373 | ||
374 | addr = msgs[i].addr >> 1; | |
375 | ||
376 | dprintk2(2, "%s %s addr=%x len=%d:", | |
377 | (msgs[i].flags & I2C_M_RD) ? "read" : "write", | |
378 | i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); | |
b9255176 SD |
379 | if (!msgs[i].len) { |
380 | /* no len: check only for device presence */ | |
e0d3bafd SD |
381 | rc = cx231xx_i2c_check_for_device(i2c_adap, &msgs[i]); |
382 | if (rc < 0) { | |
383 | dprintk2(2, " no device\n"); | |
b8383962 | 384 | mutex_unlock(&dev->i2c_lock); |
e0d3bafd SD |
385 | return rc; |
386 | } | |
387 | ||
388 | } else if (msgs[i].flags & I2C_M_RD) { | |
389 | /* read bytes */ | |
390 | rc = cx231xx_i2c_recv_bytes(i2c_adap, &msgs[i]); | |
391 | if (i2c_debug >= 2) { | |
392 | for (byte = 0; byte < msgs[i].len; byte++) | |
393 | printk(" %02x", msgs[i].buf[byte]); | |
394 | } | |
395 | } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && | |
84b5dbf3 | 396 | msgs[i].addr == msgs[i + 1].addr |
64fbf444 | 397 | && (msgs[i].len <= 2) && (bus->nr < 3)) { |
e0d3bafd | 398 | /* read bytes */ |
84b5dbf3 MCC |
399 | rc = cx231xx_i2c_recv_bytes_with_saddr(i2c_adap, |
400 | &msgs[i], | |
401 | &msgs[i + 1]); | |
e0d3bafd SD |
402 | if (i2c_debug >= 2) { |
403 | for (byte = 0; byte < msgs[i].len; byte++) | |
404 | printk(" %02x", msgs[i].buf[byte]); | |
405 | } | |
84b5dbf3 | 406 | i++; |
e0d3bafd SD |
407 | } else { |
408 | /* write bytes */ | |
409 | if (i2c_debug >= 2) { | |
410 | for (byte = 0; byte < msgs[i].len; byte++) | |
411 | printk(" %02x", msgs[i].buf[byte]); | |
412 | } | |
84b5dbf3 | 413 | rc = cx231xx_i2c_send_bytes(i2c_adap, &msgs[i]); |
e0d3bafd SD |
414 | } |
415 | if (rc < 0) | |
416 | goto err; | |
417 | if (i2c_debug >= 2) | |
418 | printk("\n"); | |
419 | } | |
64fbf444 | 420 | mutex_unlock(&dev->i2c_lock); |
e0d3bafd | 421 | return num; |
b9255176 | 422 | err: |
e0d3bafd | 423 | dprintk2(2, " ERROR: %i\n", rc); |
64fbf444 | 424 | mutex_unlock(&dev->i2c_lock); |
e0d3bafd SD |
425 | return rc; |
426 | } | |
427 | ||
428 | /* ----------------------------------------------------------- */ | |
429 | ||
430 | /* | |
431 | * functionality() | |
432 | */ | |
433 | static u32 functionality(struct i2c_adapter *adap) | |
434 | { | |
435 | return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; | |
436 | } | |
437 | ||
e0d3bafd | 438 | static struct i2c_algorithm cx231xx_algo = { |
84b5dbf3 | 439 | .master_xfer = cx231xx_i2c_xfer, |
e0d3bafd SD |
440 | .functionality = functionality, |
441 | }; | |
442 | ||
443 | static struct i2c_adapter cx231xx_adap_template = { | |
444 | .owner = THIS_MODULE, | |
e0d3bafd | 445 | .name = "cx231xx", |
e0d3bafd | 446 | .algo = &cx231xx_algo, |
e0d3bafd SD |
447 | }; |
448 | ||
449 | static struct i2c_client cx231xx_client_template = { | |
450 | .name = "cx231xx internal", | |
451 | }; | |
452 | ||
453 | /* ----------------------------------------------------------- */ | |
454 | ||
455 | /* | |
456 | * i2c_devs | |
457 | * incomplete list of known devices | |
458 | */ | |
459 | static char *i2c_devs[128] = { | |
460 | [0x60 >> 1] = "colibri", | |
461 | [0x88 >> 1] = "hammerhead", | |
84b5dbf3 | 462 | [0x8e >> 1] = "CIR", |
e0d3bafd | 463 | [0x32 >> 1] = "GeminiIII", |
84b5dbf3 | 464 | [0x02 >> 1] = "Aquarius", |
e0d3bafd | 465 | [0xa0 >> 1] = "eeprom", |
3f25ffa2 MCC |
466 | [0xc0 >> 1] = "tuner", |
467 | [0xc2 >> 1] = "tuner", | |
e0d3bafd SD |
468 | }; |
469 | ||
470 | /* | |
471 | * cx231xx_do_i2c_scan() | |
472 | * check i2c address range for devices | |
473 | */ | |
474 | void cx231xx_do_i2c_scan(struct cx231xx *dev, struct i2c_client *c) | |
475 | { | |
476 | unsigned char buf; | |
477 | int i, rc; | |
478 | ||
84b5dbf3 | 479 | cx231xx_info(": Checking for I2C devices ..\n"); |
e0d3bafd SD |
480 | for (i = 0; i < 128; i++) { |
481 | c->addr = i; | |
482 | rc = i2c_master_recv(c, &buf, 0); | |
483 | if (rc < 0) | |
484 | continue; | |
485 | cx231xx_info("%s: i2c scan: found device @ 0x%x [%s]\n", | |
84b5dbf3 MCC |
486 | dev->name, i << 1, |
487 | i2c_devs[i] ? i2c_devs[i] : "???"); | |
e0d3bafd | 488 | } |
84b5dbf3 | 489 | cx231xx_info(": Completed Checking for I2C devices.\n"); |
e0d3bafd SD |
490 | } |
491 | ||
e0d3bafd SD |
492 | /* |
493 | * cx231xx_i2c_register() | |
494 | * register i2c bus | |
495 | */ | |
496 | int cx231xx_i2c_register(struct cx231xx_i2c *bus) | |
497 | { | |
84b5dbf3 | 498 | struct cx231xx *dev = bus->dev; |
e0d3bafd | 499 | |
84b5dbf3 | 500 | BUG_ON(!dev->cx231xx_send_usb_command); |
e0d3bafd | 501 | |
84b5dbf3 MCC |
502 | memcpy(&bus->i2c_adap, &cx231xx_adap_template, sizeof(bus->i2c_adap)); |
503 | memcpy(&bus->i2c_algo, &cx231xx_algo, sizeof(bus->i2c_algo)); | |
e0d3bafd SD |
504 | memcpy(&bus->i2c_client, &cx231xx_client_template, |
505 | sizeof(bus->i2c_client)); | |
506 | ||
507 | bus->i2c_adap.dev.parent = &dev->udev->dev; | |
508 | ||
84b5dbf3 | 509 | strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name)); |
e0d3bafd SD |
510 | |
511 | bus->i2c_algo.data = bus; | |
512 | bus->i2c_adap.algo_data = bus; | |
b1196126 | 513 | i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev); |
e0d3bafd SD |
514 | i2c_add_adapter(&bus->i2c_adap); |
515 | ||
516 | bus->i2c_client.adapter = &bus->i2c_adap; | |
517 | ||
518 | if (0 == bus->i2c_rc) { | |
e0d3bafd SD |
519 | if (i2c_scan) |
520 | cx231xx_do_i2c_scan(dev, &bus->i2c_client); | |
521 | } else | |
522 | cx231xx_warn("%s: i2c bus %d register FAILED\n", | |
84b5dbf3 | 523 | dev->name, bus->nr); |
e0d3bafd SD |
524 | |
525 | return bus->i2c_rc; | |
526 | } | |
527 | ||
528 | /* | |
529 | * cx231xx_i2c_unregister() | |
530 | * unregister i2c_bus | |
531 | */ | |
532 | int cx231xx_i2c_unregister(struct cx231xx_i2c *bus) | |
533 | { | |
534 | i2c_del_adapter(&bus->i2c_adap); | |
535 | return 0; | |
536 | } |