162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * (c) 2005 Hartmut Hackmann 562306a36Sopenharmony_ci * (c) 2007 Michael Krufky 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/slab.h> 1062306a36Sopenharmony_ci#include <asm/types.h> 1162306a36Sopenharmony_ci#include <linux/dvb/frontend.h> 1262306a36Sopenharmony_ci#include <linux/videodev2.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "tda827x.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic int debug; 1762306a36Sopenharmony_cimodule_param(debug, int, 0644); 1862306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define dprintk(args...) \ 2162306a36Sopenharmony_ci do { \ 2262306a36Sopenharmony_ci if (debug) printk(KERN_DEBUG "tda827x: " args); \ 2362306a36Sopenharmony_ci } while (0) 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistruct tda827x_priv { 2662306a36Sopenharmony_ci int i2c_addr; 2762306a36Sopenharmony_ci struct i2c_adapter *i2c_adap; 2862306a36Sopenharmony_ci struct tda827x_config *cfg; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci unsigned int sgIF; 3162306a36Sopenharmony_ci unsigned char lpsel; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci u32 frequency; 3462306a36Sopenharmony_ci u32 bandwidth; 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic void tda827x_set_std(struct dvb_frontend *fe, 3862306a36Sopenharmony_ci struct analog_parameters *params) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci struct tda827x_priv *priv = fe->tuner_priv; 4162306a36Sopenharmony_ci char *mode; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci priv->lpsel = 0; 4462306a36Sopenharmony_ci if (params->std & V4L2_STD_MN) { 4562306a36Sopenharmony_ci priv->sgIF = 92; 4662306a36Sopenharmony_ci priv->lpsel = 1; 4762306a36Sopenharmony_ci mode = "MN"; 4862306a36Sopenharmony_ci } else if (params->std & V4L2_STD_B) { 4962306a36Sopenharmony_ci priv->sgIF = 108; 5062306a36Sopenharmony_ci mode = "B"; 5162306a36Sopenharmony_ci } else if (params->std & V4L2_STD_GH) { 5262306a36Sopenharmony_ci priv->sgIF = 124; 5362306a36Sopenharmony_ci mode = "GH"; 5462306a36Sopenharmony_ci } else if (params->std & V4L2_STD_PAL_I) { 5562306a36Sopenharmony_ci priv->sgIF = 124; 5662306a36Sopenharmony_ci mode = "I"; 5762306a36Sopenharmony_ci } else if (params->std & V4L2_STD_DK) { 5862306a36Sopenharmony_ci priv->sgIF = 124; 5962306a36Sopenharmony_ci mode = "DK"; 6062306a36Sopenharmony_ci } else if (params->std & V4L2_STD_SECAM_L) { 6162306a36Sopenharmony_ci priv->sgIF = 124; 6262306a36Sopenharmony_ci mode = "L"; 6362306a36Sopenharmony_ci } else if (params->std & V4L2_STD_SECAM_LC) { 6462306a36Sopenharmony_ci priv->sgIF = 20; 6562306a36Sopenharmony_ci mode = "LC"; 6662306a36Sopenharmony_ci } else { 6762306a36Sopenharmony_ci priv->sgIF = 124; 6862306a36Sopenharmony_ci mode = "xx"; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci if (params->mode == V4L2_TUNER_RADIO) { 7262306a36Sopenharmony_ci priv->sgIF = 88; /* if frequency is 5.5 MHz */ 7362306a36Sopenharmony_ci dprintk("setting tda827x to radio FM\n"); 7462306a36Sopenharmony_ci } else 7562306a36Sopenharmony_ci dprintk("setting tda827x to system %s\n", mode); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* ------------------------------------------------------------------ */ 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistruct tda827x_data { 8262306a36Sopenharmony_ci u32 lomax; 8362306a36Sopenharmony_ci u8 spd; 8462306a36Sopenharmony_ci u8 bs; 8562306a36Sopenharmony_ci u8 bp; 8662306a36Sopenharmony_ci u8 cp; 8762306a36Sopenharmony_ci u8 gc3; 8862306a36Sopenharmony_ci u8 div1p5; 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic const struct tda827x_data tda827x_table[] = { 9262306a36Sopenharmony_ci { .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, 9362306a36Sopenharmony_ci { .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, 9462306a36Sopenharmony_ci { .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, 9562306a36Sopenharmony_ci { .lomax = 84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, 9662306a36Sopenharmony_ci { .lomax = 93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, 9762306a36Sopenharmony_ci { .lomax = 98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, 9862306a36Sopenharmony_ci { .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, 9962306a36Sopenharmony_ci { .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, 10062306a36Sopenharmony_ci { .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, 10162306a36Sopenharmony_ci { .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, 10262306a36Sopenharmony_ci { .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, 10362306a36Sopenharmony_ci { .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, 10462306a36Sopenharmony_ci { .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, 10562306a36Sopenharmony_ci { .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, 10662306a36Sopenharmony_ci { .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, 10762306a36Sopenharmony_ci { .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, 10862306a36Sopenharmony_ci { .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, 10962306a36Sopenharmony_ci { .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, 11062306a36Sopenharmony_ci { .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, 11162306a36Sopenharmony_ci { .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, 11262306a36Sopenharmony_ci { .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, 11362306a36Sopenharmony_ci { .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, 11462306a36Sopenharmony_ci { .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, 11562306a36Sopenharmony_ci { .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, 11662306a36Sopenharmony_ci { .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, 11762306a36Sopenharmony_ci { .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, 11862306a36Sopenharmony_ci { .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, 11962306a36Sopenharmony_ci { .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, 12062306a36Sopenharmony_ci { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic int tuner_transfer(struct dvb_frontend *fe, 12462306a36Sopenharmony_ci struct i2c_msg *msg, 12562306a36Sopenharmony_ci const int size) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci int rc; 12862306a36Sopenharmony_ci struct tda827x_priv *priv = fe->tuner_priv; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 13162306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 13262306a36Sopenharmony_ci rc = i2c_transfer(priv->i2c_adap, msg, size); 13362306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 13462306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (rc >= 0 && rc != size) 13762306a36Sopenharmony_ci return -EIO; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci return rc; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic int tda827xo_set_params(struct dvb_frontend *fe) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 14562306a36Sopenharmony_ci struct tda827x_priv *priv = fe->tuner_priv; 14662306a36Sopenharmony_ci u8 buf[14]; 14762306a36Sopenharmony_ci int rc; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, 15062306a36Sopenharmony_ci .buf = buf, .len = sizeof(buf) }; 15162306a36Sopenharmony_ci int i, tuner_freq, if_freq; 15262306a36Sopenharmony_ci u32 N; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci dprintk("%s:\n", __func__); 15562306a36Sopenharmony_ci if (c->bandwidth_hz == 0) { 15662306a36Sopenharmony_ci if_freq = 5000000; 15762306a36Sopenharmony_ci } else if (c->bandwidth_hz <= 6000000) { 15862306a36Sopenharmony_ci if_freq = 4000000; 15962306a36Sopenharmony_ci } else if (c->bandwidth_hz <= 7000000) { 16062306a36Sopenharmony_ci if_freq = 4500000; 16162306a36Sopenharmony_ci } else { /* 8 MHz */ 16262306a36Sopenharmony_ci if_freq = 5000000; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci tuner_freq = c->frequency; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci i = 0; 16762306a36Sopenharmony_ci while (tda827x_table[i].lomax < tuner_freq) { 16862306a36Sopenharmony_ci if (tda827x_table[i + 1].lomax == 0) 16962306a36Sopenharmony_ci break; 17062306a36Sopenharmony_ci i++; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci tuner_freq += if_freq; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2); 17662306a36Sopenharmony_ci buf[0] = 0; 17762306a36Sopenharmony_ci buf[1] = (N>>8) | 0x40; 17862306a36Sopenharmony_ci buf[2] = N & 0xff; 17962306a36Sopenharmony_ci buf[3] = 0; 18062306a36Sopenharmony_ci buf[4] = 0x52; 18162306a36Sopenharmony_ci buf[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) + 18262306a36Sopenharmony_ci (tda827x_table[i].bs << 3) + 18362306a36Sopenharmony_ci tda827x_table[i].bp; 18462306a36Sopenharmony_ci buf[6] = (tda827x_table[i].gc3 << 4) + 0x8f; 18562306a36Sopenharmony_ci buf[7] = 0xbf; 18662306a36Sopenharmony_ci buf[8] = 0x2a; 18762306a36Sopenharmony_ci buf[9] = 0x05; 18862306a36Sopenharmony_ci buf[10] = 0xff; 18962306a36Sopenharmony_ci buf[11] = 0x00; 19062306a36Sopenharmony_ci buf[12] = 0x00; 19162306a36Sopenharmony_ci buf[13] = 0x40; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci msg.len = 14; 19462306a36Sopenharmony_ci rc = tuner_transfer(fe, &msg, 1); 19562306a36Sopenharmony_ci if (rc < 0) 19662306a36Sopenharmony_ci goto err; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci msleep(500); 19962306a36Sopenharmony_ci /* correct CP value */ 20062306a36Sopenharmony_ci buf[0] = 0x30; 20162306a36Sopenharmony_ci buf[1] = 0x50 + tda827x_table[i].cp; 20262306a36Sopenharmony_ci msg.len = 2; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci rc = tuner_transfer(fe, &msg, 1); 20562306a36Sopenharmony_ci if (rc < 0) 20662306a36Sopenharmony_ci goto err; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci priv->frequency = c->frequency; 20962306a36Sopenharmony_ci priv->bandwidth = c->bandwidth_hz; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci return 0; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cierr: 21462306a36Sopenharmony_ci printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n", 21562306a36Sopenharmony_ci __func__, priv->i2c_addr << 1); 21662306a36Sopenharmony_ci return rc; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic int tda827xo_sleep(struct dvb_frontend *fe) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci struct tda827x_priv *priv = fe->tuner_priv; 22262306a36Sopenharmony_ci static u8 buf[] = { 0x30, 0xd0 }; 22362306a36Sopenharmony_ci struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, 22462306a36Sopenharmony_ci .buf = buf, .len = sizeof(buf) }; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci dprintk("%s:\n", __func__); 22762306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (priv->cfg && priv->cfg->sleep) 23062306a36Sopenharmony_ci priv->cfg->sleep(fe); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci return 0; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci/* ------------------------------------------------------------------ */ 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic int tda827xo_set_analog_params(struct dvb_frontend *fe, 23862306a36Sopenharmony_ci struct analog_parameters *params) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci unsigned char tuner_reg[8]; 24162306a36Sopenharmony_ci unsigned char reg2[2]; 24262306a36Sopenharmony_ci u32 N; 24362306a36Sopenharmony_ci int i; 24462306a36Sopenharmony_ci struct tda827x_priv *priv = fe->tuner_priv; 24562306a36Sopenharmony_ci struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 }; 24662306a36Sopenharmony_ci unsigned int freq = params->frequency; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci tda827x_set_std(fe, params); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (params->mode == V4L2_TUNER_RADIO) 25162306a36Sopenharmony_ci freq = freq / 1000; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci N = freq + priv->sgIF; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci i = 0; 25662306a36Sopenharmony_ci while (tda827x_table[i].lomax < N * 62500) { 25762306a36Sopenharmony_ci if (tda827x_table[i + 1].lomax == 0) 25862306a36Sopenharmony_ci break; 25962306a36Sopenharmony_ci i++; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci N = N << tda827x_table[i].spd; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci tuner_reg[0] = 0; 26562306a36Sopenharmony_ci tuner_reg[1] = (unsigned char)(N>>8); 26662306a36Sopenharmony_ci tuner_reg[2] = (unsigned char) N; 26762306a36Sopenharmony_ci tuner_reg[3] = 0x40; 26862306a36Sopenharmony_ci tuner_reg[4] = 0x52 + (priv->lpsel << 5); 26962306a36Sopenharmony_ci tuner_reg[5] = (tda827x_table[i].spd << 6) + 27062306a36Sopenharmony_ci (tda827x_table[i].div1p5 << 5) + 27162306a36Sopenharmony_ci (tda827x_table[i].bs << 3) + tda827x_table[i].bp; 27262306a36Sopenharmony_ci tuner_reg[6] = 0x8f + (tda827x_table[i].gc3 << 4); 27362306a36Sopenharmony_ci tuner_reg[7] = 0x8f; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci msg.buf = tuner_reg; 27662306a36Sopenharmony_ci msg.len = 8; 27762306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci msg.buf = reg2; 28062306a36Sopenharmony_ci msg.len = 2; 28162306a36Sopenharmony_ci reg2[0] = 0x80; 28262306a36Sopenharmony_ci reg2[1] = 0; 28362306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci reg2[0] = 0x60; 28662306a36Sopenharmony_ci reg2[1] = 0xbf; 28762306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci reg2[0] = 0x30; 29062306a36Sopenharmony_ci reg2[1] = tuner_reg[4] + 0x80; 29162306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci msleep(1); 29462306a36Sopenharmony_ci reg2[0] = 0x30; 29562306a36Sopenharmony_ci reg2[1] = tuner_reg[4] + 4; 29662306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci msleep(1); 29962306a36Sopenharmony_ci reg2[0] = 0x30; 30062306a36Sopenharmony_ci reg2[1] = tuner_reg[4]; 30162306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci msleep(550); 30462306a36Sopenharmony_ci reg2[0] = 0x30; 30562306a36Sopenharmony_ci reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp; 30662306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci reg2[0] = 0x60; 30962306a36Sopenharmony_ci reg2[1] = 0x3f; 31062306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci reg2[0] = 0x80; 31362306a36Sopenharmony_ci reg2[1] = 0x08; /* Vsync en */ 31462306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci priv->frequency = params->frequency; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci return 0; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic void tda827xo_agcf(struct dvb_frontend *fe) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci struct tda827x_priv *priv = fe->tuner_priv; 32462306a36Sopenharmony_ci unsigned char data[] = { 0x80, 0x0c }; 32562306a36Sopenharmony_ci struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, 32662306a36Sopenharmony_ci .buf = data, .len = 2}; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci/* ------------------------------------------------------------------ */ 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistruct tda827xa_data { 33462306a36Sopenharmony_ci u32 lomax; 33562306a36Sopenharmony_ci u8 svco; 33662306a36Sopenharmony_ci u8 spd; 33762306a36Sopenharmony_ci u8 scr; 33862306a36Sopenharmony_ci u8 sbs; 33962306a36Sopenharmony_ci u8 gc3; 34062306a36Sopenharmony_ci}; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic struct tda827xa_data tda827xa_dvbt[] = { 34362306a36Sopenharmony_ci { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1}, 34462306a36Sopenharmony_ci { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, 34562306a36Sopenharmony_ci { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, 34662306a36Sopenharmony_ci { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, 34762306a36Sopenharmony_ci { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, 34862306a36Sopenharmony_ci { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, 34962306a36Sopenharmony_ci { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, 35062306a36Sopenharmony_ci { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, 35162306a36Sopenharmony_ci { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, 35262306a36Sopenharmony_ci { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, 35362306a36Sopenharmony_ci { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, 35462306a36Sopenharmony_ci { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, 35562306a36Sopenharmony_ci { .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, 35662306a36Sopenharmony_ci { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, 35762306a36Sopenharmony_ci { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, 35862306a36Sopenharmony_ci { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, 35962306a36Sopenharmony_ci { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, 36062306a36Sopenharmony_ci { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, 36162306a36Sopenharmony_ci { .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, 36262306a36Sopenharmony_ci { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, 36362306a36Sopenharmony_ci { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, 36462306a36Sopenharmony_ci { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, 36562306a36Sopenharmony_ci { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, 36662306a36Sopenharmony_ci { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, 36762306a36Sopenharmony_ci { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, 36862306a36Sopenharmony_ci { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, 36962306a36Sopenharmony_ci { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} 37062306a36Sopenharmony_ci}; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic struct tda827xa_data tda827xa_dvbc[] = { 37362306a36Sopenharmony_ci { .lomax = 50125000, .svco = 2, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3}, 37462306a36Sopenharmony_ci { .lomax = 58500000, .svco = 3, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3}, 37562306a36Sopenharmony_ci { .lomax = 69250000, .svco = 0, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3}, 37662306a36Sopenharmony_ci { .lomax = 83625000, .svco = 1, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3}, 37762306a36Sopenharmony_ci { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3}, 37862306a36Sopenharmony_ci { .lomax = 100250000, .svco = 2, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1}, 37962306a36Sopenharmony_ci { .lomax = 117000000, .svco = 3, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1}, 38062306a36Sopenharmony_ci { .lomax = 138500000, .svco = 0, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1}, 38162306a36Sopenharmony_ci { .lomax = 167250000, .svco = 1, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1}, 38262306a36Sopenharmony_ci { .lomax = 187000000, .svco = 2, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1}, 38362306a36Sopenharmony_ci { .lomax = 200500000, .svco = 2, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 1}, 38462306a36Sopenharmony_ci { .lomax = 234000000, .svco = 3, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 3}, 38562306a36Sopenharmony_ci { .lomax = 277000000, .svco = 0, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 3}, 38662306a36Sopenharmony_ci { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 1}, 38762306a36Sopenharmony_ci { .lomax = 334500000, .svco = 1, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3}, 38862306a36Sopenharmony_ci { .lomax = 401000000, .svco = 2, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3}, 38962306a36Sopenharmony_ci { .lomax = 468000000, .svco = 3, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 1}, 39062306a36Sopenharmony_ci { .lomax = 535000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, 39162306a36Sopenharmony_ci { .lomax = 554000000, .svco = 0, .spd = 0, .scr = 2, .sbs = 3, .gc3 = 1}, 39262306a36Sopenharmony_ci { .lomax = 638000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, 39362306a36Sopenharmony_ci { .lomax = 669000000, .svco = 1, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1}, 39462306a36Sopenharmony_ci { .lomax = 720000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, 39562306a36Sopenharmony_ci { .lomax = 802000000, .svco = 2, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1}, 39662306a36Sopenharmony_ci { .lomax = 835000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, 39762306a36Sopenharmony_ci { .lomax = 885000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, 39862306a36Sopenharmony_ci { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1}, 39962306a36Sopenharmony_ci { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} 40062306a36Sopenharmony_ci}; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic struct tda827xa_data tda827xa_analog[] = { 40362306a36Sopenharmony_ci { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3}, 40462306a36Sopenharmony_ci { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, 40562306a36Sopenharmony_ci { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, 40662306a36Sopenharmony_ci { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, 40762306a36Sopenharmony_ci { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, 40862306a36Sopenharmony_ci { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, 40962306a36Sopenharmony_ci { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, 41062306a36Sopenharmony_ci { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, 41162306a36Sopenharmony_ci { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, 41262306a36Sopenharmony_ci { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, 41362306a36Sopenharmony_ci { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3}, 41462306a36Sopenharmony_ci { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3}, 41562306a36Sopenharmony_ci { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, 41662306a36Sopenharmony_ci { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, 41762306a36Sopenharmony_ci { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, 41862306a36Sopenharmony_ci { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, 41962306a36Sopenharmony_ci { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, 42062306a36Sopenharmony_ci { .lomax = 554000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, 42162306a36Sopenharmony_ci { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, 42262306a36Sopenharmony_ci { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, 42362306a36Sopenharmony_ci { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, 42462306a36Sopenharmony_ci { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, 42562306a36Sopenharmony_ci { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, 42662306a36Sopenharmony_ci { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, 42762306a36Sopenharmony_ci { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, 42862306a36Sopenharmony_ci { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} 42962306a36Sopenharmony_ci}; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic int tda827xa_sleep(struct dvb_frontend *fe) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci struct tda827x_priv *priv = fe->tuner_priv; 43462306a36Sopenharmony_ci static u8 buf[] = { 0x30, 0x90 }; 43562306a36Sopenharmony_ci struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, 43662306a36Sopenharmony_ci .buf = buf, .len = sizeof(buf) }; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci dprintk("%s:\n", __func__); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (priv->cfg && priv->cfg->sleep) 44362306a36Sopenharmony_ci priv->cfg->sleep(fe); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci return 0; 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic void tda827xa_lna_gain(struct dvb_frontend *fe, int high, 44962306a36Sopenharmony_ci struct analog_parameters *params) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci struct tda827x_priv *priv = fe->tuner_priv; 45262306a36Sopenharmony_ci unsigned char buf[] = {0x22, 0x01}; 45362306a36Sopenharmony_ci int arg; 45462306a36Sopenharmony_ci int gp_func; 45562306a36Sopenharmony_ci struct i2c_msg msg = { .flags = 0, .buf = buf, .len = sizeof(buf) }; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if (NULL == priv->cfg) { 45862306a36Sopenharmony_ci dprintk("tda827x_config not defined, cannot set LNA gain!\n"); 45962306a36Sopenharmony_ci return; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci msg.addr = priv->cfg->switch_addr; 46262306a36Sopenharmony_ci if (priv->cfg->config) { 46362306a36Sopenharmony_ci if (high) 46462306a36Sopenharmony_ci dprintk("setting LNA to high gain\n"); 46562306a36Sopenharmony_ci else 46662306a36Sopenharmony_ci dprintk("setting LNA to low gain\n"); 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci switch (priv->cfg->config) { 46962306a36Sopenharmony_ci case TDA8290_LNA_OFF: /* no LNA */ 47062306a36Sopenharmony_ci break; 47162306a36Sopenharmony_ci case TDA8290_LNA_GP0_HIGH_ON: /* switch is GPIO 0 of tda8290 */ 47262306a36Sopenharmony_ci case TDA8290_LNA_GP0_HIGH_OFF: 47362306a36Sopenharmony_ci if (params == NULL) { 47462306a36Sopenharmony_ci gp_func = 0; 47562306a36Sopenharmony_ci arg = 0; 47662306a36Sopenharmony_ci } else { 47762306a36Sopenharmony_ci /* turn Vsync on */ 47862306a36Sopenharmony_ci gp_func = 1; 47962306a36Sopenharmony_ci if (params->std & V4L2_STD_MN) 48062306a36Sopenharmony_ci arg = 1; 48162306a36Sopenharmony_ci else 48262306a36Sopenharmony_ci arg = 0; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci if (fe->callback) 48562306a36Sopenharmony_ci fe->callback(priv->i2c_adap->algo_data, 48662306a36Sopenharmony_ci DVB_FRONTEND_COMPONENT_TUNER, 48762306a36Sopenharmony_ci gp_func, arg); 48862306a36Sopenharmony_ci buf[1] = high ? 0 : 1; 48962306a36Sopenharmony_ci if (priv->cfg->config == TDA8290_LNA_GP0_HIGH_OFF) 49062306a36Sopenharmony_ci buf[1] = high ? 1 : 0; 49162306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 49262306a36Sopenharmony_ci break; 49362306a36Sopenharmony_ci case TDA8290_LNA_ON_BRIDGE: /* switch with GPIO of saa713x */ 49462306a36Sopenharmony_ci if (fe->callback) 49562306a36Sopenharmony_ci fe->callback(priv->i2c_adap->algo_data, 49662306a36Sopenharmony_ci DVB_FRONTEND_COMPONENT_TUNER, 0, high); 49762306a36Sopenharmony_ci break; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic int tda827xa_set_params(struct dvb_frontend *fe) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 50462306a36Sopenharmony_ci struct tda827x_priv *priv = fe->tuner_priv; 50562306a36Sopenharmony_ci struct tda827xa_data *frequency_map = tda827xa_dvbt; 50662306a36Sopenharmony_ci u8 buf[11]; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, 50962306a36Sopenharmony_ci .buf = buf, .len = sizeof(buf) }; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci int i, tuner_freq, if_freq, rc; 51262306a36Sopenharmony_ci u32 N; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci dprintk("%s:\n", __func__); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci tda827xa_lna_gain(fe, 1, NULL); 51762306a36Sopenharmony_ci msleep(20); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (c->bandwidth_hz == 0) { 52062306a36Sopenharmony_ci if_freq = 5000000; 52162306a36Sopenharmony_ci } else if (c->bandwidth_hz <= 6000000) { 52262306a36Sopenharmony_ci if_freq = 4000000; 52362306a36Sopenharmony_ci } else if (c->bandwidth_hz <= 7000000) { 52462306a36Sopenharmony_ci if_freq = 4500000; 52562306a36Sopenharmony_ci } else { /* 8 MHz */ 52662306a36Sopenharmony_ci if_freq = 5000000; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci tuner_freq = c->frequency; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci switch (c->delivery_system) { 53162306a36Sopenharmony_ci case SYS_DVBC_ANNEX_A: 53262306a36Sopenharmony_ci case SYS_DVBC_ANNEX_C: 53362306a36Sopenharmony_ci dprintk("%s select tda827xa_dvbc\n", __func__); 53462306a36Sopenharmony_ci frequency_map = tda827xa_dvbc; 53562306a36Sopenharmony_ci break; 53662306a36Sopenharmony_ci default: 53762306a36Sopenharmony_ci break; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci i = 0; 54162306a36Sopenharmony_ci while (frequency_map[i].lomax < tuner_freq) { 54262306a36Sopenharmony_ci if (frequency_map[i + 1].lomax == 0) 54362306a36Sopenharmony_ci break; 54462306a36Sopenharmony_ci i++; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci tuner_freq += if_freq; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci N = ((tuner_freq + 31250) / 62500) << frequency_map[i].spd; 55062306a36Sopenharmony_ci buf[0] = 0; // subaddress 55162306a36Sopenharmony_ci buf[1] = N >> 8; 55262306a36Sopenharmony_ci buf[2] = N & 0xff; 55362306a36Sopenharmony_ci buf[3] = 0; 55462306a36Sopenharmony_ci buf[4] = 0x16; 55562306a36Sopenharmony_ci buf[5] = (frequency_map[i].spd << 5) + (frequency_map[i].svco << 3) + 55662306a36Sopenharmony_ci frequency_map[i].sbs; 55762306a36Sopenharmony_ci buf[6] = 0x4b + (frequency_map[i].gc3 << 4); 55862306a36Sopenharmony_ci buf[7] = 0x1c; 55962306a36Sopenharmony_ci buf[8] = 0x06; 56062306a36Sopenharmony_ci buf[9] = 0x24; 56162306a36Sopenharmony_ci buf[10] = 0x00; 56262306a36Sopenharmony_ci msg.len = 11; 56362306a36Sopenharmony_ci rc = tuner_transfer(fe, &msg, 1); 56462306a36Sopenharmony_ci if (rc < 0) 56562306a36Sopenharmony_ci goto err; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci buf[0] = 0x90; 56862306a36Sopenharmony_ci buf[1] = 0xff; 56962306a36Sopenharmony_ci buf[2] = 0x60; 57062306a36Sopenharmony_ci buf[3] = 0x00; 57162306a36Sopenharmony_ci buf[4] = 0x59; // lpsel, for 6MHz + 2 57262306a36Sopenharmony_ci msg.len = 5; 57362306a36Sopenharmony_ci rc = tuner_transfer(fe, &msg, 1); 57462306a36Sopenharmony_ci if (rc < 0) 57562306a36Sopenharmony_ci goto err; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci buf[0] = 0xa0; 57862306a36Sopenharmony_ci buf[1] = 0x40; 57962306a36Sopenharmony_ci msg.len = 2; 58062306a36Sopenharmony_ci rc = tuner_transfer(fe, &msg, 1); 58162306a36Sopenharmony_ci if (rc < 0) 58262306a36Sopenharmony_ci goto err; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci msleep(11); 58562306a36Sopenharmony_ci msg.flags = I2C_M_RD; 58662306a36Sopenharmony_ci rc = tuner_transfer(fe, &msg, 1); 58762306a36Sopenharmony_ci if (rc < 0) 58862306a36Sopenharmony_ci goto err; 58962306a36Sopenharmony_ci msg.flags = 0; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci buf[1] >>= 4; 59262306a36Sopenharmony_ci dprintk("tda8275a AGC2 gain is: %d\n", buf[1]); 59362306a36Sopenharmony_ci if ((buf[1]) < 2) { 59462306a36Sopenharmony_ci tda827xa_lna_gain(fe, 0, NULL); 59562306a36Sopenharmony_ci buf[0] = 0x60; 59662306a36Sopenharmony_ci buf[1] = 0x0c; 59762306a36Sopenharmony_ci rc = tuner_transfer(fe, &msg, 1); 59862306a36Sopenharmony_ci if (rc < 0) 59962306a36Sopenharmony_ci goto err; 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci buf[0] = 0xc0; 60362306a36Sopenharmony_ci buf[1] = 0x99; // lpsel, for 6MHz + 2 60462306a36Sopenharmony_ci rc = tuner_transfer(fe, &msg, 1); 60562306a36Sopenharmony_ci if (rc < 0) 60662306a36Sopenharmony_ci goto err; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci buf[0] = 0x60; 60962306a36Sopenharmony_ci buf[1] = 0x3c; 61062306a36Sopenharmony_ci rc = tuner_transfer(fe, &msg, 1); 61162306a36Sopenharmony_ci if (rc < 0) 61262306a36Sopenharmony_ci goto err; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci /* correct CP value */ 61562306a36Sopenharmony_ci buf[0] = 0x30; 61662306a36Sopenharmony_ci buf[1] = 0x10 + frequency_map[i].scr; 61762306a36Sopenharmony_ci rc = tuner_transfer(fe, &msg, 1); 61862306a36Sopenharmony_ci if (rc < 0) 61962306a36Sopenharmony_ci goto err; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci msleep(163); 62262306a36Sopenharmony_ci buf[0] = 0xc0; 62362306a36Sopenharmony_ci buf[1] = 0x39; // lpsel, for 6MHz + 2 62462306a36Sopenharmony_ci rc = tuner_transfer(fe, &msg, 1); 62562306a36Sopenharmony_ci if (rc < 0) 62662306a36Sopenharmony_ci goto err; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci msleep(3); 62962306a36Sopenharmony_ci /* freeze AGC1 */ 63062306a36Sopenharmony_ci buf[0] = 0x50; 63162306a36Sopenharmony_ci buf[1] = 0x4f + (frequency_map[i].gc3 << 4); 63262306a36Sopenharmony_ci rc = tuner_transfer(fe, &msg, 1); 63362306a36Sopenharmony_ci if (rc < 0) 63462306a36Sopenharmony_ci goto err; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci priv->frequency = c->frequency; 63762306a36Sopenharmony_ci priv->bandwidth = c->bandwidth_hz; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci return 0; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cierr: 64262306a36Sopenharmony_ci printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n", 64362306a36Sopenharmony_ci __func__, priv->i2c_addr << 1); 64462306a36Sopenharmony_ci return rc; 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic int tda827xa_set_analog_params(struct dvb_frontend *fe, 64962306a36Sopenharmony_ci struct analog_parameters *params) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci unsigned char tuner_reg[11]; 65262306a36Sopenharmony_ci u32 N; 65362306a36Sopenharmony_ci int i; 65462306a36Sopenharmony_ci struct tda827x_priv *priv = fe->tuner_priv; 65562306a36Sopenharmony_ci struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, 65662306a36Sopenharmony_ci .buf = tuner_reg, .len = sizeof(tuner_reg) }; 65762306a36Sopenharmony_ci unsigned int freq = params->frequency; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci tda827x_set_std(fe, params); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci tda827xa_lna_gain(fe, 1, params); 66262306a36Sopenharmony_ci msleep(10); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci if (params->mode == V4L2_TUNER_RADIO) 66562306a36Sopenharmony_ci freq = freq / 1000; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci N = freq + priv->sgIF; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci i = 0; 67062306a36Sopenharmony_ci while (tda827xa_analog[i].lomax < N * 62500) { 67162306a36Sopenharmony_ci if (tda827xa_analog[i + 1].lomax == 0) 67262306a36Sopenharmony_ci break; 67362306a36Sopenharmony_ci i++; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci N = N << tda827xa_analog[i].spd; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci tuner_reg[0] = 0; 67962306a36Sopenharmony_ci tuner_reg[1] = (unsigned char)(N>>8); 68062306a36Sopenharmony_ci tuner_reg[2] = (unsigned char) N; 68162306a36Sopenharmony_ci tuner_reg[3] = 0; 68262306a36Sopenharmony_ci tuner_reg[4] = 0x16; 68362306a36Sopenharmony_ci tuner_reg[5] = (tda827xa_analog[i].spd << 5) + 68462306a36Sopenharmony_ci (tda827xa_analog[i].svco << 3) + 68562306a36Sopenharmony_ci tda827xa_analog[i].sbs; 68662306a36Sopenharmony_ci tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4); 68762306a36Sopenharmony_ci tuner_reg[7] = 0x1c; 68862306a36Sopenharmony_ci tuner_reg[8] = 4; 68962306a36Sopenharmony_ci tuner_reg[9] = 0x20; 69062306a36Sopenharmony_ci tuner_reg[10] = 0x00; 69162306a36Sopenharmony_ci msg.len = 11; 69262306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci tuner_reg[0] = 0x90; 69562306a36Sopenharmony_ci tuner_reg[1] = 0xff; 69662306a36Sopenharmony_ci tuner_reg[2] = 0xe0; 69762306a36Sopenharmony_ci tuner_reg[3] = 0; 69862306a36Sopenharmony_ci tuner_reg[4] = 0x99 + (priv->lpsel << 1); 69962306a36Sopenharmony_ci msg.len = 5; 70062306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci tuner_reg[0] = 0xa0; 70362306a36Sopenharmony_ci tuner_reg[1] = 0xc0; 70462306a36Sopenharmony_ci msg.len = 2; 70562306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci tuner_reg[0] = 0x30; 70862306a36Sopenharmony_ci tuner_reg[1] = 0x10 + tda827xa_analog[i].scr; 70962306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci msg.flags = I2C_M_RD; 71262306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 71362306a36Sopenharmony_ci msg.flags = 0; 71462306a36Sopenharmony_ci tuner_reg[1] >>= 4; 71562306a36Sopenharmony_ci dprintk("AGC2 gain is: %d\n", tuner_reg[1]); 71662306a36Sopenharmony_ci if (tuner_reg[1] < 1) 71762306a36Sopenharmony_ci tda827xa_lna_gain(fe, 0, params); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci msleep(100); 72062306a36Sopenharmony_ci tuner_reg[0] = 0x60; 72162306a36Sopenharmony_ci tuner_reg[1] = 0x3c; 72262306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci msleep(163); 72562306a36Sopenharmony_ci tuner_reg[0] = 0x50; 72662306a36Sopenharmony_ci tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); 72762306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci tuner_reg[0] = 0x80; 73062306a36Sopenharmony_ci tuner_reg[1] = 0x28; 73162306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci tuner_reg[0] = 0xb0; 73462306a36Sopenharmony_ci tuner_reg[1] = 0x01; 73562306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci tuner_reg[0] = 0xc0; 73862306a36Sopenharmony_ci tuner_reg[1] = 0x19 + (priv->lpsel << 1); 73962306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci priv->frequency = params->frequency; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci return 0; 74462306a36Sopenharmony_ci} 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_cistatic void tda827xa_agcf(struct dvb_frontend *fe) 74762306a36Sopenharmony_ci{ 74862306a36Sopenharmony_ci struct tda827x_priv *priv = fe->tuner_priv; 74962306a36Sopenharmony_ci unsigned char data[] = {0x80, 0x2c}; 75062306a36Sopenharmony_ci struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0, 75162306a36Sopenharmony_ci .buf = data, .len = 2}; 75262306a36Sopenharmony_ci tuner_transfer(fe, &msg, 1); 75362306a36Sopenharmony_ci} 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci/* ------------------------------------------------------------------ */ 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_cistatic void tda827x_release(struct dvb_frontend *fe) 75862306a36Sopenharmony_ci{ 75962306a36Sopenharmony_ci kfree(fe->tuner_priv); 76062306a36Sopenharmony_ci fe->tuner_priv = NULL; 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_cistatic int tda827x_get_frequency(struct dvb_frontend *fe, u32 *frequency) 76462306a36Sopenharmony_ci{ 76562306a36Sopenharmony_ci struct tda827x_priv *priv = fe->tuner_priv; 76662306a36Sopenharmony_ci *frequency = priv->frequency; 76762306a36Sopenharmony_ci return 0; 76862306a36Sopenharmony_ci} 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_cistatic int tda827x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci struct tda827x_priv *priv = fe->tuner_priv; 77362306a36Sopenharmony_ci *bandwidth = priv->bandwidth; 77462306a36Sopenharmony_ci return 0; 77562306a36Sopenharmony_ci} 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_cistatic int tda827x_init(struct dvb_frontend *fe) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci struct tda827x_priv *priv = fe->tuner_priv; 78062306a36Sopenharmony_ci dprintk("%s:\n", __func__); 78162306a36Sopenharmony_ci if (priv->cfg && priv->cfg->init) 78262306a36Sopenharmony_ci priv->cfg->init(fe); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci return 0; 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_cistatic int tda827x_probe_version(struct dvb_frontend *fe); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_cistatic int tda827x_initial_init(struct dvb_frontend *fe) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci int ret; 79262306a36Sopenharmony_ci ret = tda827x_probe_version(fe); 79362306a36Sopenharmony_ci if (ret) 79462306a36Sopenharmony_ci return ret; 79562306a36Sopenharmony_ci return fe->ops.tuner_ops.init(fe); 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic int tda827x_initial_sleep(struct dvb_frontend *fe) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci int ret; 80162306a36Sopenharmony_ci ret = tda827x_probe_version(fe); 80262306a36Sopenharmony_ci if (ret) 80362306a36Sopenharmony_ci return ret; 80462306a36Sopenharmony_ci return fe->ops.tuner_ops.sleep(fe); 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_cistatic const struct dvb_tuner_ops tda827xo_tuner_ops = { 80862306a36Sopenharmony_ci .info = { 80962306a36Sopenharmony_ci .name = "Philips TDA827X", 81062306a36Sopenharmony_ci .frequency_min_hz = 55 * MHz, 81162306a36Sopenharmony_ci .frequency_max_hz = 860 * MHz, 81262306a36Sopenharmony_ci .frequency_step_hz = 250 * kHz 81362306a36Sopenharmony_ci }, 81462306a36Sopenharmony_ci .release = tda827x_release, 81562306a36Sopenharmony_ci .init = tda827x_initial_init, 81662306a36Sopenharmony_ci .sleep = tda827x_initial_sleep, 81762306a36Sopenharmony_ci .set_params = tda827xo_set_params, 81862306a36Sopenharmony_ci .set_analog_params = tda827xo_set_analog_params, 81962306a36Sopenharmony_ci .get_frequency = tda827x_get_frequency, 82062306a36Sopenharmony_ci .get_bandwidth = tda827x_get_bandwidth, 82162306a36Sopenharmony_ci}; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_cistatic const struct dvb_tuner_ops tda827xa_tuner_ops = { 82462306a36Sopenharmony_ci .info = { 82562306a36Sopenharmony_ci .name = "Philips TDA827XA", 82662306a36Sopenharmony_ci .frequency_min_hz = 44 * MHz, 82762306a36Sopenharmony_ci .frequency_max_hz = 906 * MHz, 82862306a36Sopenharmony_ci .frequency_step_hz = 62500 82962306a36Sopenharmony_ci }, 83062306a36Sopenharmony_ci .release = tda827x_release, 83162306a36Sopenharmony_ci .init = tda827x_init, 83262306a36Sopenharmony_ci .sleep = tda827xa_sleep, 83362306a36Sopenharmony_ci .set_params = tda827xa_set_params, 83462306a36Sopenharmony_ci .set_analog_params = tda827xa_set_analog_params, 83562306a36Sopenharmony_ci .get_frequency = tda827x_get_frequency, 83662306a36Sopenharmony_ci .get_bandwidth = tda827x_get_bandwidth, 83762306a36Sopenharmony_ci}; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_cistatic int tda827x_probe_version(struct dvb_frontend *fe) 84062306a36Sopenharmony_ci{ 84162306a36Sopenharmony_ci u8 data; 84262306a36Sopenharmony_ci int rc; 84362306a36Sopenharmony_ci struct tda827x_priv *priv = fe->tuner_priv; 84462306a36Sopenharmony_ci struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = I2C_M_RD, 84562306a36Sopenharmony_ci .buf = &data, .len = 1 }; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci rc = tuner_transfer(fe, &msg, 1); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci if (rc < 0) { 85062306a36Sopenharmony_ci printk("%s: could not read from tuner at addr: 0x%02x\n", 85162306a36Sopenharmony_ci __func__, msg.addr << 1); 85262306a36Sopenharmony_ci return rc; 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci if ((data & 0x3c) == 0) { 85562306a36Sopenharmony_ci dprintk("tda827x tuner found\n"); 85662306a36Sopenharmony_ci fe->ops.tuner_ops.init = tda827x_init; 85762306a36Sopenharmony_ci fe->ops.tuner_ops.sleep = tda827xo_sleep; 85862306a36Sopenharmony_ci if (priv->cfg) 85962306a36Sopenharmony_ci priv->cfg->agcf = tda827xo_agcf; 86062306a36Sopenharmony_ci } else { 86162306a36Sopenharmony_ci dprintk("tda827xa tuner found\n"); 86262306a36Sopenharmony_ci memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops)); 86362306a36Sopenharmony_ci if (priv->cfg) 86462306a36Sopenharmony_ci priv->cfg->agcf = tda827xa_agcf; 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci return 0; 86762306a36Sopenharmony_ci} 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_cistruct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr, 87062306a36Sopenharmony_ci struct i2c_adapter *i2c, 87162306a36Sopenharmony_ci struct tda827x_config *cfg) 87262306a36Sopenharmony_ci{ 87362306a36Sopenharmony_ci struct tda827x_priv *priv = NULL; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci dprintk("%s:\n", __func__); 87662306a36Sopenharmony_ci priv = kzalloc(sizeof(struct tda827x_priv), GFP_KERNEL); 87762306a36Sopenharmony_ci if (priv == NULL) 87862306a36Sopenharmony_ci return NULL; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci priv->i2c_addr = addr; 88162306a36Sopenharmony_ci priv->i2c_adap = i2c; 88262306a36Sopenharmony_ci priv->cfg = cfg; 88362306a36Sopenharmony_ci memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops)); 88462306a36Sopenharmony_ci fe->tuner_priv = priv; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci dprintk("type set to %s\n", fe->ops.tuner_ops.info.name); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci return fe; 88962306a36Sopenharmony_ci} 89062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tda827x_attach); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ciMODULE_DESCRIPTION("DVB TDA827x driver"); 89362306a36Sopenharmony_ciMODULE_AUTHOR("Hartmut Hackmann <hartmut.hackmann@t-online.de>"); 89462306a36Sopenharmony_ciMODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); 89562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 896