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

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

DEFINITIONS

This source file includes following definitions.
  1. cx24110_writereg
  2. cx24110_readreg
  3. cx24110_set_inversion
  4. cx24110_set_fec
  5. cx24110_get_fec
  6. cx24110_set_symbolrate
  7. _cx24110_pll_write
  8. cx24110_initfe
  9. cx24110_set_voltage
  10. cx24110_diseqc_send_burst
  11. cx24110_send_diseqc_msg
  12. cx24110_read_status
  13. cx24110_read_ber
  14. cx24110_read_signal_strength
  15. cx24110_read_snr
  16. cx24110_read_ucblocks
  17. cx24110_set_frontend
  18. cx24110_get_frontend
  19. cx24110_set_tone
  20. cx24110_release
  21. cx24110_attach

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3     cx24110 - Single Chip Satellite Channel Receiver driver module
   4 
   5     Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> based on
   6     work
   7     Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
   8 
   9 
  10 */
  11 
  12 #include <linux/slab.h>
  13 #include <linux/kernel.h>
  14 #include <linux/module.h>
  15 #include <linux/init.h>
  16 
  17 #include <media/dvb_frontend.h>
  18 #include "cx24110.h"
  19 
  20 
  21 struct cx24110_state {
  22 
  23         struct i2c_adapter* i2c;
  24 
  25         const struct cx24110_config* config;
  26 
  27         struct dvb_frontend frontend;
  28 
  29         u32 lastber;
  30         u32 lastbler;
  31         u32 lastesn0;
  32 };
  33 
  34 static int debug;
  35 #define dprintk(args...) \
  36         do { \
  37                 if (debug) printk(KERN_DEBUG "cx24110: " args); \
  38         } while (0)
  39 
  40 static struct {u8 reg; u8 data;} cx24110_regdata[]=
  41                       /* Comments beginning with @ denote this value should
  42                          be the default */
  43         {{0x09,0x01}, /* SoftResetAll */
  44          {0x09,0x00}, /* release reset */
  45          {0x01,0xe8}, /* MSB of code rate 27.5MS/s */
  46          {0x02,0x17}, /* middle byte " */
  47          {0x03,0x29}, /* LSB         " */
  48          {0x05,0x03}, /* @ DVB mode, standard code rate 3/4 */
  49          {0x06,0xa5}, /* @ PLL 60MHz */
  50          {0x07,0x01}, /* @ Fclk, i.e. sampling clock, 60MHz */
  51          {0x0a,0x00}, /* @ partial chip disables, do not set */
  52          {0x0b,0x01}, /* set output clock in gapped mode, start signal low
  53                          active for first byte */
  54          {0x0c,0x11}, /* no parity bytes, large hold time, serial data out */
  55          {0x0d,0x6f}, /* @ RS Sync/Unsync thresholds */
  56          {0x10,0x40}, /* chip doc is misleading here: write bit 6 as 1
  57                          to avoid starting the BER counter. Reset the
  58                          CRC test bit. Finite counting selected */
  59          {0x15,0xff}, /* @ size of the limited time window for RS BER
  60                          estimation. It is <value>*256 RS blocks, this
  61                          gives approx. 2.6 sec at 27.5MS/s, rate 3/4 */
  62          {0x16,0x00}, /* @ enable all RS output ports */
  63          {0x17,0x04}, /* @ time window allowed for the RS to sync */
  64          {0x18,0xae}, /* @ allow all standard DVB code rates to be scanned
  65                          for automatically */
  66                       /* leave the current code rate and normalization
  67                          registers as they are after reset... */
  68          {0x21,0x10}, /* @ during AutoAcq, search each viterbi setting
  69                          only once */
  70          {0x23,0x18}, /* @ size of the limited time window for Viterbi BER
  71                          estimation. It is <value>*65536 channel bits, i.e.
  72                          approx. 38ms at 27.5MS/s, rate 3/4 */
  73          {0x24,0x24}, /* do not trigger Viterbi CRC test. Finite count window */
  74                       /* leave front-end AGC parameters at default values */
  75                       /* leave decimation AGC parameters at default values */
  76          {0x35,0x40}, /* disable all interrupts. They are not connected anyway */
  77          {0x36,0xff}, /* clear all interrupt pending flags */
  78          {0x37,0x00}, /* @ fully enable AutoAcqq state machine */
  79          {0x38,0x07}, /* @ enable fade recovery, but not autostart AutoAcq */
  80                       /* leave the equalizer parameters on their default values */
  81                       /* leave the final AGC parameters on their default values */
  82          {0x41,0x00}, /* @ MSB of front-end derotator frequency */
  83          {0x42,0x00}, /* @ middle bytes " */
  84          {0x43,0x00}, /* @ LSB          " */
  85                       /* leave the carrier tracking loop parameters on default */
  86                       /* leave the bit timing loop parameters at default */
  87          {0x56,0x4d}, /* set the filtune voltage to 2.7V, as recommended by */
  88                       /* the cx24108 data sheet for symbol rates above 15MS/s */
  89          {0x57,0x00}, /* @ Filter sigma delta enabled, positive */
  90          {0x61,0x95}, /* GPIO pins 1-4 have special function */
  91          {0x62,0x05}, /* GPIO pin 5 has special function, pin 6 is GPIO */
  92          {0x63,0x00}, /* All GPIO pins use CMOS output characteristics */
  93          {0x64,0x20}, /* GPIO 6 is input, all others are outputs */
  94          {0x6d,0x30}, /* tuner auto mode clock freq 62kHz */
  95          {0x70,0x15}, /* use auto mode, tuner word is 21 bits long */
  96          {0x73,0x00}, /* @ disable several demod bypasses */
  97          {0x74,0x00}, /* @  " */
  98          {0x75,0x00}  /* @  " */
  99                       /* the remaining registers are for SEC */
 100         };
 101 
 102 
 103 static int cx24110_writereg (struct cx24110_state* state, int reg, int data)
 104 {
 105         u8 buf [] = { reg, data };
 106         struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
 107         int err;
 108 
 109         if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
 110                 dprintk("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n",
 111                         __func__, err, reg, data);
 112                 return -EREMOTEIO;
 113         }
 114 
 115         return 0;
 116 }
 117 
 118 static int cx24110_readreg (struct cx24110_state* state, u8 reg)
 119 {
 120         int ret;
 121         u8 b0 [] = { reg };
 122         u8 b1 [] = { 0 };
 123         struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
 124                            { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
 125 
 126         ret = i2c_transfer(state->i2c, msg, 2);
 127 
 128         if (ret != 2) return ret;
 129 
 130         return b1[0];
 131 }
 132 
 133 static int cx24110_set_inversion(struct cx24110_state *state,
 134                                  enum fe_spectral_inversion inversion)
 135 {
 136 /* fixme (low): error handling */
 137 
 138         switch (inversion) {
 139         case INVERSION_OFF:
 140                 cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1);
 141                 /* AcqSpectrInvDis on. No idea why someone should want this */
 142                 cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)&0xf7);
 143                 /* Initial value 0 at start of acq */
 144                 cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)&0xef);
 145                 /* current value 0 */
 146                 /* The cx24110 manual tells us this reg is read-only.
 147                    But what the heck... set it ayways */
 148                 break;
 149         case INVERSION_ON:
 150                 cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1);
 151                 /* AcqSpectrInvDis on. No idea why someone should want this */
 152                 cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)|0x08);
 153                 /* Initial value 1 at start of acq */
 154                 cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)|0x10);
 155                 /* current value 1 */
 156                 break;
 157         case INVERSION_AUTO:
 158                 cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)&0xfe);
 159                 /* AcqSpectrInvDis off. Leave initial & current states as is */
 160                 break;
 161         default:
 162                 return -EINVAL;
 163         }
 164 
 165         return 0;
 166 }
 167 
 168 static int cx24110_set_fec(struct cx24110_state *state, enum fe_code_rate fec)
 169 {
 170         static const int rate[FEC_AUTO] = {-1,    1,    2,    3,    5,    7, -1};
 171         static const int g1[FEC_AUTO]   = {-1, 0x01, 0x02, 0x05, 0x15, 0x45, -1};
 172         static const int g2[FEC_AUTO]   = {-1, 0x01, 0x03, 0x06, 0x1a, 0x7a, -1};
 173 
 174         /* Well, the AutoAcq engine of the cx24106 and 24110 automatically
 175            searches all enabled viterbi rates, and can handle non-standard
 176            rates as well. */
 177 
 178         if (fec > FEC_AUTO)
 179                 fec = FEC_AUTO;
 180 
 181         if (fec == FEC_AUTO) { /* (re-)establish AutoAcq behaviour */
 182                 cx24110_writereg(state, 0x37, cx24110_readreg(state, 0x37) & 0xdf);
 183                 /* clear AcqVitDis bit */
 184                 cx24110_writereg(state, 0x18, 0xae);
 185                 /* allow all DVB standard code rates */
 186                 cx24110_writereg(state, 0x05, (cx24110_readreg(state, 0x05) & 0xf0) | 0x3);
 187                 /* set nominal Viterbi rate 3/4 */
 188                 cx24110_writereg(state, 0x22, (cx24110_readreg(state, 0x22) & 0xf0) | 0x3);
 189                 /* set current Viterbi rate 3/4 */
 190                 cx24110_writereg(state, 0x1a, 0x05);
 191                 cx24110_writereg(state, 0x1b, 0x06);
 192                 /* set the puncture registers for code rate 3/4 */
 193                 return 0;
 194         } else {
 195                 cx24110_writereg(state, 0x37, cx24110_readreg(state, 0x37) | 0x20);
 196                 /* set AcqVitDis bit */
 197                 if (rate[fec] < 0)
 198                         return -EINVAL;
 199 
 200                 cx24110_writereg(state, 0x05, (cx24110_readreg(state, 0x05) & 0xf0) | rate[fec]);
 201                 /* set nominal Viterbi rate */
 202                 cx24110_writereg(state, 0x22, (cx24110_readreg(state, 0x22) & 0xf0) | rate[fec]);
 203                 /* set current Viterbi rate */
 204                 cx24110_writereg(state, 0x1a, g1[fec]);
 205                 cx24110_writereg(state, 0x1b, g2[fec]);
 206                 /* not sure if this is the right way: I always used AutoAcq mode */
 207         }
 208         return 0;
 209 }
 210 
 211 static enum fe_code_rate cx24110_get_fec(struct cx24110_state *state)
 212 {
 213         int i;
 214 
 215         i=cx24110_readreg(state,0x22)&0x0f;
 216         if(!(i&0x08)) {
 217                 return FEC_1_2 + i - 1;
 218         } else {
 219 /* fixme (low): a special code rate has been selected. In theory, we need to
 220    return a denominator value, a numerator value, and a pair of puncture
 221    maps to correctly describe this mode. But this should never happen in
 222    practice, because it cannot be set by cx24110_get_fec. */
 223            return FEC_NONE;
 224         }
 225 }
 226 
 227 static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
 228 {
 229 /* fixme (low): add error handling */
 230         u32 ratio;
 231         u32 tmp, fclk, BDRI;
 232 
 233         static const u32 bands[]={5000000UL,15000000UL,90999000UL/2};
 234         int i;
 235 
 236         dprintk("cx24110 debug: entering %s(%d)\n",__func__,srate);
 237         if (srate>90999000UL/2)
 238                 srate=90999000UL/2;
 239         if (srate<500000)
 240                 srate=500000;
 241 
 242         for(i = 0; (i < ARRAY_SIZE(bands)) && (srate>bands[i]); i++)
 243                 ;
 244         /* first, check which sample rate is appropriate: 45, 60 80 or 90 MHz,
 245            and set the PLL accordingly (R07[1:0] Fclk, R06[7:4] PLLmult,
 246            R06[3:0] PLLphaseDetGain */
 247         tmp=cx24110_readreg(state,0x07)&0xfc;
 248         if(srate<90999000UL/4) { /* sample rate 45MHz*/
 249                 cx24110_writereg(state,0x07,tmp);
 250                 cx24110_writereg(state,0x06,0x78);
 251                 fclk=90999000UL/2;
 252         } else if(srate<60666000UL/2) { /* sample rate 60MHz */
 253                 cx24110_writereg(state,0x07,tmp|0x1);
 254                 cx24110_writereg(state,0x06,0xa5);
 255                 fclk=60666000UL;
 256         } else if(srate<80888000UL/2) { /* sample rate 80MHz */
 257                 cx24110_writereg(state,0x07,tmp|0x2);
 258                 cx24110_writereg(state,0x06,0x87);
 259                 fclk=80888000UL;
 260         } else { /* sample rate 90MHz */
 261                 cx24110_writereg(state,0x07,tmp|0x3);
 262                 cx24110_writereg(state,0x06,0x78);
 263                 fclk=90999000UL;
 264         }
 265         dprintk("cx24110 debug: fclk %d Hz\n",fclk);
 266         /* we need to divide two integers with approx. 27 bits in 32 bit
 267            arithmetic giving a 25 bit result */
 268         /* the maximum dividend is 90999000/2, 0x02b6446c, this number is
 269            also the most complex divisor. Hence, the dividend has,
 270            assuming 32bit unsigned arithmetic, 6 clear bits on top, the
 271            divisor 2 unused bits at the bottom. Also, the quotient is
 272            always less than 1/2. Borrowed from VES1893.c, of course */
 273 
 274         tmp=srate<<6;
 275         BDRI=fclk>>2;
 276         ratio=(tmp/BDRI);
 277 
 278         tmp=(tmp%BDRI)<<8;
 279         ratio=(ratio<<8)+(tmp/BDRI);
 280 
 281         tmp=(tmp%BDRI)<<8;
 282         ratio=(ratio<<8)+(tmp/BDRI);
 283 
 284         tmp=(tmp%BDRI)<<1;
 285         ratio=(ratio<<1)+(tmp/BDRI);
 286 
 287         dprintk("srate= %d (range %d, up to %d)\n", srate,i,bands[i]);
 288         dprintk("fclk = %d\n", fclk);
 289         dprintk("ratio= %08x\n", ratio);
 290 
 291         cx24110_writereg(state, 0x1, (ratio>>16)&0xff);
 292         cx24110_writereg(state, 0x2, (ratio>>8)&0xff);
 293         cx24110_writereg(state, 0x3, (ratio)&0xff);
 294 
 295         return 0;
 296 
 297 }
 298 
 299 static int _cx24110_pll_write (struct dvb_frontend* fe, const u8 buf[], int len)
 300 {
 301         struct cx24110_state *state = fe->demodulator_priv;
 302 
 303         if (len != 3)
 304                 return -EINVAL;
 305 
 306 /* tuner data is 21 bits long, must be left-aligned in data */
 307 /* tuner cx24108 is written through a dedicated 3wire interface on the demod chip */
 308 /* FIXME (low): add error handling, avoid infinite loops if HW fails... */
 309 
 310         cx24110_writereg(state,0x6d,0x30); /* auto mode at 62kHz */
 311         cx24110_writereg(state,0x70,0x15); /* auto mode 21 bits */
 312 
 313         /* if the auto tuner writer is still busy, clear it out */
 314         while (cx24110_readreg(state,0x6d)&0x80)
 315                 cx24110_writereg(state,0x72,0);
 316 
 317         /* write the topmost 8 bits */
 318         cx24110_writereg(state,0x72,buf[0]);
 319 
 320         /* wait for the send to be completed */
 321         while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
 322                 ;
 323 
 324         /* send another 8 bytes */
 325         cx24110_writereg(state,0x72,buf[1]);
 326         while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
 327                 ;
 328 
 329         /* and the topmost 5 bits of this byte */
 330         cx24110_writereg(state,0x72,buf[2]);
 331         while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
 332                 ;
 333 
 334         /* now strobe the enable line once */
 335         cx24110_writereg(state,0x6d,0x32);
 336         cx24110_writereg(state,0x6d,0x30);
 337 
 338         return 0;
 339 }
 340 
 341 static int cx24110_initfe(struct dvb_frontend* fe)
 342 {
 343         struct cx24110_state *state = fe->demodulator_priv;
 344 /* fixme (low): error handling */
 345         int i;
 346 
 347         dprintk("%s: init chip\n", __func__);
 348 
 349         for(i = 0; i < ARRAY_SIZE(cx24110_regdata); i++) {
 350                 cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data);
 351         }
 352 
 353         return 0;
 354 }
 355 
 356 static int cx24110_set_voltage(struct dvb_frontend *fe,
 357                                enum fe_sec_voltage voltage)
 358 {
 359         struct cx24110_state *state = fe->demodulator_priv;
 360 
 361         switch (voltage) {
 362         case SEC_VOLTAGE_13:
 363                 return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0xc0);
 364         case SEC_VOLTAGE_18:
 365                 return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0x40);
 366         default:
 367                 return -EINVAL;
 368         }
 369 }
 370 
 371 static int cx24110_diseqc_send_burst(struct dvb_frontend *fe,
 372                                      enum fe_sec_mini_cmd burst)
 373 {
 374         int rv, bit;
 375         struct cx24110_state *state = fe->demodulator_priv;
 376         unsigned long timeout;
 377 
 378         if (burst == SEC_MINI_A)
 379                 bit = 0x00;
 380         else if (burst == SEC_MINI_B)
 381                 bit = 0x08;
 382         else
 383                 return -EINVAL;
 384 
 385         rv = cx24110_readreg(state, 0x77);
 386         if (!(rv & 0x04))
 387                 cx24110_writereg(state, 0x77, rv | 0x04);
 388 
 389         rv = cx24110_readreg(state, 0x76);
 390         cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40 | bit));
 391         timeout = jiffies + msecs_to_jiffies(100);
 392         while (!time_after(jiffies, timeout) && !(cx24110_readreg(state, 0x76) & 0x40))
 393                 ; /* wait for LNB ready */
 394 
 395         return 0;
 396 }
 397 
 398 static int cx24110_send_diseqc_msg(struct dvb_frontend* fe,
 399                                    struct dvb_diseqc_master_cmd *cmd)
 400 {
 401         int i, rv;
 402         struct cx24110_state *state = fe->demodulator_priv;
 403         unsigned long timeout;
 404 
 405         if (cmd->msg_len < 3 || cmd->msg_len > 6)
 406                 return -EINVAL;  /* not implemented */
 407 
 408         for (i = 0; i < cmd->msg_len; i++)
 409                 cx24110_writereg(state, 0x79 + i, cmd->msg[i]);
 410 
 411         rv = cx24110_readreg(state, 0x77);
 412         if (rv & 0x04) {
 413                 cx24110_writereg(state, 0x77, rv & ~0x04);
 414                 msleep(30); /* reportedly fixes switching problems */
 415         }
 416 
 417         rv = cx24110_readreg(state, 0x76);
 418 
 419         cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40) | ((cmd->msg_len-3) & 3));
 420         timeout = jiffies + msecs_to_jiffies(100);
 421         while (!time_after(jiffies, timeout) && !(cx24110_readreg(state, 0x76) & 0x40))
 422                 ; /* wait for LNB ready */
 423 
 424         return 0;
 425 }
 426 
 427 static int cx24110_read_status(struct dvb_frontend *fe,
 428                                enum fe_status *status)
 429 {
 430         struct cx24110_state *state = fe->demodulator_priv;
 431 
 432         int sync = cx24110_readreg (state, 0x55);
 433 
 434         *status = 0;
 435 
 436         if (sync & 0x10)
 437                 *status |= FE_HAS_SIGNAL;
 438 
 439         if (sync & 0x08)
 440                 *status |= FE_HAS_CARRIER;
 441 
 442         sync = cx24110_readreg (state, 0x08);
 443 
 444         if (sync & 0x40)
 445                 *status |= FE_HAS_VITERBI;
 446 
 447         if (sync & 0x20)
 448                 *status |= FE_HAS_SYNC;
 449 
 450         if ((sync & 0x60) == 0x60)
 451                 *status |= FE_HAS_LOCK;
 452 
 453         return 0;
 454 }
 455 
 456 static int cx24110_read_ber(struct dvb_frontend* fe, u32* ber)
 457 {
 458         struct cx24110_state *state = fe->demodulator_priv;
 459 
 460         /* fixme (maybe): value range is 16 bit. Scale? */
 461         if(cx24110_readreg(state,0x24)&0x10) {
 462                 /* the Viterbi error counter has finished one counting window */
 463                 cx24110_writereg(state,0x24,0x04); /* select the ber reg */
 464                 state->lastber=cx24110_readreg(state,0x25)|
 465                         (cx24110_readreg(state,0x26)<<8);
 466                 cx24110_writereg(state,0x24,0x04); /* start new count window */
 467                 cx24110_writereg(state,0x24,0x14);
 468         }
 469         *ber = state->lastber;
 470 
 471         return 0;
 472 }
 473 
 474 static int cx24110_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
 475 {
 476         struct cx24110_state *state = fe->demodulator_priv;
 477 
 478 /* no provision in hardware. Read the frontend AGC accumulator. No idea how to scale this, but I know it is 2s complement */
 479         u8 signal = cx24110_readreg (state, 0x27)+128;
 480         *signal_strength = (signal << 8) | signal;
 481 
 482         return 0;
 483 }
 484 
 485 static int cx24110_read_snr(struct dvb_frontend* fe, u16* snr)
 486 {
 487         struct cx24110_state *state = fe->demodulator_priv;
 488 
 489         /* no provision in hardware. Can be computed from the Es/N0 estimator, but I don't know how. */
 490         if(cx24110_readreg(state,0x6a)&0x80) {
 491                 /* the Es/N0 error counter has finished one counting window */
 492                 state->lastesn0=cx24110_readreg(state,0x69)|
 493                         (cx24110_readreg(state,0x68)<<8);
 494                 cx24110_writereg(state,0x6a,0x84); /* start new count window */
 495         }
 496         *snr = state->lastesn0;
 497 
 498         return 0;
 499 }
 500 
 501 static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
 502 {
 503         struct cx24110_state *state = fe->demodulator_priv;
 504 
 505         if(cx24110_readreg(state,0x10)&0x40) {
 506                 /* the RS error counter has finished one counting window */
 507                 cx24110_writereg(state,0x10,0x60); /* select the byer reg */
 508                 (void)(cx24110_readreg(state, 0x12) |
 509                         (cx24110_readreg(state, 0x13) << 8) |
 510                         (cx24110_readreg(state, 0x14) << 16));
 511                 cx24110_writereg(state,0x10,0x70); /* select the bler reg */
 512                 state->lastbler=cx24110_readreg(state,0x12)|
 513                         (cx24110_readreg(state,0x13)<<8)|
 514                         (cx24110_readreg(state,0x14)<<16);
 515                 cx24110_writereg(state,0x10,0x20); /* start new count window */
 516         }
 517         *ucblocks = state->lastbler;
 518 
 519         return 0;
 520 }
 521 
 522 static int cx24110_set_frontend(struct dvb_frontend *fe)
 523 {
 524         struct cx24110_state *state = fe->demodulator_priv;
 525         struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 526 
 527         if (fe->ops.tuner_ops.set_params) {
 528                 fe->ops.tuner_ops.set_params(fe);
 529                 if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
 530         }
 531 
 532         cx24110_set_inversion(state, p->inversion);
 533         cx24110_set_fec(state, p->fec_inner);
 534         cx24110_set_symbolrate(state, p->symbol_rate);
 535         cx24110_writereg(state,0x04,0x05); /* start acquisition */
 536 
 537         return 0;
 538 }
 539 
 540 static int cx24110_get_frontend(struct dvb_frontend *fe,
 541                                 struct dtv_frontend_properties *p)
 542 {
 543         struct cx24110_state *state = fe->demodulator_priv;
 544         s32 afc; unsigned sclk;
 545 
 546 /* cannot read back tuner settings (freq). Need to have some private storage */
 547 
 548         sclk = cx24110_readreg (state, 0x07) & 0x03;
 549 /* ok, real AFC (FEDR) freq. is afc/2^24*fsamp, fsamp=45/60/80/90MHz.
 550  * Need 64 bit arithmetic. Is thiss possible in the kernel? */
 551         if (sclk==0) sclk=90999000L/2L;
 552         else if (sclk==1) sclk=60666000L;
 553         else if (sclk==2) sclk=80888000L;
 554         else sclk=90999000L;
 555         sclk>>=8;
 556         afc = sclk*(cx24110_readreg (state, 0x44)&0x1f)+
 557               ((sclk*cx24110_readreg (state, 0x45))>>8)+
 558               ((sclk*cx24110_readreg (state, 0x46))>>16);
 559 
 560         p->frequency += afc;
 561         p->inversion = (cx24110_readreg (state, 0x22) & 0x10) ?
 562                                 INVERSION_ON : INVERSION_OFF;
 563         p->fec_inner = cx24110_get_fec(state);
 564 
 565         return 0;
 566 }
 567 
 568 static int cx24110_set_tone(struct dvb_frontend *fe,
 569                             enum fe_sec_tone_mode tone)
 570 {
 571         struct cx24110_state *state = fe->demodulator_priv;
 572 
 573         return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&~0x10)|(((tone==SEC_TONE_ON))?0x10:0));
 574 }
 575 
 576 static void cx24110_release(struct dvb_frontend* fe)
 577 {
 578         struct cx24110_state* state = fe->demodulator_priv;
 579         kfree(state);
 580 }
 581 
 582 static const struct dvb_frontend_ops cx24110_ops;
 583 
 584 struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
 585                                     struct i2c_adapter* i2c)
 586 {
 587         struct cx24110_state* state = NULL;
 588         int ret;
 589 
 590         /* allocate memory for the internal state */
 591         state = kzalloc(sizeof(struct cx24110_state), GFP_KERNEL);
 592         if (state == NULL) goto error;
 593 
 594         /* setup the state */
 595         state->config = config;
 596         state->i2c = i2c;
 597         state->lastber = 0;
 598         state->lastbler = 0;
 599         state->lastesn0 = 0;
 600 
 601         /* check if the demod is there */
 602         ret = cx24110_readreg(state, 0x00);
 603         if ((ret != 0x5a) && (ret != 0x69)) goto error;
 604 
 605         /* create dvb_frontend */
 606         memcpy(&state->frontend.ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
 607         state->frontend.demodulator_priv = state;
 608         return &state->frontend;
 609 
 610 error:
 611         kfree(state);
 612         return NULL;
 613 }
 614 
 615 static const struct dvb_frontend_ops cx24110_ops = {
 616         .delsys = { SYS_DVBS },
 617         .info = {
 618                 .name = "Conexant CX24110 DVB-S",
 619                 .frequency_min_hz =  950 * MHz,
 620                 .frequency_max_hz = 2150 * MHz,
 621                 .frequency_stepsize_hz = 1011 * kHz,
 622                 .frequency_tolerance_hz = 29500 * kHz,
 623                 .symbol_rate_min = 1000000,
 624                 .symbol_rate_max = 45000000,
 625                 .caps = FE_CAN_INVERSION_AUTO |
 626                         FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
 627                         FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
 628                         FE_CAN_QPSK | FE_CAN_RECOVER
 629         },
 630 
 631         .release = cx24110_release,
 632 
 633         .init = cx24110_initfe,
 634         .write = _cx24110_pll_write,
 635         .set_frontend = cx24110_set_frontend,
 636         .get_frontend = cx24110_get_frontend,
 637         .read_status = cx24110_read_status,
 638         .read_ber = cx24110_read_ber,
 639         .read_signal_strength = cx24110_read_signal_strength,
 640         .read_snr = cx24110_read_snr,
 641         .read_ucblocks = cx24110_read_ucblocks,
 642 
 643         .diseqc_send_master_cmd = cx24110_send_diseqc_msg,
 644         .set_tone = cx24110_set_tone,
 645         .set_voltage = cx24110_set_voltage,
 646         .diseqc_send_burst = cx24110_diseqc_send_burst,
 647 };
 648 
 649 module_param(debug, int, 0644);
 650 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 651 
 652 MODULE_DESCRIPTION("Conexant CX24110 DVB-S Demodulator driver");
 653 MODULE_AUTHOR("Peter Hettkamp");
 654 MODULE_LICENSE("GPL");
 655 
 656 EXPORT_SYMBOL(cx24110_attach);

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