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