]>
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 | ||
a6c2ba28 | 44 | /* |
f5ae371a FS |
45 | * em2800_i2c_send_bytes() |
46 | * send up to 4 bytes to the em2800 i2c device | |
596d92d5 | 47 | */ |
f5ae371a | 48 | static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) |
596d92d5 MCC |
49 | { |
50 | int ret; | |
51 | int write_timeout; | |
a6bad040 | 52 | u8 b2[6]; |
f5ae371a FS |
53 | |
54 | if (len < 1 || len > 4) | |
55 | return -EOPNOTSUPP; | |
56 | ||
596d92d5 MCC |
57 | BUG_ON(len < 1 || len > 4); |
58 | b2[5] = 0x80 + len - 1; | |
59 | b2[4] = addr; | |
60 | b2[3] = buf[0]; | |
61 | if (len > 1) | |
62 | b2[2] = buf[1]; | |
63 | if (len > 2) | |
64 | b2[1] = buf[2]; | |
65 | if (len > 3) | |
66 | b2[0] = buf[3]; | |
67 | ||
2fcc82d8 | 68 | /* trigger write */ |
3acf2809 | 69 | ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len); |
596d92d5 | 70 | if (ret != 2 + len) { |
45f04e82 FS |
71 | em28xx_warn("failed to trigger write to i2c address 0x%x " |
72 | "(error=%i)\n", addr, ret); | |
73 | return (ret < 0) ? ret : -EIO; | |
596d92d5 | 74 | } |
2fcc82d8 FS |
75 | /* wait for completion */ |
76 | for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0; | |
596d92d5 | 77 | write_timeout -= 5) { |
3acf2809 | 78 | ret = dev->em28xx_read_reg(dev, 0x05); |
45f04e82 | 79 | if (ret == 0x80 + len - 1) { |
596d92d5 | 80 | return len; |
45f04e82 FS |
81 | } else if (ret == 0x94 + len - 1) { |
82 | return -ENODEV; | |
83 | } else if (ret < 0) { | |
84 | em28xx_warn("failed to get i2c transfer status from " | |
85 | "bridge register (error=%i)\n", ret); | |
86 | return ret; | |
87 | } | |
e8e41da4 | 88 | msleep(5); |
596d92d5 | 89 | } |
45f04e82 | 90 | em28xx_warn("write to i2c device at 0x%x timed out\n", addr); |
596d92d5 MCC |
91 | return -EIO; |
92 | } | |
93 | ||
596d92d5 | 94 | /* |
2fcc82d8 FS |
95 | * em2800_i2c_recv_bytes() |
96 | * read up to 4 bytes from the em2800 i2c device | |
596d92d5 | 97 | */ |
2fcc82d8 | 98 | static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) |
596d92d5 | 99 | { |
2fcc82d8 | 100 | u8 buf2[4]; |
596d92d5 | 101 | int ret; |
2fcc82d8 FS |
102 | int read_timeout; |
103 | int i; | |
104 | ||
105 | if (len < 1 || len > 4) | |
106 | return -EOPNOTSUPP; | |
107 | ||
108 | /* trigger read */ | |
109 | buf2[1] = 0x84 + len - 1; | |
110 | buf2[0] = addr; | |
111 | ret = dev->em28xx_write_regs(dev, 0x04, buf2, 2); | |
112 | if (ret != 2) { | |
113 | em28xx_warn("failed to trigger read from i2c address 0x%x " | |
114 | "(error=%i)\n", addr, ret); | |
115 | return (ret < 0) ? ret : -EIO; | |
596d92d5 | 116 | } |
d45b9b8a | 117 | |
2fcc82d8 FS |
118 | /* wait for completion */ |
119 | for (read_timeout = EM2800_I2C_XFER_TIMEOUT; read_timeout > 0; | |
120 | read_timeout -= 5) { | |
121 | ret = dev->em28xx_read_reg(dev, 0x05); | |
122 | if (ret == 0x84 + len - 1) { | |
123 | break; | |
124 | } else if (ret == 0x94 + len - 1) { | |
596d92d5 | 125 | return -ENODEV; |
2fcc82d8 FS |
126 | } else if (ret < 0) { |
127 | em28xx_warn("failed to get i2c transfer status from " | |
128 | "bridge register (error=%i)\n", ret); | |
129 | return ret; | |
130 | } | |
e8e41da4 | 131 | msleep(5); |
596d92d5 | 132 | } |
2fcc82d8 FS |
133 | if (ret != 0x84 + len - 1) |
134 | em28xx_warn("read from i2c device at 0x%x timed out\n", addr); | |
135 | ||
136 | /* get the received message */ | |
137 | ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len); | |
138 | if (ret != len) { | |
139 | em28xx_warn("reading from i2c device at 0x%x failed: " | |
140 | "couldn't get the received message from the bridge " | |
141 | "(error=%i)\n", addr, ret); | |
142 | return (ret < 0) ? ret : -EIO; | |
143 | } | |
144 | for (i = 0; i < len; i++) | |
145 | buf[i] = buf2[len - 1 - i]; | |
146 | ||
147 | return ret; | |
596d92d5 MCC |
148 | } |
149 | ||
150 | /* | |
2fcc82d8 FS |
151 | * em2800_i2c_check_for_device() |
152 | * check if there is an i2c device at the supplied address | |
596d92d5 | 153 | */ |
2fcc82d8 | 154 | static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr) |
596d92d5 | 155 | { |
2fcc82d8 | 156 | u8 buf; |
596d92d5 | 157 | int ret; |
f5ae371a | 158 | |
2fcc82d8 FS |
159 | ret = em2800_i2c_recv_bytes(dev, addr, &buf, 1); |
160 | if (ret == 1) | |
161 | return 0; | |
162 | return (ret < 0) ? ret : -EIO; | |
596d92d5 MCC |
163 | } |
164 | ||
165 | /* | |
3acf2809 | 166 | * em28xx_i2c_send_bytes() |
a6c2ba28 | 167 | */ |
a6bad040 FS |
168 | static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, |
169 | u16 len, int stop) | |
a6c2ba28 | 170 | { |
bbc70e64 | 171 | int write_timeout, ret; |
a6c2ba28 | 172 | |
f5ae371a FS |
173 | if (len < 1 || len > 64) |
174 | return -EOPNOTSUPP; | |
45f04e82 FS |
175 | /* NOTE: limited by the USB ctrl message constraints |
176 | * Zero length reads always succeed, even if no device is connected */ | |
f5ae371a | 177 | |
45f04e82 FS |
178 | /* Write to i2c device */ |
179 | ret = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len); | |
180 | if (ret != len) { | |
181 | if (ret < 0) { | |
182 | em28xx_warn("writing to i2c device at 0x%x failed " | |
183 | "(error=%i)\n", addr, ret); | |
184 | return ret; | |
185 | } else { | |
186 | em28xx_warn("%i bytes write to i2c device at 0x%x " | |
187 | "requested, but %i bytes written\n", | |
188 | len, addr, ret); | |
189 | return -EIO; | |
190 | } | |
191 | } | |
a6c2ba28 | 192 | |
45f04e82 | 193 | /* Check success of the i2c operation */ |
2fcc82d8 | 194 | for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0; |
bbc70e64 MCC |
195 | write_timeout -= 5) { |
196 | ret = dev->em28xx_read_reg(dev, 0x05); | |
45f04e82 FS |
197 | if (ret == 0) { /* success */ |
198 | return len; | |
199 | } else if (ret == 0x10) { | |
200 | return -ENODEV; | |
201 | } else if (ret < 0) { | |
202 | em28xx_warn("failed to read i2c transfer status from " | |
203 | "bridge (error=%i)\n", ret); | |
204 | return ret; | |
205 | } | |
bbc70e64 | 206 | msleep(5); |
45f04e82 FS |
207 | /* NOTE: do we really have to wait for success ? |
208 | Never seen anything else than 0x00 or 0x10 | |
209 | (even with high payload) ... */ | |
bbc70e64 | 210 | } |
45f04e82 FS |
211 | em28xx_warn("write to i2c device at 0x%x timed out\n", addr); |
212 | return -EIO; | |
a6c2ba28 | 213 | } |
214 | ||
215 | /* | |
3acf2809 | 216 | * em28xx_i2c_recv_bytes() |
a6c2ba28 | 217 | * read a byte from the i2c device |
218 | */ | |
a6bad040 | 219 | static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) |
a6c2ba28 | 220 | { |
221 | int ret; | |
f5ae371a FS |
222 | |
223 | if (len < 1 || len > 64) | |
224 | return -EOPNOTSUPP; | |
45f04e82 FS |
225 | /* NOTE: limited by the USB ctrl message constraints |
226 | * Zero length reads always succeed, even if no device is connected */ | |
f5ae371a | 227 | |
45f04e82 | 228 | /* Read data from i2c device */ |
3acf2809 | 229 | ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len); |
45f04e82 FS |
230 | if (ret != len) { |
231 | if (ret < 0) { | |
232 | em28xx_warn("reading from i2c device at 0x%x failed " | |
233 | "(error=%i)\n", addr, ret); | |
234 | return ret; | |
235 | } else { | |
236 | em28xx_warn("%i bytes requested from i2c device at " | |
237 | "0x%x, but %i bytes received\n", | |
238 | len, addr, ret); | |
239 | return -EIO; | |
240 | } | |
241 | } | |
242 | ||
243 | /* Check success of the i2c operation */ | |
244 | ret = dev->em28xx_read_reg(dev, 0x05); | |
a6c2ba28 | 245 | if (ret < 0) { |
45f04e82 FS |
246 | em28xx_warn("failed to read i2c transfer status from " |
247 | "bridge (error=%i)\n", ret); | |
a6c2ba28 | 248 | return ret; |
249 | } | |
45f04e82 FS |
250 | if (ret > 0) { |
251 | if (ret == 0x10) { | |
252 | return -ENODEV; | |
253 | } else { | |
254 | em28xx_warn("unknown i2c error (status=%i)\n", ret); | |
255 | return -EIO; | |
256 | } | |
257 | } | |
258 | return len; | |
a6c2ba28 | 259 | } |
260 | ||
261 | /* | |
3acf2809 | 262 | * em28xx_i2c_check_for_device() |
a6c2ba28 | 263 | * check if there is a i2c_device at the supplied address |
264 | */ | |
a6bad040 | 265 | static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr) |
a6c2ba28 | 266 | { |
a6c2ba28 | 267 | int ret; |
45f04e82 | 268 | u8 buf; |
a6c2ba28 | 269 | |
45f04e82 FS |
270 | ret = em28xx_i2c_recv_bytes(dev, addr, &buf, 1); |
271 | if (ret == 1) | |
272 | return 0; | |
273 | return (ret < 0) ? ret : -EIO; | |
a6c2ba28 | 274 | } |
275 | ||
276 | /* | |
3acf2809 | 277 | * em28xx_i2c_xfer() |
a6c2ba28 | 278 | * the main i2c transfer function |
279 | */ | |
3acf2809 | 280 | static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, |
a6c2ba28 | 281 | struct i2c_msg msgs[], int num) |
282 | { | |
3acf2809 | 283 | struct em28xx *dev = i2c_adap->algo_data; |
a6c2ba28 | 284 | int addr, rc, i, byte; |
285 | ||
286 | if (num <= 0) | |
287 | return 0; | |
288 | for (i = 0; i < num; i++) { | |
289 | addr = msgs[i].addr << 1; | |
d90f0677 | 290 | if (i2c_debug) |
d7a80eaa FS |
291 | printk(KERN_DEBUG "%s at %s: %s %s addr=%02x len=%d:", |
292 | dev->name, __func__ , | |
293 | (msgs[i].flags & I2C_M_RD) ? "read" : "write", | |
294 | i == num - 1 ? "stop" : "nonstop", | |
295 | addr, msgs[i].len); | |
6ea54d93 | 296 | if (!msgs[i].len) { /* no len: check only for device presence */ |
505b6d0b | 297 | if (dev->board.is_em2800) |
596d92d5 MCC |
298 | rc = em2800_i2c_check_for_device(dev, addr); |
299 | else | |
3acf2809 | 300 | rc = em28xx_i2c_check_for_device(dev, addr); |
45f04e82 | 301 | if (rc == -ENODEV) { |
d90f0677 | 302 | if (i2c_debug) |
45f04e82 | 303 | printk(" no device\n"); |
a6c2ba28 | 304 | return rc; |
305 | } | |
596d92d5 | 306 | } else if (msgs[i].flags & I2C_M_RD) { |
a6c2ba28 | 307 | /* read bytes */ |
505b6d0b | 308 | if (dev->board.is_em2800) |
596d92d5 MCC |
309 | rc = em2800_i2c_recv_bytes(dev, addr, |
310 | msgs[i].buf, | |
311 | msgs[i].len); | |
312 | else | |
3acf2809 | 313 | rc = em28xx_i2c_recv_bytes(dev, addr, |
596d92d5 MCC |
314 | msgs[i].buf, |
315 | msgs[i].len); | |
d90f0677 | 316 | if (i2c_debug) { |
6ea54d93 | 317 | for (byte = 0; byte < msgs[i].len; byte++) |
a6c2ba28 | 318 | printk(" %02x", msgs[i].buf[byte]); |
a6c2ba28 | 319 | } |
320 | } else { | |
321 | /* write bytes */ | |
d90f0677 | 322 | if (i2c_debug) { |
a6c2ba28 | 323 | for (byte = 0; byte < msgs[i].len; byte++) |
324 | printk(" %02x", msgs[i].buf[byte]); | |
325 | } | |
505b6d0b | 326 | if (dev->board.is_em2800) |
596d92d5 MCC |
327 | rc = em2800_i2c_send_bytes(dev, addr, |
328 | msgs[i].buf, | |
329 | msgs[i].len); | |
330 | else | |
3acf2809 | 331 | rc = em28xx_i2c_send_bytes(dev, addr, |
596d92d5 MCC |
332 | msgs[i].buf, |
333 | msgs[i].len, | |
334 | i == num - 1); | |
a6c2ba28 | 335 | } |
45f04e82 | 336 | if (rc < 0) { |
d90f0677 | 337 | if (i2c_debug) |
45f04e82 FS |
338 | printk(" ERROR: %i\n", rc); |
339 | return rc; | |
340 | } | |
d90f0677 | 341 | if (i2c_debug) |
a6c2ba28 | 342 | printk("\n"); |
343 | } | |
344 | ||
345 | return num; | |
a6c2ba28 | 346 | } |
347 | ||
03910cc3 MCC |
348 | /* based on linux/sunrpc/svcauth.h and linux/hash.h |
349 | * The original hash function returns a different value, if arch is x86_64 | |
350 | * or i386. | |
351 | */ | |
352 | static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits) | |
353 | { | |
354 | unsigned long hash = 0; | |
355 | unsigned long l = 0; | |
356 | int len = 0; | |
357 | unsigned char c; | |
358 | do { | |
359 | if (len == length) { | |
360 | c = (char)len; | |
361 | len = -1; | |
362 | } else | |
363 | c = *buf++; | |
364 | l = (l << 8) | c; | |
365 | len++; | |
366 | if ((len & (32 / 8 - 1)) == 0) | |
367 | hash = ((hash^l) * 0x9e370001UL); | |
368 | } while (len); | |
369 | ||
370 | return (hash >> (32 - bits)) & 0xffffffffUL; | |
371 | } | |
372 | ||
3acf2809 | 373 | static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) |
a6c2ba28 | 374 | { |
87b52439 | 375 | unsigned char buf[2], *p = eedata; |
3acf2809 | 376 | struct em28xx_eeprom *em_eeprom = (void *)eedata; |
90271964 | 377 | int i, err, size = len, block, block_max; |
a6c2ba28 | 378 | |
379 | dev->i2c_client.addr = 0xa0 >> 1; | |
596d92d5 MCC |
380 | |
381 | /* Check if board has eeprom */ | |
87b52439 | 382 | err = i2c_master_recv(&dev->i2c_client, buf, 0); |
f2a01a00 | 383 | if (err < 0) { |
12d7ce18 | 384 | em28xx_info("board has no eeprom\n"); |
c41109fc MCC |
385 | memset(eedata, 0, len); |
386 | return -ENODEV; | |
f2a01a00 | 387 | } |
596d92d5 | 388 | |
87b52439 FS |
389 | /* Select address memory address 0x00(00) */ |
390 | buf[0] = 0; | |
391 | buf[1] = 0; | |
392 | err = i2c_master_send(&dev->i2c_client, buf, 1 + dev->eeprom_addrwidth_16bit); | |
393 | if (err != 1 + dev->eeprom_addrwidth_16bit) { | |
12d7ce18 | 394 | em28xx_errdev("failed to read eeprom (err=%d)\n", err); |
f2a01a00 | 395 | return err; |
a6c2ba28 | 396 | } |
90271964 | 397 | |
87b52439 | 398 | /* Read eeprom content */ |
90271964 FS |
399 | if (dev->board.is_em2800) |
400 | block_max = 4; | |
401 | else | |
402 | block_max = 64; | |
a6c2ba28 | 403 | while (size > 0) { |
90271964 FS |
404 | if (size > block_max) |
405 | block = block_max; | |
a6c2ba28 | 406 | else |
407 | block = size; | |
408 | ||
409 | if (block != | |
410 | (err = i2c_master_recv(&dev->i2c_client, p, block))) { | |
12d7ce18 | 411 | em28xx_errdev("i2c eeprom read error (err=%d)\n", err); |
f2a01a00 | 412 | return err; |
a6c2ba28 | 413 | } |
414 | size -= block; | |
415 | p += block; | |
416 | } | |
87b52439 FS |
417 | |
418 | /* Display eeprom content */ | |
a6c2ba28 | 419 | for (i = 0; i < len; i++) { |
87b52439 FS |
420 | if (0 == (i % 16)) { |
421 | if (dev->eeprom_addrwidth_16bit) | |
422 | em28xx_info("i2c eeprom %04x:", i); | |
423 | else | |
424 | em28xx_info("i2c eeprom %02x:", i); | |
425 | } | |
a6c2ba28 | 426 | printk(" %02x", eedata[i]); |
427 | if (15 == (i % 16)) | |
428 | printk("\n"); | |
429 | } | |
430 | ||
87b52439 FS |
431 | if (dev->eeprom_addrwidth_16bit && |
432 | eedata[0] == 0x26 && eedata[3] == 0x00) { | |
433 | /* new eeprom format; size 4-64kb */ | |
434 | dev->hash = em28xx_hash_mem(eedata, len, 32); | |
435 | em28xx_info("EEPROM hash = 0x%08lx\n", dev->hash); | |
436 | em28xx_info("EEPROM info: boot page address = 0x%02x04, " | |
437 | "boot configuration = 0x%02x\n", | |
438 | eedata[1], eedata[2]); | |
439 | /* boot configuration (address 0x0002): | |
440 | * [0] microcode download speed: 1 = 400 kHz; 0 = 100 kHz | |
441 | * [1] always selects 12 kb RAM | |
442 | * [2] USB device speed: 1 = force Full Speed; 0 = auto detect | |
443 | * [4] 1 = force fast mode and no suspend for device testing | |
444 | * [5:7] USB PHY tuning registers; determined by device | |
445 | * characterization | |
446 | */ | |
447 | ||
448 | /* FIXME: | |
449 | * - read more than 256 bytes / addresses above 0x00ff | |
450 | * - find offset for device config dataset and extract it | |
451 | * - decrypt eeprom data for camera bridges (em25xx, em276x+) | |
452 | * - use separate/different eeprom hashes (not yet used) | |
453 | */ | |
454 | ||
455 | return 0; | |
456 | } else if (em_eeprom->id[0] != 0x1a || em_eeprom->id[1] != 0xeb || | |
457 | em_eeprom->id[2] != 0x67 || em_eeprom->id[3] != 0x95) { | |
458 | em28xx_info("unknown eeprom format or eeprom corrupted !\n"); | |
f55eacbe FS |
459 | return -ENODEV; |
460 | } | |
461 | ||
462 | dev->hash = em28xx_hash_mem(eedata, len, 32); | |
03910cc3 | 463 | |
0c28dcc0 FS |
464 | em28xx_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", |
465 | em_eeprom->id[0], em_eeprom->id[1], | |
466 | em_eeprom->id[2], em_eeprom->id[3], dev->hash); | |
1bee0184 | 467 | |
12d7ce18 | 468 | em28xx_info("EEPROM info:\n"); |
a6c2ba28 | 469 | |
0c28dcc0 | 470 | switch (le16_to_cpu(em_eeprom->chip_conf) >> 4 & 0x3) { |
a6c2ba28 | 471 | case 0: |
12d7ce18 | 472 | em28xx_info("\tNo audio on board.\n"); |
a6c2ba28 | 473 | break; |
474 | case 1: | |
12d7ce18 | 475 | em28xx_info("\tAC97 audio (5 sample rates)\n"); |
a6c2ba28 | 476 | break; |
477 | case 2: | |
12d7ce18 | 478 | em28xx_info("\tI2S audio, sample rate=32k\n"); |
a6c2ba28 | 479 | break; |
480 | case 3: | |
12d7ce18 | 481 | em28xx_info("\tI2S audio, 3 sample rates\n"); |
a6c2ba28 | 482 | break; |
483 | } | |
484 | ||
0c28dcc0 | 485 | if (le16_to_cpu(em_eeprom->chip_conf) & 1 << 3) |
12d7ce18 | 486 | em28xx_info("\tUSB Remote wakeup capable\n"); |
a6c2ba28 | 487 | |
0c28dcc0 | 488 | if (le16_to_cpu(em_eeprom->chip_conf) & 1 << 2) |
12d7ce18 | 489 | em28xx_info("\tUSB Self power capable\n"); |
a6c2ba28 | 490 | |
0c28dcc0 | 491 | switch (le16_to_cpu(em_eeprom->chip_conf) & 0x3) { |
a6c2ba28 | 492 | case 0: |
12d7ce18 | 493 | em28xx_info("\t500mA max power\n"); |
a6c2ba28 | 494 | break; |
495 | case 1: | |
12d7ce18 | 496 | em28xx_info("\t400mA max power\n"); |
a6c2ba28 | 497 | break; |
498 | case 2: | |
12d7ce18 | 499 | em28xx_info("\t300mA max power\n"); |
a6c2ba28 | 500 | break; |
501 | case 3: | |
12d7ce18 | 502 | em28xx_info("\t200mA max power\n"); |
a6c2ba28 | 503 | break; |
504 | } | |
12d7ce18 FS |
505 | em28xx_info("\tTable at offset 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n", |
506 | em_eeprom->string_idx_table, | |
0c28dcc0 FS |
507 | le16_to_cpu(em_eeprom->string1), |
508 | le16_to_cpu(em_eeprom->string2), | |
509 | le16_to_cpu(em_eeprom->string3)); | |
a6c2ba28 | 510 | |
511 | return 0; | |
512 | } | |
513 | ||
514 | /* ----------------------------------------------------------- */ | |
515 | ||
a6c2ba28 | 516 | /* |
517 | * functionality() | |
518 | */ | |
519 | static u32 functionality(struct i2c_adapter *adap) | |
520 | { | |
eaf33c40 FS |
521 | struct em28xx *dev = adap->algo_data; |
522 | u32 func_flags = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | |
523 | if (dev->board.is_em2800) | |
524 | func_flags &= ~I2C_FUNC_SMBUS_WRITE_BLOCK_DATA; | |
525 | return func_flags; | |
a6c2ba28 | 526 | } |
527 | ||
3acf2809 MCC |
528 | static struct i2c_algorithm em28xx_algo = { |
529 | .master_xfer = em28xx_i2c_xfer, | |
a6c2ba28 | 530 | .functionality = functionality, |
531 | }; | |
532 | ||
3acf2809 | 533 | static struct i2c_adapter em28xx_adap_template = { |
a6c2ba28 | 534 | .owner = THIS_MODULE, |
3acf2809 | 535 | .name = "em28xx", |
3acf2809 | 536 | .algo = &em28xx_algo, |
a6c2ba28 | 537 | }; |
538 | ||
3acf2809 MCC |
539 | static struct i2c_client em28xx_client_template = { |
540 | .name = "em28xx internal", | |
a6c2ba28 | 541 | }; |
542 | ||
543 | /* ----------------------------------------------------------- */ | |
544 | ||
545 | /* | |
546 | * i2c_devs | |
547 | * incomplete list of known devices | |
548 | */ | |
549 | static char *i2c_devs[128] = { | |
0b3966e4 | 550 | [0x3e >> 1] = "remote IR sensor", |
a6c2ba28 | 551 | [0x4a >> 1] = "saa7113h", |
729841ed | 552 | [0x52 >> 1] = "drxk", |
a6c2ba28 | 553 | [0x60 >> 1] = "remote IR sensor", |
da45a2a5 | 554 | [0x8e >> 1] = "remote IR sensor", |
a6c2ba28 | 555 | [0x86 >> 1] = "tda9887", |
556 | [0x80 >> 1] = "msp34xx", | |
557 | [0x88 >> 1] = "msp34xx", | |
558 | [0xa0 >> 1] = "eeprom", | |
2bd1d9eb | 559 | [0xb0 >> 1] = "tda9874", |
a6c2ba28 | 560 | [0xb8 >> 1] = "tvp5150a", |
791a08fc | 561 | [0xba >> 1] = "webcam sensor or tvp5150a", |
a6c2ba28 | 562 | [0xc0 >> 1] = "tuner (analog)", |
563 | [0xc2 >> 1] = "tuner (analog)", | |
564 | [0xc4 >> 1] = "tuner (analog)", | |
565 | [0xc6 >> 1] = "tuner (analog)", | |
566 | }; | |
567 | ||
568 | /* | |
569 | * do_i2c_scan() | |
570 | * check i2c address range for devices | |
571 | */ | |
fad7b958 | 572 | void em28xx_do_i2c_scan(struct em28xx *dev) |
a6c2ba28 | 573 | { |
fad7b958 | 574 | u8 i2c_devicelist[128]; |
a6c2ba28 | 575 | unsigned char buf; |
576 | int i, rc; | |
577 | ||
fad7b958 SS |
578 | memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist)); |
579 | ||
53c4e955 | 580 | for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { |
fad7b958 SS |
581 | dev->i2c_client.addr = i; |
582 | rc = i2c_master_recv(&dev->i2c_client, &buf, 0); | |
a6c2ba28 | 583 | if (rc < 0) |
584 | continue; | |
fad7b958 | 585 | i2c_devicelist[i] = i; |
12d7ce18 FS |
586 | em28xx_info("found i2c device @ 0x%x [%s]\n", |
587 | i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); | |
a6c2ba28 | 588 | } |
fad7b958 SS |
589 | |
590 | dev->i2c_hash = em28xx_hash_mem(i2c_devicelist, | |
591 | ARRAY_SIZE(i2c_devicelist), 32); | |
a6c2ba28 | 592 | } |
593 | ||
a6c2ba28 | 594 | /* |
3acf2809 | 595 | * em28xx_i2c_register() |
a6c2ba28 | 596 | * register i2c bus |
597 | */ | |
3acf2809 | 598 | int em28xx_i2c_register(struct em28xx *dev) |
a6c2ba28 | 599 | { |
f2a01a00 DSL |
600 | int retval; |
601 | ||
3acf2809 MCC |
602 | BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg); |
603 | BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req); | |
604 | dev->i2c_adap = em28xx_adap_template; | |
a6c2ba28 | 605 | dev->i2c_adap.dev.parent = &dev->udev->dev; |
606 | strcpy(dev->i2c_adap.name, dev->name); | |
607 | dev->i2c_adap.algo_data = dev; | |
f2cf250a | 608 | i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); |
f2a01a00 DSL |
609 | |
610 | retval = i2c_add_adapter(&dev->i2c_adap); | |
611 | if (retval < 0) { | |
612 | em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n", | |
613 | __func__, retval); | |
614 | return retval; | |
615 | } | |
a6c2ba28 | 616 | |
3acf2809 | 617 | dev->i2c_client = em28xx_client_template; |
a6c2ba28 | 618 | dev->i2c_client.adapter = &dev->i2c_adap; |
619 | ||
f2a01a00 | 620 | retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata)); |
c41109fc | 621 | if ((retval < 0) && (retval != -ENODEV)) { |
f2a01a00 DSL |
622 | em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n", |
623 | __func__, retval); | |
c41109fc | 624 | |
f2a01a00 DSL |
625 | return retval; |
626 | } | |
a6c2ba28 | 627 | |
628 | if (i2c_scan) | |
fad7b958 | 629 | em28xx_do_i2c_scan(dev); |
c41109fc | 630 | |
a6c2ba28 | 631 | return 0; |
632 | } | |
633 | ||
634 | /* | |
3acf2809 | 635 | * em28xx_i2c_unregister() |
a6c2ba28 | 636 | * unregister i2c_bus |
637 | */ | |
3acf2809 | 638 | int em28xx_i2c_unregister(struct em28xx *dev) |
a6c2ba28 | 639 | { |
640 | i2c_del_adapter(&dev->i2c_adap); | |
641 | return 0; | |
642 | } |