0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/slab.h>
0013 #include <linux/kernel.h>
0014 #include <linux/module.h>
0015 #include <linux/init.h>
0016
0017 #include <media/dvb_frontend.h>
0018 #include "cx24110.h"
0019
0020
0021 struct cx24110_state {
0022
0023 struct i2c_adapter* i2c;
0024
0025 const struct cx24110_config* config;
0026
0027 struct dvb_frontend frontend;
0028
0029 u32 lastber;
0030 u32 lastbler;
0031 u32 lastesn0;
0032 };
0033
0034 static int debug;
0035 #define dprintk(args...) \
0036 do { \
0037 if (debug) printk(KERN_DEBUG "cx24110: " args); \
0038 } while (0)
0039
0040 static struct {u8 reg; u8 data;} cx24110_regdata[]=
0041
0042
0043 {{0x09,0x01},
0044 {0x09,0x00},
0045 {0x01,0xe8},
0046 {0x02,0x17},
0047 {0x03,0x29},
0048 {0x05,0x03},
0049 {0x06,0xa5},
0050 {0x07,0x01},
0051 {0x0a,0x00},
0052 {0x0b,0x01},
0053
0054 {0x0c,0x11},
0055 {0x0d,0x6f},
0056 {0x10,0x40},
0057
0058
0059 {0x15,0xff},
0060
0061
0062 {0x16,0x00},
0063 {0x17,0x04},
0064 {0x18,0xae},
0065
0066
0067
0068 {0x21,0x10},
0069
0070 {0x23,0x18},
0071
0072
0073 {0x24,0x24},
0074
0075
0076 {0x35,0x40},
0077 {0x36,0xff},
0078 {0x37,0x00},
0079 {0x38,0x07},
0080
0081
0082 {0x41,0x00},
0083 {0x42,0x00},
0084 {0x43,0x00},
0085
0086
0087 {0x56,0x4d},
0088
0089 {0x57,0x00},
0090 {0x61,0x95},
0091 {0x62,0x05},
0092 {0x63,0x00},
0093 {0x64,0x20},
0094 {0x6d,0x30},
0095 {0x70,0x15},
0096 {0x73,0x00},
0097 {0x74,0x00},
0098 {0x75,0x00}
0099
0100 };
0101
0102
0103 static int cx24110_writereg (struct cx24110_state* state, int reg, int data)
0104 {
0105 u8 buf [] = { reg, data };
0106 struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
0107 int err;
0108
0109 if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
0110 dprintk("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n",
0111 __func__, err, reg, data);
0112 return -EREMOTEIO;
0113 }
0114
0115 return 0;
0116 }
0117
0118 static int cx24110_readreg (struct cx24110_state* state, u8 reg)
0119 {
0120 int ret;
0121 u8 b0 [] = { reg };
0122 u8 b1 [] = { 0 };
0123 struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
0124 { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
0125
0126 ret = i2c_transfer(state->i2c, msg, 2);
0127
0128 if (ret != 2) return ret;
0129
0130 return b1[0];
0131 }
0132
0133 static int cx24110_set_inversion(struct cx24110_state *state,
0134 enum fe_spectral_inversion inversion)
0135 {
0136
0137
0138 switch (inversion) {
0139 case INVERSION_OFF:
0140 cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1);
0141
0142 cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)&0xf7);
0143
0144 cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)&0xef);
0145
0146
0147
0148 break;
0149 case INVERSION_ON:
0150 cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1);
0151
0152 cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)|0x08);
0153
0154 cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)|0x10);
0155
0156 break;
0157 case INVERSION_AUTO:
0158 cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)&0xfe);
0159
0160 break;
0161 default:
0162 return -EINVAL;
0163 }
0164
0165 return 0;
0166 }
0167
0168 static int cx24110_set_fec(struct cx24110_state *state, enum fe_code_rate fec)
0169 {
0170 static const int rate[FEC_AUTO] = {-1, 1, 2, 3, 5, 7, -1};
0171 static const int g1[FEC_AUTO] = {-1, 0x01, 0x02, 0x05, 0x15, 0x45, -1};
0172 static const int g2[FEC_AUTO] = {-1, 0x01, 0x03, 0x06, 0x1a, 0x7a, -1};
0173
0174
0175
0176
0177
0178 if (fec > FEC_AUTO)
0179 fec = FEC_AUTO;
0180
0181 if (fec == FEC_AUTO) {
0182 cx24110_writereg(state, 0x37, cx24110_readreg(state, 0x37) & 0xdf);
0183
0184 cx24110_writereg(state, 0x18, 0xae);
0185
0186 cx24110_writereg(state, 0x05, (cx24110_readreg(state, 0x05) & 0xf0) | 0x3);
0187
0188 cx24110_writereg(state, 0x22, (cx24110_readreg(state, 0x22) & 0xf0) | 0x3);
0189
0190 cx24110_writereg(state, 0x1a, 0x05);
0191 cx24110_writereg(state, 0x1b, 0x06);
0192
0193 return 0;
0194 } else {
0195 cx24110_writereg(state, 0x37, cx24110_readreg(state, 0x37) | 0x20);
0196
0197 if (rate[fec] < 0)
0198 return -EINVAL;
0199
0200 cx24110_writereg(state, 0x05, (cx24110_readreg(state, 0x05) & 0xf0) | rate[fec]);
0201
0202 cx24110_writereg(state, 0x22, (cx24110_readreg(state, 0x22) & 0xf0) | rate[fec]);
0203
0204 cx24110_writereg(state, 0x1a, g1[fec]);
0205 cx24110_writereg(state, 0x1b, g2[fec]);
0206
0207 }
0208 return 0;
0209 }
0210
0211 static enum fe_code_rate cx24110_get_fec(struct cx24110_state *state)
0212 {
0213 int i;
0214
0215 i=cx24110_readreg(state,0x22)&0x0f;
0216 if(!(i&0x08)) {
0217 return FEC_1_2 + i - 1;
0218 } else {
0219
0220
0221
0222
0223 return FEC_NONE;
0224 }
0225 }
0226
0227 static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
0228 {
0229
0230 u32 ratio;
0231 u32 tmp, fclk, BDRI;
0232
0233 static const u32 bands[]={5000000UL,15000000UL,90999000UL/2};
0234 int i;
0235
0236 dprintk("cx24110 debug: entering %s(%d)\n",__func__,srate);
0237 if (srate>90999000UL/2)
0238 srate=90999000UL/2;
0239 if (srate<500000)
0240 srate=500000;
0241
0242 for(i = 0; (i < ARRAY_SIZE(bands)) && (srate>bands[i]); i++)
0243 ;
0244
0245
0246
0247 tmp=cx24110_readreg(state,0x07)&0xfc;
0248 if(srate<90999000UL/4) {
0249 cx24110_writereg(state,0x07,tmp);
0250 cx24110_writereg(state,0x06,0x78);
0251 fclk=90999000UL/2;
0252 } else if(srate<60666000UL/2) {
0253 cx24110_writereg(state,0x07,tmp|0x1);
0254 cx24110_writereg(state,0x06,0xa5);
0255 fclk=60666000UL;
0256 } else if(srate<80888000UL/2) {
0257 cx24110_writereg(state,0x07,tmp|0x2);
0258 cx24110_writereg(state,0x06,0x87);
0259 fclk=80888000UL;
0260 } else {
0261 cx24110_writereg(state,0x07,tmp|0x3);
0262 cx24110_writereg(state,0x06,0x78);
0263 fclk=90999000UL;
0264 }
0265 dprintk("cx24110 debug: fclk %d Hz\n",fclk);
0266
0267
0268
0269
0270
0271
0272
0273
0274 tmp=srate<<6;
0275 BDRI=fclk>>2;
0276 ratio=(tmp/BDRI);
0277
0278 tmp=(tmp%BDRI)<<8;
0279 ratio=(ratio<<8)+(tmp/BDRI);
0280
0281 tmp=(tmp%BDRI)<<8;
0282 ratio=(ratio<<8)+(tmp/BDRI);
0283
0284 tmp=(tmp%BDRI)<<1;
0285 ratio=(ratio<<1)+(tmp/BDRI);
0286
0287 dprintk("srate= %d (range %d, up to %d)\n", srate,i,bands[i]);
0288 dprintk("fclk = %d\n", fclk);
0289 dprintk("ratio= %08x\n", ratio);
0290
0291 cx24110_writereg(state, 0x1, (ratio>>16)&0xff);
0292 cx24110_writereg(state, 0x2, (ratio>>8)&0xff);
0293 cx24110_writereg(state, 0x3, (ratio)&0xff);
0294
0295 return 0;
0296
0297 }
0298
0299 static int _cx24110_pll_write (struct dvb_frontend* fe, const u8 buf[], int len)
0300 {
0301 struct cx24110_state *state = fe->demodulator_priv;
0302
0303 if (len != 3)
0304 return -EINVAL;
0305
0306
0307
0308
0309
0310 cx24110_writereg(state,0x6d,0x30);
0311 cx24110_writereg(state,0x70,0x15);
0312
0313
0314 while (cx24110_readreg(state,0x6d)&0x80)
0315 cx24110_writereg(state,0x72,0);
0316
0317
0318 cx24110_writereg(state,0x72,buf[0]);
0319
0320
0321 while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
0322 ;
0323
0324
0325 cx24110_writereg(state,0x72,buf[1]);
0326 while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
0327 ;
0328
0329
0330 cx24110_writereg(state,0x72,buf[2]);
0331 while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
0332 ;
0333
0334
0335 cx24110_writereg(state,0x6d,0x32);
0336 cx24110_writereg(state,0x6d,0x30);
0337
0338 return 0;
0339 }
0340
0341 static int cx24110_initfe(struct dvb_frontend* fe)
0342 {
0343 struct cx24110_state *state = fe->demodulator_priv;
0344
0345 int i;
0346
0347 dprintk("%s: init chip\n", __func__);
0348
0349 for(i = 0; i < ARRAY_SIZE(cx24110_regdata); i++) {
0350 cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data);
0351 }
0352
0353 return 0;
0354 }
0355
0356 static int cx24110_set_voltage(struct dvb_frontend *fe,
0357 enum fe_sec_voltage voltage)
0358 {
0359 struct cx24110_state *state = fe->demodulator_priv;
0360
0361 switch (voltage) {
0362 case SEC_VOLTAGE_13:
0363 return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0xc0);
0364 case SEC_VOLTAGE_18:
0365 return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0x40);
0366 default:
0367 return -EINVAL;
0368 }
0369 }
0370
0371 static int cx24110_diseqc_send_burst(struct dvb_frontend *fe,
0372 enum fe_sec_mini_cmd burst)
0373 {
0374 int rv, bit;
0375 struct cx24110_state *state = fe->demodulator_priv;
0376 unsigned long timeout;
0377
0378 if (burst == SEC_MINI_A)
0379 bit = 0x00;
0380 else if (burst == SEC_MINI_B)
0381 bit = 0x08;
0382 else
0383 return -EINVAL;
0384
0385 rv = cx24110_readreg(state, 0x77);
0386 if (!(rv & 0x04))
0387 cx24110_writereg(state, 0x77, rv | 0x04);
0388
0389 rv = cx24110_readreg(state, 0x76);
0390 cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40 | bit));
0391 timeout = jiffies + msecs_to_jiffies(100);
0392 while (!time_after(jiffies, timeout) && !(cx24110_readreg(state, 0x76) & 0x40))
0393 ;
0394
0395 return 0;
0396 }
0397
0398 static int cx24110_send_diseqc_msg(struct dvb_frontend* fe,
0399 struct dvb_diseqc_master_cmd *cmd)
0400 {
0401 int i, rv;
0402 struct cx24110_state *state = fe->demodulator_priv;
0403 unsigned long timeout;
0404
0405 if (cmd->msg_len < 3 || cmd->msg_len > 6)
0406 return -EINVAL;
0407
0408 for (i = 0; i < cmd->msg_len; i++)
0409 cx24110_writereg(state, 0x79 + i, cmd->msg[i]);
0410
0411 rv = cx24110_readreg(state, 0x77);
0412 if (rv & 0x04) {
0413 cx24110_writereg(state, 0x77, rv & ~0x04);
0414 msleep(30);
0415 }
0416
0417 rv = cx24110_readreg(state, 0x76);
0418
0419 cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40) | ((cmd->msg_len-3) & 3));
0420 timeout = jiffies + msecs_to_jiffies(100);
0421 while (!time_after(jiffies, timeout) && !(cx24110_readreg(state, 0x76) & 0x40))
0422 ;
0423
0424 return 0;
0425 }
0426
0427 static int cx24110_read_status(struct dvb_frontend *fe,
0428 enum fe_status *status)
0429 {
0430 struct cx24110_state *state = fe->demodulator_priv;
0431
0432 int sync = cx24110_readreg (state, 0x55);
0433
0434 *status = 0;
0435
0436 if (sync & 0x10)
0437 *status |= FE_HAS_SIGNAL;
0438
0439 if (sync & 0x08)
0440 *status |= FE_HAS_CARRIER;
0441
0442 sync = cx24110_readreg (state, 0x08);
0443
0444 if (sync & 0x40)
0445 *status |= FE_HAS_VITERBI;
0446
0447 if (sync & 0x20)
0448 *status |= FE_HAS_SYNC;
0449
0450 if ((sync & 0x60) == 0x60)
0451 *status |= FE_HAS_LOCK;
0452
0453 return 0;
0454 }
0455
0456 static int cx24110_read_ber(struct dvb_frontend* fe, u32* ber)
0457 {
0458 struct cx24110_state *state = fe->demodulator_priv;
0459
0460
0461 if(cx24110_readreg(state,0x24)&0x10) {
0462
0463 cx24110_writereg(state,0x24,0x04);
0464 state->lastber=cx24110_readreg(state,0x25)|
0465 (cx24110_readreg(state,0x26)<<8);
0466 cx24110_writereg(state,0x24,0x04);
0467 cx24110_writereg(state,0x24,0x14);
0468 }
0469 *ber = state->lastber;
0470
0471 return 0;
0472 }
0473
0474 static int cx24110_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
0475 {
0476 struct cx24110_state *state = fe->demodulator_priv;
0477
0478
0479 u8 signal = cx24110_readreg (state, 0x27)+128;
0480 *signal_strength = (signal << 8) | signal;
0481
0482 return 0;
0483 }
0484
0485 static int cx24110_read_snr(struct dvb_frontend* fe, u16* snr)
0486 {
0487 struct cx24110_state *state = fe->demodulator_priv;
0488
0489
0490 if(cx24110_readreg(state,0x6a)&0x80) {
0491
0492 state->lastesn0=cx24110_readreg(state,0x69)|
0493 (cx24110_readreg(state,0x68)<<8);
0494 cx24110_writereg(state,0x6a,0x84);
0495 }
0496 *snr = state->lastesn0;
0497
0498 return 0;
0499 }
0500
0501 static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
0502 {
0503 struct cx24110_state *state = fe->demodulator_priv;
0504
0505 if(cx24110_readreg(state,0x10)&0x40) {
0506
0507 cx24110_writereg(state,0x10,0x60);
0508 (void)(cx24110_readreg(state, 0x12) |
0509 (cx24110_readreg(state, 0x13) << 8) |
0510 (cx24110_readreg(state, 0x14) << 16));
0511 cx24110_writereg(state,0x10,0x70);
0512 state->lastbler=cx24110_readreg(state,0x12)|
0513 (cx24110_readreg(state,0x13)<<8)|
0514 (cx24110_readreg(state,0x14)<<16);
0515 cx24110_writereg(state,0x10,0x20);
0516 }
0517 *ucblocks = state->lastbler;
0518
0519 return 0;
0520 }
0521
0522 static int cx24110_set_frontend(struct dvb_frontend *fe)
0523 {
0524 struct cx24110_state *state = fe->demodulator_priv;
0525 struct dtv_frontend_properties *p = &fe->dtv_property_cache;
0526
0527 if (fe->ops.tuner_ops.set_params) {
0528 fe->ops.tuner_ops.set_params(fe);
0529 if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
0530 }
0531
0532 cx24110_set_inversion(state, p->inversion);
0533 cx24110_set_fec(state, p->fec_inner);
0534 cx24110_set_symbolrate(state, p->symbol_rate);
0535 cx24110_writereg(state,0x04,0x05);
0536
0537 return 0;
0538 }
0539
0540 static int cx24110_get_frontend(struct dvb_frontend *fe,
0541 struct dtv_frontend_properties *p)
0542 {
0543 struct cx24110_state *state = fe->demodulator_priv;
0544 s32 afc; unsigned sclk;
0545
0546
0547
0548 sclk = cx24110_readreg (state, 0x07) & 0x03;
0549
0550
0551 if (sclk==0) sclk=90999000L/2L;
0552 else if (sclk==1) sclk=60666000L;
0553 else if (sclk==2) sclk=80888000L;
0554 else sclk=90999000L;
0555 sclk>>=8;
0556 afc = sclk*(cx24110_readreg (state, 0x44)&0x1f)+
0557 ((sclk*cx24110_readreg (state, 0x45))>>8)+
0558 ((sclk*cx24110_readreg (state, 0x46))>>16);
0559
0560 p->frequency += afc;
0561 p->inversion = (cx24110_readreg (state, 0x22) & 0x10) ?
0562 INVERSION_ON : INVERSION_OFF;
0563 p->fec_inner = cx24110_get_fec(state);
0564
0565 return 0;
0566 }
0567
0568 static int cx24110_set_tone(struct dvb_frontend *fe,
0569 enum fe_sec_tone_mode tone)
0570 {
0571 struct cx24110_state *state = fe->demodulator_priv;
0572
0573 return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&~0x10)|(((tone==SEC_TONE_ON))?0x10:0));
0574 }
0575
0576 static void cx24110_release(struct dvb_frontend* fe)
0577 {
0578 struct cx24110_state* state = fe->demodulator_priv;
0579 kfree(state);
0580 }
0581
0582 static const struct dvb_frontend_ops cx24110_ops;
0583
0584 struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
0585 struct i2c_adapter* i2c)
0586 {
0587 struct cx24110_state* state = NULL;
0588 int ret;
0589
0590
0591 state = kzalloc(sizeof(struct cx24110_state), GFP_KERNEL);
0592 if (state == NULL) goto error;
0593
0594
0595 state->config = config;
0596 state->i2c = i2c;
0597 state->lastber = 0;
0598 state->lastbler = 0;
0599 state->lastesn0 = 0;
0600
0601
0602 ret = cx24110_readreg(state, 0x00);
0603 if ((ret != 0x5a) && (ret != 0x69)) goto error;
0604
0605
0606 memcpy(&state->frontend.ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
0607 state->frontend.demodulator_priv = state;
0608 return &state->frontend;
0609
0610 error:
0611 kfree(state);
0612 return NULL;
0613 }
0614
0615 static const struct dvb_frontend_ops cx24110_ops = {
0616 .delsys = { SYS_DVBS },
0617 .info = {
0618 .name = "Conexant CX24110 DVB-S",
0619 .frequency_min_hz = 950 * MHz,
0620 .frequency_max_hz = 2150 * MHz,
0621 .frequency_stepsize_hz = 1011 * kHz,
0622 .frequency_tolerance_hz = 29500 * kHz,
0623 .symbol_rate_min = 1000000,
0624 .symbol_rate_max = 45000000,
0625 .caps = FE_CAN_INVERSION_AUTO |
0626 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
0627 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
0628 FE_CAN_QPSK | FE_CAN_RECOVER
0629 },
0630
0631 .release = cx24110_release,
0632
0633 .init = cx24110_initfe,
0634 .write = _cx24110_pll_write,
0635 .set_frontend = cx24110_set_frontend,
0636 .get_frontend = cx24110_get_frontend,
0637 .read_status = cx24110_read_status,
0638 .read_ber = cx24110_read_ber,
0639 .read_signal_strength = cx24110_read_signal_strength,
0640 .read_snr = cx24110_read_snr,
0641 .read_ucblocks = cx24110_read_ucblocks,
0642
0643 .diseqc_send_master_cmd = cx24110_send_diseqc_msg,
0644 .set_tone = cx24110_set_tone,
0645 .set_voltage = cx24110_set_voltage,
0646 .diseqc_send_burst = cx24110_diseqc_send_burst,
0647 };
0648
0649 module_param(debug, int, 0644);
0650 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
0651
0652 MODULE_DESCRIPTION("Conexant CX24110 DVB-S Demodulator driver");
0653 MODULE_AUTHOR("Peter Hettkamp");
0654 MODULE_LICENSE("GPL");
0655
0656 EXPORT_SYMBOL(cx24110_attach);