linux/drivers/media/dvb-frontends/dib0070.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
   4 *
   5 * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/)
   6 *
   7 * This code is more or less generated from another driver, please
   8 * excuse some codingstyle oddities.
   9 */
  10
  11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  12
  13#include <linux/kernel.h>
  14#include <linux/slab.h>
  15#include <linux/i2c.h>
  16#include <linux/mutex.h>
  17
  18#include <media/dvb_frontend.h>
  19
  20#include "dib0070.h"
  21#include "dibx000_common.h"
  22
  23static int debug;
  24module_param(debug, int, 0644);
  25MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
  26
  27#define dprintk(fmt, arg...) do {                                       \
  28        if (debug)                                                      \
  29                printk(KERN_DEBUG pr_fmt("%s: " fmt),                   \
  30                       __func__, ##arg);                                \
  31} while (0)
  32
  33#define DIB0070_P1D  0x00
  34#define DIB0070_P1F  0x01
  35#define DIB0070_P1G  0x03
  36#define DIB0070S_P1A 0x02
  37
  38struct dib0070_state {
  39        struct i2c_adapter *i2c;
  40        struct dvb_frontend *fe;
  41        const struct dib0070_config *cfg;
  42        u16 wbd_ff_offset;
  43        u8 revision;
  44
  45        enum frontend_tune_state tune_state;
  46        u32 current_rf;
  47
  48        /* for the captrim binary search */
  49        s8 step;
  50        u16 adc_diff;
  51
  52        s8 captrim;
  53        s8 fcaptrim;
  54        u16 lo4;
  55
  56        const struct dib0070_tuning *current_tune_table_index;
  57        const struct dib0070_lna_match *lna_match;
  58
  59        u8  wbd_gain_current;
  60        u16 wbd_offset_3_3[2];
  61
  62        /* for the I2C transfer */
  63        struct i2c_msg msg[2];
  64        u8 i2c_write_buffer[3];
  65        u8 i2c_read_buffer[2];
  66        struct mutex i2c_buffer_lock;
  67};
  68
  69static u16 dib0070_read_reg(struct dib0070_state *state, u8 reg)
  70{
  71        u16 ret;
  72
  73        if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
  74                dprintk("could not acquire lock\n");
  75                return 0;
  76        }
  77
  78        state->i2c_write_buffer[0] = reg;
  79
  80        memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
  81        state->msg[0].addr = state->cfg->i2c_address;
  82        state->msg[0].flags = 0;
  83        state->msg[0].buf = state->i2c_write_buffer;
  84        state->msg[0].len = 1;
  85        state->msg[1].addr = state->cfg->i2c_address;
  86        state->msg[1].flags = I2C_M_RD;
  87        state->msg[1].buf = state->i2c_read_buffer;
  88        state->msg[1].len = 2;
  89
  90        if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
  91                pr_warn("DiB0070 I2C read failed\n");
  92                ret = 0;
  93        } else
  94                ret = (state->i2c_read_buffer[0] << 8)
  95                        | state->i2c_read_buffer[1];
  96
  97        mutex_unlock(&state->i2c_buffer_lock);
  98        return ret;
  99}
 100
 101static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
 102{
 103        int ret;
 104
 105        if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
 106                dprintk("could not acquire lock\n");
 107                return -EINVAL;
 108        }
 109        state->i2c_write_buffer[0] = reg;
 110        state->i2c_write_buffer[1] = val >> 8;
 111        state->i2c_write_buffer[2] = val & 0xff;
 112
 113        memset(state->msg, 0, sizeof(struct i2c_msg));
 114        state->msg[0].addr = state->cfg->i2c_address;
 115        state->msg[0].flags = 0;
 116        state->msg[0].buf = state->i2c_write_buffer;
 117        state->msg[0].len = 3;
 118
 119        if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
 120                pr_warn("DiB0070 I2C write failed\n");
 121                ret = -EREMOTEIO;
 122        } else
 123                ret = 0;
 124
 125        mutex_unlock(&state->i2c_buffer_lock);
 126        return ret;
 127}
 128
 129#define HARD_RESET(state) do { \
 130    state->cfg->sleep(state->fe, 0); \
 131    if (state->cfg->reset) { \
 132        state->cfg->reset(state->fe,1); msleep(10); \
 133        state->cfg->reset(state->fe,0); msleep(10); \
 134    } \
 135} while (0)
 136
 137static int dib0070_set_bandwidth(struct dvb_frontend *fe)
 138        {
 139        struct dib0070_state *state = fe->tuner_priv;
 140        u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff;
 141
 142        if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 7000)
 143                tmp |= (0 << 14);
 144        else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 6000)
 145                tmp |= (1 << 14);
 146        else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 5000)
 147                tmp |= (2 << 14);
 148        else
 149                tmp |= (3 << 14);
 150
 151        dib0070_write_reg(state, 0x02, tmp);
 152
 153        /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */
 154        if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) {
 155                u16 value = dib0070_read_reg(state, 0x17);
 156
 157                dib0070_write_reg(state, 0x17, value & 0xfffc);
 158                tmp = dib0070_read_reg(state, 0x01) & 0x01ff;
 159                dib0070_write_reg(state, 0x01, tmp | (60 << 9));
 160
 161                dib0070_write_reg(state, 0x17, value);
 162        }
 163        return 0;
 164}
 165
 166static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state *tune_state)
 167{
 168        int8_t step_sign;
 169        u16 adc;
 170        int ret = 0;
 171
 172        if (*tune_state == CT_TUNER_STEP_0) {
 173                dib0070_write_reg(state, 0x0f, 0xed10);
 174                dib0070_write_reg(state, 0x17,    0x0034);
 175
 176                dib0070_write_reg(state, 0x18, 0x0032);
 177                state->step = state->captrim = state->fcaptrim = 64;
 178                state->adc_diff = 3000;
 179                ret = 20;
 180
 181                *tune_state = CT_TUNER_STEP_1;
 182        } else if (*tune_state == CT_TUNER_STEP_1) {
 183                state->step /= 2;
 184                dib0070_write_reg(state, 0x14, state->lo4 | state->captrim);
 185                ret = 15;
 186
 187                *tune_state = CT_TUNER_STEP_2;
 188        } else if (*tune_state == CT_TUNER_STEP_2) {
 189
 190                adc = dib0070_read_reg(state, 0x19);
 191
 192                dprintk("CAPTRIM=%d; ADC = %hd (ADC) & %dmV\n", state->captrim,
 193                        adc, (u32)adc * (u32)1800 / (u32)1024);
 194
 195                if (adc >= 400) {
 196                        adc -= 400;
 197                        step_sign = -1;
 198                } else {
 199                        adc = 400 - adc;
 200                        step_sign = 1;
 201                }
 202
 203                if (adc < state->adc_diff) {
 204                        dprintk("CAPTRIM=%d is closer to target (%hd/%hd)\n",
 205                                state->captrim, adc, state->adc_diff);
 206                        state->adc_diff = adc;
 207                        state->fcaptrim = state->captrim;
 208                }
 209                state->captrim += (step_sign * state->step);
 210
 211                if (state->step >= 1)
 212                        *tune_state = CT_TUNER_STEP_1;
 213                else
 214                        *tune_state = CT_TUNER_STEP_3;
 215
 216        } else if (*tune_state == CT_TUNER_STEP_3) {
 217                dib0070_write_reg(state, 0x14, state->lo4 | state->fcaptrim);
 218                dib0070_write_reg(state, 0x18, 0x07ff);
 219                *tune_state = CT_TUNER_STEP_4;
 220        }
 221
 222        return ret;
 223}
 224
 225static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt)
 226{
 227        struct dib0070_state *state = fe->tuner_priv;
 228        u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0);
 229
 230        dprintk("CTRL_LO5: 0x%x\n", lo5);
 231        return dib0070_write_reg(state, 0x15, lo5);
 232}
 233
 234void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open)
 235{
 236        struct dib0070_state *state = fe->tuner_priv;
 237
 238        if (open) {
 239                dib0070_write_reg(state, 0x1b, 0xff00);
 240                dib0070_write_reg(state, 0x1a, 0x0000);
 241        } else {
 242                dib0070_write_reg(state, 0x1b, 0x4112);
 243                if (state->cfg->vga_filter != 0) {
 244                        dib0070_write_reg(state, 0x1a, state->cfg->vga_filter);
 245                        dprintk("vga filter register is set to %x\n", state->cfg->vga_filter);
 246                } else
 247                        dib0070_write_reg(state, 0x1a, 0x0009);
 248        }
 249}
 250
 251EXPORT_SYMBOL(dib0070_ctrl_agc_filter);
 252struct dib0070_tuning {
 253        u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
 254        u8 switch_trim;
 255        u8 vco_band;
 256        u8 hfdiv;
 257        u8 vco_multi;
 258        u8 presc;
 259        u8 wbdmux;
 260        u16 tuner_enable;
 261};
 262
 263struct dib0070_lna_match {
 264        u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
 265        u8 lna_band;
 266};
 267
 268static const struct dib0070_tuning dib0070s_tuning_table[] = {
 269        {     570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800 }, /* UHF */
 270        {     700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800 },
 271        {     863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800 },
 272        {    1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND */
 273        {    1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
 274        {    2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
 275        { 0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000 }, /* SBAND */
 276};
 277
 278static const struct dib0070_tuning dib0070_tuning_table[] = {
 279        {     115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000 }, /* FM below 92MHz cannot be tuned */
 280        {     179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000 }, /* VHF */
 281        {     189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000 },
 282        {     250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000 },
 283        {     569999, 2, 1, 5,  6, 2, 2, 0x4000 | 0x0800 }, /* UHF */
 284        {     699999, 2, 0, 1,  4, 2, 2, 0x4000 | 0x0800 },
 285        {     863999, 2, 1, 1,  4, 2, 2, 0x4000 | 0x0800 },
 286        { 0xffffffff, 0, 1, 0,  2, 2, 4, 0x2000 | 0x0400 }, /* LBAND or everything higher than UHF */
 287};
 288
 289static const struct dib0070_lna_match dib0070_lna_flip_chip[] = {
 290        {     180000, 0 }, /* VHF */
 291        {     188000, 1 },
 292        {     196400, 2 },
 293        {     250000, 3 },
 294        {     550000, 0 }, /* UHF */
 295        {     590000, 1 },
 296        {     666000, 3 },
 297        {     864000, 5 },
 298        {    1500000, 0 }, /* LBAND or everything higher than UHF */
 299        {    1600000, 1 },
 300        {    2000000, 3 },
 301        { 0xffffffff, 7 },
 302};
 303
 304static const struct dib0070_lna_match dib0070_lna[] = {
 305        {     180000, 0 }, /* VHF */
 306        {     188000, 1 },
 307        {     196400, 2 },
 308        {     250000, 3 },
 309        {     550000, 2 }, /* UHF */
 310        {     650000, 3 },
 311        {     750000, 5 },
 312        {     850000, 6 },
 313        {     864000, 7 },
 314        {    1500000, 0 }, /* LBAND or everything higher than UHF */
 315        {    1600000, 1 },
 316        {    2000000, 3 },
 317        { 0xffffffff, 7 },
 318};
 319
 320#define LPF     100
 321static int dib0070_tune_digital(struct dvb_frontend *fe)
 322{
 323        struct dib0070_state *state = fe->tuner_priv;
 324
 325        const struct dib0070_tuning *tune;
 326        const struct dib0070_lna_match *lna_match;
 327
 328        enum frontend_tune_state *tune_state = &state->tune_state;
 329        int ret = 10; /* 1ms is the default delay most of the time */
 330
 331        u8  band = (u8)BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency/1000);
 332        u32 freq = fe->dtv_property_cache.frequency/1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf);
 333
 334#ifdef CONFIG_SYS_ISDBT
 335        if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1)
 336                        if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2)
 337                        && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
 338                        || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
 339                                && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == (state->fe->dtv_property_cache.isdbt_sb_segment_count / 2)))
 340                        || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
 341                                && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))))
 342                                freq += 850;
 343#endif
 344        if (state->current_rf != freq) {
 345
 346                switch (state->revision) {
 347                case DIB0070S_P1A:
 348                tune = dib0070s_tuning_table;
 349                lna_match = dib0070_lna;
 350                break;
 351                default:
 352                tune = dib0070_tuning_table;
 353                if (state->cfg->flip_chip)
 354                        lna_match = dib0070_lna_flip_chip;
 355                else
 356                        lna_match = dib0070_lna;
 357                break;
 358                }
 359                while (freq > tune->max_freq) /* find the right one */
 360                        tune++;
 361                while (freq > lna_match->max_freq) /* find the right one */
 362                        lna_match++;
 363
 364                state->current_tune_table_index = tune;
 365                state->lna_match = lna_match;
 366        }
 367
 368        if (*tune_state == CT_TUNER_START) {
 369                dprintk("Tuning for Band: %d (%d kHz)\n", band, freq);
 370                if (state->current_rf != freq) {
 371                        u8 REFDIV;
 372                        u32 FBDiv, Rest, FREF, VCOF_kHz;
 373                        u8 Den;
 374
 375                        state->current_rf = freq;
 376                        state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7);
 377
 378
 379                        dib0070_write_reg(state, 0x17, 0x30);
 380
 381
 382                        VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2;
 383
 384                        switch (band) {
 385                        case BAND_VHF:
 386                                REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000);
 387                                break;
 388                        case BAND_FM:
 389                                REFDIV = (u8) ((state->cfg->clock_khz) / 1000);
 390                                break;
 391                        default:
 392                                REFDIV = (u8) (state->cfg->clock_khz  / 10000);
 393                                break;
 394                        }
 395                        FREF = state->cfg->clock_khz / REFDIV;
 396
 397
 398
 399                        switch (state->revision) {
 400                        case DIB0070S_P1A:
 401                                FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF);
 402                                Rest  = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF;
 403                                break;
 404
 405                        case DIB0070_P1G:
 406                        case DIB0070_P1F:
 407                        default:
 408                                FBDiv = (freq / (FREF / 2));
 409                                Rest  = 2 * freq - FBDiv * FREF;
 410                                break;
 411                        }
 412
 413                        if (Rest < LPF)
 414                                Rest = 0;
 415                        else if (Rest < 2 * LPF)
 416                                Rest = 2 * LPF;
 417                        else if (Rest > (FREF - LPF)) {
 418                                Rest = 0;
 419                                FBDiv += 1;
 420                        } else if (Rest > (FREF - 2 * LPF))
 421                                Rest = FREF - 2 * LPF;
 422                        Rest = (Rest * 6528) / (FREF / 10);
 423
 424                        Den = 1;
 425                        if (Rest > 0) {
 426                                state->lo4 |= (1 << 14) | (1 << 12);
 427                                Den = 255;
 428                        }
 429
 430
 431                        dib0070_write_reg(state, 0x11, (u16)FBDiv);
 432                        dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV);
 433                        dib0070_write_reg(state, 0x13, (u16) Rest);
 434
 435                        if (state->revision == DIB0070S_P1A) {
 436
 437                                if (band == BAND_SBAND) {
 438                                        dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
 439                                        dib0070_write_reg(state, 0x1d, 0xFFFF);
 440                                } else
 441                                        dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1);
 442                        }
 443
 444                        dib0070_write_reg(state, 0x20,
 445                                0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable);
 446
 447                        dprintk("REFDIV: %u, FREF: %d\n", REFDIV, FREF);
 448                        dprintk("FBDIV: %d, Rest: %d\n", FBDiv, Rest);
 449                        dprintk("Num: %u, Den: %u, SD: %d\n", (u16)Rest, Den,
 450                                (state->lo4 >> 12) & 0x1);
 451                        dprintk("HFDIV code: %u\n",
 452                                state->current_tune_table_index->hfdiv);
 453                        dprintk("VCO = %u\n",
 454                                state->current_tune_table_index->vco_band);
 455                        dprintk("VCOF: ((%u*%d) << 1))\n",
 456                                state->current_tune_table_index->vco_multi,
 457                                freq);
 458
 459                        *tune_state = CT_TUNER_STEP_0;
 460                } else { /* we are already tuned to this frequency - the configuration is correct  */
 461                        ret = 50; /* wakeup time */
 462                        *tune_state = CT_TUNER_STEP_5;
 463                }
 464        } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) {
 465
 466                ret = dib0070_captrim(state, tune_state);
 467
 468        } else if (*tune_state == CT_TUNER_STEP_4) {
 469                const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
 470                if (tmp != NULL) {
 471                        while (freq/1000 > tmp->freq) /* find the right one */
 472                                tmp++;
 473                        dib0070_write_reg(state, 0x0f,
 474                                (0 << 15) | (1 << 14) | (3 << 12)
 475                                | (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7)
 476                                | (state->current_tune_table_index->wbdmux << 0));
 477                        state->wbd_gain_current = tmp->wbd_gain_val;
 478                } else {
 479                        dib0070_write_reg(state, 0x0f,
 480                                          (0 << 15) | (1 << 14) | (3 << 12)
 481                                          | (6 << 9) | (0 << 8) | (1 << 7)
 482                                          | (state->current_tune_table_index->wbdmux << 0));
 483                        state->wbd_gain_current = 6;
 484                }
 485
 486                dib0070_write_reg(state, 0x06, 0x3fff);
 487                dib0070_write_reg(state, 0x07,
 488                                  (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0));
 489                dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127));
 490                dib0070_write_reg(state, 0x0d, 0x0d80);
 491
 492
 493                dib0070_write_reg(state, 0x18,   0x07ff);
 494                dib0070_write_reg(state, 0x17, 0x0033);
 495
 496
 497                *tune_state = CT_TUNER_STEP_5;
 498        } else if (*tune_state == CT_TUNER_STEP_5) {
 499                dib0070_set_bandwidth(fe);
 500                *tune_state = CT_TUNER_STOP;
 501        } else {
 502                ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */
 503        }
 504        return ret;
 505}
 506
 507
 508static int dib0070_tune(struct dvb_frontend *fe)
 509{
 510        struct dib0070_state *state = fe->tuner_priv;
 511        uint32_t ret;
 512
 513        state->tune_state = CT_TUNER_START;
 514
 515        do {
 516                ret = dib0070_tune_digital(fe);
 517                if (ret != FE_CALLBACK_TIME_NEVER)
 518                        msleep(ret/10);
 519                else
 520                break;
 521        } while (state->tune_state != CT_TUNER_STOP);
 522
 523        return 0;
 524}
 525
 526static int dib0070_wakeup(struct dvb_frontend *fe)
 527{
 528        struct dib0070_state *state = fe->tuner_priv;
 529        if (state->cfg->sleep)
 530                state->cfg->sleep(fe, 0);
 531        return 0;
 532}
 533
 534static int dib0070_sleep(struct dvb_frontend *fe)
 535{
 536        struct dib0070_state *state = fe->tuner_priv;
 537        if (state->cfg->sleep)
 538                state->cfg->sleep(fe, 1);
 539        return 0;
 540}
 541
 542u8 dib0070_get_rf_output(struct dvb_frontend *fe)
 543{
 544        struct dib0070_state *state = fe->tuner_priv;
 545        return (dib0070_read_reg(state, 0x07) >> 11) & 0x3;
 546}
 547EXPORT_SYMBOL(dib0070_get_rf_output);
 548
 549int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no)
 550{
 551        struct dib0070_state *state = fe->tuner_priv;
 552        u16 rxrf2 = dib0070_read_reg(state, 0x07) & 0xfe7ff;
 553        if (no > 3)
 554                no = 3;
 555        if (no < 1)
 556                no = 1;
 557        return dib0070_write_reg(state, 0x07, rxrf2 | (no << 11));
 558}
 559EXPORT_SYMBOL(dib0070_set_rf_output);
 560
 561static const u16 dib0070_p1f_defaults[] =
 562
 563{
 564        7, 0x02,
 565                0x0008,
 566                0x0000,
 567                0x0000,
 568                0x0000,
 569                0x0000,
 570                0x0002,
 571                0x0100,
 572
 573        3, 0x0d,
 574                0x0d80,
 575                0x0001,
 576                0x0000,
 577
 578        4, 0x11,
 579                0x0000,
 580                0x0103,
 581                0x0000,
 582                0x0000,
 583
 584        3, 0x16,
 585                0x0004 | 0x0040,
 586                0x0030,
 587                0x07ff,
 588
 589        6, 0x1b,
 590                0x4112,
 591                0xff00,
 592                0xc07f,
 593                0x0000,
 594                0x0180,
 595                0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
 596
 597        0,
 598};
 599
 600static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain)
 601{
 602        u16 tuner_en = dib0070_read_reg(state, 0x20);
 603        u16 offset;
 604
 605        dib0070_write_reg(state, 0x18, 0x07ff);
 606        dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
 607        dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0));
 608        msleep(9);
 609        offset = dib0070_read_reg(state, 0x19);
 610        dib0070_write_reg(state, 0x20, tuner_en);
 611        return offset;
 612}
 613
 614static void dib0070_wbd_offset_calibration(struct dib0070_state *state)
 615{
 616        u8 gain;
 617        for (gain = 6; gain < 8; gain++) {
 618                state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2);
 619                dprintk("Gain: %d, WBDOffset (3.3V) = %hd\n", gain, state->wbd_offset_3_3[gain-6]);
 620        }
 621}
 622
 623u16 dib0070_wbd_offset(struct dvb_frontend *fe)
 624{
 625        struct dib0070_state *state = fe->tuner_priv;
 626        const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
 627        u32 freq = fe->dtv_property_cache.frequency/1000;
 628
 629        if (tmp != NULL) {
 630                while (freq/1000 > tmp->freq) /* find the right one */
 631                        tmp++;
 632                state->wbd_gain_current = tmp->wbd_gain_val;
 633        } else
 634                state->wbd_gain_current = 6;
 635
 636        return state->wbd_offset_3_3[state->wbd_gain_current - 6];
 637}
 638EXPORT_SYMBOL(dib0070_wbd_offset);
 639
 640#define pgm_read_word(w) (*w)
 641static int dib0070_reset(struct dvb_frontend *fe)
 642{
 643        struct dib0070_state *state = fe->tuner_priv;
 644        u16 l, r, *n;
 645
 646        HARD_RESET(state);
 647
 648
 649#ifndef FORCE_SBAND_TUNER
 650        if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1)
 651                state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff;
 652        else
 653#else
 654#warning forcing SBAND
 655#endif
 656        state->revision = DIB0070S_P1A;
 657
 658        /* P1F or not */
 659        dprintk("Revision: %x\n", state->revision);
 660
 661        if (state->revision == DIB0070_P1D) {
 662                dprintk("Error: this driver is not to be used meant for P1D or earlier\n");
 663                return -EINVAL;
 664        }
 665
 666        n = (u16 *) dib0070_p1f_defaults;
 667        l = pgm_read_word(n++);
 668        while (l) {
 669                r = pgm_read_word(n++);
 670                do {
 671                        dib0070_write_reg(state, (u8)r, pgm_read_word(n++));
 672                        r++;
 673                } while (--l);
 674                l = pgm_read_word(n++);
 675        }
 676
 677        if (state->cfg->force_crystal_mode != 0)
 678                r = state->cfg->force_crystal_mode;
 679        else if (state->cfg->clock_khz >= 24000)
 680                r = 1;
 681        else
 682                r = 2;
 683
 684
 685        r |= state->cfg->osc_buffer_state << 3;
 686
 687        dib0070_write_reg(state, 0x10, r);
 688        dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 5));
 689
 690        if (state->cfg->invert_iq) {
 691                r = dib0070_read_reg(state, 0x02) & 0xffdf;
 692                dib0070_write_reg(state, 0x02, r | (1 << 5));
 693        }
 694
 695        if (state->revision == DIB0070S_P1A)
 696                dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
 697        else
 698                dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump,
 699                                     state->cfg->enable_third_order_filter);
 700
 701        dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8);
 702
 703        dib0070_wbd_offset_calibration(state);
 704
 705        return 0;
 706}
 707
 708static int dib0070_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 709{
 710        struct dib0070_state *state = fe->tuner_priv;
 711
 712        *frequency = 1000 * state->current_rf;
 713        return 0;
 714}
 715
 716static void dib0070_release(struct dvb_frontend *fe)
 717{
 718        kfree(fe->tuner_priv);
 719        fe->tuner_priv = NULL;
 720}
 721
 722static const struct dvb_tuner_ops dib0070_ops = {
 723        .info = {
 724                .name              = "DiBcom DiB0070",
 725                .frequency_min_hz  =  45 * MHz,
 726                .frequency_max_hz  = 860 * MHz,
 727                .frequency_step_hz =   1 * kHz,
 728        },
 729        .release       = dib0070_release,
 730
 731        .init          = dib0070_wakeup,
 732        .sleep         = dib0070_sleep,
 733        .set_params    = dib0070_tune,
 734
 735        .get_frequency = dib0070_get_frequency,
 736//      .get_bandwidth = dib0070_get_bandwidth
 737};
 738
 739struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
 740{
 741        struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL);
 742        if (state == NULL)
 743                return NULL;
 744
 745        state->cfg = cfg;
 746        state->i2c = i2c;
 747        state->fe  = fe;
 748        mutex_init(&state->i2c_buffer_lock);
 749        fe->tuner_priv = state;
 750
 751        if (dib0070_reset(fe) != 0)
 752                goto free_mem;
 753
 754        pr_info("DiB0070: successfully identified\n");
 755        memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
 756
 757        fe->tuner_priv = state;
 758        return fe;
 759
 760free_mem:
 761        kfree(state);
 762        fe->tuner_priv = NULL;
 763        return NULL;
 764}
 765EXPORT_SYMBOL(dib0070_attach);
 766
 767MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
 768MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
 769MODULE_LICENSE("GPL");
 770