Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003     Samsung S5H1409 VSB/QAM demodulator driver
0004 
0005     Copyright (C) 2006 Steven Toth <stoth@linuxtv.org>
0006 
0007 
0008 */
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/init.h>
0012 #include <linux/module.h>
0013 #include <linux/string.h>
0014 #include <linux/slab.h>
0015 #include <linux/delay.h>
0016 #include <media/dvb_frontend.h>
0017 #include "s5h1409.h"
0018 
0019 struct s5h1409_state {
0020 
0021     struct i2c_adapter *i2c;
0022 
0023     /* configuration settings */
0024     const struct s5h1409_config *config;
0025 
0026     struct dvb_frontend frontend;
0027 
0028     /* previous uncorrected block counter */
0029     enum fe_modulation current_modulation;
0030 
0031     u32 current_frequency;
0032     int if_freq;
0033 
0034     u32 is_qam_locked;
0035 
0036     /* QAM tuning state goes through the following state transitions */
0037 #define QAM_STATE_UNTUNED 0
0038 #define QAM_STATE_TUNING_STARTED 1
0039 #define QAM_STATE_INTERLEAVE_SET 2
0040 #define QAM_STATE_QAM_OPTIMIZED_L1 3
0041 #define QAM_STATE_QAM_OPTIMIZED_L2 4
0042 #define QAM_STATE_QAM_OPTIMIZED_L3 5
0043     u8  qam_state;
0044 };
0045 
0046 static int debug;
0047 module_param(debug, int, 0644);
0048 MODULE_PARM_DESC(debug, "Enable verbose debug messages");
0049 
0050 #define dprintk if (debug) printk
0051 
0052 /* Register values to initialise the demod, this will set VSB by default */
0053 static struct init_tab {
0054     u8  reg;
0055     u16 data;
0056 } init_tab[] = {
0057     { 0x00, 0x0071, },
0058     { 0x01, 0x3213, },
0059     { 0x09, 0x0025, },
0060     { 0x1c, 0x001d, },
0061     { 0x1f, 0x002d, },
0062     { 0x20, 0x001d, },
0063     { 0x22, 0x0022, },
0064     { 0x23, 0x0020, },
0065     { 0x29, 0x110f, },
0066     { 0x2a, 0x10b4, },
0067     { 0x2b, 0x10ae, },
0068     { 0x2c, 0x0031, },
0069     { 0x31, 0x010d, },
0070     { 0x32, 0x0100, },
0071     { 0x44, 0x0510, },
0072     { 0x54, 0x0104, },
0073     { 0x58, 0x2222, },
0074     { 0x59, 0x1162, },
0075     { 0x5a, 0x3211, },
0076     { 0x5d, 0x0370, },
0077     { 0x5e, 0x0296, },
0078     { 0x61, 0x0010, },
0079     { 0x63, 0x4a00, },
0080     { 0x65, 0x0800, },
0081     { 0x71, 0x0003, },
0082     { 0x72, 0x0470, },
0083     { 0x81, 0x0002, },
0084     { 0x82, 0x0600, },
0085     { 0x86, 0x0002, },
0086     { 0x8a, 0x2c38, },
0087     { 0x8b, 0x2a37, },
0088     { 0x92, 0x302f, },
0089     { 0x93, 0x3332, },
0090     { 0x96, 0x000c, },
0091     { 0x99, 0x0101, },
0092     { 0x9c, 0x2e37, },
0093     { 0x9d, 0x2c37, },
0094     { 0x9e, 0x2c37, },
0095     { 0xab, 0x0100, },
0096     { 0xac, 0x1003, },
0097     { 0xad, 0x103f, },
0098     { 0xe2, 0x0100, },
0099     { 0xe3, 0x1000, },
0100     { 0x28, 0x1010, },
0101     { 0xb1, 0x000e, },
0102 };
0103 
0104 /* VSB SNR lookup table */
0105 static struct vsb_snr_tab {
0106     u16 val;
0107     u16 data;
0108 } vsb_snr_tab[] = {
0109     {  924, 300, },
0110     {  923, 300, },
0111     {  918, 295, },
0112     {  915, 290, },
0113     {  911, 285, },
0114     {  906, 280, },
0115     {  901, 275, },
0116     {  896, 270, },
0117     {  891, 265, },
0118     {  885, 260, },
0119     {  879, 255, },
0120     {  873, 250, },
0121     {  864, 245, },
0122     {  858, 240, },
0123     {  850, 235, },
0124     {  841, 230, },
0125     {  832, 225, },
0126     {  823, 220, },
0127     {  812, 215, },
0128     {  802, 210, },
0129     {  788, 205, },
0130     {  778, 200, },
0131     {  767, 195, },
0132     {  753, 190, },
0133     {  740, 185, },
0134     {  725, 180, },
0135     {  707, 175, },
0136     {  689, 170, },
0137     {  671, 165, },
0138     {  656, 160, },
0139     {  637, 155, },
0140     {  616, 150, },
0141     {  542, 145, },
0142     {  519, 140, },
0143     {  507, 135, },
0144     {  497, 130, },
0145     {  492, 125, },
0146     {  474, 120, },
0147     {  300, 111, },
0148     {    0,   0, },
0149 };
0150 
0151 /* QAM64 SNR lookup table */
0152 static struct qam64_snr_tab {
0153     u16 val;
0154     u16 data;
0155 } qam64_snr_tab[] = {
0156     {    1,   0, },
0157     {   12, 300, },
0158     {   15, 290, },
0159     {   18, 280, },
0160     {   22, 270, },
0161     {   23, 268, },
0162     {   24, 266, },
0163     {   25, 264, },
0164     {   27, 262, },
0165     {   28, 260, },
0166     {   29, 258, },
0167     {   30, 256, },
0168     {   32, 254, },
0169     {   33, 252, },
0170     {   34, 250, },
0171     {   35, 249, },
0172     {   36, 248, },
0173     {   37, 247, },
0174     {   38, 246, },
0175     {   39, 245, },
0176     {   40, 244, },
0177     {   41, 243, },
0178     {   42, 241, },
0179     {   43, 240, },
0180     {   44, 239, },
0181     {   45, 238, },
0182     {   46, 237, },
0183     {   47, 236, },
0184     {   48, 235, },
0185     {   49, 234, },
0186     {   50, 233, },
0187     {   51, 232, },
0188     {   52, 231, },
0189     {   53, 230, },
0190     {   55, 229, },
0191     {   56, 228, },
0192     {   57, 227, },
0193     {   58, 226, },
0194     {   59, 225, },
0195     {   60, 224, },
0196     {   62, 223, },
0197     {   63, 222, },
0198     {   65, 221, },
0199     {   66, 220, },
0200     {   68, 219, },
0201     {   69, 218, },
0202     {   70, 217, },
0203     {   72, 216, },
0204     {   73, 215, },
0205     {   75, 214, },
0206     {   76, 213, },
0207     {   78, 212, },
0208     {   80, 211, },
0209     {   81, 210, },
0210     {   83, 209, },
0211     {   84, 208, },
0212     {   85, 207, },
0213     {   87, 206, },
0214     {   89, 205, },
0215     {   91, 204, },
0216     {   93, 203, },
0217     {   95, 202, },
0218     {   96, 201, },
0219     {  104, 200, },
0220     {  255,   0, },
0221 };
0222 
0223 /* QAM256 SNR lookup table */
0224 static struct qam256_snr_tab {
0225     u16 val;
0226     u16 data;
0227 } qam256_snr_tab[] = {
0228     {    1,   0, },
0229     {   12, 400, },
0230     {   13, 390, },
0231     {   15, 380, },
0232     {   17, 360, },
0233     {   19, 350, },
0234     {   22, 348, },
0235     {   23, 346, },
0236     {   24, 344, },
0237     {   25, 342, },
0238     {   26, 340, },
0239     {   27, 336, },
0240     {   28, 334, },
0241     {   29, 332, },
0242     {   30, 330, },
0243     {   31, 328, },
0244     {   32, 326, },
0245     {   33, 325, },
0246     {   34, 322, },
0247     {   35, 320, },
0248     {   37, 318, },
0249     {   39, 316, },
0250     {   40, 314, },
0251     {   41, 312, },
0252     {   42, 310, },
0253     {   43, 308, },
0254     {   46, 306, },
0255     {   47, 304, },
0256     {   49, 302, },
0257     {   51, 300, },
0258     {   53, 298, },
0259     {   54, 297, },
0260     {   55, 296, },
0261     {   56, 295, },
0262     {   57, 294, },
0263     {   59, 293, },
0264     {   60, 292, },
0265     {   61, 291, },
0266     {   63, 290, },
0267     {   64, 289, },
0268     {   65, 288, },
0269     {   66, 287, },
0270     {   68, 286, },
0271     {   69, 285, },
0272     {   71, 284, },
0273     {   72, 283, },
0274     {   74, 282, },
0275     {   75, 281, },
0276     {   76, 280, },
0277     {   77, 279, },
0278     {   78, 278, },
0279     {   81, 277, },
0280     {   83, 276, },
0281     {   84, 275, },
0282     {   86, 274, },
0283     {   87, 273, },
0284     {   89, 272, },
0285     {   90, 271, },
0286     {   92, 270, },
0287     {   93, 269, },
0288     {   95, 268, },
0289     {   96, 267, },
0290     {   98, 266, },
0291     {  100, 265, },
0292     {  102, 264, },
0293     {  104, 263, },
0294     {  105, 262, },
0295     {  106, 261, },
0296     {  110, 260, },
0297     {  255,   0, },
0298 };
0299 
0300 /* 8 bit registers, 16 bit values */
0301 static int s5h1409_writereg(struct s5h1409_state *state, u8 reg, u16 data)
0302 {
0303     int ret;
0304     u8 buf[] = { reg, data >> 8,  data & 0xff };
0305 
0306     struct i2c_msg msg = { .addr = state->config->demod_address,
0307                    .flags = 0, .buf = buf, .len = 3 };
0308 
0309     ret = i2c_transfer(state->i2c, &msg, 1);
0310 
0311     if (ret != 1)
0312         printk(KERN_ERR "%s: error (reg == 0x%02x, val == 0x%04x, ret == %i)\n",
0313                __func__, reg, data, ret);
0314 
0315     return (ret != 1) ? -1 : 0;
0316 }
0317 
0318 static u16 s5h1409_readreg(struct s5h1409_state *state, u8 reg)
0319 {
0320     int ret;
0321     u8 b0[] = { reg };
0322     u8 b1[] = { 0, 0 };
0323 
0324     struct i2c_msg msg[] = {
0325         { .addr = state->config->demod_address, .flags = 0,
0326           .buf = b0, .len = 1 },
0327         { .addr = state->config->demod_address, .flags = I2C_M_RD,
0328           .buf = b1, .len = 2 } };
0329 
0330     ret = i2c_transfer(state->i2c, msg, 2);
0331 
0332     if (ret != 2)
0333         printk("%s: readreg error (ret == %i)\n", __func__, ret);
0334     return (b1[0] << 8) | b1[1];
0335 }
0336 
0337 static int s5h1409_softreset(struct dvb_frontend *fe)
0338 {
0339     struct s5h1409_state *state = fe->demodulator_priv;
0340 
0341     dprintk("%s()\n", __func__);
0342 
0343     s5h1409_writereg(state, 0xf5, 0);
0344     s5h1409_writereg(state, 0xf5, 1);
0345     state->is_qam_locked = 0;
0346     state->qam_state = QAM_STATE_UNTUNED;
0347     return 0;
0348 }
0349 
0350 #define S5H1409_VSB_IF_FREQ 5380
0351 #define S5H1409_QAM_IF_FREQ (state->config->qam_if)
0352 
0353 static int s5h1409_set_if_freq(struct dvb_frontend *fe, int KHz)
0354 {
0355     struct s5h1409_state *state = fe->demodulator_priv;
0356 
0357     dprintk("%s(%d KHz)\n", __func__, KHz);
0358 
0359     switch (KHz) {
0360     case 4000:
0361         s5h1409_writereg(state, 0x87, 0x014b);
0362         s5h1409_writereg(state, 0x88, 0x0cb5);
0363         s5h1409_writereg(state, 0x89, 0x03e2);
0364         break;
0365     case 5380:
0366     case 44000:
0367     default:
0368         s5h1409_writereg(state, 0x87, 0x01be);
0369         s5h1409_writereg(state, 0x88, 0x0436);
0370         s5h1409_writereg(state, 0x89, 0x054d);
0371         break;
0372     }
0373     state->if_freq = KHz;
0374 
0375     return 0;
0376 }
0377 
0378 static int s5h1409_set_spectralinversion(struct dvb_frontend *fe, int inverted)
0379 {
0380     struct s5h1409_state *state = fe->demodulator_priv;
0381 
0382     dprintk("%s(%d)\n", __func__, inverted);
0383 
0384     if (inverted == 1)
0385         return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */
0386     else
0387         return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */
0388 }
0389 
0390 static int s5h1409_enable_modulation(struct dvb_frontend *fe,
0391                      enum fe_modulation m)
0392 {
0393     struct s5h1409_state *state = fe->demodulator_priv;
0394 
0395     dprintk("%s(0x%08x)\n", __func__, m);
0396 
0397     switch (m) {
0398     case VSB_8:
0399         dprintk("%s() VSB_8\n", __func__);
0400         if (state->if_freq != S5H1409_VSB_IF_FREQ)
0401             s5h1409_set_if_freq(fe, S5H1409_VSB_IF_FREQ);
0402         s5h1409_writereg(state, 0xf4, 0);
0403         break;
0404     case QAM_64:
0405     case QAM_256:
0406     case QAM_AUTO:
0407         dprintk("%s() QAM_AUTO (64/256)\n", __func__);
0408         if (state->if_freq != S5H1409_QAM_IF_FREQ)
0409             s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ);
0410         s5h1409_writereg(state, 0xf4, 1);
0411         s5h1409_writereg(state, 0x85, 0x110);
0412         break;
0413     default:
0414         dprintk("%s() Invalid modulation\n", __func__);
0415         return -EINVAL;
0416     }
0417 
0418     state->current_modulation = m;
0419     s5h1409_softreset(fe);
0420 
0421     return 0;
0422 }
0423 
0424 static int s5h1409_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
0425 {
0426     struct s5h1409_state *state = fe->demodulator_priv;
0427 
0428     dprintk("%s(%d)\n", __func__, enable);
0429 
0430     if (enable)
0431         return s5h1409_writereg(state, 0xf3, 1);
0432     else
0433         return s5h1409_writereg(state, 0xf3, 0);
0434 }
0435 
0436 static int s5h1409_set_gpio(struct dvb_frontend *fe, int enable)
0437 {
0438     struct s5h1409_state *state = fe->demodulator_priv;
0439 
0440     dprintk("%s(%d)\n", __func__, enable);
0441 
0442     if (enable)
0443         return s5h1409_writereg(state, 0xe3,
0444             s5h1409_readreg(state, 0xe3) | 0x1100);
0445     else
0446         return s5h1409_writereg(state, 0xe3,
0447             s5h1409_readreg(state, 0xe3) & 0xfeff);
0448 }
0449 
0450 static int s5h1409_sleep(struct dvb_frontend *fe, int enable)
0451 {
0452     struct s5h1409_state *state = fe->demodulator_priv;
0453 
0454     dprintk("%s(%d)\n", __func__, enable);
0455 
0456     return s5h1409_writereg(state, 0xf2, enable);
0457 }
0458 
0459 static int s5h1409_register_reset(struct dvb_frontend *fe)
0460 {
0461     struct s5h1409_state *state = fe->demodulator_priv;
0462 
0463     dprintk("%s()\n", __func__);
0464 
0465     return s5h1409_writereg(state, 0xfa, 0);
0466 }
0467 
0468 static void s5h1409_set_qam_amhum_mode(struct dvb_frontend *fe)
0469 {
0470     struct s5h1409_state *state = fe->demodulator_priv;
0471     u16 reg;
0472 
0473     if (state->qam_state < QAM_STATE_INTERLEAVE_SET) {
0474         /* We should not perform amhum optimization until
0475            the interleave mode has been configured */
0476         return;
0477     }
0478 
0479     if (state->qam_state == QAM_STATE_QAM_OPTIMIZED_L3) {
0480         /* We've already reached the maximum optimization level, so
0481            don't bother banging on the status registers */
0482         return;
0483     }
0484 
0485     /* QAM EQ lock check */
0486     reg = s5h1409_readreg(state, 0xf0);
0487 
0488     if ((reg >> 13) & 0x1) {
0489         reg &= 0xff;
0490 
0491         s5h1409_writereg(state, 0x96, 0x000c);
0492         if (reg < 0x68) {
0493             if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L3) {
0494                 dprintk("%s() setting QAM state to OPT_L3\n",
0495                     __func__);
0496                 s5h1409_writereg(state, 0x93, 0x3130);
0497                 s5h1409_writereg(state, 0x9e, 0x2836);
0498                 state->qam_state = QAM_STATE_QAM_OPTIMIZED_L3;
0499             }
0500         } else {
0501             if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L2) {
0502                 dprintk("%s() setting QAM state to OPT_L2\n",
0503                     __func__);
0504                 s5h1409_writereg(state, 0x93, 0x3332);
0505                 s5h1409_writereg(state, 0x9e, 0x2c37);
0506                 state->qam_state = QAM_STATE_QAM_OPTIMIZED_L2;
0507             }
0508         }
0509 
0510     } else {
0511         if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L1) {
0512             dprintk("%s() setting QAM state to OPT_L1\n", __func__);
0513             s5h1409_writereg(state, 0x96, 0x0008);
0514             s5h1409_writereg(state, 0x93, 0x3332);
0515             s5h1409_writereg(state, 0x9e, 0x2c37);
0516             state->qam_state = QAM_STATE_QAM_OPTIMIZED_L1;
0517         }
0518     }
0519 }
0520 
0521 static void s5h1409_set_qam_amhum_mode_legacy(struct dvb_frontend *fe)
0522 {
0523     struct s5h1409_state *state = fe->demodulator_priv;
0524     u16 reg;
0525 
0526     if (state->is_qam_locked)
0527         return;
0528 
0529     /* QAM EQ lock check */
0530     reg = s5h1409_readreg(state, 0xf0);
0531 
0532     if ((reg >> 13) & 0x1) {
0533 
0534         state->is_qam_locked = 1;
0535         reg &= 0xff;
0536 
0537         s5h1409_writereg(state, 0x96, 0x00c);
0538         if ((reg < 0x38) || (reg > 0x68)) {
0539             s5h1409_writereg(state, 0x93, 0x3332);
0540             s5h1409_writereg(state, 0x9e, 0x2c37);
0541         } else {
0542             s5h1409_writereg(state, 0x93, 0x3130);
0543             s5h1409_writereg(state, 0x9e, 0x2836);
0544         }
0545 
0546     } else {
0547         s5h1409_writereg(state, 0x96, 0x0008);
0548         s5h1409_writereg(state, 0x93, 0x3332);
0549         s5h1409_writereg(state, 0x9e, 0x2c37);
0550     }
0551 }
0552 
0553 static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe)
0554 {
0555     struct s5h1409_state *state = fe->demodulator_priv;
0556     u16 reg, reg1, reg2;
0557 
0558     if (state->qam_state >= QAM_STATE_INTERLEAVE_SET) {
0559         /* We've done the optimization already */
0560         return;
0561     }
0562 
0563     reg = s5h1409_readreg(state, 0xf1);
0564 
0565     /* Master lock */
0566     if ((reg >> 15) & 0x1) {
0567         if (state->qam_state == QAM_STATE_UNTUNED ||
0568             state->qam_state == QAM_STATE_TUNING_STARTED) {
0569             dprintk("%s() setting QAM state to INTERLEAVE_SET\n",
0570                 __func__);
0571             reg1 = s5h1409_readreg(state, 0xb2);
0572             reg2 = s5h1409_readreg(state, 0xad);
0573 
0574             s5h1409_writereg(state, 0x96, 0x0020);
0575             s5h1409_writereg(state, 0xad,
0576                 (((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)));
0577             state->qam_state = QAM_STATE_INTERLEAVE_SET;
0578         }
0579     } else {
0580         if (state->qam_state == QAM_STATE_UNTUNED) {
0581             dprintk("%s() setting QAM state to TUNING_STARTED\n",
0582                 __func__);
0583             s5h1409_writereg(state, 0x96, 0x08);
0584             s5h1409_writereg(state, 0xab,
0585                 s5h1409_readreg(state, 0xab) | 0x1001);
0586             state->qam_state = QAM_STATE_TUNING_STARTED;
0587         }
0588     }
0589 }
0590 
0591 static void s5h1409_set_qam_interleave_mode_legacy(struct dvb_frontend *fe)
0592 {
0593     struct s5h1409_state *state = fe->demodulator_priv;
0594     u16 reg, reg1, reg2;
0595 
0596     reg = s5h1409_readreg(state, 0xf1);
0597 
0598     /* Master lock */
0599     if ((reg >> 15) & 0x1) {
0600         if (state->qam_state != 2) {
0601             state->qam_state = 2;
0602             reg1 = s5h1409_readreg(state, 0xb2);
0603             reg2 = s5h1409_readreg(state, 0xad);
0604 
0605             s5h1409_writereg(state, 0x96, 0x20);
0606             s5h1409_writereg(state, 0xad,
0607                 (((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)));
0608             s5h1409_writereg(state, 0xab,
0609                 s5h1409_readreg(state, 0xab) & 0xeffe);
0610         }
0611     } else {
0612         if (state->qam_state != 1) {
0613             state->qam_state = 1;
0614             s5h1409_writereg(state, 0x96, 0x08);
0615             s5h1409_writereg(state, 0xab,
0616                 s5h1409_readreg(state, 0xab) | 0x1001);
0617         }
0618     }
0619 }
0620 
0621 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
0622 static int s5h1409_set_frontend(struct dvb_frontend *fe)
0623 {
0624     struct dtv_frontend_properties *p = &fe->dtv_property_cache;
0625     struct s5h1409_state *state = fe->demodulator_priv;
0626 
0627     dprintk("%s(frequency=%d)\n", __func__, p->frequency);
0628 
0629     s5h1409_softreset(fe);
0630 
0631     state->current_frequency = p->frequency;
0632 
0633     s5h1409_enable_modulation(fe, p->modulation);
0634 
0635     if (fe->ops.tuner_ops.set_params) {
0636         if (fe->ops.i2c_gate_ctrl)
0637             fe->ops.i2c_gate_ctrl(fe, 1);
0638         fe->ops.tuner_ops.set_params(fe);
0639         if (fe->ops.i2c_gate_ctrl)
0640             fe->ops.i2c_gate_ctrl(fe, 0);
0641     }
0642 
0643     /* Issue a reset to the demod so it knows to resync against the
0644        newly tuned frequency */
0645     s5h1409_softreset(fe);
0646 
0647     /* Optimize the demod for QAM */
0648     if (state->current_modulation != VSB_8) {
0649         /* This almost certainly applies to all boards, but for now
0650            only do it for the HVR-1600.  Once the other boards are
0651            tested, the "legacy" versions can just go away */
0652         if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) {
0653             s5h1409_set_qam_interleave_mode(fe);
0654             s5h1409_set_qam_amhum_mode(fe);
0655         } else {
0656             s5h1409_set_qam_amhum_mode_legacy(fe);
0657             s5h1409_set_qam_interleave_mode_legacy(fe);
0658         }
0659     }
0660 
0661     return 0;
0662 }
0663 
0664 static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode)
0665 {
0666     struct s5h1409_state *state = fe->demodulator_priv;
0667     u16 val;
0668 
0669     dprintk("%s(%d)\n", __func__, mode);
0670 
0671     val = s5h1409_readreg(state, 0xac) & 0xcfff;
0672     switch (mode) {
0673     case S5H1409_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK:
0674         val |= 0x0000;
0675         break;
0676     case S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK:
0677         dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode);
0678         val |= 0x1000;
0679         break;
0680     case S5H1409_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK:
0681         val |= 0x2000;
0682         break;
0683     case S5H1409_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK:
0684         val |= 0x3000;
0685         break;
0686     default:
0687         return -EINVAL;
0688     }
0689 
0690     /* Configure MPEG Signal Timing charactistics */
0691     return s5h1409_writereg(state, 0xac, val);
0692 }
0693 
0694 /* Reset the demod hardware and reset all of the configuration registers
0695    to a default state. */
0696 static int s5h1409_init(struct dvb_frontend *fe)
0697 {
0698     int i;
0699 
0700     struct s5h1409_state *state = fe->demodulator_priv;
0701     dprintk("%s()\n", __func__);
0702 
0703     s5h1409_sleep(fe, 0);
0704     s5h1409_register_reset(fe);
0705 
0706     for (i = 0; i < ARRAY_SIZE(init_tab); i++)
0707         s5h1409_writereg(state, init_tab[i].reg, init_tab[i].data);
0708 
0709     /* The datasheet says that after initialisation, VSB is default */
0710     state->current_modulation = VSB_8;
0711 
0712     /* Optimize for the HVR-1600 if appropriate.  Note that some of these
0713        may get folded into the generic case after testing with other
0714        devices */
0715     if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) {
0716         /* VSB AGC REF */
0717         s5h1409_writereg(state, 0x09, 0x0050);
0718 
0719         /* Unknown but Windows driver does it... */
0720         s5h1409_writereg(state, 0x21, 0x0001);
0721         s5h1409_writereg(state, 0x50, 0x030e);
0722 
0723         /* QAM AGC REF */
0724         s5h1409_writereg(state, 0x82, 0x0800);
0725     }
0726 
0727     if (state->config->output_mode == S5H1409_SERIAL_OUTPUT)
0728         s5h1409_writereg(state, 0xab,
0729             s5h1409_readreg(state, 0xab) | 0x100); /* Serial */
0730     else
0731         s5h1409_writereg(state, 0xab,
0732             s5h1409_readreg(state, 0xab) & 0xfeff); /* Parallel */
0733 
0734     s5h1409_set_spectralinversion(fe, state->config->inversion);
0735     s5h1409_set_if_freq(fe, state->if_freq);
0736     s5h1409_set_gpio(fe, state->config->gpio);
0737     s5h1409_set_mpeg_timing(fe, state->config->mpeg_timing);
0738     s5h1409_softreset(fe);
0739 
0740     /* Note: Leaving the I2C gate closed. */
0741     s5h1409_i2c_gate_ctrl(fe, 0);
0742 
0743     return 0;
0744 }
0745 
0746 static int s5h1409_read_status(struct dvb_frontend *fe, enum fe_status *status)
0747 {
0748     struct s5h1409_state *state = fe->demodulator_priv;
0749     u16 reg;
0750     u32 tuner_status = 0;
0751 
0752     *status = 0;
0753 
0754     /* Optimize the demod for QAM */
0755     if (state->current_modulation != VSB_8) {
0756         /* This almost certainly applies to all boards, but for now
0757            only do it for the HVR-1600.  Once the other boards are
0758            tested, the "legacy" versions can just go away */
0759         if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) {
0760             s5h1409_set_qam_interleave_mode(fe);
0761             s5h1409_set_qam_amhum_mode(fe);
0762         }
0763     }
0764 
0765     /* Get the demodulator status */
0766     reg = s5h1409_readreg(state, 0xf1);
0767     if (reg & 0x1000)
0768         *status |= FE_HAS_VITERBI;
0769     if (reg & 0x8000)
0770         *status |= FE_HAS_LOCK | FE_HAS_SYNC;
0771 
0772     switch (state->config->status_mode) {
0773     case S5H1409_DEMODLOCKING:
0774         if (*status & FE_HAS_VITERBI)
0775             *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
0776         break;
0777     case S5H1409_TUNERLOCKING:
0778         /* Get the tuner status */
0779         if (fe->ops.tuner_ops.get_status) {
0780             if (fe->ops.i2c_gate_ctrl)
0781                 fe->ops.i2c_gate_ctrl(fe, 1);
0782 
0783             fe->ops.tuner_ops.get_status(fe, &tuner_status);
0784 
0785             if (fe->ops.i2c_gate_ctrl)
0786                 fe->ops.i2c_gate_ctrl(fe, 0);
0787         }
0788         if (tuner_status)
0789             *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
0790         break;
0791     }
0792 
0793     dprintk("%s() status 0x%08x\n", __func__, *status);
0794 
0795     return 0;
0796 }
0797 
0798 static int s5h1409_qam256_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
0799 {
0800     int i, ret = -EINVAL;
0801     dprintk("%s()\n", __func__);
0802 
0803     for (i = 0; i < ARRAY_SIZE(qam256_snr_tab); i++) {
0804         if (v < qam256_snr_tab[i].val) {
0805             *snr = qam256_snr_tab[i].data;
0806             ret = 0;
0807             break;
0808         }
0809     }
0810     return ret;
0811 }
0812 
0813 static int s5h1409_qam64_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
0814 {
0815     int i, ret = -EINVAL;
0816     dprintk("%s()\n", __func__);
0817 
0818     for (i = 0; i < ARRAY_SIZE(qam64_snr_tab); i++) {
0819         if (v < qam64_snr_tab[i].val) {
0820             *snr = qam64_snr_tab[i].data;
0821             ret = 0;
0822             break;
0823         }
0824     }
0825     return ret;
0826 }
0827 
0828 static int s5h1409_vsb_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
0829 {
0830     int i, ret = -EINVAL;
0831     dprintk("%s()\n", __func__);
0832 
0833     for (i = 0; i < ARRAY_SIZE(vsb_snr_tab); i++) {
0834         if (v > vsb_snr_tab[i].val) {
0835             *snr = vsb_snr_tab[i].data;
0836             ret = 0;
0837             break;
0838         }
0839     }
0840     dprintk("%s() snr=%d\n", __func__, *snr);
0841     return ret;
0842 }
0843 
0844 static int s5h1409_read_snr(struct dvb_frontend *fe, u16 *snr)
0845 {
0846     struct s5h1409_state *state = fe->demodulator_priv;
0847     u16 reg;
0848     dprintk("%s()\n", __func__);
0849 
0850     switch (state->current_modulation) {
0851     case QAM_64:
0852         reg = s5h1409_readreg(state, 0xf0) & 0xff;
0853         return s5h1409_qam64_lookup_snr(fe, snr, reg);
0854     case QAM_256:
0855         reg = s5h1409_readreg(state, 0xf0) & 0xff;
0856         return s5h1409_qam256_lookup_snr(fe, snr, reg);
0857     case VSB_8:
0858         reg = s5h1409_readreg(state, 0xf1) & 0x3ff;
0859         return s5h1409_vsb_lookup_snr(fe, snr, reg);
0860     default:
0861         break;
0862     }
0863 
0864     return -EINVAL;
0865 }
0866 
0867 static int s5h1409_read_signal_strength(struct dvb_frontend *fe,
0868                     u16 *signal_strength)
0869 {
0870     /* borrowed from lgdt330x.c
0871      *
0872      * Calculate strength from SNR up to 35dB
0873      * Even though the SNR can go higher than 35dB,
0874      * there is some comfort factor in having a range of
0875      * strong signals that can show at 100%
0876      */
0877     u16 snr;
0878     u32 tmp;
0879     int ret = s5h1409_read_snr(fe, &snr);
0880 
0881     *signal_strength = 0;
0882 
0883     if (0 == ret) {
0884         /* The following calculation method was chosen
0885          * purely for the sake of code re-use from the
0886          * other demod drivers that use this method */
0887 
0888         /* Convert from SNR in dB * 10 to 8.24 fixed-point */
0889         tmp = (snr * ((1 << 24) / 10));
0890 
0891         /* Convert from 8.24 fixed-point to
0892          * scale the range 0 - 35*2^24 into 0 - 65535*/
0893         if (tmp >= 8960 * 0x10000)
0894             *signal_strength = 0xffff;
0895         else
0896             *signal_strength = tmp / 8960;
0897     }
0898 
0899     return ret;
0900 }
0901 
0902 static int s5h1409_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
0903 {
0904     struct s5h1409_state *state = fe->demodulator_priv;
0905 
0906     *ucblocks = s5h1409_readreg(state, 0xb5);
0907 
0908     return 0;
0909 }
0910 
0911 static int s5h1409_read_ber(struct dvb_frontend *fe, u32 *ber)
0912 {
0913     return s5h1409_read_ucblocks(fe, ber);
0914 }
0915 
0916 static int s5h1409_get_frontend(struct dvb_frontend *fe,
0917                 struct dtv_frontend_properties *p)
0918 {
0919     struct s5h1409_state *state = fe->demodulator_priv;
0920 
0921     p->frequency = state->current_frequency;
0922     p->modulation = state->current_modulation;
0923 
0924     return 0;
0925 }
0926 
0927 static int s5h1409_get_tune_settings(struct dvb_frontend *fe,
0928                      struct dvb_frontend_tune_settings *tune)
0929 {
0930     tune->min_delay_ms = 1000;
0931     return 0;
0932 }
0933 
0934 static void s5h1409_release(struct dvb_frontend *fe)
0935 {
0936     struct s5h1409_state *state = fe->demodulator_priv;
0937     kfree(state);
0938 }
0939 
0940 static const struct dvb_frontend_ops s5h1409_ops;
0941 
0942 struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config,
0943                     struct i2c_adapter *i2c)
0944 {
0945     struct s5h1409_state *state = NULL;
0946     u16 reg;
0947 
0948     /* allocate memory for the internal state */
0949     state = kzalloc(sizeof(struct s5h1409_state), GFP_KERNEL);
0950     if (state == NULL)
0951         goto error;
0952 
0953     /* setup the state */
0954     state->config = config;
0955     state->i2c = i2c;
0956     state->current_modulation = 0;
0957     state->if_freq = S5H1409_VSB_IF_FREQ;
0958 
0959     /* check if the demod exists */
0960     reg = s5h1409_readreg(state, 0x04);
0961     if ((reg != 0x0066) && (reg != 0x007f))
0962         goto error;
0963 
0964     /* create dvb_frontend */
0965     memcpy(&state->frontend.ops, &s5h1409_ops,
0966            sizeof(struct dvb_frontend_ops));
0967     state->frontend.demodulator_priv = state;
0968 
0969     if (s5h1409_init(&state->frontend) != 0) {
0970         printk(KERN_ERR "%s: Failed to initialize correctly\n",
0971             __func__);
0972         goto error;
0973     }
0974 
0975     /* Note: Leaving the I2C gate open here. */
0976     s5h1409_i2c_gate_ctrl(&state->frontend, 1);
0977 
0978     return &state->frontend;
0979 
0980 error:
0981     kfree(state);
0982     return NULL;
0983 }
0984 EXPORT_SYMBOL(s5h1409_attach);
0985 
0986 static const struct dvb_frontend_ops s5h1409_ops = {
0987     .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
0988     .info = {
0989         .name           = "Samsung S5H1409 QAM/8VSB Frontend",
0990         .frequency_min_hz   =  54 * MHz,
0991         .frequency_max_hz   = 858 * MHz,
0992         .frequency_stepsize_hz  = 62500,
0993         .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
0994     },
0995 
0996     .init                 = s5h1409_init,
0997     .i2c_gate_ctrl        = s5h1409_i2c_gate_ctrl,
0998     .set_frontend         = s5h1409_set_frontend,
0999     .get_frontend         = s5h1409_get_frontend,
1000     .get_tune_settings    = s5h1409_get_tune_settings,
1001     .read_status          = s5h1409_read_status,
1002     .read_ber             = s5h1409_read_ber,
1003     .read_signal_strength = s5h1409_read_signal_strength,
1004     .read_snr             = s5h1409_read_snr,
1005     .read_ucblocks        = s5h1409_read_ucblocks,
1006     .release              = s5h1409_release,
1007 };
1008 
1009 MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver");
1010 MODULE_AUTHOR("Steven Toth");
1011 MODULE_LICENSE("GPL");