initial commit with v2.6.9
[linux-2.6.9-moxart.git] / drivers / media / dvb / frontends / nxt6000.c
blob7116b0ba5df0d0e9e9b871411070bc08098eedef
1 /*
3 NxtWave Communications - NXT6000 demodulator driver
5 This driver currently supports:
7 Alps TDME7 (Tuner: MITEL SP5659)
8 Alps TDED4 (Tuner: TI ALP510, external Nxt6000)
9 Comtech DVBT-6k07 (PLL IC: SP5730)
11 Copyright (C) 2002-2003 Florian Schirmer <jolt@tuxbox.org>
12 Copyright (C) 2003 Paul Andreassen <paul@andreassen.com.au>
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 */
30 #include <linux/init.h>
31 #include <linux/kernel.h>
32 #include <linux/module.h>
33 #include <linux/string.h>
34 #include <linux/slab.h>
36 #include "dvb_frontend.h"
37 #include "nxt6000.h"
39 static int debug = 0;
41 MODULE_DESCRIPTION("NxtWave NXT6000 DVB demodulator driver");
42 MODULE_AUTHOR("Florian Schirmer");
43 MODULE_LICENSE("GPL");
44 MODULE_PARM(debug, "i");
46 static struct dvb_frontend_info nxt6000_info = {
48 .name = "NxtWave NXT6000",
49 .type = FE_OFDM,
50 .frequency_min = 0,
51 .frequency_max = 863250000,
52 .frequency_stepsize = 62500,
53 /*.frequency_tolerance = */ /* FIXME: 12% of SR */
54 .symbol_rate_min = 0, /* FIXME */
55 .symbol_rate_max = 9360000, /* FIXME */
56 .symbol_rate_tolerance = 4000,
57 .notifier_delay = 0,
58 .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
59 FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
60 FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
61 FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
62 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
63 FE_CAN_HIERARCHY_AUTO,
66 struct nxt6000_config {
67 u8 demod_addr;
68 u8 tuner_addr;
69 u8 tuner_type;
70 u8 clock_inversion;
73 #define TUNER_TYPE_ALP510 0
74 #define TUNER_TYPE_SP5659 1
75 #define TUNER_TYPE_SP5730 2
77 #define FE2NXT(fe) ((struct nxt6000_config *)((fe)->data))
78 #define FREQ2DIV(freq) ((freq + 36166667) / 166667)
80 #define dprintk if (debug) printk
82 static int nxt6000_write(struct dvb_i2c_bus *i2c, u8 addr, u8 reg, u8 data)
85 u8 buf[] = {reg, data};
86 struct i2c_msg msg = {.addr = addr >> 1, .flags = 0, .buf = buf, .len = 2};
87 int ret;
89 if ((ret = i2c->xfer(i2c, &msg, 1)) != 1)
90 dprintk("nxt6000: nxt6000_write error (.addr = 0x%02X, reg: 0x%02X, data: 0x%02X, ret: %d)\n", addr, reg, data, ret);
92 return (ret != 1) ? -EFAULT : 0;
96 static u8 nxt6000_writereg(struct dvb_frontend *fe, u8 reg, u8 data)
99 struct nxt6000_config *nxt = FE2NXT(fe);
101 return nxt6000_write(fe->i2c, nxt->demod_addr, reg, data);
105 static u8 nxt6000_read(struct dvb_i2c_bus *i2c, u8 addr, u8 reg)
108 int ret;
109 u8 b0[] = {reg};
110 u8 b1[] = {0};
111 struct i2c_msg msgs[] = {
112 {.addr = addr >> 1,.flags = 0,.buf = b0,.len = 1},
113 {.addr = addr >> 1,.flags = I2C_M_RD,.buf = b1,.len = 1}
116 ret = i2c->xfer(i2c, msgs, 2);
118 if (ret != 2)
119 dprintk("nxt6000: nxt6000_read error (.addr = 0x%02X, reg: 0x%02X, ret: %d)\n", addr, reg, ret);
121 return b1[0];
125 static u8 nxt6000_readreg(struct dvb_frontend *fe, u8 reg)
128 struct nxt6000_config *nxt = FE2NXT(fe);
130 return nxt6000_read(fe->i2c, nxt->demod_addr, reg);
133 static int pll_test(struct dvb_i2c_bus *i2c, u8 demod_addr, u8 tuner_addr)
135 u8 buf [1];
136 struct i2c_msg msg = {.addr = tuner_addr >> 1,.flags = I2C_M_RD,.buf = buf,.len = 1 };
137 int ret;
139 nxt6000_write(i2c, demod_addr, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */
140 ret = i2c->xfer(i2c, &msg, 1);
141 nxt6000_write(i2c, demod_addr, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */
143 return (ret != 1) ? -EFAULT : 0;
146 static int pll_write(struct dvb_i2c_bus *i2c, u8 demod_addr, u8 tuner_addr, u8 *buf, u8 len)
149 struct i2c_msg msg = {.addr = tuner_addr >> 1, .flags = 0, .buf = buf, .len = len};
150 int ret;
152 nxt6000_write(i2c, demod_addr, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */
153 ret = i2c->xfer(i2c, &msg, 1);
154 nxt6000_write(i2c, demod_addr, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */
156 if (ret != 1)
157 dprintk("nxt6000: pll_write error %d\n", ret);
159 return (ret != 1) ? -EFAULT : 0;
163 static int sp5659_set_tv_freq(struct dvb_frontend *fe, u32 freq)
166 u8 buf[4];
167 struct nxt6000_config *nxt = FE2NXT(fe);
169 buf[0] = (FREQ2DIV(freq) >> 8) & 0x7F;
170 buf[1] = FREQ2DIV(freq) & 0xFF;
171 buf[2] = (((FREQ2DIV(freq) >> 15) & 0x03) << 5) | 0x85;
173 if ((freq >= 174000000) && (freq < 230000000))
174 buf[3] = 0x82;
175 else if ((freq >= 470000000) && (freq < 782000000))
176 buf[3] = 0x85;
177 else if ((freq >= 782000000) && (freq < 863000000))
178 buf[3] = 0xC5;
179 else
180 return -EINVAL;
182 return pll_write(fe->i2c, nxt->demod_addr, nxt->tuner_addr, buf, 4);
186 static int alp510_set_tv_freq(struct dvb_frontend *fe, u32 freq)
189 u8 buf[4];
190 struct nxt6000_config *nxt = FE2NXT(fe);
192 buf[0] = (FREQ2DIV(freq) >> 8) & 0x7F;
193 buf[1] = FREQ2DIV(freq) & 0xFF;
194 buf[2] = 0x85;
196 #if 0
197 if ((freq >= 47000000) && (freq < 153000000))
198 buf[3] = 0x01;
199 else if ((freq >= 153000000) && (freq < 430000000))
200 buf[3] = 0x02;
201 else if ((freq >= 430000000) && (freq < 824000000))
202 buf[3] = 0x08;
203 else if ((freq >= 824000000) && (freq < 863000000))
204 buf[3] = 0x88;
205 else
206 return -EINVAL;
207 #else
208 if ((freq >= 47000000) && (freq < 153000000))
209 buf[3] = 0x01;
210 else if ((freq >= 153000000) && (freq < 430000000))
211 buf[3] = 0x02;
212 else if ((freq >= 430000000) && (freq < 824000000))
213 buf[3] = 0x0C;
214 else if ((freq >= 824000000) && (freq < 863000000))
215 buf[3] = 0x8C;
216 else
217 return -EINVAL;
218 #endif
220 return pll_write(fe->i2c, nxt->demod_addr, nxt->tuner_addr, buf, 4);
224 static int sp5730_set_tv_freq(struct dvb_frontend *fe, u32 freq)
227 u8 buf[4];
228 struct nxt6000_config *nxt = FE2NXT(fe);
230 buf[0] = (FREQ2DIV(freq) >> 8) & 0x7F;
231 buf[1] = FREQ2DIV(freq) & 0xFF;
232 buf[2] = 0x93;
234 if ((freq >= 51000000) && (freq < 132100000))
235 buf[3] = 0x05;
236 else if ((freq >= 132100000) && (freq < 143000000))
237 buf[3] = 0x45;
238 else if ((freq >= 146000000) && (freq < 349100000))
239 buf[3] = 0x06;
240 else if ((freq >= 349100000) && (freq < 397100000))
241 buf[3] = 0x46;
242 else if ((freq >= 397100000) && (freq < 426000000))
243 buf[3] = 0x86;
244 else if ((freq >= 430000000) && (freq < 659100000))
245 buf[3] = 0x03;
246 else if ((freq >= 659100000) && (freq < 759100000))
247 buf[3] = 0x43;
248 else if ((freq >= 759100000) && (freq < 858000000))
249 buf[3] = 0x83;
250 else
251 return -EINVAL;
253 return pll_write(fe->i2c, nxt->demod_addr, nxt->tuner_addr, buf, 4);
257 static void nxt6000_reset(struct dvb_frontend *fe)
260 u8 val;
262 val = nxt6000_readreg(fe, OFDM_COR_CTL);
264 nxt6000_writereg(fe, OFDM_COR_CTL, val & ~COREACT);
265 nxt6000_writereg(fe, OFDM_COR_CTL, val | COREACT);
269 static int nxt6000_set_bandwidth(struct dvb_frontend *fe, fe_bandwidth_t bandwidth)
272 u16 nominal_rate;
273 int result;
275 switch(bandwidth) {
277 case BANDWIDTH_6_MHZ:
279 nominal_rate = 0x55B7;
281 break;
283 case BANDWIDTH_7_MHZ:
285 nominal_rate = 0x6400;
287 break;
289 case BANDWIDTH_8_MHZ:
291 nominal_rate = 0x7249;
293 break;
295 default:
297 return -EINVAL;
301 if ((result = nxt6000_writereg(fe, OFDM_TRL_NOMINALRATE_1, nominal_rate & 0xFF)) < 0)
302 return result;
304 return nxt6000_writereg(fe, OFDM_TRL_NOMINALRATE_2, (nominal_rate >> 8) & 0xFF);
308 static int nxt6000_set_guard_interval(struct dvb_frontend *fe, fe_guard_interval_t guard_interval)
311 switch(guard_interval) {
313 case GUARD_INTERVAL_1_32:
315 return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, 0x00 | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x03));
317 case GUARD_INTERVAL_1_16:
319 return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, 0x01 | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x03));
321 case GUARD_INTERVAL_AUTO:
322 case GUARD_INTERVAL_1_8:
324 return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, 0x02 | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x03));
326 case GUARD_INTERVAL_1_4:
328 return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, 0x03 | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x03));
330 default:
332 return -EINVAL;
338 static int nxt6000_set_inversion(struct dvb_frontend *fe, fe_spectral_inversion_t inversion)
341 switch(inversion) {
343 case INVERSION_OFF:
345 return nxt6000_writereg(fe, OFDM_ITB_CTL, 0x00);
347 case INVERSION_ON:
349 return nxt6000_writereg(fe, OFDM_ITB_CTL, ITBINV);
351 default:
353 return -EINVAL;
359 static int nxt6000_set_transmission_mode(struct dvb_frontend *fe, fe_transmit_mode_t transmission_mode)
362 int result;
364 switch(transmission_mode) {
366 case TRANSMISSION_MODE_2K:
368 if ((result = nxt6000_writereg(fe, EN_DMD_RACQ, 0x00 | (nxt6000_readreg(fe, EN_DMD_RACQ) & ~0x03))) < 0)
369 return result;
371 return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, (0x00 << 2) | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x04));
373 case TRANSMISSION_MODE_8K:
374 case TRANSMISSION_MODE_AUTO:
376 if ((result = nxt6000_writereg(fe, EN_DMD_RACQ, 0x02 | (nxt6000_readreg(fe, EN_DMD_RACQ) & ~0x03))) < 0)
377 return result;
379 return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, (0x01 << 2) | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x04));
381 default:
383 return -EINVAL;
389 static void nxt6000_setup(struct dvb_frontend *fe)
392 struct nxt6000_config *nxt = FE2NXT(fe);
394 nxt6000_writereg(fe, RS_COR_SYNC_PARAM, SYNC_PARAM);
395 nxt6000_writereg(fe, BER_CTRL, /*(1 << 2) |*/ (0x01 << 1) | 0x01);
396 nxt6000_writereg(fe, VIT_COR_CTL, VIT_COR_RESYNC);
397 nxt6000_writereg(fe, OFDM_COR_CTL, (0x01 << 5) | (nxt6000_readreg(fe, OFDM_COR_CTL) & 0x0F));
398 nxt6000_writereg(fe, OFDM_COR_MODEGUARD, FORCEMODE8K | 0x02);
399 nxt6000_writereg(fe, OFDM_AGC_CTL, AGCLAST | INITIAL_AGC_BW);
400 nxt6000_writereg(fe, OFDM_ITB_FREQ_1, 0x06);
401 nxt6000_writereg(fe, OFDM_ITB_FREQ_2, 0x31);
402 nxt6000_writereg(fe, OFDM_CAS_CTL, (0x01 << 7) | (0x02 << 3) | 0x04);
403 nxt6000_writereg(fe, CAS_FREQ, 0xBB); /* CHECKME */
404 nxt6000_writereg(fe, OFDM_SYR_CTL, 1 << 2);
405 nxt6000_writereg(fe, OFDM_PPM_CTL_1, PPM256);
406 nxt6000_writereg(fe, OFDM_TRL_NOMINALRATE_1, 0x49);
407 nxt6000_writereg(fe, OFDM_TRL_NOMINALRATE_2, 0x72);
408 nxt6000_writereg(fe, ANALOG_CONTROL_0, 1 << 5);
409 nxt6000_writereg(fe, EN_DMD_RACQ, (1 << 7) | (3 << 4) | 2);
410 nxt6000_writereg(fe, DIAG_CONFIG, TB_SET);
412 if (nxt->clock_inversion)
413 nxt6000_writereg(fe, SUB_DIAG_MODE_SEL, CLKINVERSION);
414 else
415 nxt6000_writereg(fe, SUB_DIAG_MODE_SEL, 0);
417 nxt6000_writereg(fe, TS_FORMAT, 0);
421 static void nxt6000_dump_status(struct dvb_frontend *fe)
423 u8 val;
426 printk("RS_COR_STAT: 0x%02X\n", nxt6000_readreg(fe, RS_COR_STAT));
427 printk("VIT_SYNC_STATUS: 0x%02X\n", nxt6000_readreg(fe, VIT_SYNC_STATUS));
428 printk("OFDM_COR_STAT: 0x%02X\n", nxt6000_readreg(fe, OFDM_COR_STAT));
429 printk("OFDM_SYR_STAT: 0x%02X\n", nxt6000_readreg(fe, OFDM_SYR_STAT));
430 printk("OFDM_TPS_RCVD_1: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_1));
431 printk("OFDM_TPS_RCVD_2: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_2));
432 printk("OFDM_TPS_RCVD_3: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_3));
433 printk("OFDM_TPS_RCVD_4: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_4));
434 printk("OFDM_TPS_RESERVED_1: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RESERVED_1));
435 printk("OFDM_TPS_RESERVED_2: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RESERVED_2));
437 printk("NXT6000 status:");
439 val = nxt6000_readreg(fe, RS_COR_STAT);
441 printk(" DATA DESCR LOCK: %d,", val & 0x01);
442 printk(" DATA SYNC LOCK: %d,", (val >> 1) & 0x01);
444 val = nxt6000_readreg(fe, VIT_SYNC_STATUS);
446 printk(" VITERBI LOCK: %d,", (val >> 7) & 0x01);
448 switch((val >> 4) & 0x07) {
450 case 0x00:
452 printk(" VITERBI CODERATE: 1/2,");
454 break;
456 case 0x01:
458 printk(" VITERBI CODERATE: 2/3,");
460 break;
462 case 0x02:
464 printk(" VITERBI CODERATE: 3/4,");
466 break;
468 case 0x03:
469 printk(" VITERBI CODERATE: 5/6,");
470 break;
472 case 0x04:
473 printk(" VITERBI CODERATE: 7/8,");
474 break;
476 default:
478 printk(" VITERBI CODERATE: Reserved,");
482 val = nxt6000_readreg(fe, OFDM_COR_STAT);
484 printk(" CHCTrack: %d,", (val >> 7) & 0x01);
485 printk(" TPSLock: %d,", (val >> 6) & 0x01);
486 printk(" SYRLock: %d,", (val >> 5) & 0x01);
487 printk(" AGCLock: %d,", (val >> 4) & 0x01);
489 switch(val & 0x0F) {
491 case 0x00:
493 printk(" CoreState: IDLE,");
495 break;
497 case 0x02:
499 printk(" CoreState: WAIT_AGC,");
501 break;
503 case 0x03:
505 printk(" CoreState: WAIT_SYR,");
507 break;
509 case 0x04:
510 printk(" CoreState: WAIT_PPM,");
511 break;
513 case 0x01:
514 printk(" CoreState: WAIT_TRL,");
515 break;
517 case 0x05:
519 printk(" CoreState: WAIT_TPS,");
521 break;
523 case 0x06:
525 printk(" CoreState: MONITOR_TPS,");
527 break;
529 default:
531 printk(" CoreState: Reserved,");
535 val = nxt6000_readreg(fe, OFDM_SYR_STAT);
537 printk(" SYRLock: %d,", (val >> 4) & 0x01);
538 printk(" SYRMode: %s,", (val >> 2) & 0x01 ? "8K" : "2K");
540 switch((val >> 4) & 0x03) {
542 case 0x00:
544 printk(" SYRGuard: 1/32,");
546 break;
548 case 0x01:
550 printk(" SYRGuard: 1/16,");
552 break;
554 case 0x02:
556 printk(" SYRGuard: 1/8,");
558 break;
560 case 0x03:
562 printk(" SYRGuard: 1/4,");
564 break;
568 val = nxt6000_readreg(fe, OFDM_TPS_RCVD_3);
570 switch((val >> 4) & 0x07) {
572 case 0x00:
574 printk(" TPSLP: 1/2,");
576 break;
578 case 0x01:
580 printk(" TPSLP: 2/3,");
582 break;
584 case 0x02:
586 printk(" TPSLP: 3/4,");
588 break;
590 case 0x03:
591 printk(" TPSLP: 5/6,");
592 break;
594 case 0x04:
595 printk(" TPSLP: 7/8,");
596 break;
598 default:
600 printk(" TPSLP: Reserved,");
604 switch(val & 0x07) {
606 case 0x00:
608 printk(" TPSHP: 1/2,");
610 break;
612 case 0x01:
614 printk(" TPSHP: 2/3,");
616 break;
618 case 0x02:
620 printk(" TPSHP: 3/4,");
622 break;
624 case 0x03:
625 printk(" TPSHP: 5/6,");
626 break;
628 case 0x04:
629 printk(" TPSHP: 7/8,");
630 break;
632 default:
634 printk(" TPSHP: Reserved,");
638 val = nxt6000_readreg(fe, OFDM_TPS_RCVD_4);
640 printk(" TPSMode: %s,", val & 0x01 ? "8K" : "2K");
642 switch((val >> 4) & 0x03) {
644 case 0x00:
646 printk(" TPSGuard: 1/32,");
648 break;
650 case 0x01:
652 printk(" TPSGuard: 1/16,");
654 break;
656 case 0x02:
658 printk(" TPSGuard: 1/8,");
660 break;
662 case 0x03:
664 printk(" TPSGuard: 1/4,");
666 break;
670 /* Strange magic required to gain access to RF_AGC_STATUS */
671 nxt6000_readreg(fe, RF_AGC_VAL_1);
672 val = nxt6000_readreg(fe, RF_AGC_STATUS);
673 val = nxt6000_readreg(fe, RF_AGC_STATUS);
675 printk(" RF AGC LOCK: %d,", (val >> 4) & 0x01);
677 printk("\n");
681 static int nxt6000_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
684 switch (cmd) {
686 case FE_GET_INFO:
688 memcpy(arg, &nxt6000_info, sizeof (struct dvb_frontend_info));
690 return 0;
692 case FE_READ_STATUS:
694 fe_status_t *status = (fe_status_t *)arg;
696 u8 core_status;
698 *status = 0;
700 core_status = nxt6000_readreg(fe, OFDM_COR_STAT);
702 if (core_status & AGCLOCKED)
703 *status |= FE_HAS_SIGNAL;
705 if (nxt6000_readreg(fe, OFDM_SYR_STAT) & GI14_SYR_LOCK)
706 *status |= FE_HAS_CARRIER;
708 if (nxt6000_readreg(fe, VIT_SYNC_STATUS) & VITINSYNC)
709 *status |= FE_HAS_VITERBI;
711 if (nxt6000_readreg(fe, RS_COR_STAT) & RSCORESTATUS)
712 *status |= FE_HAS_SYNC;
714 if ((core_status & TPSLOCKED) && (*status == (FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)))
715 *status |= FE_HAS_LOCK;
717 if (debug)
718 nxt6000_dump_status(fe);
720 return 0;
724 case FE_READ_BER:
726 u32 *ber = (u32 *)arg;
728 *ber=0;
730 return 0;
734 case FE_READ_SIGNAL_STRENGTH:
736 s16 *signal = (s16 *) arg;
738 *signal=(((signed char)readreg(client, 0x16))+128)<<8;
740 *signal = 0;
741 return 0;
745 case FE_READ_SNR:
747 s16 *snr = (s16 *) arg;
749 *snr=readreg(client, 0x24)<<8;
750 *snr|=readreg(client, 0x25);
752 *snr = 0;
753 break;
756 case FE_READ_UNCORRECTED_BLOCKS:
758 u32 *ublocks = (u32 *)arg;
760 *ublocks = 0;
762 break;
765 case FE_INIT:
766 nxt6000_reset(fe);
767 nxt6000_setup(fe);
768 break;
770 case FE_SET_FRONTEND:
772 struct nxt6000_config *nxt = FE2NXT(fe);
773 struct dvb_frontend_parameters *param = (struct dvb_frontend_parameters *)arg;
774 int result;
776 switch(nxt->tuner_type) {
778 case TUNER_TYPE_ALP510:
780 if ((result = alp510_set_tv_freq(fe, param->frequency)) < 0)
781 return result;
783 break;
785 case TUNER_TYPE_SP5659:
787 if ((result = sp5659_set_tv_freq(fe, param->frequency)) < 0)
788 return result;
790 break;
792 case TUNER_TYPE_SP5730:
794 if ((result = sp5730_set_tv_freq(fe, param->frequency)) < 0)
795 return result;
797 break;
799 default:
801 return -EFAULT;
805 if ((result = nxt6000_set_bandwidth(fe, param->u.ofdm.bandwidth)) < 0)
806 return result;
807 if ((result = nxt6000_set_guard_interval(fe, param->u.ofdm.guard_interval)) < 0)
808 return result;
809 if ((result = nxt6000_set_transmission_mode(fe, param->u.ofdm.transmission_mode)) < 0)
810 return result;
811 if ((result = nxt6000_set_inversion(fe, param->inversion)) < 0)
812 return result;
814 break;
817 default:
819 return -EOPNOTSUPP;
823 return 0;
827 static u8 demod_addr_tbl[] = {0x14, 0x18, 0x24, 0x28};
829 static int nxt6000_attach(struct dvb_i2c_bus *i2c, void **data)
831 u8 addr_nr;
832 u8 fe_count = 0;
833 struct nxt6000_config *pnxt;
835 dprintk("nxt6000: attach\n");
837 pnxt = kmalloc(sizeof(demod_addr_tbl)*sizeof(struct nxt6000_config), GFP_KERNEL);
838 if (NULL == pnxt) {
839 dprintk("nxt6000: no memory for private data.\n");
840 return -ENOMEM;
842 *data = pnxt;
844 for (addr_nr = 0; addr_nr < sizeof(demod_addr_tbl); addr_nr++) {
845 struct nxt6000_config *nxt = &pnxt[addr_nr];
847 if (nxt6000_read(i2c, demod_addr_tbl[addr_nr], OFDM_MSC_REV) != NXT6000ASICDEVICE)
848 continue;
850 if (pll_test(i2c, demod_addr_tbl[addr_nr], 0xC0) == 0) {
851 nxt->tuner_addr = 0xC0;
852 nxt->tuner_type = TUNER_TYPE_ALP510;
853 nxt->clock_inversion = 1;
855 dprintk("nxt6000: detected TI ALP510 tuner at 0x%02X\n", nxt->tuner_addr);
857 } else if (pll_test(i2c, demod_addr_tbl[addr_nr], 0xC2) == 0) {
858 nxt->tuner_addr = 0xC2;
859 nxt->tuner_type = TUNER_TYPE_SP5659;
860 nxt->clock_inversion = 0;
862 dprintk("nxt6000: detected MITEL SP5659 tuner at 0x%02X\n", nxt->tuner_addr);
864 } else if (pll_test(i2c, demod_addr_tbl[addr_nr], 0xC0) == 0) {
865 nxt->tuner_addr = 0xC0;
866 nxt->tuner_type = TUNER_TYPE_SP5730;
867 nxt->clock_inversion = 0;
869 dprintk("nxt6000: detected SP5730 tuner at 0x%02X\n", nxt->tuner_addr);
871 } else {
872 printk("nxt6000: unable to detect tuner\n");
873 continue;
876 nxt->demod_addr = demod_addr_tbl[addr_nr];
878 dprintk("nxt6000: attached at %d:%d\n", i2c->adapter->num, i2c->id);
880 dvb_register_frontend(nxt6000_ioctl, i2c, (void *)nxt, &nxt6000_info);
882 fe_count++;
885 if (fe_count == 0) {
886 kfree(pnxt);
887 return -ENODEV;
890 return 0;
893 static void nxt6000_detach(struct dvb_i2c_bus *i2c, void *data)
895 struct nxt6000_config *pnxt = (struct nxt6000_config *)data;
896 dprintk("nxt6000: detach\n");
897 dvb_unregister_frontend(nxt6000_ioctl, i2c);
898 kfree(pnxt);
901 static __init int nxt6000_init(void)
904 dprintk("nxt6000: init\n");
906 return dvb_register_i2c_device(THIS_MODULE, nxt6000_attach, nxt6000_detach);
910 static __exit void nxt6000_exit(void)
913 dprintk("nxt6000: cleanup\n");
915 dvb_unregister_i2c_device(nxt6000_attach);
919 module_init(nxt6000_init);
920 module_exit(nxt6000_exit);