]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/tm6000/tm6000-i2c.c
V4L/DVB (12821): tm6000: update USB request names and clean up i2c routine
[karo-tx-linux.git] / drivers / staging / tm6000 / tm6000-i2c.c
1 /*
2    tm6000-i2c.c - driver for TM5600/TM6000 USB video capture devices
3
4    Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
5
6    Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
7         - Fix SMBus Read Byte command
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 version 2
12
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.
17
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.
21  */
22
23 #include <linux/module.h>
24 #include <linux/kernel.h>
25 #include <linux/usb.h>
26 #include <linux/i2c.h>
27
28 #include "tm6000.h"
29 #include "tm6000-regs.h"
30 #include <media/v4l2-common.h>
31 #include <media/tuner.h>
32 #include "tuner-xc2028.h"
33
34
35 /*FIXME: Hack to avoid needing to patch i2c-id.h */
36 #define I2C_HW_B_TM6000 I2C_HW_B_EM28XX
37 /* ----------------------------------------------------------- */
38
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");
42
43 static unsigned int i2c_debug = 0;
44 module_param(i2c_debug, int, 0644);
45 MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
46
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)
50
51
52 /* Returns 0 if address is found */
53 static int tm6000_i2c_scan(struct i2c_adapter *i2c_adap, int addr)
54 {
55         struct tm6000_core *dev = i2c_adap->algo_data;
56
57 #if 1
58         /* HACK: i2c scan is not working yet */
59         if (
60                 (dev->caps.has_tuner   && (addr==dev->tuner_addr)) ||
61                 (dev->caps.has_tda9874 && (addr==0xb0)) ||
62                 (dev->caps.has_eeprom  && (addr==0xa0))
63            ) {
64                 printk("Hack: enabling device at addr 0x%02x\n",addr);
65                 return (1);
66         } else {
67                 return -ENODEV;
68         }
69 #else
70         int rc=-ENODEV;
71         char buf[1];
72
73         /* This sends addr + 1 byte with 0 */
74         rc = tm6000_read_write_usb (dev,
75                 USB_DIR_IN | USB_TYPE_VENDOR,
76                 REQ_16_SET_GET_I2C_WR1_RDN,
77                 addr, 0,
78                 buf, 0);
79         msleep(10);
80
81         if (rc<0) {
82                 if (i2c_debug>=2)
83                         printk("no device at addr 0x%02x\n",addr);
84         }
85
86         printk("Hack: check on addr 0x%02x returned %d\n",addr,rc);
87
88         return rc;
89 #endif
90 }
91
92 static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
93                            struct i2c_msg msgs[], int num)
94 {
95         struct tm6000_core *dev = i2c_adap->algo_data;
96         int addr, rc, i, byte;
97
98         if (num <= 0)
99                 return 0;
100         for (i = 0; i < num; i++) {
101                 addr = (msgs[i].addr << 1) & 0xff;
102                 i2c_dprintk(2,"%s %s addr=0x%x len=%d:",
103                          (msgs[i].flags & I2C_M_RD) ? "read" : "write",
104                          i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
105                 if (!msgs[i].len) {
106                         /* Do I2C scan */
107                         rc = tm6000_i2c_scan(i2c_adap, addr);
108                 } else if (msgs[i].flags & I2C_M_RD) {
109                         /* read request without preceding register selection */
110                         /*
111                          * The TM6000 only supports a read transaction
112                          * immediately after a 1 or 2 byte write to select
113                          * a register.  We cannot fulfil this request.
114                          */
115                         i2c_dprintk(2, " read without preceding write not"
116                                        " supported");
117                         rc = -EOPNOTSUPP;
118                         goto err;
119                 } else if (i + 1 < num && msgs[i].len <= 2 &&
120                            (msgs[i + 1].flags & I2C_M_RD) &&
121                            msgs[i].addr == msgs[i + 1].addr) {
122                         /* 1 or 2 byte write followed by a read */
123                         if (i2c_debug >= 2)
124                                 for (byte = 0; byte < msgs[i].len; byte++)
125                                         printk(" %02x", msgs[i].buf[byte]);
126                         i2c_dprintk(2, "; joined to read %s len=%d:",
127                                     i == num - 2 ? "stop" : "nonstop",
128                                     msgs[i + 1].len);
129                         rc = tm6000_read_write_usb (dev,
130                                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
131                                 msgs[i].len == 1 ? REQ_16_SET_GET_I2C_WR1_RDN
132                                                  : REQ_14_SET_GET_I2C_WR2_RDN,
133                                 addr | msgs[i].buf[0] << 8,
134                                 msgs[i].len == 1 ? 0 : msgs[i].buf[1],
135                                 msgs[i + 1].buf, msgs[i + 1].len);
136                         i++;
137                         if (i2c_debug >= 2)
138                                 for (byte = 0; byte < msgs[i].len; byte++)
139                                         printk(" %02x", msgs[i].buf[byte]);
140                 } else {
141                         /* write bytes */
142                         if (i2c_debug >= 2)
143                                 for (byte = 0; byte < msgs[i].len; byte++)
144                                         printk(" %02x", msgs[i].buf[byte]);
145                         rc = tm6000_read_write_usb(dev,
146                                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
147                                 REQ_16_SET_GET_I2C_WR1_RDN,
148                                 addr | msgs[i].buf[0] << 8, 0,
149                                 msgs[i].buf + 1, msgs[i].len - 1);
150                 }
151                 if (i2c_debug >= 2)
152                         printk("\n");
153                 if (rc < 0)
154                         goto err;
155         }
156
157         return num;
158 err:
159         i2c_dprintk(2," ERROR: %i\n", rc);
160         return rc;
161 }
162
163 static int tm6000_i2c_eeprom(struct tm6000_core *dev,
164                              unsigned char *eedata, int len)
165 {
166         int i, rc;
167         unsigned char *p = eedata;
168         unsigned char bytes[17];
169
170         dev->i2c_client.addr = 0xa0 >> 1;
171
172         bytes[16] = '\0';
173         for (i = 0; i < len; ) {
174         *p = i;
175         rc = tm6000_read_write_usb (dev,
176                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
177                 REQ_16_SET_GET_I2C_WR1_RDN, 0xa0 | i<<8, 0, p, 1);
178                 if (rc < 1) {
179                         if (p == eedata)
180                                 goto noeeprom;
181                         else {
182                                 printk(KERN_WARNING
183                                 "%s: i2c eeprom read error (err=%d)\n",
184                                 dev->name, rc);
185                         }
186                         return -1;
187                 }
188                 p++;
189                 if (0 == (i % 16))
190                         printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
191                 printk(" %02x", eedata[i]);
192                 if ((eedata[i] >= ' ') && (eedata[i] <= 'z')) {
193                         bytes[i%16] = eedata[i];
194                 } else {
195                         bytes[i%16]='.';
196                 }
197
198                 i++;
199
200                 if (0 == (i % 16)) {
201                         bytes[16] = '\0';
202                         printk("  %s\n", bytes);
203                 }
204         }
205         if (0 != (i%16)) {
206                 bytes[i%16] = '\0';
207                 for (i %= 16; i < 16; i++)
208                         printk("   ");
209         }
210         printk("  %s\n", bytes);
211
212         return 0;
213
214 noeeprom:
215         printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
216                        dev->name, rc);
217         return rc;
218 }
219
220 /* ----------------------------------------------------------- */
221
222 /*
223  * algo_control()
224  */
225 static int algo_control(struct i2c_adapter *adapter,
226                         unsigned int cmd, unsigned long arg)
227 {
228         return 0;
229 }
230
231 /*
232  * functionality()
233  */
234 static u32 functionality(struct i2c_adapter *adap)
235 {
236         return I2C_FUNC_SMBUS_EMUL;
237 }
238
239 #ifndef I2C_PEC
240 static void inc_use(struct i2c_adapter *adap)
241 {
242         MOD_INC_USE_COUNT;
243 }
244
245 static void dec_use(struct i2c_adapter *adap)
246 {
247         MOD_DEC_USE_COUNT;
248 }
249 #endif
250
251 #define mass_write(addr, reg, data...)                                  \
252         { const static u8 _val[] = data;                                \
253         rc=tm6000_read_write_usb(dev,USB_DIR_OUT | USB_TYPE_VENDOR,     \
254         REQ_16_SET_GET_I2C_WR1_RDN,(reg<<8)+addr, 0x00, (u8 *) _val,    \
255         ARRAY_SIZE(_val));                                              \
256         if (rc<0) {                                                     \
257                 printk(KERN_ERR "Error on line %d: %d\n",__LINE__,rc);  \
258                 return rc;                                              \
259         }                                                               \
260         msleep (10);                                                    \
261         }
262
263 /* Tuner callback to provide the proper gpio changes needed for xc2028 */
264
265 static int tm6000_tuner_callback(void *ptr, int command, int arg)
266 {
267         int rc=0;
268         struct tm6000_core *dev = ptr;
269
270         if (dev->tuner_type!=TUNER_XC2028)
271                 return 0;
272
273         switch (command) {
274         case XC2028_RESET_CLK:
275                 tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT,
276                                         0x02, arg);
277                 msleep(10);
278                 rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
279                                         TM6000_GPIO_CLK, 0);
280                 if (rc<0)
281                         return rc;
282                 msleep(10);
283                 rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
284                                         TM6000_GPIO_CLK, 1);
285                 break;
286         case XC2028_TUNER_RESET:
287                 /* Reset codes during load firmware */
288                 switch (arg) {
289                 case 0:
290                         tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
291                                         dev->tuner_reset_gpio, 0x00);
292                         msleep(130);
293                         tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
294                                         dev->tuner_reset_gpio, 0x01);
295                         msleep(130);
296                         break;
297                 case 1:
298                         tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT,
299                                                 0x02, 0x01);
300                         msleep(10);
301                         break;
302
303                 case 2:
304                         rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
305                                                 TM6000_GPIO_CLK, 0);
306                         if (rc<0)
307                                 return rc;
308                         msleep(100);
309                         rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
310                                                 TM6000_GPIO_CLK, 1);
311                         msleep(100);
312                         break;
313                 }
314         }
315         return (rc);
316 }
317
318 static int attach_inform(struct i2c_client *client)
319 {
320         struct tm6000_core *dev = client->adapter->algo_data;
321         struct tuner_setup tun_setup;
322
323         i2c_dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
324                 client->driver->driver.name, client->addr, client->name);
325
326         switch (client->addr<<1) {
327         case 0xb0:
328                 request_module("tvaudio");
329                 return 0;
330         }
331
332         /* If tuner, initialize the tuner part */
333         if ( dev->tuner_addr != client->addr<<1 ) {
334                 return 0;
335         }
336
337         memset (&tun_setup, 0, sizeof(tun_setup));
338
339         tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
340         tun_setup.type = dev->tuner_type;
341         tun_setup.addr = dev->tuner_addr>>1;
342         tun_setup.tuner_callback = tm6000_tuner_callback;
343
344         client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup);
345
346         return 0;
347 }
348
349 static struct i2c_algorithm tm6000_algo = {
350         .master_xfer   = tm6000_i2c_xfer,
351         .algo_control  = algo_control,
352         .functionality = functionality,
353 };
354
355 static struct i2c_adapter tm6000_adap_template = {
356 #ifdef I2C_PEC
357         .owner = THIS_MODULE,
358 #else
359         .inc_use = inc_use,
360         .dec_use = dec_use,
361 #endif
362         .class = I2C_CLASS_TV_ANALOG,
363         .name = "tm6000",
364         .id = I2C_HW_B_TM6000,
365         .algo = &tm6000_algo,
366         .client_register = attach_inform,
367 };
368
369 static struct i2c_client tm6000_client_template = {
370         .name = "tm6000 internal",
371 };
372
373 /* ----------------------------------------------------------- */
374
375 /*
376  * i2c_devs
377  * incomplete list of known devices
378  */
379 static char *i2c_devs[128] = {
380         [0xc2 >> 1] = "tuner (analog)",
381 };
382
383 /*
384  * do_i2c_scan()
385  * check i2c address range for devices
386  */
387 static void do_i2c_scan(char *name, struct i2c_client *c)
388 {
389         unsigned char buf;
390         int i, rc;
391
392         for (i = 0; i < 128; i++) {
393                 c->addr = i;
394                 rc = i2c_master_recv(c, &buf, 0);
395                 if (rc < 0)
396                         continue;
397                 printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", name,
398                        i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
399         }
400 }
401
402 /*
403  * tm6000_i2c_call_clients()
404  * send commands to all attached i2c devices
405  */
406 void tm6000_i2c_call_clients(struct tm6000_core *dev, unsigned int cmd, void *arg)
407 {
408         BUG_ON(NULL == dev->i2c_adap.algo_data);
409         i2c_clients_command(&dev->i2c_adap, cmd, arg);
410 }
411
412 /*
413  * tm6000_i2c_register()
414  * register i2c bus
415  */
416 int tm6000_i2c_register(struct tm6000_core *dev)
417 {
418         unsigned char eedata[256];
419
420         dev->i2c_adap = tm6000_adap_template;
421         dev->i2c_adap.dev.parent = &dev->udev->dev;
422         strcpy(dev->i2c_adap.name, dev->name);
423         dev->i2c_adap.algo_data = dev;
424         i2c_add_adapter(&dev->i2c_adap);
425
426         dev->i2c_client = tm6000_client_template;
427         dev->i2c_client.adapter = &dev->i2c_adap;
428
429         if (i2c_scan)
430                 do_i2c_scan(dev->name, &dev->i2c_client);
431
432         tm6000_i2c_eeprom(dev, eedata, sizeof(eedata));
433
434         return 0;
435 }
436
437 /*
438  * tm6000_i2c_unregister()
439  * unregister i2c_bus
440  */
441 int tm6000_i2c_unregister(struct tm6000_core *dev)
442 {
443         i2c_del_adapter(&dev->i2c_adap);
444         return 0;
445 }