]>
Commit | Line | Data |
---|---|---|
a6c2ba28 | 1 | /* |
f7abcd38 | 2 | em28xx-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices |
a6c2ba28 | 3 | |
f7abcd38 MCC |
4 | Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it> |
5 | Markus Rechberger <mrechberger@gmail.com> | |
2e7c6dc3 | 6 | Mauro Carvalho Chehab <mchehab@infradead.org> |
f7abcd38 | 7 | Sascha Sommer <saschasommer@freenet.de> |
a6c2ba28 | 8 | |
9 | This program is free software; you can redistribute it and/or modify | |
10 | it under the terms of the GNU General Public License as published by | |
11 | the Free Software Foundation; either version 2 of the License, or | |
12 | (at your option) any later version. | |
13 | ||
14 | This program is distributed in the hope that it will be useful, | |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | GNU General Public License for more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
20 | along with this program; if not, write to the Free Software | |
21 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
22 | */ | |
23 | ||
24 | #include <linux/module.h> | |
25 | #include <linux/kernel.h> | |
26 | #include <linux/usb.h> | |
27 | #include <linux/i2c.h> | |
a6c2ba28 | 28 | |
f7abcd38 | 29 | #include "em28xx.h" |
6c362c8e | 30 | #include "tuner-xc2028.h" |
5e453dc7 | 31 | #include <media/v4l2-common.h> |
d5e52653 | 32 | #include <media/tuner.h> |
a6c2ba28 | 33 | |
34 | /* ----------------------------------------------------------- */ | |
35 | ||
ff699e6b | 36 | static unsigned int i2c_scan; |
a6c2ba28 | 37 | module_param(i2c_scan, int, 0444); |
38 | MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); | |
39 | ||
ff699e6b | 40 | static unsigned int i2c_debug; |
a6c2ba28 | 41 | module_param(i2c_debug, int, 0644); |
42 | MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); | |
43 | ||
6ea54d93 DSL |
44 | |
45 | #define dprintk1(lvl, fmt, args...) \ | |
46 | do { \ | |
47 | if (i2c_debug >= lvl) { \ | |
48 | printk(fmt, ##args); \ | |
49 | } \ | |
50 | } while (0) | |
51 | ||
52 | #define dprintk2(lvl, fmt, args...) \ | |
53 | do { \ | |
54 | if (i2c_debug >= lvl) { \ | |
55 | printk(KERN_DEBUG "%s at %s: " fmt, \ | |
56 | dev->name, __func__ , ##args); \ | |
57 | } \ | |
58 | } while (0) | |
a6c2ba28 | 59 | |
60 | /* | |
596d92d5 MCC |
61 | * em2800_i2c_send_max4() |
62 | * send up to 4 bytes to the i2c device | |
63 | */ | |
3acf2809 | 64 | static int em2800_i2c_send_max4(struct em28xx *dev, unsigned char addr, |
596d92d5 MCC |
65 | char *buf, int len) |
66 | { | |
67 | int ret; | |
68 | int write_timeout; | |
69 | unsigned char b2[6]; | |
70 | BUG_ON(len < 1 || len > 4); | |
71 | b2[5] = 0x80 + len - 1; | |
72 | b2[4] = addr; | |
73 | b2[3] = buf[0]; | |
74 | if (len > 1) | |
75 | b2[2] = buf[1]; | |
76 | if (len > 2) | |
77 | b2[1] = buf[2]; | |
78 | if (len > 3) | |
79 | b2[0] = buf[3]; | |
80 | ||
3acf2809 | 81 | ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len); |
596d92d5 | 82 | if (ret != 2 + len) { |
beb7dd86 | 83 | em28xx_warn("writing to i2c device failed (error=%i)\n", ret); |
596d92d5 MCC |
84 | return -EIO; |
85 | } | |
86 | for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0; | |
87 | write_timeout -= 5) { | |
3acf2809 | 88 | ret = dev->em28xx_read_reg(dev, 0x05); |
596d92d5 MCC |
89 | if (ret == 0x80 + len - 1) |
90 | return len; | |
e8e41da4 | 91 | msleep(5); |
596d92d5 | 92 | } |
3acf2809 | 93 | em28xx_warn("i2c write timed out\n"); |
596d92d5 MCC |
94 | return -EIO; |
95 | } | |
96 | ||
97 | /* | |
98 | * em2800_i2c_send_bytes() | |
99 | */ | |
100 | static int em2800_i2c_send_bytes(void *data, unsigned char addr, char *buf, | |
101 | short len) | |
102 | { | |
103 | char *bufPtr = buf; | |
104 | int ret; | |
105 | int wrcount = 0; | |
106 | int count; | |
107 | int maxLen = 4; | |
3acf2809 | 108 | struct em28xx *dev = (struct em28xx *)data; |
596d92d5 MCC |
109 | while (len > 0) { |
110 | count = (len > maxLen) ? maxLen : len; | |
111 | ret = em2800_i2c_send_max4(dev, addr, bufPtr, count); | |
112 | if (ret > 0) { | |
113 | len -= count; | |
114 | bufPtr += count; | |
115 | wrcount += count; | |
116 | } else | |
117 | return (ret < 0) ? ret : -EFAULT; | |
118 | } | |
119 | return wrcount; | |
120 | } | |
121 | ||
122 | /* | |
123 | * em2800_i2c_check_for_device() | |
124 | * check if there is a i2c_device at the supplied address | |
125 | */ | |
3acf2809 | 126 | static int em2800_i2c_check_for_device(struct em28xx *dev, unsigned char addr) |
596d92d5 MCC |
127 | { |
128 | char msg; | |
129 | int ret; | |
130 | int write_timeout; | |
131 | msg = addr; | |
3acf2809 | 132 | ret = dev->em28xx_write_regs(dev, 0x04, &msg, 1); |
596d92d5 | 133 | if (ret < 0) { |
3acf2809 | 134 | em28xx_warn("setting i2c device address failed (error=%i)\n", |
596d92d5 MCC |
135 | ret); |
136 | return ret; | |
137 | } | |
138 | msg = 0x84; | |
3acf2809 | 139 | ret = dev->em28xx_write_regs(dev, 0x05, &msg, 1); |
596d92d5 | 140 | if (ret < 0) { |
3acf2809 | 141 | em28xx_warn("preparing i2c read failed (error=%i)\n", ret); |
596d92d5 MCC |
142 | return ret; |
143 | } | |
144 | for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0; | |
145 | write_timeout -= 5) { | |
d45b9b8a HV |
146 | unsigned reg = dev->em28xx_read_reg(dev, 0x5); |
147 | ||
148 | if (reg == 0x94) | |
596d92d5 | 149 | return -ENODEV; |
d45b9b8a | 150 | else if (reg == 0x84) |
596d92d5 | 151 | return 0; |
e8e41da4 | 152 | msleep(5); |
596d92d5 MCC |
153 | } |
154 | return -ENODEV; | |
155 | } | |
156 | ||
157 | /* | |
158 | * em2800_i2c_recv_bytes() | |
159 | * read from the i2c device | |
160 | */ | |
3acf2809 | 161 | static int em2800_i2c_recv_bytes(struct em28xx *dev, unsigned char addr, |
596d92d5 MCC |
162 | char *buf, int len) |
163 | { | |
164 | int ret; | |
165 | /* check for the device and set i2c read address */ | |
166 | ret = em2800_i2c_check_for_device(dev, addr); | |
167 | if (ret) { | |
3acf2809 | 168 | em28xx_warn |
596d92d5 MCC |
169 | ("preparing read at i2c address 0x%x failed (error=%i)\n", |
170 | addr, ret); | |
171 | return ret; | |
172 | } | |
3acf2809 | 173 | ret = dev->em28xx_read_reg_req_len(dev, 0x0, 0x3, buf, len); |
596d92d5 | 174 | if (ret < 0) { |
3acf2809 | 175 | em28xx_warn("reading from i2c device at 0x%x failed (error=%i)", |
596d92d5 MCC |
176 | addr, ret); |
177 | return ret; | |
178 | } | |
179 | return ret; | |
180 | } | |
181 | ||
182 | /* | |
3acf2809 | 183 | * em28xx_i2c_send_bytes() |
a6c2ba28 | 184 | * untested for more than 4 bytes |
185 | */ | |
3acf2809 | 186 | static int em28xx_i2c_send_bytes(void *data, unsigned char addr, char *buf, |
596d92d5 | 187 | short len, int stop) |
a6c2ba28 | 188 | { |
189 | int wrcount = 0; | |
3acf2809 | 190 | struct em28xx *dev = (struct em28xx *)data; |
a6c2ba28 | 191 | |
3acf2809 | 192 | wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len); |
a6c2ba28 | 193 | |
194 | return wrcount; | |
195 | } | |
196 | ||
197 | /* | |
3acf2809 | 198 | * em28xx_i2c_recv_bytes() |
a6c2ba28 | 199 | * read a byte from the i2c device |
200 | */ | |
3acf2809 | 201 | static int em28xx_i2c_recv_bytes(struct em28xx *dev, unsigned char addr, |
596d92d5 | 202 | char *buf, int len) |
a6c2ba28 | 203 | { |
204 | int ret; | |
3acf2809 | 205 | ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len); |
a6c2ba28 | 206 | if (ret < 0) { |
3acf2809 | 207 | em28xx_warn("reading i2c device failed (error=%i)\n", ret); |
a6c2ba28 | 208 | return ret; |
209 | } | |
3acf2809 | 210 | if (dev->em28xx_read_reg(dev, 0x5) != 0) |
a6c2ba28 | 211 | return -ENODEV; |
212 | return ret; | |
213 | } | |
214 | ||
215 | /* | |
3acf2809 | 216 | * em28xx_i2c_check_for_device() |
a6c2ba28 | 217 | * check if there is a i2c_device at the supplied address |
218 | */ | |
3acf2809 | 219 | static int em28xx_i2c_check_for_device(struct em28xx *dev, unsigned char addr) |
a6c2ba28 | 220 | { |
221 | char msg; | |
222 | int ret; | |
223 | msg = addr; | |
224 | ||
3acf2809 | 225 | ret = dev->em28xx_read_reg_req(dev, 2, addr); |
a6c2ba28 | 226 | if (ret < 0) { |
3acf2809 | 227 | em28xx_warn("reading from i2c device failed (error=%i)\n", ret); |
a6c2ba28 | 228 | return ret; |
229 | } | |
3acf2809 | 230 | if (dev->em28xx_read_reg(dev, 0x5) != 0) |
a6c2ba28 | 231 | return -ENODEV; |
232 | return 0; | |
233 | } | |
234 | ||
235 | /* | |
3acf2809 | 236 | * em28xx_i2c_xfer() |
a6c2ba28 | 237 | * the main i2c transfer function |
238 | */ | |
3acf2809 | 239 | static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, |
a6c2ba28 | 240 | struct i2c_msg msgs[], int num) |
241 | { | |
3acf2809 | 242 | struct em28xx *dev = i2c_adap->algo_data; |
a6c2ba28 | 243 | int addr, rc, i, byte; |
244 | ||
245 | if (num <= 0) | |
246 | return 0; | |
247 | for (i = 0; i < num; i++) { | |
248 | addr = msgs[i].addr << 1; | |
6ea54d93 | 249 | dprintk2(2, "%s %s addr=%x len=%d:", |
a6c2ba28 | 250 | (msgs[i].flags & I2C_M_RD) ? "read" : "write", |
251 | i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); | |
6ea54d93 | 252 | if (!msgs[i].len) { /* no len: check only for device presence */ |
596d92d5 MCC |
253 | if (dev->is_em2800) |
254 | rc = em2800_i2c_check_for_device(dev, addr); | |
255 | else | |
3acf2809 | 256 | rc = em28xx_i2c_check_for_device(dev, addr); |
a6c2ba28 | 257 | if (rc < 0) { |
6ea54d93 | 258 | dprintk2(2, " no device\n"); |
a6c2ba28 | 259 | return rc; |
260 | } | |
261 | ||
596d92d5 | 262 | } else if (msgs[i].flags & I2C_M_RD) { |
a6c2ba28 | 263 | /* read bytes */ |
596d92d5 MCC |
264 | if (dev->is_em2800) |
265 | rc = em2800_i2c_recv_bytes(dev, addr, | |
266 | msgs[i].buf, | |
267 | msgs[i].len); | |
268 | else | |
3acf2809 | 269 | rc = em28xx_i2c_recv_bytes(dev, addr, |
596d92d5 MCC |
270 | msgs[i].buf, |
271 | msgs[i].len); | |
6ea54d93 DSL |
272 | if (i2c_debug >= 2) { |
273 | for (byte = 0; byte < msgs[i].len; byte++) | |
a6c2ba28 | 274 | printk(" %02x", msgs[i].buf[byte]); |
a6c2ba28 | 275 | } |
276 | } else { | |
277 | /* write bytes */ | |
6ea54d93 | 278 | if (i2c_debug >= 2) { |
a6c2ba28 | 279 | for (byte = 0; byte < msgs[i].len; byte++) |
280 | printk(" %02x", msgs[i].buf[byte]); | |
281 | } | |
596d92d5 MCC |
282 | if (dev->is_em2800) |
283 | rc = em2800_i2c_send_bytes(dev, addr, | |
284 | msgs[i].buf, | |
285 | msgs[i].len); | |
286 | else | |
3acf2809 | 287 | rc = em28xx_i2c_send_bytes(dev, addr, |
596d92d5 MCC |
288 | msgs[i].buf, |
289 | msgs[i].len, | |
290 | i == num - 1); | |
a6c2ba28 | 291 | } |
e8e41da4 MR |
292 | if (rc < 0) |
293 | goto err; | |
6ea54d93 | 294 | if (i2c_debug >= 2) |
a6c2ba28 | 295 | printk("\n"); |
296 | } | |
297 | ||
298 | return num; | |
6ea54d93 DSL |
299 | err: |
300 | dprintk2(2, " ERROR: %i\n", rc); | |
a6c2ba28 | 301 | return rc; |
302 | } | |
303 | ||
03910cc3 MCC |
304 | /* based on linux/sunrpc/svcauth.h and linux/hash.h |
305 | * The original hash function returns a different value, if arch is x86_64 | |
306 | * or i386. | |
307 | */ | |
308 | static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits) | |
309 | { | |
310 | unsigned long hash = 0; | |
311 | unsigned long l = 0; | |
312 | int len = 0; | |
313 | unsigned char c; | |
314 | do { | |
315 | if (len == length) { | |
316 | c = (char)len; | |
317 | len = -1; | |
318 | } else | |
319 | c = *buf++; | |
320 | l = (l << 8) | c; | |
321 | len++; | |
322 | if ((len & (32 / 8 - 1)) == 0) | |
323 | hash = ((hash^l) * 0x9e370001UL); | |
324 | } while (len); | |
325 | ||
326 | return (hash >> (32 - bits)) & 0xffffffffUL; | |
327 | } | |
328 | ||
3acf2809 | 329 | static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) |
a6c2ba28 | 330 | { |
331 | unsigned char buf, *p = eedata; | |
3acf2809 | 332 | struct em28xx_eeprom *em_eeprom = (void *)eedata; |
a6c2ba28 | 333 | int i, err, size = len, block; |
334 | ||
335 | dev->i2c_client.addr = 0xa0 >> 1; | |
596d92d5 MCC |
336 | |
337 | /* Check if board has eeprom */ | |
338 | err = i2c_master_recv(&dev->i2c_client, &buf, 0); | |
f2a01a00 | 339 | if (err < 0) { |
c41109fc MCC |
340 | em28xx_errdev("board has no eeprom\n"); |
341 | memset(eedata, 0, len); | |
342 | return -ENODEV; | |
f2a01a00 | 343 | } |
596d92d5 | 344 | |
a6c2ba28 | 345 | buf = 0; |
6ea54d93 DSL |
346 | |
347 | err = i2c_master_send(&dev->i2c_client, &buf, 1); | |
348 | if (err != 1) { | |
a6c2ba28 | 349 | printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n", |
350 | dev->name, err); | |
f2a01a00 | 351 | return err; |
a6c2ba28 | 352 | } |
353 | while (size > 0) { | |
354 | if (size > 16) | |
355 | block = 16; | |
356 | else | |
357 | block = size; | |
358 | ||
359 | if (block != | |
360 | (err = i2c_master_recv(&dev->i2c_client, p, block))) { | |
361 | printk(KERN_WARNING | |
362 | "%s: i2c eeprom read error (err=%d)\n", | |
363 | dev->name, err); | |
f2a01a00 | 364 | return err; |
a6c2ba28 | 365 | } |
366 | size -= block; | |
367 | p += block; | |
368 | } | |
369 | for (i = 0; i < len; i++) { | |
370 | if (0 == (i % 16)) | |
371 | printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i); | |
372 | printk(" %02x", eedata[i]); | |
373 | if (15 == (i % 16)) | |
374 | printk("\n"); | |
375 | } | |
376 | ||
03910cc3 MCC |
377 | if (em_eeprom->id == 0x9567eb1a) |
378 | dev->hash = em28xx_hash_mem(eedata, len, 32); | |
379 | ||
380 | printk(KERN_INFO "EEPROM ID= 0x%08x, hash = 0x%08lx\n", | |
381 | em_eeprom->id, dev->hash); | |
a6c2ba28 | 382 | printk(KERN_INFO "Vendor/Product ID= %04x:%04x\n", em_eeprom->vendor_ID, |
383 | em_eeprom->product_ID); | |
384 | ||
385 | switch (em_eeprom->chip_conf >> 4 & 0x3) { | |
386 | case 0: | |
387 | printk(KERN_INFO "No audio on board.\n"); | |
388 | break; | |
389 | case 1: | |
390 | printk(KERN_INFO "AC97 audio (5 sample rates)\n"); | |
391 | break; | |
392 | case 2: | |
393 | printk(KERN_INFO "I2S audio, sample rate=32k\n"); | |
394 | break; | |
395 | case 3: | |
396 | printk(KERN_INFO "I2S audio, 3 sample rates\n"); | |
397 | break; | |
398 | } | |
399 | ||
400 | if (em_eeprom->chip_conf & 1 << 3) | |
401 | printk(KERN_INFO "USB Remote wakeup capable\n"); | |
402 | ||
403 | if (em_eeprom->chip_conf & 1 << 2) | |
404 | printk(KERN_INFO "USB Self power capable\n"); | |
405 | ||
406 | switch (em_eeprom->chip_conf & 0x3) { | |
407 | case 0: | |
408 | printk(KERN_INFO "500mA max power\n"); | |
409 | break; | |
410 | case 1: | |
411 | printk(KERN_INFO "400mA max power\n"); | |
412 | break; | |
413 | case 2: | |
414 | printk(KERN_INFO "300mA max power\n"); | |
415 | break; | |
416 | case 3: | |
417 | printk(KERN_INFO "200mA max power\n"); | |
418 | break; | |
419 | } | |
91cad0f2 | 420 | printk(KERN_INFO "Table at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n", |
6ea54d93 DSL |
421 | em_eeprom->string_idx_table, |
422 | em_eeprom->string1, | |
423 | em_eeprom->string2, | |
424 | em_eeprom->string3); | |
a6c2ba28 | 425 | |
426 | return 0; | |
427 | } | |
428 | ||
429 | /* ----------------------------------------------------------- */ | |
430 | ||
a6c2ba28 | 431 | /* |
432 | * functionality() | |
433 | */ | |
434 | static u32 functionality(struct i2c_adapter *adap) | |
435 | { | |
436 | return I2C_FUNC_SMBUS_EMUL; | |
437 | } | |
438 | ||
a6c2ba28 | 439 | /* |
440 | * attach_inform() | |
441 | * gets called when a device attaches to the i2c bus | |
442 | * does some basic configuration | |
443 | */ | |
444 | static int attach_inform(struct i2c_client *client) | |
445 | { | |
3acf2809 | 446 | struct em28xx *dev = client->adapter->algo_data; |
a6c2ba28 | 447 | |
a6c2ba28 | 448 | switch (client->addr << 1) { |
6ea54d93 DSL |
449 | case 0x86: |
450 | case 0x84: | |
451 | case 0x96: | |
452 | case 0x94: | |
453 | { | |
454 | struct v4l2_priv_tun_config tda9887_cfg; | |
455 | ||
456 | struct tuner_setup tun_setup; | |
457 | ||
458 | tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; | |
459 | tun_setup.type = TUNER_TDA9887; | |
460 | tun_setup.addr = client->addr; | |
461 | ||
462 | em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, | |
463 | &tun_setup); | |
464 | ||
465 | tda9887_cfg.tuner = TUNER_TDA9887; | |
466 | tda9887_cfg.priv = &dev->tda9887_conf; | |
467 | em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, | |
468 | &tda9887_cfg); | |
469 | break; | |
470 | } | |
471 | case 0x42: | |
472 | dprintk1(1, "attach_inform: saa7114 detected.\n"); | |
473 | break; | |
474 | case 0x4a: | |
475 | dprintk1(1, "attach_inform: saa7113 detected.\n"); | |
476 | break; | |
477 | case 0xa0: | |
478 | dprintk1(1, "attach_inform: eeprom detected.\n"); | |
479 | break; | |
480 | case 0x60: | |
481 | case 0x8e: | |
482 | { | |
483 | struct IR_i2c *ir = i2c_get_clientdata(client); | |
484 | dprintk1(1, "attach_inform: IR detected (%s).\n", | |
485 | ir->phys); | |
486 | em28xx_set_ir(dev, ir); | |
487 | break; | |
488 | } | |
489 | case 0x80: | |
490 | case 0x88: | |
491 | dprintk1(1, "attach_inform: msp34xx detected.\n"); | |
492 | break; | |
493 | case 0xb8: | |
494 | case 0xba: | |
495 | dprintk1(1, "attach_inform: tvp5150 detected.\n"); | |
496 | break; | |
497 | ||
498 | default: | |
499 | if (!dev->tuner_addr) | |
500 | dev->tuner_addr = client->addr; | |
501 | ||
502 | dprintk1(1, "attach inform: detected I2C address %x\n", | |
503 | client->addr << 1); | |
03910cc3 | 504 | |
a6c2ba28 | 505 | } |
506 | ||
507 | return 0; | |
508 | } | |
509 | ||
3acf2809 MCC |
510 | static struct i2c_algorithm em28xx_algo = { |
511 | .master_xfer = em28xx_i2c_xfer, | |
a6c2ba28 | 512 | .functionality = functionality, |
513 | }; | |
514 | ||
3acf2809 | 515 | static struct i2c_adapter em28xx_adap_template = { |
a6c2ba28 | 516 | .owner = THIS_MODULE, |
a6c2ba28 | 517 | .class = I2C_CLASS_TV_ANALOG, |
3acf2809 MCC |
518 | .name = "em28xx", |
519 | .id = I2C_HW_B_EM28XX, | |
520 | .algo = &em28xx_algo, | |
a6c2ba28 | 521 | .client_register = attach_inform, |
522 | }; | |
523 | ||
3acf2809 MCC |
524 | static struct i2c_client em28xx_client_template = { |
525 | .name = "em28xx internal", | |
a6c2ba28 | 526 | }; |
527 | ||
528 | /* ----------------------------------------------------------- */ | |
529 | ||
530 | /* | |
531 | * i2c_devs | |
532 | * incomplete list of known devices | |
533 | */ | |
534 | static char *i2c_devs[128] = { | |
535 | [0x4a >> 1] = "saa7113h", | |
536 | [0x60 >> 1] = "remote IR sensor", | |
da45a2a5 | 537 | [0x8e >> 1] = "remote IR sensor", |
a6c2ba28 | 538 | [0x86 >> 1] = "tda9887", |
539 | [0x80 >> 1] = "msp34xx", | |
540 | [0x88 >> 1] = "msp34xx", | |
541 | [0xa0 >> 1] = "eeprom", | |
542 | [0xb8 >> 1] = "tvp5150a", | |
543 | [0xba >> 1] = "tvp5150a", | |
544 | [0xc0 >> 1] = "tuner (analog)", | |
545 | [0xc2 >> 1] = "tuner (analog)", | |
546 | [0xc4 >> 1] = "tuner (analog)", | |
547 | [0xc6 >> 1] = "tuner (analog)", | |
548 | }; | |
549 | ||
550 | /* | |
551 | * do_i2c_scan() | |
552 | * check i2c address range for devices | |
553 | */ | |
fad7b958 | 554 | void em28xx_do_i2c_scan(struct em28xx *dev) |
a6c2ba28 | 555 | { |
fad7b958 | 556 | u8 i2c_devicelist[128]; |
a6c2ba28 | 557 | unsigned char buf; |
558 | int i, rc; | |
559 | ||
fad7b958 SS |
560 | memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist)); |
561 | ||
53c4e955 | 562 | for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { |
fad7b958 SS |
563 | dev->i2c_client.addr = i; |
564 | rc = i2c_master_recv(&dev->i2c_client, &buf, 0); | |
a6c2ba28 | 565 | if (rc < 0) |
566 | continue; | |
fad7b958 SS |
567 | i2c_devicelist[i] = i; |
568 | printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", | |
569 | dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); | |
a6c2ba28 | 570 | } |
fad7b958 SS |
571 | |
572 | dev->i2c_hash = em28xx_hash_mem(i2c_devicelist, | |
573 | ARRAY_SIZE(i2c_devicelist), 32); | |
a6c2ba28 | 574 | } |
575 | ||
576 | /* | |
3acf2809 | 577 | * em28xx_i2c_call_clients() |
a6c2ba28 | 578 | * send commands to all attached i2c devices |
579 | */ | |
3acf2809 | 580 | void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg) |
a6c2ba28 | 581 | { |
582 | BUG_ON(NULL == dev->i2c_adap.algo_data); | |
583 | i2c_clients_command(&dev->i2c_adap, cmd, arg); | |
584 | } | |
585 | ||
586 | /* | |
3acf2809 | 587 | * em28xx_i2c_register() |
a6c2ba28 | 588 | * register i2c bus |
589 | */ | |
3acf2809 | 590 | int em28xx_i2c_register(struct em28xx *dev) |
a6c2ba28 | 591 | { |
f2a01a00 DSL |
592 | int retval; |
593 | ||
3acf2809 MCC |
594 | BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg); |
595 | BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req); | |
596 | dev->i2c_adap = em28xx_adap_template; | |
a6c2ba28 | 597 | dev->i2c_adap.dev.parent = &dev->udev->dev; |
598 | strcpy(dev->i2c_adap.name, dev->name); | |
599 | dev->i2c_adap.algo_data = dev; | |
f2a01a00 DSL |
600 | |
601 | retval = i2c_add_adapter(&dev->i2c_adap); | |
602 | if (retval < 0) { | |
603 | em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n", | |
604 | __func__, retval); | |
605 | return retval; | |
606 | } | |
a6c2ba28 | 607 | |
3acf2809 | 608 | dev->i2c_client = em28xx_client_template; |
a6c2ba28 | 609 | dev->i2c_client.adapter = &dev->i2c_adap; |
610 | ||
f2a01a00 | 611 | retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata)); |
c41109fc | 612 | if ((retval < 0) && (retval != -ENODEV)) { |
f2a01a00 DSL |
613 | em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n", |
614 | __func__, retval); | |
c41109fc | 615 | |
f2a01a00 DSL |
616 | return retval; |
617 | } | |
a6c2ba28 | 618 | |
619 | if (i2c_scan) | |
fad7b958 | 620 | em28xx_do_i2c_scan(dev); |
c41109fc | 621 | |
a6c2ba28 | 622 | return 0; |
623 | } | |
624 | ||
625 | /* | |
3acf2809 | 626 | * em28xx_i2c_unregister() |
a6c2ba28 | 627 | * unregister i2c_bus |
628 | */ | |
3acf2809 | 629 | int em28xx_i2c_unregister(struct em28xx *dev) |
a6c2ba28 | 630 | { |
631 | i2c_del_adapter(&dev->i2c_adap); | |
632 | return 0; | |
633 | } |