19a0bf528SMauro Carvalho Chehab /* 29a0bf528SMauro Carvalho Chehab Driver for STV0297 demodulator 39a0bf528SMauro Carvalho Chehab 49a0bf528SMauro Carvalho Chehab Copyright (C) 2004 Andrew de Quincey <adq_dvb@lidskialf.net> 59a0bf528SMauro Carvalho Chehab Copyright (C) 2003-2004 Dennis Noermann <dennis.noermann@noernet.de> 69a0bf528SMauro Carvalho Chehab 79a0bf528SMauro Carvalho Chehab This program is free software; you can redistribute it and/or modify 89a0bf528SMauro Carvalho Chehab it under the terms of the GNU General Public License as published by 99a0bf528SMauro Carvalho Chehab the Free Software Foundation; either version 2 of the License, or 109a0bf528SMauro Carvalho Chehab (at your option) any later version. 119a0bf528SMauro Carvalho Chehab 129a0bf528SMauro Carvalho Chehab This program is distributed in the hope that it will be useful, 139a0bf528SMauro Carvalho Chehab but WITHOUT ANY WARRANTY; without even the implied warranty of 149a0bf528SMauro Carvalho Chehab MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 159a0bf528SMauro Carvalho Chehab GNU General Public License for more details. 169a0bf528SMauro Carvalho Chehab 179a0bf528SMauro Carvalho Chehab You should have received a copy of the GNU General Public License 189a0bf528SMauro Carvalho Chehab along with this program; if not, write to the Free Software 199a0bf528SMauro Carvalho Chehab Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 209a0bf528SMauro Carvalho Chehab */ 219a0bf528SMauro Carvalho Chehab 229a0bf528SMauro Carvalho Chehab #include <linux/init.h> 239a0bf528SMauro Carvalho Chehab #include <linux/kernel.h> 249a0bf528SMauro Carvalho Chehab #include <linux/module.h> 259a0bf528SMauro Carvalho Chehab #include <linux/string.h> 269a0bf528SMauro Carvalho Chehab #include <linux/delay.h> 279a0bf528SMauro Carvalho Chehab #include <linux/jiffies.h> 289a0bf528SMauro Carvalho Chehab #include <linux/slab.h> 299a0bf528SMauro Carvalho Chehab 309a0bf528SMauro Carvalho Chehab #include "dvb_frontend.h" 319a0bf528SMauro Carvalho Chehab #include "stv0297.h" 329a0bf528SMauro Carvalho Chehab 339a0bf528SMauro Carvalho Chehab struct stv0297_state { 349a0bf528SMauro Carvalho Chehab struct i2c_adapter *i2c; 359a0bf528SMauro Carvalho Chehab const struct stv0297_config *config; 369a0bf528SMauro Carvalho Chehab struct dvb_frontend frontend; 379a0bf528SMauro Carvalho Chehab 389a0bf528SMauro Carvalho Chehab unsigned long last_ber; 399a0bf528SMauro Carvalho Chehab unsigned long base_freq; 409a0bf528SMauro Carvalho Chehab }; 419a0bf528SMauro Carvalho Chehab 429a0bf528SMauro Carvalho Chehab #if 1 439a0bf528SMauro Carvalho Chehab #define dprintk(x...) printk(x) 449a0bf528SMauro Carvalho Chehab #else 459a0bf528SMauro Carvalho Chehab #define dprintk(x...) 469a0bf528SMauro Carvalho Chehab #endif 479a0bf528SMauro Carvalho Chehab 489a0bf528SMauro Carvalho Chehab #define STV0297_CLOCK_KHZ 28900 499a0bf528SMauro Carvalho Chehab 509a0bf528SMauro Carvalho Chehab 519a0bf528SMauro Carvalho Chehab static int stv0297_writereg(struct stv0297_state *state, u8 reg, u8 data) 529a0bf528SMauro Carvalho Chehab { 539a0bf528SMauro Carvalho Chehab int ret; 549a0bf528SMauro Carvalho Chehab u8 buf[] = { reg, data }; 559a0bf528SMauro Carvalho Chehab struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 2 }; 569a0bf528SMauro Carvalho Chehab 579a0bf528SMauro Carvalho Chehab ret = i2c_transfer(state->i2c, &msg, 1); 589a0bf528SMauro Carvalho Chehab 599a0bf528SMauro Carvalho Chehab if (ret != 1) 60*4bd69e7bSMauro Carvalho Chehab dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", 61*4bd69e7bSMauro Carvalho Chehab __func__, reg, data, ret); 629a0bf528SMauro Carvalho Chehab 639a0bf528SMauro Carvalho Chehab return (ret != 1) ? -1 : 0; 649a0bf528SMauro Carvalho Chehab } 659a0bf528SMauro Carvalho Chehab 669a0bf528SMauro Carvalho Chehab static int stv0297_readreg(struct stv0297_state *state, u8 reg) 679a0bf528SMauro Carvalho Chehab { 689a0bf528SMauro Carvalho Chehab int ret; 699a0bf528SMauro Carvalho Chehab u8 b0[] = { reg }; 709a0bf528SMauro Carvalho Chehab u8 b1[] = { 0 }; 719a0bf528SMauro Carvalho Chehab struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1}, 729a0bf528SMauro Carvalho Chehab {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1} 739a0bf528SMauro Carvalho Chehab }; 749a0bf528SMauro Carvalho Chehab 759a0bf528SMauro Carvalho Chehab // this device needs a STOP between the register and data 769a0bf528SMauro Carvalho Chehab if (state->config->stop_during_read) { 779a0bf528SMauro Carvalho Chehab if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) { 789a0bf528SMauro Carvalho Chehab dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg, ret); 799a0bf528SMauro Carvalho Chehab return -1; 809a0bf528SMauro Carvalho Chehab } 819a0bf528SMauro Carvalho Chehab if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) { 829a0bf528SMauro Carvalho Chehab dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg, ret); 839a0bf528SMauro Carvalho Chehab return -1; 849a0bf528SMauro Carvalho Chehab } 859a0bf528SMauro Carvalho Chehab } else { 869a0bf528SMauro Carvalho Chehab if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { 879a0bf528SMauro Carvalho Chehab dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg, ret); 889a0bf528SMauro Carvalho Chehab return -1; 899a0bf528SMauro Carvalho Chehab } 909a0bf528SMauro Carvalho Chehab } 919a0bf528SMauro Carvalho Chehab 929a0bf528SMauro Carvalho Chehab return b1[0]; 939a0bf528SMauro Carvalho Chehab } 949a0bf528SMauro Carvalho Chehab 959a0bf528SMauro Carvalho Chehab static int stv0297_writereg_mask(struct stv0297_state *state, u8 reg, u8 mask, u8 data) 969a0bf528SMauro Carvalho Chehab { 979a0bf528SMauro Carvalho Chehab int val; 989a0bf528SMauro Carvalho Chehab 999a0bf528SMauro Carvalho Chehab val = stv0297_readreg(state, reg); 1009a0bf528SMauro Carvalho Chehab val &= ~mask; 1019a0bf528SMauro Carvalho Chehab val |= (data & mask); 1029a0bf528SMauro Carvalho Chehab stv0297_writereg(state, reg, val); 1039a0bf528SMauro Carvalho Chehab 1049a0bf528SMauro Carvalho Chehab return 0; 1059a0bf528SMauro Carvalho Chehab } 1069a0bf528SMauro Carvalho Chehab 1079a0bf528SMauro Carvalho Chehab static int stv0297_readregs(struct stv0297_state *state, u8 reg1, u8 * b, u8 len) 1089a0bf528SMauro Carvalho Chehab { 1099a0bf528SMauro Carvalho Chehab int ret; 1109a0bf528SMauro Carvalho Chehab struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = 1119a0bf528SMauro Carvalho Chehab ®1,.len = 1}, 1129a0bf528SMauro Carvalho Chehab {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b,.len = len} 1139a0bf528SMauro Carvalho Chehab }; 1149a0bf528SMauro Carvalho Chehab 1159a0bf528SMauro Carvalho Chehab // this device needs a STOP between the register and data 1169a0bf528SMauro Carvalho Chehab if (state->config->stop_during_read) { 1179a0bf528SMauro Carvalho Chehab if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) { 1189a0bf528SMauro Carvalho Chehab dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg1, ret); 1199a0bf528SMauro Carvalho Chehab return -1; 1209a0bf528SMauro Carvalho Chehab } 1219a0bf528SMauro Carvalho Chehab if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) { 1229a0bf528SMauro Carvalho Chehab dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg1, ret); 1239a0bf528SMauro Carvalho Chehab return -1; 1249a0bf528SMauro Carvalho Chehab } 1259a0bf528SMauro Carvalho Chehab } else { 1269a0bf528SMauro Carvalho Chehab if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { 1279a0bf528SMauro Carvalho Chehab dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg1, ret); 1289a0bf528SMauro Carvalho Chehab return -1; 1299a0bf528SMauro Carvalho Chehab } 1309a0bf528SMauro Carvalho Chehab } 1319a0bf528SMauro Carvalho Chehab 1329a0bf528SMauro Carvalho Chehab return 0; 1339a0bf528SMauro Carvalho Chehab } 1349a0bf528SMauro Carvalho Chehab 1359a0bf528SMauro Carvalho Chehab static u32 stv0297_get_symbolrate(struct stv0297_state *state) 1369a0bf528SMauro Carvalho Chehab { 1379a0bf528SMauro Carvalho Chehab u64 tmp; 1389a0bf528SMauro Carvalho Chehab 1395e6b681bSMauro Carvalho Chehab tmp = (u64)(stv0297_readreg(state, 0x55) 1405e6b681bSMauro Carvalho Chehab | (stv0297_readreg(state, 0x56) << 8) 1415e6b681bSMauro Carvalho Chehab | (stv0297_readreg(state, 0x57) << 16) 1425e6b681bSMauro Carvalho Chehab | (stv0297_readreg(state, 0x58) << 24)); 1439a0bf528SMauro Carvalho Chehab 1449a0bf528SMauro Carvalho Chehab tmp *= STV0297_CLOCK_KHZ; 1459a0bf528SMauro Carvalho Chehab tmp >>= 32; 1469a0bf528SMauro Carvalho Chehab 1479a0bf528SMauro Carvalho Chehab return (u32) tmp; 1489a0bf528SMauro Carvalho Chehab } 1499a0bf528SMauro Carvalho Chehab 1509a0bf528SMauro Carvalho Chehab static void stv0297_set_symbolrate(struct stv0297_state *state, u32 srate) 1519a0bf528SMauro Carvalho Chehab { 1529a0bf528SMauro Carvalho Chehab long tmp; 1539a0bf528SMauro Carvalho Chehab 1549a0bf528SMauro Carvalho Chehab tmp = 131072L * srate; /* 131072 = 2^17 */ 1559a0bf528SMauro Carvalho Chehab tmp = tmp / (STV0297_CLOCK_KHZ / 4); /* 1/4 = 2^-2 */ 1569a0bf528SMauro Carvalho Chehab tmp = tmp * 8192L; /* 8192 = 2^13 */ 1579a0bf528SMauro Carvalho Chehab 1589a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x55, (unsigned char) (tmp & 0xFF)); 1599a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x56, (unsigned char) (tmp >> 8)); 1609a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x57, (unsigned char) (tmp >> 16)); 1619a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x58, (unsigned char) (tmp >> 24)); 1629a0bf528SMauro Carvalho Chehab } 1639a0bf528SMauro Carvalho Chehab 1649a0bf528SMauro Carvalho Chehab static void stv0297_set_sweeprate(struct stv0297_state *state, short fshift, long symrate) 1659a0bf528SMauro Carvalho Chehab { 1669a0bf528SMauro Carvalho Chehab long tmp; 1679a0bf528SMauro Carvalho Chehab 1689a0bf528SMauro Carvalho Chehab tmp = (long) fshift *262144L; /* 262144 = 2*18 */ 1699a0bf528SMauro Carvalho Chehab tmp /= symrate; 1709a0bf528SMauro Carvalho Chehab tmp *= 1024; /* 1024 = 2*10 */ 1719a0bf528SMauro Carvalho Chehab 1729a0bf528SMauro Carvalho Chehab // adjust 1739a0bf528SMauro Carvalho Chehab if (tmp >= 0) { 1749a0bf528SMauro Carvalho Chehab tmp += 500000; 1759a0bf528SMauro Carvalho Chehab } else { 1769a0bf528SMauro Carvalho Chehab tmp -= 500000; 1779a0bf528SMauro Carvalho Chehab } 1789a0bf528SMauro Carvalho Chehab tmp /= 1000000; 1799a0bf528SMauro Carvalho Chehab 1809a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x60, tmp & 0xFF); 1819a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x69, 0xF0, (tmp >> 4) & 0xf0); 1829a0bf528SMauro Carvalho Chehab } 1839a0bf528SMauro Carvalho Chehab 1849a0bf528SMauro Carvalho Chehab static void stv0297_set_carrieroffset(struct stv0297_state *state, long offset) 1859a0bf528SMauro Carvalho Chehab { 1869a0bf528SMauro Carvalho Chehab long tmp; 1879a0bf528SMauro Carvalho Chehab 1889a0bf528SMauro Carvalho Chehab /* symrate is hardcoded to 10000 */ 1899a0bf528SMauro Carvalho Chehab tmp = offset * 26844L; /* (2**28)/10000 */ 1909a0bf528SMauro Carvalho Chehab if (tmp < 0) 1919a0bf528SMauro Carvalho Chehab tmp += 0x10000000; 1929a0bf528SMauro Carvalho Chehab tmp &= 0x0FFFFFFF; 1939a0bf528SMauro Carvalho Chehab 1949a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x66, (unsigned char) (tmp & 0xFF)); 1959a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x67, (unsigned char) (tmp >> 8)); 1969a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x68, (unsigned char) (tmp >> 16)); 1979a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x69, 0x0F, (tmp >> 24) & 0x0f); 1989a0bf528SMauro Carvalho Chehab } 1999a0bf528SMauro Carvalho Chehab 2009a0bf528SMauro Carvalho Chehab /* 2019a0bf528SMauro Carvalho Chehab static long stv0297_get_carrieroffset(struct stv0297_state *state) 2029a0bf528SMauro Carvalho Chehab { 2039a0bf528SMauro Carvalho Chehab s64 tmp; 2049a0bf528SMauro Carvalho Chehab 2059a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x6B, 0x00); 2069a0bf528SMauro Carvalho Chehab 2079a0bf528SMauro Carvalho Chehab tmp = stv0297_readreg(state, 0x66); 2089a0bf528SMauro Carvalho Chehab tmp |= (stv0297_readreg(state, 0x67) << 8); 2099a0bf528SMauro Carvalho Chehab tmp |= (stv0297_readreg(state, 0x68) << 16); 2109a0bf528SMauro Carvalho Chehab tmp |= (stv0297_readreg(state, 0x69) & 0x0F) << 24; 2119a0bf528SMauro Carvalho Chehab 2129a0bf528SMauro Carvalho Chehab tmp *= stv0297_get_symbolrate(state); 2139a0bf528SMauro Carvalho Chehab tmp >>= 28; 2149a0bf528SMauro Carvalho Chehab 2159a0bf528SMauro Carvalho Chehab return (s32) tmp; 2169a0bf528SMauro Carvalho Chehab } 2179a0bf528SMauro Carvalho Chehab */ 2189a0bf528SMauro Carvalho Chehab 2199a0bf528SMauro Carvalho Chehab static void stv0297_set_initialdemodfreq(struct stv0297_state *state, long freq) 2209a0bf528SMauro Carvalho Chehab { 2219a0bf528SMauro Carvalho Chehab s32 tmp; 2229a0bf528SMauro Carvalho Chehab 2239a0bf528SMauro Carvalho Chehab if (freq > 10000) 2249a0bf528SMauro Carvalho Chehab freq -= STV0297_CLOCK_KHZ; 2259a0bf528SMauro Carvalho Chehab 2269a0bf528SMauro Carvalho Chehab tmp = (STV0297_CLOCK_KHZ * 1000) / (1 << 16); 2279a0bf528SMauro Carvalho Chehab tmp = (freq * 1000) / tmp; 2289a0bf528SMauro Carvalho Chehab if (tmp > 0xffff) 2299a0bf528SMauro Carvalho Chehab tmp = 0xffff; 2309a0bf528SMauro Carvalho Chehab 2319a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x25, 0x80, 0x80); 2329a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x21, tmp >> 8); 2339a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x20, tmp); 2349a0bf528SMauro Carvalho Chehab } 2359a0bf528SMauro Carvalho Chehab 2360df289a2SMauro Carvalho Chehab static int stv0297_set_qam(struct stv0297_state *state, 2370df289a2SMauro Carvalho Chehab enum fe_modulation modulation) 2389a0bf528SMauro Carvalho Chehab { 2399a0bf528SMauro Carvalho Chehab int val = 0; 2409a0bf528SMauro Carvalho Chehab 2419a0bf528SMauro Carvalho Chehab switch (modulation) { 2429a0bf528SMauro Carvalho Chehab case QAM_16: 2439a0bf528SMauro Carvalho Chehab val = 0; 2449a0bf528SMauro Carvalho Chehab break; 2459a0bf528SMauro Carvalho Chehab 2469a0bf528SMauro Carvalho Chehab case QAM_32: 2479a0bf528SMauro Carvalho Chehab val = 1; 2489a0bf528SMauro Carvalho Chehab break; 2499a0bf528SMauro Carvalho Chehab 2509a0bf528SMauro Carvalho Chehab case QAM_64: 2519a0bf528SMauro Carvalho Chehab val = 4; 2529a0bf528SMauro Carvalho Chehab break; 2539a0bf528SMauro Carvalho Chehab 2549a0bf528SMauro Carvalho Chehab case QAM_128: 2559a0bf528SMauro Carvalho Chehab val = 2; 2569a0bf528SMauro Carvalho Chehab break; 2579a0bf528SMauro Carvalho Chehab 2589a0bf528SMauro Carvalho Chehab case QAM_256: 2599a0bf528SMauro Carvalho Chehab val = 3; 2609a0bf528SMauro Carvalho Chehab break; 2619a0bf528SMauro Carvalho Chehab 2629a0bf528SMauro Carvalho Chehab default: 2639a0bf528SMauro Carvalho Chehab return -EINVAL; 2649a0bf528SMauro Carvalho Chehab } 2659a0bf528SMauro Carvalho Chehab 2669a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x00, 0x70, val << 4); 2679a0bf528SMauro Carvalho Chehab 2689a0bf528SMauro Carvalho Chehab return 0; 2699a0bf528SMauro Carvalho Chehab } 2709a0bf528SMauro Carvalho Chehab 2710df289a2SMauro Carvalho Chehab static int stv0297_set_inversion(struct stv0297_state *state, 2720df289a2SMauro Carvalho Chehab enum fe_spectral_inversion inversion) 2739a0bf528SMauro Carvalho Chehab { 2749a0bf528SMauro Carvalho Chehab int val = 0; 2759a0bf528SMauro Carvalho Chehab 2769a0bf528SMauro Carvalho Chehab switch (inversion) { 2779a0bf528SMauro Carvalho Chehab case INVERSION_OFF: 2789a0bf528SMauro Carvalho Chehab val = 0; 2799a0bf528SMauro Carvalho Chehab break; 2809a0bf528SMauro Carvalho Chehab 2819a0bf528SMauro Carvalho Chehab case INVERSION_ON: 2829a0bf528SMauro Carvalho Chehab val = 1; 2839a0bf528SMauro Carvalho Chehab break; 2849a0bf528SMauro Carvalho Chehab 2859a0bf528SMauro Carvalho Chehab default: 2869a0bf528SMauro Carvalho Chehab return -EINVAL; 2879a0bf528SMauro Carvalho Chehab } 2889a0bf528SMauro Carvalho Chehab 2899a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x83, 0x08, val << 3); 2909a0bf528SMauro Carvalho Chehab 2919a0bf528SMauro Carvalho Chehab return 0; 2929a0bf528SMauro Carvalho Chehab } 2939a0bf528SMauro Carvalho Chehab 2949a0bf528SMauro Carvalho Chehab static int stv0297_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) 2959a0bf528SMauro Carvalho Chehab { 2969a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 2979a0bf528SMauro Carvalho Chehab 2989a0bf528SMauro Carvalho Chehab if (enable) { 2999a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x87, 0x78); 3009a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x86, 0xc8); 3019a0bf528SMauro Carvalho Chehab } 3029a0bf528SMauro Carvalho Chehab 3039a0bf528SMauro Carvalho Chehab return 0; 3049a0bf528SMauro Carvalho Chehab } 3059a0bf528SMauro Carvalho Chehab 3069a0bf528SMauro Carvalho Chehab static int stv0297_init(struct dvb_frontend *fe) 3079a0bf528SMauro Carvalho Chehab { 3089a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 3099a0bf528SMauro Carvalho Chehab int i; 3109a0bf528SMauro Carvalho Chehab 3119a0bf528SMauro Carvalho Chehab /* load init table */ 3129a0bf528SMauro Carvalho Chehab for (i=0; !(state->config->inittab[i] == 0xff && state->config->inittab[i+1] == 0xff); i+=2) 3139a0bf528SMauro Carvalho Chehab stv0297_writereg(state, state->config->inittab[i], state->config->inittab[i+1]); 3149a0bf528SMauro Carvalho Chehab msleep(200); 3159a0bf528SMauro Carvalho Chehab 3169a0bf528SMauro Carvalho Chehab state->last_ber = 0; 3179a0bf528SMauro Carvalho Chehab 3189a0bf528SMauro Carvalho Chehab return 0; 3199a0bf528SMauro Carvalho Chehab } 3209a0bf528SMauro Carvalho Chehab 3219a0bf528SMauro Carvalho Chehab static int stv0297_sleep(struct dvb_frontend *fe) 3229a0bf528SMauro Carvalho Chehab { 3239a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 3249a0bf528SMauro Carvalho Chehab 3259a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x80, 1, 1); 3269a0bf528SMauro Carvalho Chehab 3279a0bf528SMauro Carvalho Chehab return 0; 3289a0bf528SMauro Carvalho Chehab } 3299a0bf528SMauro Carvalho Chehab 3300df289a2SMauro Carvalho Chehab static int stv0297_read_status(struct dvb_frontend *fe, 3310df289a2SMauro Carvalho Chehab enum fe_status *status) 3329a0bf528SMauro Carvalho Chehab { 3339a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 3349a0bf528SMauro Carvalho Chehab 3359a0bf528SMauro Carvalho Chehab u8 sync = stv0297_readreg(state, 0xDF); 3369a0bf528SMauro Carvalho Chehab 3379a0bf528SMauro Carvalho Chehab *status = 0; 3389a0bf528SMauro Carvalho Chehab if (sync & 0x80) 3399a0bf528SMauro Carvalho Chehab *status |= 3409a0bf528SMauro Carvalho Chehab FE_HAS_SYNC | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_LOCK; 3419a0bf528SMauro Carvalho Chehab return 0; 3429a0bf528SMauro Carvalho Chehab } 3439a0bf528SMauro Carvalho Chehab 3449a0bf528SMauro Carvalho Chehab static int stv0297_read_ber(struct dvb_frontend *fe, u32 * ber) 3459a0bf528SMauro Carvalho Chehab { 3469a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 3479a0bf528SMauro Carvalho Chehab u8 BER[3]; 3489a0bf528SMauro Carvalho Chehab 3499a0bf528SMauro Carvalho Chehab stv0297_readregs(state, 0xA0, BER, 3); 3509a0bf528SMauro Carvalho Chehab if (!(BER[0] & 0x80)) { 3519a0bf528SMauro Carvalho Chehab state->last_ber = BER[2] << 8 | BER[1]; 3529a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0xA0, 0x80, 0x80); 3539a0bf528SMauro Carvalho Chehab } 3549a0bf528SMauro Carvalho Chehab 3559a0bf528SMauro Carvalho Chehab *ber = state->last_ber; 3569a0bf528SMauro Carvalho Chehab 3579a0bf528SMauro Carvalho Chehab return 0; 3589a0bf528SMauro Carvalho Chehab } 3599a0bf528SMauro Carvalho Chehab 3609a0bf528SMauro Carvalho Chehab 3619a0bf528SMauro Carvalho Chehab static int stv0297_read_signal_strength(struct dvb_frontend *fe, u16 * strength) 3629a0bf528SMauro Carvalho Chehab { 3639a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 3649a0bf528SMauro Carvalho Chehab u8 STRENGTH[3]; 3659a0bf528SMauro Carvalho Chehab u16 tmp; 3669a0bf528SMauro Carvalho Chehab 3679a0bf528SMauro Carvalho Chehab stv0297_readregs(state, 0x41, STRENGTH, 3); 3689a0bf528SMauro Carvalho Chehab tmp = (STRENGTH[1] & 0x03) << 8 | STRENGTH[0]; 3699a0bf528SMauro Carvalho Chehab if (STRENGTH[2] & 0x20) { 3709a0bf528SMauro Carvalho Chehab if (tmp < 0x200) 3719a0bf528SMauro Carvalho Chehab tmp = 0; 3729a0bf528SMauro Carvalho Chehab else 3739a0bf528SMauro Carvalho Chehab tmp = tmp - 0x200; 3749a0bf528SMauro Carvalho Chehab } else { 3759a0bf528SMauro Carvalho Chehab if (tmp > 0x1ff) 3769a0bf528SMauro Carvalho Chehab tmp = 0; 3779a0bf528SMauro Carvalho Chehab else 3789a0bf528SMauro Carvalho Chehab tmp = 0x1ff - tmp; 3799a0bf528SMauro Carvalho Chehab } 3809a0bf528SMauro Carvalho Chehab *strength = (tmp << 7) | (tmp >> 2); 3819a0bf528SMauro Carvalho Chehab return 0; 3829a0bf528SMauro Carvalho Chehab } 3839a0bf528SMauro Carvalho Chehab 3849a0bf528SMauro Carvalho Chehab static int stv0297_read_snr(struct dvb_frontend *fe, u16 * snr) 3859a0bf528SMauro Carvalho Chehab { 3869a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 3879a0bf528SMauro Carvalho Chehab u8 SNR[2]; 3889a0bf528SMauro Carvalho Chehab 3899a0bf528SMauro Carvalho Chehab stv0297_readregs(state, 0x07, SNR, 2); 3909a0bf528SMauro Carvalho Chehab *snr = SNR[1] << 8 | SNR[0]; 3919a0bf528SMauro Carvalho Chehab 3929a0bf528SMauro Carvalho Chehab return 0; 3939a0bf528SMauro Carvalho Chehab } 3949a0bf528SMauro Carvalho Chehab 3959a0bf528SMauro Carvalho Chehab static int stv0297_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks) 3969a0bf528SMauro Carvalho Chehab { 3979a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 3989a0bf528SMauro Carvalho Chehab 3999a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0xDF, 0x03, 0x03); /* freeze the counters */ 4009a0bf528SMauro Carvalho Chehab 4019a0bf528SMauro Carvalho Chehab *ucblocks = (stv0297_readreg(state, 0xD5) << 8) 4029a0bf528SMauro Carvalho Chehab | stv0297_readreg(state, 0xD4); 4039a0bf528SMauro Carvalho Chehab 4049a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0xDF, 0x03, 0x02); /* clear the counters */ 4059a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0xDF, 0x03, 0x01); /* re-enable the counters */ 4069a0bf528SMauro Carvalho Chehab 4079a0bf528SMauro Carvalho Chehab return 0; 4089a0bf528SMauro Carvalho Chehab } 4099a0bf528SMauro Carvalho Chehab 4109a0bf528SMauro Carvalho Chehab static int stv0297_set_frontend(struct dvb_frontend *fe) 4119a0bf528SMauro Carvalho Chehab { 4129a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *p = &fe->dtv_property_cache; 4139a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 4149a0bf528SMauro Carvalho Chehab int u_threshold; 4159a0bf528SMauro Carvalho Chehab int initial_u; 4169a0bf528SMauro Carvalho Chehab int blind_u; 4179a0bf528SMauro Carvalho Chehab int delay; 4189a0bf528SMauro Carvalho Chehab int sweeprate; 4199a0bf528SMauro Carvalho Chehab int carrieroffset; 4209a0bf528SMauro Carvalho Chehab unsigned long timeout; 4210df289a2SMauro Carvalho Chehab enum fe_spectral_inversion inversion; 4229a0bf528SMauro Carvalho Chehab 4239a0bf528SMauro Carvalho Chehab switch (p->modulation) { 4249a0bf528SMauro Carvalho Chehab case QAM_16: 4259a0bf528SMauro Carvalho Chehab case QAM_32: 4269a0bf528SMauro Carvalho Chehab case QAM_64: 4279a0bf528SMauro Carvalho Chehab delay = 100; 4289a0bf528SMauro Carvalho Chehab sweeprate = 1000; 4299a0bf528SMauro Carvalho Chehab break; 4309a0bf528SMauro Carvalho Chehab 4319a0bf528SMauro Carvalho Chehab case QAM_128: 4329a0bf528SMauro Carvalho Chehab case QAM_256: 4339a0bf528SMauro Carvalho Chehab delay = 200; 4349a0bf528SMauro Carvalho Chehab sweeprate = 500; 4359a0bf528SMauro Carvalho Chehab break; 4369a0bf528SMauro Carvalho Chehab 4379a0bf528SMauro Carvalho Chehab default: 4389a0bf528SMauro Carvalho Chehab return -EINVAL; 4399a0bf528SMauro Carvalho Chehab } 4409a0bf528SMauro Carvalho Chehab 4419a0bf528SMauro Carvalho Chehab // determine inversion dependent parameters 4429a0bf528SMauro Carvalho Chehab inversion = p->inversion; 4439a0bf528SMauro Carvalho Chehab if (state->config->invert) 4449a0bf528SMauro Carvalho Chehab inversion = (inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON; 4459a0bf528SMauro Carvalho Chehab carrieroffset = -330; 4469a0bf528SMauro Carvalho Chehab switch (inversion) { 4479a0bf528SMauro Carvalho Chehab case INVERSION_OFF: 4489a0bf528SMauro Carvalho Chehab break; 4499a0bf528SMauro Carvalho Chehab 4509a0bf528SMauro Carvalho Chehab case INVERSION_ON: 4519a0bf528SMauro Carvalho Chehab sweeprate = -sweeprate; 4529a0bf528SMauro Carvalho Chehab carrieroffset = -carrieroffset; 4539a0bf528SMauro Carvalho Chehab break; 4549a0bf528SMauro Carvalho Chehab 4559a0bf528SMauro Carvalho Chehab default: 4569a0bf528SMauro Carvalho Chehab return -EINVAL; 4579a0bf528SMauro Carvalho Chehab } 4589a0bf528SMauro Carvalho Chehab 4599a0bf528SMauro Carvalho Chehab stv0297_init(fe); 4609a0bf528SMauro Carvalho Chehab if (fe->ops.tuner_ops.set_params) { 4619a0bf528SMauro Carvalho Chehab fe->ops.tuner_ops.set_params(fe); 4629a0bf528SMauro Carvalho Chehab if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); 4639a0bf528SMauro Carvalho Chehab } 4649a0bf528SMauro Carvalho Chehab 4659a0bf528SMauro Carvalho Chehab /* clear software interrupts */ 4669a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x82, 0x0); 4679a0bf528SMauro Carvalho Chehab 4689a0bf528SMauro Carvalho Chehab /* set initial demodulation frequency */ 4699a0bf528SMauro Carvalho Chehab stv0297_set_initialdemodfreq(state, 7250); 4709a0bf528SMauro Carvalho Chehab 4719a0bf528SMauro Carvalho Chehab /* setup AGC */ 4729a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x43, 0x10, 0x00); 4739a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x41, 0x00); 4749a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x42, 0x03, 0x01); 4759a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x36, 0x60, 0x00); 4769a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x36, 0x18, 0x00); 4779a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x71, 0x80, 0x80); 4789a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x72, 0x00); 4799a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x73, 0x00); 4809a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x74, 0x0F, 0x00); 4819a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x43, 0x08, 0x00); 4829a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x71, 0x80, 0x00); 4839a0bf528SMauro Carvalho Chehab 4849a0bf528SMauro Carvalho Chehab /* setup STL */ 4859a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x5a, 0x20, 0x20); 4869a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x5b, 0x02, 0x02); 4879a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x5b, 0x02, 0x00); 4889a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x5b, 0x01, 0x00); 4899a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x5a, 0x40, 0x40); 4909a0bf528SMauro Carvalho Chehab 4919a0bf528SMauro Carvalho Chehab /* disable frequency sweep */ 4929a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x6a, 0x01, 0x00); 4939a0bf528SMauro Carvalho Chehab 4949a0bf528SMauro Carvalho Chehab /* reset deinterleaver */ 4959a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x81, 0x01, 0x01); 4969a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x81, 0x01, 0x00); 4979a0bf528SMauro Carvalho Chehab 4989a0bf528SMauro Carvalho Chehab /* ??? */ 4999a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x83, 0x20, 0x20); 5009a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x83, 0x20, 0x00); 5019a0bf528SMauro Carvalho Chehab 5029a0bf528SMauro Carvalho Chehab /* reset equaliser */ 5039a0bf528SMauro Carvalho Chehab u_threshold = stv0297_readreg(state, 0x00) & 0xf; 5049a0bf528SMauro Carvalho Chehab initial_u = stv0297_readreg(state, 0x01) >> 4; 5059a0bf528SMauro Carvalho Chehab blind_u = stv0297_readreg(state, 0x01) & 0xf; 5069a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x84, 0x01, 0x01); 5079a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x84, 0x01, 0x00); 5089a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x00, 0x0f, u_threshold); 5099a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x01, 0xf0, initial_u << 4); 5109a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x01, 0x0f, blind_u); 5119a0bf528SMauro Carvalho Chehab 5129a0bf528SMauro Carvalho Chehab /* data comes from internal A/D */ 5139a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x87, 0x80, 0x00); 5149a0bf528SMauro Carvalho Chehab 5159a0bf528SMauro Carvalho Chehab /* clear phase registers */ 5169a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x63, 0x00); 5179a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x64, 0x00); 5189a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x65, 0x00); 5199a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x66, 0x00); 5209a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x67, 0x00); 5219a0bf528SMauro Carvalho Chehab stv0297_writereg(state, 0x68, 0x00); 5229a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x69, 0x0f, 0x00); 5239a0bf528SMauro Carvalho Chehab 5249a0bf528SMauro Carvalho Chehab /* set parameters */ 5259a0bf528SMauro Carvalho Chehab stv0297_set_qam(state, p->modulation); 5269a0bf528SMauro Carvalho Chehab stv0297_set_symbolrate(state, p->symbol_rate / 1000); 5279a0bf528SMauro Carvalho Chehab stv0297_set_sweeprate(state, sweeprate, p->symbol_rate / 1000); 5289a0bf528SMauro Carvalho Chehab stv0297_set_carrieroffset(state, carrieroffset); 5299a0bf528SMauro Carvalho Chehab stv0297_set_inversion(state, inversion); 5309a0bf528SMauro Carvalho Chehab 5319a0bf528SMauro Carvalho Chehab /* kick off lock */ 5329a0bf528SMauro Carvalho Chehab /* Disable corner detection for higher QAMs */ 5339a0bf528SMauro Carvalho Chehab if (p->modulation == QAM_128 || 5349a0bf528SMauro Carvalho Chehab p->modulation == QAM_256) 5359a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x88, 0x08, 0x00); 5369a0bf528SMauro Carvalho Chehab else 5379a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x88, 0x08, 0x08); 5389a0bf528SMauro Carvalho Chehab 5399a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x5a, 0x20, 0x00); 5409a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x6a, 0x01, 0x01); 5419a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x43, 0x40, 0x40); 5429a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x5b, 0x30, 0x00); 5439a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x03, 0x0c, 0x0c); 5449a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x03, 0x03, 0x03); 5459a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x43, 0x10, 0x10); 5469a0bf528SMauro Carvalho Chehab 5479a0bf528SMauro Carvalho Chehab /* wait for WGAGC lock */ 5489a0bf528SMauro Carvalho Chehab timeout = jiffies + msecs_to_jiffies(2000); 5499a0bf528SMauro Carvalho Chehab while (time_before(jiffies, timeout)) { 5509a0bf528SMauro Carvalho Chehab msleep(10); 5519a0bf528SMauro Carvalho Chehab if (stv0297_readreg(state, 0x43) & 0x08) 5529a0bf528SMauro Carvalho Chehab break; 5539a0bf528SMauro Carvalho Chehab } 5549a0bf528SMauro Carvalho Chehab if (time_after(jiffies, timeout)) { 5559a0bf528SMauro Carvalho Chehab goto timeout; 5569a0bf528SMauro Carvalho Chehab } 5579a0bf528SMauro Carvalho Chehab msleep(20); 5589a0bf528SMauro Carvalho Chehab 5599a0bf528SMauro Carvalho Chehab /* wait for equaliser partial convergence */ 5609a0bf528SMauro Carvalho Chehab timeout = jiffies + msecs_to_jiffies(500); 5619a0bf528SMauro Carvalho Chehab while (time_before(jiffies, timeout)) { 5629a0bf528SMauro Carvalho Chehab msleep(10); 5639a0bf528SMauro Carvalho Chehab 5649a0bf528SMauro Carvalho Chehab if (stv0297_readreg(state, 0x82) & 0x04) { 5659a0bf528SMauro Carvalho Chehab break; 5669a0bf528SMauro Carvalho Chehab } 5679a0bf528SMauro Carvalho Chehab } 5689a0bf528SMauro Carvalho Chehab if (time_after(jiffies, timeout)) { 5699a0bf528SMauro Carvalho Chehab goto timeout; 5709a0bf528SMauro Carvalho Chehab } 5719a0bf528SMauro Carvalho Chehab 5729a0bf528SMauro Carvalho Chehab /* wait for equaliser full convergence */ 5739a0bf528SMauro Carvalho Chehab timeout = jiffies + msecs_to_jiffies(delay); 5749a0bf528SMauro Carvalho Chehab while (time_before(jiffies, timeout)) { 5759a0bf528SMauro Carvalho Chehab msleep(10); 5769a0bf528SMauro Carvalho Chehab 5779a0bf528SMauro Carvalho Chehab if (stv0297_readreg(state, 0x82) & 0x08) { 5789a0bf528SMauro Carvalho Chehab break; 5799a0bf528SMauro Carvalho Chehab } 5809a0bf528SMauro Carvalho Chehab } 5819a0bf528SMauro Carvalho Chehab if (time_after(jiffies, timeout)) { 5829a0bf528SMauro Carvalho Chehab goto timeout; 5839a0bf528SMauro Carvalho Chehab } 5849a0bf528SMauro Carvalho Chehab 5859a0bf528SMauro Carvalho Chehab /* disable sweep */ 5869a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x6a, 1, 0); 5879a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x88, 8, 0); 5889a0bf528SMauro Carvalho Chehab 5899a0bf528SMauro Carvalho Chehab /* wait for main lock */ 5909a0bf528SMauro Carvalho Chehab timeout = jiffies + msecs_to_jiffies(20); 5919a0bf528SMauro Carvalho Chehab while (time_before(jiffies, timeout)) { 5929a0bf528SMauro Carvalho Chehab msleep(10); 5939a0bf528SMauro Carvalho Chehab 5949a0bf528SMauro Carvalho Chehab if (stv0297_readreg(state, 0xDF) & 0x80) { 5959a0bf528SMauro Carvalho Chehab break; 5969a0bf528SMauro Carvalho Chehab } 5979a0bf528SMauro Carvalho Chehab } 5989a0bf528SMauro Carvalho Chehab if (time_after(jiffies, timeout)) { 5999a0bf528SMauro Carvalho Chehab goto timeout; 6009a0bf528SMauro Carvalho Chehab } 6019a0bf528SMauro Carvalho Chehab msleep(100); 6029a0bf528SMauro Carvalho Chehab 6039a0bf528SMauro Carvalho Chehab /* is it still locked after that delay? */ 6049a0bf528SMauro Carvalho Chehab if (!(stv0297_readreg(state, 0xDF) & 0x80)) { 6059a0bf528SMauro Carvalho Chehab goto timeout; 6069a0bf528SMauro Carvalho Chehab } 6079a0bf528SMauro Carvalho Chehab 6089a0bf528SMauro Carvalho Chehab /* success!! */ 6099a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x5a, 0x40, 0x00); 6109a0bf528SMauro Carvalho Chehab state->base_freq = p->frequency; 6119a0bf528SMauro Carvalho Chehab return 0; 6129a0bf528SMauro Carvalho Chehab 6139a0bf528SMauro Carvalho Chehab timeout: 6149a0bf528SMauro Carvalho Chehab stv0297_writereg_mask(state, 0x6a, 0x01, 0x00); 6159a0bf528SMauro Carvalho Chehab return 0; 6169a0bf528SMauro Carvalho Chehab } 6179a0bf528SMauro Carvalho Chehab 6187e3e68bcSMauro Carvalho Chehab static int stv0297_get_frontend(struct dvb_frontend *fe, 6197e3e68bcSMauro Carvalho Chehab struct dtv_frontend_properties *p) 6209a0bf528SMauro Carvalho Chehab { 6219a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 6229a0bf528SMauro Carvalho Chehab int reg_00, reg_83; 6239a0bf528SMauro Carvalho Chehab 6249a0bf528SMauro Carvalho Chehab reg_00 = stv0297_readreg(state, 0x00); 6259a0bf528SMauro Carvalho Chehab reg_83 = stv0297_readreg(state, 0x83); 6269a0bf528SMauro Carvalho Chehab 6279a0bf528SMauro Carvalho Chehab p->frequency = state->base_freq; 6289a0bf528SMauro Carvalho Chehab p->inversion = (reg_83 & 0x08) ? INVERSION_ON : INVERSION_OFF; 6299a0bf528SMauro Carvalho Chehab if (state->config->invert) 6309a0bf528SMauro Carvalho Chehab p->inversion = (p->inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON; 6319a0bf528SMauro Carvalho Chehab p->symbol_rate = stv0297_get_symbolrate(state) * 1000; 6329a0bf528SMauro Carvalho Chehab p->fec_inner = FEC_NONE; 6339a0bf528SMauro Carvalho Chehab 6349a0bf528SMauro Carvalho Chehab switch ((reg_00 >> 4) & 0x7) { 6359a0bf528SMauro Carvalho Chehab case 0: 6369a0bf528SMauro Carvalho Chehab p->modulation = QAM_16; 6379a0bf528SMauro Carvalho Chehab break; 6389a0bf528SMauro Carvalho Chehab case 1: 6399a0bf528SMauro Carvalho Chehab p->modulation = QAM_32; 6409a0bf528SMauro Carvalho Chehab break; 6419a0bf528SMauro Carvalho Chehab case 2: 6429a0bf528SMauro Carvalho Chehab p->modulation = QAM_128; 6439a0bf528SMauro Carvalho Chehab break; 6449a0bf528SMauro Carvalho Chehab case 3: 6459a0bf528SMauro Carvalho Chehab p->modulation = QAM_256; 6469a0bf528SMauro Carvalho Chehab break; 6479a0bf528SMauro Carvalho Chehab case 4: 6489a0bf528SMauro Carvalho Chehab p->modulation = QAM_64; 6499a0bf528SMauro Carvalho Chehab break; 6509a0bf528SMauro Carvalho Chehab } 6519a0bf528SMauro Carvalho Chehab 6529a0bf528SMauro Carvalho Chehab return 0; 6539a0bf528SMauro Carvalho Chehab } 6549a0bf528SMauro Carvalho Chehab 6559a0bf528SMauro Carvalho Chehab static void stv0297_release(struct dvb_frontend *fe) 6569a0bf528SMauro Carvalho Chehab { 6579a0bf528SMauro Carvalho Chehab struct stv0297_state *state = fe->demodulator_priv; 6589a0bf528SMauro Carvalho Chehab kfree(state); 6599a0bf528SMauro Carvalho Chehab } 6609a0bf528SMauro Carvalho Chehab 6619a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops stv0297_ops; 6629a0bf528SMauro Carvalho Chehab 6639a0bf528SMauro Carvalho Chehab struct dvb_frontend *stv0297_attach(const struct stv0297_config *config, 6649a0bf528SMauro Carvalho Chehab struct i2c_adapter *i2c) 6659a0bf528SMauro Carvalho Chehab { 6669a0bf528SMauro Carvalho Chehab struct stv0297_state *state = NULL; 6679a0bf528SMauro Carvalho Chehab 6689a0bf528SMauro Carvalho Chehab /* allocate memory for the internal state */ 6699a0bf528SMauro Carvalho Chehab state = kzalloc(sizeof(struct stv0297_state), GFP_KERNEL); 6709a0bf528SMauro Carvalho Chehab if (state == NULL) 6719a0bf528SMauro Carvalho Chehab goto error; 6729a0bf528SMauro Carvalho Chehab 6739a0bf528SMauro Carvalho Chehab /* setup the state */ 6749a0bf528SMauro Carvalho Chehab state->config = config; 6759a0bf528SMauro Carvalho Chehab state->i2c = i2c; 6769a0bf528SMauro Carvalho Chehab state->last_ber = 0; 6779a0bf528SMauro Carvalho Chehab state->base_freq = 0; 6789a0bf528SMauro Carvalho Chehab 6799a0bf528SMauro Carvalho Chehab /* check if the demod is there */ 6809a0bf528SMauro Carvalho Chehab if ((stv0297_readreg(state, 0x80) & 0x70) != 0x20) 6819a0bf528SMauro Carvalho Chehab goto error; 6829a0bf528SMauro Carvalho Chehab 6839a0bf528SMauro Carvalho Chehab /* create dvb_frontend */ 6849a0bf528SMauro Carvalho Chehab memcpy(&state->frontend.ops, &stv0297_ops, sizeof(struct dvb_frontend_ops)); 6859a0bf528SMauro Carvalho Chehab state->frontend.demodulator_priv = state; 6869a0bf528SMauro Carvalho Chehab return &state->frontend; 6879a0bf528SMauro Carvalho Chehab 6889a0bf528SMauro Carvalho Chehab error: 6899a0bf528SMauro Carvalho Chehab kfree(state); 6909a0bf528SMauro Carvalho Chehab return NULL; 6919a0bf528SMauro Carvalho Chehab } 6929a0bf528SMauro Carvalho Chehab 6939a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops stv0297_ops = { 6949a0bf528SMauro Carvalho Chehab .delsys = { SYS_DVBC_ANNEX_A }, 6959a0bf528SMauro Carvalho Chehab .info = { 6969a0bf528SMauro Carvalho Chehab .name = "ST STV0297 DVB-C", 6979a0bf528SMauro Carvalho Chehab .frequency_min = 47000000, 6989a0bf528SMauro Carvalho Chehab .frequency_max = 862000000, 6999a0bf528SMauro Carvalho Chehab .frequency_stepsize = 62500, 7009a0bf528SMauro Carvalho Chehab .symbol_rate_min = 870000, 7019a0bf528SMauro Carvalho Chehab .symbol_rate_max = 11700000, 7029a0bf528SMauro Carvalho Chehab .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | 7039a0bf528SMauro Carvalho Chehab FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO}, 7049a0bf528SMauro Carvalho Chehab 7059a0bf528SMauro Carvalho Chehab .release = stv0297_release, 7069a0bf528SMauro Carvalho Chehab 7079a0bf528SMauro Carvalho Chehab .init = stv0297_init, 7089a0bf528SMauro Carvalho Chehab .sleep = stv0297_sleep, 7099a0bf528SMauro Carvalho Chehab .i2c_gate_ctrl = stv0297_i2c_gate_ctrl, 7109a0bf528SMauro Carvalho Chehab 7119a0bf528SMauro Carvalho Chehab .set_frontend = stv0297_set_frontend, 7129a0bf528SMauro Carvalho Chehab .get_frontend = stv0297_get_frontend, 7139a0bf528SMauro Carvalho Chehab 7149a0bf528SMauro Carvalho Chehab .read_status = stv0297_read_status, 7159a0bf528SMauro Carvalho Chehab .read_ber = stv0297_read_ber, 7169a0bf528SMauro Carvalho Chehab .read_signal_strength = stv0297_read_signal_strength, 7179a0bf528SMauro Carvalho Chehab .read_snr = stv0297_read_snr, 7189a0bf528SMauro Carvalho Chehab .read_ucblocks = stv0297_read_ucblocks, 7199a0bf528SMauro Carvalho Chehab }; 7209a0bf528SMauro Carvalho Chehab 7219a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("ST STV0297 DVB-C Demodulator driver"); 7229a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Dennis Noermann and Andrew de Quincey"); 7239a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL"); 7249a0bf528SMauro Carvalho Chehab 7259a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(stv0297_attach); 726