xref: /openbmc/linux/drivers/media/dvb-frontends/tda10023.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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