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

mxl301rf.c (7842B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * MaxLinear MxL301RF OFDM tuner driver
      4 *
      5 * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
      6 */
      7
      8/*
      9 * NOTICE:
     10 * This driver is incomplete and lacks init/config of the chips,
     11 * as the necessary info is not disclosed.
     12 * Other features like get_if_frequency() are missing as well.
     13 * It assumes that users of this driver (such as a PCI bridge of
     14 * DTV receiver cards) properly init and configure the chip
     15 * via I2C *before* calling this driver's init() function.
     16 *
     17 * Currently, PT3 driver is the only one that uses this driver,
     18 * and contains init/config code in its firmware.
     19 * Thus some part of the code might be dependent on PT3 specific config.
     20 */
     21
     22#include <linux/kernel.h>
     23#include "mxl301rf.h"
     24
     25struct mxl301rf_state {
     26	struct mxl301rf_config cfg;
     27	struct i2c_client *i2c;
     28};
     29
     30static struct mxl301rf_state *cfg_to_state(struct mxl301rf_config *c)
     31{
     32	return container_of(c, struct mxl301rf_state, cfg);
     33}
     34
     35static int raw_write(struct mxl301rf_state *state, const u8 *buf, int len)
     36{
     37	int ret;
     38
     39	ret = i2c_master_send(state->i2c, buf, len);
     40	if (ret >= 0 && ret < len)
     41		ret = -EIO;
     42	return (ret == len) ? 0 : ret;
     43}
     44
     45static int reg_write(struct mxl301rf_state *state, u8 reg, u8 val)
     46{
     47	u8 buf[2] = { reg, val };
     48
     49	return raw_write(state, buf, 2);
     50}
     51
     52static int reg_read(struct mxl301rf_state *state, u8 reg, u8 *val)
     53{
     54	u8 wbuf[2] = { 0xfb, reg };
     55	int ret;
     56
     57	ret = raw_write(state, wbuf, sizeof(wbuf));
     58	if (ret == 0)
     59		ret = i2c_master_recv(state->i2c, val, 1);
     60	if (ret >= 0 && ret < 1)
     61		ret = -EIO;
     62	return (ret == 1) ? 0 : ret;
     63}
     64
     65/* tuner_ops */
     66
     67/* get RSSI and update propery cache, set to *out in % */
     68static int mxl301rf_get_rf_strength(struct dvb_frontend *fe, u16 *out)
     69{
     70	struct mxl301rf_state *state;
     71	int ret;
     72	u8  rf_in1, rf_in2, rf_off1, rf_off2;
     73	u16 rf_in, rf_off;
     74	s64 level;
     75	struct dtv_fe_stats *rssi;
     76
     77	rssi = &fe->dtv_property_cache.strength;
     78	rssi->len = 1;
     79	rssi->stat[0].scale = FE_SCALE_NOT_AVAILABLE;
     80	*out = 0;
     81
     82	state = fe->tuner_priv;
     83	ret = reg_write(state, 0x14, 0x01);
     84	if (ret < 0)
     85		return ret;
     86	usleep_range(1000, 2000);
     87
     88	ret = reg_read(state, 0x18, &rf_in1);
     89	if (ret == 0)
     90		ret = reg_read(state, 0x19, &rf_in2);
     91	if (ret == 0)
     92		ret = reg_read(state, 0xd6, &rf_off1);
     93	if (ret == 0)
     94		ret = reg_read(state, 0xd7, &rf_off2);
     95	if (ret != 0)
     96		return ret;
     97
     98	rf_in = (rf_in2 & 0x07) << 8 | rf_in1;
     99	rf_off = (rf_off2 & 0x0f) << 5 | (rf_off1 >> 3);
    100	level = rf_in - rf_off - (113 << 3); /* x8 dBm */
    101	level = level * 1000 / 8;
    102	rssi->stat[0].svalue = level;
    103	rssi->stat[0].scale = FE_SCALE_DECIBEL;
    104	/* *out = (level - min) * 100 / (max - min) */
    105	*out = (rf_in - rf_off + (1 << 9) - 1) * 100 / ((5 << 9) - 2);
    106	return 0;
    107}
    108
    109/* spur shift parameters */
    110struct shf {
    111	u32	freq;		/* Channel center frequency */
    112	u32	ofst_th;	/* Offset frequency threshold */
    113	u8	shf_val;	/* Spur shift value */
    114	u8	shf_dir;	/* Spur shift direction */
    115};
    116
    117static const struct shf shf_tab[] = {
    118	{  64500, 500, 0x92, 0x07 },
    119	{ 191500, 300, 0xe2, 0x07 },
    120	{ 205500, 500, 0x2c, 0x04 },
    121	{ 212500, 500, 0x1e, 0x04 },
    122	{ 226500, 500, 0xd4, 0x07 },
    123	{  99143, 500, 0x9c, 0x07 },
    124	{ 173143, 500, 0xd4, 0x07 },
    125	{ 191143, 300, 0xd4, 0x07 },
    126	{ 207143, 500, 0xce, 0x07 },
    127	{ 225143, 500, 0xce, 0x07 },
    128	{ 243143, 500, 0xd4, 0x07 },
    129	{ 261143, 500, 0xd4, 0x07 },
    130	{ 291143, 500, 0xd4, 0x07 },
    131	{ 339143, 500, 0x2c, 0x04 },
    132	{ 117143, 500, 0x7a, 0x07 },
    133	{ 135143, 300, 0x7a, 0x07 },
    134	{ 153143, 500, 0x01, 0x07 }
    135};
    136
    137struct reg_val {
    138	u8 reg;
    139	u8 val;
    140} __attribute__ ((__packed__));
    141
    142static const struct reg_val set_idac[] = {
    143	{ 0x0d, 0x00 },
    144	{ 0x0c, 0x67 },
    145	{ 0x6f, 0x89 },
    146	{ 0x70, 0x0c },
    147	{ 0x6f, 0x8a },
    148	{ 0x70, 0x0e },
    149	{ 0x6f, 0x8b },
    150	{ 0x70, 0x1c },
    151};
    152
    153static int mxl301rf_set_params(struct dvb_frontend *fe)
    154{
    155	struct reg_val tune0[] = {
    156		{ 0x13, 0x00 },		/* abort tuning */
    157		{ 0x3b, 0xc0 },
    158		{ 0x3b, 0x80 },
    159		{ 0x10, 0x95 },		/* BW */
    160		{ 0x1a, 0x05 },
    161		{ 0x61, 0x00 },		/* spur shift value (placeholder) */
    162		{ 0x62, 0xa0 }		/* spur shift direction (placeholder) */
    163	};
    164
    165	struct reg_val tune1[] = {
    166		{ 0x11, 0x40 },		/* RF frequency L (placeholder) */
    167		{ 0x12, 0x0e },		/* RF frequency H (placeholder) */
    168		{ 0x13, 0x01 }		/* start tune */
    169	};
    170
    171	struct mxl301rf_state *state;
    172	u32 freq;
    173	u16 f;
    174	u32 tmp, div;
    175	int i, ret;
    176
    177	state = fe->tuner_priv;
    178	freq = fe->dtv_property_cache.frequency;
    179
    180	/* spur shift function (for analog) */
    181	for (i = 0; i < ARRAY_SIZE(shf_tab); i++) {
    182		if (freq >= (shf_tab[i].freq - shf_tab[i].ofst_th) * 1000 &&
    183		    freq <= (shf_tab[i].freq + shf_tab[i].ofst_th) * 1000) {
    184			tune0[5].val = shf_tab[i].shf_val;
    185			tune0[6].val = 0xa0 | shf_tab[i].shf_dir;
    186			break;
    187		}
    188	}
    189	ret = raw_write(state, (u8 *) tune0, sizeof(tune0));
    190	if (ret < 0)
    191		goto failed;
    192	usleep_range(3000, 4000);
    193
    194	/* convert freq to 10.6 fixed point float [MHz] */
    195	f = freq / 1000000;
    196	tmp = freq % 1000000;
    197	div = 1000000;
    198	for (i = 0; i < 6; i++) {
    199		f <<= 1;
    200		div >>= 1;
    201		if (tmp > div) {
    202			tmp -= div;
    203			f |= 1;
    204		}
    205	}
    206	if (tmp > 7812)
    207		f++;
    208	tune1[0].val = f & 0xff;
    209	tune1[1].val = f >> 8;
    210	ret = raw_write(state, (u8 *) tune1, sizeof(tune1));
    211	if (ret < 0)
    212		goto failed;
    213	msleep(31);
    214
    215	ret = reg_write(state, 0x1a, 0x0d);
    216	if (ret < 0)
    217		goto failed;
    218	ret = raw_write(state, (u8 *) set_idac, sizeof(set_idac));
    219	if (ret < 0)
    220		goto failed;
    221	return 0;
    222
    223failed:
    224	dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
    225		__func__, fe->dvb->num, fe->id);
    226	return ret;
    227}
    228
    229static const struct reg_val standby_data[] = {
    230	{ 0x01, 0x00 },
    231	{ 0x13, 0x00 }
    232};
    233
    234static int mxl301rf_sleep(struct dvb_frontend *fe)
    235{
    236	struct mxl301rf_state *state;
    237	int ret;
    238
    239	state = fe->tuner_priv;
    240	ret = raw_write(state, (u8 *)standby_data, sizeof(standby_data));
    241	if (ret < 0)
    242		dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
    243			__func__, fe->dvb->num, fe->id);
    244	return ret;
    245}
    246
    247
    248/* init sequence is not public.
    249 * the parent must have init'ed the device.
    250 * just wake up here.
    251 */
    252static int mxl301rf_init(struct dvb_frontend *fe)
    253{
    254	struct mxl301rf_state *state;
    255	int ret;
    256
    257	state = fe->tuner_priv;
    258
    259	ret = reg_write(state, 0x01, 0x01);
    260	if (ret < 0) {
    261		dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
    262			 __func__, fe->dvb->num, fe->id);
    263		return ret;
    264	}
    265	return 0;
    266}
    267
    268/* I2C driver functions */
    269
    270static const struct dvb_tuner_ops mxl301rf_ops = {
    271	.info = {
    272		.name = "MaxLinear MxL301RF",
    273
    274		.frequency_min_hz =  93 * MHz,
    275		.frequency_max_hz = 803 * MHz + 142857,
    276	},
    277
    278	.init = mxl301rf_init,
    279	.sleep = mxl301rf_sleep,
    280
    281	.set_params = mxl301rf_set_params,
    282	.get_rf_strength = mxl301rf_get_rf_strength,
    283};
    284
    285
    286static int mxl301rf_probe(struct i2c_client *client,
    287			  const struct i2c_device_id *id)
    288{
    289	struct mxl301rf_state *state;
    290	struct mxl301rf_config *cfg;
    291	struct dvb_frontend *fe;
    292
    293	state = kzalloc(sizeof(*state), GFP_KERNEL);
    294	if (!state)
    295		return -ENOMEM;
    296
    297	state->i2c = client;
    298	cfg = client->dev.platform_data;
    299
    300	memcpy(&state->cfg, cfg, sizeof(state->cfg));
    301	fe = cfg->fe;
    302	fe->tuner_priv = state;
    303	memcpy(&fe->ops.tuner_ops, &mxl301rf_ops, sizeof(mxl301rf_ops));
    304
    305	i2c_set_clientdata(client, &state->cfg);
    306	dev_info(&client->dev, "MaxLinear MxL301RF attached.\n");
    307	return 0;
    308}
    309
    310static int mxl301rf_remove(struct i2c_client *client)
    311{
    312	struct mxl301rf_state *state;
    313
    314	state = cfg_to_state(i2c_get_clientdata(client));
    315	state->cfg.fe->tuner_priv = NULL;
    316	kfree(state);
    317	return 0;
    318}
    319
    320
    321static const struct i2c_device_id mxl301rf_id[] = {
    322	{"mxl301rf", 0},
    323	{}
    324};
    325MODULE_DEVICE_TABLE(i2c, mxl301rf_id);
    326
    327static struct i2c_driver mxl301rf_driver = {
    328	.driver = {
    329		.name	= "mxl301rf",
    330	},
    331	.probe		= mxl301rf_probe,
    332	.remove		= mxl301rf_remove,
    333	.id_table	= mxl301rf_id,
    334};
    335
    336module_i2c_driver(mxl301rf_driver);
    337
    338MODULE_DESCRIPTION("MaxLinear MXL301RF tuner");
    339MODULE_AUTHOR("Akihiro TSUKADA");
    340MODULE_LICENSE("GPL");