ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / media / dvb / frontends / ves1820.c
1 /* 
2     VES1820  - Single Chip Cable Channel Receiver driver module
3                used on the the Siemens DVB-C cards
4
5     Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
6
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */    
21
22 #include <linux/config.h>
23 #include <linux/delay.h>
24 #include <linux/errno.h>
25 #include <linux/init.h>
26 #include <linux/kernel.h>
27 #include <linux/module.h>
28 #include <linux/string.h>
29 #include <linux/slab.h>
30
31 #include "dvb_frontend.h"
32 #include "dvb_functions.h"
33
34
35 #if 0
36 #define dprintk(x...) printk(x)
37 #else
38 #define dprintk(x...)
39 #endif
40
41 #define MAX_UNITS 4
42 static int pwm[MAX_UNITS] = { -1, -1, -1, -1 };
43 static int verbose;
44
45 /**
46  *  since we need only a few bits to store internal state we don't allocate
47  *  extra memory but use frontend->data as bitfield
48  */
49
50 #define SET_PWM(data,pwm) do {          \
51         long d = (long)data;            \
52         d &= ~0xff;                     \
53         d |= pwm;                       \
54         data = (void *)d;               \
55 } while (0)
56
57 #define SET_REG0(data,reg0) do {        \
58         long d = (long)data;            \
59         d &= ~(0xff << 8);              \
60         d |= reg0 << 8;                 \
61         data = (void *)d;               \
62 } while (0)
63
64 #define SET_TUNER(data,type) do {       \
65         long d = (long)data;            \
66         d &= ~(0xff << 16);             \
67         d |= type << 16;                \
68         data = (void *)d;               \
69 } while (0)
70
71 #define SET_DEMOD_ADDR(data,type) do {  \
72         long d = (long)data;            \
73         d &= ~(0xff << 24);             \
74         d |= type << 24;                \
75         data = (void *)d;               \
76 } while (0)
77
78 #define GET_PWM(data) ((u8) ((long) data & 0xff))
79 #define GET_REG0(data) ((u8) (((long) data >> 8) & 0xff))
80 #define GET_TUNER(data) ((u8) (((long) data >> 16) & 0xff))
81 #define GET_DEMOD_ADDR(data) ((u8) (((long) data >> 24) & 0xff))
82
83 #if defined(CONFIG_DBOX2)
84 #define XIN 69600000UL
85 #define DISABLE_INVERSION(reg0)         do { reg0 &= ~0x20; } while (0)
86 #define ENABLE_INVERSION(reg0)          do { reg0 |= 0x20; } while (0)
87 #define HAS_INVERSION(reg0)             (reg0 & 0x20)
88 #else   /* PCI cards */
89 #define XIN 57840000UL
90 #define DISABLE_INVERSION(reg0)         do { reg0 |= 0x20; } while (0)
91 #define ENABLE_INVERSION(reg0)          do { reg0 &= ~0x20; } while (0)
92 #define HAS_INVERSION(reg0)             (!(reg0 & 0x20))
93 #endif
94
95 #define FIN (XIN >> 4)
96
97
98
99 static struct dvb_frontend_info ves1820_info = {
100         .name = "VES1820 based DVB-C frontend",
101         .type = FE_QAM,
102         .frequency_stepsize = 62500,
103         .frequency_min = 51000000,
104         .frequency_max = 858000000,
105         .symbol_rate_min = (XIN/2)/64,     /* SACLK/64 == (XIN/2)/64 */
106         .symbol_rate_max = (XIN/2)/4,      /* SACLK/4 */
107 #if 0
108         .frequency_tolerance = ???,
109         .symbol_rate_tolerance = ???,  /* ppm */  /* == 8% (spec p. 5) */
110         .notifier_delay = ?,
111 #endif
112         .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
113                 FE_CAN_QAM_128 | FE_CAN_QAM_256 | 
114                 FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO,
115 };
116
117
118
119 static u8 ves1820_inittab [] =
120 {
121         0x69, 0x6A, 0x9B, 0x12, 0x12, 0x46, 0x26, 0x1A,
122         0x43, 0x6A, 0xAA, 0xAA, 0x1E, 0x85, 0x43, 0x20,
123         0xE0, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00,
124         0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
125         0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127         0x00, 0x00, 0x00, 0x00, 0x40
128 };
129
130
131 static int ves1820_writereg (struct dvb_frontend *fe, u8 reg, u8 data)
132 {
133         u8 addr = GET_DEMOD_ADDR(fe->data);
134         u8 buf[] = { 0x00, reg, data };
135         struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
136         struct dvb_i2c_bus *i2c = fe->i2c;
137         int ret;
138
139         ret = i2c->xfer (i2c, &msg, 1);
140
141         if (ret != 1)
142                 printk("DVB: VES1820(%d): %s, writereg error "
143                         "(reg == 0x%02x, val == 0x%02x, ret == %i)\n",
144                         fe->i2c->adapter->num, __FUNCTION__, reg, data, ret);
145
146         dvb_delay(10);
147         return (ret != 1) ? -EREMOTEIO : 0;
148 }
149
150
151 static u8 ves1820_readreg (struct dvb_frontend *fe, u8 reg)
152 {
153         u8 b0 [] = { 0x00, reg };
154         u8 b1 [] = { 0 };
155         u8 addr = GET_DEMOD_ADDR(fe->data);
156         struct i2c_msg msg [] = { { .addr = addr, .flags = 0, .buf = b0, .len = 2 },
157                            { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
158         struct dvb_i2c_bus *i2c = fe->i2c;
159         int ret;
160
161         ret = i2c->xfer (i2c, msg, 2);
162
163         if (ret != 2)
164                 printk("DVB: VES1820(%d): %s: readreg error (ret == %i)\n",
165                                 fe->i2c->adapter->num, __FUNCTION__, ret);
166
167         return b1[0];
168 }
169
170
171 static int tuner_write (struct dvb_i2c_bus *i2c, u8 addr, u8 data [4])
172 {
173         int ret;
174         struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
175
176         ret = i2c->xfer (i2c, &msg, 1);
177
178         if (ret != 1)
179                 printk("DVB: VES1820(%d): %s: i/o error (ret == %i)\n",
180                                 i2c->adapter->num, __FUNCTION__, ret);
181
182         return (ret != 1) ? -EREMOTEIO : 0;
183 }
184
185
186 /**
187  *   set up the downconverter frequency divisor for a
188  *   reference clock comparision frequency of 62.5 kHz.
189  */
190 static int tuner_set_tv_freq (struct dvb_frontend *fe, u32 freq)
191 {
192         u32 div, ifreq;
193         static u8 addr [] = { 0x61, 0x62 };
194         static u8 byte3 [] = { 0x8e, 0x85 };
195         int tuner_type = GET_TUNER(fe->data);
196         u8 buf [4];
197
198         if (tuner_type == 0xff)     /*  PLL not reachable over i2c ...  */
199                 return 0;
200
201         if (strstr (fe->i2c->adapter->name, "Technotrend") ||
202             strstr (fe->i2c->adapter->name, "TT-Budget"))
203                 ifreq = 35937500;
204         else
205                 ifreq = 36125000;
206
207         div = (freq + ifreq + 31250) / 62500;
208
209         buf[0] = (div >> 8) & 0x7f;
210         buf[1] = div & 0xff;
211         buf[2] = byte3[tuner_type];
212
213         if (tuner_type == 1) {
214                 buf[2] |= (div >> 10) & 0x60;
215                 buf[3] = (freq < 174000000 ? 0x88 :
216                           freq < 470000000 ? 0x84 : 0x81);
217         } else {
218                 buf[3] = (freq < 174000000 ? 0xa1 :
219                           freq < 454000000 ? 0x92 : 0x34);
220         }
221
222         return tuner_write (fe->i2c, addr[tuner_type], buf);
223 }
224
225
226 static int ves1820_setup_reg0 (struct dvb_frontend *fe, u8 reg0,
227                         fe_spectral_inversion_t inversion)
228 {
229         reg0 |= GET_REG0(fe->data) & 0x62;
230         
231         if (INVERSION_ON == inversion)
232                 ENABLE_INVERSION(reg0);
233         else if (INVERSION_OFF == inversion)
234                 DISABLE_INVERSION(reg0);
235         
236         ves1820_writereg (fe, 0x00, reg0 & 0xfe);
237         ves1820_writereg (fe, 0x00, reg0 | 0x01);
238
239         /**
240          *  check lock and toggle inversion bit if required...
241          */
242         if (INVERSION_AUTO == inversion && !(ves1820_readreg (fe, 0x11) & 0x08)) {
243                 mdelay(50);
244                 if (!(ves1820_readreg (fe, 0x11) & 0x08)) {
245                         reg0 ^= 0x20;
246                         ves1820_writereg (fe, 0x00, reg0 & 0xfe);
247                         ves1820_writereg (fe, 0x00, reg0 | 0x01);
248                 }
249         }
250
251         SET_REG0(fe->data, reg0);
252
253         return 0;
254 }
255
256
257 static int ves1820_init (struct dvb_frontend *fe)
258 {
259         int i;
260         
261         dprintk("DVB: VES1820(%d): init chip\n", fe->i2c->adapter->num);
262
263         ves1820_writereg (fe, 0, 0);
264
265 #if defined(CONFIG_DBOX2)
266         ves1820_inittab[2] &= ~0x08;
267 #endif
268
269         for (i=0; i<53; i++)
270                 ves1820_writereg (fe, i, ves1820_inittab[i]);
271
272         ves1820_writereg (fe, 0x34, GET_PWM(fe->data)); 
273
274         return 0;
275 }
276
277
278 static int ves1820_set_symbolrate (struct dvb_frontend *fe, u32 symbolrate)
279 {
280         s32 BDR; 
281         s32 BDRI;
282         s16 SFIL=0;
283         u16 NDEC = 0;
284         u32 tmp, ratio;
285
286         if (symbolrate > XIN/2) 
287                 symbolrate = XIN/2;
288
289         if (symbolrate < 500000)
290                 symbolrate = 500000;
291
292         if (symbolrate < XIN/16) NDEC = 1;
293         if (symbolrate < XIN/32) NDEC = 2;
294         if (symbolrate < XIN/64) NDEC = 3;
295
296         if (symbolrate < (u32)(XIN/12.3)) SFIL = 1;
297         if (symbolrate < (u32)(XIN/16))  SFIL = 0;
298         if (symbolrate < (u32)(XIN/24.6)) SFIL = 1;
299         if (symbolrate < (u32)(XIN/32))  SFIL = 0;
300         if (symbolrate < (u32)(XIN/49.2)) SFIL = 1;
301         if (symbolrate < (u32)(XIN/64))  SFIL = 0;
302         if (symbolrate < (u32)(XIN/98.4)) SFIL = 1;
303         
304         symbolrate <<= NDEC;
305         ratio = (symbolrate << 4) / FIN;
306         tmp =  ((symbolrate << 4) % FIN) << 8;
307         ratio = (ratio << 8) + tmp / FIN;
308         tmp = (tmp % FIN) << 8;
309         ratio = (ratio << 8) + (tmp + FIN/2) / FIN;
310         
311         BDR = ratio;
312         BDRI = (((XIN << 5) / symbolrate) + 1) / 2;
313         
314         if (BDRI > 0xFF) 
315                 BDRI = 0xFF;
316         
317         SFIL = (SFIL << 4) | ves1820_inittab[0x0E];
318         
319         NDEC = (NDEC << 6) | ves1820_inittab[0x03];
320
321         ves1820_writereg (fe, 0x03, NDEC);
322         ves1820_writereg (fe, 0x0a, BDR&0xff);
323         ves1820_writereg (fe, 0x0b, (BDR>> 8)&0xff);
324         ves1820_writereg (fe, 0x0c, (BDR>>16)&0x3f);
325
326         ves1820_writereg (fe, 0x0d, BDRI);
327         ves1820_writereg (fe, 0x0e, SFIL);
328
329         return 0;
330 }
331
332
333 static int ves1820_set_parameters (struct dvb_frontend *fe,
334                             struct dvb_frontend_parameters *p)
335 {
336         static const u8 reg0x00 [] = { 0x00, 0x04, 0x08, 0x0c, 0x10 };
337         static const u8 reg0x01 [] = {  140,  140,  106,  100,   92 };
338         static const u8 reg0x05 [] = {  135,  100,   70,   54,   38 };
339         static const u8 reg0x08 [] = {  162,  116,   67,   52,   35 };
340         static const u8 reg0x09 [] = {  145,  150,  106,  126,  107 };
341         int real_qam = p->u.qam.modulation - QAM_16;
342
343         if (real_qam < 0 || real_qam > 4)
344                 return -EINVAL;
345
346         tuner_set_tv_freq (fe, p->frequency);
347         ves1820_set_symbolrate (fe, p->u.qam.symbol_rate);
348         ves1820_writereg (fe, 0x34, GET_PWM(fe->data));
349
350         ves1820_writereg (fe, 0x01, reg0x01[real_qam]);
351         ves1820_writereg (fe, 0x05, reg0x05[real_qam]);
352         ves1820_writereg (fe, 0x08, reg0x08[real_qam]);
353         ves1820_writereg (fe, 0x09, reg0x09[real_qam]);
354
355         ves1820_setup_reg0 (fe, reg0x00[real_qam], p->inversion);
356
357         /* yes, this speeds things up: userspace reports lock in about 8 ms
358            instead of 500 to 1200 ms after calling FE_SET_FRONTEND. */
359         mdelay(50);
360
361         return 0;
362 }
363
364
365
366 static int ves1820_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
367 {
368         switch (cmd) {
369         case FE_GET_INFO:
370                 memcpy (arg, &ves1820_info, sizeof(struct dvb_frontend_info));
371                 break;
372
373         case FE_READ_STATUS:
374         {
375                 fe_status_t *status = (fe_status_t *) arg;
376                 int sync;
377
378                 *status = 0;
379
380                 sync = ves1820_readreg (fe, 0x11);
381
382                 if (sync & 1)
383                         *status |= FE_HAS_SIGNAL;
384
385                 if (sync & 2)
386                         *status |= FE_HAS_CARRIER;
387
388                 if (sync & 2)           /* XXX FIXME! */
389                         *status |= FE_HAS_VITERBI;
390                 
391                 if (sync & 4)
392                         *status |= FE_HAS_SYNC;
393
394                 if (sync & 8)
395                         *status |= FE_HAS_LOCK;
396
397                 break;
398         }
399
400         case FE_READ_BER:
401         {
402                 u32 ber = ves1820_readreg(fe, 0x14) |
403                          (ves1820_readreg(fe, 0x15) << 8) |
404                          ((ves1820_readreg(fe, 0x16) & 0x0f) << 16);
405                 *((u32*) arg) = 10 * ber;
406                 break;
407         }
408         case FE_READ_SIGNAL_STRENGTH:
409         {
410                 u8 gain = ves1820_readreg(fe, 0x17);
411                 *((u16*) arg) = (gain << 8) | gain;
412                 break;
413         }
414
415         case FE_READ_SNR:
416         {
417                 u8 quality = ~ves1820_readreg(fe, 0x18);
418                 *((u16*) arg) = (quality << 8) | quality;
419                 break;
420         }
421
422         case FE_READ_UNCORRECTED_BLOCKS:
423                 *((u32*) arg) = ves1820_readreg (fe, 0x13) & 0x7f;
424                 if (*((u32*) arg) == 0x7f)
425                         *((u32*) arg) = 0xffffffff;
426                 /* reset uncorrected block counter */
427                 ves1820_writereg (fe, 0x10, ves1820_inittab[0x10] & 0xdf);
428                 ves1820_writereg (fe, 0x10, ves1820_inittab[0x10]);
429                 break;
430
431         case FE_SET_FRONTEND:
432                 return ves1820_set_parameters (fe, arg);
433
434         case FE_GET_FRONTEND:
435         {
436                 struct dvb_frontend_parameters *p = (struct dvb_frontend_parameters *)arg;
437                 u8 reg0 = GET_REG0(fe->data);
438                 int sync;
439                 s8 afc = 0;
440                 
441                 sync = ves1820_readreg (fe, 0x11);
442                         afc = ves1820_readreg(fe, 0x19);
443                 if (verbose) {
444                         /* AFC only valid when carrier has been recovered */
445                         printk(sync & 2 ? "DVB: VES1820(%d): AFC (%d) %dHz\n" :
446                                           "DVB: VES1820(%d): [AFC (%d) %dHz]\n",
447                                         fe->i2c->adapter->num, afc,
448                                -((s32)p->u.qam.symbol_rate * afc) >> 10);
449                 }
450
451                 p->inversion = HAS_INVERSION(reg0) ? INVERSION_ON : INVERSION_OFF;
452                 p->u.qam.modulation = ((reg0 >> 2) & 7) + QAM_16;
453
454                 p->u.qam.fec_inner = FEC_NONE;
455
456                 p->frequency = ((p->frequency + 31250) / 62500) * 62500;
457                 if (sync & 2)
458                         p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10;
459                 break;
460         }
461         case FE_SLEEP:
462                 ves1820_writereg (fe, 0x1b, 0x02);  /* pdown ADC */
463                 ves1820_writereg (fe, 0x00, 0x80);  /* standby */
464                 break;
465
466         case FE_INIT:
467                 return ves1820_init (fe);
468
469         default:
470                 return -EINVAL;
471         }
472
473         return 0;
474
475
476
477 static long probe_tuner (struct dvb_i2c_bus *i2c)
478 {
479         static const struct i2c_msg msg1 = 
480                 { .addr = 0x61, .flags = 0, .buf = NULL, .len = 0 };
481         static const struct i2c_msg msg2 =
482                 { .addr = 0x62, .flags = 0, .buf = NULL, .len = 0 };
483         int type;
484
485         if (i2c->xfer(i2c, &msg1, 1) == 1) {
486                 type = 0;
487                 printk ("DVB: VES1820(%d): setup for tuner spXXXX\n", i2c->adapter->num);
488         } else if (i2c->xfer(i2c, &msg2, 1) == 1) {
489                 type = 1;
490                 printk ("DVB: VES1820(%d): setup for tuner sp5659c\n", i2c->adapter->num);
491         } else {
492                 type = -1;
493         }
494
495         return type;
496 }
497
498
499 static u8 read_pwm (struct dvb_i2c_bus *i2c)
500 {
501         u8 b = 0xff;
502         u8 pwm;
503         struct i2c_msg msg [] = { { .addr = 0x50, .flags = 0, .buf = &b, .len = 1 },
504                          { .addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1 } };
505
506         if ((i2c->xfer(i2c, msg, 2) != 2) || (pwm == 0xff))
507                 pwm = 0x48;
508
509         printk("DVB: VES1820(%d): pwm=0x%02x\n", i2c->adapter->num, pwm);
510
511         return pwm;
512 }
513
514
515 static long probe_demod_addr (struct dvb_i2c_bus *i2c)
516 {
517         u8 b [] = { 0x00, 0x1a };
518         u8 id;
519         struct i2c_msg msg [] = { { .addr = 0x08, .flags = 0, .buf = b, .len = 2 },
520                            { .addr = 0x08, .flags = I2C_M_RD, .buf = &id, .len = 1 } };
521
522         if (i2c->xfer(i2c, msg, 2) == 2 && (id & 0xf0) == 0x70)
523                 return msg[0].addr;
524
525         msg[0].addr = msg[1].addr = 0x09;
526
527         if (i2c->xfer(i2c, msg, 2) == 2 && (id & 0xf0) == 0x70)
528                 return msg[0].addr;
529
530         return -1;
531 }
532
533
534 static int ves1820_attach (struct dvb_i2c_bus *i2c, void **data)
535 {
536         void *priv = NULL;
537         long demod_addr;
538         long tuner_type;
539
540         if ((demod_addr = probe_demod_addr(i2c)) < 0)
541                 return -ENODEV;
542
543         tuner_type = probe_tuner(i2c);
544
545         if ((i2c->adapter->num < MAX_UNITS) && pwm[i2c->adapter->num] != -1) {
546                 printk("DVB: VES1820(%d): pwm=0x%02x (user specified)\n",
547                                 i2c->adapter->num, pwm[i2c->adapter->num]);
548                 SET_PWM(priv, pwm[i2c->adapter->num]);
549         }
550         else
551                 SET_PWM(priv, read_pwm(i2c));
552         SET_REG0(priv, ves1820_inittab[0]);
553         SET_TUNER(priv, tuner_type);
554         SET_DEMOD_ADDR(priv, demod_addr);
555
556         return dvb_register_frontend (ves1820_ioctl, i2c, priv, &ves1820_info);
557 }
558
559
560 static void ves1820_detach (struct dvb_i2c_bus *i2c, void *data)
561 {
562         dvb_unregister_frontend (ves1820_ioctl, i2c);
563 }
564
565
566 static int __init init_ves1820 (void)
567 {
568         int i;
569         for (i = 0; i < MAX_UNITS; i++)
570                 if (pwm[i] < -1 || pwm[i] > 255)
571                         return -EINVAL;
572         return dvb_register_i2c_device (THIS_MODULE,
573                                         ves1820_attach, ves1820_detach);
574 }
575
576
577 static void __exit exit_ves1820 (void)
578 {
579         dvb_unregister_i2c_device (ves1820_attach);
580 }
581
582
583 module_init(init_ves1820);
584 module_exit(exit_ves1820);
585
586 MODULE_PARM(pwm, "1-" __MODULE_STRING(MAX_UNITS) "i");
587 MODULE_PARM_DESC(pwm, "override PWM value stored in EEPROM (tuner calibration)");
588 MODULE_PARM(verbose, "i");
589 MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting");
590
591 MODULE_DESCRIPTION("VES1820 DVB-C frontend driver");
592 MODULE_AUTHOR("Ralph Metzler, Holger Waechtler");
593 MODULE_LICENSE("GPL");
594