linux/drivers/media/dvb-frontends/s5h1420.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Driver for
   4 *    Samsung S5H1420 and
   5 *    PnpNetwork PN1010 QPSK Demodulator
   6 *
   7 * Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net>
   8 * Copyright (C) 2005-8 Patrick Boettcher <pb@linuxtv.org>
   9 */
  10
  11#include <linux/kernel.h>
  12#include <linux/module.h>
  13#include <linux/init.h>
  14#include <linux/string.h>
  15#include <linux/slab.h>
  16#include <linux/delay.h>
  17#include <linux/jiffies.h>
  18#include <asm/div64.h>
  19
  20#include <linux/i2c.h>
  21
  22
  23#include <media/dvb_frontend.h>
  24#include "s5h1420.h"
  25#include "s5h1420_priv.h"
  26
  27#define TONE_FREQ 22000
  28
  29struct s5h1420_state {
  30        struct i2c_adapter* i2c;
  31        const struct s5h1420_config* config;
  32
  33        struct dvb_frontend frontend;
  34        struct i2c_adapter tuner_i2c_adapter;
  35
  36        u8 CON_1_val;
  37
  38        u8 postlocked:1;
  39        u32 fclk;
  40        u32 tunedfreq;
  41        enum fe_code_rate fec_inner;
  42        u32 symbol_rate;
  43
  44        /* FIXME: ugly workaround for flexcop's incapable i2c-controller
  45         * it does not support repeated-start, workaround: write addr-1
  46         * and then read
  47         */
  48        u8 shadow[256];
  49};
  50
  51static u32 s5h1420_getsymbolrate(struct s5h1420_state* state);
  52static int s5h1420_get_tune_settings(struct dvb_frontend* fe,
  53                                     struct dvb_frontend_tune_settings* fesettings);
  54
  55
  56static int debug;
  57module_param(debug, int, 0644);
  58MODULE_PARM_DESC(debug, "enable debugging");
  59
  60#define dprintk(x...) do { \
  61        if (debug) \
  62                printk(KERN_DEBUG "S5H1420: " x); \
  63} while (0)
  64
  65static u8 s5h1420_readreg(struct s5h1420_state *state, u8 reg)
  66{
  67        int ret;
  68        u8 b[2];
  69        struct i2c_msg msg[] = {
  70                { .addr = state->config->demod_address, .flags = 0, .buf = b, .len = 2 },
  71                { .addr = state->config->demod_address, .flags = 0, .buf = &reg, .len = 1 },
  72                { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = 1 },
  73        };
  74
  75        b[0] = (reg - 1) & 0xff;
  76        b[1] = state->shadow[(reg - 1) & 0xff];
  77
  78        if (state->config->repeated_start_workaround) {
  79                ret = i2c_transfer(state->i2c, msg, 3);
  80                if (ret != 3)
  81                        return ret;
  82        } else {
  83                ret = i2c_transfer(state->i2c, &msg[1], 1);
  84                if (ret != 1)
  85                        return ret;
  86                ret = i2c_transfer(state->i2c, &msg[2], 1);
  87                if (ret != 1)
  88                        return ret;
  89        }
  90
  91        /* dprintk("rd(%02x): %02x %02x\n", state->config->demod_address, reg, b[0]); */
  92
  93        return b[0];
  94}
  95
  96static int s5h1420_writereg (struct s5h1420_state* state, u8 reg, u8 data)
  97{
  98        u8 buf[] = { reg, data };
  99        struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
 100        int err;
 101
 102        /* dprintk("wr(%02x): %02x %02x\n", state->config->demod_address, reg, data); */
 103        err = i2c_transfer(state->i2c, &msg, 1);
 104        if (err != 1) {
 105                dprintk("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data);
 106                return -EREMOTEIO;
 107        }
 108        state->shadow[reg] = data;
 109
 110        return 0;
 111}
 112
 113static int s5h1420_set_voltage(struct dvb_frontend *fe,
 114                               enum fe_sec_voltage voltage)
 115{
 116        struct s5h1420_state* state = fe->demodulator_priv;
 117
 118        dprintk("enter %s\n", __func__);
 119
 120        switch(voltage) {
 121        case SEC_VOLTAGE_13:
 122                s5h1420_writereg(state, 0x3c,
 123                                 (s5h1420_readreg(state, 0x3c) & 0xfe) | 0x02);
 124                break;
 125
 126        case SEC_VOLTAGE_18:
 127                s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) | 0x03);
 128                break;
 129
 130        case SEC_VOLTAGE_OFF:
 131                s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) & 0xfd);
 132                break;
 133        }
 134
 135        dprintk("leave %s\n", __func__);
 136        return 0;
 137}
 138
 139static int s5h1420_set_tone(struct dvb_frontend *fe,
 140                            enum fe_sec_tone_mode tone)
 141{
 142        struct s5h1420_state* state = fe->demodulator_priv;
 143
 144        dprintk("enter %s\n", __func__);
 145        switch(tone) {
 146        case SEC_TONE_ON:
 147                s5h1420_writereg(state, 0x3b,
 148                                 (s5h1420_readreg(state, 0x3b) & 0x74) | 0x08);
 149                break;
 150
 151        case SEC_TONE_OFF:
 152                s5h1420_writereg(state, 0x3b,
 153                                 (s5h1420_readreg(state, 0x3b) & 0x74) | 0x01);
 154                break;
 155        }
 156        dprintk("leave %s\n", __func__);
 157
 158        return 0;
 159}
 160
 161static int s5h1420_send_master_cmd (struct dvb_frontend* fe,
 162                                    struct dvb_diseqc_master_cmd* cmd)
 163{
 164        struct s5h1420_state* state = fe->demodulator_priv;
 165        u8 val;
 166        int i;
 167        unsigned long timeout;
 168        int result = 0;
 169
 170        dprintk("enter %s\n", __func__);
 171        if (cmd->msg_len > sizeof(cmd->msg))
 172                return -EINVAL;
 173
 174        /* setup for DISEQC */
 175        val = s5h1420_readreg(state, 0x3b);
 176        s5h1420_writereg(state, 0x3b, 0x02);
 177        msleep(15);
 178
 179        /* write the DISEQC command bytes */
 180        for(i=0; i< cmd->msg_len; i++) {
 181                s5h1420_writereg(state, 0x3d + i, cmd->msg[i]);
 182        }
 183
 184        /* kick off transmission */
 185        s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) |
 186                                      ((cmd->msg_len-1) << 4) | 0x08);
 187
 188        /* wait for transmission to complete */
 189        timeout = jiffies + ((100*HZ) / 1000);
 190        while(time_before(jiffies, timeout)) {
 191                if (!(s5h1420_readreg(state, 0x3b) & 0x08))
 192                        break;
 193
 194                msleep(5);
 195        }
 196        if (time_after(jiffies, timeout))
 197                result = -ETIMEDOUT;
 198
 199        /* restore original settings */
 200        s5h1420_writereg(state, 0x3b, val);
 201        msleep(15);
 202        dprintk("leave %s\n", __func__);
 203        return result;
 204}
 205
 206static int s5h1420_recv_slave_reply (struct dvb_frontend* fe,
 207                                     struct dvb_diseqc_slave_reply* reply)
 208{
 209        struct s5h1420_state* state = fe->demodulator_priv;
 210        u8 val;
 211        int i;
 212        int length;
 213        unsigned long timeout;
 214        int result = 0;
 215
 216        /* setup for DISEQC receive */
 217        val = s5h1420_readreg(state, 0x3b);
 218        s5h1420_writereg(state, 0x3b, 0x82); /* FIXME: guess - do we need to set DIS_RDY(0x08) in receive mode? */
 219        msleep(15);
 220
 221        /* wait for reception to complete */
 222        timeout = jiffies + ((reply->timeout*HZ) / 1000);
 223        while(time_before(jiffies, timeout)) {
 224                if (!(s5h1420_readreg(state, 0x3b) & 0x80)) /* FIXME: do we test DIS_RDY(0x08) or RCV_EN(0x80)? */
 225                        break;
 226
 227                msleep(5);
 228        }
 229        if (time_after(jiffies, timeout)) {
 230                result = -ETIMEDOUT;
 231                goto exit;
 232        }
 233
 234        /* check error flag - FIXME: not sure what this does - docs do not describe
 235         * beyond "error flag for diseqc receive data :( */
 236        if (s5h1420_readreg(state, 0x49)) {
 237                result = -EIO;
 238                goto exit;
 239        }
 240
 241        /* check length */
 242        length = (s5h1420_readreg(state, 0x3b) & 0x70) >> 4;
 243        if (length > sizeof(reply->msg)) {
 244                result = -EOVERFLOW;
 245                goto exit;
 246        }
 247        reply->msg_len = length;
 248
 249        /* extract data */
 250        for(i=0; i< length; i++) {
 251                reply->msg[i] = s5h1420_readreg(state, 0x3d + i);
 252        }
 253
 254exit:
 255        /* restore original settings */
 256        s5h1420_writereg(state, 0x3b, val);
 257        msleep(15);
 258        return result;
 259}
 260
 261static int s5h1420_send_burst(struct dvb_frontend *fe,
 262                              enum fe_sec_mini_cmd minicmd)
 263{
 264        struct s5h1420_state* state = fe->demodulator_priv;
 265        u8 val;
 266        int result = 0;
 267        unsigned long timeout;
 268
 269        /* setup for tone burst */
 270        val = s5h1420_readreg(state, 0x3b);
 271        s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x70) | 0x01);
 272
 273        /* set value for B position if requested */
 274        if (minicmd == SEC_MINI_B) {
 275                s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x04);
 276        }
 277        msleep(15);
 278
 279        /* start transmission */
 280        s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x08);
 281
 282        /* wait for transmission to complete */
 283        timeout = jiffies + ((100*HZ) / 1000);
 284        while(time_before(jiffies, timeout)) {
 285                if (!(s5h1420_readreg(state, 0x3b) & 0x08))
 286                        break;
 287
 288                msleep(5);
 289        }
 290        if (time_after(jiffies, timeout))
 291                result = -ETIMEDOUT;
 292
 293        /* restore original settings */
 294        s5h1420_writereg(state, 0x3b, val);
 295        msleep(15);
 296        return result;
 297}
 298
 299static enum fe_status s5h1420_get_status_bits(struct s5h1420_state *state)
 300{
 301        u8 val;
 302        enum fe_status status = 0;
 303
 304        val = s5h1420_readreg(state, 0x14);
 305        if (val & 0x02)
 306                status |=  FE_HAS_SIGNAL;
 307        if (val & 0x01)
 308                status |=  FE_HAS_CARRIER;
 309        val = s5h1420_readreg(state, 0x36);
 310        if (val & 0x01)
 311                status |=  FE_HAS_VITERBI;
 312        if (val & 0x20)
 313                status |=  FE_HAS_SYNC;
 314        if (status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI|FE_HAS_SYNC))
 315                status |=  FE_HAS_LOCK;
 316
 317        return status;
 318}
 319
 320static int s5h1420_read_status(struct dvb_frontend *fe,
 321                               enum fe_status *status)
 322{
 323        struct s5h1420_state* state = fe->demodulator_priv;
 324        u8 val;
 325
 326        dprintk("enter %s\n", __func__);
 327
 328        if (status == NULL)
 329                return -EINVAL;
 330
 331        /* determine lock state */
 332        *status = s5h1420_get_status_bits(state);
 333
 334        /* fix for FEC 5/6 inversion issue - if it doesn't quite lock, invert
 335        the inversion, wait a bit and check again */
 336        if (*status == (FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI)) {
 337                val = s5h1420_readreg(state, Vit10);
 338                if ((val & 0x07) == 0x03) {
 339                        if (val & 0x08)
 340                                s5h1420_writereg(state, Vit09, 0x13);
 341                        else
 342                                s5h1420_writereg(state, Vit09, 0x1b);
 343
 344                        /* wait a bit then update lock status */
 345                        mdelay(200);
 346                        *status = s5h1420_get_status_bits(state);
 347                }
 348        }
 349
 350        /* perform post lock setup */
 351        if ((*status & FE_HAS_LOCK) && !state->postlocked) {
 352
 353                /* calculate the data rate */
 354                u32 tmp = s5h1420_getsymbolrate(state);
 355                switch (s5h1420_readreg(state, Vit10) & 0x07) {
 356                case 0: tmp = (tmp * 2 * 1) / 2; break;
 357                case 1: tmp = (tmp * 2 * 2) / 3; break;
 358                case 2: tmp = (tmp * 2 * 3) / 4; break;
 359                case 3: tmp = (tmp * 2 * 5) / 6; break;
 360                case 4: tmp = (tmp * 2 * 6) / 7; break;
 361                case 5: tmp = (tmp * 2 * 7) / 8; break;
 362                }
 363
 364                if (tmp == 0) {
 365                        printk(KERN_ERR "s5h1420: avoided division by 0\n");
 366                        tmp = 1;
 367                }
 368                tmp = state->fclk / tmp;
 369
 370
 371                /* set the MPEG_CLK_INTL for the calculated data rate */
 372                if (tmp < 2)
 373                        val = 0x00;
 374                else if (tmp < 5)
 375                        val = 0x01;
 376                else if (tmp < 9)
 377                        val = 0x02;
 378                else if (tmp < 13)
 379                        val = 0x03;
 380                else if (tmp < 17)
 381                        val = 0x04;
 382                else if (tmp < 25)
 383                        val = 0x05;
 384                else if (tmp < 33)
 385                        val = 0x06;
 386                else
 387                        val = 0x07;
 388                dprintk("for MPEG_CLK_INTL %d %x\n", tmp, val);
 389
 390                s5h1420_writereg(state, FEC01, 0x18);
 391                s5h1420_writereg(state, FEC01, 0x10);
 392                s5h1420_writereg(state, FEC01, val);
 393
 394                /* Enable "MPEG_Out" */
 395                val = s5h1420_readreg(state, Mpeg02);
 396                s5h1420_writereg(state, Mpeg02, val | (1 << 6));
 397
 398                /* kicker disable */
 399                val = s5h1420_readreg(state, QPSK01) & 0x7f;
 400                s5h1420_writereg(state, QPSK01, val);
 401
 402                /* DC freeze TODO it was never activated by default or it can stay activated */
 403
 404                if (s5h1420_getsymbolrate(state) >= 20000000) {
 405                        s5h1420_writereg(state, Loop04, 0x8a);
 406                        s5h1420_writereg(state, Loop05, 0x6a);
 407                } else {
 408                        s5h1420_writereg(state, Loop04, 0x58);
 409                        s5h1420_writereg(state, Loop05, 0x27);
 410                }
 411
 412                /* post-lock processing has been done! */
 413                state->postlocked = 1;
 414        }
 415
 416        dprintk("leave %s\n", __func__);
 417
 418        return 0;
 419}
 420
 421static int s5h1420_read_ber(struct dvb_frontend* fe, u32* ber)
 422{
 423        struct s5h1420_state* state = fe->demodulator_priv;
 424
 425        s5h1420_writereg(state, 0x46, 0x1d);
 426        mdelay(25);
 427
 428        *ber = (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47);
 429
 430        return 0;
 431}
 432
 433static int s5h1420_read_signal_strength(struct dvb_frontend* fe, u16* strength)
 434{
 435        struct s5h1420_state* state = fe->demodulator_priv;
 436
 437        u8 val = s5h1420_readreg(state, 0x15);
 438
 439        *strength =  (u16) ((val << 8) | val);
 440
 441        return 0;
 442}
 443
 444static int s5h1420_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
 445{
 446        struct s5h1420_state* state = fe->demodulator_priv;
 447
 448        s5h1420_writereg(state, 0x46, 0x1f);
 449        mdelay(25);
 450
 451        *ucblocks = (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47);
 452
 453        return 0;
 454}
 455
 456static void s5h1420_reset(struct s5h1420_state* state)
 457{
 458        dprintk("%s\n", __func__);
 459        s5h1420_writereg (state, 0x01, 0x08);
 460        s5h1420_writereg (state, 0x01, 0x00);
 461        udelay(10);
 462}
 463
 464static void s5h1420_setsymbolrate(struct s5h1420_state* state,
 465                                  struct dtv_frontend_properties *p)
 466{
 467        u8 v;
 468        u64 val;
 469
 470        dprintk("enter %s\n", __func__);
 471
 472        val = ((u64) p->symbol_rate / 1000ULL) * (1ULL<<24);
 473        if (p->symbol_rate < 29000000)
 474                val *= 2;
 475        do_div(val, (state->fclk / 1000));
 476
 477        dprintk("symbol rate register: %06llx\n", (unsigned long long)val);
 478
 479        v = s5h1420_readreg(state, Loop01);
 480        s5h1420_writereg(state, Loop01, v & 0x7f);
 481        s5h1420_writereg(state, Tnco01, val >> 16);
 482        s5h1420_writereg(state, Tnco02, val >> 8);
 483        s5h1420_writereg(state, Tnco03, val & 0xff);
 484        s5h1420_writereg(state, Loop01,  v | 0x80);
 485        dprintk("leave %s\n", __func__);
 486}
 487
 488static u32 s5h1420_getsymbolrate(struct s5h1420_state* state)
 489{
 490        return state->symbol_rate;
 491}
 492
 493static void s5h1420_setfreqoffset(struct s5h1420_state* state, int freqoffset)
 494{
 495        int val;
 496        u8 v;
 497
 498        dprintk("enter %s\n", __func__);
 499
 500        /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so
 501         * divide fclk by 1000000 to get the correct value. */
 502        val = -(int) ((freqoffset * (1<<24)) / (state->fclk / 1000000));
 503
 504        dprintk("phase rotator/freqoffset: %d %06x\n", freqoffset, val);
 505
 506        v = s5h1420_readreg(state, Loop01);
 507        s5h1420_writereg(state, Loop01, v & 0xbf);
 508        s5h1420_writereg(state, Pnco01, val >> 16);
 509        s5h1420_writereg(state, Pnco02, val >> 8);
 510        s5h1420_writereg(state, Pnco03, val & 0xff);
 511        s5h1420_writereg(state, Loop01, v | 0x40);
 512        dprintk("leave %s\n", __func__);
 513}
 514
 515static int s5h1420_getfreqoffset(struct s5h1420_state* state)
 516{
 517        int val;
 518
 519        s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08);
 520        val  = s5h1420_readreg(state, 0x0e) << 16;
 521        val |= s5h1420_readreg(state, 0x0f) << 8;
 522        val |= s5h1420_readreg(state, 0x10);
 523        s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7);
 524
 525        if (val & 0x800000)
 526                val |= 0xff000000;
 527
 528        /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so
 529         * divide fclk by 1000000 to get the correct value. */
 530        val = (((-val) * (state->fclk/1000000)) / (1<<24));
 531
 532        return val;
 533}
 534
 535static void s5h1420_setfec_inversion(struct s5h1420_state* state,
 536                                     struct dtv_frontend_properties *p)
 537{
 538        u8 inversion = 0;
 539        u8 vit08, vit09;
 540
 541        dprintk("enter %s\n", __func__);
 542
 543        if (p->inversion == INVERSION_OFF)
 544                inversion = state->config->invert ? 0x08 : 0;
 545        else if (p->inversion == INVERSION_ON)
 546                inversion = state->config->invert ? 0 : 0x08;
 547
 548        if ((p->fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) {
 549                vit08 = 0x3f;
 550                vit09 = 0;
 551        } else {
 552                switch (p->fec_inner) {
 553                case FEC_1_2:
 554                        vit08 = 0x01;
 555                        vit09 = 0x10;
 556                        break;
 557
 558                case FEC_2_3:
 559                        vit08 = 0x02;
 560                        vit09 = 0x11;
 561                        break;
 562
 563                case FEC_3_4:
 564                        vit08 = 0x04;
 565                        vit09 = 0x12;
 566                        break;
 567
 568                case FEC_5_6:
 569                        vit08 = 0x08;
 570                        vit09 = 0x13;
 571                        break;
 572
 573                case FEC_6_7:
 574                        vit08 = 0x10;
 575                        vit09 = 0x14;
 576                        break;
 577
 578                case FEC_7_8:
 579                        vit08 = 0x20;
 580                        vit09 = 0x15;
 581                        break;
 582
 583                default:
 584                        return;
 585                }
 586        }
 587        vit09 |= inversion;
 588        dprintk("fec: %02x %02x\n", vit08, vit09);
 589        s5h1420_writereg(state, Vit08, vit08);
 590        s5h1420_writereg(state, Vit09, vit09);
 591        dprintk("leave %s\n", __func__);
 592}
 593
 594static enum fe_code_rate s5h1420_getfec(struct s5h1420_state *state)
 595{
 596        switch(s5h1420_readreg(state, 0x32) & 0x07) {
 597        case 0:
 598                return FEC_1_2;
 599
 600        case 1:
 601                return FEC_2_3;
 602
 603        case 2:
 604                return FEC_3_4;
 605
 606        case 3:
 607                return FEC_5_6;
 608
 609        case 4:
 610                return FEC_6_7;
 611
 612        case 5:
 613                return FEC_7_8;
 614        }
 615
 616        return FEC_NONE;
 617}
 618
 619static enum fe_spectral_inversion
 620s5h1420_getinversion(struct s5h1420_state *state)
 621{
 622        if (s5h1420_readreg(state, 0x32) & 0x08)
 623                return INVERSION_ON;
 624
 625        return INVERSION_OFF;
 626}
 627
 628static int s5h1420_set_frontend(struct dvb_frontend *fe)
 629{
 630        struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 631        struct s5h1420_state* state = fe->demodulator_priv;
 632        int frequency_delta;
 633        struct dvb_frontend_tune_settings fesettings;
 634
 635        dprintk("enter %s\n", __func__);
 636
 637        /* check if we should do a fast-tune */
 638        s5h1420_get_tune_settings(fe, &fesettings);
 639        frequency_delta = p->frequency - state->tunedfreq;
 640        if ((frequency_delta > -fesettings.max_drift) &&
 641                        (frequency_delta < fesettings.max_drift) &&
 642                        (frequency_delta != 0) &&
 643                        (state->fec_inner == p->fec_inner) &&
 644                        (state->symbol_rate == p->symbol_rate)) {
 645
 646                if (fe->ops.tuner_ops.set_params) {
 647                        fe->ops.tuner_ops.set_params(fe);
 648                        if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
 649                }
 650                if (fe->ops.tuner_ops.get_frequency) {
 651                        u32 tmp;
 652                        fe->ops.tuner_ops.get_frequency(fe, &tmp);
 653                        if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
 654                        s5h1420_setfreqoffset(state, p->frequency - tmp);
 655                } else {
 656                        s5h1420_setfreqoffset(state, 0);
 657                }
 658                dprintk("simple tune\n");
 659                return 0;
 660        }
 661        dprintk("tuning demod\n");
 662
 663        /* first of all, software reset */
 664        s5h1420_reset(state);
 665
 666        /* set s5h1420 fclk PLL according to desired symbol rate */
 667        if (p->symbol_rate > 33000000)
 668                state->fclk = 80000000;
 669        else if (p->symbol_rate > 28500000)
 670                state->fclk = 59000000;
 671        else if (p->symbol_rate > 25000000)
 672                state->fclk = 86000000;
 673        else if (p->symbol_rate > 1900000)
 674                state->fclk = 88000000;
 675        else
 676                state->fclk = 44000000;
 677
 678        dprintk("pll01: %d, ToneFreq: %d\n", state->fclk/1000000 - 8, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
 679        s5h1420_writereg(state, PLL01, state->fclk/1000000 - 8);
 680        s5h1420_writereg(state, PLL02, 0x40);
 681        s5h1420_writereg(state, DiS01, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
 682
 683        /* TODO DC offset removal, config parameter ? */
 684        if (p->symbol_rate > 29000000)
 685                s5h1420_writereg(state, QPSK01, 0xae | 0x10);
 686        else
 687                s5h1420_writereg(state, QPSK01, 0xac | 0x10);
 688
 689        /* set misc registers */
 690        s5h1420_writereg(state, CON_1, 0x00);
 691        s5h1420_writereg(state, QPSK02, 0x00);
 692        s5h1420_writereg(state, Pre01, 0xb0);
 693
 694        s5h1420_writereg(state, Loop01, 0xF0);
 695        s5h1420_writereg(state, Loop02, 0x2a); /* e7 for s5h1420 */
 696        s5h1420_writereg(state, Loop03, 0x79); /* 78 for s5h1420 */
 697        if (p->symbol_rate > 20000000)
 698                s5h1420_writereg(state, Loop04, 0x79);
 699        else
 700                s5h1420_writereg(state, Loop04, 0x58);
 701        s5h1420_writereg(state, Loop05, 0x6b);
 702
 703        if (p->symbol_rate >= 8000000)
 704                s5h1420_writereg(state, Post01, (0 << 6) | 0x10);
 705        else if (p->symbol_rate >= 4000000)
 706                s5h1420_writereg(state, Post01, (1 << 6) | 0x10);
 707        else
 708                s5h1420_writereg(state, Post01, (3 << 6) | 0x10);
 709
 710        s5h1420_writereg(state, Monitor12, 0x00); /* unfreeze DC compensation */
 711
 712        s5h1420_writereg(state, Sync01, 0x33);
 713        s5h1420_writereg(state, Mpeg01, state->config->cdclk_polarity);
 714        s5h1420_writereg(state, Mpeg02, 0x3d); /* Parallel output more, disabled -> enabled later */
 715        s5h1420_writereg(state, Err01, 0x03); /* 0x1d for s5h1420 */
 716
 717        s5h1420_writereg(state, Vit06, 0x6e); /* 0x8e for s5h1420 */
 718        s5h1420_writereg(state, DiS03, 0x00);
 719        s5h1420_writereg(state, Rf01, 0x61); /* Tuner i2c address - for the gate controller */
 720
 721        /* set tuner PLL */
 722        if (fe->ops.tuner_ops.set_params) {
 723                fe->ops.tuner_ops.set_params(fe);
 724                if (fe->ops.i2c_gate_ctrl)
 725                        fe->ops.i2c_gate_ctrl(fe, 0);
 726                s5h1420_setfreqoffset(state, 0);
 727        }
 728
 729        /* set the reset of the parameters */
 730        s5h1420_setsymbolrate(state, p);
 731        s5h1420_setfec_inversion(state, p);
 732
 733        /* start QPSK */
 734        s5h1420_writereg(state, QPSK01, s5h1420_readreg(state, QPSK01) | 1);
 735
 736        state->fec_inner = p->fec_inner;
 737        state->symbol_rate = p->symbol_rate;
 738        state->postlocked = 0;
 739        state->tunedfreq = p->frequency;
 740
 741        dprintk("leave %s\n", __func__);
 742        return 0;
 743}
 744
 745static int s5h1420_get_frontend(struct dvb_frontend* fe,
 746                                struct dtv_frontend_properties *p)
 747{
 748        struct s5h1420_state* state = fe->demodulator_priv;
 749
 750        p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state);
 751        p->inversion = s5h1420_getinversion(state);
 752        p->symbol_rate = s5h1420_getsymbolrate(state);
 753        p->fec_inner = s5h1420_getfec(state);
 754
 755        return 0;
 756}
 757
 758static int s5h1420_get_tune_settings(struct dvb_frontend* fe,
 759                                     struct dvb_frontend_tune_settings* fesettings)
 760{
 761        struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 762        if (p->symbol_rate > 20000000) {
 763                fesettings->min_delay_ms = 50;
 764                fesettings->step_size = 2000;
 765                fesettings->max_drift = 8000;
 766        } else if (p->symbol_rate > 12000000) {
 767                fesettings->min_delay_ms = 100;
 768                fesettings->step_size = 1500;
 769                fesettings->max_drift = 9000;
 770        } else if (p->symbol_rate > 8000000) {
 771                fesettings->min_delay_ms = 100;
 772                fesettings->step_size = 1000;
 773                fesettings->max_drift = 8000;
 774        } else if (p->symbol_rate > 4000000) {
 775                fesettings->min_delay_ms = 100;
 776                fesettings->step_size = 500;
 777                fesettings->max_drift = 7000;
 778        } else if (p->symbol_rate > 2000000) {
 779                fesettings->min_delay_ms = 200;
 780                fesettings->step_size = (p->symbol_rate / 8000);
 781                fesettings->max_drift = 14 * fesettings->step_size;
 782        } else {
 783                fesettings->min_delay_ms = 200;
 784                fesettings->step_size = (p->symbol_rate / 8000);
 785                fesettings->max_drift = 18 * fesettings->step_size;
 786        }
 787
 788        return 0;
 789}
 790
 791static int s5h1420_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
 792{
 793        struct s5h1420_state* state = fe->demodulator_priv;
 794
 795        if (enable)
 796                return s5h1420_writereg(state, 0x02, state->CON_1_val | 1);
 797        else
 798                return s5h1420_writereg(state, 0x02, state->CON_1_val & 0xfe);
 799}
 800
 801static int s5h1420_init (struct dvb_frontend* fe)
 802{
 803        struct s5h1420_state* state = fe->demodulator_priv;
 804
 805        /* disable power down and do reset */
 806        state->CON_1_val = state->config->serial_mpeg << 4;
 807        s5h1420_writereg(state, 0x02, state->CON_1_val);
 808        msleep(10);
 809        s5h1420_reset(state);
 810
 811        return 0;
 812}
 813
 814static int s5h1420_sleep(struct dvb_frontend* fe)
 815{
 816        struct s5h1420_state* state = fe->demodulator_priv;
 817        state->CON_1_val = 0x12;
 818        return s5h1420_writereg(state, 0x02, state->CON_1_val);
 819}
 820
 821static void s5h1420_release(struct dvb_frontend* fe)
 822{
 823        struct s5h1420_state* state = fe->demodulator_priv;
 824        i2c_del_adapter(&state->tuner_i2c_adapter);
 825        kfree(state);
 826}
 827
 828static u32 s5h1420_tuner_i2c_func(struct i2c_adapter *adapter)
 829{
 830        return I2C_FUNC_I2C;
 831}
 832
 833static int s5h1420_tuner_i2c_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
 834{
 835        struct s5h1420_state *state = i2c_get_adapdata(i2c_adap);
 836        struct i2c_msg m[3];
 837        u8 tx_open[2] = { CON_1, state->CON_1_val | 1 }; /* repeater stops once there was a stop condition */
 838
 839        if (1 + num > ARRAY_SIZE(m)) {
 840                printk(KERN_WARNING
 841                       "%s: i2c xfer: num=%d is too big!\n",
 842                       KBUILD_MODNAME, num);
 843                return  -EOPNOTSUPP;
 844        }
 845
 846        memset(m, 0, sizeof(struct i2c_msg) * (1 + num));
 847
 848        m[0].addr = state->config->demod_address;
 849        m[0].buf  = tx_open;
 850        m[0].len  = 2;
 851
 852        memcpy(&m[1], msg, sizeof(struct i2c_msg) * num);
 853
 854        return i2c_transfer(state->i2c, m, 1 + num) == 1 + num ? num : -EIO;
 855}
 856
 857static const struct i2c_algorithm s5h1420_tuner_i2c_algo = {
 858        .master_xfer   = s5h1420_tuner_i2c_tuner_xfer,
 859        .functionality = s5h1420_tuner_i2c_func,
 860};
 861
 862struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe)
 863{
 864        struct s5h1420_state *state = fe->demodulator_priv;
 865        return &state->tuner_i2c_adapter;
 866}
 867EXPORT_SYMBOL(s5h1420_get_tuner_i2c_adapter);
 868
 869static const struct dvb_frontend_ops s5h1420_ops;
 870
 871struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
 872                                    struct i2c_adapter *i2c)
 873{
 874        /* allocate memory for the internal state */
 875        struct s5h1420_state *state = kzalloc(sizeof(struct s5h1420_state), GFP_KERNEL);
 876        u8 i;
 877
 878        if (state == NULL)
 879                goto error;
 880
 881        /* setup the state */
 882        state->config = config;
 883        state->i2c = i2c;
 884        state->postlocked = 0;
 885        state->fclk = 88000000;
 886        state->tunedfreq = 0;
 887        state->fec_inner = FEC_NONE;
 888        state->symbol_rate = 0;
 889
 890        /* check if the demod is there + identify it */
 891        i = s5h1420_readreg(state, ID01);
 892        if (i != 0x03)
 893                goto error;
 894
 895        memset(state->shadow, 0xff, sizeof(state->shadow));
 896
 897        for (i = 0; i < 0x50; i++)
 898                state->shadow[i] = s5h1420_readreg(state, i);
 899
 900        /* create dvb_frontend */
 901        memcpy(&state->frontend.ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));
 902        state->frontend.demodulator_priv = state;
 903
 904        /* create tuner i2c adapter */
 905        strscpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus",
 906                sizeof(state->tuner_i2c_adapter.name));
 907        state->tuner_i2c_adapter.algo      = &s5h1420_tuner_i2c_algo;
 908        state->tuner_i2c_adapter.algo_data = NULL;
 909        i2c_set_adapdata(&state->tuner_i2c_adapter, state);
 910        if (i2c_add_adapter(&state->tuner_i2c_adapter) < 0) {
 911                printk(KERN_ERR "S5H1420/PN1010: tuner i2c bus could not be initialized\n");
 912                goto error;
 913        }
 914
 915        return &state->frontend;
 916
 917error:
 918        kfree(state);
 919        return NULL;
 920}
 921EXPORT_SYMBOL(s5h1420_attach);
 922
 923static const struct dvb_frontend_ops s5h1420_ops = {
 924        .delsys = { SYS_DVBS },
 925        .info = {
 926                .name     = "Samsung S5H1420/PnpNetwork PN1010 DVB-S",
 927                .frequency_min_hz    =  950 * MHz,
 928                .frequency_max_hz    = 2150 * MHz,
 929                .frequency_stepsize_hz = 125 * kHz,
 930                .frequency_tolerance_hz  = 29500 * kHz,
 931                .symbol_rate_min  = 1000000,
 932                .symbol_rate_max  = 45000000,
 933                /*  .symbol_rate_tolerance  = ???,*/
 934                .caps = FE_CAN_INVERSION_AUTO |
 935                FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
 936                FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
 937                FE_CAN_QPSK
 938        },
 939
 940        .release = s5h1420_release,
 941
 942        .init = s5h1420_init,
 943        .sleep = s5h1420_sleep,
 944        .i2c_gate_ctrl = s5h1420_i2c_gate_ctrl,
 945
 946        .set_frontend = s5h1420_set_frontend,
 947        .get_frontend = s5h1420_get_frontend,
 948        .get_tune_settings = s5h1420_get_tune_settings,
 949
 950        .read_status = s5h1420_read_status,
 951        .read_ber = s5h1420_read_ber,
 952        .read_signal_strength = s5h1420_read_signal_strength,
 953        .read_ucblocks = s5h1420_read_ucblocks,
 954
 955        .diseqc_send_master_cmd = s5h1420_send_master_cmd,
 956        .diseqc_recv_slave_reply = s5h1420_recv_slave_reply,
 957        .diseqc_send_burst = s5h1420_send_burst,
 958        .set_tone = s5h1420_set_tone,
 959        .set_voltage = s5h1420_set_voltage,
 960};
 961
 962MODULE_DESCRIPTION("Samsung S5H1420/PnpNetwork PN1010 DVB-S Demodulator driver");
 963MODULE_AUTHOR("Andrew de Quincey, Patrick Boettcher");
 964MODULE_LICENSE("GPL");
 965