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