aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick Boettcher <pb@linuxtv.org>2008-11-23 14:26:54 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-12-30 06:38:34 -0500
commit4c48ae8e8a490f16abbd874602135bcd83c84f26 (patch)
treebfc24684580dc6ddffb462092b288917ba424f69
parent2bdd29cf3d4d32e4371fbd6b27ea171f2c1f0836 (diff)
V4L/DVB (9811): Add support for the CX24113 DVB-S tuner driver
This commit adds support for the CX24113 DVB-S tuner driver and thus support for the Technisat Skystar2 revision 2.8. The driver was created with the help of Technisat. Thank you very much. Signed-off-by: Patrick Boettcher <pb@linuxtv.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/dvb/b2c2/Kconfig1
-rw-r--r--drivers/media/dvb/frontends/Kconfig8
-rw-r--r--drivers/media/dvb/frontends/Makefile1
-rw-r--r--drivers/media/dvb/frontends/cx24113.c608
-rw-r--r--drivers/media/dvb/frontends/cx24113.h11
5 files changed, 626 insertions, 3 deletions
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
index b34301d56cd2..a8c6249c4099 100644
--- a/drivers/media/dvb/b2c2/Kconfig
+++ b/drivers/media/dvb/b2c2/Kconfig
@@ -14,6 +14,7 @@ config DVB_B2C2_FLEXCOP
14 select DVB_ISL6421 if !DVB_FE_CUSTOMISE 14 select DVB_ISL6421 if !DVB_FE_CUSTOMISE
15 select DVB_CX24123 if !DVB_FE_CUSTOMISE 15 select DVB_CX24123 if !DVB_FE_CUSTOMISE
16 select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE 16 select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
17 select DVB_TUNER_CX24113 if !DVB_FE_CUSTOMISE
17 help 18 help
18 Support for the digital TV receiver chip made by B2C2 Inc. included in 19 Support for the digital TV receiver chip made by B2C2 Inc. included in
19 Technisats PCI cards and USB boxes. 20 Technisats PCI cards and USB boxes.
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 2470d88e901a..00269560793a 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -118,6 +118,14 @@ config DVB_TUNER_ITD1000
118 help 118 help
119 A DVB-S tuner module. Say Y when you want to support this frontend. 119 A DVB-S tuner module. Say Y when you want to support this frontend.
120 120
121config DVB_TUNER_CX24113
122 tristate "Conexant CX24113/CX24128 tuner for DVB-S/DSS"
123 depends on DVB_CORE && I2C
124 default m if DVB_FE_CUSTOMISE
125 help
126 A DVB-S tuner module. Say Y when you want to support this frontend.
127
128
121config DVB_TDA826X 129config DVB_TDA826X
122 tristate "Philips TDA826X silicon tuner" 130 tristate "Philips TDA826X silicon tuner"
123 depends on DVB_CORE && I2C 131 depends on DVB_CORE && I2C
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 7a19c0c7b7a0..af7bdf0ad4c7 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
54obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o 54obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
55obj-$(CONFIG_DVB_AU8522) += au8522.o 55obj-$(CONFIG_DVB_AU8522) += au8522.o
56obj-$(CONFIG_DVB_TDA10048) += tda10048.o 56obj-$(CONFIG_DVB_TDA10048) += tda10048.o
57obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
57obj-$(CONFIG_DVB_S5H1411) += s5h1411.o 58obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
58obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o 59obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
59obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o 60obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
diff --git a/drivers/media/dvb/frontends/cx24113.c b/drivers/media/dvb/frontends/cx24113.c
new file mode 100644
index 000000000000..e2e5df9de1ec
--- /dev/null
+++ b/drivers/media/dvb/frontends/cx24113.c
@@ -0,0 +1,608 @@
1/*
2 * Driver for Conexant CX24113/CX24128 Tuner (Satelite)
3 *
4 * Copyright (C) 2007-8 Patrick Boettcher <pb@linuxtv.org>
5 *
6 * Developed for BBTI / Technisat
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 *
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24#include <linux/slab.h>
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/init.h>
28
29#include "dvb_frontend.h"
30#include "cx24113.h"
31
32static int debug;
33
34#define info(args...) do { printk(KERN_INFO "CX24113: " args); } while (0)
35#define err(args...) do { printk(KERN_ERR "CX24113: " args); } while (0)
36
37#define dprintk(args...) \
38 do { \
39 if (debug) { \
40 printk(KERN_DEBUG "CX24113: %s: ", __func__); \
41 printk(args); \
42 } \
43 } while (0)
44
45struct cx24113_state {
46 struct i2c_adapter *i2c;
47 const struct cx24113_config *config;
48
49#define REV_CX24113 0x23
50 u8 rev;
51 u8 ver;
52
53 u8 icp_mode:1;
54
55#define ICP_LEVEL1 0
56#define ICP_LEVEL2 1
57#define ICP_LEVEL3 2
58#define ICP_LEVEL4 3
59 u8 icp_man:2;
60 u8 icp_auto_low:2;
61 u8 icp_auto_mlow:2;
62 u8 icp_auto_mhi:2;
63 u8 icp_auto_hi:2;
64 u8 icp_dig;
65
66#define LNA_MIN_GAIN 0
67#define LNA_MID_GAIN 1
68#define LNA_MAX_GAIN 2
69 u8 lna_gain:2;
70
71 u8 acp_on:1;
72
73 u8 vco_mode:2;
74 u8 vco_shift:1;
75#define VCOBANDSEL_6 0x80
76#define VCOBANDSEL_5 0x01
77#define VCOBANDSEL_4 0x02
78#define VCOBANDSEL_3 0x04
79#define VCOBANDSEL_2 0x08
80#define VCOBANDSEL_1 0x10
81 u8 vco_band;
82
83#define VCODIV4 4
84#define VCODIV2 2
85 u8 vcodiv;
86
87 u8 bs_delay:4;
88 u16 bs_freqcnt:13;
89 u16 bs_rdiv;
90 u8 prescaler_mode:1;
91
92 u8 rfvga_bias_ctrl;
93
94 s16 tuner_gain_thres;
95 u8 gain_level;
96
97 u32 frequency;
98
99 u8 refdiv;
100
101 u8 Fwindow_enabled;
102};
103
104static int cx24113_writereg(struct cx24113_state *state, int reg, int data)
105{
106 u8 buf[] = { reg, data };
107 struct i2c_msg msg = { .addr = state->config->i2c_addr,
108 .flags = 0, .buf = buf, .len = 2 };
109 int err = i2c_transfer(state->i2c, &msg, 1);
110 if (err != 1) {
111 printk(KERN_DEBUG "%s: writereg error(err == %i, reg == 0x%02x,"
112 " data == 0x%02x)\n", __func__, err, reg, data);
113 return err;
114 }
115
116 return 0;
117}
118
119static int cx24113_readreg(struct cx24113_state *state, u8 reg)
120{
121 int ret;
122 u8 b;
123 struct i2c_msg msg[] = {
124 { .addr = state->config->i2c_addr,
125 .flags = 0, .buf = &reg, .len = 1 },
126 { .addr = state->config->i2c_addr,
127 .flags = I2C_M_RD, .buf = &b, .len = 1 }
128 };
129
130 ret = i2c_transfer(state->i2c, msg, 2);
131
132 if (ret != 2) {
133 printk(KERN_DEBUG "%s: reg=0x%x (error=%d)\n",
134 __func__, reg, ret);
135 return ret;
136 }
137
138 return b;
139}
140
141static void cx24113_set_parameters(struct cx24113_state *state)
142{
143 u8 r;
144
145 r = cx24113_readreg(state, 0x10) & 0x82;
146 r |= state->icp_mode;
147 r |= state->icp_man << 4;
148 r |= state->icp_dig << 2;
149 r |= state->prescaler_mode << 5;
150 cx24113_writereg(state, 0x10, r);
151
152 r = (state->icp_auto_low << 0) | (state->icp_auto_mlow << 2)
153 | (state->icp_auto_mhi << 4) | (state->icp_auto_hi << 6);
154 cx24113_writereg(state, 0x11, r);
155
156 if (state->rev == REV_CX24113) {
157 r = cx24113_readreg(state, 0x20) & 0xec;
158 r |= state->lna_gain;
159 r |= state->rfvga_bias_ctrl << 4;
160 cx24113_writereg(state, 0x20, r);
161 }
162
163 r = cx24113_readreg(state, 0x12) & 0x03;
164 r |= state->acp_on << 2;
165 r |= state->bs_delay << 4;
166 cx24113_writereg(state, 0x12, r);
167
168 r = cx24113_readreg(state, 0x18) & 0x40;
169 r |= state->vco_shift;
170 if (state->vco_band == VCOBANDSEL_6)
171 r |= (1 << 7);
172 else
173 r |= (state->vco_band << 1);
174 cx24113_writereg(state, 0x18, r);
175
176 r = cx24113_readreg(state, 0x14) & 0x20;
177 r |= (state->vco_mode << 6) | ((state->bs_freqcnt >> 8) & 0x1f);
178 cx24113_writereg(state, 0x14, r);
179 cx24113_writereg(state, 0x15, (state->bs_freqcnt & 0xff));
180
181 cx24113_writereg(state, 0x16, (state->bs_rdiv >> 4) & 0xff);
182 r = (cx24113_readreg(state, 0x17) & 0x0f) |
183 ((state->bs_rdiv & 0x0f) << 4);
184 cx24113_writereg(state, 0x17, r);
185}
186
187#define VGA_0 0x00
188#define VGA_1 0x04
189#define VGA_2 0x02
190#define VGA_3 0x06
191#define VGA_4 0x01
192#define VGA_5 0x05
193#define VGA_6 0x03
194#define VGA_7 0x07
195
196#define RFVGA_0 0x00
197#define RFVGA_1 0x01
198#define RFVGA_2 0x02
199#define RFVGA_3 0x03
200
201static int cx24113_set_gain_settings(struct cx24113_state *state,
202 s16 power_estimation)
203{
204 u8 ampout = cx24113_readreg(state, 0x1d) & 0xf0,
205 vga = cx24113_readreg(state, 0x1f) & 0x3f,
206 rfvga = cx24113_readreg(state, 0x20) & 0xf3;
207 u8 gain_level = power_estimation >= state->tuner_gain_thres;
208
209 dprintk("power estimation: %d, thres: %d, gain_level: %d/%d\n",
210 power_estimation, state->tuner_gain_thres,
211 state->gain_level, gain_level);
212
213 if (gain_level == state->gain_level)
214 return 0; /* nothing to be done */
215
216 ampout |= 0xf;
217
218 if (gain_level) {
219 rfvga |= RFVGA_0 << 2;
220 vga |= (VGA_7 << 3) | VGA_7;
221 } else {
222 rfvga |= RFVGA_2 << 2;
223 vga |= (VGA_6 << 3) | VGA_2;
224 }
225 state->gain_level = gain_level;
226
227 cx24113_writereg(state, 0x1d, ampout);
228 cx24113_writereg(state, 0x1f, vga);
229 cx24113_writereg(state, 0x20, rfvga);
230
231 return 1; /* did something */
232}
233
234static int cx24113_set_Fref(struct cx24113_state *state, u8 high)
235{
236 u8 xtal = cx24113_readreg(state, 0x02);
237 if (state->rev == 0x43 && state->vcodiv == VCODIV4)
238 high = 1;
239
240 xtal &= ~0x2;
241 if (high)
242 xtal |= high << 1;
243 return cx24113_writereg(state, 0x02, xtal);
244}
245
246static int cx24113_enable(struct cx24113_state *state, u8 enable)
247{
248 u8 r21 = (cx24113_readreg(state, 0x21) & 0xc0) | enable;
249 if (state->rev == REV_CX24113)
250 r21 |= (1 << 1);
251 return cx24113_writereg(state, 0x21, r21);
252}
253
254static int cx24113_set_bandwidth(struct cx24113_state *state, u32 bandwidth_khz)
255{
256 u8 r;
257
258 if (bandwidth_khz <= 19000)
259 r = 0x03 << 6;
260 else if (bandwidth_khz <= 25000)
261 r = 0x02 << 6;
262 else
263 r = 0x01 << 6;
264
265 dprintk("bandwidth to be set: %d\n", bandwidth_khz);
266 bandwidth_khz *= 10;
267 bandwidth_khz -= 10000;
268 bandwidth_khz /= 1000;
269 bandwidth_khz += 5;
270 bandwidth_khz /= 10;
271
272 dprintk("bandwidth: %d %d\n", r >> 6, bandwidth_khz);
273
274 r |= bandwidth_khz & 0x3f;
275
276 return cx24113_writereg(state, 0x1e, r);
277}
278
279static int cx24113_set_clk_inversion(struct cx24113_state *state, u8 on)
280{
281 u8 r = (cx24113_readreg(state, 0x10) & 0x7f) | ((on & 0x1) << 7);
282 return cx24113_writereg(state, 0x10, r);
283}
284
285static int cx24113_get_status(struct dvb_frontend *fe, u32 *status)
286{
287 struct cx24113_state *state = fe->tuner_priv;
288 u8 r = (cx24113_readreg(state, 0x10) & 0x02) >> 1;
289 if (r)
290 *status |= TUNER_STATUS_LOCKED;
291 dprintk("PLL locked: %d\n", r);
292 return 0;
293}
294
295static u8 cx24113_set_ref_div(struct cx24113_state *state, u8 refdiv)
296{
297 if (state->rev == 0x43 && state->vcodiv == VCODIV4)
298 refdiv = 2;
299 return state->refdiv = refdiv;
300}
301
302static void cx24113_calc_pll_nf(struct cx24113_state *state, u16 *n, s32 *f)
303{
304 s32 N;
305 s64 F;
306 u8 R, r;
307 u8 vcodiv;
308 u8 factor;
309 s32 freq_hz = state->frequency * 1000;
310
311 if (state->config->xtal_khz < 20000)
312 factor = 1;
313 else
314 factor = 2;
315
316 if (state->rev == REV_CX24113) {
317 if (state->frequency >= 1100000)
318 vcodiv = VCODIV2;
319 else
320 vcodiv = VCODIV4;
321 } else {
322 if (state->frequency >= 1165000)
323 vcodiv = VCODIV2;
324 else
325 vcodiv = VCODIV4;
326 }
327 state->vcodiv = vcodiv;
328
329 dprintk("calculating N/F for %dHz with vcodiv %d\n", freq_hz, vcodiv);
330 R = 0;
331 do {
332 R = cx24113_set_ref_div(state, R + 1);
333
334 /* calculate tuner PLL settings: */
335 N = (freq_hz / 100 * vcodiv) * R;
336 N /= (state->config->xtal_khz) * factor * 2;
337 N += 5; /* For round up. */
338 N /= 10;
339 N -= 32;
340 } while (N < 6 && R < 3);
341
342 if (N < 6) {
343 err("strange frequency: N < 6\n");
344 return;
345 }
346 F = freq_hz;
347 F *= (u64) (R * vcodiv * 262144);
348 dprintk("1 N: %d, F: %lld, R: %d\n", N, F, R);
349 do_div(F, state->config->xtal_khz*1000 * factor * 2);
350 dprintk("2 N: %d, F: %lld, R: %d\n", N, F, R);
351 F -= (N + 32) * 262144;
352
353 dprintk("3 N: %d, F: %lld, R: %d\n", N, F, R);
354
355 if (state->Fwindow_enabled) {
356 if (F > (262144 / 2 - 1638))
357 F = 262144 / 2 - 1638;
358 if (F < (-262144 / 2 + 1638))
359 F = -262144 / 2 + 1638;
360 if ((F < 3277 && F > 0) || (F > -3277 && F < 0)) {
361 F = 0;
362 r = cx24113_readreg(state, 0x10);
363 cx24113_writereg(state, 0x10, r | (1 << 6));
364 }
365 }
366 dprintk("4 N: %d, F: %lld, R: %d\n", N, F, R);
367
368 *n = (u16) N;
369 *f = (s32) F;
370}
371
372
373static void cx24113_set_nfr(struct cx24113_state *state, u16 n, s32 f, u8 r)
374{
375 u8 reg;
376 cx24113_writereg(state, 0x19, (n >> 1) & 0xff);
377
378 reg = ((n & 0x1) << 7) | ((f >> 11) & 0x7f);
379 cx24113_writereg(state, 0x1a, reg);
380
381 cx24113_writereg(state, 0x1b, (f >> 3) & 0xff);
382
383 reg = cx24113_readreg(state, 0x1c) & 0x1f;
384 cx24113_writereg(state, 0x1c, reg | ((f & 0x7) << 5));
385
386 cx24113_set_Fref(state, r - 1);
387}
388
389static int cx24113_set_frequency(struct cx24113_state *state, u32 frequency)
390{
391 u8 r = 1; /* or 2 */
392 u16 n = 6;
393 s32 f = 0;
394
395 r = cx24113_readreg(state, 0x14);
396 cx24113_writereg(state, 0x14, r & 0x3f);
397
398 r = cx24113_readreg(state, 0x10);
399 cx24113_writereg(state, 0x10, r & 0xbf);
400
401 state->frequency = frequency;
402
403 dprintk("tuning to frequency: %d\n", frequency);
404
405 cx24113_calc_pll_nf(state, &n, &f);
406 cx24113_set_nfr(state, n, f, state->refdiv);
407
408 r = cx24113_readreg(state, 0x18) & 0xbf;
409 if (state->vcodiv != VCODIV2)
410 r |= 1 << 6;
411 cx24113_writereg(state, 0x18, r);
412
413 /* The need for this sleep is not clear. But helps in some cases */
414 msleep(5);
415
416 r = cx24113_readreg(state, 0x1c) & 0xef;
417 cx24113_writereg(state, 0x1c, r | (1 << 4));
418 return 0;
419}
420
421static int cx24113_init(struct dvb_frontend *fe)
422{
423 struct cx24113_state *state = fe->tuner_priv;
424 int ret;
425
426 state->tuner_gain_thres = -50;
427 state->gain_level = 255; /* to force a gain-setting initialization */
428 state->icp_mode = 0;
429
430 if (state->config->xtal_khz < 11000) {
431 state->icp_auto_hi = ICP_LEVEL4;
432 state->icp_auto_mhi = ICP_LEVEL4;
433 state->icp_auto_mlow = ICP_LEVEL3;
434 state->icp_auto_low = ICP_LEVEL3;
435 } else {
436 state->icp_auto_hi = ICP_LEVEL4;
437 state->icp_auto_mhi = ICP_LEVEL4;
438 state->icp_auto_mlow = ICP_LEVEL3;
439 state->icp_auto_low = ICP_LEVEL2;
440 }
441
442 state->icp_dig = ICP_LEVEL3;
443 state->icp_man = ICP_LEVEL1;
444 state->acp_on = 1;
445 state->vco_mode = 0;
446 state->vco_shift = 0;
447 state->vco_band = VCOBANDSEL_1;
448 state->bs_delay = 8;
449 state->bs_freqcnt = 0x0fff;
450 state->bs_rdiv = 0x0fff;
451 state->prescaler_mode = 0;
452 state->lna_gain = LNA_MAX_GAIN;
453 state->rfvga_bias_ctrl = 1;
454 state->Fwindow_enabled = 1;
455
456 cx24113_set_Fref(state, 0);
457 cx24113_enable(state, 0x3d);
458 cx24113_set_parameters(state);
459
460 cx24113_set_gain_settings(state, -30);
461
462 cx24113_set_bandwidth(state, 18025);
463 cx24113_set_clk_inversion(state, 1);
464
465 if (state->config->xtal_khz >= 40000)
466 ret = cx24113_writereg(state, 0x02,
467 (cx24113_readreg(state, 0x02) & 0xfb) | (1 << 2));
468 else
469 ret = cx24113_writereg(state, 0x02,
470 (cx24113_readreg(state, 0x02) & 0xfb) | (0 << 2));
471
472 return ret;
473}
474
475static int cx24113_set_params(struct dvb_frontend *fe,
476 struct dvb_frontend_parameters *p)
477{
478 struct cx24113_state *state = fe->tuner_priv;
479 /* for a ROLL-OFF factor of 0.35, 0.2: 600, 0.25: 625 */
480 u32 roll_off = 675;
481 u32 bw;
482
483 bw = ((p->u.qpsk.symbol_rate/100) * roll_off) / 1000;
484 bw += (10000000/100) + 5;
485 bw /= 10;
486 bw += 1000;
487 cx24113_set_bandwidth(state, bw);
488
489 cx24113_set_frequency(state, p->frequency);
490 msleep(5);
491 return cx24113_get_status(fe, &bw);
492}
493
494static s8 cx24113_agc_table[2][10] = {
495 {-54, -41, -35, -30, -25, -21, -16, -10, -6, -2},
496 {-39, -35, -30, -25, -19, -15, -11, -5, 1, 9},
497};
498
499void cx24113_agc_callback(struct dvb_frontend *fe)
500{
501 struct cx24113_state *state = fe->tuner_priv;
502 s16 s, i;
503 if (!fe->ops.read_signal_strength)
504 return;
505
506 do {
507 /* this only works with the current CX24123 implementation */
508 fe->ops.read_signal_strength(fe, (u16 *) &s);
509 s >>= 8;
510 dprintk("signal strength: %d\n", s);
511 for (i = 0; i < sizeof(cx24113_agc_table[0]); i++)
512 if (cx24113_agc_table[state->gain_level][i] > s)
513 break;
514 s = -25 - i*5;
515 } while (cx24113_set_gain_settings(state, s));
516}
517EXPORT_SYMBOL(cx24113_agc_callback);
518
519static int cx24113_get_frequency(struct dvb_frontend *fe, u32 *frequency)
520{
521 struct cx24113_state *state = fe->tuner_priv;
522 *frequency = state->frequency;
523 return 0;
524}
525
526static int cx24113_release(struct dvb_frontend *fe)
527{
528 struct cx24113_state *state = fe->tuner_priv;
529 dprintk("\n");
530 fe->tuner_priv = NULL;
531 kfree(state);
532 return 0;
533}
534
535static const struct dvb_tuner_ops cx24113_tuner_ops = {
536 .info = {
537 .name = "Conexant CX24113",
538 .frequency_min = 950000,
539 .frequency_max = 2150000,
540 .frequency_step = 125,
541 },
542
543 .release = cx24113_release,
544
545 .init = cx24113_init,
546 .sleep = NULL,
547
548 .set_params = cx24113_set_params,
549 .get_frequency = cx24113_get_frequency,
550 .get_bandwidth = NULL,
551 .get_status = cx24113_get_status,
552};
553
554struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
555 const struct cx24113_config *config, struct i2c_adapter *i2c)
556{
557 /* allocate memory for the internal state */
558 struct cx24113_state *state =
559 kzalloc(sizeof(struct cx24113_state), GFP_KERNEL);
560 if (state == NULL) {
561 err("Unable to kmalloc\n");
562 goto error;
563 }
564
565 /* setup the state */
566 state->config = config;
567 state->i2c = i2c;
568
569 info("trying to detect myself\n");
570
571 /* making a dummy read, because of some expected troubles
572 * after power on */
573 cx24113_readreg(state, 0x00);
574
575 switch (state->rev = cx24113_readreg(state, 0x00)) {
576 case 0x43:
577 info("unknown device\n");
578 break;
579 case REV_CX24113:
580 info("CX24113\n");
581 break;
582 default:
583 err("unsupported revision: %x\n", state->rev);
584 goto error;
585 }
586 state->ver = cx24113_readreg(state, 0x01);
587 info("version: %x\n", state->ver);
588
589 /* create dvb_frontend */
590 memcpy(&fe->ops.tuner_ops, &cx24113_tuner_ops,
591 sizeof(struct dvb_tuner_ops));
592 fe->tuner_priv = state;
593 return fe;
594
595error:
596 kfree(state);
597
598 return NULL;
599}
600EXPORT_SYMBOL(cx24113_attach);
601
602module_param(debug, int, 0644);
603MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
604
605MODULE_AUTHOR("Patrick Boettcher <pb@linuxtv.org>");
606MODULE_DESCRIPTION("DVB Frontend module for Conexant CX24113/CX24128hardware");
607MODULE_LICENSE("GPL");
608
diff --git a/drivers/media/dvb/frontends/cx24113.h b/drivers/media/dvb/frontends/cx24113.h
index 5ab3dd11076b..5de0f7ffd8d2 100644
--- a/drivers/media/dvb/frontends/cx24113.h
+++ b/drivers/media/dvb/frontends/cx24113.h
@@ -16,7 +16,7 @@
16 * 16 *
17 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */ 20 */
21 21
22#ifndef CX24113_H 22#ifndef CX24113_H
@@ -30,9 +30,13 @@ struct cx24113_config {
30 u32 xtal_khz; 30 u32 xtal_khz;
31}; 31};
32 32
33/* TODO: #if defined(CONFIG_DVB_TUNER_CX24113) || \ 33#if defined(CONFIG_DVB_TUNER_CX24113) || \
34 * (defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE)) */ 34 (defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE))
35extern struct dvb_frontend *cx24113_attach(struct dvb_frontend *,
36 const struct cx24113_config *config, struct i2c_adapter *i2c);
35 37
38extern void cx24113_agc_callback(struct dvb_frontend *fe);
39#else
36static inline struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe, 40static inline struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
37 const struct cx24113_config *config, struct i2c_adapter *i2c) 41 const struct cx24113_config *config, struct i2c_adapter *i2c)
38{ 42{
@@ -44,5 +48,6 @@ static inline void cx24113_agc_callback(struct dvb_frontend *fe)
44{ 48{
45 printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); 49 printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
46} 50}
51#endif
47 52
48#endif /* CX24113_H */ 53#endif /* CX24113_H */