This source file includes following definitions.
- cx24110_writereg
- cx24110_readreg
- cx24110_set_inversion
- cx24110_set_fec
- cx24110_get_fec
- cx24110_set_symbolrate
- _cx24110_pll_write
- cx24110_initfe
- cx24110_set_voltage
- cx24110_diseqc_send_burst
- cx24110_send_diseqc_msg
- cx24110_read_status
- cx24110_read_ber
- cx24110_read_signal_strength
- cx24110_read_snr
- cx24110_read_ucblocks
- cx24110_set_frontend
- cx24110_get_frontend
- cx24110_set_tone
- cx24110_release
- cx24110_attach
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   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                       
  42 
  43         {{0x09,0x01}, 
  44          {0x09,0x00}, 
  45          {0x01,0xe8}, 
  46          {0x02,0x17}, 
  47          {0x03,0x29}, 
  48          {0x05,0x03}, 
  49          {0x06,0xa5}, 
  50          {0x07,0x01}, 
  51          {0x0a,0x00}, 
  52          {0x0b,0x01}, 
  53 
  54          {0x0c,0x11}, 
  55          {0x0d,0x6f}, 
  56          {0x10,0x40}, 
  57 
  58 
  59          {0x15,0xff}, 
  60 
  61 
  62          {0x16,0x00}, 
  63          {0x17,0x04}, 
  64          {0x18,0xae}, 
  65 
  66                       
  67 
  68          {0x21,0x10}, 
  69 
  70          {0x23,0x18}, 
  71 
  72 
  73          {0x24,0x24}, 
  74                       
  75                       
  76          {0x35,0x40}, 
  77          {0x36,0xff}, 
  78          {0x37,0x00}, 
  79          {0x38,0x07}, 
  80                       
  81                       
  82          {0x41,0x00}, 
  83          {0x42,0x00}, 
  84          {0x43,0x00}, 
  85                       
  86                       
  87          {0x56,0x4d}, 
  88                       
  89          {0x57,0x00}, 
  90          {0x61,0x95}, 
  91          {0x62,0x05}, 
  92          {0x63,0x00}, 
  93          {0x64,0x20}, 
  94          {0x6d,0x30}, 
  95          {0x70,0x15}, 
  96          {0x73,0x00}, 
  97          {0x74,0x00}, 
  98          {0x75,0x00}  
  99                       
 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 
 137 
 138         switch (inversion) {
 139         case INVERSION_OFF:
 140                 cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1);
 141                 
 142                 cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)&0xf7);
 143                 
 144                 cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)&0xef);
 145                 
 146                 
 147 
 148                 break;
 149         case INVERSION_ON:
 150                 cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1);
 151                 
 152                 cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)|0x08);
 153                 
 154                 cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)|0x10);
 155                 
 156                 break;
 157         case INVERSION_AUTO:
 158                 cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)&0xfe);
 159                 
 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         
 175 
 176 
 177 
 178         if (fec > FEC_AUTO)
 179                 fec = FEC_AUTO;
 180 
 181         if (fec == FEC_AUTO) { 
 182                 cx24110_writereg(state, 0x37, cx24110_readreg(state, 0x37) & 0xdf);
 183                 
 184                 cx24110_writereg(state, 0x18, 0xae);
 185                 
 186                 cx24110_writereg(state, 0x05, (cx24110_readreg(state, 0x05) & 0xf0) | 0x3);
 187                 
 188                 cx24110_writereg(state, 0x22, (cx24110_readreg(state, 0x22) & 0xf0) | 0x3);
 189                 
 190                 cx24110_writereg(state, 0x1a, 0x05);
 191                 cx24110_writereg(state, 0x1b, 0x06);
 192                 
 193                 return 0;
 194         } else {
 195                 cx24110_writereg(state, 0x37, cx24110_readreg(state, 0x37) | 0x20);
 196                 
 197                 if (rate[fec] < 0)
 198                         return -EINVAL;
 199 
 200                 cx24110_writereg(state, 0x05, (cx24110_readreg(state, 0x05) & 0xf0) | rate[fec]);
 201                 
 202                 cx24110_writereg(state, 0x22, (cx24110_readreg(state, 0x22) & 0xf0) | rate[fec]);
 203                 
 204                 cx24110_writereg(state, 0x1a, g1[fec]);
 205                 cx24110_writereg(state, 0x1b, g2[fec]);
 206                 
 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 
 220 
 221 
 222 
 223            return FEC_NONE;
 224         }
 225 }
 226 
 227 static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
 228 {
 229 
 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         
 245 
 246 
 247         tmp=cx24110_readreg(state,0x07)&0xfc;
 248         if(srate<90999000UL/4) { 
 249                 cx24110_writereg(state,0x07,tmp);
 250                 cx24110_writereg(state,0x06,0x78);
 251                 fclk=90999000UL/2;
 252         } else if(srate<60666000UL/2) { 
 253                 cx24110_writereg(state,0x07,tmp|0x1);
 254                 cx24110_writereg(state,0x06,0xa5);
 255                 fclk=60666000UL;
 256         } else if(srate<80888000UL/2) { 
 257                 cx24110_writereg(state,0x07,tmp|0x2);
 258                 cx24110_writereg(state,0x06,0x87);
 259                 fclk=80888000UL;
 260         } else { 
 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         
 267 
 268         
 269 
 270 
 271 
 272 
 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 
 307 
 308 
 309 
 310         cx24110_writereg(state,0x6d,0x30); 
 311         cx24110_writereg(state,0x70,0x15); 
 312 
 313         
 314         while (cx24110_readreg(state,0x6d)&0x80)
 315                 cx24110_writereg(state,0x72,0);
 316 
 317         
 318         cx24110_writereg(state,0x72,buf[0]);
 319 
 320         
 321         while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
 322                 ;
 323 
 324         
 325         cx24110_writereg(state,0x72,buf[1]);
 326         while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
 327                 ;
 328 
 329         
 330         cx24110_writereg(state,0x72,buf[2]);
 331         while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
 332                 ;
 333 
 334         
 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 
 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                 ; 
 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;  
 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); 
 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                 ; 
 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         
 461         if(cx24110_readreg(state,0x24)&0x10) {
 462                 
 463                 cx24110_writereg(state,0x24,0x04); 
 464                 state->lastber=cx24110_readreg(state,0x25)|
 465                         (cx24110_readreg(state,0x26)<<8);
 466                 cx24110_writereg(state,0x24,0x04); 
 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 
 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         
 490         if(cx24110_readreg(state,0x6a)&0x80) {
 491                 
 492                 state->lastesn0=cx24110_readreg(state,0x69)|
 493                         (cx24110_readreg(state,0x68)<<8);
 494                 cx24110_writereg(state,0x6a,0x84); 
 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                 
 507                 cx24110_writereg(state,0x10,0x60); 
 508                 (void)(cx24110_readreg(state, 0x12) |
 509                         (cx24110_readreg(state, 0x13) << 8) |
 510                         (cx24110_readreg(state, 0x14) << 16));
 511                 cx24110_writereg(state,0x10,0x70); 
 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); 
 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); 
 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 
 547 
 548         sclk = cx24110_readreg (state, 0x07) & 0x03;
 549 
 550 
 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         
 591         state = kzalloc(sizeof(struct cx24110_state), GFP_KERNEL);
 592         if (state == NULL) goto error;
 593 
 594         
 595         state->config = config;
 596         state->i2c = i2c;
 597         state->lastber = 0;
 598         state->lastbler = 0;
 599         state->lastesn0 = 0;
 600 
 601         
 602         ret = cx24110_readreg(state, 0x00);
 603         if ((ret != 0x5a) && (ret != 0x69)) goto error;
 604 
 605         
 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);