174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 29a0bf528SMauro Carvalho Chehab /* 39a0bf528SMauro Carvalho Chehab Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver 49a0bf528SMauro Carvalho Chehab 59a0bf528SMauro Carvalho Chehab Copyright (C) 2006-2008 Steven Toth <stoth@hauppauge.com> 69a0bf528SMauro Carvalho Chehab Copyright (C) 2006-2007 Georg Acher 79a0bf528SMauro Carvalho Chehab Copyright (C) 2007-2008 Darron Broad 89a0bf528SMauro Carvalho Chehab March 2007 99a0bf528SMauro Carvalho Chehab Fixed some bugs. 109a0bf528SMauro Carvalho Chehab Added diseqc support. 119a0bf528SMauro Carvalho Chehab Added corrected signal strength support. 129a0bf528SMauro Carvalho Chehab August 2007 139a0bf528SMauro Carvalho Chehab Sync with legacy version. 149a0bf528SMauro Carvalho Chehab Some clean ups. 159a0bf528SMauro Carvalho Chehab Copyright (C) 2008 Igor Liplianin 169a0bf528SMauro Carvalho Chehab September, 9th 2008 179a0bf528SMauro Carvalho Chehab Fixed locking on high symbol rates (>30000). 189a0bf528SMauro Carvalho Chehab Implement MPEG initialization parameter. 199a0bf528SMauro Carvalho Chehab January, 17th 2009 209a0bf528SMauro Carvalho Chehab Fill set_voltage with actually control voltage code. 219a0bf528SMauro Carvalho Chehab Correct set tone to not affect voltage. 229a0bf528SMauro Carvalho Chehab 239a0bf528SMauro Carvalho Chehab */ 249a0bf528SMauro Carvalho Chehab 259a0bf528SMauro Carvalho Chehab #include <linux/slab.h> 269a0bf528SMauro Carvalho Chehab #include <linux/kernel.h> 279a0bf528SMauro Carvalho Chehab #include <linux/module.h> 289a0bf528SMauro Carvalho Chehab #include <linux/moduleparam.h> 299a0bf528SMauro Carvalho Chehab #include <linux/init.h> 309a0bf528SMauro Carvalho Chehab #include <linux/firmware.h> 319a0bf528SMauro Carvalho Chehab 32fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h> 339a0bf528SMauro Carvalho Chehab #include "cx24116.h" 349a0bf528SMauro Carvalho Chehab 359a0bf528SMauro Carvalho Chehab static int debug; 369a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644); 379a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); 389a0bf528SMauro Carvalho Chehab 399a0bf528SMauro Carvalho Chehab #define dprintk(args...) \ 409a0bf528SMauro Carvalho Chehab do { \ 419a0bf528SMauro Carvalho Chehab if (debug) \ 429a0bf528SMauro Carvalho Chehab printk(KERN_INFO "cx24116: " args); \ 439a0bf528SMauro Carvalho Chehab } while (0) 449a0bf528SMauro Carvalho Chehab 459a0bf528SMauro Carvalho Chehab #define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw" 469a0bf528SMauro Carvalho Chehab #define CX24116_SEARCH_RANGE_KHZ 5000 479a0bf528SMauro Carvalho Chehab 489a0bf528SMauro Carvalho Chehab /* known registers */ 499a0bf528SMauro Carvalho Chehab #define CX24116_REG_COMMAND (0x00) /* command args 0x00..0x1e */ 509a0bf528SMauro Carvalho Chehab #define CX24116_REG_EXECUTE (0x1f) /* execute command */ 519a0bf528SMauro Carvalho Chehab #define CX24116_REG_MAILBOX (0x96) /* FW or multipurpose mailbox? */ 529a0bf528SMauro Carvalho Chehab #define CX24116_REG_RESET (0x20) /* reset status > 0 */ 539a0bf528SMauro Carvalho Chehab #define CX24116_REG_SIGNAL (0x9e) /* signal low */ 549a0bf528SMauro Carvalho Chehab #define CX24116_REG_SSTATUS (0x9d) /* signal high / status */ 559a0bf528SMauro Carvalho Chehab #define CX24116_REG_QUALITY8 (0xa3) 569a0bf528SMauro Carvalho Chehab #define CX24116_REG_QSTATUS (0xbc) 579a0bf528SMauro Carvalho Chehab #define CX24116_REG_QUALITY0 (0xd5) 589a0bf528SMauro Carvalho Chehab #define CX24116_REG_BER0 (0xc9) 599a0bf528SMauro Carvalho Chehab #define CX24116_REG_BER8 (0xc8) 609a0bf528SMauro Carvalho Chehab #define CX24116_REG_BER16 (0xc7) 619a0bf528SMauro Carvalho Chehab #define CX24116_REG_BER24 (0xc6) 629a0bf528SMauro Carvalho Chehab #define CX24116_REG_UCB0 (0xcb) 639a0bf528SMauro Carvalho Chehab #define CX24116_REG_UCB8 (0xca) 649a0bf528SMauro Carvalho Chehab #define CX24116_REG_CLKDIV (0xf3) 659a0bf528SMauro Carvalho Chehab #define CX24116_REG_RATEDIV (0xf9) 669a0bf528SMauro Carvalho Chehab 679a0bf528SMauro Carvalho Chehab /* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */ 689a0bf528SMauro Carvalho Chehab #define CX24116_REG_FECSTATUS (0x9c) 699a0bf528SMauro Carvalho Chehab 709a0bf528SMauro Carvalho Chehab /* FECSTATUS bits */ 719a0bf528SMauro Carvalho Chehab /* mask to determine configured fec (not tuned) or actual fec (tuned) */ 729a0bf528SMauro Carvalho Chehab #define CX24116_FEC_FECMASK (0x1f) 739a0bf528SMauro Carvalho Chehab 749a0bf528SMauro Carvalho Chehab /* Select DVB-S demodulator, else DVB-S2 */ 759a0bf528SMauro Carvalho Chehab #define CX24116_FEC_DVBS (0x20) 769a0bf528SMauro Carvalho Chehab #define CX24116_FEC_UNKNOWN (0x40) /* Unknown/unused */ 779a0bf528SMauro Carvalho Chehab 789a0bf528SMauro Carvalho Chehab /* Pilot mode requested when tuning else always reset when tuned */ 799a0bf528SMauro Carvalho Chehab #define CX24116_FEC_PILOT (0x80) 809a0bf528SMauro Carvalho Chehab 819a0bf528SMauro Carvalho Chehab /* arg buffer size */ 829a0bf528SMauro Carvalho Chehab #define CX24116_ARGLEN (0x1e) 839a0bf528SMauro Carvalho Chehab 849a0bf528SMauro Carvalho Chehab /* rolloff */ 859a0bf528SMauro Carvalho Chehab #define CX24116_ROLLOFF_020 (0x00) 869a0bf528SMauro Carvalho Chehab #define CX24116_ROLLOFF_025 (0x01) 879a0bf528SMauro Carvalho Chehab #define CX24116_ROLLOFF_035 (0x02) 889a0bf528SMauro Carvalho Chehab 899a0bf528SMauro Carvalho Chehab /* pilot bit */ 909a0bf528SMauro Carvalho Chehab #define CX24116_PILOT_OFF (0x00) 919a0bf528SMauro Carvalho Chehab #define CX24116_PILOT_ON (0x40) 929a0bf528SMauro Carvalho Chehab 939a0bf528SMauro Carvalho Chehab /* signal status */ 949a0bf528SMauro Carvalho Chehab #define CX24116_HAS_SIGNAL (0x01) 959a0bf528SMauro Carvalho Chehab #define CX24116_HAS_CARRIER (0x02) 969a0bf528SMauro Carvalho Chehab #define CX24116_HAS_VITERBI (0x04) 979a0bf528SMauro Carvalho Chehab #define CX24116_HAS_SYNCLOCK (0x08) 989a0bf528SMauro Carvalho Chehab #define CX24116_HAS_UNKNOWN1 (0x10) 999a0bf528SMauro Carvalho Chehab #define CX24116_HAS_UNKNOWN2 (0x20) 1009a0bf528SMauro Carvalho Chehab #define CX24116_STATUS_MASK (0x0f) 1019a0bf528SMauro Carvalho Chehab #define CX24116_SIGNAL_MASK (0xc0) 1029a0bf528SMauro Carvalho Chehab 1039a0bf528SMauro Carvalho Chehab #define CX24116_DISEQC_TONEOFF (0) /* toneburst never sent */ 1049a0bf528SMauro Carvalho Chehab #define CX24116_DISEQC_TONECACHE (1) /* toneburst cached */ 1059a0bf528SMauro Carvalho Chehab #define CX24116_DISEQC_MESGCACHE (2) /* message cached */ 1069a0bf528SMauro Carvalho Chehab 1079a0bf528SMauro Carvalho Chehab /* arg offset for DiSEqC */ 1089a0bf528SMauro Carvalho Chehab #define CX24116_DISEQC_BURST (1) 1099a0bf528SMauro Carvalho Chehab #define CX24116_DISEQC_ARG2_2 (2) /* unknown value=2 */ 1109a0bf528SMauro Carvalho Chehab #define CX24116_DISEQC_ARG3_0 (3) /* unknown value=0 */ 1119a0bf528SMauro Carvalho Chehab #define CX24116_DISEQC_ARG4_0 (4) /* unknown value=0 */ 1129a0bf528SMauro Carvalho Chehab #define CX24116_DISEQC_MSGLEN (5) 1139a0bf528SMauro Carvalho Chehab #define CX24116_DISEQC_MSGOFS (6) 1149a0bf528SMauro Carvalho Chehab 1159a0bf528SMauro Carvalho Chehab /* DiSEqC burst */ 1169a0bf528SMauro Carvalho Chehab #define CX24116_DISEQC_MINI_A (0) 1179a0bf528SMauro Carvalho Chehab #define CX24116_DISEQC_MINI_B (1) 1189a0bf528SMauro Carvalho Chehab 1199a0bf528SMauro Carvalho Chehab /* DiSEqC tone burst */ 1209a0bf528SMauro Carvalho Chehab static int toneburst = 1; 1219a0bf528SMauro Carvalho Chehab module_param(toneburst, int, 0644); 1229a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, "\ 1239a0bf528SMauro Carvalho Chehab "2=MESSAGE CACHE (default:1)"); 1249a0bf528SMauro Carvalho Chehab 1259a0bf528SMauro Carvalho Chehab /* SNR measurements */ 1269a0bf528SMauro Carvalho Chehab static int esno_snr; 1279a0bf528SMauro Carvalho Chehab module_param(esno_snr, int, 0644); 1289a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(esno_snr, "SNR return units, 0=PERCENTAGE 0-100, "\ 1299a0bf528SMauro Carvalho Chehab "1=ESNO(db * 10) (default:0)"); 1309a0bf528SMauro Carvalho Chehab 1319a0bf528SMauro Carvalho Chehab enum cmds { 1329a0bf528SMauro Carvalho Chehab CMD_SET_VCO = 0x10, 1339a0bf528SMauro Carvalho Chehab CMD_TUNEREQUEST = 0x11, 1349a0bf528SMauro Carvalho Chehab CMD_MPEGCONFIG = 0x13, 1359a0bf528SMauro Carvalho Chehab CMD_TUNERINIT = 0x14, 1369a0bf528SMauro Carvalho Chehab CMD_BANDWIDTH = 0x15, 1379a0bf528SMauro Carvalho Chehab CMD_GETAGC = 0x19, 1389a0bf528SMauro Carvalho Chehab CMD_LNBCONFIG = 0x20, 1399a0bf528SMauro Carvalho Chehab CMD_LNBSEND = 0x21, /* Formerly CMD_SEND_DISEQC */ 1409a0bf528SMauro Carvalho Chehab CMD_LNBDCLEVEL = 0x22, 1419a0bf528SMauro Carvalho Chehab CMD_SET_TONE = 0x23, 1429a0bf528SMauro Carvalho Chehab CMD_UPDFWVERS = 0x35, 1439a0bf528SMauro Carvalho Chehab CMD_TUNERSLEEP = 0x36, 1449a0bf528SMauro Carvalho Chehab CMD_AGCCONTROL = 0x3b, /* Unknown */ 1459a0bf528SMauro Carvalho Chehab }; 1469a0bf528SMauro Carvalho Chehab 1479a0bf528SMauro Carvalho Chehab /* The Demod/Tuner can't easily provide these, we cache them */ 1489a0bf528SMauro Carvalho Chehab struct cx24116_tuning { 1499a0bf528SMauro Carvalho Chehab u32 frequency; 1509a0bf528SMauro Carvalho Chehab u32 symbol_rate; 1510df289a2SMauro Carvalho Chehab enum fe_spectral_inversion inversion; 1520df289a2SMauro Carvalho Chehab enum fe_code_rate fec; 1539a0bf528SMauro Carvalho Chehab 1540df289a2SMauro Carvalho Chehab enum fe_delivery_system delsys; 1550df289a2SMauro Carvalho Chehab enum fe_modulation modulation; 1560df289a2SMauro Carvalho Chehab enum fe_pilot pilot; 1570df289a2SMauro Carvalho Chehab enum fe_rolloff rolloff; 1589a0bf528SMauro Carvalho Chehab 1599a0bf528SMauro Carvalho Chehab /* Demod values */ 1609a0bf528SMauro Carvalho Chehab u8 fec_val; 1619a0bf528SMauro Carvalho Chehab u8 fec_mask; 1629a0bf528SMauro Carvalho Chehab u8 inversion_val; 1639a0bf528SMauro Carvalho Chehab u8 pilot_val; 1649a0bf528SMauro Carvalho Chehab u8 rolloff_val; 1659a0bf528SMauro Carvalho Chehab }; 1669a0bf528SMauro Carvalho Chehab 1679a0bf528SMauro Carvalho Chehab /* Basic commands that are sent to the firmware */ 1689a0bf528SMauro Carvalho Chehab struct cx24116_cmd { 1699a0bf528SMauro Carvalho Chehab u8 len; 1709a0bf528SMauro Carvalho Chehab u8 args[CX24116_ARGLEN]; 1719a0bf528SMauro Carvalho Chehab }; 1729a0bf528SMauro Carvalho Chehab 1739a0bf528SMauro Carvalho Chehab struct cx24116_state { 1749a0bf528SMauro Carvalho Chehab struct i2c_adapter *i2c; 1759a0bf528SMauro Carvalho Chehab const struct cx24116_config *config; 1769a0bf528SMauro Carvalho Chehab 1779a0bf528SMauro Carvalho Chehab struct dvb_frontend frontend; 1789a0bf528SMauro Carvalho Chehab 1799a0bf528SMauro Carvalho Chehab struct cx24116_tuning dcur; 1809a0bf528SMauro Carvalho Chehab struct cx24116_tuning dnxt; 1819a0bf528SMauro Carvalho Chehab 1829a0bf528SMauro Carvalho Chehab u8 skip_fw_load; 1839a0bf528SMauro Carvalho Chehab u8 burst; 1849a0bf528SMauro Carvalho Chehab struct cx24116_cmd dsec_cmd; 1859a0bf528SMauro Carvalho Chehab }; 1869a0bf528SMauro Carvalho Chehab 1879a0bf528SMauro Carvalho Chehab static int cx24116_writereg(struct cx24116_state *state, int reg, int data) 1889a0bf528SMauro Carvalho Chehab { 1899a0bf528SMauro Carvalho Chehab u8 buf[] = { reg, data }; 1909a0bf528SMauro Carvalho Chehab struct i2c_msg msg = { .addr = state->config->demod_address, 1919a0bf528SMauro Carvalho Chehab .flags = 0, .buf = buf, .len = 2 }; 1929a0bf528SMauro Carvalho Chehab int err; 1939a0bf528SMauro Carvalho Chehab 1949a0bf528SMauro Carvalho Chehab if (debug > 1) 1959a0bf528SMauro Carvalho Chehab printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n", 1969a0bf528SMauro Carvalho Chehab __func__, reg, data); 1979a0bf528SMauro Carvalho Chehab 1989a0bf528SMauro Carvalho Chehab err = i2c_transfer(state->i2c, &msg, 1); 1999a0bf528SMauro Carvalho Chehab if (err != 1) { 2004bd69e7bSMauro Carvalho Chehab printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x, value == 0x%02x)\n", 2014bd69e7bSMauro Carvalho Chehab __func__, err, reg, data); 2029a0bf528SMauro Carvalho Chehab return -EREMOTEIO; 2039a0bf528SMauro Carvalho Chehab } 2049a0bf528SMauro Carvalho Chehab 2059a0bf528SMauro Carvalho Chehab return 0; 2069a0bf528SMauro Carvalho Chehab } 2079a0bf528SMauro Carvalho Chehab 2089a0bf528SMauro Carvalho Chehab /* Bulk byte writes to a single I2C address, for 32k firmware load */ 2099a0bf528SMauro Carvalho Chehab static int cx24116_writeregN(struct cx24116_state *state, int reg, 2109a0bf528SMauro Carvalho Chehab const u8 *data, u16 len) 2119a0bf528SMauro Carvalho Chehab { 212d303b7c5SMarkus Elfring int ret; 2139a0bf528SMauro Carvalho Chehab struct i2c_msg msg; 2149a0bf528SMauro Carvalho Chehab u8 *buf; 2159a0bf528SMauro Carvalho Chehab 2169a0bf528SMauro Carvalho Chehab buf = kmalloc(len + 1, GFP_KERNEL); 2179722e569SMarkus Elfring if (!buf) 2189722e569SMarkus Elfring return -ENOMEM; 2199a0bf528SMauro Carvalho Chehab 2209a0bf528SMauro Carvalho Chehab *(buf) = reg; 2219a0bf528SMauro Carvalho Chehab memcpy(buf + 1, data, len); 2229a0bf528SMauro Carvalho Chehab 2239a0bf528SMauro Carvalho Chehab msg.addr = state->config->demod_address; 2249a0bf528SMauro Carvalho Chehab msg.flags = 0; 2259a0bf528SMauro Carvalho Chehab msg.buf = buf; 2269a0bf528SMauro Carvalho Chehab msg.len = len + 1; 2279a0bf528SMauro Carvalho Chehab 2289a0bf528SMauro Carvalho Chehab if (debug > 1) 2299a0bf528SMauro Carvalho Chehab printk(KERN_INFO "cx24116: %s: write regN 0x%02x, len = %d\n", 2309a0bf528SMauro Carvalho Chehab __func__, reg, len); 2319a0bf528SMauro Carvalho Chehab 2329a0bf528SMauro Carvalho Chehab ret = i2c_transfer(state->i2c, &msg, 1); 2339a0bf528SMauro Carvalho Chehab if (ret != 1) { 2349a0bf528SMauro Carvalho Chehab printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n", 2359a0bf528SMauro Carvalho Chehab __func__, ret, reg); 2369a0bf528SMauro Carvalho Chehab ret = -EREMOTEIO; 2379a0bf528SMauro Carvalho Chehab } 2389a0bf528SMauro Carvalho Chehab 2399a0bf528SMauro Carvalho Chehab kfree(buf); 2409a0bf528SMauro Carvalho Chehab 2419a0bf528SMauro Carvalho Chehab return ret; 2429a0bf528SMauro Carvalho Chehab } 2439a0bf528SMauro Carvalho Chehab 2449a0bf528SMauro Carvalho Chehab static int cx24116_readreg(struct cx24116_state *state, u8 reg) 2459a0bf528SMauro Carvalho Chehab { 2469a0bf528SMauro Carvalho Chehab int ret; 2479a0bf528SMauro Carvalho Chehab u8 b0[] = { reg }; 2489a0bf528SMauro Carvalho Chehab u8 b1[] = { 0 }; 2499a0bf528SMauro Carvalho Chehab struct i2c_msg msg[] = { 2509a0bf528SMauro Carvalho Chehab { .addr = state->config->demod_address, .flags = 0, 2519a0bf528SMauro Carvalho Chehab .buf = b0, .len = 1 }, 2529a0bf528SMauro Carvalho Chehab { .addr = state->config->demod_address, .flags = I2C_M_RD, 2539a0bf528SMauro Carvalho Chehab .buf = b1, .len = 1 } 2549a0bf528SMauro Carvalho Chehab }; 2559a0bf528SMauro Carvalho Chehab 2569a0bf528SMauro Carvalho Chehab ret = i2c_transfer(state->i2c, msg, 2); 2579a0bf528SMauro Carvalho Chehab 2589a0bf528SMauro Carvalho Chehab if (ret != 2) { 2599a0bf528SMauro Carvalho Chehab printk(KERN_ERR "%s: reg=0x%x (error=%d)\n", 2609a0bf528SMauro Carvalho Chehab __func__, reg, ret); 2619a0bf528SMauro Carvalho Chehab return ret; 2629a0bf528SMauro Carvalho Chehab } 2639a0bf528SMauro Carvalho Chehab 2649a0bf528SMauro Carvalho Chehab if (debug > 1) 2659a0bf528SMauro Carvalho Chehab printk(KERN_INFO "cx24116: read reg 0x%02x, value 0x%02x\n", 2669a0bf528SMauro Carvalho Chehab reg, b1[0]); 2679a0bf528SMauro Carvalho Chehab 2689a0bf528SMauro Carvalho Chehab return b1[0]; 2699a0bf528SMauro Carvalho Chehab } 2709a0bf528SMauro Carvalho Chehab 2719a0bf528SMauro Carvalho Chehab static int cx24116_set_inversion(struct cx24116_state *state, 2720df289a2SMauro Carvalho Chehab enum fe_spectral_inversion inversion) 2739a0bf528SMauro Carvalho Chehab { 2749a0bf528SMauro Carvalho Chehab dprintk("%s(%d)\n", __func__, inversion); 2759a0bf528SMauro Carvalho Chehab 2769a0bf528SMauro Carvalho Chehab switch (inversion) { 2779a0bf528SMauro Carvalho Chehab case INVERSION_OFF: 2789a0bf528SMauro Carvalho Chehab state->dnxt.inversion_val = 0x00; 2799a0bf528SMauro Carvalho Chehab break; 2809a0bf528SMauro Carvalho Chehab case INVERSION_ON: 2819a0bf528SMauro Carvalho Chehab state->dnxt.inversion_val = 0x04; 2829a0bf528SMauro Carvalho Chehab break; 2839a0bf528SMauro Carvalho Chehab case INVERSION_AUTO: 2849a0bf528SMauro Carvalho Chehab state->dnxt.inversion_val = 0x0C; 2859a0bf528SMauro Carvalho Chehab break; 2869a0bf528SMauro Carvalho Chehab default: 2879a0bf528SMauro Carvalho Chehab return -EINVAL; 2889a0bf528SMauro Carvalho Chehab } 2899a0bf528SMauro Carvalho Chehab 2909a0bf528SMauro Carvalho Chehab state->dnxt.inversion = inversion; 2919a0bf528SMauro Carvalho Chehab 2929a0bf528SMauro Carvalho Chehab return 0; 2939a0bf528SMauro Carvalho Chehab } 2949a0bf528SMauro Carvalho Chehab 2959a0bf528SMauro Carvalho Chehab /* 2969a0bf528SMauro Carvalho Chehab * modfec (modulation and FEC) 2979a0bf528SMauro Carvalho Chehab * =========================== 2989a0bf528SMauro Carvalho Chehab * 2999a0bf528SMauro Carvalho Chehab * MOD FEC mask/val standard 3009a0bf528SMauro Carvalho Chehab * ---- -------- ----------- -------- 3019a0bf528SMauro Carvalho Chehab * QPSK FEC_1_2 0x02 0x02+X DVB-S 3029a0bf528SMauro Carvalho Chehab * QPSK FEC_2_3 0x04 0x02+X DVB-S 3039a0bf528SMauro Carvalho Chehab * QPSK FEC_3_4 0x08 0x02+X DVB-S 3049a0bf528SMauro Carvalho Chehab * QPSK FEC_4_5 0x10 0x02+X DVB-S (?) 3059a0bf528SMauro Carvalho Chehab * QPSK FEC_5_6 0x20 0x02+X DVB-S 3069a0bf528SMauro Carvalho Chehab * QPSK FEC_6_7 0x40 0x02+X DVB-S 3079a0bf528SMauro Carvalho Chehab * QPSK FEC_7_8 0x80 0x02+X DVB-S 3089a0bf528SMauro Carvalho Chehab * QPSK FEC_8_9 0x01 0x02+X DVB-S (?) (NOT SUPPORTED?) 3099a0bf528SMauro Carvalho Chehab * QPSK AUTO 0xff 0x02+X DVB-S 3109a0bf528SMauro Carvalho Chehab * 3119a0bf528SMauro Carvalho Chehab * For DVB-S high byte probably represents FEC 3129a0bf528SMauro Carvalho Chehab * and low byte selects the modulator. The high 3139a0bf528SMauro Carvalho Chehab * byte is search range mask. Bit 5 may turn 3149a0bf528SMauro Carvalho Chehab * on DVB-S and remaining bits represent some 3159a0bf528SMauro Carvalho Chehab * kind of calibration (how/what i do not know). 3169a0bf528SMauro Carvalho Chehab * 3179a0bf528SMauro Carvalho Chehab * Eg.(2/3) szap "Zone Horror" 3189a0bf528SMauro Carvalho Chehab * 3199a0bf528SMauro Carvalho Chehab * mask/val = 0x04, 0x20 3209a0bf528SMauro Carvalho Chehab * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 0 | FE_HAS_LOCK 3219a0bf528SMauro Carvalho Chehab * 3229a0bf528SMauro Carvalho Chehab * mask/val = 0x04, 0x30 3239a0bf528SMauro Carvalho Chehab * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 0 | FE_HAS_LOCK 3249a0bf528SMauro Carvalho Chehab * 3259a0bf528SMauro Carvalho Chehab * After tuning FECSTATUS contains actual FEC 3269a0bf528SMauro Carvalho Chehab * in use numbered 1 through to 8 for 1/2 .. 2/3 etc 3279a0bf528SMauro Carvalho Chehab * 3289a0bf528SMauro Carvalho Chehab * NBC=NOT/NON BACKWARD COMPATIBLE WITH DVB-S (DVB-S2 only) 3299a0bf528SMauro Carvalho Chehab * 3309a0bf528SMauro Carvalho Chehab * NBC-QPSK FEC_1_2 0x00, 0x04 DVB-S2 3319a0bf528SMauro Carvalho Chehab * NBC-QPSK FEC_3_5 0x00, 0x05 DVB-S2 3329a0bf528SMauro Carvalho Chehab * NBC-QPSK FEC_2_3 0x00, 0x06 DVB-S2 3339a0bf528SMauro Carvalho Chehab * NBC-QPSK FEC_3_4 0x00, 0x07 DVB-S2 3349a0bf528SMauro Carvalho Chehab * NBC-QPSK FEC_4_5 0x00, 0x08 DVB-S2 3359a0bf528SMauro Carvalho Chehab * NBC-QPSK FEC_5_6 0x00, 0x09 DVB-S2 3369a0bf528SMauro Carvalho Chehab * NBC-QPSK FEC_8_9 0x00, 0x0a DVB-S2 3379a0bf528SMauro Carvalho Chehab * NBC-QPSK FEC_9_10 0x00, 0x0b DVB-S2 3389a0bf528SMauro Carvalho Chehab * 3399a0bf528SMauro Carvalho Chehab * NBC-8PSK FEC_3_5 0x00, 0x0c DVB-S2 3409a0bf528SMauro Carvalho Chehab * NBC-8PSK FEC_2_3 0x00, 0x0d DVB-S2 3419a0bf528SMauro Carvalho Chehab * NBC-8PSK FEC_3_4 0x00, 0x0e DVB-S2 3429a0bf528SMauro Carvalho Chehab * NBC-8PSK FEC_5_6 0x00, 0x0f DVB-S2 3439a0bf528SMauro Carvalho Chehab * NBC-8PSK FEC_8_9 0x00, 0x10 DVB-S2 3449a0bf528SMauro Carvalho Chehab * NBC-8PSK FEC_9_10 0x00, 0x11 DVB-S2 3459a0bf528SMauro Carvalho Chehab * 3469a0bf528SMauro Carvalho Chehab * For DVB-S2 low bytes selects both modulator 3479a0bf528SMauro Carvalho Chehab * and FEC. High byte is meaningless here. To 3489a0bf528SMauro Carvalho Chehab * set pilot, bit 6 (0x40) is set. When inspecting 3499a0bf528SMauro Carvalho Chehab * FECSTATUS bit 7 (0x80) represents the pilot 3509a0bf528SMauro Carvalho Chehab * selection whilst not tuned. When tuned, actual FEC 3519a0bf528SMauro Carvalho Chehab * in use is found in FECSTATUS as per above. Pilot 3529a0bf528SMauro Carvalho Chehab * value is reset. 3539a0bf528SMauro Carvalho Chehab */ 3549a0bf528SMauro Carvalho Chehab 3559a0bf528SMauro Carvalho Chehab /* A table of modulation, fec and configuration bytes for the demod. 3569a0bf528SMauro Carvalho Chehab * Not all S2 mmodulation schemes are support and not all rates with 3579a0bf528SMauro Carvalho Chehab * a scheme are support. Especially, no auto detect when in S2 mode. 3589a0bf528SMauro Carvalho Chehab */ 3599a0bf528SMauro Carvalho Chehab static struct cx24116_modfec { 3600df289a2SMauro Carvalho Chehab enum fe_delivery_system delivery_system; 3610df289a2SMauro Carvalho Chehab enum fe_modulation modulation; 3620df289a2SMauro Carvalho Chehab enum fe_code_rate fec; 3639a0bf528SMauro Carvalho Chehab u8 mask; /* In DVBS mode this is used to autodetect */ 3649a0bf528SMauro Carvalho Chehab u8 val; /* Passed to the firmware to indicate mode selection */ 3659a0bf528SMauro Carvalho Chehab } CX24116_MODFEC_MODES[] = { 3669a0bf528SMauro Carvalho Chehab /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */ 3679a0bf528SMauro Carvalho Chehab 3689a0bf528SMauro Carvalho Chehab /*mod fec mask val */ 3699a0bf528SMauro Carvalho Chehab { SYS_DVBS, QPSK, FEC_NONE, 0xfe, 0x30 }, 3709a0bf528SMauro Carvalho Chehab { SYS_DVBS, QPSK, FEC_1_2, 0x02, 0x2e }, /* 00000010 00101110 */ 3719a0bf528SMauro Carvalho Chehab { SYS_DVBS, QPSK, FEC_2_3, 0x04, 0x2f }, /* 00000100 00101111 */ 3729a0bf528SMauro Carvalho Chehab { SYS_DVBS, QPSK, FEC_3_4, 0x08, 0x30 }, /* 00001000 00110000 */ 3739a0bf528SMauro Carvalho Chehab { SYS_DVBS, QPSK, FEC_4_5, 0xfe, 0x30 }, /* 000?0000 ? */ 3749a0bf528SMauro Carvalho Chehab { SYS_DVBS, QPSK, FEC_5_6, 0x20, 0x31 }, /* 00100000 00110001 */ 3759a0bf528SMauro Carvalho Chehab { SYS_DVBS, QPSK, FEC_6_7, 0xfe, 0x30 }, /* 0?000000 ? */ 3769a0bf528SMauro Carvalho Chehab { SYS_DVBS, QPSK, FEC_7_8, 0x80, 0x32 }, /* 10000000 00110010 */ 3779a0bf528SMauro Carvalho Chehab { SYS_DVBS, QPSK, FEC_8_9, 0xfe, 0x30 }, /* 0000000? ? */ 3789a0bf528SMauro Carvalho Chehab { SYS_DVBS, QPSK, FEC_AUTO, 0xfe, 0x30 }, 3799a0bf528SMauro Carvalho Chehab /* NBC-QPSK */ 3809a0bf528SMauro Carvalho Chehab { SYS_DVBS2, QPSK, FEC_1_2, 0x00, 0x04 }, 3819a0bf528SMauro Carvalho Chehab { SYS_DVBS2, QPSK, FEC_3_5, 0x00, 0x05 }, 3829a0bf528SMauro Carvalho Chehab { SYS_DVBS2, QPSK, FEC_2_3, 0x00, 0x06 }, 3839a0bf528SMauro Carvalho Chehab { SYS_DVBS2, QPSK, FEC_3_4, 0x00, 0x07 }, 3849a0bf528SMauro Carvalho Chehab { SYS_DVBS2, QPSK, FEC_4_5, 0x00, 0x08 }, 3859a0bf528SMauro Carvalho Chehab { SYS_DVBS2, QPSK, FEC_5_6, 0x00, 0x09 }, 3869a0bf528SMauro Carvalho Chehab { SYS_DVBS2, QPSK, FEC_8_9, 0x00, 0x0a }, 3879a0bf528SMauro Carvalho Chehab { SYS_DVBS2, QPSK, FEC_9_10, 0x00, 0x0b }, 3889a0bf528SMauro Carvalho Chehab /* 8PSK */ 3899a0bf528SMauro Carvalho Chehab { SYS_DVBS2, PSK_8, FEC_3_5, 0x00, 0x0c }, 3909a0bf528SMauro Carvalho Chehab { SYS_DVBS2, PSK_8, FEC_2_3, 0x00, 0x0d }, 3919a0bf528SMauro Carvalho Chehab { SYS_DVBS2, PSK_8, FEC_3_4, 0x00, 0x0e }, 3929a0bf528SMauro Carvalho Chehab { SYS_DVBS2, PSK_8, FEC_5_6, 0x00, 0x0f }, 3939a0bf528SMauro Carvalho Chehab { SYS_DVBS2, PSK_8, FEC_8_9, 0x00, 0x10 }, 3949a0bf528SMauro Carvalho Chehab { SYS_DVBS2, PSK_8, FEC_9_10, 0x00, 0x11 }, 3959a0bf528SMauro Carvalho Chehab /* 3969a0bf528SMauro Carvalho Chehab * `val' can be found in the FECSTATUS register when tuning. 3979a0bf528SMauro Carvalho Chehab * FECSTATUS will give the actual FEC in use if tuning was successful. 3989a0bf528SMauro Carvalho Chehab */ 3999a0bf528SMauro Carvalho Chehab }; 4009a0bf528SMauro Carvalho Chehab 4019a0bf528SMauro Carvalho Chehab static int cx24116_lookup_fecmod(struct cx24116_state *state, 4020df289a2SMauro Carvalho Chehab enum fe_delivery_system d, enum fe_modulation m, enum fe_code_rate f) 4039a0bf528SMauro Carvalho Chehab { 4049a0bf528SMauro Carvalho Chehab int i, ret = -EOPNOTSUPP; 4059a0bf528SMauro Carvalho Chehab 4069a0bf528SMauro Carvalho Chehab dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f); 4079a0bf528SMauro Carvalho Chehab 4089a0bf528SMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(CX24116_MODFEC_MODES); i++) { 4099a0bf528SMauro Carvalho Chehab if ((d == CX24116_MODFEC_MODES[i].delivery_system) && 4109a0bf528SMauro Carvalho Chehab (m == CX24116_MODFEC_MODES[i].modulation) && 4119a0bf528SMauro Carvalho Chehab (f == CX24116_MODFEC_MODES[i].fec)) { 4129a0bf528SMauro Carvalho Chehab ret = i; 4139a0bf528SMauro Carvalho Chehab break; 4149a0bf528SMauro Carvalho Chehab } 4159a0bf528SMauro Carvalho Chehab } 4169a0bf528SMauro Carvalho Chehab 4179a0bf528SMauro Carvalho Chehab return ret; 4189a0bf528SMauro Carvalho Chehab } 4199a0bf528SMauro Carvalho Chehab 4209a0bf528SMauro Carvalho Chehab static int cx24116_set_fec(struct cx24116_state *state, 4210df289a2SMauro Carvalho Chehab enum fe_delivery_system delsys, 4220df289a2SMauro Carvalho Chehab enum fe_modulation mod, 4230df289a2SMauro Carvalho Chehab enum fe_code_rate fec) 4249a0bf528SMauro Carvalho Chehab { 4259a0bf528SMauro Carvalho Chehab int ret = 0; 4269a0bf528SMauro Carvalho Chehab 4279a0bf528SMauro Carvalho Chehab dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec); 4289a0bf528SMauro Carvalho Chehab 4299a0bf528SMauro Carvalho Chehab ret = cx24116_lookup_fecmod(state, delsys, mod, fec); 4309a0bf528SMauro Carvalho Chehab 4319a0bf528SMauro Carvalho Chehab if (ret < 0) 4329a0bf528SMauro Carvalho Chehab return ret; 4339a0bf528SMauro Carvalho Chehab 4349a0bf528SMauro Carvalho Chehab state->dnxt.fec = fec; 4359a0bf528SMauro Carvalho Chehab state->dnxt.fec_val = CX24116_MODFEC_MODES[ret].val; 4369a0bf528SMauro Carvalho Chehab state->dnxt.fec_mask = CX24116_MODFEC_MODES[ret].mask; 4379a0bf528SMauro Carvalho Chehab dprintk("%s() mask/val = 0x%02x/0x%02x\n", __func__, 4389a0bf528SMauro Carvalho Chehab state->dnxt.fec_mask, state->dnxt.fec_val); 4399a0bf528SMauro Carvalho Chehab 4409a0bf528SMauro Carvalho Chehab return 0; 4419a0bf528SMauro Carvalho Chehab } 4429a0bf528SMauro Carvalho Chehab 4439a0bf528SMauro Carvalho Chehab static int cx24116_set_symbolrate(struct cx24116_state *state, u32 rate) 4449a0bf528SMauro Carvalho Chehab { 4459a0bf528SMauro Carvalho Chehab dprintk("%s(%d)\n", __func__, rate); 4469a0bf528SMauro Carvalho Chehab 4479a0bf528SMauro Carvalho Chehab /* check if symbol rate is within limits */ 4489a0bf528SMauro Carvalho Chehab if ((rate > state->frontend.ops.info.symbol_rate_max) || 4499a0bf528SMauro Carvalho Chehab (rate < state->frontend.ops.info.symbol_rate_min)) { 4509a0bf528SMauro Carvalho Chehab dprintk("%s() unsupported symbol_rate = %d\n", __func__, rate); 4519a0bf528SMauro Carvalho Chehab return -EOPNOTSUPP; 4529a0bf528SMauro Carvalho Chehab } 4539a0bf528SMauro Carvalho Chehab 4549a0bf528SMauro Carvalho Chehab state->dnxt.symbol_rate = rate; 4559a0bf528SMauro Carvalho Chehab dprintk("%s() symbol_rate = %d\n", __func__, rate); 4569a0bf528SMauro Carvalho Chehab 4579a0bf528SMauro Carvalho Chehab return 0; 4589a0bf528SMauro Carvalho Chehab } 4599a0bf528SMauro Carvalho Chehab 4609a0bf528SMauro Carvalho Chehab static int cx24116_load_firmware(struct dvb_frontend *fe, 4619a0bf528SMauro Carvalho Chehab const struct firmware *fw); 4629a0bf528SMauro Carvalho Chehab 4639a0bf528SMauro Carvalho Chehab static int cx24116_firmware_ondemand(struct dvb_frontend *fe) 4649a0bf528SMauro Carvalho Chehab { 4659a0bf528SMauro Carvalho Chehab struct cx24116_state *state = fe->demodulator_priv; 4669a0bf528SMauro Carvalho Chehab const struct firmware *fw; 4679a0bf528SMauro Carvalho Chehab int ret = 0; 4689a0bf528SMauro Carvalho Chehab 4699a0bf528SMauro Carvalho Chehab dprintk("%s()\n", __func__); 4709a0bf528SMauro Carvalho Chehab 4719a0bf528SMauro Carvalho Chehab if (cx24116_readreg(state, 0x20) > 0) { 4729a0bf528SMauro Carvalho Chehab 4739a0bf528SMauro Carvalho Chehab if (state->skip_fw_load) 4749a0bf528SMauro Carvalho Chehab return 0; 4759a0bf528SMauro Carvalho Chehab 4769a0bf528SMauro Carvalho Chehab /* Load firmware */ 4779a0bf528SMauro Carvalho Chehab /* request the firmware, this will block until loaded */ 4789a0bf528SMauro Carvalho Chehab printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", 4799a0bf528SMauro Carvalho Chehab __func__, CX24116_DEFAULT_FIRMWARE); 4809a0bf528SMauro Carvalho Chehab ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE, 4819a0bf528SMauro Carvalho Chehab state->i2c->dev.parent); 4829a0bf528SMauro Carvalho Chehab printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", 4839a0bf528SMauro Carvalho Chehab __func__); 4849a0bf528SMauro Carvalho Chehab if (ret) { 4854bd69e7bSMauro Carvalho Chehab printk(KERN_ERR "%s: No firmware uploaded (timeout or file not found?)\n", 4864bd69e7bSMauro Carvalho Chehab __func__); 4879a0bf528SMauro Carvalho Chehab return ret; 4889a0bf528SMauro Carvalho Chehab } 4899a0bf528SMauro Carvalho Chehab 4909a0bf528SMauro Carvalho Chehab /* Make sure we don't recurse back through here 4919a0bf528SMauro Carvalho Chehab * during loading */ 4929a0bf528SMauro Carvalho Chehab state->skip_fw_load = 1; 4939a0bf528SMauro Carvalho Chehab 4949a0bf528SMauro Carvalho Chehab ret = cx24116_load_firmware(fe, fw); 4959a0bf528SMauro Carvalho Chehab if (ret) 4969a0bf528SMauro Carvalho Chehab printk(KERN_ERR "%s: Writing firmware to device failed\n", 4979a0bf528SMauro Carvalho Chehab __func__); 4989a0bf528SMauro Carvalho Chehab 4999a0bf528SMauro Carvalho Chehab release_firmware(fw); 5009a0bf528SMauro Carvalho Chehab 5019a0bf528SMauro Carvalho Chehab printk(KERN_INFO "%s: Firmware upload %s\n", __func__, 5029a0bf528SMauro Carvalho Chehab ret == 0 ? "complete" : "failed"); 5039a0bf528SMauro Carvalho Chehab 5049a0bf528SMauro Carvalho Chehab /* Ensure firmware is always loaded if required */ 5059a0bf528SMauro Carvalho Chehab state->skip_fw_load = 0; 5069a0bf528SMauro Carvalho Chehab } 5079a0bf528SMauro Carvalho Chehab 5089a0bf528SMauro Carvalho Chehab return ret; 5099a0bf528SMauro Carvalho Chehab } 5109a0bf528SMauro Carvalho Chehab 5119a0bf528SMauro Carvalho Chehab /* Take a basic firmware command structure, format it 5129a0bf528SMauro Carvalho Chehab * and forward it for processing 5139a0bf528SMauro Carvalho Chehab */ 5149a0bf528SMauro Carvalho Chehab static int cx24116_cmd_execute(struct dvb_frontend *fe, struct cx24116_cmd *cmd) 5159a0bf528SMauro Carvalho Chehab { 5169a0bf528SMauro Carvalho Chehab struct cx24116_state *state = fe->demodulator_priv; 5179a0bf528SMauro Carvalho Chehab int i, ret; 5189a0bf528SMauro Carvalho Chehab 5199a0bf528SMauro Carvalho Chehab dprintk("%s()\n", __func__); 5209a0bf528SMauro Carvalho Chehab 5219a0bf528SMauro Carvalho Chehab /* Load the firmware if required */ 5229a0bf528SMauro Carvalho Chehab ret = cx24116_firmware_ondemand(fe); 5239a0bf528SMauro Carvalho Chehab if (ret != 0) { 5249a0bf528SMauro Carvalho Chehab printk(KERN_ERR "%s(): Unable initialise the firmware\n", 5259a0bf528SMauro Carvalho Chehab __func__); 5269a0bf528SMauro Carvalho Chehab return ret; 5279a0bf528SMauro Carvalho Chehab } 5289a0bf528SMauro Carvalho Chehab 5299a0bf528SMauro Carvalho Chehab /* Write the command */ 5309a0bf528SMauro Carvalho Chehab for (i = 0; i < cmd->len ; i++) { 5319a0bf528SMauro Carvalho Chehab dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]); 5329a0bf528SMauro Carvalho Chehab cx24116_writereg(state, i, cmd->args[i]); 5339a0bf528SMauro Carvalho Chehab } 5349a0bf528SMauro Carvalho Chehab 5359a0bf528SMauro Carvalho Chehab /* Start execution and wait for cmd to terminate */ 5369a0bf528SMauro Carvalho Chehab cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01); 5379a0bf528SMauro Carvalho Chehab while (cx24116_readreg(state, CX24116_REG_EXECUTE)) { 5389a0bf528SMauro Carvalho Chehab msleep(10); 5399a0bf528SMauro Carvalho Chehab if (i++ > 64) { 5409a0bf528SMauro Carvalho Chehab /* Avoid looping forever if the firmware does 5419a0bf528SMauro Carvalho Chehab not respond */ 5429a0bf528SMauro Carvalho Chehab printk(KERN_WARNING "%s() Firmware not responding\n", 5439a0bf528SMauro Carvalho Chehab __func__); 5449a0bf528SMauro Carvalho Chehab return -EREMOTEIO; 5459a0bf528SMauro Carvalho Chehab } 5469a0bf528SMauro Carvalho Chehab } 5479a0bf528SMauro Carvalho Chehab return 0; 5489a0bf528SMauro Carvalho Chehab } 5499a0bf528SMauro Carvalho Chehab 5509a0bf528SMauro Carvalho Chehab static int cx24116_load_firmware(struct dvb_frontend *fe, 5519a0bf528SMauro Carvalho Chehab const struct firmware *fw) 5529a0bf528SMauro Carvalho Chehab { 5539a0bf528SMauro Carvalho Chehab struct cx24116_state *state = fe->demodulator_priv; 5549a0bf528SMauro Carvalho Chehab struct cx24116_cmd cmd; 5559a0bf528SMauro Carvalho Chehab int i, ret, len, max, remaining; 5569a0bf528SMauro Carvalho Chehab unsigned char vers[4]; 5579a0bf528SMauro Carvalho Chehab 5589a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 5599a0bf528SMauro Carvalho Chehab dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n", 5609a0bf528SMauro Carvalho Chehab fw->size, 5619a0bf528SMauro Carvalho Chehab fw->data[0], 5629a0bf528SMauro Carvalho Chehab fw->data[1], 5639a0bf528SMauro Carvalho Chehab fw->data[fw->size-2], 5649a0bf528SMauro Carvalho Chehab fw->data[fw->size-1]); 5659a0bf528SMauro Carvalho Chehab 5669a0bf528SMauro Carvalho Chehab /* Toggle 88x SRST pin to reset demod */ 5679a0bf528SMauro Carvalho Chehab if (state->config->reset_device) 5689a0bf528SMauro Carvalho Chehab state->config->reset_device(fe); 5699a0bf528SMauro Carvalho Chehab 5709a0bf528SMauro Carvalho Chehab /* Begin the firmware load process */ 5719a0bf528SMauro Carvalho Chehab /* Prepare the demod, load the firmware, cleanup after load */ 5729a0bf528SMauro Carvalho Chehab 5739a0bf528SMauro Carvalho Chehab /* Init PLL */ 5749a0bf528SMauro Carvalho Chehab cx24116_writereg(state, 0xE5, 0x00); 5759a0bf528SMauro Carvalho Chehab cx24116_writereg(state, 0xF1, 0x08); 5769a0bf528SMauro Carvalho Chehab cx24116_writereg(state, 0xF2, 0x13); 5779a0bf528SMauro Carvalho Chehab 5789a0bf528SMauro Carvalho Chehab /* Start PLL */ 5799a0bf528SMauro Carvalho Chehab cx24116_writereg(state, 0xe0, 0x03); 5809a0bf528SMauro Carvalho Chehab cx24116_writereg(state, 0xe0, 0x00); 5819a0bf528SMauro Carvalho Chehab 5829a0bf528SMauro Carvalho Chehab /* Unknown */ 5839a0bf528SMauro Carvalho Chehab cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46); 5849a0bf528SMauro Carvalho Chehab cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00); 5859a0bf528SMauro Carvalho Chehab 5869a0bf528SMauro Carvalho Chehab /* Unknown */ 5879a0bf528SMauro Carvalho Chehab cx24116_writereg(state, 0xF0, 0x03); 5889a0bf528SMauro Carvalho Chehab cx24116_writereg(state, 0xF4, 0x81); 5899a0bf528SMauro Carvalho Chehab cx24116_writereg(state, 0xF5, 0x00); 5909a0bf528SMauro Carvalho Chehab cx24116_writereg(state, 0xF6, 0x00); 5919a0bf528SMauro Carvalho Chehab 5929a0bf528SMauro Carvalho Chehab /* Split firmware to the max I2C write len and write. 5939a0bf528SMauro Carvalho Chehab * Writes whole firmware as one write when i2c_wr_max is set to 0. */ 5949a0bf528SMauro Carvalho Chehab if (state->config->i2c_wr_max) 5959a0bf528SMauro Carvalho Chehab max = state->config->i2c_wr_max; 5969a0bf528SMauro Carvalho Chehab else 5979a0bf528SMauro Carvalho Chehab max = INT_MAX; /* enough for 32k firmware */ 5989a0bf528SMauro Carvalho Chehab 5999a0bf528SMauro Carvalho Chehab for (remaining = fw->size; remaining > 0; remaining -= max - 1) { 6009a0bf528SMauro Carvalho Chehab len = remaining; 6019a0bf528SMauro Carvalho Chehab if (len > max - 1) 6029a0bf528SMauro Carvalho Chehab len = max - 1; 6039a0bf528SMauro Carvalho Chehab 6049a0bf528SMauro Carvalho Chehab cx24116_writeregN(state, 0xF7, &fw->data[fw->size - remaining], 6059a0bf528SMauro Carvalho Chehab len); 6069a0bf528SMauro Carvalho Chehab } 6079a0bf528SMauro Carvalho Chehab 6089a0bf528SMauro Carvalho Chehab cx24116_writereg(state, 0xF4, 0x10); 6099a0bf528SMauro Carvalho Chehab cx24116_writereg(state, 0xF0, 0x00); 6109a0bf528SMauro Carvalho Chehab cx24116_writereg(state, 0xF8, 0x06); 6119a0bf528SMauro Carvalho Chehab 6129a0bf528SMauro Carvalho Chehab /* Firmware CMD 10: VCO config */ 6139a0bf528SMauro Carvalho Chehab cmd.args[0x00] = CMD_SET_VCO; 6149a0bf528SMauro Carvalho Chehab cmd.args[0x01] = 0x05; 6159a0bf528SMauro Carvalho Chehab cmd.args[0x02] = 0xdc; 6169a0bf528SMauro Carvalho Chehab cmd.args[0x03] = 0xda; 6179a0bf528SMauro Carvalho Chehab cmd.args[0x04] = 0xae; 6189a0bf528SMauro Carvalho Chehab cmd.args[0x05] = 0xaa; 6199a0bf528SMauro Carvalho Chehab cmd.args[0x06] = 0x04; 6209a0bf528SMauro Carvalho Chehab cmd.args[0x07] = 0x9d; 6219a0bf528SMauro Carvalho Chehab cmd.args[0x08] = 0xfc; 6229a0bf528SMauro Carvalho Chehab cmd.args[0x09] = 0x06; 6239a0bf528SMauro Carvalho Chehab cmd.len = 0x0a; 6249a0bf528SMauro Carvalho Chehab ret = cx24116_cmd_execute(fe, &cmd); 6259a0bf528SMauro Carvalho Chehab if (ret != 0) 6269a0bf528SMauro Carvalho Chehab return ret; 6279a0bf528SMauro Carvalho Chehab 6289a0bf528SMauro Carvalho Chehab cx24116_writereg(state, CX24116_REG_SSTATUS, 0x00); 6299a0bf528SMauro Carvalho Chehab 6309a0bf528SMauro Carvalho Chehab /* Firmware CMD 14: Tuner config */ 6319a0bf528SMauro Carvalho Chehab cmd.args[0x00] = CMD_TUNERINIT; 6329a0bf528SMauro Carvalho Chehab cmd.args[0x01] = 0x00; 6339a0bf528SMauro Carvalho Chehab cmd.args[0x02] = 0x00; 6349a0bf528SMauro Carvalho Chehab cmd.len = 0x03; 6359a0bf528SMauro Carvalho Chehab ret = cx24116_cmd_execute(fe, &cmd); 6369a0bf528SMauro Carvalho Chehab if (ret != 0) 6379a0bf528SMauro Carvalho Chehab return ret; 6389a0bf528SMauro Carvalho Chehab 6399a0bf528SMauro Carvalho Chehab cx24116_writereg(state, 0xe5, 0x00); 6409a0bf528SMauro Carvalho Chehab 6419a0bf528SMauro Carvalho Chehab /* Firmware CMD 13: MPEG config */ 6429a0bf528SMauro Carvalho Chehab cmd.args[0x00] = CMD_MPEGCONFIG; 6439a0bf528SMauro Carvalho Chehab cmd.args[0x01] = 0x01; 6449a0bf528SMauro Carvalho Chehab cmd.args[0x02] = 0x75; 6459a0bf528SMauro Carvalho Chehab cmd.args[0x03] = 0x00; 6469a0bf528SMauro Carvalho Chehab if (state->config->mpg_clk_pos_pol) 6479a0bf528SMauro Carvalho Chehab cmd.args[0x04] = state->config->mpg_clk_pos_pol; 6489a0bf528SMauro Carvalho Chehab else 6499a0bf528SMauro Carvalho Chehab cmd.args[0x04] = 0x02; 6509a0bf528SMauro Carvalho Chehab cmd.args[0x05] = 0x00; 6519a0bf528SMauro Carvalho Chehab cmd.len = 0x06; 6529a0bf528SMauro Carvalho Chehab ret = cx24116_cmd_execute(fe, &cmd); 6539a0bf528SMauro Carvalho Chehab if (ret != 0) 6549a0bf528SMauro Carvalho Chehab return ret; 6559a0bf528SMauro Carvalho Chehab 6569a0bf528SMauro Carvalho Chehab /* Firmware CMD 35: Get firmware version */ 6579a0bf528SMauro Carvalho Chehab cmd.args[0x00] = CMD_UPDFWVERS; 6589a0bf528SMauro Carvalho Chehab cmd.len = 0x02; 6599a0bf528SMauro Carvalho Chehab for (i = 0; i < 4; i++) { 6609a0bf528SMauro Carvalho Chehab cmd.args[0x01] = i; 6619a0bf528SMauro Carvalho Chehab ret = cx24116_cmd_execute(fe, &cmd); 6629a0bf528SMauro Carvalho Chehab if (ret != 0) 6639a0bf528SMauro Carvalho Chehab return ret; 6649a0bf528SMauro Carvalho Chehab vers[i] = cx24116_readreg(state, CX24116_REG_MAILBOX); 6659a0bf528SMauro Carvalho Chehab } 6669a0bf528SMauro Carvalho Chehab printk(KERN_INFO "%s: FW version %i.%i.%i.%i\n", __func__, 6679a0bf528SMauro Carvalho Chehab vers[0], vers[1], vers[2], vers[3]); 6689a0bf528SMauro Carvalho Chehab 6699a0bf528SMauro Carvalho Chehab return 0; 6709a0bf528SMauro Carvalho Chehab } 6719a0bf528SMauro Carvalho Chehab 6720df289a2SMauro Carvalho Chehab static int cx24116_read_status(struct dvb_frontend *fe, enum fe_status *status) 6739a0bf528SMauro Carvalho Chehab { 6749a0bf528SMauro Carvalho Chehab struct cx24116_state *state = fe->demodulator_priv; 6759a0bf528SMauro Carvalho Chehab 6769a0bf528SMauro Carvalho Chehab int lock = cx24116_readreg(state, CX24116_REG_SSTATUS) & 6779a0bf528SMauro Carvalho Chehab CX24116_STATUS_MASK; 6789a0bf528SMauro Carvalho Chehab 6799a0bf528SMauro Carvalho Chehab dprintk("%s: status = 0x%02x\n", __func__, lock); 6809a0bf528SMauro Carvalho Chehab 6819a0bf528SMauro Carvalho Chehab *status = 0; 6829a0bf528SMauro Carvalho Chehab 6839a0bf528SMauro Carvalho Chehab if (lock & CX24116_HAS_SIGNAL) 6849a0bf528SMauro Carvalho Chehab *status |= FE_HAS_SIGNAL; 6859a0bf528SMauro Carvalho Chehab if (lock & CX24116_HAS_CARRIER) 6869a0bf528SMauro Carvalho Chehab *status |= FE_HAS_CARRIER; 6879a0bf528SMauro Carvalho Chehab if (lock & CX24116_HAS_VITERBI) 6889a0bf528SMauro Carvalho Chehab *status |= FE_HAS_VITERBI; 6899a0bf528SMauro Carvalho Chehab if (lock & CX24116_HAS_SYNCLOCK) 6909a0bf528SMauro Carvalho Chehab *status |= FE_HAS_SYNC | FE_HAS_LOCK; 6919a0bf528SMauro Carvalho Chehab 6929a0bf528SMauro Carvalho Chehab return 0; 6939a0bf528SMauro Carvalho Chehab } 6949a0bf528SMauro Carvalho Chehab 6959a0bf528SMauro Carvalho Chehab static int cx24116_read_ber(struct dvb_frontend *fe, u32 *ber) 6969a0bf528SMauro Carvalho Chehab { 6979a0bf528SMauro Carvalho Chehab struct cx24116_state *state = fe->demodulator_priv; 6989a0bf528SMauro Carvalho Chehab 6999a0bf528SMauro Carvalho Chehab dprintk("%s()\n", __func__); 7009a0bf528SMauro Carvalho Chehab 7019a0bf528SMauro Carvalho Chehab *ber = (cx24116_readreg(state, CX24116_REG_BER24) << 24) | 7029a0bf528SMauro Carvalho Chehab (cx24116_readreg(state, CX24116_REG_BER16) << 16) | 7039a0bf528SMauro Carvalho Chehab (cx24116_readreg(state, CX24116_REG_BER8) << 8) | 7049a0bf528SMauro Carvalho Chehab cx24116_readreg(state, CX24116_REG_BER0); 7059a0bf528SMauro Carvalho Chehab 7069a0bf528SMauro Carvalho Chehab return 0; 7079a0bf528SMauro Carvalho Chehab } 7089a0bf528SMauro Carvalho Chehab 7099a0bf528SMauro Carvalho Chehab /* TODO Determine function and scale appropriately */ 7109a0bf528SMauro Carvalho Chehab static int cx24116_read_signal_strength(struct dvb_frontend *fe, 7119a0bf528SMauro Carvalho Chehab u16 *signal_strength) 7129a0bf528SMauro Carvalho Chehab { 7139a0bf528SMauro Carvalho Chehab struct cx24116_state *state = fe->demodulator_priv; 7149a0bf528SMauro Carvalho Chehab struct cx24116_cmd cmd; 7159a0bf528SMauro Carvalho Chehab int ret; 7169a0bf528SMauro Carvalho Chehab u16 sig_reading; 7179a0bf528SMauro Carvalho Chehab 7189a0bf528SMauro Carvalho Chehab dprintk("%s()\n", __func__); 7199a0bf528SMauro Carvalho Chehab 7209a0bf528SMauro Carvalho Chehab /* Firmware CMD 19: Get AGC */ 7219a0bf528SMauro Carvalho Chehab cmd.args[0x00] = CMD_GETAGC; 7229a0bf528SMauro Carvalho Chehab cmd.len = 0x01; 7239a0bf528SMauro Carvalho Chehab ret = cx24116_cmd_execute(fe, &cmd); 7249a0bf528SMauro Carvalho Chehab if (ret != 0) 7259a0bf528SMauro Carvalho Chehab return ret; 7269a0bf528SMauro Carvalho Chehab 7279a0bf528SMauro Carvalho Chehab sig_reading = 7289a0bf528SMauro Carvalho Chehab (cx24116_readreg(state, 7299a0bf528SMauro Carvalho Chehab CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK) | 7309a0bf528SMauro Carvalho Chehab (cx24116_readreg(state, CX24116_REG_SIGNAL) << 6); 7319a0bf528SMauro Carvalho Chehab *signal_strength = 0 - sig_reading; 7329a0bf528SMauro Carvalho Chehab 7339a0bf528SMauro Carvalho Chehab dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", 7349a0bf528SMauro Carvalho Chehab __func__, sig_reading, *signal_strength); 7359a0bf528SMauro Carvalho Chehab 7369a0bf528SMauro Carvalho Chehab return 0; 7379a0bf528SMauro Carvalho Chehab } 7389a0bf528SMauro Carvalho Chehab 7399a0bf528SMauro Carvalho Chehab /* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */ 7409a0bf528SMauro Carvalho Chehab static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr) 7419a0bf528SMauro Carvalho Chehab { 7429a0bf528SMauro Carvalho Chehab struct cx24116_state *state = fe->demodulator_priv; 7439a0bf528SMauro Carvalho Chehab u8 snr_reading; 7449a0bf528SMauro Carvalho Chehab static const u32 snr_tab[] = { /* 10 x Table (rounded up) */ 7459a0bf528SMauro Carvalho Chehab 0x00000, 0x0199A, 0x03333, 0x04ccD, 0x06667, 7469a0bf528SMauro Carvalho Chehab 0x08000, 0x0999A, 0x0b333, 0x0cccD, 0x0e667, 7479a0bf528SMauro Carvalho Chehab 0x10000, 0x1199A, 0x13333, 0x14ccD, 0x16667, 7489a0bf528SMauro Carvalho Chehab 0x18000 }; 7499a0bf528SMauro Carvalho Chehab 7509a0bf528SMauro Carvalho Chehab dprintk("%s()\n", __func__); 7519a0bf528SMauro Carvalho Chehab 7529a0bf528SMauro Carvalho Chehab snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0); 7539a0bf528SMauro Carvalho Chehab 7549a0bf528SMauro Carvalho Chehab if (snr_reading >= 0xa0 /* 100% */) 7559a0bf528SMauro Carvalho Chehab *snr = 0xffff; 7569a0bf528SMauro Carvalho Chehab else 7579a0bf528SMauro Carvalho Chehab *snr = snr_tab[(snr_reading & 0xf0) >> 4] + 7589a0bf528SMauro Carvalho Chehab (snr_tab[(snr_reading & 0x0f)] >> 4); 7599a0bf528SMauro Carvalho Chehab 7609a0bf528SMauro Carvalho Chehab dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__, 7619a0bf528SMauro Carvalho Chehab snr_reading, *snr); 7629a0bf528SMauro Carvalho Chehab 7639a0bf528SMauro Carvalho Chehab return 0; 7649a0bf528SMauro Carvalho Chehab } 7659a0bf528SMauro Carvalho Chehab 7669a0bf528SMauro Carvalho Chehab /* The reelbox patches show the value in the registers represents 7679a0bf528SMauro Carvalho Chehab * ESNO, from 0->30db (values 0->300). We provide this value by 7689a0bf528SMauro Carvalho Chehab * default. 7699a0bf528SMauro Carvalho Chehab */ 7709a0bf528SMauro Carvalho Chehab static int cx24116_read_snr_esno(struct dvb_frontend *fe, u16 *snr) 7719a0bf528SMauro Carvalho Chehab { 7729a0bf528SMauro Carvalho Chehab struct cx24116_state *state = fe->demodulator_priv; 7739a0bf528SMauro Carvalho Chehab 7749a0bf528SMauro Carvalho Chehab dprintk("%s()\n", __func__); 7759a0bf528SMauro Carvalho Chehab 7769a0bf528SMauro Carvalho Chehab *snr = cx24116_readreg(state, CX24116_REG_QUALITY8) << 8 | 7779a0bf528SMauro Carvalho Chehab cx24116_readreg(state, CX24116_REG_QUALITY0); 7789a0bf528SMauro Carvalho Chehab 7799a0bf528SMauro Carvalho Chehab dprintk("%s: raw 0x%04x\n", __func__, *snr); 7809a0bf528SMauro Carvalho Chehab 7819a0bf528SMauro Carvalho Chehab return 0; 7829a0bf528SMauro Carvalho Chehab } 7839a0bf528SMauro Carvalho Chehab 7849a0bf528SMauro Carvalho Chehab static int cx24116_read_snr(struct dvb_frontend *fe, u16 *snr) 7859a0bf528SMauro Carvalho Chehab { 7869a0bf528SMauro Carvalho Chehab if (esno_snr == 1) 7879a0bf528SMauro Carvalho Chehab return cx24116_read_snr_esno(fe, snr); 7889a0bf528SMauro Carvalho Chehab else 7899a0bf528SMauro Carvalho Chehab return cx24116_read_snr_pct(fe, snr); 7909a0bf528SMauro Carvalho Chehab } 7919a0bf528SMauro Carvalho Chehab 7929a0bf528SMauro Carvalho Chehab static int cx24116_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) 7939a0bf528SMauro Carvalho Chehab { 7949a0bf528SMauro Carvalho Chehab struct cx24116_state *state = fe->demodulator_priv; 7959a0bf528SMauro Carvalho Chehab 7969a0bf528SMauro Carvalho Chehab dprintk("%s()\n", __func__); 7979a0bf528SMauro Carvalho Chehab 7989a0bf528SMauro Carvalho Chehab *ucblocks = (cx24116_readreg(state, CX24116_REG_UCB8) << 8) | 7999a0bf528SMauro Carvalho Chehab cx24116_readreg(state, CX24116_REG_UCB0); 8009a0bf528SMauro Carvalho Chehab 8019a0bf528SMauro Carvalho Chehab return 0; 8029a0bf528SMauro Carvalho Chehab } 8039a0bf528SMauro Carvalho Chehab 8049a0bf528SMauro Carvalho Chehab /* Overwrite the current tuning params, we are about to tune */ 8059a0bf528SMauro Carvalho Chehab static void cx24116_clone_params(struct dvb_frontend *fe) 8069a0bf528SMauro Carvalho Chehab { 8079a0bf528SMauro Carvalho Chehab struct cx24116_state *state = fe->demodulator_priv; 808ee45ddc1SEzequiel Garcia state->dcur = state->dnxt; 8099a0bf528SMauro Carvalho Chehab } 8109a0bf528SMauro Carvalho Chehab 8119a0bf528SMauro Carvalho Chehab /* Wait for LNB */ 8129a0bf528SMauro Carvalho Chehab static int cx24116_wait_for_lnb(struct dvb_frontend *fe) 8139a0bf528SMauro Carvalho Chehab { 8149a0bf528SMauro Carvalho Chehab struct cx24116_state *state = fe->demodulator_priv; 8159a0bf528SMauro Carvalho Chehab int i; 8169a0bf528SMauro Carvalho Chehab 8179a0bf528SMauro Carvalho Chehab dprintk("%s() qstatus = 0x%02x\n", __func__, 8189a0bf528SMauro Carvalho Chehab cx24116_readreg(state, CX24116_REG_QSTATUS)); 8199a0bf528SMauro Carvalho Chehab 8209a0bf528SMauro Carvalho Chehab /* Wait for up to 300 ms */ 8219a0bf528SMauro Carvalho Chehab for (i = 0; i < 30 ; i++) { 8229a0bf528SMauro Carvalho Chehab if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20) 8239a0bf528SMauro Carvalho Chehab return 0; 8249a0bf528SMauro Carvalho Chehab msleep(10); 8259a0bf528SMauro Carvalho Chehab } 8269a0bf528SMauro Carvalho Chehab 8279a0bf528SMauro Carvalho Chehab dprintk("%s(): LNB not ready\n", __func__); 8289a0bf528SMauro Carvalho Chehab 8299a0bf528SMauro Carvalho Chehab return -ETIMEDOUT; /* -EBUSY ? */ 8309a0bf528SMauro Carvalho Chehab } 8319a0bf528SMauro Carvalho Chehab 8329a0bf528SMauro Carvalho Chehab static int cx24116_set_voltage(struct dvb_frontend *fe, 8330df289a2SMauro Carvalho Chehab enum fe_sec_voltage voltage) 8349a0bf528SMauro Carvalho Chehab { 8359a0bf528SMauro Carvalho Chehab struct cx24116_cmd cmd; 8369a0bf528SMauro Carvalho Chehab int ret; 8379a0bf528SMauro Carvalho Chehab 8389a0bf528SMauro Carvalho Chehab dprintk("%s: %s\n", __func__, 8399a0bf528SMauro Carvalho Chehab voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : 8409a0bf528SMauro Carvalho Chehab voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); 8419a0bf528SMauro Carvalho Chehab 8429a0bf528SMauro Carvalho Chehab /* Wait for LNB ready */ 8439a0bf528SMauro Carvalho Chehab ret = cx24116_wait_for_lnb(fe); 8449a0bf528SMauro Carvalho Chehab if (ret != 0) 8459a0bf528SMauro Carvalho Chehab return ret; 8469a0bf528SMauro Carvalho Chehab 8479a0bf528SMauro Carvalho Chehab /* Wait for voltage/min repeat delay */ 8489a0bf528SMauro Carvalho Chehab msleep(100); 8499a0bf528SMauro Carvalho Chehab 8509a0bf528SMauro Carvalho Chehab cmd.args[0x00] = CMD_LNBDCLEVEL; 8519a0bf528SMauro Carvalho Chehab cmd.args[0x01] = (voltage == SEC_VOLTAGE_18 ? 0x01 : 0x00); 8529a0bf528SMauro Carvalho Chehab cmd.len = 0x02; 8539a0bf528SMauro Carvalho Chehab 8549a0bf528SMauro Carvalho Chehab /* Min delay time before DiSEqC send */ 8559a0bf528SMauro Carvalho Chehab msleep(15); 8569a0bf528SMauro Carvalho Chehab 8579a0bf528SMauro Carvalho Chehab return cx24116_cmd_execute(fe, &cmd); 8589a0bf528SMauro Carvalho Chehab } 8599a0bf528SMauro Carvalho Chehab 8609a0bf528SMauro Carvalho Chehab static int cx24116_set_tone(struct dvb_frontend *fe, 8610df289a2SMauro Carvalho Chehab enum fe_sec_tone_mode tone) 8629a0bf528SMauro Carvalho Chehab { 8639a0bf528SMauro Carvalho Chehab struct cx24116_cmd cmd; 8649a0bf528SMauro Carvalho Chehab int ret; 8659a0bf528SMauro Carvalho Chehab 8669a0bf528SMauro Carvalho Chehab dprintk("%s(%d)\n", __func__, tone); 8679a0bf528SMauro Carvalho Chehab if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) { 8689a0bf528SMauro Carvalho Chehab printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone); 8699a0bf528SMauro Carvalho Chehab return -EINVAL; 8709a0bf528SMauro Carvalho Chehab } 8719a0bf528SMauro Carvalho Chehab 8729a0bf528SMauro Carvalho Chehab /* Wait for LNB ready */ 8739a0bf528SMauro Carvalho Chehab ret = cx24116_wait_for_lnb(fe); 8749a0bf528SMauro Carvalho Chehab if (ret != 0) 8759a0bf528SMauro Carvalho Chehab return ret; 8769a0bf528SMauro Carvalho Chehab 8779a0bf528SMauro Carvalho Chehab /* Min delay time after DiSEqC send */ 8789a0bf528SMauro Carvalho Chehab msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */ 8799a0bf528SMauro Carvalho Chehab 8809a0bf528SMauro Carvalho Chehab /* Now we set the tone */ 8819a0bf528SMauro Carvalho Chehab cmd.args[0x00] = CMD_SET_TONE; 8829a0bf528SMauro Carvalho Chehab cmd.args[0x01] = 0x00; 8839a0bf528SMauro Carvalho Chehab cmd.args[0x02] = 0x00; 8849a0bf528SMauro Carvalho Chehab 8859a0bf528SMauro Carvalho Chehab switch (tone) { 8869a0bf528SMauro Carvalho Chehab case SEC_TONE_ON: 8879a0bf528SMauro Carvalho Chehab dprintk("%s: setting tone on\n", __func__); 8889a0bf528SMauro Carvalho Chehab cmd.args[0x03] = 0x01; 8899a0bf528SMauro Carvalho Chehab break; 8909a0bf528SMauro Carvalho Chehab case SEC_TONE_OFF: 8919a0bf528SMauro Carvalho Chehab dprintk("%s: setting tone off\n", __func__); 8929a0bf528SMauro Carvalho Chehab cmd.args[0x03] = 0x00; 8939a0bf528SMauro Carvalho Chehab break; 8949a0bf528SMauro Carvalho Chehab } 8959a0bf528SMauro Carvalho Chehab cmd.len = 0x04; 8969a0bf528SMauro Carvalho Chehab 8979a0bf528SMauro Carvalho Chehab /* Min delay time before DiSEqC send */ 8989a0bf528SMauro Carvalho Chehab msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */ 8999a0bf528SMauro Carvalho Chehab 9009a0bf528SMauro Carvalho Chehab return cx24116_cmd_execute(fe, &cmd); 9019a0bf528SMauro Carvalho Chehab } 9029a0bf528SMauro Carvalho Chehab 9039a0bf528SMauro Carvalho Chehab /* Initialise DiSEqC */ 9049a0bf528SMauro Carvalho Chehab static int cx24116_diseqc_init(struct dvb_frontend *fe) 9059a0bf528SMauro Carvalho Chehab { 9069a0bf528SMauro Carvalho Chehab struct cx24116_state *state = fe->demodulator_priv; 9079a0bf528SMauro Carvalho Chehab struct cx24116_cmd cmd; 9089a0bf528SMauro Carvalho Chehab int ret; 9099a0bf528SMauro Carvalho Chehab 9109a0bf528SMauro Carvalho Chehab /* Firmware CMD 20: LNB/DiSEqC config */ 9119a0bf528SMauro Carvalho Chehab cmd.args[0x00] = CMD_LNBCONFIG; 9129a0bf528SMauro Carvalho Chehab cmd.args[0x01] = 0x00; 9139a0bf528SMauro Carvalho Chehab cmd.args[0x02] = 0x10; 9149a0bf528SMauro Carvalho Chehab cmd.args[0x03] = 0x00; 9159a0bf528SMauro Carvalho Chehab cmd.args[0x04] = 0x8f; 9169a0bf528SMauro Carvalho Chehab cmd.args[0x05] = 0x28; 9179a0bf528SMauro Carvalho Chehab cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01; 9189a0bf528SMauro Carvalho Chehab cmd.args[0x07] = 0x01; 9199a0bf528SMauro Carvalho Chehab cmd.len = 0x08; 9209a0bf528SMauro Carvalho Chehab ret = cx24116_cmd_execute(fe, &cmd); 9219a0bf528SMauro Carvalho Chehab if (ret != 0) 9229a0bf528SMauro Carvalho Chehab return ret; 9239a0bf528SMauro Carvalho Chehab 9249a0bf528SMauro Carvalho Chehab /* Prepare a DiSEqC command */ 9259a0bf528SMauro Carvalho Chehab state->dsec_cmd.args[0x00] = CMD_LNBSEND; 9269a0bf528SMauro Carvalho Chehab 9279a0bf528SMauro Carvalho Chehab /* DiSEqC burst */ 9289a0bf528SMauro Carvalho Chehab state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A; 9299a0bf528SMauro Carvalho Chehab 9309a0bf528SMauro Carvalho Chehab /* Unknown */ 9319a0bf528SMauro Carvalho Chehab state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02; 9329a0bf528SMauro Carvalho Chehab state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00; 9339a0bf528SMauro Carvalho Chehab /* Continuation flag? */ 9349a0bf528SMauro Carvalho Chehab state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00; 9359a0bf528SMauro Carvalho Chehab 9369a0bf528SMauro Carvalho Chehab /* DiSEqC message length */ 9379a0bf528SMauro Carvalho Chehab state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00; 9389a0bf528SMauro Carvalho Chehab 9399a0bf528SMauro Carvalho Chehab /* Command length */ 9409a0bf528SMauro Carvalho Chehab state->dsec_cmd.len = CX24116_DISEQC_MSGOFS; 9419a0bf528SMauro Carvalho Chehab 9429a0bf528SMauro Carvalho Chehab return 0; 9439a0bf528SMauro Carvalho Chehab } 9449a0bf528SMauro Carvalho Chehab 9459a0bf528SMauro Carvalho Chehab /* Send DiSEqC message with derived burst (hack) || previous burst */ 9469a0bf528SMauro Carvalho Chehab static int cx24116_send_diseqc_msg(struct dvb_frontend *fe, 9479a0bf528SMauro Carvalho Chehab struct dvb_diseqc_master_cmd *d) 9489a0bf528SMauro Carvalho Chehab { 9499a0bf528SMauro Carvalho Chehab struct cx24116_state *state = fe->demodulator_priv; 9509a0bf528SMauro Carvalho Chehab int i, ret; 9519a0bf528SMauro Carvalho Chehab 9521fa2337aSMauro Carvalho Chehab /* Validate length */ 9531fa2337aSMauro Carvalho Chehab if (d->msg_len > sizeof(d->msg)) 9541fa2337aSMauro Carvalho Chehab return -EINVAL; 9551fa2337aSMauro Carvalho Chehab 9569a0bf528SMauro Carvalho Chehab /* Dump DiSEqC message */ 9579a0bf528SMauro Carvalho Chehab if (debug) { 9589a0bf528SMauro Carvalho Chehab printk(KERN_INFO "cx24116: %s(", __func__); 9599a0bf528SMauro Carvalho Chehab for (i = 0 ; i < d->msg_len ;) { 9609a0bf528SMauro Carvalho Chehab printk(KERN_INFO "0x%02x", d->msg[i]); 9619a0bf528SMauro Carvalho Chehab if (++i < d->msg_len) 9629a0bf528SMauro Carvalho Chehab printk(KERN_INFO ", "); 9639a0bf528SMauro Carvalho Chehab } 9649a0bf528SMauro Carvalho Chehab printk(") toneburst=%d\n", toneburst); 9659a0bf528SMauro Carvalho Chehab } 9669a0bf528SMauro Carvalho Chehab 9679a0bf528SMauro Carvalho Chehab /* DiSEqC message */ 9689a0bf528SMauro Carvalho Chehab for (i = 0; i < d->msg_len; i++) 9699a0bf528SMauro Carvalho Chehab state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i]; 9709a0bf528SMauro Carvalho Chehab 9719a0bf528SMauro Carvalho Chehab /* DiSEqC message length */ 9729a0bf528SMauro Carvalho Chehab state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len; 9739a0bf528SMauro Carvalho Chehab 9749a0bf528SMauro Carvalho Chehab /* Command length */ 9759a0bf528SMauro Carvalho Chehab state->dsec_cmd.len = CX24116_DISEQC_MSGOFS + 9769a0bf528SMauro Carvalho Chehab state->dsec_cmd.args[CX24116_DISEQC_MSGLEN]; 9779a0bf528SMauro Carvalho Chehab 9789a0bf528SMauro Carvalho Chehab /* DiSEqC toneburst */ 9799a0bf528SMauro Carvalho Chehab if (toneburst == CX24116_DISEQC_MESGCACHE) 9809a0bf528SMauro Carvalho Chehab /* Message is cached */ 9819a0bf528SMauro Carvalho Chehab return 0; 9829a0bf528SMauro Carvalho Chehab 9839a0bf528SMauro Carvalho Chehab else if (toneburst == CX24116_DISEQC_TONEOFF) 9849a0bf528SMauro Carvalho Chehab /* Message is sent without burst */ 9859a0bf528SMauro Carvalho Chehab state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0; 9869a0bf528SMauro Carvalho Chehab 9879a0bf528SMauro Carvalho Chehab else if (toneburst == CX24116_DISEQC_TONECACHE) { 9889a0bf528SMauro Carvalho Chehab /* 9899a0bf528SMauro Carvalho Chehab * Message is sent with derived else cached burst 9909a0bf528SMauro Carvalho Chehab * 9919a0bf528SMauro Carvalho Chehab * WRITE PORT GROUP COMMAND 38 9929a0bf528SMauro Carvalho Chehab * 9939a0bf528SMauro Carvalho Chehab * 0/A/A: E0 10 38 F0..F3 9949a0bf528SMauro Carvalho Chehab * 1/B/B: E0 10 38 F4..F7 9959a0bf528SMauro Carvalho Chehab * 2/C/A: E0 10 38 F8..FB 9969a0bf528SMauro Carvalho Chehab * 3/D/B: E0 10 38 FC..FF 9979a0bf528SMauro Carvalho Chehab * 9989a0bf528SMauro Carvalho Chehab * databyte[3]= 8421:8421 9999a0bf528SMauro Carvalho Chehab * ABCD:WXYZ 10009a0bf528SMauro Carvalho Chehab * CLR :SET 10019a0bf528SMauro Carvalho Chehab * 10029a0bf528SMauro Carvalho Chehab * WX= PORT SELECT 0..3 (X=TONEBURST) 10039a0bf528SMauro Carvalho Chehab * Y = VOLTAGE (0=13V, 1=18V) 10049a0bf528SMauro Carvalho Chehab * Z = BAND (0=LOW, 1=HIGH(22K)) 10059a0bf528SMauro Carvalho Chehab */ 10069a0bf528SMauro Carvalho Chehab if (d->msg_len >= 4 && d->msg[2] == 0x38) 10079a0bf528SMauro Carvalho Chehab state->dsec_cmd.args[CX24116_DISEQC_BURST] = 10089a0bf528SMauro Carvalho Chehab ((d->msg[3] & 4) >> 2); 10099a0bf528SMauro Carvalho Chehab if (debug) 10109a0bf528SMauro Carvalho Chehab dprintk("%s burst=%d\n", __func__, 10119a0bf528SMauro Carvalho Chehab state->dsec_cmd.args[CX24116_DISEQC_BURST]); 10129a0bf528SMauro Carvalho Chehab } 10139a0bf528SMauro Carvalho Chehab 10149a0bf528SMauro Carvalho Chehab /* Wait for LNB ready */ 10159a0bf528SMauro Carvalho Chehab ret = cx24116_wait_for_lnb(fe); 10169a0bf528SMauro Carvalho Chehab if (ret != 0) 10179a0bf528SMauro Carvalho Chehab return ret; 10189a0bf528SMauro Carvalho Chehab 10199a0bf528SMauro Carvalho Chehab /* Wait for voltage/min repeat delay */ 10209a0bf528SMauro Carvalho Chehab msleep(100); 10219a0bf528SMauro Carvalho Chehab 10229a0bf528SMauro Carvalho Chehab /* Command */ 10239a0bf528SMauro Carvalho Chehab ret = cx24116_cmd_execute(fe, &state->dsec_cmd); 10249a0bf528SMauro Carvalho Chehab if (ret != 0) 10259a0bf528SMauro Carvalho Chehab return ret; 10269a0bf528SMauro Carvalho Chehab /* 10279a0bf528SMauro Carvalho Chehab * Wait for send 10289a0bf528SMauro Carvalho Chehab * 10299a0bf528SMauro Carvalho Chehab * Eutelsat spec: 10309a0bf528SMauro Carvalho Chehab * >15ms delay + (XXX determine if FW does this, see set_tone) 10319a0bf528SMauro Carvalho Chehab * 13.5ms per byte + 10329a0bf528SMauro Carvalho Chehab * >15ms delay + 10339a0bf528SMauro Carvalho Chehab * 12.5ms burst + 10349a0bf528SMauro Carvalho Chehab * >15ms delay (XXX determine if FW does this, see set_tone) 10359a0bf528SMauro Carvalho Chehab */ 10369a0bf528SMauro Carvalho Chehab msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 10379a0bf528SMauro Carvalho Chehab ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60)); 10389a0bf528SMauro Carvalho Chehab 10399a0bf528SMauro Carvalho Chehab return 0; 10409a0bf528SMauro Carvalho Chehab } 10419a0bf528SMauro Carvalho Chehab 10429a0bf528SMauro Carvalho Chehab /* Send DiSEqC burst */ 10439a0bf528SMauro Carvalho Chehab static int cx24116_diseqc_send_burst(struct dvb_frontend *fe, 10440df289a2SMauro Carvalho Chehab enum fe_sec_mini_cmd burst) 10459a0bf528SMauro Carvalho Chehab { 10469a0bf528SMauro Carvalho Chehab struct cx24116_state *state = fe->demodulator_priv; 10479a0bf528SMauro Carvalho Chehab int ret; 10489a0bf528SMauro Carvalho Chehab 10499a0bf528SMauro Carvalho Chehab dprintk("%s(%d) toneburst=%d\n", __func__, burst, toneburst); 10509a0bf528SMauro Carvalho Chehab 10519a0bf528SMauro Carvalho Chehab /* DiSEqC burst */ 10529a0bf528SMauro Carvalho Chehab if (burst == SEC_MINI_A) 10539a0bf528SMauro Carvalho Chehab state->dsec_cmd.args[CX24116_DISEQC_BURST] = 10549a0bf528SMauro Carvalho Chehab CX24116_DISEQC_MINI_A; 10559a0bf528SMauro Carvalho Chehab else if (burst == SEC_MINI_B) 10569a0bf528SMauro Carvalho Chehab state->dsec_cmd.args[CX24116_DISEQC_BURST] = 10579a0bf528SMauro Carvalho Chehab CX24116_DISEQC_MINI_B; 10589a0bf528SMauro Carvalho Chehab else 10599a0bf528SMauro Carvalho Chehab return -EINVAL; 10609a0bf528SMauro Carvalho Chehab 10619a0bf528SMauro Carvalho Chehab /* DiSEqC toneburst */ 10629a0bf528SMauro Carvalho Chehab if (toneburst != CX24116_DISEQC_MESGCACHE) 10639a0bf528SMauro Carvalho Chehab /* Burst is cached */ 10649a0bf528SMauro Carvalho Chehab return 0; 10659a0bf528SMauro Carvalho Chehab 10669a0bf528SMauro Carvalho Chehab /* Burst is to be sent with cached message */ 10679a0bf528SMauro Carvalho Chehab 10689a0bf528SMauro Carvalho Chehab /* Wait for LNB ready */ 10699a0bf528SMauro Carvalho Chehab ret = cx24116_wait_for_lnb(fe); 10709a0bf528SMauro Carvalho Chehab if (ret != 0) 10719a0bf528SMauro Carvalho Chehab return ret; 10729a0bf528SMauro Carvalho Chehab 10739a0bf528SMauro Carvalho Chehab /* Wait for voltage/min repeat delay */ 10749a0bf528SMauro Carvalho Chehab msleep(100); 10759a0bf528SMauro Carvalho Chehab 10769a0bf528SMauro Carvalho Chehab /* Command */ 10779a0bf528SMauro Carvalho Chehab ret = cx24116_cmd_execute(fe, &state->dsec_cmd); 10789a0bf528SMauro Carvalho Chehab if (ret != 0) 10799a0bf528SMauro Carvalho Chehab return ret; 10809a0bf528SMauro Carvalho Chehab 10819a0bf528SMauro Carvalho Chehab /* 10829a0bf528SMauro Carvalho Chehab * Wait for send 10839a0bf528SMauro Carvalho Chehab * 10849a0bf528SMauro Carvalho Chehab * Eutelsat spec: 10859a0bf528SMauro Carvalho Chehab * >15ms delay + (XXX determine if FW does this, see set_tone) 10869a0bf528SMauro Carvalho Chehab * 13.5ms per byte + 10879a0bf528SMauro Carvalho Chehab * >15ms delay + 10889a0bf528SMauro Carvalho Chehab * 12.5ms burst + 10899a0bf528SMauro Carvalho Chehab * >15ms delay (XXX determine if FW does this, see set_tone) 10909a0bf528SMauro Carvalho Chehab */ 10919a0bf528SMauro Carvalho Chehab msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60); 10929a0bf528SMauro Carvalho Chehab 10939a0bf528SMauro Carvalho Chehab return 0; 10949a0bf528SMauro Carvalho Chehab } 10959a0bf528SMauro Carvalho Chehab 10969a0bf528SMauro Carvalho Chehab static void cx24116_release(struct dvb_frontend *fe) 10979a0bf528SMauro Carvalho Chehab { 10989a0bf528SMauro Carvalho Chehab struct cx24116_state *state = fe->demodulator_priv; 10999a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 11009a0bf528SMauro Carvalho Chehab kfree(state); 11019a0bf528SMauro Carvalho Chehab } 11029a0bf528SMauro Carvalho Chehab 1103bd336e63SMax Kellermann static const struct dvb_frontend_ops cx24116_ops; 11049a0bf528SMauro Carvalho Chehab 11059a0bf528SMauro Carvalho Chehab struct dvb_frontend *cx24116_attach(const struct cx24116_config *config, 11069a0bf528SMauro Carvalho Chehab struct i2c_adapter *i2c) 11079a0bf528SMauro Carvalho Chehab { 1108d303b7c5SMarkus Elfring struct cx24116_state *state; 11099a0bf528SMauro Carvalho Chehab int ret; 11109a0bf528SMauro Carvalho Chehab 11119a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__); 11129a0bf528SMauro Carvalho Chehab 11139a0bf528SMauro Carvalho Chehab /* allocate memory for the internal state */ 11142d3da59fSMarkus Elfring state = kzalloc(sizeof(*state), GFP_KERNEL); 11159a0bf528SMauro Carvalho Chehab if (state == NULL) 11169722e569SMarkus Elfring return NULL; 11179a0bf528SMauro Carvalho Chehab 11189a0bf528SMauro Carvalho Chehab state->config = config; 11199a0bf528SMauro Carvalho Chehab state->i2c = i2c; 11209a0bf528SMauro Carvalho Chehab 11219a0bf528SMauro Carvalho Chehab /* check if the demod is present */ 11229a0bf528SMauro Carvalho Chehab ret = (cx24116_readreg(state, 0xFF) << 8) | 11239a0bf528SMauro Carvalho Chehab cx24116_readreg(state, 0xFE); 11249a0bf528SMauro Carvalho Chehab if (ret != 0x0501) { 11259722e569SMarkus Elfring kfree(state); 11269a0bf528SMauro Carvalho Chehab printk(KERN_INFO "Invalid probe, probably not a CX24116 device\n"); 11279722e569SMarkus Elfring return NULL; 11289a0bf528SMauro Carvalho Chehab } 11299a0bf528SMauro Carvalho Chehab 11309a0bf528SMauro Carvalho Chehab /* create dvb_frontend */ 11319a0bf528SMauro Carvalho Chehab memcpy(&state->frontend.ops, &cx24116_ops, 11329a0bf528SMauro Carvalho Chehab sizeof(struct dvb_frontend_ops)); 11339a0bf528SMauro Carvalho Chehab state->frontend.demodulator_priv = state; 11349a0bf528SMauro Carvalho Chehab return &state->frontend; 11359a0bf528SMauro Carvalho Chehab } 1136*86495af1SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(cx24116_attach); 11379a0bf528SMauro Carvalho Chehab 11389a0bf528SMauro Carvalho Chehab /* 11399a0bf528SMauro Carvalho Chehab * Initialise or wake up device 11409a0bf528SMauro Carvalho Chehab * 11419a0bf528SMauro Carvalho Chehab * Power config will reset and load initial firmware if required 11429a0bf528SMauro Carvalho Chehab */ 11439a0bf528SMauro Carvalho Chehab static int cx24116_initfe(struct dvb_frontend *fe) 11449a0bf528SMauro Carvalho Chehab { 11459a0bf528SMauro Carvalho Chehab struct cx24116_state *state = fe->demodulator_priv; 11469a0bf528SMauro Carvalho Chehab struct cx24116_cmd cmd; 11479a0bf528SMauro Carvalho Chehab int ret; 11489a0bf528SMauro Carvalho Chehab 11499a0bf528SMauro Carvalho Chehab dprintk("%s()\n", __func__); 11509a0bf528SMauro Carvalho Chehab 11519a0bf528SMauro Carvalho Chehab /* Power on */ 11529a0bf528SMauro Carvalho Chehab cx24116_writereg(state, 0xe0, 0); 11539a0bf528SMauro Carvalho Chehab cx24116_writereg(state, 0xe1, 0); 11549a0bf528SMauro Carvalho Chehab cx24116_writereg(state, 0xea, 0); 11559a0bf528SMauro Carvalho Chehab 11569a0bf528SMauro Carvalho Chehab /* Firmware CMD 36: Power config */ 11579a0bf528SMauro Carvalho Chehab cmd.args[0x00] = CMD_TUNERSLEEP; 11589a0bf528SMauro Carvalho Chehab cmd.args[0x01] = 0; 11599a0bf528SMauro Carvalho Chehab cmd.len = 0x02; 11609a0bf528SMauro Carvalho Chehab ret = cx24116_cmd_execute(fe, &cmd); 11619a0bf528SMauro Carvalho Chehab if (ret != 0) 11629a0bf528SMauro Carvalho Chehab return ret; 11639a0bf528SMauro Carvalho Chehab 11649a0bf528SMauro Carvalho Chehab ret = cx24116_diseqc_init(fe); 11659a0bf528SMauro Carvalho Chehab if (ret != 0) 11669a0bf528SMauro Carvalho Chehab return ret; 11679a0bf528SMauro Carvalho Chehab 11689a0bf528SMauro Carvalho Chehab /* HVR-4000 needs this */ 11699a0bf528SMauro Carvalho Chehab return cx24116_set_voltage(fe, SEC_VOLTAGE_13); 11709a0bf528SMauro Carvalho Chehab } 11719a0bf528SMauro Carvalho Chehab 11729a0bf528SMauro Carvalho Chehab /* 11739a0bf528SMauro Carvalho Chehab * Put device to sleep 11749a0bf528SMauro Carvalho Chehab */ 11759a0bf528SMauro Carvalho Chehab static int cx24116_sleep(struct dvb_frontend *fe) 11769a0bf528SMauro Carvalho Chehab { 11779a0bf528SMauro Carvalho Chehab struct cx24116_state *state = fe->demodulator_priv; 11789a0bf528SMauro Carvalho Chehab struct cx24116_cmd cmd; 11799a0bf528SMauro Carvalho Chehab int ret; 11809a0bf528SMauro Carvalho Chehab 11819a0bf528SMauro Carvalho Chehab dprintk("%s()\n", __func__); 11829a0bf528SMauro Carvalho Chehab 11839a0bf528SMauro Carvalho Chehab /* Firmware CMD 36: Power config */ 11849a0bf528SMauro Carvalho Chehab cmd.args[0x00] = CMD_TUNERSLEEP; 11859a0bf528SMauro Carvalho Chehab cmd.args[0x01] = 1; 11869a0bf528SMauro Carvalho Chehab cmd.len = 0x02; 11879a0bf528SMauro Carvalho Chehab ret = cx24116_cmd_execute(fe, &cmd); 11889a0bf528SMauro Carvalho Chehab if (ret != 0) 11899a0bf528SMauro Carvalho Chehab return ret; 11909a0bf528SMauro Carvalho Chehab 11919a0bf528SMauro Carvalho Chehab /* Power off (Shutdown clocks) */ 11929a0bf528SMauro Carvalho Chehab cx24116_writereg(state, 0xea, 0xff); 11939a0bf528SMauro Carvalho Chehab cx24116_writereg(state, 0xe1, 1); 11949a0bf528SMauro Carvalho Chehab cx24116_writereg(state, 0xe0, 1); 11959a0bf528SMauro Carvalho Chehab 11969a0bf528SMauro Carvalho Chehab return 0; 11979a0bf528SMauro Carvalho Chehab } 11989a0bf528SMauro Carvalho Chehab 11999a0bf528SMauro Carvalho Chehab /* dvb-core told us to tune, the tv property cache will be complete, 12009a0bf528SMauro Carvalho Chehab * it's safe for is to pull values and use them for tuning purposes. 12019a0bf528SMauro Carvalho Chehab */ 12029a0bf528SMauro Carvalho Chehab static int cx24116_set_frontend(struct dvb_frontend *fe) 12039a0bf528SMauro Carvalho Chehab { 12049a0bf528SMauro Carvalho Chehab struct cx24116_state *state = fe->demodulator_priv; 12059a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *c = &fe->dtv_property_cache; 12069a0bf528SMauro Carvalho Chehab struct cx24116_cmd cmd; 12070df289a2SMauro Carvalho Chehab enum fe_status tunerstat; 12089a0bf528SMauro Carvalho Chehab int i, status, ret, retune = 1; 12099a0bf528SMauro Carvalho Chehab 12109a0bf528SMauro Carvalho Chehab dprintk("%s()\n", __func__); 12119a0bf528SMauro Carvalho Chehab 12129a0bf528SMauro Carvalho Chehab switch (c->delivery_system) { 12139a0bf528SMauro Carvalho Chehab case SYS_DVBS: 12149a0bf528SMauro Carvalho Chehab dprintk("%s: DVB-S delivery system selected\n", __func__); 12159a0bf528SMauro Carvalho Chehab 12169a0bf528SMauro Carvalho Chehab /* Only QPSK is supported for DVB-S */ 12179a0bf528SMauro Carvalho Chehab if (c->modulation != QPSK) { 12189a0bf528SMauro Carvalho Chehab dprintk("%s: unsupported modulation selected (%d)\n", 12199a0bf528SMauro Carvalho Chehab __func__, c->modulation); 12209a0bf528SMauro Carvalho Chehab return -EOPNOTSUPP; 12219a0bf528SMauro Carvalho Chehab } 12229a0bf528SMauro Carvalho Chehab 12239a0bf528SMauro Carvalho Chehab /* Pilot doesn't exist in DVB-S, turn bit off */ 12249a0bf528SMauro Carvalho Chehab state->dnxt.pilot_val = CX24116_PILOT_OFF; 12259a0bf528SMauro Carvalho Chehab 12269a0bf528SMauro Carvalho Chehab /* DVB-S only supports 0.35 */ 12279a0bf528SMauro Carvalho Chehab if (c->rolloff != ROLLOFF_35) { 12289a0bf528SMauro Carvalho Chehab dprintk("%s: unsupported rolloff selected (%d)\n", 12299a0bf528SMauro Carvalho Chehab __func__, c->rolloff); 12309a0bf528SMauro Carvalho Chehab return -EOPNOTSUPP; 12319a0bf528SMauro Carvalho Chehab } 12329a0bf528SMauro Carvalho Chehab state->dnxt.rolloff_val = CX24116_ROLLOFF_035; 12339a0bf528SMauro Carvalho Chehab break; 12349a0bf528SMauro Carvalho Chehab 12359a0bf528SMauro Carvalho Chehab case SYS_DVBS2: 12369a0bf528SMauro Carvalho Chehab dprintk("%s: DVB-S2 delivery system selected\n", __func__); 12379a0bf528SMauro Carvalho Chehab 12389a0bf528SMauro Carvalho Chehab /* 12399a0bf528SMauro Carvalho Chehab * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2, 12409a0bf528SMauro Carvalho Chehab * but not hardware auto detection 12419a0bf528SMauro Carvalho Chehab */ 12429a0bf528SMauro Carvalho Chehab if (c->modulation != PSK_8 && c->modulation != QPSK) { 12439a0bf528SMauro Carvalho Chehab dprintk("%s: unsupported modulation selected (%d)\n", 12449a0bf528SMauro Carvalho Chehab __func__, c->modulation); 12459a0bf528SMauro Carvalho Chehab return -EOPNOTSUPP; 12469a0bf528SMauro Carvalho Chehab } 12479a0bf528SMauro Carvalho Chehab 12489a0bf528SMauro Carvalho Chehab switch (c->pilot) { 12499a0bf528SMauro Carvalho Chehab case PILOT_AUTO: /* Not supported but emulated */ 12509a0bf528SMauro Carvalho Chehab state->dnxt.pilot_val = (c->modulation == QPSK) 12519a0bf528SMauro Carvalho Chehab ? CX24116_PILOT_OFF : CX24116_PILOT_ON; 12529a0bf528SMauro Carvalho Chehab retune++; 12539a0bf528SMauro Carvalho Chehab break; 12549a0bf528SMauro Carvalho Chehab case PILOT_OFF: 12559a0bf528SMauro Carvalho Chehab state->dnxt.pilot_val = CX24116_PILOT_OFF; 12569a0bf528SMauro Carvalho Chehab break; 12579a0bf528SMauro Carvalho Chehab case PILOT_ON: 12589a0bf528SMauro Carvalho Chehab state->dnxt.pilot_val = CX24116_PILOT_ON; 12599a0bf528SMauro Carvalho Chehab break; 12609a0bf528SMauro Carvalho Chehab default: 12619a0bf528SMauro Carvalho Chehab dprintk("%s: unsupported pilot mode selected (%d)\n", 12629a0bf528SMauro Carvalho Chehab __func__, c->pilot); 12639a0bf528SMauro Carvalho Chehab return -EOPNOTSUPP; 12649a0bf528SMauro Carvalho Chehab } 12659a0bf528SMauro Carvalho Chehab 12669a0bf528SMauro Carvalho Chehab switch (c->rolloff) { 12679a0bf528SMauro Carvalho Chehab case ROLLOFF_20: 12689a0bf528SMauro Carvalho Chehab state->dnxt.rolloff_val = CX24116_ROLLOFF_020; 12699a0bf528SMauro Carvalho Chehab break; 12709a0bf528SMauro Carvalho Chehab case ROLLOFF_25: 12719a0bf528SMauro Carvalho Chehab state->dnxt.rolloff_val = CX24116_ROLLOFF_025; 12729a0bf528SMauro Carvalho Chehab break; 12739a0bf528SMauro Carvalho Chehab case ROLLOFF_35: 12749a0bf528SMauro Carvalho Chehab state->dnxt.rolloff_val = CX24116_ROLLOFF_035; 12759a0bf528SMauro Carvalho Chehab break; 12769a0bf528SMauro Carvalho Chehab case ROLLOFF_AUTO: /* Rolloff must be explicit */ 12779a0bf528SMauro Carvalho Chehab default: 12789a0bf528SMauro Carvalho Chehab dprintk("%s: unsupported rolloff selected (%d)\n", 12799a0bf528SMauro Carvalho Chehab __func__, c->rolloff); 12809a0bf528SMauro Carvalho Chehab return -EOPNOTSUPP; 12819a0bf528SMauro Carvalho Chehab } 12829a0bf528SMauro Carvalho Chehab break; 12839a0bf528SMauro Carvalho Chehab 12849a0bf528SMauro Carvalho Chehab default: 12859a0bf528SMauro Carvalho Chehab dprintk("%s: unsupported delivery system selected (%d)\n", 12869a0bf528SMauro Carvalho Chehab __func__, c->delivery_system); 12879a0bf528SMauro Carvalho Chehab return -EOPNOTSUPP; 12889a0bf528SMauro Carvalho Chehab } 12899a0bf528SMauro Carvalho Chehab state->dnxt.delsys = c->delivery_system; 12909a0bf528SMauro Carvalho Chehab state->dnxt.modulation = c->modulation; 12919a0bf528SMauro Carvalho Chehab state->dnxt.frequency = c->frequency; 12929a0bf528SMauro Carvalho Chehab state->dnxt.pilot = c->pilot; 12939a0bf528SMauro Carvalho Chehab state->dnxt.rolloff = c->rolloff; 12949a0bf528SMauro Carvalho Chehab 12959a0bf528SMauro Carvalho Chehab ret = cx24116_set_inversion(state, c->inversion); 12969a0bf528SMauro Carvalho Chehab if (ret != 0) 12979a0bf528SMauro Carvalho Chehab return ret; 12989a0bf528SMauro Carvalho Chehab 12999a0bf528SMauro Carvalho Chehab /* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */ 13009a0bf528SMauro Carvalho Chehab ret = cx24116_set_fec(state, c->delivery_system, c->modulation, c->fec_inner); 13019a0bf528SMauro Carvalho Chehab if (ret != 0) 13029a0bf528SMauro Carvalho Chehab return ret; 13039a0bf528SMauro Carvalho Chehab 13049a0bf528SMauro Carvalho Chehab ret = cx24116_set_symbolrate(state, c->symbol_rate); 13059a0bf528SMauro Carvalho Chehab if (ret != 0) 13069a0bf528SMauro Carvalho Chehab return ret; 13079a0bf528SMauro Carvalho Chehab 13089a0bf528SMauro Carvalho Chehab /* discard the 'current' tuning parameters and prepare to tune */ 13099a0bf528SMauro Carvalho Chehab cx24116_clone_params(fe); 13109a0bf528SMauro Carvalho Chehab 13119a0bf528SMauro Carvalho Chehab dprintk("%s: delsys = %d\n", __func__, state->dcur.delsys); 13129a0bf528SMauro Carvalho Chehab dprintk("%s: modulation = %d\n", __func__, state->dcur.modulation); 13139a0bf528SMauro Carvalho Chehab dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency); 13149a0bf528SMauro Carvalho Chehab dprintk("%s: pilot = %d (val = 0x%02x)\n", __func__, 13159a0bf528SMauro Carvalho Chehab state->dcur.pilot, state->dcur.pilot_val); 13169a0bf528SMauro Carvalho Chehab dprintk("%s: retune = %d\n", __func__, retune); 13179a0bf528SMauro Carvalho Chehab dprintk("%s: rolloff = %d (val = 0x%02x)\n", __func__, 13189a0bf528SMauro Carvalho Chehab state->dcur.rolloff, state->dcur.rolloff_val); 13199a0bf528SMauro Carvalho Chehab dprintk("%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate); 13209a0bf528SMauro Carvalho Chehab dprintk("%s: FEC = %d (mask/val = 0x%02x/0x%02x)\n", __func__, 13219a0bf528SMauro Carvalho Chehab state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val); 13229a0bf528SMauro Carvalho Chehab dprintk("%s: Inversion = %d (val = 0x%02x)\n", __func__, 13239a0bf528SMauro Carvalho Chehab state->dcur.inversion, state->dcur.inversion_val); 13249a0bf528SMauro Carvalho Chehab 13259a0bf528SMauro Carvalho Chehab /* This is also done in advise/acquire on HVR4000 but not on LITE */ 13269a0bf528SMauro Carvalho Chehab if (state->config->set_ts_params) 13279a0bf528SMauro Carvalho Chehab state->config->set_ts_params(fe, 0); 13289a0bf528SMauro Carvalho Chehab 13299a0bf528SMauro Carvalho Chehab /* Set/Reset B/W */ 13309a0bf528SMauro Carvalho Chehab cmd.args[0x00] = CMD_BANDWIDTH; 13319a0bf528SMauro Carvalho Chehab cmd.args[0x01] = 0x01; 13329a0bf528SMauro Carvalho Chehab cmd.len = 0x02; 13339a0bf528SMauro Carvalho Chehab ret = cx24116_cmd_execute(fe, &cmd); 13349a0bf528SMauro Carvalho Chehab if (ret != 0) 13359a0bf528SMauro Carvalho Chehab return ret; 13369a0bf528SMauro Carvalho Chehab 13379a0bf528SMauro Carvalho Chehab /* Prepare a tune request */ 13389a0bf528SMauro Carvalho Chehab cmd.args[0x00] = CMD_TUNEREQUEST; 13399a0bf528SMauro Carvalho Chehab 13409a0bf528SMauro Carvalho Chehab /* Frequency */ 13419a0bf528SMauro Carvalho Chehab cmd.args[0x01] = (state->dcur.frequency & 0xff0000) >> 16; 13429a0bf528SMauro Carvalho Chehab cmd.args[0x02] = (state->dcur.frequency & 0x00ff00) >> 8; 13439a0bf528SMauro Carvalho Chehab cmd.args[0x03] = (state->dcur.frequency & 0x0000ff); 13449a0bf528SMauro Carvalho Chehab 13459a0bf528SMauro Carvalho Chehab /* Symbol Rate */ 13469a0bf528SMauro Carvalho Chehab cmd.args[0x04] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8; 13479a0bf528SMauro Carvalho Chehab cmd.args[0x05] = ((state->dcur.symbol_rate / 1000) & 0x00ff); 13489a0bf528SMauro Carvalho Chehab 13499a0bf528SMauro Carvalho Chehab /* Automatic Inversion */ 13509a0bf528SMauro Carvalho Chehab cmd.args[0x06] = state->dcur.inversion_val; 13519a0bf528SMauro Carvalho Chehab 13529a0bf528SMauro Carvalho Chehab /* Modulation / FEC / Pilot */ 13539a0bf528SMauro Carvalho Chehab cmd.args[0x07] = state->dcur.fec_val | state->dcur.pilot_val; 13549a0bf528SMauro Carvalho Chehab 13559a0bf528SMauro Carvalho Chehab cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8; 13569a0bf528SMauro Carvalho Chehab cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff; 13579a0bf528SMauro Carvalho Chehab cmd.args[0x0a] = 0x00; 13589a0bf528SMauro Carvalho Chehab cmd.args[0x0b] = 0x00; 13599a0bf528SMauro Carvalho Chehab cmd.args[0x0c] = state->dcur.rolloff_val; 13609a0bf528SMauro Carvalho Chehab cmd.args[0x0d] = state->dcur.fec_mask; 13619a0bf528SMauro Carvalho Chehab 13629a0bf528SMauro Carvalho Chehab if (state->dcur.symbol_rate > 30000000) { 13639a0bf528SMauro Carvalho Chehab cmd.args[0x0e] = 0x04; 13649a0bf528SMauro Carvalho Chehab cmd.args[0x0f] = 0x00; 13659a0bf528SMauro Carvalho Chehab cmd.args[0x10] = 0x01; 13669a0bf528SMauro Carvalho Chehab cmd.args[0x11] = 0x77; 13679a0bf528SMauro Carvalho Chehab cmd.args[0x12] = 0x36; 13689a0bf528SMauro Carvalho Chehab cx24116_writereg(state, CX24116_REG_CLKDIV, 0x44); 13699a0bf528SMauro Carvalho Chehab cx24116_writereg(state, CX24116_REG_RATEDIV, 0x01); 13709a0bf528SMauro Carvalho Chehab } else { 13719a0bf528SMauro Carvalho Chehab cmd.args[0x0e] = 0x06; 13729a0bf528SMauro Carvalho Chehab cmd.args[0x0f] = 0x00; 13739a0bf528SMauro Carvalho Chehab cmd.args[0x10] = 0x00; 13749a0bf528SMauro Carvalho Chehab cmd.args[0x11] = 0xFA; 13759a0bf528SMauro Carvalho Chehab cmd.args[0x12] = 0x24; 13769a0bf528SMauro Carvalho Chehab cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46); 13779a0bf528SMauro Carvalho Chehab cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00); 13789a0bf528SMauro Carvalho Chehab } 13799a0bf528SMauro Carvalho Chehab 13809a0bf528SMauro Carvalho Chehab cmd.len = 0x13; 13819a0bf528SMauro Carvalho Chehab 13829a0bf528SMauro Carvalho Chehab /* We need to support pilot and non-pilot tuning in the 13839a0bf528SMauro Carvalho Chehab * driver automatically. This is a workaround for because 13849a0bf528SMauro Carvalho Chehab * the demod does not support autodetect. 13859a0bf528SMauro Carvalho Chehab */ 13869a0bf528SMauro Carvalho Chehab do { 13879a0bf528SMauro Carvalho Chehab /* Reset status register */ 13889a0bf528SMauro Carvalho Chehab status = cx24116_readreg(state, CX24116_REG_SSTATUS) 13899a0bf528SMauro Carvalho Chehab & CX24116_SIGNAL_MASK; 13909a0bf528SMauro Carvalho Chehab cx24116_writereg(state, CX24116_REG_SSTATUS, status); 13919a0bf528SMauro Carvalho Chehab 13929a0bf528SMauro Carvalho Chehab /* Tune */ 13939a0bf528SMauro Carvalho Chehab ret = cx24116_cmd_execute(fe, &cmd); 13949a0bf528SMauro Carvalho Chehab if (ret != 0) 13959a0bf528SMauro Carvalho Chehab break; 13969a0bf528SMauro Carvalho Chehab 13979a0bf528SMauro Carvalho Chehab /* 13989a0bf528SMauro Carvalho Chehab * Wait for up to 500 ms before retrying 13999a0bf528SMauro Carvalho Chehab * 14009a0bf528SMauro Carvalho Chehab * If we are able to tune then generally it occurs within 100ms. 14019a0bf528SMauro Carvalho Chehab * If it takes longer, try a different toneburst setting. 14029a0bf528SMauro Carvalho Chehab */ 14039a0bf528SMauro Carvalho Chehab for (i = 0; i < 50 ; i++) { 14049a0bf528SMauro Carvalho Chehab cx24116_read_status(fe, &tunerstat); 14059a0bf528SMauro Carvalho Chehab status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC); 14069a0bf528SMauro Carvalho Chehab if (status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) { 14079a0bf528SMauro Carvalho Chehab dprintk("%s: Tuned\n", __func__); 14089a0bf528SMauro Carvalho Chehab goto tuned; 14099a0bf528SMauro Carvalho Chehab } 14109a0bf528SMauro Carvalho Chehab msleep(10); 14119a0bf528SMauro Carvalho Chehab } 14129a0bf528SMauro Carvalho Chehab 14139a0bf528SMauro Carvalho Chehab dprintk("%s: Not tuned\n", __func__); 14149a0bf528SMauro Carvalho Chehab 14159a0bf528SMauro Carvalho Chehab /* Toggle pilot bit when in auto-pilot */ 14169a0bf528SMauro Carvalho Chehab if (state->dcur.pilot == PILOT_AUTO) 14179a0bf528SMauro Carvalho Chehab cmd.args[0x07] ^= CX24116_PILOT_ON; 14189a0bf528SMauro Carvalho Chehab } while (--retune); 14199a0bf528SMauro Carvalho Chehab 14209a0bf528SMauro Carvalho Chehab tuned: /* Set/Reset B/W */ 14219a0bf528SMauro Carvalho Chehab cmd.args[0x00] = CMD_BANDWIDTH; 14229a0bf528SMauro Carvalho Chehab cmd.args[0x01] = 0x00; 14239a0bf528SMauro Carvalho Chehab cmd.len = 0x02; 14249a0bf528SMauro Carvalho Chehab return cx24116_cmd_execute(fe, &cmd); 14259a0bf528SMauro Carvalho Chehab } 14269a0bf528SMauro Carvalho Chehab 14279a0bf528SMauro Carvalho Chehab static int cx24116_tune(struct dvb_frontend *fe, bool re_tune, 14280df289a2SMauro Carvalho Chehab unsigned int mode_flags, unsigned int *delay, enum fe_status *status) 14299a0bf528SMauro Carvalho Chehab { 14309a0bf528SMauro Carvalho Chehab /* 14319a0bf528SMauro Carvalho Chehab * It is safe to discard "params" here, as the DVB core will sync 14329a0bf528SMauro Carvalho Chehab * fe->dtv_property_cache with fepriv->parameters_in, where the 14339a0bf528SMauro Carvalho Chehab * DVBv3 params are stored. The only practical usage for it indicate 14349a0bf528SMauro Carvalho Chehab * that re-tuning is needed, e. g. (fepriv->state & FESTATE_RETUNE) is 14359a0bf528SMauro Carvalho Chehab * true. 14369a0bf528SMauro Carvalho Chehab */ 14379a0bf528SMauro Carvalho Chehab 14389a0bf528SMauro Carvalho Chehab *delay = HZ / 5; 14399a0bf528SMauro Carvalho Chehab if (re_tune) { 14409a0bf528SMauro Carvalho Chehab int ret = cx24116_set_frontend(fe); 14419a0bf528SMauro Carvalho Chehab if (ret) 14429a0bf528SMauro Carvalho Chehab return ret; 14439a0bf528SMauro Carvalho Chehab } 14449a0bf528SMauro Carvalho Chehab return cx24116_read_status(fe, status); 14459a0bf528SMauro Carvalho Chehab } 14469a0bf528SMauro Carvalho Chehab 14478d718e53SLuc Van Oostenryck static enum dvbfe_algo cx24116_get_algo(struct dvb_frontend *fe) 14489a0bf528SMauro Carvalho Chehab { 14499a0bf528SMauro Carvalho Chehab return DVBFE_ALGO_HW; 14509a0bf528SMauro Carvalho Chehab } 14519a0bf528SMauro Carvalho Chehab 1452bd336e63SMax Kellermann static const struct dvb_frontend_ops cx24116_ops = { 14539a0bf528SMauro Carvalho Chehab .delsys = { SYS_DVBS, SYS_DVBS2 }, 14549a0bf528SMauro Carvalho Chehab .info = { 14559a0bf528SMauro Carvalho Chehab .name = "Conexant CX24116/CX24118", 1456f1b1eabfSMauro Carvalho Chehab .frequency_min_hz = 950 * MHz, 1457f1b1eabfSMauro Carvalho Chehab .frequency_max_hz = 2150 * MHz, 1458f1b1eabfSMauro Carvalho Chehab .frequency_stepsize_hz = 1011 * kHz, 1459f1b1eabfSMauro Carvalho Chehab .frequency_tolerance_hz = 5 * MHz, 14609a0bf528SMauro Carvalho Chehab .symbol_rate_min = 1000000, 14619a0bf528SMauro Carvalho Chehab .symbol_rate_max = 45000000, 14629a0bf528SMauro Carvalho Chehab .caps = FE_CAN_INVERSION_AUTO | 14639a0bf528SMauro Carvalho Chehab FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 14649a0bf528SMauro Carvalho Chehab FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | 14659a0bf528SMauro Carvalho Chehab FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 14669a0bf528SMauro Carvalho Chehab FE_CAN_2G_MODULATION | 14679a0bf528SMauro Carvalho Chehab FE_CAN_QPSK | FE_CAN_RECOVER 14689a0bf528SMauro Carvalho Chehab }, 14699a0bf528SMauro Carvalho Chehab 14709a0bf528SMauro Carvalho Chehab .release = cx24116_release, 14719a0bf528SMauro Carvalho Chehab 14729a0bf528SMauro Carvalho Chehab .init = cx24116_initfe, 14739a0bf528SMauro Carvalho Chehab .sleep = cx24116_sleep, 14749a0bf528SMauro Carvalho Chehab .read_status = cx24116_read_status, 14759a0bf528SMauro Carvalho Chehab .read_ber = cx24116_read_ber, 14769a0bf528SMauro Carvalho Chehab .read_signal_strength = cx24116_read_signal_strength, 14779a0bf528SMauro Carvalho Chehab .read_snr = cx24116_read_snr, 14789a0bf528SMauro Carvalho Chehab .read_ucblocks = cx24116_read_ucblocks, 14799a0bf528SMauro Carvalho Chehab .set_tone = cx24116_set_tone, 14809a0bf528SMauro Carvalho Chehab .set_voltage = cx24116_set_voltage, 14819a0bf528SMauro Carvalho Chehab .diseqc_send_master_cmd = cx24116_send_diseqc_msg, 14829a0bf528SMauro Carvalho Chehab .diseqc_send_burst = cx24116_diseqc_send_burst, 14839a0bf528SMauro Carvalho Chehab .get_frontend_algo = cx24116_get_algo, 14849a0bf528SMauro Carvalho Chehab .tune = cx24116_tune, 14859a0bf528SMauro Carvalho Chehab 14869a0bf528SMauro Carvalho Chehab .set_frontend = cx24116_set_frontend, 14879a0bf528SMauro Carvalho Chehab }; 14889a0bf528SMauro Carvalho Chehab 14899a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware"); 14909a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Steven Toth"); 14919a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL"); 14929a0bf528SMauro Carvalho Chehab 1493