brintos

brintos / linux-shallow public Read only

0
0
Text · 14.8 KiB · fe5af24 Raw
597 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3    driver for LSI L64781 COFDM demodulator4 5    Copyright (C) 2001 Holger Waechtler for Convergence Integrated Media GmbH6		       Marko Kohtala <marko.kohtala@luukku.com>7 8 9*/10 11#include <linux/init.h>12#include <linux/kernel.h>13#include <linux/module.h>14#include <linux/string.h>15#include <linux/slab.h>16#include <media/dvb_frontend.h>17#include "l64781.h"18 19 20struct l64781_state {21	struct i2c_adapter* i2c;22	const struct l64781_config* config;23	struct dvb_frontend frontend;24 25	/* private demodulator data */26	unsigned int first:1;27};28 29#define dprintk(args...) \30	do { \31		if (debug) printk(KERN_DEBUG "l64781: " args); \32	} while (0)33 34static int debug;35 36module_param(debug, int, 0644);37MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");38 39 40static int l64781_writereg (struct l64781_state* state, u8 reg, u8 data)41{42	int ret;43	u8 buf [] = { reg, data };44	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };45 46	if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1)47		dprintk ("%s: write_reg error (reg == %02x) = %02x!\n",48			 __func__, reg, ret);49 50	return (ret != 1) ? -1 : 0;51}52 53static int l64781_readreg (struct l64781_state* state, u8 reg)54{55	int ret;56	u8 b0 [] = { reg };57	u8 b1 [] = { 0 };58	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },59			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };60 61	ret = i2c_transfer(state->i2c, msg, 2);62 63	if (ret != 2) return ret;64 65	return b1[0];66}67 68static void apply_tps (struct l64781_state* state)69{70	l64781_writereg (state, 0x2a, 0x00);71	l64781_writereg (state, 0x2a, 0x01);72 73	/* This here is a little bit questionable because it enables74	   the automatic update of TPS registers. I think we'd need to75	   handle the IRQ from FE to update some other registers as76	   well, or at least implement some magic to tuning to correct77	   to the TPS received from transmission. */78	l64781_writereg (state, 0x2a, 0x02);79}80 81 82static void reset_afc (struct l64781_state* state)83{84	/* Set AFC stall for the AFC_INIT_FRQ setting, TIM_STALL for85	   timing offset */86	l64781_writereg (state, 0x07, 0x9e); /* stall AFC */87	l64781_writereg (state, 0x08, 0);    /* AFC INIT FREQ */88	l64781_writereg (state, 0x09, 0);89	l64781_writereg (state, 0x0a, 0);90	l64781_writereg (state, 0x07, 0x8e);91	l64781_writereg (state, 0x0e, 0);    /* AGC gain to zero in beginning */92	l64781_writereg (state, 0x11, 0x80); /* stall TIM */93	l64781_writereg (state, 0x10, 0);    /* TIM_OFFSET_LSB */94	l64781_writereg (state, 0x12, 0);95	l64781_writereg (state, 0x13, 0);96	l64781_writereg (state, 0x11, 0x00);97}98 99static int reset_and_configure (struct l64781_state* state)100{101	u8 buf [] = { 0x06 };102	struct i2c_msg msg = { .addr = 0x00, .flags = 0, .buf = buf, .len = 1 };103	// NOTE: this is correct in writing to address 0x00104 105	return (i2c_transfer(state->i2c, &msg, 1) == 1) ? 0 : -ENODEV;106}107 108static int apply_frontend_param(struct dvb_frontend *fe)109{110	struct dtv_frontend_properties *p = &fe->dtv_property_cache;111	struct l64781_state* state = fe->demodulator_priv;112	/* The coderates for FEC_NONE, FEC_4_5 and FEC_FEC_6_7 are arbitrary */113	static const u8 fec_tab[] = { 7, 0, 1, 2, 9, 3, 10, 4 };114	/* QPSK, QAM_16, QAM_64 */115	static const u8 qam_tab [] = { 2, 4, 0, 6 };116	static const u8 guard_tab [] = { 1, 2, 4, 8 };117	/* The Grundig 29504-401.04 Tuner comes with 18.432MHz crystal. */118	static const u32 ppm = 8000;119	u32 ddfs_offset_fixed;120/*	u32 ddfs_offset_variable = 0x6000-((1000000UL+ppm)/ */121/*			bw_tab[p->bandWidth]<<10)/15625; */122	u32 init_freq;123	u32 spi_bias;124	u8 val0x04;125	u8 val0x05;126	u8 val0x06;127	int bw;128 129	switch (p->bandwidth_hz) {130	case 8000000:131		bw = 8;132		break;133	case 7000000:134		bw = 7;135		break;136	case 6000000:137		bw = 6;138		break;139	default:140		return -EINVAL;141	}142 143	if (fe->ops.tuner_ops.set_params) {144		fe->ops.tuner_ops.set_params(fe);145		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);146	}147 148	if (p->inversion != INVERSION_ON &&149	    p->inversion != INVERSION_OFF)150		return -EINVAL;151 152	if (p->code_rate_HP != FEC_1_2 && p->code_rate_HP != FEC_2_3 &&153	    p->code_rate_HP != FEC_3_4 && p->code_rate_HP != FEC_5_6 &&154	    p->code_rate_HP != FEC_7_8)155		return -EINVAL;156 157	if (p->hierarchy != HIERARCHY_NONE &&158	    (p->code_rate_LP != FEC_1_2 && p->code_rate_LP != FEC_2_3 &&159	     p->code_rate_LP != FEC_3_4 && p->code_rate_LP != FEC_5_6 &&160	     p->code_rate_LP != FEC_7_8))161		return -EINVAL;162 163	if (p->modulation != QPSK && p->modulation != QAM_16 &&164	    p->modulation != QAM_64)165		return -EINVAL;166 167	if (p->transmission_mode != TRANSMISSION_MODE_2K &&168	    p->transmission_mode != TRANSMISSION_MODE_8K)169		return -EINVAL;170 171	if ((int)p->guard_interval < GUARD_INTERVAL_1_32 ||172	    p->guard_interval > GUARD_INTERVAL_1_4)173		return -EINVAL;174 175	if ((int)p->hierarchy < HIERARCHY_NONE ||176	    p->hierarchy > HIERARCHY_4)177		return -EINVAL;178 179	ddfs_offset_fixed = 0x4000-(ppm<<16)/bw/1000000;180 181	/* This works up to 20000 ppm, it overflows if too large ppm! */182	init_freq = (((8UL<<25) + (8UL<<19) / 25*ppm / (15625/25)) /183			bw & 0xFFFFFF);184 185	/* SPI bias calculation is slightly modified to fit in 32bit */186	/* will work for high ppm only... */187	spi_bias = 378 * (1 << 10);188	spi_bias *= 16;189	spi_bias *= bw;190	spi_bias *= qam_tab[p->modulation];191	spi_bias /= p->code_rate_HP + 1;192	spi_bias /= (guard_tab[p->guard_interval] + 32);193	spi_bias *= 1000;194	spi_bias /= 1000 + ppm/1000;195	spi_bias *= p->code_rate_HP;196 197	val0x04 = (p->transmission_mode << 2) | p->guard_interval;198	val0x05 = fec_tab[p->code_rate_HP];199 200	if (p->hierarchy != HIERARCHY_NONE)201		val0x05 |= (p->code_rate_LP - FEC_1_2) << 3;202 203	val0x06 = (p->hierarchy << 2) | p->modulation;204 205	l64781_writereg (state, 0x04, val0x04);206	l64781_writereg (state, 0x05, val0x05);207	l64781_writereg (state, 0x06, val0x06);208 209	reset_afc (state);210 211	/* Technical manual section 2.6.1, TIM_IIR_GAIN optimal values */212	l64781_writereg (state, 0x15,213			 p->transmission_mode == TRANSMISSION_MODE_2K ? 1 : 3);214	l64781_writereg (state, 0x16, init_freq & 0xff);215	l64781_writereg (state, 0x17, (init_freq >> 8) & 0xff);216	l64781_writereg (state, 0x18, (init_freq >> 16) & 0xff);217 218	l64781_writereg (state, 0x1b, spi_bias & 0xff);219	l64781_writereg (state, 0x1c, (spi_bias >> 8) & 0xff);220	l64781_writereg (state, 0x1d, ((spi_bias >> 16) & 0x7f) |221		(p->inversion == INVERSION_ON ? 0x80 : 0x00));222 223	l64781_writereg (state, 0x22, ddfs_offset_fixed & 0xff);224	l64781_writereg (state, 0x23, (ddfs_offset_fixed >> 8) & 0x3f);225 226	l64781_readreg (state, 0x00);  /*  clear interrupt registers... */227	l64781_readreg (state, 0x01);  /*  dto. */228 229	apply_tps (state);230 231	return 0;232}233 234static int get_frontend(struct dvb_frontend *fe,235			struct dtv_frontend_properties *p)236{237	struct l64781_state* state = fe->demodulator_priv;238	int tmp;239 240 241	tmp = l64781_readreg(state, 0x04);242	switch(tmp & 3) {243	case 0:244		p->guard_interval = GUARD_INTERVAL_1_32;245		break;246	case 1:247		p->guard_interval = GUARD_INTERVAL_1_16;248		break;249	case 2:250		p->guard_interval = GUARD_INTERVAL_1_8;251		break;252	case 3:253		p->guard_interval = GUARD_INTERVAL_1_4;254		break;255	}256	switch((tmp >> 2) & 3) {257	case 0:258		p->transmission_mode = TRANSMISSION_MODE_2K;259		break;260	case 1:261		p->transmission_mode = TRANSMISSION_MODE_8K;262		break;263	default:264		printk(KERN_WARNING "Unexpected value for transmission_mode\n");265	}266 267	tmp = l64781_readreg(state, 0x05);268	switch(tmp & 7) {269	case 0:270		p->code_rate_HP = FEC_1_2;271		break;272	case 1:273		p->code_rate_HP = FEC_2_3;274		break;275	case 2:276		p->code_rate_HP = FEC_3_4;277		break;278	case 3:279		p->code_rate_HP = FEC_5_6;280		break;281	case 4:282		p->code_rate_HP = FEC_7_8;283		break;284	default:285		printk("Unexpected value for code_rate_HP\n");286	}287	switch((tmp >> 3) & 7) {288	case 0:289		p->code_rate_LP = FEC_1_2;290		break;291	case 1:292		p->code_rate_LP = FEC_2_3;293		break;294	case 2:295		p->code_rate_LP = FEC_3_4;296		break;297	case 3:298		p->code_rate_LP = FEC_5_6;299		break;300	case 4:301		p->code_rate_LP = FEC_7_8;302		break;303	default:304		printk("Unexpected value for code_rate_LP\n");305	}306 307	tmp = l64781_readreg(state, 0x06);308	switch(tmp & 3) {309	case 0:310		p->modulation = QPSK;311		break;312	case 1:313		p->modulation = QAM_16;314		break;315	case 2:316		p->modulation = QAM_64;317		break;318	default:319		printk(KERN_WARNING "Unexpected value for modulation\n");320	}321	switch((tmp >> 2) & 7) {322	case 0:323		p->hierarchy = HIERARCHY_NONE;324		break;325	case 1:326		p->hierarchy = HIERARCHY_1;327		break;328	case 2:329		p->hierarchy = HIERARCHY_2;330		break;331	case 3:332		p->hierarchy = HIERARCHY_4;333		break;334	default:335		printk("Unexpected value for hierarchy\n");336	}337 338 339	tmp = l64781_readreg (state, 0x1d);340	p->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF;341 342	tmp = (int) (l64781_readreg (state, 0x08) |343		     (l64781_readreg (state, 0x09) << 8) |344		     (l64781_readreg (state, 0x0a) << 16));345	p->frequency += tmp;346 347	return 0;348}349 350static int l64781_read_status(struct dvb_frontend *fe, enum fe_status *status)351{352	struct l64781_state* state = fe->demodulator_priv;353	int sync = l64781_readreg (state, 0x32);354	int gain = l64781_readreg (state, 0x0e);355 356	l64781_readreg (state, 0x00);  /*  clear interrupt registers... */357	l64781_readreg (state, 0x01);  /*  dto. */358 359	*status = 0;360 361	if (gain > 5)362		*status |= FE_HAS_SIGNAL;363 364	if (sync & 0x02) /* VCXO locked, this criteria should be ok */365		*status |= FE_HAS_CARRIER;366 367	if (sync & 0x20)368		*status |= FE_HAS_VITERBI;369 370	if (sync & 0x40)371		*status |= FE_HAS_SYNC;372 373	if (sync == 0x7f)374		*status |= FE_HAS_LOCK;375 376	return 0;377}378 379static int l64781_read_ber(struct dvb_frontend* fe, u32* ber)380{381	struct l64781_state* state = fe->demodulator_priv;382 383	/*   XXX FIXME: set up counting period (reg 0x26...0x28)384	 */385	*ber = l64781_readreg (state, 0x39)386	    | (l64781_readreg (state, 0x3a) << 8);387 388	return 0;389}390 391static int l64781_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)392{393	struct l64781_state* state = fe->demodulator_priv;394 395	u8 gain = l64781_readreg (state, 0x0e);396	*signal_strength = (gain << 8) | gain;397 398	return 0;399}400 401static int l64781_read_snr(struct dvb_frontend* fe, u16* snr)402{403	struct l64781_state* state = fe->demodulator_priv;404 405	u8 avg_quality = 0xff - l64781_readreg (state, 0x33);406	*snr = (avg_quality << 8) | avg_quality; /* not exact, but...*/407 408	return 0;409}410 411static int l64781_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)412{413	struct l64781_state* state = fe->demodulator_priv;414 415	*ucblocks = l64781_readreg (state, 0x37)416	   | (l64781_readreg (state, 0x38) << 8);417 418	return 0;419}420 421static int l64781_sleep(struct dvb_frontend* fe)422{423	struct l64781_state* state = fe->demodulator_priv;424 425	/* Power down */426	return l64781_writereg (state, 0x3e, 0x5a);427}428 429static int l64781_init(struct dvb_frontend* fe)430{431	struct l64781_state* state = fe->demodulator_priv;432 433	reset_and_configure (state);434 435	/* Power up */436	l64781_writereg (state, 0x3e, 0xa5);437 438	/* Reset hard */439	l64781_writereg (state, 0x2a, 0x04);440	l64781_writereg (state, 0x2a, 0x00);441 442	/* Set tuner specific things */443	/* AFC_POL, set also in reset_afc */444	l64781_writereg (state, 0x07, 0x8e);445 446	/* Use internal ADC */447	l64781_writereg (state, 0x0b, 0x81);448 449	/* AGC loop gain, and polarity is positive */450	l64781_writereg (state, 0x0c, 0x84);451 452	/* Internal ADC outputs two's complement */453	l64781_writereg (state, 0x0d, 0x8c);454 455	/* With ppm=8000, it seems the DTR_SENSITIVITY will result in456	   value of 2 with all possible bandwidths and guard457	   intervals, which is the initial value anyway. */458	/*l64781_writereg (state, 0x19, 0x92);*/459 460	/* Everything is two's complement, soft bit and CSI_OUT too */461	l64781_writereg (state, 0x1e, 0x09);462 463	/* delay a bit after first init attempt */464	if (state->first) {465		state->first = 0;466		msleep(200);467	}468 469	return 0;470}471 472static int l64781_get_tune_settings(struct dvb_frontend* fe,473				    struct dvb_frontend_tune_settings* fesettings)474{475	fesettings->min_delay_ms = 4000;476	fesettings->step_size = 0;477	fesettings->max_drift = 0;478	return 0;479}480 481static void l64781_release(struct dvb_frontend* fe)482{483	struct l64781_state* state = fe->demodulator_priv;484	kfree(state);485}486 487static const struct dvb_frontend_ops l64781_ops;488 489struct dvb_frontend* l64781_attach(const struct l64781_config* config,490				   struct i2c_adapter* i2c)491{492	struct l64781_state* state = NULL;493	int reg0x3e = -1;494	u8 b0 [] = { 0x1a };495	u8 b1 [] = { 0x00 };496	struct i2c_msg msg [] = { { .addr = config->demod_address, .flags = 0, .buf = b0, .len = 1 },497			   { .addr = config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };498 499	/* allocate memory for the internal state */500	state = kzalloc(sizeof(struct l64781_state), GFP_KERNEL);501	if (state == NULL) goto error;502 503	/* setup the state */504	state->config = config;505	state->i2c = i2c;506	state->first = 1;507 508	/*509	 *  the L64781 won't show up before we send the reset_and_configure()510	 *  broadcast. If nothing responds there is no L64781 on the bus...511	 */512	if (reset_and_configure(state) < 0) {513		dprintk("No response to reset and configure broadcast...\n");514		goto error;515	}516 517	/* The chip always responds to reads */518	if (i2c_transfer(state->i2c, msg, 2) != 2) {519		dprintk("No response to read on I2C bus\n");520		goto error;521	}522 523	/* Save current register contents for bailout */524	reg0x3e = l64781_readreg(state, 0x3e);525 526	/* Reading the POWER_DOWN register always returns 0 */527	if (reg0x3e != 0) {528		dprintk("Device doesn't look like L64781\n");529		goto error;530	}531 532	/* Turn the chip off */533	l64781_writereg (state, 0x3e, 0x5a);534 535	/* Responds to all reads with 0 */536	if (l64781_readreg(state, 0x1a) != 0) {537		dprintk("Read 1 returned unexpected value\n");538		goto error;539	}540 541	/* Turn the chip on */542	l64781_writereg (state, 0x3e, 0xa5);543 544	/* Responds with register default value */545	if (l64781_readreg(state, 0x1a) != 0xa1) {546		dprintk("Read 2 returned unexpected value\n");547		goto error;548	}549 550	/* create dvb_frontend */551	memcpy(&state->frontend.ops, &l64781_ops, sizeof(struct dvb_frontend_ops));552	state->frontend.demodulator_priv = state;553	return &state->frontend;554 555error:556	if (reg0x3e >= 0)557		l64781_writereg (state, 0x3e, reg0x3e);  /* restore reg 0x3e */558	kfree(state);559	return NULL;560}561 562static const struct dvb_frontend_ops l64781_ops = {563	.delsys = { SYS_DVBT },564	.info = {565		.name = "LSI L64781 DVB-T",566	/*	.frequency_min_hz = ???,*/567	/*	.frequency_max_hz = ???,*/568		.frequency_stepsize_hz = 166666,569	/*      .symbol_rate_tolerance = ???,*/570		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |571		      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |572		      FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |573		      FE_CAN_MUTE_TS574	},575 576	.release = l64781_release,577 578	.init = l64781_init,579	.sleep = l64781_sleep,580 581	.set_frontend = apply_frontend_param,582	.get_frontend = get_frontend,583	.get_tune_settings = l64781_get_tune_settings,584 585	.read_status = l64781_read_status,586	.read_ber = l64781_read_ber,587	.read_signal_strength = l64781_read_signal_strength,588	.read_snr = l64781_read_snr,589	.read_ucblocks = l64781_read_ucblocks,590};591 592MODULE_DESCRIPTION("LSI L64781 DVB-T Demodulator driver");593MODULE_AUTHOR("Holger Waechtler, Marko Kohtala");594MODULE_LICENSE("GPL");595 596EXPORT_SYMBOL_GPL(l64781_attach);597