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

tda18218.c (8205B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * NXP TDA18218HN silicon tuner driver
      4 *
      5 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
      6 */
      7
      8#include "tda18218_priv.h"
      9
     10/* Max transfer size done by I2C transfer functions */
     11#define MAX_XFER_SIZE  64
     12
     13/* write multiple registers */
     14static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
     15{
     16	int ret = 0, len2, remaining;
     17	u8 buf[MAX_XFER_SIZE];
     18	struct i2c_msg msg[1] = {
     19		{
     20			.addr = priv->cfg->i2c_address,
     21			.flags = 0,
     22			.buf = buf,
     23		}
     24	};
     25
     26	if (1 + len > sizeof(buf)) {
     27		dev_warn(&priv->i2c->dev,
     28			 "%s: i2c wr reg=%04x: len=%d is too big!\n",
     29			 KBUILD_MODNAME, reg, len);
     30		return -EINVAL;
     31	}
     32
     33	for (remaining = len; remaining > 0;
     34			remaining -= (priv->cfg->i2c_wr_max - 1)) {
     35		len2 = remaining;
     36		if (len2 > (priv->cfg->i2c_wr_max - 1))
     37			len2 = (priv->cfg->i2c_wr_max - 1);
     38
     39		msg[0].len = 1 + len2;
     40		buf[0] = reg + len - remaining;
     41		memcpy(&buf[1], &val[len - remaining], len2);
     42
     43		ret = i2c_transfer(priv->i2c, msg, 1);
     44		if (ret != 1)
     45			break;
     46	}
     47
     48	if (ret == 1) {
     49		ret = 0;
     50	} else {
     51		dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \
     52				"len=%d\n", KBUILD_MODNAME, ret, reg, len);
     53		ret = -EREMOTEIO;
     54	}
     55
     56	return ret;
     57}
     58
     59/* read multiple registers */
     60static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
     61{
     62	int ret;
     63	u8 buf[MAX_XFER_SIZE]; /* we must start read always from reg 0x00 */
     64	struct i2c_msg msg[2] = {
     65		{
     66			.addr = priv->cfg->i2c_address,
     67			.flags = 0,
     68			.len = 1,
     69			.buf = "\x00",
     70		}, {
     71			.addr = priv->cfg->i2c_address,
     72			.flags = I2C_M_RD,
     73			.len = reg + len,
     74			.buf = buf,
     75		}
     76	};
     77
     78	if (reg + len > sizeof(buf)) {
     79		dev_warn(&priv->i2c->dev,
     80			 "%s: i2c wr reg=%04x: len=%d is too big!\n",
     81			 KBUILD_MODNAME, reg, len);
     82		return -EINVAL;
     83	}
     84
     85	ret = i2c_transfer(priv->i2c, msg, 2);
     86	if (ret == 2) {
     87		memcpy(val, &buf[reg], len);
     88		ret = 0;
     89	} else {
     90		dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \
     91				"len=%d\n", KBUILD_MODNAME, ret, reg, len);
     92		ret = -EREMOTEIO;
     93	}
     94
     95	return ret;
     96}
     97
     98/* write single register */
     99static int tda18218_wr_reg(struct tda18218_priv *priv, u8 reg, u8 val)
    100{
    101	return tda18218_wr_regs(priv, reg, &val, 1);
    102}
    103
    104/* read single register */
    105
    106static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val)
    107{
    108	return tda18218_rd_regs(priv, reg, val, 1);
    109}
    110
    111static int tda18218_set_params(struct dvb_frontend *fe)
    112{
    113	struct tda18218_priv *priv = fe->tuner_priv;
    114	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
    115	u32 bw = c->bandwidth_hz;
    116	int ret;
    117	u8 buf[3], i, BP_Filter, LP_Fc;
    118	u32 LO_Frac;
    119	/* TODO: find out correct AGC algorithm */
    120	u8 agc[][2] = {
    121		{ R20_AGC11, 0x60 },
    122		{ R23_AGC21, 0x02 },
    123		{ R20_AGC11, 0xa0 },
    124		{ R23_AGC21, 0x09 },
    125		{ R20_AGC11, 0xe0 },
    126		{ R23_AGC21, 0x0c },
    127		{ R20_AGC11, 0x40 },
    128		{ R23_AGC21, 0x01 },
    129		{ R20_AGC11, 0x80 },
    130		{ R23_AGC21, 0x08 },
    131		{ R20_AGC11, 0xc0 },
    132		{ R23_AGC21, 0x0b },
    133		{ R24_AGC22, 0x1c },
    134		{ R24_AGC22, 0x0c },
    135	};
    136
    137	if (fe->ops.i2c_gate_ctrl)
    138		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
    139
    140	/* low-pass filter cut-off frequency */
    141	if (bw <= 6000000) {
    142		LP_Fc = 0;
    143		priv->if_frequency = 3000000;
    144	} else if (bw <= 7000000) {
    145		LP_Fc = 1;
    146		priv->if_frequency = 3500000;
    147	} else {
    148		LP_Fc = 2;
    149		priv->if_frequency = 4000000;
    150	}
    151
    152	LO_Frac = c->frequency + priv->if_frequency;
    153
    154	/* band-pass filter */
    155	if (LO_Frac < 188000000)
    156		BP_Filter = 3;
    157	else if (LO_Frac < 253000000)
    158		BP_Filter = 4;
    159	else if (LO_Frac < 343000000)
    160		BP_Filter = 5;
    161	else
    162		BP_Filter = 6;
    163
    164	buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */
    165	buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */
    166	buf[2] = priv->regs[R1C_AGC2B];
    167	ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3);
    168	if (ret)
    169		goto error;
    170
    171	buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */
    172	buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */
    173	buf[2] = (LO_Frac / 1000) << 4 |
    174		(priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */
    175	ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3);
    176	if (ret)
    177		goto error;
    178
    179	buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */
    180	ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
    181	if (ret)
    182		goto error;
    183
    184	buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */
    185	ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
    186	if (ret)
    187		goto error;
    188
    189	/* trigger AGC */
    190	for (i = 0; i < ARRAY_SIZE(agc); i++) {
    191		ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]);
    192		if (ret)
    193			goto error;
    194	}
    195
    196error:
    197	if (fe->ops.i2c_gate_ctrl)
    198		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
    199
    200	if (ret)
    201		dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
    202
    203	return ret;
    204}
    205
    206static int tda18218_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
    207{
    208	struct tda18218_priv *priv = fe->tuner_priv;
    209	*frequency = priv->if_frequency;
    210	dev_dbg(&priv->i2c->dev, "%s: if_frequency=%d\n", __func__, *frequency);
    211	return 0;
    212}
    213
    214static int tda18218_sleep(struct dvb_frontend *fe)
    215{
    216	struct tda18218_priv *priv = fe->tuner_priv;
    217	int ret;
    218
    219	if (fe->ops.i2c_gate_ctrl)
    220		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
    221
    222	/* standby */
    223	ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
    224
    225	if (fe->ops.i2c_gate_ctrl)
    226		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
    227
    228	if (ret)
    229		dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
    230
    231	return ret;
    232}
    233
    234static int tda18218_init(struct dvb_frontend *fe)
    235{
    236	struct tda18218_priv *priv = fe->tuner_priv;
    237	int ret;
    238
    239	/* TODO: calibrations */
    240
    241	if (fe->ops.i2c_gate_ctrl)
    242		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
    243
    244	ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS);
    245
    246	if (fe->ops.i2c_gate_ctrl)
    247		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
    248
    249	if (ret)
    250		dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
    251
    252	return ret;
    253}
    254
    255static void tda18218_release(struct dvb_frontend *fe)
    256{
    257	kfree(fe->tuner_priv);
    258	fe->tuner_priv = NULL;
    259}
    260
    261static const struct dvb_tuner_ops tda18218_tuner_ops = {
    262	.info = {
    263		.name              = "NXP TDA18218",
    264
    265		.frequency_min_hz  = 174 * MHz,
    266		.frequency_max_hz  = 864 * MHz,
    267		.frequency_step_hz =   1 * kHz,
    268	},
    269
    270	.release       = tda18218_release,
    271	.init          = tda18218_init,
    272	.sleep         = tda18218_sleep,
    273
    274	.set_params    = tda18218_set_params,
    275
    276	.get_if_frequency = tda18218_get_if_frequency,
    277};
    278
    279struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
    280	struct i2c_adapter *i2c, struct tda18218_config *cfg)
    281{
    282	struct tda18218_priv *priv = NULL;
    283	u8 val;
    284	int ret;
    285	/* chip default registers values */
    286	static u8 def_regs[] = {
    287		0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40,
    288		0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00,
    289		0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01,
    290		0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9,
    291		0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00,
    292		0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6
    293	};
    294
    295	priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL);
    296	if (priv == NULL)
    297		return NULL;
    298
    299	priv->cfg = cfg;
    300	priv->i2c = i2c;
    301	fe->tuner_priv = priv;
    302
    303	if (fe->ops.i2c_gate_ctrl)
    304		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
    305
    306	/* check if the tuner is there */
    307	ret = tda18218_rd_reg(priv, R00_ID, &val);
    308	if (!ret)
    309		dev_dbg(&priv->i2c->dev, "%s: chip id=%02x\n", __func__, val);
    310	if (ret || val != def_regs[R00_ID]) {
    311		kfree(priv);
    312		return NULL;
    313	}
    314
    315	dev_info(&priv->i2c->dev,
    316			"%s: NXP TDA18218HN successfully identified\n",
    317			KBUILD_MODNAME);
    318
    319	memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops,
    320		sizeof(struct dvb_tuner_ops));
    321	memcpy(priv->regs, def_regs, sizeof(def_regs));
    322
    323	/* loop-through enabled chip default register values */
    324	if (priv->cfg->loop_through) {
    325		priv->regs[R17_PD1] = 0xb0;
    326		priv->regs[R18_PD2] = 0x59;
    327	}
    328
    329	/* standby */
    330	ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
    331	if (ret)
    332		dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
    333
    334	if (fe->ops.i2c_gate_ctrl)
    335		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
    336
    337	return fe;
    338}
    339EXPORT_SYMBOL(tda18218_attach);
    340
    341MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver");
    342MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
    343MODULE_LICENSE("GPL");