brintos

brintos / linux-shallow public Read only

0
0
Text · 30.5 KiB · bdc8311 Raw
1203 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *    Support for LG Electronics LGDT3304 and LGDT3305 - VSB/QAM4 *5 *    Copyright (C) 2008, 2009, 2010 Michael Krufky <mkrufky@linuxtv.org>6 *7 *    LGDT3304 support by Jarod Wilson <jarod@redhat.com>8 */9 10#include <asm/div64.h>11#include <linux/dvb/frontend.h>12#include <linux/slab.h>13#include <linux/int_log.h>14#include "lgdt3305.h"15 16static int debug;17module_param(debug, int, 0644);18MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))");19 20#define DBG_INFO 121#define DBG_REG  222 23#define lg_printk(kern, fmt, arg...)					\24	printk(kern "%s: " fmt, __func__, ##arg)25 26#define lg_info(fmt, arg...)	printk(KERN_INFO "lgdt3305: " fmt, ##arg)27#define lg_warn(fmt, arg...)	lg_printk(KERN_WARNING,       fmt, ##arg)28#define lg_err(fmt, arg...)	lg_printk(KERN_ERR,           fmt, ##arg)29#define lg_dbg(fmt, arg...) if (debug & DBG_INFO)			\30				lg_printk(KERN_DEBUG,         fmt, ##arg)31#define lg_reg(fmt, arg...) if (debug & DBG_REG)			\32				lg_printk(KERN_DEBUG,         fmt, ##arg)33 34#define lg_fail(ret)							\35({									\36	int __ret;							\37	__ret = (ret < 0);						\38	if (__ret)							\39		lg_err("error %d on line %d\n",	ret, __LINE__);		\40	__ret;								\41})42 43struct lgdt3305_state {44	struct i2c_adapter *i2c_adap;45	const struct lgdt3305_config *cfg;46 47	struct dvb_frontend frontend;48 49	enum fe_modulation current_modulation;50	u32 current_frequency;51	u32 snr;52};53 54/* ------------------------------------------------------------------------ */55 56/* FIXME: verify & document the LGDT3304 registers */57 58#define LGDT3305_GEN_CTRL_1                   0x000059#define LGDT3305_GEN_CTRL_2                   0x000160#define LGDT3305_GEN_CTRL_3                   0x000261#define LGDT3305_GEN_STATUS                   0x000362#define LGDT3305_GEN_CONTROL                  0x000763#define LGDT3305_GEN_CTRL_4                   0x000a64#define LGDT3305_DGTL_AGC_REF_1               0x001265#define LGDT3305_DGTL_AGC_REF_2               0x001366#define LGDT3305_CR_CTR_FREQ_1                0x010667#define LGDT3305_CR_CTR_FREQ_2                0x010768#define LGDT3305_CR_CTR_FREQ_3                0x010869#define LGDT3305_CR_CTR_FREQ_4                0x010970#define LGDT3305_CR_MSE_1                     0x011b71#define LGDT3305_CR_MSE_2                     0x011c72#define LGDT3305_CR_LOCK_STATUS               0x011d73#define LGDT3305_CR_CTRL_7                    0x012674#define LGDT3305_AGC_POWER_REF_1              0x030075#define LGDT3305_AGC_POWER_REF_2              0x030176#define LGDT3305_AGC_DELAY_PT_1               0x030277#define LGDT3305_AGC_DELAY_PT_2               0x030378#define LGDT3305_RFAGC_LOOP_FLTR_BW_1         0x030679#define LGDT3305_RFAGC_LOOP_FLTR_BW_2         0x030780#define LGDT3305_IFBW_1                       0x030881#define LGDT3305_IFBW_2                       0x030982#define LGDT3305_AGC_CTRL_1                   0x030c83#define LGDT3305_AGC_CTRL_4                   0x031484#define LGDT3305_EQ_MSE_1                     0x041385#define LGDT3305_EQ_MSE_2                     0x041486#define LGDT3305_EQ_MSE_3                     0x041587#define LGDT3305_PT_MSE_1                     0x041788#define LGDT3305_PT_MSE_2                     0x041889#define LGDT3305_PT_MSE_3                     0x041990#define LGDT3305_FEC_BLOCK_CTRL               0x050491#define LGDT3305_FEC_LOCK_STATUS              0x050a92#define LGDT3305_FEC_PKT_ERR_1                0x050c93#define LGDT3305_FEC_PKT_ERR_2                0x050d94#define LGDT3305_TP_CTRL_1                    0x050e95#define LGDT3305_BERT_PERIOD                  0x080196#define LGDT3305_BERT_ERROR_COUNT_1           0x080a97#define LGDT3305_BERT_ERROR_COUNT_2           0x080b98#define LGDT3305_BERT_ERROR_COUNT_3           0x080c99#define LGDT3305_BERT_ERROR_COUNT_4           0x080d100 101static int lgdt3305_write_reg(struct lgdt3305_state *state, u16 reg, u8 val)102{103	int ret;104	u8 buf[] = { reg >> 8, reg & 0xff, val };105	struct i2c_msg msg = {106		.addr = state->cfg->i2c_addr, .flags = 0,107		.buf = buf, .len = 3,108	};109 110	lg_reg("reg: 0x%04x, val: 0x%02x\n", reg, val);111 112	ret = i2c_transfer(state->i2c_adap, &msg, 1);113 114	if (ret != 1) {115		lg_err("error (addr %02x %02x <- %02x, err = %i)\n",116		       msg.buf[0], msg.buf[1], msg.buf[2], ret);117		if (ret < 0)118			return ret;119		else120			return -EREMOTEIO;121	}122	return 0;123}124 125static int lgdt3305_read_reg(struct lgdt3305_state *state, u16 reg, u8 *val)126{127	int ret;128	u8 reg_buf[] = { reg >> 8, reg & 0xff };129	struct i2c_msg msg[] = {130		{ .addr = state->cfg->i2c_addr,131		  .flags = 0, .buf = reg_buf, .len = 2 },132		{ .addr = state->cfg->i2c_addr,133		  .flags = I2C_M_RD, .buf = val, .len = 1 },134	};135 136	lg_reg("reg: 0x%04x\n", reg);137 138	ret = i2c_transfer(state->i2c_adap, msg, 2);139 140	if (ret != 2) {141		lg_err("error (addr %02x reg %04x error (ret == %i)\n",142		       state->cfg->i2c_addr, reg, ret);143		if (ret < 0)144			return ret;145		else146			return -EREMOTEIO;147	}148	return 0;149}150 151#define read_reg(state, reg)						\152({									\153	u8 __val;							\154	int ret = lgdt3305_read_reg(state, reg, &__val);		\155	if (lg_fail(ret))						\156		__val = 0;						\157	__val;								\158})159 160static int lgdt3305_set_reg_bit(struct lgdt3305_state *state,161				u16 reg, int bit, int onoff)162{163	u8 val;164	int ret;165 166	lg_reg("reg: 0x%04x, bit: %d, level: %d\n", reg, bit, onoff);167 168	ret = lgdt3305_read_reg(state, reg, &val);169	if (lg_fail(ret))170		goto fail;171 172	val &= ~(1 << bit);173	val |= (onoff & 1) << bit;174 175	ret = lgdt3305_write_reg(state, reg, val);176fail:177	return ret;178}179 180struct lgdt3305_reg {181	u16 reg;182	u8 val;183};184 185static int lgdt3305_write_regs(struct lgdt3305_state *state,186			       struct lgdt3305_reg *regs, int len)187{188	int i, ret;189 190	lg_reg("writing %d registers...\n", len);191 192	for (i = 0; i < len - 1; i++) {193		ret = lgdt3305_write_reg(state, regs[i].reg, regs[i].val);194		if (lg_fail(ret))195			return ret;196	}197	return 0;198}199 200/* ------------------------------------------------------------------------ */201 202static int lgdt3305_soft_reset(struct lgdt3305_state *state)203{204	int ret;205 206	lg_dbg("\n");207 208	ret = lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_3, 0, 0);209	if (lg_fail(ret))210		goto fail;211 212	msleep(20);213	ret = lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_3, 0, 1);214fail:215	return ret;216}217 218static inline int lgdt3305_mpeg_mode(struct lgdt3305_state *state,219				     enum lgdt3305_mpeg_mode mode)220{221	lg_dbg("(%d)\n", mode);222	return lgdt3305_set_reg_bit(state, LGDT3305_TP_CTRL_1, 5, mode);223}224 225static int lgdt3305_mpeg_mode_polarity(struct lgdt3305_state *state)226{227	u8 val;228	int ret;229	enum lgdt3305_tp_clock_edge edge = state->cfg->tpclk_edge;230	enum lgdt3305_tp_clock_mode mode = state->cfg->tpclk_mode;231	enum lgdt3305_tp_valid_polarity valid = state->cfg->tpvalid_polarity;232 233	lg_dbg("edge = %d, valid = %d\n", edge, valid);234 235	ret = lgdt3305_read_reg(state, LGDT3305_TP_CTRL_1, &val);236	if (lg_fail(ret))237		goto fail;238 239	val &= ~0x09;240 241	if (edge)242		val |= 0x08;243	if (mode)244		val |= 0x40;245	if (valid)246		val |= 0x01;247 248	ret = lgdt3305_write_reg(state, LGDT3305_TP_CTRL_1, val);249	if (lg_fail(ret))250		goto fail;251 252	ret = lgdt3305_soft_reset(state);253fail:254	return ret;255}256 257static int lgdt3305_set_modulation(struct lgdt3305_state *state,258				   struct dtv_frontend_properties *p)259{260	u8 opermode;261	int ret;262 263	lg_dbg("\n");264 265	ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_1, &opermode);266	if (lg_fail(ret))267		goto fail;268 269	opermode &= ~0x03;270 271	switch (p->modulation) {272	case VSB_8:273		opermode |= 0x03;274		break;275	case QAM_64:276		opermode |= 0x00;277		break;278	case QAM_256:279		opermode |= 0x01;280		break;281	default:282		return -EINVAL;283	}284	ret = lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_1, opermode);285fail:286	return ret;287}288 289static int lgdt3305_set_filter_extension(struct lgdt3305_state *state,290					 struct dtv_frontend_properties *p)291{292	int val;293 294	switch (p->modulation) {295	case VSB_8:296		val = 0;297		break;298	case QAM_64:299	case QAM_256:300		val = 1;301		break;302	default:303		return -EINVAL;304	}305	lg_dbg("val = %d\n", val);306 307	return lgdt3305_set_reg_bit(state, 0x043f, 2, val);308}309 310/* ------------------------------------------------------------------------ */311 312static int lgdt3305_passband_digital_agc(struct lgdt3305_state *state,313					 struct dtv_frontend_properties *p)314{315	u16 agc_ref;316 317	switch (p->modulation) {318	case VSB_8:319		agc_ref = 0x32c4;320		break;321	case QAM_64:322		agc_ref = 0x2a00;323		break;324	case QAM_256:325		agc_ref = 0x2a80;326		break;327	default:328		return -EINVAL;329	}330 331	lg_dbg("agc ref: 0x%04x\n", agc_ref);332 333	lgdt3305_write_reg(state, LGDT3305_DGTL_AGC_REF_1, agc_ref >> 8);334	lgdt3305_write_reg(state, LGDT3305_DGTL_AGC_REF_2, agc_ref & 0xff);335 336	return 0;337}338 339static int lgdt3305_rfagc_loop(struct lgdt3305_state *state,340			       struct dtv_frontend_properties *p)341{342	u16 ifbw, rfbw, agcdelay;343 344	switch (p->modulation) {345	case VSB_8:346		agcdelay = 0x04c0;347		rfbw     = 0x8000;348		ifbw     = 0x8000;349		break;350	case QAM_64:351	case QAM_256:352		agcdelay = 0x046b;353		rfbw     = 0x8889;354		/* FIXME: investigate optimal ifbw & rfbw values for the355		 *        DT3304 and re-write this switch..case block */356		if (state->cfg->demod_chip == LGDT3304)357			ifbw = 0x6666;358		else /* (state->cfg->demod_chip == LGDT3305) */359			ifbw = 0x8888;360		break;361	default:362		return -EINVAL;363	}364 365	if (state->cfg->rf_agc_loop) {366		lg_dbg("agcdelay: 0x%04x, rfbw: 0x%04x\n", agcdelay, rfbw);367 368		/* rf agc loop filter bandwidth */369		lgdt3305_write_reg(state, LGDT3305_AGC_DELAY_PT_1,370				   agcdelay >> 8);371		lgdt3305_write_reg(state, LGDT3305_AGC_DELAY_PT_2,372				   agcdelay & 0xff);373 374		lgdt3305_write_reg(state, LGDT3305_RFAGC_LOOP_FLTR_BW_1,375				   rfbw >> 8);376		lgdt3305_write_reg(state, LGDT3305_RFAGC_LOOP_FLTR_BW_2,377				   rfbw & 0xff);378	} else {379		lg_dbg("ifbw: 0x%04x\n", ifbw);380 381		/* if agc loop filter bandwidth */382		lgdt3305_write_reg(state, LGDT3305_IFBW_1, ifbw >> 8);383		lgdt3305_write_reg(state, LGDT3305_IFBW_2, ifbw & 0xff);384	}385 386	return 0;387}388 389static int lgdt3305_agc_setup(struct lgdt3305_state *state,390			      struct dtv_frontend_properties *p)391{392	int lockdten, acqen;393 394	switch (p->modulation) {395	case VSB_8:396		lockdten = 0;397		acqen = 0;398		break;399	case QAM_64:400	case QAM_256:401		lockdten = 1;402		acqen = 1;403		break;404	default:405		return -EINVAL;406	}407 408	lg_dbg("lockdten = %d, acqen = %d\n", lockdten, acqen);409 410	/* control agc function */411	switch (state->cfg->demod_chip) {412	case LGDT3304:413		lgdt3305_write_reg(state, 0x0314, 0xe1 | lockdten << 1);414		lgdt3305_set_reg_bit(state, 0x030e, 2, acqen);415		break;416	case LGDT3305:417		lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1);418		lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen);419		break;420	default:421		return -EINVAL;422	}423 424	return lgdt3305_rfagc_loop(state, p);425}426 427static int lgdt3305_set_agc_power_ref(struct lgdt3305_state *state,428				      struct dtv_frontend_properties *p)429{430	u16 usref = 0;431 432	switch (p->modulation) {433	case VSB_8:434		if (state->cfg->usref_8vsb)435			usref = state->cfg->usref_8vsb;436		break;437	case QAM_64:438		if (state->cfg->usref_qam64)439			usref = state->cfg->usref_qam64;440		break;441	case QAM_256:442		if (state->cfg->usref_qam256)443			usref = state->cfg->usref_qam256;444		break;445	default:446		return -EINVAL;447	}448 449	if (usref) {450		lg_dbg("set manual mode: 0x%04x\n", usref);451 452		lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 3, 1);453 454		lgdt3305_write_reg(state, LGDT3305_AGC_POWER_REF_1,455				   0xff & (usref >> 8));456		lgdt3305_write_reg(state, LGDT3305_AGC_POWER_REF_2,457				   0xff & (usref >> 0));458	}459	return 0;460}461 462/* ------------------------------------------------------------------------ */463 464static int lgdt3305_spectral_inversion(struct lgdt3305_state *state,465				       struct dtv_frontend_properties *p,466				       int inversion)467{468	int ret;469 470	lg_dbg("(%d)\n", inversion);471 472	switch (p->modulation) {473	case VSB_8:474		ret = lgdt3305_write_reg(state, LGDT3305_CR_CTRL_7,475					 inversion ? 0xf9 : 0x79);476		break;477	case QAM_64:478	case QAM_256:479		ret = lgdt3305_write_reg(state, LGDT3305_FEC_BLOCK_CTRL,480					 inversion ? 0xfd : 0xff);481		break;482	default:483		ret = -EINVAL;484	}485	return ret;486}487 488static int lgdt3305_set_if(struct lgdt3305_state *state,489			   struct dtv_frontend_properties *p)490{491	u16 if_freq_khz;492	u8 nco1, nco2, nco3, nco4;493	u64 nco;494 495	switch (p->modulation) {496	case VSB_8:497		if_freq_khz = state->cfg->vsb_if_khz;498		break;499	case QAM_64:500	case QAM_256:501		if_freq_khz = state->cfg->qam_if_khz;502		break;503	default:504		return -EINVAL;505	}506 507	nco = if_freq_khz / 10;508 509	switch (p->modulation) {510	case VSB_8:511		nco <<= 24;512		do_div(nco, 625);513		break;514	case QAM_64:515	case QAM_256:516		nco <<= 28;517		do_div(nco, 625);518		break;519	default:520		return -EINVAL;521	}522 523	nco1 = (nco >> 24) & 0x3f;524	nco1 |= 0x40;525	nco2 = (nco >> 16) & 0xff;526	nco3 = (nco >> 8) & 0xff;527	nco4 = nco & 0xff;528 529	lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, nco1);530	lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, nco2);531	lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, nco3);532	lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, nco4);533 534	lg_dbg("%d KHz -> [%02x%02x%02x%02x]\n",535	       if_freq_khz, nco1, nco2, nco3, nco4);536 537	return 0;538}539 540/* ------------------------------------------------------------------------ */541 542static int lgdt3305_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)543{544	struct lgdt3305_state *state = fe->demodulator_priv;545 546	if (state->cfg->deny_i2c_rptr)547		return 0;548 549	lg_dbg("(%d)\n", enable);550 551	return lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_2, 5,552				    enable ? 0 : 1);553}554 555static int lgdt3305_sleep(struct dvb_frontend *fe)556{557	struct lgdt3305_state *state = fe->demodulator_priv;558	u8 gen_ctrl_3, gen_ctrl_4;559 560	lg_dbg("\n");561 562	gen_ctrl_3 = read_reg(state, LGDT3305_GEN_CTRL_3);563	gen_ctrl_4 = read_reg(state, LGDT3305_GEN_CTRL_4);564 565	/* hold in software reset while sleeping */566	gen_ctrl_3 &= ~0x01;567	/* tristate the IF-AGC pin */568	gen_ctrl_3 |=  0x02;569	/* tristate the RF-AGC pin */570	gen_ctrl_3 |=  0x04;571 572	/* disable vsb/qam module */573	gen_ctrl_4 &= ~0x01;574	/* disable adc module */575	gen_ctrl_4 &= ~0x02;576 577	lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_3, gen_ctrl_3);578	lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_4, gen_ctrl_4);579 580	return 0;581}582 583static int lgdt3305_init(struct dvb_frontend *fe)584{585	struct lgdt3305_state *state = fe->demodulator_priv;586	int ret;587 588	static struct lgdt3305_reg lgdt3304_init_data[] = {589		{ .reg = LGDT3305_GEN_CTRL_1,           .val = 0x03, },590		{ .reg = 0x000d,                        .val = 0x02, },591		{ .reg = 0x000e,                        .val = 0x02, },592		{ .reg = LGDT3305_DGTL_AGC_REF_1,       .val = 0x32, },593		{ .reg = LGDT3305_DGTL_AGC_REF_2,       .val = 0xc4, },594		{ .reg = LGDT3305_CR_CTR_FREQ_1,        .val = 0x00, },595		{ .reg = LGDT3305_CR_CTR_FREQ_2,        .val = 0x00, },596		{ .reg = LGDT3305_CR_CTR_FREQ_3,        .val = 0x00, },597		{ .reg = LGDT3305_CR_CTR_FREQ_4,        .val = 0x00, },598		{ .reg = LGDT3305_CR_CTRL_7,            .val = 0xf9, },599		{ .reg = 0x0112,                        .val = 0x17, },600		{ .reg = 0x0113,                        .val = 0x15, },601		{ .reg = 0x0114,                        .val = 0x18, },602		{ .reg = 0x0115,                        .val = 0xff, },603		{ .reg = 0x0116,                        .val = 0x3c, },604		{ .reg = 0x0214,                        .val = 0x67, },605		{ .reg = 0x0424,                        .val = 0x8d, },606		{ .reg = 0x0427,                        .val = 0x12, },607		{ .reg = 0x0428,                        .val = 0x4f, },608		{ .reg = LGDT3305_IFBW_1,               .val = 0x80, },609		{ .reg = LGDT3305_IFBW_2,               .val = 0x00, },610		{ .reg = 0x030a,                        .val = 0x08, },611		{ .reg = 0x030b,                        .val = 0x9b, },612		{ .reg = 0x030d,                        .val = 0x00, },613		{ .reg = 0x030e,                        .val = 0x1c, },614		{ .reg = 0x0314,                        .val = 0xe1, },615		{ .reg = 0x000d,                        .val = 0x82, },616		{ .reg = LGDT3305_TP_CTRL_1,            .val = 0x5b, },617		{ .reg = LGDT3305_TP_CTRL_1,            .val = 0x5b, },618	};619 620	static struct lgdt3305_reg lgdt3305_init_data[] = {621		{ .reg = LGDT3305_GEN_CTRL_1,           .val = 0x03, },622		{ .reg = LGDT3305_GEN_CTRL_2,           .val = 0xb0, },623		{ .reg = LGDT3305_GEN_CTRL_3,           .val = 0x01, },624		{ .reg = LGDT3305_GEN_CONTROL,          .val = 0x6f, },625		{ .reg = LGDT3305_GEN_CTRL_4,           .val = 0x03, },626		{ .reg = LGDT3305_DGTL_AGC_REF_1,       .val = 0x32, },627		{ .reg = LGDT3305_DGTL_AGC_REF_2,       .val = 0xc4, },628		{ .reg = LGDT3305_CR_CTR_FREQ_1,        .val = 0x00, },629		{ .reg = LGDT3305_CR_CTR_FREQ_2,        .val = 0x00, },630		{ .reg = LGDT3305_CR_CTR_FREQ_3,        .val = 0x00, },631		{ .reg = LGDT3305_CR_CTR_FREQ_4,        .val = 0x00, },632		{ .reg = LGDT3305_CR_CTRL_7,            .val = 0x79, },633		{ .reg = LGDT3305_AGC_POWER_REF_1,      .val = 0x32, },634		{ .reg = LGDT3305_AGC_POWER_REF_2,      .val = 0xc4, },635		{ .reg = LGDT3305_AGC_DELAY_PT_1,       .val = 0x0d, },636		{ .reg = LGDT3305_AGC_DELAY_PT_2,       .val = 0x30, },637		{ .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_1, .val = 0x80, },638		{ .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_2, .val = 0x00, },639		{ .reg = LGDT3305_IFBW_1,               .val = 0x80, },640		{ .reg = LGDT3305_IFBW_2,               .val = 0x00, },641		{ .reg = LGDT3305_AGC_CTRL_1,           .val = 0x30, },642		{ .reg = LGDT3305_AGC_CTRL_4,           .val = 0x61, },643		{ .reg = LGDT3305_FEC_BLOCK_CTRL,       .val = 0xff, },644		{ .reg = LGDT3305_TP_CTRL_1,            .val = 0x1b, },645	};646 647	lg_dbg("\n");648 649	switch (state->cfg->demod_chip) {650	case LGDT3304:651		ret = lgdt3305_write_regs(state, lgdt3304_init_data,652					  ARRAY_SIZE(lgdt3304_init_data));653		break;654	case LGDT3305:655		ret = lgdt3305_write_regs(state, lgdt3305_init_data,656					  ARRAY_SIZE(lgdt3305_init_data));657		break;658	default:659		ret = -EINVAL;660	}661	if (lg_fail(ret))662		goto fail;663 664	ret = lgdt3305_soft_reset(state);665fail:666	return ret;667}668 669static int lgdt3304_set_parameters(struct dvb_frontend *fe)670{671	struct dtv_frontend_properties *p = &fe->dtv_property_cache;672	struct lgdt3305_state *state = fe->demodulator_priv;673	int ret;674 675	lg_dbg("(%d, %d)\n", p->frequency, p->modulation);676 677	if (fe->ops.tuner_ops.set_params) {678		ret = fe->ops.tuner_ops.set_params(fe);679		if (fe->ops.i2c_gate_ctrl)680			fe->ops.i2c_gate_ctrl(fe, 0);681		if (lg_fail(ret))682			goto fail;683		state->current_frequency = p->frequency;684	}685 686	ret = lgdt3305_set_modulation(state, p);687	if (lg_fail(ret))688		goto fail;689 690	ret = lgdt3305_passband_digital_agc(state, p);691	if (lg_fail(ret))692		goto fail;693 694	ret = lgdt3305_agc_setup(state, p);695	if (lg_fail(ret))696		goto fail;697 698	/* reg 0x030d is 3304-only... seen in vsb and qam usbsnoops... */699	switch (p->modulation) {700	case VSB_8:701		lgdt3305_write_reg(state, 0x030d, 0x00);702		lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, 0x4f);703		lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, 0x0c);704		lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, 0xac);705		lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, 0xba);706		break;707	case QAM_64:708	case QAM_256:709		lgdt3305_write_reg(state, 0x030d, 0x14);710		ret = lgdt3305_set_if(state, p);711		if (lg_fail(ret))712			goto fail;713		break;714	default:715		return -EINVAL;716	}717 718 719	ret = lgdt3305_spectral_inversion(state, p,720					  state->cfg->spectral_inversion721					  ? 1 : 0);722	if (lg_fail(ret))723		goto fail;724 725	state->current_modulation = p->modulation;726 727	ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode);728	if (lg_fail(ret))729		goto fail;730 731	/* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */732	ret = lgdt3305_mpeg_mode_polarity(state);733fail:734	return ret;735}736 737static int lgdt3305_set_parameters(struct dvb_frontend *fe)738{739	struct dtv_frontend_properties *p = &fe->dtv_property_cache;740	struct lgdt3305_state *state = fe->demodulator_priv;741	int ret;742 743	lg_dbg("(%d, %d)\n", p->frequency, p->modulation);744 745	if (fe->ops.tuner_ops.set_params) {746		ret = fe->ops.tuner_ops.set_params(fe);747		if (fe->ops.i2c_gate_ctrl)748			fe->ops.i2c_gate_ctrl(fe, 0);749		if (lg_fail(ret))750			goto fail;751		state->current_frequency = p->frequency;752	}753 754	ret = lgdt3305_set_modulation(state, p);755	if (lg_fail(ret))756		goto fail;757 758	ret = lgdt3305_passband_digital_agc(state, p);759	if (lg_fail(ret))760		goto fail;761	ret = lgdt3305_set_agc_power_ref(state, p);762	if (lg_fail(ret))763		goto fail;764	ret = lgdt3305_agc_setup(state, p);765	if (lg_fail(ret))766		goto fail;767 768	/* low if */769	ret = lgdt3305_write_reg(state, LGDT3305_GEN_CONTROL, 0x2f);770	if (lg_fail(ret))771		goto fail;772	ret = lgdt3305_set_reg_bit(state, LGDT3305_CR_CTR_FREQ_1, 6, 1);773	if (lg_fail(ret))774		goto fail;775 776	ret = lgdt3305_set_if(state, p);777	if (lg_fail(ret))778		goto fail;779	ret = lgdt3305_spectral_inversion(state, p,780					  state->cfg->spectral_inversion781					  ? 1 : 0);782	if (lg_fail(ret))783		goto fail;784 785	ret = lgdt3305_set_filter_extension(state, p);786	if (lg_fail(ret))787		goto fail;788 789	state->current_modulation = p->modulation;790 791	ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode);792	if (lg_fail(ret))793		goto fail;794 795	/* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */796	ret = lgdt3305_mpeg_mode_polarity(state);797fail:798	return ret;799}800 801static int lgdt3305_get_frontend(struct dvb_frontend *fe,802				 struct dtv_frontend_properties *p)803{804	struct lgdt3305_state *state = fe->demodulator_priv;805 806	lg_dbg("\n");807 808	p->modulation = state->current_modulation;809	p->frequency = state->current_frequency;810	return 0;811}812 813/* ------------------------------------------------------------------------ */814 815static int lgdt3305_read_cr_lock_status(struct lgdt3305_state *state,816					int *locked)817{818	u8 val;819	int ret;820	char *cr_lock_state = "";821 822	*locked = 0;823 824	ret = lgdt3305_read_reg(state, LGDT3305_CR_LOCK_STATUS, &val);825	if (lg_fail(ret))826		goto fail;827 828	switch (state->current_modulation) {829	case QAM_256:830	case QAM_64:831		if (val & (1 << 1))832			*locked = 1;833 834		switch (val & 0x07) {835		case 0:836			cr_lock_state = "QAM UNLOCK";837			break;838		case 4:839			cr_lock_state = "QAM 1stLock";840			break;841		case 6:842			cr_lock_state = "QAM 2ndLock";843			break;844		case 7:845			cr_lock_state = "QAM FinalLock";846			break;847		default:848			cr_lock_state = "CLOCKQAM-INVALID!";849			break;850		}851		break;852	case VSB_8:853		if (val & (1 << 7)) {854			*locked = 1;855			cr_lock_state = "CLOCKVSB";856		}857		break;858	default:859		ret = -EINVAL;860	}861	lg_dbg("(%d) %s\n", *locked, cr_lock_state);862fail:863	return ret;864}865 866static int lgdt3305_read_fec_lock_status(struct lgdt3305_state *state,867					 int *locked)868{869	u8 val;870	int ret, mpeg_lock, fec_lock, viterbi_lock;871 872	*locked = 0;873 874	switch (state->current_modulation) {875	case QAM_256:876	case QAM_64:877		ret = lgdt3305_read_reg(state,878					LGDT3305_FEC_LOCK_STATUS, &val);879		if (lg_fail(ret))880			goto fail;881 882		mpeg_lock    = (val & (1 << 0)) ? 1 : 0;883		fec_lock     = (val & (1 << 2)) ? 1 : 0;884		viterbi_lock = (val & (1 << 3)) ? 1 : 0;885 886		*locked = mpeg_lock && fec_lock && viterbi_lock;887 888		lg_dbg("(%d) %s%s%s\n", *locked,889		       mpeg_lock    ? "mpeg lock  "  : "",890		       fec_lock     ? "fec lock  "   : "",891		       viterbi_lock ? "viterbi lock" : "");892		break;893	case VSB_8:894	default:895		ret = -EINVAL;896	}897fail:898	return ret;899}900 901static int lgdt3305_read_status(struct dvb_frontend *fe, enum fe_status *status)902{903	struct lgdt3305_state *state = fe->demodulator_priv;904	u8 val;905	int ret, signal, inlock, nofecerr, snrgood,906		cr_lock, fec_lock, sync_lock;907 908	*status = 0;909 910	ret = lgdt3305_read_reg(state, LGDT3305_GEN_STATUS, &val);911	if (lg_fail(ret))912		goto fail;913 914	signal    = (val & (1 << 4)) ? 1 : 0;915	inlock    = (val & (1 << 3)) ? 0 : 1;916	sync_lock = (val & (1 << 2)) ? 1 : 0;917	nofecerr  = (val & (1 << 1)) ? 1 : 0;918	snrgood   = (val & (1 << 0)) ? 1 : 0;919 920	lg_dbg("%s%s%s%s%s\n",921	       signal    ? "SIGNALEXIST " : "",922	       inlock    ? "INLOCK "      : "",923	       sync_lock ? "SYNCLOCK "    : "",924	       nofecerr  ? "NOFECERR "    : "",925	       snrgood   ? "SNRGOOD "     : "");926 927	ret = lgdt3305_read_cr_lock_status(state, &cr_lock);928	if (lg_fail(ret))929		goto fail;930 931	if (signal)932		*status |= FE_HAS_SIGNAL;933	if (cr_lock)934		*status |= FE_HAS_CARRIER;935	if (nofecerr)936		*status |= FE_HAS_VITERBI;937	if (sync_lock)938		*status |= FE_HAS_SYNC;939 940	switch (state->current_modulation) {941	case QAM_256:942	case QAM_64:943		/* signal bit is unreliable on the DT3304 in QAM mode */944		if (((LGDT3304 == state->cfg->demod_chip)) && (cr_lock))945			*status |= FE_HAS_SIGNAL;946 947		ret = lgdt3305_read_fec_lock_status(state, &fec_lock);948		if (lg_fail(ret))949			goto fail;950 951		if (fec_lock)952			*status |= FE_HAS_LOCK;953		break;954	case VSB_8:955		if (inlock)956			*status |= FE_HAS_LOCK;957		break;958	default:959		ret = -EINVAL;960	}961fail:962	return ret;963}964 965/* ------------------------------------------------------------------------ */966 967/* borrowed from lgdt330x.c */968static u32 calculate_snr(u32 mse, u32 c)969{970	if (mse == 0) /* no signal */971		return 0;972 973	mse = intlog10(mse);974	if (mse > c) {975		/* Negative SNR, which is possible, but realisticly the976		demod will lose lock before the signal gets this bad.  The977		API only allows for unsigned values, so just return 0 */978		return 0;979	}980	return 10*(c - mse);981}982 983static int lgdt3305_read_snr(struct dvb_frontend *fe, u16 *snr)984{985	struct lgdt3305_state *state = fe->demodulator_priv;986	u32 noise;	/* noise value */987	u32 c;		/* per-modulation SNR calculation constant */988 989	switch (state->current_modulation) {990	case VSB_8:991#ifdef USE_PTMSE992		/* Use Phase Tracker Mean-Square Error Register */993		/* SNR for ranges from -13.11 to +44.08 */994		noise =	((read_reg(state, LGDT3305_PT_MSE_1) & 0x07) << 16) |995			(read_reg(state, LGDT3305_PT_MSE_2) << 8) |996			(read_reg(state, LGDT3305_PT_MSE_3) & 0xff);997		c = 73957994; /* log10(25*32^2)*2^24 */998#else999		/* Use Equalizer Mean-Square Error Register */1000		/* SNR for ranges from -16.12 to +44.08 */1001		noise =	((read_reg(state, LGDT3305_EQ_MSE_1) & 0x0f) << 16) |1002			(read_reg(state, LGDT3305_EQ_MSE_2) << 8) |1003			(read_reg(state, LGDT3305_EQ_MSE_3) & 0xff);1004		c = 73957994; /* log10(25*32^2)*2^24 */1005#endif1006		break;1007	case QAM_64:1008	case QAM_256:1009		noise = (read_reg(state, LGDT3305_CR_MSE_1) << 8) |1010			(read_reg(state, LGDT3305_CR_MSE_2) & 0xff);1011 1012		c = (state->current_modulation == QAM_64) ?1013			97939837 : 98026066;1014		/* log10(688128)*2^24 and log10(696320)*2^24 */1015		break;1016	default:1017		return -EINVAL;1018	}1019	state->snr = calculate_snr(noise, c);1020	/* report SNR in dB * 10 */1021	*snr = (state->snr / ((1 << 24) / 10));1022	lg_dbg("noise = 0x%08x, snr = %d.%02d dB\n", noise,1023	       state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16);1024 1025	return 0;1026}1027 1028static int lgdt3305_read_signal_strength(struct dvb_frontend *fe,1029					 u16 *strength)1030{1031	/* borrowed from lgdt330x.c1032	 *1033	 * Calculate strength from SNR up to 35dB1034	 * Even though the SNR can go higher than 35dB,1035	 * there is some comfort factor in having a range of1036	 * strong signals that can show at 100%1037	 */1038	struct lgdt3305_state *state = fe->demodulator_priv;1039	u16 snr;1040	int ret;1041 1042	*strength = 0;1043 1044	ret = fe->ops.read_snr(fe, &snr);1045	if (lg_fail(ret))1046		goto fail;1047	/* Rather than use the 8.8 value snr, use state->snr which is 8.24 */1048	/* scale the range 0 - 35*2^24 into 0 - 65535 */1049	if (state->snr >= 8960 * 0x10000)1050		*strength = 0xffff;1051	else1052		*strength = state->snr / 8960;1053fail:1054	return ret;1055}1056 1057/* ------------------------------------------------------------------------ */1058 1059static int lgdt3305_read_ber(struct dvb_frontend *fe, u32 *ber)1060{1061	*ber = 0;1062	return 0;1063}1064 1065static int lgdt3305_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)1066{1067	struct lgdt3305_state *state = fe->demodulator_priv;1068 1069	*ucblocks =1070		(read_reg(state, LGDT3305_FEC_PKT_ERR_1) << 8) |1071		(read_reg(state, LGDT3305_FEC_PKT_ERR_2) & 0xff);1072 1073	return 0;1074}1075 1076static int lgdt3305_get_tune_settings(struct dvb_frontend *fe,1077				      struct dvb_frontend_tune_settings1078					*fe_tune_settings)1079{1080	fe_tune_settings->min_delay_ms = 500;1081	lg_dbg("\n");1082	return 0;1083}1084 1085static void lgdt3305_release(struct dvb_frontend *fe)1086{1087	struct lgdt3305_state *state = fe->demodulator_priv;1088	lg_dbg("\n");1089	kfree(state);1090}1091 1092static const struct dvb_frontend_ops lgdt3304_ops;1093static const struct dvb_frontend_ops lgdt3305_ops;1094 1095struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,1096				     struct i2c_adapter *i2c_adap)1097{1098	struct lgdt3305_state *state = NULL;1099	int ret;1100	u8 val;1101 1102	lg_dbg("(%d-%04x)\n",1103	       i2c_adap ? i2c_adapter_id(i2c_adap) : 0,1104	       config ? config->i2c_addr : 0);1105 1106	state = kzalloc(sizeof(struct lgdt3305_state), GFP_KERNEL);1107	if (state == NULL)1108		goto fail;1109 1110	state->cfg = config;1111	state->i2c_adap = i2c_adap;1112 1113	switch (config->demod_chip) {1114	case LGDT3304:1115		memcpy(&state->frontend.ops, &lgdt3304_ops,1116		       sizeof(struct dvb_frontend_ops));1117		break;1118	case LGDT3305:1119		memcpy(&state->frontend.ops, &lgdt3305_ops,1120		       sizeof(struct dvb_frontend_ops));1121		break;1122	default:1123		goto fail;1124	}1125	state->frontend.demodulator_priv = state;1126 1127	/* verify that we're talking to a lg dt3304/5 */1128	ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_2, &val);1129	if ((lg_fail(ret)) | (val == 0))1130		goto fail;1131	ret = lgdt3305_write_reg(state, 0x0808, 0x80);1132	if (lg_fail(ret))1133		goto fail;1134	ret = lgdt3305_read_reg(state, 0x0808, &val);1135	if ((lg_fail(ret)) | (val != 0x80))1136		goto fail;1137	ret = lgdt3305_write_reg(state, 0x0808, 0x00);1138	if (lg_fail(ret))1139		goto fail;1140 1141	state->current_frequency = -1;1142	state->current_modulation = -1;1143 1144	return &state->frontend;1145fail:1146	lg_warn("unable to detect %s hardware\n",1147		config->demod_chip ? "LGDT3304" : "LGDT3305");1148	kfree(state);1149	return NULL;1150}1151EXPORT_SYMBOL_GPL(lgdt3305_attach);1152 1153static const struct dvb_frontend_ops lgdt3304_ops = {1154	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },1155	.info = {1156		.name = "LG Electronics LGDT3304 VSB/QAM Frontend",1157		.frequency_min_hz      =  54 * MHz,1158		.frequency_max_hz      = 858 * MHz,1159		.frequency_stepsize_hz = 62500,1160		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB1161	},1162	.i2c_gate_ctrl        = lgdt3305_i2c_gate_ctrl,1163	.init                 = lgdt3305_init,1164	.sleep                = lgdt3305_sleep,1165	.set_frontend         = lgdt3304_set_parameters,1166	.get_frontend         = lgdt3305_get_frontend,1167	.get_tune_settings    = lgdt3305_get_tune_settings,1168	.read_status          = lgdt3305_read_status,1169	.read_ber             = lgdt3305_read_ber,1170	.read_signal_strength = lgdt3305_read_signal_strength,1171	.read_snr             = lgdt3305_read_snr,1172	.read_ucblocks        = lgdt3305_read_ucblocks,1173	.release              = lgdt3305_release,1174};1175 1176static const struct dvb_frontend_ops lgdt3305_ops = {1177	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },1178	.info = {1179		.name = "LG Electronics LGDT3305 VSB/QAM Frontend",1180		.frequency_min_hz      =  54 * MHz,1181		.frequency_max_hz      = 858 * MHz,1182		.frequency_stepsize_hz = 62500,1183		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB1184	},1185	.i2c_gate_ctrl        = lgdt3305_i2c_gate_ctrl,1186	.init                 = lgdt3305_init,1187	.sleep                = lgdt3305_sleep,1188	.set_frontend         = lgdt3305_set_parameters,1189	.get_frontend         = lgdt3305_get_frontend,1190	.get_tune_settings    = lgdt3305_get_tune_settings,1191	.read_status          = lgdt3305_read_status,1192	.read_ber             = lgdt3305_read_ber,1193	.read_signal_strength = lgdt3305_read_signal_strength,1194	.read_snr             = lgdt3305_read_snr,1195	.read_ucblocks        = lgdt3305_read_ucblocks,1196	.release              = lgdt3305_release,1197};1198 1199MODULE_DESCRIPTION("LG Electronics LGDT3304/5 ATSC/QAM-B Demodulator Driver");1200MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");1201MODULE_LICENSE("GPL");1202MODULE_VERSION("0.2");1203