1*9a0bf528SMauro Carvalho Chehab /* DVB compliant Linux driver for the DVB-S si2109/2110 demodulator 2*9a0bf528SMauro Carvalho Chehab * 3*9a0bf528SMauro Carvalho Chehab * Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) 4*9a0bf528SMauro Carvalho Chehab * 5*9a0bf528SMauro Carvalho Chehab * This program is free software; you can redistribute it and/or modify 6*9a0bf528SMauro Carvalho Chehab * it under the terms of the GNU General Public License as published by 7*9a0bf528SMauro Carvalho Chehab * the Free Software Foundation; either version 2 of the License, or 8*9a0bf528SMauro Carvalho Chehab * (at your option) any later version. 9*9a0bf528SMauro Carvalho Chehab * 10*9a0bf528SMauro Carvalho Chehab */ 11*9a0bf528SMauro Carvalho Chehab #include <linux/init.h> 12*9a0bf528SMauro Carvalho Chehab #include <linux/kernel.h> 13*9a0bf528SMauro Carvalho Chehab #include <linux/module.h> 14*9a0bf528SMauro Carvalho Chehab #include <linux/string.h> 15*9a0bf528SMauro Carvalho Chehab #include <linux/slab.h> 16*9a0bf528SMauro Carvalho Chehab #include <linux/jiffies.h> 17*9a0bf528SMauro Carvalho Chehab #include <asm/div64.h> 18*9a0bf528SMauro Carvalho Chehab 19*9a0bf528SMauro Carvalho Chehab #include "dvb_frontend.h" 20*9a0bf528SMauro Carvalho Chehab #include "si21xx.h" 21*9a0bf528SMauro Carvalho Chehab 22*9a0bf528SMauro Carvalho Chehab #define REVISION_REG 0x00 23*9a0bf528SMauro Carvalho Chehab #define SYSTEM_MODE_REG 0x01 24*9a0bf528SMauro Carvalho Chehab #define TS_CTRL_REG_1 0x02 25*9a0bf528SMauro Carvalho Chehab #define TS_CTRL_REG_2 0x03 26*9a0bf528SMauro Carvalho Chehab #define PIN_CTRL_REG_1 0x04 27*9a0bf528SMauro Carvalho Chehab #define PIN_CTRL_REG_2 0x05 28*9a0bf528SMauro Carvalho Chehab #define LOCK_STATUS_REG_1 0x0f 29*9a0bf528SMauro Carvalho Chehab #define LOCK_STATUS_REG_2 0x10 30*9a0bf528SMauro Carvalho Chehab #define ACQ_STATUS_REG 0x11 31*9a0bf528SMauro Carvalho Chehab #define ACQ_CTRL_REG_1 0x13 32*9a0bf528SMauro Carvalho Chehab #define ACQ_CTRL_REG_2 0x14 33*9a0bf528SMauro Carvalho Chehab #define PLL_DIVISOR_REG 0x15 34*9a0bf528SMauro Carvalho Chehab #define COARSE_TUNE_REG 0x16 35*9a0bf528SMauro Carvalho Chehab #define FINE_TUNE_REG_L 0x17 36*9a0bf528SMauro Carvalho Chehab #define FINE_TUNE_REG_H 0x18 37*9a0bf528SMauro Carvalho Chehab 38*9a0bf528SMauro Carvalho Chehab #define ANALOG_AGC_POWER_LEVEL_REG 0x28 39*9a0bf528SMauro Carvalho Chehab #define CFO_ESTIMATOR_CTRL_REG_1 0x29 40*9a0bf528SMauro Carvalho Chehab #define CFO_ESTIMATOR_CTRL_REG_2 0x2a 41*9a0bf528SMauro Carvalho Chehab #define CFO_ESTIMATOR_CTRL_REG_3 0x2b 42*9a0bf528SMauro Carvalho Chehab 43*9a0bf528SMauro Carvalho Chehab #define SYM_RATE_ESTIMATE_REG_L 0x31 44*9a0bf528SMauro Carvalho Chehab #define SYM_RATE_ESTIMATE_REG_M 0x32 45*9a0bf528SMauro Carvalho Chehab #define SYM_RATE_ESTIMATE_REG_H 0x33 46*9a0bf528SMauro Carvalho Chehab 47*9a0bf528SMauro Carvalho Chehab #define CFO_ESTIMATOR_OFFSET_REG_L 0x36 48*9a0bf528SMauro Carvalho Chehab #define CFO_ESTIMATOR_OFFSET_REG_H 0x37 49*9a0bf528SMauro Carvalho Chehab #define CFO_ERROR_REG_L 0x38 50*9a0bf528SMauro Carvalho Chehab #define CFO_ERROR_REG_H 0x39 51*9a0bf528SMauro Carvalho Chehab #define SYM_RATE_ESTIMATOR_CTRL_REG 0x3a 52*9a0bf528SMauro Carvalho Chehab 53*9a0bf528SMauro Carvalho Chehab #define SYM_RATE_REG_L 0x3f 54*9a0bf528SMauro Carvalho Chehab #define SYM_RATE_REG_M 0x40 55*9a0bf528SMauro Carvalho Chehab #define SYM_RATE_REG_H 0x41 56*9a0bf528SMauro Carvalho Chehab #define SYM_RATE_ESTIMATOR_MAXIMUM_REG 0x42 57*9a0bf528SMauro Carvalho Chehab #define SYM_RATE_ESTIMATOR_MINIMUM_REG 0x43 58*9a0bf528SMauro Carvalho Chehab 59*9a0bf528SMauro Carvalho Chehab #define C_N_ESTIMATOR_CTRL_REG 0x7c 60*9a0bf528SMauro Carvalho Chehab #define C_N_ESTIMATOR_THRSHLD_REG 0x7d 61*9a0bf528SMauro Carvalho Chehab #define C_N_ESTIMATOR_LEVEL_REG_L 0x7e 62*9a0bf528SMauro Carvalho Chehab #define C_N_ESTIMATOR_LEVEL_REG_H 0x7f 63*9a0bf528SMauro Carvalho Chehab 64*9a0bf528SMauro Carvalho Chehab #define BLIND_SCAN_CTRL_REG 0x80 65*9a0bf528SMauro Carvalho Chehab 66*9a0bf528SMauro Carvalho Chehab #define LSA_CTRL_REG_1 0x8D 67*9a0bf528SMauro Carvalho Chehab #define SPCTRM_TILT_CORR_THRSHLD_REG 0x8f 68*9a0bf528SMauro Carvalho Chehab #define ONE_DB_BNDWDTH_THRSHLD_REG 0x90 69*9a0bf528SMauro Carvalho Chehab #define TWO_DB_BNDWDTH_THRSHLD_REG 0x91 70*9a0bf528SMauro Carvalho Chehab #define THREE_DB_BNDWDTH_THRSHLD_REG 0x92 71*9a0bf528SMauro Carvalho Chehab #define INBAND_POWER_THRSHLD_REG 0x93 72*9a0bf528SMauro Carvalho Chehab #define REF_NOISE_LVL_MRGN_THRSHLD_REG 0x94 73*9a0bf528SMauro Carvalho Chehab 74*9a0bf528SMauro Carvalho Chehab #define VIT_SRCH_CTRL_REG_1 0xa0 75*9a0bf528SMauro Carvalho Chehab #define VIT_SRCH_CTRL_REG_2 0xa1 76*9a0bf528SMauro Carvalho Chehab #define VIT_SRCH_CTRL_REG_3 0xa2 77*9a0bf528SMauro Carvalho Chehab #define VIT_SRCH_STATUS_REG 0xa3 78*9a0bf528SMauro Carvalho Chehab #define VITERBI_BER_COUNT_REG_L 0xab 79*9a0bf528SMauro Carvalho Chehab #define REED_SOLOMON_CTRL_REG 0xb0 80*9a0bf528SMauro Carvalho Chehab #define REED_SOLOMON_ERROR_COUNT_REG_L 0xb1 81*9a0bf528SMauro Carvalho Chehab #define PRBS_CTRL_REG 0xb5 82*9a0bf528SMauro Carvalho Chehab 83*9a0bf528SMauro Carvalho Chehab #define LNB_CTRL_REG_1 0xc0 84*9a0bf528SMauro Carvalho Chehab #define LNB_CTRL_REG_2 0xc1 85*9a0bf528SMauro Carvalho Chehab #define LNB_CTRL_REG_3 0xc2 86*9a0bf528SMauro Carvalho Chehab #define LNB_CTRL_REG_4 0xc3 87*9a0bf528SMauro Carvalho Chehab #define LNB_CTRL_STATUS_REG 0xc4 88*9a0bf528SMauro Carvalho Chehab #define LNB_FIFO_REGS_0 0xc5 89*9a0bf528SMauro Carvalho Chehab #define LNB_FIFO_REGS_1 0xc6 90*9a0bf528SMauro Carvalho Chehab #define LNB_FIFO_REGS_2 0xc7 91*9a0bf528SMauro Carvalho Chehab #define LNB_FIFO_REGS_3 0xc8 92*9a0bf528SMauro Carvalho Chehab #define LNB_FIFO_REGS_4 0xc9 93*9a0bf528SMauro Carvalho Chehab #define LNB_FIFO_REGS_5 0xca 94*9a0bf528SMauro Carvalho Chehab #define LNB_SUPPLY_CTRL_REG_1 0xcb 95*9a0bf528SMauro Carvalho Chehab #define LNB_SUPPLY_CTRL_REG_2 0xcc 96*9a0bf528SMauro Carvalho Chehab #define LNB_SUPPLY_CTRL_REG_3 0xcd 97*9a0bf528SMauro Carvalho Chehab #define LNB_SUPPLY_CTRL_REG_4 0xce 98*9a0bf528SMauro Carvalho Chehab #define LNB_SUPPLY_STATUS_REG 0xcf 99*9a0bf528SMauro Carvalho Chehab 100*9a0bf528SMauro Carvalho Chehab #define FAIL -1 101*9a0bf528SMauro Carvalho Chehab #define PASS 0 102*9a0bf528SMauro Carvalho Chehab 103*9a0bf528SMauro Carvalho Chehab #define ALLOWABLE_FS_COUNT 10 104*9a0bf528SMauro Carvalho Chehab #define STATUS_BER 0 105*9a0bf528SMauro Carvalho Chehab #define STATUS_UCBLOCKS 1 106*9a0bf528SMauro Carvalho Chehab 107*9a0bf528SMauro Carvalho Chehab static int debug; 108*9a0bf528SMauro Carvalho Chehab #define dprintk(args...) \ 109*9a0bf528SMauro Carvalho Chehab do { \ 110*9a0bf528SMauro Carvalho Chehab if (debug) \ 111*9a0bf528SMauro Carvalho Chehab printk(KERN_DEBUG "si21xx: " args); \ 112*9a0bf528SMauro Carvalho Chehab } while (0) 113*9a0bf528SMauro Carvalho Chehab 114*9a0bf528SMauro Carvalho Chehab enum { 115*9a0bf528SMauro Carvalho Chehab ACTIVE_HIGH, 116*9a0bf528SMauro Carvalho Chehab ACTIVE_LOW 117*9a0bf528SMauro Carvalho Chehab }; 118*9a0bf528SMauro Carvalho Chehab enum { 119*9a0bf528SMauro Carvalho Chehab BYTE_WIDE, 120*9a0bf528SMauro Carvalho Chehab BIT_WIDE 121*9a0bf528SMauro Carvalho Chehab }; 122*9a0bf528SMauro Carvalho Chehab enum { 123*9a0bf528SMauro Carvalho Chehab CLK_GAPPED_MODE, 124*9a0bf528SMauro Carvalho Chehab CLK_CONTINUOUS_MODE 125*9a0bf528SMauro Carvalho Chehab }; 126*9a0bf528SMauro Carvalho Chehab enum { 127*9a0bf528SMauro Carvalho Chehab RISING_EDGE, 128*9a0bf528SMauro Carvalho Chehab FALLING_EDGE 129*9a0bf528SMauro Carvalho Chehab }; 130*9a0bf528SMauro Carvalho Chehab enum { 131*9a0bf528SMauro Carvalho Chehab MSB_FIRST, 132*9a0bf528SMauro Carvalho Chehab LSB_FIRST 133*9a0bf528SMauro Carvalho Chehab }; 134*9a0bf528SMauro Carvalho Chehab enum { 135*9a0bf528SMauro Carvalho Chehab SERIAL, 136*9a0bf528SMauro Carvalho Chehab PARALLEL 137*9a0bf528SMauro Carvalho Chehab }; 138*9a0bf528SMauro Carvalho Chehab 139*9a0bf528SMauro Carvalho Chehab struct si21xx_state { 140*9a0bf528SMauro Carvalho Chehab struct i2c_adapter *i2c; 141*9a0bf528SMauro Carvalho Chehab const struct si21xx_config *config; 142*9a0bf528SMauro Carvalho Chehab struct dvb_frontend frontend; 143*9a0bf528SMauro Carvalho Chehab u8 initialised:1; 144*9a0bf528SMauro Carvalho Chehab int errmode; 145*9a0bf528SMauro Carvalho Chehab int fs; /*Sampling rate of the ADC in MHz*/ 146*9a0bf528SMauro Carvalho Chehab }; 147*9a0bf528SMauro Carvalho Chehab 148*9a0bf528SMauro Carvalho Chehab /* register default initialization */ 149*9a0bf528SMauro Carvalho Chehab static u8 serit_sp1511lhb_inittab[] = { 150*9a0bf528SMauro Carvalho Chehab 0x01, 0x28, /* set i2c_inc_disable */ 151*9a0bf528SMauro Carvalho Chehab 0x20, 0x03, 152*9a0bf528SMauro Carvalho Chehab 0x27, 0x20, 153*9a0bf528SMauro Carvalho Chehab 0xe0, 0x45, 154*9a0bf528SMauro Carvalho Chehab 0xe1, 0x08, 155*9a0bf528SMauro Carvalho Chehab 0xfe, 0x01, 156*9a0bf528SMauro Carvalho Chehab 0x01, 0x28, 157*9a0bf528SMauro Carvalho Chehab 0x89, 0x09, 158*9a0bf528SMauro Carvalho Chehab 0x04, 0x80, 159*9a0bf528SMauro Carvalho Chehab 0x05, 0x01, 160*9a0bf528SMauro Carvalho Chehab 0x06, 0x00, 161*9a0bf528SMauro Carvalho Chehab 0x20, 0x03, 162*9a0bf528SMauro Carvalho Chehab 0x24, 0x88, 163*9a0bf528SMauro Carvalho Chehab 0x29, 0x09, 164*9a0bf528SMauro Carvalho Chehab 0x2a, 0x0f, 165*9a0bf528SMauro Carvalho Chehab 0x2c, 0x10, 166*9a0bf528SMauro Carvalho Chehab 0x2d, 0x19, 167*9a0bf528SMauro Carvalho Chehab 0x2e, 0x08, 168*9a0bf528SMauro Carvalho Chehab 0x2f, 0x10, 169*9a0bf528SMauro Carvalho Chehab 0x30, 0x19, 170*9a0bf528SMauro Carvalho Chehab 0x34, 0x20, 171*9a0bf528SMauro Carvalho Chehab 0x35, 0x03, 172*9a0bf528SMauro Carvalho Chehab 0x45, 0x02, 173*9a0bf528SMauro Carvalho Chehab 0x46, 0x45, 174*9a0bf528SMauro Carvalho Chehab 0x47, 0xd0, 175*9a0bf528SMauro Carvalho Chehab 0x48, 0x00, 176*9a0bf528SMauro Carvalho Chehab 0x49, 0x40, 177*9a0bf528SMauro Carvalho Chehab 0x4a, 0x03, 178*9a0bf528SMauro Carvalho Chehab 0x4c, 0xfd, 179*9a0bf528SMauro Carvalho Chehab 0x4f, 0x2e, 180*9a0bf528SMauro Carvalho Chehab 0x50, 0x2e, 181*9a0bf528SMauro Carvalho Chehab 0x51, 0x10, 182*9a0bf528SMauro Carvalho Chehab 0x52, 0x10, 183*9a0bf528SMauro Carvalho Chehab 0x56, 0x92, 184*9a0bf528SMauro Carvalho Chehab 0x59, 0x00, 185*9a0bf528SMauro Carvalho Chehab 0x5a, 0x2d, 186*9a0bf528SMauro Carvalho Chehab 0x5b, 0x33, 187*9a0bf528SMauro Carvalho Chehab 0x5c, 0x1f, 188*9a0bf528SMauro Carvalho Chehab 0x5f, 0x76, 189*9a0bf528SMauro Carvalho Chehab 0x62, 0xc0, 190*9a0bf528SMauro Carvalho Chehab 0x63, 0xc0, 191*9a0bf528SMauro Carvalho Chehab 0x64, 0xf3, 192*9a0bf528SMauro Carvalho Chehab 0x65, 0xf3, 193*9a0bf528SMauro Carvalho Chehab 0x79, 0x40, 194*9a0bf528SMauro Carvalho Chehab 0x6a, 0x40, 195*9a0bf528SMauro Carvalho Chehab 0x6b, 0x0a, 196*9a0bf528SMauro Carvalho Chehab 0x6c, 0x80, 197*9a0bf528SMauro Carvalho Chehab 0x6d, 0x27, 198*9a0bf528SMauro Carvalho Chehab 0x71, 0x06, 199*9a0bf528SMauro Carvalho Chehab 0x75, 0x60, 200*9a0bf528SMauro Carvalho Chehab 0x78, 0x00, 201*9a0bf528SMauro Carvalho Chehab 0x79, 0xb5, 202*9a0bf528SMauro Carvalho Chehab 0x7c, 0x05, 203*9a0bf528SMauro Carvalho Chehab 0x7d, 0x1a, 204*9a0bf528SMauro Carvalho Chehab 0x87, 0x55, 205*9a0bf528SMauro Carvalho Chehab 0x88, 0x72, 206*9a0bf528SMauro Carvalho Chehab 0x8f, 0x08, 207*9a0bf528SMauro Carvalho Chehab 0x90, 0xe0, 208*9a0bf528SMauro Carvalho Chehab 0x94, 0x40, 209*9a0bf528SMauro Carvalho Chehab 0xa0, 0x3f, 210*9a0bf528SMauro Carvalho Chehab 0xa1, 0xc0, 211*9a0bf528SMauro Carvalho Chehab 0xa4, 0xcc, 212*9a0bf528SMauro Carvalho Chehab 0xa5, 0x66, 213*9a0bf528SMauro Carvalho Chehab 0xa6, 0x66, 214*9a0bf528SMauro Carvalho Chehab 0xa7, 0x7b, 215*9a0bf528SMauro Carvalho Chehab 0xa8, 0x7b, 216*9a0bf528SMauro Carvalho Chehab 0xa9, 0x7b, 217*9a0bf528SMauro Carvalho Chehab 0xaa, 0x9a, 218*9a0bf528SMauro Carvalho Chehab 0xed, 0x04, 219*9a0bf528SMauro Carvalho Chehab 0xad, 0x00, 220*9a0bf528SMauro Carvalho Chehab 0xae, 0x03, 221*9a0bf528SMauro Carvalho Chehab 0xcc, 0xab, 222*9a0bf528SMauro Carvalho Chehab 0x01, 0x08, 223*9a0bf528SMauro Carvalho Chehab 0xff, 0xff 224*9a0bf528SMauro Carvalho Chehab }; 225*9a0bf528SMauro Carvalho Chehab 226*9a0bf528SMauro Carvalho Chehab /* low level read/writes */ 227*9a0bf528SMauro Carvalho Chehab static int si21_writeregs(struct si21xx_state *state, u8 reg1, 228*9a0bf528SMauro Carvalho Chehab u8 *data, int len) 229*9a0bf528SMauro Carvalho Chehab { 230*9a0bf528SMauro Carvalho Chehab int ret; 231*9a0bf528SMauro Carvalho Chehab u8 buf[60];/* = { reg1, data };*/ 232*9a0bf528SMauro Carvalho Chehab struct i2c_msg msg = { 233*9a0bf528SMauro Carvalho Chehab .addr = state->config->demod_address, 234*9a0bf528SMauro Carvalho Chehab .flags = 0, 235*9a0bf528SMauro Carvalho Chehab .buf = buf, 236*9a0bf528SMauro Carvalho Chehab .len = len + 1 237*9a0bf528SMauro Carvalho Chehab }; 238*9a0bf528SMauro Carvalho Chehab 239*9a0bf528SMauro Carvalho Chehab msg.buf[0] = reg1; 240*9a0bf528SMauro Carvalho Chehab memcpy(msg.buf + 1, data, len); 241*9a0bf528SMauro Carvalho Chehab 242*9a0bf528SMauro Carvalho Chehab ret = i2c_transfer(state->i2c, &msg, 1); 243*9a0bf528SMauro Carvalho Chehab 244*9a0bf528SMauro Carvalho Chehab if (ret != 1) 245*9a0bf528SMauro Carvalho Chehab dprintk("%s: writereg error (reg1 == 0x%02x, data == 0x%02x, " 246*9a0bf528SMauro Carvalho Chehab "ret == %i)\n", __func__, reg1, data[0], ret); 247*9a0bf528SMauro Carvalho Chehab 248*9a0bf528SMauro Carvalho Chehab return (ret != 1) ? -EREMOTEIO : 0; 249*9a0bf528SMauro Carvalho Chehab } 250*9a0bf528SMauro Carvalho Chehab 251*9a0bf528SMauro Carvalho Chehab static int si21_writereg(struct si21xx_state *state, u8 reg, u8 data) 252*9a0bf528SMauro Carvalho Chehab { 253*9a0bf528SMauro Carvalho Chehab int ret; 254*9a0bf528SMauro Carvalho Chehab u8 buf[] = { reg, data }; 255*9a0bf528SMauro Carvalho Chehab struct i2c_msg msg = { 256*9a0bf528SMauro Carvalho Chehab .addr = state->config->demod_address, 257*9a0bf528SMauro Carvalho Chehab .flags = 0, 258*9a0bf528SMauro Carvalho Chehab .buf = buf, 259*9a0bf528SMauro Carvalho Chehab .len = 2 260*9a0bf528SMauro Carvalho Chehab }; 261*9a0bf528SMauro Carvalho Chehab 262*9a0bf528SMauro Carvalho Chehab ret = i2c_transfer(state->i2c, &msg, 1); 263*9a0bf528SMauro Carvalho Chehab 264*9a0bf528SMauro Carvalho Chehab if (ret != 1) 265*9a0bf528SMauro Carvalho Chehab dprintk("%s: writereg error (reg == 0x%02x, data == 0x%02x, " 266*9a0bf528SMauro Carvalho Chehab "ret == %i)\n", __func__, reg, data, ret); 267*9a0bf528SMauro Carvalho Chehab 268*9a0bf528SMauro Carvalho Chehab return (ret != 1) ? -EREMOTEIO : 0; 269*9a0bf528SMauro Carvalho Chehab } 270*9a0bf528SMauro Carvalho Chehab 271*9a0bf528SMauro Carvalho Chehab static int si21_write(struct dvb_frontend *fe, const u8 buf[], int len) 272*9a0bf528SMauro Carvalho Chehab { 273*9a0bf528SMauro Carvalho Chehab struct si21xx_state *state = fe->demodulator_priv; 274*9a0bf528SMauro Carvalho Chehab 275*9a0bf528SMauro Carvalho Chehab if (len != 2) 276*9a0bf528SMauro Carvalho Chehab return -EINVAL; 277*9a0bf528SMauro Carvalho Chehab 278*9a0bf528SMauro Carvalho Chehab return si21_writereg(state, buf[0], buf[1]); 279*9a0bf528SMauro Carvalho Chehab } 280*9a0bf528SMauro Carvalho Chehab 281*9a0bf528SMauro Carvalho Chehab static u8 si21_readreg(struct si21xx_state *state, u8 reg) 282*9a0bf528SMauro Carvalho Chehab { 283*9a0bf528SMauro Carvalho Chehab int ret; 284*9a0bf528SMauro Carvalho Chehab u8 b0[] = { reg }; 285*9a0bf528SMauro Carvalho Chehab u8 b1[] = { 0 }; 286*9a0bf528SMauro Carvalho Chehab struct i2c_msg msg[] = { 287*9a0bf528SMauro Carvalho Chehab { 288*9a0bf528SMauro Carvalho Chehab .addr = state->config->demod_address, 289*9a0bf528SMauro Carvalho Chehab .flags = 0, 290*9a0bf528SMauro Carvalho Chehab .buf = b0, 291*9a0bf528SMauro Carvalho Chehab .len = 1 292*9a0bf528SMauro Carvalho Chehab }, { 293*9a0bf528SMauro Carvalho Chehab .addr = state->config->demod_address, 294*9a0bf528SMauro Carvalho Chehab .flags = I2C_M_RD, 295*9a0bf528SMauro Carvalho Chehab .buf = b1, 296*9a0bf528SMauro Carvalho Chehab .len = 1 297*9a0bf528SMauro Carvalho Chehab } 298*9a0bf528SMauro Carvalho Chehab }; 299*9a0bf528SMauro Carvalho Chehab 300*9a0bf528SMauro Carvalho Chehab ret = i2c_transfer(state->i2c, msg, 2); 301*9a0bf528SMauro Carvalho Chehab 302*9a0bf528SMauro Carvalho Chehab if (ret != 2) 303*9a0bf528SMauro Carvalho Chehab dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", 304*9a0bf528SMauro Carvalho Chehab __func__, reg, ret); 305*9a0bf528SMauro Carvalho Chehab 306*9a0bf528SMauro Carvalho Chehab return b1[0]; 307*9a0bf528SMauro Carvalho Chehab } 308*9a0bf528SMauro Carvalho Chehab 309*9a0bf528SMauro Carvalho Chehab static int si21_readregs(struct si21xx_state *state, u8 reg1, u8 *b, u8 len) 310*9a0bf528SMauro Carvalho Chehab { 311*9a0bf528SMauro Carvalho Chehab int ret; 312*9a0bf528SMauro Carvalho Chehab struct i2c_msg msg[] = { 313*9a0bf528SMauro Carvalho Chehab { 314*9a0bf528SMauro Carvalho Chehab .addr = state->config->demod_address, 315*9a0bf528SMauro Carvalho Chehab .flags = 0, 316*9a0bf528SMauro Carvalho Chehab .buf = ®1, 317*9a0bf528SMauro Carvalho Chehab .len = 1 318*9a0bf528SMauro Carvalho Chehab }, { 319*9a0bf528SMauro Carvalho Chehab .addr = state->config->demod_address, 320*9a0bf528SMauro Carvalho Chehab .flags = I2C_M_RD, 321*9a0bf528SMauro Carvalho Chehab .buf = b, 322*9a0bf528SMauro Carvalho Chehab .len = len 323*9a0bf528SMauro Carvalho Chehab } 324*9a0bf528SMauro Carvalho Chehab }; 325*9a0bf528SMauro Carvalho Chehab 326*9a0bf528SMauro Carvalho Chehab ret = i2c_transfer(state->i2c, msg, 2); 327*9a0bf528SMauro Carvalho Chehab 328*9a0bf528SMauro Carvalho Chehab if (ret != 2) 329*9a0bf528SMauro Carvalho Chehab dprintk("%s: readreg error (ret == %i)\n", __func__, ret); 330*9a0bf528SMauro Carvalho Chehab 331*9a0bf528SMauro Carvalho Chehab return ret == 2 ? 0 : -1; 332*9a0bf528SMauro Carvalho Chehab } 333*9a0bf528SMauro Carvalho Chehab 334*9a0bf528SMauro Carvalho Chehab static int si21xx_wait_diseqc_idle(struct si21xx_state *state, int timeout) 335*9a0bf528SMauro Carvalho Chehab { 336*9a0bf528SMauro Carvalho Chehab unsigned long start = jiffies; 337*9a0bf528SMauro Carvalho Chehab 338*9a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 339*9a0bf528SMauro Carvalho Chehab 340*9a0bf528SMauro Carvalho Chehab while ((si21_readreg(state, LNB_CTRL_REG_1) & 0x8) == 8) { 341*9a0bf528SMauro Carvalho Chehab if (jiffies - start > timeout) { 342*9a0bf528SMauro Carvalho Chehab dprintk("%s: timeout!!\n", __func__); 343*9a0bf528SMauro Carvalho Chehab return -ETIMEDOUT; 344*9a0bf528SMauro Carvalho Chehab } 345*9a0bf528SMauro Carvalho Chehab msleep(10); 346*9a0bf528SMauro Carvalho Chehab }; 347*9a0bf528SMauro Carvalho Chehab 348*9a0bf528SMauro Carvalho Chehab return 0; 349*9a0bf528SMauro Carvalho Chehab } 350*9a0bf528SMauro Carvalho Chehab 351*9a0bf528SMauro Carvalho Chehab static int si21xx_set_symbolrate(struct dvb_frontend *fe, u32 srate) 352*9a0bf528SMauro Carvalho Chehab { 353*9a0bf528SMauro Carvalho Chehab struct si21xx_state *state = fe->demodulator_priv; 354*9a0bf528SMauro Carvalho Chehab u32 sym_rate, data_rate; 355*9a0bf528SMauro Carvalho Chehab int i; 356*9a0bf528SMauro Carvalho Chehab u8 sym_rate_bytes[3]; 357*9a0bf528SMauro Carvalho Chehab 358*9a0bf528SMauro Carvalho Chehab dprintk("%s : srate = %i\n", __func__ , srate); 359*9a0bf528SMauro Carvalho Chehab 360*9a0bf528SMauro Carvalho Chehab if ((srate < 1000000) || (srate > 45000000)) 361*9a0bf528SMauro Carvalho Chehab return -EINVAL; 362*9a0bf528SMauro Carvalho Chehab 363*9a0bf528SMauro Carvalho Chehab data_rate = srate; 364*9a0bf528SMauro Carvalho Chehab sym_rate = 0; 365*9a0bf528SMauro Carvalho Chehab 366*9a0bf528SMauro Carvalho Chehab for (i = 0; i < 4; ++i) { 367*9a0bf528SMauro Carvalho Chehab sym_rate /= 100; 368*9a0bf528SMauro Carvalho Chehab sym_rate = sym_rate + ((data_rate % 100) * 0x800000) / 369*9a0bf528SMauro Carvalho Chehab state->fs; 370*9a0bf528SMauro Carvalho Chehab data_rate /= 100; 371*9a0bf528SMauro Carvalho Chehab } 372*9a0bf528SMauro Carvalho Chehab for (i = 0; i < 3; ++i) 373*9a0bf528SMauro Carvalho Chehab sym_rate_bytes[i] = (u8)((sym_rate >> (i * 8)) & 0xff); 374*9a0bf528SMauro Carvalho Chehab 375*9a0bf528SMauro Carvalho Chehab si21_writeregs(state, SYM_RATE_REG_L, sym_rate_bytes, 0x03); 376*9a0bf528SMauro Carvalho Chehab 377*9a0bf528SMauro Carvalho Chehab return 0; 378*9a0bf528SMauro Carvalho Chehab } 379*9a0bf528SMauro Carvalho Chehab 380*9a0bf528SMauro Carvalho Chehab static int si21xx_send_diseqc_msg(struct dvb_frontend *fe, 381*9a0bf528SMauro Carvalho Chehab struct dvb_diseqc_master_cmd *m) 382*9a0bf528SMauro Carvalho Chehab { 383*9a0bf528SMauro Carvalho Chehab struct si21xx_state *state = fe->demodulator_priv; 384*9a0bf528SMauro Carvalho Chehab u8 lnb_status; 385*9a0bf528SMauro Carvalho Chehab u8 LNB_CTRL_1; 386*9a0bf528SMauro Carvalho Chehab int status; 387*9a0bf528SMauro Carvalho Chehab 388*9a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 389*9a0bf528SMauro Carvalho Chehab 390*9a0bf528SMauro Carvalho Chehab status = PASS; 391*9a0bf528SMauro Carvalho Chehab LNB_CTRL_1 = 0; 392*9a0bf528SMauro Carvalho Chehab 393*9a0bf528SMauro Carvalho Chehab status |= si21_readregs(state, LNB_CTRL_STATUS_REG, &lnb_status, 0x01); 394*9a0bf528SMauro Carvalho Chehab status |= si21_readregs(state, LNB_CTRL_REG_1, &lnb_status, 0x01); 395*9a0bf528SMauro Carvalho Chehab 396*9a0bf528SMauro Carvalho Chehab /*fill the FIFO*/ 397*9a0bf528SMauro Carvalho Chehab status |= si21_writeregs(state, LNB_FIFO_REGS_0, m->msg, m->msg_len); 398*9a0bf528SMauro Carvalho Chehab 399*9a0bf528SMauro Carvalho Chehab LNB_CTRL_1 = (lnb_status & 0x70); 400*9a0bf528SMauro Carvalho Chehab LNB_CTRL_1 |= m->msg_len; 401*9a0bf528SMauro Carvalho Chehab 402*9a0bf528SMauro Carvalho Chehab LNB_CTRL_1 |= 0x80; /* begin LNB signaling */ 403*9a0bf528SMauro Carvalho Chehab 404*9a0bf528SMauro Carvalho Chehab status |= si21_writeregs(state, LNB_CTRL_REG_1, &LNB_CTRL_1, 0x01); 405*9a0bf528SMauro Carvalho Chehab 406*9a0bf528SMauro Carvalho Chehab return status; 407*9a0bf528SMauro Carvalho Chehab } 408*9a0bf528SMauro Carvalho Chehab 409*9a0bf528SMauro Carvalho Chehab static int si21xx_send_diseqc_burst(struct dvb_frontend *fe, 410*9a0bf528SMauro Carvalho Chehab fe_sec_mini_cmd_t burst) 411*9a0bf528SMauro Carvalho Chehab { 412*9a0bf528SMauro Carvalho Chehab struct si21xx_state *state = fe->demodulator_priv; 413*9a0bf528SMauro Carvalho Chehab u8 val; 414*9a0bf528SMauro Carvalho Chehab 415*9a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 416*9a0bf528SMauro Carvalho Chehab 417*9a0bf528SMauro Carvalho Chehab if (si21xx_wait_diseqc_idle(state, 100) < 0) 418*9a0bf528SMauro Carvalho Chehab return -ETIMEDOUT; 419*9a0bf528SMauro Carvalho Chehab 420*9a0bf528SMauro Carvalho Chehab val = (0x80 | si21_readreg(state, 0xc1)); 421*9a0bf528SMauro Carvalho Chehab if (si21_writereg(state, LNB_CTRL_REG_1, 422*9a0bf528SMauro Carvalho Chehab burst == SEC_MINI_A ? (val & ~0x10) : (val | 0x10))) 423*9a0bf528SMauro Carvalho Chehab return -EREMOTEIO; 424*9a0bf528SMauro Carvalho Chehab 425*9a0bf528SMauro Carvalho Chehab if (si21xx_wait_diseqc_idle(state, 100) < 0) 426*9a0bf528SMauro Carvalho Chehab return -ETIMEDOUT; 427*9a0bf528SMauro Carvalho Chehab 428*9a0bf528SMauro Carvalho Chehab if (si21_writereg(state, LNB_CTRL_REG_1, val)) 429*9a0bf528SMauro Carvalho Chehab return -EREMOTEIO; 430*9a0bf528SMauro Carvalho Chehab 431*9a0bf528SMauro Carvalho Chehab return 0; 432*9a0bf528SMauro Carvalho Chehab } 433*9a0bf528SMauro Carvalho Chehab /* 30.06.2008 */ 434*9a0bf528SMauro Carvalho Chehab static int si21xx_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) 435*9a0bf528SMauro Carvalho Chehab { 436*9a0bf528SMauro Carvalho Chehab struct si21xx_state *state = fe->demodulator_priv; 437*9a0bf528SMauro Carvalho Chehab u8 val; 438*9a0bf528SMauro Carvalho Chehab 439*9a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 440*9a0bf528SMauro Carvalho Chehab val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1)); 441*9a0bf528SMauro Carvalho Chehab 442*9a0bf528SMauro Carvalho Chehab switch (tone) { 443*9a0bf528SMauro Carvalho Chehab case SEC_TONE_ON: 444*9a0bf528SMauro Carvalho Chehab return si21_writereg(state, LNB_CTRL_REG_1, val | 0x20); 445*9a0bf528SMauro Carvalho Chehab 446*9a0bf528SMauro Carvalho Chehab case SEC_TONE_OFF: 447*9a0bf528SMauro Carvalho Chehab return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x20)); 448*9a0bf528SMauro Carvalho Chehab 449*9a0bf528SMauro Carvalho Chehab default: 450*9a0bf528SMauro Carvalho Chehab return -EINVAL; 451*9a0bf528SMauro Carvalho Chehab } 452*9a0bf528SMauro Carvalho Chehab } 453*9a0bf528SMauro Carvalho Chehab 454*9a0bf528SMauro Carvalho Chehab static int si21xx_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) 455*9a0bf528SMauro Carvalho Chehab { 456*9a0bf528SMauro Carvalho Chehab struct si21xx_state *state = fe->demodulator_priv; 457*9a0bf528SMauro Carvalho Chehab 458*9a0bf528SMauro Carvalho Chehab u8 val; 459*9a0bf528SMauro Carvalho Chehab dprintk("%s: %s\n", __func__, 460*9a0bf528SMauro Carvalho Chehab volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : 461*9a0bf528SMauro Carvalho Chehab volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); 462*9a0bf528SMauro Carvalho Chehab 463*9a0bf528SMauro Carvalho Chehab 464*9a0bf528SMauro Carvalho Chehab val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1)); 465*9a0bf528SMauro Carvalho Chehab 466*9a0bf528SMauro Carvalho Chehab switch (volt) { 467*9a0bf528SMauro Carvalho Chehab case SEC_VOLTAGE_18: 468*9a0bf528SMauro Carvalho Chehab return si21_writereg(state, LNB_CTRL_REG_1, val | 0x40); 469*9a0bf528SMauro Carvalho Chehab break; 470*9a0bf528SMauro Carvalho Chehab case SEC_VOLTAGE_13: 471*9a0bf528SMauro Carvalho Chehab return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x40)); 472*9a0bf528SMauro Carvalho Chehab break; 473*9a0bf528SMauro Carvalho Chehab default: 474*9a0bf528SMauro Carvalho Chehab return -EINVAL; 475*9a0bf528SMauro Carvalho Chehab }; 476*9a0bf528SMauro Carvalho Chehab } 477*9a0bf528SMauro Carvalho Chehab 478*9a0bf528SMauro Carvalho Chehab static int si21xx_init(struct dvb_frontend *fe) 479*9a0bf528SMauro Carvalho Chehab { 480*9a0bf528SMauro Carvalho Chehab struct si21xx_state *state = fe->demodulator_priv; 481*9a0bf528SMauro Carvalho Chehab int i; 482*9a0bf528SMauro Carvalho Chehab int status = 0; 483*9a0bf528SMauro Carvalho Chehab u8 reg1; 484*9a0bf528SMauro Carvalho Chehab u8 val; 485*9a0bf528SMauro Carvalho Chehab u8 reg2[2]; 486*9a0bf528SMauro Carvalho Chehab 487*9a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 488*9a0bf528SMauro Carvalho Chehab 489*9a0bf528SMauro Carvalho Chehab for (i = 0; ; i += 2) { 490*9a0bf528SMauro Carvalho Chehab reg1 = serit_sp1511lhb_inittab[i]; 491*9a0bf528SMauro Carvalho Chehab val = serit_sp1511lhb_inittab[i+1]; 492*9a0bf528SMauro Carvalho Chehab if (reg1 == 0xff && val == 0xff) 493*9a0bf528SMauro Carvalho Chehab break; 494*9a0bf528SMauro Carvalho Chehab si21_writeregs(state, reg1, &val, 1); 495*9a0bf528SMauro Carvalho Chehab } 496*9a0bf528SMauro Carvalho Chehab 497*9a0bf528SMauro Carvalho Chehab /*DVB QPSK SYSTEM MODE REG*/ 498*9a0bf528SMauro Carvalho Chehab reg1 = 0x08; 499*9a0bf528SMauro Carvalho Chehab si21_writeregs(state, SYSTEM_MODE_REG, ®1, 0x01); 500*9a0bf528SMauro Carvalho Chehab 501*9a0bf528SMauro Carvalho Chehab /*transport stream config*/ 502*9a0bf528SMauro Carvalho Chehab /* 503*9a0bf528SMauro Carvalho Chehab mode = PARALLEL; 504*9a0bf528SMauro Carvalho Chehab sdata_form = LSB_FIRST; 505*9a0bf528SMauro Carvalho Chehab clk_edge = FALLING_EDGE; 506*9a0bf528SMauro Carvalho Chehab clk_mode = CLK_GAPPED_MODE; 507*9a0bf528SMauro Carvalho Chehab strt_len = BYTE_WIDE; 508*9a0bf528SMauro Carvalho Chehab sync_pol = ACTIVE_HIGH; 509*9a0bf528SMauro Carvalho Chehab val_pol = ACTIVE_HIGH; 510*9a0bf528SMauro Carvalho Chehab err_pol = ACTIVE_HIGH; 511*9a0bf528SMauro Carvalho Chehab sclk_rate = 0x00; 512*9a0bf528SMauro Carvalho Chehab parity = 0x00 ; 513*9a0bf528SMauro Carvalho Chehab data_delay = 0x00; 514*9a0bf528SMauro Carvalho Chehab clk_delay = 0x00; 515*9a0bf528SMauro Carvalho Chehab pclk_smooth = 0x00; 516*9a0bf528SMauro Carvalho Chehab */ 517*9a0bf528SMauro Carvalho Chehab reg2[0] = 518*9a0bf528SMauro Carvalho Chehab PARALLEL + (LSB_FIRST << 1) 519*9a0bf528SMauro Carvalho Chehab + (FALLING_EDGE << 2) + (CLK_GAPPED_MODE << 3) 520*9a0bf528SMauro Carvalho Chehab + (BYTE_WIDE << 4) + (ACTIVE_HIGH << 5) 521*9a0bf528SMauro Carvalho Chehab + (ACTIVE_HIGH << 6) + (ACTIVE_HIGH << 7); 522*9a0bf528SMauro Carvalho Chehab 523*9a0bf528SMauro Carvalho Chehab reg2[1] = 0; 524*9a0bf528SMauro Carvalho Chehab /* sclk_rate + (parity << 2) 525*9a0bf528SMauro Carvalho Chehab + (data_delay << 3) + (clk_delay << 4) 526*9a0bf528SMauro Carvalho Chehab + (pclk_smooth << 5); 527*9a0bf528SMauro Carvalho Chehab */ 528*9a0bf528SMauro Carvalho Chehab status |= si21_writeregs(state, TS_CTRL_REG_1, reg2, 0x02); 529*9a0bf528SMauro Carvalho Chehab if (status != 0) 530*9a0bf528SMauro Carvalho Chehab dprintk(" %s : TS Set Error\n", __func__); 531*9a0bf528SMauro Carvalho Chehab 532*9a0bf528SMauro Carvalho Chehab return 0; 533*9a0bf528SMauro Carvalho Chehab 534*9a0bf528SMauro Carvalho Chehab } 535*9a0bf528SMauro Carvalho Chehab 536*9a0bf528SMauro Carvalho Chehab static int si21_read_status(struct dvb_frontend *fe, fe_status_t *status) 537*9a0bf528SMauro Carvalho Chehab { 538*9a0bf528SMauro Carvalho Chehab struct si21xx_state *state = fe->demodulator_priv; 539*9a0bf528SMauro Carvalho Chehab u8 regs_read[2]; 540*9a0bf528SMauro Carvalho Chehab u8 reg_read; 541*9a0bf528SMauro Carvalho Chehab u8 i; 542*9a0bf528SMauro Carvalho Chehab u8 lock; 543*9a0bf528SMauro Carvalho Chehab u8 signal = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG); 544*9a0bf528SMauro Carvalho Chehab 545*9a0bf528SMauro Carvalho Chehab si21_readregs(state, LOCK_STATUS_REG_1, regs_read, 0x02); 546*9a0bf528SMauro Carvalho Chehab reg_read = 0; 547*9a0bf528SMauro Carvalho Chehab 548*9a0bf528SMauro Carvalho Chehab for (i = 0; i < 7; ++i) 549*9a0bf528SMauro Carvalho Chehab reg_read |= ((regs_read[0] >> i) & 0x01) << (6 - i); 550*9a0bf528SMauro Carvalho Chehab 551*9a0bf528SMauro Carvalho Chehab lock = ((reg_read & 0x7f) | (regs_read[1] & 0x80)); 552*9a0bf528SMauro Carvalho Chehab 553*9a0bf528SMauro Carvalho Chehab dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, lock); 554*9a0bf528SMauro Carvalho Chehab *status = 0; 555*9a0bf528SMauro Carvalho Chehab 556*9a0bf528SMauro Carvalho Chehab if (signal > 10) 557*9a0bf528SMauro Carvalho Chehab *status |= FE_HAS_SIGNAL; 558*9a0bf528SMauro Carvalho Chehab 559*9a0bf528SMauro Carvalho Chehab if (lock & 0x2) 560*9a0bf528SMauro Carvalho Chehab *status |= FE_HAS_CARRIER; 561*9a0bf528SMauro Carvalho Chehab 562*9a0bf528SMauro Carvalho Chehab if (lock & 0x20) 563*9a0bf528SMauro Carvalho Chehab *status |= FE_HAS_VITERBI; 564*9a0bf528SMauro Carvalho Chehab 565*9a0bf528SMauro Carvalho Chehab if (lock & 0x40) 566*9a0bf528SMauro Carvalho Chehab *status |= FE_HAS_SYNC; 567*9a0bf528SMauro Carvalho Chehab 568*9a0bf528SMauro Carvalho Chehab if ((lock & 0x7b) == 0x7b) 569*9a0bf528SMauro Carvalho Chehab *status |= FE_HAS_LOCK; 570*9a0bf528SMauro Carvalho Chehab 571*9a0bf528SMauro Carvalho Chehab return 0; 572*9a0bf528SMauro Carvalho Chehab } 573*9a0bf528SMauro Carvalho Chehab 574*9a0bf528SMauro Carvalho Chehab static int si21_read_signal_strength(struct dvb_frontend *fe, u16 *strength) 575*9a0bf528SMauro Carvalho Chehab { 576*9a0bf528SMauro Carvalho Chehab struct si21xx_state *state = fe->demodulator_priv; 577*9a0bf528SMauro Carvalho Chehab 578*9a0bf528SMauro Carvalho Chehab /*status = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG, 579*9a0bf528SMauro Carvalho Chehab (u8*)agclevel, 0x01);*/ 580*9a0bf528SMauro Carvalho Chehab 581*9a0bf528SMauro Carvalho Chehab u16 signal = (3 * si21_readreg(state, 0x27) * 582*9a0bf528SMauro Carvalho Chehab si21_readreg(state, 0x28)); 583*9a0bf528SMauro Carvalho Chehab 584*9a0bf528SMauro Carvalho Chehab dprintk("%s : AGCPWR: 0x%02x%02x, signal=0x%04x\n", __func__, 585*9a0bf528SMauro Carvalho Chehab si21_readreg(state, 0x27), 586*9a0bf528SMauro Carvalho Chehab si21_readreg(state, 0x28), (int) signal); 587*9a0bf528SMauro Carvalho Chehab 588*9a0bf528SMauro Carvalho Chehab signal <<= 4; 589*9a0bf528SMauro Carvalho Chehab *strength = signal; 590*9a0bf528SMauro Carvalho Chehab 591*9a0bf528SMauro Carvalho Chehab return 0; 592*9a0bf528SMauro Carvalho Chehab } 593*9a0bf528SMauro Carvalho Chehab 594*9a0bf528SMauro Carvalho Chehab static int si21_read_ber(struct dvb_frontend *fe, u32 *ber) 595*9a0bf528SMauro Carvalho Chehab { 596*9a0bf528SMauro Carvalho Chehab struct si21xx_state *state = fe->demodulator_priv; 597*9a0bf528SMauro Carvalho Chehab 598*9a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 599*9a0bf528SMauro Carvalho Chehab 600*9a0bf528SMauro Carvalho Chehab if (state->errmode != STATUS_BER) 601*9a0bf528SMauro Carvalho Chehab return 0; 602*9a0bf528SMauro Carvalho Chehab 603*9a0bf528SMauro Carvalho Chehab *ber = (si21_readreg(state, 0x1d) << 8) | 604*9a0bf528SMauro Carvalho Chehab si21_readreg(state, 0x1e); 605*9a0bf528SMauro Carvalho Chehab 606*9a0bf528SMauro Carvalho Chehab return 0; 607*9a0bf528SMauro Carvalho Chehab } 608*9a0bf528SMauro Carvalho Chehab 609*9a0bf528SMauro Carvalho Chehab static int si21_read_snr(struct dvb_frontend *fe, u16 *snr) 610*9a0bf528SMauro Carvalho Chehab { 611*9a0bf528SMauro Carvalho Chehab struct si21xx_state *state = fe->demodulator_priv; 612*9a0bf528SMauro Carvalho Chehab 613*9a0bf528SMauro Carvalho Chehab s32 xsnr = 0xffff - ((si21_readreg(state, 0x24) << 8) | 614*9a0bf528SMauro Carvalho Chehab si21_readreg(state, 0x25)); 615*9a0bf528SMauro Carvalho Chehab xsnr = 3 * (xsnr - 0xa100); 616*9a0bf528SMauro Carvalho Chehab *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr; 617*9a0bf528SMauro Carvalho Chehab 618*9a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 619*9a0bf528SMauro Carvalho Chehab 620*9a0bf528SMauro Carvalho Chehab return 0; 621*9a0bf528SMauro Carvalho Chehab } 622*9a0bf528SMauro Carvalho Chehab 623*9a0bf528SMauro Carvalho Chehab static int si21_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) 624*9a0bf528SMauro Carvalho Chehab { 625*9a0bf528SMauro Carvalho Chehab struct si21xx_state *state = fe->demodulator_priv; 626*9a0bf528SMauro Carvalho Chehab 627*9a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 628*9a0bf528SMauro Carvalho Chehab 629*9a0bf528SMauro Carvalho Chehab if (state->errmode != STATUS_UCBLOCKS) 630*9a0bf528SMauro Carvalho Chehab *ucblocks = 0; 631*9a0bf528SMauro Carvalho Chehab else 632*9a0bf528SMauro Carvalho Chehab *ucblocks = (si21_readreg(state, 0x1d) << 8) | 633*9a0bf528SMauro Carvalho Chehab si21_readreg(state, 0x1e); 634*9a0bf528SMauro Carvalho Chehab 635*9a0bf528SMauro Carvalho Chehab return 0; 636*9a0bf528SMauro Carvalho Chehab } 637*9a0bf528SMauro Carvalho Chehab 638*9a0bf528SMauro Carvalho Chehab /* initiates a channel acquisition sequence 639*9a0bf528SMauro Carvalho Chehab using the specified symbol rate and code rate */ 640*9a0bf528SMauro Carvalho Chehab static int si21xx_setacquire(struct dvb_frontend *fe, int symbrate, 641*9a0bf528SMauro Carvalho Chehab fe_code_rate_t crate) 642*9a0bf528SMauro Carvalho Chehab { 643*9a0bf528SMauro Carvalho Chehab 644*9a0bf528SMauro Carvalho Chehab struct si21xx_state *state = fe->demodulator_priv; 645*9a0bf528SMauro Carvalho Chehab u8 coderates[] = { 646*9a0bf528SMauro Carvalho Chehab 0x0, 0x01, 0x02, 0x04, 0x00, 647*9a0bf528SMauro Carvalho Chehab 0x8, 0x10, 0x20, 0x00, 0x3f 648*9a0bf528SMauro Carvalho Chehab }; 649*9a0bf528SMauro Carvalho Chehab 650*9a0bf528SMauro Carvalho Chehab u8 coderate_ptr; 651*9a0bf528SMauro Carvalho Chehab int status; 652*9a0bf528SMauro Carvalho Chehab u8 start_acq = 0x80; 653*9a0bf528SMauro Carvalho Chehab u8 reg, regs[3]; 654*9a0bf528SMauro Carvalho Chehab 655*9a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 656*9a0bf528SMauro Carvalho Chehab 657*9a0bf528SMauro Carvalho Chehab status = PASS; 658*9a0bf528SMauro Carvalho Chehab coderate_ptr = coderates[crate]; 659*9a0bf528SMauro Carvalho Chehab 660*9a0bf528SMauro Carvalho Chehab si21xx_set_symbolrate(fe, symbrate); 661*9a0bf528SMauro Carvalho Chehab 662*9a0bf528SMauro Carvalho Chehab /* write code rates to use in the Viterbi search */ 663*9a0bf528SMauro Carvalho Chehab status |= si21_writeregs(state, 664*9a0bf528SMauro Carvalho Chehab VIT_SRCH_CTRL_REG_1, 665*9a0bf528SMauro Carvalho Chehab &coderate_ptr, 0x01); 666*9a0bf528SMauro Carvalho Chehab 667*9a0bf528SMauro Carvalho Chehab /* clear acq_start bit */ 668*9a0bf528SMauro Carvalho Chehab status |= si21_readregs(state, ACQ_CTRL_REG_2, ®, 0x01); 669*9a0bf528SMauro Carvalho Chehab reg &= ~start_acq; 670*9a0bf528SMauro Carvalho Chehab status |= si21_writeregs(state, ACQ_CTRL_REG_2, ®, 0x01); 671*9a0bf528SMauro Carvalho Chehab 672*9a0bf528SMauro Carvalho Chehab /* use new Carrier Frequency Offset Estimator (QuickLock) */ 673*9a0bf528SMauro Carvalho Chehab regs[0] = 0xCB; 674*9a0bf528SMauro Carvalho Chehab regs[1] = 0x40; 675*9a0bf528SMauro Carvalho Chehab regs[2] = 0xCB; 676*9a0bf528SMauro Carvalho Chehab 677*9a0bf528SMauro Carvalho Chehab status |= si21_writeregs(state, 678*9a0bf528SMauro Carvalho Chehab TWO_DB_BNDWDTH_THRSHLD_REG, 679*9a0bf528SMauro Carvalho Chehab ®s[0], 0x03); 680*9a0bf528SMauro Carvalho Chehab reg = 0x56; 681*9a0bf528SMauro Carvalho Chehab status |= si21_writeregs(state, 682*9a0bf528SMauro Carvalho Chehab LSA_CTRL_REG_1, ®, 1); 683*9a0bf528SMauro Carvalho Chehab reg = 0x05; 684*9a0bf528SMauro Carvalho Chehab status |= si21_writeregs(state, 685*9a0bf528SMauro Carvalho Chehab BLIND_SCAN_CTRL_REG, ®, 1); 686*9a0bf528SMauro Carvalho Chehab /* start automatic acq */ 687*9a0bf528SMauro Carvalho Chehab status |= si21_writeregs(state, 688*9a0bf528SMauro Carvalho Chehab ACQ_CTRL_REG_2, &start_acq, 0x01); 689*9a0bf528SMauro Carvalho Chehab 690*9a0bf528SMauro Carvalho Chehab return status; 691*9a0bf528SMauro Carvalho Chehab } 692*9a0bf528SMauro Carvalho Chehab 693*9a0bf528SMauro Carvalho Chehab static int si21xx_set_frontend(struct dvb_frontend *fe) 694*9a0bf528SMauro Carvalho Chehab { 695*9a0bf528SMauro Carvalho Chehab struct si21xx_state *state = fe->demodulator_priv; 696*9a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *c = &fe->dtv_property_cache; 697*9a0bf528SMauro Carvalho Chehab 698*9a0bf528SMauro Carvalho Chehab /* freq Channel carrier frequency in KHz (i.e. 1550000 KHz) 699*9a0bf528SMauro Carvalho Chehab datarate Channel symbol rate in Sps (i.e. 22500000 Sps)*/ 700*9a0bf528SMauro Carvalho Chehab 701*9a0bf528SMauro Carvalho Chehab /* in MHz */ 702*9a0bf528SMauro Carvalho Chehab unsigned char coarse_tune_freq; 703*9a0bf528SMauro Carvalho Chehab int fine_tune_freq; 704*9a0bf528SMauro Carvalho Chehab unsigned char sample_rate = 0; 705*9a0bf528SMauro Carvalho Chehab /* boolean */ 706*9a0bf528SMauro Carvalho Chehab bool inband_interferer_ind; 707*9a0bf528SMauro Carvalho Chehab 708*9a0bf528SMauro Carvalho Chehab /* INTERMEDIATE VALUES */ 709*9a0bf528SMauro Carvalho Chehab int icoarse_tune_freq; /* MHz */ 710*9a0bf528SMauro Carvalho Chehab int ifine_tune_freq; /* MHz */ 711*9a0bf528SMauro Carvalho Chehab unsigned int band_high; 712*9a0bf528SMauro Carvalho Chehab unsigned int band_low; 713*9a0bf528SMauro Carvalho Chehab unsigned int x1; 714*9a0bf528SMauro Carvalho Chehab unsigned int x2; 715*9a0bf528SMauro Carvalho Chehab int i; 716*9a0bf528SMauro Carvalho Chehab bool inband_interferer_div2[ALLOWABLE_FS_COUNT]; 717*9a0bf528SMauro Carvalho Chehab bool inband_interferer_div4[ALLOWABLE_FS_COUNT]; 718*9a0bf528SMauro Carvalho Chehab int status; 719*9a0bf528SMauro Carvalho Chehab 720*9a0bf528SMauro Carvalho Chehab /* allowable sample rates for ADC in MHz */ 721*9a0bf528SMauro Carvalho Chehab int afs[ALLOWABLE_FS_COUNT] = { 200, 192, 193, 194, 195, 722*9a0bf528SMauro Carvalho Chehab 196, 204, 205, 206, 207 723*9a0bf528SMauro Carvalho Chehab }; 724*9a0bf528SMauro Carvalho Chehab /* in MHz */ 725*9a0bf528SMauro Carvalho Chehab int if_limit_high; 726*9a0bf528SMauro Carvalho Chehab int if_limit_low; 727*9a0bf528SMauro Carvalho Chehab int lnb_lo; 728*9a0bf528SMauro Carvalho Chehab int lnb_uncertanity; 729*9a0bf528SMauro Carvalho Chehab 730*9a0bf528SMauro Carvalho Chehab int rf_freq; 731*9a0bf528SMauro Carvalho Chehab int data_rate; 732*9a0bf528SMauro Carvalho Chehab unsigned char regs[4]; 733*9a0bf528SMauro Carvalho Chehab 734*9a0bf528SMauro Carvalho Chehab dprintk("%s : FE_SET_FRONTEND\n", __func__); 735*9a0bf528SMauro Carvalho Chehab 736*9a0bf528SMauro Carvalho Chehab if (c->delivery_system != SYS_DVBS) { 737*9a0bf528SMauro Carvalho Chehab dprintk("%s: unsupported delivery system selected (%d)\n", 738*9a0bf528SMauro Carvalho Chehab __func__, c->delivery_system); 739*9a0bf528SMauro Carvalho Chehab return -EOPNOTSUPP; 740*9a0bf528SMauro Carvalho Chehab } 741*9a0bf528SMauro Carvalho Chehab 742*9a0bf528SMauro Carvalho Chehab for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) 743*9a0bf528SMauro Carvalho Chehab inband_interferer_div2[i] = inband_interferer_div4[i] = false; 744*9a0bf528SMauro Carvalho Chehab 745*9a0bf528SMauro Carvalho Chehab if_limit_high = -700000; 746*9a0bf528SMauro Carvalho Chehab if_limit_low = -100000; 747*9a0bf528SMauro Carvalho Chehab /* in MHz */ 748*9a0bf528SMauro Carvalho Chehab lnb_lo = 0; 749*9a0bf528SMauro Carvalho Chehab lnb_uncertanity = 0; 750*9a0bf528SMauro Carvalho Chehab 751*9a0bf528SMauro Carvalho Chehab rf_freq = 10 * c->frequency ; 752*9a0bf528SMauro Carvalho Chehab data_rate = c->symbol_rate / 100; 753*9a0bf528SMauro Carvalho Chehab 754*9a0bf528SMauro Carvalho Chehab status = PASS; 755*9a0bf528SMauro Carvalho Chehab 756*9a0bf528SMauro Carvalho Chehab band_low = (rf_freq - lnb_lo) - ((lnb_uncertanity * 200) 757*9a0bf528SMauro Carvalho Chehab + (data_rate * 135)) / 200; 758*9a0bf528SMauro Carvalho Chehab 759*9a0bf528SMauro Carvalho Chehab band_high = (rf_freq - lnb_lo) + ((lnb_uncertanity * 200) 760*9a0bf528SMauro Carvalho Chehab + (data_rate * 135)) / 200; 761*9a0bf528SMauro Carvalho Chehab 762*9a0bf528SMauro Carvalho Chehab 763*9a0bf528SMauro Carvalho Chehab icoarse_tune_freq = 100000 * 764*9a0bf528SMauro Carvalho Chehab (((rf_freq - lnb_lo) - 765*9a0bf528SMauro Carvalho Chehab (if_limit_low + if_limit_high) / 2) 766*9a0bf528SMauro Carvalho Chehab / 100000); 767*9a0bf528SMauro Carvalho Chehab 768*9a0bf528SMauro Carvalho Chehab ifine_tune_freq = (rf_freq - lnb_lo) - icoarse_tune_freq ; 769*9a0bf528SMauro Carvalho Chehab 770*9a0bf528SMauro Carvalho Chehab for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { 771*9a0bf528SMauro Carvalho Chehab x1 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) * 772*9a0bf528SMauro Carvalho Chehab (afs[i] * 2500) + afs[i] * 2500; 773*9a0bf528SMauro Carvalho Chehab 774*9a0bf528SMauro Carvalho Chehab x2 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) * 775*9a0bf528SMauro Carvalho Chehab (afs[i] * 2500); 776*9a0bf528SMauro Carvalho Chehab 777*9a0bf528SMauro Carvalho Chehab if (((band_low < x1) && (x1 < band_high)) || 778*9a0bf528SMauro Carvalho Chehab ((band_low < x2) && (x2 < band_high))) 779*9a0bf528SMauro Carvalho Chehab inband_interferer_div4[i] = true; 780*9a0bf528SMauro Carvalho Chehab 781*9a0bf528SMauro Carvalho Chehab } 782*9a0bf528SMauro Carvalho Chehab 783*9a0bf528SMauro Carvalho Chehab for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { 784*9a0bf528SMauro Carvalho Chehab x1 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) * 785*9a0bf528SMauro Carvalho Chehab (afs[i] * 5000) + afs[i] * 5000; 786*9a0bf528SMauro Carvalho Chehab 787*9a0bf528SMauro Carvalho Chehab x2 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) * 788*9a0bf528SMauro Carvalho Chehab (afs[i] * 5000); 789*9a0bf528SMauro Carvalho Chehab 790*9a0bf528SMauro Carvalho Chehab if (((band_low < x1) && (x1 < band_high)) || 791*9a0bf528SMauro Carvalho Chehab ((band_low < x2) && (x2 < band_high))) 792*9a0bf528SMauro Carvalho Chehab inband_interferer_div2[i] = true; 793*9a0bf528SMauro Carvalho Chehab } 794*9a0bf528SMauro Carvalho Chehab 795*9a0bf528SMauro Carvalho Chehab inband_interferer_ind = true; 796*9a0bf528SMauro Carvalho Chehab for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { 797*9a0bf528SMauro Carvalho Chehab if (inband_interferer_div2[i] || inband_interferer_div4[i]) { 798*9a0bf528SMauro Carvalho Chehab inband_interferer_ind = false; 799*9a0bf528SMauro Carvalho Chehab break; 800*9a0bf528SMauro Carvalho Chehab } 801*9a0bf528SMauro Carvalho Chehab } 802*9a0bf528SMauro Carvalho Chehab 803*9a0bf528SMauro Carvalho Chehab if (inband_interferer_ind) { 804*9a0bf528SMauro Carvalho Chehab for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { 805*9a0bf528SMauro Carvalho Chehab if (!inband_interferer_div2[i]) { 806*9a0bf528SMauro Carvalho Chehab sample_rate = (u8) afs[i]; 807*9a0bf528SMauro Carvalho Chehab break; 808*9a0bf528SMauro Carvalho Chehab } 809*9a0bf528SMauro Carvalho Chehab } 810*9a0bf528SMauro Carvalho Chehab } else { 811*9a0bf528SMauro Carvalho Chehab for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { 812*9a0bf528SMauro Carvalho Chehab if ((inband_interferer_div2[i] || 813*9a0bf528SMauro Carvalho Chehab !inband_interferer_div4[i])) { 814*9a0bf528SMauro Carvalho Chehab sample_rate = (u8) afs[i]; 815*9a0bf528SMauro Carvalho Chehab break; 816*9a0bf528SMauro Carvalho Chehab } 817*9a0bf528SMauro Carvalho Chehab } 818*9a0bf528SMauro Carvalho Chehab 819*9a0bf528SMauro Carvalho Chehab } 820*9a0bf528SMauro Carvalho Chehab 821*9a0bf528SMauro Carvalho Chehab if (sample_rate > 207 || sample_rate < 192) 822*9a0bf528SMauro Carvalho Chehab sample_rate = 200; 823*9a0bf528SMauro Carvalho Chehab 824*9a0bf528SMauro Carvalho Chehab fine_tune_freq = ((0x4000 * (ifine_tune_freq / 10)) / 825*9a0bf528SMauro Carvalho Chehab ((sample_rate) * 1000)); 826*9a0bf528SMauro Carvalho Chehab 827*9a0bf528SMauro Carvalho Chehab coarse_tune_freq = (u8)(icoarse_tune_freq / 100000); 828*9a0bf528SMauro Carvalho Chehab 829*9a0bf528SMauro Carvalho Chehab regs[0] = sample_rate; 830*9a0bf528SMauro Carvalho Chehab regs[1] = coarse_tune_freq; 831*9a0bf528SMauro Carvalho Chehab regs[2] = fine_tune_freq & 0xFF; 832*9a0bf528SMauro Carvalho Chehab regs[3] = fine_tune_freq >> 8 & 0xFF; 833*9a0bf528SMauro Carvalho Chehab 834*9a0bf528SMauro Carvalho Chehab status |= si21_writeregs(state, PLL_DIVISOR_REG, ®s[0], 0x04); 835*9a0bf528SMauro Carvalho Chehab 836*9a0bf528SMauro Carvalho Chehab state->fs = sample_rate;/*ADC MHz*/ 837*9a0bf528SMauro Carvalho Chehab si21xx_setacquire(fe, c->symbol_rate, c->fec_inner); 838*9a0bf528SMauro Carvalho Chehab 839*9a0bf528SMauro Carvalho Chehab return 0; 840*9a0bf528SMauro Carvalho Chehab } 841*9a0bf528SMauro Carvalho Chehab 842*9a0bf528SMauro Carvalho Chehab static int si21xx_sleep(struct dvb_frontend *fe) 843*9a0bf528SMauro Carvalho Chehab { 844*9a0bf528SMauro Carvalho Chehab struct si21xx_state *state = fe->demodulator_priv; 845*9a0bf528SMauro Carvalho Chehab u8 regdata; 846*9a0bf528SMauro Carvalho Chehab 847*9a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 848*9a0bf528SMauro Carvalho Chehab 849*9a0bf528SMauro Carvalho Chehab si21_readregs(state, SYSTEM_MODE_REG, ®data, 0x01); 850*9a0bf528SMauro Carvalho Chehab regdata |= 1 << 6; 851*9a0bf528SMauro Carvalho Chehab si21_writeregs(state, SYSTEM_MODE_REG, ®data, 0x01); 852*9a0bf528SMauro Carvalho Chehab state->initialised = 0; 853*9a0bf528SMauro Carvalho Chehab 854*9a0bf528SMauro Carvalho Chehab return 0; 855*9a0bf528SMauro Carvalho Chehab } 856*9a0bf528SMauro Carvalho Chehab 857*9a0bf528SMauro Carvalho Chehab static void si21xx_release(struct dvb_frontend *fe) 858*9a0bf528SMauro Carvalho Chehab { 859*9a0bf528SMauro Carvalho Chehab struct si21xx_state *state = fe->demodulator_priv; 860*9a0bf528SMauro Carvalho Chehab 861*9a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 862*9a0bf528SMauro Carvalho Chehab 863*9a0bf528SMauro Carvalho Chehab kfree(state); 864*9a0bf528SMauro Carvalho Chehab } 865*9a0bf528SMauro Carvalho Chehab 866*9a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops si21xx_ops = { 867*9a0bf528SMauro Carvalho Chehab .delsys = { SYS_DVBS }, 868*9a0bf528SMauro Carvalho Chehab .info = { 869*9a0bf528SMauro Carvalho Chehab .name = "SL SI21XX DVB-S", 870*9a0bf528SMauro Carvalho Chehab .frequency_min = 950000, 871*9a0bf528SMauro Carvalho Chehab .frequency_max = 2150000, 872*9a0bf528SMauro Carvalho Chehab .frequency_stepsize = 125, /* kHz for QPSK frontends */ 873*9a0bf528SMauro Carvalho Chehab .frequency_tolerance = 0, 874*9a0bf528SMauro Carvalho Chehab .symbol_rate_min = 1000000, 875*9a0bf528SMauro Carvalho Chehab .symbol_rate_max = 45000000, 876*9a0bf528SMauro Carvalho Chehab .symbol_rate_tolerance = 500, /* ppm */ 877*9a0bf528SMauro Carvalho Chehab .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 878*9a0bf528SMauro Carvalho Chehab FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | 879*9a0bf528SMauro Carvalho Chehab FE_CAN_QPSK | 880*9a0bf528SMauro Carvalho Chehab FE_CAN_FEC_AUTO 881*9a0bf528SMauro Carvalho Chehab }, 882*9a0bf528SMauro Carvalho Chehab 883*9a0bf528SMauro Carvalho Chehab .release = si21xx_release, 884*9a0bf528SMauro Carvalho Chehab .init = si21xx_init, 885*9a0bf528SMauro Carvalho Chehab .sleep = si21xx_sleep, 886*9a0bf528SMauro Carvalho Chehab .write = si21_write, 887*9a0bf528SMauro Carvalho Chehab .read_status = si21_read_status, 888*9a0bf528SMauro Carvalho Chehab .read_ber = si21_read_ber, 889*9a0bf528SMauro Carvalho Chehab .read_signal_strength = si21_read_signal_strength, 890*9a0bf528SMauro Carvalho Chehab .read_snr = si21_read_snr, 891*9a0bf528SMauro Carvalho Chehab .read_ucblocks = si21_read_ucblocks, 892*9a0bf528SMauro Carvalho Chehab .diseqc_send_master_cmd = si21xx_send_diseqc_msg, 893*9a0bf528SMauro Carvalho Chehab .diseqc_send_burst = si21xx_send_diseqc_burst, 894*9a0bf528SMauro Carvalho Chehab .set_tone = si21xx_set_tone, 895*9a0bf528SMauro Carvalho Chehab .set_voltage = si21xx_set_voltage, 896*9a0bf528SMauro Carvalho Chehab 897*9a0bf528SMauro Carvalho Chehab .set_frontend = si21xx_set_frontend, 898*9a0bf528SMauro Carvalho Chehab }; 899*9a0bf528SMauro Carvalho Chehab 900*9a0bf528SMauro Carvalho Chehab struct dvb_frontend *si21xx_attach(const struct si21xx_config *config, 901*9a0bf528SMauro Carvalho Chehab struct i2c_adapter *i2c) 902*9a0bf528SMauro Carvalho Chehab { 903*9a0bf528SMauro Carvalho Chehab struct si21xx_state *state = NULL; 904*9a0bf528SMauro Carvalho Chehab int id; 905*9a0bf528SMauro Carvalho Chehab 906*9a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 907*9a0bf528SMauro Carvalho Chehab 908*9a0bf528SMauro Carvalho Chehab /* allocate memory for the internal state */ 909*9a0bf528SMauro Carvalho Chehab state = kzalloc(sizeof(struct si21xx_state), GFP_KERNEL); 910*9a0bf528SMauro Carvalho Chehab if (state == NULL) 911*9a0bf528SMauro Carvalho Chehab goto error; 912*9a0bf528SMauro Carvalho Chehab 913*9a0bf528SMauro Carvalho Chehab /* setup the state */ 914*9a0bf528SMauro Carvalho Chehab state->config = config; 915*9a0bf528SMauro Carvalho Chehab state->i2c = i2c; 916*9a0bf528SMauro Carvalho Chehab state->initialised = 0; 917*9a0bf528SMauro Carvalho Chehab state->errmode = STATUS_BER; 918*9a0bf528SMauro Carvalho Chehab 919*9a0bf528SMauro Carvalho Chehab /* check if the demod is there */ 920*9a0bf528SMauro Carvalho Chehab id = si21_readreg(state, SYSTEM_MODE_REG); 921*9a0bf528SMauro Carvalho Chehab si21_writereg(state, SYSTEM_MODE_REG, id | 0x40); /* standby off */ 922*9a0bf528SMauro Carvalho Chehab msleep(200); 923*9a0bf528SMauro Carvalho Chehab id = si21_readreg(state, 0x00); 924*9a0bf528SMauro Carvalho Chehab 925*9a0bf528SMauro Carvalho Chehab /* register 0x00 contains: 926*9a0bf528SMauro Carvalho Chehab 0x34 for SI2107 927*9a0bf528SMauro Carvalho Chehab 0x24 for SI2108 928*9a0bf528SMauro Carvalho Chehab 0x14 for SI2109 929*9a0bf528SMauro Carvalho Chehab 0x04 for SI2110 930*9a0bf528SMauro Carvalho Chehab */ 931*9a0bf528SMauro Carvalho Chehab if (id != 0x04 && id != 0x14) 932*9a0bf528SMauro Carvalho Chehab goto error; 933*9a0bf528SMauro Carvalho Chehab 934*9a0bf528SMauro Carvalho Chehab /* create dvb_frontend */ 935*9a0bf528SMauro Carvalho Chehab memcpy(&state->frontend.ops, &si21xx_ops, 936*9a0bf528SMauro Carvalho Chehab sizeof(struct dvb_frontend_ops)); 937*9a0bf528SMauro Carvalho Chehab state->frontend.demodulator_priv = state; 938*9a0bf528SMauro Carvalho Chehab return &state->frontend; 939*9a0bf528SMauro Carvalho Chehab 940*9a0bf528SMauro Carvalho Chehab error: 941*9a0bf528SMauro Carvalho Chehab kfree(state); 942*9a0bf528SMauro Carvalho Chehab return NULL; 943*9a0bf528SMauro Carvalho Chehab } 944*9a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(si21xx_attach); 945*9a0bf528SMauro Carvalho Chehab 946*9a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644); 947*9a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); 948*9a0bf528SMauro Carvalho Chehab 949*9a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("SL SI21XX DVB Demodulator driver"); 950*9a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Igor M. Liplianin"); 951*9a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL"); 952