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

dib0070.c (20499B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
      4 *
      5 * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/)
      6 *
      7 * This code is more or less generated from another driver, please
      8 * excuse some codingstyle oddities.
      9 */
     10
     11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     12
     13#include <linux/kernel.h>
     14#include <linux/slab.h>
     15#include <linux/i2c.h>
     16#include <linux/mutex.h>
     17
     18#include <media/dvb_frontend.h>
     19
     20#include "dib0070.h"
     21#include "dibx000_common.h"
     22
     23static int debug;
     24module_param(debug, int, 0644);
     25MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
     26
     27#define dprintk(fmt, arg...) do {					\
     28	if (debug)							\
     29		printk(KERN_DEBUG pr_fmt("%s: " fmt),			\
     30		       __func__, ##arg);				\
     31} while (0)
     32
     33#define DIB0070_P1D  0x00
     34#define DIB0070_P1F  0x01
     35#define DIB0070_P1G  0x03
     36#define DIB0070S_P1A 0x02
     37
     38struct dib0070_state {
     39	struct i2c_adapter *i2c;
     40	struct dvb_frontend *fe;
     41	const struct dib0070_config *cfg;
     42	u16 wbd_ff_offset;
     43	u8 revision;
     44
     45	enum frontend_tune_state tune_state;
     46	u32 current_rf;
     47
     48	/* for the captrim binary search */
     49	s8 step;
     50	u16 adc_diff;
     51
     52	s8 captrim;
     53	s8 fcaptrim;
     54	u16 lo4;
     55
     56	const struct dib0070_tuning *current_tune_table_index;
     57	const struct dib0070_lna_match *lna_match;
     58
     59	u8  wbd_gain_current;
     60	u16 wbd_offset_3_3[2];
     61
     62	/* for the I2C transfer */
     63	struct i2c_msg msg[2];
     64	u8 i2c_write_buffer[3];
     65	u8 i2c_read_buffer[2];
     66	struct mutex i2c_buffer_lock;
     67};
     68
     69static u16 dib0070_read_reg(struct dib0070_state *state, u8 reg)
     70{
     71	u16 ret;
     72
     73	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
     74		dprintk("could not acquire lock\n");
     75		return 0;
     76	}
     77
     78	state->i2c_write_buffer[0] = reg;
     79
     80	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
     81	state->msg[0].addr = state->cfg->i2c_address;
     82	state->msg[0].flags = 0;
     83	state->msg[0].buf = state->i2c_write_buffer;
     84	state->msg[0].len = 1;
     85	state->msg[1].addr = state->cfg->i2c_address;
     86	state->msg[1].flags = I2C_M_RD;
     87	state->msg[1].buf = state->i2c_read_buffer;
     88	state->msg[1].len = 2;
     89
     90	if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
     91		pr_warn("DiB0070 I2C read failed\n");
     92		ret = 0;
     93	} else
     94		ret = (state->i2c_read_buffer[0] << 8)
     95			| state->i2c_read_buffer[1];
     96
     97	mutex_unlock(&state->i2c_buffer_lock);
     98	return ret;
     99}
    100
    101static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
    102{
    103	int ret;
    104
    105	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
    106		dprintk("could not acquire lock\n");
    107		return -EINVAL;
    108	}
    109	state->i2c_write_buffer[0] = reg;
    110	state->i2c_write_buffer[1] = val >> 8;
    111	state->i2c_write_buffer[2] = val & 0xff;
    112
    113	memset(state->msg, 0, sizeof(struct i2c_msg));
    114	state->msg[0].addr = state->cfg->i2c_address;
    115	state->msg[0].flags = 0;
    116	state->msg[0].buf = state->i2c_write_buffer;
    117	state->msg[0].len = 3;
    118
    119	if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
    120		pr_warn("DiB0070 I2C write failed\n");
    121		ret = -EREMOTEIO;
    122	} else
    123		ret = 0;
    124
    125	mutex_unlock(&state->i2c_buffer_lock);
    126	return ret;
    127}
    128
    129#define HARD_RESET(state) do { \
    130    state->cfg->sleep(state->fe, 0); \
    131    if (state->cfg->reset) { \
    132	state->cfg->reset(state->fe,1); msleep(10); \
    133	state->cfg->reset(state->fe,0); msleep(10); \
    134    } \
    135} while (0)
    136
    137static int dib0070_set_bandwidth(struct dvb_frontend *fe)
    138	{
    139	struct dib0070_state *state = fe->tuner_priv;
    140	u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff;
    141
    142	if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 7000)
    143		tmp |= (0 << 14);
    144	else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 6000)
    145		tmp |= (1 << 14);
    146	else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 5000)
    147		tmp |= (2 << 14);
    148	else
    149		tmp |= (3 << 14);
    150
    151	dib0070_write_reg(state, 0x02, tmp);
    152
    153	/* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */
    154	if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) {
    155		u16 value = dib0070_read_reg(state, 0x17);
    156
    157		dib0070_write_reg(state, 0x17, value & 0xfffc);
    158		tmp = dib0070_read_reg(state, 0x01) & 0x01ff;
    159		dib0070_write_reg(state, 0x01, tmp | (60 << 9));
    160
    161		dib0070_write_reg(state, 0x17, value);
    162	}
    163	return 0;
    164}
    165
    166static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state *tune_state)
    167{
    168	int8_t step_sign;
    169	u16 adc;
    170	int ret = 0;
    171
    172	if (*tune_state == CT_TUNER_STEP_0) {
    173		dib0070_write_reg(state, 0x0f, 0xed10);
    174		dib0070_write_reg(state, 0x17,    0x0034);
    175
    176		dib0070_write_reg(state, 0x18, 0x0032);
    177		state->step = state->captrim = state->fcaptrim = 64;
    178		state->adc_diff = 3000;
    179		ret = 20;
    180
    181		*tune_state = CT_TUNER_STEP_1;
    182	} else if (*tune_state == CT_TUNER_STEP_1) {
    183		state->step /= 2;
    184		dib0070_write_reg(state, 0x14, state->lo4 | state->captrim);
    185		ret = 15;
    186
    187		*tune_state = CT_TUNER_STEP_2;
    188	} else if (*tune_state == CT_TUNER_STEP_2) {
    189
    190		adc = dib0070_read_reg(state, 0x19);
    191
    192		dprintk("CAPTRIM=%d; ADC = %hd (ADC) & %dmV\n", state->captrim,
    193			adc, (u32)adc * (u32)1800 / (u32)1024);
    194
    195		if (adc >= 400) {
    196			adc -= 400;
    197			step_sign = -1;
    198		} else {
    199			adc = 400 - adc;
    200			step_sign = 1;
    201		}
    202
    203		if (adc < state->adc_diff) {
    204			dprintk("CAPTRIM=%d is closer to target (%hd/%hd)\n",
    205				state->captrim, adc, state->adc_diff);
    206			state->adc_diff = adc;
    207			state->fcaptrim = state->captrim;
    208		}
    209		state->captrim += (step_sign * state->step);
    210
    211		if (state->step >= 1)
    212			*tune_state = CT_TUNER_STEP_1;
    213		else
    214			*tune_state = CT_TUNER_STEP_3;
    215
    216	} else if (*tune_state == CT_TUNER_STEP_3) {
    217		dib0070_write_reg(state, 0x14, state->lo4 | state->fcaptrim);
    218		dib0070_write_reg(state, 0x18, 0x07ff);
    219		*tune_state = CT_TUNER_STEP_4;
    220	}
    221
    222	return ret;
    223}
    224
    225static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt)
    226{
    227	struct dib0070_state *state = fe->tuner_priv;
    228	u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0);
    229
    230	dprintk("CTRL_LO5: 0x%x\n", lo5);
    231	return dib0070_write_reg(state, 0x15, lo5);
    232}
    233
    234void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open)
    235{
    236	struct dib0070_state *state = fe->tuner_priv;
    237
    238	if (open) {
    239		dib0070_write_reg(state, 0x1b, 0xff00);
    240		dib0070_write_reg(state, 0x1a, 0x0000);
    241	} else {
    242		dib0070_write_reg(state, 0x1b, 0x4112);
    243		if (state->cfg->vga_filter != 0) {
    244			dib0070_write_reg(state, 0x1a, state->cfg->vga_filter);
    245			dprintk("vga filter register is set to %x\n", state->cfg->vga_filter);
    246		} else
    247			dib0070_write_reg(state, 0x1a, 0x0009);
    248	}
    249}
    250
    251EXPORT_SYMBOL(dib0070_ctrl_agc_filter);
    252struct dib0070_tuning {
    253	u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
    254	u8 switch_trim;
    255	u8 vco_band;
    256	u8 hfdiv;
    257	u8 vco_multi;
    258	u8 presc;
    259	u8 wbdmux;
    260	u16 tuner_enable;
    261};
    262
    263struct dib0070_lna_match {
    264	u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
    265	u8 lna_band;
    266};
    267
    268static const struct dib0070_tuning dib0070s_tuning_table[] = {
    269	{     570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800 }, /* UHF */
    270	{     700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800 },
    271	{     863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800 },
    272	{    1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND */
    273	{    1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
    274	{    2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
    275	{ 0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000 }, /* SBAND */
    276};
    277
    278static const struct dib0070_tuning dib0070_tuning_table[] = {
    279	{     115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000 }, /* FM below 92MHz cannot be tuned */
    280	{     179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000 }, /* VHF */
    281	{     189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000 },
    282	{     250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000 },
    283	{     569999, 2, 1, 5,  6, 2, 2, 0x4000 | 0x0800 }, /* UHF */
    284	{     699999, 2, 0, 1,  4, 2, 2, 0x4000 | 0x0800 },
    285	{     863999, 2, 1, 1,  4, 2, 2, 0x4000 | 0x0800 },
    286	{ 0xffffffff, 0, 1, 0,  2, 2, 4, 0x2000 | 0x0400 }, /* LBAND or everything higher than UHF */
    287};
    288
    289static const struct dib0070_lna_match dib0070_lna_flip_chip[] = {
    290	{     180000, 0 }, /* VHF */
    291	{     188000, 1 },
    292	{     196400, 2 },
    293	{     250000, 3 },
    294	{     550000, 0 }, /* UHF */
    295	{     590000, 1 },
    296	{     666000, 3 },
    297	{     864000, 5 },
    298	{    1500000, 0 }, /* LBAND or everything higher than UHF */
    299	{    1600000, 1 },
    300	{    2000000, 3 },
    301	{ 0xffffffff, 7 },
    302};
    303
    304static const struct dib0070_lna_match dib0070_lna[] = {
    305	{     180000, 0 }, /* VHF */
    306	{     188000, 1 },
    307	{     196400, 2 },
    308	{     250000, 3 },
    309	{     550000, 2 }, /* UHF */
    310	{     650000, 3 },
    311	{     750000, 5 },
    312	{     850000, 6 },
    313	{     864000, 7 },
    314	{    1500000, 0 }, /* LBAND or everything higher than UHF */
    315	{    1600000, 1 },
    316	{    2000000, 3 },
    317	{ 0xffffffff, 7 },
    318};
    319
    320#define LPF	100
    321static int dib0070_tune_digital(struct dvb_frontend *fe)
    322{
    323	struct dib0070_state *state = fe->tuner_priv;
    324
    325	const struct dib0070_tuning *tune;
    326	const struct dib0070_lna_match *lna_match;
    327
    328	enum frontend_tune_state *tune_state = &state->tune_state;
    329	int ret = 10; /* 1ms is the default delay most of the time */
    330
    331	u8  band = (u8)BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency/1000);
    332	u32 freq = fe->dtv_property_cache.frequency/1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf);
    333
    334#ifdef CONFIG_SYS_ISDBT
    335	if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1)
    336			if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2)
    337			&& (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
    338			|| (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
    339				&& (state->fe->dtv_property_cache.isdbt_sb_segment_idx == (state->fe->dtv_property_cache.isdbt_sb_segment_count / 2)))
    340			|| (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
    341				&& (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))))
    342				freq += 850;
    343#endif
    344	if (state->current_rf != freq) {
    345
    346		switch (state->revision) {
    347		case DIB0070S_P1A:
    348		tune = dib0070s_tuning_table;
    349		lna_match = dib0070_lna;
    350		break;
    351		default:
    352		tune = dib0070_tuning_table;
    353		if (state->cfg->flip_chip)
    354			lna_match = dib0070_lna_flip_chip;
    355		else
    356			lna_match = dib0070_lna;
    357		break;
    358		}
    359		while (freq > tune->max_freq) /* find the right one */
    360			tune++;
    361		while (freq > lna_match->max_freq) /* find the right one */
    362			lna_match++;
    363
    364		state->current_tune_table_index = tune;
    365		state->lna_match = lna_match;
    366	}
    367
    368	if (*tune_state == CT_TUNER_START) {
    369		dprintk("Tuning for Band: %d (%d kHz)\n", band, freq);
    370		if (state->current_rf != freq) {
    371			u8 REFDIV;
    372			u32 FBDiv, Rest, FREF, VCOF_kHz;
    373			u8 Den;
    374
    375			state->current_rf = freq;
    376			state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7);
    377
    378
    379			dib0070_write_reg(state, 0x17, 0x30);
    380
    381
    382			VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2;
    383
    384			switch (band) {
    385			case BAND_VHF:
    386				REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000);
    387				break;
    388			case BAND_FM:
    389				REFDIV = (u8) ((state->cfg->clock_khz) / 1000);
    390				break;
    391			default:
    392				REFDIV = (u8) (state->cfg->clock_khz  / 10000);
    393				break;
    394			}
    395			FREF = state->cfg->clock_khz / REFDIV;
    396
    397
    398
    399			switch (state->revision) {
    400			case DIB0070S_P1A:
    401				FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF);
    402				Rest  = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF;
    403				break;
    404
    405			case DIB0070_P1G:
    406			case DIB0070_P1F:
    407			default:
    408				FBDiv = (freq / (FREF / 2));
    409				Rest  = 2 * freq - FBDiv * FREF;
    410				break;
    411			}
    412
    413			if (Rest < LPF)
    414				Rest = 0;
    415			else if (Rest < 2 * LPF)
    416				Rest = 2 * LPF;
    417			else if (Rest > (FREF - LPF)) {
    418				Rest = 0;
    419				FBDiv += 1;
    420			} else if (Rest > (FREF - 2 * LPF))
    421				Rest = FREF - 2 * LPF;
    422			Rest = (Rest * 6528) / (FREF / 10);
    423
    424			Den = 1;
    425			if (Rest > 0) {
    426				state->lo4 |= (1 << 14) | (1 << 12);
    427				Den = 255;
    428			}
    429
    430
    431			dib0070_write_reg(state, 0x11, (u16)FBDiv);
    432			dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV);
    433			dib0070_write_reg(state, 0x13, (u16) Rest);
    434
    435			if (state->revision == DIB0070S_P1A) {
    436
    437				if (band == BAND_SBAND) {
    438					dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
    439					dib0070_write_reg(state, 0x1d, 0xFFFF);
    440				} else
    441					dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1);
    442			}
    443
    444			dib0070_write_reg(state, 0x20,
    445				0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable);
    446
    447			dprintk("REFDIV: %u, FREF: %d\n", REFDIV, FREF);
    448			dprintk("FBDIV: %d, Rest: %d\n", FBDiv, Rest);
    449			dprintk("Num: %u, Den: %u, SD: %d\n", (u16)Rest, Den,
    450				(state->lo4 >> 12) & 0x1);
    451			dprintk("HFDIV code: %u\n",
    452				state->current_tune_table_index->hfdiv);
    453			dprintk("VCO = %u\n",
    454				state->current_tune_table_index->vco_band);
    455			dprintk("VCOF: ((%u*%d) << 1))\n",
    456				state->current_tune_table_index->vco_multi,
    457				freq);
    458
    459			*tune_state = CT_TUNER_STEP_0;
    460		} else { /* we are already tuned to this frequency - the configuration is correct  */
    461			ret = 50; /* wakeup time */
    462			*tune_state = CT_TUNER_STEP_5;
    463		}
    464	} else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) {
    465
    466		ret = dib0070_captrim(state, tune_state);
    467
    468	} else if (*tune_state == CT_TUNER_STEP_4) {
    469		const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
    470		if (tmp != NULL) {
    471			while (freq/1000 > tmp->freq) /* find the right one */
    472				tmp++;
    473			dib0070_write_reg(state, 0x0f,
    474				(0 << 15) | (1 << 14) | (3 << 12)
    475				| (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7)
    476				| (state->current_tune_table_index->wbdmux << 0));
    477			state->wbd_gain_current = tmp->wbd_gain_val;
    478		} else {
    479			dib0070_write_reg(state, 0x0f,
    480					  (0 << 15) | (1 << 14) | (3 << 12)
    481					  | (6 << 9) | (0 << 8) | (1 << 7)
    482					  | (state->current_tune_table_index->wbdmux << 0));
    483			state->wbd_gain_current = 6;
    484		}
    485
    486		dib0070_write_reg(state, 0x06, 0x3fff);
    487		dib0070_write_reg(state, 0x07,
    488				  (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0));
    489		dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127));
    490		dib0070_write_reg(state, 0x0d, 0x0d80);
    491
    492
    493		dib0070_write_reg(state, 0x18,   0x07ff);
    494		dib0070_write_reg(state, 0x17, 0x0033);
    495
    496
    497		*tune_state = CT_TUNER_STEP_5;
    498	} else if (*tune_state == CT_TUNER_STEP_5) {
    499		dib0070_set_bandwidth(fe);
    500		*tune_state = CT_TUNER_STOP;
    501	} else {
    502		ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */
    503	}
    504	return ret;
    505}
    506
    507
    508static int dib0070_tune(struct dvb_frontend *fe)
    509{
    510	struct dib0070_state *state = fe->tuner_priv;
    511	uint32_t ret;
    512
    513	state->tune_state = CT_TUNER_START;
    514
    515	do {
    516		ret = dib0070_tune_digital(fe);
    517		if (ret != FE_CALLBACK_TIME_NEVER)
    518			msleep(ret/10);
    519		else
    520		break;
    521	} while (state->tune_state != CT_TUNER_STOP);
    522
    523	return 0;
    524}
    525
    526static int dib0070_wakeup(struct dvb_frontend *fe)
    527{
    528	struct dib0070_state *state = fe->tuner_priv;
    529	if (state->cfg->sleep)
    530		state->cfg->sleep(fe, 0);
    531	return 0;
    532}
    533
    534static int dib0070_sleep(struct dvb_frontend *fe)
    535{
    536	struct dib0070_state *state = fe->tuner_priv;
    537	if (state->cfg->sleep)
    538		state->cfg->sleep(fe, 1);
    539	return 0;
    540}
    541
    542u8 dib0070_get_rf_output(struct dvb_frontend *fe)
    543{
    544	struct dib0070_state *state = fe->tuner_priv;
    545	return (dib0070_read_reg(state, 0x07) >> 11) & 0x3;
    546}
    547EXPORT_SYMBOL(dib0070_get_rf_output);
    548
    549int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no)
    550{
    551	struct dib0070_state *state = fe->tuner_priv;
    552	u16 rxrf2 = dib0070_read_reg(state, 0x07) & 0xfe7ff;
    553	if (no > 3)
    554		no = 3;
    555	if (no < 1)
    556		no = 1;
    557	return dib0070_write_reg(state, 0x07, rxrf2 | (no << 11));
    558}
    559EXPORT_SYMBOL(dib0070_set_rf_output);
    560
    561static const u16 dib0070_p1f_defaults[] =
    562
    563{
    564	7, 0x02,
    565		0x0008,
    566		0x0000,
    567		0x0000,
    568		0x0000,
    569		0x0000,
    570		0x0002,
    571		0x0100,
    572
    573	3, 0x0d,
    574		0x0d80,
    575		0x0001,
    576		0x0000,
    577
    578	4, 0x11,
    579		0x0000,
    580		0x0103,
    581		0x0000,
    582		0x0000,
    583
    584	3, 0x16,
    585		0x0004 | 0x0040,
    586		0x0030,
    587		0x07ff,
    588
    589	6, 0x1b,
    590		0x4112,
    591		0xff00,
    592		0xc07f,
    593		0x0000,
    594		0x0180,
    595		0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
    596
    597	0,
    598};
    599
    600static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain)
    601{
    602	u16 tuner_en = dib0070_read_reg(state, 0x20);
    603	u16 offset;
    604
    605	dib0070_write_reg(state, 0x18, 0x07ff);
    606	dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
    607	dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0));
    608	msleep(9);
    609	offset = dib0070_read_reg(state, 0x19);
    610	dib0070_write_reg(state, 0x20, tuner_en);
    611	return offset;
    612}
    613
    614static void dib0070_wbd_offset_calibration(struct dib0070_state *state)
    615{
    616	u8 gain;
    617	for (gain = 6; gain < 8; gain++) {
    618		state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2);
    619		dprintk("Gain: %d, WBDOffset (3.3V) = %hd\n", gain, state->wbd_offset_3_3[gain-6]);
    620	}
    621}
    622
    623u16 dib0070_wbd_offset(struct dvb_frontend *fe)
    624{
    625	struct dib0070_state *state = fe->tuner_priv;
    626	const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
    627	u32 freq = fe->dtv_property_cache.frequency/1000;
    628
    629	if (tmp != NULL) {
    630		while (freq/1000 > tmp->freq) /* find the right one */
    631			tmp++;
    632		state->wbd_gain_current = tmp->wbd_gain_val;
    633	} else
    634		state->wbd_gain_current = 6;
    635
    636	return state->wbd_offset_3_3[state->wbd_gain_current - 6];
    637}
    638EXPORT_SYMBOL(dib0070_wbd_offset);
    639
    640#define pgm_read_word(w) (*w)
    641static int dib0070_reset(struct dvb_frontend *fe)
    642{
    643	struct dib0070_state *state = fe->tuner_priv;
    644	u16 l, r, *n;
    645
    646	HARD_RESET(state);
    647
    648
    649#ifndef FORCE_SBAND_TUNER
    650	if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1)
    651		state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff;
    652	else
    653#else
    654#warning forcing SBAND
    655#endif
    656	state->revision = DIB0070S_P1A;
    657
    658	/* P1F or not */
    659	dprintk("Revision: %x\n", state->revision);
    660
    661	if (state->revision == DIB0070_P1D) {
    662		dprintk("Error: this driver is not to be used meant for P1D or earlier\n");
    663		return -EINVAL;
    664	}
    665
    666	n = (u16 *) dib0070_p1f_defaults;
    667	l = pgm_read_word(n++);
    668	while (l) {
    669		r = pgm_read_word(n++);
    670		do {
    671			dib0070_write_reg(state, (u8)r, pgm_read_word(n++));
    672			r++;
    673		} while (--l);
    674		l = pgm_read_word(n++);
    675	}
    676
    677	if (state->cfg->force_crystal_mode != 0)
    678		r = state->cfg->force_crystal_mode;
    679	else if (state->cfg->clock_khz >= 24000)
    680		r = 1;
    681	else
    682		r = 2;
    683
    684
    685	r |= state->cfg->osc_buffer_state << 3;
    686
    687	dib0070_write_reg(state, 0x10, r);
    688	dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 5));
    689
    690	if (state->cfg->invert_iq) {
    691		r = dib0070_read_reg(state, 0x02) & 0xffdf;
    692		dib0070_write_reg(state, 0x02, r | (1 << 5));
    693	}
    694
    695	if (state->revision == DIB0070S_P1A)
    696		dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
    697	else
    698		dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump,
    699				     state->cfg->enable_third_order_filter);
    700
    701	dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8);
    702
    703	dib0070_wbd_offset_calibration(state);
    704
    705	return 0;
    706}
    707
    708static int dib0070_get_frequency(struct dvb_frontend *fe, u32 *frequency)
    709{
    710	struct dib0070_state *state = fe->tuner_priv;
    711
    712	*frequency = 1000 * state->current_rf;
    713	return 0;
    714}
    715
    716static void dib0070_release(struct dvb_frontend *fe)
    717{
    718	kfree(fe->tuner_priv);
    719	fe->tuner_priv = NULL;
    720}
    721
    722static const struct dvb_tuner_ops dib0070_ops = {
    723	.info = {
    724		.name              = "DiBcom DiB0070",
    725		.frequency_min_hz  =  45 * MHz,
    726		.frequency_max_hz  = 860 * MHz,
    727		.frequency_step_hz =   1 * kHz,
    728	},
    729	.release       = dib0070_release,
    730
    731	.init          = dib0070_wakeup,
    732	.sleep         = dib0070_sleep,
    733	.set_params    = dib0070_tune,
    734
    735	.get_frequency = dib0070_get_frequency,
    736//      .get_bandwidth = dib0070_get_bandwidth
    737};
    738
    739struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
    740{
    741	struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL);
    742	if (state == NULL)
    743		return NULL;
    744
    745	state->cfg = cfg;
    746	state->i2c = i2c;
    747	state->fe  = fe;
    748	mutex_init(&state->i2c_buffer_lock);
    749	fe->tuner_priv = state;
    750
    751	if (dib0070_reset(fe) != 0)
    752		goto free_mem;
    753
    754	pr_info("DiB0070: successfully identified\n");
    755	memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
    756
    757	fe->tuner_priv = state;
    758	return fe;
    759
    760free_mem:
    761	kfree(state);
    762	fe->tuner_priv = NULL;
    763	return NULL;
    764}
    765EXPORT_SYMBOL(dib0070_attach);
    766
    767MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
    768MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
    769MODULE_LICENSE("GPL");