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