0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 #include <linux/slab.h>
0026 #include <linux/kernel.h>
0027 #include <linux/module.h>
0028 #include <linux/moduleparam.h>
0029 #include <linux/init.h>
0030 #include <linux/firmware.h>
0031
0032 #include <media/dvb_frontend.h>
0033 #include "cx24116.h"
0034
0035 static int debug;
0036 module_param(debug, int, 0644);
0037 MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
0038
0039 #define dprintk(args...) \
0040 do { \
0041 if (debug) \
0042 printk(KERN_INFO "cx24116: " args); \
0043 } while (0)
0044
0045 #define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw"
0046 #define CX24116_SEARCH_RANGE_KHZ 5000
0047
0048
0049 #define CX24116_REG_COMMAND (0x00)
0050 #define CX24116_REG_EXECUTE (0x1f)
0051 #define CX24116_REG_MAILBOX (0x96)
0052 #define CX24116_REG_RESET (0x20)
0053 #define CX24116_REG_SIGNAL (0x9e)
0054 #define CX24116_REG_SSTATUS (0x9d)
0055 #define CX24116_REG_QUALITY8 (0xa3)
0056 #define CX24116_REG_QSTATUS (0xbc)
0057 #define CX24116_REG_QUALITY0 (0xd5)
0058 #define CX24116_REG_BER0 (0xc9)
0059 #define CX24116_REG_BER8 (0xc8)
0060 #define CX24116_REG_BER16 (0xc7)
0061 #define CX24116_REG_BER24 (0xc6)
0062 #define CX24116_REG_UCB0 (0xcb)
0063 #define CX24116_REG_UCB8 (0xca)
0064 #define CX24116_REG_CLKDIV (0xf3)
0065 #define CX24116_REG_RATEDIV (0xf9)
0066
0067
0068 #define CX24116_REG_FECSTATUS (0x9c)
0069
0070
0071
0072 #define CX24116_FEC_FECMASK (0x1f)
0073
0074
0075 #define CX24116_FEC_DVBS (0x20)
0076 #define CX24116_FEC_UNKNOWN (0x40)
0077
0078
0079 #define CX24116_FEC_PILOT (0x80)
0080
0081
0082 #define CX24116_ARGLEN (0x1e)
0083
0084
0085 #define CX24116_ROLLOFF_020 (0x00)
0086 #define CX24116_ROLLOFF_025 (0x01)
0087 #define CX24116_ROLLOFF_035 (0x02)
0088
0089
0090 #define CX24116_PILOT_OFF (0x00)
0091 #define CX24116_PILOT_ON (0x40)
0092
0093
0094 #define CX24116_HAS_SIGNAL (0x01)
0095 #define CX24116_HAS_CARRIER (0x02)
0096 #define CX24116_HAS_VITERBI (0x04)
0097 #define CX24116_HAS_SYNCLOCK (0x08)
0098 #define CX24116_HAS_UNKNOWN1 (0x10)
0099 #define CX24116_HAS_UNKNOWN2 (0x20)
0100 #define CX24116_STATUS_MASK (0x0f)
0101 #define CX24116_SIGNAL_MASK (0xc0)
0102
0103 #define CX24116_DISEQC_TONEOFF (0)
0104 #define CX24116_DISEQC_TONECACHE (1)
0105 #define CX24116_DISEQC_MESGCACHE (2)
0106
0107
0108 #define CX24116_DISEQC_BURST (1)
0109 #define CX24116_DISEQC_ARG2_2 (2)
0110 #define CX24116_DISEQC_ARG3_0 (3)
0111 #define CX24116_DISEQC_ARG4_0 (4)
0112 #define CX24116_DISEQC_MSGLEN (5)
0113 #define CX24116_DISEQC_MSGOFS (6)
0114
0115
0116 #define CX24116_DISEQC_MINI_A (0)
0117 #define CX24116_DISEQC_MINI_B (1)
0118
0119
0120 static int toneburst = 1;
0121 module_param(toneburst, int, 0644);
0122 MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, "\
0123 "2=MESSAGE CACHE (default:1)");
0124
0125
0126 static int esno_snr;
0127 module_param(esno_snr, int, 0644);
0128 MODULE_PARM_DESC(esno_snr, "SNR return units, 0=PERCENTAGE 0-100, "\
0129 "1=ESNO(db * 10) (default:0)");
0130
0131 enum cmds {
0132 CMD_SET_VCO = 0x10,
0133 CMD_TUNEREQUEST = 0x11,
0134 CMD_MPEGCONFIG = 0x13,
0135 CMD_TUNERINIT = 0x14,
0136 CMD_BANDWIDTH = 0x15,
0137 CMD_GETAGC = 0x19,
0138 CMD_LNBCONFIG = 0x20,
0139 CMD_LNBSEND = 0x21,
0140 CMD_LNBDCLEVEL = 0x22,
0141 CMD_SET_TONE = 0x23,
0142 CMD_UPDFWVERS = 0x35,
0143 CMD_TUNERSLEEP = 0x36,
0144 CMD_AGCCONTROL = 0x3b,
0145 };
0146
0147
0148 struct cx24116_tuning {
0149 u32 frequency;
0150 u32 symbol_rate;
0151 enum fe_spectral_inversion inversion;
0152 enum fe_code_rate fec;
0153
0154 enum fe_delivery_system delsys;
0155 enum fe_modulation modulation;
0156 enum fe_pilot pilot;
0157 enum fe_rolloff rolloff;
0158
0159
0160 u8 fec_val;
0161 u8 fec_mask;
0162 u8 inversion_val;
0163 u8 pilot_val;
0164 u8 rolloff_val;
0165 };
0166
0167
0168 struct cx24116_cmd {
0169 u8 len;
0170 u8 args[CX24116_ARGLEN];
0171 };
0172
0173 struct cx24116_state {
0174 struct i2c_adapter *i2c;
0175 const struct cx24116_config *config;
0176
0177 struct dvb_frontend frontend;
0178
0179 struct cx24116_tuning dcur;
0180 struct cx24116_tuning dnxt;
0181
0182 u8 skip_fw_load;
0183 u8 burst;
0184 struct cx24116_cmd dsec_cmd;
0185 };
0186
0187 static int cx24116_writereg(struct cx24116_state *state, int reg, int data)
0188 {
0189 u8 buf[] = { reg, data };
0190 struct i2c_msg msg = { .addr = state->config->demod_address,
0191 .flags = 0, .buf = buf, .len = 2 };
0192 int err;
0193
0194 if (debug > 1)
0195 printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n",
0196 __func__, reg, data);
0197
0198 err = i2c_transfer(state->i2c, &msg, 1);
0199 if (err != 1) {
0200 printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x, value == 0x%02x)\n",
0201 __func__, err, reg, data);
0202 return -EREMOTEIO;
0203 }
0204
0205 return 0;
0206 }
0207
0208
0209 static int cx24116_writeregN(struct cx24116_state *state, int reg,
0210 const u8 *data, u16 len)
0211 {
0212 int ret;
0213 struct i2c_msg msg;
0214 u8 *buf;
0215
0216 buf = kmalloc(len + 1, GFP_KERNEL);
0217 if (!buf)
0218 return -ENOMEM;
0219
0220 *(buf) = reg;
0221 memcpy(buf + 1, data, len);
0222
0223 msg.addr = state->config->demod_address;
0224 msg.flags = 0;
0225 msg.buf = buf;
0226 msg.len = len + 1;
0227
0228 if (debug > 1)
0229 printk(KERN_INFO "cx24116: %s: write regN 0x%02x, len = %d\n",
0230 __func__, reg, len);
0231
0232 ret = i2c_transfer(state->i2c, &msg, 1);
0233 if (ret != 1) {
0234 printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n",
0235 __func__, ret, reg);
0236 ret = -EREMOTEIO;
0237 }
0238
0239 kfree(buf);
0240
0241 return ret;
0242 }
0243
0244 static int cx24116_readreg(struct cx24116_state *state, u8 reg)
0245 {
0246 int ret;
0247 u8 b0[] = { reg };
0248 u8 b1[] = { 0 };
0249 struct i2c_msg msg[] = {
0250 { .addr = state->config->demod_address, .flags = 0,
0251 .buf = b0, .len = 1 },
0252 { .addr = state->config->demod_address, .flags = I2C_M_RD,
0253 .buf = b1, .len = 1 }
0254 };
0255
0256 ret = i2c_transfer(state->i2c, msg, 2);
0257
0258 if (ret != 2) {
0259 printk(KERN_ERR "%s: reg=0x%x (error=%d)\n",
0260 __func__, reg, ret);
0261 return ret;
0262 }
0263
0264 if (debug > 1)
0265 printk(KERN_INFO "cx24116: read reg 0x%02x, value 0x%02x\n",
0266 reg, b1[0]);
0267
0268 return b1[0];
0269 }
0270
0271 static int cx24116_set_inversion(struct cx24116_state *state,
0272 enum fe_spectral_inversion inversion)
0273 {
0274 dprintk("%s(%d)\n", __func__, inversion);
0275
0276 switch (inversion) {
0277 case INVERSION_OFF:
0278 state->dnxt.inversion_val = 0x00;
0279 break;
0280 case INVERSION_ON:
0281 state->dnxt.inversion_val = 0x04;
0282 break;
0283 case INVERSION_AUTO:
0284 state->dnxt.inversion_val = 0x0C;
0285 break;
0286 default:
0287 return -EINVAL;
0288 }
0289
0290 state->dnxt.inversion = inversion;
0291
0292 return 0;
0293 }
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359 static struct cx24116_modfec {
0360 enum fe_delivery_system delivery_system;
0361 enum fe_modulation modulation;
0362 enum fe_code_rate fec;
0363 u8 mask;
0364 u8 val;
0365 } CX24116_MODFEC_MODES[] = {
0366
0367
0368
0369 { SYS_DVBS, QPSK, FEC_NONE, 0xfe, 0x30 },
0370 { SYS_DVBS, QPSK, FEC_1_2, 0x02, 0x2e },
0371 { SYS_DVBS, QPSK, FEC_2_3, 0x04, 0x2f },
0372 { SYS_DVBS, QPSK, FEC_3_4, 0x08, 0x30 },
0373 { SYS_DVBS, QPSK, FEC_4_5, 0xfe, 0x30 },
0374 { SYS_DVBS, QPSK, FEC_5_6, 0x20, 0x31 },
0375 { SYS_DVBS, QPSK, FEC_6_7, 0xfe, 0x30 },
0376 { SYS_DVBS, QPSK, FEC_7_8, 0x80, 0x32 },
0377 { SYS_DVBS, QPSK, FEC_8_9, 0xfe, 0x30 },
0378 { SYS_DVBS, QPSK, FEC_AUTO, 0xfe, 0x30 },
0379
0380 { SYS_DVBS2, QPSK, FEC_1_2, 0x00, 0x04 },
0381 { SYS_DVBS2, QPSK, FEC_3_5, 0x00, 0x05 },
0382 { SYS_DVBS2, QPSK, FEC_2_3, 0x00, 0x06 },
0383 { SYS_DVBS2, QPSK, FEC_3_4, 0x00, 0x07 },
0384 { SYS_DVBS2, QPSK, FEC_4_5, 0x00, 0x08 },
0385 { SYS_DVBS2, QPSK, FEC_5_6, 0x00, 0x09 },
0386 { SYS_DVBS2, QPSK, FEC_8_9, 0x00, 0x0a },
0387 { SYS_DVBS2, QPSK, FEC_9_10, 0x00, 0x0b },
0388
0389 { SYS_DVBS2, PSK_8, FEC_3_5, 0x00, 0x0c },
0390 { SYS_DVBS2, PSK_8, FEC_2_3, 0x00, 0x0d },
0391 { SYS_DVBS2, PSK_8, FEC_3_4, 0x00, 0x0e },
0392 { SYS_DVBS2, PSK_8, FEC_5_6, 0x00, 0x0f },
0393 { SYS_DVBS2, PSK_8, FEC_8_9, 0x00, 0x10 },
0394 { SYS_DVBS2, PSK_8, FEC_9_10, 0x00, 0x11 },
0395
0396
0397
0398
0399 };
0400
0401 static int cx24116_lookup_fecmod(struct cx24116_state *state,
0402 enum fe_delivery_system d, enum fe_modulation m, enum fe_code_rate f)
0403 {
0404 int i, ret = -EOPNOTSUPP;
0405
0406 dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f);
0407
0408 for (i = 0; i < ARRAY_SIZE(CX24116_MODFEC_MODES); i++) {
0409 if ((d == CX24116_MODFEC_MODES[i].delivery_system) &&
0410 (m == CX24116_MODFEC_MODES[i].modulation) &&
0411 (f == CX24116_MODFEC_MODES[i].fec)) {
0412 ret = i;
0413 break;
0414 }
0415 }
0416
0417 return ret;
0418 }
0419
0420 static int cx24116_set_fec(struct cx24116_state *state,
0421 enum fe_delivery_system delsys,
0422 enum fe_modulation mod,
0423 enum fe_code_rate fec)
0424 {
0425 int ret = 0;
0426
0427 dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec);
0428
0429 ret = cx24116_lookup_fecmod(state, delsys, mod, fec);
0430
0431 if (ret < 0)
0432 return ret;
0433
0434 state->dnxt.fec = fec;
0435 state->dnxt.fec_val = CX24116_MODFEC_MODES[ret].val;
0436 state->dnxt.fec_mask = CX24116_MODFEC_MODES[ret].mask;
0437 dprintk("%s() mask/val = 0x%02x/0x%02x\n", __func__,
0438 state->dnxt.fec_mask, state->dnxt.fec_val);
0439
0440 return 0;
0441 }
0442
0443 static int cx24116_set_symbolrate(struct cx24116_state *state, u32 rate)
0444 {
0445 dprintk("%s(%d)\n", __func__, rate);
0446
0447
0448 if ((rate > state->frontend.ops.info.symbol_rate_max) ||
0449 (rate < state->frontend.ops.info.symbol_rate_min)) {
0450 dprintk("%s() unsupported symbol_rate = %d\n", __func__, rate);
0451 return -EOPNOTSUPP;
0452 }
0453
0454 state->dnxt.symbol_rate = rate;
0455 dprintk("%s() symbol_rate = %d\n", __func__, rate);
0456
0457 return 0;
0458 }
0459
0460 static int cx24116_load_firmware(struct dvb_frontend *fe,
0461 const struct firmware *fw);
0462
0463 static int cx24116_firmware_ondemand(struct dvb_frontend *fe)
0464 {
0465 struct cx24116_state *state = fe->demodulator_priv;
0466 const struct firmware *fw;
0467 int ret = 0;
0468
0469 dprintk("%s()\n", __func__);
0470
0471 if (cx24116_readreg(state, 0x20) > 0) {
0472
0473 if (state->skip_fw_load)
0474 return 0;
0475
0476
0477
0478 printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n",
0479 __func__, CX24116_DEFAULT_FIRMWARE);
0480 ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE,
0481 state->i2c->dev.parent);
0482 printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n",
0483 __func__);
0484 if (ret) {
0485 printk(KERN_ERR "%s: No firmware uploaded (timeout or file not found?)\n",
0486 __func__);
0487 return ret;
0488 }
0489
0490
0491
0492 state->skip_fw_load = 1;
0493
0494 ret = cx24116_load_firmware(fe, fw);
0495 if (ret)
0496 printk(KERN_ERR "%s: Writing firmware to device failed\n",
0497 __func__);
0498
0499 release_firmware(fw);
0500
0501 printk(KERN_INFO "%s: Firmware upload %s\n", __func__,
0502 ret == 0 ? "complete" : "failed");
0503
0504
0505 state->skip_fw_load = 0;
0506 }
0507
0508 return ret;
0509 }
0510
0511
0512
0513
0514 static int cx24116_cmd_execute(struct dvb_frontend *fe, struct cx24116_cmd *cmd)
0515 {
0516 struct cx24116_state *state = fe->demodulator_priv;
0517 int i, ret;
0518
0519 dprintk("%s()\n", __func__);
0520
0521
0522 ret = cx24116_firmware_ondemand(fe);
0523 if (ret != 0) {
0524 printk(KERN_ERR "%s(): Unable initialise the firmware\n",
0525 __func__);
0526 return ret;
0527 }
0528
0529
0530 for (i = 0; i < cmd->len ; i++) {
0531 dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]);
0532 cx24116_writereg(state, i, cmd->args[i]);
0533 }
0534
0535
0536 cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01);
0537 while (cx24116_readreg(state, CX24116_REG_EXECUTE)) {
0538 msleep(10);
0539 if (i++ > 64) {
0540
0541
0542 printk(KERN_WARNING "%s() Firmware not responding\n",
0543 __func__);
0544 return -EREMOTEIO;
0545 }
0546 }
0547 return 0;
0548 }
0549
0550 static int cx24116_load_firmware(struct dvb_frontend *fe,
0551 const struct firmware *fw)
0552 {
0553 struct cx24116_state *state = fe->demodulator_priv;
0554 struct cx24116_cmd cmd;
0555 int i, ret, len, max, remaining;
0556 unsigned char vers[4];
0557
0558 dprintk("%s\n", __func__);
0559 dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
0560 fw->size,
0561 fw->data[0],
0562 fw->data[1],
0563 fw->data[fw->size-2],
0564 fw->data[fw->size-1]);
0565
0566
0567 if (state->config->reset_device)
0568 state->config->reset_device(fe);
0569
0570
0571
0572
0573
0574 cx24116_writereg(state, 0xE5, 0x00);
0575 cx24116_writereg(state, 0xF1, 0x08);
0576 cx24116_writereg(state, 0xF2, 0x13);
0577
0578
0579 cx24116_writereg(state, 0xe0, 0x03);
0580 cx24116_writereg(state, 0xe0, 0x00);
0581
0582
0583 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
0584 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
0585
0586
0587 cx24116_writereg(state, 0xF0, 0x03);
0588 cx24116_writereg(state, 0xF4, 0x81);
0589 cx24116_writereg(state, 0xF5, 0x00);
0590 cx24116_writereg(state, 0xF6, 0x00);
0591
0592
0593
0594 if (state->config->i2c_wr_max)
0595 max = state->config->i2c_wr_max;
0596 else
0597 max = INT_MAX;
0598
0599 for (remaining = fw->size; remaining > 0; remaining -= max - 1) {
0600 len = remaining;
0601 if (len > max - 1)
0602 len = max - 1;
0603
0604 cx24116_writeregN(state, 0xF7, &fw->data[fw->size - remaining],
0605 len);
0606 }
0607
0608 cx24116_writereg(state, 0xF4, 0x10);
0609 cx24116_writereg(state, 0xF0, 0x00);
0610 cx24116_writereg(state, 0xF8, 0x06);
0611
0612
0613 cmd.args[0x00] = CMD_SET_VCO;
0614 cmd.args[0x01] = 0x05;
0615 cmd.args[0x02] = 0xdc;
0616 cmd.args[0x03] = 0xda;
0617 cmd.args[0x04] = 0xae;
0618 cmd.args[0x05] = 0xaa;
0619 cmd.args[0x06] = 0x04;
0620 cmd.args[0x07] = 0x9d;
0621 cmd.args[0x08] = 0xfc;
0622 cmd.args[0x09] = 0x06;
0623 cmd.len = 0x0a;
0624 ret = cx24116_cmd_execute(fe, &cmd);
0625 if (ret != 0)
0626 return ret;
0627
0628 cx24116_writereg(state, CX24116_REG_SSTATUS, 0x00);
0629
0630
0631 cmd.args[0x00] = CMD_TUNERINIT;
0632 cmd.args[0x01] = 0x00;
0633 cmd.args[0x02] = 0x00;
0634 cmd.len = 0x03;
0635 ret = cx24116_cmd_execute(fe, &cmd);
0636 if (ret != 0)
0637 return ret;
0638
0639 cx24116_writereg(state, 0xe5, 0x00);
0640
0641
0642 cmd.args[0x00] = CMD_MPEGCONFIG;
0643 cmd.args[0x01] = 0x01;
0644 cmd.args[0x02] = 0x75;
0645 cmd.args[0x03] = 0x00;
0646 if (state->config->mpg_clk_pos_pol)
0647 cmd.args[0x04] = state->config->mpg_clk_pos_pol;
0648 else
0649 cmd.args[0x04] = 0x02;
0650 cmd.args[0x05] = 0x00;
0651 cmd.len = 0x06;
0652 ret = cx24116_cmd_execute(fe, &cmd);
0653 if (ret != 0)
0654 return ret;
0655
0656
0657 cmd.args[0x00] = CMD_UPDFWVERS;
0658 cmd.len = 0x02;
0659 for (i = 0; i < 4; i++) {
0660 cmd.args[0x01] = i;
0661 ret = cx24116_cmd_execute(fe, &cmd);
0662 if (ret != 0)
0663 return ret;
0664 vers[i] = cx24116_readreg(state, CX24116_REG_MAILBOX);
0665 }
0666 printk(KERN_INFO "%s: FW version %i.%i.%i.%i\n", __func__,
0667 vers[0], vers[1], vers[2], vers[3]);
0668
0669 return 0;
0670 }
0671
0672 static int cx24116_read_status(struct dvb_frontend *fe, enum fe_status *status)
0673 {
0674 struct cx24116_state *state = fe->demodulator_priv;
0675
0676 int lock = cx24116_readreg(state, CX24116_REG_SSTATUS) &
0677 CX24116_STATUS_MASK;
0678
0679 dprintk("%s: status = 0x%02x\n", __func__, lock);
0680
0681 *status = 0;
0682
0683 if (lock & CX24116_HAS_SIGNAL)
0684 *status |= FE_HAS_SIGNAL;
0685 if (lock & CX24116_HAS_CARRIER)
0686 *status |= FE_HAS_CARRIER;
0687 if (lock & CX24116_HAS_VITERBI)
0688 *status |= FE_HAS_VITERBI;
0689 if (lock & CX24116_HAS_SYNCLOCK)
0690 *status |= FE_HAS_SYNC | FE_HAS_LOCK;
0691
0692 return 0;
0693 }
0694
0695 static int cx24116_read_ber(struct dvb_frontend *fe, u32 *ber)
0696 {
0697 struct cx24116_state *state = fe->demodulator_priv;
0698
0699 dprintk("%s()\n", __func__);
0700
0701 *ber = (cx24116_readreg(state, CX24116_REG_BER24) << 24) |
0702 (cx24116_readreg(state, CX24116_REG_BER16) << 16) |
0703 (cx24116_readreg(state, CX24116_REG_BER8) << 8) |
0704 cx24116_readreg(state, CX24116_REG_BER0);
0705
0706 return 0;
0707 }
0708
0709
0710 static int cx24116_read_signal_strength(struct dvb_frontend *fe,
0711 u16 *signal_strength)
0712 {
0713 struct cx24116_state *state = fe->demodulator_priv;
0714 struct cx24116_cmd cmd;
0715 int ret;
0716 u16 sig_reading;
0717
0718 dprintk("%s()\n", __func__);
0719
0720
0721 cmd.args[0x00] = CMD_GETAGC;
0722 cmd.len = 0x01;
0723 ret = cx24116_cmd_execute(fe, &cmd);
0724 if (ret != 0)
0725 return ret;
0726
0727 sig_reading =
0728 (cx24116_readreg(state,
0729 CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK) |
0730 (cx24116_readreg(state, CX24116_REG_SIGNAL) << 6);
0731 *signal_strength = 0 - sig_reading;
0732
0733 dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n",
0734 __func__, sig_reading, *signal_strength);
0735
0736 return 0;
0737 }
0738
0739
0740 static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr)
0741 {
0742 struct cx24116_state *state = fe->demodulator_priv;
0743 u8 snr_reading;
0744 static const u32 snr_tab[] = {
0745 0x00000, 0x0199A, 0x03333, 0x04ccD, 0x06667,
0746 0x08000, 0x0999A, 0x0b333, 0x0cccD, 0x0e667,
0747 0x10000, 0x1199A, 0x13333, 0x14ccD, 0x16667,
0748 0x18000 };
0749
0750 dprintk("%s()\n", __func__);
0751
0752 snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0);
0753
0754 if (snr_reading >= 0xa0 )
0755 *snr = 0xffff;
0756 else
0757 *snr = snr_tab[(snr_reading & 0xf0) >> 4] +
0758 (snr_tab[(snr_reading & 0x0f)] >> 4);
0759
0760 dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
0761 snr_reading, *snr);
0762
0763 return 0;
0764 }
0765
0766
0767
0768
0769
0770 static int cx24116_read_snr_esno(struct dvb_frontend *fe, u16 *snr)
0771 {
0772 struct cx24116_state *state = fe->demodulator_priv;
0773
0774 dprintk("%s()\n", __func__);
0775
0776 *snr = cx24116_readreg(state, CX24116_REG_QUALITY8) << 8 |
0777 cx24116_readreg(state, CX24116_REG_QUALITY0);
0778
0779 dprintk("%s: raw 0x%04x\n", __func__, *snr);
0780
0781 return 0;
0782 }
0783
0784 static int cx24116_read_snr(struct dvb_frontend *fe, u16 *snr)
0785 {
0786 if (esno_snr == 1)
0787 return cx24116_read_snr_esno(fe, snr);
0788 else
0789 return cx24116_read_snr_pct(fe, snr);
0790 }
0791
0792 static int cx24116_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
0793 {
0794 struct cx24116_state *state = fe->demodulator_priv;
0795
0796 dprintk("%s()\n", __func__);
0797
0798 *ucblocks = (cx24116_readreg(state, CX24116_REG_UCB8) << 8) |
0799 cx24116_readreg(state, CX24116_REG_UCB0);
0800
0801 return 0;
0802 }
0803
0804
0805 static void cx24116_clone_params(struct dvb_frontend *fe)
0806 {
0807 struct cx24116_state *state = fe->demodulator_priv;
0808 state->dcur = state->dnxt;
0809 }
0810
0811
0812 static int cx24116_wait_for_lnb(struct dvb_frontend *fe)
0813 {
0814 struct cx24116_state *state = fe->demodulator_priv;
0815 int i;
0816
0817 dprintk("%s() qstatus = 0x%02x\n", __func__,
0818 cx24116_readreg(state, CX24116_REG_QSTATUS));
0819
0820
0821 for (i = 0; i < 30 ; i++) {
0822 if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20)
0823 return 0;
0824 msleep(10);
0825 }
0826
0827 dprintk("%s(): LNB not ready\n", __func__);
0828
0829 return -ETIMEDOUT;
0830 }
0831
0832 static int cx24116_set_voltage(struct dvb_frontend *fe,
0833 enum fe_sec_voltage voltage)
0834 {
0835 struct cx24116_cmd cmd;
0836 int ret;
0837
0838 dprintk("%s: %s\n", __func__,
0839 voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
0840 voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
0841
0842
0843 ret = cx24116_wait_for_lnb(fe);
0844 if (ret != 0)
0845 return ret;
0846
0847
0848 msleep(100);
0849
0850 cmd.args[0x00] = CMD_LNBDCLEVEL;
0851 cmd.args[0x01] = (voltage == SEC_VOLTAGE_18 ? 0x01 : 0x00);
0852 cmd.len = 0x02;
0853
0854
0855 msleep(15);
0856
0857 return cx24116_cmd_execute(fe, &cmd);
0858 }
0859
0860 static int cx24116_set_tone(struct dvb_frontend *fe,
0861 enum fe_sec_tone_mode tone)
0862 {
0863 struct cx24116_cmd cmd;
0864 int ret;
0865
0866 dprintk("%s(%d)\n", __func__, tone);
0867 if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
0868 printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
0869 return -EINVAL;
0870 }
0871
0872
0873 ret = cx24116_wait_for_lnb(fe);
0874 if (ret != 0)
0875 return ret;
0876
0877
0878 msleep(15);
0879
0880
0881 cmd.args[0x00] = CMD_SET_TONE;
0882 cmd.args[0x01] = 0x00;
0883 cmd.args[0x02] = 0x00;
0884
0885 switch (tone) {
0886 case SEC_TONE_ON:
0887 dprintk("%s: setting tone on\n", __func__);
0888 cmd.args[0x03] = 0x01;
0889 break;
0890 case SEC_TONE_OFF:
0891 dprintk("%s: setting tone off\n", __func__);
0892 cmd.args[0x03] = 0x00;
0893 break;
0894 }
0895 cmd.len = 0x04;
0896
0897
0898 msleep(15);
0899
0900 return cx24116_cmd_execute(fe, &cmd);
0901 }
0902
0903
0904 static int cx24116_diseqc_init(struct dvb_frontend *fe)
0905 {
0906 struct cx24116_state *state = fe->demodulator_priv;
0907 struct cx24116_cmd cmd;
0908 int ret;
0909
0910
0911 cmd.args[0x00] = CMD_LNBCONFIG;
0912 cmd.args[0x01] = 0x00;
0913 cmd.args[0x02] = 0x10;
0914 cmd.args[0x03] = 0x00;
0915 cmd.args[0x04] = 0x8f;
0916 cmd.args[0x05] = 0x28;
0917 cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01;
0918 cmd.args[0x07] = 0x01;
0919 cmd.len = 0x08;
0920 ret = cx24116_cmd_execute(fe, &cmd);
0921 if (ret != 0)
0922 return ret;
0923
0924
0925 state->dsec_cmd.args[0x00] = CMD_LNBSEND;
0926
0927
0928 state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A;
0929
0930
0931 state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02;
0932 state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00;
0933
0934 state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00;
0935
0936
0937 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00;
0938
0939
0940 state->dsec_cmd.len = CX24116_DISEQC_MSGOFS;
0941
0942 return 0;
0943 }
0944
0945
0946 static int cx24116_send_diseqc_msg(struct dvb_frontend *fe,
0947 struct dvb_diseqc_master_cmd *d)
0948 {
0949 struct cx24116_state *state = fe->demodulator_priv;
0950 int i, ret;
0951
0952
0953 if (d->msg_len > sizeof(d->msg))
0954 return -EINVAL;
0955
0956
0957 if (debug) {
0958 printk(KERN_INFO "cx24116: %s(", __func__);
0959 for (i = 0 ; i < d->msg_len ;) {
0960 printk(KERN_INFO "0x%02x", d->msg[i]);
0961 if (++i < d->msg_len)
0962 printk(KERN_INFO ", ");
0963 }
0964 printk(") toneburst=%d\n", toneburst);
0965 }
0966
0967
0968 for (i = 0; i < d->msg_len; i++)
0969 state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i];
0970
0971
0972 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len;
0973
0974
0975 state->dsec_cmd.len = CX24116_DISEQC_MSGOFS +
0976 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN];
0977
0978
0979 if (toneburst == CX24116_DISEQC_MESGCACHE)
0980
0981 return 0;
0982
0983 else if (toneburst == CX24116_DISEQC_TONEOFF)
0984
0985 state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0;
0986
0987 else if (toneburst == CX24116_DISEQC_TONECACHE) {
0988
0989
0990
0991
0992
0993
0994
0995
0996
0997
0998
0999
1000
1001
1002
1003
1004
1005
1006 if (d->msg_len >= 4 && d->msg[2] == 0x38)
1007 state->dsec_cmd.args[CX24116_DISEQC_BURST] =
1008 ((d->msg[3] & 4) >> 2);
1009 if (debug)
1010 dprintk("%s burst=%d\n", __func__,
1011 state->dsec_cmd.args[CX24116_DISEQC_BURST]);
1012 }
1013
1014
1015 ret = cx24116_wait_for_lnb(fe);
1016 if (ret != 0)
1017 return ret;
1018
1019
1020 msleep(100);
1021
1022
1023 ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
1024 if (ret != 0)
1025 return ret;
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036 msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) +
1037 ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60));
1038
1039 return 0;
1040 }
1041
1042
1043 static int cx24116_diseqc_send_burst(struct dvb_frontend *fe,
1044 enum fe_sec_mini_cmd burst)
1045 {
1046 struct cx24116_state *state = fe->demodulator_priv;
1047 int ret;
1048
1049 dprintk("%s(%d) toneburst=%d\n", __func__, burst, toneburst);
1050
1051
1052 if (burst == SEC_MINI_A)
1053 state->dsec_cmd.args[CX24116_DISEQC_BURST] =
1054 CX24116_DISEQC_MINI_A;
1055 else if (burst == SEC_MINI_B)
1056 state->dsec_cmd.args[CX24116_DISEQC_BURST] =
1057 CX24116_DISEQC_MINI_B;
1058 else
1059 return -EINVAL;
1060
1061
1062 if (toneburst != CX24116_DISEQC_MESGCACHE)
1063
1064 return 0;
1065
1066
1067
1068
1069 ret = cx24116_wait_for_lnb(fe);
1070 if (ret != 0)
1071 return ret;
1072
1073
1074 msleep(100);
1075
1076
1077 ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
1078 if (ret != 0)
1079 return ret;
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091 msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60);
1092
1093 return 0;
1094 }
1095
1096 static void cx24116_release(struct dvb_frontend *fe)
1097 {
1098 struct cx24116_state *state = fe->demodulator_priv;
1099 dprintk("%s\n", __func__);
1100 kfree(state);
1101 }
1102
1103 static const struct dvb_frontend_ops cx24116_ops;
1104
1105 struct dvb_frontend *cx24116_attach(const struct cx24116_config *config,
1106 struct i2c_adapter *i2c)
1107 {
1108 struct cx24116_state *state;
1109 int ret;
1110
1111 dprintk("%s\n", __func__);
1112
1113
1114 state = kzalloc(sizeof(*state), GFP_KERNEL);
1115 if (state == NULL)
1116 return NULL;
1117
1118 state->config = config;
1119 state->i2c = i2c;
1120
1121
1122 ret = (cx24116_readreg(state, 0xFF) << 8) |
1123 cx24116_readreg(state, 0xFE);
1124 if (ret != 0x0501) {
1125 kfree(state);
1126 printk(KERN_INFO "Invalid probe, probably not a CX24116 device\n");
1127 return NULL;
1128 }
1129
1130
1131 memcpy(&state->frontend.ops, &cx24116_ops,
1132 sizeof(struct dvb_frontend_ops));
1133 state->frontend.demodulator_priv = state;
1134 return &state->frontend;
1135 }
1136 EXPORT_SYMBOL(cx24116_attach);
1137
1138
1139
1140
1141
1142
1143 static int cx24116_initfe(struct dvb_frontend *fe)
1144 {
1145 struct cx24116_state *state = fe->demodulator_priv;
1146 struct cx24116_cmd cmd;
1147 int ret;
1148
1149 dprintk("%s()\n", __func__);
1150
1151
1152 cx24116_writereg(state, 0xe0, 0);
1153 cx24116_writereg(state, 0xe1, 0);
1154 cx24116_writereg(state, 0xea, 0);
1155
1156
1157 cmd.args[0x00] = CMD_TUNERSLEEP;
1158 cmd.args[0x01] = 0;
1159 cmd.len = 0x02;
1160 ret = cx24116_cmd_execute(fe, &cmd);
1161 if (ret != 0)
1162 return ret;
1163
1164 ret = cx24116_diseqc_init(fe);
1165 if (ret != 0)
1166 return ret;
1167
1168
1169 return cx24116_set_voltage(fe, SEC_VOLTAGE_13);
1170 }
1171
1172
1173
1174
1175 static int cx24116_sleep(struct dvb_frontend *fe)
1176 {
1177 struct cx24116_state *state = fe->demodulator_priv;
1178 struct cx24116_cmd cmd;
1179 int ret;
1180
1181 dprintk("%s()\n", __func__);
1182
1183
1184 cmd.args[0x00] = CMD_TUNERSLEEP;
1185 cmd.args[0x01] = 1;
1186 cmd.len = 0x02;
1187 ret = cx24116_cmd_execute(fe, &cmd);
1188 if (ret != 0)
1189 return ret;
1190
1191
1192 cx24116_writereg(state, 0xea, 0xff);
1193 cx24116_writereg(state, 0xe1, 1);
1194 cx24116_writereg(state, 0xe0, 1);
1195
1196 return 0;
1197 }
1198
1199
1200
1201
1202 static int cx24116_set_frontend(struct dvb_frontend *fe)
1203 {
1204 struct cx24116_state *state = fe->demodulator_priv;
1205 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
1206 struct cx24116_cmd cmd;
1207 enum fe_status tunerstat;
1208 int i, status, ret, retune = 1;
1209
1210 dprintk("%s()\n", __func__);
1211
1212 switch (c->delivery_system) {
1213 case SYS_DVBS:
1214 dprintk("%s: DVB-S delivery system selected\n", __func__);
1215
1216
1217 if (c->modulation != QPSK) {
1218 dprintk("%s: unsupported modulation selected (%d)\n",
1219 __func__, c->modulation);
1220 return -EOPNOTSUPP;
1221 }
1222
1223
1224 state->dnxt.pilot_val = CX24116_PILOT_OFF;
1225
1226
1227 if (c->rolloff != ROLLOFF_35) {
1228 dprintk("%s: unsupported rolloff selected (%d)\n",
1229 __func__, c->rolloff);
1230 return -EOPNOTSUPP;
1231 }
1232 state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
1233 break;
1234
1235 case SYS_DVBS2:
1236 dprintk("%s: DVB-S2 delivery system selected\n", __func__);
1237
1238
1239
1240
1241
1242 if (c->modulation != PSK_8 && c->modulation != QPSK) {
1243 dprintk("%s: unsupported modulation selected (%d)\n",
1244 __func__, c->modulation);
1245 return -EOPNOTSUPP;
1246 }
1247
1248 switch (c->pilot) {
1249 case PILOT_AUTO:
1250 state->dnxt.pilot_val = (c->modulation == QPSK)
1251 ? CX24116_PILOT_OFF : CX24116_PILOT_ON;
1252 retune++;
1253 break;
1254 case PILOT_OFF:
1255 state->dnxt.pilot_val = CX24116_PILOT_OFF;
1256 break;
1257 case PILOT_ON:
1258 state->dnxt.pilot_val = CX24116_PILOT_ON;
1259 break;
1260 default:
1261 dprintk("%s: unsupported pilot mode selected (%d)\n",
1262 __func__, c->pilot);
1263 return -EOPNOTSUPP;
1264 }
1265
1266 switch (c->rolloff) {
1267 case ROLLOFF_20:
1268 state->dnxt.rolloff_val = CX24116_ROLLOFF_020;
1269 break;
1270 case ROLLOFF_25:
1271 state->dnxt.rolloff_val = CX24116_ROLLOFF_025;
1272 break;
1273 case ROLLOFF_35:
1274 state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
1275 break;
1276 case ROLLOFF_AUTO:
1277 default:
1278 dprintk("%s: unsupported rolloff selected (%d)\n",
1279 __func__, c->rolloff);
1280 return -EOPNOTSUPP;
1281 }
1282 break;
1283
1284 default:
1285 dprintk("%s: unsupported delivery system selected (%d)\n",
1286 __func__, c->delivery_system);
1287 return -EOPNOTSUPP;
1288 }
1289 state->dnxt.delsys = c->delivery_system;
1290 state->dnxt.modulation = c->modulation;
1291 state->dnxt.frequency = c->frequency;
1292 state->dnxt.pilot = c->pilot;
1293 state->dnxt.rolloff = c->rolloff;
1294
1295 ret = cx24116_set_inversion(state, c->inversion);
1296 if (ret != 0)
1297 return ret;
1298
1299
1300 ret = cx24116_set_fec(state, c->delivery_system, c->modulation, c->fec_inner);
1301 if (ret != 0)
1302 return ret;
1303
1304 ret = cx24116_set_symbolrate(state, c->symbol_rate);
1305 if (ret != 0)
1306 return ret;
1307
1308
1309 cx24116_clone_params(fe);
1310
1311 dprintk("%s: delsys = %d\n", __func__, state->dcur.delsys);
1312 dprintk("%s: modulation = %d\n", __func__, state->dcur.modulation);
1313 dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency);
1314 dprintk("%s: pilot = %d (val = 0x%02x)\n", __func__,
1315 state->dcur.pilot, state->dcur.pilot_val);
1316 dprintk("%s: retune = %d\n", __func__, retune);
1317 dprintk("%s: rolloff = %d (val = 0x%02x)\n", __func__,
1318 state->dcur.rolloff, state->dcur.rolloff_val);
1319 dprintk("%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate);
1320 dprintk("%s: FEC = %d (mask/val = 0x%02x/0x%02x)\n", __func__,
1321 state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val);
1322 dprintk("%s: Inversion = %d (val = 0x%02x)\n", __func__,
1323 state->dcur.inversion, state->dcur.inversion_val);
1324
1325
1326 if (state->config->set_ts_params)
1327 state->config->set_ts_params(fe, 0);
1328
1329
1330 cmd.args[0x00] = CMD_BANDWIDTH;
1331 cmd.args[0x01] = 0x01;
1332 cmd.len = 0x02;
1333 ret = cx24116_cmd_execute(fe, &cmd);
1334 if (ret != 0)
1335 return ret;
1336
1337
1338 cmd.args[0x00] = CMD_TUNEREQUEST;
1339
1340
1341 cmd.args[0x01] = (state->dcur.frequency & 0xff0000) >> 16;
1342 cmd.args[0x02] = (state->dcur.frequency & 0x00ff00) >> 8;
1343 cmd.args[0x03] = (state->dcur.frequency & 0x0000ff);
1344
1345
1346 cmd.args[0x04] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8;
1347 cmd.args[0x05] = ((state->dcur.symbol_rate / 1000) & 0x00ff);
1348
1349
1350 cmd.args[0x06] = state->dcur.inversion_val;
1351
1352
1353 cmd.args[0x07] = state->dcur.fec_val | state->dcur.pilot_val;
1354
1355 cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8;
1356 cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff;
1357 cmd.args[0x0a] = 0x00;
1358 cmd.args[0x0b] = 0x00;
1359 cmd.args[0x0c] = state->dcur.rolloff_val;
1360 cmd.args[0x0d] = state->dcur.fec_mask;
1361
1362 if (state->dcur.symbol_rate > 30000000) {
1363 cmd.args[0x0e] = 0x04;
1364 cmd.args[0x0f] = 0x00;
1365 cmd.args[0x10] = 0x01;
1366 cmd.args[0x11] = 0x77;
1367 cmd.args[0x12] = 0x36;
1368 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x44);
1369 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x01);
1370 } else {
1371 cmd.args[0x0e] = 0x06;
1372 cmd.args[0x0f] = 0x00;
1373 cmd.args[0x10] = 0x00;
1374 cmd.args[0x11] = 0xFA;
1375 cmd.args[0x12] = 0x24;
1376 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
1377 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
1378 }
1379
1380 cmd.len = 0x13;
1381
1382
1383
1384
1385
1386 do {
1387
1388 status = cx24116_readreg(state, CX24116_REG_SSTATUS)
1389 & CX24116_SIGNAL_MASK;
1390 cx24116_writereg(state, CX24116_REG_SSTATUS, status);
1391
1392
1393 ret = cx24116_cmd_execute(fe, &cmd);
1394 if (ret != 0)
1395 break;
1396
1397
1398
1399
1400
1401
1402
1403 for (i = 0; i < 50 ; i++) {
1404 cx24116_read_status(fe, &tunerstat);
1405 status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC);
1406 if (status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) {
1407 dprintk("%s: Tuned\n", __func__);
1408 goto tuned;
1409 }
1410 msleep(10);
1411 }
1412
1413 dprintk("%s: Not tuned\n", __func__);
1414
1415
1416 if (state->dcur.pilot == PILOT_AUTO)
1417 cmd.args[0x07] ^= CX24116_PILOT_ON;
1418 } while (--retune);
1419
1420 tuned:
1421 cmd.args[0x00] = CMD_BANDWIDTH;
1422 cmd.args[0x01] = 0x00;
1423 cmd.len = 0x02;
1424 return cx24116_cmd_execute(fe, &cmd);
1425 }
1426
1427 static int cx24116_tune(struct dvb_frontend *fe, bool re_tune,
1428 unsigned int mode_flags, unsigned int *delay, enum fe_status *status)
1429 {
1430
1431
1432
1433
1434
1435
1436
1437
1438 *delay = HZ / 5;
1439 if (re_tune) {
1440 int ret = cx24116_set_frontend(fe);
1441 if (ret)
1442 return ret;
1443 }
1444 return cx24116_read_status(fe, status);
1445 }
1446
1447 static enum dvbfe_algo cx24116_get_algo(struct dvb_frontend *fe)
1448 {
1449 return DVBFE_ALGO_HW;
1450 }
1451
1452 static const struct dvb_frontend_ops cx24116_ops = {
1453 .delsys = { SYS_DVBS, SYS_DVBS2 },
1454 .info = {
1455 .name = "Conexant CX24116/CX24118",
1456 .frequency_min_hz = 950 * MHz,
1457 .frequency_max_hz = 2150 * MHz,
1458 .frequency_stepsize_hz = 1011 * kHz,
1459 .frequency_tolerance_hz = 5 * MHz,
1460 .symbol_rate_min = 1000000,
1461 .symbol_rate_max = 45000000,
1462 .caps = FE_CAN_INVERSION_AUTO |
1463 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1464 FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
1465 FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
1466 FE_CAN_2G_MODULATION |
1467 FE_CAN_QPSK | FE_CAN_RECOVER
1468 },
1469
1470 .release = cx24116_release,
1471
1472 .init = cx24116_initfe,
1473 .sleep = cx24116_sleep,
1474 .read_status = cx24116_read_status,
1475 .read_ber = cx24116_read_ber,
1476 .read_signal_strength = cx24116_read_signal_strength,
1477 .read_snr = cx24116_read_snr,
1478 .read_ucblocks = cx24116_read_ucblocks,
1479 .set_tone = cx24116_set_tone,
1480 .set_voltage = cx24116_set_voltage,
1481 .diseqc_send_master_cmd = cx24116_send_diseqc_msg,
1482 .diseqc_send_burst = cx24116_diseqc_send_burst,
1483 .get_frontend_algo = cx24116_get_algo,
1484 .tune = cx24116_tune,
1485
1486 .set_frontend = cx24116_set_frontend,
1487 };
1488
1489 MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware");
1490 MODULE_AUTHOR("Steven Toth");
1491 MODULE_LICENSE("GPL");
1492