blob: e2003455f2b2d9dc9d5ca9efa36aa6fb5070d08b [file] [log] [blame]
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001/*
Mauro Carvalho Chehabf7abcd32005-11-08 21:38:25 -08002 em28xx-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08003
Mauro Carvalho Chehabf7abcd32005-11-08 21:38:25 -08004 Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
5 Markus Rechberger <mrechberger@gmail.com>
Mauro Carvalho Chehab2e7c6dc2006-04-03 07:53:40 -03006 Mauro Carvalho Chehab <mchehab@infradead.org>
Mauro Carvalho Chehabf7abcd32005-11-08 21:38:25 -08007 Sascha Sommer <saschasommer@freenet.de>
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08008
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>
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080028#include <linux/video_decoder.h>
29
Mauro Carvalho Chehabf7abcd32005-11-08 21:38:25 -080030#include "em28xx.h"
Mauro Carvalho Chehab6c362c82007-10-29 23:36:12 -030031#include "tuner-xc2028.h"
Michael Krufky5e453dc2006-01-09 15:32:31 -020032#include <media/v4l2-common.h>
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -080033#include <media/tuner.h>
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080034
35/* ----------------------------------------------------------- */
36
37static unsigned int i2c_scan = 0;
38module_param(i2c_scan, int, 0444);
39MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
40
41static unsigned int i2c_debug = 0;
42module_param(i2c_debug, int, 0644);
43MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
44
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -080045#define dprintk1(lvl,fmt, args...) if (i2c_debug>=lvl) do {\
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -080046 printk(fmt, ##args); } while (0)
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -080047#define dprintk2(lvl,fmt, args...) if (i2c_debug>=lvl) do{ \
48 printk(KERN_DEBUG "%s at %s: " fmt, \
Jean Delvaref85c6572005-12-19 08:53:59 -020049 dev->name, __FUNCTION__ , ##args); } while (0)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080050
51/*
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080052 * em2800_i2c_send_max4()
53 * send up to 4 bytes to the i2c device
54 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080055static int em2800_i2c_send_max4(struct em28xx *dev, unsigned char addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080056 char *buf, int len)
57{
58 int ret;
59 int write_timeout;
60 unsigned char b2[6];
61 BUG_ON(len < 1 || len > 4);
62 b2[5] = 0x80 + len - 1;
63 b2[4] = addr;
64 b2[3] = buf[0];
65 if (len > 1)
66 b2[2] = buf[1];
67 if (len > 2)
68 b2[1] = buf[2];
69 if (len > 3)
70 b2[0] = buf[3];
71
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080072 ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080073 if (ret != 2 + len) {
Robert P. J. Daybeb7dd82007-05-09 07:14:03 +020074 em28xx_warn("writing to i2c device failed (error=%i)\n", ret);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080075 return -EIO;
76 }
77 for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
78 write_timeout -= 5) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080079 ret = dev->em28xx_read_reg(dev, 0x05);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080080 if (ret == 0x80 + len - 1)
81 return len;
Markus Rechbergere8e41da2006-02-07 06:49:11 -020082 msleep(5);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080083 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080084 em28xx_warn("i2c write timed out\n");
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080085 return -EIO;
86}
87
88/*
89 * em2800_i2c_send_bytes()
90 */
91static int em2800_i2c_send_bytes(void *data, unsigned char addr, char *buf,
92 short len)
93{
94 char *bufPtr = buf;
95 int ret;
96 int wrcount = 0;
97 int count;
98 int maxLen = 4;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080099 struct em28xx *dev = (struct em28xx *)data;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800100 while (len > 0) {
101 count = (len > maxLen) ? maxLen : len;
102 ret = em2800_i2c_send_max4(dev, addr, bufPtr, count);
103 if (ret > 0) {
104 len -= count;
105 bufPtr += count;
106 wrcount += count;
107 } else
108 return (ret < 0) ? ret : -EFAULT;
109 }
110 return wrcount;
111}
112
113/*
114 * em2800_i2c_check_for_device()
115 * check if there is a i2c_device at the supplied address
116 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800117static int em2800_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800118{
119 char msg;
120 int ret;
121 int write_timeout;
122 msg = addr;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800123 ret = dev->em28xx_write_regs(dev, 0x04, &msg, 1);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800124 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800125 em28xx_warn("setting i2c device address failed (error=%i)\n",
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800126 ret);
127 return ret;
128 }
129 msg = 0x84;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800130 ret = dev->em28xx_write_regs(dev, 0x05, &msg, 1);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800131 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800132 em28xx_warn("preparing i2c read failed (error=%i)\n", ret);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800133 return ret;
134 }
135 for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
136 write_timeout -= 5) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800137 unsigned msg = dev->em28xx_read_reg(dev, 0x5);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800138 if (msg == 0x94)
139 return -ENODEV;
140 else if (msg == 0x84)
141 return 0;
Markus Rechbergere8e41da2006-02-07 06:49:11 -0200142 msleep(5);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800143 }
144 return -ENODEV;
145}
146
147/*
148 * em2800_i2c_recv_bytes()
149 * read from the i2c device
150 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800151static int em2800_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800152 char *buf, int len)
153{
154 int ret;
155 /* check for the device and set i2c read address */
156 ret = em2800_i2c_check_for_device(dev, addr);
157 if (ret) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800158 em28xx_warn
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800159 ("preparing read at i2c address 0x%x failed (error=%i)\n",
160 addr, ret);
161 return ret;
162 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800163 ret = dev->em28xx_read_reg_req_len(dev, 0x0, 0x3, buf, len);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800164 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800165 em28xx_warn("reading from i2c device at 0x%x failed (error=%i)",
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800166 addr, ret);
167 return ret;
168 }
169 return ret;
170}
171
172/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800173 * em28xx_i2c_send_bytes()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800174 * untested for more than 4 bytes
175 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800176static int em28xx_i2c_send_bytes(void *data, unsigned char addr, char *buf,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800177 short len, int stop)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800178{
179 int wrcount = 0;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800180 struct em28xx *dev = (struct em28xx *)data;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800181
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800182 wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800183
184 return wrcount;
185}
186
187/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800188 * em28xx_i2c_recv_bytes()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800189 * read a byte from the i2c device
190 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800191static int em28xx_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800192 char *buf, int len)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800193{
194 int ret;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800195 ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800196 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800197 em28xx_warn("reading i2c device failed (error=%i)\n", ret);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800198 return ret;
199 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800200 if (dev->em28xx_read_reg(dev, 0x5) != 0)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800201 return -ENODEV;
202 return ret;
203}
204
205/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800206 * em28xx_i2c_check_for_device()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800207 * check if there is a i2c_device at the supplied address
208 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800209static int em28xx_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800210{
211 char msg;
212 int ret;
213 msg = addr;
214
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800215 ret = dev->em28xx_read_reg_req(dev, 2, addr);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800216 if (ret < 0) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800217 em28xx_warn("reading from i2c device failed (error=%i)\n", ret);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800218 return ret;
219 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800220 if (dev->em28xx_read_reg(dev, 0x5) != 0)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800221 return -ENODEV;
222 return 0;
223}
224
225/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800226 * em28xx_i2c_xfer()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800227 * the main i2c transfer function
228 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800229static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800230 struct i2c_msg msgs[], int num)
231{
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800232 struct em28xx *dev = i2c_adap->algo_data;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800233 int addr, rc, i, byte;
234
235 if (num <= 0)
236 return 0;
237 for (i = 0; i < num; i++) {
238 addr = msgs[i].addr << 1;
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800239 dprintk2(2,"%s %s addr=%x len=%d:",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800240 (msgs[i].flags & I2C_M_RD) ? "read" : "write",
241 i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
242 if (!msgs[i].len) { /* no len: check only for device presence */
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800243 if (dev->is_em2800)
244 rc = em2800_i2c_check_for_device(dev, addr);
245 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800246 rc = em28xx_i2c_check_for_device(dev, addr);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800247 if (rc < 0) {
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800248 dprintk2(2," no device\n");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800249 return rc;
250 }
251
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800252 } else if (msgs[i].flags & I2C_M_RD) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800253 /* read bytes */
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800254 if (dev->is_em2800)
255 rc = em2800_i2c_recv_bytes(dev, addr,
256 msgs[i].buf,
257 msgs[i].len);
258 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800259 rc = em28xx_i2c_recv_bytes(dev, addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800260 msgs[i].buf,
261 msgs[i].len);
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800262 if (i2c_debug>=2) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800263 for (byte = 0; byte < msgs[i].len; byte++) {
264 printk(" %02x", msgs[i].buf[byte]);
265 }
266 }
267 } else {
268 /* write bytes */
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800269 if (i2c_debug>=2) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800270 for (byte = 0; byte < msgs[i].len; byte++)
271 printk(" %02x", msgs[i].buf[byte]);
272 }
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800273 if (dev->is_em2800)
274 rc = em2800_i2c_send_bytes(dev, addr,
275 msgs[i].buf,
276 msgs[i].len);
277 else
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800278 rc = em28xx_i2c_send_bytes(dev, addr,
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800279 msgs[i].buf,
280 msgs[i].len,
281 i == num - 1);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800282 }
Markus Rechbergere8e41da2006-02-07 06:49:11 -0200283 if (rc < 0)
284 goto err;
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800285 if (i2c_debug>=2)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800286 printk("\n");
287 }
288
289 return num;
290 err:
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800291 dprintk2(2," ERROR: %i\n", rc);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800292 return rc;
293}
294
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300295/* based on linux/sunrpc/svcauth.h and linux/hash.h
296 * The original hash function returns a different value, if arch is x86_64
297 * or i386.
298 */
299static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
300{
301 unsigned long hash = 0;
302 unsigned long l = 0;
303 int len = 0;
304 unsigned char c;
305 do {
306 if (len == length) {
307 c = (char)len;
308 len = -1;
309 } else
310 c = *buf++;
311 l = (l << 8) | c;
312 len++;
313 if ((len & (32 / 8 - 1)) == 0)
314 hash = ((hash^l) * 0x9e370001UL);
315 } while (len);
316
317 return (hash >> (32 - bits)) & 0xffffffffUL;
318}
319
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800320static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800321{
322 unsigned char buf, *p = eedata;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800323 struct em28xx_eeprom *em_eeprom = (void *)eedata;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800324 int i, err, size = len, block;
325
326 dev->i2c_client.addr = 0xa0 >> 1;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800327
328 /* Check if board has eeprom */
329 err = i2c_master_recv(&dev->i2c_client, &buf, 0);
330 if (err < 0)
331 return -1;
332
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800333 buf = 0;
334 if (1 != (err = i2c_master_send(&dev->i2c_client, &buf, 1))) {
335 printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
336 dev->name, err);
337 return -1;
338 }
339 while (size > 0) {
340 if (size > 16)
341 block = 16;
342 else
343 block = size;
344
345 if (block !=
346 (err = i2c_master_recv(&dev->i2c_client, p, block))) {
347 printk(KERN_WARNING
348 "%s: i2c eeprom read error (err=%d)\n",
349 dev->name, err);
350 return -1;
351 }
352 size -= block;
353 p += block;
354 }
355 for (i = 0; i < len; i++) {
356 if (0 == (i % 16))
357 printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
358 printk(" %02x", eedata[i]);
359 if (15 == (i % 16))
360 printk("\n");
361 }
362
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300363 if (em_eeprom->id == 0x9567eb1a)
364 dev->hash = em28xx_hash_mem(eedata, len, 32);
365
366 printk(KERN_INFO "EEPROM ID= 0x%08x, hash = 0x%08lx\n",
367 em_eeprom->id, dev->hash);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800368 printk(KERN_INFO "Vendor/Product ID= %04x:%04x\n", em_eeprom->vendor_ID,
369 em_eeprom->product_ID);
370
371 switch (em_eeprom->chip_conf >> 4 & 0x3) {
372 case 0:
373 printk(KERN_INFO "No audio on board.\n");
374 break;
375 case 1:
376 printk(KERN_INFO "AC97 audio (5 sample rates)\n");
377 break;
378 case 2:
379 printk(KERN_INFO "I2S audio, sample rate=32k\n");
380 break;
381 case 3:
382 printk(KERN_INFO "I2S audio, 3 sample rates\n");
383 break;
384 }
385
386 if (em_eeprom->chip_conf & 1 << 3)
387 printk(KERN_INFO "USB Remote wakeup capable\n");
388
389 if (em_eeprom->chip_conf & 1 << 2)
390 printk(KERN_INFO "USB Self power capable\n");
391
392 switch (em_eeprom->chip_conf & 0x3) {
393 case 0:
394 printk(KERN_INFO "500mA max power\n");
395 break;
396 case 1:
397 printk(KERN_INFO "400mA max power\n");
398 break;
399 case 2:
400 printk(KERN_INFO "300mA max power\n");
401 break;
402 case 3:
403 printk(KERN_INFO "200mA max power\n");
404 break;
405 }
Mauro Carvalho Chehab91cad0f2005-11-08 21:38:13 -0800406 printk(KERN_INFO "Table at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
407 em_eeprom->string_idx_table,em_eeprom->string1,
408 em_eeprom->string2,em_eeprom->string3);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800409
410 return 0;
411}
412
413/* ----------------------------------------------------------- */
414
415/*
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800416 * functionality()
417 */
418static u32 functionality(struct i2c_adapter *adap)
419{
420 return I2C_FUNC_SMBUS_EMUL;
421}
422
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800423
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800424/*
425 * attach_inform()
426 * gets called when a device attaches to the i2c bus
427 * does some basic configuration
428 */
429static int attach_inform(struct i2c_client *client)
430{
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800431 struct em28xx *dev = client->adapter->algo_data;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800432
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800433 switch (client->addr << 1) {
Ludovico Cavedon8c6da5c2007-11-02 16:37:32 -0300434 case 0x86:
Mauro Carvalho Chehabfe51f812007-11-02 16:46:28 -0300435 case 0x84:
436 case 0x96:
437 case 0x94:
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300438 {
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300439 struct v4l2_priv_tun_config tda9887_cfg;
440
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300441 struct tuner_setup tun_setup;
442
443 tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
444 tun_setup.type = TUNER_TDA9887;
445 tun_setup.addr = client->addr;
446
447 em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300448
449 tda9887_cfg.tuner = TUNER_TDA9887;
450 tda9887_cfg.priv = &dev->tda9887_conf;
451 em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG,
452 &tda9887_cfg);
Markus Rechbergera9ae9fb2005-11-08 21:37:20 -0800453 break;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300454 }
Markus Rechberger30556b22005-11-08 21:38:05 -0800455 case 0x42:
456 dprintk1(1,"attach_inform: saa7114 detected.\n");
457 break;
Markus Rechbergera9ae9fb2005-11-08 21:37:20 -0800458 case 0x4a:
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800459 dprintk1(1,"attach_inform: saa7113 detected.\n");
Markus Rechbergera9ae9fb2005-11-08 21:37:20 -0800460 break;
461 case 0xa0:
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800462 dprintk1(1,"attach_inform: eeprom detected.\n");
Markus Rechbergera9ae9fb2005-11-08 21:37:20 -0800463 break;
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800464 case 0x60:
465 case 0x8e:
466 {
467 struct IR_i2c *ir = i2c_get_clientdata(client);
468 dprintk1(1,"attach_inform: IR detected (%s).\n",ir->phys);
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800469 em28xx_set_ir(dev,ir);
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800470 break;
471 }
Markus Rechbergera9ae9fb2005-11-08 21:37:20 -0800472 case 0x80:
473 case 0x88:
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800474 dprintk1(1,"attach_inform: msp34xx detected.\n");
Markus Rechbergera9ae9fb2005-11-08 21:37:20 -0800475 break;
476 case 0xb8:
477 case 0xba:
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800478 dprintk1(1,"attach_inform: tvp5150 detected.\n");
Markus Rechbergera9ae9fb2005-11-08 21:37:20 -0800479 break;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300480
Markus Rechbergera9ae9fb2005-11-08 21:37:20 -0800481 default:
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300482 if (!dev->tuner_addr)
483 dev->tuner_addr = client->addr;
484
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800485 dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1);
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -0300486
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800487 }
488
489 return 0;
490}
491
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800492static struct i2c_algorithm em28xx_algo = {
493 .master_xfer = em28xx_i2c_xfer,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800494 .functionality = functionality,
495};
496
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800497static struct i2c_adapter em28xx_adap_template = {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800498 .owner = THIS_MODULE,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800499 .class = I2C_CLASS_TV_ANALOG,
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800500 .name = "em28xx",
501 .id = I2C_HW_B_EM28XX,
502 .algo = &em28xx_algo,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800503 .client_register = attach_inform,
504};
505
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800506static struct i2c_client em28xx_client_template = {
507 .name = "em28xx internal",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800508};
509
510/* ----------------------------------------------------------- */
511
512/*
513 * i2c_devs
514 * incomplete list of known devices
515 */
516static char *i2c_devs[128] = {
517 [0x4a >> 1] = "saa7113h",
518 [0x60 >> 1] = "remote IR sensor",
Markus Rechbergerda45a2a2005-11-08 21:37:31 -0800519 [0x8e >> 1] = "remote IR sensor",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800520 [0x86 >> 1] = "tda9887",
521 [0x80 >> 1] = "msp34xx",
522 [0x88 >> 1] = "msp34xx",
523 [0xa0 >> 1] = "eeprom",
524 [0xb8 >> 1] = "tvp5150a",
525 [0xba >> 1] = "tvp5150a",
526 [0xc0 >> 1] = "tuner (analog)",
527 [0xc2 >> 1] = "tuner (analog)",
528 [0xc4 >> 1] = "tuner (analog)",
529 [0xc6 >> 1] = "tuner (analog)",
530};
531
532/*
533 * do_i2c_scan()
534 * check i2c address range for devices
535 */
536static void do_i2c_scan(char *name, struct i2c_client *c)
537{
538 unsigned char buf;
539 int i, rc;
540
Mauro Carvalho Chehab53c4e952007-03-29 08:42:30 -0300541 for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800542 c->addr = i;
543 rc = i2c_master_recv(c, &buf, 0);
544 if (rc < 0)
545 continue;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800546 printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", name,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800547 i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
548 }
549}
550
551/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800552 * em28xx_i2c_call_clients()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800553 * send commands to all attached i2c devices
554 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800555void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800556{
557 BUG_ON(NULL == dev->i2c_adap.algo_data);
558 i2c_clients_command(&dev->i2c_adap, cmd, arg);
559}
560
561/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800562 * em28xx_i2c_register()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800563 * register i2c bus
564 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800565int em28xx_i2c_register(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800566{
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800567 BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
568 BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
569 dev->i2c_adap = em28xx_adap_template;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800570 dev->i2c_adap.dev.parent = &dev->udev->dev;
571 strcpy(dev->i2c_adap.name, dev->name);
572 dev->i2c_adap.algo_data = dev;
573 i2c_add_adapter(&dev->i2c_adap);
574
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800575 dev->i2c_client = em28xx_client_template;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800576 dev->i2c_client.adapter = &dev->i2c_adap;
577
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800578 em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800579
580 if (i2c_scan)
581 do_i2c_scan(dev->name, &dev->i2c_client);
582 return 0;
583}
584
585/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800586 * em28xx_i2c_unregister()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800587 * unregister i2c_bus
588 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800589int em28xx_i2c_unregister(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800590{
591 i2c_del_adapter(&dev->i2c_adap);
592 return 0;
593}