blob: a33878e0879945a6bbd5200b94ee9cba32fa1a23 [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 Chehab3acf2802005-11-08 21:38:27 -0800295static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800296{
297 unsigned char buf, *p = eedata;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800298 struct em28xx_eeprom *em_eeprom = (void *)eedata;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800299 int i, err, size = len, block;
300
301 dev->i2c_client.addr = 0xa0 >> 1;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800302
303 /* Check if board has eeprom */
304 err = i2c_master_recv(&dev->i2c_client, &buf, 0);
305 if (err < 0)
306 return -1;
307
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800308 buf = 0;
309 if (1 != (err = i2c_master_send(&dev->i2c_client, &buf, 1))) {
310 printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
311 dev->name, err);
312 return -1;
313 }
314 while (size > 0) {
315 if (size > 16)
316 block = 16;
317 else
318 block = size;
319
320 if (block !=
321 (err = i2c_master_recv(&dev->i2c_client, p, block))) {
322 printk(KERN_WARNING
323 "%s: i2c eeprom read error (err=%d)\n",
324 dev->name, err);
325 return -1;
326 }
327 size -= block;
328 p += block;
329 }
330 for (i = 0; i < len; i++) {
331 if (0 == (i % 16))
332 printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
333 printk(" %02x", eedata[i]);
334 if (15 == (i % 16))
335 printk("\n");
336 }
337
338 printk(KERN_INFO "EEPROM ID= 0x%08x\n", em_eeprom->id);
339 printk(KERN_INFO "Vendor/Product ID= %04x:%04x\n", em_eeprom->vendor_ID,
340 em_eeprom->product_ID);
341
342 switch (em_eeprom->chip_conf >> 4 & 0x3) {
343 case 0:
344 printk(KERN_INFO "No audio on board.\n");
345 break;
346 case 1:
347 printk(KERN_INFO "AC97 audio (5 sample rates)\n");
348 break;
349 case 2:
350 printk(KERN_INFO "I2S audio, sample rate=32k\n");
351 break;
352 case 3:
353 printk(KERN_INFO "I2S audio, 3 sample rates\n");
354 break;
355 }
356
357 if (em_eeprom->chip_conf & 1 << 3)
358 printk(KERN_INFO "USB Remote wakeup capable\n");
359
360 if (em_eeprom->chip_conf & 1 << 2)
361 printk(KERN_INFO "USB Self power capable\n");
362
363 switch (em_eeprom->chip_conf & 0x3) {
364 case 0:
365 printk(KERN_INFO "500mA max power\n");
366 break;
367 case 1:
368 printk(KERN_INFO "400mA max power\n");
369 break;
370 case 2:
371 printk(KERN_INFO "300mA max power\n");
372 break;
373 case 3:
374 printk(KERN_INFO "200mA max power\n");
375 break;
376 }
Mauro Carvalho Chehab91cad0f2005-11-08 21:38:13 -0800377 printk(KERN_INFO "Table at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
378 em_eeprom->string_idx_table,em_eeprom->string1,
379 em_eeprom->string2,em_eeprom->string3);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800380
381 return 0;
382}
383
384/* ----------------------------------------------------------- */
385
386/*
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800387 * functionality()
388 */
389static u32 functionality(struct i2c_adapter *adap)
390{
391 return I2C_FUNC_SMBUS_EMUL;
392}
393
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800394
Mauro Carvalho Chehab6c362c82007-10-29 23:36:12 -0300395static int em28xx_tuner_callback(void *ptr, int command, int arg)
396{
397 int rc = 0;
398 struct em28xx *dev = ptr;
399
400 if (dev->tuner_type != TUNER_XC2028)
401 return 0;
402
403 switch (command) {
404 case XC2028_TUNER_RESET:
405 /* FIXME: This is device-dependent */
406 dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
407 dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1);
408
409 msleep(140);
410 break;
411 }
412 return rc;
413}
414
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800415static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800416{
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800417 struct em28xx *dev = client->adapter->algo_data;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800418 struct tuner_setup tun_setup;
419
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800420 if (dev->has_tuner) {
421 tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
422 tun_setup.type = dev->tuner_type;
423 tun_setup.addr = dev->tuner_addr;
Mauro Carvalho Chehab6c362c82007-10-29 23:36:12 -0300424 tun_setup.tuner_callback = em28xx_tuner_callback;
425
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800426 em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800427 }
Nickolay V. Shmyrevfd35a6b2005-11-08 21:37:09 -0800428
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800429 return (0);
430}
431
432/*
433 * attach_inform()
434 * gets called when a device attaches to the i2c bus
435 * does some basic configuration
436 */
437static int attach_inform(struct i2c_client *client)
438{
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800439 struct em28xx *dev = client->adapter->algo_data;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800440
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800441 switch (client->addr << 1) {
Ludovico Cavedon8c6da5c2007-11-02 16:37:32 -0300442 case 0x86:
Mauro Carvalho Chehabfe51f812007-11-02 16:46:28 -0300443 case 0x84:
444 case 0x96:
445 case 0x94:
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300446 {
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300447 struct v4l2_priv_tun_config tda9887_cfg;
448
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300449 struct tuner_setup tun_setup;
450
451 tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
452 tun_setup.type = TUNER_TDA9887;
453 tun_setup.addr = client->addr;
454
455 em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300456
457 tda9887_cfg.tuner = TUNER_TDA9887;
458 tda9887_cfg.priv = &dev->tda9887_conf;
459 em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG,
460 &tda9887_cfg);
Markus Rechbergera9ae9fb2005-11-08 21:37:20 -0800461 break;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300462 }
Markus Rechberger30556b22005-11-08 21:38:05 -0800463 case 0x42:
464 dprintk1(1,"attach_inform: saa7114 detected.\n");
465 break;
Markus Rechbergera9ae9fb2005-11-08 21:37:20 -0800466 case 0x4a:
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800467 dprintk1(1,"attach_inform: saa7113 detected.\n");
Markus Rechbergera9ae9fb2005-11-08 21:37:20 -0800468 break;
469 case 0xa0:
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800470 dprintk1(1,"attach_inform: eeprom detected.\n");
Markus Rechbergera9ae9fb2005-11-08 21:37:20 -0800471 break;
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800472 case 0x60:
473 case 0x8e:
474 {
475 struct IR_i2c *ir = i2c_get_clientdata(client);
476 dprintk1(1,"attach_inform: IR detected (%s).\n",ir->phys);
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800477 em28xx_set_ir(dev,ir);
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800478 break;
479 }
Markus Rechbergera9ae9fb2005-11-08 21:37:20 -0800480 case 0x80:
481 case 0x88:
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800482 dprintk1(1,"attach_inform: msp34xx detected.\n");
Markus Rechbergera9ae9fb2005-11-08 21:37:20 -0800483 break;
484 case 0xb8:
485 case 0xba:
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800486 dprintk1(1,"attach_inform: tvp5150 detected.\n");
Markus Rechbergera9ae9fb2005-11-08 21:37:20 -0800487 break;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300488
Markus Rechbergera9ae9fb2005-11-08 21:37:20 -0800489 default:
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800490 dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1);
Markus Rechbergera9ae9fb2005-11-08 21:37:20 -0800491 dev->tuner_addr = client->addr;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800492 em28xx_set_tuner(-1, client);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800493 }
494
495 return 0;
496}
497
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800498static struct i2c_algorithm em28xx_algo = {
499 .master_xfer = em28xx_i2c_xfer,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800500 .functionality = functionality,
501};
502
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800503static struct i2c_adapter em28xx_adap_template = {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800504 .owner = THIS_MODULE,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800505 .class = I2C_CLASS_TV_ANALOG,
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800506 .name = "em28xx",
507 .id = I2C_HW_B_EM28XX,
508 .algo = &em28xx_algo,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800509 .client_register = attach_inform,
510};
511
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800512static struct i2c_client em28xx_client_template = {
513 .name = "em28xx internal",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800514};
515
516/* ----------------------------------------------------------- */
517
518/*
519 * i2c_devs
520 * incomplete list of known devices
521 */
522static char *i2c_devs[128] = {
523 [0x4a >> 1] = "saa7113h",
524 [0x60 >> 1] = "remote IR sensor",
Markus Rechbergerda45a2a2005-11-08 21:37:31 -0800525 [0x8e >> 1] = "remote IR sensor",
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800526 [0x86 >> 1] = "tda9887",
527 [0x80 >> 1] = "msp34xx",
528 [0x88 >> 1] = "msp34xx",
529 [0xa0 >> 1] = "eeprom",
530 [0xb8 >> 1] = "tvp5150a",
531 [0xba >> 1] = "tvp5150a",
532 [0xc0 >> 1] = "tuner (analog)",
533 [0xc2 >> 1] = "tuner (analog)",
534 [0xc4 >> 1] = "tuner (analog)",
535 [0xc6 >> 1] = "tuner (analog)",
536};
537
538/*
539 * do_i2c_scan()
540 * check i2c address range for devices
541 */
542static void do_i2c_scan(char *name, struct i2c_client *c)
543{
544 unsigned char buf;
545 int i, rc;
546
Mauro Carvalho Chehab53c4e952007-03-29 08:42:30 -0300547 for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800548 c->addr = i;
549 rc = i2c_master_recv(c, &buf, 0);
550 if (rc < 0)
551 continue;
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -0800552 printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", name,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800553 i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
554 }
555}
556
557/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800558 * em28xx_i2c_call_clients()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800559 * send commands to all attached i2c devices
560 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800561void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800562{
563 BUG_ON(NULL == dev->i2c_adap.algo_data);
564 i2c_clients_command(&dev->i2c_adap, cmd, arg);
565}
566
567/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800568 * em28xx_i2c_register()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800569 * register i2c bus
570 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800571int em28xx_i2c_register(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800572{
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800573 BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
574 BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
575 dev->i2c_adap = em28xx_adap_template;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800576 dev->i2c_adap.dev.parent = &dev->udev->dev;
577 strcpy(dev->i2c_adap.name, dev->name);
578 dev->i2c_adap.algo_data = dev;
579 i2c_add_adapter(&dev->i2c_adap);
580
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800581 dev->i2c_client = em28xx_client_template;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800582 dev->i2c_client.adapter = &dev->i2c_adap;
583
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800584 em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800585
586 if (i2c_scan)
587 do_i2c_scan(dev->name, &dev->i2c_client);
588 return 0;
589}
590
591/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800592 * em28xx_i2c_unregister()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800593 * unregister i2c_bus
594 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800595int em28xx_i2c_unregister(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800596{
597 i2c_del_adapter(&dev->i2c_adap);
598 return 0;
599}