cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

stv0288.c (13072B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3	Driver for ST STV0288 demodulator
      4	Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de
      5		for Reel Multimedia
      6	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 some
      9		procedures.
     10	2010-09-01 Josef Pavlik <josef@pavlik.it>
     11		Fixed diseqc_msg, diseqc_burst and set_tone problems
     12
     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 0
     40#define STATUS_UCBLOCKS 1
     41
     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 = 2
     60	};
     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 = 1
     92		}, {
     93			.addr = state->config->demod_address,
     94			.flags = I2C_M_RD,
     95			.buf = b1,
     96			.len = 1
     97		}
     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	char tm;
    444	unsigned char tda[3];
    445	u8 reg, time_out = 0;
    446
    447	dprintk("%s : FE_SET_FRONTEND\n", __func__);
    448
    449	if (c->delivery_system != SYS_DVBS) {
    450		dprintk("%s: unsupported delivery system selected (%d)\n",
    451			__func__, c->delivery_system);
    452		return -EOPNOTSUPP;
    453	}
    454
    455	if (state->config->set_ts_params)
    456		state->config->set_ts_params(fe, 0);
    457
    458	/* only frequency & symbol_rate are used for tuner*/
    459	if (fe->ops.tuner_ops.set_params) {
    460		fe->ops.tuner_ops.set_params(fe);
    461		if (fe->ops.i2c_gate_ctrl)
    462			fe->ops.i2c_gate_ctrl(fe, 0);
    463	}
    464
    465	udelay(10);
    466	stv0288_set_symbolrate(fe, c->symbol_rate);
    467	/* Carrier lock control register */
    468	stv0288_writeregI(state, 0x15, 0xc5);
    469
    470	tda[2] = 0x0; /* CFRL */
    471	for (tm = -9; tm < 7;) {
    472		/* Viterbi status */
    473		reg = stv0288_readreg(state, 0x24);
    474		if (reg & 0x8)
    475				break;
    476		if (reg & 0x80) {
    477			time_out++;
    478			if (time_out > 10)
    479				break;
    480			tda[2] += 40;
    481			if (tda[2] < 40)
    482				tm++;
    483		} else {
    484			tm++;
    485			tda[2] = 0;
    486			time_out = 0;
    487		}
    488		tda[1] = (unsigned char)tm;
    489		stv0288_writeregI(state, 0x2b, tda[1]);
    490		stv0288_writeregI(state, 0x2c, tda[2]);
    491		msleep(30);
    492	}
    493	state->tuner_frequency = c->frequency;
    494	state->fec_inner = FEC_AUTO;
    495	state->symbol_rate = c->symbol_rate;
    496
    497	return 0;
    498}
    499
    500static int stv0288_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
    501{
    502	struct stv0288_state *state = fe->demodulator_priv;
    503
    504	if (enable)
    505		stv0288_writeregI(state, 0x01, 0xb5);
    506	else
    507		stv0288_writeregI(state, 0x01, 0x35);
    508
    509	udelay(1);
    510
    511	return 0;
    512}
    513
    514static void stv0288_release(struct dvb_frontend *fe)
    515{
    516	struct stv0288_state *state = fe->demodulator_priv;
    517	kfree(state);
    518}
    519
    520static const struct dvb_frontend_ops stv0288_ops = {
    521	.delsys = { SYS_DVBS },
    522	.info = {
    523		.name			= "ST STV0288 DVB-S",
    524		.frequency_min_hz	=  950 * MHz,
    525		.frequency_max_hz	= 2150 * MHz,
    526		.frequency_stepsize_hz	=    1 * MHz,
    527		.symbol_rate_min	= 1000000,
    528		.symbol_rate_max	= 45000000,
    529		.symbol_rate_tolerance	= 500,	/* ppm */
    530		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
    531		      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
    532		      FE_CAN_QPSK |
    533		      FE_CAN_FEC_AUTO
    534	},
    535
    536	.release = stv0288_release,
    537	.init = stv0288_init,
    538	.sleep = stv0288_sleep,
    539	.write = stv0288_write,
    540	.i2c_gate_ctrl = stv0288_i2c_gate_ctrl,
    541	.read_status = stv0288_read_status,
    542	.read_ber = stv0288_read_ber,
    543	.read_signal_strength = stv0288_read_signal_strength,
    544	.read_snr = stv0288_read_snr,
    545	.read_ucblocks = stv0288_read_ucblocks,
    546	.diseqc_send_master_cmd = stv0288_send_diseqc_msg,
    547	.diseqc_send_burst = stv0288_send_diseqc_burst,
    548	.set_tone = stv0288_set_tone,
    549	.set_voltage = stv0288_set_voltage,
    550
    551	.set_frontend = stv0288_set_frontend,
    552};
    553
    554struct dvb_frontend *stv0288_attach(const struct stv0288_config *config,
    555				    struct i2c_adapter *i2c)
    556{
    557	struct stv0288_state *state = NULL;
    558	int id;
    559
    560	/* allocate memory for the internal state */
    561	state = kzalloc(sizeof(struct stv0288_state), GFP_KERNEL);
    562	if (state == NULL)
    563		goto error;
    564
    565	/* setup the state */
    566	state->config = config;
    567	state->i2c = i2c;
    568	state->initialised = 0;
    569	state->tuner_frequency = 0;
    570	state->symbol_rate = 0;
    571	state->fec_inner = 0;
    572	state->errmode = STATUS_BER;
    573
    574	stv0288_writeregI(state, 0x41, 0x04);
    575	msleep(200);
    576	id = stv0288_readreg(state, 0x00);
    577	dprintk("stv0288 id %x\n", id);
    578
    579	/* register 0x00 contains 0x11 for STV0288  */
    580	if (id != 0x11)
    581		goto error;
    582
    583	/* create dvb_frontend */
    584	memcpy(&state->frontend.ops, &stv0288_ops,
    585			sizeof(struct dvb_frontend_ops));
    586	state->frontend.demodulator_priv = state;
    587	return &state->frontend;
    588
    589error:
    590	kfree(state);
    591
    592	return NULL;
    593}
    594EXPORT_SYMBOL(stv0288_attach);
    595
    596module_param(debug_legacy_dish_switch, int, 0444);
    597MODULE_PARM_DESC(debug_legacy_dish_switch,
    598		"Enable timing analysis for Dish Network legacy switches");
    599
    600module_param(debug, int, 0644);
    601MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
    602
    603MODULE_DESCRIPTION("ST STV0288 DVB Demodulator driver");
    604MODULE_AUTHOR("Georg Acher, Bob Liu, Igor liplianin");
    605MODULE_LICENSE("GPL");
    606