X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmedia%2Fdvb%2Ffrontends%2Fat76c651.c;h=4b6c539a0d67d420dd503ac083fc1f4a7d4b2427;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=01d438a4fa29afef9a39477f5616528037864f9b;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/drivers/media/dvb/frontends/at76c651.c b/drivers/media/dvb/frontends/at76c651.c index 01d438a4f..4b6c539a0 100644 --- a/drivers/media/dvb/frontends/at76c651.c +++ b/drivers/media/dvb/frontends/at76c651.c @@ -1,10 +1,10 @@ /* * at76c651.c * - * Atmel DVB-C Frontend Driver (at76c651/dat7021) + * Atmel DVB-C Frontend Driver (at76c651/tua6010xs) * * Copyright (C) 2001 fnbrd - * & 2002 Andreas Oberritter + * & 2002-2004 Andreas Oberritter * & 2003 Wolfram Joost * * This program is free software; you can redistribute it and/or modify @@ -21,59 +21,46 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + * AT76C651 + * http://www.nalanda.nitc.ac.in/industry/datasheets/atmel/acrobat/doc1293.pdf + * http://www.atmel.com/atmel/acrobat/doc1320.pdf */ #include #include +#include #include #include #include +#include +#include "dvb_frontend.h" +#include "at76c651.h" -#if defined(__powerpc__) -#include -#endif -#include "dvb_frontend.h" -#include "dvb_i2c.h" -#include "dvb_functions.h" +struct at76c651_state { -static int debug = 0; -static u8 at76c651_qam; -static u8 at76c651_revision; + struct i2c_adapter* i2c; -#define dprintk if (debug) printk + struct dvb_frontend_ops ops; -/* - * DAT7021 - * ------- - * Input Frequency Range (RF): 48.25 MHz to 863.25 MHz - * Band Width: 8 MHz - * Level Input (Range for Digital Signals): -61 dBm to -41 dBm - * Output Frequency (IF): 36 MHz - * - * (see http://www.atmel.com/atmel/acrobat/doc1320.pdf) - */ + const struct at76c651_config* config; + + struct dvb_frontend frontend; + + /* revision of the chip */ + u8 revision; -static struct dvb_frontend_info at76c651_info = { - - .name = "Atmel AT76C651(B) with DAT7021", - .type = FE_QAM, - .frequency_min = 48250000, - .frequency_max = 863250000, - .frequency_stepsize = 62500, - /*.frequency_tolerance = */ /* FIXME: 12% of SR */ - .symbol_rate_min = 0, /* FIXME */ - .symbol_rate_max = 9360000, /* FIXME */ - .symbol_rate_tolerance = 4000, - .notifier_delay = 0, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | - FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | - FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | - FE_CAN_MUTE_TS | FE_CAN_QAM_256 | FE_CAN_RECOVER + /* last QAM value set */ + u8 qam; }; +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "at76c651: " args); \ + } while (0) + + #if ! defined(__powerpc__) static __inline__ int __ilog2(unsigned long x) { @@ -89,229 +76,150 @@ static __inline__ int __ilog2(unsigned long x) } #endif -static int at76c651_writereg(struct dvb_i2c_bus *i2c, u8 reg, u8 data) +static int at76c651_writereg(struct at76c651_state* state, u8 reg, u8 data) { - int ret; u8 buf[] = { reg, data }; - struct i2c_msg msg = { .addr = 0x1a >> 1, .flags = 0, .buf = buf, .len = 2 }; + struct i2c_msg msg = + { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; - ret = i2c->xfer(i2c, &msg, 1); + ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) dprintk("%s: writereg error " "(reg == 0x%02x, val == 0x%02x, ret == %i)\n", __FUNCTION__, reg, data, ret); - dvb_delay(10); + msleep(10); return (ret != 1) ? -EREMOTEIO : 0; - } -static u8 at76c651_readreg(struct dvb_i2c_bus *i2c, u8 reg) +static u8 at76c651_readreg(struct at76c651_state* state, u8 reg) { - int ret; - u8 b0[] = { reg }; - u8 b1[] = { 0 }; - struct i2c_msg msg[] = { {.addr = 0x1a >> 1, .flags = 0, .buf = b0, .len = 1}, - {.addr = 0x1a >> 1, .flags = I2C_M_RD, .buf = b1, .len = 1} }; + u8 val; + struct i2c_msg msg[] = { + { .addr = state->config->demod_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = &val, .len = 1 } + }; - ret = i2c->xfer(i2c, msg, 2); + ret = i2c_transfer(state->i2c, msg, 2); if (ret != 2) dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); - return b1[0]; - + return val; } -static int at76c651_reset(struct dvb_i2c_bus *i2c) +static int at76c651_reset(struct at76c651_state* state) { - - return at76c651_writereg(i2c, 0x07, 0x01); - + return at76c651_writereg(state, 0x07, 0x01); } -static int at76c651_disable_interrupts(struct dvb_i2c_bus *i2c) +static void at76c651_disable_interrupts(struct at76c651_state* state) { - - return at76c651_writereg(i2c, 0x0b, 0x00); - + at76c651_writereg(state, 0x0b, 0x00); } -static int at76c651_set_auto_config(struct dvb_i2c_bus *i2c) +static int at76c651_set_auto_config(struct at76c651_state *state) { - /* * Autoconfig */ - at76c651_writereg(i2c, 0x06, 0x01); + at76c651_writereg(state, 0x06, 0x01); /* * Performance optimizations, should be done after autoconfig */ - at76c651_writereg(i2c, 0x10, 0x06); - at76c651_writereg(i2c, 0x11, ((at76c651_qam == 5) || (at76c651_qam == 7)) ? 0x12 : 0x10); - at76c651_writereg(i2c, 0x15, 0x28); - at76c651_writereg(i2c, 0x20, 0x09); - at76c651_writereg(i2c, 0x24, ((at76c651_qam == 5) || (at76c651_qam == 7)) ? 0xC0 : 0x90); - at76c651_writereg(i2c, 0x30, 0x90); - if (at76c651_qam == 5) - at76c651_writereg(i2c, 0x35, 0x2A); + at76c651_writereg(state, 0x10, 0x06); + at76c651_writereg(state, 0x11, ((state->qam == 5) || (state->qam == 7)) ? 0x12 : 0x10); + at76c651_writereg(state, 0x15, 0x28); + at76c651_writereg(state, 0x20, 0x09); + at76c651_writereg(state, 0x24, ((state->qam == 5) || (state->qam == 7)) ? 0xC0 : 0x90); + at76c651_writereg(state, 0x30, 0x90); + if (state->qam == 5) + at76c651_writereg(state, 0x35, 0x2A); /* * Initialize A/D-converter */ - if (at76c651_revision == 0x11) { - at76c651_writereg(i2c, 0x2E, 0x38); - at76c651_writereg(i2c, 0x2F, 0x13); + if (state->revision == 0x11) { + at76c651_writereg(state, 0x2E, 0x38); + at76c651_writereg(state, 0x2F, 0x13); } - at76c651_disable_interrupts(i2c); + at76c651_disable_interrupts(state); /* * Restart operation */ - at76c651_reset(i2c); - - return 0; - -} - -static int at76c651_set_bbfreq(struct dvb_i2c_bus *i2c) -{ - - at76c651_writereg(i2c, 0x04, 0x3f); - at76c651_writereg(i2c, 0x05, 0xee); - - return 0; - -} - -static int at76c651_switch_tuner_i2c(struct dvb_i2c_bus *i2c, u8 enable) -{ - - if (enable) - return at76c651_writereg(i2c, 0x0c, 0xc2 | 0x01); - else - return at76c651_writereg(i2c, 0x0c, 0xc2); - -} - -static int dat7021_write(struct dvb_i2c_bus *i2c, u32 tw) -{ - - int ret; - struct i2c_msg msg = - { .addr = 0xc2 >> 1, .flags = 0, .buf = (u8 *) & tw, .len = sizeof (tw) }; - -#ifdef __LITTLE_ENDIAN - tw = __cpu_to_be32(tw); -#endif - - at76c651_switch_tuner_i2c(i2c, 1); - - ret = i2c->xfer(i2c, &msg, 1); - - at76c651_switch_tuner_i2c(i2c, 0); - - if (ret != 4) - return -EFAULT; - - at76c651_reset(i2c); + at76c651_reset(state); return 0; - } -static int dat7021_set_tv_freq(struct dvb_i2c_bus *i2c, u32 freq) +static void at76c651_set_bbfreq(struct at76c651_state* state) { - - u32 dw; - - freq /= 1000; - - if ((freq < 48250) || (freq > 863250)) - return -EINVAL; - - /* - * formula: dw=0x17e28e06+(freq-346000UL)/8000UL*0x800000 - * or: dw=0x4E28E06+(freq-42000) / 125 * 0x20000 - */ - - dw = (freq - 42000) * 4096; - dw = dw / 125; - dw = dw * 32; - - if (freq > 394000) - dw += 0x4E28E85; - else - dw += 0x4E28E06; - - return dat7021_write(i2c, dw); - + at76c651_writereg(state, 0x04, 0x3f); + at76c651_writereg(state, 0x05, 0xee); } -static int at76c651_set_symbolrate(struct dvb_i2c_bus *i2c, u32 symbolrate) +static int at76c651_set_symbol_rate(struct at76c651_state* state, u32 symbol_rate) { - u8 exponent; u32 mantissa; - if (symbolrate > 9360000) + if (symbol_rate > 9360000) return -EINVAL; /* * FREF = 57800 kHz - * exponent = 10 + floor ( log2 ( symbolrate / FREF ) ) - * mantissa = ( symbolrate / FREF) * ( 1 << ( 30 - exponent ) ) + * exponent = 10 + floor (log2(symbol_rate / FREF)) + * mantissa = (symbol_rate / FREF) * (1 << (30 - exponent)) */ - exponent = __ilog2((symbolrate << 4) / 903125); - mantissa = ((symbolrate / 3125) * (1 << (24 - exponent))) / 289; + exponent = __ilog2((symbol_rate << 4) / 903125); + mantissa = ((symbol_rate / 3125) * (1 << (24 - exponent))) / 289; - at76c651_writereg(i2c, 0x00, mantissa >> 13); - at76c651_writereg(i2c, 0x01, mantissa >> 5); - at76c651_writereg(i2c, 0x02, (mantissa << 3) | exponent); + at76c651_writereg(state, 0x00, mantissa >> 13); + at76c651_writereg(state, 0x01, mantissa >> 5); + at76c651_writereg(state, 0x02, (mantissa << 3) | exponent); return 0; - } -static int at76c651_set_qam(struct dvb_i2c_bus *i2c, fe_modulation_t qam) +static int at76c651_set_qam(struct at76c651_state *state, fe_modulation_t qam) { - switch (qam) { case QPSK: - at76c651_qam = 0x02; + state->qam = 0x02; break; case QAM_16: - at76c651_qam = 0x04; + state->qam = 0x04; break; case QAM_32: - at76c651_qam = 0x05; + state->qam = 0x05; break; case QAM_64: - at76c651_qam = 0x06; + state->qam = 0x06; break; case QAM_128: - at76c651_qam = 0x07; + state->qam = 0x07; break; case QAM_256: - at76c651_qam = 0x08; + state->qam = 0x08; break; #if 0 case QAM_512: - at76c651_qam = 0x09; + state->qam = 0x09; break; case QAM_1024: - at76c651_qam = 0x0A; + state->qam = 0x0A; break; #endif default: @@ -319,15 +227,12 @@ static int at76c651_set_qam(struct dvb_i2c_bus *i2c, fe_modulation_t qam) } - return at76c651_writereg(i2c, 0x03, at76c651_qam); - + return at76c651_writereg(state, 0x03, state->qam); } -static int at76c651_set_inversion(struct dvb_i2c_bus *i2c, - fe_spectral_inversion_t inversion) +static int at76c651_set_inversion(struct at76c651_state* state, fe_spectral_inversion_t inversion) { - - u8 feciqinv = at76c651_readreg(i2c, 0x60); + u8 feciqinv = at76c651_readreg(state, 0x60); switch (inversion) { case INVERSION_OFF: @@ -347,56 +252,63 @@ static int at76c651_set_inversion(struct dvb_i2c_bus *i2c, return -EINVAL; } - return at76c651_writereg(i2c, 0x60, feciqinv); - + return at76c651_writereg(state, 0x60, feciqinv); } -static int at76c651_set_parameters(struct dvb_i2c_bus *i2c, - struct dvb_frontend_parameters *p) -{ - dat7021_set_tv_freq(i2c, p->frequency); - at76c651_set_symbolrate(i2c, p->u.qam.symbol_rate); - at76c651_set_inversion(i2c, p->inversion); - at76c651_set_auto_config(i2c); - at76c651_reset(i2c); - return 0; -} -static int at76c651_set_defaults(struct dvb_i2c_bus *i2c) + + + + +static int at76c651_set_parameters(struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) { + int ret; + struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; - at76c651_set_symbolrate(i2c, 6900000); - at76c651_set_qam(i2c, QAM_64); - at76c651_set_bbfreq(i2c); - at76c651_set_auto_config(i2c); + at76c651_writereg(state, 0x0c, 0xc3); + state->config->pll_set(fe, p); + at76c651_writereg(state, 0x0c, 0xc2); - return 0; + if ((ret = at76c651_set_symbol_rate(state, p->u.qam.symbol_rate))) + return ret; + if ((ret = at76c651_set_inversion(state, p->inversion))) + return ret; + + return at76c651_set_auto_config(state); } -static int at76c651_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg) +static int at76c651_set_defaults(struct dvb_frontend* fe) { + struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; - switch (cmd) { + at76c651_set_symbol_rate(state, 6900000); + at76c651_set_qam(state, QAM_64); + at76c651_set_bbfreq(state); + at76c651_set_auto_config(state); - case FE_GET_INFO: - memcpy(arg, &at76c651_info, sizeof (struct dvb_frontend_info)); - break; + if (state->config->pll_init) { + at76c651_writereg(state, 0x0c, 0xc3); + state->config->pll_init(fe); + at76c651_writereg(state, 0x0c, 0xc2); +} - case FE_READ_STATUS: - { + return 0; +} - fe_status_t *status = (fe_status_t *) arg; +static int at76c651_read_status(struct dvb_frontend* fe, fe_status_t* status) + { + struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; u8 sync; /* * Bits: FEC, CAR, EQU, TIM, AGC2, AGC1, ADC, PLL (PLL=0) */ - sync = at76c651_readreg(fe->i2c, 0x80); - + sync = at76c651_readreg(state, 0x80); *status = 0; if (sync & (0x04 | 0x10)) /* AGC1 || TIM */ @@ -414,122 +326,138 @@ static int at76c651_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg) if ((sync & 0xF0) == 0xF0) /* TIM && EQU && CAR && FEC */ *status |= FE_HAS_LOCK; - break; - + return 0; } - case FE_READ_BER: +static int at76c651_read_ber(struct dvb_frontend* fe, u32* ber) { - u32 *ber = (u32 *) arg; + struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; - *ber = (at76c651_readreg(fe->i2c, 0x81) & 0x0F) << 16; - *ber |= at76c651_readreg(fe->i2c, 0x82) << 8; - *ber |= at76c651_readreg(fe->i2c, 0x83); + *ber = (at76c651_readreg(state, 0x81) & 0x0F) << 16; + *ber |= at76c651_readreg(state, 0x82) << 8; + *ber |= at76c651_readreg(state, 0x83); *ber *= 10; - break; + return 0; } - case FE_READ_SIGNAL_STRENGTH: +static int at76c651_read_signal_strength(struct dvb_frontend* fe, u16* strength) { - u8 gain = ~at76c651_readreg(fe->i2c, 0x91); - - *(u16 *) arg = (gain << 8) | gain; - break; - } + struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; - case FE_READ_SNR: - *(u16 *) arg = - 0xFFFF - - ((at76c651_readreg(fe->i2c, 0x8F) << 8) | - at76c651_readreg(fe->i2c, 0x90)); - break; + u8 gain = ~at76c651_readreg(state, 0x91); + *strength = (gain << 8) | gain; - case FE_READ_UNCORRECTED_BLOCKS: - *(u32 *) arg = at76c651_readreg(fe->i2c, 0x82); - break; + return 0; +} - case FE_SET_FRONTEND: - return at76c651_set_parameters(fe->i2c, arg); +static int at76c651_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; - case FE_GET_FRONTEND: - break; + *snr = 0xFFFF - + ((at76c651_readreg(state, 0x8F) << 8) | + at76c651_readreg(state, 0x90)); - case FE_SLEEP: - break; - case FE_INIT: - return at76c651_set_defaults(fe->i2c); + return 0; +} - case FE_GET_TUNE_SETTINGS: +static int at76c651_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { - struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg; - fesettings->min_delay_ms = 50; - fesettings->step_size = 0; - fesettings->max_drift = 0; - return 0; - } + struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; - default: - return -ENOIOCTLCMD; - } + *ucblocks = at76c651_readreg(state, 0x82); return 0; - } -static int at76c651_attach(struct dvb_i2c_bus *i2c, void **data) +static int at76c651_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *fesettings) { - if ( (at76c651_readreg(i2c, 0x0E) != 0x65) || - ( ( (at76c651_revision = at76c651_readreg(i2c, 0x0F)) & 0xFE) != 0x10) ) -{ - dprintk("no AT76C651(B) found\n"); - return -ENODEV; + fesettings->min_delay_ms = 50; + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; } - if (at76c651_revision == 0x10) - { - dprintk("AT76C651A found\n"); - strcpy(at76c651_info.name,"Atmel AT76C651A with DAT7021"); - } - else - { - strcpy(at76c651_info.name,"Atmel AT76C651B with DAT7021"); - dprintk("AT76C651B found\n"); +static void at76c651_release(struct dvb_frontend* fe) +{ + struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; + kfree(state); } - at76c651_set_defaults(i2c); - - return dvb_register_frontend(at76c651_ioctl, i2c, NULL, &at76c651_info); +static struct dvb_frontend_ops at76c651_ops; -} - -static void at76c651_detach(struct dvb_i2c_bus *i2c, void *data) +struct dvb_frontend* at76c651_attach(const struct at76c651_config* config, + struct i2c_adapter* i2c) { + struct at76c651_state* state = NULL; - dvb_unregister_frontend(at76c651_ioctl, i2c); + /* allocate memory for the internal state */ + state = (struct at76c651_state*) kmalloc(sizeof(struct at76c651_state), GFP_KERNEL); + if (state == NULL) goto error; -} + /* setup the state */ + state->config = config; + state->qam = 0; -static int __init at76c651_init(void) -{ + /* check if the demod is there */ + if (at76c651_readreg(state, 0x0e) != 0x65) goto error; - return dvb_register_i2c_device(THIS_MODULE, at76c651_attach, - at76c651_detach); + /* finalise state setup */ + state->i2c = i2c; + state->revision = at76c651_readreg(state, 0x0f) & 0xfe; + memcpy(&state->ops, &at76c651_ops, sizeof(struct dvb_frontend_ops)); -} - -static void __exit at76c651_exit(void) -{ - - dvb_unregister_i2c_device(at76c651_attach); + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; +error: + if (state) kfree(state); + return NULL; } -module_init(at76c651_init); -module_exit(at76c651_exit); +static struct dvb_frontend_ops at76c651_ops = { + + .info = { + .name = "Atmel AT76C651B DVB-C", + .type = FE_QAM, + .frequency_min = 48250000, + .frequency_max = 863250000, + .frequency_stepsize = 62500, + /*.frequency_tolerance = */ /* FIXME: 12% of SR */ + .symbol_rate_min = 0, /* FIXME */ + .symbol_rate_max = 9360000, /* FIXME */ + .symbol_rate_tolerance = 4000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | + FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | + FE_CAN_MUTE_TS | FE_CAN_QAM_256 | FE_CAN_RECOVER + }, + + .release = at76c651_release, + + .init = at76c651_set_defaults, + + .set_frontend = at76c651_set_parameters, + .get_tune_settings = at76c651_get_tune_settings, + + .read_status = at76c651_read_status, + .read_ber = at76c651_read_ber, + .read_signal_strength = at76c651_read_signal_strength, + .read_snr = at76c651_read_snr, + .read_ucblocks = at76c651_read_ucblocks, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -MODULE_DESCRIPTION("at76c651/dat7021 dvb-c frontend driver"); +MODULE_DESCRIPTION("Atmel AT76C651 DVB-C Demodulator Driver"); MODULE_AUTHOR("Andreas Oberritter "); MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); + +EXPORT_SYMBOL(at76c651_attach);