18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci Driver for ST STV0299 demodulator 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci Copyright (C) 2001-2002 Convergence Integrated Media GmbH 68c2ecf20Sopenharmony_ci <ralph@convergence.de>, 78c2ecf20Sopenharmony_ci <holger@convergence.de>, 88c2ecf20Sopenharmony_ci <js@convergence.de> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci Philips SU1278/SH 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci Copyright (C) 2002 by Peter Schildmann <peter.schildmann@web.de> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci LG TDQF-S001F 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci Copyright (C) 2002 Felix Domke <tmbinc@elitedvb.net> 198c2ecf20Sopenharmony_ci & Andreas Oberritter <obi@linuxtv.org> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci Support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci Copyright (C) 2003 Vadim Catana <skystar@moldova.cc>: 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci Support for Philips SU1278 on Technotrend hardware 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci Copyright (C) 2004 Andrew de Quincey <adq_dvb@lidskialf.net> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci*/ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <linux/init.h> 348c2ecf20Sopenharmony_ci#include <linux/kernel.h> 358c2ecf20Sopenharmony_ci#include <linux/ktime.h> 368c2ecf20Sopenharmony_ci#include <linux/module.h> 378c2ecf20Sopenharmony_ci#include <linux/string.h> 388c2ecf20Sopenharmony_ci#include <linux/slab.h> 398c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 408c2ecf20Sopenharmony_ci#include <asm/div64.h> 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 438c2ecf20Sopenharmony_ci#include "stv0299.h" 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistruct stv0299_state { 468c2ecf20Sopenharmony_ci struct i2c_adapter* i2c; 478c2ecf20Sopenharmony_ci const struct stv0299_config* config; 488c2ecf20Sopenharmony_ci struct dvb_frontend frontend; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci u8 initialised:1; 518c2ecf20Sopenharmony_ci u32 tuner_frequency; 528c2ecf20Sopenharmony_ci u32 symbol_rate; 538c2ecf20Sopenharmony_ci enum fe_code_rate fec_inner; 548c2ecf20Sopenharmony_ci int errmode; 558c2ecf20Sopenharmony_ci u32 ucblocks; 568c2ecf20Sopenharmony_ci u8 mcr_reg; 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define STATUS_BER 0 608c2ecf20Sopenharmony_ci#define STATUS_UCBLOCKS 1 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic int debug; 638c2ecf20Sopenharmony_cistatic int debug_legacy_dish_switch; 648c2ecf20Sopenharmony_ci#define dprintk(args...) \ 658c2ecf20Sopenharmony_ci do { \ 668c2ecf20Sopenharmony_ci if (debug) printk(KERN_DEBUG "stv0299: " args); \ 678c2ecf20Sopenharmony_ci } while (0) 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci int ret; 738c2ecf20Sopenharmony_ci u8 buf [] = { reg, data }; 748c2ecf20Sopenharmony_ci struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci ret = i2c_transfer (state->i2c, &msg, 1); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (ret != 1) 798c2ecf20Sopenharmony_ci dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", 808c2ecf20Sopenharmony_ci __func__, reg, data, ret); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return (ret != 1) ? -EREMOTEIO : 0; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic int stv0299_write(struct dvb_frontend* fe, const u8 buf[], int len) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct stv0299_state* state = fe->demodulator_priv; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (len != 2) 908c2ecf20Sopenharmony_ci return -EINVAL; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci return stv0299_writeregI(state, buf[0], buf[1]); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic u8 stv0299_readreg (struct stv0299_state* state, u8 reg) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci int ret; 988c2ecf20Sopenharmony_ci u8 b0 [] = { reg }; 998c2ecf20Sopenharmony_ci u8 b1 [] = { 0 }; 1008c2ecf20Sopenharmony_ci struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, 1018c2ecf20Sopenharmony_ci { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci ret = i2c_transfer (state->i2c, msg, 2); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (ret != 2) 1068c2ecf20Sopenharmony_ci dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", 1078c2ecf20Sopenharmony_ci __func__, reg, ret); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return b1[0]; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci int ret; 1158c2ecf20Sopenharmony_ci struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = ®1, .len = 1 }, 1168c2ecf20Sopenharmony_ci { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } }; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci ret = i2c_transfer (state->i2c, msg, 2); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (ret != 2) 1218c2ecf20Sopenharmony_ci dprintk("%s: readreg error (ret == %i)\n", __func__, ret); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci return ret == 2 ? 0 : ret; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic int stv0299_set_FEC(struct stv0299_state *state, enum fe_code_rate fec) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci dprintk ("%s\n", __func__); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci switch (fec) { 1318c2ecf20Sopenharmony_ci case FEC_AUTO: 1328c2ecf20Sopenharmony_ci { 1338c2ecf20Sopenharmony_ci return stv0299_writeregI (state, 0x31, 0x1f); 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci case FEC_1_2: 1368c2ecf20Sopenharmony_ci { 1378c2ecf20Sopenharmony_ci return stv0299_writeregI (state, 0x31, 0x01); 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci case FEC_2_3: 1408c2ecf20Sopenharmony_ci { 1418c2ecf20Sopenharmony_ci return stv0299_writeregI (state, 0x31, 0x02); 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci case FEC_3_4: 1448c2ecf20Sopenharmony_ci { 1458c2ecf20Sopenharmony_ci return stv0299_writeregI (state, 0x31, 0x04); 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci case FEC_5_6: 1488c2ecf20Sopenharmony_ci { 1498c2ecf20Sopenharmony_ci return stv0299_writeregI (state, 0x31, 0x08); 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci case FEC_7_8: 1528c2ecf20Sopenharmony_ci { 1538c2ecf20Sopenharmony_ci return stv0299_writeregI (state, 0x31, 0x10); 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci default: 1568c2ecf20Sopenharmony_ci { 1578c2ecf20Sopenharmony_ci return -EINVAL; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic enum fe_code_rate stv0299_get_fec(struct stv0299_state *state) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci static enum fe_code_rate fec_tab[] = { FEC_2_3, FEC_3_4, FEC_5_6, 1658c2ecf20Sopenharmony_ci FEC_7_8, FEC_1_2 }; 1668c2ecf20Sopenharmony_ci u8 index; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci dprintk ("%s\n", __func__); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci index = stv0299_readreg (state, 0x1b); 1718c2ecf20Sopenharmony_ci index &= 0x7; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (index > 4) 1748c2ecf20Sopenharmony_ci return FEC_AUTO; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci return fec_tab [index]; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic int stv0299_wait_diseqc_fifo (struct stv0299_state* state, int timeout) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci unsigned long start = jiffies; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci dprintk ("%s\n", __func__); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci while (stv0299_readreg(state, 0x0a) & 1) { 1868c2ecf20Sopenharmony_ci if (jiffies - start > timeout) { 1878c2ecf20Sopenharmony_ci dprintk ("%s: timeout!!\n", __func__); 1888c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci msleep(10); 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci return 0; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci unsigned long start = jiffies; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci dprintk ("%s\n", __func__); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci while ((stv0299_readreg(state, 0x0a) & 3) != 2 ) { 2038c2ecf20Sopenharmony_ci if (jiffies - start > timeout) { 2048c2ecf20Sopenharmony_ci dprintk ("%s: timeout!!\n", __func__); 2058c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci msleep(10); 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci return 0; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic int stv0299_set_symbolrate (struct dvb_frontend* fe, u32 srate) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci struct stv0299_state* state = fe->demodulator_priv; 2168c2ecf20Sopenharmony_ci u64 big = srate; 2178c2ecf20Sopenharmony_ci u32 ratio; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci // check rate is within limits 2208c2ecf20Sopenharmony_ci if ((srate < 1000000) || (srate > 45000000)) return -EINVAL; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci // calculate value to program 2238c2ecf20Sopenharmony_ci big = big << 20; 2248c2ecf20Sopenharmony_ci big += (state->config->mclk-1); // round correctly 2258c2ecf20Sopenharmony_ci do_div(big, state->config->mclk); 2268c2ecf20Sopenharmony_ci ratio = big << 4; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci return state->config->set_symbol_rate(fe, srate, ratio); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic int stv0299_get_symbolrate (struct stv0299_state* state) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci u32 Mclk = state->config->mclk / 4096L; 2348c2ecf20Sopenharmony_ci u32 srate; 2358c2ecf20Sopenharmony_ci s32 offset; 2368c2ecf20Sopenharmony_ci u8 sfr[3]; 2378c2ecf20Sopenharmony_ci s8 rtf; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci dprintk ("%s\n", __func__); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci stv0299_readregs (state, 0x1f, sfr, 3); 2428c2ecf20Sopenharmony_ci stv0299_readregs (state, 0x1a, (u8 *)&rtf, 1); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci srate = (sfr[0] << 8) | sfr[1]; 2458c2ecf20Sopenharmony_ci srate *= Mclk; 2468c2ecf20Sopenharmony_ci srate /= 16; 2478c2ecf20Sopenharmony_ci srate += (sfr[2] >> 4) * Mclk / 256; 2488c2ecf20Sopenharmony_ci offset = (s32) rtf * (srate / 4096L); 2498c2ecf20Sopenharmony_ci offset /= 128; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci dprintk ("%s : srate = %i\n", __func__, srate); 2528c2ecf20Sopenharmony_ci dprintk ("%s : ofset = %i\n", __func__, offset); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci srate += offset; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci srate += 1000; 2578c2ecf20Sopenharmony_ci srate /= 2000; 2588c2ecf20Sopenharmony_ci srate *= 2000; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci return srate; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic int stv0299_send_diseqc_msg (struct dvb_frontend* fe, 2648c2ecf20Sopenharmony_ci struct dvb_diseqc_master_cmd *m) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci struct stv0299_state* state = fe->demodulator_priv; 2678c2ecf20Sopenharmony_ci u8 val; 2688c2ecf20Sopenharmony_ci int i; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci dprintk ("%s\n", __func__); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (stv0299_wait_diseqc_idle (state, 100) < 0) 2738c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci val = stv0299_readreg (state, 0x08); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x6)) /* DiSEqC mode */ 2788c2ecf20Sopenharmony_ci return -EREMOTEIO; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci for (i=0; i<m->msg_len; i++) { 2818c2ecf20Sopenharmony_ci if (stv0299_wait_diseqc_fifo (state, 100) < 0) 2828c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (stv0299_writeregI (state, 0x09, m->msg[i])) 2858c2ecf20Sopenharmony_ci return -EREMOTEIO; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (stv0299_wait_diseqc_idle (state, 100) < 0) 2898c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci return 0; 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic int stv0299_send_diseqc_burst(struct dvb_frontend *fe, 2958c2ecf20Sopenharmony_ci enum fe_sec_mini_cmd burst) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci struct stv0299_state* state = fe->demodulator_priv; 2988c2ecf20Sopenharmony_ci u8 val; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci dprintk ("%s\n", __func__); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (stv0299_wait_diseqc_idle (state, 100) < 0) 3038c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci val = stv0299_readreg (state, 0x08); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x2)) /* burst mode */ 3088c2ecf20Sopenharmony_ci return -EREMOTEIO; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (stv0299_writeregI (state, 0x09, burst == SEC_MINI_A ? 0x00 : 0xff)) 3118c2ecf20Sopenharmony_ci return -EREMOTEIO; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (stv0299_wait_diseqc_idle (state, 100) < 0) 3148c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (stv0299_writeregI (state, 0x08, val)) 3178c2ecf20Sopenharmony_ci return -EREMOTEIO; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci return 0; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic int stv0299_set_tone(struct dvb_frontend *fe, 3238c2ecf20Sopenharmony_ci enum fe_sec_tone_mode tone) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct stv0299_state* state = fe->demodulator_priv; 3268c2ecf20Sopenharmony_ci u8 val; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (stv0299_wait_diseqc_idle (state, 100) < 0) 3298c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci val = stv0299_readreg (state, 0x08); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci switch (tone) { 3348c2ecf20Sopenharmony_ci case SEC_TONE_ON: 3358c2ecf20Sopenharmony_ci return stv0299_writeregI (state, 0x08, val | 0x3); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci case SEC_TONE_OFF: 3388c2ecf20Sopenharmony_ci return stv0299_writeregI (state, 0x08, (val & ~0x3) | 0x02); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci default: 3418c2ecf20Sopenharmony_ci return -EINVAL; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic int stv0299_set_voltage(struct dvb_frontend *fe, 3468c2ecf20Sopenharmony_ci enum fe_sec_voltage voltage) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci struct stv0299_state* state = fe->demodulator_priv; 3498c2ecf20Sopenharmony_ci u8 reg0x08; 3508c2ecf20Sopenharmony_ci u8 reg0x0c; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci dprintk("%s: %s\n", __func__, 3538c2ecf20Sopenharmony_ci voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : 3548c2ecf20Sopenharmony_ci voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci reg0x08 = stv0299_readreg (state, 0x08); 3578c2ecf20Sopenharmony_ci reg0x0c = stv0299_readreg (state, 0x0c); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci /* 3608c2ecf20Sopenharmony_ci * H/V switching over OP0, OP1 and OP2 are LNB power enable bits 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_ci reg0x0c &= 0x0f; 3638c2ecf20Sopenharmony_ci reg0x08 = (reg0x08 & 0x3f) | (state->config->lock_output << 6); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci switch (voltage) { 3668c2ecf20Sopenharmony_ci case SEC_VOLTAGE_13: 3678c2ecf20Sopenharmony_ci if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0) 3688c2ecf20Sopenharmony_ci reg0x0c |= 0x10; /* OP1 off, OP0 on */ 3698c2ecf20Sopenharmony_ci else 3708c2ecf20Sopenharmony_ci reg0x0c |= 0x40; /* OP1 on, OP0 off */ 3718c2ecf20Sopenharmony_ci break; 3728c2ecf20Sopenharmony_ci case SEC_VOLTAGE_18: 3738c2ecf20Sopenharmony_ci reg0x0c |= 0x50; /* OP1 on, OP0 on */ 3748c2ecf20Sopenharmony_ci break; 3758c2ecf20Sopenharmony_ci case SEC_VOLTAGE_OFF: 3768c2ecf20Sopenharmony_ci /* LNB power off! */ 3778c2ecf20Sopenharmony_ci reg0x08 = 0x00; 3788c2ecf20Sopenharmony_ci reg0x0c = 0x00; 3798c2ecf20Sopenharmony_ci break; 3808c2ecf20Sopenharmony_ci default: 3818c2ecf20Sopenharmony_ci return -EINVAL; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (state->config->op0_off) 3858c2ecf20Sopenharmony_ci reg0x0c &= ~0x10; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci stv0299_writeregI(state, 0x08, reg0x08); 3888c2ecf20Sopenharmony_ci return stv0299_writeregI(state, 0x0c, reg0x0c); 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long cmd) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci struct stv0299_state* state = fe->demodulator_priv; 3948c2ecf20Sopenharmony_ci u8 reg0x08; 3958c2ecf20Sopenharmony_ci u8 reg0x0c; 3968c2ecf20Sopenharmony_ci u8 lv_mask = 0x40; 3978c2ecf20Sopenharmony_ci u8 last = 1; 3988c2ecf20Sopenharmony_ci int i; 3998c2ecf20Sopenharmony_ci ktime_t nexttime; 4008c2ecf20Sopenharmony_ci ktime_t tv[10]; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci reg0x08 = stv0299_readreg (state, 0x08); 4038c2ecf20Sopenharmony_ci reg0x0c = stv0299_readreg (state, 0x0c); 4048c2ecf20Sopenharmony_ci reg0x0c &= 0x0f; 4058c2ecf20Sopenharmony_ci stv0299_writeregI (state, 0x08, (reg0x08 & 0x3f) | (state->config->lock_output << 6)); 4068c2ecf20Sopenharmony_ci if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0) 4078c2ecf20Sopenharmony_ci lv_mask = 0x10; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci cmd = cmd << 1; 4108c2ecf20Sopenharmony_ci if (debug_legacy_dish_switch) 4118c2ecf20Sopenharmony_ci printk ("%s switch command: 0x%04lx\n",__func__, cmd); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci nexttime = ktime_get_boottime(); 4148c2ecf20Sopenharmony_ci if (debug_legacy_dish_switch) 4158c2ecf20Sopenharmony_ci tv[0] = nexttime; 4168c2ecf20Sopenharmony_ci stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */ 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci dvb_frontend_sleep_until(&nexttime, 32000); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci for (i=0; i<9; i++) { 4218c2ecf20Sopenharmony_ci if (debug_legacy_dish_switch) 4228c2ecf20Sopenharmony_ci tv[i+1] = ktime_get_boottime(); 4238c2ecf20Sopenharmony_ci if((cmd & 0x01) != last) { 4248c2ecf20Sopenharmony_ci /* set voltage to (last ? 13V : 18V) */ 4258c2ecf20Sopenharmony_ci stv0299_writeregI (state, 0x0c, reg0x0c | (last ? lv_mask : 0x50)); 4268c2ecf20Sopenharmony_ci last = (last) ? 0 : 1; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci cmd = cmd >> 1; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (i != 8) 4328c2ecf20Sopenharmony_ci dvb_frontend_sleep_until(&nexttime, 8000); 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci if (debug_legacy_dish_switch) { 4358c2ecf20Sopenharmony_ci printk ("%s(%d): switch delay (should be 32k followed by all 8k\n", 4368c2ecf20Sopenharmony_ci __func__, fe->dvb->num); 4378c2ecf20Sopenharmony_ci for (i = 1; i < 10; i++) 4388c2ecf20Sopenharmony_ci printk("%d: %d\n", i, 4398c2ecf20Sopenharmony_ci (int) ktime_us_delta(tv[i], tv[i-1])); 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci return 0; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic int stv0299_init (struct dvb_frontend* fe) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci struct stv0299_state* state = fe->demodulator_priv; 4488c2ecf20Sopenharmony_ci int i; 4498c2ecf20Sopenharmony_ci u8 reg; 4508c2ecf20Sopenharmony_ci u8 val; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci dprintk("stv0299: init chip\n"); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci stv0299_writeregI(state, 0x02, 0x30 | state->mcr_reg); 4558c2ecf20Sopenharmony_ci msleep(50); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci for (i = 0; ; i += 2) { 4588c2ecf20Sopenharmony_ci reg = state->config->inittab[i]; 4598c2ecf20Sopenharmony_ci val = state->config->inittab[i+1]; 4608c2ecf20Sopenharmony_ci if (reg == 0xff && val == 0xff) 4618c2ecf20Sopenharmony_ci break; 4628c2ecf20Sopenharmony_ci if (reg == 0x0c && state->config->op0_off) 4638c2ecf20Sopenharmony_ci val &= ~0x10; 4648c2ecf20Sopenharmony_ci if (reg == 0x2) 4658c2ecf20Sopenharmony_ci state->mcr_reg = val & 0xf; 4668c2ecf20Sopenharmony_ci stv0299_writeregI(state, reg, val); 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci return 0; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic int stv0299_read_status(struct dvb_frontend *fe, 4738c2ecf20Sopenharmony_ci enum fe_status *status) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci struct stv0299_state* state = fe->demodulator_priv; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci u8 signal = 0xff - stv0299_readreg (state, 0x18); 4788c2ecf20Sopenharmony_ci u8 sync = stv0299_readreg (state, 0x1b); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync); 4818c2ecf20Sopenharmony_ci *status = 0; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (signal > 10) 4848c2ecf20Sopenharmony_ci *status |= FE_HAS_SIGNAL; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci if (sync & 0x80) 4878c2ecf20Sopenharmony_ci *status |= FE_HAS_CARRIER; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci if (sync & 0x10) 4908c2ecf20Sopenharmony_ci *status |= FE_HAS_VITERBI; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci if (sync & 0x08) 4938c2ecf20Sopenharmony_ci *status |= FE_HAS_SYNC; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci if ((sync & 0x98) == 0x98) 4968c2ecf20Sopenharmony_ci *status |= FE_HAS_LOCK; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci return 0; 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic int stv0299_read_ber(struct dvb_frontend* fe, u32* ber) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci struct stv0299_state* state = fe->demodulator_priv; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci if (state->errmode != STATUS_BER) 5068c2ecf20Sopenharmony_ci return -ENOSYS; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci *ber = stv0299_readreg(state, 0x1e) | (stv0299_readreg(state, 0x1d) << 8); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci return 0; 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cistatic int stv0299_read_signal_strength(struct dvb_frontend* fe, u16* strength) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci struct stv0299_state* state = fe->demodulator_priv; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci s32 signal = 0xffff - ((stv0299_readreg (state, 0x18) << 8) 5188c2ecf20Sopenharmony_ci | stv0299_readreg (state, 0x19)); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __func__, 5218c2ecf20Sopenharmony_ci stv0299_readreg (state, 0x18), 5228c2ecf20Sopenharmony_ci stv0299_readreg (state, 0x19), (int) signal); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci signal = signal * 5 / 4; 5258c2ecf20Sopenharmony_ci *strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci return 0; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic int stv0299_read_snr(struct dvb_frontend* fe, u16* snr) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci struct stv0299_state* state = fe->demodulator_priv; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci s32 xsnr = 0xffff - ((stv0299_readreg (state, 0x24) << 8) 5358c2ecf20Sopenharmony_ci | stv0299_readreg (state, 0x25)); 5368c2ecf20Sopenharmony_ci xsnr = 3 * (xsnr - 0xa100); 5378c2ecf20Sopenharmony_ci *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci return 0; 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci struct stv0299_state* state = fe->demodulator_priv; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci if (state->errmode != STATUS_UCBLOCKS) 5478c2ecf20Sopenharmony_ci return -ENOSYS; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci state->ucblocks += stv0299_readreg(state, 0x1e); 5508c2ecf20Sopenharmony_ci state->ucblocks += (stv0299_readreg(state, 0x1d) << 8); 5518c2ecf20Sopenharmony_ci *ucblocks = state->ucblocks; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci return 0; 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic int stv0299_set_frontend(struct dvb_frontend *fe) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 5598c2ecf20Sopenharmony_ci struct stv0299_state* state = fe->demodulator_priv; 5608c2ecf20Sopenharmony_ci int invval = 0; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci dprintk ("%s : FE_SET_FRONTEND\n", __func__); 5638c2ecf20Sopenharmony_ci if (state->config->set_ts_params) 5648c2ecf20Sopenharmony_ci state->config->set_ts_params(fe, 0); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci // set the inversion 5678c2ecf20Sopenharmony_ci if (p->inversion == INVERSION_OFF) invval = 0; 5688c2ecf20Sopenharmony_ci else if (p->inversion == INVERSION_ON) invval = 1; 5698c2ecf20Sopenharmony_ci else { 5708c2ecf20Sopenharmony_ci printk("stv0299 does not support auto-inversion\n"); 5718c2ecf20Sopenharmony_ci return -EINVAL; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci if (state->config->invert) invval = (~invval) & 1; 5748c2ecf20Sopenharmony_ci stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.set_params) { 5778c2ecf20Sopenharmony_ci fe->ops.tuner_ops.set_params(fe); 5788c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci stv0299_set_FEC(state, p->fec_inner); 5828c2ecf20Sopenharmony_ci stv0299_set_symbolrate(fe, p->symbol_rate); 5838c2ecf20Sopenharmony_ci stv0299_writeregI(state, 0x22, 0x00); 5848c2ecf20Sopenharmony_ci stv0299_writeregI(state, 0x23, 0x00); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci state->tuner_frequency = p->frequency; 5878c2ecf20Sopenharmony_ci state->fec_inner = p->fec_inner; 5888c2ecf20Sopenharmony_ci state->symbol_rate = p->symbol_rate; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci return 0; 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic int stv0299_get_frontend(struct dvb_frontend *fe, 5948c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci struct stv0299_state* state = fe->demodulator_priv; 5978c2ecf20Sopenharmony_ci s32 derot_freq; 5988c2ecf20Sopenharmony_ci int invval; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci derot_freq = (s32)(s16) ((stv0299_readreg (state, 0x22) << 8) 6018c2ecf20Sopenharmony_ci | stv0299_readreg (state, 0x23)); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci derot_freq *= (state->config->mclk >> 16); 6048c2ecf20Sopenharmony_ci derot_freq += 500; 6058c2ecf20Sopenharmony_ci derot_freq /= 1000; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci p->frequency += derot_freq; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci invval = stv0299_readreg (state, 0x0c) & 1; 6108c2ecf20Sopenharmony_ci if (state->config->invert) invval = (~invval) & 1; 6118c2ecf20Sopenharmony_ci p->inversion = invval ? INVERSION_ON : INVERSION_OFF; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci p->fec_inner = stv0299_get_fec(state); 6148c2ecf20Sopenharmony_ci p->symbol_rate = stv0299_get_symbolrate(state); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci return 0; 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cistatic int stv0299_sleep(struct dvb_frontend* fe) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci struct stv0299_state* state = fe->demodulator_priv; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci stv0299_writeregI(state, 0x02, 0xb0 | state->mcr_reg); 6248c2ecf20Sopenharmony_ci state->initialised = 0; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci return 0; 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cistatic int stv0299_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci struct stv0299_state* state = fe->demodulator_priv; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci if (enable) { 6348c2ecf20Sopenharmony_ci stv0299_writeregI(state, 0x05, 0xb5); 6358c2ecf20Sopenharmony_ci } else { 6368c2ecf20Sopenharmony_ci stv0299_writeregI(state, 0x05, 0x35); 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci udelay(1); 6398c2ecf20Sopenharmony_ci return 0; 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_cistatic int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci struct stv0299_state* state = fe->demodulator_priv; 6458c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci fesettings->min_delay_ms = state->config->min_delay_ms; 6488c2ecf20Sopenharmony_ci if (p->symbol_rate < 10000000) { 6498c2ecf20Sopenharmony_ci fesettings->step_size = p->symbol_rate / 32000; 6508c2ecf20Sopenharmony_ci fesettings->max_drift = 5000; 6518c2ecf20Sopenharmony_ci } else { 6528c2ecf20Sopenharmony_ci fesettings->step_size = p->symbol_rate / 16000; 6538c2ecf20Sopenharmony_ci fesettings->max_drift = p->symbol_rate / 2000; 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci return 0; 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic void stv0299_release(struct dvb_frontend* fe) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci struct stv0299_state* state = fe->demodulator_priv; 6618c2ecf20Sopenharmony_ci kfree(state); 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops stv0299_ops; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_cistruct dvb_frontend* stv0299_attach(const struct stv0299_config* config, 6678c2ecf20Sopenharmony_ci struct i2c_adapter* i2c) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci struct stv0299_state* state = NULL; 6708c2ecf20Sopenharmony_ci int id; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci /* allocate memory for the internal state */ 6738c2ecf20Sopenharmony_ci state = kzalloc(sizeof(struct stv0299_state), GFP_KERNEL); 6748c2ecf20Sopenharmony_ci if (state == NULL) goto error; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci /* setup the state */ 6778c2ecf20Sopenharmony_ci state->config = config; 6788c2ecf20Sopenharmony_ci state->i2c = i2c; 6798c2ecf20Sopenharmony_ci state->initialised = 0; 6808c2ecf20Sopenharmony_ci state->tuner_frequency = 0; 6818c2ecf20Sopenharmony_ci state->symbol_rate = 0; 6828c2ecf20Sopenharmony_ci state->fec_inner = 0; 6838c2ecf20Sopenharmony_ci state->errmode = STATUS_BER; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci /* check if the demod is there */ 6868c2ecf20Sopenharmony_ci stv0299_writeregI(state, 0x02, 0x30); /* standby off */ 6878c2ecf20Sopenharmony_ci msleep(200); 6888c2ecf20Sopenharmony_ci id = stv0299_readreg(state, 0x00); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci /* register 0x00 contains 0xa1 for STV0299 and STV0299B */ 6918c2ecf20Sopenharmony_ci /* register 0x00 might contain 0x80 when returning from standby */ 6928c2ecf20Sopenharmony_ci if (id != 0xa1 && id != 0x80) goto error; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci /* create dvb_frontend */ 6958c2ecf20Sopenharmony_ci memcpy(&state->frontend.ops, &stv0299_ops, sizeof(struct dvb_frontend_ops)); 6968c2ecf20Sopenharmony_ci state->frontend.demodulator_priv = state; 6978c2ecf20Sopenharmony_ci return &state->frontend; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_cierror: 7008c2ecf20Sopenharmony_ci kfree(state); 7018c2ecf20Sopenharmony_ci return NULL; 7028c2ecf20Sopenharmony_ci} 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops stv0299_ops = { 7058c2ecf20Sopenharmony_ci .delsys = { SYS_DVBS }, 7068c2ecf20Sopenharmony_ci .info = { 7078c2ecf20Sopenharmony_ci .name = "ST STV0299 DVB-S", 7088c2ecf20Sopenharmony_ci .frequency_min_hz = 950 * MHz, 7098c2ecf20Sopenharmony_ci .frequency_max_hz = 2150 * MHz, 7108c2ecf20Sopenharmony_ci .frequency_stepsize_hz = 125 * kHz, 7118c2ecf20Sopenharmony_ci .symbol_rate_min = 1000000, 7128c2ecf20Sopenharmony_ci .symbol_rate_max = 45000000, 7138c2ecf20Sopenharmony_ci .symbol_rate_tolerance = 500, /* ppm */ 7148c2ecf20Sopenharmony_ci .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 7158c2ecf20Sopenharmony_ci FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | 7168c2ecf20Sopenharmony_ci FE_CAN_QPSK | 7178c2ecf20Sopenharmony_ci FE_CAN_FEC_AUTO 7188c2ecf20Sopenharmony_ci }, 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci .release = stv0299_release, 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci .init = stv0299_init, 7238c2ecf20Sopenharmony_ci .sleep = stv0299_sleep, 7248c2ecf20Sopenharmony_ci .write = stv0299_write, 7258c2ecf20Sopenharmony_ci .i2c_gate_ctrl = stv0299_i2c_gate_ctrl, 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci .set_frontend = stv0299_set_frontend, 7288c2ecf20Sopenharmony_ci .get_frontend = stv0299_get_frontend, 7298c2ecf20Sopenharmony_ci .get_tune_settings = stv0299_get_tune_settings, 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci .read_status = stv0299_read_status, 7328c2ecf20Sopenharmony_ci .read_ber = stv0299_read_ber, 7338c2ecf20Sopenharmony_ci .read_signal_strength = stv0299_read_signal_strength, 7348c2ecf20Sopenharmony_ci .read_snr = stv0299_read_snr, 7358c2ecf20Sopenharmony_ci .read_ucblocks = stv0299_read_ucblocks, 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci .diseqc_send_master_cmd = stv0299_send_diseqc_msg, 7388c2ecf20Sopenharmony_ci .diseqc_send_burst = stv0299_send_diseqc_burst, 7398c2ecf20Sopenharmony_ci .set_tone = stv0299_set_tone, 7408c2ecf20Sopenharmony_ci .set_voltage = stv0299_set_voltage, 7418c2ecf20Sopenharmony_ci .dishnetwork_send_legacy_command = stv0299_send_legacy_dish_cmd, 7428c2ecf20Sopenharmony_ci}; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cimodule_param(debug_legacy_dish_switch, int, 0444); 7458c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug_legacy_dish_switch, "Enable timing analysis for Dish Network legacy switches"); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 7488c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ST STV0299 DVB Demodulator driver"); 7518c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, Andreas Oberritter, Andrew de Quincey, Kenneth Aafly"); 7528c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(stv0299_attach); 755