Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Patrick Boettcher and committed by
Mauro Carvalho Chehab
4c48ae8e 2bdd29cf

+626 -3
+1
drivers/media/dvb/b2c2/Kconfig
··· 14 14 select DVB_ISL6421 if !DVB_FE_CUSTOMISE 15 15 select DVB_CX24123 if !DVB_FE_CUSTOMISE 16 16 select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE 17 + select DVB_TUNER_CX24113 if !DVB_FE_CUSTOMISE 17 18 help 18 19 Support for the digital TV receiver chip made by B2C2 Inc. included in 19 20 Technisats PCI cards and USB boxes.
+8
drivers/media/dvb/frontends/Kconfig
··· 118 118 help 119 119 A DVB-S tuner module. Say Y when you want to support this frontend. 120 120 121 + config 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 + 121 129 config DVB_TDA826X 122 130 tristate "Philips TDA826X silicon tuner" 123 131 depends on DVB_CORE && I2C
+1
drivers/media/dvb/frontends/Makefile
··· 54 54 obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o 55 55 obj-$(CONFIG_DVB_AU8522) += au8522.o 56 56 obj-$(CONFIG_DVB_TDA10048) += tda10048.o 57 + obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o 57 58 obj-$(CONFIG_DVB_S5H1411) += s5h1411.o 58 59 obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o 59 60 obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
+608
drivers/media/dvb/frontends/cx24113.c
··· 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 + 32 + static 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 + 45 + struct 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 + 104 + static 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 + 119 + static 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 + 141 + static 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 + 201 + static 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 + 234 + static 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 + 246 + static 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 + 254 + static 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 + 279 + static 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 + 285 + static 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 + 295 + static 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 + 302 + static 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 + 373 + static 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 + 389 + static 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 + 421 + static 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 + 475 + static 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 + 494 + static 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 + 499 + void 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 + } 517 + EXPORT_SYMBOL(cx24113_agc_callback); 518 + 519 + static 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 + 526 + static 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 + 535 + static 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 + 554 + struct 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 + 595 + error: 596 + kfree(state); 597 + 598 + return NULL; 599 + } 600 + EXPORT_SYMBOL(cx24113_attach); 601 + 602 + module_param(debug, int, 0644); 603 + MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); 604 + 605 + MODULE_AUTHOR("Patrick Boettcher <pb@linuxtv.org>"); 606 + MODULE_DESCRIPTION("DVB Frontend module for Conexant CX24113/CX24128hardware"); 607 + MODULE_LICENSE("GPL"); 608 +
+8 -3
drivers/media/dvb/frontends/cx24113.h
··· 16 16 * 17 17 * You should have received a copy of the GNU General Public License 18 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 22 #ifndef CX24113_H ··· 30 30 u32 xtal_khz; 31 31 }; 32 32 33 - /* TODO: #if defined(CONFIG_DVB_TUNER_CX24113) || \ 34 - * (defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE)) */ 33 + #if defined(CONFIG_DVB_TUNER_CX24113) || \ 34 + (defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE)) 35 + extern struct dvb_frontend *cx24113_attach(struct dvb_frontend *, 36 + const struct cx24113_config *config, struct i2c_adapter *i2c); 35 37 38 + extern void cx24113_agc_callback(struct dvb_frontend *fe); 39 + #else 36 40 static inline struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe, 37 41 const struct cx24113_config *config, struct i2c_adapter *i2c) 38 42 { ··· 48 44 { 49 45 printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); 50 46 } 47 + #endif 51 48 52 49 #endif /* CX24113_H */