brintos

brintos / linux-shallow public Read only

0
0
Text · 12.8 KiB · a5581bd Raw
606 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3	Driver for ST STV0288 demodulator4	Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de5		for Reel Multimedia6	Copyright (C) 2008 TurboSight.com, Bob Liu <bob@turbosight.com>7	Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>8		Removed stb6000 specific tuner code and revised some9		procedures.10	2010-09-01 Josef Pavlik <josef@pavlik.it>11		Fixed diseqc_msg, diseqc_burst and set_tone problems12 13 14*/15 16#include <linux/init.h>17#include <linux/kernel.h>18#include <linux/module.h>19#include <linux/string.h>20#include <linux/slab.h>21#include <linux/jiffies.h>22#include <asm/div64.h>23 24#include <media/dvb_frontend.h>25#include "stv0288.h"26 27struct stv0288_state {28	struct i2c_adapter *i2c;29	const struct stv0288_config *config;30	struct dvb_frontend frontend;31 32	u8 initialised:1;33	u32 tuner_frequency;34	u32 symbol_rate;35	enum fe_code_rate fec_inner;36	int errmode;37};38 39#define STATUS_BER 040#define STATUS_UCBLOCKS 141 42static int debug;43static int debug_legacy_dish_switch;44#define dprintk(args...) \45	do { \46		if (debug) \47			printk(KERN_DEBUG "stv0288: " args); \48	} while (0)49 50 51static int stv0288_writeregI(struct stv0288_state *state, u8 reg, u8 data)52{53	int ret;54	u8 buf[] = { reg, data };55	struct i2c_msg msg = {56		.addr = state->config->demod_address,57		.flags = 0,58		.buf = buf,59		.len = 260	};61 62	ret = i2c_transfer(state->i2c, &msg, 1);63 64	if (ret != 1)65		dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",66			__func__, reg, data, ret);67 68	return (ret != 1) ? -EREMOTEIO : 0;69}70 71static int stv0288_write(struct dvb_frontend *fe, const u8 buf[], int len)72{73	struct stv0288_state *state = fe->demodulator_priv;74 75	if (len != 2)76		return -EINVAL;77 78	return stv0288_writeregI(state, buf[0], buf[1]);79}80 81static u8 stv0288_readreg(struct stv0288_state *state, u8 reg)82{83	int ret;84	u8 b0[] = { reg };85	u8 b1[] = { 0 };86	struct i2c_msg msg[] = {87		{88			.addr = state->config->demod_address,89			.flags = 0,90			.buf = b0,91			.len = 192		}, {93			.addr = state->config->demod_address,94			.flags = I2C_M_RD,95			.buf = b1,96			.len = 197		}98	};99 100	ret = i2c_transfer(state->i2c, msg, 2);101 102	if (ret != 2)103		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",104				__func__, reg, ret);105 106	return b1[0];107}108 109static int stv0288_set_symbolrate(struct dvb_frontend *fe, u32 srate)110{111	struct stv0288_state *state = fe->demodulator_priv;112	unsigned int temp;113	unsigned char b[3];114 115	if ((srate < 1000000) || (srate > 45000000))116		return -EINVAL;117 118	stv0288_writeregI(state, 0x22, 0);119	stv0288_writeregI(state, 0x23, 0);120	stv0288_writeregI(state, 0x2b, 0xff);121	stv0288_writeregI(state, 0x2c, 0xf7);122 123	temp = (unsigned int)srate / 1000;124 125	temp = temp * 32768;126	temp = temp / 25;127	temp = temp / 125;128	b[0] = (unsigned char)((temp >> 12) & 0xff);129	b[1] = (unsigned char)((temp >> 4) & 0xff);130	b[2] = (unsigned char)((temp << 4) & 0xf0);131	stv0288_writeregI(state, 0x28, 0x80); /* SFRH */132	stv0288_writeregI(state, 0x29, 0); /* SFRM */133	stv0288_writeregI(state, 0x2a, 0); /* SFRL */134 135	stv0288_writeregI(state, 0x28, b[0]);136	stv0288_writeregI(state, 0x29, b[1]);137	stv0288_writeregI(state, 0x2a, b[2]);138	dprintk("stv0288: stv0288_set_symbolrate\n");139 140	return 0;141}142 143static int stv0288_send_diseqc_msg(struct dvb_frontend *fe,144				    struct dvb_diseqc_master_cmd *m)145{146	struct stv0288_state *state = fe->demodulator_priv;147 148	int i;149 150	dprintk("%s\n", __func__);151 152	stv0288_writeregI(state, 0x09, 0);153	msleep(30);154	stv0288_writeregI(state, 0x05, 0x12);/* modulated mode, single shot */155 156	for (i = 0; i < m->msg_len; i++) {157		if (stv0288_writeregI(state, 0x06, m->msg[i]))158			return -EREMOTEIO;159	}160	msleep(m->msg_len*12);161	return 0;162}163 164static int stv0288_send_diseqc_burst(struct dvb_frontend *fe,165				     enum fe_sec_mini_cmd burst)166{167	struct stv0288_state *state = fe->demodulator_priv;168 169	dprintk("%s\n", __func__);170 171	if (stv0288_writeregI(state, 0x05, 0x03))/* burst mode, single shot */172		return -EREMOTEIO;173 174	if (stv0288_writeregI(state, 0x06, burst == SEC_MINI_A ? 0x00 : 0xff))175		return -EREMOTEIO;176 177	msleep(15);178	if (stv0288_writeregI(state, 0x05, 0x12))179		return -EREMOTEIO;180 181	return 0;182}183 184static int stv0288_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone)185{186	struct stv0288_state *state = fe->demodulator_priv;187 188	switch (tone) {189	case SEC_TONE_ON:190		if (stv0288_writeregI(state, 0x05, 0x10))/* cont carrier */191			return -EREMOTEIO;192	break;193 194	case SEC_TONE_OFF:195		if (stv0288_writeregI(state, 0x05, 0x12))/* burst mode off*/196			return -EREMOTEIO;197	break;198 199	default:200		return -EINVAL;201	}202	return 0;203}204 205static u8 stv0288_inittab[] = {206	0x01, 0x15,207	0x02, 0x20,208	0x09, 0x0,209	0x0a, 0x4,210	0x0b, 0x0,211	0x0c, 0x0,212	0x0d, 0x0,213	0x0e, 0xd4,214	0x0f, 0x30,215	0x11, 0x80,216	0x12, 0x03,217	0x13, 0x48,218	0x14, 0x84,219	0x15, 0x45,220	0x16, 0xb7,221	0x17, 0x9c,222	0x18, 0x0,223	0x19, 0xa6,224	0x1a, 0x88,225	0x1b, 0x8f,226	0x1c, 0xf0,227	0x20, 0x0b,228	0x21, 0x54,229	0x22, 0x0,230	0x23, 0x0,231	0x2b, 0xff,232	0x2c, 0xf7,233	0x30, 0x0,234	0x31, 0x1e,235	0x32, 0x14,236	0x33, 0x0f,237	0x34, 0x09,238	0x35, 0x0c,239	0x36, 0x05,240	0x37, 0x2f,241	0x38, 0x16,242	0x39, 0xbe,243	0x3a, 0x0,244	0x3b, 0x13,245	0x3c, 0x11,246	0x3d, 0x30,247	0x40, 0x63,248	0x41, 0x04,249	0x42, 0x20,250	0x43, 0x00,251	0x44, 0x00,252	0x45, 0x00,253	0x46, 0x00,254	0x47, 0x00,255	0x4a, 0x00,256	0x50, 0x10,257	0x51, 0x38,258	0x52, 0x21,259	0x58, 0x54,260	0x59, 0x86,261	0x5a, 0x0,262	0x5b, 0x9b,263	0x5c, 0x08,264	0x5d, 0x7f,265	0x5e, 0x0,266	0x5f, 0xff,267	0x70, 0x0,268	0x71, 0x0,269	0x72, 0x0,270	0x74, 0x0,271	0x75, 0x0,272	0x76, 0x0,273	0x81, 0x0,274	0x82, 0x3f,275	0x83, 0x3f,276	0x84, 0x0,277	0x85, 0x0,278	0x88, 0x0,279	0x89, 0x0,280	0x8a, 0x0,281	0x8b, 0x0,282	0x8c, 0x0,283	0x90, 0x0,284	0x91, 0x0,285	0x92, 0x0,286	0x93, 0x0,287	0x94, 0x1c,288	0x97, 0x0,289	0xa0, 0x48,290	0xa1, 0x0,291	0xb0, 0xb8,292	0xb1, 0x3a,293	0xb2, 0x10,294	0xb3, 0x82,295	0xb4, 0x80,296	0xb5, 0x82,297	0xb6, 0x82,298	0xb7, 0x82,299	0xb8, 0x20,300	0xb9, 0x0,301	0xf0, 0x0,302	0xf1, 0x0,303	0xf2, 0xc0,304	0x51, 0x36,305	0x52, 0x09,306	0x53, 0x94,307	0x54, 0x62,308	0x55, 0x29,309	0x56, 0x64,310	0x57, 0x2b,311	0xff, 0xff,312};313 314static int stv0288_set_voltage(struct dvb_frontend *fe,315			       enum fe_sec_voltage volt)316{317	dprintk("%s: %s\n", __func__,318		volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :319		volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");320 321	return 0;322}323 324static int stv0288_init(struct dvb_frontend *fe)325{326	struct stv0288_state *state = fe->demodulator_priv;327	int i;328	u8 reg;329	u8 val;330 331	dprintk("stv0288: init chip\n");332	stv0288_writeregI(state, 0x41, 0x04);333	msleep(50);334 335	/* we have default inittab */336	if (state->config->inittab == NULL) {337		for (i = 0; !(stv0288_inittab[i] == 0xff &&338				stv0288_inittab[i + 1] == 0xff); i += 2)339			stv0288_writeregI(state, stv0288_inittab[i],340					stv0288_inittab[i + 1]);341	} else {342		for (i = 0; ; i += 2)  {343			reg = state->config->inittab[i];344			val = state->config->inittab[i+1];345			if (reg == 0xff && val == 0xff)346				break;347			stv0288_writeregI(state, reg, val);348		}349	}350	return 0;351}352 353static int stv0288_read_status(struct dvb_frontend *fe, enum fe_status *status)354{355	struct stv0288_state *state = fe->demodulator_priv;356 357	u8 sync = stv0288_readreg(state, 0x24);358	if (sync == 255)359		sync = 0;360 361	dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync);362 363	*status = 0;364	if (sync & 0x80)365		*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;366	if (sync & 0x10)367		*status |= FE_HAS_VITERBI;368	if (sync & 0x08) {369		*status |= FE_HAS_LOCK;370		dprintk("stv0288 has locked\n");371	}372 373	return 0;374}375 376static int stv0288_read_ber(struct dvb_frontend *fe, u32 *ber)377{378	struct stv0288_state *state = fe->demodulator_priv;379 380	if (state->errmode != STATUS_BER)381		return 0;382	*ber = (stv0288_readreg(state, 0x26) << 8) |383					stv0288_readreg(state, 0x27);384	dprintk("stv0288_read_ber %d\n", *ber);385 386	return 0;387}388 389 390static int stv0288_read_signal_strength(struct dvb_frontend *fe, u16 *strength)391{392	struct stv0288_state *state = fe->demodulator_priv;393 394	s32 signal =  0xffff - ((stv0288_readreg(state, 0x10) << 8));395 396 397	signal = signal * 5 / 4;398	*strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal;399	dprintk("stv0288_read_signal_strength %d\n", *strength);400 401	return 0;402}403static int stv0288_sleep(struct dvb_frontend *fe)404{405	struct stv0288_state *state = fe->demodulator_priv;406 407	stv0288_writeregI(state, 0x41, 0x84);408	state->initialised = 0;409 410	return 0;411}412static int stv0288_read_snr(struct dvb_frontend *fe, u16 *snr)413{414	struct stv0288_state *state = fe->demodulator_priv;415 416	s32 xsnr = 0xffff - ((stv0288_readreg(state, 0x2d) << 8)417			   | stv0288_readreg(state, 0x2e));418	xsnr = 3 * (xsnr - 0xa100);419	*snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr;420	dprintk("stv0288_read_snr %d\n", *snr);421 422	return 0;423}424 425static int stv0288_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)426{427	struct stv0288_state *state = fe->demodulator_priv;428 429	if (state->errmode != STATUS_BER)430		return 0;431	*ucblocks = (stv0288_readreg(state, 0x26) << 8) |432					stv0288_readreg(state, 0x27);433	dprintk("stv0288_read_ber %d\n", *ucblocks);434 435	return 0;436}437 438static int stv0288_set_frontend(struct dvb_frontend *fe)439{440	struct stv0288_state *state = fe->demodulator_priv;441	struct dtv_frontend_properties *c = &fe->dtv_property_cache;442 443	u8 tda[3], reg, time_out = 0;444	s8 tm;445 446	dprintk("%s : FE_SET_FRONTEND\n", __func__);447 448	if (c->delivery_system != SYS_DVBS) {449		dprintk("%s: unsupported delivery system selected (%d)\n",450			__func__, c->delivery_system);451		return -EOPNOTSUPP;452	}453 454	if (state->config->set_ts_params)455		state->config->set_ts_params(fe, 0);456 457	/* only frequency & symbol_rate are used for tuner*/458	if (fe->ops.tuner_ops.set_params) {459		fe->ops.tuner_ops.set_params(fe);460		if (fe->ops.i2c_gate_ctrl)461			fe->ops.i2c_gate_ctrl(fe, 0);462	}463 464	udelay(10);465	stv0288_set_symbolrate(fe, c->symbol_rate);466	/* Carrier lock control register */467	stv0288_writeregI(state, 0x15, 0xc5);468 469	tda[2] = 0x0; /* CFRL */470	for (tm = -9; tm < 7;) {471		/* Viterbi status */472		reg = stv0288_readreg(state, 0x24);473		if (reg & 0x8)474				break;475		if (reg & 0x80) {476			time_out++;477			if (time_out > 10)478				break;479			tda[2] += 40;480			if (tda[2] < 40)481				tm++;482		} else {483			tm++;484			tda[2] = 0;485			time_out = 0;486		}487		tda[1] = (unsigned char)tm;488		stv0288_writeregI(state, 0x2b, tda[1]);489		stv0288_writeregI(state, 0x2c, tda[2]);490		msleep(30);491	}492	state->tuner_frequency = c->frequency;493	state->fec_inner = FEC_AUTO;494	state->symbol_rate = c->symbol_rate;495 496	return 0;497}498 499static int stv0288_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)500{501	struct stv0288_state *state = fe->demodulator_priv;502 503	if (enable)504		stv0288_writeregI(state, 0x01, 0xb5);505	else506		stv0288_writeregI(state, 0x01, 0x35);507 508	udelay(1);509 510	return 0;511}512 513static void stv0288_release(struct dvb_frontend *fe)514{515	struct stv0288_state *state = fe->demodulator_priv;516	kfree(state);517}518 519static const struct dvb_frontend_ops stv0288_ops = {520	.delsys = { SYS_DVBS },521	.info = {522		.name			= "ST STV0288 DVB-S",523		.frequency_min_hz	=  950 * MHz,524		.frequency_max_hz	= 2150 * MHz,525		.frequency_stepsize_hz	=    1 * MHz,526		.symbol_rate_min	= 1000000,527		.symbol_rate_max	= 45000000,528		.symbol_rate_tolerance	= 500,	/* ppm */529		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |530		      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |531		      FE_CAN_QPSK |532		      FE_CAN_FEC_AUTO533	},534 535	.release = stv0288_release,536	.init = stv0288_init,537	.sleep = stv0288_sleep,538	.write = stv0288_write,539	.i2c_gate_ctrl = stv0288_i2c_gate_ctrl,540	.read_status = stv0288_read_status,541	.read_ber = stv0288_read_ber,542	.read_signal_strength = stv0288_read_signal_strength,543	.read_snr = stv0288_read_snr,544	.read_ucblocks = stv0288_read_ucblocks,545	.diseqc_send_master_cmd = stv0288_send_diseqc_msg,546	.diseqc_send_burst = stv0288_send_diseqc_burst,547	.set_tone = stv0288_set_tone,548	.set_voltage = stv0288_set_voltage,549 550	.set_frontend = stv0288_set_frontend,551};552 553struct dvb_frontend *stv0288_attach(const struct stv0288_config *config,554				    struct i2c_adapter *i2c)555{556	struct stv0288_state *state = NULL;557	int id;558 559	/* allocate memory for the internal state */560	state = kzalloc(sizeof(struct stv0288_state), GFP_KERNEL);561	if (state == NULL)562		goto error;563 564	/* setup the state */565	state->config = config;566	state->i2c = i2c;567	state->initialised = 0;568	state->tuner_frequency = 0;569	state->symbol_rate = 0;570	state->fec_inner = 0;571	state->errmode = STATUS_BER;572 573	stv0288_writeregI(state, 0x41, 0x04);574	msleep(200);575	id = stv0288_readreg(state, 0x00);576	dprintk("stv0288 id %x\n", id);577 578	/* register 0x00 contains 0x11 for STV0288  */579	if (id != 0x11)580		goto error;581 582	/* create dvb_frontend */583	memcpy(&state->frontend.ops, &stv0288_ops,584			sizeof(struct dvb_frontend_ops));585	state->frontend.demodulator_priv = state;586	return &state->frontend;587 588error:589	kfree(state);590 591	return NULL;592}593EXPORT_SYMBOL_GPL(stv0288_attach);594 595module_param(debug_legacy_dish_switch, int, 0444);596MODULE_PARM_DESC(debug_legacy_dish_switch,597		"Enable timing analysis for Dish Network legacy switches");598 599module_param(debug, int, 0644);600MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");601 602MODULE_DESCRIPTION("ST STV0288 DVB Demodulator driver");603MODULE_AUTHOR("Georg Acher, Bob Liu, Igor liplianin");604MODULE_LICENSE("GPL");605 606