1*9a0bf528SMauro Carvalho Chehab /* 2*9a0bf528SMauro Carvalho Chehab Driver for STV0297 demodulator 3*9a0bf528SMauro Carvalho Chehab 4*9a0bf528SMauro Carvalho Chehab Copyright (C) 2004 Andrew de Quincey <adq_dvb@lidskialf.net> 5*9a0bf528SMauro Carvalho Chehab Copyright (C) 2003-2004 Dennis Noermann <dennis.noermann@noernet.de> 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 #include <linux/init.h> 23*9a0bf528SMauro Carvalho Chehab #include <linux/kernel.h> 24*9a0bf528SMauro Carvalho Chehab #include <linux/module.h> 25*9a0bf528SMauro Carvalho Chehab #include <linux/string.h> 26*9a0bf528SMauro Carvalho Chehab #include <linux/delay.h> 27*9a0bf528SMauro Carvalho Chehab #include <linux/jiffies.h> 28*9a0bf528SMauro Carvalho Chehab #include <linux/slab.h> 29*9a0bf528SMauro Carvalho Chehab 30*9a0bf528SMauro Carvalho Chehab #include "dvb_frontend.h" 31*9a0bf528SMauro Carvalho Chehab #include "stv0297.h" 32*9a0bf528SMauro Carvalho Chehab 33*9a0bf528SMauro Carvalho Chehab struct stv0297_state { 34*9a0bf528SMauro Carvalho Chehab struct i2c_adapter *i2c; 35*9a0bf528SMauro Carvalho Chehab const struct stv0297_config *config; 36*9a0bf528SMauro Carvalho Chehab struct dvb_frontend frontend; 37*9a0bf528SMauro Carvalho Chehab 38*9a0bf528SMauro Carvalho Chehab unsigned long last_ber; 39*9a0bf528SMauro Carvalho Chehab unsigned long base_freq; 40*9a0bf528SMauro Carvalho Chehab }; 41*9a0bf528SMauro Carvalho Chehab 42*9a0bf528SMauro Carvalho Chehab #if 1 43*9a0bf528SMauro Carvalho Chehab #define dprintk(x...) printk(x) 44*9a0bf528SMauro Carvalho Chehab #else 45*9a0bf528SMauro Carvalho Chehab #define dprintk(x...) 46*9a0bf528SMauro Carvalho Chehab #endif 47*9a0bf528SMauro Carvalho Chehab 48*9a0bf528SMauro Carvalho Chehab #define STV0297_CLOCK_KHZ 28900 49*9a0bf528SMauro Carvalho Chehab 50*9a0bf528SMauro Carvalho Chehab 51*9a0bf528SMauro Carvalho Chehab static int stv0297_writereg(struct stv0297_state *state, u8 reg, u8 data) 52*9a0bf528SMauro Carvalho Chehab { 53*9a0bf528SMauro Carvalho Chehab int ret; 54*9a0bf528SMauro Carvalho Chehab u8 buf[] = { reg, data }; 55*9a0bf528SMauro Carvalho Chehab struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 2 }; 56*9a0bf528SMauro Carvalho Chehab 57*9a0bf528SMauro Carvalho Chehab ret = i2c_transfer(state->i2c, &msg, 1); 58*9a0bf528SMauro Carvalho Chehab 59*9a0bf528SMauro Carvalho Chehab if (ret != 1) 60*9a0bf528SMauro Carvalho Chehab dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " 61*9a0bf528SMauro Carvalho Chehab "ret == %i)\n", __func__, reg, data, ret); 62*9a0bf528SMauro Carvalho Chehab 63*9a0bf528SMauro Carvalho Chehab return (ret != 1) ? -1 : 0; 64*9a0bf528SMauro Carvalho Chehab } 65*9a0bf528SMauro Carvalho Chehab 66*9a0bf528SMauro Carvalho Chehab static int stv0297_readreg(struct stv0297_state *state, u8 reg) 67*9a0bf528SMauro Carvalho Chehab { 68*9a0bf528SMauro Carvalho Chehab int ret; 69*9a0bf528SMauro Carvalho Chehab u8 b0[] = { reg }; 70*9a0bf528SMauro Carvalho Chehab u8 b1[] = { 0 }; 71*9a0bf528SMauro Carvalho Chehab struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1}, 72*9a0bf528SMauro Carvalho Chehab {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1} 73*9a0bf528SMauro Carvalho Chehab }; 74*9a0bf528SMauro Carvalho Chehab 75*9a0bf528SMauro Carvalho Chehab // this device needs a STOP between the register and data 76*9a0bf528SMauro Carvalho Chehab if (state->config->stop_during_read) { 77*9a0bf528SMauro Carvalho Chehab if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) { 78*9a0bf528SMauro Carvalho Chehab dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg, ret); 79*9a0bf528SMauro Carvalho Chehab return -1; 80*9a0bf528SMauro Carvalho Chehab } 81*9a0bf528SMauro Carvalho Chehab if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) { 82*9a0bf528SMauro Carvalho Chehab dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg, ret); 83*9a0bf528SMauro Carvalho Chehab return -1; 84*9a0bf528SMauro Carvalho Chehab } 85*9a0bf528SMauro Carvalho Chehab } else { 86*9a0bf528SMauro Carvalho Chehab if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { 87*9a0bf528SMauro Carvalho Chehab dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg, ret); 88*9a0bf528SMauro Carvalho Chehab return -1; 89*9a0bf528SMauro Carvalho Chehab } 90*9a0bf528SMauro Carvalho Chehab } 91*9a0bf528SMauro Carvalho Chehab 92*9a0bf528SMauro Carvalho Chehab return b1[0]; 93*9a0bf528SMauro Carvalho Chehab } 94*9a0bf528SMauro Carvalho Chehab 95*9a0bf528SMauro Carvalho Chehab static int stv0297_writereg_mask(struct stv0297_state *state, u8 reg, u8 mask, u8 data) 96*9a0bf528SMauro Carvalho Chehab { 97*9a0bf528SMauro Carvalho Chehab int val; 98*9a0bf528SMauro Carvalho Chehab 99*9a0bf528SMauro Carvalho Chehab val = stv0297_readreg(state, reg); 100*9a0bf528SMauro Carvalho Chehab val &= ~mask; 101*9a0bf528SMauro Carvalho Chehab val |= (data & mask); 102*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, reg, val); 103*9a0bf528SMauro Carvalho Chehab 104*9a0bf528SMauro Carvalho Chehab return 0; 105*9a0bf528SMauro Carvalho Chehab } 106*9a0bf528SMauro Carvalho Chehab 107*9a0bf528SMauro Carvalho Chehab static int stv0297_readregs(struct stv0297_state *state, u8 reg1, u8 * b, u8 len) 108*9a0bf528SMauro Carvalho Chehab { 109*9a0bf528SMauro Carvalho Chehab int ret; 110*9a0bf528SMauro Carvalho Chehab struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = 111*9a0bf528SMauro Carvalho Chehab ®1,.len = 1}, 112*9a0bf528SMauro Carvalho Chehab {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b,.len = len} 113*9a0bf528SMauro Carvalho Chehab }; 114*9a0bf528SMauro Carvalho Chehab 115*9a0bf528SMauro Carvalho Chehab // this device needs a STOP between the register and data 116*9a0bf528SMauro Carvalho Chehab if (state->config->stop_during_read) { 117*9a0bf528SMauro Carvalho Chehab if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) { 118*9a0bf528SMauro Carvalho Chehab dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg1, ret); 119*9a0bf528SMauro Carvalho Chehab return -1; 120*9a0bf528SMauro Carvalho Chehab } 121*9a0bf528SMauro Carvalho Chehab if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) { 122*9a0bf528SMauro Carvalho Chehab dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg1, ret); 123*9a0bf528SMauro Carvalho Chehab return -1; 124*9a0bf528SMauro Carvalho Chehab } 125*9a0bf528SMauro Carvalho Chehab } else { 126*9a0bf528SMauro Carvalho Chehab if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { 127*9a0bf528SMauro Carvalho Chehab dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg1, ret); 128*9a0bf528SMauro Carvalho Chehab return -1; 129*9a0bf528SMauro Carvalho Chehab } 130*9a0bf528SMauro Carvalho Chehab } 131*9a0bf528SMauro Carvalho Chehab 132*9a0bf528SMauro Carvalho Chehab return 0; 133*9a0bf528SMauro Carvalho Chehab } 134*9a0bf528SMauro Carvalho Chehab 135*9a0bf528SMauro Carvalho Chehab static u32 stv0297_get_symbolrate(struct stv0297_state *state) 136*9a0bf528SMauro Carvalho Chehab { 137*9a0bf528SMauro Carvalho Chehab u64 tmp; 138*9a0bf528SMauro Carvalho Chehab 139*9a0bf528SMauro Carvalho Chehab tmp = stv0297_readreg(state, 0x55); 140*9a0bf528SMauro Carvalho Chehab tmp |= stv0297_readreg(state, 0x56) << 8; 141*9a0bf528SMauro Carvalho Chehab tmp |= stv0297_readreg(state, 0x57) << 16; 142*9a0bf528SMauro Carvalho Chehab tmp |= stv0297_readreg(state, 0x58) << 24; 143*9a0bf528SMauro Carvalho Chehab 144*9a0bf528SMauro Carvalho Chehab tmp *= STV0297_CLOCK_KHZ; 145*9a0bf528SMauro Carvalho Chehab tmp >>= 32; 146*9a0bf528SMauro Carvalho Chehab 147*9a0bf528SMauro Carvalho Chehab return (u32) tmp; 148*9a0bf528SMauro Carvalho Chehab } 149*9a0bf528SMauro Carvalho Chehab 150*9a0bf528SMauro Carvalho Chehab static void stv0297_set_symbolrate(struct stv0297_state *state, u32 srate) 151*9a0bf528SMauro Carvalho Chehab { 152*9a0bf528SMauro Carvalho Chehab long tmp; 153*9a0bf528SMauro Carvalho Chehab 154*9a0bf528SMauro Carvalho Chehab tmp = 131072L * srate; /* 131072 = 2^17 */ 155*9a0bf528SMauro Carvalho Chehab tmp = tmp / (STV0297_CLOCK_KHZ / 4); /* 1/4 = 2^-2 */ 156*9a0bf528SMauro Carvalho Chehab tmp = tmp * 8192L; /* 8192 = 2^13 */ 157*9a0bf528SMauro Carvalho Chehab 158*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x55, (unsigned char) (tmp & 0xFF)); 159*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x56, (unsigned char) (tmp >> 8)); 160*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x57, (unsigned char) (tmp >> 16)); 161*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x58, (unsigned char) (tmp >> 24)); 162*9a0bf528SMauro Carvalho Chehab } 163*9a0bf528SMauro Carvalho Chehab 164*9a0bf528SMauro Carvalho Chehab static void stv0297_set_sweeprate(struct stv0297_state *state, short fshift, long symrate) 165*9a0bf528SMauro Carvalho Chehab { 166*9a0bf528SMauro Carvalho Chehab long tmp; 167*9a0bf528SMauro Carvalho Chehab 168*9a0bf528SMauro Carvalho Chehab tmp = (long) fshift *262144L; /* 262144 = 2*18 */ 169*9a0bf528SMauro Carvalho Chehab tmp /= symrate; 170*9a0bf528SMauro Carvalho Chehab tmp *= 1024; /* 1024 = 2*10 */ 171*9a0bf528SMauro Carvalho Chehab 172*9a0bf528SMauro Carvalho Chehab // adjust 173*9a0bf528SMauro Carvalho Chehab if (tmp >= 0) { 174*9a0bf528SMauro Carvalho Chehab tmp += 500000; 175*9a0bf528SMauro Carvalho Chehab } else { 176*9a0bf528SMauro Carvalho Chehab tmp -= 500000; 177*9a0bf528SMauro Carvalho Chehab } 178*9a0bf528SMauro Carvalho Chehab tmp /= 1000000; 179*9a0bf528SMauro Carvalho Chehab 180*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x60, tmp & 0xFF); 181*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x69, 0xF0, (tmp >> 4) & 0xf0); 182*9a0bf528SMauro Carvalho Chehab } 183*9a0bf528SMauro Carvalho Chehab 184*9a0bf528SMauro Carvalho Chehab static void stv0297_set_carrieroffset(struct stv0297_state *state, long offset) 185*9a0bf528SMauro Carvalho Chehab { 186*9a0bf528SMauro Carvalho Chehab long tmp; 187*9a0bf528SMauro Carvalho Chehab 188*9a0bf528SMauro Carvalho Chehab /* symrate is hardcoded to 10000 */ 189*9a0bf528SMauro Carvalho Chehab tmp = offset * 26844L; /* (2**28)/10000 */ 190*9a0bf528SMauro Carvalho Chehab if (tmp < 0) 191*9a0bf528SMauro Carvalho Chehab tmp += 0x10000000; 192*9a0bf528SMauro Carvalho Chehab tmp &= 0x0FFFFFFF; 193*9a0bf528SMauro Carvalho Chehab 194*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x66, (unsigned char) (tmp & 0xFF)); 195*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x67, (unsigned char) (tmp >> 8)); 196*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x68, (unsigned char) (tmp >> 16)); 197*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x69, 0x0F, (tmp >> 24) & 0x0f); 198*9a0bf528SMauro Carvalho Chehab } 199*9a0bf528SMauro Carvalho Chehab 200*9a0bf528SMauro Carvalho Chehab /* 201*9a0bf528SMauro Carvalho Chehab static long stv0297_get_carrieroffset(struct stv0297_state *state) 202*9a0bf528SMauro Carvalho Chehab { 203*9a0bf528SMauro Carvalho Chehab s64 tmp; 204*9a0bf528SMauro Carvalho Chehab 205*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x6B, 0x00); 206*9a0bf528SMauro Carvalho Chehab 207*9a0bf528SMauro Carvalho Chehab tmp = stv0297_readreg(state, 0x66); 208*9a0bf528SMauro Carvalho Chehab tmp |= (stv0297_readreg(state, 0x67) << 8); 209*9a0bf528SMauro Carvalho Chehab tmp |= (stv0297_readreg(state, 0x68) << 16); 210*9a0bf528SMauro Carvalho Chehab tmp |= (stv0297_readreg(state, 0x69) & 0x0F) << 24; 211*9a0bf528SMauro Carvalho Chehab 212*9a0bf528SMauro Carvalho Chehab tmp *= stv0297_get_symbolrate(state); 213*9a0bf528SMauro Carvalho Chehab tmp >>= 28; 214*9a0bf528SMauro Carvalho Chehab 215*9a0bf528SMauro Carvalho Chehab return (s32) tmp; 216*9a0bf528SMauro Carvalho Chehab } 217*9a0bf528SMauro Carvalho Chehab */ 218*9a0bf528SMauro Carvalho Chehab 219*9a0bf528SMauro Carvalho Chehab static void stv0297_set_initialdemodfreq(struct stv0297_state *state, long freq) 220*9a0bf528SMauro Carvalho Chehab { 221*9a0bf528SMauro Carvalho Chehab s32 tmp; 222*9a0bf528SMauro Carvalho Chehab 223*9a0bf528SMauro Carvalho Chehab if (freq > 10000) 224*9a0bf528SMauro Carvalho Chehab freq -= STV0297_CLOCK_KHZ; 225*9a0bf528SMauro Carvalho Chehab 226*9a0bf528SMauro Carvalho Chehab tmp = (STV0297_CLOCK_KHZ * 1000) / (1 << 16); 227*9a0bf528SMauro Carvalho Chehab tmp = (freq * 1000) / tmp; 228*9a0bf528SMauro Carvalho Chehab if (tmp > 0xffff) 229*9a0bf528SMauro Carvalho Chehab tmp = 0xffff; 230*9a0bf528SMauro Carvalho Chehab 231*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x25, 0x80, 0x80); 232*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x21, tmp >> 8); 233*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x20, tmp); 234*9a0bf528SMauro Carvalho Chehab } 235*9a0bf528SMauro Carvalho Chehab 236*9a0bf528SMauro Carvalho Chehab static int stv0297_set_qam(struct stv0297_state *state, fe_modulation_t modulation) 237*9a0bf528SMauro Carvalho Chehab { 238*9a0bf528SMauro Carvalho Chehab int val = 0; 239*9a0bf528SMauro Carvalho Chehab 240*9a0bf528SMauro Carvalho Chehab switch (modulation) { 241*9a0bf528SMauro Carvalho Chehab case QAM_16: 242*9a0bf528SMauro Carvalho Chehab val = 0; 243*9a0bf528SMauro Carvalho Chehab break; 244*9a0bf528SMauro Carvalho Chehab 245*9a0bf528SMauro Carvalho Chehab case QAM_32: 246*9a0bf528SMauro Carvalho Chehab val = 1; 247*9a0bf528SMauro Carvalho Chehab break; 248*9a0bf528SMauro Carvalho Chehab 249*9a0bf528SMauro Carvalho Chehab case QAM_64: 250*9a0bf528SMauro Carvalho Chehab val = 4; 251*9a0bf528SMauro Carvalho Chehab break; 252*9a0bf528SMauro Carvalho Chehab 253*9a0bf528SMauro Carvalho Chehab case QAM_128: 254*9a0bf528SMauro Carvalho Chehab val = 2; 255*9a0bf528SMauro Carvalho Chehab break; 256*9a0bf528SMauro Carvalho Chehab 257*9a0bf528SMauro Carvalho Chehab case QAM_256: 258*9a0bf528SMauro Carvalho Chehab val = 3; 259*9a0bf528SMauro Carvalho Chehab break; 260*9a0bf528SMauro Carvalho Chehab 261*9a0bf528SMauro Carvalho Chehab default: 262*9a0bf528SMauro Carvalho Chehab return -EINVAL; 263*9a0bf528SMauro Carvalho Chehab } 264*9a0bf528SMauro Carvalho Chehab 265*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x00, 0x70, val << 4); 266*9a0bf528SMauro Carvalho Chehab 267*9a0bf528SMauro Carvalho Chehab return 0; 268*9a0bf528SMauro Carvalho Chehab } 269*9a0bf528SMauro Carvalho Chehab 270*9a0bf528SMauro Carvalho Chehab static int stv0297_set_inversion(struct stv0297_state *state, fe_spectral_inversion_t inversion) 271*9a0bf528SMauro Carvalho Chehab { 272*9a0bf528SMauro Carvalho Chehab int val = 0; 273*9a0bf528SMauro Carvalho Chehab 274*9a0bf528SMauro Carvalho Chehab switch (inversion) { 275*9a0bf528SMauro Carvalho Chehab case INVERSION_OFF: 276*9a0bf528SMauro Carvalho Chehab val = 0; 277*9a0bf528SMauro Carvalho Chehab break; 278*9a0bf528SMauro Carvalho Chehab 279*9a0bf528SMauro Carvalho Chehab case INVERSION_ON: 280*9a0bf528SMauro Carvalho Chehab val = 1; 281*9a0bf528SMauro Carvalho Chehab break; 282*9a0bf528SMauro Carvalho Chehab 283*9a0bf528SMauro Carvalho Chehab default: 284*9a0bf528SMauro Carvalho Chehab return -EINVAL; 285*9a0bf528SMauro Carvalho Chehab } 286*9a0bf528SMauro Carvalho Chehab 287*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x83, 0x08, val << 3); 288*9a0bf528SMauro Carvalho Chehab 289*9a0bf528SMauro Carvalho Chehab return 0; 290*9a0bf528SMauro Carvalho Chehab } 291*9a0bf528SMauro Carvalho Chehab 292*9a0bf528SMauro Carvalho Chehab static int stv0297_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) 293*9a0bf528SMauro Carvalho Chehab { 294*9a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 295*9a0bf528SMauro Carvalho Chehab 296*9a0bf528SMauro Carvalho Chehab if (enable) { 297*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x87, 0x78); 298*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x86, 0xc8); 299*9a0bf528SMauro Carvalho Chehab } 300*9a0bf528SMauro Carvalho Chehab 301*9a0bf528SMauro Carvalho Chehab return 0; 302*9a0bf528SMauro Carvalho Chehab } 303*9a0bf528SMauro Carvalho Chehab 304*9a0bf528SMauro Carvalho Chehab static int stv0297_init(struct dvb_frontend *fe) 305*9a0bf528SMauro Carvalho Chehab { 306*9a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 307*9a0bf528SMauro Carvalho Chehab int i; 308*9a0bf528SMauro Carvalho Chehab 309*9a0bf528SMauro Carvalho Chehab /* load init table */ 310*9a0bf528SMauro Carvalho Chehab for (i=0; !(state->config->inittab[i] == 0xff && state->config->inittab[i+1] == 0xff); i+=2) 311*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, state->config->inittab[i], state->config->inittab[i+1]); 312*9a0bf528SMauro Carvalho Chehab msleep(200); 313*9a0bf528SMauro Carvalho Chehab 314*9a0bf528SMauro Carvalho Chehab state->last_ber = 0; 315*9a0bf528SMauro Carvalho Chehab 316*9a0bf528SMauro Carvalho Chehab return 0; 317*9a0bf528SMauro Carvalho Chehab } 318*9a0bf528SMauro Carvalho Chehab 319*9a0bf528SMauro Carvalho Chehab static int stv0297_sleep(struct dvb_frontend *fe) 320*9a0bf528SMauro Carvalho Chehab { 321*9a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 322*9a0bf528SMauro Carvalho Chehab 323*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x80, 1, 1); 324*9a0bf528SMauro Carvalho Chehab 325*9a0bf528SMauro Carvalho Chehab return 0; 326*9a0bf528SMauro Carvalho Chehab } 327*9a0bf528SMauro Carvalho Chehab 328*9a0bf528SMauro Carvalho Chehab static int stv0297_read_status(struct dvb_frontend *fe, fe_status_t * status) 329*9a0bf528SMauro Carvalho Chehab { 330*9a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 331*9a0bf528SMauro Carvalho Chehab 332*9a0bf528SMauro Carvalho Chehab u8 sync = stv0297_readreg(state, 0xDF); 333*9a0bf528SMauro Carvalho Chehab 334*9a0bf528SMauro Carvalho Chehab *status = 0; 335*9a0bf528SMauro Carvalho Chehab if (sync & 0x80) 336*9a0bf528SMauro Carvalho Chehab *status |= 337*9a0bf528SMauro Carvalho Chehab FE_HAS_SYNC | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_LOCK; 338*9a0bf528SMauro Carvalho Chehab return 0; 339*9a0bf528SMauro Carvalho Chehab } 340*9a0bf528SMauro Carvalho Chehab 341*9a0bf528SMauro Carvalho Chehab static int stv0297_read_ber(struct dvb_frontend *fe, u32 * ber) 342*9a0bf528SMauro Carvalho Chehab { 343*9a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 344*9a0bf528SMauro Carvalho Chehab u8 BER[3]; 345*9a0bf528SMauro Carvalho Chehab 346*9a0bf528SMauro Carvalho Chehab stv0297_readregs(state, 0xA0, BER, 3); 347*9a0bf528SMauro Carvalho Chehab if (!(BER[0] & 0x80)) { 348*9a0bf528SMauro Carvalho Chehab state->last_ber = BER[2] << 8 | BER[1]; 349*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0xA0, 0x80, 0x80); 350*9a0bf528SMauro Carvalho Chehab } 351*9a0bf528SMauro Carvalho Chehab 352*9a0bf528SMauro Carvalho Chehab *ber = state->last_ber; 353*9a0bf528SMauro Carvalho Chehab 354*9a0bf528SMauro Carvalho Chehab return 0; 355*9a0bf528SMauro Carvalho Chehab } 356*9a0bf528SMauro Carvalho Chehab 357*9a0bf528SMauro Carvalho Chehab 358*9a0bf528SMauro Carvalho Chehab static int stv0297_read_signal_strength(struct dvb_frontend *fe, u16 * strength) 359*9a0bf528SMauro Carvalho Chehab { 360*9a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 361*9a0bf528SMauro Carvalho Chehab u8 STRENGTH[3]; 362*9a0bf528SMauro Carvalho Chehab u16 tmp; 363*9a0bf528SMauro Carvalho Chehab 364*9a0bf528SMauro Carvalho Chehab stv0297_readregs(state, 0x41, STRENGTH, 3); 365*9a0bf528SMauro Carvalho Chehab tmp = (STRENGTH[1] & 0x03) << 8 | STRENGTH[0]; 366*9a0bf528SMauro Carvalho Chehab if (STRENGTH[2] & 0x20) { 367*9a0bf528SMauro Carvalho Chehab if (tmp < 0x200) 368*9a0bf528SMauro Carvalho Chehab tmp = 0; 369*9a0bf528SMauro Carvalho Chehab else 370*9a0bf528SMauro Carvalho Chehab tmp = tmp - 0x200; 371*9a0bf528SMauro Carvalho Chehab } else { 372*9a0bf528SMauro Carvalho Chehab if (tmp > 0x1ff) 373*9a0bf528SMauro Carvalho Chehab tmp = 0; 374*9a0bf528SMauro Carvalho Chehab else 375*9a0bf528SMauro Carvalho Chehab tmp = 0x1ff - tmp; 376*9a0bf528SMauro Carvalho Chehab } 377*9a0bf528SMauro Carvalho Chehab *strength = (tmp << 7) | (tmp >> 2); 378*9a0bf528SMauro Carvalho Chehab return 0; 379*9a0bf528SMauro Carvalho Chehab } 380*9a0bf528SMauro Carvalho Chehab 381*9a0bf528SMauro Carvalho Chehab static int stv0297_read_snr(struct dvb_frontend *fe, u16 * snr) 382*9a0bf528SMauro Carvalho Chehab { 383*9a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 384*9a0bf528SMauro Carvalho Chehab u8 SNR[2]; 385*9a0bf528SMauro Carvalho Chehab 386*9a0bf528SMauro Carvalho Chehab stv0297_readregs(state, 0x07, SNR, 2); 387*9a0bf528SMauro Carvalho Chehab *snr = SNR[1] << 8 | SNR[0]; 388*9a0bf528SMauro Carvalho Chehab 389*9a0bf528SMauro Carvalho Chehab return 0; 390*9a0bf528SMauro Carvalho Chehab } 391*9a0bf528SMauro Carvalho Chehab 392*9a0bf528SMauro Carvalho Chehab static int stv0297_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks) 393*9a0bf528SMauro Carvalho Chehab { 394*9a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 395*9a0bf528SMauro Carvalho Chehab 396*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0xDF, 0x03, 0x03); /* freeze the counters */ 397*9a0bf528SMauro Carvalho Chehab 398*9a0bf528SMauro Carvalho Chehab *ucblocks = (stv0297_readreg(state, 0xD5) << 8) 399*9a0bf528SMauro Carvalho Chehab | stv0297_readreg(state, 0xD4); 400*9a0bf528SMauro Carvalho Chehab 401*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0xDF, 0x03, 0x02); /* clear the counters */ 402*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0xDF, 0x03, 0x01); /* re-enable the counters */ 403*9a0bf528SMauro Carvalho Chehab 404*9a0bf528SMauro Carvalho Chehab return 0; 405*9a0bf528SMauro Carvalho Chehab } 406*9a0bf528SMauro Carvalho Chehab 407*9a0bf528SMauro Carvalho Chehab static int stv0297_set_frontend(struct dvb_frontend *fe) 408*9a0bf528SMauro Carvalho Chehab { 409*9a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *p = &fe->dtv_property_cache; 410*9a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 411*9a0bf528SMauro Carvalho Chehab int u_threshold; 412*9a0bf528SMauro Carvalho Chehab int initial_u; 413*9a0bf528SMauro Carvalho Chehab int blind_u; 414*9a0bf528SMauro Carvalho Chehab int delay; 415*9a0bf528SMauro Carvalho Chehab int sweeprate; 416*9a0bf528SMauro Carvalho Chehab int carrieroffset; 417*9a0bf528SMauro Carvalho Chehab unsigned long timeout; 418*9a0bf528SMauro Carvalho Chehab fe_spectral_inversion_t inversion; 419*9a0bf528SMauro Carvalho Chehab 420*9a0bf528SMauro Carvalho Chehab switch (p->modulation) { 421*9a0bf528SMauro Carvalho Chehab case QAM_16: 422*9a0bf528SMauro Carvalho Chehab case QAM_32: 423*9a0bf528SMauro Carvalho Chehab case QAM_64: 424*9a0bf528SMauro Carvalho Chehab delay = 100; 425*9a0bf528SMauro Carvalho Chehab sweeprate = 1000; 426*9a0bf528SMauro Carvalho Chehab break; 427*9a0bf528SMauro Carvalho Chehab 428*9a0bf528SMauro Carvalho Chehab case QAM_128: 429*9a0bf528SMauro Carvalho Chehab case QAM_256: 430*9a0bf528SMauro Carvalho Chehab delay = 200; 431*9a0bf528SMauro Carvalho Chehab sweeprate = 500; 432*9a0bf528SMauro Carvalho Chehab break; 433*9a0bf528SMauro Carvalho Chehab 434*9a0bf528SMauro Carvalho Chehab default: 435*9a0bf528SMauro Carvalho Chehab return -EINVAL; 436*9a0bf528SMauro Carvalho Chehab } 437*9a0bf528SMauro Carvalho Chehab 438*9a0bf528SMauro Carvalho Chehab // determine inversion dependent parameters 439*9a0bf528SMauro Carvalho Chehab inversion = p->inversion; 440*9a0bf528SMauro Carvalho Chehab if (state->config->invert) 441*9a0bf528SMauro Carvalho Chehab inversion = (inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON; 442*9a0bf528SMauro Carvalho Chehab carrieroffset = -330; 443*9a0bf528SMauro Carvalho Chehab switch (inversion) { 444*9a0bf528SMauro Carvalho Chehab case INVERSION_OFF: 445*9a0bf528SMauro Carvalho Chehab break; 446*9a0bf528SMauro Carvalho Chehab 447*9a0bf528SMauro Carvalho Chehab case INVERSION_ON: 448*9a0bf528SMauro Carvalho Chehab sweeprate = -sweeprate; 449*9a0bf528SMauro Carvalho Chehab carrieroffset = -carrieroffset; 450*9a0bf528SMauro Carvalho Chehab break; 451*9a0bf528SMauro Carvalho Chehab 452*9a0bf528SMauro Carvalho Chehab default: 453*9a0bf528SMauro Carvalho Chehab return -EINVAL; 454*9a0bf528SMauro Carvalho Chehab } 455*9a0bf528SMauro Carvalho Chehab 456*9a0bf528SMauro Carvalho Chehab stv0297_init(fe); 457*9a0bf528SMauro Carvalho Chehab if (fe->ops.tuner_ops.set_params) { 458*9a0bf528SMauro Carvalho Chehab fe->ops.tuner_ops.set_params(fe); 459*9a0bf528SMauro Carvalho Chehab if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); 460*9a0bf528SMauro Carvalho Chehab } 461*9a0bf528SMauro Carvalho Chehab 462*9a0bf528SMauro Carvalho Chehab /* clear software interrupts */ 463*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x82, 0x0); 464*9a0bf528SMauro Carvalho Chehab 465*9a0bf528SMauro Carvalho Chehab /* set initial demodulation frequency */ 466*9a0bf528SMauro Carvalho Chehab stv0297_set_initialdemodfreq(state, 7250); 467*9a0bf528SMauro Carvalho Chehab 468*9a0bf528SMauro Carvalho Chehab /* setup AGC */ 469*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x43, 0x10, 0x00); 470*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x41, 0x00); 471*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x42, 0x03, 0x01); 472*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x36, 0x60, 0x00); 473*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x36, 0x18, 0x00); 474*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x71, 0x80, 0x80); 475*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x72, 0x00); 476*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x73, 0x00); 477*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x74, 0x0F, 0x00); 478*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x43, 0x08, 0x00); 479*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x71, 0x80, 0x00); 480*9a0bf528SMauro Carvalho Chehab 481*9a0bf528SMauro Carvalho Chehab /* setup STL */ 482*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x5a, 0x20, 0x20); 483*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x5b, 0x02, 0x02); 484*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x5b, 0x02, 0x00); 485*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x5b, 0x01, 0x00); 486*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x5a, 0x40, 0x40); 487*9a0bf528SMauro Carvalho Chehab 488*9a0bf528SMauro Carvalho Chehab /* disable frequency sweep */ 489*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x6a, 0x01, 0x00); 490*9a0bf528SMauro Carvalho Chehab 491*9a0bf528SMauro Carvalho Chehab /* reset deinterleaver */ 492*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x81, 0x01, 0x01); 493*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x81, 0x01, 0x00); 494*9a0bf528SMauro Carvalho Chehab 495*9a0bf528SMauro Carvalho Chehab /* ??? */ 496*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x83, 0x20, 0x20); 497*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x83, 0x20, 0x00); 498*9a0bf528SMauro Carvalho Chehab 499*9a0bf528SMauro Carvalho Chehab /* reset equaliser */ 500*9a0bf528SMauro Carvalho Chehab u_threshold = stv0297_readreg(state, 0x00) & 0xf; 501*9a0bf528SMauro Carvalho Chehab initial_u = stv0297_readreg(state, 0x01) >> 4; 502*9a0bf528SMauro Carvalho Chehab blind_u = stv0297_readreg(state, 0x01) & 0xf; 503*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x84, 0x01, 0x01); 504*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x84, 0x01, 0x00); 505*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x00, 0x0f, u_threshold); 506*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x01, 0xf0, initial_u << 4); 507*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x01, 0x0f, blind_u); 508*9a0bf528SMauro Carvalho Chehab 509*9a0bf528SMauro Carvalho Chehab /* data comes from internal A/D */ 510*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x87, 0x80, 0x00); 511*9a0bf528SMauro Carvalho Chehab 512*9a0bf528SMauro Carvalho Chehab /* clear phase registers */ 513*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x63, 0x00); 514*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x64, 0x00); 515*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x65, 0x00); 516*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x66, 0x00); 517*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x67, 0x00); 518*9a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x68, 0x00); 519*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x69, 0x0f, 0x00); 520*9a0bf528SMauro Carvalho Chehab 521*9a0bf528SMauro Carvalho Chehab /* set parameters */ 522*9a0bf528SMauro Carvalho Chehab stv0297_set_qam(state, p->modulation); 523*9a0bf528SMauro Carvalho Chehab stv0297_set_symbolrate(state, p->symbol_rate / 1000); 524*9a0bf528SMauro Carvalho Chehab stv0297_set_sweeprate(state, sweeprate, p->symbol_rate / 1000); 525*9a0bf528SMauro Carvalho Chehab stv0297_set_carrieroffset(state, carrieroffset); 526*9a0bf528SMauro Carvalho Chehab stv0297_set_inversion(state, inversion); 527*9a0bf528SMauro Carvalho Chehab 528*9a0bf528SMauro Carvalho Chehab /* kick off lock */ 529*9a0bf528SMauro Carvalho Chehab /* Disable corner detection for higher QAMs */ 530*9a0bf528SMauro Carvalho Chehab if (p->modulation == QAM_128 || 531*9a0bf528SMauro Carvalho Chehab p->modulation == QAM_256) 532*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x88, 0x08, 0x00); 533*9a0bf528SMauro Carvalho Chehab else 534*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x88, 0x08, 0x08); 535*9a0bf528SMauro Carvalho Chehab 536*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x5a, 0x20, 0x00); 537*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x6a, 0x01, 0x01); 538*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x43, 0x40, 0x40); 539*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x5b, 0x30, 0x00); 540*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x03, 0x0c, 0x0c); 541*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x03, 0x03, 0x03); 542*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x43, 0x10, 0x10); 543*9a0bf528SMauro Carvalho Chehab 544*9a0bf528SMauro Carvalho Chehab /* wait for WGAGC lock */ 545*9a0bf528SMauro Carvalho Chehab timeout = jiffies + msecs_to_jiffies(2000); 546*9a0bf528SMauro Carvalho Chehab while (time_before(jiffies, timeout)) { 547*9a0bf528SMauro Carvalho Chehab msleep(10); 548*9a0bf528SMauro Carvalho Chehab if (stv0297_readreg(state, 0x43) & 0x08) 549*9a0bf528SMauro Carvalho Chehab break; 550*9a0bf528SMauro Carvalho Chehab } 551*9a0bf528SMauro Carvalho Chehab if (time_after(jiffies, timeout)) { 552*9a0bf528SMauro Carvalho Chehab goto timeout; 553*9a0bf528SMauro Carvalho Chehab } 554*9a0bf528SMauro Carvalho Chehab msleep(20); 555*9a0bf528SMauro Carvalho Chehab 556*9a0bf528SMauro Carvalho Chehab /* wait for equaliser partial convergence */ 557*9a0bf528SMauro Carvalho Chehab timeout = jiffies + msecs_to_jiffies(500); 558*9a0bf528SMauro Carvalho Chehab while (time_before(jiffies, timeout)) { 559*9a0bf528SMauro Carvalho Chehab msleep(10); 560*9a0bf528SMauro Carvalho Chehab 561*9a0bf528SMauro Carvalho Chehab if (stv0297_readreg(state, 0x82) & 0x04) { 562*9a0bf528SMauro Carvalho Chehab break; 563*9a0bf528SMauro Carvalho Chehab } 564*9a0bf528SMauro Carvalho Chehab } 565*9a0bf528SMauro Carvalho Chehab if (time_after(jiffies, timeout)) { 566*9a0bf528SMauro Carvalho Chehab goto timeout; 567*9a0bf528SMauro Carvalho Chehab } 568*9a0bf528SMauro Carvalho Chehab 569*9a0bf528SMauro Carvalho Chehab /* wait for equaliser full convergence */ 570*9a0bf528SMauro Carvalho Chehab timeout = jiffies + msecs_to_jiffies(delay); 571*9a0bf528SMauro Carvalho Chehab while (time_before(jiffies, timeout)) { 572*9a0bf528SMauro Carvalho Chehab msleep(10); 573*9a0bf528SMauro Carvalho Chehab 574*9a0bf528SMauro Carvalho Chehab if (stv0297_readreg(state, 0x82) & 0x08) { 575*9a0bf528SMauro Carvalho Chehab break; 576*9a0bf528SMauro Carvalho Chehab } 577*9a0bf528SMauro Carvalho Chehab } 578*9a0bf528SMauro Carvalho Chehab if (time_after(jiffies, timeout)) { 579*9a0bf528SMauro Carvalho Chehab goto timeout; 580*9a0bf528SMauro Carvalho Chehab } 581*9a0bf528SMauro Carvalho Chehab 582*9a0bf528SMauro Carvalho Chehab /* disable sweep */ 583*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x6a, 1, 0); 584*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x88, 8, 0); 585*9a0bf528SMauro Carvalho Chehab 586*9a0bf528SMauro Carvalho Chehab /* wait for main lock */ 587*9a0bf528SMauro Carvalho Chehab timeout = jiffies + msecs_to_jiffies(20); 588*9a0bf528SMauro Carvalho Chehab while (time_before(jiffies, timeout)) { 589*9a0bf528SMauro Carvalho Chehab msleep(10); 590*9a0bf528SMauro Carvalho Chehab 591*9a0bf528SMauro Carvalho Chehab if (stv0297_readreg(state, 0xDF) & 0x80) { 592*9a0bf528SMauro Carvalho Chehab break; 593*9a0bf528SMauro Carvalho Chehab } 594*9a0bf528SMauro Carvalho Chehab } 595*9a0bf528SMauro Carvalho Chehab if (time_after(jiffies, timeout)) { 596*9a0bf528SMauro Carvalho Chehab goto timeout; 597*9a0bf528SMauro Carvalho Chehab } 598*9a0bf528SMauro Carvalho Chehab msleep(100); 599*9a0bf528SMauro Carvalho Chehab 600*9a0bf528SMauro Carvalho Chehab /* is it still locked after that delay? */ 601*9a0bf528SMauro Carvalho Chehab if (!(stv0297_readreg(state, 0xDF) & 0x80)) { 602*9a0bf528SMauro Carvalho Chehab goto timeout; 603*9a0bf528SMauro Carvalho Chehab } 604*9a0bf528SMauro Carvalho Chehab 605*9a0bf528SMauro Carvalho Chehab /* success!! */ 606*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x5a, 0x40, 0x00); 607*9a0bf528SMauro Carvalho Chehab state->base_freq = p->frequency; 608*9a0bf528SMauro Carvalho Chehab return 0; 609*9a0bf528SMauro Carvalho Chehab 610*9a0bf528SMauro Carvalho Chehab timeout: 611*9a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x6a, 0x01, 0x00); 612*9a0bf528SMauro Carvalho Chehab return 0; 613*9a0bf528SMauro Carvalho Chehab } 614*9a0bf528SMauro Carvalho Chehab 615*9a0bf528SMauro Carvalho Chehab static int stv0297_get_frontend(struct dvb_frontend *fe) 616*9a0bf528SMauro Carvalho Chehab { 617*9a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *p = &fe->dtv_property_cache; 618*9a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 619*9a0bf528SMauro Carvalho Chehab int reg_00, reg_83; 620*9a0bf528SMauro Carvalho Chehab 621*9a0bf528SMauro Carvalho Chehab reg_00 = stv0297_readreg(state, 0x00); 622*9a0bf528SMauro Carvalho Chehab reg_83 = stv0297_readreg(state, 0x83); 623*9a0bf528SMauro Carvalho Chehab 624*9a0bf528SMauro Carvalho Chehab p->frequency = state->base_freq; 625*9a0bf528SMauro Carvalho Chehab p->inversion = (reg_83 & 0x08) ? INVERSION_ON : INVERSION_OFF; 626*9a0bf528SMauro Carvalho Chehab if (state->config->invert) 627*9a0bf528SMauro Carvalho Chehab p->inversion = (p->inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON; 628*9a0bf528SMauro Carvalho Chehab p->symbol_rate = stv0297_get_symbolrate(state) * 1000; 629*9a0bf528SMauro Carvalho Chehab p->fec_inner = FEC_NONE; 630*9a0bf528SMauro Carvalho Chehab 631*9a0bf528SMauro Carvalho Chehab switch ((reg_00 >> 4) & 0x7) { 632*9a0bf528SMauro Carvalho Chehab case 0: 633*9a0bf528SMauro Carvalho Chehab p->modulation = QAM_16; 634*9a0bf528SMauro Carvalho Chehab break; 635*9a0bf528SMauro Carvalho Chehab case 1: 636*9a0bf528SMauro Carvalho Chehab p->modulation = QAM_32; 637*9a0bf528SMauro Carvalho Chehab break; 638*9a0bf528SMauro Carvalho Chehab case 2: 639*9a0bf528SMauro Carvalho Chehab p->modulation = QAM_128; 640*9a0bf528SMauro Carvalho Chehab break; 641*9a0bf528SMauro Carvalho Chehab case 3: 642*9a0bf528SMauro Carvalho Chehab p->modulation = QAM_256; 643*9a0bf528SMauro Carvalho Chehab break; 644*9a0bf528SMauro Carvalho Chehab case 4: 645*9a0bf528SMauro Carvalho Chehab p->modulation = QAM_64; 646*9a0bf528SMauro Carvalho Chehab break; 647*9a0bf528SMauro Carvalho Chehab } 648*9a0bf528SMauro Carvalho Chehab 649*9a0bf528SMauro Carvalho Chehab return 0; 650*9a0bf528SMauro Carvalho Chehab } 651*9a0bf528SMauro Carvalho Chehab 652*9a0bf528SMauro Carvalho Chehab static void stv0297_release(struct dvb_frontend *fe) 653*9a0bf528SMauro Carvalho Chehab { 654*9a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 655*9a0bf528SMauro Carvalho Chehab kfree(state); 656*9a0bf528SMauro Carvalho Chehab } 657*9a0bf528SMauro Carvalho Chehab 658*9a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops stv0297_ops; 659*9a0bf528SMauro Carvalho Chehab 660*9a0bf528SMauro Carvalho Chehab struct dvb_frontend *stv0297_attach(const struct stv0297_config *config, 661*9a0bf528SMauro Carvalho Chehab struct i2c_adapter *i2c) 662*9a0bf528SMauro Carvalho Chehab { 663*9a0bf528SMauro Carvalho Chehab struct stv0297_state *state = NULL; 664*9a0bf528SMauro Carvalho Chehab 665*9a0bf528SMauro Carvalho Chehab /* allocate memory for the internal state */ 666*9a0bf528SMauro Carvalho Chehab state = kzalloc(sizeof(struct stv0297_state), GFP_KERNEL); 667*9a0bf528SMauro Carvalho Chehab if (state == NULL) 668*9a0bf528SMauro Carvalho Chehab goto error; 669*9a0bf528SMauro Carvalho Chehab 670*9a0bf528SMauro Carvalho Chehab /* setup the state */ 671*9a0bf528SMauro Carvalho Chehab state->config = config; 672*9a0bf528SMauro Carvalho Chehab state->i2c = i2c; 673*9a0bf528SMauro Carvalho Chehab state->last_ber = 0; 674*9a0bf528SMauro Carvalho Chehab state->base_freq = 0; 675*9a0bf528SMauro Carvalho Chehab 676*9a0bf528SMauro Carvalho Chehab /* check if the demod is there */ 677*9a0bf528SMauro Carvalho Chehab if ((stv0297_readreg(state, 0x80) & 0x70) != 0x20) 678*9a0bf528SMauro Carvalho Chehab goto error; 679*9a0bf528SMauro Carvalho Chehab 680*9a0bf528SMauro Carvalho Chehab /* create dvb_frontend */ 681*9a0bf528SMauro Carvalho Chehab memcpy(&state->frontend.ops, &stv0297_ops, sizeof(struct dvb_frontend_ops)); 682*9a0bf528SMauro Carvalho Chehab state->frontend.demodulator_priv = state; 683*9a0bf528SMauro Carvalho Chehab return &state->frontend; 684*9a0bf528SMauro Carvalho Chehab 685*9a0bf528SMauro Carvalho Chehab error: 686*9a0bf528SMauro Carvalho Chehab kfree(state); 687*9a0bf528SMauro Carvalho Chehab return NULL; 688*9a0bf528SMauro Carvalho Chehab } 689*9a0bf528SMauro Carvalho Chehab 690*9a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops stv0297_ops = { 691*9a0bf528SMauro Carvalho Chehab .delsys = { SYS_DVBC_ANNEX_A }, 692*9a0bf528SMauro Carvalho Chehab .info = { 693*9a0bf528SMauro Carvalho Chehab .name = "ST STV0297 DVB-C", 694*9a0bf528SMauro Carvalho Chehab .frequency_min = 47000000, 695*9a0bf528SMauro Carvalho Chehab .frequency_max = 862000000, 696*9a0bf528SMauro Carvalho Chehab .frequency_stepsize = 62500, 697*9a0bf528SMauro Carvalho Chehab .symbol_rate_min = 870000, 698*9a0bf528SMauro Carvalho Chehab .symbol_rate_max = 11700000, 699*9a0bf528SMauro Carvalho Chehab .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | 700*9a0bf528SMauro Carvalho Chehab FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO}, 701*9a0bf528SMauro Carvalho Chehab 702*9a0bf528SMauro Carvalho Chehab .release = stv0297_release, 703*9a0bf528SMauro Carvalho Chehab 704*9a0bf528SMauro Carvalho Chehab .init = stv0297_init, 705*9a0bf528SMauro Carvalho Chehab .sleep = stv0297_sleep, 706*9a0bf528SMauro Carvalho Chehab .i2c_gate_ctrl = stv0297_i2c_gate_ctrl, 707*9a0bf528SMauro Carvalho Chehab 708*9a0bf528SMauro Carvalho Chehab .set_frontend = stv0297_set_frontend, 709*9a0bf528SMauro Carvalho Chehab .get_frontend = stv0297_get_frontend, 710*9a0bf528SMauro Carvalho Chehab 711*9a0bf528SMauro Carvalho Chehab .read_status = stv0297_read_status, 712*9a0bf528SMauro Carvalho Chehab .read_ber = stv0297_read_ber, 713*9a0bf528SMauro Carvalho Chehab .read_signal_strength = stv0297_read_signal_strength, 714*9a0bf528SMauro Carvalho Chehab .read_snr = stv0297_read_snr, 715*9a0bf528SMauro Carvalho Chehab .read_ucblocks = stv0297_read_ucblocks, 716*9a0bf528SMauro Carvalho Chehab }; 717*9a0bf528SMauro Carvalho Chehab 718*9a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("ST STV0297 DVB-C Demodulator driver"); 719*9a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Dennis Noermann and Andrew de Quincey"); 720*9a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL"); 721*9a0bf528SMauro Carvalho Chehab 722*9a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(stv0297_attach); 723