initial commit with v2.6.9
[linux-2.6.9-moxart.git] / drivers / media / dvb / frontends / alps_tdlb7.c
blob8ca5b028937bde9d630d2ca5cd302e30f07a2ab0
1 /*
2 Driver for Alps TDLB7 Frontend
4 Copyright (C) 1999 Juergen Peitz
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 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.
24 /*
25 This driver needs a copy of the firmware file 'Sc_main.mc' from the Haupauge
26 windows driver in the '/usr/lib/DVB/driver/frontends' directory.
27 You can also pass the complete file name with the module parameter 'firmware_file'.
29 */
31 #include <linux/module.h>
32 #include <linux/init.h>
33 #include <linux/vmalloc.h>
34 #include <linux/fs.h>
35 #include <linux/unistd.h>
36 #include <linux/delay.h>
37 #include <linux/syscalls.h>
39 #include "dvb_frontend.h"
40 #include "dvb_functions.h"
42 #ifndef CONFIG_ALPS_TDLB7_FIRMWARE_LOCATION
43 #define CONFIG_ALPS_TDLB7_FIRMWARE_LOCATION "/usr/lib/DVB/driver/frontends/Sc_main.mc"
44 #endif
46 static char * firmware_file = CONFIG_ALPS_TDLB7_FIRMWARE_LOCATION;
47 static int debug = 0;
49 #define dprintk if (debug) printk
51 /* firmware size for sp8870 */
52 #define SP8870_FIRMWARE_SIZE 16382
54 /* starting point for firmware in file 'Sc_main.mc' */
55 #define SP8870_FIRMWARE_OFFSET 0x0A
57 static struct dvb_frontend_info tdlb7_info = {
58 .name = "Alps TDLB7",
59 .type = FE_OFDM,
60 .frequency_min = 470000000,
61 .frequency_max = 860000000,
62 .frequency_stepsize = 166666,
63 .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
64 FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 |
65 FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
66 FE_CAN_QPSK | FE_CAN_QAM_16 |
67 FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
68 FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER
72 static int sp8870_writereg (struct dvb_i2c_bus *i2c, u16 reg, u16 data)
74 u8 buf [] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff };
75 struct i2c_msg msg = { .addr = 0x71, .flags = 0, .buf = buf, .len = 4 };
76 int err;
78 if ((err = i2c->xfer (i2c, &msg, 1)) != 1) {
79 dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data);
80 return -EREMOTEIO;
83 return 0;
87 static u16 sp8870_readreg (struct dvb_i2c_bus *i2c, u16 reg)
89 int ret;
90 u8 b0 [] = { reg >> 8 , reg & 0xff };
91 u8 b1 [] = { 0, 0 };
92 struct i2c_msg msg [] = { { .addr = 0x71, .flags = 0, .buf = b0, .len = 2 },
93 { .addr = 0x71, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
95 ret = i2c->xfer (i2c, msg, 2);
97 if (ret != 2) {
98 dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
99 return -1;
102 return (b1[0] << 8 | b1[1]);
106 static int sp5659_write (struct dvb_i2c_bus *i2c, u8 data [4])
108 int ret;
109 struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = 4 };
111 ret = i2c->xfer (i2c, &msg, 1);
113 if (ret != 1)
114 printk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret);
116 return (ret != 1) ? -1 : 0;
120 static void sp5659_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq)
122 u32 div = (freq + 36200000) / 166666;
123 u8 buf [4];
124 int pwr;
126 if (freq <= 782000000)
127 pwr = 1;
128 else
129 pwr = 2;
131 buf[0] = (div >> 8) & 0x7f;
132 buf[1] = div & 0xff;
133 buf[2] = 0x85;
134 buf[3] = pwr << 6;
136 /* open i2c gate for PLL message transmission... */
137 sp8870_writereg(i2c, 0x206, 0x001);
138 sp5659_write (i2c, buf);
139 sp8870_writereg(i2c, 0x206, 0x000);
143 static int sp8870_read_firmware_file (const char *fn, char **fp)
145 int fd;
146 loff_t filesize;
147 char *dp;
149 fd = sys_open(fn, 0, 0);
150 if (fd == -1) {
151 printk("%s: unable to open '%s'.\n", __FUNCTION__, fn);
152 return -EIO;
155 filesize = sys_lseek(fd, 0L, 2);
156 if (filesize <= 0 || filesize < SP8870_FIRMWARE_OFFSET + SP8870_FIRMWARE_SIZE) {
157 printk("%s: firmware filesize to small '%s'\n", __FUNCTION__, fn);
158 sys_close(fd);
159 return -EIO;
162 *fp= dp = vmalloc(SP8870_FIRMWARE_SIZE);
163 if (dp == NULL) {
164 printk("%s: out of memory loading '%s'.\n", __FUNCTION__, fn);
165 sys_close(fd);
166 return -EIO;
169 sys_lseek(fd, SP8870_FIRMWARE_OFFSET, 0);
170 if (sys_read(fd, dp, SP8870_FIRMWARE_SIZE) != SP8870_FIRMWARE_SIZE) {
171 printk("%s: failed to read '%s'.\n",__FUNCTION__, fn);
172 vfree(dp);
173 sys_close(fd);
174 return -EIO;
177 sys_close(fd);
178 *fp = dp;
180 return 0;
184 static int sp8870_firmware_upload (struct dvb_i2c_bus *i2c)
186 struct i2c_msg msg;
187 char *fw_buf = NULL;
188 int fw_pos;
189 u8 tx_buf[255];
190 int tx_len;
191 int err = 0;
192 mm_segment_t fs = get_fs();
194 dprintk ("%s: ...\n", __FUNCTION__);
196 // system controller stop
197 sp8870_writereg(i2c,0x0F00,0x0000);
199 // instruction RAM register hiword
200 sp8870_writereg(i2c, 0x8F08, ((SP8870_FIRMWARE_SIZE / 2) & 0xFFFF));
202 // instruction RAM MWR
203 sp8870_writereg(i2c, 0x8F0A, ((SP8870_FIRMWARE_SIZE / 2) >> 16));
205 // reading firmware file to buffer
206 set_fs(get_ds());
207 err = sp8870_read_firmware_file(firmware_file, (char**) &fw_buf);
208 set_fs(fs);
209 if (err != 0) {
210 printk("%s: reading firmware file failed!\n", __FUNCTION__);
211 return err;
214 // do firmware upload
215 fw_pos = 0;
216 while (fw_pos < SP8870_FIRMWARE_SIZE){
217 tx_len = (fw_pos <= SP8870_FIRMWARE_SIZE - 252) ? 252 : SP8870_FIRMWARE_SIZE - fw_pos;
218 // write register 0xCF0A
219 tx_buf[0] = 0xCF;
220 tx_buf[1] = 0x0A;
221 memcpy(&tx_buf[2], fw_buf + fw_pos, tx_len);
222 msg.addr=0x71;
223 msg.flags=0;
224 msg.buf = tx_buf;
225 msg.len = tx_len + 2;
226 if ((err = i2c->xfer (i2c, &msg, 1)) != 1) {
227 printk("%s: firmware upload failed!\n", __FUNCTION__);
228 printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err);
229 vfree(fw_buf);
230 return err;
232 fw_pos += tx_len;
235 vfree(fw_buf);
237 dprintk ("%s: done!\n", __FUNCTION__);
238 return 0;
242 static void sp8870_microcontroller_stop (struct dvb_i2c_bus *i2c)
244 sp8870_writereg(i2c, 0x0F08, 0x000);
245 sp8870_writereg(i2c, 0x0F09, 0x000);
247 // microcontroller STOP
248 sp8870_writereg(i2c, 0x0F00, 0x000);
252 static void sp8870_microcontroller_start (struct dvb_i2c_bus *i2c)
254 sp8870_writereg(i2c, 0x0F08, 0x000);
255 sp8870_writereg(i2c, 0x0F09, 0x000);
257 // microcontroller START
258 sp8870_writereg(i2c, 0x0F00, 0x001);
259 // not documented but if we don't read 0x0D01 out here
260 // we don't get a correct data valid signal
261 sp8870_readreg(i2c, 0x0D01);
265 static int sp8870_init (struct dvb_i2c_bus *i2c)
267 dprintk ("%s\n", __FUNCTION__);
269 /* enable TS output and interface pins */
270 sp8870_writereg(i2c, 0xc18, 0x00d);
272 // system controller stop
273 sp8870_microcontroller_stop(i2c);
275 // ADC mode
276 sp8870_writereg(i2c,0x0301,0x0003);
278 // Reed Solomon parity bytes passed to output
279 sp8870_writereg(i2c,0x0C13,0x0001);
281 // MPEG clock is suppressed if no valid data
282 sp8870_writereg(i2c,0x0C14,0x0001);
284 /* bit 0x010: enable data valid signal */
285 sp8870_writereg(i2c, 0x0D00, 0x010);
286 sp8870_writereg(i2c, 0x0D01, 0x000);
288 return 0;
292 static int sp8870_read_status (struct dvb_i2c_bus *i2c, fe_status_t * fe_status)
294 int status;
295 int signal;
297 *fe_status = 0;
299 status = sp8870_readreg (i2c, 0x0200);
300 if (status < 0)
301 return -EIO;
303 signal = sp8870_readreg (i2c, 0x0303);
304 if (signal < 0)
305 return -EIO;
307 if (signal > 0x0F)
308 *fe_status |= FE_HAS_SIGNAL;
309 if (status & 0x08)
310 *fe_status |= FE_HAS_SYNC;
311 if (status & 0x04)
312 *fe_status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_VITERBI;
314 return 0;
318 static int sp8870_read_ber (struct dvb_i2c_bus *i2c, u32 * ber)
320 int ret;
321 u32 tmp;
323 *ber = 0;
325 ret = sp8870_readreg(i2c, 0xC08);
326 if (ret < 0)
327 return -EIO;
329 tmp = ret & 0x3F;
331 ret = sp8870_readreg(i2c, 0xC07);
332 if (ret < 0)
333 return -EIO;
335 tmp = ret << 6;
337 if (tmp >= 0x3FFF0)
338 tmp = ~0;
340 *ber = tmp;
342 return 0;
346 static int sp8870_read_signal_strength (struct dvb_i2c_bus *i2c, u16 * signal)
348 int ret;
349 u16 tmp;
351 *signal = 0;
353 ret = sp8870_readreg (i2c, 0x306);
354 if (ret < 0)
355 return -EIO;
357 tmp = ret << 8;
359 ret = sp8870_readreg (i2c, 0x303);
360 if (ret < 0)
361 return -EIO;
363 tmp |= ret;
365 if (tmp)
366 *signal = 0xFFFF - tmp;
368 return 0;
372 static int sp8870_read_snr(struct dvb_i2c_bus *i2c, u32* snr)
374 *snr=0;
375 return -EOPNOTSUPP;
379 static int sp8870_read_uncorrected_blocks (struct dvb_i2c_bus *i2c, u32* ublocks)
381 int ret;
383 *ublocks=0;
385 ret = sp8870_readreg(i2c, 0xC0C);
386 if (ret < 0)
387 return -EIO;
389 if (ret == 0xFFFF)
390 ret = ~0;
392 *ublocks = ret;
394 return 0;
398 static int sp8870_read_data_valid_signal(struct dvb_i2c_bus *i2c)
400 return (sp8870_readreg(i2c, 0x0D02) > 0);
404 static
405 int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
407 int known_parameters = 1;
409 *reg0xc05 = 0x000;
411 switch (p->u.ofdm.constellation) {
412 case QPSK:
413 break;
414 case QAM_16:
415 *reg0xc05 |= (1 << 10);
416 break;
417 case QAM_64:
418 *reg0xc05 |= (2 << 10);
419 break;
420 case QAM_AUTO:
421 known_parameters = 0;
422 break;
423 default:
424 return -EINVAL;
427 switch (p->u.ofdm.hierarchy_information) {
428 case HIERARCHY_NONE:
429 break;
430 case HIERARCHY_1:
431 *reg0xc05 |= (1 << 7);
432 break;
433 case HIERARCHY_2:
434 *reg0xc05 |= (2 << 7);
435 break;
436 case HIERARCHY_4:
437 *reg0xc05 |= (3 << 7);
438 break;
439 case HIERARCHY_AUTO:
440 known_parameters = 0;
441 break;
442 default:
443 return -EINVAL;
446 switch (p->u.ofdm.code_rate_HP) {
447 case FEC_1_2:
448 break;
449 case FEC_2_3:
450 *reg0xc05 |= (1 << 3);
451 break;
452 case FEC_3_4:
453 *reg0xc05 |= (2 << 3);
454 break;
455 case FEC_5_6:
456 *reg0xc05 |= (3 << 3);
457 break;
458 case FEC_7_8:
459 *reg0xc05 |= (4 << 3);
460 break;
461 case FEC_AUTO:
462 known_parameters = 0;
463 break;
464 default:
465 return -EINVAL;
468 if (known_parameters)
469 *reg0xc05 |= (2 << 1); /* use specified parameters */
470 else
471 *reg0xc05 |= (1 << 1); /* enable autoprobing */
473 return 0;
477 static int sp8870_set_frontend_parameters (struct dvb_i2c_bus *i2c,
478 struct dvb_frontend_parameters *p)
480 int err;
481 u16 reg0xc05;
483 if ((err = configure_reg0xc05(p, &reg0xc05)))
484 return err;
486 // system controller stop
487 sp8870_microcontroller_stop(i2c);
489 // set tuner parameters
490 sp5659_set_tv_freq (i2c, p->frequency);
492 // sample rate correction bit [23..17]
493 sp8870_writereg(i2c,0x0319,0x000A);
495 // sample rate correction bit [16..0]
496 sp8870_writereg(i2c,0x031A,0x0AAB);
498 // integer carrier offset
499 sp8870_writereg(i2c,0x0309,0x0400);
501 // fractional carrier offset
502 sp8870_writereg(i2c,0x030A,0x0000);
504 // filter for 6/7/8 Mhz channel
505 if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
506 sp8870_writereg(i2c,0x0311,0x0002);
507 else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
508 sp8870_writereg(i2c,0x0311,0x0001);
509 else
510 sp8870_writereg(i2c,0x0311,0x0000);
512 // scan order: 2k first = 0x0000, 8k first = 0x0001
513 if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K)
514 sp8870_writereg(i2c,0x0338,0x0000);
515 else
516 sp8870_writereg(i2c,0x0338,0x0001);
518 sp8870_writereg(i2c, 0xc05, reg0xc05);
520 // read status reg in order to clear pending irqs
521 sp8870_readreg(i2c, 0x200);
523 // system controller start
524 sp8870_microcontroller_start(i2c);
526 return 0;
530 // number of trials to recover from lockup
531 #define MAXTRIALS 5
532 // maximum checks for data valid signal
533 #define MAXCHECKS 100
535 // only for debugging: counter for detected lockups
536 static int lockups = 0;
537 // only for debugging: counter for channel switches
538 static int switches = 0;
540 static int sp8870_set_frontend (struct dvb_i2c_bus *i2c, struct dvb_frontend_parameters *p)
543 The firmware of the sp8870 sometimes locks up after setting frontend parameters.
544 We try to detect this by checking the data valid signal.
545 If it is not set after MAXCHECKS we try to recover the lockup by setting
546 the frontend parameters again.
549 int err = 0;
550 int valid = 0;
551 int trials = 0;
552 int check_count = 0;
554 dprintk("%s: frequency = %i\n", __FUNCTION__, p->frequency);
556 for (trials = 1; trials <= MAXTRIALS; trials++) {
558 if ((err = sp8870_set_frontend_parameters(i2c, p)))
559 return err;
561 for (check_count = 0; check_count < MAXCHECKS; check_count++) {
562 // valid = ((sp8870_readreg(i2c, 0x0200) & 4) == 0);
563 valid = sp8870_read_data_valid_signal(i2c);
564 if (valid) {
565 dprintk("%s: delay = %i usec\n",
566 __FUNCTION__, check_count * 10);
567 break;
569 udelay(10);
571 if (valid)
572 break;
575 if (!valid) {
576 printk("%s: firmware crash!!!!!!\n", __FUNCTION__);
577 return -EIO;
580 if (debug) {
581 if (valid) {
582 if (trials > 1) {
583 printk("%s: firmware lockup!!!\n", __FUNCTION__);
584 printk("%s: recovered after %i trial(s))\n", __FUNCTION__, trials - 1);
585 lockups++;
588 switches++;
589 printk("%s: switches = %i lockups = %i\n", __FUNCTION__, switches, lockups);
592 return 0;
596 static int sp8870_sleep(struct dvb_i2c_bus *i2c)
598 // tristate TS output and disable interface pins
599 return sp8870_writereg(i2c, 0xC18, 0x000);
603 static int sp8870_wake_up(struct dvb_i2c_bus *i2c)
605 // enable TS output and interface pins
606 return sp8870_writereg(i2c, 0xC18, 0x00D);
610 static int tdlb7_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
612 struct dvb_i2c_bus *i2c = fe->i2c;
614 switch (cmd) {
615 case FE_GET_INFO:
616 memcpy (arg, &tdlb7_info, sizeof(struct dvb_frontend_info));
617 break;
619 case FE_READ_STATUS:
620 return sp8870_read_status(i2c, (fe_status_t *) arg);
622 case FE_READ_BER:
623 return sp8870_read_ber(i2c, (u32 *) arg);
625 case FE_READ_SIGNAL_STRENGTH:
626 return sp8870_read_signal_strength(i2c, (u16 *) arg);
628 case FE_READ_SNR: // not supported by hardware?
629 return sp8870_read_snr(i2c, (u32 *) arg);
631 case FE_READ_UNCORRECTED_BLOCKS:
632 return sp8870_read_uncorrected_blocks(i2c, (u32 *) arg);
634 case FE_SET_FRONTEND:
635 return sp8870_set_frontend(i2c, (struct dvb_frontend_parameters*) arg);
637 case FE_GET_FRONTEND: // FIXME: read known values back from Hardware...
638 return -EOPNOTSUPP;
640 case FE_SLEEP:
641 return sp8870_sleep(i2c);
643 case FE_INIT:
644 sp8870_wake_up(i2c);
645 if (fe->data == NULL) { // first time initialisation...
646 fe->data = (void*) ~0;
647 sp8870_init (i2c);
649 break;
651 case FE_GET_TUNE_SETTINGS:
653 struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg;
654 fesettings->min_delay_ms = 150;
655 fesettings->step_size = 166667;
656 fesettings->max_drift = 166667*2;
657 return 0;
660 default:
661 return -EOPNOTSUPP;
664 return 0;
668 static int tdlb7_attach (struct dvb_i2c_bus *i2c, void **data)
670 u8 b0 [] = { 0x02 , 0x00 };
671 u8 b1 [] = { 0, 0 };
672 struct i2c_msg msg [] = { { .addr = 0x71, .flags = 0, .buf = b0, .len = 2 },
673 { .addr = 0x71, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
675 dprintk ("%s\n", __FUNCTION__);
677 if (i2c->xfer (i2c, msg, 2) != 2)
678 return -ENODEV;
680 sp8870_firmware_upload(i2c);
682 return dvb_register_frontend (tdlb7_ioctl, i2c, NULL, &tdlb7_info);
686 static void tdlb7_detach (struct dvb_i2c_bus *i2c, void *data)
688 dprintk ("%s\n", __FUNCTION__);
690 dvb_unregister_frontend (tdlb7_ioctl, i2c);
694 static int __init init_tdlb7 (void)
696 dprintk ("%s\n", __FUNCTION__);
698 return dvb_register_i2c_device (THIS_MODULE, tdlb7_attach, tdlb7_detach);
702 static void __exit exit_tdlb7 (void)
704 dprintk ("%s\n", __FUNCTION__);
706 dvb_unregister_i2c_device (tdlb7_attach);
710 module_init(init_tdlb7);
711 module_exit(exit_tdlb7);
714 MODULE_PARM(debug,"i");
715 MODULE_PARM_DESC(debug, "enable verbose debug messages");
717 MODULE_PARM(firmware_file,"s");
718 MODULE_PARM_DESC(firmware_file, "where to find the firmware file");
720 MODULE_DESCRIPTION("TDLB7 DVB-T Frontend");
721 MODULE_AUTHOR("Juergen Peitz");
722 MODULE_LICENSE("GPL");