18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci    tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci*/
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include "tda18271-priv.h"
108c2ecf20Sopenharmony_ci#include "tda8290.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/delay.h>
138c2ecf20Sopenharmony_ci#include <linux/videodev2.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ciint tda18271_debug;
168c2ecf20Sopenharmony_cimodule_param_named(debug, tda18271_debug, int, 0644);
178c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "set debug level (info=1, map=2, reg=4, adv=8, cal=16 (or-able))");
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic int tda18271_cal_on_startup = -1;
208c2ecf20Sopenharmony_cimodule_param_named(cal, tda18271_cal_on_startup, int, 0644);
218c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup");
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(tda18271_list_mutex);
248c2ecf20Sopenharmony_cistatic LIST_HEAD(hybrid_tuner_instance_list);
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/*---------------------------------------------------------------------*/
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic int tda18271_toggle_output(struct dvb_frontend *fe, int standby)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	int ret = tda18271_set_standby_mode(fe, standby ? 1 : 0,
338c2ecf20Sopenharmony_ci			priv->output_opt & TDA18271_OUTPUT_LT_OFF ? 1 : 0,
348c2ecf20Sopenharmony_ci			priv->output_opt & TDA18271_OUTPUT_XT_OFF ? 1 : 0);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	if (tda_fail(ret))
378c2ecf20Sopenharmony_ci		goto fail;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	tda_dbg("%s mode: xtal oscillator %s, slave tuner loop through %s\n",
408c2ecf20Sopenharmony_ci		standby ? "standby" : "active",
418c2ecf20Sopenharmony_ci		priv->output_opt & TDA18271_OUTPUT_XT_OFF ? "off" : "on",
428c2ecf20Sopenharmony_ci		priv->output_opt & TDA18271_OUTPUT_LT_OFF ? "off" : "on");
438c2ecf20Sopenharmony_cifail:
448c2ecf20Sopenharmony_ci	return ret;
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci/*---------------------------------------------------------------------*/
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic inline int charge_pump_source(struct dvb_frontend *fe, int force)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
528c2ecf20Sopenharmony_ci	return tda18271_charge_pump_source(fe,
538c2ecf20Sopenharmony_ci					   (priv->role == TDA18271_SLAVE) ?
548c2ecf20Sopenharmony_ci					   TDA18271_CAL_PLL :
558c2ecf20Sopenharmony_ci					   TDA18271_MAIN_PLL, force);
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic inline void tda18271_set_if_notch(struct dvb_frontend *fe)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
618c2ecf20Sopenharmony_ci	unsigned char *regs = priv->tda18271_regs;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	switch (priv->mode) {
648c2ecf20Sopenharmony_ci	case TDA18271_ANALOG:
658c2ecf20Sopenharmony_ci		regs[R_MPD]  &= ~0x80; /* IF notch = 0 */
668c2ecf20Sopenharmony_ci		break;
678c2ecf20Sopenharmony_ci	case TDA18271_DIGITAL:
688c2ecf20Sopenharmony_ci		regs[R_MPD]  |= 0x80; /* IF notch = 1 */
698c2ecf20Sopenharmony_ci		break;
708c2ecf20Sopenharmony_ci	}
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic int tda18271_channel_configuration(struct dvb_frontend *fe,
748c2ecf20Sopenharmony_ci					  struct tda18271_std_map_item *map,
758c2ecf20Sopenharmony_ci					  u32 freq, u32 bw)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
788c2ecf20Sopenharmony_ci	unsigned char *regs = priv->tda18271_regs;
798c2ecf20Sopenharmony_ci	int ret;
808c2ecf20Sopenharmony_ci	u32 N;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	/* update TV broadcast parameters */
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	/* set standard */
858c2ecf20Sopenharmony_ci	regs[R_EP3]  &= ~0x1f; /* clear std bits */
868c2ecf20Sopenharmony_ci	regs[R_EP3]  |= (map->agc_mode << 3) | map->std;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	if (priv->id == TDA18271HDC2) {
898c2ecf20Sopenharmony_ci		/* set rfagc to high speed mode */
908c2ecf20Sopenharmony_ci		regs[R_EP3] &= ~0x04;
918c2ecf20Sopenharmony_ci	}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	/* set cal mode to normal */
948c2ecf20Sopenharmony_ci	regs[R_EP4]  &= ~0x03;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	/* update IF output level */
978c2ecf20Sopenharmony_ci	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
988c2ecf20Sopenharmony_ci	regs[R_EP4]  |= (map->if_lvl << 2);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	/* update FM_RFn */
1018c2ecf20Sopenharmony_ci	regs[R_EP4]  &= ~0x80;
1028c2ecf20Sopenharmony_ci	regs[R_EP4]  |= map->fm_rfn << 7;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	/* update rf top / if top */
1058c2ecf20Sopenharmony_ci	regs[R_EB22]  = 0x00;
1068c2ecf20Sopenharmony_ci	regs[R_EB22] |= map->rfagc_top;
1078c2ecf20Sopenharmony_ci	ret = tda18271_write_regs(fe, R_EB22, 1);
1088c2ecf20Sopenharmony_ci	if (tda_fail(ret))
1098c2ecf20Sopenharmony_ci		goto fail;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	/* --------------------------------------------------------------- */
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	/* disable Power Level Indicator */
1148c2ecf20Sopenharmony_ci	regs[R_EP1]  |= 0x40;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	/* make sure thermometer is off */
1178c2ecf20Sopenharmony_ci	regs[R_TM]   &= ~0x10;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	/* frequency dependent parameters */
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	tda18271_calc_ir_measure(fe, &freq);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	tda18271_calc_bp_filter(fe, &freq);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	tda18271_calc_rf_band(fe, &freq);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	tda18271_calc_gain_taper(fe, &freq);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	/* --------------------------------------------------------------- */
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	/* dual tuner and agc1 extra configuration */
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	switch (priv->role) {
1348c2ecf20Sopenharmony_ci	case TDA18271_MASTER:
1358c2ecf20Sopenharmony_ci		regs[R_EB1]  |= 0x04; /* main vco */
1368c2ecf20Sopenharmony_ci		break;
1378c2ecf20Sopenharmony_ci	case TDA18271_SLAVE:
1388c2ecf20Sopenharmony_ci		regs[R_EB1]  &= ~0x04; /* cal vco */
1398c2ecf20Sopenharmony_ci		break;
1408c2ecf20Sopenharmony_ci	}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	/* agc1 always active */
1438c2ecf20Sopenharmony_ci	regs[R_EB1]  &= ~0x02;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	/* agc1 has priority on agc2 */
1468c2ecf20Sopenharmony_ci	regs[R_EB1]  &= ~0x01;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	ret = tda18271_write_regs(fe, R_EB1, 1);
1498c2ecf20Sopenharmony_ci	if (tda_fail(ret))
1508c2ecf20Sopenharmony_ci		goto fail;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	/* --------------------------------------------------------------- */
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	N = map->if_freq * 1000 + freq;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	switch (priv->role) {
1578c2ecf20Sopenharmony_ci	case TDA18271_MASTER:
1588c2ecf20Sopenharmony_ci		tda18271_calc_main_pll(fe, N);
1598c2ecf20Sopenharmony_ci		tda18271_set_if_notch(fe);
1608c2ecf20Sopenharmony_ci		tda18271_write_regs(fe, R_MPD, 4);
1618c2ecf20Sopenharmony_ci		break;
1628c2ecf20Sopenharmony_ci	case TDA18271_SLAVE:
1638c2ecf20Sopenharmony_ci		tda18271_calc_cal_pll(fe, N);
1648c2ecf20Sopenharmony_ci		tda18271_write_regs(fe, R_CPD, 4);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci		regs[R_MPD] = regs[R_CPD] & 0x7f;
1678c2ecf20Sopenharmony_ci		tda18271_set_if_notch(fe);
1688c2ecf20Sopenharmony_ci		tda18271_write_regs(fe, R_MPD, 1);
1698c2ecf20Sopenharmony_ci		break;
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	ret = tda18271_write_regs(fe, R_TM, 7);
1738c2ecf20Sopenharmony_ci	if (tda_fail(ret))
1748c2ecf20Sopenharmony_ci		goto fail;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	/* force charge pump source */
1778c2ecf20Sopenharmony_ci	charge_pump_source(fe, 1);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	msleep(1);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	/* return pll to normal operation */
1828c2ecf20Sopenharmony_ci	charge_pump_source(fe, 0);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	msleep(20);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	if (priv->id == TDA18271HDC2) {
1878c2ecf20Sopenharmony_ci		/* set rfagc to normal speed mode */
1888c2ecf20Sopenharmony_ci		if (map->fm_rfn)
1898c2ecf20Sopenharmony_ci			regs[R_EP3] &= ~0x04;
1908c2ecf20Sopenharmony_ci		else
1918c2ecf20Sopenharmony_ci			regs[R_EP3] |= 0x04;
1928c2ecf20Sopenharmony_ci		ret = tda18271_write_regs(fe, R_EP3, 1);
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_cifail:
1958c2ecf20Sopenharmony_ci	return ret;
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic int tda18271_read_thermometer(struct dvb_frontend *fe)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
2018c2ecf20Sopenharmony_ci	unsigned char *regs = priv->tda18271_regs;
2028c2ecf20Sopenharmony_ci	int tm;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	/* switch thermometer on */
2058c2ecf20Sopenharmony_ci	regs[R_TM]   |= 0x10;
2068c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_TM, 1);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	/* read thermometer info */
2098c2ecf20Sopenharmony_ci	tda18271_read_regs(fe);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	if ((((regs[R_TM] & 0x0f) == 0x00) && ((regs[R_TM] & 0x20) == 0x20)) ||
2128c2ecf20Sopenharmony_ci	    (((regs[R_TM] & 0x0f) == 0x08) && ((regs[R_TM] & 0x20) == 0x00))) {
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci		if ((regs[R_TM] & 0x20) == 0x20)
2158c2ecf20Sopenharmony_ci			regs[R_TM] &= ~0x20;
2168c2ecf20Sopenharmony_ci		else
2178c2ecf20Sopenharmony_ci			regs[R_TM] |= 0x20;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci		tda18271_write_regs(fe, R_TM, 1);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci		msleep(10); /* temperature sensing */
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci		/* read thermometer info */
2248c2ecf20Sopenharmony_ci		tda18271_read_regs(fe);
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	tm = tda18271_lookup_thermometer(fe);
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	/* switch thermometer off */
2308c2ecf20Sopenharmony_ci	regs[R_TM]   &= ~0x10;
2318c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_TM, 1);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	/* set CAL mode to normal */
2348c2ecf20Sopenharmony_ci	regs[R_EP4]  &= ~0x03;
2358c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EP4, 1);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	return tm;
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe,
2438c2ecf20Sopenharmony_ci						     u32 freq)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
2468c2ecf20Sopenharmony_ci	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
2478c2ecf20Sopenharmony_ci	unsigned char *regs = priv->tda18271_regs;
2488c2ecf20Sopenharmony_ci	int i, ret;
2498c2ecf20Sopenharmony_ci	u8 tm_current, dc_over_dt, rf_tab;
2508c2ecf20Sopenharmony_ci	s32 rfcal_comp, approx;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	/* power up */
2538c2ecf20Sopenharmony_ci	ret = tda18271_set_standby_mode(fe, 0, 0, 0);
2548c2ecf20Sopenharmony_ci	if (tda_fail(ret))
2558c2ecf20Sopenharmony_ci		goto fail;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	/* read die current temperature */
2588c2ecf20Sopenharmony_ci	tm_current = tda18271_read_thermometer(fe);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	/* frequency dependent parameters */
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	tda18271_calc_rf_cal(fe, &freq);
2638c2ecf20Sopenharmony_ci	rf_tab = regs[R_EB14];
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	i = tda18271_lookup_rf_band(fe, &freq, NULL);
2668c2ecf20Sopenharmony_ci	if (tda_fail(i))
2678c2ecf20Sopenharmony_ci		return i;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) {
2708c2ecf20Sopenharmony_ci		approx = map[i].rf_a1 * (s32)(freq / 1000 - map[i].rf1) +
2718c2ecf20Sopenharmony_ci			map[i].rf_b1 + rf_tab;
2728c2ecf20Sopenharmony_ci	} else {
2738c2ecf20Sopenharmony_ci		approx = map[i].rf_a2 * (s32)(freq / 1000 - map[i].rf2) +
2748c2ecf20Sopenharmony_ci			map[i].rf_b2 + rf_tab;
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	if (approx < 0)
2788c2ecf20Sopenharmony_ci		approx = 0;
2798c2ecf20Sopenharmony_ci	if (approx > 255)
2808c2ecf20Sopenharmony_ci		approx = 255;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt);
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	/* calculate temperature compensation */
2858c2ecf20Sopenharmony_ci	rfcal_comp = dc_over_dt * (s32)(tm_current - priv->tm_rfcal) / 1000;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	regs[R_EB14] = (unsigned char)(approx + rfcal_comp);
2888c2ecf20Sopenharmony_ci	ret = tda18271_write_regs(fe, R_EB14, 1);
2898c2ecf20Sopenharmony_cifail:
2908c2ecf20Sopenharmony_ci	return ret;
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_cistatic int tda18271_por(struct dvb_frontend *fe)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
2968c2ecf20Sopenharmony_ci	unsigned char *regs = priv->tda18271_regs;
2978c2ecf20Sopenharmony_ci	int ret;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	/* power up detector 1 */
3008c2ecf20Sopenharmony_ci	regs[R_EB12] &= ~0x20;
3018c2ecf20Sopenharmony_ci	ret = tda18271_write_regs(fe, R_EB12, 1);
3028c2ecf20Sopenharmony_ci	if (tda_fail(ret))
3038c2ecf20Sopenharmony_ci		goto fail;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	regs[R_EB18] &= ~0x80; /* turn agc1 loop on */
3068c2ecf20Sopenharmony_ci	regs[R_EB18] &= ~0x03; /* set agc1_gain to  6 dB */
3078c2ecf20Sopenharmony_ci	ret = tda18271_write_regs(fe, R_EB18, 1);
3088c2ecf20Sopenharmony_ci	if (tda_fail(ret))
3098c2ecf20Sopenharmony_ci		goto fail;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	/* POR mode */
3148c2ecf20Sopenharmony_ci	ret = tda18271_set_standby_mode(fe, 1, 0, 0);
3158c2ecf20Sopenharmony_ci	if (tda_fail(ret))
3168c2ecf20Sopenharmony_ci		goto fail;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	/* disable 1.5 MHz low pass filter */
3198c2ecf20Sopenharmony_ci	regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */
3208c2ecf20Sopenharmony_ci	regs[R_EB23] &= ~0x02; /* XXX: lp_fc[2] = 0 */
3218c2ecf20Sopenharmony_ci	ret = tda18271_write_regs(fe, R_EB21, 3);
3228c2ecf20Sopenharmony_cifail:
3238c2ecf20Sopenharmony_ci	return ret;
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_cistatic int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
3298c2ecf20Sopenharmony_ci	unsigned char *regs = priv->tda18271_regs;
3308c2ecf20Sopenharmony_ci	u32 N;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	/* set CAL mode to normal */
3338c2ecf20Sopenharmony_ci	regs[R_EP4]  &= ~0x03;
3348c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EP4, 1);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	/* switch off agc1 */
3378c2ecf20Sopenharmony_ci	regs[R_EP3]  |= 0x40; /* sm_lt = 1 */
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	regs[R_EB18] |= 0x03; /* set agc1_gain to 15 dB */
3408c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EB18, 1);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	/* frequency dependent parameters */
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	tda18271_calc_bp_filter(fe, &freq);
3458c2ecf20Sopenharmony_ci	tda18271_calc_gain_taper(fe, &freq);
3468c2ecf20Sopenharmony_ci	tda18271_calc_rf_band(fe, &freq);
3478c2ecf20Sopenharmony_ci	tda18271_calc_km(fe, &freq);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EP1, 3);
3508c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EB13, 1);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	/* main pll charge pump source */
3538c2ecf20Sopenharmony_ci	tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	/* cal pll charge pump source */
3568c2ecf20Sopenharmony_ci	tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 1);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	/* force dcdc converter to 0 V */
3598c2ecf20Sopenharmony_ci	regs[R_EB14] = 0x00;
3608c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EB14, 1);
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	/* disable plls lock */
3638c2ecf20Sopenharmony_ci	regs[R_EB20] &= ~0x20;
3648c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EB20, 1);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	/* set CAL mode to RF tracking filter calibration */
3678c2ecf20Sopenharmony_ci	regs[R_EP4]  |= 0x03;
3688c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EP4, 2);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	/* --------------------------------------------------------------- */
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	/* set the internal calibration signal */
3738c2ecf20Sopenharmony_ci	N = freq;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	tda18271_calc_cal_pll(fe, N);
3768c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_CPD, 4);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	/* downconvert internal calibration */
3798c2ecf20Sopenharmony_ci	N += 1000000;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	tda18271_calc_main_pll(fe, N);
3828c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_MPD, 4);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	msleep(5);
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EP2, 1);
3878c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EP1, 1);
3888c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EP2, 1);
3898c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EP1, 1);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	/* --------------------------------------------------------------- */
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	/* normal operation for the main pll */
3948c2ecf20Sopenharmony_ci	tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0);
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	/* normal operation for the cal pll  */
3978c2ecf20Sopenharmony_ci	tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 0);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	msleep(10); /* plls locking */
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	/* launch the rf tracking filters calibration */
4028c2ecf20Sopenharmony_ci	regs[R_EB20]  |= 0x20;
4038c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EB20, 1);
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	msleep(60); /* calibration */
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	/* --------------------------------------------------------------- */
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	/* set CAL mode to normal */
4108c2ecf20Sopenharmony_ci	regs[R_EP4]  &= ~0x03;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	/* switch on agc1 */
4138c2ecf20Sopenharmony_ci	regs[R_EP3]  &= ~0x40; /* sm_lt = 0 */
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	regs[R_EB18] &= ~0x03; /* set agc1_gain to  6 dB */
4168c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EB18, 1);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EP3, 2);
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	/* synchronization */
4218c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EP1, 1);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	/* get calibration result */
4248c2ecf20Sopenharmony_ci	tda18271_read_extended(fe);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	return regs[R_EB14];
4278c2ecf20Sopenharmony_ci}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_cistatic int tda18271_powerscan(struct dvb_frontend *fe,
4308c2ecf20Sopenharmony_ci			      u32 *freq_in, u32 *freq_out)
4318c2ecf20Sopenharmony_ci{
4328c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
4338c2ecf20Sopenharmony_ci	unsigned char *regs = priv->tda18271_regs;
4348c2ecf20Sopenharmony_ci	int sgn, bcal, count, wait, ret;
4358c2ecf20Sopenharmony_ci	u8 cid_target;
4368c2ecf20Sopenharmony_ci	u16 count_limit;
4378c2ecf20Sopenharmony_ci	u32 freq;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	freq = *freq_in;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	tda18271_calc_rf_band(fe, &freq);
4428c2ecf20Sopenharmony_ci	tda18271_calc_rf_cal(fe, &freq);
4438c2ecf20Sopenharmony_ci	tda18271_calc_gain_taper(fe, &freq);
4448c2ecf20Sopenharmony_ci	tda18271_lookup_cid_target(fe, &freq, &cid_target, &count_limit);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EP2, 1);
4478c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EB14, 1);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	/* downconvert frequency */
4508c2ecf20Sopenharmony_ci	freq += 1000000;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	tda18271_calc_main_pll(fe, freq);
4538c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_MPD, 4);
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	msleep(5); /* pll locking */
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	/* detection mode */
4588c2ecf20Sopenharmony_ci	regs[R_EP4]  &= ~0x03;
4598c2ecf20Sopenharmony_ci	regs[R_EP4]  |= 0x01;
4608c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EP4, 1);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	/* launch power detection measurement */
4638c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EP2, 1);
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	/* read power detection info, stored in EB10 */
4668c2ecf20Sopenharmony_ci	ret = tda18271_read_extended(fe);
4678c2ecf20Sopenharmony_ci	if (tda_fail(ret))
4688c2ecf20Sopenharmony_ci		return ret;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	/* algorithm initialization */
4718c2ecf20Sopenharmony_ci	sgn = 1;
4728c2ecf20Sopenharmony_ci	*freq_out = *freq_in;
4738c2ecf20Sopenharmony_ci	bcal = 0;
4748c2ecf20Sopenharmony_ci	count = 0;
4758c2ecf20Sopenharmony_ci	wait = false;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	while ((regs[R_EB10] & 0x3f) < cid_target) {
4788c2ecf20Sopenharmony_ci		/* downconvert updated freq to 1 MHz */
4798c2ecf20Sopenharmony_ci		freq = *freq_in + (sgn * count) + 1000000;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci		tda18271_calc_main_pll(fe, freq);
4828c2ecf20Sopenharmony_ci		tda18271_write_regs(fe, R_MPD, 4);
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci		if (wait) {
4858c2ecf20Sopenharmony_ci			msleep(5); /* pll locking */
4868c2ecf20Sopenharmony_ci			wait = false;
4878c2ecf20Sopenharmony_ci		} else
4888c2ecf20Sopenharmony_ci			udelay(100); /* pll locking */
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci		/* launch power detection measurement */
4918c2ecf20Sopenharmony_ci		tda18271_write_regs(fe, R_EP2, 1);
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci		/* read power detection info, stored in EB10 */
4948c2ecf20Sopenharmony_ci		ret = tda18271_read_extended(fe);
4958c2ecf20Sopenharmony_ci		if (tda_fail(ret))
4968c2ecf20Sopenharmony_ci			return ret;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci		count += 200;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci		if (count <= count_limit)
5018c2ecf20Sopenharmony_ci			continue;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci		if (sgn <= 0)
5048c2ecf20Sopenharmony_ci			break;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci		sgn = -1 * sgn;
5078c2ecf20Sopenharmony_ci		count = 200;
5088c2ecf20Sopenharmony_ci		wait = true;
5098c2ecf20Sopenharmony_ci	}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	if ((regs[R_EB10] & 0x3f) >= cid_target) {
5128c2ecf20Sopenharmony_ci		bcal = 1;
5138c2ecf20Sopenharmony_ci		*freq_out = freq - 1000000;
5148c2ecf20Sopenharmony_ci	} else
5158c2ecf20Sopenharmony_ci		bcal = 0;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	tda_cal("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n",
5188c2ecf20Sopenharmony_ci		bcal, *freq_in, *freq_out, freq);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	return bcal;
5218c2ecf20Sopenharmony_ci}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_cistatic int tda18271_powerscan_init(struct dvb_frontend *fe)
5248c2ecf20Sopenharmony_ci{
5258c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
5268c2ecf20Sopenharmony_ci	unsigned char *regs = priv->tda18271_regs;
5278c2ecf20Sopenharmony_ci	int ret;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	/* set standard to digital */
5308c2ecf20Sopenharmony_ci	regs[R_EP3]  &= ~0x1f; /* clear std bits */
5318c2ecf20Sopenharmony_ci	regs[R_EP3]  |= 0x12;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	/* set cal mode to normal */
5348c2ecf20Sopenharmony_ci	regs[R_EP4]  &= ~0x03;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	/* update IF output level */
5378c2ecf20Sopenharmony_ci	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	ret = tda18271_write_regs(fe, R_EP3, 2);
5408c2ecf20Sopenharmony_ci	if (tda_fail(ret))
5418c2ecf20Sopenharmony_ci		goto fail;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	regs[R_EB18] &= ~0x03; /* set agc1_gain to   6 dB */
5448c2ecf20Sopenharmony_ci	ret = tda18271_write_regs(fe, R_EB18, 1);
5458c2ecf20Sopenharmony_ci	if (tda_fail(ret))
5468c2ecf20Sopenharmony_ci		goto fail;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	/* 1.5 MHz low pass filter */
5518c2ecf20Sopenharmony_ci	regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */
5528c2ecf20Sopenharmony_ci	regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	ret = tda18271_write_regs(fe, R_EB21, 3);
5558c2ecf20Sopenharmony_cifail:
5568c2ecf20Sopenharmony_ci	return ret;
5578c2ecf20Sopenharmony_ci}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_cistatic int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq)
5608c2ecf20Sopenharmony_ci{
5618c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
5628c2ecf20Sopenharmony_ci	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
5638c2ecf20Sopenharmony_ci	unsigned char *regs = priv->tda18271_regs;
5648c2ecf20Sopenharmony_ci	int bcal, rf, i;
5658c2ecf20Sopenharmony_ci	s32 divisor, dividend;
5668c2ecf20Sopenharmony_ci#define RF1 0
5678c2ecf20Sopenharmony_ci#define RF2 1
5688c2ecf20Sopenharmony_ci#define RF3 2
5698c2ecf20Sopenharmony_ci	u32 rf_default[3];
5708c2ecf20Sopenharmony_ci	u32 rf_freq[3];
5718c2ecf20Sopenharmony_ci	s32 prog_cal[3];
5728c2ecf20Sopenharmony_ci	s32 prog_tab[3];
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	i = tda18271_lookup_rf_band(fe, &freq, NULL);
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	if (tda_fail(i))
5778c2ecf20Sopenharmony_ci		return i;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	rf_default[RF1] = 1000 * map[i].rf1_def;
5808c2ecf20Sopenharmony_ci	rf_default[RF2] = 1000 * map[i].rf2_def;
5818c2ecf20Sopenharmony_ci	rf_default[RF3] = 1000 * map[i].rf3_def;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	for (rf = RF1; rf <= RF3; rf++) {
5848c2ecf20Sopenharmony_ci		if (0 == rf_default[rf])
5858c2ecf20Sopenharmony_ci			return 0;
5868c2ecf20Sopenharmony_ci		tda_cal("freq = %d, rf = %d\n", freq, rf);
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci		/* look for optimized calibration frequency */
5898c2ecf20Sopenharmony_ci		bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]);
5908c2ecf20Sopenharmony_ci		if (tda_fail(bcal))
5918c2ecf20Sopenharmony_ci			return bcal;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci		tda18271_calc_rf_cal(fe, &rf_freq[rf]);
5948c2ecf20Sopenharmony_ci		prog_tab[rf] = (s32)regs[R_EB14];
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci		if (1 == bcal)
5978c2ecf20Sopenharmony_ci			prog_cal[rf] =
5988c2ecf20Sopenharmony_ci				(s32)tda18271_calibrate_rf(fe, rf_freq[rf]);
5998c2ecf20Sopenharmony_ci		else
6008c2ecf20Sopenharmony_ci			prog_cal[rf] = prog_tab[rf];
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci		switch (rf) {
6038c2ecf20Sopenharmony_ci		case RF1:
6048c2ecf20Sopenharmony_ci			map[i].rf_a1 = 0;
6058c2ecf20Sopenharmony_ci			map[i].rf_b1 = (prog_cal[RF1] - prog_tab[RF1]);
6068c2ecf20Sopenharmony_ci			map[i].rf1   = rf_freq[RF1] / 1000;
6078c2ecf20Sopenharmony_ci			break;
6088c2ecf20Sopenharmony_ci		case RF2:
6098c2ecf20Sopenharmony_ci			dividend = (prog_cal[RF2] - prog_tab[RF2] -
6108c2ecf20Sopenharmony_ci				    prog_cal[RF1] + prog_tab[RF1]);
6118c2ecf20Sopenharmony_ci			divisor = (s32)(rf_freq[RF2] - rf_freq[RF1]) / 1000;
6128c2ecf20Sopenharmony_ci			map[i].rf_a1 = (dividend / divisor);
6138c2ecf20Sopenharmony_ci			map[i].rf2   = rf_freq[RF2] / 1000;
6148c2ecf20Sopenharmony_ci			break;
6158c2ecf20Sopenharmony_ci		case RF3:
6168c2ecf20Sopenharmony_ci			dividend = (prog_cal[RF3] - prog_tab[RF3] -
6178c2ecf20Sopenharmony_ci				    prog_cal[RF2] + prog_tab[RF2]);
6188c2ecf20Sopenharmony_ci			divisor = (s32)(rf_freq[RF3] - rf_freq[RF2]) / 1000;
6198c2ecf20Sopenharmony_ci			map[i].rf_a2 = (dividend / divisor);
6208c2ecf20Sopenharmony_ci			map[i].rf_b2 = (prog_cal[RF2] - prog_tab[RF2]);
6218c2ecf20Sopenharmony_ci			map[i].rf3   = rf_freq[RF3] / 1000;
6228c2ecf20Sopenharmony_ci			break;
6238c2ecf20Sopenharmony_ci		default:
6248c2ecf20Sopenharmony_ci			BUG();
6258c2ecf20Sopenharmony_ci		}
6268c2ecf20Sopenharmony_ci	}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	return 0;
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_cistatic int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe)
6328c2ecf20Sopenharmony_ci{
6338c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
6348c2ecf20Sopenharmony_ci	unsigned int i;
6358c2ecf20Sopenharmony_ci	int ret;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	tda_info("performing RF tracking filter calibration\n");
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	/* wait for die temperature stabilization */
6408c2ecf20Sopenharmony_ci	msleep(200);
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	ret = tda18271_powerscan_init(fe);
6438c2ecf20Sopenharmony_ci	if (tda_fail(ret))
6448c2ecf20Sopenharmony_ci		goto fail;
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	/* rf band calibration */
6478c2ecf20Sopenharmony_ci	for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++) {
6488c2ecf20Sopenharmony_ci		ret =
6498c2ecf20Sopenharmony_ci		tda18271_rf_tracking_filters_init(fe, 1000 *
6508c2ecf20Sopenharmony_ci						  priv->rf_cal_state[i].rfmax);
6518c2ecf20Sopenharmony_ci		if (tda_fail(ret))
6528c2ecf20Sopenharmony_ci			goto fail;
6538c2ecf20Sopenharmony_ci	}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	priv->tm_rfcal = tda18271_read_thermometer(fe);
6568c2ecf20Sopenharmony_cifail:
6578c2ecf20Sopenharmony_ci	return ret;
6588c2ecf20Sopenharmony_ci}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_cistatic int tda18271c2_rf_cal_init(struct dvb_frontend *fe)
6638c2ecf20Sopenharmony_ci{
6648c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
6658c2ecf20Sopenharmony_ci	unsigned char *regs = priv->tda18271_regs;
6668c2ecf20Sopenharmony_ci	int ret;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	/* test RF_CAL_OK to see if we need init */
6698c2ecf20Sopenharmony_ci	if ((regs[R_EP1] & 0x10) == 0)
6708c2ecf20Sopenharmony_ci		priv->cal_initialized = false;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	if (priv->cal_initialized)
6738c2ecf20Sopenharmony_ci		return 0;
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	ret = tda18271_calc_rf_filter_curve(fe);
6768c2ecf20Sopenharmony_ci	if (tda_fail(ret))
6778c2ecf20Sopenharmony_ci		goto fail;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	ret = tda18271_por(fe);
6808c2ecf20Sopenharmony_ci	if (tda_fail(ret))
6818c2ecf20Sopenharmony_ci		goto fail;
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	tda_info("RF tracking filter calibration complete\n");
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	priv->cal_initialized = true;
6868c2ecf20Sopenharmony_ci	goto end;
6878c2ecf20Sopenharmony_cifail:
6888c2ecf20Sopenharmony_ci	tda_info("RF tracking filter calibration failed!\n");
6898c2ecf20Sopenharmony_ciend:
6908c2ecf20Sopenharmony_ci	return ret;
6918c2ecf20Sopenharmony_ci}
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_cistatic int tda18271c1_rf_tracking_filter_calibration(struct dvb_frontend *fe,
6948c2ecf20Sopenharmony_ci						     u32 freq, u32 bw)
6958c2ecf20Sopenharmony_ci{
6968c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
6978c2ecf20Sopenharmony_ci	unsigned char *regs = priv->tda18271_regs;
6988c2ecf20Sopenharmony_ci	int ret;
6998c2ecf20Sopenharmony_ci	u32 N = 0;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	/* calculate bp filter */
7028c2ecf20Sopenharmony_ci	tda18271_calc_bp_filter(fe, &freq);
7038c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EP1, 1);
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	regs[R_EB4]  &= 0x07;
7068c2ecf20Sopenharmony_ci	regs[R_EB4]  |= 0x60;
7078c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EB4, 1);
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	regs[R_EB7]   = 0x60;
7108c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EB7, 1);
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	regs[R_EB14]  = 0x00;
7138c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EB14, 1);
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	regs[R_EB20]  = 0xcc;
7168c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EB20, 1);
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	/* set cal mode to RF tracking filter calibration */
7198c2ecf20Sopenharmony_ci	regs[R_EP4]  |= 0x03;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	/* calculate cal pll */
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	switch (priv->mode) {
7248c2ecf20Sopenharmony_ci	case TDA18271_ANALOG:
7258c2ecf20Sopenharmony_ci		N = freq - 1250000;
7268c2ecf20Sopenharmony_ci		break;
7278c2ecf20Sopenharmony_ci	case TDA18271_DIGITAL:
7288c2ecf20Sopenharmony_ci		N = freq + bw / 2;
7298c2ecf20Sopenharmony_ci		break;
7308c2ecf20Sopenharmony_ci	}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	tda18271_calc_cal_pll(fe, N);
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	/* calculate main pll */
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	switch (priv->mode) {
7378c2ecf20Sopenharmony_ci	case TDA18271_ANALOG:
7388c2ecf20Sopenharmony_ci		N = freq - 250000;
7398c2ecf20Sopenharmony_ci		break;
7408c2ecf20Sopenharmony_ci	case TDA18271_DIGITAL:
7418c2ecf20Sopenharmony_ci		N = freq + bw / 2 + 1000000;
7428c2ecf20Sopenharmony_ci		break;
7438c2ecf20Sopenharmony_ci	}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	tda18271_calc_main_pll(fe, N);
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	ret = tda18271_write_regs(fe, R_EP3, 11);
7488c2ecf20Sopenharmony_ci	if (tda_fail(ret))
7498c2ecf20Sopenharmony_ci		return ret;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	msleep(5); /* RF tracking filter calibration initialization */
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	/* search for K,M,CO for RF calibration */
7548c2ecf20Sopenharmony_ci	tda18271_calc_km(fe, &freq);
7558c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EB13, 1);
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	/* search for rf band */
7588c2ecf20Sopenharmony_ci	tda18271_calc_rf_band(fe, &freq);
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	/* search for gain taper */
7618c2ecf20Sopenharmony_ci	tda18271_calc_gain_taper(fe, &freq);
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EP2, 1);
7648c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EP1, 1);
7658c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EP2, 1);
7668c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EP1, 1);
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	regs[R_EB4]  &= 0x07;
7698c2ecf20Sopenharmony_ci	regs[R_EB4]  |= 0x40;
7708c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EB4, 1);
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	regs[R_EB7]   = 0x40;
7738c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EB7, 1);
7748c2ecf20Sopenharmony_ci	msleep(10); /* pll locking */
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	regs[R_EB20]  = 0xec;
7778c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EB20, 1);
7788c2ecf20Sopenharmony_ci	msleep(60); /* RF tracking filter calibration completion */
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	regs[R_EP4]  &= ~0x03; /* set cal mode to normal */
7818c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EP4, 1);
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	tda18271_write_regs(fe, R_EP1, 1);
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	/* RF tracking filter correction for VHF_Low band */
7868c2ecf20Sopenharmony_ci	if (0 == tda18271_calc_rf_cal(fe, &freq))
7878c2ecf20Sopenharmony_ci		tda18271_write_regs(fe, R_EB14, 1);
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	return 0;
7908c2ecf20Sopenharmony_ci}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_cistatic int tda18271_ir_cal_init(struct dvb_frontend *fe)
7958c2ecf20Sopenharmony_ci{
7968c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
7978c2ecf20Sopenharmony_ci	unsigned char *regs = priv->tda18271_regs;
7988c2ecf20Sopenharmony_ci	int ret;
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	ret = tda18271_read_regs(fe);
8018c2ecf20Sopenharmony_ci	if (tda_fail(ret))
8028c2ecf20Sopenharmony_ci		goto fail;
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	/* test IR_CAL_OK to see if we need init */
8058c2ecf20Sopenharmony_ci	if ((regs[R_EP1] & 0x08) == 0)
8068c2ecf20Sopenharmony_ci		ret = tda18271_init_regs(fe);
8078c2ecf20Sopenharmony_cifail:
8088c2ecf20Sopenharmony_ci	return ret;
8098c2ecf20Sopenharmony_ci}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_cistatic int tda18271_init(struct dvb_frontend *fe)
8128c2ecf20Sopenharmony_ci{
8138c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
8148c2ecf20Sopenharmony_ci	int ret;
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	mutex_lock(&priv->lock);
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	/* full power up */
8198c2ecf20Sopenharmony_ci	ret = tda18271_set_standby_mode(fe, 0, 0, 0);
8208c2ecf20Sopenharmony_ci	if (tda_fail(ret))
8218c2ecf20Sopenharmony_ci		goto fail;
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	/* initialization */
8248c2ecf20Sopenharmony_ci	ret = tda18271_ir_cal_init(fe);
8258c2ecf20Sopenharmony_ci	if (tda_fail(ret))
8268c2ecf20Sopenharmony_ci		goto fail;
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	if (priv->id == TDA18271HDC2)
8298c2ecf20Sopenharmony_ci		tda18271c2_rf_cal_init(fe);
8308c2ecf20Sopenharmony_cifail:
8318c2ecf20Sopenharmony_ci	mutex_unlock(&priv->lock);
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	return ret;
8348c2ecf20Sopenharmony_ci}
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_cistatic int tda18271_sleep(struct dvb_frontend *fe)
8378c2ecf20Sopenharmony_ci{
8388c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
8398c2ecf20Sopenharmony_ci	int ret;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	mutex_lock(&priv->lock);
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	/* enter standby mode, with required output features enabled */
8448c2ecf20Sopenharmony_ci	ret = tda18271_toggle_output(fe, 1);
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	mutex_unlock(&priv->lock);
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	return ret;
8498c2ecf20Sopenharmony_ci}
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_cistatic int tda18271_agc(struct dvb_frontend *fe)
8548c2ecf20Sopenharmony_ci{
8558c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
8568c2ecf20Sopenharmony_ci	int ret = 0;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	switch (priv->config) {
8598c2ecf20Sopenharmony_ci	case TDA8290_LNA_OFF:
8608c2ecf20Sopenharmony_ci		/* no external agc configuration required */
8618c2ecf20Sopenharmony_ci		if (tda18271_debug & DBG_ADV)
8628c2ecf20Sopenharmony_ci			tda_dbg("no agc configuration provided\n");
8638c2ecf20Sopenharmony_ci		break;
8648c2ecf20Sopenharmony_ci	case TDA8290_LNA_ON_BRIDGE:
8658c2ecf20Sopenharmony_ci		/* switch with GPIO of saa713x */
8668c2ecf20Sopenharmony_ci		tda_dbg("invoking callback\n");
8678c2ecf20Sopenharmony_ci		if (fe->callback)
8688c2ecf20Sopenharmony_ci			ret = fe->callback(priv->i2c_props.adap->algo_data,
8698c2ecf20Sopenharmony_ci					   DVB_FRONTEND_COMPONENT_TUNER,
8708c2ecf20Sopenharmony_ci					   TDA18271_CALLBACK_CMD_AGC_ENABLE,
8718c2ecf20Sopenharmony_ci					   priv->mode);
8728c2ecf20Sopenharmony_ci		break;
8738c2ecf20Sopenharmony_ci	case TDA8290_LNA_GP0_HIGH_ON:
8748c2ecf20Sopenharmony_ci	case TDA8290_LNA_GP0_HIGH_OFF:
8758c2ecf20Sopenharmony_ci	default:
8768c2ecf20Sopenharmony_ci		/* n/a - currently not supported */
8778c2ecf20Sopenharmony_ci		tda_err("unsupported configuration: %d\n", priv->config);
8788c2ecf20Sopenharmony_ci		ret = -EINVAL;
8798c2ecf20Sopenharmony_ci		break;
8808c2ecf20Sopenharmony_ci	}
8818c2ecf20Sopenharmony_ci	return ret;
8828c2ecf20Sopenharmony_ci}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_cistatic int tda18271_tune(struct dvb_frontend *fe,
8858c2ecf20Sopenharmony_ci			 struct tda18271_std_map_item *map, u32 freq, u32 bw)
8868c2ecf20Sopenharmony_ci{
8878c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
8888c2ecf20Sopenharmony_ci	int ret;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	tda_dbg("freq = %d, ifc = %d, bw = %d, agc_mode = %d, std = %d\n",
8918c2ecf20Sopenharmony_ci		freq, map->if_freq, bw, map->agc_mode, map->std);
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	ret = tda18271_agc(fe);
8948c2ecf20Sopenharmony_ci	if (tda_fail(ret))
8958c2ecf20Sopenharmony_ci		tda_warn("failed to configure agc\n");
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	ret = tda18271_init(fe);
8988c2ecf20Sopenharmony_ci	if (tda_fail(ret))
8998c2ecf20Sopenharmony_ci		goto fail;
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	mutex_lock(&priv->lock);
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	switch (priv->id) {
9048c2ecf20Sopenharmony_ci	case TDA18271HDC1:
9058c2ecf20Sopenharmony_ci		tda18271c1_rf_tracking_filter_calibration(fe, freq, bw);
9068c2ecf20Sopenharmony_ci		break;
9078c2ecf20Sopenharmony_ci	case TDA18271HDC2:
9088c2ecf20Sopenharmony_ci		tda18271c2_rf_tracking_filters_correction(fe, freq);
9098c2ecf20Sopenharmony_ci		break;
9108c2ecf20Sopenharmony_ci	}
9118c2ecf20Sopenharmony_ci	ret = tda18271_channel_configuration(fe, map, freq, bw);
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	mutex_unlock(&priv->lock);
9148c2ecf20Sopenharmony_cifail:
9158c2ecf20Sopenharmony_ci	return ret;
9168c2ecf20Sopenharmony_ci}
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_cistatic int tda18271_set_params(struct dvb_frontend *fe)
9218c2ecf20Sopenharmony_ci{
9228c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
9238c2ecf20Sopenharmony_ci	u32 delsys = c->delivery_system;
9248c2ecf20Sopenharmony_ci	u32 bw = c->bandwidth_hz;
9258c2ecf20Sopenharmony_ci	u32 freq = c->frequency;
9268c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
9278c2ecf20Sopenharmony_ci	struct tda18271_std_map *std_map = &priv->std;
9288c2ecf20Sopenharmony_ci	struct tda18271_std_map_item *map;
9298c2ecf20Sopenharmony_ci	int ret;
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	priv->mode = TDA18271_DIGITAL;
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	switch (delsys) {
9348c2ecf20Sopenharmony_ci	case SYS_ATSC:
9358c2ecf20Sopenharmony_ci		map = &std_map->atsc_6;
9368c2ecf20Sopenharmony_ci		bw = 6000000;
9378c2ecf20Sopenharmony_ci		break;
9388c2ecf20Sopenharmony_ci	case SYS_ISDBT:
9398c2ecf20Sopenharmony_ci	case SYS_DVBT:
9408c2ecf20Sopenharmony_ci	case SYS_DVBT2:
9418c2ecf20Sopenharmony_ci		if (bw <= 6000000) {
9428c2ecf20Sopenharmony_ci			map = &std_map->dvbt_6;
9438c2ecf20Sopenharmony_ci		} else if (bw <= 7000000) {
9448c2ecf20Sopenharmony_ci			map = &std_map->dvbt_7;
9458c2ecf20Sopenharmony_ci		} else {
9468c2ecf20Sopenharmony_ci			map = &std_map->dvbt_8;
9478c2ecf20Sopenharmony_ci		}
9488c2ecf20Sopenharmony_ci		break;
9498c2ecf20Sopenharmony_ci	case SYS_DVBC_ANNEX_B:
9508c2ecf20Sopenharmony_ci		bw = 6000000;
9518c2ecf20Sopenharmony_ci		fallthrough;
9528c2ecf20Sopenharmony_ci	case SYS_DVBC_ANNEX_A:
9538c2ecf20Sopenharmony_ci	case SYS_DVBC_ANNEX_C:
9548c2ecf20Sopenharmony_ci		if (bw <= 6000000) {
9558c2ecf20Sopenharmony_ci			map = &std_map->qam_6;
9568c2ecf20Sopenharmony_ci		} else if (bw <= 7000000) {
9578c2ecf20Sopenharmony_ci			map = &std_map->qam_7;
9588c2ecf20Sopenharmony_ci		} else {
9598c2ecf20Sopenharmony_ci			map = &std_map->qam_8;
9608c2ecf20Sopenharmony_ci		}
9618c2ecf20Sopenharmony_ci		break;
9628c2ecf20Sopenharmony_ci	default:
9638c2ecf20Sopenharmony_ci		tda_warn("modulation type not supported!\n");
9648c2ecf20Sopenharmony_ci		return -EINVAL;
9658c2ecf20Sopenharmony_ci	}
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	/* When tuning digital, the analog demod must be tri-stated */
9688c2ecf20Sopenharmony_ci	if (fe->ops.analog_ops.standby)
9698c2ecf20Sopenharmony_ci		fe->ops.analog_ops.standby(fe);
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	ret = tda18271_tune(fe, map, freq, bw);
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	if (tda_fail(ret))
9748c2ecf20Sopenharmony_ci		goto fail;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	priv->if_freq   = map->if_freq;
9778c2ecf20Sopenharmony_ci	priv->frequency = freq;
9788c2ecf20Sopenharmony_ci	priv->bandwidth = bw;
9798c2ecf20Sopenharmony_cifail:
9808c2ecf20Sopenharmony_ci	return ret;
9818c2ecf20Sopenharmony_ci}
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_cistatic int tda18271_set_analog_params(struct dvb_frontend *fe,
9848c2ecf20Sopenharmony_ci				      struct analog_parameters *params)
9858c2ecf20Sopenharmony_ci{
9868c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
9878c2ecf20Sopenharmony_ci	struct tda18271_std_map *std_map = &priv->std;
9888c2ecf20Sopenharmony_ci	struct tda18271_std_map_item *map;
9898c2ecf20Sopenharmony_ci	char *mode;
9908c2ecf20Sopenharmony_ci	int ret;
9918c2ecf20Sopenharmony_ci	u32 freq = params->frequency * 125 *
9928c2ecf20Sopenharmony_ci		((params->mode == V4L2_TUNER_RADIO) ? 1 : 1000) / 2;
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci	priv->mode = TDA18271_ANALOG;
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	if (params->mode == V4L2_TUNER_RADIO) {
9978c2ecf20Sopenharmony_ci		map = &std_map->fm_radio;
9988c2ecf20Sopenharmony_ci		mode = "fm";
9998c2ecf20Sopenharmony_ci	} else if (params->std & V4L2_STD_MN) {
10008c2ecf20Sopenharmony_ci		map = &std_map->atv_mn;
10018c2ecf20Sopenharmony_ci		mode = "MN";
10028c2ecf20Sopenharmony_ci	} else if (params->std & V4L2_STD_B) {
10038c2ecf20Sopenharmony_ci		map = &std_map->atv_b;
10048c2ecf20Sopenharmony_ci		mode = "B";
10058c2ecf20Sopenharmony_ci	} else if (params->std & V4L2_STD_GH) {
10068c2ecf20Sopenharmony_ci		map = &std_map->atv_gh;
10078c2ecf20Sopenharmony_ci		mode = "GH";
10088c2ecf20Sopenharmony_ci	} else if (params->std & V4L2_STD_PAL_I) {
10098c2ecf20Sopenharmony_ci		map = &std_map->atv_i;
10108c2ecf20Sopenharmony_ci		mode = "I";
10118c2ecf20Sopenharmony_ci	} else if (params->std & V4L2_STD_DK) {
10128c2ecf20Sopenharmony_ci		map = &std_map->atv_dk;
10138c2ecf20Sopenharmony_ci		mode = "DK";
10148c2ecf20Sopenharmony_ci	} else if (params->std & V4L2_STD_SECAM_L) {
10158c2ecf20Sopenharmony_ci		map = &std_map->atv_l;
10168c2ecf20Sopenharmony_ci		mode = "L";
10178c2ecf20Sopenharmony_ci	} else if (params->std & V4L2_STD_SECAM_LC) {
10188c2ecf20Sopenharmony_ci		map = &std_map->atv_lc;
10198c2ecf20Sopenharmony_ci		mode = "L'";
10208c2ecf20Sopenharmony_ci	} else {
10218c2ecf20Sopenharmony_ci		map = &std_map->atv_i;
10228c2ecf20Sopenharmony_ci		mode = "xx";
10238c2ecf20Sopenharmony_ci	}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	tda_dbg("setting tda18271 to system %s\n", mode);
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	ret = tda18271_tune(fe, map, freq, 0);
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	if (tda_fail(ret))
10308c2ecf20Sopenharmony_ci		goto fail;
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	priv->if_freq   = map->if_freq;
10338c2ecf20Sopenharmony_ci	priv->frequency = freq;
10348c2ecf20Sopenharmony_ci	priv->bandwidth = 0;
10358c2ecf20Sopenharmony_cifail:
10368c2ecf20Sopenharmony_ci	return ret;
10378c2ecf20Sopenharmony_ci}
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_cistatic void tda18271_release(struct dvb_frontend *fe)
10408c2ecf20Sopenharmony_ci{
10418c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	mutex_lock(&tda18271_list_mutex);
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	if (priv)
10468c2ecf20Sopenharmony_ci		hybrid_tuner_release_state(priv);
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	mutex_unlock(&tda18271_list_mutex);
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	fe->tuner_priv = NULL;
10518c2ecf20Sopenharmony_ci}
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_cistatic int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency)
10548c2ecf20Sopenharmony_ci{
10558c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
10568c2ecf20Sopenharmony_ci	*frequency = priv->frequency;
10578c2ecf20Sopenharmony_ci	return 0;
10588c2ecf20Sopenharmony_ci}
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_cistatic int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
10618c2ecf20Sopenharmony_ci{
10628c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
10638c2ecf20Sopenharmony_ci	*bandwidth = priv->bandwidth;
10648c2ecf20Sopenharmony_ci	return 0;
10658c2ecf20Sopenharmony_ci}
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_cistatic int tda18271_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
10688c2ecf20Sopenharmony_ci{
10698c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
10708c2ecf20Sopenharmony_ci	*frequency = (u32)priv->if_freq * 1000;
10718c2ecf20Sopenharmony_ci	return 0;
10728c2ecf20Sopenharmony_ci}
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci#define tda18271_update_std(std_cfg, name) do {				\
10778c2ecf20Sopenharmony_ci	if (map->std_cfg.if_freq +					\
10788c2ecf20Sopenharmony_ci		map->std_cfg.agc_mode + map->std_cfg.std +		\
10798c2ecf20Sopenharmony_ci		map->std_cfg.if_lvl + map->std_cfg.rfagc_top > 0) {	\
10808c2ecf20Sopenharmony_ci		tda_dbg("Using custom std config for %s\n", name);	\
10818c2ecf20Sopenharmony_ci		memcpy(&std->std_cfg, &map->std_cfg,			\
10828c2ecf20Sopenharmony_ci			sizeof(struct tda18271_std_map_item));		\
10838c2ecf20Sopenharmony_ci	} } while (0)
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci#define tda18271_dump_std_item(std_cfg, name) do {			\
10868c2ecf20Sopenharmony_ci	tda_dbg("(%s) if_freq = %d, agc_mode = %d, std = %d, "		\
10878c2ecf20Sopenharmony_ci		"if_lvl = %d, rfagc_top = 0x%02x\n",			\
10888c2ecf20Sopenharmony_ci		name, std->std_cfg.if_freq,				\
10898c2ecf20Sopenharmony_ci		std->std_cfg.agc_mode, std->std_cfg.std,		\
10908c2ecf20Sopenharmony_ci		std->std_cfg.if_lvl, std->std_cfg.rfagc_top);		\
10918c2ecf20Sopenharmony_ci	} while (0)
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_cistatic int tda18271_dump_std_map(struct dvb_frontend *fe)
10948c2ecf20Sopenharmony_ci{
10958c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
10968c2ecf20Sopenharmony_ci	struct tda18271_std_map *std = &priv->std;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	tda_dbg("========== STANDARD MAP SETTINGS ==========\n");
10998c2ecf20Sopenharmony_ci	tda18271_dump_std_item(fm_radio, "  fm  ");
11008c2ecf20Sopenharmony_ci	tda18271_dump_std_item(atv_b,  "atv b ");
11018c2ecf20Sopenharmony_ci	tda18271_dump_std_item(atv_dk, "atv dk");
11028c2ecf20Sopenharmony_ci	tda18271_dump_std_item(atv_gh, "atv gh");
11038c2ecf20Sopenharmony_ci	tda18271_dump_std_item(atv_i,  "atv i ");
11048c2ecf20Sopenharmony_ci	tda18271_dump_std_item(atv_l,  "atv l ");
11058c2ecf20Sopenharmony_ci	tda18271_dump_std_item(atv_lc, "atv l'");
11068c2ecf20Sopenharmony_ci	tda18271_dump_std_item(atv_mn, "atv mn");
11078c2ecf20Sopenharmony_ci	tda18271_dump_std_item(atsc_6, "atsc 6");
11088c2ecf20Sopenharmony_ci	tda18271_dump_std_item(dvbt_6, "dvbt 6");
11098c2ecf20Sopenharmony_ci	tda18271_dump_std_item(dvbt_7, "dvbt 7");
11108c2ecf20Sopenharmony_ci	tda18271_dump_std_item(dvbt_8, "dvbt 8");
11118c2ecf20Sopenharmony_ci	tda18271_dump_std_item(qam_6,  "qam 6 ");
11128c2ecf20Sopenharmony_ci	tda18271_dump_std_item(qam_7,  "qam 7 ");
11138c2ecf20Sopenharmony_ci	tda18271_dump_std_item(qam_8,  "qam 8 ");
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	return 0;
11168c2ecf20Sopenharmony_ci}
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_cistatic int tda18271_update_std_map(struct dvb_frontend *fe,
11198c2ecf20Sopenharmony_ci				   struct tda18271_std_map *map)
11208c2ecf20Sopenharmony_ci{
11218c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
11228c2ecf20Sopenharmony_ci	struct tda18271_std_map *std = &priv->std;
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	if (!map)
11258c2ecf20Sopenharmony_ci		return -EINVAL;
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci	tda18271_update_std(fm_radio, "fm");
11288c2ecf20Sopenharmony_ci	tda18271_update_std(atv_b,  "atv b");
11298c2ecf20Sopenharmony_ci	tda18271_update_std(atv_dk, "atv dk");
11308c2ecf20Sopenharmony_ci	tda18271_update_std(atv_gh, "atv gh");
11318c2ecf20Sopenharmony_ci	tda18271_update_std(atv_i,  "atv i");
11328c2ecf20Sopenharmony_ci	tda18271_update_std(atv_l,  "atv l");
11338c2ecf20Sopenharmony_ci	tda18271_update_std(atv_lc, "atv l'");
11348c2ecf20Sopenharmony_ci	tda18271_update_std(atv_mn, "atv mn");
11358c2ecf20Sopenharmony_ci	tda18271_update_std(atsc_6, "atsc 6");
11368c2ecf20Sopenharmony_ci	tda18271_update_std(dvbt_6, "dvbt 6");
11378c2ecf20Sopenharmony_ci	tda18271_update_std(dvbt_7, "dvbt 7");
11388c2ecf20Sopenharmony_ci	tda18271_update_std(dvbt_8, "dvbt 8");
11398c2ecf20Sopenharmony_ci	tda18271_update_std(qam_6,  "qam 6");
11408c2ecf20Sopenharmony_ci	tda18271_update_std(qam_7,  "qam 7");
11418c2ecf20Sopenharmony_ci	tda18271_update_std(qam_8,  "qam 8");
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci	return 0;
11448c2ecf20Sopenharmony_ci}
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_cistatic int tda18271_get_id(struct dvb_frontend *fe)
11478c2ecf20Sopenharmony_ci{
11488c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
11498c2ecf20Sopenharmony_ci	unsigned char *regs = priv->tda18271_regs;
11508c2ecf20Sopenharmony_ci	char *name;
11518c2ecf20Sopenharmony_ci	int ret;
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci	mutex_lock(&priv->lock);
11548c2ecf20Sopenharmony_ci	ret = tda18271_read_regs(fe);
11558c2ecf20Sopenharmony_ci	mutex_unlock(&priv->lock);
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	if (ret) {
11588c2ecf20Sopenharmony_ci		tda_info("Error reading device ID @ %d-%04x, bailing out.\n",
11598c2ecf20Sopenharmony_ci			 i2c_adapter_id(priv->i2c_props.adap),
11608c2ecf20Sopenharmony_ci			 priv->i2c_props.addr);
11618c2ecf20Sopenharmony_ci		return -EIO;
11628c2ecf20Sopenharmony_ci	}
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci	switch (regs[R_ID] & 0x7f) {
11658c2ecf20Sopenharmony_ci	case 3:
11668c2ecf20Sopenharmony_ci		name = "TDA18271HD/C1";
11678c2ecf20Sopenharmony_ci		priv->id = TDA18271HDC1;
11688c2ecf20Sopenharmony_ci		break;
11698c2ecf20Sopenharmony_ci	case 4:
11708c2ecf20Sopenharmony_ci		name = "TDA18271HD/C2";
11718c2ecf20Sopenharmony_ci		priv->id = TDA18271HDC2;
11728c2ecf20Sopenharmony_ci		break;
11738c2ecf20Sopenharmony_ci	default:
11748c2ecf20Sopenharmony_ci		tda_info("Unknown device (%i) detected @ %d-%04x, device not supported.\n",
11758c2ecf20Sopenharmony_ci			 regs[R_ID], i2c_adapter_id(priv->i2c_props.adap),
11768c2ecf20Sopenharmony_ci			 priv->i2c_props.addr);
11778c2ecf20Sopenharmony_ci		return -EINVAL;
11788c2ecf20Sopenharmony_ci	}
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	tda_info("%s detected @ %d-%04x\n", name,
11818c2ecf20Sopenharmony_ci		 i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr);
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci	return 0;
11848c2ecf20Sopenharmony_ci}
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_cistatic int tda18271_setup_configuration(struct dvb_frontend *fe,
11878c2ecf20Sopenharmony_ci					struct tda18271_config *cfg)
11888c2ecf20Sopenharmony_ci{
11898c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = fe->tuner_priv;
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
11928c2ecf20Sopenharmony_ci	priv->role = (cfg) ? cfg->role : TDA18271_MASTER;
11938c2ecf20Sopenharmony_ci	priv->config = (cfg) ? cfg->config : 0;
11948c2ecf20Sopenharmony_ci	priv->small_i2c = (cfg) ?
11958c2ecf20Sopenharmony_ci		cfg->small_i2c : TDA18271_39_BYTE_CHUNK_INIT;
11968c2ecf20Sopenharmony_ci	priv->output_opt = (cfg) ?
11978c2ecf20Sopenharmony_ci		cfg->output_opt : TDA18271_OUTPUT_LT_XT_ON;
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci	return 0;
12008c2ecf20Sopenharmony_ci}
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_cistatic inline int tda18271_need_cal_on_startup(struct tda18271_config *cfg)
12038c2ecf20Sopenharmony_ci{
12048c2ecf20Sopenharmony_ci	/* tda18271_cal_on_startup == -1 when cal module option is unset */
12058c2ecf20Sopenharmony_ci	return ((tda18271_cal_on_startup == -1) ?
12068c2ecf20Sopenharmony_ci		/* honor configuration setting */
12078c2ecf20Sopenharmony_ci		((cfg) && (cfg->rf_cal_on_startup)) :
12088c2ecf20Sopenharmony_ci		/* module option overrides configuration setting */
12098c2ecf20Sopenharmony_ci		(tda18271_cal_on_startup)) ? 1 : 0;
12108c2ecf20Sopenharmony_ci}
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_cistatic int tda18271_set_config(struct dvb_frontend *fe, void *priv_cfg)
12138c2ecf20Sopenharmony_ci{
12148c2ecf20Sopenharmony_ci	struct tda18271_config *cfg = (struct tda18271_config *) priv_cfg;
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	tda18271_setup_configuration(fe, cfg);
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	if (tda18271_need_cal_on_startup(cfg))
12198c2ecf20Sopenharmony_ci		tda18271_init(fe);
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	/* override default std map with values in config struct */
12228c2ecf20Sopenharmony_ci	if ((cfg) && (cfg->std_map))
12238c2ecf20Sopenharmony_ci		tda18271_update_std_map(fe, cfg->std_map);
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	return 0;
12268c2ecf20Sopenharmony_ci}
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_cistatic const struct dvb_tuner_ops tda18271_tuner_ops = {
12298c2ecf20Sopenharmony_ci	.info = {
12308c2ecf20Sopenharmony_ci		.name = "NXP TDA18271HD",
12318c2ecf20Sopenharmony_ci		.frequency_min_hz  =  45 * MHz,
12328c2ecf20Sopenharmony_ci		.frequency_max_hz  = 864 * MHz,
12338c2ecf20Sopenharmony_ci		.frequency_step_hz = 62500
12348c2ecf20Sopenharmony_ci	},
12358c2ecf20Sopenharmony_ci	.init              = tda18271_init,
12368c2ecf20Sopenharmony_ci	.sleep             = tda18271_sleep,
12378c2ecf20Sopenharmony_ci	.set_params        = tda18271_set_params,
12388c2ecf20Sopenharmony_ci	.set_analog_params = tda18271_set_analog_params,
12398c2ecf20Sopenharmony_ci	.release           = tda18271_release,
12408c2ecf20Sopenharmony_ci	.set_config        = tda18271_set_config,
12418c2ecf20Sopenharmony_ci	.get_frequency     = tda18271_get_frequency,
12428c2ecf20Sopenharmony_ci	.get_bandwidth     = tda18271_get_bandwidth,
12438c2ecf20Sopenharmony_ci	.get_if_frequency  = tda18271_get_if_frequency,
12448c2ecf20Sopenharmony_ci};
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_cistruct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
12478c2ecf20Sopenharmony_ci				     struct i2c_adapter *i2c,
12488c2ecf20Sopenharmony_ci				     struct tda18271_config *cfg)
12498c2ecf20Sopenharmony_ci{
12508c2ecf20Sopenharmony_ci	struct tda18271_priv *priv = NULL;
12518c2ecf20Sopenharmony_ci	int instance, ret;
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	mutex_lock(&tda18271_list_mutex);
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	instance = hybrid_tuner_request_state(struct tda18271_priv, priv,
12568c2ecf20Sopenharmony_ci					      hybrid_tuner_instance_list,
12578c2ecf20Sopenharmony_ci					      i2c, addr, "tda18271");
12588c2ecf20Sopenharmony_ci	switch (instance) {
12598c2ecf20Sopenharmony_ci	case 0:
12608c2ecf20Sopenharmony_ci		goto fail;
12618c2ecf20Sopenharmony_ci	case 1:
12628c2ecf20Sopenharmony_ci		/* new tuner instance */
12638c2ecf20Sopenharmony_ci		fe->tuner_priv = priv;
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci		tda18271_setup_configuration(fe, cfg);
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci		priv->cal_initialized = false;
12688c2ecf20Sopenharmony_ci		mutex_init(&priv->lock);
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci		ret = tda18271_get_id(fe);
12718c2ecf20Sopenharmony_ci		if (tda_fail(ret))
12728c2ecf20Sopenharmony_ci			goto fail;
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci		ret = tda18271_assign_map_layout(fe);
12758c2ecf20Sopenharmony_ci		if (tda_fail(ret))
12768c2ecf20Sopenharmony_ci			goto fail;
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci		/* if delay_cal is set, delay IR & RF calibration until init()
12798c2ecf20Sopenharmony_ci		 * module option 'cal' overrides this delay */
12808c2ecf20Sopenharmony_ci		if ((cfg->delay_cal) && (!tda18271_need_cal_on_startup(cfg)))
12818c2ecf20Sopenharmony_ci			break;
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci		mutex_lock(&priv->lock);
12848c2ecf20Sopenharmony_ci		tda18271_init_regs(fe);
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci		if ((tda18271_need_cal_on_startup(cfg)) &&
12878c2ecf20Sopenharmony_ci		    (priv->id == TDA18271HDC2))
12888c2ecf20Sopenharmony_ci			tda18271c2_rf_cal_init(fe);
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci		/* enter standby mode, with required output features enabled */
12918c2ecf20Sopenharmony_ci		ret = tda18271_toggle_output(fe, 1);
12928c2ecf20Sopenharmony_ci		tda_fail(ret);
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci		mutex_unlock(&priv->lock);
12958c2ecf20Sopenharmony_ci		break;
12968c2ecf20Sopenharmony_ci	default:
12978c2ecf20Sopenharmony_ci		/* existing tuner instance */
12988c2ecf20Sopenharmony_ci		fe->tuner_priv = priv;
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci		/* allow dvb driver to override configuration settings */
13018c2ecf20Sopenharmony_ci		if (cfg) {
13028c2ecf20Sopenharmony_ci			if (cfg->gate != TDA18271_GATE_ANALOG)
13038c2ecf20Sopenharmony_ci				priv->gate = cfg->gate;
13048c2ecf20Sopenharmony_ci			if (cfg->role)
13058c2ecf20Sopenharmony_ci				priv->role = cfg->role;
13068c2ecf20Sopenharmony_ci			if (cfg->config)
13078c2ecf20Sopenharmony_ci				priv->config = cfg->config;
13088c2ecf20Sopenharmony_ci			if (cfg->small_i2c)
13098c2ecf20Sopenharmony_ci				priv->small_i2c = cfg->small_i2c;
13108c2ecf20Sopenharmony_ci			if (cfg->output_opt)
13118c2ecf20Sopenharmony_ci				priv->output_opt = cfg->output_opt;
13128c2ecf20Sopenharmony_ci			if (cfg->std_map)
13138c2ecf20Sopenharmony_ci				tda18271_update_std_map(fe, cfg->std_map);
13148c2ecf20Sopenharmony_ci		}
13158c2ecf20Sopenharmony_ci		if (tda18271_need_cal_on_startup(cfg))
13168c2ecf20Sopenharmony_ci			tda18271_init(fe);
13178c2ecf20Sopenharmony_ci		break;
13188c2ecf20Sopenharmony_ci	}
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	/* override default std map with values in config struct */
13218c2ecf20Sopenharmony_ci	if ((cfg) && (cfg->std_map))
13228c2ecf20Sopenharmony_ci		tda18271_update_std_map(fe, cfg->std_map);
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_ci	mutex_unlock(&tda18271_list_mutex);
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci	memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops,
13278c2ecf20Sopenharmony_ci	       sizeof(struct dvb_tuner_ops));
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci	if (tda18271_debug & (DBG_MAP | DBG_ADV))
13308c2ecf20Sopenharmony_ci		tda18271_dump_std_map(fe);
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	return fe;
13338c2ecf20Sopenharmony_cifail:
13348c2ecf20Sopenharmony_ci	mutex_unlock(&tda18271_list_mutex);
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci	tda18271_release(fe);
13378c2ecf20Sopenharmony_ci	return NULL;
13388c2ecf20Sopenharmony_ci}
13398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tda18271_attach);
13408c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver");
13418c2ecf20Sopenharmony_ciMODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
13428c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
13438c2ecf20Sopenharmony_ciMODULE_VERSION("0.4");
1344