174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
29a0bf528SMauro Carvalho Chehab /*
39a0bf528SMauro Carvalho Chehab TDA10023 - DVB-C decoder
49a0bf528SMauro Carvalho Chehab (as used in Philips CU1216-3 NIM and the Reelbox DVB-C tuner card)
59a0bf528SMauro Carvalho Chehab
69a0bf528SMauro Carvalho Chehab Copyright (C) 2005 Georg Acher, BayCom GmbH (acher at baycom dot de)
79a0bf528SMauro Carvalho Chehab Copyright (c) 2006 Hartmut Birr (e9hack at gmail dot com)
89a0bf528SMauro Carvalho Chehab
99a0bf528SMauro Carvalho Chehab Remotely based on tda10021.c
109a0bf528SMauro Carvalho Chehab Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
119a0bf528SMauro Carvalho Chehab Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
129a0bf528SMauro Carvalho Chehab Support for TDA10021
139a0bf528SMauro Carvalho Chehab
149a0bf528SMauro Carvalho Chehab */
159a0bf528SMauro Carvalho Chehab
169a0bf528SMauro Carvalho Chehab #include <linux/delay.h>
179a0bf528SMauro Carvalho Chehab #include <linux/errno.h>
189a0bf528SMauro Carvalho Chehab #include <linux/init.h>
199a0bf528SMauro Carvalho Chehab #include <linux/kernel.h>
209a0bf528SMauro Carvalho Chehab #include <linux/module.h>
219a0bf528SMauro Carvalho Chehab #include <linux/string.h>
229a0bf528SMauro Carvalho Chehab #include <linux/slab.h>
239a0bf528SMauro Carvalho Chehab
249a0bf528SMauro Carvalho Chehab #include <asm/div64.h>
259a0bf528SMauro Carvalho Chehab
26fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h>
279a0bf528SMauro Carvalho Chehab #include "tda1002x.h"
289a0bf528SMauro Carvalho Chehab
299a0bf528SMauro Carvalho Chehab #define REG0_INIT_VAL 0x23
309a0bf528SMauro Carvalho Chehab
319a0bf528SMauro Carvalho Chehab struct tda10023_state {
329a0bf528SMauro Carvalho Chehab struct i2c_adapter* i2c;
339a0bf528SMauro Carvalho Chehab /* configuration settings */
349a0bf528SMauro Carvalho Chehab const struct tda10023_config *config;
359a0bf528SMauro Carvalho Chehab struct dvb_frontend frontend;
369a0bf528SMauro Carvalho Chehab
379a0bf528SMauro Carvalho Chehab u8 pwm;
389a0bf528SMauro Carvalho Chehab u8 reg0;
399a0bf528SMauro Carvalho Chehab
409a0bf528SMauro Carvalho Chehab /* clock settings */
419a0bf528SMauro Carvalho Chehab u32 xtal;
429a0bf528SMauro Carvalho Chehab u8 pll_m;
439a0bf528SMauro Carvalho Chehab u8 pll_p;
449a0bf528SMauro Carvalho Chehab u8 pll_n;
459a0bf528SMauro Carvalho Chehab u32 sysclk;
469a0bf528SMauro Carvalho Chehab };
479a0bf528SMauro Carvalho Chehab
489a0bf528SMauro Carvalho Chehab #define dprintk(x...)
499a0bf528SMauro Carvalho Chehab
509a0bf528SMauro Carvalho Chehab static int verbose;
519a0bf528SMauro Carvalho Chehab
tda10023_readreg(struct tda10023_state * state,u8 reg)529a0bf528SMauro Carvalho Chehab static u8 tda10023_readreg (struct tda10023_state* state, u8 reg)
539a0bf528SMauro Carvalho Chehab {
549a0bf528SMauro Carvalho Chehab u8 b0 [] = { reg };
559a0bf528SMauro Carvalho Chehab u8 b1 [] = { 0 };
569a0bf528SMauro Carvalho Chehab struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
579a0bf528SMauro Carvalho Chehab { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
589a0bf528SMauro Carvalho Chehab int ret;
599a0bf528SMauro Carvalho Chehab
609a0bf528SMauro Carvalho Chehab ret = i2c_transfer (state->i2c, msg, 2);
619a0bf528SMauro Carvalho Chehab if (ret != 2) {
629a0bf528SMauro Carvalho Chehab int num = state->frontend.dvb ? state->frontend.dvb->num : -1;
634bd69e7bSMauro Carvalho Chehab printk(KERN_ERR "DVB: TDA10023(%d): %s: readreg error (reg == 0x%02x, ret == %i)\n",
649a0bf528SMauro Carvalho Chehab num, __func__, reg, ret);
659a0bf528SMauro Carvalho Chehab }
669a0bf528SMauro Carvalho Chehab return b1[0];
679a0bf528SMauro Carvalho Chehab }
689a0bf528SMauro Carvalho Chehab
tda10023_writereg(struct tda10023_state * state,u8 reg,u8 data)699a0bf528SMauro Carvalho Chehab static int tda10023_writereg (struct tda10023_state* state, u8 reg, u8 data)
709a0bf528SMauro Carvalho Chehab {
719a0bf528SMauro Carvalho Chehab u8 buf[] = { reg, data };
729a0bf528SMauro Carvalho Chehab struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
739a0bf528SMauro Carvalho Chehab int ret;
749a0bf528SMauro Carvalho Chehab
759a0bf528SMauro Carvalho Chehab ret = i2c_transfer (state->i2c, &msg, 1);
769a0bf528SMauro Carvalho Chehab if (ret != 1) {
779a0bf528SMauro Carvalho Chehab int num = state->frontend.dvb ? state->frontend.dvb->num : -1;
784bd69e7bSMauro Carvalho Chehab printk(KERN_ERR "DVB: TDA10023(%d): %s, writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
799a0bf528SMauro Carvalho Chehab num, __func__, reg, data, ret);
809a0bf528SMauro Carvalho Chehab }
819a0bf528SMauro Carvalho Chehab return (ret != 1) ? -EREMOTEIO : 0;
829a0bf528SMauro Carvalho Chehab }
839a0bf528SMauro Carvalho Chehab
849a0bf528SMauro Carvalho Chehab
tda10023_writebit(struct tda10023_state * state,u8 reg,u8 mask,u8 data)859a0bf528SMauro Carvalho Chehab static int tda10023_writebit (struct tda10023_state* state, u8 reg, u8 mask,u8 data)
869a0bf528SMauro Carvalho Chehab {
879a0bf528SMauro Carvalho Chehab if (mask==0xff)
889a0bf528SMauro Carvalho Chehab return tda10023_writereg(state, reg, data);
899a0bf528SMauro Carvalho Chehab else {
909a0bf528SMauro Carvalho Chehab u8 val;
919a0bf528SMauro Carvalho Chehab val=tda10023_readreg(state,reg);
929a0bf528SMauro Carvalho Chehab val&=~mask;
939a0bf528SMauro Carvalho Chehab val|=(data&mask);
949a0bf528SMauro Carvalho Chehab return tda10023_writereg(state, reg, val);
959a0bf528SMauro Carvalho Chehab }
969a0bf528SMauro Carvalho Chehab }
979a0bf528SMauro Carvalho Chehab
tda10023_writetab(struct tda10023_state * state,u8 * tab)989a0bf528SMauro Carvalho Chehab static void tda10023_writetab(struct tda10023_state* state, u8* tab)
999a0bf528SMauro Carvalho Chehab {
1009a0bf528SMauro Carvalho Chehab u8 r,m,v;
1019a0bf528SMauro Carvalho Chehab while (1) {
1029a0bf528SMauro Carvalho Chehab r=*tab++;
1039a0bf528SMauro Carvalho Chehab m=*tab++;
1049a0bf528SMauro Carvalho Chehab v=*tab++;
1059a0bf528SMauro Carvalho Chehab if (r==0xff) {
1069a0bf528SMauro Carvalho Chehab if (m==0xff)
1079a0bf528SMauro Carvalho Chehab break;
1089a0bf528SMauro Carvalho Chehab else
1099a0bf528SMauro Carvalho Chehab msleep(m);
1109a0bf528SMauro Carvalho Chehab }
1119a0bf528SMauro Carvalho Chehab else
1129a0bf528SMauro Carvalho Chehab tda10023_writebit(state,r,m,v);
1139a0bf528SMauro Carvalho Chehab }
1149a0bf528SMauro Carvalho Chehab }
1159a0bf528SMauro Carvalho Chehab
1169a0bf528SMauro Carvalho Chehab //get access to tuner
lock_tuner(struct tda10023_state * state)1179a0bf528SMauro Carvalho Chehab static int lock_tuner(struct tda10023_state* state)
1189a0bf528SMauro Carvalho Chehab {
1199a0bf528SMauro Carvalho Chehab u8 buf[2] = { 0x0f, 0xc0 };
1209a0bf528SMauro Carvalho Chehab struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
1219a0bf528SMauro Carvalho Chehab
1229a0bf528SMauro Carvalho Chehab if(i2c_transfer(state->i2c, &msg, 1) != 1)
1239a0bf528SMauro Carvalho Chehab {
1249a0bf528SMauro Carvalho Chehab printk("tda10023: lock tuner fails\n");
1259a0bf528SMauro Carvalho Chehab return -EREMOTEIO;
1269a0bf528SMauro Carvalho Chehab }
1279a0bf528SMauro Carvalho Chehab return 0;
1289a0bf528SMauro Carvalho Chehab }
1299a0bf528SMauro Carvalho Chehab
1309a0bf528SMauro Carvalho Chehab //release access from tuner
unlock_tuner(struct tda10023_state * state)1319a0bf528SMauro Carvalho Chehab static int unlock_tuner(struct tda10023_state* state)
1329a0bf528SMauro Carvalho Chehab {
1339a0bf528SMauro Carvalho Chehab u8 buf[2] = { 0x0f, 0x40 };
1349a0bf528SMauro Carvalho Chehab struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
1359a0bf528SMauro Carvalho Chehab
1369a0bf528SMauro Carvalho Chehab if(i2c_transfer(state->i2c, &msg_post, 1) != 1)
1379a0bf528SMauro Carvalho Chehab {
1389a0bf528SMauro Carvalho Chehab printk("tda10023: unlock tuner fails\n");
1399a0bf528SMauro Carvalho Chehab return -EREMOTEIO;
1409a0bf528SMauro Carvalho Chehab }
1419a0bf528SMauro Carvalho Chehab return 0;
1429a0bf528SMauro Carvalho Chehab }
1439a0bf528SMauro Carvalho Chehab
tda10023_setup_reg0(struct tda10023_state * state,u8 reg0)1449a0bf528SMauro Carvalho Chehab static int tda10023_setup_reg0 (struct tda10023_state* state, u8 reg0)
1459a0bf528SMauro Carvalho Chehab {
1469a0bf528SMauro Carvalho Chehab reg0 |= state->reg0 & 0x63;
1479a0bf528SMauro Carvalho Chehab
1489a0bf528SMauro Carvalho Chehab tda10023_writereg (state, 0x00, reg0 & 0xfe);
1499a0bf528SMauro Carvalho Chehab tda10023_writereg (state, 0x00, reg0 | 0x01);
1509a0bf528SMauro Carvalho Chehab
1519a0bf528SMauro Carvalho Chehab state->reg0 = reg0;
1529a0bf528SMauro Carvalho Chehab return 0;
1539a0bf528SMauro Carvalho Chehab }
1549a0bf528SMauro Carvalho Chehab
tda10023_set_symbolrate(struct tda10023_state * state,u32 sr)1559a0bf528SMauro Carvalho Chehab static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr)
1569a0bf528SMauro Carvalho Chehab {
1579a0bf528SMauro Carvalho Chehab s32 BDR;
1589a0bf528SMauro Carvalho Chehab s32 BDRI;
1599a0bf528SMauro Carvalho Chehab s16 SFIL=0;
1609a0bf528SMauro Carvalho Chehab u16 NDEC = 0;
1619a0bf528SMauro Carvalho Chehab
1629a0bf528SMauro Carvalho Chehab /* avoid floating point operations multiplying syscloc and divider
1639a0bf528SMauro Carvalho Chehab by 10 */
1649a0bf528SMauro Carvalho Chehab u32 sysclk_x_10 = state->sysclk * 10;
1659a0bf528SMauro Carvalho Chehab
1669a0bf528SMauro Carvalho Chehab if (sr < (u32)(sysclk_x_10/984)) {
1679a0bf528SMauro Carvalho Chehab NDEC=3;
1689a0bf528SMauro Carvalho Chehab SFIL=1;
1699a0bf528SMauro Carvalho Chehab } else if (sr < (u32)(sysclk_x_10/640)) {
1709a0bf528SMauro Carvalho Chehab NDEC=3;
1719a0bf528SMauro Carvalho Chehab SFIL=0;
1729a0bf528SMauro Carvalho Chehab } else if (sr < (u32)(sysclk_x_10/492)) {
1739a0bf528SMauro Carvalho Chehab NDEC=2;
1749a0bf528SMauro Carvalho Chehab SFIL=1;
1759a0bf528SMauro Carvalho Chehab } else if (sr < (u32)(sysclk_x_10/320)) {
1769a0bf528SMauro Carvalho Chehab NDEC=2;
1779a0bf528SMauro Carvalho Chehab SFIL=0;
1789a0bf528SMauro Carvalho Chehab } else if (sr < (u32)(sysclk_x_10/246)) {
1799a0bf528SMauro Carvalho Chehab NDEC=1;
1809a0bf528SMauro Carvalho Chehab SFIL=1;
1819a0bf528SMauro Carvalho Chehab } else if (sr < (u32)(sysclk_x_10/160)) {
1829a0bf528SMauro Carvalho Chehab NDEC=1;
1839a0bf528SMauro Carvalho Chehab SFIL=0;
1849a0bf528SMauro Carvalho Chehab } else if (sr < (u32)(sysclk_x_10/123)) {
1859a0bf528SMauro Carvalho Chehab NDEC=0;
1869a0bf528SMauro Carvalho Chehab SFIL=1;
1879a0bf528SMauro Carvalho Chehab }
1889a0bf528SMauro Carvalho Chehab
1899a0bf528SMauro Carvalho Chehab BDRI = (state->sysclk)*16;
1909a0bf528SMauro Carvalho Chehab BDRI>>=NDEC;
1919a0bf528SMauro Carvalho Chehab BDRI +=sr/2;
1929a0bf528SMauro Carvalho Chehab BDRI /=sr;
1939a0bf528SMauro Carvalho Chehab
1949a0bf528SMauro Carvalho Chehab if (BDRI>255)
1959a0bf528SMauro Carvalho Chehab BDRI=255;
1969a0bf528SMauro Carvalho Chehab
1979a0bf528SMauro Carvalho Chehab {
1989a0bf528SMauro Carvalho Chehab u64 BDRX;
1999a0bf528SMauro Carvalho Chehab
2009a0bf528SMauro Carvalho Chehab BDRX=1<<(24+NDEC);
2019a0bf528SMauro Carvalho Chehab BDRX*=sr;
2029a0bf528SMauro Carvalho Chehab do_div(BDRX, state->sysclk); /* BDRX/=SYSCLK; */
2039a0bf528SMauro Carvalho Chehab
2049a0bf528SMauro Carvalho Chehab BDR=(s32)BDRX;
2059a0bf528SMauro Carvalho Chehab }
2069a0bf528SMauro Carvalho Chehab dprintk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n",
2079a0bf528SMauro Carvalho Chehab sr, BDR, BDRI, NDEC);
2089a0bf528SMauro Carvalho Chehab tda10023_writebit (state, 0x03, 0xc0, NDEC<<6);
2099a0bf528SMauro Carvalho Chehab tda10023_writereg (state, 0x0a, BDR&255);
2109a0bf528SMauro Carvalho Chehab tda10023_writereg (state, 0x0b, (BDR>>8)&255);
2119a0bf528SMauro Carvalho Chehab tda10023_writereg (state, 0x0c, (BDR>>16)&31);
2129a0bf528SMauro Carvalho Chehab tda10023_writereg (state, 0x0d, BDRI);
2139a0bf528SMauro Carvalho Chehab tda10023_writereg (state, 0x3d, (SFIL<<7));
2149a0bf528SMauro Carvalho Chehab return 0;
2159a0bf528SMauro Carvalho Chehab }
2169a0bf528SMauro Carvalho Chehab
tda10023_init(struct dvb_frontend * fe)2179a0bf528SMauro Carvalho Chehab static int tda10023_init (struct dvb_frontend *fe)
2189a0bf528SMauro Carvalho Chehab {
2199a0bf528SMauro Carvalho Chehab struct tda10023_state* state = fe->demodulator_priv;
2209a0bf528SMauro Carvalho Chehab u8 tda10023_inittab[] = {
2219a0bf528SMauro Carvalho Chehab /* reg mask val */
2229a0bf528SMauro Carvalho Chehab /* 000 */ 0x2a, 0xff, 0x02, /* PLL3, Bypass, Power Down */
2239a0bf528SMauro Carvalho Chehab /* 003 */ 0xff, 0x64, 0x00, /* Sleep 100ms */
2249a0bf528SMauro Carvalho Chehab /* 006 */ 0x2a, 0xff, 0x03, /* PLL3, Bypass, Power Down */
2259a0bf528SMauro Carvalho Chehab /* 009 */ 0xff, 0x64, 0x00, /* Sleep 100ms */
2269a0bf528SMauro Carvalho Chehab /* PLL1 */
2279a0bf528SMauro Carvalho Chehab /* 012 */ 0x28, 0xff, (state->pll_m-1),
2289a0bf528SMauro Carvalho Chehab /* PLL2 */
2299a0bf528SMauro Carvalho Chehab /* 015 */ 0x29, 0xff, ((state->pll_p-1)<<6)|(state->pll_n-1),
2309a0bf528SMauro Carvalho Chehab /* GPR FSAMPLING=1 */
2319a0bf528SMauro Carvalho Chehab /* 018 */ 0x00, 0xff, REG0_INIT_VAL,
2329a0bf528SMauro Carvalho Chehab /* 021 */ 0x2a, 0xff, 0x08, /* PLL3 PSACLK=1 */
2339a0bf528SMauro Carvalho Chehab /* 024 */ 0xff, 0x64, 0x00, /* Sleep 100ms */
2349a0bf528SMauro Carvalho Chehab /* 027 */ 0x1f, 0xff, 0x00, /* RESET */
2359a0bf528SMauro Carvalho Chehab /* 030 */ 0xff, 0x64, 0x00, /* Sleep 100ms */
2369a0bf528SMauro Carvalho Chehab /* 033 */ 0xe6, 0x0c, 0x04, /* RSCFG_IND */
2379a0bf528SMauro Carvalho Chehab /* 036 */ 0x10, 0xc0, 0x80, /* DECDVBCFG1 PBER=1 */
2389a0bf528SMauro Carvalho Chehab
2399a0bf528SMauro Carvalho Chehab /* 039 */ 0x0e, 0xff, 0x82, /* GAIN1 */
2409a0bf528SMauro Carvalho Chehab /* 042 */ 0x03, 0x08, 0x08, /* CLKCONF DYN=1 */
2419a0bf528SMauro Carvalho Chehab /* 045 */ 0x2e, 0xbf, 0x30, /* AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1
2429a0bf528SMauro Carvalho Chehab PPWMTUN=0 PPWMIF=0 */
2439a0bf528SMauro Carvalho Chehab /* 048 */ 0x01, 0xff, 0x30, /* AGCREF */
2449a0bf528SMauro Carvalho Chehab /* 051 */ 0x1e, 0x84, 0x84, /* CONTROL SACLK_ON=1 */
2459a0bf528SMauro Carvalho Chehab /* 054 */ 0x1b, 0xff, 0xc8, /* ADC TWOS=1 */
2469a0bf528SMauro Carvalho Chehab /* 057 */ 0x3b, 0xff, 0xff, /* IFMAX */
2479a0bf528SMauro Carvalho Chehab /* 060 */ 0x3c, 0xff, 0x00, /* IFMIN */
2489a0bf528SMauro Carvalho Chehab /* 063 */ 0x34, 0xff, 0x00, /* PWMREF */
2499a0bf528SMauro Carvalho Chehab /* 066 */ 0x35, 0xff, 0xff, /* TUNMAX */
2509a0bf528SMauro Carvalho Chehab /* 069 */ 0x36, 0xff, 0x00, /* TUNMIN */
2519a0bf528SMauro Carvalho Chehab /* 072 */ 0x06, 0xff, 0x7f, /* EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1 */
2529a0bf528SMauro Carvalho Chehab /* 075 */ 0x1c, 0x30, 0x30, /* EQCONF2 STEPALGO=SGNALGO=1 */
2539a0bf528SMauro Carvalho Chehab /* 078 */ 0x37, 0xff, 0xf6, /* DELTAF_LSB */
2549a0bf528SMauro Carvalho Chehab /* 081 */ 0x38, 0xff, 0xff, /* DELTAF_MSB */
2559a0bf528SMauro Carvalho Chehab /* 084 */ 0x02, 0xff, 0x93, /* AGCCONF1 IFS=1 KAGCIF=2 KAGCTUN=3 */
2569a0bf528SMauro Carvalho Chehab /* 087 */ 0x2d, 0xff, 0xf6, /* SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2 */
2579a0bf528SMauro Carvalho Chehab /* 090 */ 0x04, 0x10, 0x00, /* SWRAMP=1 */
2589a0bf528SMauro Carvalho Chehab /* 093 */ 0x12, 0xff, TDA10023_OUTPUT_MODE_PARALLEL_B, /*
2599a0bf528SMauro Carvalho Chehab INTP1 POCLKP=1 FEL=1 MFS=0 */
2609a0bf528SMauro Carvalho Chehab /* 096 */ 0x2b, 0x01, 0xa1, /* INTS1 */
2619a0bf528SMauro Carvalho Chehab /* 099 */ 0x20, 0xff, 0x04, /* INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=? */
2629a0bf528SMauro Carvalho Chehab /* 102 */ 0x2c, 0xff, 0x0d, /* INTP/S TRIP=0 TRIS=0 */
2639a0bf528SMauro Carvalho Chehab /* 105 */ 0xc4, 0xff, 0x00,
2649a0bf528SMauro Carvalho Chehab /* 108 */ 0xc3, 0x30, 0x00,
2659a0bf528SMauro Carvalho Chehab /* 111 */ 0xb5, 0xff, 0x19, /* ERAGC_THD */
2669a0bf528SMauro Carvalho Chehab /* 114 */ 0x00, 0x03, 0x01, /* GPR, CLBS soft reset */
2679a0bf528SMauro Carvalho Chehab /* 117 */ 0x00, 0x03, 0x03, /* GPR, CLBS soft reset */
2689a0bf528SMauro Carvalho Chehab /* 120 */ 0xff, 0x64, 0x00, /* Sleep 100ms */
2699a0bf528SMauro Carvalho Chehab /* 123 */ 0xff, 0xff, 0xff
2709a0bf528SMauro Carvalho Chehab };
2719a0bf528SMauro Carvalho Chehab dprintk("DVB: TDA10023(%d): init chip\n", fe->dvb->num);
2729a0bf528SMauro Carvalho Chehab
2739a0bf528SMauro Carvalho Chehab /* override default values if set in config */
2749a0bf528SMauro Carvalho Chehab if (state->config->deltaf) {
2759a0bf528SMauro Carvalho Chehab tda10023_inittab[80] = (state->config->deltaf & 0xff);
2769a0bf528SMauro Carvalho Chehab tda10023_inittab[83] = (state->config->deltaf >> 8);
2779a0bf528SMauro Carvalho Chehab }
2789a0bf528SMauro Carvalho Chehab
2799a0bf528SMauro Carvalho Chehab if (state->config->output_mode)
2809a0bf528SMauro Carvalho Chehab tda10023_inittab[95] = state->config->output_mode;
2819a0bf528SMauro Carvalho Chehab
2829a0bf528SMauro Carvalho Chehab tda10023_writetab(state, tda10023_inittab);
2839a0bf528SMauro Carvalho Chehab
2849a0bf528SMauro Carvalho Chehab return 0;
2859a0bf528SMauro Carvalho Chehab }
2869a0bf528SMauro Carvalho Chehab
2879a0bf528SMauro Carvalho Chehab struct qam_params {
2889a0bf528SMauro Carvalho Chehab u8 qam, lockthr, mseth, aref, agcrefnyq, eragnyq_thd;
2899a0bf528SMauro Carvalho Chehab };
2909a0bf528SMauro Carvalho Chehab
tda10023_set_parameters(struct dvb_frontend * fe)2919a0bf528SMauro Carvalho Chehab static int tda10023_set_parameters(struct dvb_frontend *fe)
2929a0bf528SMauro Carvalho Chehab {
2939a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *c = &fe->dtv_property_cache;
2949a0bf528SMauro Carvalho Chehab u32 delsys = c->delivery_system;
2959a0bf528SMauro Carvalho Chehab unsigned qam = c->modulation;
2969a0bf528SMauro Carvalho Chehab bool is_annex_c;
2979a0bf528SMauro Carvalho Chehab struct tda10023_state* state = fe->demodulator_priv;
2989a0bf528SMauro Carvalho Chehab static const struct qam_params qam_params[] = {
2999a0bf528SMauro Carvalho Chehab /* Modulation QAM LOCKTHR MSETH AREF AGCREFNYQ ERAGCNYQ_THD */
3009a0bf528SMauro Carvalho Chehab [QPSK] = { (5<<2), 0x78, 0x8c, 0x96, 0x78, 0x4c },
3019a0bf528SMauro Carvalho Chehab [QAM_16] = { (0<<2), 0x87, 0xa2, 0x91, 0x8c, 0x57 },
3029a0bf528SMauro Carvalho Chehab [QAM_32] = { (1<<2), 0x64, 0x74, 0x96, 0x8c, 0x57 },
3039a0bf528SMauro Carvalho Chehab [QAM_64] = { (2<<2), 0x46, 0x43, 0x6a, 0x6a, 0x44 },
3049a0bf528SMauro Carvalho Chehab [QAM_128] = { (3<<2), 0x36, 0x34, 0x7e, 0x78, 0x4c },
3059a0bf528SMauro Carvalho Chehab [QAM_256] = { (4<<2), 0x26, 0x23, 0x6c, 0x5c, 0x3c },
3069a0bf528SMauro Carvalho Chehab };
3079a0bf528SMauro Carvalho Chehab
3089a0bf528SMauro Carvalho Chehab switch (delsys) {
3099a0bf528SMauro Carvalho Chehab case SYS_DVBC_ANNEX_A:
3109a0bf528SMauro Carvalho Chehab is_annex_c = false;
3119a0bf528SMauro Carvalho Chehab break;
3129a0bf528SMauro Carvalho Chehab case SYS_DVBC_ANNEX_C:
3139a0bf528SMauro Carvalho Chehab is_annex_c = true;
3149a0bf528SMauro Carvalho Chehab break;
3159a0bf528SMauro Carvalho Chehab default:
3169a0bf528SMauro Carvalho Chehab return -EINVAL;
3179a0bf528SMauro Carvalho Chehab }
3189a0bf528SMauro Carvalho Chehab
3199a0bf528SMauro Carvalho Chehab /*
3205a13e40bSMauro Carvalho Chehab * gcc optimizes the code below the same way as it would code:
3219a0bf528SMauro Carvalho Chehab * "if (qam > 5) return -EINVAL;"
3229a0bf528SMauro Carvalho Chehab * Yet, the code is clearer, as it shows what QAM standards are
3239a0bf528SMauro Carvalho Chehab * supported by the driver, and avoids the usage of magic numbers on
3249a0bf528SMauro Carvalho Chehab * it.
3259a0bf528SMauro Carvalho Chehab */
3269a0bf528SMauro Carvalho Chehab switch (qam) {
3279a0bf528SMauro Carvalho Chehab case QPSK:
3289a0bf528SMauro Carvalho Chehab case QAM_16:
3299a0bf528SMauro Carvalho Chehab case QAM_32:
3309a0bf528SMauro Carvalho Chehab case QAM_64:
3319a0bf528SMauro Carvalho Chehab case QAM_128:
3329a0bf528SMauro Carvalho Chehab case QAM_256:
3339a0bf528SMauro Carvalho Chehab break;
3349a0bf528SMauro Carvalho Chehab default:
3359a0bf528SMauro Carvalho Chehab return -EINVAL;
3369a0bf528SMauro Carvalho Chehab }
3379a0bf528SMauro Carvalho Chehab
3389a0bf528SMauro Carvalho Chehab if (fe->ops.tuner_ops.set_params) {
3399a0bf528SMauro Carvalho Chehab fe->ops.tuner_ops.set_params(fe);
3409a0bf528SMauro Carvalho Chehab if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
3419a0bf528SMauro Carvalho Chehab }
3429a0bf528SMauro Carvalho Chehab
3439a0bf528SMauro Carvalho Chehab tda10023_set_symbolrate(state, c->symbol_rate);
3449a0bf528SMauro Carvalho Chehab tda10023_writereg(state, 0x05, qam_params[qam].lockthr);
3459a0bf528SMauro Carvalho Chehab tda10023_writereg(state, 0x08, qam_params[qam].mseth);
3469a0bf528SMauro Carvalho Chehab tda10023_writereg(state, 0x09, qam_params[qam].aref);
3479a0bf528SMauro Carvalho Chehab tda10023_writereg(state, 0xb4, qam_params[qam].agcrefnyq);
3489a0bf528SMauro Carvalho Chehab tda10023_writereg(state, 0xb6, qam_params[qam].eragnyq_thd);
3499a0bf528SMauro Carvalho Chehab #if 0
3509a0bf528SMauro Carvalho Chehab tda10023_writereg(state, 0x04, (c->inversion ? 0x12 : 0x32));
3519a0bf528SMauro Carvalho Chehab tda10023_writebit(state, 0x04, 0x60, (c->inversion ? 0 : 0x20));
3529a0bf528SMauro Carvalho Chehab #endif
3539a0bf528SMauro Carvalho Chehab tda10023_writebit(state, 0x04, 0x40, 0x40);
3549a0bf528SMauro Carvalho Chehab
3559a0bf528SMauro Carvalho Chehab if (is_annex_c)
3569a0bf528SMauro Carvalho Chehab tda10023_writebit(state, 0x3d, 0xfc, 0x03);
3579a0bf528SMauro Carvalho Chehab else
3589a0bf528SMauro Carvalho Chehab tda10023_writebit(state, 0x3d, 0xfc, 0x02);
3599a0bf528SMauro Carvalho Chehab
3609a0bf528SMauro Carvalho Chehab tda10023_setup_reg0(state, qam_params[qam].qam);
3619a0bf528SMauro Carvalho Chehab
3629a0bf528SMauro Carvalho Chehab return 0;
3639a0bf528SMauro Carvalho Chehab }
3649a0bf528SMauro Carvalho Chehab
tda10023_read_status(struct dvb_frontend * fe,enum fe_status * status)3650df289a2SMauro Carvalho Chehab static int tda10023_read_status(struct dvb_frontend *fe,
3660df289a2SMauro Carvalho Chehab enum fe_status *status)
3679a0bf528SMauro Carvalho Chehab {
3689a0bf528SMauro Carvalho Chehab struct tda10023_state* state = fe->demodulator_priv;
3699a0bf528SMauro Carvalho Chehab int sync;
3709a0bf528SMauro Carvalho Chehab
3719a0bf528SMauro Carvalho Chehab *status = 0;
3729a0bf528SMauro Carvalho Chehab
3739a0bf528SMauro Carvalho Chehab //0x11[1] == CARLOCK -> Carrier locked
3749a0bf528SMauro Carvalho Chehab //0x11[2] == FSYNC -> Frame synchronisation
3759a0bf528SMauro Carvalho Chehab //0x11[3] == FEL -> Front End locked
3769a0bf528SMauro Carvalho Chehab //0x11[6] == NODVB -> DVB Mode Information
3779a0bf528SMauro Carvalho Chehab sync = tda10023_readreg (state, 0x11);
3789a0bf528SMauro Carvalho Chehab
3799a0bf528SMauro Carvalho Chehab if (sync & 2)
3809a0bf528SMauro Carvalho Chehab *status |= FE_HAS_SIGNAL|FE_HAS_CARRIER;
3819a0bf528SMauro Carvalho Chehab
3829a0bf528SMauro Carvalho Chehab if (sync & 4)
3839a0bf528SMauro Carvalho Chehab *status |= FE_HAS_SYNC|FE_HAS_VITERBI;
3849a0bf528SMauro Carvalho Chehab
3859a0bf528SMauro Carvalho Chehab if (sync & 8)
3869a0bf528SMauro Carvalho Chehab *status |= FE_HAS_LOCK;
3879a0bf528SMauro Carvalho Chehab
3889a0bf528SMauro Carvalho Chehab return 0;
3899a0bf528SMauro Carvalho Chehab }
3909a0bf528SMauro Carvalho Chehab
tda10023_read_ber(struct dvb_frontend * fe,u32 * ber)3919a0bf528SMauro Carvalho Chehab static int tda10023_read_ber(struct dvb_frontend* fe, u32* ber)
3929a0bf528SMauro Carvalho Chehab {
3939a0bf528SMauro Carvalho Chehab struct tda10023_state* state = fe->demodulator_priv;
3949a0bf528SMauro Carvalho Chehab u8 a,b,c;
3959a0bf528SMauro Carvalho Chehab a=tda10023_readreg(state, 0x14);
3969a0bf528SMauro Carvalho Chehab b=tda10023_readreg(state, 0x15);
3979a0bf528SMauro Carvalho Chehab c=tda10023_readreg(state, 0x16)&0xf;
3989a0bf528SMauro Carvalho Chehab tda10023_writebit (state, 0x10, 0xc0, 0x00);
3999a0bf528SMauro Carvalho Chehab
4009a0bf528SMauro Carvalho Chehab *ber = a | (b<<8)| (c<<16);
4019a0bf528SMauro Carvalho Chehab return 0;
4029a0bf528SMauro Carvalho Chehab }
4039a0bf528SMauro Carvalho Chehab
tda10023_read_signal_strength(struct dvb_frontend * fe,u16 * strength)4049a0bf528SMauro Carvalho Chehab static int tda10023_read_signal_strength(struct dvb_frontend* fe, u16* strength)
4059a0bf528SMauro Carvalho Chehab {
4069a0bf528SMauro Carvalho Chehab struct tda10023_state* state = fe->demodulator_priv;
4079a0bf528SMauro Carvalho Chehab u8 ifgain=tda10023_readreg(state, 0x2f);
4089a0bf528SMauro Carvalho Chehab
4099a0bf528SMauro Carvalho Chehab u16 gain = ((255-tda10023_readreg(state, 0x17))) + (255-ifgain)/16;
4109a0bf528SMauro Carvalho Chehab // Max raw value is about 0xb0 -> Normalize to >0xf0 after 0x90
4119a0bf528SMauro Carvalho Chehab if (gain>0x90)
4129a0bf528SMauro Carvalho Chehab gain=gain+2*(gain-0x90);
4139a0bf528SMauro Carvalho Chehab if (gain>255)
4149a0bf528SMauro Carvalho Chehab gain=255;
4159a0bf528SMauro Carvalho Chehab
4169a0bf528SMauro Carvalho Chehab *strength = (gain<<8)|gain;
4179a0bf528SMauro Carvalho Chehab return 0;
4189a0bf528SMauro Carvalho Chehab }
4199a0bf528SMauro Carvalho Chehab
tda10023_read_snr(struct dvb_frontend * fe,u16 * snr)4209a0bf528SMauro Carvalho Chehab static int tda10023_read_snr(struct dvb_frontend* fe, u16* snr)
4219a0bf528SMauro Carvalho Chehab {
4229a0bf528SMauro Carvalho Chehab struct tda10023_state* state = fe->demodulator_priv;
4239a0bf528SMauro Carvalho Chehab
4249a0bf528SMauro Carvalho Chehab u8 quality = ~tda10023_readreg(state, 0x18);
4259a0bf528SMauro Carvalho Chehab *snr = (quality << 8) | quality;
4269a0bf528SMauro Carvalho Chehab return 0;
4279a0bf528SMauro Carvalho Chehab }
4289a0bf528SMauro Carvalho Chehab
tda10023_read_ucblocks(struct dvb_frontend * fe,u32 * ucblocks)4299a0bf528SMauro Carvalho Chehab static int tda10023_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
4309a0bf528SMauro Carvalho Chehab {
4319a0bf528SMauro Carvalho Chehab struct tda10023_state* state = fe->demodulator_priv;
4329a0bf528SMauro Carvalho Chehab u8 a,b,c,d;
4339a0bf528SMauro Carvalho Chehab a= tda10023_readreg (state, 0x74);
4349a0bf528SMauro Carvalho Chehab b= tda10023_readreg (state, 0x75);
4359a0bf528SMauro Carvalho Chehab c= tda10023_readreg (state, 0x76);
4369a0bf528SMauro Carvalho Chehab d= tda10023_readreg (state, 0x77);
4379a0bf528SMauro Carvalho Chehab *ucblocks = a | (b<<8)|(c<<16)|(d<<24);
4389a0bf528SMauro Carvalho Chehab
4399a0bf528SMauro Carvalho Chehab tda10023_writebit (state, 0x10, 0x20,0x00);
4409a0bf528SMauro Carvalho Chehab tda10023_writebit (state, 0x10, 0x20,0x20);
4419a0bf528SMauro Carvalho Chehab tda10023_writebit (state, 0x13, 0x01, 0x00);
4429a0bf528SMauro Carvalho Chehab
4439a0bf528SMauro Carvalho Chehab return 0;
4449a0bf528SMauro Carvalho Chehab }
4459a0bf528SMauro Carvalho Chehab
tda10023_get_frontend(struct dvb_frontend * fe,struct dtv_frontend_properties * p)4467e3e68bcSMauro Carvalho Chehab static int tda10023_get_frontend(struct dvb_frontend *fe,
4477e3e68bcSMauro Carvalho Chehab struct dtv_frontend_properties *p)
4489a0bf528SMauro Carvalho Chehab {
4499a0bf528SMauro Carvalho Chehab struct tda10023_state* state = fe->demodulator_priv;
4509a0bf528SMauro Carvalho Chehab int sync,inv;
4519a0bf528SMauro Carvalho Chehab s8 afc = 0;
4529a0bf528SMauro Carvalho Chehab
4539a0bf528SMauro Carvalho Chehab sync = tda10023_readreg(state, 0x11);
4549a0bf528SMauro Carvalho Chehab afc = tda10023_readreg(state, 0x19);
4559a0bf528SMauro Carvalho Chehab inv = tda10023_readreg(state, 0x04);
4569a0bf528SMauro Carvalho Chehab
4579a0bf528SMauro Carvalho Chehab if (verbose) {
4589a0bf528SMauro Carvalho Chehab /* AFC only valid when carrier has been recovered */
4599a0bf528SMauro Carvalho Chehab printk(sync & 2 ? "DVB: TDA10023(%d): AFC (%d) %dHz\n" :
4609a0bf528SMauro Carvalho Chehab "DVB: TDA10023(%d): [AFC (%d) %dHz]\n",
4619a0bf528SMauro Carvalho Chehab state->frontend.dvb->num, afc,
4629a0bf528SMauro Carvalho Chehab -((s32)p->symbol_rate * afc) >> 10);
4639a0bf528SMauro Carvalho Chehab }
4649a0bf528SMauro Carvalho Chehab
4659a0bf528SMauro Carvalho Chehab p->inversion = (inv&0x20?0:1);
4669a0bf528SMauro Carvalho Chehab p->modulation = ((state->reg0 >> 2) & 7) + QAM_16;
4679a0bf528SMauro Carvalho Chehab
4689a0bf528SMauro Carvalho Chehab p->fec_inner = FEC_NONE;
4699a0bf528SMauro Carvalho Chehab p->frequency = ((p->frequency + 31250) / 62500) * 62500;
4709a0bf528SMauro Carvalho Chehab
4719a0bf528SMauro Carvalho Chehab if (sync & 2)
4729a0bf528SMauro Carvalho Chehab p->frequency -= ((s32)p->symbol_rate * afc) >> 10;
4739a0bf528SMauro Carvalho Chehab
4749a0bf528SMauro Carvalho Chehab return 0;
4759a0bf528SMauro Carvalho Chehab }
4769a0bf528SMauro Carvalho Chehab
tda10023_sleep(struct dvb_frontend * fe)4779a0bf528SMauro Carvalho Chehab static int tda10023_sleep(struct dvb_frontend* fe)
4789a0bf528SMauro Carvalho Chehab {
4799a0bf528SMauro Carvalho Chehab struct tda10023_state* state = fe->demodulator_priv;
4809a0bf528SMauro Carvalho Chehab
4819a0bf528SMauro Carvalho Chehab tda10023_writereg (state, 0x1b, 0x02); /* pdown ADC */
4829a0bf528SMauro Carvalho Chehab tda10023_writereg (state, 0x00, 0x80); /* standby */
4839a0bf528SMauro Carvalho Chehab
4849a0bf528SMauro Carvalho Chehab return 0;
4859a0bf528SMauro Carvalho Chehab }
4869a0bf528SMauro Carvalho Chehab
tda10023_i2c_gate_ctrl(struct dvb_frontend * fe,int enable)4879a0bf528SMauro Carvalho Chehab static int tda10023_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
4889a0bf528SMauro Carvalho Chehab {
4899a0bf528SMauro Carvalho Chehab struct tda10023_state* state = fe->demodulator_priv;
4909a0bf528SMauro Carvalho Chehab
4919a0bf528SMauro Carvalho Chehab if (enable) {
4929a0bf528SMauro Carvalho Chehab lock_tuner(state);
4939a0bf528SMauro Carvalho Chehab } else {
4949a0bf528SMauro Carvalho Chehab unlock_tuner(state);
4959a0bf528SMauro Carvalho Chehab }
4969a0bf528SMauro Carvalho Chehab return 0;
4979a0bf528SMauro Carvalho Chehab }
4989a0bf528SMauro Carvalho Chehab
tda10023_release(struct dvb_frontend * fe)4999a0bf528SMauro Carvalho Chehab static void tda10023_release(struct dvb_frontend* fe)
5009a0bf528SMauro Carvalho Chehab {
5019a0bf528SMauro Carvalho Chehab struct tda10023_state* state = fe->demodulator_priv;
5029a0bf528SMauro Carvalho Chehab kfree(state);
5039a0bf528SMauro Carvalho Chehab }
5049a0bf528SMauro Carvalho Chehab
505bd336e63SMax Kellermann static const struct dvb_frontend_ops tda10023_ops;
5069a0bf528SMauro Carvalho Chehab
tda10023_attach(const struct tda10023_config * config,struct i2c_adapter * i2c,u8 pwm)5079a0bf528SMauro Carvalho Chehab struct dvb_frontend *tda10023_attach(const struct tda10023_config *config,
5089a0bf528SMauro Carvalho Chehab struct i2c_adapter *i2c,
5099a0bf528SMauro Carvalho Chehab u8 pwm)
5109a0bf528SMauro Carvalho Chehab {
5119a0bf528SMauro Carvalho Chehab struct tda10023_state* state = NULL;
5129a0bf528SMauro Carvalho Chehab
5139a0bf528SMauro Carvalho Chehab /* allocate memory for the internal state */
5149a0bf528SMauro Carvalho Chehab state = kzalloc(sizeof(struct tda10023_state), GFP_KERNEL);
5159a0bf528SMauro Carvalho Chehab if (state == NULL) goto error;
5169a0bf528SMauro Carvalho Chehab
5179a0bf528SMauro Carvalho Chehab /* setup the state */
5189a0bf528SMauro Carvalho Chehab state->config = config;
5199a0bf528SMauro Carvalho Chehab state->i2c = i2c;
5209a0bf528SMauro Carvalho Chehab
5219a0bf528SMauro Carvalho Chehab /* wakeup if in standby */
5229a0bf528SMauro Carvalho Chehab tda10023_writereg (state, 0x00, 0x33);
5239a0bf528SMauro Carvalho Chehab /* check if the demod is there */
5249a0bf528SMauro Carvalho Chehab if ((tda10023_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
5259a0bf528SMauro Carvalho Chehab
5269a0bf528SMauro Carvalho Chehab /* create dvb_frontend */
5279a0bf528SMauro Carvalho Chehab memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
5289a0bf528SMauro Carvalho Chehab state->pwm = pwm;
5299a0bf528SMauro Carvalho Chehab state->reg0 = REG0_INIT_VAL;
5309a0bf528SMauro Carvalho Chehab if (state->config->xtal) {
5319a0bf528SMauro Carvalho Chehab state->xtal = state->config->xtal;
5329a0bf528SMauro Carvalho Chehab state->pll_m = state->config->pll_m;
5339a0bf528SMauro Carvalho Chehab state->pll_p = state->config->pll_p;
5349a0bf528SMauro Carvalho Chehab state->pll_n = state->config->pll_n;
5359a0bf528SMauro Carvalho Chehab } else {
5369a0bf528SMauro Carvalho Chehab /* set default values if not defined in config */
5379a0bf528SMauro Carvalho Chehab state->xtal = 28920000;
5389a0bf528SMauro Carvalho Chehab state->pll_m = 8;
5399a0bf528SMauro Carvalho Chehab state->pll_p = 4;
5409a0bf528SMauro Carvalho Chehab state->pll_n = 1;
5419a0bf528SMauro Carvalho Chehab }
5429a0bf528SMauro Carvalho Chehab
5439a0bf528SMauro Carvalho Chehab /* calc sysclk */
5449a0bf528SMauro Carvalho Chehab state->sysclk = (state->xtal * state->pll_m / \
5459a0bf528SMauro Carvalho Chehab (state->pll_n * state->pll_p));
5469a0bf528SMauro Carvalho Chehab
5479a0bf528SMauro Carvalho Chehab state->frontend.ops.info.symbol_rate_min = (state->sysclk/2)/64;
5489a0bf528SMauro Carvalho Chehab state->frontend.ops.info.symbol_rate_max = (state->sysclk/2)/4;
5499a0bf528SMauro Carvalho Chehab
5509a0bf528SMauro Carvalho Chehab dprintk("DVB: TDA10023 %s: xtal:%d pll_m:%d pll_p:%d pll_n:%d\n",
5519a0bf528SMauro Carvalho Chehab __func__, state->xtal, state->pll_m, state->pll_p,
5529a0bf528SMauro Carvalho Chehab state->pll_n);
5539a0bf528SMauro Carvalho Chehab
5549a0bf528SMauro Carvalho Chehab state->frontend.demodulator_priv = state;
5559a0bf528SMauro Carvalho Chehab return &state->frontend;
5569a0bf528SMauro Carvalho Chehab
5579a0bf528SMauro Carvalho Chehab error:
5589a0bf528SMauro Carvalho Chehab kfree(state);
5599a0bf528SMauro Carvalho Chehab return NULL;
5609a0bf528SMauro Carvalho Chehab }
5619a0bf528SMauro Carvalho Chehab
562bd336e63SMax Kellermann static const struct dvb_frontend_ops tda10023_ops = {
5639a0bf528SMauro Carvalho Chehab .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C },
5649a0bf528SMauro Carvalho Chehab .info = {
5659a0bf528SMauro Carvalho Chehab .name = "Philips TDA10023 DVB-C",
566f1b1eabfSMauro Carvalho Chehab .frequency_min_hz = 47 * MHz,
567f1b1eabfSMauro Carvalho Chehab .frequency_max_hz = 862 * MHz,
568f1b1eabfSMauro Carvalho Chehab .frequency_stepsize_hz = 62500,
5699a0bf528SMauro Carvalho Chehab .symbol_rate_min = 0, /* set in tda10023_attach */
5709a0bf528SMauro Carvalho Chehab .symbol_rate_max = 0, /* set in tda10023_attach */
5719a0bf528SMauro Carvalho Chehab .caps = 0x400 | //FE_CAN_QAM_4
5729a0bf528SMauro Carvalho Chehab FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
5739a0bf528SMauro Carvalho Chehab FE_CAN_QAM_128 | FE_CAN_QAM_256 |
5749a0bf528SMauro Carvalho Chehab FE_CAN_FEC_AUTO
5759a0bf528SMauro Carvalho Chehab },
5769a0bf528SMauro Carvalho Chehab
5779a0bf528SMauro Carvalho Chehab .release = tda10023_release,
5789a0bf528SMauro Carvalho Chehab
5799a0bf528SMauro Carvalho Chehab .init = tda10023_init,
5809a0bf528SMauro Carvalho Chehab .sleep = tda10023_sleep,
5819a0bf528SMauro Carvalho Chehab .i2c_gate_ctrl = tda10023_i2c_gate_ctrl,
5829a0bf528SMauro Carvalho Chehab
5839a0bf528SMauro Carvalho Chehab .set_frontend = tda10023_set_parameters,
5849a0bf528SMauro Carvalho Chehab .get_frontend = tda10023_get_frontend,
5859a0bf528SMauro Carvalho Chehab .read_status = tda10023_read_status,
5869a0bf528SMauro Carvalho Chehab .read_ber = tda10023_read_ber,
5879a0bf528SMauro Carvalho Chehab .read_signal_strength = tda10023_read_signal_strength,
5889a0bf528SMauro Carvalho Chehab .read_snr = tda10023_read_snr,
5899a0bf528SMauro Carvalho Chehab .read_ucblocks = tda10023_read_ucblocks,
5909a0bf528SMauro Carvalho Chehab };
5919a0bf528SMauro Carvalho Chehab
5929a0bf528SMauro Carvalho Chehab
5939a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Philips TDA10023 DVB-C demodulator driver");
5949a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Georg Acher, Hartmut Birr");
5959a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
5969a0bf528SMauro Carvalho Chehab
597*86495af1SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(tda10023_attach);
598