2 tm6000-i2c.c - driver for TM5600/TM6000 USB video capture devices
4 Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
6 Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
7 - Fix SMBus Read Byte command
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 version 2
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <linux/module.h>
24 #include <linux/kernel.h>
25 #include <linux/usb.h>
26 #include <linux/i2c.h>
29 #include "tm6000-regs.h"
30 #include <media/v4l2-common.h>
31 #include <media/tuner.h>
32 #include "tuner-xc2028.h"
35 /*FIXME: Hack to avoid needing to patch i2c-id.h */
36 #define I2C_HW_B_TM6000 I2C_HW_B_EM28XX
37 /* ----------------------------------------------------------- */
39 static unsigned int i2c_scan = 0;
40 module_param(i2c_scan, int, 0444);
41 MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
43 static unsigned int i2c_debug = 0;
44 module_param(i2c_debug, int, 0644);
45 MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
47 #define i2c_dprintk(lvl,fmt, args...) if (i2c_debug>=lvl) do{ \
48 printk(KERN_DEBUG "%s at %s: " fmt, \
49 dev->name, __FUNCTION__ , ##args); } while (0)
52 /* Returns 0 if address is found */
53 static int tm6000_i2c_scan(struct i2c_adapter *i2c_adap, int addr)
55 struct tm6000_core *dev = i2c_adap->algo_data;
58 /* HACK: i2c scan is not working yet */
60 (dev->caps.has_tuner && (addr==dev->tuner_addr)) ||
61 (dev->caps.has_tda9874 && (addr==0xb0)) ||
62 (dev->caps.has_zl10353 && (addr==0x1e)) ||
63 (dev->caps.has_eeprom && (addr==0xa0))
65 printk("Hack: enabling device at addr 0x%02x\n",addr);
74 /* This sends addr + 1 byte with 0 */
75 rc = tm6000_read_write_usb (dev,
76 USB_DIR_IN | USB_TYPE_VENDOR,
77 REQ_16_SET_GET_I2CSEQ,
84 printk("no device at addr 0x%02x\n",addr);
87 printk("Hack: check on addr 0x%02x returned %d\n",addr,rc);
93 static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
94 struct i2c_msg msgs[], int num)
96 struct tm6000_core *dev = i2c_adap->algo_data;
97 int addr, rc, i, byte;
102 for (i = 0; i < num; i++) {
103 addr = (msgs[i].addr << 1) &0xff;
104 i2c_dprintk(2,"%s %s addr=0x%x len=%d:",
105 (msgs[i].flags & I2C_M_RD) ? "read" : "write",
106 i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
109 rc=tm6000_i2c_scan(i2c_adap, addr);
110 } else if (msgs[i].flags & I2C_M_RD) {
112 /* I2C is assumed to have always a subaddr at the first byte of the
113 message bus. Also, the first i2c value of the answer is returned
116 /* SMBus Read Byte command */
117 if(msgs[i].len == 1) {
118 // we use the previously used register to read from
119 rc = tm6000_read_write_usb (dev,
120 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
121 REQ_16_SET_GET_I2CSEQ,
122 addr | prev_reg<<8, 0,
123 msgs[i].buf, msgs[i].len);
126 rc = tm6000_read_write_usb (dev,
127 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
128 REQ_16_SET_GET_I2CSEQ,
129 addr|(*msgs[i].buf)<<8, 0,
130 msgs[i].buf, msgs[i].len);
133 for (byte = 0; byte < msgs[i].len; byte++) {
134 printk(" %02x", msgs[i].buf[byte]);
140 for (byte = 0; byte < msgs[i].len; byte++)
141 printk(" %02x", msgs[i].buf[byte]);
144 /* SMBus Write Byte command followed by a read command */
145 if(msgs[i].len == 1 && i+1 < num && msgs[i+1].flags & I2C_M_RD
146 && msgs[i+1].addr == msgs[i].addr) {
147 prev_reg = msgs[i].buf[0];
151 rc = tm6000_read_write_usb (dev,
152 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
153 REQ_16_SET_GET_I2CSEQ,
154 addr|(*msgs[i].buf)<<8, 0,
155 msgs[i].buf+1, msgs[i].len-1);
157 if(msgs[i].len >= 1) {
158 prev_reg = msgs[i].buf[0];
172 i2c_dprintk(2," ERROR: %i\n", rc);
177 static int tm6000_i2c_eeprom( struct tm6000_core *dev,
178 unsigned char *eedata, int len )
181 unsigned char *p = eedata;
182 unsigned char bytes[17];
184 dev->i2c_client.addr = 0xa0 >> 1;
186 //006779: OUT: 000006 ms 089867 ms c0 0e a0 00 00 00 01 00 <<< 00
187 //006780: OUT: 000005 ms 089873 ms c0 10 a0 00 00 00 01 00 <<< 00
188 //006781: OUT: 000108 ms 089878 ms 40 0e a0 00 00 00 01 00 >>> 99
189 //006782: OUT: 000015 ms 089986 ms c0 0e a0 00 01 00 01 00 <<< 99
190 //006783: OUT: 000004 ms 090001 ms c0 0e a0 00 10 00 01 00 <<< 99
191 //006784: OUT: 000005 ms 090005 ms 40 10 a0 00 00 00 01 00 >>> 00
192 //006785: OUT: 000308 ms 090010 ms 40 0e a0 00 00 00 01 00 >>> 00
195 for (i = 0; i < len; i++) {
198 rc = i2c_master_recv(&dev->i2c_client, p, 1);
201 printk (KERN_WARNING "%s doesn't have eeprom",
205 "%s: i2c eeprom read error (err=%d)\n",
212 printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
213 printk(" %02x", eedata[i]);
214 if ((eedata[i]>=' ')&&(eedata[i]<='z')) {
215 bytes[i%16]=eedata[i];
219 if (15 == (i % 16)) {
221 printk(" %s\n", bytes);
226 printk(" %s\n", bytes);
231 /* ----------------------------------------------------------- */
236 static int algo_control(struct i2c_adapter *adapter,
237 unsigned int cmd, unsigned long arg)
245 static u32 functionality(struct i2c_adapter *adap)
247 return I2C_FUNC_SMBUS_EMUL;
251 static void inc_use(struct i2c_adapter *adap)
256 static void dec_use(struct i2c_adapter *adap)
262 #define mass_write(addr, reg, data...) \
263 { const static u8 _val[] = data; \
264 rc=tm6000_read_write_usb(dev,USB_DIR_OUT | USB_TYPE_VENDOR, \
265 REQ_16_SET_GET_I2CSEQ,(reg<<8)+addr, 0x00, (u8 *) _val, \
268 printk(KERN_ERR "Error on line %d: %d\n",__LINE__,rc); \
274 int static init_zl10353 (struct tm6000_core *dev, u8 addr)
278 mass_write (addr, 0x89, { 0x38 });
279 mass_write (addr, 0x8a, { 0x2d });
280 mass_write (addr, 0x50, { 0xff });
281 mass_write (addr, 0x51, { 0x00 , 0x00 , 0x50 });
282 mass_write (addr, 0x54, { 0x72 , 0x49 });
283 mass_write (addr, 0x87, { 0x0e , 0x0e });
284 mass_write (addr, 0x7b, { 0x04 });
285 mass_write (addr, 0x57, { 0xb8 , 0xc2 });
286 mass_write (addr, 0x59, { 0x00 , 0x02 , 0x00 , 0x00 , 0x01 });
287 mass_write (addr, 0x59, { 0x00 , 0x00 , 0xb3 , 0xd0 , 0x01 });
288 mass_write (addr, 0x58, { 0xc0 , 0x11 , 0xc5 , 0xc2 , 0xa4 , 0x01 });
289 mass_write (addr, 0x5e, { 0x01 });
290 mass_write (addr, 0x67, { 0x1c , 0x20 });
291 mass_write (addr, 0x75, { 0x33 });
292 mass_write (addr, 0x85, { 0x10 , 0x40 });
293 mass_write (addr, 0x8c, { 0x0b , 0x00 , 0x40 , 0x00 });
298 /* Tuner callback to provide the proper gpio changes needed for xc2028 */
300 static int tm6000_tuner_callback(void *ptr, int command, int arg)
303 struct tm6000_core *dev = ptr;
305 if (dev->tuner_type!=TUNER_XC2028)
309 case XC2028_RESET_CLK:
310 tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT,
313 rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
318 rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
321 case XC2028_TUNER_RESET:
322 /* Reset codes during load firmware */
325 tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
326 TM6000_GPIO_1, 0x00);
328 tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
329 TM6000_GPIO_1, 0x01);
332 tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT,
338 rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
343 rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
347 tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
348 TM6000_GPIO_4, 0x00);
350 tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
351 TM6000_GPIO_4, 0x01);
359 static int attach_inform(struct i2c_client *client)
361 struct tm6000_core *dev = client->adapter->algo_data;
362 struct tuner_setup tun_setup;
363 unsigned char eedata[11];
365 i2c_dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
366 client->driver->driver.name, client->addr, client->name);
368 switch (client->addr<<1) {
370 init_zl10353 (dev, client->addr);
373 tm6000_i2c_eeprom(dev, eedata, sizeof(eedata)-1);
374 eedata[sizeof(eedata)]='\0';
376 printk("Board string ID = %s\n",eedata);
379 request_module("tvaudio");
383 /* If tuner, initialize the tuner part */
384 if ( dev->tuner_addr != client->addr<<1 ) {
388 memset (&tun_setup, 0, sizeof(tun_setup));
390 tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
391 tun_setup.type = dev->tuner_type;
392 tun_setup.addr = dev->tuner_addr>>1;
393 tun_setup.tuner_callback = tm6000_tuner_callback;
395 client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup);
400 static struct i2c_algorithm tm6000_algo = {
401 .master_xfer = tm6000_i2c_xfer,
402 .algo_control = algo_control,
403 .functionality = functionality,
406 static struct i2c_adapter tm6000_adap_template = {
408 .owner = THIS_MODULE,
413 .class = I2C_CLASS_TV_ANALOG,
415 .id = I2C_HW_B_TM6000,
416 .algo = &tm6000_algo,
417 .client_register = attach_inform,
420 static struct i2c_client tm6000_client_template = {
421 .name = "tm6000 internal",
424 /* ----------------------------------------------------------- */
428 * incomplete list of known devices
430 static char *i2c_devs[128] = {
431 [0xc2 >> 1] = "tuner (analog)",
436 * check i2c address range for devices
438 static void do_i2c_scan(char *name, struct i2c_client *c)
443 for (i = 0; i < 128; i++) {
445 rc = i2c_master_recv(c, &buf, 0);
448 printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", name,
449 i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
454 * tm6000_i2c_call_clients()
455 * send commands to all attached i2c devices
457 void tm6000_i2c_call_clients(struct tm6000_core *dev, unsigned int cmd, void *arg)
459 BUG_ON(NULL == dev->i2c_adap.algo_data);
460 i2c_clients_command(&dev->i2c_adap, cmd, arg);
464 * tm6000_i2c_register()
467 int tm6000_i2c_register(struct tm6000_core *dev)
469 dev->i2c_adap = tm6000_adap_template;
470 dev->i2c_adap.dev.parent = &dev->udev->dev;
471 strcpy(dev->i2c_adap.name, dev->name);
472 dev->i2c_adap.algo_data = dev;
473 i2c_add_adapter(&dev->i2c_adap);
475 dev->i2c_client = tm6000_client_template;
476 dev->i2c_client.adapter = &dev->i2c_adap;
479 do_i2c_scan(dev->name, &dev->i2c_client);
485 * tm6000_i2c_unregister()
488 int tm6000_i2c_unregister(struct tm6000_core *dev)
490 i2c_del_adapter(&dev->i2c_adap);