blob: d96d0b9e189940624d3c5c8d2ef334502333a9cc [file] [log] [blame]
Michael Krufky8ce47da2007-04-27 12:31:14 -03001/*
2 *
3 * (c) 2005 Hartmut Hackmann
4 * (c) 2007 Michael Krufky
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21#include <linux/module.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090022#include <linux/slab.h>
Michael Krufky8ce47da2007-04-27 12:31:14 -030023#include <asm/types.h>
Michael Krufky746d97322007-08-25 19:08:45 -030024#include <linux/dvb/frontend.h>
25#include <linux/videodev2.h>
Michael Krufky8ce47da2007-04-27 12:31:14 -030026
27#include "tda827x.h"
28
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030029static int debug;
Michael Krufky746d97322007-08-25 19:08:45 -030030module_param(debug, int, 0644);
31MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
32
Michael Krufky8ce47da2007-04-27 12:31:14 -030033#define dprintk(args...) \
34 do { \
35 if (debug) printk(KERN_DEBUG "tda827x: " args); \
36 } while (0)
37
38struct tda827x_priv {
39 int i2c_addr;
40 struct i2c_adapter *i2c_adap;
41 struct tda827x_config *cfg;
Michael Krufky5c82f442007-10-22 01:10:39 -030042
43 unsigned int sgIF;
44 unsigned char lpsel;
45
Michael Krufky8ce47da2007-04-27 12:31:14 -030046 u32 frequency;
47 u32 bandwidth;
48};
49
Michael Krufky5c82f442007-10-22 01:10:39 -030050static void tda827x_set_std(struct dvb_frontend *fe,
51 struct analog_parameters *params)
52{
53 struct tda827x_priv *priv = fe->tuner_priv;
54 char *mode;
55
56 priv->lpsel = 0;
57 if (params->std & V4L2_STD_MN) {
58 priv->sgIF = 92;
59 priv->lpsel = 1;
60 mode = "MN";
61 } else if (params->std & V4L2_STD_B) {
62 priv->sgIF = 108;
63 mode = "B";
64 } else if (params->std & V4L2_STD_GH) {
65 priv->sgIF = 124;
66 mode = "GH";
67 } else if (params->std & V4L2_STD_PAL_I) {
68 priv->sgIF = 124;
69 mode = "I";
70 } else if (params->std & V4L2_STD_DK) {
71 priv->sgIF = 124;
72 mode = "DK";
73 } else if (params->std & V4L2_STD_SECAM_L) {
74 priv->sgIF = 124;
75 mode = "L";
76 } else if (params->std & V4L2_STD_SECAM_LC) {
77 priv->sgIF = 20;
78 mode = "LC";
79 } else {
80 priv->sgIF = 124;
81 mode = "xx";
82 }
83
Mauro Carvalho Chehabe5218ee2008-12-07 23:01:57 -030084 if (params->mode == V4L2_TUNER_RADIO) {
Michael Krufky5c82f442007-10-22 01:10:39 -030085 priv->sgIF = 88; /* if frequency is 5.5 MHz */
Mauro Carvalho Chehabe5218ee2008-12-07 23:01:57 -030086 dprintk("setting tda827x to radio FM\n");
87 } else
88 dprintk("setting tda827x to system %s\n", mode);
Michael Krufky5c82f442007-10-22 01:10:39 -030089}
90
91
92/* ------------------------------------------------------------------ */
93
Michael Krufky8ce47da2007-04-27 12:31:14 -030094struct tda827x_data {
95 u32 lomax;
96 u8 spd;
97 u8 bs;
98 u8 bp;
99 u8 cp;
100 u8 gc3;
101 u8 div1p5;
102};
103
Michael Krufky746d97322007-08-25 19:08:45 -0300104static const struct tda827x_data tda827x_table[] = {
Michael Krufky8ce47da2007-04-27 12:31:14 -0300105 { .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
106 { .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
107 { .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
108 { .lomax = 84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
109 { .lomax = 93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0},
110 { .lomax = 98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0},
111 { .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
112 { .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1},
113 { .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1},
114 { .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
115 { .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
116 { .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0},
117 { .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
118 { .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
119 { .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1},
120 { .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1},
121 { .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
122 { .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
123 { .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
124 { .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
125 { .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1},
126 { .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1},
127 { .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
128 { .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
129 { .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
130 { .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0},
131 { .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
132 { .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0},
133 { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}
134};
135
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300136static int tuner_transfer(struct dvb_frontend *fe,
137 struct i2c_msg *msg,
138 const int size)
139{
140 int rc;
141 struct tda827x_priv *priv = fe->tuner_priv;
142
143 if (fe->ops.i2c_gate_ctrl)
144 fe->ops.i2c_gate_ctrl(fe, 1);
145 rc = i2c_transfer(priv->i2c_adap, msg, size);
146 if (fe->ops.i2c_gate_ctrl)
147 fe->ops.i2c_gate_ctrl(fe, 0);
148
149 if (rc >= 0 && rc != size)
150 return -EIO;
151
152 return rc;
153}
154
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -0300155static int tda827xo_set_params(struct dvb_frontend *fe)
Michael Krufky8ce47da2007-04-27 12:31:14 -0300156{
Mauro Carvalho Chehab53ccd1c2011-12-21 08:39:44 -0300157 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300158 struct tda827x_priv *priv = fe->tuner_priv;
159 u8 buf[14];
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300160 int rc;
Mauro Carvalho Chehab53ccd1c2011-12-21 08:39:44 -0300161 u32 band;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300162
163 struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
164 .buf = buf, .len = sizeof(buf) };
165 int i, tuner_freq, if_freq;
166 u32 N;
167
Hartmut Hackmann7bff4b42008-04-22 14:46:08 -0300168 dprintk("%s:\n", __func__);
Mauro Carvalho Chehab53ccd1c2011-12-21 08:39:44 -0300169 if (c->bandwidth_hz == 0) {
Michael Krufky8ce47da2007-04-27 12:31:14 -0300170 if_freq = 5000000;
Mauro Carvalho Chehab53ccd1c2011-12-21 08:39:44 -0300171 band = BANDWIDTH_8_MHZ;
172 } else if (c->bandwidth_hz <= 6000000) {
173 if_freq = 4000000;
174 band = BANDWIDTH_6_MHZ;
175 } else if (c->bandwidth_hz <= 7000000) {
176 if_freq = 4500000;
177 band = BANDWIDTH_7_MHZ;
178 } else { /* 8 MHz */
179 if_freq = 5000000;
180 band = BANDWIDTH_8_MHZ;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300181 }
Mauro Carvalho Chehab53ccd1c2011-12-21 08:39:44 -0300182 tuner_freq = c->frequency;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300183
184 i = 0;
Michael Krufky746d97322007-08-25 19:08:45 -0300185 while (tda827x_table[i].lomax < tuner_freq) {
186 if (tda827x_table[i + 1].lomax == 0)
Michael Krufky8ce47da2007-04-27 12:31:14 -0300187 break;
188 i++;
189 }
190
Jose Alberto Reguero2d84ca22011-07-16 08:38:13 -0300191 tuner_freq += if_freq;
192
Michael Krufky746d97322007-08-25 19:08:45 -0300193 N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2);
Michael Krufky8ce47da2007-04-27 12:31:14 -0300194 buf[0] = 0;
195 buf[1] = (N>>8) | 0x40;
196 buf[2] = N & 0xff;
197 buf[3] = 0;
198 buf[4] = 0x52;
Michael Krufky746d97322007-08-25 19:08:45 -0300199 buf[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) +
200 (tda827x_table[i].bs << 3) +
201 tda827x_table[i].bp;
202 buf[6] = (tda827x_table[i].gc3 << 4) + 0x8f;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300203 buf[7] = 0xbf;
204 buf[8] = 0x2a;
205 buf[9] = 0x05;
206 buf[10] = 0xff;
207 buf[11] = 0x00;
208 buf[12] = 0x00;
209 buf[13] = 0x40;
210
211 msg.len = 14;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300212 rc = tuner_transfer(fe, &msg, 1);
213 if (rc < 0)
214 goto err;
215
Michael Krufky8ce47da2007-04-27 12:31:14 -0300216 msleep(500);
217 /* correct CP value */
218 buf[0] = 0x30;
Michael Krufky746d97322007-08-25 19:08:45 -0300219 buf[1] = 0x50 + tda827x_table[i].cp;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300220 msg.len = 2;
221
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300222 rc = tuner_transfer(fe, &msg, 1);
223 if (rc < 0)
224 goto err;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300225
Mauro Carvalho Chehab53ccd1c2011-12-21 08:39:44 -0300226 priv->frequency = c->frequency;
227 priv->bandwidth = band;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300228
229 return 0;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300230
231err:
232 printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n",
233 __func__, priv->i2c_addr << 1);
234 return rc;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300235}
236
237static int tda827xo_sleep(struct dvb_frontend *fe)
238{
239 struct tda827x_priv *priv = fe->tuner_priv;
240 static u8 buf[] = { 0x30, 0xd0 };
241 struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
242 .buf = buf, .len = sizeof(buf) };
243
Hartmut Hackmann7bff4b42008-04-22 14:46:08 -0300244 dprintk("%s:\n", __func__);
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300245 tuner_transfer(fe, &msg, 1);
Michael Krufky8ce47da2007-04-27 12:31:14 -0300246
247 if (priv->cfg && priv->cfg->sleep)
248 priv->cfg->sleep(fe);
249
250 return 0;
251}
252
253/* ------------------------------------------------------------------ */
254
Michael Krufky746d97322007-08-25 19:08:45 -0300255static int tda827xo_set_analog_params(struct dvb_frontend *fe,
256 struct analog_parameters *params)
257{
258 unsigned char tuner_reg[8];
259 unsigned char reg2[2];
260 u32 N;
261 int i;
262 struct tda827x_priv *priv = fe->tuner_priv;
263 struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 };
264 unsigned int freq = params->frequency;
265
Michael Krufky5c82f442007-10-22 01:10:39 -0300266 tda827x_set_std(fe, params);
267
Michael Krufky746d97322007-08-25 19:08:45 -0300268 if (params->mode == V4L2_TUNER_RADIO)
269 freq = freq / 1000;
270
Michael Krufky5c82f442007-10-22 01:10:39 -0300271 N = freq + priv->sgIF;
Michael Krufky746d97322007-08-25 19:08:45 -0300272
273 i = 0;
274 while (tda827x_table[i].lomax < N * 62500) {
275 if (tda827x_table[i + 1].lomax == 0)
276 break;
277 i++;
278 }
279
280 N = N << tda827x_table[i].spd;
281
282 tuner_reg[0] = 0;
283 tuner_reg[1] = (unsigned char)(N>>8);
284 tuner_reg[2] = (unsigned char) N;
285 tuner_reg[3] = 0x40;
Michael Krufky5c82f442007-10-22 01:10:39 -0300286 tuner_reg[4] = 0x52 + (priv->lpsel << 5);
Michael Krufky746d97322007-08-25 19:08:45 -0300287 tuner_reg[5] = (tda827x_table[i].spd << 6) +
288 (tda827x_table[i].div1p5 << 5) +
289 (tda827x_table[i].bs << 3) + tda827x_table[i].bp;
290 tuner_reg[6] = 0x8f + (tda827x_table[i].gc3 << 4);
291 tuner_reg[7] = 0x8f;
292
293 msg.buf = tuner_reg;
294 msg.len = 8;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300295 tuner_transfer(fe, &msg, 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300296
297 msg.buf = reg2;
298 msg.len = 2;
299 reg2[0] = 0x80;
300 reg2[1] = 0;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300301 tuner_transfer(fe, &msg, 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300302
303 reg2[0] = 0x60;
304 reg2[1] = 0xbf;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300305 tuner_transfer(fe, &msg, 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300306
307 reg2[0] = 0x30;
308 reg2[1] = tuner_reg[4] + 0x80;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300309 tuner_transfer(fe, &msg, 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300310
311 msleep(1);
312 reg2[0] = 0x30;
313 reg2[1] = tuner_reg[4] + 4;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300314 tuner_transfer(fe, &msg, 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300315
316 msleep(1);
317 reg2[0] = 0x30;
318 reg2[1] = tuner_reg[4];
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300319 tuner_transfer(fe, &msg, 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300320
321 msleep(550);
322 reg2[0] = 0x30;
323 reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300324 tuner_transfer(fe, &msg, 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300325
326 reg2[0] = 0x60;
327 reg2[1] = 0x3f;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300328 tuner_transfer(fe, &msg, 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300329
330 reg2[0] = 0x80;
331 reg2[1] = 0x08; /* Vsync en */
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300332 tuner_transfer(fe, &msg, 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300333
Mauro Carvalho Chehab92d90f12008-12-08 00:49:33 -0300334 priv->frequency = params->frequency;
Michael Krufky746d97322007-08-25 19:08:45 -0300335
336 return 0;
337}
338
339static void tda827xo_agcf(struct dvb_frontend *fe)
340{
341 struct tda827x_priv *priv = fe->tuner_priv;
342 unsigned char data[] = { 0x80, 0x0c };
343 struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
344 .buf = data, .len = 2};
345
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300346 tuner_transfer(fe, &msg, 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300347}
348
349/* ------------------------------------------------------------------ */
350
Michael Krufky8ce47da2007-04-27 12:31:14 -0300351struct tda827xa_data {
352 u32 lomax;
353 u8 svco;
354 u8 spd;
355 u8 scr;
356 u8 sbs;
357 u8 gc3;
358};
359
klaas de waalcf47d872009-03-25 17:53:02 -0300360static struct tda827xa_data tda827xa_dvbt[] = {
Michael Krufky8ce47da2007-04-27 12:31:14 -0300361 { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1},
362 { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
363 { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
364 { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
365 { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},
366 { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
367 { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
368 { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
369 { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
370 { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
371 { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
372 { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
373 { .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
374 { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
375 { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
376 { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
377 { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
378 { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
379 { .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
380 { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
381 { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
382 { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
383 { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
384 { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
385 { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
386 { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},
387 { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
388};
389
klaas de waalcf47d872009-03-25 17:53:02 -0300390static struct tda827xa_data tda827xa_dvbc[] = {
391 { .lomax = 50125000, .svco = 2, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3},
392 { .lomax = 58500000, .svco = 3, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3},
393 { .lomax = 69250000, .svco = 0, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3},
394 { .lomax = 83625000, .svco = 1, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3},
395 { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3},
396 { .lomax = 100250000, .svco = 2, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1},
397 { .lomax = 117000000, .svco = 3, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1},
398 { .lomax = 138500000, .svco = 0, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1},
399 { .lomax = 167250000, .svco = 1, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1},
400 { .lomax = 187000000, .svco = 2, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1},
401 { .lomax = 200500000, .svco = 2, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 1},
402 { .lomax = 234000000, .svco = 3, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 3},
403 { .lomax = 277000000, .svco = 0, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 3},
404 { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 1},
405 { .lomax = 334500000, .svco = 1, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3},
406 { .lomax = 401000000, .svco = 2, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3},
407 { .lomax = 468000000, .svco = 3, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 1},
408 { .lomax = 535000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
409 { .lomax = 554000000, .svco = 0, .spd = 0, .scr = 2, .sbs = 3, .gc3 = 1},
410 { .lomax = 638000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
411 { .lomax = 669000000, .svco = 1, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1},
412 { .lomax = 720000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
413 { .lomax = 802000000, .svco = 2, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1},
414 { .lomax = 835000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
415 { .lomax = 885000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
416 { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1},
417 { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
418};
419
Michael Krufky746d97322007-08-25 19:08:45 -0300420static struct tda827xa_data tda827xa_analog[] = {
421 { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3},
422 { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
423 { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
424 { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
425 { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},
426 { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
427 { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
428 { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
429 { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
430 { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
431 { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3},
432 { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3},
433 { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
434 { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},
435 { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},
436 { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
437 { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
438 { .lomax = 554000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
439 { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
440 { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
441 { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
442 { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
443 { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
444 { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
445 { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},
446 { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
447};
448
Hartmut Hackmann7bff4b42008-04-22 14:46:08 -0300449static int tda827xa_sleep(struct dvb_frontend *fe)
450{
451 struct tda827x_priv *priv = fe->tuner_priv;
452 static u8 buf[] = { 0x30, 0x90 };
453 struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
454 .buf = buf, .len = sizeof(buf) };
455
456 dprintk("%s:\n", __func__);
Hartmut Hackmann7bff4b42008-04-22 14:46:08 -0300457
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300458 tuner_transfer(fe, &msg, 1);
Hartmut Hackmann7bff4b42008-04-22 14:46:08 -0300459
460 if (priv->cfg && priv->cfg->sleep)
461 priv->cfg->sleep(fe);
462
463 return 0;
464}
465
466static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
467 struct analog_parameters *params)
468{
469 struct tda827x_priv *priv = fe->tuner_priv;
470 unsigned char buf[] = {0x22, 0x01};
471 int arg;
472 int gp_func;
Sigmund Augdal67642a02008-06-05 12:53:08 -0300473 struct i2c_msg msg = { .flags = 0, .buf = buf, .len = sizeof(buf) };
Hartmut Hackmann7bff4b42008-04-22 14:46:08 -0300474
475 if (NULL == priv->cfg) {
476 dprintk("tda827x_config not defined, cannot set LNA gain!\n");
477 return;
478 }
Sigmund Augdal67642a02008-06-05 12:53:08 -0300479 msg.addr = priv->cfg->switch_addr;
Hartmut Hackmann7bff4b42008-04-22 14:46:08 -0300480 if (priv->cfg->config) {
481 if (high)
482 dprintk("setting LNA to high gain\n");
483 else
484 dprintk("setting LNA to low gain\n");
485 }
486 switch (priv->cfg->config) {
487 case 0: /* no LNA */
488 break;
489 case 1: /* switch is GPIO 0 of tda8290 */
490 case 2:
491 if (params == NULL) {
492 gp_func = 0;
493 arg = 0;
494 } else {
495 /* turn Vsync on */
496 gp_func = 1;
497 if (params->std & V4L2_STD_MN)
498 arg = 1;
499 else
500 arg = 0;
501 }
Michael Krufkyd7cba042008-09-12 13:31:45 -0300502 if (fe->callback)
503 fe->callback(priv->i2c_adap->algo_data,
504 DVB_FRONTEND_COMPONENT_TUNER,
505 gp_func, arg);
Hartmut Hackmann7bff4b42008-04-22 14:46:08 -0300506 buf[1] = high ? 0 : 1;
507 if (priv->cfg->config == 2)
508 buf[1] = high ? 1 : 0;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300509 tuner_transfer(fe, &msg, 1);
Hartmut Hackmann7bff4b42008-04-22 14:46:08 -0300510 break;
511 case 3: /* switch with GPIO of saa713x */
Michael Krufkyd7cba042008-09-12 13:31:45 -0300512 if (fe->callback)
513 fe->callback(priv->i2c_adap->algo_data,
514 DVB_FRONTEND_COMPONENT_TUNER, 0, high);
Hartmut Hackmann7bff4b42008-04-22 14:46:08 -0300515 break;
516 }
517}
518
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -0300519static int tda827xa_set_params(struct dvb_frontend *fe)
Michael Krufky8ce47da2007-04-27 12:31:14 -0300520{
Mauro Carvalho Chehab53ccd1c2011-12-21 08:39:44 -0300521 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300522 struct tda827x_priv *priv = fe->tuner_priv;
klaas de waalcf47d872009-03-25 17:53:02 -0300523 struct tda827xa_data *frequency_map = tda827xa_dvbt;
Hartmut Hackmannede22002007-04-27 12:31:32 -0300524 u8 buf[11];
Mauro Carvalho Chehab53ccd1c2011-12-21 08:39:44 -0300525 u32 band;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300526
527 struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
528 .buf = buf, .len = sizeof(buf) };
529
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300530 int i, tuner_freq, if_freq, rc;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300531 u32 N;
532
Hartmut Hackmann7bff4b42008-04-22 14:46:08 -0300533 dprintk("%s:\n", __func__);
534
535 tda827xa_lna_gain(fe, 1, NULL);
Michael Krufky8ce47da2007-04-27 12:31:14 -0300536 msleep(20);
537
Mauro Carvalho Chehab53ccd1c2011-12-21 08:39:44 -0300538 if (c->bandwidth_hz == 0) {
Michael Krufky8ce47da2007-04-27 12:31:14 -0300539 if_freq = 5000000;
Mauro Carvalho Chehab53ccd1c2011-12-21 08:39:44 -0300540 band = BANDWIDTH_8_MHZ;
541 } else if (c->bandwidth_hz <= 6000000) {
542 if_freq = 4000000;
543 band = BANDWIDTH_6_MHZ;
544 } else if (c->bandwidth_hz <= 7000000) {
545 if_freq = 4500000;
546 band = BANDWIDTH_7_MHZ;
547 } else { /* 8 MHz */
548 if_freq = 5000000;
549 band = BANDWIDTH_8_MHZ;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300550 }
Mauro Carvalho Chehab53ccd1c2011-12-21 08:39:44 -0300551 tuner_freq = c->frequency;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300552
klaas de waalcf47d872009-03-25 17:53:02 -0300553 if (fe->ops.info.type == FE_QAM) {
554 dprintk("%s select tda827xa_dvbc\n", __func__);
555 frequency_map = tda827xa_dvbc;
556 }
557
Michael Krufky8ce47da2007-04-27 12:31:14 -0300558 i = 0;
klaas de waalcf47d872009-03-25 17:53:02 -0300559 while (frequency_map[i].lomax < tuner_freq) {
560 if (frequency_map[i + 1].lomax == 0)
Michael Krufky8ce47da2007-04-27 12:31:14 -0300561 break;
562 i++;
563 }
564
Jose Alberto Reguero2d84ca22011-07-16 08:38:13 -0300565 tuner_freq += if_freq;
566
klaas de waalcf47d872009-03-25 17:53:02 -0300567 N = ((tuner_freq + 31250) / 62500) << frequency_map[i].spd;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300568 buf[0] = 0; // subaddress
569 buf[1] = N >> 8;
570 buf[2] = N & 0xff;
571 buf[3] = 0;
572 buf[4] = 0x16;
klaas de waalcf47d872009-03-25 17:53:02 -0300573 buf[5] = (frequency_map[i].spd << 5) + (frequency_map[i].svco << 3) +
574 frequency_map[i].sbs;
575 buf[6] = 0x4b + (frequency_map[i].gc3 << 4);
Michael Krufky8ce47da2007-04-27 12:31:14 -0300576 buf[7] = 0x1c;
577 buf[8] = 0x06;
578 buf[9] = 0x24;
579 buf[10] = 0x00;
580 msg.len = 11;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300581 rc = tuner_transfer(fe, &msg, 1);
582 if (rc < 0)
583 goto err;
584
Michael Krufky8ce47da2007-04-27 12:31:14 -0300585 buf[0] = 0x90;
586 buf[1] = 0xff;
587 buf[2] = 0x60;
588 buf[3] = 0x00;
589 buf[4] = 0x59; // lpsel, for 6MHz + 2
590 msg.len = 5;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300591 rc = tuner_transfer(fe, &msg, 1);
592 if (rc < 0)
593 goto err;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300594
595 buf[0] = 0xa0;
596 buf[1] = 0x40;
597 msg.len = 2;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300598 rc = tuner_transfer(fe, &msg, 1);
599 if (rc < 0)
600 goto err;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300601
602 msleep(11);
603 msg.flags = I2C_M_RD;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300604 rc = tuner_transfer(fe, &msg, 1);
605 if (rc < 0)
606 goto err;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300607 msg.flags = 0;
608
609 buf[1] >>= 4;
610 dprintk("tda8275a AGC2 gain is: %d\n", buf[1]);
611 if ((buf[1]) < 2) {
Hartmut Hackmann7bff4b42008-04-22 14:46:08 -0300612 tda827xa_lna_gain(fe, 0, NULL);
Michael Krufky8ce47da2007-04-27 12:31:14 -0300613 buf[0] = 0x60;
614 buf[1] = 0x0c;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300615 rc = tuner_transfer(fe, &msg, 1);
616 if (rc < 0)
617 goto err;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300618 }
619
620 buf[0] = 0xc0;
621 buf[1] = 0x99; // lpsel, for 6MHz + 2
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300622 rc = tuner_transfer(fe, &msg, 1);
623 if (rc < 0)
624 goto err;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300625
626 buf[0] = 0x60;
627 buf[1] = 0x3c;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300628 rc = tuner_transfer(fe, &msg, 1);
629 if (rc < 0)
630 goto err;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300631
632 /* correct CP value */
633 buf[0] = 0x30;
klaas de waalcf47d872009-03-25 17:53:02 -0300634 buf[1] = 0x10 + frequency_map[i].scr;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300635 rc = tuner_transfer(fe, &msg, 1);
636 if (rc < 0)
637 goto err;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300638
639 msleep(163);
640 buf[0] = 0xc0;
641 buf[1] = 0x39; // lpsel, for 6MHz + 2
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300642 rc = tuner_transfer(fe, &msg, 1);
643 if (rc < 0)
644 goto err;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300645
646 msleep(3);
647 /* freeze AGC1 */
648 buf[0] = 0x50;
klaas de waalcf47d872009-03-25 17:53:02 -0300649 buf[1] = 0x4f + (frequency_map[i].gc3 << 4);
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300650 rc = tuner_transfer(fe, &msg, 1);
651 if (rc < 0)
652 goto err;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300653
Mauro Carvalho Chehab53ccd1c2011-12-21 08:39:44 -0300654 priv->frequency = c->frequency;
655 priv->bandwidth = band;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300656
Michael Krufky8ce47da2007-04-27 12:31:14 -0300657 return 0;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300658
659err:
660 printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n",
661 __func__, priv->i2c_addr << 1);
662 return rc;
Michael Krufky8ce47da2007-04-27 12:31:14 -0300663}
664
Michael Krufky746d97322007-08-25 19:08:45 -0300665
666static int tda827xa_set_analog_params(struct dvb_frontend *fe,
667 struct analog_parameters *params)
668{
669 unsigned char tuner_reg[11];
670 u32 N;
671 int i;
672 struct tda827x_priv *priv = fe->tuner_priv;
673 struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
674 .buf = tuner_reg, .len = sizeof(tuner_reg) };
675 unsigned int freq = params->frequency;
676
Michael Krufky5c82f442007-10-22 01:10:39 -0300677 tda827x_set_std(fe, params);
678
Michael Krufky746d97322007-08-25 19:08:45 -0300679 tda827xa_lna_gain(fe, 1, params);
680 msleep(10);
681
682 if (params->mode == V4L2_TUNER_RADIO)
683 freq = freq / 1000;
684
Michael Krufky5c82f442007-10-22 01:10:39 -0300685 N = freq + priv->sgIF;
Michael Krufky746d97322007-08-25 19:08:45 -0300686
687 i = 0;
688 while (tda827xa_analog[i].lomax < N * 62500) {
689 if (tda827xa_analog[i + 1].lomax == 0)
690 break;
691 i++;
692 }
693
694 N = N << tda827xa_analog[i].spd;
695
696 tuner_reg[0] = 0;
697 tuner_reg[1] = (unsigned char)(N>>8);
698 tuner_reg[2] = (unsigned char) N;
699 tuner_reg[3] = 0;
700 tuner_reg[4] = 0x16;
701 tuner_reg[5] = (tda827xa_analog[i].spd << 5) +
702 (tda827xa_analog[i].svco << 3) +
703 tda827xa_analog[i].sbs;
704 tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4);
705 tuner_reg[7] = 0x1c;
706 tuner_reg[8] = 4;
707 tuner_reg[9] = 0x20;
708 tuner_reg[10] = 0x00;
709 msg.len = 11;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300710 tuner_transfer(fe, &msg, 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300711
712 tuner_reg[0] = 0x90;
713 tuner_reg[1] = 0xff;
714 tuner_reg[2] = 0xe0;
715 tuner_reg[3] = 0;
Michael Krufky5c82f442007-10-22 01:10:39 -0300716 tuner_reg[4] = 0x99 + (priv->lpsel << 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300717 msg.len = 5;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300718 tuner_transfer(fe, &msg, 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300719
720 tuner_reg[0] = 0xa0;
721 tuner_reg[1] = 0xc0;
722 msg.len = 2;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300723 tuner_transfer(fe, &msg, 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300724
725 tuner_reg[0] = 0x30;
726 tuner_reg[1] = 0x10 + tda827xa_analog[i].scr;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300727 tuner_transfer(fe, &msg, 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300728
729 msg.flags = I2C_M_RD;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300730 tuner_transfer(fe, &msg, 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300731 msg.flags = 0;
732 tuner_reg[1] >>= 4;
733 dprintk("AGC2 gain is: %d\n", tuner_reg[1]);
734 if (tuner_reg[1] < 1)
735 tda827xa_lna_gain(fe, 0, params);
736
737 msleep(100);
738 tuner_reg[0] = 0x60;
739 tuner_reg[1] = 0x3c;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300740 tuner_transfer(fe, &msg, 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300741
742 msleep(163);
743 tuner_reg[0] = 0x50;
744 tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300745 tuner_transfer(fe, &msg, 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300746
747 tuner_reg[0] = 0x80;
748 tuner_reg[1] = 0x28;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300749 tuner_transfer(fe, &msg, 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300750
751 tuner_reg[0] = 0xb0;
752 tuner_reg[1] = 0x01;
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300753 tuner_transfer(fe, &msg, 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300754
755 tuner_reg[0] = 0xc0;
Michael Krufky5c82f442007-10-22 01:10:39 -0300756 tuner_reg[1] = 0x19 + (priv->lpsel << 1);
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300757 tuner_transfer(fe, &msg, 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300758
Mauro Carvalho Chehab92d90f12008-12-08 00:49:33 -0300759 priv->frequency = params->frequency;
Michael Krufky746d97322007-08-25 19:08:45 -0300760
761 return 0;
762}
763
764static void tda827xa_agcf(struct dvb_frontend *fe)
765{
766 struct tda827x_priv *priv = fe->tuner_priv;
767 unsigned char data[] = {0x80, 0x2c};
768 struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0,
769 .buf = data, .len = 2};
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300770 tuner_transfer(fe, &msg, 1);
Michael Krufky746d97322007-08-25 19:08:45 -0300771}
772
773/* ------------------------------------------------------------------ */
774
Michael Krufky8ce47da2007-04-27 12:31:14 -0300775static int tda827x_release(struct dvb_frontend *fe)
776{
777 kfree(fe->tuner_priv);
778 fe->tuner_priv = NULL;
779 return 0;
780}
781
782static int tda827x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
783{
784 struct tda827x_priv *priv = fe->tuner_priv;
785 *frequency = priv->frequency;
786 return 0;
787}
788
789static int tda827x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
790{
791 struct tda827x_priv *priv = fe->tuner_priv;
792 *bandwidth = priv->bandwidth;
793 return 0;
794}
795
796static int tda827x_init(struct dvb_frontend *fe)
797{
798 struct tda827x_priv *priv = fe->tuner_priv;
Hartmut Hackmann7bff4b42008-04-22 14:46:08 -0300799 dprintk("%s:\n", __func__);
Michael Krufky8ce47da2007-04-27 12:31:14 -0300800 if (priv->cfg && priv->cfg->init)
801 priv->cfg->init(fe);
802
803 return 0;
804}
805
Hartmut Hackmann9971f4f2007-03-23 21:00:07 -0300806static int tda827x_probe_version(struct dvb_frontend *fe);
807
808static int tda827x_initial_init(struct dvb_frontend *fe)
809{
810 int ret;
811 ret = tda827x_probe_version(fe);
812 if (ret)
813 return ret;
814 return fe->ops.tuner_ops.init(fe);
815}
816
817static int tda827x_initial_sleep(struct dvb_frontend *fe)
818{
819 int ret;
820 ret = tda827x_probe_version(fe);
821 if (ret)
822 return ret;
823 return fe->ops.tuner_ops.sleep(fe);
824}
Michael Krufky8ce47da2007-04-27 12:31:14 -0300825
826static struct dvb_tuner_ops tda827xo_tuner_ops = {
827 .info = {
828 .name = "Philips TDA827X",
Hartmut Hackmann11f65102007-04-27 12:31:15 -0300829 .frequency_min = 55000000,
830 .frequency_max = 860000000,
831 .frequency_step = 250000
Michael Krufky8ce47da2007-04-27 12:31:14 -0300832 },
833 .release = tda827x_release,
Hartmut Hackmann9971f4f2007-03-23 21:00:07 -0300834 .init = tda827x_initial_init,
835 .sleep = tda827x_initial_sleep,
Michael Krufky8ce47da2007-04-27 12:31:14 -0300836 .set_params = tda827xo_set_params,
Michael Krufky746d97322007-08-25 19:08:45 -0300837 .set_analog_params = tda827xo_set_analog_params,
Michael Krufky8ce47da2007-04-27 12:31:14 -0300838 .get_frequency = tda827x_get_frequency,
839 .get_bandwidth = tda827x_get_bandwidth,
840};
841
842static struct dvb_tuner_ops tda827xa_tuner_ops = {
843 .info = {
844 .name = "Philips TDA827XA",
Hartmut Hackmann11f65102007-04-27 12:31:15 -0300845 .frequency_min = 44000000,
846 .frequency_max = 906000000,
847 .frequency_step = 62500
Michael Krufky8ce47da2007-04-27 12:31:14 -0300848 },
849 .release = tda827x_release,
850 .init = tda827x_init,
851 .sleep = tda827xa_sleep,
852 .set_params = tda827xa_set_params,
Michael Krufky746d97322007-08-25 19:08:45 -0300853 .set_analog_params = tda827xa_set_analog_params,
Michael Krufky8ce47da2007-04-27 12:31:14 -0300854 .get_frequency = tda827x_get_frequency,
855 .get_bandwidth = tda827x_get_bandwidth,
856};
857
Hartmut Hackmann9971f4f2007-03-23 21:00:07 -0300858static int tda827x_probe_version(struct dvb_frontend *fe)
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300859{
860 u8 data;
861 int rc;
Hartmut Hackmann9971f4f2007-03-23 21:00:07 -0300862 struct tda827x_priv *priv = fe->tuner_priv;
863 struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = I2C_M_RD,
864 .buf = &data, .len = 1 };
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300865
866 rc = tuner_transfer(fe, &msg, 1);
867
868 if (rc < 0) {
Hartmut Hackmann9971f4f2007-03-23 21:00:07 -0300869 printk("%s: could not read from tuner at addr: 0x%02x\n",
Hartmut Hackmann7bff4b42008-04-22 14:46:08 -0300870 __func__, msg.addr << 1);
Mauro Carvalho Chehab68d5ce72009-02-08 08:34:43 -0300871 return rc;
Hartmut Hackmann9971f4f2007-03-23 21:00:07 -0300872 }
873 if ((data & 0x3c) == 0) {
874 dprintk("tda827x tuner found\n");
875 fe->ops.tuner_ops.init = tda827x_init;
876 fe->ops.tuner_ops.sleep = tda827xo_sleep;
Michael Krufky3b0c4532007-11-18 14:15:42 -0300877 if (priv->cfg)
878 priv->cfg->agcf = tda827xo_agcf;
Hartmut Hackmann9971f4f2007-03-23 21:00:07 -0300879 } else {
880 dprintk("tda827xa tuner found\n");
881 memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops));
Michael Krufky3b0c4532007-11-18 14:15:42 -0300882 if (priv->cfg)
883 priv->cfg->agcf = tda827xa_agcf;
Hartmut Hackmann9971f4f2007-03-23 21:00:07 -0300884 }
885 return 0;
886}
887
Michael Krufky8ce47da2007-04-27 12:31:14 -0300888struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr,
889 struct i2c_adapter *i2c,
890 struct tda827x_config *cfg)
891{
892 struct tda827x_priv *priv = NULL;
Hartmut Hackmann9971f4f2007-03-23 21:00:07 -0300893
Hartmut Hackmann7bff4b42008-04-22 14:46:08 -0300894 dprintk("%s:\n", __func__);
Michael Krufky8ce47da2007-04-27 12:31:14 -0300895 priv = kzalloc(sizeof(struct tda827x_priv), GFP_KERNEL);
896 if (priv == NULL)
897 return NULL;
898
899 priv->i2c_addr = addr;
900 priv->i2c_adap = i2c;
901 priv->cfg = cfg;
Hartmut Hackmann9971f4f2007-03-23 21:00:07 -0300902 memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops));
Michael Krufky8ce47da2007-04-27 12:31:14 -0300903 fe->tuner_priv = priv;
Hartmut Hackmann9971f4f2007-03-23 21:00:07 -0300904
Michael Krufky746d97322007-08-25 19:08:45 -0300905 dprintk("type set to %s\n", fe->ops.tuner_ops.info.name);
906
Michael Krufky8ce47da2007-04-27 12:31:14 -0300907 return fe;
908}
Michael Krufkyce1f8bd2007-10-22 00:28:50 -0300909EXPORT_SYMBOL_GPL(tda827x_attach);
Michael Krufky8ce47da2007-04-27 12:31:14 -0300910
Michael Krufky8ce47da2007-04-27 12:31:14 -0300911MODULE_DESCRIPTION("DVB TDA827x driver");
Hartmut Hackmann11f65102007-04-27 12:31:15 -0300912MODULE_AUTHOR("Hartmut Hackmann <hartmut.hackmann@t-online.de>");
913MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
Michael Krufky8ce47da2007-04-27 12:31:14 -0300914MODULE_LICENSE("GPL");
915
916/*
917 * Overrides for Emacs so that we follow Linus's tabbing style.
918 * ---------------------------------------------------------------------------
919 * Local variables:
920 * c-basic-offset: 8
921 * End:
922 */