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=%hd; ADC = %hd (ADC) & %dmV\n", state->captrim, adc, (u32) adc*(u32)1800/(u32)1024);
 193
 194                if (adc >= 400) {
 195                        adc -= 400;
 196                        step_sign = -1;
 197                } else {
 198                        adc = 400 - adc;
 199                        step_sign = 1;
 200                }
 201
 202                if (adc < state->adc_diff) {
 203                        dprintk("CAPTRIM=%hd is closer to target (%hd/%hd)\n", state->captrim, adc, state->adc_diff);
 204                        state->adc_diff = adc;
 205                        state->fcaptrim = state->captrim;
 206                }
 207                state->captrim += (step_sign * state->step);
 208
 209                if (state->step >= 1)
 210                        *tune_state = CT_TUNER_STEP_1;
 211                else
 212                        *tune_state = CT_TUNER_STEP_3;
 213
 214        } else if (*tune_state == CT_TUNER_STEP_3) {
 215                dib0070_write_reg(state, 0x14, state->lo4 | state->fcaptrim);
 216                dib0070_write_reg(state, 0x18, 0x07ff);
 217                *tune_state = CT_TUNER_STEP_4;
 218        }
 219
 220        return ret;
 221}
 222
 223static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt)
 224{
 225        struct dib0070_state *state = fe->tuner_priv;
 226        u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0);
 227
 228        dprintk("CTRL_LO5: 0x%x\n", lo5);
 229        return dib0070_write_reg(state, 0x15, lo5);
 230}
 231
 232void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open)
 233{
 234        struct dib0070_state *state = fe->tuner_priv;
 235
 236        if (open) {
 237                dib0070_write_reg(state, 0x1b, 0xff00);
 238                dib0070_write_reg(state, 0x1a, 0x0000);
 239        } else {
 240                dib0070_write_reg(state, 0x1b, 0x4112);
 241                if (state->cfg->vga_filter != 0) {
 242                        dib0070_write_reg(state, 0x1a, state->cfg->vga_filter);
 243                        dprintk("vga filter register is set to %x\n", state->cfg->vga_filter);
 244                } else
 245                        dib0070_write_reg(state, 0x1a, 0x0009);
 246        }
 247}
 248
 249EXPORT_SYMBOL(dib0070_ctrl_agc_filter);
 250struct dib0070_tuning {
 251        u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
 252        u8 switch_trim;
 253        u8 vco_band;
 254        u8 hfdiv;
 255        u8 vco_multi;
 256        u8 presc;
 257        u8 wbdmux;
 258        u16 tuner_enable;
 259};
 260
 261struct dib0070_lna_match {
 262        u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
 263        u8 lna_band;
 264};
 265
 266static const struct dib0070_tuning dib0070s_tuning_table[] = {
 267        {     570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800 }, /* UHF */
 268        {     700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800 },
 269        {     863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800 },
 270        {    1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND */
 271        {    1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
 272        {    2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
 273        { 0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000 }, /* SBAND */
 274};
 275
 276static const struct dib0070_tuning dib0070_tuning_table[] = {
 277        {     115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000 }, /* FM below 92MHz cannot be tuned */
 278        {     179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000 }, /* VHF */
 279        {     189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000 },
 280        {     250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000 },
 281        {     569999, 2, 1, 5,  6, 2, 2, 0x4000 | 0x0800 }, /* UHF */
 282        {     699999, 2, 0, 1,  4, 2, 2, 0x4000 | 0x0800 },
 283        {     863999, 2, 1, 1,  4, 2, 2, 0x4000 | 0x0800 },
 284        { 0xffffffff, 0, 1, 0,  2, 2, 4, 0x2000 | 0x0400 }, /* LBAND or everything higher than UHF */
 285};
 286
 287static const struct dib0070_lna_match dib0070_lna_flip_chip[] = {
 288        {     180000, 0 }, /* VHF */
 289        {     188000, 1 },
 290        {     196400, 2 },
 291        {     250000, 3 },
 292        {     550000, 0 }, /* UHF */
 293        {     590000, 1 },
 294        {     666000, 3 },
 295        {     864000, 5 },
 296        {    1500000, 0 }, /* LBAND or everything higher than UHF */
 297        {    1600000, 1 },
 298        {    2000000, 3 },
 299        { 0xffffffff, 7 },
 300};
 301
 302static const struct dib0070_lna_match dib0070_lna[] = {
 303        {     180000, 0 }, /* VHF */
 304        {     188000, 1 },
 305        {     196400, 2 },
 306        {     250000, 3 },
 307        {     550000, 2 }, /* UHF */
 308        {     650000, 3 },
 309        {     750000, 5 },
 310        {     850000, 6 },
 311        {     864000, 7 },
 312        {    1500000, 0 }, /* LBAND or everything higher than UHF */
 313        {    1600000, 1 },
 314        {    2000000, 3 },
 315        { 0xffffffff, 7 },
 316};
 317
 318#define LPF     100
 319static int dib0070_tune_digital(struct dvb_frontend *fe)
 320{
 321        struct dib0070_state *state = fe->tuner_priv;
 322
 323        const struct dib0070_tuning *tune;
 324        const struct dib0070_lna_match *lna_match;
 325
 326        enum frontend_tune_state *tune_state = &state->tune_state;
 327        int ret = 10; /* 1ms is the default delay most of the time */
 328
 329        u8  band = (u8)BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency/1000);
 330        u32 freq = fe->dtv_property_cache.frequency/1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf);
 331
 332#ifdef CONFIG_SYS_ISDBT
 333        if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1)
 334                        if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2)
 335                        && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
 336                        || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
 337                                && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == (state->fe->dtv_property_cache.isdbt_sb_segment_count / 2)))
 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) + 1))))
 340                                freq += 850;
 341#endif
 342        if (state->current_rf != freq) {
 343
 344                switch (state->revision) {
 345                case DIB0070S_P1A:
 346                tune = dib0070s_tuning_table;
 347                lna_match = dib0070_lna;
 348                break;
 349                default:
 350                tune = dib0070_tuning_table;
 351                if (state->cfg->flip_chip)
 352                        lna_match = dib0070_lna_flip_chip;
 353                else
 354                        lna_match = dib0070_lna;
 355                break;
 356                }
 357                while (freq > tune->max_freq) /* find the right one */
 358                        tune++;
 359                while (freq > lna_match->max_freq) /* find the right one */
 360                        lna_match++;
 361
 362                state->current_tune_table_index = tune;
 363                state->lna_match = lna_match;
 364        }
 365
 366        if (*tune_state == CT_TUNER_START) {
 367                dprintk("Tuning for Band: %hd (%d kHz)\n", band, freq);
 368                if (state->current_rf != freq) {
 369                        u8 REFDIV;
 370                        u32 FBDiv, Rest, FREF, VCOF_kHz;
 371                        u8 Den;
 372
 373                        state->current_rf = freq;
 374                        state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7);
 375
 376
 377                        dib0070_write_reg(state, 0x17, 0x30);
 378
 379
 380                        VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2;
 381
 382                        switch (band) {
 383                        case BAND_VHF:
 384                                REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000);
 385                                break;
 386                        case BAND_FM:
 387                                REFDIV = (u8) ((state->cfg->clock_khz) / 1000);
 388                                break;
 389                        default:
 390                                REFDIV = (u8) (state->cfg->clock_khz  / 10000);
 391                                break;
 392                        }
 393                        FREF = state->cfg->clock_khz / REFDIV;
 394
 395
 396
 397                        switch (state->revision) {
 398                        case DIB0070S_P1A:
 399                                FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF);
 400                                Rest  = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF;
 401                                break;
 402
 403                        case DIB0070_P1G:
 404                        case DIB0070_P1F:
 405                        default:
 406                                FBDiv = (freq / (FREF / 2));
 407                                Rest  = 2 * freq - FBDiv * FREF;
 408                                break;
 409                        }
 410
 411                        if (Rest < LPF)
 412                                Rest = 0;
 413                        else if (Rest < 2 * LPF)
 414                                Rest = 2 * LPF;
 415                        else if (Rest > (FREF - LPF)) {
 416                                Rest = 0;
 417                                FBDiv += 1;
 418                        } else if (Rest > (FREF - 2 * LPF))
 419                                Rest = FREF - 2 * LPF;
 420                        Rest = (Rest * 6528) / (FREF / 10);
 421
 422                        Den = 1;
 423                        if (Rest > 0) {
 424                                state->lo4 |= (1 << 14) | (1 << 12);
 425                                Den = 255;
 426                        }
 427
 428
 429                        dib0070_write_reg(state, 0x11, (u16)FBDiv);
 430                        dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV);
 431                        dib0070_write_reg(state, 0x13, (u16) Rest);
 432
 433                        if (state->revision == DIB0070S_P1A) {
 434
 435                                if (band == BAND_SBAND) {
 436                                        dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
 437                                        dib0070_write_reg(state, 0x1d, 0xFFFF);
 438                                } else
 439                                        dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1);
 440                        }
 441
 442                        dib0070_write_reg(state, 0x20,
 443                                0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable);
 444
 445                        dprintk("REFDIV: %hd, FREF: %d\n", REFDIV, FREF);
 446                        dprintk("FBDIV: %d, Rest: %d\n", FBDiv, Rest);
 447                        dprintk("Num: %hd, Den: %hd, SD: %hd\n", (u16) Rest, Den, (state->lo4 >> 12) & 0x1);
 448                        dprintk("HFDIV code: %hd\n", state->current_tune_table_index->hfdiv);
 449                        dprintk("VCO = %hd\n", state->current_tune_table_index->vco_band);
 450                        dprintk("VCOF: ((%hd*%d) << 1))\n", state->current_tune_table_index->vco_multi, freq);
 451
 452                        *tune_state = CT_TUNER_STEP_0;
 453                } else { /* we are already tuned to this frequency - the configuration is correct  */
 454                        ret = 50; /* wakeup time */
 455                        *tune_state = CT_TUNER_STEP_5;
 456                }
 457        } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) {
 458
 459                ret = dib0070_captrim(state, tune_state);
 460
 461        } else if (*tune_state == CT_TUNER_STEP_4) {
 462                const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
 463                if (tmp != NULL) {
 464                        while (freq/1000 > tmp->freq) /* find the right one */
 465                                tmp++;
 466                        dib0070_write_reg(state, 0x0f,
 467                                (0 << 15) | (1 << 14) | (3 << 12)
 468                                | (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7)
 469                                | (state->current_tune_table_index->wbdmux << 0));
 470                        state->wbd_gain_current = tmp->wbd_gain_val;
 471                } else {
 472                        dib0070_write_reg(state, 0x0f,
 473                                          (0 << 15) | (1 << 14) | (3 << 12)
 474                                          | (6 << 9) | (0 << 8) | (1 << 7)
 475                                          | (state->current_tune_table_index->wbdmux << 0));
 476                        state->wbd_gain_current = 6;
 477                }
 478
 479                dib0070_write_reg(state, 0x06, 0x3fff);
 480                dib0070_write_reg(state, 0x07,
 481                                  (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0));
 482                dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127));
 483                dib0070_write_reg(state, 0x0d, 0x0d80);
 484
 485
 486                dib0070_write_reg(state, 0x18,   0x07ff);
 487                dib0070_write_reg(state, 0x17, 0x0033);
 488
 489
 490                *tune_state = CT_TUNER_STEP_5;
 491        } else if (*tune_state == CT_TUNER_STEP_5) {
 492                dib0070_set_bandwidth(fe);
 493                *tune_state = CT_TUNER_STOP;
 494        } else {
 495                ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */
 496        }
 497        return ret;
 498}
 499
 500
 501static int dib0070_tune(struct dvb_frontend *fe)
 502{
 503        struct dib0070_state *state = fe->tuner_priv;
 504        uint32_t ret;
 505
 506        state->tune_state = CT_TUNER_START;
 507
 508        do {
 509                ret = dib0070_tune_digital(fe);
 510                if (ret != FE_CALLBACK_TIME_NEVER)
 511                        msleep(ret/10);
 512                else
 513                break;
 514        } while (state->tune_state != CT_TUNER_STOP);
 515
 516        return 0;
 517}
 518
 519static int dib0070_wakeup(struct dvb_frontend *fe)
 520{
 521        struct dib0070_state *state = fe->tuner_priv;
 522        if (state->cfg->sleep)
 523                state->cfg->sleep(fe, 0);
 524        return 0;
 525}
 526
 527static int dib0070_sleep(struct dvb_frontend *fe)
 528{
 529        struct dib0070_state *state = fe->tuner_priv;
 530        if (state->cfg->sleep)
 531                state->cfg->sleep(fe, 1);
 532        return 0;
 533}
 534
 535u8 dib0070_get_rf_output(struct dvb_frontend *fe)
 536{
 537        struct dib0070_state *state = fe->tuner_priv;
 538        return (dib0070_read_reg(state, 0x07) >> 11) & 0x3;
 539}
 540EXPORT_SYMBOL(dib0070_get_rf_output);
 541
 542int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no)
 543{
 544        struct dib0070_state *state = fe->tuner_priv;
 545        u16 rxrf2 = dib0070_read_reg(state, 0x07) & 0xfe7ff;
 546        if (no > 3)
 547                no = 3;
 548        if (no < 1)
 549                no = 1;
 550        return dib0070_write_reg(state, 0x07, rxrf2 | (no << 11));
 551}
 552EXPORT_SYMBOL(dib0070_set_rf_output);
 553
 554static const u16 dib0070_p1f_defaults[] =
 555
 556{
 557        7, 0x02,
 558                0x0008,
 559                0x0000,
 560                0x0000,
 561                0x0000,
 562                0x0000,
 563                0x0002,
 564                0x0100,
 565
 566        3, 0x0d,
 567                0x0d80,
 568                0x0001,
 569                0x0000,
 570
 571        4, 0x11,
 572                0x0000,
 573                0x0103,
 574                0x0000,
 575                0x0000,
 576
 577        3, 0x16,
 578                0x0004 | 0x0040,
 579                0x0030,
 580                0x07ff,
 581
 582        6, 0x1b,
 583                0x4112,
 584                0xff00,
 585                0xc07f,
 586                0x0000,
 587                0x0180,
 588                0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
 589
 590        0,
 591};
 592
 593static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain)
 594{
 595        u16 tuner_en = dib0070_read_reg(state, 0x20);
 596        u16 offset;
 597
 598        dib0070_write_reg(state, 0x18, 0x07ff);
 599        dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
 600        dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0));
 601        msleep(9);
 602        offset = dib0070_read_reg(state, 0x19);
 603        dib0070_write_reg(state, 0x20, tuner_en);
 604        return offset;
 605}
 606
 607static void dib0070_wbd_offset_calibration(struct dib0070_state *state)
 608{
 609        u8 gain;
 610        for (gain = 6; gain < 8; gain++) {
 611                state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2);
 612                dprintk("Gain: %d, WBDOffset (3.3V) = %hd\n", gain, state->wbd_offset_3_3[gain-6]);
 613        }
 614}
 615
 616u16 dib0070_wbd_offset(struct dvb_frontend *fe)
 617{
 618        struct dib0070_state *state = fe->tuner_priv;
 619        const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
 620        u32 freq = fe->dtv_property_cache.frequency/1000;
 621
 622        if (tmp != NULL) {
 623                while (freq/1000 > tmp->freq) /* find the right one */
 624                        tmp++;
 625                state->wbd_gain_current = tmp->wbd_gain_val;
 626        } else
 627                state->wbd_gain_current = 6;
 628
 629        return state->wbd_offset_3_3[state->wbd_gain_current - 6];
 630}
 631EXPORT_SYMBOL(dib0070_wbd_offset);
 632
 633#define pgm_read_word(w) (*w)
 634static int dib0070_reset(struct dvb_frontend *fe)
 635{
 636        struct dib0070_state *state = fe->tuner_priv;
 637        u16 l, r, *n;
 638
 639        HARD_RESET(state);
 640
 641
 642#ifndef FORCE_SBAND_TUNER
 643        if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1)
 644                state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff;
 645        else
 646#else
 647#warning forcing SBAND
 648#endif
 649        state->revision = DIB0070S_P1A;
 650
 651        /* P1F or not */
 652        dprintk("Revision: %x\n", state->revision);
 653
 654        if (state->revision == DIB0070_P1D) {
 655                dprintk("Error: this driver is not to be used meant for P1D or earlier\n");
 656                return -EINVAL;
 657        }
 658
 659        n = (u16 *) dib0070_p1f_defaults;
 660        l = pgm_read_word(n++);
 661        while (l) {
 662                r = pgm_read_word(n++);
 663                do {
 664                        dib0070_write_reg(state, (u8)r, pgm_read_word(n++));
 665                        r++;
 666                } while (--l);
 667                l = pgm_read_word(n++);
 668        }
 669
 670        if (state->cfg->force_crystal_mode != 0)
 671                r = state->cfg->force_crystal_mode;
 672        else if (state->cfg->clock_khz >= 24000)
 673                r = 1;
 674        else
 675                r = 2;
 676
 677
 678        r |= state->cfg->osc_buffer_state << 3;
 679
 680        dib0070_write_reg(state, 0x10, r);
 681        dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 5));
 682
 683        if (state->cfg->invert_iq) {
 684                r = dib0070_read_reg(state, 0x02) & 0xffdf;
 685                dib0070_write_reg(state, 0x02, r | (1 << 5));
 686        }
 687
 688        if (state->revision == DIB0070S_P1A)
 689                dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
 690        else
 691                dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump,
 692                                     state->cfg->enable_third_order_filter);
 693
 694        dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8);
 695
 696        dib0070_wbd_offset_calibration(state);
 697
 698        return 0;
 699}
 700
 701static int dib0070_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 702{
 703        struct dib0070_state *state = fe->tuner_priv;
 704
 705        *frequency = 1000 * state->current_rf;
 706        return 0;
 707}
 708
 709static void dib0070_release(struct dvb_frontend *fe)
 710{
 711        kfree(fe->tuner_priv);
 712        fe->tuner_priv = NULL;
 713}
 714
 715static const struct dvb_tuner_ops dib0070_ops = {
 716        .info = {
 717                .name              = "DiBcom DiB0070",
 718                .frequency_min_hz  =  45 * MHz,
 719                .frequency_max_hz  = 860 * MHz,
 720                .frequency_step_hz =   1 * kHz,
 721        },
 722        .release       = dib0070_release,
 723
 724        .init          = dib0070_wakeup,
 725        .sleep         = dib0070_sleep,
 726        .set_params    = dib0070_tune,
 727
 728        .get_frequency = dib0070_get_frequency,
 729//      .get_bandwidth = dib0070_get_bandwidth
 730};
 731
 732struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
 733{
 734        struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL);
 735        if (state == NULL)
 736                return NULL;
 737
 738        state->cfg = cfg;
 739        state->i2c = i2c;
 740        state->fe  = fe;
 741        mutex_init(&state->i2c_buffer_lock);
 742        fe->tuner_priv = state;
 743
 744        if (dib0070_reset(fe) != 0)
 745                goto free_mem;
 746
 747        pr_info("DiB0070: successfully identified\n");
 748        memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
 749
 750        fe->tuner_priv = state;
 751        return fe;
 752
 753free_mem:
 754        kfree(state);
 755        fe->tuner_priv = NULL;
 756        return NULL;
 757}
 758EXPORT_SYMBOL(dib0070_attach);
 759
 760MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
 761MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
 762MODULE_LICENSE("GPL");
 763