1/* 2 * Driver for Micronas drx397xD demodulator 3 * 4 * Copyright (C) 2007 Henk Vergonet <Henk.Vergonet@gmail.com> 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, see <http://www.gnu.org/licenses/>. 18 */ 19 20#define DEBUG /* uncomment if you want debugging output */ 21#include <linux/kernel.h> 22#include <linux/module.h> 23#include <linux/moduleparam.h> 24#include <linux/init.h> 25#include <linux/device.h> 26#include <linux/delay.h> 27#include <linux/string.h> 28#include <linux/firmware.h> 29#include <linux/slab.h> 30#include <asm/div64.h> 31 32#include "dvb_frontend.h" 33#include "drx397xD.h" 34 35static const char mod_name[] = "drx397xD"; 36 37#define MAX_CLOCK_DRIFT 200 /* maximal 200 PPM allowed */ 38 39#define F_SET_0D0h 1 40#define F_SET_0D4h 2 41 42enum fw_ix { 43#define _FW_ENTRY(a, b, c) b 44#include "drx397xD_fw.h" 45}; 46 47/* chip specifics */ 48struct drx397xD_state { 49 struct i2c_adapter *i2c; 50 struct dvb_frontend frontend; 51 struct drx397xD_config config; 52 enum fw_ix chip_rev; 53 int flags; 54 u32 bandwidth_parm; /* internal bandwidth conversions */ 55 u32 f_osc; /* w90: actual osc frequency [Hz] */ 56}; 57 58/* Firmware */ 59static const char *blob_name[] = { 60#define _BLOB_ENTRY(a, b) a 61#include "drx397xD_fw.h" 62}; 63 64enum blob_ix { 65#define _BLOB_ENTRY(a, b) b 66#include "drx397xD_fw.h" 67}; 68 69static struct { 70 const char *name; 71 const struct firmware *file; 72 rwlock_t lock; 73 int refcnt; 74 const u8 *data[ARRAY_SIZE(blob_name)]; 75} fw[] = { 76#define _FW_ENTRY(a, b, c) { \ 77 .name = a, \ 78 .file = NULL, \ 79 .lock = __RW_LOCK_UNLOCKED(fw[c].lock), \ 80 .refcnt = 0, \ 81 .data = { } } 82#include "drx397xD_fw.h" 83}; 84 85/* use only with writer lock acquired */ 86static void _drx_release_fw(struct drx397xD_state *s, enum fw_ix ix) 87{ 88 memset(&fw[ix].data[0], 0, sizeof(fw[0].data)); 89 if (fw[ix].file) 90 release_firmware(fw[ix].file); 91} 92 93static void drx_release_fw(struct drx397xD_state *s) 94{ 95 enum fw_ix ix = s->chip_rev; 96 97 pr_debug("%s\n", __func__); 98 99 write_lock(&fw[ix].lock); 100 if (fw[ix].refcnt) { 101 fw[ix].refcnt--; 102 if (fw[ix].refcnt == 0) 103 _drx_release_fw(s, ix); 104 } 105 write_unlock(&fw[ix].lock); 106} 107 108static int drx_load_fw(struct drx397xD_state *s, enum fw_ix ix) 109{ 110 const u8 *data; 111 size_t size, len; 112 int i = 0, j, rc = -EINVAL; 113 114 pr_debug("%s\n", __func__); 115 116 if (ix < 0 || ix >= ARRAY_SIZE(fw)) 117 return -EINVAL; 118 s->chip_rev = ix; 119 120 write_lock(&fw[ix].lock); 121 if (fw[ix].file) { 122 rc = 0; 123 goto exit_ok; 124 } 125 memset(&fw[ix].data[0], 0, sizeof(fw[0].data)); 126 127 rc = request_firmware(&fw[ix].file, fw[ix].name, s->i2c->dev.parent); 128 if (rc != 0) { 129 printk(KERN_ERR "%s: Firmware \"%s\" not available\n", 130 mod_name, fw[ix].name); 131 goto exit_err; 132 } 133 134 if (!fw[ix].file->data || fw[ix].file->size < 10) 135 goto exit_corrupt; 136 137 data = fw[ix].file->data; 138 size = fw[ix].file->size; 139 140 if (data[i++] != 2) /* check firmware version */ 141 goto exit_corrupt; 142 143 do { 144 switch (data[i++]) { 145 case 0x00: /* bytecode */ 146 if (i >= size) 147 break; 148 i += data[i]; 149 case 0x01: /* reset */ 150 case 0x02: /* sleep */ 151 i++; 152 break; 153 case 0xfe: /* name */ 154 len = strnlen(&data[i], size - i); 155 if (i + len + 1 >= size) 156 goto exit_corrupt; 157 if (data[i + len + 1] != 0) 158 goto exit_corrupt; 159 for (j = 0; j < ARRAY_SIZE(blob_name); j++) { 160 if (strcmp(blob_name[j], &data[i]) == 0) { 161 fw[ix].data[j] = &data[i + len + 1]; 162 pr_debug("Loading %s\n", blob_name[j]); 163 } 164 } 165 i += len + 1; 166 break; 167 case 0xff: /* file terminator */ 168 if (i == size) { 169 rc = 0; 170 goto exit_ok; 171 } 172 default: 173 goto exit_corrupt; 174 } 175 } while (i < size); 176 177exit_corrupt: 178 printk(KERN_ERR "%s: Firmware is corrupt\n", mod_name); 179exit_err: 180 _drx_release_fw(s, ix); 181 fw[ix].refcnt--; 182exit_ok: 183 fw[ix].refcnt++; 184 write_unlock(&fw[ix].lock); 185 186 return rc; 187} 188 189/* i2c bus IO */ 190static int write_fw(struct drx397xD_state *s, enum blob_ix ix) 191{ 192 const u8 *data; 193 int len, rc = 0, i = 0; 194 struct i2c_msg msg = { 195 .addr = s->config.demod_address, 196 .flags = 0 197 }; 198 199 if (ix < 0 || ix >= ARRAY_SIZE(blob_name)) { 200 pr_debug("%s drx_fw_ix_t out of range\n", __func__); 201 return -EINVAL; 202 } 203 pr_debug("%s %s\n", __func__, blob_name[ix]); 204 205 read_lock(&fw[s->chip_rev].lock); 206 data = fw[s->chip_rev].data[ix]; 207 if (!data) { 208 rc = -EINVAL; 209 goto exit_rc; 210 } 211 212 for (;;) { 213 switch (data[i++]) { 214 case 0: /* bytecode */ 215 len = data[i++]; 216 msg.len = len; 217 msg.buf = (__u8 *) &data[i]; 218 if (i2c_transfer(s->i2c, &msg, 1) != 1) { 219 rc = -EIO; 220 goto exit_rc; 221 } 222 i += len; 223 break; 224 case 1: /* reset */ 225 case 2: /* sleep */ 226 i++; 227 break; 228 default: 229 goto exit_rc; 230 } 231 } 232exit_rc: 233 read_unlock(&fw[s->chip_rev].lock); 234 235 return 0; 236} 237 238/* Function is not endian safe, use the RD16 wrapper below */ 239static int _read16(struct drx397xD_state *s, __le32 i2c_adr) 240{ 241 int rc; 242 u8 a[4]; 243 __le16 v; 244 struct i2c_msg msg[2] = { 245 { 246 .addr = s->config.demod_address, 247 .flags = 0, 248 .buf = a, 249 .len = sizeof(a) 250 }, { 251 .addr = s->config.demod_address, 252 .flags = I2C_M_RD, 253 .buf = (u8 *)&v, 254 .len = sizeof(v) 255 } 256 }; 257 258 *(__le32 *) a = i2c_adr; 259 260 rc = i2c_transfer(s->i2c, msg, 2); 261 if (rc != 2) 262 return -EIO; 263 264 return le16_to_cpu(v); 265} 266 267/* Function is not endian safe, use the WR16.. wrappers below */ 268static int _write16(struct drx397xD_state *s, __le32 i2c_adr, __le16 val) 269{ 270 u8 a[6]; 271 int rc; 272 struct i2c_msg msg = { 273 .addr = s->config.demod_address, 274 .flags = 0, 275 .buf = a, 276 .len = sizeof(a) 277 }; 278 279 *(__le32 *)a = i2c_adr; 280 *(__le16 *)&a[4] = val; 281 282 rc = i2c_transfer(s->i2c, &msg, 1); 283 if (rc != 1) 284 return -EIO; 285 286 return 0; 287} 288 289#define WR16(ss, adr, val) \ 290 _write16(ss, I2C_ADR_C0(adr), cpu_to_le16(val)) 291#define WR16_E0(ss, adr, val) \ 292 _write16(ss, I2C_ADR_E0(adr), cpu_to_le16(val)) 293#define RD16(ss, adr) \ 294 _read16(ss, I2C_ADR_C0(adr)) 295 296#define EXIT_RC(cmd) \ 297 if ((rc = (cmd)) < 0) \ 298 goto exit_rc 299 300/* Tuner callback */ 301static int PLL_Set(struct drx397xD_state *s, 302 struct dvb_frontend_parameters *fep, int *df_tuner) 303{ 304 struct dvb_frontend *fe = &s->frontend; 305 u32 f_tuner, f = fep->frequency; 306 int rc; 307 308 pr_debug("%s\n", __func__); 309 310 if ((f > s->frontend.ops.tuner_ops.info.frequency_max) || 311 (f < s->frontend.ops.tuner_ops.info.frequency_min)) 312 return -EINVAL; 313 314 *df_tuner = 0; 315 if (!s->frontend.ops.tuner_ops.set_params || 316 !s->frontend.ops.tuner_ops.get_frequency) 317 return -ENOSYS; 318 319 rc = s->frontend.ops.tuner_ops.set_params(fe, fep); 320 if (rc < 0) 321 return rc; 322 323 rc = s->frontend.ops.tuner_ops.get_frequency(fe, &f_tuner); 324 if (rc < 0) 325 return rc; 326 327 *df_tuner = f_tuner - f; 328 pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __func__, f, 329 f_tuner); 330 331 return 0; 332} 333 334/* Demodulator helper functions */ 335static int SC_WaitForReady(struct drx397xD_state *s) 336{ 337 int cnt = 1000; 338 int rc; 339 340 pr_debug("%s\n", __func__); 341 342 while (cnt--) { 343 rc = RD16(s, 0x820043); 344 if (rc == 0) 345 return 0; 346 } 347 348 return -1; 349} 350 351static int SC_SendCommand(struct drx397xD_state *s, int cmd) 352{ 353 int rc; 354 355 pr_debug("%s\n", __func__); 356 357 WR16(s, 0x820043, cmd); 358 SC_WaitForReady(s); 359 rc = RD16(s, 0x820042); 360 if ((rc & 0xffff) == 0xffff) 361 return -1; 362 363 return 0; 364} 365 366static int HI_Command(struct drx397xD_state *s, u16 cmd) 367{ 368 int rc, cnt = 1000; 369 370 pr_debug("%s\n", __func__); 371 372 rc = WR16(s, 0x420032, cmd); 373 if (rc < 0) 374 return rc; 375 376 do { 377 rc = RD16(s, 0x420032); 378 if (rc == 0) { 379 rc = RD16(s, 0x420031); 380 return rc; 381 } 382 if (rc < 0) 383 return rc; 384 } while (--cnt); 385 386 return rc; 387} 388 389static int HI_CfgCommand(struct drx397xD_state *s) 390{ 391 392 pr_debug("%s\n", __func__); 393 394 WR16(s, 0x420033, 0x3973); 395 WR16(s, 0x420034, s->config.w50); /* code 4, log 4 */ 396 WR16(s, 0x420035, s->config.w52); /* code 15, log 9 */ 397 WR16(s, 0x420036, s->config.demod_address << 1); 398 WR16(s, 0x420037, s->config.w56); /* code (set_i2c ?? initX 1 ), log 1 */ 399 /* WR16(s, 0x420033, 0x3973); */ 400 if ((s->config.w56 & 8) == 0) 401 return HI_Command(s, 3); 402 403 return WR16(s, 0x420032, 0x3); 404} 405 406static const u8 fastIncrDecLUT_15273[] = { 407 0x0e, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14, 408 0x15, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x1c, 0x1d, 0x1f 409}; 410 411static const u8 slowIncrDecLUT_15272[] = { 412 3, 4, 4, 5, 6 413}; 414 415static int SetCfgIfAgc(struct drx397xD_state *s, struct drx397xD_CfgIfAgc *agc) 416{ 417 u16 w06 = agc->w06; 418 u16 w08 = agc->w08; 419 u16 w0A = agc->w0A; 420 u16 w0C = agc->w0C; 421 int quot, rem, i, rc = -EINVAL; 422 423 pr_debug("%s\n", __func__); 424 425 if (agc->w04 > 0x3ff) 426 goto exit_rc; 427 428 if (agc->d00 == 1) { 429 EXIT_RC(RD16(s, 0x0c20010)); 430 rc &= ~0x10; 431 EXIT_RC(WR16(s, 0x0c20010, rc)); 432 return WR16(s, 0x0c20030, agc->w04 & 0x7ff); 433 } 434 435 if (agc->d00 != 0) 436 goto exit_rc; 437 if (w0A < w08) 438 goto exit_rc; 439 if (w0A > 0x3ff) 440 goto exit_rc; 441 if (w0C > 0x3ff) 442 goto exit_rc; 443 if (w06 > 0x3ff) 444 goto exit_rc; 445 446 EXIT_RC(RD16(s, 0x0c20010)); 447 rc |= 0x10; 448 EXIT_RC(WR16(s, 0x0c20010, rc)); 449 450 EXIT_RC(WR16(s, 0x0c20025, (w06 >> 1) & 0x1ff)); 451 EXIT_RC(WR16(s, 0x0c20031, (w0A - w08) >> 1)); 452 EXIT_RC(WR16(s, 0x0c20032, ((w0A + w08) >> 1) - 0x1ff)); 453 454 quot = w0C / 113; 455 rem = w0C % 113; 456 if (quot <= 8) { 457 quot = 8 - quot; 458 } else { 459 quot = 0; 460 rem += 113; 461 } 462 463 EXIT_RC(WR16(s, 0x0c20024, quot)); 464 465 i = fastIncrDecLUT_15273[rem / 8]; 466 EXIT_RC(WR16(s, 0x0c2002d, i)); 467 EXIT_RC(WR16(s, 0x0c2002e, i)); 468 469 i = slowIncrDecLUT_15272[rem / 28]; 470 EXIT_RC(WR16(s, 0x0c2002b, i)); 471 rc = WR16(s, 0x0c2002c, i); 472exit_rc: 473 return rc; 474} 475 476static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc) 477{ 478 u16 w04 = agc->w04; 479 u16 w06 = agc->w06; 480 int rc = -1; 481 482 pr_debug("%s %d 0x%x 0x%x\n", __func__, agc->d00, w04, w06); 483 484 if (w04 > 0x3ff) 485 goto exit_rc; 486 487 switch (agc->d00) { 488 case 1: 489 if (w04 == 0x3ff) 490 w04 = 0x400; 491 492 EXIT_RC(WR16(s, 0x0c20036, w04)); 493 s->config.w9C &= ~2; 494 EXIT_RC(WR16(s, 0x0c20015, s->config.w9C)); 495 EXIT_RC(RD16(s, 0x0c20010)); 496 rc &= 0xbfdf; 497 EXIT_RC(WR16(s, 0x0c20010, rc)); 498 EXIT_RC(RD16(s, 0x0c20013)); 499 rc &= ~2; 500 break; 501 case 0: 502 /* loc_8000659 */ 503 s->config.w9C &= ~2; 504 EXIT_RC(WR16(s, 0x0c20015, s->config.w9C)); 505 EXIT_RC(RD16(s, 0x0c20010)); 506 rc &= 0xbfdf; 507 rc |= 0x4000; 508 EXIT_RC(WR16(s, 0x0c20010, rc)); 509 EXIT_RC(WR16(s, 0x0c20051, (w06 >> 4) & 0x3f)); 510 EXIT_RC(RD16(s, 0x0c20013)); 511 rc &= ~2; 512 break; 513 default: 514 s->config.w9C |= 2; 515 EXIT_RC(WR16(s, 0x0c20015, s->config.w9C)); 516 EXIT_RC(RD16(s, 0x0c20010)); 517 rc &= 0xbfdf; 518 EXIT_RC(WR16(s, 0x0c20010, rc)); 519 520 EXIT_RC(WR16(s, 0x0c20036, 0)); 521 522 EXIT_RC(RD16(s, 0x0c20013)); 523 rc |= 2; 524 } 525 rc = WR16(s, 0x0c20013, rc); 526 527exit_rc: 528 return rc; 529} 530 531static int GetLockStatus(struct drx397xD_state *s, int *lockstat) 532{ 533 int rc; 534 535 *lockstat = 0; 536 537 rc = RD16(s, 0x082004b); 538 if (rc < 0) 539 return rc; 540 541 if (s->config.d60 != 2) 542 return 0; 543 544 if ((rc & 7) == 7) 545 *lockstat |= 1; 546 if ((rc & 3) == 3) 547 *lockstat |= 2; 548 if (rc & 1) 549 *lockstat |= 4; 550 return 0; 551} 552 553static int CorrectSysClockDeviation(struct drx397xD_state *s) 554{ 555 int rc = -EINVAL; 556 int lockstat; 557 u32 clk, clk_limit; 558 559 pr_debug("%s\n", __func__); 560 561 if (s->config.d5C == 0) { 562 EXIT_RC(WR16(s, 0x08200e8, 0x010)); 563 EXIT_RC(WR16(s, 0x08200e9, 0x113)); 564 s->config.d5C = 1; 565 return rc; 566 } 567 if (s->config.d5C != 1) 568 goto exit_rc; 569 570 rc = RD16(s, 0x0820048); 571 572 rc = GetLockStatus(s, &lockstat); 573 if (rc < 0) 574 goto exit_rc; 575 if ((lockstat & 1) == 0) 576 goto exit_rc; 577 578 EXIT_RC(WR16(s, 0x0420033, 0x200)); 579 EXIT_RC(WR16(s, 0x0420034, 0xc5)); 580 EXIT_RC(WR16(s, 0x0420035, 0x10)); 581 EXIT_RC(WR16(s, 0x0420036, 0x1)); 582 EXIT_RC(WR16(s, 0x0420037, 0xa)); 583 EXIT_RC(HI_Command(s, 6)); 584 EXIT_RC(RD16(s, 0x0420040)); 585 clk = rc; 586 EXIT_RC(RD16(s, 0x0420041)); 587 clk |= rc << 16; 588 589 if (clk <= 0x26ffff) 590 goto exit_rc; 591 if (clk > 0x610000) 592 goto exit_rc; 593 594 if (!s->bandwidth_parm) 595 return -EINVAL; 596 597 /* round & convert to Hz */ 598 clk = ((u64) (clk + 0x800000) * s->bandwidth_parm + (1 << 20)) >> 21; 599 clk_limit = s->config.f_osc * MAX_CLOCK_DRIFT / 1000; 600 601 if (clk - s->config.f_osc * 1000 + clk_limit <= 2 * clk_limit) { 602 s->f_osc = clk; 603 pr_debug("%s: osc %d %d [Hz]\n", __func__, 604 s->config.f_osc * 1000, clk - s->config.f_osc * 1000); 605 } 606 rc = WR16(s, 0x08200e8, 0); 607 608exit_rc: 609 return rc; 610} 611 612static int ConfigureMPEGOutput(struct drx397xD_state *s, int type) 613{ 614 int rc, si, bp; 615 616 pr_debug("%s\n", __func__); 617 618 si = s->config.wA0; 619 if (s->config.w98 == 0) { 620 si |= 1; 621 bp = 0; 622 } else { 623 si &= ~1; 624 bp = 0x200; 625 } 626 if (s->config.w9A == 0) 627 si |= 0x80; 628 else 629 si &= ~0x80; 630 631 EXIT_RC(WR16(s, 0x2150045, 0)); 632 EXIT_RC(WR16(s, 0x2150010, si)); 633 EXIT_RC(WR16(s, 0x2150011, bp)); 634 rc = WR16(s, 0x2150012, (type == 0 ? 0xfff : 0)); 635 636exit_rc: 637 return rc; 638} 639 640static int drx_tune(struct drx397xD_state *s, 641 struct dvb_frontend_parameters *fep) 642{ 643 u16 v22 = 0; 644 u16 v1C = 0; 645 u16 v1A = 0; 646 u16 v18 = 0; 647 u32 edi = 0, ebx = 0, ebp = 0, edx = 0; 648 u16 v20 = 0, v1E = 0, v16 = 0, v14 = 0, v12 = 0, v10 = 0, v0E = 0; 649 650 int rc, df_tuner = 0; 651 int a, b, c, d; 652 pr_debug("%s %d\n", __func__, s->config.d60); 653 654 if (s->config.d60 != 2) 655 goto set_tuner; 656 rc = CorrectSysClockDeviation(s); 657 if (rc < 0) 658 goto set_tuner; 659 660 s->config.d60 = 1; 661 rc = ConfigureMPEGOutput(s, 0); 662 if (rc < 0) 663 goto set_tuner; 664set_tuner: 665 666 rc = PLL_Set(s, fep, &df_tuner); 667 if (rc < 0) { 668 printk(KERN_ERR "Error in pll_set\n"); 669 goto exit_rc; 670 } 671 msleep(200); 672 673 a = rc = RD16(s, 0x2150016); 674 if (rc < 0) 675 goto exit_rc; 676 b = rc = RD16(s, 0x2150010); 677 if (rc < 0) 678 goto exit_rc; 679 c = rc = RD16(s, 0x2150034); 680 if (rc < 0) 681 goto exit_rc; 682 d = rc = RD16(s, 0x2150035); 683 if (rc < 0) 684 goto exit_rc; 685 rc = WR16(s, 0x2150014, c); 686 rc = WR16(s, 0x2150015, d); 687 rc = WR16(s, 0x2150010, 0); 688 rc = WR16(s, 0x2150000, 2); 689 rc = WR16(s, 0x2150036, 0x0fff); 690 rc = WR16(s, 0x2150016, a); 691 692 rc = WR16(s, 0x2150010, 2); 693 rc = WR16(s, 0x2150007, 0); 694 rc = WR16(s, 0x2150000, 1); 695 rc = WR16(s, 0x2110000, 0); 696 rc = WR16(s, 0x0800000, 0); 697 rc = WR16(s, 0x2800000, 0); 698 rc = WR16(s, 0x2110010, 0x664); 699 700 rc = write_fw(s, DRXD_ResetECRAM); 701 rc = WR16(s, 0x2110000, 1); 702 703 rc = write_fw(s, DRXD_InitSC); 704 if (rc < 0) 705 goto exit_rc; 706 707 rc = SetCfgIfAgc(s, &s->config.ifagc); 708 if (rc < 0) 709 goto exit_rc; 710 711 rc = SetCfgRfAgc(s, &s->config.rfagc); 712 if (rc < 0) 713 goto exit_rc; 714 715 if (fep->u.ofdm.transmission_mode != TRANSMISSION_MODE_2K) 716 v22 = 1; 717 switch (fep->u.ofdm.transmission_mode) { 718 case TRANSMISSION_MODE_8K: 719 edi = 1; 720 if (s->chip_rev == DRXD_FW_B1) 721 break; 722 723 rc = WR16(s, 0x2010010, 0); 724 if (rc < 0) 725 break; 726 v1C = 0x63; 727 v1A = 0x53; 728 v18 = 0x43; 729 break; 730 default: 731 edi = 0; 732 if (s->chip_rev == DRXD_FW_B1) 733 break; 734 735 rc = WR16(s, 0x2010010, 1); 736 if (rc < 0) 737 break; 738 739 v1C = 0x61; 740 v1A = 0x47; 741 v18 = 0x41; 742 } 743 744 switch (fep->u.ofdm.guard_interval) { 745 case GUARD_INTERVAL_1_4: 746 edi |= 0x0c; 747 break; 748 case GUARD_INTERVAL_1_8: 749 edi |= 0x08; 750 break; 751 case GUARD_INTERVAL_1_16: 752 edi |= 0x04; 753 break; 754 case GUARD_INTERVAL_1_32: 755 break; 756 default: 757 v22 |= 2; 758 } 759 760 ebx = 0; 761 ebp = 0; 762 v20 = 0; 763 v1E = 0; 764 v16 = 0; 765 v14 = 0; 766 v12 = 0; 767 v10 = 0; 768 v0E = 0; 769 770 switch (fep->u.ofdm.hierarchy_information) { 771 case HIERARCHY_1: 772 edi |= 0x40; 773 if (s->chip_rev == DRXD_FW_B1) 774 break; 775 rc = WR16(s, 0x1c10047, 1); 776 if (rc < 0) 777 goto exit_rc; 778 rc = WR16(s, 0x2010012, 1); 779 if (rc < 0) 780 goto exit_rc; 781 ebx = 0x19f; 782 ebp = 0x1fb; 783 v20 = 0x0c0; 784 v1E = 0x195; 785 v16 = 0x1d6; 786 v14 = 0x1ef; 787 v12 = 4; 788 v10 = 5; 789 v0E = 5; 790 break; 791 case HIERARCHY_2: 792 edi |= 0x80; 793 if (s->chip_rev == DRXD_FW_B1) 794 break; 795 rc = WR16(s, 0x1c10047, 2); 796 if (rc < 0) 797 goto exit_rc; 798 rc = WR16(s, 0x2010012, 2); 799 if (rc < 0) 800 goto exit_rc; 801 ebx = 0x08f; 802 ebp = 0x12f; 803 v20 = 0x0c0; 804 v1E = 0x11e; 805 v16 = 0x1d6; 806 v14 = 0x15e; 807 v12 = 4; 808 v10 = 5; 809 v0E = 5; 810 break; 811 case HIERARCHY_4: 812 edi |= 0xc0; 813 if (s->chip_rev == DRXD_FW_B1) 814 break; 815 rc = WR16(s, 0x1c10047, 3); 816 if (rc < 0) 817 goto exit_rc; 818 rc = WR16(s, 0x2010012, 3); 819 if (rc < 0) 820 goto exit_rc; 821 ebx = 0x14d; 822 ebp = 0x197; 823 v20 = 0x0c0; 824 v1E = 0x1ce; 825 v16 = 0x1d6; 826 v14 = 0x11a; 827 v12 = 4; 828 v10 = 6; 829 v0E = 5; 830 break; 831 default: 832 v22 |= 8; 833 if (s->chip_rev == DRXD_FW_B1) 834 break; 835 rc = WR16(s, 0x1c10047, 0); 836 if (rc < 0) 837 goto exit_rc; 838 rc = WR16(s, 0x2010012, 0); 839 if (rc < 0) 840 goto exit_rc; 841 /* QPSK QAM16 QAM64 */ 842 ebx = 0x19f; /* 62 */ 843 ebp = 0x1fb; /* 15 */ 844 v20 = 0x16a; /* 62 */ 845 v1E = 0x195; /* 62 */ 846 v16 = 0x1bb; /* 15 */ 847 v14 = 0x1ef; /* 15 */ 848 v12 = 5; /* 16 */ 849 v10 = 5; /* 16 */ 850 v0E = 5; /* 16 */ 851 } 852 853 switch (fep->u.ofdm.constellation) { 854 default: 855 v22 |= 4; 856 case QPSK: 857 if (s->chip_rev == DRXD_FW_B1) 858 break; 859 860 rc = WR16(s, 0x1c10046, 0); 861 if (rc < 0) 862 goto exit_rc; 863 rc = WR16(s, 0x2010011, 0); 864 if (rc < 0) 865 goto exit_rc; 866 rc = WR16(s, 0x201001a, 0x10); 867 if (rc < 0) 868 goto exit_rc; 869 rc = WR16(s, 0x201001b, 0); 870 if (rc < 0) 871 goto exit_rc; 872 rc = WR16(s, 0x201001c, 0); 873 if (rc < 0) 874 goto exit_rc; 875 rc = WR16(s, 0x1c10062, v20); 876 if (rc < 0) 877 goto exit_rc; 878 rc = WR16(s, 0x1c1002a, v1C); 879 if (rc < 0) 880 goto exit_rc; 881 rc = WR16(s, 0x1c10015, v16); 882 if (rc < 0) 883 goto exit_rc; 884 rc = WR16(s, 0x1c10016, v12); 885 if (rc < 0) 886 goto exit_rc; 887 break; 888 case QAM_16: 889 edi |= 0x10; 890 if (s->chip_rev == DRXD_FW_B1) 891 break; 892 893 rc = WR16(s, 0x1c10046, 1); 894 if (rc < 0) 895 goto exit_rc; 896 rc = WR16(s, 0x2010011, 1); 897 if (rc < 0) 898 goto exit_rc; 899 rc = WR16(s, 0x201001a, 0x10); 900 if (rc < 0) 901 goto exit_rc; 902 rc = WR16(s, 0x201001b, 4); 903 if (rc < 0) 904 goto exit_rc; 905 rc = WR16(s, 0x201001c, 0); 906 if (rc < 0) 907 goto exit_rc; 908 rc = WR16(s, 0x1c10062, v1E); 909 if (rc < 0) 910 goto exit_rc; 911 rc = WR16(s, 0x1c1002a, v1A); 912 if (rc < 0) 913 goto exit_rc; 914 rc = WR16(s, 0x1c10015, v14); 915 if (rc < 0) 916 goto exit_rc; 917 rc = WR16(s, 0x1c10016, v10); 918 if (rc < 0) 919 goto exit_rc; 920 break; 921 case QAM_64: 922 edi |= 0x20; 923 rc = WR16(s, 0x1c10046, 2); 924 if (rc < 0) 925 goto exit_rc; 926 rc = WR16(s, 0x2010011, 2); 927 if (rc < 0) 928 goto exit_rc; 929 rc = WR16(s, 0x201001a, 0x20); 930 if (rc < 0) 931 goto exit_rc; 932 rc = WR16(s, 0x201001b, 8); 933 if (rc < 0) 934 goto exit_rc; 935 rc = WR16(s, 0x201001c, 2); 936 if (rc < 0) 937 goto exit_rc; 938 rc = WR16(s, 0x1c10062, ebx); 939 if (rc < 0) 940 goto exit_rc; 941 rc = WR16(s, 0x1c1002a, v18); 942 if (rc < 0) 943 goto exit_rc; 944 rc = WR16(s, 0x1c10015, ebp); 945 if (rc < 0) 946 goto exit_rc; 947 rc = WR16(s, 0x1c10016, v0E); 948 if (rc < 0) 949 goto exit_rc; 950 break; 951 } 952 953 if (s->config.s20d24 == 1) { 954 rc = WR16(s, 0x2010013, 0); 955 } else { 956 rc = WR16(s, 0x2010013, 1); 957 edi |= 0x1000; 958 } 959 960 switch (fep->u.ofdm.code_rate_HP) { 961 default: 962 v22 |= 0x10; 963 case FEC_1_2: 964 if (s->chip_rev == DRXD_FW_B1) 965 break; 966 rc = WR16(s, 0x2090011, 0); 967 break; 968 case FEC_2_3: 969 edi |= 0x200; 970 if (s->chip_rev == DRXD_FW_B1) 971 break; 972 rc = WR16(s, 0x2090011, 1); 973 break; 974 case FEC_3_4: 975 edi |= 0x400; 976 if (s->chip_rev == DRXD_FW_B1) 977 break; 978 rc = WR16(s, 0x2090011, 2); 979 break; 980 case FEC_5_6: /* 5 */ 981 edi |= 0x600; 982 if (s->chip_rev == DRXD_FW_B1) 983 break; 984 rc = WR16(s, 0x2090011, 3); 985 break; 986 case FEC_7_8: /* 7 */ 987 edi |= 0x800; 988 if (s->chip_rev == DRXD_FW_B1) 989 break; 990 rc = WR16(s, 0x2090011, 4); 991 break; 992 }; 993 if (rc < 0) 994 goto exit_rc; 995 996 switch (fep->u.ofdm.bandwidth) { 997 default: 998 rc = -EINVAL; 999 goto exit_rc; 1000 case BANDWIDTH_8_MHZ: /* 0 */ 1001 case BANDWIDTH_AUTO: 1002 rc = WR16(s, 0x0c2003f, 0x32); 1003 s->bandwidth_parm = ebx = 0x8b8249; 1004 edx = 0; 1005 break; 1006 case BANDWIDTH_7_MHZ: 1007 rc = WR16(s, 0x0c2003f, 0x3b); 1008 s->bandwidth_parm = ebx = 0x7a1200; 1009 edx = 0x4807; 1010 break; 1011 case BANDWIDTH_6_MHZ: 1012 rc = WR16(s, 0x0c2003f, 0x47); 1013 s->bandwidth_parm = ebx = 0x68a1b6; 1014 edx = 0x0f07; 1015 break; 1016 }; 1017 1018 if (rc < 0) 1019 goto exit_rc; 1020 1021 rc = WR16(s, 0x08200ec, edx); 1022 if (rc < 0) 1023 goto exit_rc; 1024 1025 rc = RD16(s, 0x0820050); 1026 if (rc < 0) 1027 goto exit_rc; 1028 rc = WR16(s, 0x0820050, rc); 1029 1030 { 1031 /* Configure bandwidth specific factor */ 1032 ebx = div64_u64(((u64) (s->f_osc) << 21) + (ebx >> 1), 1033 (u64)ebx) - 0x800000; 1034 EXIT_RC(WR16(s, 0x0c50010, ebx & 0xffff)); 1035 EXIT_RC(WR16(s, 0x0c50011, ebx >> 16)); 1036 1037 /* drx397xD oscillator calibration */ 1038 ebx = div64_u64(((u64) (s->config.f_if + df_tuner) << 28) + 1039 (s->f_osc >> 1), (u64)s->f_osc); 1040 } 1041 ebx &= 0xfffffff; 1042 if (fep->inversion == INVERSION_ON) 1043 ebx = 0x10000000 - ebx; 1044 1045 EXIT_RC(WR16(s, 0x0c30010, ebx & 0xffff)); 1046 EXIT_RC(WR16(s, 0x0c30011, ebx >> 16)); 1047 1048 EXIT_RC(WR16(s, 0x0800000, 1)); 1049 EXIT_RC(RD16(s, 0x0800000)); 1050 1051 1052 EXIT_RC(SC_WaitForReady(s)); 1053 EXIT_RC(WR16(s, 0x0820042, 0)); 1054 EXIT_RC(WR16(s, 0x0820041, v22)); 1055 EXIT_RC(WR16(s, 0x0820040, edi)); 1056 EXIT_RC(SC_SendCommand(s, 3)); 1057 1058 rc = RD16(s, 0x0800000); 1059 1060 SC_WaitForReady(s); 1061 WR16(s, 0x0820042, 0); 1062 WR16(s, 0x0820041, 1); 1063 WR16(s, 0x0820040, 1); 1064 SC_SendCommand(s, 1); 1065 1066 1067 rc = WR16(s, 0x2150000, 2); 1068 rc = WR16(s, 0x2150016, a); 1069 rc = WR16(s, 0x2150010, 4); 1070 rc = WR16(s, 0x2150036, 0); 1071 rc = WR16(s, 0x2150000, 1); 1072 s->config.d60 = 2; 1073 1074exit_rc: 1075 return rc; 1076} 1077 1078/******************************************************************************* 1079 * DVB interface 1080 ******************************************************************************/ 1081 1082static int drx397x_init(struct dvb_frontend *fe) 1083{ 1084 struct drx397xD_state *s = fe->demodulator_priv; 1085 int rc; 1086 1087 pr_debug("%s\n", __func__); 1088 1089 s->config.rfagc.d00 = 2; /* 0x7c */ 1090 s->config.rfagc.w04 = 0; 1091 s->config.rfagc.w06 = 0x3ff; 1092 1093 s->config.ifagc.d00 = 0; /* 0x68 */ 1094 s->config.ifagc.w04 = 0; 1095 s->config.ifagc.w06 = 140; 1096 s->config.ifagc.w08 = 0; 1097 s->config.ifagc.w0A = 0x3ff; 1098 s->config.ifagc.w0C = 0x388; 1099 1100 /* for signal strenght calculations */ 1101 s->config.ss76 = 820; 1102 s->config.ss78 = 2200; 1103 s->config.ss7A = 150; 1104 1105 /* HI_CfgCommand */ 1106 s->config.w50 = 4; 1107 s->config.w52 = 9; 1108 1109 s->config.f_if = 42800000; /* d14: intermediate frequency [Hz] */ 1110 s->config.f_osc = 48000; /* s66 : oscillator frequency [kHz] */ 1111 s->config.w92 = 12000; 1112 1113 s->config.w9C = 0x000e; 1114 s->config.w9E = 0x0000; 1115 1116 /* ConfigureMPEGOutput params */ 1117 s->config.wA0 = 4; 1118 s->config.w98 = 1; 1119 s->config.w9A = 1; 1120 1121 /* get chip revision */ 1122 rc = RD16(s, 0x2410019); 1123 if (rc < 0) 1124 return -ENODEV; 1125 1126 if (rc == 0) { 1127 printk(KERN_INFO "%s: chip revision A2\n", mod_name); 1128 rc = drx_load_fw(s, DRXD_FW_A2); 1129 } else { 1130 1131 rc = (rc >> 12) - 3; 1132 switch (rc) { 1133 case 1: 1134 s->flags |= F_SET_0D4h; 1135 case 0: 1136 case 4: 1137 s->flags |= F_SET_0D0h; 1138 break; 1139 case 2: 1140 case 5: 1141 break; 1142 case 3: 1143 s->flags |= F_SET_0D4h; 1144 break; 1145 default: 1146 return -ENODEV; 1147 }; 1148 printk(KERN_INFO "%s: chip revision B1.%d\n", mod_name, rc); 1149 rc = drx_load_fw(s, DRXD_FW_B1); 1150 } 1151 if (rc < 0) 1152 goto error; 1153 1154 rc = WR16(s, 0x0420033, 0x3973); 1155 if (rc < 0) 1156 goto error; 1157 1158 rc = HI_Command(s, 2); 1159 1160 msleep(1); 1161 1162 if (s->chip_rev == DRXD_FW_A2) { 1163 rc = WR16(s, 0x043012d, 0x47F); 1164 if (rc < 0) 1165 goto error; 1166 } 1167 rc = WR16_E0(s, 0x0400000, 0); 1168 if (rc < 0) 1169 goto error; 1170 1171 if (s->config.w92 > 20000 || s->config.w92 % 4000) { 1172 printk(KERN_ERR "%s: invalid osc frequency\n", mod_name); 1173 rc = -1; 1174 goto error; 1175 } 1176 1177 rc = WR16(s, 0x2410010, 1); 1178 if (rc < 0) 1179 goto error; 1180 rc = WR16(s, 0x2410011, 0x15); 1181 if (rc < 0) 1182 goto error; 1183 rc = WR16(s, 0x2410012, s->config.w92 / 4000); 1184 if (rc < 0) 1185 goto error; 1186#ifdef ORIG_FW 1187 rc = WR16(s, 0x2410015, 2); 1188 if (rc < 0) 1189 goto error; 1190#endif 1191 rc = WR16(s, 0x2410017, 0x3973); 1192 if (rc < 0) 1193 goto error; 1194 1195 s->f_osc = s->config.f_osc * 1000; /* initial estimator */ 1196 1197 s->config.w56 = 1; 1198 1199 rc = HI_CfgCommand(s); 1200 if (rc < 0) 1201 goto error; 1202 1203 rc = write_fw(s, DRXD_InitAtomicRead); 1204 if (rc < 0) 1205 goto error; 1206 1207 if (s->chip_rev == DRXD_FW_A2) { 1208 rc = WR16(s, 0x2150013, 0); 1209 if (rc < 0) 1210 goto error; 1211 } 1212 1213 rc = WR16_E0(s, 0x0400002, 0); 1214 if (rc < 0) 1215 goto error; 1216 rc = WR16(s, 0x0400002, 0); 1217 if (rc < 0) 1218 goto error; 1219 1220 if (s->chip_rev == DRXD_FW_A2) { 1221 rc = write_fw(s, DRXD_ResetCEFR); 1222 if (rc < 0) 1223 goto error; 1224 } 1225 rc = write_fw(s, DRXD_microcode); 1226 if (rc < 0) 1227 goto error; 1228 1229 s->config.w9C = 0x0e; 1230 if (s->flags & F_SET_0D0h) { 1231 s->config.w9C = 0; 1232 rc = RD16(s, 0x0c20010); 1233 if (rc < 0) 1234 goto write_DRXD_InitFE_1; 1235 1236 rc &= ~0x1000; 1237 rc = WR16(s, 0x0c20010, rc); 1238 if (rc < 0) 1239 goto write_DRXD_InitFE_1; 1240 1241 rc = RD16(s, 0x0c20011); 1242 if (rc < 0) 1243 goto write_DRXD_InitFE_1; 1244 1245 rc &= ~0x8; 1246 rc = WR16(s, 0x0c20011, rc); 1247 if (rc < 0) 1248 goto write_DRXD_InitFE_1; 1249 1250 rc = WR16(s, 0x0c20012, 1); 1251 } 1252 1253write_DRXD_InitFE_1: 1254 1255 rc = write_fw(s, DRXD_InitFE_1); 1256 if (rc < 0) 1257 goto error; 1258 1259 rc = 1; 1260 if (s->chip_rev == DRXD_FW_B1) { 1261 if (s->flags & F_SET_0D0h) 1262 rc = 0; 1263 } else { 1264 if (s->flags & F_SET_0D0h) 1265 rc = 4; 1266 } 1267 1268 rc = WR16(s, 0x0C20012, rc); 1269 if (rc < 0) 1270 goto error; 1271 1272 rc = WR16(s, 0x0C20013, s->config.w9E); 1273 if (rc < 0) 1274 goto error; 1275 rc = WR16(s, 0x0C20015, s->config.w9C); 1276 if (rc < 0) 1277 goto error; 1278 1279 rc = write_fw(s, DRXD_InitFE_2); 1280 if (rc < 0) 1281 goto error; 1282 rc = write_fw(s, DRXD_InitFT); 1283 if (rc < 0) 1284 goto error; 1285 rc = write_fw(s, DRXD_InitCP); 1286 if (rc < 0) 1287 goto error; 1288 rc = write_fw(s, DRXD_InitCE); 1289 if (rc < 0) 1290 goto error; 1291 rc = write_fw(s, DRXD_InitEQ); 1292 if (rc < 0) 1293 goto error; 1294 rc = write_fw(s, DRXD_InitEC); 1295 if (rc < 0) 1296 goto error; 1297 rc = write_fw(s, DRXD_InitSC); 1298 if (rc < 0) 1299 goto error; 1300 1301 rc = SetCfgIfAgc(s, &s->config.ifagc); 1302 if (rc < 0) 1303 goto error; 1304 1305 rc = SetCfgRfAgc(s, &s->config.rfagc); 1306 if (rc < 0) 1307 goto error; 1308 1309 rc = ConfigureMPEGOutput(s, 1); 1310 rc = WR16(s, 0x08201fe, 0x0017); 1311 rc = WR16(s, 0x08201ff, 0x0101); 1312 1313 s->config.d5C = 0; 1314 s->config.d60 = 1; 1315 s->config.d48 = 1; 1316 1317error: 1318 return rc; 1319} 1320 1321static int drx397x_get_frontend(struct dvb_frontend *fe, 1322 struct dvb_frontend_parameters *params) 1323{ 1324 return 0; 1325} 1326 1327static int drx397x_set_frontend(struct dvb_frontend *fe, 1328 struct dvb_frontend_parameters *params) 1329{ 1330 struct drx397xD_state *s = fe->demodulator_priv; 1331 1332 s->config.s20d24 = 1; 1333 1334 return drx_tune(s, params); 1335} 1336 1337static int drx397x_get_tune_settings(struct dvb_frontend *fe, 1338 struct dvb_frontend_tune_settings 1339 *fe_tune_settings) 1340{ 1341 fe_tune_settings->min_delay_ms = 10000; 1342 fe_tune_settings->step_size = 0; 1343 fe_tune_settings->max_drift = 0; 1344 1345 return 0; 1346} 1347 1348static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t *status) 1349{ 1350 struct drx397xD_state *s = fe->demodulator_priv; 1351 int lockstat; 1352 1353 GetLockStatus(s, &lockstat); 1354 1355 *status = 0; 1356 if (lockstat & 2) { 1357 CorrectSysClockDeviation(s); 1358 ConfigureMPEGOutput(s, 1); 1359 *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI; 1360 } 1361 if (lockstat & 4) 1362 *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; 1363 1364 return 0; 1365} 1366 1367static int drx397x_read_ber(struct dvb_frontend *fe, unsigned int *ber) 1368{ 1369 *ber = 0; 1370 1371 return 0; 1372} 1373 1374static int drx397x_read_snr(struct dvb_frontend *fe, u16 *snr) 1375{ 1376 *snr = 0; 1377 1378 return 0; 1379} 1380 1381static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 *strength) 1382{ 1383 struct drx397xD_state *s = fe->demodulator_priv; 1384 int rc; 1385 1386 if (s->config.ifagc.d00 == 2) { 1387 *strength = 0xffff; 1388 return 0; 1389 } 1390 rc = RD16(s, 0x0c20035); 1391 if (rc < 0) { 1392 *strength = 0; 1393 return 0; 1394 } 1395 rc &= 0x3ff; 1396 /* Signal strength is calculated using the following formula: 1397 * 1398 * a = 2200 * 150 / (2200 + 150); 1399 * a = a * 3300 / (a + 820); 1400 * b = 2200 * 3300 / (2200 + 820); 1401 * c = (((b-a) * rc) >> 10 + a) << 4; 1402 * strength = ~c & 0xffff; 1403 * 1404 * The following does the same but with less rounding errors: 1405 */ 1406 *strength = ~(7720 + (rc * 30744 >> 10)); 1407 1408 return 0; 1409} 1410 1411static int drx397x_read_ucblocks(struct dvb_frontend *fe, 1412 unsigned int *ucblocks) 1413{ 1414 *ucblocks = 0; 1415 1416 return 0; 1417} 1418 1419static int drx397x_sleep(struct dvb_frontend *fe) 1420{ 1421 return 0; 1422} 1423 1424static void drx397x_release(struct dvb_frontend *fe) 1425{ 1426 struct drx397xD_state *s = fe->demodulator_priv; 1427 printk(KERN_INFO "%s: release demodulator\n", mod_name); 1428 if (s) { 1429 drx_release_fw(s); 1430 kfree(s); 1431 } 1432 1433} 1434 1435static struct dvb_frontend_ops drx397x_ops = { 1436 1437 .info = { 1438 .name = "Micronas DRX397xD DVB-T Frontend", 1439 .type = FE_OFDM, 1440 .frequency_min = 47125000, 1441 .frequency_max = 855250000, 1442 .frequency_stepsize = 166667, 1443 .frequency_tolerance = 0, 1444 .caps = /* 0x0C01B2EAE */ 1445 FE_CAN_FEC_1_2 | /* = 0x2, */ 1446 FE_CAN_FEC_2_3 | /* = 0x4, */ 1447 FE_CAN_FEC_3_4 | /* = 0x8, */ 1448 FE_CAN_FEC_5_6 | /* = 0x20, */ 1449 FE_CAN_FEC_7_8 | /* = 0x80, */ 1450 FE_CAN_FEC_AUTO | /* = 0x200, */ 1451 FE_CAN_QPSK | /* = 0x400, */ 1452 FE_CAN_QAM_16 | /* = 0x800, */ 1453 FE_CAN_QAM_64 | /* = 0x2000, */ 1454 FE_CAN_QAM_AUTO | /* = 0x10000, */ 1455 FE_CAN_TRANSMISSION_MODE_AUTO | /* = 0x20000, */ 1456 FE_CAN_GUARD_INTERVAL_AUTO | /* = 0x80000, */ 1457 FE_CAN_HIERARCHY_AUTO | /* = 0x100000, */ 1458 FE_CAN_RECOVER | /* = 0x40000000, */ 1459 FE_CAN_MUTE_TS /* = 0x80000000 */ 1460 }, 1461 1462 .release = drx397x_release, 1463 .init = drx397x_init, 1464 .sleep = drx397x_sleep, 1465 1466 .set_frontend = drx397x_set_frontend, 1467 .get_tune_settings = drx397x_get_tune_settings, 1468 .get_frontend = drx397x_get_frontend, 1469 1470 .read_status = drx397x_read_status, 1471 .read_snr = drx397x_read_snr, 1472 .read_signal_strength = drx397x_read_signal_strength, 1473 .read_ber = drx397x_read_ber, 1474 .read_ucblocks = drx397x_read_ucblocks, 1475}; 1476 1477struct dvb_frontend *drx397xD_attach(const struct drx397xD_config *config, 1478 struct i2c_adapter *i2c) 1479{ 1480 struct drx397xD_state *state; 1481 1482 /* allocate memory for the internal state */ 1483 state = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL); 1484 if (!state) 1485 goto error; 1486 1487 /* setup the state */ 1488 state->i2c = i2c; 1489 memcpy(&state->config, config, sizeof(struct drx397xD_config)); 1490 1491 /* check if the demod is there */ 1492 if (RD16(state, 0x2410019) < 0) 1493 goto error; 1494 1495 /* create dvb_frontend */ 1496 memcpy(&state->frontend.ops, &drx397x_ops, 1497 sizeof(struct dvb_frontend_ops)); 1498 state->frontend.demodulator_priv = state; 1499 1500 return &state->frontend; 1501error: 1502 kfree(state); 1503 1504 return NULL; 1505} 1506EXPORT_SYMBOL(drx397xD_attach); 1507 1508MODULE_DESCRIPTION("Micronas DRX397xD DVB-T Frontend"); 1509MODULE_AUTHOR("Henk Vergonet"); 1510MODULE_LICENSE("GPL"); 1511