162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci i2c tv tuner chip device driver 562306a36Sopenharmony_ci controls the philips tda8290+75 tuner chip combo. 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci This "tda8290" module was split apart from the original "tuner" module. 962306a36Sopenharmony_ci*/ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/i2c.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/videodev2.h> 1562306a36Sopenharmony_ci#include "tuner-i2c.h" 1662306a36Sopenharmony_ci#include "tda8290.h" 1762306a36Sopenharmony_ci#include "tda827x.h" 1862306a36Sopenharmony_ci#include "tda18271.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic int debug; 2162306a36Sopenharmony_cimodule_param(debug, int, 0644); 2262306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "enable verbose debug messages"); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic int deemphasis_50; 2562306a36Sopenharmony_cimodule_param(deemphasis_50, int, 0644); 2662306a36Sopenharmony_ciMODULE_PARM_DESC(deemphasis_50, "0 - 75us deemphasis; 1 - 50us deemphasis"); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* ---------------------------------------------------------------------- */ 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistruct tda8290_priv { 3162306a36Sopenharmony_ci struct tuner_i2c_props i2c_props; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci unsigned char tda8290_easy_mode; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci unsigned char tda827x_addr; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci unsigned char ver; 3862306a36Sopenharmony_ci#define TDA8290 1 3962306a36Sopenharmony_ci#define TDA8295 2 4062306a36Sopenharmony_ci#define TDA8275 4 4162306a36Sopenharmony_ci#define TDA8275A 8 4262306a36Sopenharmony_ci#define TDA18271 16 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci struct tda827x_config cfg; 4562306a36Sopenharmony_ci struct tda18271_std_map *tda18271_std_map; 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/*---------------------------------------------------------------------*/ 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic int tda8290_i2c_bridge(struct dvb_frontend *fe, int close) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci struct tda8290_priv *priv = fe->analog_demod_priv; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci static unsigned char enable[2] = { 0x21, 0xC0 }; 5562306a36Sopenharmony_ci static unsigned char disable[2] = { 0x21, 0x00 }; 5662306a36Sopenharmony_ci unsigned char *msg; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (close) { 5962306a36Sopenharmony_ci msg = enable; 6062306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); 6162306a36Sopenharmony_ci /* let the bridge stabilize */ 6262306a36Sopenharmony_ci msleep(20); 6362306a36Sopenharmony_ci } else { 6462306a36Sopenharmony_ci msg = disable; 6562306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci return 0; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic int tda8295_i2c_bridge(struct dvb_frontend *fe, int close) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct tda8290_priv *priv = fe->analog_demod_priv; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci static unsigned char enable[2] = { 0x45, 0xc1 }; 7662306a36Sopenharmony_ci static unsigned char disable[2] = { 0x46, 0x00 }; 7762306a36Sopenharmony_ci static unsigned char buf[3] = { 0x45, 0x01, 0x00 }; 7862306a36Sopenharmony_ci unsigned char *msg; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (close) { 8162306a36Sopenharmony_ci msg = enable; 8262306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); 8362306a36Sopenharmony_ci /* let the bridge stabilize */ 8462306a36Sopenharmony_ci msleep(20); 8562306a36Sopenharmony_ci } else { 8662306a36Sopenharmony_ci msg = disable; 8762306a36Sopenharmony_ci tuner_i2c_xfer_send_recv(&priv->i2c_props, msg, 1, &msg[1], 1); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci buf[2] = msg[1]; 9062306a36Sopenharmony_ci buf[2] &= ~0x04; 9162306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, buf, 3); 9262306a36Sopenharmony_ci msleep(5); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci msg[1] |= 0x04; 9562306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return 0; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/*---------------------------------------------------------------------*/ 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic void set_audio(struct dvb_frontend *fe, 10462306a36Sopenharmony_ci struct analog_parameters *params) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct tda8290_priv *priv = fe->analog_demod_priv; 10762306a36Sopenharmony_ci char* mode; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (params->std & V4L2_STD_MN) { 11062306a36Sopenharmony_ci priv->tda8290_easy_mode = 0x01; 11162306a36Sopenharmony_ci mode = "MN"; 11262306a36Sopenharmony_ci } else if (params->std & V4L2_STD_B) { 11362306a36Sopenharmony_ci priv->tda8290_easy_mode = 0x02; 11462306a36Sopenharmony_ci mode = "B"; 11562306a36Sopenharmony_ci } else if (params->std & V4L2_STD_GH) { 11662306a36Sopenharmony_ci priv->tda8290_easy_mode = 0x04; 11762306a36Sopenharmony_ci mode = "GH"; 11862306a36Sopenharmony_ci } else if (params->std & V4L2_STD_PAL_I) { 11962306a36Sopenharmony_ci priv->tda8290_easy_mode = 0x08; 12062306a36Sopenharmony_ci mode = "I"; 12162306a36Sopenharmony_ci } else if (params->std & V4L2_STD_DK) { 12262306a36Sopenharmony_ci priv->tda8290_easy_mode = 0x10; 12362306a36Sopenharmony_ci mode = "DK"; 12462306a36Sopenharmony_ci } else if (params->std & V4L2_STD_SECAM_L) { 12562306a36Sopenharmony_ci priv->tda8290_easy_mode = 0x20; 12662306a36Sopenharmony_ci mode = "L"; 12762306a36Sopenharmony_ci } else if (params->std & V4L2_STD_SECAM_LC) { 12862306a36Sopenharmony_ci priv->tda8290_easy_mode = 0x40; 12962306a36Sopenharmony_ci mode = "LC"; 13062306a36Sopenharmony_ci } else { 13162306a36Sopenharmony_ci priv->tda8290_easy_mode = 0x10; 13262306a36Sopenharmony_ci mode = "xx"; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (params->mode == V4L2_TUNER_RADIO) { 13662306a36Sopenharmony_ci /* Set TDA8295 to FM radio; Start TDA8290 with MN values */ 13762306a36Sopenharmony_ci priv->tda8290_easy_mode = (priv->ver & TDA8295) ? 0x80 : 0x01; 13862306a36Sopenharmony_ci tuner_dbg("setting to radio FM\n"); 13962306a36Sopenharmony_ci } else { 14062306a36Sopenharmony_ci tuner_dbg("setting tda829x to system %s\n", mode); 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic struct { 14562306a36Sopenharmony_ci unsigned char seq[2]; 14662306a36Sopenharmony_ci} fm_mode[] = { 14762306a36Sopenharmony_ci { { 0x01, 0x81} }, /* Put device into expert mode */ 14862306a36Sopenharmony_ci { { 0x03, 0x48} }, /* Disable NOTCH and VIDEO filters */ 14962306a36Sopenharmony_ci { { 0x04, 0x04} }, /* Disable color carrier filter (SSIF) */ 15062306a36Sopenharmony_ci { { 0x05, 0x04} }, /* ADC headroom */ 15162306a36Sopenharmony_ci { { 0x06, 0x10} }, /* group delay flat */ 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci { { 0x07, 0x00} }, /* use the same radio DTO values as a tda8295 */ 15462306a36Sopenharmony_ci { { 0x08, 0x00} }, 15562306a36Sopenharmony_ci { { 0x09, 0x80} }, 15662306a36Sopenharmony_ci { { 0x0a, 0xda} }, 15762306a36Sopenharmony_ci { { 0x0b, 0x4b} }, 15862306a36Sopenharmony_ci { { 0x0c, 0x68} }, 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci { { 0x0d, 0x00} }, /* PLL off, no video carrier detect */ 16162306a36Sopenharmony_ci { { 0x14, 0x00} }, /* disable auto mute if no video */ 16262306a36Sopenharmony_ci}; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic void tda8290_set_params(struct dvb_frontend *fe, 16562306a36Sopenharmony_ci struct analog_parameters *params) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct tda8290_priv *priv = fe->analog_demod_priv; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci static unsigned char soft_reset[] = { 0x00, 0x00 }; 17062306a36Sopenharmony_ci unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode }; 17162306a36Sopenharmony_ci static unsigned char expert_mode[] = { 0x01, 0x80 }; 17262306a36Sopenharmony_ci static unsigned char agc_out_on[] = { 0x02, 0x00 }; 17362306a36Sopenharmony_ci static unsigned char gainset_off[] = { 0x28, 0x14 }; 17462306a36Sopenharmony_ci static unsigned char if_agc_spd[] = { 0x0f, 0x88 }; 17562306a36Sopenharmony_ci static unsigned char adc_head_6[] = { 0x05, 0x04 }; 17662306a36Sopenharmony_ci static unsigned char adc_head_9[] = { 0x05, 0x02 }; 17762306a36Sopenharmony_ci static unsigned char adc_head_12[] = { 0x05, 0x01 }; 17862306a36Sopenharmony_ci static unsigned char pll_bw_nom[] = { 0x0d, 0x47 }; 17962306a36Sopenharmony_ci static unsigned char pll_bw_low[] = { 0x0d, 0x27 }; 18062306a36Sopenharmony_ci static unsigned char gainset_2[] = { 0x28, 0x64 }; 18162306a36Sopenharmony_ci static unsigned char agc_rst_on[] = { 0x0e, 0x0b }; 18262306a36Sopenharmony_ci static unsigned char agc_rst_off[] = { 0x0e, 0x09 }; 18362306a36Sopenharmony_ci static unsigned char if_agc_set[] = { 0x0f, 0x81 }; 18462306a36Sopenharmony_ci static unsigned char addr_adc_sat = 0x1a; 18562306a36Sopenharmony_ci static unsigned char addr_agc_stat = 0x1d; 18662306a36Sopenharmony_ci static unsigned char addr_pll_stat = 0x1b; 18762306a36Sopenharmony_ci static unsigned char adc_sat = 0, agc_stat = 0, 18862306a36Sopenharmony_ci pll_stat; 18962306a36Sopenharmony_ci int i; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci set_audio(fe, params); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (priv->cfg.config) 19462306a36Sopenharmony_ci tuner_dbg("tda827xa config is 0x%02x\n", priv->cfg.config); 19562306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2); 19662306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2); 19762306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2); 19862306a36Sopenharmony_ci msleep(1); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (params->mode == V4L2_TUNER_RADIO) { 20162306a36Sopenharmony_ci unsigned char deemphasis[] = { 0x13, 1 }; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* FIXME: allow using a different deemphasis */ 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (deemphasis_50) 20662306a36Sopenharmony_ci deemphasis[1] = 2; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(fm_mode); i++) 20962306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, fm_mode[i].seq, 2); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, deemphasis, 2); 21262306a36Sopenharmony_ci } else { 21362306a36Sopenharmony_ci expert_mode[1] = priv->tda8290_easy_mode + 0x80; 21462306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2); 21562306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2); 21662306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2); 21762306a36Sopenharmony_ci if (priv->tda8290_easy_mode & 0x60) 21862306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2); 21962306a36Sopenharmony_ci else 22062306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2); 22162306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2); 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (fe->ops.analog_ops.i2c_gate_ctrl) 22662306a36Sopenharmony_ci fe->ops.analog_ops.i2c_gate_ctrl(fe, 1); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (fe->ops.tuner_ops.set_analog_params) 22962306a36Sopenharmony_ci fe->ops.tuner_ops.set_analog_params(fe, params); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci for (i = 0; i < 3; i++) { 23262306a36Sopenharmony_ci tuner_i2c_xfer_send_recv(&priv->i2c_props, 23362306a36Sopenharmony_ci &addr_pll_stat, 1, &pll_stat, 1); 23462306a36Sopenharmony_ci if (pll_stat & 0x80) { 23562306a36Sopenharmony_ci tuner_i2c_xfer_send_recv(&priv->i2c_props, 23662306a36Sopenharmony_ci &addr_adc_sat, 1, 23762306a36Sopenharmony_ci &adc_sat, 1); 23862306a36Sopenharmony_ci tuner_i2c_xfer_send_recv(&priv->i2c_props, 23962306a36Sopenharmony_ci &addr_agc_stat, 1, 24062306a36Sopenharmony_ci &agc_stat, 1); 24162306a36Sopenharmony_ci tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat); 24262306a36Sopenharmony_ci break; 24362306a36Sopenharmony_ci } else { 24462306a36Sopenharmony_ci tuner_dbg("tda8290 not locked, no signal?\n"); 24562306a36Sopenharmony_ci msleep(100); 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci /* adjust headroom resp. gain */ 24962306a36Sopenharmony_ci if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) { 25062306a36Sopenharmony_ci tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n", 25162306a36Sopenharmony_ci agc_stat, adc_sat, pll_stat & 0x80); 25262306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, gainset_2, 2); 25362306a36Sopenharmony_ci msleep(100); 25462306a36Sopenharmony_ci tuner_i2c_xfer_send_recv(&priv->i2c_props, 25562306a36Sopenharmony_ci &addr_agc_stat, 1, &agc_stat, 1); 25662306a36Sopenharmony_ci tuner_i2c_xfer_send_recv(&priv->i2c_props, 25762306a36Sopenharmony_ci &addr_pll_stat, 1, &pll_stat, 1); 25862306a36Sopenharmony_ci if ((agc_stat > 115) || !(pll_stat & 0x80)) { 25962306a36Sopenharmony_ci tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n", 26062306a36Sopenharmony_ci agc_stat, pll_stat & 0x80); 26162306a36Sopenharmony_ci if (priv->cfg.agcf) 26262306a36Sopenharmony_ci priv->cfg.agcf(fe); 26362306a36Sopenharmony_ci msleep(100); 26462306a36Sopenharmony_ci tuner_i2c_xfer_send_recv(&priv->i2c_props, 26562306a36Sopenharmony_ci &addr_agc_stat, 1, 26662306a36Sopenharmony_ci &agc_stat, 1); 26762306a36Sopenharmony_ci tuner_i2c_xfer_send_recv(&priv->i2c_props, 26862306a36Sopenharmony_ci &addr_pll_stat, 1, 26962306a36Sopenharmony_ci &pll_stat, 1); 27062306a36Sopenharmony_ci if((agc_stat > 115) || !(pll_stat & 0x80)) { 27162306a36Sopenharmony_ci tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat); 27262306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, adc_head_12, 2); 27362306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_low, 2); 27462306a36Sopenharmony_ci msleep(100); 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* l/ l' deadlock? */ 28062306a36Sopenharmony_ci if(priv->tda8290_easy_mode & 0x60) { 28162306a36Sopenharmony_ci tuner_i2c_xfer_send_recv(&priv->i2c_props, 28262306a36Sopenharmony_ci &addr_adc_sat, 1, 28362306a36Sopenharmony_ci &adc_sat, 1); 28462306a36Sopenharmony_ci tuner_i2c_xfer_send_recv(&priv->i2c_props, 28562306a36Sopenharmony_ci &addr_pll_stat, 1, 28662306a36Sopenharmony_ci &pll_stat, 1); 28762306a36Sopenharmony_ci if ((adc_sat > 20) || !(pll_stat & 0x80)) { 28862306a36Sopenharmony_ci tuner_dbg("trying to resolve SECAM L deadlock\n"); 28962306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_on, 2); 29062306a36Sopenharmony_ci msleep(40); 29162306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_off, 2); 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (fe->ops.analog_ops.i2c_gate_ctrl) 29662306a36Sopenharmony_ci fe->ops.analog_ops.i2c_gate_ctrl(fe, 0); 29762306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2); 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci/*---------------------------------------------------------------------*/ 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic void tda8295_power(struct dvb_frontend *fe, int enable) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct tda8290_priv *priv = fe->analog_demod_priv; 30562306a36Sopenharmony_ci unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */ 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (enable) 31062306a36Sopenharmony_ci buf[1] = 0x01; 31162306a36Sopenharmony_ci else 31262306a36Sopenharmony_ci buf[1] = 0x03; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct tda8290_priv *priv = fe->analog_demod_priv; 32062306a36Sopenharmony_ci unsigned char buf[] = { 0x01, 0x00 }; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (enable) 32562306a36Sopenharmony_ci buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */ 32662306a36Sopenharmony_ci else 32762306a36Sopenharmony_ci buf[1] = 0x00; /* reset active bit */ 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic void tda8295_set_video_std(struct dvb_frontend *fe) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci struct tda8290_priv *priv = fe->analog_demod_priv; 33562306a36Sopenharmony_ci unsigned char buf[] = { 0x00, priv->tda8290_easy_mode }; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci tda8295_set_easy_mode(fe, 1); 34062306a36Sopenharmony_ci msleep(20); 34162306a36Sopenharmony_ci tda8295_set_easy_mode(fe, 0); 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci/*---------------------------------------------------------------------*/ 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic void tda8295_agc1_out(struct dvb_frontend *fe, int enable) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci struct tda8290_priv *priv = fe->analog_demod_priv; 34962306a36Sopenharmony_ci unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */ 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (enable) 35462306a36Sopenharmony_ci buf[1] &= ~0x40; 35562306a36Sopenharmony_ci else 35662306a36Sopenharmony_ci buf[1] |= 0x40; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic void tda8295_agc2_out(struct dvb_frontend *fe, int enable) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci struct tda8290_priv *priv = fe->analog_demod_priv; 36462306a36Sopenharmony_ci unsigned char set_gpio_cf[] = { 0x44, 0x00 }; 36562306a36Sopenharmony_ci unsigned char set_gpio_val[] = { 0x46, 0x00 }; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci tuner_i2c_xfer_send_recv(&priv->i2c_props, 36862306a36Sopenharmony_ci &set_gpio_cf[0], 1, &set_gpio_cf[1], 1); 36962306a36Sopenharmony_ci tuner_i2c_xfer_send_recv(&priv->i2c_props, 37062306a36Sopenharmony_ci &set_gpio_val[0], 1, &set_gpio_val[1], 1); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */ 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci if (enable) { 37562306a36Sopenharmony_ci set_gpio_cf[1] |= 0x01; /* config GPIO_0 as Open Drain Out */ 37662306a36Sopenharmony_ci set_gpio_val[1] &= 0xfe; /* set GPIO_0 pin low */ 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_cf, 2); 37962306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2); 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic int tda8295_has_signal(struct dvb_frontend *fe, u16 *signal) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci struct tda8290_priv *priv = fe->analog_demod_priv; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci unsigned char hvpll_stat = 0x26; 38762306a36Sopenharmony_ci unsigned char ret; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci tuner_i2c_xfer_send_recv(&priv->i2c_props, &hvpll_stat, 1, &ret, 1); 39062306a36Sopenharmony_ci *signal = (ret & 0x01) ? 65535 : 0; 39162306a36Sopenharmony_ci return 0; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci/*---------------------------------------------------------------------*/ 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic void tda8295_set_params(struct dvb_frontend *fe, 39762306a36Sopenharmony_ci struct analog_parameters *params) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci struct tda8290_priv *priv = fe->analog_demod_priv; 40062306a36Sopenharmony_ci u16 signal = 0; 40162306a36Sopenharmony_ci unsigned char blanking_mode[] = { 0x1d, 0x00 }; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci set_audio(fe, params); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci tuner_dbg("%s: freq = %d\n", __func__, params->frequency); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci tda8295_power(fe, 1); 40862306a36Sopenharmony_ci tda8295_agc1_out(fe, 1); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci tuner_i2c_xfer_send_recv(&priv->i2c_props, 41162306a36Sopenharmony_ci &blanking_mode[0], 1, &blanking_mode[1], 1); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci tda8295_set_video_std(fe); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci blanking_mode[1] = 0x03; 41662306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2); 41762306a36Sopenharmony_ci msleep(20); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (fe->ops.analog_ops.i2c_gate_ctrl) 42062306a36Sopenharmony_ci fe->ops.analog_ops.i2c_gate_ctrl(fe, 1); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (fe->ops.tuner_ops.set_analog_params) 42362306a36Sopenharmony_ci fe->ops.tuner_ops.set_analog_params(fe, params); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (priv->cfg.agcf) 42662306a36Sopenharmony_ci priv->cfg.agcf(fe); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci tda8295_has_signal(fe, &signal); 42962306a36Sopenharmony_ci if (signal) 43062306a36Sopenharmony_ci tuner_dbg("tda8295 is locked\n"); 43162306a36Sopenharmony_ci else 43262306a36Sopenharmony_ci tuner_dbg("tda8295 not locked, no signal?\n"); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci if (fe->ops.analog_ops.i2c_gate_ctrl) 43562306a36Sopenharmony_ci fe->ops.analog_ops.i2c_gate_ctrl(fe, 0); 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci/*---------------------------------------------------------------------*/ 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic int tda8290_has_signal(struct dvb_frontend *fe, u16 *signal) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci struct tda8290_priv *priv = fe->analog_demod_priv; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci unsigned char i2c_get_afc[1] = { 0x1B }; 44562306a36Sopenharmony_ci unsigned char afc = 0; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci tuner_i2c_xfer_send_recv(&priv->i2c_props, 44862306a36Sopenharmony_ci i2c_get_afc, ARRAY_SIZE(i2c_get_afc), &afc, 1); 44962306a36Sopenharmony_ci *signal = (afc & 0x80) ? 65535 : 0; 45062306a36Sopenharmony_ci return 0; 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci/*---------------------------------------------------------------------*/ 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic void tda8290_standby(struct dvb_frontend *fe) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci struct tda8290_priv *priv = fe->analog_demod_priv; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci static unsigned char cb1[] = { 0x30, 0xD0 }; 46062306a36Sopenharmony_ci static unsigned char tda8290_standby[] = { 0x00, 0x02 }; 46162306a36Sopenharmony_ci static unsigned char tda8290_agc_tri[] = { 0x02, 0x20 }; 46262306a36Sopenharmony_ci struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci if (fe->ops.analog_ops.i2c_gate_ctrl) 46562306a36Sopenharmony_ci fe->ops.analog_ops.i2c_gate_ctrl(fe, 1); 46662306a36Sopenharmony_ci if (priv->ver & TDA8275A) 46762306a36Sopenharmony_ci cb1[1] = 0x90; 46862306a36Sopenharmony_ci i2c_transfer(priv->i2c_props.adap, &msg, 1); 46962306a36Sopenharmony_ci if (fe->ops.analog_ops.i2c_gate_ctrl) 47062306a36Sopenharmony_ci fe->ops.analog_ops.i2c_gate_ctrl(fe, 0); 47162306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2); 47262306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic void tda8295_standby(struct dvb_frontend *fe) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci tda8295_agc1_out(fe, 0); /* Put AGC in tri-state */ 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci tda8295_power(fe, 0); 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic void tda8290_init_if(struct dvb_frontend *fe) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci struct tda8290_priv *priv = fe->analog_demod_priv; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci static unsigned char set_VS[] = { 0x30, 0x6F }; 48762306a36Sopenharmony_ci static unsigned char set_GP00_CF[] = { 0x20, 0x01 }; 48862306a36Sopenharmony_ci static unsigned char set_GP01_CF[] = { 0x20, 0x0B }; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci if ((priv->cfg.config == TDA8290_LNA_GP0_HIGH_ON) || 49162306a36Sopenharmony_ci (priv->cfg.config == TDA8290_LNA_GP0_HIGH_OFF)) 49262306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2); 49362306a36Sopenharmony_ci else 49462306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2); 49562306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cistatic void tda8295_init_if(struct dvb_frontend *fe) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci struct tda8290_priv *priv = fe->analog_demod_priv; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci static unsigned char set_adc_ctl[] = { 0x33, 0x14 }; 50362306a36Sopenharmony_ci static unsigned char set_adc_ctl2[] = { 0x34, 0x00 }; 50462306a36Sopenharmony_ci static unsigned char set_pll_reg6[] = { 0x3e, 0x63 }; 50562306a36Sopenharmony_ci static unsigned char set_pll_reg0[] = { 0x38, 0x23 }; 50662306a36Sopenharmony_ci static unsigned char set_pll_reg7[] = { 0x3f, 0x01 }; 50762306a36Sopenharmony_ci static unsigned char set_pll_reg10[] = { 0x42, 0x61 }; 50862306a36Sopenharmony_ci static unsigned char set_gpio_reg0[] = { 0x44, 0x0b }; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci tda8295_power(fe, 1); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci tda8295_set_easy_mode(fe, 0); 51362306a36Sopenharmony_ci tda8295_set_video_std(fe); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl, 2); 51662306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl2, 2); 51762306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg6, 2); 51862306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg0, 2); 51962306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg7, 2); 52062306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg10, 2); 52162306a36Sopenharmony_ci tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_reg0, 2); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci tda8295_agc1_out(fe, 0); 52462306a36Sopenharmony_ci tda8295_agc2_out(fe, 0); 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic void tda8290_init_tuner(struct dvb_frontend *fe) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci struct tda8290_priv *priv = fe->analog_demod_priv; 53062306a36Sopenharmony_ci static unsigned char tda8275_init[] = 53162306a36Sopenharmony_ci { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf, 53262306a36Sopenharmony_ci 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; 53362306a36Sopenharmony_ci static unsigned char tda8275a_init[] = 53462306a36Sopenharmony_ci { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b, 53562306a36Sopenharmony_ci 0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b }; 53662306a36Sopenharmony_ci struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, 53762306a36Sopenharmony_ci .buf=tda8275_init, .len = 14}; 53862306a36Sopenharmony_ci if (priv->ver & TDA8275A) 53962306a36Sopenharmony_ci msg.buf = tda8275a_init; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (fe->ops.analog_ops.i2c_gate_ctrl) 54262306a36Sopenharmony_ci fe->ops.analog_ops.i2c_gate_ctrl(fe, 1); 54362306a36Sopenharmony_ci i2c_transfer(priv->i2c_props.adap, &msg, 1); 54462306a36Sopenharmony_ci if (fe->ops.analog_ops.i2c_gate_ctrl) 54562306a36Sopenharmony_ci fe->ops.analog_ops.i2c_gate_ctrl(fe, 0); 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci/*---------------------------------------------------------------------*/ 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_cistatic void tda829x_release(struct dvb_frontend *fe) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci struct tda8290_priv *priv = fe->analog_demod_priv; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci /* only try to release the tuner if we've 55562306a36Sopenharmony_ci * attached it from within this module */ 55662306a36Sopenharmony_ci if (priv->ver & (TDA18271 | TDA8275 | TDA8275A)) 55762306a36Sopenharmony_ci if (fe->ops.tuner_ops.release) 55862306a36Sopenharmony_ci fe->ops.tuner_ops.release(fe); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci kfree(fe->analog_demod_priv); 56162306a36Sopenharmony_ci fe->analog_demod_priv = NULL; 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_cistatic struct tda18271_config tda829x_tda18271_config = { 56562306a36Sopenharmony_ci .gate = TDA18271_GATE_ANALOG, 56662306a36Sopenharmony_ci}; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cistatic int tda829x_find_tuner(struct dvb_frontend *fe) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci struct tda8290_priv *priv = fe->analog_demod_priv; 57162306a36Sopenharmony_ci int i, ret, tuners_found; 57262306a36Sopenharmony_ci u32 tuner_addrs; 57362306a36Sopenharmony_ci u8 data; 57462306a36Sopenharmony_ci struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 }; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (fe->ops.analog_ops.i2c_gate_ctrl) 57762306a36Sopenharmony_ci fe->ops.analog_ops.i2c_gate_ctrl(fe, 1); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci /* probe for tuner chip */ 58062306a36Sopenharmony_ci tuners_found = 0; 58162306a36Sopenharmony_ci tuner_addrs = 0; 58262306a36Sopenharmony_ci for (i = 0x60; i <= 0x63; i++) { 58362306a36Sopenharmony_ci msg.addr = i; 58462306a36Sopenharmony_ci ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); 58562306a36Sopenharmony_ci if (ret == 1) { 58662306a36Sopenharmony_ci tuners_found++; 58762306a36Sopenharmony_ci tuner_addrs = (tuner_addrs << 8) + i; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci /* if there is more than one tuner, we expect the right one is 59162306a36Sopenharmony_ci behind the bridge and we choose the highest address that doesn't 59262306a36Sopenharmony_ci give a response now 59362306a36Sopenharmony_ci */ 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (fe->ops.analog_ops.i2c_gate_ctrl) 59662306a36Sopenharmony_ci fe->ops.analog_ops.i2c_gate_ctrl(fe, 0); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci if (tuners_found > 1) 59962306a36Sopenharmony_ci for (i = 0; i < tuners_found; i++) { 60062306a36Sopenharmony_ci msg.addr = tuner_addrs & 0xff; 60162306a36Sopenharmony_ci ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); 60262306a36Sopenharmony_ci if (ret == 1) 60362306a36Sopenharmony_ci tuner_addrs = tuner_addrs >> 8; 60462306a36Sopenharmony_ci else 60562306a36Sopenharmony_ci break; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci if (tuner_addrs == 0) { 60962306a36Sopenharmony_ci tuner_addrs = 0x60; 61062306a36Sopenharmony_ci tuner_info("could not clearly identify tuner address, defaulting to %x\n", 61162306a36Sopenharmony_ci tuner_addrs); 61262306a36Sopenharmony_ci } else { 61362306a36Sopenharmony_ci tuner_addrs = tuner_addrs & 0xff; 61462306a36Sopenharmony_ci tuner_info("setting tuner address to %x\n", tuner_addrs); 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci priv->tda827x_addr = tuner_addrs; 61762306a36Sopenharmony_ci msg.addr = tuner_addrs; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (fe->ops.analog_ops.i2c_gate_ctrl) 62062306a36Sopenharmony_ci fe->ops.analog_ops.i2c_gate_ctrl(fe, 1); 62162306a36Sopenharmony_ci ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (ret != 1) { 62462306a36Sopenharmony_ci tuner_warn("tuner access failed!\n"); 62562306a36Sopenharmony_ci if (fe->ops.analog_ops.i2c_gate_ctrl) 62662306a36Sopenharmony_ci fe->ops.analog_ops.i2c_gate_ctrl(fe, 0); 62762306a36Sopenharmony_ci return -EREMOTEIO; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if ((data == 0x83) || (data == 0x84)) { 63162306a36Sopenharmony_ci priv->ver |= TDA18271; 63262306a36Sopenharmony_ci tda829x_tda18271_config.config = priv->cfg.config; 63362306a36Sopenharmony_ci tda829x_tda18271_config.std_map = priv->tda18271_std_map; 63462306a36Sopenharmony_ci dvb_attach(tda18271_attach, fe, priv->tda827x_addr, 63562306a36Sopenharmony_ci priv->i2c_props.adap, &tda829x_tda18271_config); 63662306a36Sopenharmony_ci } else { 63762306a36Sopenharmony_ci if ((data & 0x3c) == 0) 63862306a36Sopenharmony_ci priv->ver |= TDA8275; 63962306a36Sopenharmony_ci else 64062306a36Sopenharmony_ci priv->ver |= TDA8275A; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci dvb_attach(tda827x_attach, fe, priv->tda827x_addr, 64362306a36Sopenharmony_ci priv->i2c_props.adap, &priv->cfg); 64462306a36Sopenharmony_ci priv->cfg.switch_addr = priv->i2c_props.addr; 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci if (fe->ops.tuner_ops.init) 64762306a36Sopenharmony_ci fe->ops.tuner_ops.init(fe); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci if (fe->ops.tuner_ops.sleep) 65062306a36Sopenharmony_ci fe->ops.tuner_ops.sleep(fe); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (fe->ops.analog_ops.i2c_gate_ctrl) 65362306a36Sopenharmony_ci fe->ops.analog_ops.i2c_gate_ctrl(fe, 0); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci return 0; 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic int tda8290_probe(struct tuner_i2c_props *i2c_props) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci#define TDA8290_ID 0x89 66162306a36Sopenharmony_ci u8 reg = 0x1f, id; 66262306a36Sopenharmony_ci struct i2c_msg msg_read[] = { 66362306a36Sopenharmony_ci { .addr = i2c_props->addr, .flags = 0, .len = 1, .buf = ® }, 66462306a36Sopenharmony_ci { .addr = i2c_props->addr, .flags = I2C_M_RD, .len = 1, .buf = &id }, 66562306a36Sopenharmony_ci }; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* detect tda8290 */ 66862306a36Sopenharmony_ci if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) { 66962306a36Sopenharmony_ci printk(KERN_WARNING "%s: couldn't read register 0x%02x\n", 67062306a36Sopenharmony_ci __func__, reg); 67162306a36Sopenharmony_ci return -ENODEV; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci if (id == TDA8290_ID) { 67562306a36Sopenharmony_ci if (debug) 67662306a36Sopenharmony_ci printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n", 67762306a36Sopenharmony_ci __func__, i2c_adapter_id(i2c_props->adap), 67862306a36Sopenharmony_ci i2c_props->addr); 67962306a36Sopenharmony_ci return 0; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci return -ENODEV; 68262306a36Sopenharmony_ci} 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_cistatic int tda8295_probe(struct tuner_i2c_props *i2c_props) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci#define TDA8295_ID 0x8a 68762306a36Sopenharmony_ci#define TDA8295C2_ID 0x8b 68862306a36Sopenharmony_ci u8 reg = 0x2f, id; 68962306a36Sopenharmony_ci struct i2c_msg msg_read[] = { 69062306a36Sopenharmony_ci { .addr = i2c_props->addr, .flags = 0, .len = 1, .buf = ® }, 69162306a36Sopenharmony_ci { .addr = i2c_props->addr, .flags = I2C_M_RD, .len = 1, .buf = &id }, 69262306a36Sopenharmony_ci }; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci /* detect tda8295 */ 69562306a36Sopenharmony_ci if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) { 69662306a36Sopenharmony_ci printk(KERN_WARNING "%s: couldn't read register 0x%02x\n", 69762306a36Sopenharmony_ci __func__, reg); 69862306a36Sopenharmony_ci return -ENODEV; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci if ((id & 0xfe) == TDA8295_ID) { 70262306a36Sopenharmony_ci if (debug) 70362306a36Sopenharmony_ci printk(KERN_DEBUG "%s: %s detected @ %d-%04x\n", 70462306a36Sopenharmony_ci __func__, (id == TDA8295_ID) ? 70562306a36Sopenharmony_ci "tda8295c1" : "tda8295c2", 70662306a36Sopenharmony_ci i2c_adapter_id(i2c_props->adap), 70762306a36Sopenharmony_ci i2c_props->addr); 70862306a36Sopenharmony_ci return 0; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci return -ENODEV; 71262306a36Sopenharmony_ci} 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_cistatic const struct analog_demod_ops tda8290_ops = { 71562306a36Sopenharmony_ci .set_params = tda8290_set_params, 71662306a36Sopenharmony_ci .has_signal = tda8290_has_signal, 71762306a36Sopenharmony_ci .standby = tda8290_standby, 71862306a36Sopenharmony_ci .release = tda829x_release, 71962306a36Sopenharmony_ci .i2c_gate_ctrl = tda8290_i2c_bridge, 72062306a36Sopenharmony_ci}; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_cistatic const struct analog_demod_ops tda8295_ops = { 72362306a36Sopenharmony_ci .set_params = tda8295_set_params, 72462306a36Sopenharmony_ci .has_signal = tda8295_has_signal, 72562306a36Sopenharmony_ci .standby = tda8295_standby, 72662306a36Sopenharmony_ci .release = tda829x_release, 72762306a36Sopenharmony_ci .i2c_gate_ctrl = tda8295_i2c_bridge, 72862306a36Sopenharmony_ci}; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cistruct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, 73162306a36Sopenharmony_ci struct i2c_adapter *i2c_adap, u8 i2c_addr, 73262306a36Sopenharmony_ci struct tda829x_config *cfg) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci struct tda8290_priv *priv = NULL; 73562306a36Sopenharmony_ci char *name; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); 73862306a36Sopenharmony_ci if (priv == NULL) 73962306a36Sopenharmony_ci return NULL; 74062306a36Sopenharmony_ci fe->analog_demod_priv = priv; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci priv->i2c_props.addr = i2c_addr; 74362306a36Sopenharmony_ci priv->i2c_props.adap = i2c_adap; 74462306a36Sopenharmony_ci priv->i2c_props.name = "tda829x"; 74562306a36Sopenharmony_ci if (cfg) { 74662306a36Sopenharmony_ci priv->cfg.config = cfg->lna_cfg; 74762306a36Sopenharmony_ci priv->tda18271_std_map = cfg->tda18271_std_map; 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci if (tda8290_probe(&priv->i2c_props) == 0) { 75162306a36Sopenharmony_ci priv->ver = TDA8290; 75262306a36Sopenharmony_ci memcpy(&fe->ops.analog_ops, &tda8290_ops, 75362306a36Sopenharmony_ci sizeof(struct analog_demod_ops)); 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci if (tda8295_probe(&priv->i2c_props) == 0) { 75762306a36Sopenharmony_ci priv->ver = TDA8295; 75862306a36Sopenharmony_ci memcpy(&fe->ops.analog_ops, &tda8295_ops, 75962306a36Sopenharmony_ci sizeof(struct analog_demod_ops)); 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci if (cfg && cfg->no_i2c_gate) 76362306a36Sopenharmony_ci fe->ops.analog_ops.i2c_gate_ctrl = NULL; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci if (!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) { 76662306a36Sopenharmony_ci tda8295_power(fe, 1); 76762306a36Sopenharmony_ci if (tda829x_find_tuner(fe) < 0) 76862306a36Sopenharmony_ci goto fail; 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci switch (priv->ver) { 77262306a36Sopenharmony_ci case TDA8290: 77362306a36Sopenharmony_ci name = "tda8290"; 77462306a36Sopenharmony_ci break; 77562306a36Sopenharmony_ci case TDA8295: 77662306a36Sopenharmony_ci name = "tda8295"; 77762306a36Sopenharmony_ci break; 77862306a36Sopenharmony_ci case TDA8290 | TDA8275: 77962306a36Sopenharmony_ci name = "tda8290+75"; 78062306a36Sopenharmony_ci break; 78162306a36Sopenharmony_ci case TDA8295 | TDA8275: 78262306a36Sopenharmony_ci name = "tda8295+75"; 78362306a36Sopenharmony_ci break; 78462306a36Sopenharmony_ci case TDA8290 | TDA8275A: 78562306a36Sopenharmony_ci name = "tda8290+75a"; 78662306a36Sopenharmony_ci break; 78762306a36Sopenharmony_ci case TDA8295 | TDA8275A: 78862306a36Sopenharmony_ci name = "tda8295+75a"; 78962306a36Sopenharmony_ci break; 79062306a36Sopenharmony_ci case TDA8290 | TDA18271: 79162306a36Sopenharmony_ci name = "tda8290+18271"; 79262306a36Sopenharmony_ci break; 79362306a36Sopenharmony_ci case TDA8295 | TDA18271: 79462306a36Sopenharmony_ci name = "tda8295+18271"; 79562306a36Sopenharmony_ci break; 79662306a36Sopenharmony_ci default: 79762306a36Sopenharmony_ci goto fail; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci tuner_info("type set to %s\n", name); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci fe->ops.analog_ops.info.name = name; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci if (priv->ver & TDA8290) { 80462306a36Sopenharmony_ci if (priv->ver & (TDA8275 | TDA8275A)) 80562306a36Sopenharmony_ci tda8290_init_tuner(fe); 80662306a36Sopenharmony_ci tda8290_init_if(fe); 80762306a36Sopenharmony_ci } else if (priv->ver & TDA8295) 80862306a36Sopenharmony_ci tda8295_init_if(fe); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci return fe; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_cifail: 81362306a36Sopenharmony_ci memset(&fe->ops.analog_ops, 0, sizeof(struct analog_demod_ops)); 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci tda829x_release(fe); 81662306a36Sopenharmony_ci return NULL; 81762306a36Sopenharmony_ci} 81862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tda829x_attach); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ciint tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci struct tuner_i2c_props i2c_props = { 82362306a36Sopenharmony_ci .adap = i2c_adap, 82462306a36Sopenharmony_ci .addr = i2c_addr, 82562306a36Sopenharmony_ci }; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci static unsigned char soft_reset[] = { 0x00, 0x00 }; 82862306a36Sopenharmony_ci static unsigned char easy_mode_b[] = { 0x01, 0x02 }; 82962306a36Sopenharmony_ci static unsigned char easy_mode_g[] = { 0x01, 0x04 }; 83062306a36Sopenharmony_ci static unsigned char restore_9886[] = { 0x00, 0xd6, 0x30 }; 83162306a36Sopenharmony_ci static unsigned char addr_dto_lsb = 0x07; 83262306a36Sopenharmony_ci unsigned char data; 83362306a36Sopenharmony_ci#define PROBE_BUFFER_SIZE 8 83462306a36Sopenharmony_ci unsigned char buf[PROBE_BUFFER_SIZE]; 83562306a36Sopenharmony_ci int i; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci /* rule out tda9887, which would return the same byte repeatedly */ 83862306a36Sopenharmony_ci tuner_i2c_xfer_send_recv(&i2c_props, 83962306a36Sopenharmony_ci soft_reset, 1, buf, PROBE_BUFFER_SIZE); 84062306a36Sopenharmony_ci for (i = 1; i < PROBE_BUFFER_SIZE; i++) { 84162306a36Sopenharmony_ci if (buf[i] != buf[0]) 84262306a36Sopenharmony_ci break; 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci /* all bytes are equal, not a tda829x - probably a tda9887 */ 84662306a36Sopenharmony_ci if (i == PROBE_BUFFER_SIZE) 84762306a36Sopenharmony_ci return -ENODEV; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci if ((tda8290_probe(&i2c_props) == 0) || 85062306a36Sopenharmony_ci (tda8295_probe(&i2c_props) == 0)) 85162306a36Sopenharmony_ci return 0; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci /* fall back to old probing method */ 85462306a36Sopenharmony_ci tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2); 85562306a36Sopenharmony_ci tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); 85662306a36Sopenharmony_ci tuner_i2c_xfer_send_recv(&i2c_props, &addr_dto_lsb, 1, &data, 1); 85762306a36Sopenharmony_ci if (data == 0) { 85862306a36Sopenharmony_ci tuner_i2c_xfer_send(&i2c_props, easy_mode_g, 2); 85962306a36Sopenharmony_ci tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); 86062306a36Sopenharmony_ci tuner_i2c_xfer_send_recv(&i2c_props, 86162306a36Sopenharmony_ci &addr_dto_lsb, 1, &data, 1); 86262306a36Sopenharmony_ci if (data == 0x7b) { 86362306a36Sopenharmony_ci return 0; 86462306a36Sopenharmony_ci } 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci tuner_i2c_xfer_send(&i2c_props, restore_9886, 3); 86762306a36Sopenharmony_ci return -ENODEV; 86862306a36Sopenharmony_ci} 86962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tda829x_probe); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ciMODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver"); 87262306a36Sopenharmony_ciMODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky"); 87362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 874