?? si21xx.c
字號:
/* 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/version.h>#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 FALSE 0#define TRUE 1#define FAIL -1#define PASS 0#define ALLOWABLE_FS_COUNT 10#define STATUS_BER 0#define STATUS_UCBLOCKS 1static 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, 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;}#if 0static int si21xx_wait_diseqc_fifo(struct si21xx_state *state, int timeout){ unsigned long start = jiffies; dprintk("%s\n", __func__); while (((si21_readreg(state, 0xc4) >> 7) & 1) == 0) { if (jiffies - start > timeout) { dprintk("%s: timeout!!\n", __func__); return -ETIMEDOUT; } msleep(10); }; return 0;}#endifstatic 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;#if 0 u8 val; int i; if (si21xx_wait_diseqc_idle(state, 100) < 0) return -ETIMEDOUT; val = si21_readreg(state, 0x08); /* DiSEqC mode */ if (si21_writereg(state, 0x08, (val & ~0x7) | 0x6)) return -EREMOTEIO; for (i = 0; i < m->msg_len; i++) { if (si21xx_wait_diseqc_fifo(state, 100) < 0) return -ETIMEDOUT; if (si21_writereg(state, 0x09, m->msg[i])) return -EREMOTEIO; } if (si21xx_wait_diseqc_idle(state, 100) < 0) return -ETIMEDOUT; return 0; }int si21xx_set_lnb_msg(state, lnb_cmd){#endif 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);#if 0 LNB_CTRL_1 |= voltage << 6; /*voltage select*/ LNB_CTRL_1 |= tone << 5; /*continuous tone selection*/ LNB_CTRL_1 |= burst << 4; /*tone burst selection*/ LNB_CTRL_1 |= mmsg << 3; /*more messages indicator*/#endif 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 0 /* burst mode */ if (si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x10)) return -EREMOTEIO;#endif 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__);#if 0 if (si21xx_wait_diseqc_idle(state, 100) < 0) return -ETIMEDOUT;#endif 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" :
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -