]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/media/video/tuner-xc2028.c
V4L/DVB (6593): Fix scode table loading
[linux-2.6-omap-h63xx.git] / drivers / media / video / tuner-xc2028.c
1 /* tuner-xc2028
2  *
3  * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
4  *
5  * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com)
6  *       - frontend interface
7  *
8  * This code is placed under the terms of the GNU General Public License v2
9  */
10
11 #include <linux/i2c.h>
12 #include <asm/div64.h>
13 #include <linux/firmware.h>
14 #include <linux/videodev2.h>
15 #include <linux/delay.h>
16 #include <media/tuner.h>
17 #include <linux/mutex.h>
18 #include "tuner-i2c.h"
19 #include "tuner-xc2028.h"
20 #include "tuner-xc2028-types.h"
21
22 #include <linux/dvb/frontend.h>
23 #include "dvb_frontend.h"
24
25 #define PREFIX "xc2028"
26
27 static LIST_HEAD(xc2028_list);
28 /* struct for storing firmware table */
29 struct firmware_description {
30         unsigned int  type;
31         v4l2_std_id   id;
32         unsigned char *ptr;
33         unsigned int  size;
34 };
35
36 struct xc2028_data {
37         struct list_head        xc2028_list;
38         struct tuner_i2c_props  i2c_props;
39         int                     (*tuner_callback) (void *dev,
40                                                    int command, int arg);
41         struct device           *dev;
42         void                    *video_dev;
43         int                     count;
44         __u32                   frequency;
45
46         struct firmware_description *firm;
47         int                     firm_size;
48
49         __u16                   version;
50
51         struct xc2028_ctrl      ctrl;
52
53         v4l2_std_id             firm_type;         /* video stds supported
54                                                         by current firmware */
55         fe_bandwidth_t          bandwidth;         /* Firmware bandwidth:
56                                                               6M, 7M or 8M */
57         int                     need_load_generic; /* The generic firmware
58                                                               were loaded? */
59
60         int                     max_len;        /* Max firmware chunk */
61
62         enum tuner_mode mode;
63         struct i2c_client       *i2c_client;
64
65         struct mutex lock;
66 };
67
68 #define i2c_send(rc, priv, buf, size) do {                              \
69         rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size);          \
70         if (size != rc)                                                 \
71                 tuner_info("i2c output error: rc = %d (should be %d)\n",\
72                            rc, (int)size);                              \
73 } while (0)
74
75 #define i2c_rcv(rc, priv, buf, size) do {                               \
76         rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size);          \
77         if (size != rc)                                                 \
78                 tuner_info("i2c input error: rc = %d (should be %d)\n", \
79                            rc, (int)size);                              \
80 } while (0)
81
82 #define send_seq(priv, data...) do {                                    \
83         int rc;                                                         \
84         static u8 _val[] = data;                                        \
85         if (sizeof(_val) !=                                             \
86                         (rc = tuner_i2c_xfer_send(&priv->i2c_props,     \
87                                                 _val, sizeof(_val)))) { \
88                 tuner_info("Error on line %d: %d\n", __LINE__, rc);     \
89                 return -EINVAL;                                         \
90         }                                                               \
91         msleep(10);                                                     \
92 } while (0)
93
94 static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg)
95 {
96         int rc;
97         unsigned char buf[2];
98
99         tuner_info("%s called\n", __FUNCTION__);
100
101         buf[0] = reg>>8;
102         buf[1] = (unsigned char) reg;
103
104         i2c_send(rc, priv, buf, 2);
105         if (rc < 0)
106                 return rc;
107
108         i2c_rcv(rc, priv, buf, 2);
109         if (rc < 0)
110                 return rc;
111
112         return (buf[1]) | (buf[0] << 8);
113 }
114
115 void dump_firm_type(unsigned int type)
116 {
117          if (type & BASE)
118                 printk("BASE ");
119          if (type & INIT1)
120                 printk("INIT1 ");
121          if (type & F8MHZ)
122                 printk("F8MHZ ");
123          if (type & MTS)
124                 printk("MTS ");
125          if (type & D2620)
126                 printk("D2620 ");
127          if (type & D2633)
128                 printk("D2633 ");
129          if (type & DTV6)
130                 printk("DTV6 ");
131          if (type & QAM)
132                 printk("QAM ");
133          if (type & DTV7)
134                 printk("DTV7 ");
135          if (type & DTV78)
136                 printk("DTV78 ");
137          if (type & DTV8)
138                 printk("DTV8 ");
139          if (type & FM)
140                 printk("FM ");
141          if (type & INPUT1)
142                 printk("INPUT1 ");
143          if (type & LCD)
144                 printk("LCD ");
145          if (type & NOGD)
146                 printk("NOGD ");
147          if (type & MONO)
148                 printk("MONO ");
149          if (type & ATSC)
150                 printk("ATSC ");
151          if (type & IF)
152                 printk("IF ");
153          if (type & LG60)
154                 printk("LG60 ");
155          if (type & ATI638)
156                 printk("ATI638 ");
157          if (type & OREN538)
158                 printk("OREN538 ");
159          if (type & OREN36)
160                 printk("OREN36 ");
161          if (type & TOYOTA388)
162                 printk("TOYOTA388 ");
163          if (type & TOYOTA794)
164                 printk("TOYOTA794 ");
165          if (type & DIBCOM52)
166                 printk("DIBCOM52 ");
167          if (type & ZARLINK456)
168                 printk("ZARLINK456 ");
169          if (type & CHINA)
170                 printk("CHINA ");
171          if (type & F6MHZ)
172                 printk("F6MHZ ");
173          if (type & INPUT2)
174                 printk("INPUT2 ");
175          if (type & SCODE)
176                 printk("SCODE ");
177 }
178
179 static void free_firmware(struct xc2028_data *priv)
180 {
181         int i;
182
183         if (!priv->firm)
184                 return;
185
186         for (i = 0; i < priv->firm_size; i++)
187                 kfree(priv->firm[i].ptr);
188
189         kfree(priv->firm);
190
191         priv->firm = NULL;
192         priv->need_load_generic = 1;
193 }
194
195 static int load_all_firmwares(struct dvb_frontend *fe)
196 {
197         struct xc2028_data    *priv = fe->tuner_priv;
198         const struct firmware *fw   = NULL;
199         unsigned char         *p, *endp;
200         int                   rc = 0;
201         int                   n, n_array;
202         char                  name[33];
203
204         tuner_info("%s called\n", __FUNCTION__);
205
206         tuner_info("Reading firmware %s\n", priv->ctrl.fname);
207         rc = request_firmware(&fw, priv->ctrl.fname, priv->dev);
208         if (rc < 0) {
209                 if (rc == -ENOENT)
210                         tuner_info("Error: firmware %s not found.\n",
211                                    priv->ctrl.fname);
212                 else
213                         tuner_info("Error %d while requesting firmware %s \n",
214                                    rc, priv->ctrl.fname);
215
216                 return rc;
217         }
218         p = fw->data;
219         endp = p + fw->size;
220
221         if (fw->size < sizeof(name) - 1 + 2) {
222                 tuner_info("Error: firmware size is zero!\n");
223                 rc = -EINVAL;
224                 goto done;
225         }
226
227         memcpy(name, p, sizeof(name) - 1);
228         name[sizeof(name) - 1] = 0;
229         p += sizeof(name) - 1;
230
231         priv->version = le16_to_cpu(*(__u16 *) p);
232         p += 2;
233
234         tuner_info("firmware: %s, ver %d.%d\n", name,
235                    priv->version >> 8, priv->version & 0xff);
236
237         if (p + 2 > endp)
238                 goto corrupt;
239
240         n_array = le16_to_cpu(*(__u16 *) p);
241         p += 2;
242
243         tuner_info("there are %d firmwares at %s\n", n_array, priv->ctrl.fname);
244
245         priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL);
246
247         if (!fw) {
248                 tuner_info("Not enough memory for loading firmware.\n");
249                 rc = -ENOMEM;
250                 goto done;
251         }
252
253         priv->firm_size = n_array;
254         n = -1;
255         while (p < endp) {
256                 __u32 type, size;
257                 v4l2_std_id id;
258
259                 n++;
260                 if (n >= n_array) {
261                         tuner_info("Too much firmwares at the file\n");
262                         goto corrupt;
263                 }
264
265                 /* Checks if there's enough bytes to read */
266                 if (p + sizeof(type) + sizeof(id) + sizeof(size) > endp) {
267                         tuner_info("Lost firmware!\n");
268                         goto corrupt;
269                 }
270
271                 type = le32_to_cpu(*(__u32 *) p);
272                 p += sizeof(type);
273
274                 id = le64_to_cpu(*(v4l2_std_id *) p);
275                 p += sizeof(id);
276
277                 size = le32_to_cpu(*(v4l2_std_id *) p);
278                 p += sizeof(size);
279
280                 if ((!size) || (size + p > endp)) {
281                         tuner_info("Firmware type ");
282                         dump_firm_type(type);
283                         printk("(%x), id %lx corrupt (size=%ld, expected %d)\n",
284                                    type, (unsigned long)id, endp - p, size);
285                         goto corrupt;
286                 }
287
288                 priv->firm[n].ptr = kzalloc(size, GFP_KERNEL);
289                 if (!priv->firm[n].ptr) {
290                         tuner_info("Not enough memory.\n");
291                         rc = -ENOMEM;
292                         goto err;
293                 }
294                 tuner_info("Loading firmware type ");
295                 dump_firm_type(type);
296                 printk("(%x), id %lx, size=%d.\n",
297                            type, (unsigned long)id, size);
298
299                 memcpy(priv->firm[n].ptr, p, size);
300                 priv->firm[n].type = type;
301                 priv->firm[n].id   = id;
302                 priv->firm[n].size = size;
303
304                 p += size;
305         }
306
307         if (n + 1 != priv->firm_size) {
308                 tuner_info("Firmware file is incomplete!\n");
309                 goto corrupt;
310         }
311
312         goto done;
313
314 corrupt:
315         rc = -EINVAL;
316         tuner_info("Error: firmware file is corrupted!\n");
317
318 err:
319         tuner_info("Releasing loaded firmware file.\n");
320
321         free_firmware(priv);
322
323 done:
324         release_firmware(fw);
325         tuner_info("Firmware files loaded.\n");
326
327         return rc;
328 }
329
330 static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
331                          v4l2_std_id *id)
332 {
333         struct xc2028_data *priv = fe->tuner_priv;
334         int                i;
335
336         tuner_info("%s called\n", __FUNCTION__);
337
338         if (!priv->firm) {
339                 printk(KERN_ERR PREFIX "Error! firmware not loaded\n");
340                 return -EINVAL;
341         }
342
343         if (((type & ~SCODE) == 0) && (*id == 0))
344                 *id = V4L2_STD_PAL;
345
346         /* Seek for exact match */
347         for (i = 0; i < priv->firm_size; i++) {
348                 if ((type == priv->firm[i].type) && (*id == priv->firm[i].id))
349                         goto found;
350         }
351
352         /* Seek for generic video standard match */
353         for (i = 0; i < priv->firm_size; i++) {
354                 if ((type == priv->firm[i].type) && (*id & priv->firm[i].id))
355                         goto found;
356         }
357
358         /*FIXME: Would make sense to seek for type "hint" match ? */
359
360         i = -EINVAL;
361         goto ret;
362
363 found:
364         *id = priv->firm[i].id;
365
366 ret:
367         tuner_info("%s firmware for type=", (i < 0)? "Can't find": "Found");
368         dump_firm_type(type);
369         printk("(%x), id %08lx.\n", type, (unsigned long)*id);
370
371         return i;
372 }
373
374 static int load_firmware(struct dvb_frontend *fe, unsigned int type,
375                          v4l2_std_id *id)
376 {
377         struct xc2028_data *priv = fe->tuner_priv;
378         int                pos, rc;
379         unsigned char      *p, *endp, buf[priv->max_len];
380
381         tuner_info("%s called\n", __FUNCTION__);
382
383         pos = seek_firmware(fe, type, id);
384         if (pos < 0)
385                 return pos;
386
387         p = priv->firm[pos].ptr;
388
389         if (!p) {
390                 printk(KERN_ERR PREFIX "Firmware pointer were freed!");
391                 return -EINVAL;
392         }
393         endp = p + priv->firm[pos].size;
394
395         while (p < endp) {
396                 __u16 size;
397
398                 /* Checks if there's enough bytes to read */
399                 if (p + sizeof(size) > endp) {
400                         tuner_info("missing bytes\n");
401                         return -EINVAL;
402                 }
403
404                 size = le16_to_cpu(*(__u16 *) p);
405                 p += sizeof(size);
406
407                 if (size == 0xffff)
408                         return 0;
409
410                 if (!size) {
411                         /* Special callback command received */
412                         rc = priv->tuner_callback(priv->video_dev,
413                                                   XC2028_TUNER_RESET, 0);
414                         if (rc < 0) {
415                                 tuner_info("Error at RESET code %d\n",
416                                            (*p) & 0x7f);
417                                 return -EINVAL;
418                         }
419                         continue;
420                 }
421
422                 /* Checks for a sleep command */
423                 if (size & 0x8000) {
424                         msleep(size & 0x7fff);
425                         continue;
426                 }
427
428                 if ((size + p > endp)) {
429                         tuner_info("missing bytes: need %d, have %d\n",
430                                    size, (int)(endp - p));
431                         return -EINVAL;
432                 }
433
434                 buf[0] = *p;
435                 p++;
436                 size--;
437
438                 /* Sends message chunks */
439                 while (size > 0) {
440                         int len = (size < priv->max_len - 1) ?
441                                    size : priv->max_len - 1;
442
443                         memcpy(buf + 1, p, len);
444
445                         i2c_send(rc, priv, buf, len + 1);
446                         if (rc < 0) {
447                                 tuner_info("%d returned from send\n", rc);
448                                 return -EINVAL;
449                         }
450
451                         p += len;
452                         size -= len;
453                 }
454         }
455         return 0;
456 }
457
458 static int load_scode(struct dvb_frontend *fe, unsigned int type,
459                          v4l2_std_id *id, int scode)
460 {
461         struct xc2028_data *priv = fe->tuner_priv;
462         int                pos, rc;
463         unsigned char      *p;
464
465         tuner_info("%s called\n", __FUNCTION__);
466
467         pos = seek_firmware(fe, type, id);
468         if (pos < 0)
469                 return pos;
470
471         p = priv->firm[pos].ptr;
472
473         if (!p) {
474                 printk(KERN_ERR PREFIX "Firmware pointer were freed!");
475                 return -EINVAL;
476         }
477
478         if ((priv->firm[pos].size != 12 * 16) || (scode >= 16))
479                 return -EINVAL;
480
481         if (priv->version < 0x0202) {
482                 send_seq(priv, {0x20, 0x00, 0x00, 0x00});
483         } else {
484                 send_seq(priv, {0xa0, 0x00, 0x00, 0x00});
485         }
486
487         i2c_send(rc, priv, p + 12 * scode, 12);
488
489         send_seq(priv, {0x00, 0x8c});
490
491         return 0;
492 }
493
494 static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
495                           v4l2_std_id std, fe_bandwidth_t bandwidth)
496 {
497         struct xc2028_data      *priv = fe->tuner_priv;
498         int                     rc, version, hwmodel;
499         v4l2_std_id             std0 = 0;
500         unsigned int            type0 = 0, type = 0;
501         int                     change_digital_bandwidth;
502
503         tuner_info("%s called\n", __FUNCTION__);
504
505         if (!priv->firm) {
506                 if (!priv->ctrl.fname)
507                         return -EINVAL;
508
509                 rc = load_all_firmwares(fe);
510                 if (rc < 0)
511                         return rc;
512         }
513
514         tuner_info("I am in mode %u and I should switch to mode %i\n",
515                    priv->mode, new_mode);
516
517         /* first of all, determine whether we have switched the mode */
518         if (new_mode != priv->mode) {
519                 priv->mode = new_mode;
520                 priv->need_load_generic = 1;
521         }
522
523         change_digital_bandwidth = (priv->mode == T_DIGITAL_TV
524                                     && bandwidth != priv->bandwidth) ? 1 : 0;
525         tuner_info("old bandwidth %u, new bandwidth %u\n", priv->bandwidth,
526                    bandwidth);
527
528         if (priv->need_load_generic) {
529                 /* Reset is needed before loading firmware */
530                 rc = priv->tuner_callback(priv->video_dev,
531                                           XC2028_TUNER_RESET, 0);
532                 if (rc < 0)
533                         return rc;
534
535                 type0 = BASE;
536
537                 if (priv->ctrl.type == XC2028_FIRM_MTS)
538                         type0 |= MTS;
539
540                 if (priv->bandwidth == 8)
541                         type0 |= F8MHZ;
542
543                 /* FIXME: How to load FM and FM|INPUT1 firmwares? */
544
545                 rc = load_firmware(fe, type0, &std0);
546                 if (rc < 0) {
547                         tuner_info("Error %d while loading generic firmware\n",
548                                    rc);
549                         return rc;
550                 }
551
552                 priv->need_load_generic = 0;
553                 priv->firm_type = 0;
554                 if (priv->mode == T_DIGITAL_TV)
555                         change_digital_bandwidth = 1;
556         }
557
558         tuner_info("I should change bandwidth %u\n", change_digital_bandwidth);
559
560         if (change_digital_bandwidth) {
561
562                 /*FIXME: Should allow selecting between D2620 and D2633 */
563                 type |= D2620;
564
565                 /* FIXME: When should select a DTV78 firmware?
566                  */
567                 switch (bandwidth) {
568                 case BANDWIDTH_8_MHZ:
569                         type |= DTV8;
570                         break;
571                 case BANDWIDTH_7_MHZ:
572                         type |= DTV7;
573                         break;
574                 case BANDWIDTH_6_MHZ:
575                         /* FIXME: Should allow select also ATSC */
576                         type |= DTV6 | QAM;
577                         break;
578
579                 default:
580                         tuner_info("error: bandwidth not supported.\n");
581                 };
582                 priv->bandwidth = bandwidth;
583         }
584
585         /* Load INIT1, if needed */
586         tuner_info("Load init1 firmware, if exists\n");
587         type0 = BASE | INIT1;
588         if (priv->ctrl.type == XC2028_FIRM_MTS)
589                 type0 |= MTS;
590
591         /* FIXME: Should handle errors - if INIT1 found */
592         rc = load_firmware(fe, type0, &std0);
593
594         /* FIXME: Should add support for FM radio
595          */
596
597         if (priv->ctrl.type == XC2028_FIRM_MTS)
598                 type |= MTS;
599
600         tuner_info("Firmware standard to load: %08lx\n", (unsigned long)std);
601         if (priv->firm_type & std) {
602                 tuner_info("Std-specific firmware already loaded.\n");
603                 return 0;
604         }
605
606         rc = load_firmware(fe, type, &std);
607         if (rc < 0)
608                 return rc;
609
610         /* Load SCODE firmware, if exists */
611         tuner_info("Trying to load scode 0\n");
612         type |= SCODE;
613
614         rc = load_scode(fe, type, &std, 0);
615
616         version = xc2028_get_reg(priv, 0x0004);
617         hwmodel = xc2028_get_reg(priv, 0x0008);
618
619         tuner_info("Device is Xceive %d version %d.%d, "
620                    "firmware version %d.%d\n",
621                    hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
622                    (version & 0xf0) >> 4, version & 0xf);
623
624         priv->firm_type = std;
625
626         return 0;
627 }
628
629 static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
630 {
631         struct xc2028_data *priv = fe->tuner_priv;
632         int                frq_lock, signal = 0;
633
634         tuner_info("%s called\n", __FUNCTION__);
635
636         mutex_lock(&priv->lock);
637
638         *strength = 0;
639
640         /* Sync Lock Indicator */
641         frq_lock = xc2028_get_reg(priv, 0x0002);
642         if (frq_lock <= 0)
643                 goto ret;
644
645         /* Frequency is locked. Return signal quality */
646
647         /* Get SNR of the video signal */
648         signal = xc2028_get_reg(priv, 0x0040);
649
650         if (signal <= 0)
651                 signal = frq_lock;
652
653 ret:
654         mutex_unlock(&priv->lock);
655
656         *strength = signal;
657
658         return 0;
659 }
660
661 #define DIV 15625
662
663 static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ ,
664                                enum tuner_mode new_mode,
665                                v4l2_std_id std, fe_bandwidth_t bandwidth)
666 {
667         struct xc2028_data *priv = fe->tuner_priv;
668         int                rc = -EINVAL;
669         unsigned char      buf[5];
670         u32                div, offset = 0;
671
672         tuner_info("%s called\n", __FUNCTION__);
673
674         mutex_lock(&priv->lock);
675
676         /* HACK: It seems that specific firmware need to be reloaded
677            when freq is changed */
678
679         priv->firm_type = 0;
680
681         /* Reset GPIO 1 */
682         rc = priv->tuner_callback(priv->video_dev, XC2028_TUNER_RESET, 0);
683         if (rc < 0)
684                 goto ret;
685
686         msleep(10);
687         tuner_info("should set frequency %d kHz)\n", freq / 1000);
688
689         if (check_firmware(fe, new_mode, std, bandwidth) < 0)
690                 goto ret;
691
692         if (new_mode == T_DIGITAL_TV)
693                 offset = 2750000;
694
695         div = (freq - offset + DIV / 2) / DIV;
696
697         /* CMD= Set frequency */
698
699         if (priv->version < 0x0202) {
700                 send_seq(priv, {0x00, 0x02, 0x00, 0x00});
701         } else {
702                 send_seq(priv, {0x80, 0x02, 0x00, 0x00});
703         }
704
705         rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
706         if (rc < 0)
707                 goto ret;
708
709         msleep(10);
710
711         buf[0] = 0xff & (div >> 24);
712         buf[1] = 0xff & (div >> 16);
713         buf[2] = 0xff & (div >> 8);
714         buf[3] = 0xff & (div);
715         buf[4] = 0;
716
717         i2c_send(rc, priv, buf, sizeof(buf));
718         if (rc < 0)
719                 goto ret;
720         msleep(100);
721
722         priv->frequency = freq;
723
724         printk("divider= %02x %02x %02x %02x (freq=%d.%02d)\n",
725                buf[1], buf[2], buf[3], buf[4],
726                freq / 1000000, (freq % 1000000) / 10000);
727
728         rc = 0;
729
730 ret:
731         mutex_unlock(&priv->lock);
732
733         return rc;
734 }
735
736 static int xc2028_set_tv_freq(struct dvb_frontend *fe,
737                               struct analog_parameters *p)
738 {
739         struct xc2028_data *priv = fe->tuner_priv;
740
741         tuner_info("%s called\n", __FUNCTION__);
742
743         return generic_set_tv_freq(fe, 62500l * p->frequency, T_ANALOG_TV,
744                                    p->std, BANDWIDTH_8_MHZ /* NOT USED */);
745 }
746
747 static int xc2028_set_params(struct dvb_frontend *fe,
748                              struct dvb_frontend_parameters *p)
749 {
750         struct xc2028_data *priv = fe->tuner_priv;
751
752         tuner_info("%s called\n", __FUNCTION__);
753
754         /* FIXME: Only OFDM implemented */
755         if (fe->ops.info.type != FE_OFDM) {
756                 tuner_info("DTV type not implemented.\n");
757                 return -EINVAL;
758         }
759
760         return generic_set_tv_freq(fe, p->frequency, T_DIGITAL_TV,
761                                    0 /* NOT USED */,
762                                    p->u.ofdm.bandwidth);
763
764 }
765
766 static int xc2028_dvb_release(struct dvb_frontend *fe)
767 {
768         struct xc2028_data *priv = fe->tuner_priv;
769
770         tuner_info("%s called\n", __FUNCTION__);
771
772         priv->count--;
773
774         if (!priv->count) {
775                 list_del(&priv->xc2028_list);
776
777                 kfree(priv->ctrl.fname);
778
779                 free_firmware(priv);
780                 kfree(priv);
781         }
782
783         return 0;
784 }
785
786 static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency)
787 {
788         struct xc2028_data *priv = fe->tuner_priv;
789
790         tuner_info("%s called\n", __FUNCTION__);
791
792         *frequency = priv->frequency;
793
794         return 0;
795 }
796
797 static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
798 {
799         struct xc2028_data *priv = fe->tuner_priv;
800         struct xc2028_ctrl *p    = priv_cfg;
801
802         tuner_info("%s called\n", __FUNCTION__);
803
804         priv->ctrl.type = p->type;
805
806         if (p->fname) {
807                 kfree(priv->ctrl.fname);
808
809                 priv->ctrl.fname = kmalloc(strlen(p->fname) + 1, GFP_KERNEL);
810                 if (!priv->ctrl.fname)
811                         return -ENOMEM;
812
813                 free_firmware(priv);
814                 strcpy(priv->ctrl.fname, p->fname);
815         }
816
817         if (p->max_len > 0)
818                 priv->max_len = p->max_len;
819
820         tuner_info("%s OK\n", __FUNCTION__);
821
822         return 0;
823 }
824
825 static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
826         .info = {
827                  .name = "Xceive XC3028",
828                  .frequency_min = 42000000,
829                  .frequency_max = 864000000,
830                  .frequency_step = 50000,
831                  },
832
833         .set_config        = xc2028_set_config,
834         .set_analog_params = xc2028_set_tv_freq,
835         .release           = xc2028_dvb_release,
836         .get_frequency     = xc2028_get_frequency,
837         .get_rf_strength   = xc2028_signal,
838         .set_params        = xc2028_set_params,
839
840 };
841
842 int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c_adap,
843                   u8 i2c_addr, struct device *dev, void *video_dev,
844                   int (*tuner_callback) (void *dev, int command, int arg))
845 {
846         struct xc2028_data *priv;
847
848         printk(KERN_INFO PREFIX "Xcv2028/3028 init called!\n");
849
850         if (NULL == dev)
851                 return -ENODEV;
852
853         if (NULL == video_dev)
854                 return -ENODEV;
855
856         if (!tuner_callback) {
857                 printk(KERN_ERR PREFIX "No tuner callback!\n");
858                 return -EINVAL;
859         }
860
861         list_for_each_entry(priv, &xc2028_list, xc2028_list) {
862                 if (priv->dev == dev)
863                         dev = NULL;
864         }
865
866         if (dev) {
867                 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
868                 if (priv == NULL)
869                         return -ENOMEM;
870
871                 fe->tuner_priv = priv;
872
873                 priv->bandwidth = BANDWIDTH_6_MHZ;
874                 priv->need_load_generic = 1;
875                 priv->mode = T_UNINITIALIZED;
876                 priv->i2c_props.addr = i2c_addr;
877                 priv->i2c_props.adap = i2c_adap;
878                 priv->dev = dev;
879                 priv->video_dev = video_dev;
880                 priv->tuner_callback = tuner_callback;
881                 priv->max_len = 13;
882
883
884                 mutex_init(&priv->lock);
885
886                 list_add_tail(&priv->xc2028_list, &xc2028_list);
887         }
888         priv->count++;
889
890         memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops,
891                sizeof(xc2028_dvb_tuner_ops));
892
893         tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner");
894
895         return 0;
896 }
897 EXPORT_SYMBOL(xc2028_attach);
898
899 MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver");
900 MODULE_AUTHOR("Michel Ludwig <michel.ludwig@gmail.com>");
901 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
902 MODULE_LICENSE("GPL");