Path: blob/master/drivers/media/common/tuners/tda827x.c
15112 views
/*1*2* (c) 2005 Hartmut Hackmann3* (c) 2007 Michael Krufky4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License16* along with this program; if not, write to the Free Software17* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.18*/1920#include <linux/module.h>21#include <linux/slab.h>22#include <asm/types.h>23#include <linux/dvb/frontend.h>24#include <linux/videodev2.h>2526#include "tda827x.h"2728static int debug;29module_param(debug, int, 0644);30MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");3132#define dprintk(args...) \33do { \34if (debug) printk(KERN_DEBUG "tda827x: " args); \35} while (0)3637struct tda827x_priv {38int i2c_addr;39struct i2c_adapter *i2c_adap;40struct tda827x_config *cfg;4142unsigned int sgIF;43unsigned char lpsel;4445u32 frequency;46u32 bandwidth;47};4849static void tda827x_set_std(struct dvb_frontend *fe,50struct analog_parameters *params)51{52struct tda827x_priv *priv = fe->tuner_priv;53char *mode;5455priv->lpsel = 0;56if (params->std & V4L2_STD_MN) {57priv->sgIF = 92;58priv->lpsel = 1;59mode = "MN";60} else if (params->std & V4L2_STD_B) {61priv->sgIF = 108;62mode = "B";63} else if (params->std & V4L2_STD_GH) {64priv->sgIF = 124;65mode = "GH";66} else if (params->std & V4L2_STD_PAL_I) {67priv->sgIF = 124;68mode = "I";69} else if (params->std & V4L2_STD_DK) {70priv->sgIF = 124;71mode = "DK";72} else if (params->std & V4L2_STD_SECAM_L) {73priv->sgIF = 124;74mode = "L";75} else if (params->std & V4L2_STD_SECAM_LC) {76priv->sgIF = 20;77mode = "LC";78} else {79priv->sgIF = 124;80mode = "xx";81}8283if (params->mode == V4L2_TUNER_RADIO) {84priv->sgIF = 88; /* if frequency is 5.5 MHz */85dprintk("setting tda827x to radio FM\n");86} else87dprintk("setting tda827x to system %s\n", mode);88}899091/* ------------------------------------------------------------------ */9293struct tda827x_data {94u32 lomax;95u8 spd;96u8 bs;97u8 bp;98u8 cp;99u8 gc3;100u8 div1p5;101};102103static const struct tda827x_data tda827x_table[] = {104{ .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},105{ .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},106{ .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},107{ .lomax = 84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},108{ .lomax = 93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0},109{ .lomax = 98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0},110{ .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},111{ .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1},112{ .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1},113{ .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},114{ .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},115{ .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0},116{ .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},117{ .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},118{ .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1},119{ .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1},120{ .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},121{ .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},122{ .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},123{ .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},124{ .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1},125{ .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1},126{ .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},127{ .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},128{ .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},129{ .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0},130{ .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},131{ .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0},132{ .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}133};134135static int tuner_transfer(struct dvb_frontend *fe,136struct i2c_msg *msg,137const int size)138{139int rc;140struct tda827x_priv *priv = fe->tuner_priv;141142if (fe->ops.i2c_gate_ctrl)143fe->ops.i2c_gate_ctrl(fe, 1);144rc = i2c_transfer(priv->i2c_adap, msg, size);145if (fe->ops.i2c_gate_ctrl)146fe->ops.i2c_gate_ctrl(fe, 0);147148if (rc >= 0 && rc != size)149return -EIO;150151return rc;152}153154static int tda827xo_set_params(struct dvb_frontend *fe,155struct dvb_frontend_parameters *params)156{157struct tda827x_priv *priv = fe->tuner_priv;158u8 buf[14];159int rc;160161struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,162.buf = buf, .len = sizeof(buf) };163int i, tuner_freq, if_freq;164u32 N;165166dprintk("%s:\n", __func__);167switch (params->u.ofdm.bandwidth) {168case BANDWIDTH_6_MHZ:169if_freq = 4000000;170break;171case BANDWIDTH_7_MHZ:172if_freq = 4500000;173break;174default: /* 8 MHz or Auto */175if_freq = 5000000;176break;177}178tuner_freq = params->frequency + if_freq;179180i = 0;181while (tda827x_table[i].lomax < tuner_freq) {182if (tda827x_table[i + 1].lomax == 0)183break;184i++;185}186187N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2);188buf[0] = 0;189buf[1] = (N>>8) | 0x40;190buf[2] = N & 0xff;191buf[3] = 0;192buf[4] = 0x52;193buf[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) +194(tda827x_table[i].bs << 3) +195tda827x_table[i].bp;196buf[6] = (tda827x_table[i].gc3 << 4) + 0x8f;197buf[7] = 0xbf;198buf[8] = 0x2a;199buf[9] = 0x05;200buf[10] = 0xff;201buf[11] = 0x00;202buf[12] = 0x00;203buf[13] = 0x40;204205msg.len = 14;206rc = tuner_transfer(fe, &msg, 1);207if (rc < 0)208goto err;209210msleep(500);211/* correct CP value */212buf[0] = 0x30;213buf[1] = 0x50 + tda827x_table[i].cp;214msg.len = 2;215216rc = tuner_transfer(fe, &msg, 1);217if (rc < 0)218goto err;219220priv->frequency = params->frequency;221priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;222223return 0;224225err:226printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n",227__func__, priv->i2c_addr << 1);228return rc;229}230231static int tda827xo_sleep(struct dvb_frontend *fe)232{233struct tda827x_priv *priv = fe->tuner_priv;234static u8 buf[] = { 0x30, 0xd0 };235struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,236.buf = buf, .len = sizeof(buf) };237238dprintk("%s:\n", __func__);239tuner_transfer(fe, &msg, 1);240241if (priv->cfg && priv->cfg->sleep)242priv->cfg->sleep(fe);243244return 0;245}246247/* ------------------------------------------------------------------ */248249static int tda827xo_set_analog_params(struct dvb_frontend *fe,250struct analog_parameters *params)251{252unsigned char tuner_reg[8];253unsigned char reg2[2];254u32 N;255int i;256struct tda827x_priv *priv = fe->tuner_priv;257struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 };258unsigned int freq = params->frequency;259260tda827x_set_std(fe, params);261262if (params->mode == V4L2_TUNER_RADIO)263freq = freq / 1000;264265N = freq + priv->sgIF;266267i = 0;268while (tda827x_table[i].lomax < N * 62500) {269if (tda827x_table[i + 1].lomax == 0)270break;271i++;272}273274N = N << tda827x_table[i].spd;275276tuner_reg[0] = 0;277tuner_reg[1] = (unsigned char)(N>>8);278tuner_reg[2] = (unsigned char) N;279tuner_reg[3] = 0x40;280tuner_reg[4] = 0x52 + (priv->lpsel << 5);281tuner_reg[5] = (tda827x_table[i].spd << 6) +282(tda827x_table[i].div1p5 << 5) +283(tda827x_table[i].bs << 3) + tda827x_table[i].bp;284tuner_reg[6] = 0x8f + (tda827x_table[i].gc3 << 4);285tuner_reg[7] = 0x8f;286287msg.buf = tuner_reg;288msg.len = 8;289tuner_transfer(fe, &msg, 1);290291msg.buf = reg2;292msg.len = 2;293reg2[0] = 0x80;294reg2[1] = 0;295tuner_transfer(fe, &msg, 1);296297reg2[0] = 0x60;298reg2[1] = 0xbf;299tuner_transfer(fe, &msg, 1);300301reg2[0] = 0x30;302reg2[1] = tuner_reg[4] + 0x80;303tuner_transfer(fe, &msg, 1);304305msleep(1);306reg2[0] = 0x30;307reg2[1] = tuner_reg[4] + 4;308tuner_transfer(fe, &msg, 1);309310msleep(1);311reg2[0] = 0x30;312reg2[1] = tuner_reg[4];313tuner_transfer(fe, &msg, 1);314315msleep(550);316reg2[0] = 0x30;317reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp;318tuner_transfer(fe, &msg, 1);319320reg2[0] = 0x60;321reg2[1] = 0x3f;322tuner_transfer(fe, &msg, 1);323324reg2[0] = 0x80;325reg2[1] = 0x08; /* Vsync en */326tuner_transfer(fe, &msg, 1);327328priv->frequency = params->frequency;329330return 0;331}332333static void tda827xo_agcf(struct dvb_frontend *fe)334{335struct tda827x_priv *priv = fe->tuner_priv;336unsigned char data[] = { 0x80, 0x0c };337struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,338.buf = data, .len = 2};339340tuner_transfer(fe, &msg, 1);341}342343/* ------------------------------------------------------------------ */344345struct tda827xa_data {346u32 lomax;347u8 svco;348u8 spd;349u8 scr;350u8 sbs;351u8 gc3;352};353354static struct tda827xa_data tda827xa_dvbt[] = {355{ .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1},356{ .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},357{ .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},358{ .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},359{ .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},360{ .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},361{ .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},362{ .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},363{ .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},364{ .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},365{ .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},366{ .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},367{ .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},368{ .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},369{ .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},370{ .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},371{ .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},372{ .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},373{ .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},374{ .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},375{ .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},376{ .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},377{ .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},378{ .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},379{ .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},380{ .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},381{ .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}382};383384static struct tda827xa_data tda827xa_dvbc[] = {385{ .lomax = 50125000, .svco = 2, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3},386{ .lomax = 58500000, .svco = 3, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3},387{ .lomax = 69250000, .svco = 0, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3},388{ .lomax = 83625000, .svco = 1, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3},389{ .lomax = 97500000, .svco = 2, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3},390{ .lomax = 100250000, .svco = 2, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1},391{ .lomax = 117000000, .svco = 3, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1},392{ .lomax = 138500000, .svco = 0, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1},393{ .lomax = 167250000, .svco = 1, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1},394{ .lomax = 187000000, .svco = 2, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1},395{ .lomax = 200500000, .svco = 2, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 1},396{ .lomax = 234000000, .svco = 3, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 3},397{ .lomax = 277000000, .svco = 0, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 3},398{ .lomax = 325000000, .svco = 1, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 1},399{ .lomax = 334500000, .svco = 1, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3},400{ .lomax = 401000000, .svco = 2, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3},401{ .lomax = 468000000, .svco = 3, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 1},402{ .lomax = 535000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},403{ .lomax = 554000000, .svco = 0, .spd = 0, .scr = 2, .sbs = 3, .gc3 = 1},404{ .lomax = 638000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},405{ .lomax = 669000000, .svco = 1, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1},406{ .lomax = 720000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},407{ .lomax = 802000000, .svco = 2, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1},408{ .lomax = 835000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},409{ .lomax = 885000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},410{ .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1},411{ .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}412};413414static struct tda827xa_data tda827xa_analog[] = {415{ .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3},416{ .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},417{ .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},418{ .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},419{ .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},420{ .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},421{ .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},422{ .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},423{ .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},424{ .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},425{ .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3},426{ .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3},427{ .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},428{ .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},429{ .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},430{ .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},431{ .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},432{ .lomax = 554000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},433{ .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},434{ .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},435{ .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},436{ .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},437{ .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},438{ .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},439{ .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},440{ .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}441};442443static int tda827xa_sleep(struct dvb_frontend *fe)444{445struct tda827x_priv *priv = fe->tuner_priv;446static u8 buf[] = { 0x30, 0x90 };447struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,448.buf = buf, .len = sizeof(buf) };449450dprintk("%s:\n", __func__);451452tuner_transfer(fe, &msg, 1);453454if (priv->cfg && priv->cfg->sleep)455priv->cfg->sleep(fe);456457return 0;458}459460static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,461struct analog_parameters *params)462{463struct tda827x_priv *priv = fe->tuner_priv;464unsigned char buf[] = {0x22, 0x01};465int arg;466int gp_func;467struct i2c_msg msg = { .flags = 0, .buf = buf, .len = sizeof(buf) };468469if (NULL == priv->cfg) {470dprintk("tda827x_config not defined, cannot set LNA gain!\n");471return;472}473msg.addr = priv->cfg->switch_addr;474if (priv->cfg->config) {475if (high)476dprintk("setting LNA to high gain\n");477else478dprintk("setting LNA to low gain\n");479}480switch (priv->cfg->config) {481case 0: /* no LNA */482break;483case 1: /* switch is GPIO 0 of tda8290 */484case 2:485if (params == NULL) {486gp_func = 0;487arg = 0;488} else {489/* turn Vsync on */490gp_func = 1;491if (params->std & V4L2_STD_MN)492arg = 1;493else494arg = 0;495}496if (fe->callback)497fe->callback(priv->i2c_adap->algo_data,498DVB_FRONTEND_COMPONENT_TUNER,499gp_func, arg);500buf[1] = high ? 0 : 1;501if (priv->cfg->config == 2)502buf[1] = high ? 1 : 0;503tuner_transfer(fe, &msg, 1);504break;505case 3: /* switch with GPIO of saa713x */506if (fe->callback)507fe->callback(priv->i2c_adap->algo_data,508DVB_FRONTEND_COMPONENT_TUNER, 0, high);509break;510}511}512513static int tda827xa_set_params(struct dvb_frontend *fe,514struct dvb_frontend_parameters *params)515{516struct tda827x_priv *priv = fe->tuner_priv;517struct tda827xa_data *frequency_map = tda827xa_dvbt;518u8 buf[11];519520struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,521.buf = buf, .len = sizeof(buf) };522523int i, tuner_freq, if_freq, rc;524u32 N;525526dprintk("%s:\n", __func__);527528tda827xa_lna_gain(fe, 1, NULL);529msleep(20);530531switch (params->u.ofdm.bandwidth) {532case BANDWIDTH_6_MHZ:533if_freq = 4000000;534break;535case BANDWIDTH_7_MHZ:536if_freq = 4500000;537break;538default: /* 8 MHz or Auto */539if_freq = 5000000;540break;541}542tuner_freq = params->frequency + if_freq;543544if (fe->ops.info.type == FE_QAM) {545dprintk("%s select tda827xa_dvbc\n", __func__);546frequency_map = tda827xa_dvbc;547}548549i = 0;550while (frequency_map[i].lomax < tuner_freq) {551if (frequency_map[i + 1].lomax == 0)552break;553i++;554}555556N = ((tuner_freq + 31250) / 62500) << frequency_map[i].spd;557buf[0] = 0; // subaddress558buf[1] = N >> 8;559buf[2] = N & 0xff;560buf[3] = 0;561buf[4] = 0x16;562buf[5] = (frequency_map[i].spd << 5) + (frequency_map[i].svco << 3) +563frequency_map[i].sbs;564buf[6] = 0x4b + (frequency_map[i].gc3 << 4);565buf[7] = 0x1c;566buf[8] = 0x06;567buf[9] = 0x24;568buf[10] = 0x00;569msg.len = 11;570rc = tuner_transfer(fe, &msg, 1);571if (rc < 0)572goto err;573574buf[0] = 0x90;575buf[1] = 0xff;576buf[2] = 0x60;577buf[3] = 0x00;578buf[4] = 0x59; // lpsel, for 6MHz + 2579msg.len = 5;580rc = tuner_transfer(fe, &msg, 1);581if (rc < 0)582goto err;583584buf[0] = 0xa0;585buf[1] = 0x40;586msg.len = 2;587rc = tuner_transfer(fe, &msg, 1);588if (rc < 0)589goto err;590591msleep(11);592msg.flags = I2C_M_RD;593rc = tuner_transfer(fe, &msg, 1);594if (rc < 0)595goto err;596msg.flags = 0;597598buf[1] >>= 4;599dprintk("tda8275a AGC2 gain is: %d\n", buf[1]);600if ((buf[1]) < 2) {601tda827xa_lna_gain(fe, 0, NULL);602buf[0] = 0x60;603buf[1] = 0x0c;604rc = tuner_transfer(fe, &msg, 1);605if (rc < 0)606goto err;607}608609buf[0] = 0xc0;610buf[1] = 0x99; // lpsel, for 6MHz + 2611rc = tuner_transfer(fe, &msg, 1);612if (rc < 0)613goto err;614615buf[0] = 0x60;616buf[1] = 0x3c;617rc = tuner_transfer(fe, &msg, 1);618if (rc < 0)619goto err;620621/* correct CP value */622buf[0] = 0x30;623buf[1] = 0x10 + frequency_map[i].scr;624rc = tuner_transfer(fe, &msg, 1);625if (rc < 0)626goto err;627628msleep(163);629buf[0] = 0xc0;630buf[1] = 0x39; // lpsel, for 6MHz + 2631rc = tuner_transfer(fe, &msg, 1);632if (rc < 0)633goto err;634635msleep(3);636/* freeze AGC1 */637buf[0] = 0x50;638buf[1] = 0x4f + (frequency_map[i].gc3 << 4);639rc = tuner_transfer(fe, &msg, 1);640if (rc < 0)641goto err;642643priv->frequency = params->frequency;644priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;645646647return 0;648649err:650printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n",651__func__, priv->i2c_addr << 1);652return rc;653}654655656static int tda827xa_set_analog_params(struct dvb_frontend *fe,657struct analog_parameters *params)658{659unsigned char tuner_reg[11];660u32 N;661int i;662struct tda827x_priv *priv = fe->tuner_priv;663struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,664.buf = tuner_reg, .len = sizeof(tuner_reg) };665unsigned int freq = params->frequency;666667tda827x_set_std(fe, params);668669tda827xa_lna_gain(fe, 1, params);670msleep(10);671672if (params->mode == V4L2_TUNER_RADIO)673freq = freq / 1000;674675N = freq + priv->sgIF;676677i = 0;678while (tda827xa_analog[i].lomax < N * 62500) {679if (tda827xa_analog[i + 1].lomax == 0)680break;681i++;682}683684N = N << tda827xa_analog[i].spd;685686tuner_reg[0] = 0;687tuner_reg[1] = (unsigned char)(N>>8);688tuner_reg[2] = (unsigned char) N;689tuner_reg[3] = 0;690tuner_reg[4] = 0x16;691tuner_reg[5] = (tda827xa_analog[i].spd << 5) +692(tda827xa_analog[i].svco << 3) +693tda827xa_analog[i].sbs;694tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4);695tuner_reg[7] = 0x1c;696tuner_reg[8] = 4;697tuner_reg[9] = 0x20;698tuner_reg[10] = 0x00;699msg.len = 11;700tuner_transfer(fe, &msg, 1);701702tuner_reg[0] = 0x90;703tuner_reg[1] = 0xff;704tuner_reg[2] = 0xe0;705tuner_reg[3] = 0;706tuner_reg[4] = 0x99 + (priv->lpsel << 1);707msg.len = 5;708tuner_transfer(fe, &msg, 1);709710tuner_reg[0] = 0xa0;711tuner_reg[1] = 0xc0;712msg.len = 2;713tuner_transfer(fe, &msg, 1);714715tuner_reg[0] = 0x30;716tuner_reg[1] = 0x10 + tda827xa_analog[i].scr;717tuner_transfer(fe, &msg, 1);718719msg.flags = I2C_M_RD;720tuner_transfer(fe, &msg, 1);721msg.flags = 0;722tuner_reg[1] >>= 4;723dprintk("AGC2 gain is: %d\n", tuner_reg[1]);724if (tuner_reg[1] < 1)725tda827xa_lna_gain(fe, 0, params);726727msleep(100);728tuner_reg[0] = 0x60;729tuner_reg[1] = 0x3c;730tuner_transfer(fe, &msg, 1);731732msleep(163);733tuner_reg[0] = 0x50;734tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);735tuner_transfer(fe, &msg, 1);736737tuner_reg[0] = 0x80;738tuner_reg[1] = 0x28;739tuner_transfer(fe, &msg, 1);740741tuner_reg[0] = 0xb0;742tuner_reg[1] = 0x01;743tuner_transfer(fe, &msg, 1);744745tuner_reg[0] = 0xc0;746tuner_reg[1] = 0x19 + (priv->lpsel << 1);747tuner_transfer(fe, &msg, 1);748749priv->frequency = params->frequency;750751return 0;752}753754static void tda827xa_agcf(struct dvb_frontend *fe)755{756struct tda827x_priv *priv = fe->tuner_priv;757unsigned char data[] = {0x80, 0x2c};758struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0,759.buf = data, .len = 2};760tuner_transfer(fe, &msg, 1);761}762763/* ------------------------------------------------------------------ */764765static int tda827x_release(struct dvb_frontend *fe)766{767kfree(fe->tuner_priv);768fe->tuner_priv = NULL;769return 0;770}771772static int tda827x_get_frequency(struct dvb_frontend *fe, u32 *frequency)773{774struct tda827x_priv *priv = fe->tuner_priv;775*frequency = priv->frequency;776return 0;777}778779static int tda827x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)780{781struct tda827x_priv *priv = fe->tuner_priv;782*bandwidth = priv->bandwidth;783return 0;784}785786static int tda827x_init(struct dvb_frontend *fe)787{788struct tda827x_priv *priv = fe->tuner_priv;789dprintk("%s:\n", __func__);790if (priv->cfg && priv->cfg->init)791priv->cfg->init(fe);792793return 0;794}795796static int tda827x_probe_version(struct dvb_frontend *fe);797798static int tda827x_initial_init(struct dvb_frontend *fe)799{800int ret;801ret = tda827x_probe_version(fe);802if (ret)803return ret;804return fe->ops.tuner_ops.init(fe);805}806807static int tda827x_initial_sleep(struct dvb_frontend *fe)808{809int ret;810ret = tda827x_probe_version(fe);811if (ret)812return ret;813return fe->ops.tuner_ops.sleep(fe);814}815816static struct dvb_tuner_ops tda827xo_tuner_ops = {817.info = {818.name = "Philips TDA827X",819.frequency_min = 55000000,820.frequency_max = 860000000,821.frequency_step = 250000822},823.release = tda827x_release,824.init = tda827x_initial_init,825.sleep = tda827x_initial_sleep,826.set_params = tda827xo_set_params,827.set_analog_params = tda827xo_set_analog_params,828.get_frequency = tda827x_get_frequency,829.get_bandwidth = tda827x_get_bandwidth,830};831832static struct dvb_tuner_ops tda827xa_tuner_ops = {833.info = {834.name = "Philips TDA827XA",835.frequency_min = 44000000,836.frequency_max = 906000000,837.frequency_step = 62500838},839.release = tda827x_release,840.init = tda827x_init,841.sleep = tda827xa_sleep,842.set_params = tda827xa_set_params,843.set_analog_params = tda827xa_set_analog_params,844.get_frequency = tda827x_get_frequency,845.get_bandwidth = tda827x_get_bandwidth,846};847848static int tda827x_probe_version(struct dvb_frontend *fe)849{850u8 data;851int rc;852struct tda827x_priv *priv = fe->tuner_priv;853struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = I2C_M_RD,854.buf = &data, .len = 1 };855856rc = tuner_transfer(fe, &msg, 1);857858if (rc < 0) {859printk("%s: could not read from tuner at addr: 0x%02x\n",860__func__, msg.addr << 1);861return rc;862}863if ((data & 0x3c) == 0) {864dprintk("tda827x tuner found\n");865fe->ops.tuner_ops.init = tda827x_init;866fe->ops.tuner_ops.sleep = tda827xo_sleep;867if (priv->cfg)868priv->cfg->agcf = tda827xo_agcf;869} else {870dprintk("tda827xa tuner found\n");871memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops));872if (priv->cfg)873priv->cfg->agcf = tda827xa_agcf;874}875return 0;876}877878struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr,879struct i2c_adapter *i2c,880struct tda827x_config *cfg)881{882struct tda827x_priv *priv = NULL;883884dprintk("%s:\n", __func__);885priv = kzalloc(sizeof(struct tda827x_priv), GFP_KERNEL);886if (priv == NULL)887return NULL;888889priv->i2c_addr = addr;890priv->i2c_adap = i2c;891priv->cfg = cfg;892memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops));893fe->tuner_priv = priv;894895dprintk("type set to %s\n", fe->ops.tuner_ops.info.name);896897return fe;898}899EXPORT_SYMBOL_GPL(tda827x_attach);900901MODULE_DESCRIPTION("DVB TDA827x driver");902MODULE_AUTHOR("Hartmut Hackmann <[email protected]>");903MODULE_AUTHOR("Michael Krufky <[email protected]>");904MODULE_LICENSE("GPL");905906/*907* Overrides for Emacs so that we follow Linus's tabbing style.908* ---------------------------------------------------------------------------909* Local variables:910* c-basic-offset: 8911* End:912*/913914915