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