123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968 |
- /* DVB compliant Linux driver for the DVB-S si2109/2110 demodulator
- *
- * Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/string.h>
- #include <linux/slab.h>
- #include <linux/jiffies.h>
- #include <asm/div64.h>
- #include "dvb_frontend.h"
- #include "si21xx.h"
- #define REVISION_REG 0x00
- #define SYSTEM_MODE_REG 0x01
- #define TS_CTRL_REG_1 0x02
- #define TS_CTRL_REG_2 0x03
- #define PIN_CTRL_REG_1 0x04
- #define PIN_CTRL_REG_2 0x05
- #define LOCK_STATUS_REG_1 0x0f
- #define LOCK_STATUS_REG_2 0x10
- #define ACQ_STATUS_REG 0x11
- #define ACQ_CTRL_REG_1 0x13
- #define ACQ_CTRL_REG_2 0x14
- #define PLL_DIVISOR_REG 0x15
- #define COARSE_TUNE_REG 0x16
- #define FINE_TUNE_REG_L 0x17
- #define FINE_TUNE_REG_H 0x18
- #define ANALOG_AGC_POWER_LEVEL_REG 0x28
- #define CFO_ESTIMATOR_CTRL_REG_1 0x29
- #define CFO_ESTIMATOR_CTRL_REG_2 0x2a
- #define CFO_ESTIMATOR_CTRL_REG_3 0x2b
- #define SYM_RATE_ESTIMATE_REG_L 0x31
- #define SYM_RATE_ESTIMATE_REG_M 0x32
- #define SYM_RATE_ESTIMATE_REG_H 0x33
- #define CFO_ESTIMATOR_OFFSET_REG_L 0x36
- #define CFO_ESTIMATOR_OFFSET_REG_H 0x37
- #define CFO_ERROR_REG_L 0x38
- #define CFO_ERROR_REG_H 0x39
- #define SYM_RATE_ESTIMATOR_CTRL_REG 0x3a
- #define SYM_RATE_REG_L 0x3f
- #define SYM_RATE_REG_M 0x40
- #define SYM_RATE_REG_H 0x41
- #define SYM_RATE_ESTIMATOR_MAXIMUM_REG 0x42
- #define SYM_RATE_ESTIMATOR_MINIMUM_REG 0x43
- #define C_N_ESTIMATOR_CTRL_REG 0x7c
- #define C_N_ESTIMATOR_THRSHLD_REG 0x7d
- #define C_N_ESTIMATOR_LEVEL_REG_L 0x7e
- #define C_N_ESTIMATOR_LEVEL_REG_H 0x7f
- #define BLIND_SCAN_CTRL_REG 0x80
- #define LSA_CTRL_REG_1 0x8D
- #define SPCTRM_TILT_CORR_THRSHLD_REG 0x8f
- #define ONE_DB_BNDWDTH_THRSHLD_REG 0x90
- #define TWO_DB_BNDWDTH_THRSHLD_REG 0x91
- #define THREE_DB_BNDWDTH_THRSHLD_REG 0x92
- #define INBAND_POWER_THRSHLD_REG 0x93
- #define REF_NOISE_LVL_MRGN_THRSHLD_REG 0x94
- #define VIT_SRCH_CTRL_REG_1 0xa0
- #define VIT_SRCH_CTRL_REG_2 0xa1
- #define VIT_SRCH_CTRL_REG_3 0xa2
- #define VIT_SRCH_STATUS_REG 0xa3
- #define VITERBI_BER_COUNT_REG_L 0xab
- #define REED_SOLOMON_CTRL_REG 0xb0
- #define REED_SOLOMON_ERROR_COUNT_REG_L 0xb1
- #define PRBS_CTRL_REG 0xb5
- #define LNB_CTRL_REG_1 0xc0
- #define LNB_CTRL_REG_2 0xc1
- #define LNB_CTRL_REG_3 0xc2
- #define LNB_CTRL_REG_4 0xc3
- #define LNB_CTRL_STATUS_REG 0xc4
- #define LNB_FIFO_REGS_0 0xc5
- #define LNB_FIFO_REGS_1 0xc6
- #define LNB_FIFO_REGS_2 0xc7
- #define LNB_FIFO_REGS_3 0xc8
- #define LNB_FIFO_REGS_4 0xc9
- #define LNB_FIFO_REGS_5 0xca
- #define LNB_SUPPLY_CTRL_REG_1 0xcb
- #define LNB_SUPPLY_CTRL_REG_2 0xcc
- #define LNB_SUPPLY_CTRL_REG_3 0xcd
- #define LNB_SUPPLY_CTRL_REG_4 0xce
- #define LNB_SUPPLY_STATUS_REG 0xcf
- #define FAIL -1
- #define PASS 0
- #define ALLOWABLE_FS_COUNT 10
- #define STATUS_BER 0
- #define STATUS_UCBLOCKS 1
- static int debug;
- #define dprintk(args...) \
- do { \
- if (debug) \
- printk(KERN_DEBUG "si21xx: " args); \
- } while (0)
- enum {
- ACTIVE_HIGH,
- ACTIVE_LOW
- };
- enum {
- BYTE_WIDE,
- BIT_WIDE
- };
- enum {
- CLK_GAPPED_MODE,
- CLK_CONTINUOUS_MODE
- };
- enum {
- RISING_EDGE,
- FALLING_EDGE
- };
- enum {
- MSB_FIRST,
- LSB_FIRST
- };
- enum {
- SERIAL,
- PARALLEL
- };
- struct si21xx_state {
- struct i2c_adapter *i2c;
- const struct si21xx_config *config;
- struct dvb_frontend frontend;
- u8 initialised:1;
- int errmode;
- int fs; /*Sampling rate of the ADC in MHz*/
- };
- /* register default initialization */
- static u8 serit_sp1511lhb_inittab[] = {
- 0x01, 0x28, /* set i2c_inc_disable */
- 0x20, 0x03,
- 0x27, 0x20,
- 0xe0, 0x45,
- 0xe1, 0x08,
- 0xfe, 0x01,
- 0x01, 0x28,
- 0x89, 0x09,
- 0x04, 0x80,
- 0x05, 0x01,
- 0x06, 0x00,
- 0x20, 0x03,
- 0x24, 0x88,
- 0x29, 0x09,
- 0x2a, 0x0f,
- 0x2c, 0x10,
- 0x2d, 0x19,
- 0x2e, 0x08,
- 0x2f, 0x10,
- 0x30, 0x19,
- 0x34, 0x20,
- 0x35, 0x03,
- 0x45, 0x02,
- 0x46, 0x45,
- 0x47, 0xd0,
- 0x48, 0x00,
- 0x49, 0x40,
- 0x4a, 0x03,
- 0x4c, 0xfd,
- 0x4f, 0x2e,
- 0x50, 0x2e,
- 0x51, 0x10,
- 0x52, 0x10,
- 0x56, 0x92,
- 0x59, 0x00,
- 0x5a, 0x2d,
- 0x5b, 0x33,
- 0x5c, 0x1f,
- 0x5f, 0x76,
- 0x62, 0xc0,
- 0x63, 0xc0,
- 0x64, 0xf3,
- 0x65, 0xf3,
- 0x79, 0x40,
- 0x6a, 0x40,
- 0x6b, 0x0a,
- 0x6c, 0x80,
- 0x6d, 0x27,
- 0x71, 0x06,
- 0x75, 0x60,
- 0x78, 0x00,
- 0x79, 0xb5,
- 0x7c, 0x05,
- 0x7d, 0x1a,
- 0x87, 0x55,
- 0x88, 0x72,
- 0x8f, 0x08,
- 0x90, 0xe0,
- 0x94, 0x40,
- 0xa0, 0x3f,
- 0xa1, 0xc0,
- 0xa4, 0xcc,
- 0xa5, 0x66,
- 0xa6, 0x66,
- 0xa7, 0x7b,
- 0xa8, 0x7b,
- 0xa9, 0x7b,
- 0xaa, 0x9a,
- 0xed, 0x04,
- 0xad, 0x00,
- 0xae, 0x03,
- 0xcc, 0xab,
- 0x01, 0x08,
- 0xff, 0xff
- };
- /* low level read/writes */
- static int si21_writeregs(struct si21xx_state *state, u8 reg1,
- u8 *data, int len)
- {
- int ret;
- u8 buf[60];/* = { reg1, data };*/
- struct i2c_msg msg = {
- .addr = state->config->demod_address,
- .flags = 0,
- .buf = buf,
- .len = len + 1
- };
- msg.buf[0] = reg1;
- memcpy(msg.buf + 1, data, len);
- ret = i2c_transfer(state->i2c, &msg, 1);
- if (ret != 1)
- dprintk("%s: writereg error (reg1 == 0x%02x, data == 0x%02x, "
- "ret == %i)\n", __func__, reg1, data[0], ret);
- return (ret != 1) ? -EREMOTEIO : 0;
- }
- static int si21_writereg(struct si21xx_state *state, u8 reg, u8 data)
- {
- int ret;
- u8 buf[] = { reg, data };
- struct i2c_msg msg = {
- .addr = state->config->demod_address,
- .flags = 0,
- .buf = buf,
- .len = 2
- };
- ret = i2c_transfer(state->i2c, &msg, 1);
- if (ret != 1)
- dprintk("%s: writereg error (reg == 0x%02x, data == 0x%02x, "
- "ret == %i)\n", __func__, reg, data, ret);
- return (ret != 1) ? -EREMOTEIO : 0;
- }
- static int si21_write(struct dvb_frontend *fe, const u8 buf[], int len)
- {
- struct si21xx_state *state = fe->demodulator_priv;
- if (len != 2)
- return -EINVAL;
- return si21_writereg(state, buf[0], buf[1]);
- }
- static u8 si21_readreg(struct si21xx_state *state, u8 reg)
- {
- int ret;
- u8 b0[] = { reg };
- u8 b1[] = { 0 };
- struct i2c_msg msg[] = {
- {
- .addr = state->config->demod_address,
- .flags = 0,
- .buf = b0,
- .len = 1
- }, {
- .addr = state->config->demod_address,
- .flags = I2C_M_RD,
- .buf = b1,
- .len = 1
- }
- };
- ret = i2c_transfer(state->i2c, msg, 2);
- if (ret != 2)
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
- __func__, reg, ret);
- return b1[0];
- }
- static int si21_readregs(struct si21xx_state *state, u8 reg1, u8 *b, u8 len)
- {
- int ret;
- struct i2c_msg msg[] = {
- {
- .addr = state->config->demod_address,
- .flags = 0,
- .buf = ®1,
- .len = 1
- }, {
- .addr = state->config->demod_address,
- .flags = I2C_M_RD,
- .buf = b,
- .len = len
- }
- };
- ret = i2c_transfer(state->i2c, msg, 2);
- if (ret != 2)
- dprintk("%s: readreg error (ret == %i)\n", __func__, ret);
- return ret == 2 ? 0 : -1;
- }
- static int si21xx_wait_diseqc_idle(struct si21xx_state *state, int timeout)
- {
- unsigned long start = jiffies;
- dprintk("%s\n", __func__);
- while ((si21_readreg(state, LNB_CTRL_REG_1) & 0x8) == 8) {
- if (jiffies - start > timeout) {
- dprintk("%s: timeout!!\n", __func__);
- return -ETIMEDOUT;
- }
- msleep(10);
- };
- return 0;
- }
- static int si21xx_set_symbolrate(struct dvb_frontend *fe, u32 srate)
- {
- struct si21xx_state *state = fe->demodulator_priv;
- u32 sym_rate, data_rate;
- int i;
- u8 sym_rate_bytes[3];
- dprintk("%s : srate = %i\n", __func__ , srate);
- if ((srate < 1000000) || (srate > 45000000))
- return -EINVAL;
- data_rate = srate;
- sym_rate = 0;
- for (i = 0; i < 4; ++i) {
- sym_rate /= 100;
- sym_rate = sym_rate + ((data_rate % 100) * 0x800000) /
- state->fs;
- data_rate /= 100;
- }
- for (i = 0; i < 3; ++i)
- sym_rate_bytes[i] = (u8)((sym_rate >> (i * 8)) & 0xff);
- si21_writeregs(state, SYM_RATE_REG_L, sym_rate_bytes, 0x03);
- return 0;
- }
- static int si21xx_send_diseqc_msg(struct dvb_frontend *fe,
- struct dvb_diseqc_master_cmd *m)
- {
- struct si21xx_state *state = fe->demodulator_priv;
- u8 lnb_status;
- u8 LNB_CTRL_1;
- int status;
- dprintk("%s\n", __func__);
- status = PASS;
- LNB_CTRL_1 = 0;
- status |= si21_readregs(state, LNB_CTRL_STATUS_REG, &lnb_status, 0x01);
- status |= si21_readregs(state, LNB_CTRL_REG_1, &lnb_status, 0x01);
- /*fill the FIFO*/
- status |= si21_writeregs(state, LNB_FIFO_REGS_0, m->msg, m->msg_len);
- LNB_CTRL_1 = (lnb_status & 0x70);
- LNB_CTRL_1 |= m->msg_len;
- LNB_CTRL_1 |= 0x80; /* begin LNB signaling */
- status |= si21_writeregs(state, LNB_CTRL_REG_1, &LNB_CTRL_1, 0x01);
- return status;
- }
- static int si21xx_send_diseqc_burst(struct dvb_frontend *fe,
- fe_sec_mini_cmd_t burst)
- {
- struct si21xx_state *state = fe->demodulator_priv;
- u8 val;
- dprintk("%s\n", __func__);
- if (si21xx_wait_diseqc_idle(state, 100) < 0)
- return -ETIMEDOUT;
- val = (0x80 | si21_readreg(state, 0xc1));
- if (si21_writereg(state, LNB_CTRL_REG_1,
- burst == SEC_MINI_A ? (val & ~0x10) : (val | 0x10)))
- return -EREMOTEIO;
- if (si21xx_wait_diseqc_idle(state, 100) < 0)
- return -ETIMEDOUT;
- if (si21_writereg(state, LNB_CTRL_REG_1, val))
- return -EREMOTEIO;
- return 0;
- }
- /* 30.06.2008 */
- static int si21xx_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
- {
- struct si21xx_state *state = fe->demodulator_priv;
- u8 val;
- dprintk("%s\n", __func__);
- val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1));
- switch (tone) {
- case SEC_TONE_ON:
- return si21_writereg(state, LNB_CTRL_REG_1, val | 0x20);
- case SEC_TONE_OFF:
- return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x20));
- default:
- return -EINVAL;
- }
- }
- static int si21xx_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
- {
- struct si21xx_state *state = fe->demodulator_priv;
- u8 val;
- dprintk("%s: %s\n", __func__,
- volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
- volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
- val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1));
- switch (volt) {
- case SEC_VOLTAGE_18:
- return si21_writereg(state, LNB_CTRL_REG_1, val | 0x40);
- break;
- case SEC_VOLTAGE_13:
- return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x40));
- break;
- default:
- return -EINVAL;
- };
- }
- static int si21xx_init(struct dvb_frontend *fe)
- {
- struct si21xx_state *state = fe->demodulator_priv;
- int i;
- int status = 0;
- u8 reg1;
- u8 val;
- u8 reg2[2];
- dprintk("%s\n", __func__);
- for (i = 0; ; i += 2) {
- reg1 = serit_sp1511lhb_inittab[i];
- val = serit_sp1511lhb_inittab[i+1];
- if (reg1 == 0xff && val == 0xff)
- break;
- si21_writeregs(state, reg1, &val, 1);
- }
- /*DVB QPSK SYSTEM MODE REG*/
- reg1 = 0x08;
- si21_writeregs(state, SYSTEM_MODE_REG, ®1, 0x01);
- /*transport stream config*/
- /*
- mode = PARALLEL;
- sdata_form = LSB_FIRST;
- clk_edge = FALLING_EDGE;
- clk_mode = CLK_GAPPED_MODE;
- strt_len = BYTE_WIDE;
- sync_pol = ACTIVE_HIGH;
- val_pol = ACTIVE_HIGH;
- err_pol = ACTIVE_HIGH;
- sclk_rate = 0x00;
- parity = 0x00 ;
- data_delay = 0x00;
- clk_delay = 0x00;
- pclk_smooth = 0x00;
- */
- reg2[0] =
- PARALLEL + (LSB_FIRST << 1)
- + (FALLING_EDGE << 2) + (CLK_GAPPED_MODE << 3)
- + (BYTE_WIDE << 4) + (ACTIVE_HIGH << 5)
- + (ACTIVE_HIGH << 6) + (ACTIVE_HIGH << 7);
- reg2[1] = 0;
- /* sclk_rate + (parity << 2)
- + (data_delay << 3) + (clk_delay << 4)
- + (pclk_smooth << 5);
- */
- status |= si21_writeregs(state, TS_CTRL_REG_1, reg2, 0x02);
- if (status != 0)
- dprintk(" %s : TS Set Error\n", __func__);
- return 0;
- }
- static int si21_read_status(struct dvb_frontend *fe, fe_status_t *status)
- {
- struct si21xx_state *state = fe->demodulator_priv;
- u8 regs_read[2];
- u8 reg_read;
- u8 i;
- u8 lock;
- u8 signal = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG);
- si21_readregs(state, LOCK_STATUS_REG_1, regs_read, 0x02);
- reg_read = 0;
- for (i = 0; i < 7; ++i)
- reg_read |= ((regs_read[0] >> i) & 0x01) << (6 - i);
- lock = ((reg_read & 0x7f) | (regs_read[1] & 0x80));
- dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, lock);
- *status = 0;
- if (signal > 10)
- *status |= FE_HAS_SIGNAL;
- if (lock & 0x2)
- *status |= FE_HAS_CARRIER;
- if (lock & 0x20)
- *status |= FE_HAS_VITERBI;
- if (lock & 0x40)
- *status |= FE_HAS_SYNC;
- if ((lock & 0x7b) == 0x7b)
- *status |= FE_HAS_LOCK;
- return 0;
- }
- static int si21_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
- {
- struct si21xx_state *state = fe->demodulator_priv;
- /*status = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG,
- (u8*)agclevel, 0x01);*/
- u16 signal = (3 * si21_readreg(state, 0x27) *
- si21_readreg(state, 0x28));
- dprintk("%s : AGCPWR: 0x%02x%02x, signal=0x%04x\n", __func__,
- si21_readreg(state, 0x27),
- si21_readreg(state, 0x28), (int) signal);
- signal <<= 4;
- *strength = signal;
- return 0;
- }
- static int si21_read_ber(struct dvb_frontend *fe, u32 *ber)
- {
- struct si21xx_state *state = fe->demodulator_priv;
- dprintk("%s\n", __func__);
- if (state->errmode != STATUS_BER)
- return 0;
- *ber = (si21_readreg(state, 0x1d) << 8) |
- si21_readreg(state, 0x1e);
- return 0;
- }
- static int si21_read_snr(struct dvb_frontend *fe, u16 *snr)
- {
- struct si21xx_state *state = fe->demodulator_priv;
- s32 xsnr = 0xffff - ((si21_readreg(state, 0x24) << 8) |
- si21_readreg(state, 0x25));
- xsnr = 3 * (xsnr - 0xa100);
- *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr;
- dprintk("%s\n", __func__);
- return 0;
- }
- static int si21_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
- {
- struct si21xx_state *state = fe->demodulator_priv;
- dprintk("%s\n", __func__);
- if (state->errmode != STATUS_UCBLOCKS)
- *ucblocks = 0;
- else
- *ucblocks = (si21_readreg(state, 0x1d) << 8) |
- si21_readreg(state, 0x1e);
- return 0;
- }
- /* initiates a channel acquisition sequence
- using the specified symbol rate and code rate */
- static int si21xx_setacquire(struct dvb_frontend *fe, int symbrate,
- fe_code_rate_t crate)
- {
- struct si21xx_state *state = fe->demodulator_priv;
- u8 coderates[] = {
- 0x0, 0x01, 0x02, 0x04, 0x00,
- 0x8, 0x10, 0x20, 0x00, 0x3f
- };
- u8 coderate_ptr;
- int status;
- u8 start_acq = 0x80;
- u8 reg, regs[3];
- dprintk("%s\n", __func__);
- status = PASS;
- coderate_ptr = coderates[crate];
- si21xx_set_symbolrate(fe, symbrate);
- /* write code rates to use in the Viterbi search */
- status |= si21_writeregs(state,
- VIT_SRCH_CTRL_REG_1,
- &coderate_ptr, 0x01);
- /* clear acq_start bit */
- status |= si21_readregs(state, ACQ_CTRL_REG_2, ®, 0x01);
- reg &= ~start_acq;
- status |= si21_writeregs(state, ACQ_CTRL_REG_2, ®, 0x01);
- /* use new Carrier Frequency Offset Estimator (QuickLock) */
- regs[0] = 0xCB;
- regs[1] = 0x40;
- regs[2] = 0xCB;
- status |= si21_writeregs(state,
- TWO_DB_BNDWDTH_THRSHLD_REG,
- ®s[0], 0x03);
- reg = 0x56;
- status |= si21_writeregs(state,
- LSA_CTRL_REG_1, ®, 1);
- reg = 0x05;
- status |= si21_writeregs(state,
- BLIND_SCAN_CTRL_REG, ®, 1);
- /* start automatic acq */
- status |= si21_writeregs(state,
- ACQ_CTRL_REG_2, &start_acq, 0x01);
- return status;
- }
- static int si21xx_set_property(struct dvb_frontend *fe, struct dtv_property *p)
- {
- dprintk("%s(..)\n", __func__);
- return 0;
- }
- static int si21xx_get_property(struct dvb_frontend *fe, struct dtv_property *p)
- {
- dprintk("%s(..)\n", __func__);
- return 0;
- }
- static int si21xx_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *dfp)
- {
- struct si21xx_state *state = fe->demodulator_priv;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- /* freq Channel carrier frequency in KHz (i.e. 1550000 KHz)
- datarate Channel symbol rate in Sps (i.e. 22500000 Sps)*/
- /* in MHz */
- unsigned char coarse_tune_freq;
- int fine_tune_freq;
- unsigned char sample_rate = 0;
- /* boolean */
- bool inband_interferer_ind;
- /* INTERMEDIATE VALUES */
- int icoarse_tune_freq; /* MHz */
- int ifine_tune_freq; /* MHz */
- unsigned int band_high;
- unsigned int band_low;
- unsigned int x1;
- unsigned int x2;
- int i;
- bool inband_interferer_div2[ALLOWABLE_FS_COUNT];
- bool inband_interferer_div4[ALLOWABLE_FS_COUNT];
- int status;
- /* allowable sample rates for ADC in MHz */
- int afs[ALLOWABLE_FS_COUNT] = { 200, 192, 193, 194, 195,
- 196, 204, 205, 206, 207
- };
- /* in MHz */
- int if_limit_high;
- int if_limit_low;
- int lnb_lo;
- int lnb_uncertanity;
- int rf_freq;
- int data_rate;
- unsigned char regs[4];
- dprintk("%s : FE_SET_FRONTEND\n", __func__);
- if (c->delivery_system != SYS_DVBS) {
- dprintk("%s: unsupported delivery system selected (%d)\n",
- __func__, c->delivery_system);
- return -EOPNOTSUPP;
- }
- for (i = 0; i < ALLOWABLE_FS_COUNT; ++i)
- inband_interferer_div2[i] = inband_interferer_div4[i] = false;
- if_limit_high = -700000;
- if_limit_low = -100000;
- /* in MHz */
- lnb_lo = 0;
- lnb_uncertanity = 0;
- rf_freq = 10 * c->frequency ;
- data_rate = c->symbol_rate / 100;
- status = PASS;
- band_low = (rf_freq - lnb_lo) - ((lnb_uncertanity * 200)
- + (data_rate * 135)) / 200;
- band_high = (rf_freq - lnb_lo) + ((lnb_uncertanity * 200)
- + (data_rate * 135)) / 200;
- icoarse_tune_freq = 100000 *
- (((rf_freq - lnb_lo) -
- (if_limit_low + if_limit_high) / 2)
- / 100000);
- ifine_tune_freq = (rf_freq - lnb_lo) - icoarse_tune_freq ;
- for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
- x1 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) *
- (afs[i] * 2500) + afs[i] * 2500;
- x2 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) *
- (afs[i] * 2500);
- if (((band_low < x1) && (x1 < band_high)) ||
- ((band_low < x2) && (x2 < band_high)))
- inband_interferer_div4[i] = true;
- }
- for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
- x1 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) *
- (afs[i] * 5000) + afs[i] * 5000;
- x2 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) *
- (afs[i] * 5000);
- if (((band_low < x1) && (x1 < band_high)) ||
- ((band_low < x2) && (x2 < band_high)))
- inband_interferer_div2[i] = true;
- }
- inband_interferer_ind = true;
- for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
- if (inband_interferer_div2[i] || inband_interferer_div4[i]) {
- inband_interferer_ind = false;
- break;
- }
- }
- if (inband_interferer_ind) {
- for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
- if (!inband_interferer_div2[i]) {
- sample_rate = (u8) afs[i];
- break;
- }
- }
- } else {
- for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
- if ((inband_interferer_div2[i] ||
- !inband_interferer_div4[i])) {
- sample_rate = (u8) afs[i];
- break;
- }
- }
- }
- if (sample_rate > 207 || sample_rate < 192)
- sample_rate = 200;
- fine_tune_freq = ((0x4000 * (ifine_tune_freq / 10)) /
- ((sample_rate) * 1000));
- coarse_tune_freq = (u8)(icoarse_tune_freq / 100000);
- regs[0] = sample_rate;
- regs[1] = coarse_tune_freq;
- regs[2] = fine_tune_freq & 0xFF;
- regs[3] = fine_tune_freq >> 8 & 0xFF;
- status |= si21_writeregs(state, PLL_DIVISOR_REG, ®s[0], 0x04);
- state->fs = sample_rate;/*ADC MHz*/
- si21xx_setacquire(fe, c->symbol_rate, c->fec_inner);
- return 0;
- }
- static int si21xx_sleep(struct dvb_frontend *fe)
- {
- struct si21xx_state *state = fe->demodulator_priv;
- u8 regdata;
- dprintk("%s\n", __func__);
- si21_readregs(state, SYSTEM_MODE_REG, ®data, 0x01);
- regdata |= 1 << 6;
- si21_writeregs(state, SYSTEM_MODE_REG, ®data, 0x01);
- state->initialised = 0;
- return 0;
- }
- static void si21xx_release(struct dvb_frontend *fe)
- {
- struct si21xx_state *state = fe->demodulator_priv;
- dprintk("%s\n", __func__);
- kfree(state);
- }
- static struct dvb_frontend_ops si21xx_ops = {
- .info = {
- .name = "SL SI21XX DVB-S",
- .type = FE_QPSK,
- .frequency_min = 950000,
- .frequency_max = 2150000,
- .frequency_stepsize = 125, /* kHz for QPSK frontends */
- .frequency_tolerance = 0,
- .symbol_rate_min = 1000000,
- .symbol_rate_max = 45000000,
- .symbol_rate_tolerance = 500, /* ppm */
- .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
- FE_CAN_QPSK |
- FE_CAN_FEC_AUTO
- },
- .release = si21xx_release,
- .init = si21xx_init,
- .sleep = si21xx_sleep,
- .write = si21_write,
- .read_status = si21_read_status,
- .read_ber = si21_read_ber,
- .read_signal_strength = si21_read_signal_strength,
- .read_snr = si21_read_snr,
- .read_ucblocks = si21_read_ucblocks,
- .diseqc_send_master_cmd = si21xx_send_diseqc_msg,
- .diseqc_send_burst = si21xx_send_diseqc_burst,
- .set_tone = si21xx_set_tone,
- .set_voltage = si21xx_set_voltage,
- .set_property = si21xx_set_property,
- .get_property = si21xx_get_property,
- .set_frontend = si21xx_set_frontend,
- };
- struct dvb_frontend *si21xx_attach(const struct si21xx_config *config,
- struct i2c_adapter *i2c)
- {
- struct si21xx_state *state = NULL;
- int id;
- dprintk("%s\n", __func__);
- /* allocate memory for the internal state */
- state = kzalloc(sizeof(struct si21xx_state), GFP_KERNEL);
- if (state == NULL)
- goto error;
- /* setup the state */
- state->config = config;
- state->i2c = i2c;
- state->initialised = 0;
- state->errmode = STATUS_BER;
- /* check if the demod is there */
- id = si21_readreg(state, SYSTEM_MODE_REG);
- si21_writereg(state, SYSTEM_MODE_REG, id | 0x40); /* standby off */
- msleep(200);
- id = si21_readreg(state, 0x00);
- /* register 0x00 contains:
- 0x34 for SI2107
- 0x24 for SI2108
- 0x14 for SI2109
- 0x04 for SI2110
- */
- if (id != 0x04 && id != 0x14)
- goto error;
- /* create dvb_frontend */
- memcpy(&state->frontend.ops, &si21xx_ops,
- sizeof(struct dvb_frontend_ops));
- state->frontend.demodulator_priv = state;
- return &state->frontend;
- error:
- kfree(state);
- return NULL;
- }
- EXPORT_SYMBOL(si21xx_attach);
- module_param(debug, int, 0644);
- MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
- MODULE_DESCRIPTION("SL SI21XX DVB Demodulator driver");
- MODULE_AUTHOR("Igor M. Liplianin");
- MODULE_LICENSE("GPL");
|