19a0bf528SMauro Carvalho Chehab /* 29a0bf528SMauro Carvalho Chehab Driver for ST STV0299 demodulator 39a0bf528SMauro Carvalho Chehab 49a0bf528SMauro Carvalho Chehab Copyright (C) 2001-2002 Convergence Integrated Media GmbH 59a0bf528SMauro Carvalho Chehab <ralph@convergence.de>, 69a0bf528SMauro Carvalho Chehab <holger@convergence.de>, 79a0bf528SMauro Carvalho Chehab <js@convergence.de> 89a0bf528SMauro Carvalho Chehab 99a0bf528SMauro Carvalho Chehab 109a0bf528SMauro Carvalho Chehab Philips SU1278/SH 119a0bf528SMauro Carvalho Chehab 129a0bf528SMauro Carvalho Chehab Copyright (C) 2002 by Peter Schildmann <peter.schildmann@web.de> 139a0bf528SMauro Carvalho Chehab 149a0bf528SMauro Carvalho Chehab 159a0bf528SMauro Carvalho Chehab LG TDQF-S001F 169a0bf528SMauro Carvalho Chehab 179a0bf528SMauro Carvalho Chehab Copyright (C) 2002 Felix Domke <tmbinc@elitedvb.net> 189a0bf528SMauro Carvalho Chehab & Andreas Oberritter <obi@linuxtv.org> 199a0bf528SMauro Carvalho Chehab 209a0bf528SMauro Carvalho Chehab 219a0bf528SMauro Carvalho Chehab Support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B 229a0bf528SMauro Carvalho Chehab 239a0bf528SMauro Carvalho Chehab Copyright (C) 2003 Vadim Catana <skystar@moldova.cc>: 249a0bf528SMauro Carvalho Chehab 259a0bf528SMauro Carvalho Chehab Support for Philips SU1278 on Technotrend hardware 269a0bf528SMauro Carvalho Chehab 279a0bf528SMauro Carvalho Chehab Copyright (C) 2004 Andrew de Quincey <adq_dvb@lidskialf.net> 289a0bf528SMauro Carvalho Chehab 299a0bf528SMauro Carvalho Chehab This program is free software; you can redistribute it and/or modify 309a0bf528SMauro Carvalho Chehab it under the terms of the GNU General Public License as published by 319a0bf528SMauro Carvalho Chehab the Free Software Foundation; either version 2 of the License, or 329a0bf528SMauro Carvalho Chehab (at your option) any later version. 339a0bf528SMauro Carvalho Chehab 349a0bf528SMauro Carvalho Chehab This program is distributed in the hope that it will be useful, 359a0bf528SMauro Carvalho Chehab but WITHOUT ANY WARRANTY; without even the implied warranty of 369a0bf528SMauro Carvalho Chehab MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 379a0bf528SMauro Carvalho Chehab GNU General Public License for more details. 389a0bf528SMauro Carvalho Chehab 399a0bf528SMauro Carvalho Chehab You should have received a copy of the GNU General Public License 409a0bf528SMauro Carvalho Chehab along with this program; if not, write to the Free Software 419a0bf528SMauro Carvalho Chehab Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 429a0bf528SMauro Carvalho Chehab 439a0bf528SMauro Carvalho Chehab */ 449a0bf528SMauro Carvalho Chehab 459a0bf528SMauro Carvalho Chehab #include <linux/init.h> 469a0bf528SMauro Carvalho Chehab #include <linux/kernel.h> 479a0bf528SMauro Carvalho Chehab #include <linux/module.h> 489a0bf528SMauro Carvalho Chehab #include <linux/string.h> 499a0bf528SMauro Carvalho Chehab #include <linux/slab.h> 509a0bf528SMauro Carvalho Chehab #include <linux/jiffies.h> 519a0bf528SMauro Carvalho Chehab #include <asm/div64.h> 529a0bf528SMauro Carvalho Chehab 539a0bf528SMauro Carvalho Chehab #include "dvb_frontend.h" 549a0bf528SMauro Carvalho Chehab #include "stv0299.h" 559a0bf528SMauro Carvalho Chehab 569a0bf528SMauro Carvalho Chehab struct stv0299_state { 579a0bf528SMauro Carvalho Chehab struct i2c_adapter* i2c; 589a0bf528SMauro Carvalho Chehab const struct stv0299_config* config; 599a0bf528SMauro Carvalho Chehab struct dvb_frontend frontend; 609a0bf528SMauro Carvalho Chehab 619a0bf528SMauro Carvalho Chehab u8 initialised:1; 629a0bf528SMauro Carvalho Chehab u32 tuner_frequency; 639a0bf528SMauro Carvalho Chehab u32 symbol_rate; 64*0df289a2SMauro Carvalho Chehab enum fe_code_rate fec_inner; 659a0bf528SMauro Carvalho Chehab int errmode; 669a0bf528SMauro Carvalho Chehab u32 ucblocks; 679a0bf528SMauro Carvalho Chehab u8 mcr_reg; 689a0bf528SMauro Carvalho Chehab }; 699a0bf528SMauro Carvalho Chehab 709a0bf528SMauro Carvalho Chehab #define STATUS_BER 0 719a0bf528SMauro Carvalho Chehab #define STATUS_UCBLOCKS 1 729a0bf528SMauro Carvalho Chehab 739a0bf528SMauro Carvalho Chehab static int debug; 749a0bf528SMauro Carvalho Chehab static int debug_legacy_dish_switch; 759a0bf528SMauro Carvalho Chehab #define dprintk(args...) \ 769a0bf528SMauro Carvalho Chehab do { \ 779a0bf528SMauro Carvalho Chehab if (debug) printk(KERN_DEBUG "stv0299: " args); \ 789a0bf528SMauro Carvalho Chehab } while (0) 799a0bf528SMauro Carvalho Chehab 809a0bf528SMauro Carvalho Chehab 819a0bf528SMauro Carvalho Chehab static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data) 829a0bf528SMauro Carvalho Chehab { 839a0bf528SMauro Carvalho Chehab int ret; 849a0bf528SMauro Carvalho Chehab u8 buf [] = { reg, data }; 859a0bf528SMauro Carvalho Chehab struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; 869a0bf528SMauro Carvalho Chehab 879a0bf528SMauro Carvalho Chehab ret = i2c_transfer (state->i2c, &msg, 1); 889a0bf528SMauro Carvalho Chehab 899a0bf528SMauro Carvalho Chehab if (ret != 1) 909a0bf528SMauro Carvalho Chehab dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " 919a0bf528SMauro Carvalho Chehab "ret == %i)\n", __func__, reg, data, ret); 929a0bf528SMauro Carvalho Chehab 939a0bf528SMauro Carvalho Chehab return (ret != 1) ? -EREMOTEIO : 0; 949a0bf528SMauro Carvalho Chehab } 959a0bf528SMauro Carvalho Chehab 969a0bf528SMauro Carvalho Chehab static int stv0299_write(struct dvb_frontend* fe, const u8 buf[], int len) 979a0bf528SMauro Carvalho Chehab { 989a0bf528SMauro Carvalho Chehab struct stv0299_state* state = fe->demodulator_priv; 999a0bf528SMauro Carvalho Chehab 1009a0bf528SMauro Carvalho Chehab if (len != 2) 1019a0bf528SMauro Carvalho Chehab return -EINVAL; 1029a0bf528SMauro Carvalho Chehab 1039a0bf528SMauro Carvalho Chehab return stv0299_writeregI(state, buf[0], buf[1]); 1049a0bf528SMauro Carvalho Chehab } 1059a0bf528SMauro Carvalho Chehab 1069a0bf528SMauro Carvalho Chehab static u8 stv0299_readreg (struct stv0299_state* state, u8 reg) 1079a0bf528SMauro Carvalho Chehab { 1089a0bf528SMauro Carvalho Chehab int ret; 1099a0bf528SMauro Carvalho Chehab u8 b0 [] = { reg }; 1109a0bf528SMauro Carvalho Chehab u8 b1 [] = { 0 }; 1119a0bf528SMauro Carvalho Chehab struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, 1129a0bf528SMauro Carvalho Chehab { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; 1139a0bf528SMauro Carvalho Chehab 1149a0bf528SMauro Carvalho Chehab ret = i2c_transfer (state->i2c, msg, 2); 1159a0bf528SMauro Carvalho Chehab 1169a0bf528SMauro Carvalho Chehab if (ret != 2) 1179a0bf528SMauro Carvalho Chehab dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", 1189a0bf528SMauro Carvalho Chehab __func__, reg, ret); 1199a0bf528SMauro Carvalho Chehab 1209a0bf528SMauro Carvalho Chehab return b1[0]; 1219a0bf528SMauro Carvalho Chehab } 1229a0bf528SMauro Carvalho Chehab 1239a0bf528SMauro Carvalho Chehab static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len) 1249a0bf528SMauro Carvalho Chehab { 1259a0bf528SMauro Carvalho Chehab int ret; 1269a0bf528SMauro Carvalho Chehab struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = ®1, .len = 1 }, 1279a0bf528SMauro Carvalho Chehab { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } }; 1289a0bf528SMauro Carvalho Chehab 1299a0bf528SMauro Carvalho Chehab ret = i2c_transfer (state->i2c, msg, 2); 1309a0bf528SMauro Carvalho Chehab 1319a0bf528SMauro Carvalho Chehab if (ret != 2) 1329a0bf528SMauro Carvalho Chehab dprintk("%s: readreg error (ret == %i)\n", __func__, ret); 1339a0bf528SMauro Carvalho Chehab 1349a0bf528SMauro Carvalho Chehab return ret == 2 ? 0 : ret; 1359a0bf528SMauro Carvalho Chehab } 1369a0bf528SMauro Carvalho Chehab 137*0df289a2SMauro Carvalho Chehab static int stv0299_set_FEC(struct stv0299_state *state, enum fe_code_rate fec) 1389a0bf528SMauro Carvalho Chehab { 1399a0bf528SMauro Carvalho Chehab dprintk ("%s\n", __func__); 1409a0bf528SMauro Carvalho Chehab 1419a0bf528SMauro Carvalho Chehab switch (fec) { 1429a0bf528SMauro Carvalho Chehab case FEC_AUTO: 1439a0bf528SMauro Carvalho Chehab { 1449a0bf528SMauro Carvalho Chehab return stv0299_writeregI (state, 0x31, 0x1f); 1459a0bf528SMauro Carvalho Chehab } 1469a0bf528SMauro Carvalho Chehab case FEC_1_2: 1479a0bf528SMauro Carvalho Chehab { 1489a0bf528SMauro Carvalho Chehab return stv0299_writeregI (state, 0x31, 0x01); 1499a0bf528SMauro Carvalho Chehab } 1509a0bf528SMauro Carvalho Chehab case FEC_2_3: 1519a0bf528SMauro Carvalho Chehab { 1529a0bf528SMauro Carvalho Chehab return stv0299_writeregI (state, 0x31, 0x02); 1539a0bf528SMauro Carvalho Chehab } 1549a0bf528SMauro Carvalho Chehab case FEC_3_4: 1559a0bf528SMauro Carvalho Chehab { 1569a0bf528SMauro Carvalho Chehab return stv0299_writeregI (state, 0x31, 0x04); 1579a0bf528SMauro Carvalho Chehab } 1589a0bf528SMauro Carvalho Chehab case FEC_5_6: 1599a0bf528SMauro Carvalho Chehab { 1609a0bf528SMauro Carvalho Chehab return stv0299_writeregI (state, 0x31, 0x08); 1619a0bf528SMauro Carvalho Chehab } 1629a0bf528SMauro Carvalho Chehab case FEC_7_8: 1639a0bf528SMauro Carvalho Chehab { 1649a0bf528SMauro Carvalho Chehab return stv0299_writeregI (state, 0x31, 0x10); 1659a0bf528SMauro Carvalho Chehab } 1669a0bf528SMauro Carvalho Chehab default: 1679a0bf528SMauro Carvalho Chehab { 1689a0bf528SMauro Carvalho Chehab return -EINVAL; 1699a0bf528SMauro Carvalho Chehab } 1709a0bf528SMauro Carvalho Chehab } 1719a0bf528SMauro Carvalho Chehab } 1729a0bf528SMauro Carvalho Chehab 173*0df289a2SMauro Carvalho Chehab static enum fe_code_rate stv0299_get_fec(struct stv0299_state *state) 1749a0bf528SMauro Carvalho Chehab { 175*0df289a2SMauro Carvalho Chehab static enum fe_code_rate fec_tab[] = { FEC_2_3, FEC_3_4, FEC_5_6, 1769a0bf528SMauro Carvalho Chehab FEC_7_8, FEC_1_2 }; 1779a0bf528SMauro Carvalho Chehab u8 index; 1789a0bf528SMauro Carvalho Chehab 1799a0bf528SMauro Carvalho Chehab dprintk ("%s\n", __func__); 1809a0bf528SMauro Carvalho Chehab 1819a0bf528SMauro Carvalho Chehab index = stv0299_readreg (state, 0x1b); 1829a0bf528SMauro Carvalho Chehab index &= 0x7; 1839a0bf528SMauro Carvalho Chehab 1849a0bf528SMauro Carvalho Chehab if (index > 4) 1859a0bf528SMauro Carvalho Chehab return FEC_AUTO; 1869a0bf528SMauro Carvalho Chehab 1879a0bf528SMauro Carvalho Chehab return fec_tab [index]; 1889a0bf528SMauro Carvalho Chehab } 1899a0bf528SMauro Carvalho Chehab 1909a0bf528SMauro Carvalho Chehab static int stv0299_wait_diseqc_fifo (struct stv0299_state* state, int timeout) 1919a0bf528SMauro Carvalho Chehab { 1929a0bf528SMauro Carvalho Chehab unsigned long start = jiffies; 1939a0bf528SMauro Carvalho Chehab 1949a0bf528SMauro Carvalho Chehab dprintk ("%s\n", __func__); 1959a0bf528SMauro Carvalho Chehab 1969a0bf528SMauro Carvalho Chehab while (stv0299_readreg(state, 0x0a) & 1) { 1979a0bf528SMauro Carvalho Chehab if (jiffies - start > timeout) { 1989a0bf528SMauro Carvalho Chehab dprintk ("%s: timeout!!\n", __func__); 1999a0bf528SMauro Carvalho Chehab return -ETIMEDOUT; 2009a0bf528SMauro Carvalho Chehab } 2019a0bf528SMauro Carvalho Chehab msleep(10); 202c2c1b415SPeter Senna Tschudin } 2039a0bf528SMauro Carvalho Chehab 2049a0bf528SMauro Carvalho Chehab return 0; 2059a0bf528SMauro Carvalho Chehab } 2069a0bf528SMauro Carvalho Chehab 2079a0bf528SMauro Carvalho Chehab static int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout) 2089a0bf528SMauro Carvalho Chehab { 2099a0bf528SMauro Carvalho Chehab unsigned long start = jiffies; 2109a0bf528SMauro Carvalho Chehab 2119a0bf528SMauro Carvalho Chehab dprintk ("%s\n", __func__); 2129a0bf528SMauro Carvalho Chehab 2139a0bf528SMauro Carvalho Chehab while ((stv0299_readreg(state, 0x0a) & 3) != 2 ) { 2149a0bf528SMauro Carvalho Chehab if (jiffies - start > timeout) { 2159a0bf528SMauro Carvalho Chehab dprintk ("%s: timeout!!\n", __func__); 2169a0bf528SMauro Carvalho Chehab return -ETIMEDOUT; 2179a0bf528SMauro Carvalho Chehab } 2189a0bf528SMauro Carvalho Chehab msleep(10); 219c2c1b415SPeter Senna Tschudin } 2209a0bf528SMauro Carvalho Chehab 2219a0bf528SMauro Carvalho Chehab return 0; 2229a0bf528SMauro Carvalho Chehab } 2239a0bf528SMauro Carvalho Chehab 2249a0bf528SMauro Carvalho Chehab static int stv0299_set_symbolrate (struct dvb_frontend* fe, u32 srate) 2259a0bf528SMauro Carvalho Chehab { 2269a0bf528SMauro Carvalho Chehab struct stv0299_state* state = fe->demodulator_priv; 2279a0bf528SMauro Carvalho Chehab u64 big = srate; 2289a0bf528SMauro Carvalho Chehab u32 ratio; 2299a0bf528SMauro Carvalho Chehab 2309a0bf528SMauro Carvalho Chehab // check rate is within limits 2319a0bf528SMauro Carvalho Chehab if ((srate < 1000000) || (srate > 45000000)) return -EINVAL; 2329a0bf528SMauro Carvalho Chehab 2339a0bf528SMauro Carvalho Chehab // calculate value to program 2349a0bf528SMauro Carvalho Chehab big = big << 20; 2359a0bf528SMauro Carvalho Chehab big += (state->config->mclk-1); // round correctly 2369a0bf528SMauro Carvalho Chehab do_div(big, state->config->mclk); 2379a0bf528SMauro Carvalho Chehab ratio = big << 4; 2389a0bf528SMauro Carvalho Chehab 2399a0bf528SMauro Carvalho Chehab return state->config->set_symbol_rate(fe, srate, ratio); 2409a0bf528SMauro Carvalho Chehab } 2419a0bf528SMauro Carvalho Chehab 2429a0bf528SMauro Carvalho Chehab static int stv0299_get_symbolrate (struct stv0299_state* state) 2439a0bf528SMauro Carvalho Chehab { 2449a0bf528SMauro Carvalho Chehab u32 Mclk = state->config->mclk / 4096L; 2459a0bf528SMauro Carvalho Chehab u32 srate; 2469a0bf528SMauro Carvalho Chehab s32 offset; 2479a0bf528SMauro Carvalho Chehab u8 sfr[3]; 2489a0bf528SMauro Carvalho Chehab s8 rtf; 2499a0bf528SMauro Carvalho Chehab 2509a0bf528SMauro Carvalho Chehab dprintk ("%s\n", __func__); 2519a0bf528SMauro Carvalho Chehab 2529a0bf528SMauro Carvalho Chehab stv0299_readregs (state, 0x1f, sfr, 3); 2539a0bf528SMauro Carvalho Chehab stv0299_readregs (state, 0x1a, (u8 *)&rtf, 1); 2549a0bf528SMauro Carvalho Chehab 2559a0bf528SMauro Carvalho Chehab srate = (sfr[0] << 8) | sfr[1]; 2569a0bf528SMauro Carvalho Chehab srate *= Mclk; 2579a0bf528SMauro Carvalho Chehab srate /= 16; 2589a0bf528SMauro Carvalho Chehab srate += (sfr[2] >> 4) * Mclk / 256; 2599a0bf528SMauro Carvalho Chehab offset = (s32) rtf * (srate / 4096L); 2609a0bf528SMauro Carvalho Chehab offset /= 128; 2619a0bf528SMauro Carvalho Chehab 2629a0bf528SMauro Carvalho Chehab dprintk ("%s : srate = %i\n", __func__, srate); 2639a0bf528SMauro Carvalho Chehab dprintk ("%s : ofset = %i\n", __func__, offset); 2649a0bf528SMauro Carvalho Chehab 2659a0bf528SMauro Carvalho Chehab srate += offset; 2669a0bf528SMauro Carvalho Chehab 2679a0bf528SMauro Carvalho Chehab srate += 1000; 2689a0bf528SMauro Carvalho Chehab srate /= 2000; 2699a0bf528SMauro Carvalho Chehab srate *= 2000; 2709a0bf528SMauro Carvalho Chehab 2719a0bf528SMauro Carvalho Chehab return srate; 2729a0bf528SMauro Carvalho Chehab } 2739a0bf528SMauro Carvalho Chehab 2749a0bf528SMauro Carvalho Chehab static int stv0299_send_diseqc_msg (struct dvb_frontend* fe, 2759a0bf528SMauro Carvalho Chehab struct dvb_diseqc_master_cmd *m) 2769a0bf528SMauro Carvalho Chehab { 2779a0bf528SMauro Carvalho Chehab struct stv0299_state* state = fe->demodulator_priv; 2789a0bf528SMauro Carvalho Chehab u8 val; 2799a0bf528SMauro Carvalho Chehab int i; 2809a0bf528SMauro Carvalho Chehab 2819a0bf528SMauro Carvalho Chehab dprintk ("%s\n", __func__); 2829a0bf528SMauro Carvalho Chehab 2839a0bf528SMauro Carvalho Chehab if (stv0299_wait_diseqc_idle (state, 100) < 0) 2849a0bf528SMauro Carvalho Chehab return -ETIMEDOUT; 2859a0bf528SMauro Carvalho Chehab 2869a0bf528SMauro Carvalho Chehab val = stv0299_readreg (state, 0x08); 2879a0bf528SMauro Carvalho Chehab 2889a0bf528SMauro Carvalho Chehab if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x6)) /* DiSEqC mode */ 2899a0bf528SMauro Carvalho Chehab return -EREMOTEIO; 2909a0bf528SMauro Carvalho Chehab 2919a0bf528SMauro Carvalho Chehab for (i=0; i<m->msg_len; i++) { 2929a0bf528SMauro Carvalho Chehab if (stv0299_wait_diseqc_fifo (state, 100) < 0) 2939a0bf528SMauro Carvalho Chehab return -ETIMEDOUT; 2949a0bf528SMauro Carvalho Chehab 2959a0bf528SMauro Carvalho Chehab if (stv0299_writeregI (state, 0x09, m->msg[i])) 2969a0bf528SMauro Carvalho Chehab return -EREMOTEIO; 2979a0bf528SMauro Carvalho Chehab } 2989a0bf528SMauro Carvalho Chehab 2999a0bf528SMauro Carvalho Chehab if (stv0299_wait_diseqc_idle (state, 100) < 0) 3009a0bf528SMauro Carvalho Chehab return -ETIMEDOUT; 3019a0bf528SMauro Carvalho Chehab 3029a0bf528SMauro Carvalho Chehab return 0; 3039a0bf528SMauro Carvalho Chehab } 3049a0bf528SMauro Carvalho Chehab 305*0df289a2SMauro Carvalho Chehab static int stv0299_send_diseqc_burst(struct dvb_frontend *fe, 306*0df289a2SMauro Carvalho Chehab enum fe_sec_mini_cmd burst) 3079a0bf528SMauro Carvalho Chehab { 3089a0bf528SMauro Carvalho Chehab struct stv0299_state* state = fe->demodulator_priv; 3099a0bf528SMauro Carvalho Chehab u8 val; 3109a0bf528SMauro Carvalho Chehab 3119a0bf528SMauro Carvalho Chehab dprintk ("%s\n", __func__); 3129a0bf528SMauro Carvalho Chehab 3139a0bf528SMauro Carvalho Chehab if (stv0299_wait_diseqc_idle (state, 100) < 0) 3149a0bf528SMauro Carvalho Chehab return -ETIMEDOUT; 3159a0bf528SMauro Carvalho Chehab 3169a0bf528SMauro Carvalho Chehab val = stv0299_readreg (state, 0x08); 3179a0bf528SMauro Carvalho Chehab 3189a0bf528SMauro Carvalho Chehab if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x2)) /* burst mode */ 3199a0bf528SMauro Carvalho Chehab return -EREMOTEIO; 3209a0bf528SMauro Carvalho Chehab 3219a0bf528SMauro Carvalho Chehab if (stv0299_writeregI (state, 0x09, burst == SEC_MINI_A ? 0x00 : 0xff)) 3229a0bf528SMauro Carvalho Chehab return -EREMOTEIO; 3239a0bf528SMauro Carvalho Chehab 3249a0bf528SMauro Carvalho Chehab if (stv0299_wait_diseqc_idle (state, 100) < 0) 3259a0bf528SMauro Carvalho Chehab return -ETIMEDOUT; 3269a0bf528SMauro Carvalho Chehab 3279a0bf528SMauro Carvalho Chehab if (stv0299_writeregI (state, 0x08, val)) 3289a0bf528SMauro Carvalho Chehab return -EREMOTEIO; 3299a0bf528SMauro Carvalho Chehab 3309a0bf528SMauro Carvalho Chehab return 0; 3319a0bf528SMauro Carvalho Chehab } 3329a0bf528SMauro Carvalho Chehab 333*0df289a2SMauro Carvalho Chehab static int stv0299_set_tone(struct dvb_frontend *fe, 334*0df289a2SMauro Carvalho Chehab enum fe_sec_tone_mode tone) 3359a0bf528SMauro Carvalho Chehab { 3369a0bf528SMauro Carvalho Chehab struct stv0299_state* state = fe->demodulator_priv; 3379a0bf528SMauro Carvalho Chehab u8 val; 3389a0bf528SMauro Carvalho Chehab 3399a0bf528SMauro Carvalho Chehab if (stv0299_wait_diseqc_idle (state, 100) < 0) 3409a0bf528SMauro Carvalho Chehab return -ETIMEDOUT; 3419a0bf528SMauro Carvalho Chehab 3429a0bf528SMauro Carvalho Chehab val = stv0299_readreg (state, 0x08); 3439a0bf528SMauro Carvalho Chehab 3449a0bf528SMauro Carvalho Chehab switch (tone) { 3459a0bf528SMauro Carvalho Chehab case SEC_TONE_ON: 3469a0bf528SMauro Carvalho Chehab return stv0299_writeregI (state, 0x08, val | 0x3); 3479a0bf528SMauro Carvalho Chehab 3489a0bf528SMauro Carvalho Chehab case SEC_TONE_OFF: 3499a0bf528SMauro Carvalho Chehab return stv0299_writeregI (state, 0x08, (val & ~0x3) | 0x02); 3509a0bf528SMauro Carvalho Chehab 3519a0bf528SMauro Carvalho Chehab default: 3529a0bf528SMauro Carvalho Chehab return -EINVAL; 3539a0bf528SMauro Carvalho Chehab } 3549a0bf528SMauro Carvalho Chehab } 3559a0bf528SMauro Carvalho Chehab 356*0df289a2SMauro Carvalho Chehab static int stv0299_set_voltage(struct dvb_frontend *fe, 357*0df289a2SMauro Carvalho Chehab enum fe_sec_voltage voltage) 3589a0bf528SMauro Carvalho Chehab { 3599a0bf528SMauro Carvalho Chehab struct stv0299_state* state = fe->demodulator_priv; 3609a0bf528SMauro Carvalho Chehab u8 reg0x08; 3619a0bf528SMauro Carvalho Chehab u8 reg0x0c; 3629a0bf528SMauro Carvalho Chehab 3639a0bf528SMauro Carvalho Chehab dprintk("%s: %s\n", __func__, 3649a0bf528SMauro Carvalho Chehab voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : 3659a0bf528SMauro Carvalho Chehab voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); 3669a0bf528SMauro Carvalho Chehab 3679a0bf528SMauro Carvalho Chehab reg0x08 = stv0299_readreg (state, 0x08); 3689a0bf528SMauro Carvalho Chehab reg0x0c = stv0299_readreg (state, 0x0c); 3699a0bf528SMauro Carvalho Chehab 3709a0bf528SMauro Carvalho Chehab /** 3719a0bf528SMauro Carvalho Chehab * H/V switching over OP0, OP1 and OP2 are LNB power enable bits 3729a0bf528SMauro Carvalho Chehab */ 3739a0bf528SMauro Carvalho Chehab reg0x0c &= 0x0f; 3749a0bf528SMauro Carvalho Chehab reg0x08 = (reg0x08 & 0x3f) | (state->config->lock_output << 6); 3759a0bf528SMauro Carvalho Chehab 3769a0bf528SMauro Carvalho Chehab switch (voltage) { 3779a0bf528SMauro Carvalho Chehab case SEC_VOLTAGE_13: 3789a0bf528SMauro Carvalho Chehab if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0) 3799a0bf528SMauro Carvalho Chehab reg0x0c |= 0x10; /* OP1 off, OP0 on */ 3809a0bf528SMauro Carvalho Chehab else 3819a0bf528SMauro Carvalho Chehab reg0x0c |= 0x40; /* OP1 on, OP0 off */ 3829a0bf528SMauro Carvalho Chehab break; 3839a0bf528SMauro Carvalho Chehab case SEC_VOLTAGE_18: 3849a0bf528SMauro Carvalho Chehab reg0x0c |= 0x50; /* OP1 on, OP0 on */ 3859a0bf528SMauro Carvalho Chehab break; 3869a0bf528SMauro Carvalho Chehab case SEC_VOLTAGE_OFF: 3879a0bf528SMauro Carvalho Chehab /* LNB power off! */ 3889a0bf528SMauro Carvalho Chehab reg0x08 = 0x00; 3899a0bf528SMauro Carvalho Chehab reg0x0c = 0x00; 3909a0bf528SMauro Carvalho Chehab break; 3919a0bf528SMauro Carvalho Chehab default: 3929a0bf528SMauro Carvalho Chehab return -EINVAL; 393c2c1b415SPeter Senna Tschudin } 3949a0bf528SMauro Carvalho Chehab 3959a0bf528SMauro Carvalho Chehab if (state->config->op0_off) 3969a0bf528SMauro Carvalho Chehab reg0x0c &= ~0x10; 3979a0bf528SMauro Carvalho Chehab 3989a0bf528SMauro Carvalho Chehab stv0299_writeregI(state, 0x08, reg0x08); 3999a0bf528SMauro Carvalho Chehab return stv0299_writeregI(state, 0x0c, reg0x0c); 4009a0bf528SMauro Carvalho Chehab } 4019a0bf528SMauro Carvalho Chehab 4029a0bf528SMauro Carvalho Chehab static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long cmd) 4039a0bf528SMauro Carvalho Chehab { 4049a0bf528SMauro Carvalho Chehab struct stv0299_state* state = fe->demodulator_priv; 4059a0bf528SMauro Carvalho Chehab u8 reg0x08; 4069a0bf528SMauro Carvalho Chehab u8 reg0x0c; 4079a0bf528SMauro Carvalho Chehab u8 lv_mask = 0x40; 4089a0bf528SMauro Carvalho Chehab u8 last = 1; 4099a0bf528SMauro Carvalho Chehab int i; 4109a0bf528SMauro Carvalho Chehab struct timeval nexttime; 4119a0bf528SMauro Carvalho Chehab struct timeval tv[10]; 4129a0bf528SMauro Carvalho Chehab 4139a0bf528SMauro Carvalho Chehab reg0x08 = stv0299_readreg (state, 0x08); 4149a0bf528SMauro Carvalho Chehab reg0x0c = stv0299_readreg (state, 0x0c); 4159a0bf528SMauro Carvalho Chehab reg0x0c &= 0x0f; 4169a0bf528SMauro Carvalho Chehab stv0299_writeregI (state, 0x08, (reg0x08 & 0x3f) | (state->config->lock_output << 6)); 4179a0bf528SMauro Carvalho Chehab if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0) 4189a0bf528SMauro Carvalho Chehab lv_mask = 0x10; 4199a0bf528SMauro Carvalho Chehab 4209a0bf528SMauro Carvalho Chehab cmd = cmd << 1; 4219a0bf528SMauro Carvalho Chehab if (debug_legacy_dish_switch) 4229a0bf528SMauro Carvalho Chehab printk ("%s switch command: 0x%04lx\n",__func__, cmd); 4239a0bf528SMauro Carvalho Chehab 4249a0bf528SMauro Carvalho Chehab do_gettimeofday (&nexttime); 4259a0bf528SMauro Carvalho Chehab if (debug_legacy_dish_switch) 426ee45ddc1SEzequiel Garcia tv[0] = nexttime; 4279a0bf528SMauro Carvalho Chehab stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */ 4289a0bf528SMauro Carvalho Chehab 4299a0bf528SMauro Carvalho Chehab dvb_frontend_sleep_until(&nexttime, 32000); 4309a0bf528SMauro Carvalho Chehab 4319a0bf528SMauro Carvalho Chehab for (i=0; i<9; i++) { 4329a0bf528SMauro Carvalho Chehab if (debug_legacy_dish_switch) 4339a0bf528SMauro Carvalho Chehab do_gettimeofday (&tv[i+1]); 4349a0bf528SMauro Carvalho Chehab if((cmd & 0x01) != last) { 4359a0bf528SMauro Carvalho Chehab /* set voltage to (last ? 13V : 18V) */ 4369a0bf528SMauro Carvalho Chehab stv0299_writeregI (state, 0x0c, reg0x0c | (last ? lv_mask : 0x50)); 4379a0bf528SMauro Carvalho Chehab last = (last) ? 0 : 1; 4389a0bf528SMauro Carvalho Chehab } 4399a0bf528SMauro Carvalho Chehab 4409a0bf528SMauro Carvalho Chehab cmd = cmd >> 1; 4419a0bf528SMauro Carvalho Chehab 4429a0bf528SMauro Carvalho Chehab if (i != 8) 4439a0bf528SMauro Carvalho Chehab dvb_frontend_sleep_until(&nexttime, 8000); 4449a0bf528SMauro Carvalho Chehab } 4459a0bf528SMauro Carvalho Chehab if (debug_legacy_dish_switch) { 4469a0bf528SMauro Carvalho Chehab printk ("%s(%d): switch delay (should be 32k followed by all 8k\n", 4479a0bf528SMauro Carvalho Chehab __func__, fe->dvb->num); 4489a0bf528SMauro Carvalho Chehab for (i = 1; i < 10; i++) 4499a0bf528SMauro Carvalho Chehab printk ("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i])); 4509a0bf528SMauro Carvalho Chehab } 4519a0bf528SMauro Carvalho Chehab 4529a0bf528SMauro Carvalho Chehab return 0; 4539a0bf528SMauro Carvalho Chehab } 4549a0bf528SMauro Carvalho Chehab 4559a0bf528SMauro Carvalho Chehab static int stv0299_init (struct dvb_frontend* fe) 4569a0bf528SMauro Carvalho Chehab { 4579a0bf528SMauro Carvalho Chehab struct stv0299_state* state = fe->demodulator_priv; 4589a0bf528SMauro Carvalho Chehab int i; 4599a0bf528SMauro Carvalho Chehab u8 reg; 4609a0bf528SMauro Carvalho Chehab u8 val; 4619a0bf528SMauro Carvalho Chehab 4629a0bf528SMauro Carvalho Chehab dprintk("stv0299: init chip\n"); 4639a0bf528SMauro Carvalho Chehab 4649a0bf528SMauro Carvalho Chehab stv0299_writeregI(state, 0x02, 0x30 | state->mcr_reg); 4659a0bf528SMauro Carvalho Chehab msleep(50); 4669a0bf528SMauro Carvalho Chehab 4679a0bf528SMauro Carvalho Chehab for (i = 0; ; i += 2) { 4689a0bf528SMauro Carvalho Chehab reg = state->config->inittab[i]; 4699a0bf528SMauro Carvalho Chehab val = state->config->inittab[i+1]; 4709a0bf528SMauro Carvalho Chehab if (reg == 0xff && val == 0xff) 4719a0bf528SMauro Carvalho Chehab break; 4729a0bf528SMauro Carvalho Chehab if (reg == 0x0c && state->config->op0_off) 4739a0bf528SMauro Carvalho Chehab val &= ~0x10; 4749a0bf528SMauro Carvalho Chehab if (reg == 0x2) 4759a0bf528SMauro Carvalho Chehab state->mcr_reg = val & 0xf; 4769a0bf528SMauro Carvalho Chehab stv0299_writeregI(state, reg, val); 4779a0bf528SMauro Carvalho Chehab } 4789a0bf528SMauro Carvalho Chehab 4799a0bf528SMauro Carvalho Chehab return 0; 4809a0bf528SMauro Carvalho Chehab } 4819a0bf528SMauro Carvalho Chehab 482*0df289a2SMauro Carvalho Chehab static int stv0299_read_status(struct dvb_frontend *fe, 483*0df289a2SMauro Carvalho Chehab enum fe_status *status) 4849a0bf528SMauro Carvalho Chehab { 4859a0bf528SMauro Carvalho Chehab struct stv0299_state* state = fe->demodulator_priv; 4869a0bf528SMauro Carvalho Chehab 4879a0bf528SMauro Carvalho Chehab u8 signal = 0xff - stv0299_readreg (state, 0x18); 4889a0bf528SMauro Carvalho Chehab u8 sync = stv0299_readreg (state, 0x1b); 4899a0bf528SMauro Carvalho Chehab 4909a0bf528SMauro Carvalho Chehab dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync); 4919a0bf528SMauro Carvalho Chehab *status = 0; 4929a0bf528SMauro Carvalho Chehab 4939a0bf528SMauro Carvalho Chehab if (signal > 10) 4949a0bf528SMauro Carvalho Chehab *status |= FE_HAS_SIGNAL; 4959a0bf528SMauro Carvalho Chehab 4969a0bf528SMauro Carvalho Chehab if (sync & 0x80) 4979a0bf528SMauro Carvalho Chehab *status |= FE_HAS_CARRIER; 4989a0bf528SMauro Carvalho Chehab 4999a0bf528SMauro Carvalho Chehab if (sync & 0x10) 5009a0bf528SMauro Carvalho Chehab *status |= FE_HAS_VITERBI; 5019a0bf528SMauro Carvalho Chehab 5029a0bf528SMauro Carvalho Chehab if (sync & 0x08) 5039a0bf528SMauro Carvalho Chehab *status |= FE_HAS_SYNC; 5049a0bf528SMauro Carvalho Chehab 5059a0bf528SMauro Carvalho Chehab if ((sync & 0x98) == 0x98) 5069a0bf528SMauro Carvalho Chehab *status |= FE_HAS_LOCK; 5079a0bf528SMauro Carvalho Chehab 5089a0bf528SMauro Carvalho Chehab return 0; 5099a0bf528SMauro Carvalho Chehab } 5109a0bf528SMauro Carvalho Chehab 5119a0bf528SMauro Carvalho Chehab static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber) 5129a0bf528SMauro Carvalho Chehab { 5139a0bf528SMauro Carvalho Chehab struct stv0299_state* state = fe->demodulator_priv; 5149a0bf528SMauro Carvalho Chehab 5159a0bf528SMauro Carvalho Chehab if (state->errmode != STATUS_BER) 5169a0bf528SMauro Carvalho Chehab return -ENOSYS; 5179a0bf528SMauro Carvalho Chehab 5189a0bf528SMauro Carvalho Chehab *ber = stv0299_readreg(state, 0x1e) | (stv0299_readreg(state, 0x1d) << 8); 5199a0bf528SMauro Carvalho Chehab 5209a0bf528SMauro Carvalho Chehab return 0; 5219a0bf528SMauro Carvalho Chehab } 5229a0bf528SMauro Carvalho Chehab 5239a0bf528SMauro Carvalho Chehab static int stv0299_read_signal_strength(struct dvb_frontend* fe, u16* strength) 5249a0bf528SMauro Carvalho Chehab { 5259a0bf528SMauro Carvalho Chehab struct stv0299_state* state = fe->demodulator_priv; 5269a0bf528SMauro Carvalho Chehab 5279a0bf528SMauro Carvalho Chehab s32 signal = 0xffff - ((stv0299_readreg (state, 0x18) << 8) 5289a0bf528SMauro Carvalho Chehab | stv0299_readreg (state, 0x19)); 5299a0bf528SMauro Carvalho Chehab 5309a0bf528SMauro Carvalho Chehab dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __func__, 5319a0bf528SMauro Carvalho Chehab stv0299_readreg (state, 0x18), 5329a0bf528SMauro Carvalho Chehab stv0299_readreg (state, 0x19), (int) signal); 5339a0bf528SMauro Carvalho Chehab 5349a0bf528SMauro Carvalho Chehab signal = signal * 5 / 4; 5359a0bf528SMauro Carvalho Chehab *strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal; 5369a0bf528SMauro Carvalho Chehab 5379a0bf528SMauro Carvalho Chehab return 0; 5389a0bf528SMauro Carvalho Chehab } 5399a0bf528SMauro Carvalho Chehab 5409a0bf528SMauro Carvalho Chehab static int stv0299_read_snr(struct dvb_frontend* fe, u16* snr) 5419a0bf528SMauro Carvalho Chehab { 5429a0bf528SMauro Carvalho Chehab struct stv0299_state* state = fe->demodulator_priv; 5439a0bf528SMauro Carvalho Chehab 5449a0bf528SMauro Carvalho Chehab s32 xsnr = 0xffff - ((stv0299_readreg (state, 0x24) << 8) 5459a0bf528SMauro Carvalho Chehab | stv0299_readreg (state, 0x25)); 5469a0bf528SMauro Carvalho Chehab xsnr = 3 * (xsnr - 0xa100); 5479a0bf528SMauro Carvalho Chehab *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr; 5489a0bf528SMauro Carvalho Chehab 5499a0bf528SMauro Carvalho Chehab return 0; 5509a0bf528SMauro Carvalho Chehab } 5519a0bf528SMauro Carvalho Chehab 5529a0bf528SMauro Carvalho Chehab static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) 5539a0bf528SMauro Carvalho Chehab { 5549a0bf528SMauro Carvalho Chehab struct stv0299_state* state = fe->demodulator_priv; 5559a0bf528SMauro Carvalho Chehab 5569a0bf528SMauro Carvalho Chehab if (state->errmode != STATUS_UCBLOCKS) 5579a0bf528SMauro Carvalho Chehab return -ENOSYS; 5589a0bf528SMauro Carvalho Chehab 5599a0bf528SMauro Carvalho Chehab state->ucblocks += stv0299_readreg(state, 0x1e); 5609a0bf528SMauro Carvalho Chehab state->ucblocks += (stv0299_readreg(state, 0x1d) << 8); 5619a0bf528SMauro Carvalho Chehab *ucblocks = state->ucblocks; 5629a0bf528SMauro Carvalho Chehab 5639a0bf528SMauro Carvalho Chehab return 0; 5649a0bf528SMauro Carvalho Chehab } 5659a0bf528SMauro Carvalho Chehab 5669a0bf528SMauro Carvalho Chehab static int stv0299_set_frontend(struct dvb_frontend *fe) 5679a0bf528SMauro Carvalho Chehab { 5689a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *p = &fe->dtv_property_cache; 5699a0bf528SMauro Carvalho Chehab struct stv0299_state* state = fe->demodulator_priv; 5709a0bf528SMauro Carvalho Chehab int invval = 0; 5719a0bf528SMauro Carvalho Chehab 5729a0bf528SMauro Carvalho Chehab dprintk ("%s : FE_SET_FRONTEND\n", __func__); 5739a0bf528SMauro Carvalho Chehab if (state->config->set_ts_params) 5749a0bf528SMauro Carvalho Chehab state->config->set_ts_params(fe, 0); 5759a0bf528SMauro Carvalho Chehab 5769a0bf528SMauro Carvalho Chehab // set the inversion 5779a0bf528SMauro Carvalho Chehab if (p->inversion == INVERSION_OFF) invval = 0; 5789a0bf528SMauro Carvalho Chehab else if (p->inversion == INVERSION_ON) invval = 1; 5799a0bf528SMauro Carvalho Chehab else { 5809a0bf528SMauro Carvalho Chehab printk("stv0299 does not support auto-inversion\n"); 5819a0bf528SMauro Carvalho Chehab return -EINVAL; 5829a0bf528SMauro Carvalho Chehab } 5839a0bf528SMauro Carvalho Chehab if (state->config->invert) invval = (~invval) & 1; 5849a0bf528SMauro Carvalho Chehab stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval); 5859a0bf528SMauro Carvalho Chehab 5869a0bf528SMauro Carvalho Chehab if (fe->ops.tuner_ops.set_params) { 5879a0bf528SMauro Carvalho Chehab fe->ops.tuner_ops.set_params(fe); 5889a0bf528SMauro Carvalho Chehab if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); 5899a0bf528SMauro Carvalho Chehab } 5909a0bf528SMauro Carvalho Chehab 5919a0bf528SMauro Carvalho Chehab stv0299_set_FEC(state, p->fec_inner); 5929a0bf528SMauro Carvalho Chehab stv0299_set_symbolrate(fe, p->symbol_rate); 5939a0bf528SMauro Carvalho Chehab stv0299_writeregI(state, 0x22, 0x00); 5949a0bf528SMauro Carvalho Chehab stv0299_writeregI(state, 0x23, 0x00); 5959a0bf528SMauro Carvalho Chehab 5969a0bf528SMauro Carvalho Chehab state->tuner_frequency = p->frequency; 5979a0bf528SMauro Carvalho Chehab state->fec_inner = p->fec_inner; 5989a0bf528SMauro Carvalho Chehab state->symbol_rate = p->symbol_rate; 5999a0bf528SMauro Carvalho Chehab 6009a0bf528SMauro Carvalho Chehab return 0; 6019a0bf528SMauro Carvalho Chehab } 6029a0bf528SMauro Carvalho Chehab 6039a0bf528SMauro Carvalho Chehab static int stv0299_get_frontend(struct dvb_frontend *fe) 6049a0bf528SMauro Carvalho Chehab { 6059a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *p = &fe->dtv_property_cache; 6069a0bf528SMauro Carvalho Chehab struct stv0299_state* state = fe->demodulator_priv; 6079a0bf528SMauro Carvalho Chehab s32 derot_freq; 6089a0bf528SMauro Carvalho Chehab int invval; 6099a0bf528SMauro Carvalho Chehab 6109a0bf528SMauro Carvalho Chehab derot_freq = (s32)(s16) ((stv0299_readreg (state, 0x22) << 8) 6119a0bf528SMauro Carvalho Chehab | stv0299_readreg (state, 0x23)); 6129a0bf528SMauro Carvalho Chehab 6139a0bf528SMauro Carvalho Chehab derot_freq *= (state->config->mclk >> 16); 6149a0bf528SMauro Carvalho Chehab derot_freq += 500; 6159a0bf528SMauro Carvalho Chehab derot_freq /= 1000; 6169a0bf528SMauro Carvalho Chehab 6179a0bf528SMauro Carvalho Chehab p->frequency += derot_freq; 6189a0bf528SMauro Carvalho Chehab 6199a0bf528SMauro Carvalho Chehab invval = stv0299_readreg (state, 0x0c) & 1; 6209a0bf528SMauro Carvalho Chehab if (state->config->invert) invval = (~invval) & 1; 6219a0bf528SMauro Carvalho Chehab p->inversion = invval ? INVERSION_ON : INVERSION_OFF; 6229a0bf528SMauro Carvalho Chehab 6239a0bf528SMauro Carvalho Chehab p->fec_inner = stv0299_get_fec(state); 6249a0bf528SMauro Carvalho Chehab p->symbol_rate = stv0299_get_symbolrate(state); 6259a0bf528SMauro Carvalho Chehab 6269a0bf528SMauro Carvalho Chehab return 0; 6279a0bf528SMauro Carvalho Chehab } 6289a0bf528SMauro Carvalho Chehab 6299a0bf528SMauro Carvalho Chehab static int stv0299_sleep(struct dvb_frontend* fe) 6309a0bf528SMauro Carvalho Chehab { 6319a0bf528SMauro Carvalho Chehab struct stv0299_state* state = fe->demodulator_priv; 6329a0bf528SMauro Carvalho Chehab 6339a0bf528SMauro Carvalho Chehab stv0299_writeregI(state, 0x02, 0xb0 | state->mcr_reg); 6349a0bf528SMauro Carvalho Chehab state->initialised = 0; 6359a0bf528SMauro Carvalho Chehab 6369a0bf528SMauro Carvalho Chehab return 0; 6379a0bf528SMauro Carvalho Chehab } 6389a0bf528SMauro Carvalho Chehab 6399a0bf528SMauro Carvalho Chehab static int stv0299_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) 6409a0bf528SMauro Carvalho Chehab { 6419a0bf528SMauro Carvalho Chehab struct stv0299_state* state = fe->demodulator_priv; 6429a0bf528SMauro Carvalho Chehab 6439a0bf528SMauro Carvalho Chehab if (enable) { 6449a0bf528SMauro Carvalho Chehab stv0299_writeregI(state, 0x05, 0xb5); 6459a0bf528SMauro Carvalho Chehab } else { 6469a0bf528SMauro Carvalho Chehab stv0299_writeregI(state, 0x05, 0x35); 6479a0bf528SMauro Carvalho Chehab } 6489a0bf528SMauro Carvalho Chehab udelay(1); 6499a0bf528SMauro Carvalho Chehab return 0; 6509a0bf528SMauro Carvalho Chehab } 6519a0bf528SMauro Carvalho Chehab 6529a0bf528SMauro Carvalho Chehab static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) 6539a0bf528SMauro Carvalho Chehab { 6549a0bf528SMauro Carvalho Chehab struct stv0299_state* state = fe->demodulator_priv; 6559a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *p = &fe->dtv_property_cache; 6569a0bf528SMauro Carvalho Chehab 6579a0bf528SMauro Carvalho Chehab fesettings->min_delay_ms = state->config->min_delay_ms; 6589a0bf528SMauro Carvalho Chehab if (p->symbol_rate < 10000000) { 6599a0bf528SMauro Carvalho Chehab fesettings->step_size = p->symbol_rate / 32000; 6609a0bf528SMauro Carvalho Chehab fesettings->max_drift = 5000; 6619a0bf528SMauro Carvalho Chehab } else { 6629a0bf528SMauro Carvalho Chehab fesettings->step_size = p->symbol_rate / 16000; 6639a0bf528SMauro Carvalho Chehab fesettings->max_drift = p->symbol_rate / 2000; 6649a0bf528SMauro Carvalho Chehab } 6659a0bf528SMauro Carvalho Chehab return 0; 6669a0bf528SMauro Carvalho Chehab } 6679a0bf528SMauro Carvalho Chehab 6689a0bf528SMauro Carvalho Chehab static void stv0299_release(struct dvb_frontend* fe) 6699a0bf528SMauro Carvalho Chehab { 6709a0bf528SMauro Carvalho Chehab struct stv0299_state* state = fe->demodulator_priv; 6719a0bf528SMauro Carvalho Chehab kfree(state); 6729a0bf528SMauro Carvalho Chehab } 6739a0bf528SMauro Carvalho Chehab 6749a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops stv0299_ops; 6759a0bf528SMauro Carvalho Chehab 6769a0bf528SMauro Carvalho Chehab struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, 6779a0bf528SMauro Carvalho Chehab struct i2c_adapter* i2c) 6789a0bf528SMauro Carvalho Chehab { 6799a0bf528SMauro Carvalho Chehab struct stv0299_state* state = NULL; 6809a0bf528SMauro Carvalho Chehab int id; 6819a0bf528SMauro Carvalho Chehab 6829a0bf528SMauro Carvalho Chehab /* allocate memory for the internal state */ 6839a0bf528SMauro Carvalho Chehab state = kzalloc(sizeof(struct stv0299_state), GFP_KERNEL); 6849a0bf528SMauro Carvalho Chehab if (state == NULL) goto error; 6859a0bf528SMauro Carvalho Chehab 6869a0bf528SMauro Carvalho Chehab /* setup the state */ 6879a0bf528SMauro Carvalho Chehab state->config = config; 6889a0bf528SMauro Carvalho Chehab state->i2c = i2c; 6899a0bf528SMauro Carvalho Chehab state->initialised = 0; 6909a0bf528SMauro Carvalho Chehab state->tuner_frequency = 0; 6919a0bf528SMauro Carvalho Chehab state->symbol_rate = 0; 6929a0bf528SMauro Carvalho Chehab state->fec_inner = 0; 6939a0bf528SMauro Carvalho Chehab state->errmode = STATUS_BER; 6949a0bf528SMauro Carvalho Chehab 6959a0bf528SMauro Carvalho Chehab /* check if the demod is there */ 6969a0bf528SMauro Carvalho Chehab stv0299_writeregI(state, 0x02, 0x30); /* standby off */ 6979a0bf528SMauro Carvalho Chehab msleep(200); 6989a0bf528SMauro Carvalho Chehab id = stv0299_readreg(state, 0x00); 6999a0bf528SMauro Carvalho Chehab 7009a0bf528SMauro Carvalho Chehab /* register 0x00 contains 0xa1 for STV0299 and STV0299B */ 7019a0bf528SMauro Carvalho Chehab /* register 0x00 might contain 0x80 when returning from standby */ 7029a0bf528SMauro Carvalho Chehab if (id != 0xa1 && id != 0x80) goto error; 7039a0bf528SMauro Carvalho Chehab 7049a0bf528SMauro Carvalho Chehab /* create dvb_frontend */ 7059a0bf528SMauro Carvalho Chehab memcpy(&state->frontend.ops, &stv0299_ops, sizeof(struct dvb_frontend_ops)); 7069a0bf528SMauro Carvalho Chehab state->frontend.demodulator_priv = state; 7079a0bf528SMauro Carvalho Chehab return &state->frontend; 7089a0bf528SMauro Carvalho Chehab 7099a0bf528SMauro Carvalho Chehab error: 7109a0bf528SMauro Carvalho Chehab kfree(state); 7119a0bf528SMauro Carvalho Chehab return NULL; 7129a0bf528SMauro Carvalho Chehab } 7139a0bf528SMauro Carvalho Chehab 7149a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops stv0299_ops = { 7159a0bf528SMauro Carvalho Chehab .delsys = { SYS_DVBS }, 7169a0bf528SMauro Carvalho Chehab .info = { 7179a0bf528SMauro Carvalho Chehab .name = "ST STV0299 DVB-S", 7189a0bf528SMauro Carvalho Chehab .frequency_min = 950000, 7199a0bf528SMauro Carvalho Chehab .frequency_max = 2150000, 7209a0bf528SMauro Carvalho Chehab .frequency_stepsize = 125, /* kHz for QPSK frontends */ 7219a0bf528SMauro Carvalho Chehab .frequency_tolerance = 0, 7229a0bf528SMauro Carvalho Chehab .symbol_rate_min = 1000000, 7239a0bf528SMauro Carvalho Chehab .symbol_rate_max = 45000000, 7249a0bf528SMauro Carvalho Chehab .symbol_rate_tolerance = 500, /* ppm */ 7259a0bf528SMauro Carvalho Chehab .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 7269a0bf528SMauro Carvalho Chehab FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | 7279a0bf528SMauro Carvalho Chehab FE_CAN_QPSK | 7289a0bf528SMauro Carvalho Chehab FE_CAN_FEC_AUTO 7299a0bf528SMauro Carvalho Chehab }, 7309a0bf528SMauro Carvalho Chehab 7319a0bf528SMauro Carvalho Chehab .release = stv0299_release, 7329a0bf528SMauro Carvalho Chehab 7339a0bf528SMauro Carvalho Chehab .init = stv0299_init, 7349a0bf528SMauro Carvalho Chehab .sleep = stv0299_sleep, 7359a0bf528SMauro Carvalho Chehab .write = stv0299_write, 7369a0bf528SMauro Carvalho Chehab .i2c_gate_ctrl = stv0299_i2c_gate_ctrl, 7379a0bf528SMauro Carvalho Chehab 7389a0bf528SMauro Carvalho Chehab .set_frontend = stv0299_set_frontend, 7399a0bf528SMauro Carvalho Chehab .get_frontend = stv0299_get_frontend, 7409a0bf528SMauro Carvalho Chehab .get_tune_settings = stv0299_get_tune_settings, 7419a0bf528SMauro Carvalho Chehab 7429a0bf528SMauro Carvalho Chehab .read_status = stv0299_read_status, 7439a0bf528SMauro Carvalho Chehab .read_ber = stv0299_read_ber, 7449a0bf528SMauro Carvalho Chehab .read_signal_strength = stv0299_read_signal_strength, 7459a0bf528SMauro Carvalho Chehab .read_snr = stv0299_read_snr, 7469a0bf528SMauro Carvalho Chehab .read_ucblocks = stv0299_read_ucblocks, 7479a0bf528SMauro Carvalho Chehab 7489a0bf528SMauro Carvalho Chehab .diseqc_send_master_cmd = stv0299_send_diseqc_msg, 7499a0bf528SMauro Carvalho Chehab .diseqc_send_burst = stv0299_send_diseqc_burst, 7509a0bf528SMauro Carvalho Chehab .set_tone = stv0299_set_tone, 7519a0bf528SMauro Carvalho Chehab .set_voltage = stv0299_set_voltage, 7529a0bf528SMauro Carvalho Chehab .dishnetwork_send_legacy_command = stv0299_send_legacy_dish_cmd, 7539a0bf528SMauro Carvalho Chehab }; 7549a0bf528SMauro Carvalho Chehab 7559a0bf528SMauro Carvalho Chehab module_param(debug_legacy_dish_switch, int, 0444); 7569a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug_legacy_dish_switch, "Enable timing analysis for Dish Network legacy switches"); 7579a0bf528SMauro Carvalho Chehab 7589a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644); 7599a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); 7609a0bf528SMauro Carvalho Chehab 7619a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("ST STV0299 DVB Demodulator driver"); 7629a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, " 7639a0bf528SMauro Carvalho Chehab "Andreas Oberritter, Andrew de Quincey, Kenneth Aafly"); 7649a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL"); 7659a0bf528SMauro Carvalho Chehab 7669a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(stv0299_attach); 767