18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* DVB compliant Linux driver for the DVB-S si2109/2110 demodulator 38c2ecf20Sopenharmony_ci* 48c2ecf20Sopenharmony_ci* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) 58c2ecf20Sopenharmony_ci*/ 68c2ecf20Sopenharmony_ci#include <linux/init.h> 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/string.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 128c2ecf20Sopenharmony_ci#include <asm/div64.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 158c2ecf20Sopenharmony_ci#include "si21xx.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define REVISION_REG 0x00 188c2ecf20Sopenharmony_ci#define SYSTEM_MODE_REG 0x01 198c2ecf20Sopenharmony_ci#define TS_CTRL_REG_1 0x02 208c2ecf20Sopenharmony_ci#define TS_CTRL_REG_2 0x03 218c2ecf20Sopenharmony_ci#define PIN_CTRL_REG_1 0x04 228c2ecf20Sopenharmony_ci#define PIN_CTRL_REG_2 0x05 238c2ecf20Sopenharmony_ci#define LOCK_STATUS_REG_1 0x0f 248c2ecf20Sopenharmony_ci#define LOCK_STATUS_REG_2 0x10 258c2ecf20Sopenharmony_ci#define ACQ_STATUS_REG 0x11 268c2ecf20Sopenharmony_ci#define ACQ_CTRL_REG_1 0x13 278c2ecf20Sopenharmony_ci#define ACQ_CTRL_REG_2 0x14 288c2ecf20Sopenharmony_ci#define PLL_DIVISOR_REG 0x15 298c2ecf20Sopenharmony_ci#define COARSE_TUNE_REG 0x16 308c2ecf20Sopenharmony_ci#define FINE_TUNE_REG_L 0x17 318c2ecf20Sopenharmony_ci#define FINE_TUNE_REG_H 0x18 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define ANALOG_AGC_POWER_LEVEL_REG 0x28 348c2ecf20Sopenharmony_ci#define CFO_ESTIMATOR_CTRL_REG_1 0x29 358c2ecf20Sopenharmony_ci#define CFO_ESTIMATOR_CTRL_REG_2 0x2a 368c2ecf20Sopenharmony_ci#define CFO_ESTIMATOR_CTRL_REG_3 0x2b 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define SYM_RATE_ESTIMATE_REG_L 0x31 398c2ecf20Sopenharmony_ci#define SYM_RATE_ESTIMATE_REG_M 0x32 408c2ecf20Sopenharmony_ci#define SYM_RATE_ESTIMATE_REG_H 0x33 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define CFO_ESTIMATOR_OFFSET_REG_L 0x36 438c2ecf20Sopenharmony_ci#define CFO_ESTIMATOR_OFFSET_REG_H 0x37 448c2ecf20Sopenharmony_ci#define CFO_ERROR_REG_L 0x38 458c2ecf20Sopenharmony_ci#define CFO_ERROR_REG_H 0x39 468c2ecf20Sopenharmony_ci#define SYM_RATE_ESTIMATOR_CTRL_REG 0x3a 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define SYM_RATE_REG_L 0x3f 498c2ecf20Sopenharmony_ci#define SYM_RATE_REG_M 0x40 508c2ecf20Sopenharmony_ci#define SYM_RATE_REG_H 0x41 518c2ecf20Sopenharmony_ci#define SYM_RATE_ESTIMATOR_MAXIMUM_REG 0x42 528c2ecf20Sopenharmony_ci#define SYM_RATE_ESTIMATOR_MINIMUM_REG 0x43 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define C_N_ESTIMATOR_CTRL_REG 0x7c 558c2ecf20Sopenharmony_ci#define C_N_ESTIMATOR_THRSHLD_REG 0x7d 568c2ecf20Sopenharmony_ci#define C_N_ESTIMATOR_LEVEL_REG_L 0x7e 578c2ecf20Sopenharmony_ci#define C_N_ESTIMATOR_LEVEL_REG_H 0x7f 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define BLIND_SCAN_CTRL_REG 0x80 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define LSA_CTRL_REG_1 0x8D 628c2ecf20Sopenharmony_ci#define SPCTRM_TILT_CORR_THRSHLD_REG 0x8f 638c2ecf20Sopenharmony_ci#define ONE_DB_BNDWDTH_THRSHLD_REG 0x90 648c2ecf20Sopenharmony_ci#define TWO_DB_BNDWDTH_THRSHLD_REG 0x91 658c2ecf20Sopenharmony_ci#define THREE_DB_BNDWDTH_THRSHLD_REG 0x92 668c2ecf20Sopenharmony_ci#define INBAND_POWER_THRSHLD_REG 0x93 678c2ecf20Sopenharmony_ci#define REF_NOISE_LVL_MRGN_THRSHLD_REG 0x94 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define VIT_SRCH_CTRL_REG_1 0xa0 708c2ecf20Sopenharmony_ci#define VIT_SRCH_CTRL_REG_2 0xa1 718c2ecf20Sopenharmony_ci#define VIT_SRCH_CTRL_REG_3 0xa2 728c2ecf20Sopenharmony_ci#define VIT_SRCH_STATUS_REG 0xa3 738c2ecf20Sopenharmony_ci#define VITERBI_BER_COUNT_REG_L 0xab 748c2ecf20Sopenharmony_ci#define REED_SOLOMON_CTRL_REG 0xb0 758c2ecf20Sopenharmony_ci#define REED_SOLOMON_ERROR_COUNT_REG_L 0xb1 768c2ecf20Sopenharmony_ci#define PRBS_CTRL_REG 0xb5 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#define LNB_CTRL_REG_1 0xc0 798c2ecf20Sopenharmony_ci#define LNB_CTRL_REG_2 0xc1 808c2ecf20Sopenharmony_ci#define LNB_CTRL_REG_3 0xc2 818c2ecf20Sopenharmony_ci#define LNB_CTRL_REG_4 0xc3 828c2ecf20Sopenharmony_ci#define LNB_CTRL_STATUS_REG 0xc4 838c2ecf20Sopenharmony_ci#define LNB_FIFO_REGS_0 0xc5 848c2ecf20Sopenharmony_ci#define LNB_FIFO_REGS_1 0xc6 858c2ecf20Sopenharmony_ci#define LNB_FIFO_REGS_2 0xc7 868c2ecf20Sopenharmony_ci#define LNB_FIFO_REGS_3 0xc8 878c2ecf20Sopenharmony_ci#define LNB_FIFO_REGS_4 0xc9 888c2ecf20Sopenharmony_ci#define LNB_FIFO_REGS_5 0xca 898c2ecf20Sopenharmony_ci#define LNB_SUPPLY_CTRL_REG_1 0xcb 908c2ecf20Sopenharmony_ci#define LNB_SUPPLY_CTRL_REG_2 0xcc 918c2ecf20Sopenharmony_ci#define LNB_SUPPLY_CTRL_REG_3 0xcd 928c2ecf20Sopenharmony_ci#define LNB_SUPPLY_CTRL_REG_4 0xce 938c2ecf20Sopenharmony_ci#define LNB_SUPPLY_STATUS_REG 0xcf 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci#define FAIL -1 968c2ecf20Sopenharmony_ci#define PASS 0 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci#define ALLOWABLE_FS_COUNT 10 998c2ecf20Sopenharmony_ci#define STATUS_BER 0 1008c2ecf20Sopenharmony_ci#define STATUS_UCBLOCKS 1 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic int debug; 1038c2ecf20Sopenharmony_ci#define dprintk(args...) \ 1048c2ecf20Sopenharmony_ci do { \ 1058c2ecf20Sopenharmony_ci if (debug) \ 1068c2ecf20Sopenharmony_ci printk(KERN_DEBUG "si21xx: " args); \ 1078c2ecf20Sopenharmony_ci } while (0) 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cienum { 1108c2ecf20Sopenharmony_ci ACTIVE_HIGH, 1118c2ecf20Sopenharmony_ci ACTIVE_LOW 1128c2ecf20Sopenharmony_ci}; 1138c2ecf20Sopenharmony_cienum { 1148c2ecf20Sopenharmony_ci BYTE_WIDE, 1158c2ecf20Sopenharmony_ci BIT_WIDE 1168c2ecf20Sopenharmony_ci}; 1178c2ecf20Sopenharmony_cienum { 1188c2ecf20Sopenharmony_ci CLK_GAPPED_MODE, 1198c2ecf20Sopenharmony_ci CLK_CONTINUOUS_MODE 1208c2ecf20Sopenharmony_ci}; 1218c2ecf20Sopenharmony_cienum { 1228c2ecf20Sopenharmony_ci RISING_EDGE, 1238c2ecf20Sopenharmony_ci FALLING_EDGE 1248c2ecf20Sopenharmony_ci}; 1258c2ecf20Sopenharmony_cienum { 1268c2ecf20Sopenharmony_ci MSB_FIRST, 1278c2ecf20Sopenharmony_ci LSB_FIRST 1288c2ecf20Sopenharmony_ci}; 1298c2ecf20Sopenharmony_cienum { 1308c2ecf20Sopenharmony_ci SERIAL, 1318c2ecf20Sopenharmony_ci PARALLEL 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistruct si21xx_state { 1358c2ecf20Sopenharmony_ci struct i2c_adapter *i2c; 1368c2ecf20Sopenharmony_ci const struct si21xx_config *config; 1378c2ecf20Sopenharmony_ci struct dvb_frontend frontend; 1388c2ecf20Sopenharmony_ci u8 initialised:1; 1398c2ecf20Sopenharmony_ci int errmode; 1408c2ecf20Sopenharmony_ci int fs; /*Sampling rate of the ADC in MHz*/ 1418c2ecf20Sopenharmony_ci}; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/* register default initialization */ 1448c2ecf20Sopenharmony_cistatic u8 serit_sp1511lhb_inittab[] = { 1458c2ecf20Sopenharmony_ci 0x01, 0x28, /* set i2c_inc_disable */ 1468c2ecf20Sopenharmony_ci 0x20, 0x03, 1478c2ecf20Sopenharmony_ci 0x27, 0x20, 1488c2ecf20Sopenharmony_ci 0xe0, 0x45, 1498c2ecf20Sopenharmony_ci 0xe1, 0x08, 1508c2ecf20Sopenharmony_ci 0xfe, 0x01, 1518c2ecf20Sopenharmony_ci 0x01, 0x28, 1528c2ecf20Sopenharmony_ci 0x89, 0x09, 1538c2ecf20Sopenharmony_ci 0x04, 0x80, 1548c2ecf20Sopenharmony_ci 0x05, 0x01, 1558c2ecf20Sopenharmony_ci 0x06, 0x00, 1568c2ecf20Sopenharmony_ci 0x20, 0x03, 1578c2ecf20Sopenharmony_ci 0x24, 0x88, 1588c2ecf20Sopenharmony_ci 0x29, 0x09, 1598c2ecf20Sopenharmony_ci 0x2a, 0x0f, 1608c2ecf20Sopenharmony_ci 0x2c, 0x10, 1618c2ecf20Sopenharmony_ci 0x2d, 0x19, 1628c2ecf20Sopenharmony_ci 0x2e, 0x08, 1638c2ecf20Sopenharmony_ci 0x2f, 0x10, 1648c2ecf20Sopenharmony_ci 0x30, 0x19, 1658c2ecf20Sopenharmony_ci 0x34, 0x20, 1668c2ecf20Sopenharmony_ci 0x35, 0x03, 1678c2ecf20Sopenharmony_ci 0x45, 0x02, 1688c2ecf20Sopenharmony_ci 0x46, 0x45, 1698c2ecf20Sopenharmony_ci 0x47, 0xd0, 1708c2ecf20Sopenharmony_ci 0x48, 0x00, 1718c2ecf20Sopenharmony_ci 0x49, 0x40, 1728c2ecf20Sopenharmony_ci 0x4a, 0x03, 1738c2ecf20Sopenharmony_ci 0x4c, 0xfd, 1748c2ecf20Sopenharmony_ci 0x4f, 0x2e, 1758c2ecf20Sopenharmony_ci 0x50, 0x2e, 1768c2ecf20Sopenharmony_ci 0x51, 0x10, 1778c2ecf20Sopenharmony_ci 0x52, 0x10, 1788c2ecf20Sopenharmony_ci 0x56, 0x92, 1798c2ecf20Sopenharmony_ci 0x59, 0x00, 1808c2ecf20Sopenharmony_ci 0x5a, 0x2d, 1818c2ecf20Sopenharmony_ci 0x5b, 0x33, 1828c2ecf20Sopenharmony_ci 0x5c, 0x1f, 1838c2ecf20Sopenharmony_ci 0x5f, 0x76, 1848c2ecf20Sopenharmony_ci 0x62, 0xc0, 1858c2ecf20Sopenharmony_ci 0x63, 0xc0, 1868c2ecf20Sopenharmony_ci 0x64, 0xf3, 1878c2ecf20Sopenharmony_ci 0x65, 0xf3, 1888c2ecf20Sopenharmony_ci 0x79, 0x40, 1898c2ecf20Sopenharmony_ci 0x6a, 0x40, 1908c2ecf20Sopenharmony_ci 0x6b, 0x0a, 1918c2ecf20Sopenharmony_ci 0x6c, 0x80, 1928c2ecf20Sopenharmony_ci 0x6d, 0x27, 1938c2ecf20Sopenharmony_ci 0x71, 0x06, 1948c2ecf20Sopenharmony_ci 0x75, 0x60, 1958c2ecf20Sopenharmony_ci 0x78, 0x00, 1968c2ecf20Sopenharmony_ci 0x79, 0xb5, 1978c2ecf20Sopenharmony_ci 0x7c, 0x05, 1988c2ecf20Sopenharmony_ci 0x7d, 0x1a, 1998c2ecf20Sopenharmony_ci 0x87, 0x55, 2008c2ecf20Sopenharmony_ci 0x88, 0x72, 2018c2ecf20Sopenharmony_ci 0x8f, 0x08, 2028c2ecf20Sopenharmony_ci 0x90, 0xe0, 2038c2ecf20Sopenharmony_ci 0x94, 0x40, 2048c2ecf20Sopenharmony_ci 0xa0, 0x3f, 2058c2ecf20Sopenharmony_ci 0xa1, 0xc0, 2068c2ecf20Sopenharmony_ci 0xa4, 0xcc, 2078c2ecf20Sopenharmony_ci 0xa5, 0x66, 2088c2ecf20Sopenharmony_ci 0xa6, 0x66, 2098c2ecf20Sopenharmony_ci 0xa7, 0x7b, 2108c2ecf20Sopenharmony_ci 0xa8, 0x7b, 2118c2ecf20Sopenharmony_ci 0xa9, 0x7b, 2128c2ecf20Sopenharmony_ci 0xaa, 0x9a, 2138c2ecf20Sopenharmony_ci 0xed, 0x04, 2148c2ecf20Sopenharmony_ci 0xad, 0x00, 2158c2ecf20Sopenharmony_ci 0xae, 0x03, 2168c2ecf20Sopenharmony_ci 0xcc, 0xab, 2178c2ecf20Sopenharmony_ci 0x01, 0x08, 2188c2ecf20Sopenharmony_ci 0xff, 0xff 2198c2ecf20Sopenharmony_ci}; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci/* low level read/writes */ 2228c2ecf20Sopenharmony_cistatic int si21_writeregs(struct si21xx_state *state, u8 reg1, 2238c2ecf20Sopenharmony_ci u8 *data, int len) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci int ret; 2268c2ecf20Sopenharmony_ci u8 buf[60];/* = { reg1, data };*/ 2278c2ecf20Sopenharmony_ci struct i2c_msg msg = { 2288c2ecf20Sopenharmony_ci .addr = state->config->demod_address, 2298c2ecf20Sopenharmony_ci .flags = 0, 2308c2ecf20Sopenharmony_ci .buf = buf, 2318c2ecf20Sopenharmony_ci .len = len + 1 2328c2ecf20Sopenharmony_ci }; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (len > sizeof(buf) - 1) 2358c2ecf20Sopenharmony_ci return -EINVAL; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci msg.buf[0] = reg1; 2388c2ecf20Sopenharmony_ci memcpy(msg.buf + 1, data, len); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c, &msg, 1); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (ret != 1) 2438c2ecf20Sopenharmony_ci dprintk("%s: writereg error (reg1 == 0x%02x, data == 0x%02x, ret == %i)\n", 2448c2ecf20Sopenharmony_ci __func__, reg1, data[0], ret); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci return (ret != 1) ? -EREMOTEIO : 0; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int si21_writereg(struct si21xx_state *state, u8 reg, u8 data) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci int ret; 2528c2ecf20Sopenharmony_ci u8 buf[] = { reg, data }; 2538c2ecf20Sopenharmony_ci struct i2c_msg msg = { 2548c2ecf20Sopenharmony_ci .addr = state->config->demod_address, 2558c2ecf20Sopenharmony_ci .flags = 0, 2568c2ecf20Sopenharmony_ci .buf = buf, 2578c2ecf20Sopenharmony_ci .len = 2 2588c2ecf20Sopenharmony_ci }; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c, &msg, 1); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (ret != 1) 2638c2ecf20Sopenharmony_ci dprintk("%s: writereg error (reg == 0x%02x, data == 0x%02x, ret == %i)\n", 2648c2ecf20Sopenharmony_ci __func__, reg, data, ret); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci return (ret != 1) ? -EREMOTEIO : 0; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic int si21_write(struct dvb_frontend *fe, const u8 buf[], int len) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct si21xx_state *state = fe->demodulator_priv; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (len != 2) 2748c2ecf20Sopenharmony_ci return -EINVAL; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci return si21_writereg(state, buf[0], buf[1]); 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic u8 si21_readreg(struct si21xx_state *state, u8 reg) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci int ret; 2828c2ecf20Sopenharmony_ci u8 b0[] = { reg }; 2838c2ecf20Sopenharmony_ci u8 b1[] = { 0 }; 2848c2ecf20Sopenharmony_ci struct i2c_msg msg[] = { 2858c2ecf20Sopenharmony_ci { 2868c2ecf20Sopenharmony_ci .addr = state->config->demod_address, 2878c2ecf20Sopenharmony_ci .flags = 0, 2888c2ecf20Sopenharmony_ci .buf = b0, 2898c2ecf20Sopenharmony_ci .len = 1 2908c2ecf20Sopenharmony_ci }, { 2918c2ecf20Sopenharmony_ci .addr = state->config->demod_address, 2928c2ecf20Sopenharmony_ci .flags = I2C_M_RD, 2938c2ecf20Sopenharmony_ci .buf = b1, 2948c2ecf20Sopenharmony_ci .len = 1 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci }; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c, msg, 2); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci if (ret != 2) 3018c2ecf20Sopenharmony_ci dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", 3028c2ecf20Sopenharmony_ci __func__, reg, ret); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return b1[0]; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic int si21_readregs(struct si21xx_state *state, u8 reg1, u8 *b, u8 len) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci int ret; 3108c2ecf20Sopenharmony_ci struct i2c_msg msg[] = { 3118c2ecf20Sopenharmony_ci { 3128c2ecf20Sopenharmony_ci .addr = state->config->demod_address, 3138c2ecf20Sopenharmony_ci .flags = 0, 3148c2ecf20Sopenharmony_ci .buf = ®1, 3158c2ecf20Sopenharmony_ci .len = 1 3168c2ecf20Sopenharmony_ci }, { 3178c2ecf20Sopenharmony_ci .addr = state->config->demod_address, 3188c2ecf20Sopenharmony_ci .flags = I2C_M_RD, 3198c2ecf20Sopenharmony_ci .buf = b, 3208c2ecf20Sopenharmony_ci .len = len 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci }; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c, msg, 2); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (ret != 2) 3278c2ecf20Sopenharmony_ci dprintk("%s: readreg error (ret == %i)\n", __func__, ret); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci return ret == 2 ? 0 : -1; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic int si21xx_wait_diseqc_idle(struct si21xx_state *state, int timeout) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci unsigned long start = jiffies; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci while ((si21_readreg(state, LNB_CTRL_REG_1) & 0x8) == 8) { 3398c2ecf20Sopenharmony_ci if (jiffies - start > timeout) { 3408c2ecf20Sopenharmony_ci dprintk("%s: timeout!!\n", __func__); 3418c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci msleep(10); 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic int si21xx_set_symbolrate(struct dvb_frontend *fe, u32 srate) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct si21xx_state *state = fe->demodulator_priv; 3528c2ecf20Sopenharmony_ci u32 sym_rate, data_rate; 3538c2ecf20Sopenharmony_ci int i; 3548c2ecf20Sopenharmony_ci u8 sym_rate_bytes[3]; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci dprintk("%s : srate = %i\n", __func__ , srate); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if ((srate < 1000000) || (srate > 45000000)) 3598c2ecf20Sopenharmony_ci return -EINVAL; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci data_rate = srate; 3628c2ecf20Sopenharmony_ci sym_rate = 0; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci for (i = 0; i < 4; ++i) { 3658c2ecf20Sopenharmony_ci sym_rate /= 100; 3668c2ecf20Sopenharmony_ci sym_rate = sym_rate + ((data_rate % 100) * 0x800000) / 3678c2ecf20Sopenharmony_ci state->fs; 3688c2ecf20Sopenharmony_ci data_rate /= 100; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci for (i = 0; i < 3; ++i) 3718c2ecf20Sopenharmony_ci sym_rate_bytes[i] = (u8)((sym_rate >> (i * 8)) & 0xff); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci si21_writeregs(state, SYM_RATE_REG_L, sym_rate_bytes, 0x03); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci return 0; 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic int si21xx_send_diseqc_msg(struct dvb_frontend *fe, 3798c2ecf20Sopenharmony_ci struct dvb_diseqc_master_cmd *m) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci struct si21xx_state *state = fe->demodulator_priv; 3828c2ecf20Sopenharmony_ci u8 lnb_status; 3838c2ecf20Sopenharmony_ci u8 LNB_CTRL_1; 3848c2ecf20Sopenharmony_ci int status; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci status = PASS; 3898c2ecf20Sopenharmony_ci LNB_CTRL_1 = 0; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci status |= si21_readregs(state, LNB_CTRL_STATUS_REG, &lnb_status, 0x01); 3928c2ecf20Sopenharmony_ci status |= si21_readregs(state, LNB_CTRL_REG_1, &lnb_status, 0x01); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci /*fill the FIFO*/ 3958c2ecf20Sopenharmony_ci status |= si21_writeregs(state, LNB_FIFO_REGS_0, m->msg, m->msg_len); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci LNB_CTRL_1 = (lnb_status & 0x70); 3988c2ecf20Sopenharmony_ci LNB_CTRL_1 |= m->msg_len; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci LNB_CTRL_1 |= 0x80; /* begin LNB signaling */ 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci status |= si21_writeregs(state, LNB_CTRL_REG_1, &LNB_CTRL_1, 0x01); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci return status; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic int si21xx_send_diseqc_burst(struct dvb_frontend *fe, 4088c2ecf20Sopenharmony_ci enum fe_sec_mini_cmd burst) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct si21xx_state *state = fe->demodulator_priv; 4118c2ecf20Sopenharmony_ci u8 val; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (si21xx_wait_diseqc_idle(state, 100) < 0) 4168c2ecf20Sopenharmony_ci return -ETIMEDOUT; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci val = (0x80 | si21_readreg(state, 0xc1)); 4198c2ecf20Sopenharmony_ci if (si21_writereg(state, LNB_CTRL_REG_1, 4208c2ecf20Sopenharmony_ci burst == SEC_MINI_A ? (val & ~0x10) : (val | 0x10))) 4218c2ecf20Sopenharmony_ci return -EREMOTEIO; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (si21xx_wait_diseqc_idle(state, 100) < 0) 4248c2ecf20Sopenharmony_ci return -ETIMEDOUT; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (si21_writereg(state, LNB_CTRL_REG_1, val)) 4278c2ecf20Sopenharmony_ci return -EREMOTEIO; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci return 0; 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci/* 30.06.2008 */ 4328c2ecf20Sopenharmony_cistatic int si21xx_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct si21xx_state *state = fe->demodulator_priv; 4358c2ecf20Sopenharmony_ci u8 val; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 4388c2ecf20Sopenharmony_ci val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1)); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci switch (tone) { 4418c2ecf20Sopenharmony_ci case SEC_TONE_ON: 4428c2ecf20Sopenharmony_ci return si21_writereg(state, LNB_CTRL_REG_1, val | 0x20); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci case SEC_TONE_OFF: 4458c2ecf20Sopenharmony_ci return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x20)); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci default: 4488c2ecf20Sopenharmony_ci return -EINVAL; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic int si21xx_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage volt) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci struct si21xx_state *state = fe->demodulator_priv; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci u8 val; 4578c2ecf20Sopenharmony_ci dprintk("%s: %s\n", __func__, 4588c2ecf20Sopenharmony_ci volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : 4598c2ecf20Sopenharmony_ci volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1)); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci switch (volt) { 4658c2ecf20Sopenharmony_ci case SEC_VOLTAGE_18: 4668c2ecf20Sopenharmony_ci return si21_writereg(state, LNB_CTRL_REG_1, val | 0x40); 4678c2ecf20Sopenharmony_ci break; 4688c2ecf20Sopenharmony_ci case SEC_VOLTAGE_13: 4698c2ecf20Sopenharmony_ci return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x40)); 4708c2ecf20Sopenharmony_ci break; 4718c2ecf20Sopenharmony_ci default: 4728c2ecf20Sopenharmony_ci return -EINVAL; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic int si21xx_init(struct dvb_frontend *fe) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci struct si21xx_state *state = fe->demodulator_priv; 4798c2ecf20Sopenharmony_ci int i; 4808c2ecf20Sopenharmony_ci int status = 0; 4818c2ecf20Sopenharmony_ci u8 reg1; 4828c2ecf20Sopenharmony_ci u8 val; 4838c2ecf20Sopenharmony_ci u8 reg2[2]; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci for (i = 0; ; i += 2) { 4888c2ecf20Sopenharmony_ci reg1 = serit_sp1511lhb_inittab[i]; 4898c2ecf20Sopenharmony_ci val = serit_sp1511lhb_inittab[i+1]; 4908c2ecf20Sopenharmony_ci if (reg1 == 0xff && val == 0xff) 4918c2ecf20Sopenharmony_ci break; 4928c2ecf20Sopenharmony_ci si21_writeregs(state, reg1, &val, 1); 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci /*DVB QPSK SYSTEM MODE REG*/ 4968c2ecf20Sopenharmony_ci reg1 = 0x08; 4978c2ecf20Sopenharmony_ci si21_writeregs(state, SYSTEM_MODE_REG, ®1, 0x01); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci /*transport stream config*/ 5008c2ecf20Sopenharmony_ci /* 5018c2ecf20Sopenharmony_ci mode = PARALLEL; 5028c2ecf20Sopenharmony_ci sdata_form = LSB_FIRST; 5038c2ecf20Sopenharmony_ci clk_edge = FALLING_EDGE; 5048c2ecf20Sopenharmony_ci clk_mode = CLK_GAPPED_MODE; 5058c2ecf20Sopenharmony_ci strt_len = BYTE_WIDE; 5068c2ecf20Sopenharmony_ci sync_pol = ACTIVE_HIGH; 5078c2ecf20Sopenharmony_ci val_pol = ACTIVE_HIGH; 5088c2ecf20Sopenharmony_ci err_pol = ACTIVE_HIGH; 5098c2ecf20Sopenharmony_ci sclk_rate = 0x00; 5108c2ecf20Sopenharmony_ci parity = 0x00 ; 5118c2ecf20Sopenharmony_ci data_delay = 0x00; 5128c2ecf20Sopenharmony_ci clk_delay = 0x00; 5138c2ecf20Sopenharmony_ci pclk_smooth = 0x00; 5148c2ecf20Sopenharmony_ci */ 5158c2ecf20Sopenharmony_ci reg2[0] = 5168c2ecf20Sopenharmony_ci PARALLEL + (LSB_FIRST << 1) 5178c2ecf20Sopenharmony_ci + (FALLING_EDGE << 2) + (CLK_GAPPED_MODE << 3) 5188c2ecf20Sopenharmony_ci + (BYTE_WIDE << 4) + (ACTIVE_HIGH << 5) 5198c2ecf20Sopenharmony_ci + (ACTIVE_HIGH << 6) + (ACTIVE_HIGH << 7); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci reg2[1] = 0; 5228c2ecf20Sopenharmony_ci /* sclk_rate + (parity << 2) 5238c2ecf20Sopenharmony_ci + (data_delay << 3) + (clk_delay << 4) 5248c2ecf20Sopenharmony_ci + (pclk_smooth << 5); 5258c2ecf20Sopenharmony_ci */ 5268c2ecf20Sopenharmony_ci status |= si21_writeregs(state, TS_CTRL_REG_1, reg2, 0x02); 5278c2ecf20Sopenharmony_ci if (status != 0) 5288c2ecf20Sopenharmony_ci dprintk(" %s : TS Set Error\n", __func__); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci return 0; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistatic int si21_read_status(struct dvb_frontend *fe, enum fe_status *status) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci struct si21xx_state *state = fe->demodulator_priv; 5378c2ecf20Sopenharmony_ci u8 regs_read[2]; 5388c2ecf20Sopenharmony_ci u8 reg_read; 5398c2ecf20Sopenharmony_ci u8 i; 5408c2ecf20Sopenharmony_ci u8 lock; 5418c2ecf20Sopenharmony_ci u8 signal = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci si21_readregs(state, LOCK_STATUS_REG_1, regs_read, 0x02); 5448c2ecf20Sopenharmony_ci reg_read = 0; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci for (i = 0; i < 7; ++i) 5478c2ecf20Sopenharmony_ci reg_read |= ((regs_read[0] >> i) & 0x01) << (6 - i); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci lock = ((reg_read & 0x7f) | (regs_read[1] & 0x80)); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, lock); 5528c2ecf20Sopenharmony_ci *status = 0; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (signal > 10) 5558c2ecf20Sopenharmony_ci *status |= FE_HAS_SIGNAL; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (lock & 0x2) 5588c2ecf20Sopenharmony_ci *status |= FE_HAS_CARRIER; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci if (lock & 0x20) 5618c2ecf20Sopenharmony_ci *status |= FE_HAS_VITERBI; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci if (lock & 0x40) 5648c2ecf20Sopenharmony_ci *status |= FE_HAS_SYNC; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci if ((lock & 0x7b) == 0x7b) 5678c2ecf20Sopenharmony_ci *status |= FE_HAS_LOCK; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci return 0; 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic int si21_read_signal_strength(struct dvb_frontend *fe, u16 *strength) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci struct si21xx_state *state = fe->demodulator_priv; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci /*status = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG, 5778c2ecf20Sopenharmony_ci (u8*)agclevel, 0x01);*/ 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci u16 signal = (3 * si21_readreg(state, 0x27) * 5808c2ecf20Sopenharmony_ci si21_readreg(state, 0x28)); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci dprintk("%s : AGCPWR: 0x%02x%02x, signal=0x%04x\n", __func__, 5838c2ecf20Sopenharmony_ci si21_readreg(state, 0x27), 5848c2ecf20Sopenharmony_ci si21_readreg(state, 0x28), (int) signal); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci signal <<= 4; 5878c2ecf20Sopenharmony_ci *strength = signal; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci return 0; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cistatic int si21_read_ber(struct dvb_frontend *fe, u32 *ber) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci struct si21xx_state *state = fe->demodulator_priv; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (state->errmode != STATUS_BER) 5998c2ecf20Sopenharmony_ci return 0; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci *ber = (si21_readreg(state, 0x1d) << 8) | 6028c2ecf20Sopenharmony_ci si21_readreg(state, 0x1e); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci return 0; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic int si21_read_snr(struct dvb_frontend *fe, u16 *snr) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci struct si21xx_state *state = fe->demodulator_priv; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci s32 xsnr = 0xffff - ((si21_readreg(state, 0x24) << 8) | 6128c2ecf20Sopenharmony_ci si21_readreg(state, 0x25)); 6138c2ecf20Sopenharmony_ci xsnr = 3 * (xsnr - 0xa100); 6148c2ecf20Sopenharmony_ci *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci return 0; 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_cistatic int si21_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci struct si21xx_state *state = fe->demodulator_priv; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (state->errmode != STATUS_UCBLOCKS) 6288c2ecf20Sopenharmony_ci *ucblocks = 0; 6298c2ecf20Sopenharmony_ci else 6308c2ecf20Sopenharmony_ci *ucblocks = (si21_readreg(state, 0x1d) << 8) | 6318c2ecf20Sopenharmony_ci si21_readreg(state, 0x1e); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci return 0; 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci/* initiates a channel acquisition sequence 6378c2ecf20Sopenharmony_ci using the specified symbol rate and code rate */ 6388c2ecf20Sopenharmony_cistatic int si21xx_setacquire(struct dvb_frontend *fe, int symbrate, 6398c2ecf20Sopenharmony_ci enum fe_code_rate crate) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci struct si21xx_state *state = fe->demodulator_priv; 6438c2ecf20Sopenharmony_ci u8 coderates[] = { 6448c2ecf20Sopenharmony_ci 0x0, 0x01, 0x02, 0x04, 0x00, 6458c2ecf20Sopenharmony_ci 0x8, 0x10, 0x20, 0x00, 0x3f 6468c2ecf20Sopenharmony_ci }; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci u8 coderate_ptr; 6498c2ecf20Sopenharmony_ci int status; 6508c2ecf20Sopenharmony_ci u8 start_acq = 0x80; 6518c2ecf20Sopenharmony_ci u8 reg, regs[3]; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci status = PASS; 6568c2ecf20Sopenharmony_ci coderate_ptr = coderates[crate]; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci si21xx_set_symbolrate(fe, symbrate); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci /* write code rates to use in the Viterbi search */ 6618c2ecf20Sopenharmony_ci status |= si21_writeregs(state, 6628c2ecf20Sopenharmony_ci VIT_SRCH_CTRL_REG_1, 6638c2ecf20Sopenharmony_ci &coderate_ptr, 0x01); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci /* clear acq_start bit */ 6668c2ecf20Sopenharmony_ci status |= si21_readregs(state, ACQ_CTRL_REG_2, ®, 0x01); 6678c2ecf20Sopenharmony_ci reg &= ~start_acq; 6688c2ecf20Sopenharmony_ci status |= si21_writeregs(state, ACQ_CTRL_REG_2, ®, 0x01); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci /* use new Carrier Frequency Offset Estimator (QuickLock) */ 6718c2ecf20Sopenharmony_ci regs[0] = 0xCB; 6728c2ecf20Sopenharmony_ci regs[1] = 0x40; 6738c2ecf20Sopenharmony_ci regs[2] = 0xCB; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci status |= si21_writeregs(state, 6768c2ecf20Sopenharmony_ci TWO_DB_BNDWDTH_THRSHLD_REG, 6778c2ecf20Sopenharmony_ci ®s[0], 0x03); 6788c2ecf20Sopenharmony_ci reg = 0x56; 6798c2ecf20Sopenharmony_ci status |= si21_writeregs(state, 6808c2ecf20Sopenharmony_ci LSA_CTRL_REG_1, ®, 1); 6818c2ecf20Sopenharmony_ci reg = 0x05; 6828c2ecf20Sopenharmony_ci status |= si21_writeregs(state, 6838c2ecf20Sopenharmony_ci BLIND_SCAN_CTRL_REG, ®, 1); 6848c2ecf20Sopenharmony_ci /* start automatic acq */ 6858c2ecf20Sopenharmony_ci status |= si21_writeregs(state, 6868c2ecf20Sopenharmony_ci ACQ_CTRL_REG_2, &start_acq, 0x01); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci return status; 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_cistatic int si21xx_set_frontend(struct dvb_frontend *fe) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci struct si21xx_state *state = fe->demodulator_priv; 6948c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci /* freq Channel carrier frequency in KHz (i.e. 1550000 KHz) 6978c2ecf20Sopenharmony_ci datarate Channel symbol rate in Sps (i.e. 22500000 Sps)*/ 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci /* in MHz */ 7008c2ecf20Sopenharmony_ci unsigned char coarse_tune_freq; 7018c2ecf20Sopenharmony_ci int fine_tune_freq; 7028c2ecf20Sopenharmony_ci unsigned char sample_rate = 0; 7038c2ecf20Sopenharmony_ci /* boolean */ 7048c2ecf20Sopenharmony_ci bool inband_interferer_ind; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci /* INTERMEDIATE VALUES */ 7078c2ecf20Sopenharmony_ci int icoarse_tune_freq; /* MHz */ 7088c2ecf20Sopenharmony_ci int ifine_tune_freq; /* MHz */ 7098c2ecf20Sopenharmony_ci unsigned int band_high; 7108c2ecf20Sopenharmony_ci unsigned int band_low; 7118c2ecf20Sopenharmony_ci unsigned int x1; 7128c2ecf20Sopenharmony_ci unsigned int x2; 7138c2ecf20Sopenharmony_ci int i; 7148c2ecf20Sopenharmony_ci bool inband_interferer_div2[ALLOWABLE_FS_COUNT]; 7158c2ecf20Sopenharmony_ci bool inband_interferer_div4[ALLOWABLE_FS_COUNT]; 7168c2ecf20Sopenharmony_ci int status; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci /* allowable sample rates for ADC in MHz */ 7198c2ecf20Sopenharmony_ci int afs[ALLOWABLE_FS_COUNT] = { 200, 192, 193, 194, 195, 7208c2ecf20Sopenharmony_ci 196, 204, 205, 206, 207 7218c2ecf20Sopenharmony_ci }; 7228c2ecf20Sopenharmony_ci /* in MHz */ 7238c2ecf20Sopenharmony_ci int if_limit_high; 7248c2ecf20Sopenharmony_ci int if_limit_low; 7258c2ecf20Sopenharmony_ci int lnb_lo; 7268c2ecf20Sopenharmony_ci int lnb_uncertanity; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci int rf_freq; 7298c2ecf20Sopenharmony_ci int data_rate; 7308c2ecf20Sopenharmony_ci unsigned char regs[4]; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci dprintk("%s : FE_SET_FRONTEND\n", __func__); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci if (c->delivery_system != SYS_DVBS) { 7358c2ecf20Sopenharmony_ci dprintk("%s: unsupported delivery system selected (%d)\n", 7368c2ecf20Sopenharmony_ci __func__, c->delivery_system); 7378c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) 7418c2ecf20Sopenharmony_ci inband_interferer_div2[i] = inband_interferer_div4[i] = false; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci if_limit_high = -700000; 7448c2ecf20Sopenharmony_ci if_limit_low = -100000; 7458c2ecf20Sopenharmony_ci /* in MHz */ 7468c2ecf20Sopenharmony_ci lnb_lo = 0; 7478c2ecf20Sopenharmony_ci lnb_uncertanity = 0; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci rf_freq = 10 * c->frequency ; 7508c2ecf20Sopenharmony_ci data_rate = c->symbol_rate / 100; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci status = PASS; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci band_low = (rf_freq - lnb_lo) - ((lnb_uncertanity * 200) 7558c2ecf20Sopenharmony_ci + (data_rate * 135)) / 200; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci band_high = (rf_freq - lnb_lo) + ((lnb_uncertanity * 200) 7588c2ecf20Sopenharmony_ci + (data_rate * 135)) / 200; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci icoarse_tune_freq = 100000 * 7628c2ecf20Sopenharmony_ci (((rf_freq - lnb_lo) - 7638c2ecf20Sopenharmony_ci (if_limit_low + if_limit_high) / 2) 7648c2ecf20Sopenharmony_ci / 100000); 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci ifine_tune_freq = (rf_freq - lnb_lo) - icoarse_tune_freq ; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { 7698c2ecf20Sopenharmony_ci x1 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) * 7708c2ecf20Sopenharmony_ci (afs[i] * 2500) + afs[i] * 2500; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci x2 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) * 7738c2ecf20Sopenharmony_ci (afs[i] * 2500); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (((band_low < x1) && (x1 < band_high)) || 7768c2ecf20Sopenharmony_ci ((band_low < x2) && (x2 < band_high))) 7778c2ecf20Sopenharmony_ci inband_interferer_div4[i] = true; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { 7828c2ecf20Sopenharmony_ci x1 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) * 7838c2ecf20Sopenharmony_ci (afs[i] * 5000) + afs[i] * 5000; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci x2 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) * 7868c2ecf20Sopenharmony_ci (afs[i] * 5000); 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci if (((band_low < x1) && (x1 < band_high)) || 7898c2ecf20Sopenharmony_ci ((band_low < x2) && (x2 < band_high))) 7908c2ecf20Sopenharmony_ci inband_interferer_div2[i] = true; 7918c2ecf20Sopenharmony_ci } 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci inband_interferer_ind = true; 7948c2ecf20Sopenharmony_ci for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { 7958c2ecf20Sopenharmony_ci if (inband_interferer_div2[i] || inband_interferer_div4[i]) { 7968c2ecf20Sopenharmony_ci inband_interferer_ind = false; 7978c2ecf20Sopenharmony_ci break; 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci if (inband_interferer_ind) { 8028c2ecf20Sopenharmony_ci for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { 8038c2ecf20Sopenharmony_ci if (!inband_interferer_div2[i]) { 8048c2ecf20Sopenharmony_ci sample_rate = (u8) afs[i]; 8058c2ecf20Sopenharmony_ci break; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci } else { 8098c2ecf20Sopenharmony_ci for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { 8108c2ecf20Sopenharmony_ci if ((inband_interferer_div2[i] || 8118c2ecf20Sopenharmony_ci !inband_interferer_div4[i])) { 8128c2ecf20Sopenharmony_ci sample_rate = (u8) afs[i]; 8138c2ecf20Sopenharmony_ci break; 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci } 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci if (sample_rate > 207 || sample_rate < 192) 8208c2ecf20Sopenharmony_ci sample_rate = 200; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci fine_tune_freq = ((0x4000 * (ifine_tune_freq / 10)) / 8238c2ecf20Sopenharmony_ci ((sample_rate) * 1000)); 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci coarse_tune_freq = (u8)(icoarse_tune_freq / 100000); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci regs[0] = sample_rate; 8288c2ecf20Sopenharmony_ci regs[1] = coarse_tune_freq; 8298c2ecf20Sopenharmony_ci regs[2] = fine_tune_freq & 0xFF; 8308c2ecf20Sopenharmony_ci regs[3] = fine_tune_freq >> 8 & 0xFF; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci status |= si21_writeregs(state, PLL_DIVISOR_REG, ®s[0], 0x04); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci state->fs = sample_rate;/*ADC MHz*/ 8358c2ecf20Sopenharmony_ci si21xx_setacquire(fe, c->symbol_rate, c->fec_inner); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci return 0; 8388c2ecf20Sopenharmony_ci} 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_cistatic int si21xx_sleep(struct dvb_frontend *fe) 8418c2ecf20Sopenharmony_ci{ 8428c2ecf20Sopenharmony_ci struct si21xx_state *state = fe->demodulator_priv; 8438c2ecf20Sopenharmony_ci u8 regdata; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci si21_readregs(state, SYSTEM_MODE_REG, ®data, 0x01); 8488c2ecf20Sopenharmony_ci regdata |= 1 << 6; 8498c2ecf20Sopenharmony_ci si21_writeregs(state, SYSTEM_MODE_REG, ®data, 0x01); 8508c2ecf20Sopenharmony_ci state->initialised = 0; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci return 0; 8538c2ecf20Sopenharmony_ci} 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_cistatic void si21xx_release(struct dvb_frontend *fe) 8568c2ecf20Sopenharmony_ci{ 8578c2ecf20Sopenharmony_ci struct si21xx_state *state = fe->demodulator_priv; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci kfree(state); 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops si21xx_ops = { 8658c2ecf20Sopenharmony_ci .delsys = { SYS_DVBS }, 8668c2ecf20Sopenharmony_ci .info = { 8678c2ecf20Sopenharmony_ci .name = "SL SI21XX DVB-S", 8688c2ecf20Sopenharmony_ci .frequency_min_hz = 950 * MHz, 8698c2ecf20Sopenharmony_ci .frequency_max_hz = 2150 * MHz, 8708c2ecf20Sopenharmony_ci .frequency_stepsize_hz = 125 * kHz, 8718c2ecf20Sopenharmony_ci .symbol_rate_min = 1000000, 8728c2ecf20Sopenharmony_ci .symbol_rate_max = 45000000, 8738c2ecf20Sopenharmony_ci .symbol_rate_tolerance = 500, /* ppm */ 8748c2ecf20Sopenharmony_ci .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 8758c2ecf20Sopenharmony_ci FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | 8768c2ecf20Sopenharmony_ci FE_CAN_QPSK | 8778c2ecf20Sopenharmony_ci FE_CAN_FEC_AUTO 8788c2ecf20Sopenharmony_ci }, 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci .release = si21xx_release, 8818c2ecf20Sopenharmony_ci .init = si21xx_init, 8828c2ecf20Sopenharmony_ci .sleep = si21xx_sleep, 8838c2ecf20Sopenharmony_ci .write = si21_write, 8848c2ecf20Sopenharmony_ci .read_status = si21_read_status, 8858c2ecf20Sopenharmony_ci .read_ber = si21_read_ber, 8868c2ecf20Sopenharmony_ci .read_signal_strength = si21_read_signal_strength, 8878c2ecf20Sopenharmony_ci .read_snr = si21_read_snr, 8888c2ecf20Sopenharmony_ci .read_ucblocks = si21_read_ucblocks, 8898c2ecf20Sopenharmony_ci .diseqc_send_master_cmd = si21xx_send_diseqc_msg, 8908c2ecf20Sopenharmony_ci .diseqc_send_burst = si21xx_send_diseqc_burst, 8918c2ecf20Sopenharmony_ci .set_tone = si21xx_set_tone, 8928c2ecf20Sopenharmony_ci .set_voltage = si21xx_set_voltage, 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci .set_frontend = si21xx_set_frontend, 8958c2ecf20Sopenharmony_ci}; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistruct dvb_frontend *si21xx_attach(const struct si21xx_config *config, 8988c2ecf20Sopenharmony_ci struct i2c_adapter *i2c) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci struct si21xx_state *state = NULL; 9018c2ecf20Sopenharmony_ci int id; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci /* allocate memory for the internal state */ 9068c2ecf20Sopenharmony_ci state = kzalloc(sizeof(struct si21xx_state), GFP_KERNEL); 9078c2ecf20Sopenharmony_ci if (state == NULL) 9088c2ecf20Sopenharmony_ci goto error; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci /* setup the state */ 9118c2ecf20Sopenharmony_ci state->config = config; 9128c2ecf20Sopenharmony_ci state->i2c = i2c; 9138c2ecf20Sopenharmony_ci state->initialised = 0; 9148c2ecf20Sopenharmony_ci state->errmode = STATUS_BER; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci /* check if the demod is there */ 9178c2ecf20Sopenharmony_ci id = si21_readreg(state, SYSTEM_MODE_REG); 9188c2ecf20Sopenharmony_ci si21_writereg(state, SYSTEM_MODE_REG, id | 0x40); /* standby off */ 9198c2ecf20Sopenharmony_ci msleep(200); 9208c2ecf20Sopenharmony_ci id = si21_readreg(state, 0x00); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci /* register 0x00 contains: 9238c2ecf20Sopenharmony_ci 0x34 for SI2107 9248c2ecf20Sopenharmony_ci 0x24 for SI2108 9258c2ecf20Sopenharmony_ci 0x14 for SI2109 9268c2ecf20Sopenharmony_ci 0x04 for SI2110 9278c2ecf20Sopenharmony_ci */ 9288c2ecf20Sopenharmony_ci if (id != 0x04 && id != 0x14) 9298c2ecf20Sopenharmony_ci goto error; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci /* create dvb_frontend */ 9328c2ecf20Sopenharmony_ci memcpy(&state->frontend.ops, &si21xx_ops, 9338c2ecf20Sopenharmony_ci sizeof(struct dvb_frontend_ops)); 9348c2ecf20Sopenharmony_ci state->frontend.demodulator_priv = state; 9358c2ecf20Sopenharmony_ci return &state->frontend; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_cierror: 9388c2ecf20Sopenharmony_ci kfree(state); 9398c2ecf20Sopenharmony_ci return NULL; 9408c2ecf20Sopenharmony_ci} 9418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(si21xx_attach); 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 9448c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SL SI21XX DVB Demodulator driver"); 9478c2ecf20Sopenharmony_ciMODULE_AUTHOR("Igor M. Liplianin"); 9488c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 949