1*9a0bf528SMauro Carvalho Chehab /* 2*9a0bf528SMauro Carvalho Chehab driver for LSI L64781 COFDM demodulator 3*9a0bf528SMauro Carvalho Chehab 4*9a0bf528SMauro Carvalho Chehab Copyright (C) 2001 Holger Waechtler for Convergence Integrated Media GmbH 5*9a0bf528SMauro Carvalho Chehab Marko Kohtala <marko.kohtala@luukku.com> 6*9a0bf528SMauro Carvalho Chehab 7*9a0bf528SMauro Carvalho Chehab This program is free software; you can redistribute it and/or modify 8*9a0bf528SMauro Carvalho Chehab it under the terms of the GNU General Public License as published by 9*9a0bf528SMauro Carvalho Chehab the Free Software Foundation; either version 2 of the License, or 10*9a0bf528SMauro Carvalho Chehab (at your option) any later version. 11*9a0bf528SMauro Carvalho Chehab 12*9a0bf528SMauro Carvalho Chehab This program is distributed in the hope that it will be useful, 13*9a0bf528SMauro Carvalho Chehab but WITHOUT ANY WARRANTY; without even the implied warranty of 14*9a0bf528SMauro Carvalho Chehab MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*9a0bf528SMauro Carvalho Chehab GNU General Public License for more details. 16*9a0bf528SMauro Carvalho Chehab 17*9a0bf528SMauro Carvalho Chehab You should have received a copy of the GNU General Public License 18*9a0bf528SMauro Carvalho Chehab along with this program; if not, write to the Free Software 19*9a0bf528SMauro Carvalho Chehab Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20*9a0bf528SMauro Carvalho Chehab 21*9a0bf528SMauro Carvalho Chehab */ 22*9a0bf528SMauro Carvalho Chehab 23*9a0bf528SMauro Carvalho Chehab #include <linux/init.h> 24*9a0bf528SMauro Carvalho Chehab #include <linux/kernel.h> 25*9a0bf528SMauro Carvalho Chehab #include <linux/module.h> 26*9a0bf528SMauro Carvalho Chehab #include <linux/string.h> 27*9a0bf528SMauro Carvalho Chehab #include <linux/slab.h> 28*9a0bf528SMauro Carvalho Chehab #include "dvb_frontend.h" 29*9a0bf528SMauro Carvalho Chehab #include "l64781.h" 30*9a0bf528SMauro Carvalho Chehab 31*9a0bf528SMauro Carvalho Chehab 32*9a0bf528SMauro Carvalho Chehab struct l64781_state { 33*9a0bf528SMauro Carvalho Chehab struct i2c_adapter* i2c; 34*9a0bf528SMauro Carvalho Chehab const struct l64781_config* config; 35*9a0bf528SMauro Carvalho Chehab struct dvb_frontend frontend; 36*9a0bf528SMauro Carvalho Chehab 37*9a0bf528SMauro Carvalho Chehab /* private demodulator data */ 38*9a0bf528SMauro Carvalho Chehab unsigned int first:1; 39*9a0bf528SMauro Carvalho Chehab }; 40*9a0bf528SMauro Carvalho Chehab 41*9a0bf528SMauro Carvalho Chehab #define dprintk(args...) \ 42*9a0bf528SMauro Carvalho Chehab do { \ 43*9a0bf528SMauro Carvalho Chehab if (debug) printk(KERN_DEBUG "l64781: " args); \ 44*9a0bf528SMauro Carvalho Chehab } while (0) 45*9a0bf528SMauro Carvalho Chehab 46*9a0bf528SMauro Carvalho Chehab static int debug; 47*9a0bf528SMauro Carvalho Chehab 48*9a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644); 49*9a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); 50*9a0bf528SMauro Carvalho Chehab 51*9a0bf528SMauro Carvalho Chehab 52*9a0bf528SMauro Carvalho Chehab static int l64781_writereg (struct l64781_state* state, u8 reg, u8 data) 53*9a0bf528SMauro Carvalho Chehab { 54*9a0bf528SMauro Carvalho Chehab int ret; 55*9a0bf528SMauro Carvalho Chehab u8 buf [] = { reg, data }; 56*9a0bf528SMauro Carvalho Chehab struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; 57*9a0bf528SMauro Carvalho Chehab 58*9a0bf528SMauro Carvalho Chehab if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) 59*9a0bf528SMauro Carvalho Chehab dprintk ("%s: write_reg error (reg == %02x) = %02x!\n", 60*9a0bf528SMauro Carvalho Chehab __func__, reg, ret); 61*9a0bf528SMauro Carvalho Chehab 62*9a0bf528SMauro Carvalho Chehab return (ret != 1) ? -1 : 0; 63*9a0bf528SMauro Carvalho Chehab } 64*9a0bf528SMauro Carvalho Chehab 65*9a0bf528SMauro Carvalho Chehab static int l64781_readreg (struct l64781_state* state, u8 reg) 66*9a0bf528SMauro Carvalho Chehab { 67*9a0bf528SMauro Carvalho Chehab int ret; 68*9a0bf528SMauro Carvalho Chehab u8 b0 [] = { reg }; 69*9a0bf528SMauro Carvalho Chehab u8 b1 [] = { 0 }; 70*9a0bf528SMauro Carvalho Chehab struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, 71*9a0bf528SMauro Carvalho Chehab { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; 72*9a0bf528SMauro Carvalho Chehab 73*9a0bf528SMauro Carvalho Chehab ret = i2c_transfer(state->i2c, msg, 2); 74*9a0bf528SMauro Carvalho Chehab 75*9a0bf528SMauro Carvalho Chehab if (ret != 2) return ret; 76*9a0bf528SMauro Carvalho Chehab 77*9a0bf528SMauro Carvalho Chehab return b1[0]; 78*9a0bf528SMauro Carvalho Chehab } 79*9a0bf528SMauro Carvalho Chehab 80*9a0bf528SMauro Carvalho Chehab static void apply_tps (struct l64781_state* state) 81*9a0bf528SMauro Carvalho Chehab { 82*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x2a, 0x00); 83*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x2a, 0x01); 84*9a0bf528SMauro Carvalho Chehab 85*9a0bf528SMauro Carvalho Chehab /* This here is a little bit questionable because it enables 86*9a0bf528SMauro Carvalho Chehab the automatic update of TPS registers. I think we'd need to 87*9a0bf528SMauro Carvalho Chehab handle the IRQ from FE to update some other registers as 88*9a0bf528SMauro Carvalho Chehab well, or at least implement some magic to tuning to correct 89*9a0bf528SMauro Carvalho Chehab to the TPS received from transmission. */ 90*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x2a, 0x02); 91*9a0bf528SMauro Carvalho Chehab } 92*9a0bf528SMauro Carvalho Chehab 93*9a0bf528SMauro Carvalho Chehab 94*9a0bf528SMauro Carvalho Chehab static void reset_afc (struct l64781_state* state) 95*9a0bf528SMauro Carvalho Chehab { 96*9a0bf528SMauro Carvalho Chehab /* Set AFC stall for the AFC_INIT_FRQ setting, TIM_STALL for 97*9a0bf528SMauro Carvalho Chehab timing offset */ 98*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x07, 0x9e); /* stall AFC */ 99*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x08, 0); /* AFC INIT FREQ */ 100*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x09, 0); 101*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x0a, 0); 102*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x07, 0x8e); 103*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x0e, 0); /* AGC gain to zero in beginning */ 104*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x11, 0x80); /* stall TIM */ 105*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x10, 0); /* TIM_OFFSET_LSB */ 106*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x12, 0); 107*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x13, 0); 108*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x11, 0x00); 109*9a0bf528SMauro Carvalho Chehab } 110*9a0bf528SMauro Carvalho Chehab 111*9a0bf528SMauro Carvalho Chehab static int reset_and_configure (struct l64781_state* state) 112*9a0bf528SMauro Carvalho Chehab { 113*9a0bf528SMauro Carvalho Chehab u8 buf [] = { 0x06 }; 114*9a0bf528SMauro Carvalho Chehab struct i2c_msg msg = { .addr = 0x00, .flags = 0, .buf = buf, .len = 1 }; 115*9a0bf528SMauro Carvalho Chehab // NOTE: this is correct in writing to address 0x00 116*9a0bf528SMauro Carvalho Chehab 117*9a0bf528SMauro Carvalho Chehab return (i2c_transfer(state->i2c, &msg, 1) == 1) ? 0 : -ENODEV; 118*9a0bf528SMauro Carvalho Chehab } 119*9a0bf528SMauro Carvalho Chehab 120*9a0bf528SMauro Carvalho Chehab static int apply_frontend_param(struct dvb_frontend *fe) 121*9a0bf528SMauro Carvalho Chehab { 122*9a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *p = &fe->dtv_property_cache; 123*9a0bf528SMauro Carvalho Chehab struct l64781_state* state = fe->demodulator_priv; 124*9a0bf528SMauro Carvalho Chehab /* The coderates for FEC_NONE, FEC_4_5 and FEC_FEC_6_7 are arbitrary */ 125*9a0bf528SMauro Carvalho Chehab static const u8 fec_tab[] = { 7, 0, 1, 2, 9, 3, 10, 4 }; 126*9a0bf528SMauro Carvalho Chehab /* QPSK, QAM_16, QAM_64 */ 127*9a0bf528SMauro Carvalho Chehab static const u8 qam_tab [] = { 2, 4, 0, 6 }; 128*9a0bf528SMauro Carvalho Chehab static const u8 guard_tab [] = { 1, 2, 4, 8 }; 129*9a0bf528SMauro Carvalho Chehab /* The Grundig 29504-401.04 Tuner comes with 18.432MHz crystal. */ 130*9a0bf528SMauro Carvalho Chehab static const u32 ppm = 8000; 131*9a0bf528SMauro Carvalho Chehab u32 ddfs_offset_fixed; 132*9a0bf528SMauro Carvalho Chehab /* u32 ddfs_offset_variable = 0x6000-((1000000UL+ppm)/ */ 133*9a0bf528SMauro Carvalho Chehab /* bw_tab[p->bandWidth]<<10)/15625; */ 134*9a0bf528SMauro Carvalho Chehab u32 init_freq; 135*9a0bf528SMauro Carvalho Chehab u32 spi_bias; 136*9a0bf528SMauro Carvalho Chehab u8 val0x04; 137*9a0bf528SMauro Carvalho Chehab u8 val0x05; 138*9a0bf528SMauro Carvalho Chehab u8 val0x06; 139*9a0bf528SMauro Carvalho Chehab int bw; 140*9a0bf528SMauro Carvalho Chehab 141*9a0bf528SMauro Carvalho Chehab switch (p->bandwidth_hz) { 142*9a0bf528SMauro Carvalho Chehab case 8000000: 143*9a0bf528SMauro Carvalho Chehab bw = 8; 144*9a0bf528SMauro Carvalho Chehab break; 145*9a0bf528SMauro Carvalho Chehab case 7000000: 146*9a0bf528SMauro Carvalho Chehab bw = 7; 147*9a0bf528SMauro Carvalho Chehab break; 148*9a0bf528SMauro Carvalho Chehab case 6000000: 149*9a0bf528SMauro Carvalho Chehab bw = 6; 150*9a0bf528SMauro Carvalho Chehab break; 151*9a0bf528SMauro Carvalho Chehab default: 152*9a0bf528SMauro Carvalho Chehab return -EINVAL; 153*9a0bf528SMauro Carvalho Chehab } 154*9a0bf528SMauro Carvalho Chehab 155*9a0bf528SMauro Carvalho Chehab if (fe->ops.tuner_ops.set_params) { 156*9a0bf528SMauro Carvalho Chehab fe->ops.tuner_ops.set_params(fe); 157*9a0bf528SMauro Carvalho Chehab if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); 158*9a0bf528SMauro Carvalho Chehab } 159*9a0bf528SMauro Carvalho Chehab 160*9a0bf528SMauro Carvalho Chehab if (p->inversion != INVERSION_ON && 161*9a0bf528SMauro Carvalho Chehab p->inversion != INVERSION_OFF) 162*9a0bf528SMauro Carvalho Chehab return -EINVAL; 163*9a0bf528SMauro Carvalho Chehab 164*9a0bf528SMauro Carvalho Chehab if (p->code_rate_HP != FEC_1_2 && p->code_rate_HP != FEC_2_3 && 165*9a0bf528SMauro Carvalho Chehab p->code_rate_HP != FEC_3_4 && p->code_rate_HP != FEC_5_6 && 166*9a0bf528SMauro Carvalho Chehab p->code_rate_HP != FEC_7_8) 167*9a0bf528SMauro Carvalho Chehab return -EINVAL; 168*9a0bf528SMauro Carvalho Chehab 169*9a0bf528SMauro Carvalho Chehab if (p->hierarchy != HIERARCHY_NONE && 170*9a0bf528SMauro Carvalho Chehab (p->code_rate_LP != FEC_1_2 && p->code_rate_LP != FEC_2_3 && 171*9a0bf528SMauro Carvalho Chehab p->code_rate_LP != FEC_3_4 && p->code_rate_LP != FEC_5_6 && 172*9a0bf528SMauro Carvalho Chehab p->code_rate_LP != FEC_7_8)) 173*9a0bf528SMauro Carvalho Chehab return -EINVAL; 174*9a0bf528SMauro Carvalho Chehab 175*9a0bf528SMauro Carvalho Chehab if (p->modulation != QPSK && p->modulation != QAM_16 && 176*9a0bf528SMauro Carvalho Chehab p->modulation != QAM_64) 177*9a0bf528SMauro Carvalho Chehab return -EINVAL; 178*9a0bf528SMauro Carvalho Chehab 179*9a0bf528SMauro Carvalho Chehab if (p->transmission_mode != TRANSMISSION_MODE_2K && 180*9a0bf528SMauro Carvalho Chehab p->transmission_mode != TRANSMISSION_MODE_8K) 181*9a0bf528SMauro Carvalho Chehab return -EINVAL; 182*9a0bf528SMauro Carvalho Chehab 183*9a0bf528SMauro Carvalho Chehab if (p->guard_interval < GUARD_INTERVAL_1_32 || 184*9a0bf528SMauro Carvalho Chehab p->guard_interval > GUARD_INTERVAL_1_4) 185*9a0bf528SMauro Carvalho Chehab return -EINVAL; 186*9a0bf528SMauro Carvalho Chehab 187*9a0bf528SMauro Carvalho Chehab if (p->hierarchy < HIERARCHY_NONE || 188*9a0bf528SMauro Carvalho Chehab p->hierarchy > HIERARCHY_4) 189*9a0bf528SMauro Carvalho Chehab return -EINVAL; 190*9a0bf528SMauro Carvalho Chehab 191*9a0bf528SMauro Carvalho Chehab ddfs_offset_fixed = 0x4000-(ppm<<16)/bw/1000000; 192*9a0bf528SMauro Carvalho Chehab 193*9a0bf528SMauro Carvalho Chehab /* This works up to 20000 ppm, it overflows if too large ppm! */ 194*9a0bf528SMauro Carvalho Chehab init_freq = (((8UL<<25) + (8UL<<19) / 25*ppm / (15625/25)) / 195*9a0bf528SMauro Carvalho Chehab bw & 0xFFFFFF); 196*9a0bf528SMauro Carvalho Chehab 197*9a0bf528SMauro Carvalho Chehab /* SPI bias calculation is slightly modified to fit in 32bit */ 198*9a0bf528SMauro Carvalho Chehab /* will work for high ppm only... */ 199*9a0bf528SMauro Carvalho Chehab spi_bias = 378 * (1 << 10); 200*9a0bf528SMauro Carvalho Chehab spi_bias *= 16; 201*9a0bf528SMauro Carvalho Chehab spi_bias *= bw; 202*9a0bf528SMauro Carvalho Chehab spi_bias *= qam_tab[p->modulation]; 203*9a0bf528SMauro Carvalho Chehab spi_bias /= p->code_rate_HP + 1; 204*9a0bf528SMauro Carvalho Chehab spi_bias /= (guard_tab[p->guard_interval] + 32); 205*9a0bf528SMauro Carvalho Chehab spi_bias *= 1000; 206*9a0bf528SMauro Carvalho Chehab spi_bias /= 1000 + ppm/1000; 207*9a0bf528SMauro Carvalho Chehab spi_bias *= p->code_rate_HP; 208*9a0bf528SMauro Carvalho Chehab 209*9a0bf528SMauro Carvalho Chehab val0x04 = (p->transmission_mode << 2) | p->guard_interval; 210*9a0bf528SMauro Carvalho Chehab val0x05 = fec_tab[p->code_rate_HP]; 211*9a0bf528SMauro Carvalho Chehab 212*9a0bf528SMauro Carvalho Chehab if (p->hierarchy != HIERARCHY_NONE) 213*9a0bf528SMauro Carvalho Chehab val0x05 |= (p->code_rate_LP - FEC_1_2) << 3; 214*9a0bf528SMauro Carvalho Chehab 215*9a0bf528SMauro Carvalho Chehab val0x06 = (p->hierarchy << 2) | p->modulation; 216*9a0bf528SMauro Carvalho Chehab 217*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x04, val0x04); 218*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x05, val0x05); 219*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x06, val0x06); 220*9a0bf528SMauro Carvalho Chehab 221*9a0bf528SMauro Carvalho Chehab reset_afc (state); 222*9a0bf528SMauro Carvalho Chehab 223*9a0bf528SMauro Carvalho Chehab /* Technical manual section 2.6.1, TIM_IIR_GAIN optimal values */ 224*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x15, 225*9a0bf528SMauro Carvalho Chehab p->transmission_mode == TRANSMISSION_MODE_2K ? 1 : 3); 226*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x16, init_freq & 0xff); 227*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x17, (init_freq >> 8) & 0xff); 228*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x18, (init_freq >> 16) & 0xff); 229*9a0bf528SMauro Carvalho Chehab 230*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x1b, spi_bias & 0xff); 231*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x1c, (spi_bias >> 8) & 0xff); 232*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x1d, ((spi_bias >> 16) & 0x7f) | 233*9a0bf528SMauro Carvalho Chehab (p->inversion == INVERSION_ON ? 0x80 : 0x00)); 234*9a0bf528SMauro Carvalho Chehab 235*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x22, ddfs_offset_fixed & 0xff); 236*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x23, (ddfs_offset_fixed >> 8) & 0x3f); 237*9a0bf528SMauro Carvalho Chehab 238*9a0bf528SMauro Carvalho Chehab l64781_readreg (state, 0x00); /* clear interrupt registers... */ 239*9a0bf528SMauro Carvalho Chehab l64781_readreg (state, 0x01); /* dto. */ 240*9a0bf528SMauro Carvalho Chehab 241*9a0bf528SMauro Carvalho Chehab apply_tps (state); 242*9a0bf528SMauro Carvalho Chehab 243*9a0bf528SMauro Carvalho Chehab return 0; 244*9a0bf528SMauro Carvalho Chehab } 245*9a0bf528SMauro Carvalho Chehab 246*9a0bf528SMauro Carvalho Chehab static int get_frontend(struct dvb_frontend *fe) 247*9a0bf528SMauro Carvalho Chehab { 248*9a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *p = &fe->dtv_property_cache; 249*9a0bf528SMauro Carvalho Chehab struct l64781_state* state = fe->demodulator_priv; 250*9a0bf528SMauro Carvalho Chehab int tmp; 251*9a0bf528SMauro Carvalho Chehab 252*9a0bf528SMauro Carvalho Chehab 253*9a0bf528SMauro Carvalho Chehab tmp = l64781_readreg(state, 0x04); 254*9a0bf528SMauro Carvalho Chehab switch(tmp & 3) { 255*9a0bf528SMauro Carvalho Chehab case 0: 256*9a0bf528SMauro Carvalho Chehab p->guard_interval = GUARD_INTERVAL_1_32; 257*9a0bf528SMauro Carvalho Chehab break; 258*9a0bf528SMauro Carvalho Chehab case 1: 259*9a0bf528SMauro Carvalho Chehab p->guard_interval = GUARD_INTERVAL_1_16; 260*9a0bf528SMauro Carvalho Chehab break; 261*9a0bf528SMauro Carvalho Chehab case 2: 262*9a0bf528SMauro Carvalho Chehab p->guard_interval = GUARD_INTERVAL_1_8; 263*9a0bf528SMauro Carvalho Chehab break; 264*9a0bf528SMauro Carvalho Chehab case 3: 265*9a0bf528SMauro Carvalho Chehab p->guard_interval = GUARD_INTERVAL_1_4; 266*9a0bf528SMauro Carvalho Chehab break; 267*9a0bf528SMauro Carvalho Chehab } 268*9a0bf528SMauro Carvalho Chehab switch((tmp >> 2) & 3) { 269*9a0bf528SMauro Carvalho Chehab case 0: 270*9a0bf528SMauro Carvalho Chehab p->transmission_mode = TRANSMISSION_MODE_2K; 271*9a0bf528SMauro Carvalho Chehab break; 272*9a0bf528SMauro Carvalho Chehab case 1: 273*9a0bf528SMauro Carvalho Chehab p->transmission_mode = TRANSMISSION_MODE_8K; 274*9a0bf528SMauro Carvalho Chehab break; 275*9a0bf528SMauro Carvalho Chehab default: 276*9a0bf528SMauro Carvalho Chehab printk(KERN_WARNING "Unexpected value for transmission_mode\n"); 277*9a0bf528SMauro Carvalho Chehab } 278*9a0bf528SMauro Carvalho Chehab 279*9a0bf528SMauro Carvalho Chehab tmp = l64781_readreg(state, 0x05); 280*9a0bf528SMauro Carvalho Chehab switch(tmp & 7) { 281*9a0bf528SMauro Carvalho Chehab case 0: 282*9a0bf528SMauro Carvalho Chehab p->code_rate_HP = FEC_1_2; 283*9a0bf528SMauro Carvalho Chehab break; 284*9a0bf528SMauro Carvalho Chehab case 1: 285*9a0bf528SMauro Carvalho Chehab p->code_rate_HP = FEC_2_3; 286*9a0bf528SMauro Carvalho Chehab break; 287*9a0bf528SMauro Carvalho Chehab case 2: 288*9a0bf528SMauro Carvalho Chehab p->code_rate_HP = FEC_3_4; 289*9a0bf528SMauro Carvalho Chehab break; 290*9a0bf528SMauro Carvalho Chehab case 3: 291*9a0bf528SMauro Carvalho Chehab p->code_rate_HP = FEC_5_6; 292*9a0bf528SMauro Carvalho Chehab break; 293*9a0bf528SMauro Carvalho Chehab case 4: 294*9a0bf528SMauro Carvalho Chehab p->code_rate_HP = FEC_7_8; 295*9a0bf528SMauro Carvalho Chehab break; 296*9a0bf528SMauro Carvalho Chehab default: 297*9a0bf528SMauro Carvalho Chehab printk("Unexpected value for code_rate_HP\n"); 298*9a0bf528SMauro Carvalho Chehab } 299*9a0bf528SMauro Carvalho Chehab switch((tmp >> 3) & 7) { 300*9a0bf528SMauro Carvalho Chehab case 0: 301*9a0bf528SMauro Carvalho Chehab p->code_rate_LP = FEC_1_2; 302*9a0bf528SMauro Carvalho Chehab break; 303*9a0bf528SMauro Carvalho Chehab case 1: 304*9a0bf528SMauro Carvalho Chehab p->code_rate_LP = FEC_2_3; 305*9a0bf528SMauro Carvalho Chehab break; 306*9a0bf528SMauro Carvalho Chehab case 2: 307*9a0bf528SMauro Carvalho Chehab p->code_rate_LP = FEC_3_4; 308*9a0bf528SMauro Carvalho Chehab break; 309*9a0bf528SMauro Carvalho Chehab case 3: 310*9a0bf528SMauro Carvalho Chehab p->code_rate_LP = FEC_5_6; 311*9a0bf528SMauro Carvalho Chehab break; 312*9a0bf528SMauro Carvalho Chehab case 4: 313*9a0bf528SMauro Carvalho Chehab p->code_rate_LP = FEC_7_8; 314*9a0bf528SMauro Carvalho Chehab break; 315*9a0bf528SMauro Carvalho Chehab default: 316*9a0bf528SMauro Carvalho Chehab printk("Unexpected value for code_rate_LP\n"); 317*9a0bf528SMauro Carvalho Chehab } 318*9a0bf528SMauro Carvalho Chehab 319*9a0bf528SMauro Carvalho Chehab tmp = l64781_readreg(state, 0x06); 320*9a0bf528SMauro Carvalho Chehab switch(tmp & 3) { 321*9a0bf528SMauro Carvalho Chehab case 0: 322*9a0bf528SMauro Carvalho Chehab p->modulation = QPSK; 323*9a0bf528SMauro Carvalho Chehab break; 324*9a0bf528SMauro Carvalho Chehab case 1: 325*9a0bf528SMauro Carvalho Chehab p->modulation = QAM_16; 326*9a0bf528SMauro Carvalho Chehab break; 327*9a0bf528SMauro Carvalho Chehab case 2: 328*9a0bf528SMauro Carvalho Chehab p->modulation = QAM_64; 329*9a0bf528SMauro Carvalho Chehab break; 330*9a0bf528SMauro Carvalho Chehab default: 331*9a0bf528SMauro Carvalho Chehab printk(KERN_WARNING "Unexpected value for modulation\n"); 332*9a0bf528SMauro Carvalho Chehab } 333*9a0bf528SMauro Carvalho Chehab switch((tmp >> 2) & 7) { 334*9a0bf528SMauro Carvalho Chehab case 0: 335*9a0bf528SMauro Carvalho Chehab p->hierarchy = HIERARCHY_NONE; 336*9a0bf528SMauro Carvalho Chehab break; 337*9a0bf528SMauro Carvalho Chehab case 1: 338*9a0bf528SMauro Carvalho Chehab p->hierarchy = HIERARCHY_1; 339*9a0bf528SMauro Carvalho Chehab break; 340*9a0bf528SMauro Carvalho Chehab case 2: 341*9a0bf528SMauro Carvalho Chehab p->hierarchy = HIERARCHY_2; 342*9a0bf528SMauro Carvalho Chehab break; 343*9a0bf528SMauro Carvalho Chehab case 3: 344*9a0bf528SMauro Carvalho Chehab p->hierarchy = HIERARCHY_4; 345*9a0bf528SMauro Carvalho Chehab break; 346*9a0bf528SMauro Carvalho Chehab default: 347*9a0bf528SMauro Carvalho Chehab printk("Unexpected value for hierarchy\n"); 348*9a0bf528SMauro Carvalho Chehab } 349*9a0bf528SMauro Carvalho Chehab 350*9a0bf528SMauro Carvalho Chehab 351*9a0bf528SMauro Carvalho Chehab tmp = l64781_readreg (state, 0x1d); 352*9a0bf528SMauro Carvalho Chehab p->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF; 353*9a0bf528SMauro Carvalho Chehab 354*9a0bf528SMauro Carvalho Chehab tmp = (int) (l64781_readreg (state, 0x08) | 355*9a0bf528SMauro Carvalho Chehab (l64781_readreg (state, 0x09) << 8) | 356*9a0bf528SMauro Carvalho Chehab (l64781_readreg (state, 0x0a) << 16)); 357*9a0bf528SMauro Carvalho Chehab p->frequency += tmp; 358*9a0bf528SMauro Carvalho Chehab 359*9a0bf528SMauro Carvalho Chehab return 0; 360*9a0bf528SMauro Carvalho Chehab } 361*9a0bf528SMauro Carvalho Chehab 362*9a0bf528SMauro Carvalho Chehab static int l64781_read_status(struct dvb_frontend* fe, fe_status_t* status) 363*9a0bf528SMauro Carvalho Chehab { 364*9a0bf528SMauro Carvalho Chehab struct l64781_state* state = fe->demodulator_priv; 365*9a0bf528SMauro Carvalho Chehab int sync = l64781_readreg (state, 0x32); 366*9a0bf528SMauro Carvalho Chehab int gain = l64781_readreg (state, 0x0e); 367*9a0bf528SMauro Carvalho Chehab 368*9a0bf528SMauro Carvalho Chehab l64781_readreg (state, 0x00); /* clear interrupt registers... */ 369*9a0bf528SMauro Carvalho Chehab l64781_readreg (state, 0x01); /* dto. */ 370*9a0bf528SMauro Carvalho Chehab 371*9a0bf528SMauro Carvalho Chehab *status = 0; 372*9a0bf528SMauro Carvalho Chehab 373*9a0bf528SMauro Carvalho Chehab if (gain > 5) 374*9a0bf528SMauro Carvalho Chehab *status |= FE_HAS_SIGNAL; 375*9a0bf528SMauro Carvalho Chehab 376*9a0bf528SMauro Carvalho Chehab if (sync & 0x02) /* VCXO locked, this criteria should be ok */ 377*9a0bf528SMauro Carvalho Chehab *status |= FE_HAS_CARRIER; 378*9a0bf528SMauro Carvalho Chehab 379*9a0bf528SMauro Carvalho Chehab if (sync & 0x20) 380*9a0bf528SMauro Carvalho Chehab *status |= FE_HAS_VITERBI; 381*9a0bf528SMauro Carvalho Chehab 382*9a0bf528SMauro Carvalho Chehab if (sync & 0x40) 383*9a0bf528SMauro Carvalho Chehab *status |= FE_HAS_SYNC; 384*9a0bf528SMauro Carvalho Chehab 385*9a0bf528SMauro Carvalho Chehab if (sync == 0x7f) 386*9a0bf528SMauro Carvalho Chehab *status |= FE_HAS_LOCK; 387*9a0bf528SMauro Carvalho Chehab 388*9a0bf528SMauro Carvalho Chehab return 0; 389*9a0bf528SMauro Carvalho Chehab } 390*9a0bf528SMauro Carvalho Chehab 391*9a0bf528SMauro Carvalho Chehab static int l64781_read_ber(struct dvb_frontend* fe, u32* ber) 392*9a0bf528SMauro Carvalho Chehab { 393*9a0bf528SMauro Carvalho Chehab struct l64781_state* state = fe->demodulator_priv; 394*9a0bf528SMauro Carvalho Chehab 395*9a0bf528SMauro Carvalho Chehab /* XXX FIXME: set up counting period (reg 0x26...0x28) 396*9a0bf528SMauro Carvalho Chehab */ 397*9a0bf528SMauro Carvalho Chehab *ber = l64781_readreg (state, 0x39) 398*9a0bf528SMauro Carvalho Chehab | (l64781_readreg (state, 0x3a) << 8); 399*9a0bf528SMauro Carvalho Chehab 400*9a0bf528SMauro Carvalho Chehab return 0; 401*9a0bf528SMauro Carvalho Chehab } 402*9a0bf528SMauro Carvalho Chehab 403*9a0bf528SMauro Carvalho Chehab static int l64781_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) 404*9a0bf528SMauro Carvalho Chehab { 405*9a0bf528SMauro Carvalho Chehab struct l64781_state* state = fe->demodulator_priv; 406*9a0bf528SMauro Carvalho Chehab 407*9a0bf528SMauro Carvalho Chehab u8 gain = l64781_readreg (state, 0x0e); 408*9a0bf528SMauro Carvalho Chehab *signal_strength = (gain << 8) | gain; 409*9a0bf528SMauro Carvalho Chehab 410*9a0bf528SMauro Carvalho Chehab return 0; 411*9a0bf528SMauro Carvalho Chehab } 412*9a0bf528SMauro Carvalho Chehab 413*9a0bf528SMauro Carvalho Chehab static int l64781_read_snr(struct dvb_frontend* fe, u16* snr) 414*9a0bf528SMauro Carvalho Chehab { 415*9a0bf528SMauro Carvalho Chehab struct l64781_state* state = fe->demodulator_priv; 416*9a0bf528SMauro Carvalho Chehab 417*9a0bf528SMauro Carvalho Chehab u8 avg_quality = 0xff - l64781_readreg (state, 0x33); 418*9a0bf528SMauro Carvalho Chehab *snr = (avg_quality << 8) | avg_quality; /* not exact, but...*/ 419*9a0bf528SMauro Carvalho Chehab 420*9a0bf528SMauro Carvalho Chehab return 0; 421*9a0bf528SMauro Carvalho Chehab } 422*9a0bf528SMauro Carvalho Chehab 423*9a0bf528SMauro Carvalho Chehab static int l64781_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) 424*9a0bf528SMauro Carvalho Chehab { 425*9a0bf528SMauro Carvalho Chehab struct l64781_state* state = fe->demodulator_priv; 426*9a0bf528SMauro Carvalho Chehab 427*9a0bf528SMauro Carvalho Chehab *ucblocks = l64781_readreg (state, 0x37) 428*9a0bf528SMauro Carvalho Chehab | (l64781_readreg (state, 0x38) << 8); 429*9a0bf528SMauro Carvalho Chehab 430*9a0bf528SMauro Carvalho Chehab return 0; 431*9a0bf528SMauro Carvalho Chehab } 432*9a0bf528SMauro Carvalho Chehab 433*9a0bf528SMauro Carvalho Chehab static int l64781_sleep(struct dvb_frontend* fe) 434*9a0bf528SMauro Carvalho Chehab { 435*9a0bf528SMauro Carvalho Chehab struct l64781_state* state = fe->demodulator_priv; 436*9a0bf528SMauro Carvalho Chehab 437*9a0bf528SMauro Carvalho Chehab /* Power down */ 438*9a0bf528SMauro Carvalho Chehab return l64781_writereg (state, 0x3e, 0x5a); 439*9a0bf528SMauro Carvalho Chehab } 440*9a0bf528SMauro Carvalho Chehab 441*9a0bf528SMauro Carvalho Chehab static int l64781_init(struct dvb_frontend* fe) 442*9a0bf528SMauro Carvalho Chehab { 443*9a0bf528SMauro Carvalho Chehab struct l64781_state* state = fe->demodulator_priv; 444*9a0bf528SMauro Carvalho Chehab 445*9a0bf528SMauro Carvalho Chehab reset_and_configure (state); 446*9a0bf528SMauro Carvalho Chehab 447*9a0bf528SMauro Carvalho Chehab /* Power up */ 448*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x3e, 0xa5); 449*9a0bf528SMauro Carvalho Chehab 450*9a0bf528SMauro Carvalho Chehab /* Reset hard */ 451*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x2a, 0x04); 452*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x2a, 0x00); 453*9a0bf528SMauro Carvalho Chehab 454*9a0bf528SMauro Carvalho Chehab /* Set tuner specific things */ 455*9a0bf528SMauro Carvalho Chehab /* AFC_POL, set also in reset_afc */ 456*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x07, 0x8e); 457*9a0bf528SMauro Carvalho Chehab 458*9a0bf528SMauro Carvalho Chehab /* Use internal ADC */ 459*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x0b, 0x81); 460*9a0bf528SMauro Carvalho Chehab 461*9a0bf528SMauro Carvalho Chehab /* AGC loop gain, and polarity is positive */ 462*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x0c, 0x84); 463*9a0bf528SMauro Carvalho Chehab 464*9a0bf528SMauro Carvalho Chehab /* Internal ADC outputs two's complement */ 465*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x0d, 0x8c); 466*9a0bf528SMauro Carvalho Chehab 467*9a0bf528SMauro Carvalho Chehab /* With ppm=8000, it seems the DTR_SENSITIVITY will result in 468*9a0bf528SMauro Carvalho Chehab value of 2 with all possible bandwidths and guard 469*9a0bf528SMauro Carvalho Chehab intervals, which is the initial value anyway. */ 470*9a0bf528SMauro Carvalho Chehab /*l64781_writereg (state, 0x19, 0x92);*/ 471*9a0bf528SMauro Carvalho Chehab 472*9a0bf528SMauro Carvalho Chehab /* Everything is two's complement, soft bit and CSI_OUT too */ 473*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x1e, 0x09); 474*9a0bf528SMauro Carvalho Chehab 475*9a0bf528SMauro Carvalho Chehab /* delay a bit after first init attempt */ 476*9a0bf528SMauro Carvalho Chehab if (state->first) { 477*9a0bf528SMauro Carvalho Chehab state->first = 0; 478*9a0bf528SMauro Carvalho Chehab msleep(200); 479*9a0bf528SMauro Carvalho Chehab } 480*9a0bf528SMauro Carvalho Chehab 481*9a0bf528SMauro Carvalho Chehab return 0; 482*9a0bf528SMauro Carvalho Chehab } 483*9a0bf528SMauro Carvalho Chehab 484*9a0bf528SMauro Carvalho Chehab static int l64781_get_tune_settings(struct dvb_frontend* fe, 485*9a0bf528SMauro Carvalho Chehab struct dvb_frontend_tune_settings* fesettings) 486*9a0bf528SMauro Carvalho Chehab { 487*9a0bf528SMauro Carvalho Chehab fesettings->min_delay_ms = 4000; 488*9a0bf528SMauro Carvalho Chehab fesettings->step_size = 0; 489*9a0bf528SMauro Carvalho Chehab fesettings->max_drift = 0; 490*9a0bf528SMauro Carvalho Chehab return 0; 491*9a0bf528SMauro Carvalho Chehab } 492*9a0bf528SMauro Carvalho Chehab 493*9a0bf528SMauro Carvalho Chehab static void l64781_release(struct dvb_frontend* fe) 494*9a0bf528SMauro Carvalho Chehab { 495*9a0bf528SMauro Carvalho Chehab struct l64781_state* state = fe->demodulator_priv; 496*9a0bf528SMauro Carvalho Chehab kfree(state); 497*9a0bf528SMauro Carvalho Chehab } 498*9a0bf528SMauro Carvalho Chehab 499*9a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops l64781_ops; 500*9a0bf528SMauro Carvalho Chehab 501*9a0bf528SMauro Carvalho Chehab struct dvb_frontend* l64781_attach(const struct l64781_config* config, 502*9a0bf528SMauro Carvalho Chehab struct i2c_adapter* i2c) 503*9a0bf528SMauro Carvalho Chehab { 504*9a0bf528SMauro Carvalho Chehab struct l64781_state* state = NULL; 505*9a0bf528SMauro Carvalho Chehab int reg0x3e = -1; 506*9a0bf528SMauro Carvalho Chehab u8 b0 [] = { 0x1a }; 507*9a0bf528SMauro Carvalho Chehab u8 b1 [] = { 0x00 }; 508*9a0bf528SMauro Carvalho Chehab struct i2c_msg msg [] = { { .addr = config->demod_address, .flags = 0, .buf = b0, .len = 1 }, 509*9a0bf528SMauro Carvalho Chehab { .addr = config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; 510*9a0bf528SMauro Carvalho Chehab 511*9a0bf528SMauro Carvalho Chehab /* allocate memory for the internal state */ 512*9a0bf528SMauro Carvalho Chehab state = kzalloc(sizeof(struct l64781_state), GFP_KERNEL); 513*9a0bf528SMauro Carvalho Chehab if (state == NULL) goto error; 514*9a0bf528SMauro Carvalho Chehab 515*9a0bf528SMauro Carvalho Chehab /* setup the state */ 516*9a0bf528SMauro Carvalho Chehab state->config = config; 517*9a0bf528SMauro Carvalho Chehab state->i2c = i2c; 518*9a0bf528SMauro Carvalho Chehab state->first = 1; 519*9a0bf528SMauro Carvalho Chehab 520*9a0bf528SMauro Carvalho Chehab /** 521*9a0bf528SMauro Carvalho Chehab * the L64781 won't show up before we send the reset_and_configure() 522*9a0bf528SMauro Carvalho Chehab * broadcast. If nothing responds there is no L64781 on the bus... 523*9a0bf528SMauro Carvalho Chehab */ 524*9a0bf528SMauro Carvalho Chehab if (reset_and_configure(state) < 0) { 525*9a0bf528SMauro Carvalho Chehab dprintk("No response to reset and configure broadcast...\n"); 526*9a0bf528SMauro Carvalho Chehab goto error; 527*9a0bf528SMauro Carvalho Chehab } 528*9a0bf528SMauro Carvalho Chehab 529*9a0bf528SMauro Carvalho Chehab /* The chip always responds to reads */ 530*9a0bf528SMauro Carvalho Chehab if (i2c_transfer(state->i2c, msg, 2) != 2) { 531*9a0bf528SMauro Carvalho Chehab dprintk("No response to read on I2C bus\n"); 532*9a0bf528SMauro Carvalho Chehab goto error; 533*9a0bf528SMauro Carvalho Chehab } 534*9a0bf528SMauro Carvalho Chehab 535*9a0bf528SMauro Carvalho Chehab /* Save current register contents for bailout */ 536*9a0bf528SMauro Carvalho Chehab reg0x3e = l64781_readreg(state, 0x3e); 537*9a0bf528SMauro Carvalho Chehab 538*9a0bf528SMauro Carvalho Chehab /* Reading the POWER_DOWN register always returns 0 */ 539*9a0bf528SMauro Carvalho Chehab if (reg0x3e != 0) { 540*9a0bf528SMauro Carvalho Chehab dprintk("Device doesn't look like L64781\n"); 541*9a0bf528SMauro Carvalho Chehab goto error; 542*9a0bf528SMauro Carvalho Chehab } 543*9a0bf528SMauro Carvalho Chehab 544*9a0bf528SMauro Carvalho Chehab /* Turn the chip off */ 545*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x3e, 0x5a); 546*9a0bf528SMauro Carvalho Chehab 547*9a0bf528SMauro Carvalho Chehab /* Responds to all reads with 0 */ 548*9a0bf528SMauro Carvalho Chehab if (l64781_readreg(state, 0x1a) != 0) { 549*9a0bf528SMauro Carvalho Chehab dprintk("Read 1 returned unexpcted value\n"); 550*9a0bf528SMauro Carvalho Chehab goto error; 551*9a0bf528SMauro Carvalho Chehab } 552*9a0bf528SMauro Carvalho Chehab 553*9a0bf528SMauro Carvalho Chehab /* Turn the chip on */ 554*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x3e, 0xa5); 555*9a0bf528SMauro Carvalho Chehab 556*9a0bf528SMauro Carvalho Chehab /* Responds with register default value */ 557*9a0bf528SMauro Carvalho Chehab if (l64781_readreg(state, 0x1a) != 0xa1) { 558*9a0bf528SMauro Carvalho Chehab dprintk("Read 2 returned unexpcted value\n"); 559*9a0bf528SMauro Carvalho Chehab goto error; 560*9a0bf528SMauro Carvalho Chehab } 561*9a0bf528SMauro Carvalho Chehab 562*9a0bf528SMauro Carvalho Chehab /* create dvb_frontend */ 563*9a0bf528SMauro Carvalho Chehab memcpy(&state->frontend.ops, &l64781_ops, sizeof(struct dvb_frontend_ops)); 564*9a0bf528SMauro Carvalho Chehab state->frontend.demodulator_priv = state; 565*9a0bf528SMauro Carvalho Chehab return &state->frontend; 566*9a0bf528SMauro Carvalho Chehab 567*9a0bf528SMauro Carvalho Chehab error: 568*9a0bf528SMauro Carvalho Chehab if (reg0x3e >= 0) 569*9a0bf528SMauro Carvalho Chehab l64781_writereg (state, 0x3e, reg0x3e); /* restore reg 0x3e */ 570*9a0bf528SMauro Carvalho Chehab kfree(state); 571*9a0bf528SMauro Carvalho Chehab return NULL; 572*9a0bf528SMauro Carvalho Chehab } 573*9a0bf528SMauro Carvalho Chehab 574*9a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops l64781_ops = { 575*9a0bf528SMauro Carvalho Chehab .delsys = { SYS_DVBT }, 576*9a0bf528SMauro Carvalho Chehab .info = { 577*9a0bf528SMauro Carvalho Chehab .name = "LSI L64781 DVB-T", 578*9a0bf528SMauro Carvalho Chehab /* .frequency_min = ???,*/ 579*9a0bf528SMauro Carvalho Chehab /* .frequency_max = ???,*/ 580*9a0bf528SMauro Carvalho Chehab .frequency_stepsize = 166666, 581*9a0bf528SMauro Carvalho Chehab /* .frequency_tolerance = ???,*/ 582*9a0bf528SMauro Carvalho Chehab /* .symbol_rate_tolerance = ???,*/ 583*9a0bf528SMauro Carvalho Chehab .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 584*9a0bf528SMauro Carvalho Chehab FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | 585*9a0bf528SMauro Carvalho Chehab FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | 586*9a0bf528SMauro Carvalho Chehab FE_CAN_MUTE_TS 587*9a0bf528SMauro Carvalho Chehab }, 588*9a0bf528SMauro Carvalho Chehab 589*9a0bf528SMauro Carvalho Chehab .release = l64781_release, 590*9a0bf528SMauro Carvalho Chehab 591*9a0bf528SMauro Carvalho Chehab .init = l64781_init, 592*9a0bf528SMauro Carvalho Chehab .sleep = l64781_sleep, 593*9a0bf528SMauro Carvalho Chehab 594*9a0bf528SMauro Carvalho Chehab .set_frontend = apply_frontend_param, 595*9a0bf528SMauro Carvalho Chehab .get_frontend = get_frontend, 596*9a0bf528SMauro Carvalho Chehab .get_tune_settings = l64781_get_tune_settings, 597*9a0bf528SMauro Carvalho Chehab 598*9a0bf528SMauro Carvalho Chehab .read_status = l64781_read_status, 599*9a0bf528SMauro Carvalho Chehab .read_ber = l64781_read_ber, 600*9a0bf528SMauro Carvalho Chehab .read_signal_strength = l64781_read_signal_strength, 601*9a0bf528SMauro Carvalho Chehab .read_snr = l64781_read_snr, 602*9a0bf528SMauro Carvalho Chehab .read_ucblocks = l64781_read_ucblocks, 603*9a0bf528SMauro Carvalho Chehab }; 604*9a0bf528SMauro Carvalho Chehab 605*9a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("LSI L64781 DVB-T Demodulator driver"); 606*9a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Holger Waechtler, Marko Kohtala"); 607*9a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL"); 608*9a0bf528SMauro Carvalho Chehab 609*9a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(l64781_attach); 610