2 VES1820 - Single Chip Cable Channel Receiver driver module
3 used on the the Siemens DVB-C cards
5 Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
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.
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.
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.
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>
31 #include "dvb_frontend.h"
32 #include "dvb_functions.h"
36 #define dprintk(x...) printk(x)
42 static int pwm[MAX_UNITS] = { -1, -1, -1, -1 };
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
50 #define SET_PWM(data,pwm) do { \
51 long d = (long)data; \
57 #define SET_REG0(data,reg0) do { \
58 long d = (long)data; \
64 #define SET_TUNER(data,type) do { \
65 long d = (long)data; \
71 #define SET_DEMOD_ADDR(data,type) do { \
72 long d = (long)data; \
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))
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)
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))
95 #define FIN (XIN >> 4)
99 static struct dvb_frontend_info ves1820_info = {
100 .name = "VES1820 based DVB-C frontend",
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 */
108 .frequency_tolerance = ???,
109 .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */
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,
119 static u8 ves1820_inittab [] =
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
131 static int ves1820_writereg (struct dvb_frontend *fe, u8 reg, u8 data)
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;
139 ret = i2c->xfer (i2c, &msg, 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);
147 return (ret != 1) ? -EREMOTEIO : 0;
151 static u8 ves1820_readreg (struct dvb_frontend *fe, u8 reg)
153 u8 b0 [] = { 0x00, reg };
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;
161 ret = i2c->xfer (i2c, msg, 2);
164 printk("DVB: VES1820(%d): %s: readreg error (ret == %i)\n",
165 fe->i2c->adapter->num, __FUNCTION__, ret);
171 static int tuner_write (struct dvb_i2c_bus *i2c, u8 addr, u8 data [4])
174 struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
176 ret = i2c->xfer (i2c, &msg, 1);
179 printk("DVB: VES1820(%d): %s: i/o error (ret == %i)\n",
180 i2c->adapter->num, __FUNCTION__, ret);
182 return (ret != 1) ? -EREMOTEIO : 0;
187 * set up the downconverter frequency divisor for a
188 * reference clock comparision frequency of 62.5 kHz.
190 static int tuner_set_tv_freq (struct dvb_frontend *fe, u32 freq)
193 static u8 addr [] = { 0x61, 0x62 };
194 static u8 byte3 [] = { 0x8e, 0x85 };
195 int tuner_type = GET_TUNER(fe->data);
198 if (tuner_type == 0xff) /* PLL not reachable over i2c ... */
201 if (strstr (fe->i2c->adapter->name, "Technotrend") ||
202 strstr (fe->i2c->adapter->name, "TT-Budget"))
207 div = (freq + ifreq + 31250) / 62500;
209 buf[0] = (div >> 8) & 0x7f;
211 buf[2] = byte3[tuner_type];
213 if (tuner_type == 1) {
214 buf[2] |= (div >> 10) & 0x60;
215 buf[3] = (freq < 174000000 ? 0x88 :
216 freq < 470000000 ? 0x84 : 0x81);
218 buf[3] = (freq < 174000000 ? 0xa1 :
219 freq < 454000000 ? 0x92 : 0x34);
222 return tuner_write (fe->i2c, addr[tuner_type], buf);
226 static int ves1820_setup_reg0 (struct dvb_frontend *fe, u8 reg0,
227 fe_spectral_inversion_t inversion)
229 reg0 |= GET_REG0(fe->data) & 0x62;
231 if (INVERSION_ON == inversion)
232 ENABLE_INVERSION(reg0);
233 else if (INVERSION_OFF == inversion)
234 DISABLE_INVERSION(reg0);
236 ves1820_writereg (fe, 0x00, reg0 & 0xfe);
237 ves1820_writereg (fe, 0x00, reg0 | 0x01);
240 * check lock and toggle inversion bit if required...
242 if (INVERSION_AUTO == inversion && !(ves1820_readreg (fe, 0x11) & 0x08)) {
244 if (!(ves1820_readreg (fe, 0x11) & 0x08)) {
246 ves1820_writereg (fe, 0x00, reg0 & 0xfe);
247 ves1820_writereg (fe, 0x00, reg0 | 0x01);
251 SET_REG0(fe->data, reg0);
257 static int ves1820_init (struct dvb_frontend *fe)
261 dprintk("DVB: VES1820(%d): init chip\n", fe->i2c->adapter->num);
263 ves1820_writereg (fe, 0, 0);
265 #if defined(CONFIG_DBOX2)
266 ves1820_inittab[2] &= ~0x08;
270 ves1820_writereg (fe, i, ves1820_inittab[i]);
272 ves1820_writereg (fe, 0x34, GET_PWM(fe->data));
278 static int ves1820_set_symbolrate (struct dvb_frontend *fe, u32 symbolrate)
286 if (symbolrate > XIN/2)
289 if (symbolrate < 500000)
292 if (symbolrate < XIN/16) NDEC = 1;
293 if (symbolrate < XIN/32) NDEC = 2;
294 if (symbolrate < XIN/64) NDEC = 3;
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;
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;
312 BDRI = (((XIN << 5) / symbolrate) + 1) / 2;
317 SFIL = (SFIL << 4) | ves1820_inittab[0x0E];
319 NDEC = (NDEC << 6) | ves1820_inittab[0x03];
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);
326 ves1820_writereg (fe, 0x0d, BDRI);
327 ves1820_writereg (fe, 0x0e, SFIL);
333 static int ves1820_set_parameters (struct dvb_frontend *fe,
334 struct dvb_frontend_parameters *p)
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;
343 if (real_qam < 0 || real_qam > 4)
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));
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]);
355 ves1820_setup_reg0 (fe, reg0x00[real_qam], p->inversion);
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. */
366 static int ves1820_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
370 memcpy (arg, &ves1820_info, sizeof(struct dvb_frontend_info));
375 fe_status_t *status = (fe_status_t *) arg;
380 sync = ves1820_readreg (fe, 0x11);
383 *status |= FE_HAS_SIGNAL;
386 *status |= FE_HAS_CARRIER;
388 if (sync & 2) /* XXX FIXME! */
389 *status |= FE_HAS_VITERBI;
392 *status |= FE_HAS_SYNC;
395 *status |= FE_HAS_LOCK;
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;
408 case FE_READ_SIGNAL_STRENGTH:
410 u8 gain = ves1820_readreg(fe, 0x17);
411 *((u16*) arg) = (gain << 8) | gain;
417 u8 quality = ~ves1820_readreg(fe, 0x18);
418 *((u16*) arg) = (quality << 8) | quality;
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]);
431 case FE_SET_FRONTEND:
432 return ves1820_set_parameters (fe, arg);
434 case FE_GET_FRONTEND:
436 struct dvb_frontend_parameters *p = (struct dvb_frontend_parameters *)arg;
437 u8 reg0 = GET_REG0(fe->data);
441 sync = ves1820_readreg (fe, 0x11);
442 afc = ves1820_readreg(fe, 0x19);
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);
451 p->inversion = HAS_INVERSION(reg0) ? INVERSION_ON : INVERSION_OFF;
452 p->u.qam.modulation = ((reg0 >> 2) & 7) + QAM_16;
454 p->u.qam.fec_inner = FEC_NONE;
456 p->frequency = ((p->frequency + 31250) / 62500) * 62500;
458 p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10;
462 ves1820_writereg (fe, 0x1b, 0x02); /* pdown ADC */
463 ves1820_writereg (fe, 0x00, 0x80); /* standby */
467 return ves1820_init (fe);
477 static long probe_tuner (struct dvb_i2c_bus *i2c)
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 };
485 if (i2c->xfer(i2c, &msg1, 1) == 1) {
487 printk ("DVB: VES1820(%d): setup for tuner spXXXX\n", i2c->adapter->num);
488 } else if (i2c->xfer(i2c, &msg2, 1) == 1) {
490 printk ("DVB: VES1820(%d): setup for tuner sp5659c\n", i2c->adapter->num);
499 static u8 read_pwm (struct dvb_i2c_bus *i2c)
503 struct i2c_msg msg [] = { { .addr = 0x50, .flags = 0, .buf = &b, .len = 1 },
504 { .addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1 } };
506 if ((i2c->xfer(i2c, msg, 2) != 2) || (pwm == 0xff))
509 printk("DVB: VES1820(%d): pwm=0x%02x\n", i2c->adapter->num, pwm);
515 static long probe_demod_addr (struct dvb_i2c_bus *i2c)
517 u8 b [] = { 0x00, 0x1a };
519 struct i2c_msg msg [] = { { .addr = 0x08, .flags = 0, .buf = b, .len = 2 },
520 { .addr = 0x08, .flags = I2C_M_RD, .buf = &id, .len = 1 } };
522 if (i2c->xfer(i2c, msg, 2) == 2 && (id & 0xf0) == 0x70)
525 msg[0].addr = msg[1].addr = 0x09;
527 if (i2c->xfer(i2c, msg, 2) == 2 && (id & 0xf0) == 0x70)
534 static int ves1820_attach (struct dvb_i2c_bus *i2c, void **data)
540 if ((demod_addr = probe_demod_addr(i2c)) < 0)
543 tuner_type = probe_tuner(i2c);
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]);
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);
556 return dvb_register_frontend (ves1820_ioctl, i2c, priv, &ves1820_info);
560 static void ves1820_detach (struct dvb_i2c_bus *i2c, void *data)
562 dvb_unregister_frontend (ves1820_ioctl, i2c);
566 static int __init init_ves1820 (void)
569 for (i = 0; i < MAX_UNITS; i++)
570 if (pwm[i] < -1 || pwm[i] > 255)
572 return dvb_register_i2c_device (THIS_MODULE,
573 ves1820_attach, ves1820_detach);
577 static void __exit exit_ves1820 (void)
579 dvb_unregister_i2c_device (ves1820_attach);
583 module_init(init_ves1820);
584 module_exit(exit_ves1820);
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");
591 MODULE_DESCRIPTION("VES1820 DVB-C frontend driver");
592 MODULE_AUTHOR("Ralph Metzler, Holger Waechtler");
593 MODULE_LICENSE("GPL");