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