ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / media / dvb / frontends / at76c651.c
1 /*
2  * at76c651.c
3  * 
4  * Atmel DVB-C Frontend Driver (at76c651/dat7021)
5  *
6  * Copyright (C) 2001 fnbrd <fnbrd@gmx.de>
7  *             & 2002 Andreas Oberritter <obi@linuxtv.org>
8  *             & 2003 Wolfram Joost <dbox2@frokaschwei.de>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  */
25
26 #include <linux/init.h>
27 #include <linux/module.h>
28 #include <linux/kernel.h>
29 #include <linux/string.h>
30 #include <linux/slab.h>
31
32 #if defined(__powerpc__)
33 #include <asm/bitops.h>
34 #endif
35
36 #include "dvb_frontend.h"
37 #include "dvb_i2c.h"
38 #include "dvb_functions.h"
39
40 static int debug = 0;
41 static u8 at76c651_qam;
42 static u8 at76c651_revision;
43
44 #define dprintk if (debug) printk
45
46 /*
47  * DAT7021
48  * -------
49  * Input Frequency Range (RF): 48.25 MHz to 863.25 MHz
50  * Band Width: 8 MHz
51  * Level Input (Range for Digital Signals): -61 dBm to -41 dBm
52  * Output Frequency (IF): 36 MHz
53  *
54  * (see http://www.atmel.com/atmel/acrobat/doc1320.pdf)
55  */
56
57 static struct dvb_frontend_info at76c651_info = {
58
59         .name = "Atmel AT76C651(B) with DAT7021",
60         .type = FE_QAM,
61         .frequency_min = 48250000,
62         .frequency_max = 863250000,
63         .frequency_stepsize = 62500,
64         /*.frequency_tolerance = */     /* FIXME: 12% of SR */
65         .symbol_rate_min = 0,           /* FIXME */
66         .symbol_rate_max = 9360000,     /* FIXME */
67         .symbol_rate_tolerance = 4000,
68         .notifier_delay = 0,
69         .caps = FE_CAN_INVERSION_AUTO |
70             FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
71             FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
72             FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
73             FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | FE_CAN_QAM_128 |
74             FE_CAN_MUTE_TS | FE_CAN_QAM_256 | FE_CAN_RECOVER
75 };
76
77 #if ! defined(__powerpc__)
78 static __inline__ int __ilog2(unsigned long x)
79 {
80         int i;
81
82         if (x == 0)
83                 return -1;
84
85         for (i = 0; x != 0; i++)
86                 x >>= 1;
87
88         return i - 1;
89 }
90 #endif
91
92 static int at76c651_writereg(struct dvb_i2c_bus *i2c, u8 reg, u8 data)
93 {
94
95         int ret;
96         u8 buf[] = { reg, data };
97         struct i2c_msg msg = { .addr = 0x1a >> 1, .flags = 0, .buf = buf, .len = 2 };
98
99         ret = i2c->xfer(i2c, &msg, 1);
100
101         if (ret != 1)
102                 dprintk("%s: writereg error "
103                         "(reg == 0x%02x, val == 0x%02x, ret == %i)\n",
104                         __FUNCTION__, reg, data, ret);
105
106         dvb_delay(10);
107
108         return (ret != 1) ? -EREMOTEIO : 0;
109
110 }
111
112 static u8 at76c651_readreg(struct dvb_i2c_bus *i2c, u8 reg)
113 {
114
115         int ret;
116         u8 b0[] = { reg };
117         u8 b1[] = { 0 };
118         struct i2c_msg msg[] = { {.addr =  0x1a >> 1, .flags =  0, .buf =  b0, .len = 1},
119                           {.addr =  0x1a >> 1, .flags =  I2C_M_RD, .buf =  b1, .len = 1} };
120
121         ret = i2c->xfer(i2c, msg, 2);
122
123         if (ret != 2)
124                 dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
125
126         return b1[0];
127
128 }
129
130 static int at76c651_reset(struct dvb_i2c_bus *i2c)
131 {
132
133         return at76c651_writereg(i2c, 0x07, 0x01);
134
135 }
136
137 static int at76c651_disable_interrupts(struct dvb_i2c_bus *i2c)
138 {
139
140         return at76c651_writereg(i2c, 0x0b, 0x00);
141
142 }
143
144 static int at76c651_set_auto_config(struct dvb_i2c_bus *i2c)
145 {
146
147         /*
148          * Autoconfig
149          */
150
151         at76c651_writereg(i2c, 0x06, 0x01);
152
153         /*
154          * Performance optimizations, should be done after autoconfig
155          */
156
157         at76c651_writereg(i2c, 0x10, 0x06);
158         at76c651_writereg(i2c, 0x11, ((at76c651_qam == 5) || (at76c651_qam == 7)) ? 0x12 : 0x10);
159         at76c651_writereg(i2c, 0x15, 0x28);
160         at76c651_writereg(i2c, 0x20, 0x09);
161         at76c651_writereg(i2c, 0x24, ((at76c651_qam == 5) || (at76c651_qam == 7)) ? 0xC0 : 0x90);
162         at76c651_writereg(i2c, 0x30, 0x90);
163         if (at76c651_qam == 5)
164                 at76c651_writereg(i2c, 0x35, 0x2A);
165
166         /*
167          * Initialize A/D-converter
168          */
169
170         if (at76c651_revision == 0x11) {
171                 at76c651_writereg(i2c, 0x2E, 0x38);
172                 at76c651_writereg(i2c, 0x2F, 0x13);
173 }
174
175         at76c651_disable_interrupts(i2c);
176
177         /*
178          * Restart operation
179          */
180
181         at76c651_reset(i2c);
182
183         return 0;
184
185 }
186
187 static int at76c651_set_bbfreq(struct dvb_i2c_bus *i2c)
188 {
189
190         at76c651_writereg(i2c, 0x04, 0x3f);
191         at76c651_writereg(i2c, 0x05, 0xee);
192
193         return 0;
194
195 }
196
197 static int at76c651_switch_tuner_i2c(struct dvb_i2c_bus *i2c, u8 enable)
198 {
199
200         if (enable)
201                 return at76c651_writereg(i2c, 0x0c, 0xc2 | 0x01);
202         else
203                 return at76c651_writereg(i2c, 0x0c, 0xc2);
204
205 }
206
207 static int dat7021_write(struct dvb_i2c_bus *i2c, u32 tw)
208 {
209
210         int ret;
211         struct i2c_msg msg =
212             { .addr = 0xc2 >> 1, .flags = 0, .buf = (u8 *) & tw, .len = sizeof (tw) };
213
214 #ifdef __LITTLE_ENDIAN
215         tw = __cpu_to_be32(tw);
216 #endif
217
218         at76c651_switch_tuner_i2c(i2c, 1);
219
220         ret = i2c->xfer(i2c, &msg, 1);
221
222         at76c651_switch_tuner_i2c(i2c, 0);
223
224         if (ret != 4)
225                 return -EFAULT;
226
227         at76c651_reset(i2c);
228
229         return 0;
230
231 }
232
233 static int dat7021_set_tv_freq(struct dvb_i2c_bus *i2c, u32 freq)
234 {
235
236         u32 dw;
237
238         freq /= 1000;
239
240         if ((freq < 48250) || (freq > 863250))
241                 return -EINVAL;
242
243         /*
244          * formula: dw=0x17e28e06+(freq-346000UL)/8000UL*0x800000
245          *      or: dw=0x4E28E06+(freq-42000) / 125 * 0x20000
246          */
247
248         dw = (freq - 42000) * 4096;
249         dw = dw / 125;
250         dw = dw * 32;
251
252         if (freq > 394000)
253                 dw += 0x4E28E85;
254         else
255                 dw += 0x4E28E06;
256
257         return dat7021_write(i2c, dw);
258
259 }
260
261 static int at76c651_set_symbolrate(struct dvb_i2c_bus *i2c, u32 symbolrate)
262 {
263
264         u8 exponent;
265         u32 mantissa;
266
267         if (symbolrate > 9360000)
268                 return -EINVAL;
269
270         /*
271          * FREF = 57800 kHz
272          * exponent = 10 + floor ( log2 ( symbolrate / FREF ) )
273          * mantissa = ( symbolrate / FREF) * ( 1 << ( 30 - exponent ) )
274          */
275
276         exponent = __ilog2((symbolrate << 4) / 903125);
277         mantissa = ((symbolrate / 3125) * (1 << (24 - exponent))) / 289;
278
279         at76c651_writereg(i2c, 0x00, mantissa >> 13);
280         at76c651_writereg(i2c, 0x01, mantissa >> 5);
281         at76c651_writereg(i2c, 0x02, (mantissa << 3) | exponent);
282
283         return 0;
284
285 }
286
287 static int at76c651_set_qam(struct dvb_i2c_bus *i2c, fe_modulation_t qam)
288 {
289
290         switch (qam) {
291         case QPSK:
292                 at76c651_qam = 0x02;
293                 break;
294         case QAM_16:
295                 at76c651_qam = 0x04;
296                 break;
297         case QAM_32:
298                 at76c651_qam = 0x05;
299                 break;
300         case QAM_64:
301                 at76c651_qam = 0x06;
302                 break;
303         case QAM_128:
304                 at76c651_qam = 0x07;
305                 break;
306         case QAM_256:
307                 at76c651_qam = 0x08;
308                 break;
309 #if 0
310         case QAM_512:
311                 at76c651_qam = 0x09;
312                 break;
313         case QAM_1024:
314                 at76c651_qam = 0x0A;
315                 break;
316 #endif
317         default:
318                 return -EINVAL;
319
320         }
321
322         return at76c651_writereg(i2c, 0x03, at76c651_qam);
323
324 }
325
326 static int at76c651_set_inversion(struct dvb_i2c_bus *i2c,
327                        fe_spectral_inversion_t inversion)
328 {
329
330         u8 feciqinv = at76c651_readreg(i2c, 0x60);
331
332         switch (inversion) {
333         case INVERSION_OFF:
334                 feciqinv |= 0x02;
335                 feciqinv &= 0xFE;
336                 break;
337
338         case INVERSION_ON:
339                 feciqinv |= 0x03;
340                 break;
341
342         case INVERSION_AUTO:
343                 feciqinv &= 0xFC;
344                 break;
345
346         default:
347                 return -EINVAL;
348         }
349
350         return at76c651_writereg(i2c, 0x60, feciqinv);
351
352 }
353
354 static int at76c651_set_parameters(struct dvb_i2c_bus *i2c,
355                         struct dvb_frontend_parameters *p)
356 {
357
358         dat7021_set_tv_freq(i2c, p->frequency);
359         at76c651_set_symbolrate(i2c, p->u.qam.symbol_rate);
360         at76c651_set_inversion(i2c, p->inversion);
361         at76c651_set_auto_config(i2c);
362         at76c651_reset(i2c);
363
364         return 0;
365
366 }
367
368 static int at76c651_set_defaults(struct dvb_i2c_bus *i2c)
369 {
370
371         at76c651_set_symbolrate(i2c, 6900000);
372         at76c651_set_qam(i2c, QAM_64);
373         at76c651_set_bbfreq(i2c);
374         at76c651_set_auto_config(i2c);
375
376         return 0;
377
378 }
379
380 static int at76c651_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
381 {
382
383         switch (cmd) {
384
385         case FE_GET_INFO:
386                 memcpy(arg, &at76c651_info, sizeof (struct dvb_frontend_info));
387                 break;
388
389         case FE_READ_STATUS:
390                 {
391
392                         fe_status_t *status = (fe_status_t *) arg;
393                         u8 sync;
394
395                         /*
396                          * Bits: FEC, CAR, EQU, TIM, AGC2, AGC1, ADC, PLL (PLL=0) 
397                          */
398                         sync = at76c651_readreg(fe->i2c, 0x80);
399
400                         *status = 0;
401
402                         if (sync & (0x04 | 0x10))       /* AGC1 || TIM */
403                                 *status |= FE_HAS_SIGNAL;
404
405                         if (sync & 0x10)        /* TIM */
406                                 *status |= FE_HAS_CARRIER;
407
408                         if (sync & 0x80)        /* FEC */
409                                 *status |= FE_HAS_VITERBI;
410
411                         if (sync & 0x40)        /* CAR */
412                                 *status |= FE_HAS_SYNC;
413
414                         if ((sync & 0xF0) == 0xF0)      /* TIM && EQU && CAR && FEC */
415                                 *status |= FE_HAS_LOCK;
416
417                         break;
418
419                 }
420
421         case FE_READ_BER:
422                 {
423                         u32 *ber = (u32 *) arg;
424
425                         *ber = (at76c651_readreg(fe->i2c, 0x81) & 0x0F) << 16;
426                         *ber |= at76c651_readreg(fe->i2c, 0x82) << 8;
427                         *ber |= at76c651_readreg(fe->i2c, 0x83);
428                         *ber *= 10;
429
430                         break;
431                 }
432
433         case FE_READ_SIGNAL_STRENGTH:
434                 {
435                         u8 gain = ~at76c651_readreg(fe->i2c, 0x91);
436
437                         *(u16 *) arg = (gain << 8) | gain;
438                         break;
439                 }
440
441         case FE_READ_SNR:
442                 *(u16 *) arg =
443                     0xFFFF -
444                     ((at76c651_readreg(fe->i2c, 0x8F) << 8) |
445                      at76c651_readreg(fe->i2c, 0x90));
446                 break;
447
448         case FE_READ_UNCORRECTED_BLOCKS:
449                 *(u32 *) arg = at76c651_readreg(fe->i2c, 0x82);
450                 break;
451
452         case FE_SET_FRONTEND:
453                 return at76c651_set_parameters(fe->i2c, arg);
454
455         case FE_GET_FRONTEND:
456                 break;
457
458         case FE_SLEEP:
459                 break;
460
461         case FE_INIT:
462                 return at76c651_set_defaults(fe->i2c);
463
464         case FE_GET_TUNE_SETTINGS:
465         {
466                 struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg;
467                 fesettings->min_delay_ms = 50;
468                 fesettings->step_size = 0;
469                 fesettings->max_drift = 0;
470                 return 0;
471         }           
472
473         default:
474                 return -ENOIOCTLCMD;
475         }
476
477         return 0;
478
479 }
480
481 static int at76c651_attach(struct dvb_i2c_bus *i2c, void **data)
482 {
483         if ( (at76c651_readreg(i2c, 0x0E) != 0x65) ||
484              ( ( (at76c651_revision = at76c651_readreg(i2c, 0x0F)) & 0xFE) != 0x10) )
485 {
486                 dprintk("no AT76C651(B) found\n");
487                 return -ENODEV;
488         }
489
490         if (at76c651_revision == 0x10)
491         {
492                 dprintk("AT76C651A found\n");
493                 strcpy(at76c651_info.name,"Atmel AT76C651A with DAT7021");
494                 }
495         else
496         {
497                 strcpy(at76c651_info.name,"Atmel AT76C651B with DAT7021");
498                 dprintk("AT76C651B found\n");
499         }
500
501         at76c651_set_defaults(i2c);
502
503         return dvb_register_frontend(at76c651_ioctl, i2c, NULL, &at76c651_info);
504
505 }
506
507 static void at76c651_detach(struct dvb_i2c_bus *i2c, void *data)
508 {
509
510         dvb_unregister_frontend(at76c651_ioctl, i2c);
511
512 }
513
514 static int __init at76c651_init(void)
515 {
516
517         return dvb_register_i2c_device(THIS_MODULE, at76c651_attach,
518                                        at76c651_detach);
519
520 }
521
522 static void __exit at76c651_exit(void)
523 {
524
525         dvb_unregister_i2c_device(at76c651_attach);
526
527 }
528
529 module_init(at76c651_init);
530 module_exit(at76c651_exit);
531
532 MODULE_DESCRIPTION("at76c651/dat7021 dvb-c frontend driver");
533 MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
534 MODULE_LICENSE("GPL");
535 MODULE_PARM(debug, "i");