root/drivers/media/dvb-frontends/s5h1411.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. s5h1411_writereg
  2. s5h1411_readreg
  3. s5h1411_softreset
  4. s5h1411_set_if_freq
  5. s5h1411_set_mpeg_timing
  6. s5h1411_set_spectralinversion
  7. s5h1411_set_serialmode
  8. s5h1411_enable_modulation
  9. s5h1411_i2c_gate_ctrl
  10. s5h1411_set_gpio
  11. s5h1411_set_powerstate
  12. s5h1411_sleep
  13. s5h1411_register_reset
  14. s5h1411_set_frontend
  15. s5h1411_init
  16. s5h1411_read_status
  17. s5h1411_qam256_lookup_snr
  18. s5h1411_qam64_lookup_snr
  19. s5h1411_vsb_lookup_snr
  20. s5h1411_read_snr
  21. s5h1411_read_signal_strength
  22. s5h1411_read_ucblocks
  23. s5h1411_read_ber
  24. s5h1411_get_frontend
  25. s5h1411_get_tune_settings
  26. s5h1411_release
  27. s5h1411_attach

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3     Samsung S5H1411 VSB/QAM demodulator driver
   4 
   5     Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
   6 
   7 
   8 */
   9 
  10 #include <linux/kernel.h>
  11 #include <linux/init.h>
  12 #include <linux/module.h>
  13 #include <linux/string.h>
  14 #include <linux/slab.h>
  15 #include <linux/delay.h>
  16 #include <media/dvb_frontend.h>
  17 #include "s5h1411.h"
  18 
  19 struct s5h1411_state {
  20 
  21         struct i2c_adapter *i2c;
  22 
  23         /* configuration settings */
  24         const struct s5h1411_config *config;
  25 
  26         struct dvb_frontend frontend;
  27 
  28         enum fe_modulation current_modulation;
  29         unsigned int first_tune:1;
  30 
  31         u32 current_frequency;
  32         int if_freq;
  33 
  34         u8 inversion;
  35 };
  36 
  37 static int debug;
  38 
  39 #define dprintk(arg...) do {    \
  40         if (debug)              \
  41                 printk(arg);    \
  42 } while (0)
  43 
  44 /* Register values to initialise the demod, defaults to VSB */
  45 static struct init_tab {
  46         u8      addr;
  47         u8      reg;
  48         u16     data;
  49 } init_tab[] = {
  50         { S5H1411_I2C_TOP_ADDR, 0x00, 0x0071, },
  51         { S5H1411_I2C_TOP_ADDR, 0x08, 0x0047, },
  52         { S5H1411_I2C_TOP_ADDR, 0x1c, 0x0400, },
  53         { S5H1411_I2C_TOP_ADDR, 0x1e, 0x0370, },
  54         { S5H1411_I2C_TOP_ADDR, 0x1f, 0x342c, },
  55         { S5H1411_I2C_TOP_ADDR, 0x24, 0x0231, },
  56         { S5H1411_I2C_TOP_ADDR, 0x25, 0x1011, },
  57         { S5H1411_I2C_TOP_ADDR, 0x26, 0x0f07, },
  58         { S5H1411_I2C_TOP_ADDR, 0x27, 0x0f04, },
  59         { S5H1411_I2C_TOP_ADDR, 0x28, 0x070f, },
  60         { S5H1411_I2C_TOP_ADDR, 0x29, 0x2820, },
  61         { S5H1411_I2C_TOP_ADDR, 0x2a, 0x102e, },
  62         { S5H1411_I2C_TOP_ADDR, 0x2b, 0x0220, },
  63         { S5H1411_I2C_TOP_ADDR, 0x2e, 0x0d0e, },
  64         { S5H1411_I2C_TOP_ADDR, 0x2f, 0x1013, },
  65         { S5H1411_I2C_TOP_ADDR, 0x31, 0x171b, },
  66         { S5H1411_I2C_TOP_ADDR, 0x32, 0x0e0f, },
  67         { S5H1411_I2C_TOP_ADDR, 0x33, 0x0f10, },
  68         { S5H1411_I2C_TOP_ADDR, 0x34, 0x170e, },
  69         { S5H1411_I2C_TOP_ADDR, 0x35, 0x4b10, },
  70         { S5H1411_I2C_TOP_ADDR, 0x36, 0x0f17, },
  71         { S5H1411_I2C_TOP_ADDR, 0x3c, 0x1577, },
  72         { S5H1411_I2C_TOP_ADDR, 0x3d, 0x081a, },
  73         { S5H1411_I2C_TOP_ADDR, 0x3e, 0x77ee, },
  74         { S5H1411_I2C_TOP_ADDR, 0x40, 0x1e09, },
  75         { S5H1411_I2C_TOP_ADDR, 0x41, 0x0f0c, },
  76         { S5H1411_I2C_TOP_ADDR, 0x42, 0x1f10, },
  77         { S5H1411_I2C_TOP_ADDR, 0x4d, 0x0509, },
  78         { S5H1411_I2C_TOP_ADDR, 0x4e, 0x0a00, },
  79         { S5H1411_I2C_TOP_ADDR, 0x50, 0x0000, },
  80         { S5H1411_I2C_TOP_ADDR, 0x5b, 0x0000, },
  81         { S5H1411_I2C_TOP_ADDR, 0x5c, 0x0008, },
  82         { S5H1411_I2C_TOP_ADDR, 0x57, 0x1101, },
  83         { S5H1411_I2C_TOP_ADDR, 0x65, 0x007c, },
  84         { S5H1411_I2C_TOP_ADDR, 0x68, 0x0512, },
  85         { S5H1411_I2C_TOP_ADDR, 0x69, 0x0258, },
  86         { S5H1411_I2C_TOP_ADDR, 0x70, 0x0004, },
  87         { S5H1411_I2C_TOP_ADDR, 0x71, 0x0007, },
  88         { S5H1411_I2C_TOP_ADDR, 0x76, 0x00a9, },
  89         { S5H1411_I2C_TOP_ADDR, 0x78, 0x3141, },
  90         { S5H1411_I2C_TOP_ADDR, 0x7a, 0x3141, },
  91         { S5H1411_I2C_TOP_ADDR, 0xb3, 0x8003, },
  92         { S5H1411_I2C_TOP_ADDR, 0xb5, 0xa6bb, },
  93         { S5H1411_I2C_TOP_ADDR, 0xb6, 0x0609, },
  94         { S5H1411_I2C_TOP_ADDR, 0xb7, 0x2f06, },
  95         { S5H1411_I2C_TOP_ADDR, 0xb8, 0x003f, },
  96         { S5H1411_I2C_TOP_ADDR, 0xb9, 0x2700, },
  97         { S5H1411_I2C_TOP_ADDR, 0xba, 0xfac8, },
  98         { S5H1411_I2C_TOP_ADDR, 0xbe, 0x1003, },
  99         { S5H1411_I2C_TOP_ADDR, 0xbf, 0x103f, },
 100         { S5H1411_I2C_TOP_ADDR, 0xce, 0x2000, },
 101         { S5H1411_I2C_TOP_ADDR, 0xcf, 0x0800, },
 102         { S5H1411_I2C_TOP_ADDR, 0xd0, 0x0800, },
 103         { S5H1411_I2C_TOP_ADDR, 0xd1, 0x0400, },
 104         { S5H1411_I2C_TOP_ADDR, 0xd2, 0x0800, },
 105         { S5H1411_I2C_TOP_ADDR, 0xd3, 0x2000, },
 106         { S5H1411_I2C_TOP_ADDR, 0xd4, 0x3000, },
 107         { S5H1411_I2C_TOP_ADDR, 0xdb, 0x4a9b, },
 108         { S5H1411_I2C_TOP_ADDR, 0xdc, 0x1000, },
 109         { S5H1411_I2C_TOP_ADDR, 0xde, 0x0001, },
 110         { S5H1411_I2C_TOP_ADDR, 0xdf, 0x0000, },
 111         { S5H1411_I2C_TOP_ADDR, 0xe3, 0x0301, },
 112         { S5H1411_I2C_QAM_ADDR, 0xf3, 0x0000, },
 113         { S5H1411_I2C_QAM_ADDR, 0xf3, 0x0001, },
 114         { S5H1411_I2C_QAM_ADDR, 0x08, 0x0600, },
 115         { S5H1411_I2C_QAM_ADDR, 0x18, 0x4201, },
 116         { S5H1411_I2C_QAM_ADDR, 0x1e, 0x6476, },
 117         { S5H1411_I2C_QAM_ADDR, 0x21, 0x0830, },
 118         { S5H1411_I2C_QAM_ADDR, 0x0c, 0x5679, },
 119         { S5H1411_I2C_QAM_ADDR, 0x0d, 0x579b, },
 120         { S5H1411_I2C_QAM_ADDR, 0x24, 0x0102, },
 121         { S5H1411_I2C_QAM_ADDR, 0x31, 0x7488, },
 122         { S5H1411_I2C_QAM_ADDR, 0x32, 0x0a08, },
 123         { S5H1411_I2C_QAM_ADDR, 0x3d, 0x8689, },
 124         { S5H1411_I2C_QAM_ADDR, 0x49, 0x0048, },
 125         { S5H1411_I2C_QAM_ADDR, 0x57, 0x2012, },
 126         { S5H1411_I2C_QAM_ADDR, 0x5d, 0x7676, },
 127         { S5H1411_I2C_QAM_ADDR, 0x04, 0x0400, },
 128         { S5H1411_I2C_QAM_ADDR, 0x58, 0x00c0, },
 129         { S5H1411_I2C_QAM_ADDR, 0x5b, 0x0100, },
 130 };
 131 
 132 /* VSB SNR lookup table */
 133 static struct vsb_snr_tab {
 134         u16     val;
 135         u16     data;
 136 } vsb_snr_tab[] = {
 137         {  0x39f, 300, },
 138         {  0x39b, 295, },
 139         {  0x397, 290, },
 140         {  0x394, 285, },
 141         {  0x38f, 280, },
 142         {  0x38b, 275, },
 143         {  0x387, 270, },
 144         {  0x382, 265, },
 145         {  0x37d, 260, },
 146         {  0x377, 255, },
 147         {  0x370, 250, },
 148         {  0x36a, 245, },
 149         {  0x364, 240, },
 150         {  0x35b, 235, },
 151         {  0x353, 230, },
 152         {  0x349, 225, },
 153         {  0x340, 320, },
 154         {  0x337, 215, },
 155         {  0x327, 210, },
 156         {  0x31b, 205, },
 157         {  0x310, 200, },
 158         {  0x302, 195, },
 159         {  0x2f3, 190, },
 160         {  0x2e4, 185, },
 161         {  0x2d7, 180, },
 162         {  0x2cd, 175, },
 163         {  0x2bb, 170, },
 164         {  0x2a9, 165, },
 165         {  0x29e, 160, },
 166         {  0x284, 155, },
 167         {  0x27a, 150, },
 168         {  0x260, 145, },
 169         {  0x23a, 140, },
 170         {  0x224, 135, },
 171         {  0x213, 130, },
 172         {  0x204, 125, },
 173         {  0x1fe, 120, },
 174         {      0,   0, },
 175 };
 176 
 177 /* QAM64 SNR lookup table */
 178 static struct qam64_snr_tab {
 179         u16     val;
 180         u16     data;
 181 } qam64_snr_tab[] = {
 182         {  0x0001,   0, },
 183         {  0x0af0, 300, },
 184         {  0x0d80, 290, },
 185         {  0x10a0, 280, },
 186         {  0x14b5, 270, },
 187         {  0x1590, 268, },
 188         {  0x1680, 266, },
 189         {  0x17b0, 264, },
 190         {  0x18c0, 262, },
 191         {  0x19b0, 260, },
 192         {  0x1ad0, 258, },
 193         {  0x1d00, 256, },
 194         {  0x1da0, 254, },
 195         {  0x1ef0, 252, },
 196         {  0x2050, 250, },
 197         {  0x20f0, 249, },
 198         {  0x21d0, 248, },
 199         {  0x22b0, 247, },
 200         {  0x23a0, 246, },
 201         {  0x2470, 245, },
 202         {  0x24f0, 244, },
 203         {  0x25a0, 243, },
 204         {  0x26c0, 242, },
 205         {  0x27b0, 241, },
 206         {  0x28d0, 240, },
 207         {  0x29b0, 239, },
 208         {  0x2ad0, 238, },
 209         {  0x2ba0, 237, },
 210         {  0x2c80, 236, },
 211         {  0x2d20, 235, },
 212         {  0x2e00, 234, },
 213         {  0x2f10, 233, },
 214         {  0x3050, 232, },
 215         {  0x3190, 231, },
 216         {  0x3300, 230, },
 217         {  0x3340, 229, },
 218         {  0x3200, 228, },
 219         {  0x3550, 227, },
 220         {  0x3610, 226, },
 221         {  0x3600, 225, },
 222         {  0x3700, 224, },
 223         {  0x3800, 223, },
 224         {  0x3920, 222, },
 225         {  0x3a20, 221, },
 226         {  0x3b30, 220, },
 227         {  0x3d00, 219, },
 228         {  0x3e00, 218, },
 229         {  0x4000, 217, },
 230         {  0x4100, 216, },
 231         {  0x4300, 215, },
 232         {  0x4400, 214, },
 233         {  0x4600, 213, },
 234         {  0x4700, 212, },
 235         {  0x4800, 211, },
 236         {  0x4a00, 210, },
 237         {  0x4b00, 209, },
 238         {  0x4d00, 208, },
 239         {  0x4f00, 207, },
 240         {  0x5050, 206, },
 241         {  0x5200, 205, },
 242         {  0x53c0, 204, },
 243         {  0x5450, 203, },
 244         {  0x5650, 202, },
 245         {  0x5820, 201, },
 246         {  0x6000, 200, },
 247         {  0xffff,   0, },
 248 };
 249 
 250 /* QAM256 SNR lookup table */
 251 static struct qam256_snr_tab {
 252         u16     val;
 253         u16     data;
 254 } qam256_snr_tab[] = {
 255         {  0x0001,   0, },
 256         {  0x0970, 400, },
 257         {  0x0a90, 390, },
 258         {  0x0b90, 380, },
 259         {  0x0d90, 370, },
 260         {  0x0ff0, 360, },
 261         {  0x1240, 350, },
 262         {  0x1345, 348, },
 263         {  0x13c0, 346, },
 264         {  0x14c0, 344, },
 265         {  0x1500, 342, },
 266         {  0x1610, 340, },
 267         {  0x1700, 338, },
 268         {  0x1800, 336, },
 269         {  0x18b0, 334, },
 270         {  0x1900, 332, },
 271         {  0x1ab0, 330, },
 272         {  0x1bc0, 328, },
 273         {  0x1cb0, 326, },
 274         {  0x1db0, 324, },
 275         {  0x1eb0, 322, },
 276         {  0x2030, 320, },
 277         {  0x2200, 318, },
 278         {  0x2280, 316, },
 279         {  0x2410, 314, },
 280         {  0x25b0, 312, },
 281         {  0x27a0, 310, },
 282         {  0x2840, 308, },
 283         {  0x29d0, 306, },
 284         {  0x2b10, 304, },
 285         {  0x2d30, 302, },
 286         {  0x2f20, 300, },
 287         {  0x30c0, 298, },
 288         {  0x3260, 297, },
 289         {  0x32c0, 296, },
 290         {  0x3300, 295, },
 291         {  0x33b0, 294, },
 292         {  0x34b0, 293, },
 293         {  0x35a0, 292, },
 294         {  0x3650, 291, },
 295         {  0x3800, 290, },
 296         {  0x3900, 289, },
 297         {  0x3a50, 288, },
 298         {  0x3b30, 287, },
 299         {  0x3cb0, 286, },
 300         {  0x3e20, 285, },
 301         {  0x3fa0, 284, },
 302         {  0x40a0, 283, },
 303         {  0x41c0, 282, },
 304         {  0x42f0, 281, },
 305         {  0x44a0, 280, },
 306         {  0x4600, 279, },
 307         {  0x47b0, 278, },
 308         {  0x4900, 277, },
 309         {  0x4a00, 276, },
 310         {  0x4ba0, 275, },
 311         {  0x4d00, 274, },
 312         {  0x4f00, 273, },
 313         {  0x5000, 272, },
 314         {  0x51f0, 272, },
 315         {  0x53a0, 270, },
 316         {  0x5520, 269, },
 317         {  0x5700, 268, },
 318         {  0x5800, 267, },
 319         {  0x5a00, 266, },
 320         {  0x5c00, 265, },
 321         {  0x5d00, 264, },
 322         {  0x5f00, 263, },
 323         {  0x6000, 262, },
 324         {  0x6200, 261, },
 325         {  0x6400, 260, },
 326         {  0xffff,   0, },
 327 };
 328 
 329 /* 8 bit registers, 16 bit values */
 330 static int s5h1411_writereg(struct s5h1411_state *state,
 331         u8 addr, u8 reg, u16 data)
 332 {
 333         int ret;
 334         u8 buf[] = { reg, data >> 8,  data & 0xff };
 335 
 336         struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
 337 
 338         ret = i2c_transfer(state->i2c, &msg, 1);
 339 
 340         if (ret != 1)
 341                 printk(KERN_ERR "%s: writereg error 0x%02x 0x%02x 0x%04x, ret == %i)\n",
 342                        __func__, addr, reg, data, ret);
 343 
 344         return (ret != 1) ? -1 : 0;
 345 }
 346 
 347 static u16 s5h1411_readreg(struct s5h1411_state *state, u8 addr, u8 reg)
 348 {
 349         int ret;
 350         u8 b0[] = { reg };
 351         u8 b1[] = { 0, 0 };
 352 
 353         struct i2c_msg msg[] = {
 354                 { .addr = addr, .flags = 0, .buf = b0, .len = 1 },
 355                 { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
 356 
 357         ret = i2c_transfer(state->i2c, msg, 2);
 358 
 359         if (ret != 2)
 360                 printk(KERN_ERR "%s: readreg error (ret == %i)\n",
 361                         __func__, ret);
 362         return (b1[0] << 8) | b1[1];
 363 }
 364 
 365 static int s5h1411_softreset(struct dvb_frontend *fe)
 366 {
 367         struct s5h1411_state *state = fe->demodulator_priv;
 368 
 369         dprintk("%s()\n", __func__);
 370 
 371         s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf7, 0);
 372         s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf7, 1);
 373         return 0;
 374 }
 375 
 376 static int s5h1411_set_if_freq(struct dvb_frontend *fe, int KHz)
 377 {
 378         struct s5h1411_state *state = fe->demodulator_priv;
 379 
 380         dprintk("%s(%d KHz)\n", __func__, KHz);
 381 
 382         switch (KHz) {
 383         case 3250:
 384                 s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x10d5);
 385                 s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x5342);
 386                 s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x10d9);
 387                 break;
 388         case 3500:
 389                 s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x1225);
 390                 s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x1e96);
 391                 s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x1225);
 392                 break;
 393         case 4000:
 394                 s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x14bc);
 395                 s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0xb53e);
 396                 s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x14bd);
 397                 break;
 398         default:
 399                 dprintk("%s(%d KHz) Invalid, defaulting to 5380\n",
 400                         __func__, KHz);
 401                 /* fall through */
 402         case 5380:
 403         case 44000:
 404                 s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x1be4);
 405                 s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x3655);
 406                 s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x1be4);
 407                 break;
 408         }
 409 
 410         state->if_freq = KHz;
 411 
 412         return 0;
 413 }
 414 
 415 static int s5h1411_set_mpeg_timing(struct dvb_frontend *fe, int mode)
 416 {
 417         struct s5h1411_state *state = fe->demodulator_priv;
 418         u16 val;
 419 
 420         dprintk("%s(%d)\n", __func__, mode);
 421 
 422         val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbe) & 0xcfff;
 423         switch (mode) {
 424         case S5H1411_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK:
 425                 val |= 0x0000;
 426                 break;
 427         case S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK:
 428                 dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode);
 429                 val |= 0x1000;
 430                 break;
 431         case S5H1411_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK:
 432                 val |= 0x2000;
 433                 break;
 434         case S5H1411_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK:
 435                 val |= 0x3000;
 436                 break;
 437         default:
 438                 return -EINVAL;
 439         }
 440 
 441         /* Configure MPEG Signal Timing charactistics */
 442         return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbe, val);
 443 }
 444 
 445 static int s5h1411_set_spectralinversion(struct dvb_frontend *fe, int inversion)
 446 {
 447         struct s5h1411_state *state = fe->demodulator_priv;
 448         u16 val;
 449 
 450         dprintk("%s(%d)\n", __func__, inversion);
 451         val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x24) & ~0x1000;
 452 
 453         if (inversion == 1)
 454                 val |= 0x1000; /* Inverted */
 455 
 456         state->inversion = inversion;
 457         return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x24, val);
 458 }
 459 
 460 static int s5h1411_set_serialmode(struct dvb_frontend *fe, int serial)
 461 {
 462         struct s5h1411_state *state = fe->demodulator_priv;
 463         u16 val;
 464 
 465         dprintk("%s(%d)\n", __func__, serial);
 466         val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbd) & ~0x100;
 467 
 468         if (serial == 1)
 469                 val |= 0x100;
 470 
 471         return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, val);
 472 }
 473 
 474 static int s5h1411_enable_modulation(struct dvb_frontend *fe,
 475                                      enum fe_modulation m)
 476 {
 477         struct s5h1411_state *state = fe->demodulator_priv;
 478 
 479         dprintk("%s(0x%08x)\n", __func__, m);
 480 
 481         if ((state->first_tune == 0) && (m == state->current_modulation)) {
 482                 dprintk("%s() Already at desired modulation.  Skipping...\n",
 483                         __func__);
 484                 return 0;
 485         }
 486 
 487         switch (m) {
 488         case VSB_8:
 489                 dprintk("%s() VSB_8\n", __func__);
 490                 s5h1411_set_if_freq(fe, state->config->vsb_if);
 491                 s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x71);
 492                 s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf6, 0x00);
 493                 s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xcd, 0xf1);
 494                 break;
 495         case QAM_64:
 496         case QAM_256:
 497         case QAM_AUTO:
 498                 dprintk("%s() QAM_AUTO (64/256)\n", __func__);
 499                 s5h1411_set_if_freq(fe, state->config->qam_if);
 500                 s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x0171);
 501                 s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf6, 0x0001);
 502                 s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x16, 0x1101);
 503                 s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xcd, 0x00f0);
 504                 break;
 505         default:
 506                 dprintk("%s() Invalid modulation\n", __func__);
 507                 return -EINVAL;
 508         }
 509 
 510         state->current_modulation = m;
 511         state->first_tune = 0;
 512         s5h1411_softreset(fe);
 513 
 514         return 0;
 515 }
 516 
 517 static int s5h1411_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 518 {
 519         struct s5h1411_state *state = fe->demodulator_priv;
 520 
 521         dprintk("%s(%d)\n", __func__, enable);
 522 
 523         if (enable)
 524                 return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1);
 525         else
 526                 return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 0);
 527 }
 528 
 529 static int s5h1411_set_gpio(struct dvb_frontend *fe, int enable)
 530 {
 531         struct s5h1411_state *state = fe->demodulator_priv;
 532         u16 val;
 533 
 534         dprintk("%s(%d)\n", __func__, enable);
 535 
 536         val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xe0) & ~0x02;
 537 
 538         if (enable)
 539                 return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0,
 540                                 val | 0x02);
 541         else
 542                 return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0, val);
 543 }
 544 
 545 static int s5h1411_set_powerstate(struct dvb_frontend *fe, int enable)
 546 {
 547         struct s5h1411_state *state = fe->demodulator_priv;
 548 
 549         dprintk("%s(%d)\n", __func__, enable);
 550 
 551         if (enable)
 552                 s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf4, 1);
 553         else {
 554                 s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf4, 0);
 555                 s5h1411_softreset(fe);
 556         }
 557 
 558         return 0;
 559 }
 560 
 561 static int s5h1411_sleep(struct dvb_frontend *fe)
 562 {
 563         return s5h1411_set_powerstate(fe, 1);
 564 }
 565 
 566 static int s5h1411_register_reset(struct dvb_frontend *fe)
 567 {
 568         struct s5h1411_state *state = fe->demodulator_priv;
 569 
 570         dprintk("%s()\n", __func__);
 571 
 572         return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf3, 0);
 573 }
 574 
 575 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
 576 static int s5h1411_set_frontend(struct dvb_frontend *fe)
 577 {
 578         struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 579         struct s5h1411_state *state = fe->demodulator_priv;
 580 
 581         dprintk("%s(frequency=%d)\n", __func__, p->frequency);
 582 
 583         s5h1411_softreset(fe);
 584 
 585         state->current_frequency = p->frequency;
 586 
 587         s5h1411_enable_modulation(fe, p->modulation);
 588 
 589         if (fe->ops.tuner_ops.set_params) {
 590                 if (fe->ops.i2c_gate_ctrl)
 591                         fe->ops.i2c_gate_ctrl(fe, 1);
 592 
 593                 fe->ops.tuner_ops.set_params(fe);
 594 
 595                 if (fe->ops.i2c_gate_ctrl)
 596                         fe->ops.i2c_gate_ctrl(fe, 0);
 597         }
 598 
 599         /* Issue a reset to the demod so it knows to resync against the
 600            newly tuned frequency */
 601         s5h1411_softreset(fe);
 602 
 603         return 0;
 604 }
 605 
 606 /* Reset the demod hardware and reset all of the configuration registers
 607    to a default state. */
 608 static int s5h1411_init(struct dvb_frontend *fe)
 609 {
 610         struct s5h1411_state *state = fe->demodulator_priv;
 611         int i;
 612 
 613         dprintk("%s()\n", __func__);
 614 
 615         s5h1411_set_powerstate(fe, 0);
 616         s5h1411_register_reset(fe);
 617 
 618         for (i = 0; i < ARRAY_SIZE(init_tab); i++)
 619                 s5h1411_writereg(state, init_tab[i].addr,
 620                         init_tab[i].reg,
 621                         init_tab[i].data);
 622 
 623         /* The datasheet says that after initialisation, VSB is default */
 624         state->current_modulation = VSB_8;
 625 
 626         /* Although the datasheet says it's in VSB, empirical evidence
 627            shows problems getting lock on the first tuning request.  Make
 628            sure we call enable_modulation the first time around */
 629         state->first_tune = 1;
 630 
 631         if (state->config->output_mode == S5H1411_SERIAL_OUTPUT)
 632                 /* Serial */
 633                 s5h1411_set_serialmode(fe, 1);
 634         else
 635                 /* Parallel */
 636                 s5h1411_set_serialmode(fe, 0);
 637 
 638         s5h1411_set_spectralinversion(fe, state->config->inversion);
 639         s5h1411_set_if_freq(fe, state->config->vsb_if);
 640         s5h1411_set_gpio(fe, state->config->gpio);
 641         s5h1411_set_mpeg_timing(fe, state->config->mpeg_timing);
 642         s5h1411_softreset(fe);
 643 
 644         /* Note: Leaving the I2C gate closed. */
 645         s5h1411_i2c_gate_ctrl(fe, 0);
 646 
 647         return 0;
 648 }
 649 
 650 static int s5h1411_read_status(struct dvb_frontend *fe, enum fe_status *status)
 651 {
 652         struct s5h1411_state *state = fe->demodulator_priv;
 653         u16 reg;
 654         u32 tuner_status = 0;
 655 
 656         *status = 0;
 657 
 658         /* Register F2 bit 15 = Master Lock, removed */
 659 
 660         switch (state->current_modulation) {
 661         case QAM_64:
 662         case QAM_256:
 663                 reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf0);
 664                 if (reg & 0x10) /* QAM FEC Lock */
 665                         *status |= FE_HAS_SYNC | FE_HAS_LOCK;
 666                 if (reg & 0x100) /* QAM EQ Lock */
 667                         *status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL;
 668 
 669                 break;
 670         case VSB_8:
 671                 reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf2);
 672                 if (reg & 0x1000) /* FEC Lock */
 673                         *status |= FE_HAS_SYNC | FE_HAS_LOCK;
 674                 if (reg & 0x2000) /* EQ Lock */
 675                         *status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL;
 676 
 677                 reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x53);
 678                 if (reg & 0x1) /* AFC Lock */
 679                         *status |= FE_HAS_SIGNAL;
 680 
 681                 break;
 682         default:
 683                 return -EINVAL;
 684         }
 685 
 686         switch (state->config->status_mode) {
 687         case S5H1411_DEMODLOCKING:
 688                 if (*status & FE_HAS_VITERBI)
 689                         *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
 690                 break;
 691         case S5H1411_TUNERLOCKING:
 692                 /* Get the tuner status */
 693                 if (fe->ops.tuner_ops.get_status) {
 694                         if (fe->ops.i2c_gate_ctrl)
 695                                 fe->ops.i2c_gate_ctrl(fe, 1);
 696 
 697                         fe->ops.tuner_ops.get_status(fe, &tuner_status);
 698 
 699                         if (fe->ops.i2c_gate_ctrl)
 700                                 fe->ops.i2c_gate_ctrl(fe, 0);
 701                 }
 702                 if (tuner_status)
 703                         *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
 704                 break;
 705         }
 706 
 707         dprintk("%s() status 0x%08x\n", __func__, *status);
 708 
 709         return 0;
 710 }
 711 
 712 static int s5h1411_qam256_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
 713 {
 714         int i, ret = -EINVAL;
 715         dprintk("%s()\n", __func__);
 716 
 717         for (i = 0; i < ARRAY_SIZE(qam256_snr_tab); i++) {
 718                 if (v < qam256_snr_tab[i].val) {
 719                         *snr = qam256_snr_tab[i].data;
 720                         ret = 0;
 721                         break;
 722                 }
 723         }
 724         return ret;
 725 }
 726 
 727 static int s5h1411_qam64_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
 728 {
 729         int i, ret = -EINVAL;
 730         dprintk("%s()\n", __func__);
 731 
 732         for (i = 0; i < ARRAY_SIZE(qam64_snr_tab); i++) {
 733                 if (v < qam64_snr_tab[i].val) {
 734                         *snr = qam64_snr_tab[i].data;
 735                         ret = 0;
 736                         break;
 737                 }
 738         }
 739         return ret;
 740 }
 741 
 742 static int s5h1411_vsb_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
 743 {
 744         int i, ret = -EINVAL;
 745         dprintk("%s()\n", __func__);
 746 
 747         for (i = 0; i < ARRAY_SIZE(vsb_snr_tab); i++) {
 748                 if (v > vsb_snr_tab[i].val) {
 749                         *snr = vsb_snr_tab[i].data;
 750                         ret = 0;
 751                         break;
 752                 }
 753         }
 754         dprintk("%s() snr=%d\n", __func__, *snr);
 755         return ret;
 756 }
 757 
 758 static int s5h1411_read_snr(struct dvb_frontend *fe, u16 *snr)
 759 {
 760         struct s5h1411_state *state = fe->demodulator_priv;
 761         u16 reg;
 762         dprintk("%s()\n", __func__);
 763 
 764         switch (state->current_modulation) {
 765         case QAM_64:
 766                 reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf1);
 767                 return s5h1411_qam64_lookup_snr(fe, snr, reg);
 768         case QAM_256:
 769                 reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf1);
 770                 return s5h1411_qam256_lookup_snr(fe, snr, reg);
 771         case VSB_8:
 772                 reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR,
 773                         0xf2) & 0x3ff;
 774                 return s5h1411_vsb_lookup_snr(fe, snr, reg);
 775         default:
 776                 break;
 777         }
 778 
 779         return -EINVAL;
 780 }
 781 
 782 static int s5h1411_read_signal_strength(struct dvb_frontend *fe,
 783         u16 *signal_strength)
 784 {
 785         /* borrowed from lgdt330x.c
 786          *
 787          * Calculate strength from SNR up to 35dB
 788          * Even though the SNR can go higher than 35dB,
 789          * there is some comfort factor in having a range of
 790          * strong signals that can show at 100%
 791          */
 792         u16 snr;
 793         u32 tmp;
 794         int ret = s5h1411_read_snr(fe, &snr);
 795 
 796         *signal_strength = 0;
 797 
 798         if (0 == ret) {
 799                 /* The following calculation method was chosen
 800                  * purely for the sake of code re-use from the
 801                  * other demod drivers that use this method */
 802 
 803                 /* Convert from SNR in dB * 10 to 8.24 fixed-point */
 804                 tmp = (snr * ((1 << 24) / 10));
 805 
 806                 /* Convert from 8.24 fixed-point to
 807                  * scale the range 0 - 35*2^24 into 0 - 65535*/
 808                 if (tmp >= 8960 * 0x10000)
 809                         *signal_strength = 0xffff;
 810                 else
 811                         *signal_strength = tmp / 8960;
 812         }
 813 
 814         return ret;
 815 }
 816 
 817 static int s5h1411_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 818 {
 819         struct s5h1411_state *state = fe->demodulator_priv;
 820 
 821         *ucblocks = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xc9);
 822 
 823         return 0;
 824 }
 825 
 826 static int s5h1411_read_ber(struct dvb_frontend *fe, u32 *ber)
 827 {
 828         return s5h1411_read_ucblocks(fe, ber);
 829 }
 830 
 831 static int s5h1411_get_frontend(struct dvb_frontend *fe,
 832                                 struct dtv_frontend_properties *p)
 833 {
 834         struct s5h1411_state *state = fe->demodulator_priv;
 835 
 836         p->frequency = state->current_frequency;
 837         p->modulation = state->current_modulation;
 838 
 839         return 0;
 840 }
 841 
 842 static int s5h1411_get_tune_settings(struct dvb_frontend *fe,
 843                                      struct dvb_frontend_tune_settings *tune)
 844 {
 845         tune->min_delay_ms = 1000;
 846         return 0;
 847 }
 848 
 849 static void s5h1411_release(struct dvb_frontend *fe)
 850 {
 851         struct s5h1411_state *state = fe->demodulator_priv;
 852         kfree(state);
 853 }
 854 
 855 static const struct dvb_frontend_ops s5h1411_ops;
 856 
 857 struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config,
 858                                     struct i2c_adapter *i2c)
 859 {
 860         struct s5h1411_state *state = NULL;
 861         u16 reg;
 862 
 863         /* allocate memory for the internal state */
 864         state = kzalloc(sizeof(struct s5h1411_state), GFP_KERNEL);
 865         if (state == NULL)
 866                 goto error;
 867 
 868         /* setup the state */
 869         state->config = config;
 870         state->i2c = i2c;
 871         state->current_modulation = VSB_8;
 872         state->inversion = state->config->inversion;
 873 
 874         /* check if the demod exists */
 875         reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x05);
 876         if (reg != 0x0066)
 877                 goto error;
 878 
 879         /* create dvb_frontend */
 880         memcpy(&state->frontend.ops, &s5h1411_ops,
 881                sizeof(struct dvb_frontend_ops));
 882 
 883         state->frontend.demodulator_priv = state;
 884 
 885         if (s5h1411_init(&state->frontend) != 0) {
 886                 printk(KERN_ERR "%s: Failed to initialize correctly\n",
 887                         __func__);
 888                 goto error;
 889         }
 890 
 891         /* Note: Leaving the I2C gate open here. */
 892         s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1);
 893 
 894         /* Put the device into low-power mode until first use */
 895         s5h1411_set_powerstate(&state->frontend, 1);
 896 
 897         return &state->frontend;
 898 
 899 error:
 900         kfree(state);
 901         return NULL;
 902 }
 903 EXPORT_SYMBOL(s5h1411_attach);
 904 
 905 static const struct dvb_frontend_ops s5h1411_ops = {
 906         .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
 907         .info = {
 908                 .name                   = "Samsung S5H1411 QAM/8VSB Frontend",
 909                 .frequency_min_hz       =  54 * MHz,
 910                 .frequency_max_hz       = 858 * MHz,
 911                 .frequency_stepsize_hz  = 62500,
 912                 .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
 913         },
 914 
 915         .init                 = s5h1411_init,
 916         .sleep                = s5h1411_sleep,
 917         .i2c_gate_ctrl        = s5h1411_i2c_gate_ctrl,
 918         .set_frontend         = s5h1411_set_frontend,
 919         .get_frontend         = s5h1411_get_frontend,
 920         .get_tune_settings    = s5h1411_get_tune_settings,
 921         .read_status          = s5h1411_read_status,
 922         .read_ber             = s5h1411_read_ber,
 923         .read_signal_strength = s5h1411_read_signal_strength,
 924         .read_snr             = s5h1411_read_snr,
 925         .read_ucblocks        = s5h1411_read_ucblocks,
 926         .release              = s5h1411_release,
 927 };
 928 
 929 module_param(debug, int, 0644);
 930 MODULE_PARM_DESC(debug, "Enable verbose debug messages");
 931 
 932 MODULE_DESCRIPTION("Samsung S5H1411 QAM-B/ATSC Demodulator driver");
 933 MODULE_AUTHOR("Steven Toth");
 934 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */