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

ves1820.c (10876B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3    VES1820  - Single Chip Cable Channel Receiver driver module
      4
      5    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
      6
      7*/
      8
      9#include <linux/delay.h>
     10#include <linux/errno.h>
     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 <asm/div64.h>
     17
     18#include <media/dvb_frontend.h>
     19#include "ves1820.h"
     20
     21
     22
     23struct ves1820_state {
     24	struct i2c_adapter* i2c;
     25	/* configuration settings */
     26	const struct ves1820_config* config;
     27	struct dvb_frontend frontend;
     28
     29	/* private demodulator data */
     30	u8 reg0;
     31	u8 pwm;
     32};
     33
     34
     35static int verbose;
     36
     37static u8 ves1820_inittab[] = {
     38	0x69, 0x6A, 0x93, 0x1A, 0x12, 0x46, 0x26, 0x1A,
     39	0x43, 0x6A, 0xAA, 0xAA, 0x1E, 0x85, 0x43, 0x20,
     40	0xE0, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00,
     41	0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
     42	0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     43	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     44	0x00, 0x00, 0x00, 0x00, 0x40
     45};
     46
     47static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data)
     48{
     49	u8 buf[] = { 0x00, reg, data };
     50	struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 3 };
     51	int ret;
     52
     53	ret = i2c_transfer(state->i2c, &msg, 1);
     54
     55	if (ret != 1)
     56		printk("ves1820: %s(): writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
     57		       __func__, reg, data, ret);
     58
     59	return (ret != 1) ? -EREMOTEIO : 0;
     60}
     61
     62static u8 ves1820_readreg(struct ves1820_state *state, u8 reg)
     63{
     64	u8 b0[] = { 0x00, reg };
     65	u8 b1[] = { 0 };
     66	struct i2c_msg msg[] = {
     67		{.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 2},
     68		{.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
     69	};
     70	int ret;
     71
     72	ret = i2c_transfer(state->i2c, msg, 2);
     73
     74	if (ret != 2)
     75		printk("ves1820: %s(): readreg error (reg == 0x%02x, ret == %i)\n",
     76		       __func__, reg, ret);
     77
     78	return b1[0];
     79}
     80
     81static int ves1820_setup_reg0(struct ves1820_state *state,
     82			      u8 reg0, enum fe_spectral_inversion inversion)
     83{
     84	reg0 |= state->reg0 & 0x62;
     85
     86	if (INVERSION_ON == inversion) {
     87		if (!state->config->invert) reg0 |= 0x20;
     88		else reg0 &= ~0x20;
     89	} else if (INVERSION_OFF == inversion) {
     90		if (!state->config->invert) reg0 &= ~0x20;
     91		else reg0 |= 0x20;
     92	}
     93
     94	ves1820_writereg(state, 0x00, reg0 & 0xfe);
     95	ves1820_writereg(state, 0x00, reg0 | 0x01);
     96
     97	state->reg0 = reg0;
     98
     99	return 0;
    100}
    101
    102static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate)
    103{
    104	s32 BDR;
    105	s32 BDRI;
    106	s16 SFIL = 0;
    107	u16 NDEC = 0;
    108	u32 ratio;
    109	u32 fin;
    110	u32 tmp;
    111	u64 fptmp;
    112	u64 fpxin;
    113
    114	if (symbolrate > state->config->xin / 2)
    115		symbolrate = state->config->xin / 2;
    116
    117	if (symbolrate < 500000)
    118		symbolrate = 500000;
    119
    120	if (symbolrate < state->config->xin / 16)
    121		NDEC = 1;
    122	if (symbolrate < state->config->xin / 32)
    123		NDEC = 2;
    124	if (symbolrate < state->config->xin / 64)
    125		NDEC = 3;
    126
    127	/* yeuch! */
    128	fpxin = state->config->xin * 10ULL;
    129	fptmp = fpxin; do_div(fptmp, 123);
    130	if (symbolrate < fptmp)
    131		SFIL = 1;
    132	fptmp = fpxin; do_div(fptmp, 160);
    133	if (symbolrate < fptmp)
    134		SFIL = 0;
    135	fptmp = fpxin; do_div(fptmp, 246);
    136	if (symbolrate < fptmp)
    137		SFIL = 1;
    138	fptmp = fpxin; do_div(fptmp, 320);
    139	if (symbolrate < fptmp)
    140		SFIL = 0;
    141	fptmp = fpxin; do_div(fptmp, 492);
    142	if (symbolrate < fptmp)
    143		SFIL = 1;
    144	fptmp = fpxin; do_div(fptmp, 640);
    145	if (symbolrate < fptmp)
    146		SFIL = 0;
    147	fptmp = fpxin; do_div(fptmp, 984);
    148	if (symbolrate < fptmp)
    149		SFIL = 1;
    150
    151	fin = state->config->xin >> 4;
    152	symbolrate <<= NDEC;
    153	ratio = (symbolrate << 4) / fin;
    154	tmp = ((symbolrate << 4) % fin) << 8;
    155	ratio = (ratio << 8) + tmp / fin;
    156	tmp = (tmp % fin) << 8;
    157	ratio = (ratio << 8) + DIV_ROUND_CLOSEST(tmp, fin);
    158
    159	BDR = ratio;
    160	BDRI = (((state->config->xin << 5) / symbolrate) + 1) / 2;
    161
    162	if (BDRI > 0xFF)
    163		BDRI = 0xFF;
    164
    165	SFIL = (SFIL << 4) | ves1820_inittab[0x0E];
    166
    167	NDEC = (NDEC << 6) | ves1820_inittab[0x03];
    168
    169	ves1820_writereg(state, 0x03, NDEC);
    170	ves1820_writereg(state, 0x0a, BDR & 0xff);
    171	ves1820_writereg(state, 0x0b, (BDR >> 8) & 0xff);
    172	ves1820_writereg(state, 0x0c, (BDR >> 16) & 0x3f);
    173
    174	ves1820_writereg(state, 0x0d, BDRI);
    175	ves1820_writereg(state, 0x0e, SFIL);
    176
    177	return 0;
    178}
    179
    180static int ves1820_init(struct dvb_frontend* fe)
    181{
    182	struct ves1820_state* state = fe->demodulator_priv;
    183	int i;
    184
    185	ves1820_writereg(state, 0, 0);
    186
    187	for (i = 0; i < sizeof(ves1820_inittab); i++)
    188		ves1820_writereg(state, i, ves1820_inittab[i]);
    189	if (state->config->selagc)
    190		ves1820_writereg(state, 2, ves1820_inittab[2] | 0x08);
    191
    192	ves1820_writereg(state, 0x34, state->pwm);
    193
    194	return 0;
    195}
    196
    197static int ves1820_set_parameters(struct dvb_frontend *fe)
    198{
    199	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
    200	struct ves1820_state* state = fe->demodulator_priv;
    201	static const u8 reg0x00[] = { 0x00, 0x04, 0x08, 0x0c, 0x10 };
    202	static const u8 reg0x01[] = { 140, 140, 106, 100, 92 };
    203	static const u8 reg0x05[] = { 135, 100, 70, 54, 38 };
    204	static const u8 reg0x08[] = { 162, 116, 67, 52, 35 };
    205	static const u8 reg0x09[] = { 145, 150, 106, 126, 107 };
    206	int real_qam = p->modulation - QAM_16;
    207
    208	if (real_qam < 0 || real_qam > 4)
    209		return -EINVAL;
    210
    211	if (fe->ops.tuner_ops.set_params) {
    212		fe->ops.tuner_ops.set_params(fe);
    213		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
    214	}
    215
    216	ves1820_set_symbolrate(state, p->symbol_rate);
    217	ves1820_writereg(state, 0x34, state->pwm);
    218
    219	ves1820_writereg(state, 0x01, reg0x01[real_qam]);
    220	ves1820_writereg(state, 0x05, reg0x05[real_qam]);
    221	ves1820_writereg(state, 0x08, reg0x08[real_qam]);
    222	ves1820_writereg(state, 0x09, reg0x09[real_qam]);
    223
    224	ves1820_setup_reg0(state, reg0x00[real_qam], p->inversion);
    225	ves1820_writereg(state, 2, ves1820_inittab[2] | (state->config->selagc ? 0x08 : 0));
    226	return 0;
    227}
    228
    229static int ves1820_read_status(struct dvb_frontend *fe,
    230			       enum fe_status *status)
    231{
    232	struct ves1820_state* state = fe->demodulator_priv;
    233	int sync;
    234
    235	*status = 0;
    236	sync = ves1820_readreg(state, 0x11);
    237
    238	if (sync & 1)
    239		*status |= FE_HAS_SIGNAL;
    240
    241	if (sync & 2)
    242		*status |= FE_HAS_CARRIER;
    243
    244	if (sync & 2)	/* XXX FIXME! */
    245		*status |= FE_HAS_VITERBI;
    246
    247	if (sync & 4)
    248		*status |= FE_HAS_SYNC;
    249
    250	if (sync & 8)
    251		*status |= FE_HAS_LOCK;
    252
    253	return 0;
    254}
    255
    256static int ves1820_read_ber(struct dvb_frontend* fe, u32* ber)
    257{
    258	struct ves1820_state* state = fe->demodulator_priv;
    259
    260	u32 _ber = ves1820_readreg(state, 0x14) |
    261			(ves1820_readreg(state, 0x15) << 8) |
    262			((ves1820_readreg(state, 0x16) & 0x0f) << 16);
    263	*ber = 10 * _ber;
    264
    265	return 0;
    266}
    267
    268static int ves1820_read_signal_strength(struct dvb_frontend* fe, u16* strength)
    269{
    270	struct ves1820_state* state = fe->demodulator_priv;
    271
    272	u8 gain = ves1820_readreg(state, 0x17);
    273	*strength = (gain << 8) | gain;
    274
    275	return 0;
    276}
    277
    278static int ves1820_read_snr(struct dvb_frontend* fe, u16* snr)
    279{
    280	struct ves1820_state* state = fe->demodulator_priv;
    281
    282	u8 quality = ~ves1820_readreg(state, 0x18);
    283	*snr = (quality << 8) | quality;
    284
    285	return 0;
    286}
    287
    288static int ves1820_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
    289{
    290	struct ves1820_state* state = fe->demodulator_priv;
    291
    292	*ucblocks = ves1820_readreg(state, 0x13) & 0x7f;
    293	if (*ucblocks == 0x7f)
    294		*ucblocks = 0xffffffff;
    295
    296	/* reset uncorrected block counter */
    297	ves1820_writereg(state, 0x10, ves1820_inittab[0x10] & 0xdf);
    298	ves1820_writereg(state, 0x10, ves1820_inittab[0x10]);
    299
    300	return 0;
    301}
    302
    303static int ves1820_get_frontend(struct dvb_frontend *fe,
    304				struct dtv_frontend_properties *p)
    305{
    306	struct ves1820_state* state = fe->demodulator_priv;
    307	int sync;
    308	s8 afc = 0;
    309
    310	sync = ves1820_readreg(state, 0x11);
    311	afc = ves1820_readreg(state, 0x19);
    312	if (verbose) {
    313		/* AFC only valid when carrier has been recovered */
    314		printk(sync & 2 ? "ves1820: AFC (%d) %dHz\n" :
    315			"ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->symbol_rate * afc) >> 10);
    316	}
    317
    318	if (!state->config->invert) {
    319		p->inversion = (state->reg0 & 0x20) ? INVERSION_ON : INVERSION_OFF;
    320	} else {
    321		p->inversion = (!(state->reg0 & 0x20)) ? INVERSION_ON : INVERSION_OFF;
    322	}
    323
    324	p->modulation = ((state->reg0 >> 2) & 7) + QAM_16;
    325
    326	p->fec_inner = FEC_NONE;
    327
    328	p->frequency = ((p->frequency + 31250) / 62500) * 62500;
    329	if (sync & 2)
    330		p->frequency -= ((s32) p->symbol_rate * afc) >> 10;
    331
    332	return 0;
    333}
    334
    335static int ves1820_sleep(struct dvb_frontend* fe)
    336{
    337	struct ves1820_state* state = fe->demodulator_priv;
    338
    339	ves1820_writereg(state, 0x1b, 0x02);	/* pdown ADC */
    340	ves1820_writereg(state, 0x00, 0x80);	/* standby */
    341
    342	return 0;
    343}
    344
    345static int ves1820_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
    346{
    347
    348	fesettings->min_delay_ms = 200;
    349	fesettings->step_size = 0;
    350	fesettings->max_drift = 0;
    351	return 0;
    352}
    353
    354static void ves1820_release(struct dvb_frontend* fe)
    355{
    356	struct ves1820_state* state = fe->demodulator_priv;
    357	kfree(state);
    358}
    359
    360static const struct dvb_frontend_ops ves1820_ops;
    361
    362struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
    363				    struct i2c_adapter* i2c,
    364				    u8 pwm)
    365{
    366	struct ves1820_state* state = NULL;
    367
    368	/* allocate memory for the internal state */
    369	state = kzalloc(sizeof(struct ves1820_state), GFP_KERNEL);
    370	if (state == NULL)
    371		goto error;
    372
    373	/* setup the state */
    374	state->reg0 = ves1820_inittab[0];
    375	state->config = config;
    376	state->i2c = i2c;
    377	state->pwm = pwm;
    378
    379	/* check if the demod is there */
    380	if ((ves1820_readreg(state, 0x1a) & 0xf0) != 0x70)
    381		goto error;
    382
    383	if (verbose)
    384		printk("ves1820: pwm=0x%02x\n", state->pwm);
    385
    386	/* create dvb_frontend */
    387	memcpy(&state->frontend.ops, &ves1820_ops, sizeof(struct dvb_frontend_ops));
    388	state->frontend.ops.info.symbol_rate_min = (state->config->xin / 2) / 64;      /* SACLK/64 == (XIN/2)/64 */
    389	state->frontend.ops.info.symbol_rate_max = (state->config->xin / 2) / 4;       /* SACLK/4 */
    390	state->frontend.demodulator_priv = state;
    391
    392	return &state->frontend;
    393
    394error:
    395	kfree(state);
    396	return NULL;
    397}
    398
    399static const struct dvb_frontend_ops ves1820_ops = {
    400	.delsys = { SYS_DVBC_ANNEX_A },
    401	.info = {
    402		.name = "VLSI VES1820 DVB-C",
    403		.frequency_min_hz =  47 * MHz,
    404		.frequency_max_hz = 862 * MHz,
    405		.frequency_stepsize_hz = 62500,
    406		.caps = FE_CAN_QAM_16 |
    407			FE_CAN_QAM_32 |
    408			FE_CAN_QAM_64 |
    409			FE_CAN_QAM_128 |
    410			FE_CAN_QAM_256 |
    411			FE_CAN_FEC_AUTO
    412	},
    413
    414	.release = ves1820_release,
    415
    416	.init = ves1820_init,
    417	.sleep = ves1820_sleep,
    418
    419	.set_frontend = ves1820_set_parameters,
    420	.get_frontend = ves1820_get_frontend,
    421	.get_tune_settings = ves1820_get_tune_settings,
    422
    423	.read_status = ves1820_read_status,
    424	.read_ber = ves1820_read_ber,
    425	.read_signal_strength = ves1820_read_signal_strength,
    426	.read_snr = ves1820_read_snr,
    427	.read_ucblocks = ves1820_read_ucblocks,
    428};
    429
    430module_param(verbose, int, 0644);
    431MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting");
    432
    433MODULE_DESCRIPTION("VLSI VES1820 DVB-C Demodulator driver");
    434MODULE_AUTHOR("Ralph Metzler, Holger Waechtler");
    435MODULE_LICENSE("GPL");
    436
    437EXPORT_SYMBOL(ves1820_attach);