@@ -91,6 +91,8 @@
int feedcount;
int pid_filtering;
int fullts_streaming_state;
+ /* the stream will be activated by an externally (by the fe for example) */
+ int need_external_stream_control;
/* bus specific callbacks */
flexcop_ibi_value(*read_ibi_reg) (struct flexcop_device *,
@@ -177,6 +179,8 @@
struct dvb_demux_feed *dvbdmxfeed, int onoff);
void flexcop_hw_filter_init(struct flexcop_device *fc);
+extern void flexcop_external_stream_control(struct dvb_frontend *fe, u8 onoff);
+
void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff);
void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]);
@@ -12,6 +12,7 @@
#include "cx24113.h"
#include "cx24123.h"
#include "isl6421.h"
+#include "cx24120.h"
#include "mt352.h"
#include "bcm3510.h"
#include "nxt200x.h"
@@ -26,6 +27,15 @@
#define FE_SUPPORTED(fe) (defined(CONFIG_DVB_##fe) || \
(defined(CONFIG_DVB_##fe##_MODULE) && defined(MODULE)))
+#if FE_SUPPORTED(BCM3510) || FE_SUPPORTED(CX24120)
+static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
+ const struct firmware **fw, char* name)
+{
+ struct flexcop_device *fc = fe->dvb->priv;
+ return request_firmware(fw, name, fc->dev);
+}
+#endif
+
/* lnb control */
#if FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299)
static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
@@ -445,13 +455,6 @@
/* AirStar ATSC 1st generation */
#if FE_SUPPORTED(BCM3510)
-static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
- const struct firmware **fw, char* name)
-{
- struct flexcop_device *fc = fe->dvb->priv;
- return request_firmware(fw, name, fc->dev);
-}
-
static struct bcm3510_config air2pc_atsc_first_gen_config = {
.demod_address = 0x0f,
.request_firmware = flexcop_fe_request_firmware,
@@ -619,10 +622,40 @@
#define cablestar2_attach NULL
#endif
+/* SkyStar S2 PCI DVB-S/S2 card based on Conexant cx24120/cx24118 */
+#if FE_SUPPORTED(CX24120) && FE_SUPPORTED(ISL6421)
+static const struct cx24120_config skystar2_rev3_3_cx24120_config = {
+ .i2c_addr = 0x55,
+ .request_firmware = flexcop_fe_request_firmware,
+};
+
+static int skystarS2_rev33_attach(struct flexcop_device *fc, struct i2c_adapter *i2c)
+{
+// struct dvb_frontend_ops *ops;
+
+ fc->fe = dvb_attach(cx24120_attach,
+ &skystar2_rev3_3_cx24120_config, i2c);
+ if (fc->fe == NULL) return 0;
+ fc->dev_type = FC_SKYS2_REV33;
+ fc->fc_i2c_adap[2].no_base_addr = 1;
+ if ( (dvb_attach(isl6421_attach, fc->fe,
+ &fc->fc_i2c_adap[2].i2c_adap, 0x08, 0, 0) == NULL) ) {
+ err("ISL6421 could NOT be attached!");
+ return 0;
+ }
+ info("ISL6421 successfully attached.");
+// ops = &fc->fe->ops;
+ return 1;
+}
+#else
+#define skystarS2_rev33_attach NULL
+#endif
+
static struct {
flexcop_device_type_t type;
int (*attach)(struct flexcop_device *, struct i2c_adapter *);
} flexcop_frontends[] = {
+ { FC_SKYS2_REV33, skystarS2_rev33_attach },
{ FC_SKY_REV27, skystar2_rev27_attach },
{ FC_SKY_REV28, skystar2_rev28_attach },
{ FC_SKY_REV26, skystar2_rev26_attach },
@@ -11,6 +11,12 @@
deb_ts("rcv_data is now: '%s'\n", onoff ? "on" : "off");
}
+void flexcop_external_stream_control(struct dvb_frontend *fe, u8 onoff)
+{
+ struct flexcop_device *fc = fe->dvb->priv;
+ flexcop_rcv_data_ctrl(fc, onoff);
+}
+
void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff)
{
flexcop_set_ibi_value(ctrl_208, SMC_Enable_sig, onoff);
@@ -199,6 +205,7 @@
/* if it was the first or last feed request change the stream-status */
if (fc->feedcount == onoff) {
+ if (!fc->need_external_stream_control)
flexcop_rcv_data_ctrl(fc, onoff);
if (fc->stream_control) /* device specific stream control */
fc->stream_control(fc, onoff);
@@ -56,6 +56,7 @@
[FC_SKY_REV26] = "Sky2PC/SkyStar 2 DVB-S rev 2.6",
[FC_SKY_REV27] = "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u",
[FC_SKY_REV28] = "Sky2PC/SkyStar 2 DVB-S rev 2.8",
+ [FC_SKYS2_REV33]= "Sky2PC/SkyStar S2 DVB-S/S2 rev 3.3",
};
static const char *flexcop_bus_names[] = {
@@ -24,6 +24,7 @@
FC_SKY_REV26,
FC_SKY_REV27,
FC_SKY_REV28,
+ FC_SKYS2_REV33,
} flexcop_device_type_t;
typedef enum {
@@ -1,6 +1,7 @@
config DVB_B2C2_FLEXCOP
tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters"
depends on DVB_CORE && I2C
+ select DVB_CX24120 if !DVB_FE_CUSTOMISE
select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
@@ -0,0 +1,1053 @@
+/*
+ Conexant cx24120/cx24118 - DVBS/S2 Satellite demod/tuner driver
+ Version 0.0.4a 03.04.2012
+
+ Copyright (C) 2009 Sergey Tyurin <forum.free-x.de>
+ Updated 2012 by Jannis Achstetter <jannis_achstetter@web.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include "dvb_frontend.h"
+#include "cx24120.h"
+#include "cx24120_const.h"
+
+//==========================
+#define dbginfo(args...) do { if(cx24120_debug) { printk(KERN_DEBUG "CX24120: %s: >>> ", __func__); \
+ printk(args); } } while (0)
+#define info(args...) do { printk(KERN_INFO "CX24120: %s: -> ", __func__); \
+ printk(args); } while (0)
+#define err(args...) do { printk(KERN_ERR "CX24120: %s: ### ERROR: ", __func__); \
+ printk(args); } while (0)
+//==========================
+
+static int cx24120_debug=0;
+static int reg_debug=0;
+MODULE_DESCRIPTION("DVB Frontend module for Conexant CX24120/CX24118 hardware");
+module_param(cx24120_debug, int, 0644);
+MODULE_PARM_DESC(cx24120_debug, "Activates frontend debugging (default:0)");
+
+// ##############################
+struct cx24120_state {
+ struct i2c_adapter *i2c;
+ const struct cx24120_config *config;
+ struct dvb_frontend frontend;
+ u8 need_set_mpeg_out;
+ u8 attached;
+ u8 dvb_s2_mode;
+ u8 cold_init;
+};
+// #####################################
+// #### Command message to firmware ####
+struct cx24120_cmd { // total size = 36
+ u8 id; // [00] - message id
+ u8 arg[30]; // [04] - message first byte
+ u8 len; // [34] - message lengh or first registers to read
+ u8 reg; // [35] - number of registers to read
+};
+
+//===================================================================
+static int cx24120_readreg(struct cx24120_state *state, u8 reg)
+{
+ int ret;
+ u8 buf = 0;
+ struct i2c_msg msg[] = {
+ { .addr = state->config->i2c_addr,
+ .flags = 0,
+ .len = 1,
+ .buf = ® },
+
+ { .addr = state->config->i2c_addr,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = &buf }
+ };
+ ret = i2c_transfer(state->i2c, msg, 2);
+ if (ret != 2) {
+ err("Read error: reg=0x%02x, ret=0x%02x)\n", reg, ret);
+ return ret;
+ }
+ if (reg_debug) dbginfo("reg=0x%02x; data=0x%02x\n", reg, buf);
+ return buf;
+} // end cx24120_readreg
+//===================================================================
+static int cx24120_writereg(struct cx24120_state *state, u8 reg, u8 data)
+{
+ u8 buf[] = { reg, data };
+ struct i2c_msg msg = {
+ .addr = state->config->i2c_addr,
+ .flags = 0,
+ .buf = buf,
+ .len = 2 };
+ int ret;
+ ret = i2c_transfer(state->i2c, &msg, 1);
+ if (ret != 1) {
+ err("Write error: i2c_write error(err == %i, 0x%02x: 0x%02x)\n", ret, reg, data);
+ return ret;
+ }
+ if (reg_debug) dbginfo("reg=0x%02x; data=0x%02x\n", reg, data);
+ return 0;
+} // end cx24120_writereg
+//===================================================================
+static int cx24120_writeregN(struct cx24120_state *state, u8 reg, const u8 *values, u16 len, u8 incr)
+{
+ u8 buf[5]; /* maximum 4 data bytes at once - flexcop limitation (very limited i2c-interface this one) */
+ struct i2c_msg msg = {
+ .addr = state->config->i2c_addr,
+ .flags = 0,
+ .buf = buf,
+ .len = len };
+ int ret;
+
+ do {
+ buf[0] = reg;
+ msg.len = len > 4 ? 4 : len;
+ memcpy(&buf[1], values, msg.len);
+ len -= msg.len; // data length revers counter
+ values += msg.len; // incr data pointer
+ if (incr) reg += msg.len;
+ msg.len++; /* don't forget the addr byte */
+ ret = i2c_transfer(state->i2c, &msg, 1);
+ if (ret != 1) {
+ err("i2c_write error(err == %i, 0x%02x)\n", ret, reg);
+ return ret;
+ }
+ if (reg_debug) {
+ if( !(reg == 0xFA) && !(reg == 0x20) && !(reg == 0x21)) { // Exclude firmware upload & diseqc messages
+ dbginfo("reg=0x%02x; data=0x%02x,0x%02x,0x%02x,0x%02x\n", // from debug
+ reg, buf[1], buf[2], buf[3], buf[4]);
+ }
+ }
+ } while (len);
+ return 0;
+} // end cx24120_writeregN
+//===================================================================
+static struct dvb_frontend_ops cx24120_ops;
+//===================================================================
+struct dvb_frontend *cx24120_attach(const struct cx24120_config *config, struct i2c_adapter *i2c)
+{
+ struct cx24120_state *state = NULL;
+ int demod_rev;
+
+ info("Conexant cx24120/cx24118 - DVBS/S2 Satellite demod/tuner\n");
+ info("Driver version: 'SVT - 0.0.4a 03.04.2012'\n");
+ state = kzalloc(sizeof(struct cx24120_state),
+ GFP_KERNEL);
+ if (state == NULL) {
+ err("### Unable to allocate memory for cx24120_state structure. :(\n");
+ goto error;
+ }
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ /* check if the demod is present and has proper type */
+ demod_rev = cx24120_readreg(state, CX24120_REG_REVISION);
+ switch (demod_rev) {
+ case 0x07:
+ info("Demod CX24120 rev. 0x07 detected.\n");
+ break;
+ case 0x05:
+ info("Demod CX24120 rev. 0x05 detected.\n");
+ break;
+ default:
+ err("### Unsupported demod revision: 0x%x detected. Exit.\n", demod_rev);
+ goto error;
+ }
+ /* create dvb_frontend */
+ state->attached = 0x10; // set attached flag
+ state->cold_init=0;
+ memcpy(&state->frontend.ops, &cx24120_ops, sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+ info("Conexant cx24120/cx24118 - DVBS/S2 Satellite demod/tuner ATTACHED.\n");
+ return &state->frontend;
+
+error:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(cx24120_attach); // end cx24120_attach
+//===================================================================
+static int cx24120_test_rom(struct cx24120_state *state)
+{
+ int err, ret;
+ err = cx24120_readreg(state, 0xFD);
+ if (err & 4 )
+ {
+ ret = cx24120_readreg(state, 0xDF) & 0xFE;
+ err = cx24120_writereg(state, 0xDF, ret);
+ }
+ return err;
+} // end cx24120_test_rom
+//===================================================================
+static int cx24120_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct cx24120_state *state = fe->demodulator_priv;
+
+ *snr = (cx24120_readreg(state, CX24120_REG_QUALITY_H)<<8) |
+ (cx24120_readreg(state, CX24120_REG_QUALITY_L));
+ dbginfo("read SNR index = %d\n", *snr);
+
+ return 0;
+}
+EXPORT_SYMBOL(cx24120_read_snr); // end cx24120_read_snr
+//===================================================================
+static int cx24120_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ struct cx24120_state *state = fe->demodulator_priv;
+
+ *ber = (cx24120_readreg(state, CX24120_REG_BER_HH) << 24) | // BER high byte of high word
+ (cx24120_readreg(state, CX24120_REG_BER_HL) << 16) | // BER low byte of high word
+ (cx24120_readreg(state, CX24120_REG_BER_LH) << 8) | // BER high byte of low word
+ cx24120_readreg(state, CX24120_REG_BER_LL); // BER low byte of low word
+ dbginfo("read BER index = %d\n", *ber);
+
+ return 0;
+}
+EXPORT_SYMBOL(cx24120_read_ber); // end cx24120_read_ber
+//===================================================================
+static int cx24120_message_send(struct cx24120_state *state, struct cx24120_cmd *cmd);
+//===================================================================
+static int cx24120_msg_mpeg_output_global_config(struct cx24120_state *state, u8 flag)
+{
+ u8 tristate;
+ struct cx24120_cmd cmd;
+
+ memset(&cmd, 0, sizeof(struct cx24120_cmd));
+
+ cmd.id = 0x13; // (19) message Enable/Disable mpeg output ???
+ cmd.arg[0] = 1;
+ cmd.arg[1] = 0;
+ tristate = flag ? 0 : (u8)(-1);
+ cmd.arg[2] = tristate;
+ cmd.arg[3] = 1;
+ cmd.len = 4;
+
+ if(flag) dbginfo("MPEG output DISABLED\n");
+ else dbginfo("MPEG output ENABLED\n");
+
+ return cx24120_message_send(state, &cmd);
+} // end cx24120_msg_mpeg_output_global_config
+//===================================================================
+static int cx24120_message_send(struct cx24120_state *state, struct cx24120_cmd *cmd)
+{
+ u8 xxzz;
+ u32 msg_cmd_mask;
+ int ret, ficus;
+
+ if(state->dvb_s2_mode & 0x02) { // is MPEG enabled?
+ // if yes:
+ xxzz = cmd->id - 0x11; // look for specific message id
+ if ( xxzz <= 0x13 ) {
+ msg_cmd_mask = 1 << xxzz;
+ //0x0F8021 // if cmd_id 17 or 22 or 33-36, 42, 47, 57-61 etc. disable mpeg output
+ if ( msg_cmd_mask & 0x0F8021 ) { // 000011111000000000100001b
+ cx24120_msg_mpeg_output_global_config(state, 0);
+ msleep(100);
+ state->dvb_s2_mode &= 0xFD; // reset mpeg out enable flag
+ }
+ }
+ }
+ ret = cx24120_writereg(state, 0x00 /* reg id*/, cmd->id /* value */); // message start & target
+ ret = cx24120_writeregN(state, 0x01 /* reg msg*/, &cmd->arg[0], cmd->len /* len*/, 1 /* incr */); // message data
+ ret = cx24120_writereg(state, 0x1F /* reg msg_end */, 0x01 /* value */); // message end
+
+ ficus = 1000;
+ while ( cx24120_readreg(state, 0x1F)) { // is command done???
+ msleep(1);
+ if( !(--ficus)) {
+ err("Too long waiting 'done' state from reg(0x1F). :(\n");
+ return -EREMOTEIO;
+ }
+ }
+ dbginfo("Successfully send message 0x%02x\n", cmd->id);
+
+ if ( cmd->reg > 30 ) {
+ err("Too much registers to read. cmd->reg = %d", cmd->reg);
+ return -EREMOTEIO;
+ }
+ ficus = 0;
+ if ( cmd->reg ) { // cmd->reg - qty consecutive regs to read
+ while ( ficus < cmd->reg ){ // starts from reg No cmd->len
+ // number of registers to read is cmd->reg
+ // and write results starts from cmd->arg[0].
+ cmd->arg[ficus] = cx24120_readreg(state, (cmd->len+ficus+1));
+ ++ficus;
+ }
+ }
+ return 0;
+} // end cx24120_message_send
+//===================================================================
+static int cx24120_set_frontend(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ struct cx24120_state *state = fe->demodulator_priv;
+ struct cx24120_cmd cmd;
+ u32 srate, freq;
+ fe_code_rate_t fec;
+ fe_spectral_inversion_t inversion;
+ u8 smbr1, smbr2;
+ int ret;
+
+ memset(&cmd, 0, sizeof(struct cx24120_cmd));
+
+ cmd.id = CMD_TUNEREQUEST; // 0x11 set tuner parametrs
+ cmd.len = 15;
+
+ freq = p->frequency;
+ srate = p->symbol_rate;
+ fec = p->fec_inner;
+ inversion = p->inversion;
+
+ // check symbol rate
+ if ( srate > 31000000 ) { // if symbol rate > 31 000
+ smbr1 = (-(srate < 31000001) & 3) + 2; // ebp
+ smbr2 = (-(srate < 31000001) & 6) + 4; // edi
+ } else {
+ smbr1 = 3;
+ smbr2 = 6;
+ }
+
+ ret = cx24120_writereg(state, 0xE6, smbr1);
+ ret = cx24120_readreg(state, 0xF0);
+ ret &= 0xFFFFFFF0;
+ ret |= smbr2;
+ ret = cx24120_writereg(state, 0xF0, ret);
+
+ cmd.arg[0] = 0; // CMD_TUNER_REQUEST
+
+ // Frequency
+ cmd.arg[1] = (freq & 0xFF0000) >> 16; /* intermediate frequency in kHz */
+ cmd.arg[2] = (freq & 0x00FF00) >> 8;
+ cmd.arg[3] = (freq & 0x0000FF);
+
+ // Symbol Rate
+ cmd.arg[4] = ((srate/1000) & 0xFF00) >> 8;
+ cmd.arg[5] = ((srate/1000) & 0x00FF);
+
+ // Inversion
+ if ( inversion ) {
+ if ( inversion == 1 ) cmd.arg[6] = 4;
+ else cmd.arg[6] = 0x0C;
+ } else {
+ cmd.arg[6] = 0;
+ }
+
+ // FEC
+ switch ( fec ) // fec = p->u.qpsk.fec_inner
+ {
+ case 1: // FEC_1_2
+ cmd.arg[7] = 0x2E; break; // [11] = 0 by memset
+ case 2: // FEC_2_3
+ cmd.arg[7] = 0x2F; break;
+ case 3: // FEC_3_4
+ cmd.arg[7] = 0x30; break;
+ case 5: // FEC_5_6
+ cmd.arg[7] = 0x31; break;
+ case 7: // FEC_7_8
+ cmd.arg[7] = 0x32; break;
+ default: // FEC_NONE, FEC_4_5, FEC_6_7, FEC_8_9,
+ // FEC_AUTO, FEC_3_5, FEC_9_10
+ if ( state->dvb_s2_mode & 1 ) { // if DVB-S2 mode
+ cmd.arg[7] = 0;
+ cmd.arg[11] = 0;
+ } else {
+ cmd.arg[7] = 0x2E;
+ cmd.arg[11] = 0xAC;
+ }
+ break;
+ }
+ cmd.arg[8] = 0x13;
+ cmd.arg[9] = 0x88;
+ cmd.arg[10] = 0;
+ cmd.arg[12] = smbr2;
+ cmd.arg[13] = smbr1;
+ cmd.arg[14] = 0;
+
+ state->need_set_mpeg_out |= 0x01; // after tune we need restart mpeg out ?????
+
+ return cx24120_message_send(state, &cmd);
+
+}
+EXPORT_SYMBOL(cx24120_set_frontend); // end cx24120_set_frontend
+//===================================================================
+void cx24120_message_fill(struct cx24120_cmd *cmd,
+ u8 msg_id,
+ u8 *msg_addr,
+ u8 msg_len,
+ u8 num_regs)
+{
+ cmd->id = msg_id;
+ memcpy(&cmd->arg[0], msg_addr, msg_len);
+ cmd->len = msg_len;
+ cmd->reg = num_regs;
+} // end cx24120_message_fill
+//===================================================================
+static int cx24120_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength)
+{
+ struct cx24120_state *state = fe->demodulator_priv;
+ struct cx24120_cmd cmd;
+ int result, sigstr_h, sigstr_l;
+
+ cx24120_message_fill(&cmd, 0x1A/*msg_id*/, &cx24120_msg_read_sigstr[0], 1/*msg_len*/, 0/*num_regs*/);
+
+ if( !(cx24120_message_send(state, &cmd)) ) {
+ sigstr_h = (cx24120_readreg(state, CX24120_REG_SIGSTR_H) >> 6) << 8;
+ sigstr_l = cx24120_readreg(state, CX24120_REG_SIGSTR_L );
+ dbginfo("Signal strength from firmware= 0x%x\n", (sigstr_h | sigstr_l));
+ *signal_strength = ((sigstr_h | sigstr_l) << 5) & 0x0000FFFF;
+ dbginfo("Signal strength= 0x%x\n", *signal_strength);
+ result = 0;
+ } else {
+ err("error reading signal strength\n");
+ result = -EREMOTEIO;
+ }
+ return result;
+}
+EXPORT_SYMBOL(cx24120_read_signal_strength); // end cx24120_read_signal_strength
+//===================================================================
+static int cx24120_msg_mpeg_output_config(struct cx24120_state *state, u8 num,
+ struct cx24120_skystar2_mpeg_config *config_msg)
+{
+ struct cx24120_cmd cmd;
+
+ memset(&cmd, 0, sizeof(struct cx24120_cmd));
+
+ cmd.id = CMD_MPEG_INIT; // cmd->id=20 - message id
+ cmd.len = 7;
+ cmd.arg[0] = num; // sequental number - can be 0,1,2
+ cmd.arg[1] = ((config_msg->x1 & 0x01) << 1) |
+ ((config_msg->x1 >> 1) & 0x01);
+ cmd.arg[2] = 0x05;
+ cmd.arg[3] = 0x02;
+ cmd.arg[4] = ((config_msg->x2 >> 1) & 0x01);
+ cmd.arg[5] = (config_msg->x2 & 0xF0) | (config_msg->x3 & 0x0F);
+ cmd.arg[6] = state->attached; /* 0x10 if succesfully attached */
+
+ return cx24120_message_send(state, &cmd);
+} // end cx24120_msg_mpeg_output_config
+//===================================================================
+static int cx24120_diseqc_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst)
+{
+ struct cx24120_state *state = fe->demodulator_priv;
+ struct cx24120_cmd cmd;
+
+ memset(&cmd, 0, sizeof(struct cx24120_cmd));
+
+ cmd.id = CMD_DISEQC_BURST;
+ cmd.arg[0] = 0x00;
+ if (burst)
+ cmd.arg[1] = 0x01;
+ dbginfo("burst sent.\n");
+
+ return cx24120_message_send(state, &cmd);
+}
+EXPORT_SYMBOL(cx24120_diseqc_send_burst); // end cx24120_diseqc_send_burst
+//===================================================================
+static int cx24120_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+ struct cx24120_state *state = fe->demodulator_priv;
+ struct cx24120_cmd cmd;
+
+ dbginfo("cmd(0x23,4) - tone = %d\n", tone);
+ if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
+ err("Invalid tone=%d\n", tone);
+ return -EINVAL;
+ }
+ memset(&cmd, 0, sizeof(struct cx24120_cmd));
+ cmd.id = CMD_SETTONE; // 0x23
+ cmd.len = 4;
+ if (!tone)
+ cmd.arg[3] = 0x01;
+ return cx24120_message_send(state, &cmd);
+}
+EXPORT_SYMBOL(cx24120_set_tone); // end cx24120_set_tone
+//===================================================================
+static int cx24120_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ struct cx24120_state *state = fe->demodulator_priv;
+ struct cx24120_cmd cmd;
+
+ memset(&cmd, 0, sizeof(struct cx24120_cmd));
+ cmd.id = CMD_SETVOLTAGE; //
+ cmd.len = 2;
+ if (!(voltage - 1))
+ cmd.arg[1] = 0x01;
+ return cx24120_message_send(state, &cmd);
+}
+EXPORT_SYMBOL(cx24120_set_voltage); // end cx24120_set_voltage
+//===================================================================
+static int cx24120_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *d)
+{
+ struct cx24120_state *state = fe->demodulator_priv;
+ struct cx24120_cmd cmd;
+ int back_count;
+
+ dbginfo("Start sending diseqc sequence===============\n");
+
+ memset(&cmd, 0, sizeof(struct cx24120_cmd));
+
+ cmd.id = CMD_DISEQC_MSG1; // 0x20
+ cmd.len = 11;
+ cmd.arg[0] = 0x00;
+ cmd.arg[1] = 0x00;
+ cmd.arg[2] = 0x03;
+ cmd.arg[3] = 0x16;
+ cmd.arg[4] = 0x28;
+ cmd.arg[5] = 0x01;
+ cmd.arg[6] = 0x01;
+ cmd.arg[7] = 0x14;
+ cmd.arg[8] = 0x19;
+ cmd.arg[9] = 0x14;
+ cmd.arg[10] = 0x1E;
+ if ( cx24120_message_send(state, &cmd) ) {
+ err("send 1st message(0x%x) filed==========\n", cmd.id);
+ return -EREMOTEIO;
+ }
+ cmd.id = CMD_DISEQC_MSG2; // 0x21
+ cmd.len = d->msg_len + 6;
+ cmd.arg[0] = 0x00;
+ cmd.arg[1] = 0x01;
+ cmd.arg[2] = 0x02;
+ cmd.arg[3] = 0x00;
+ cmd.arg[4] = 0x00;
+ cmd.arg[5] = d->msg_len;
+
+ memcpy(&cmd.arg[6], &d->msg, d->msg_len);
+
+ if ( cx24120_message_send(state, &cmd) ) {
+ err("send 2d message(0x%x) filed========\n", cmd.id);
+ return -EREMOTEIO;
+ }
+ back_count = 100;
+ do {
+ if ( !(cx24120_readreg(state, 0x93) & 0x01) ) {
+ dbginfo("diseqc sequence sent success==========.\n");
+ return 0;
+ }
+ msleep(5);
+ --back_count;
+ } while ( back_count );
+ err("Too long waiting for diseqc.=============\n");
+ return -ETIMEDOUT;
+}
+EXPORT_SYMBOL(cx24120_send_diseqc_msg); // end cx24120_send_diseqc_msg
+//===================================================================
+static int cx24120_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct cx24120_state *state = fe->demodulator_priv;
+ struct cx24120_cmd cmd;
+ int ret, clock_seq_num, GettedFEC;
+ u8 mode_code, mode_8PSK_flag, attached_flag, clock_id;
+
+ ret = cx24120_readreg(state, CX24120_REG_STATUS); //0x3A
+ dbginfo("status = 0x%x\n", ret);
+ *status = 0;
+ if ( ret & CX24120_HAS_SIGNAL ) *status = FE_HAS_SIGNAL;
+ if ( ret & CX24120_HAS_CARRIER) *status |= FE_HAS_CARRIER;
+ if ( ret & CX24120_HAS_VITERBI) *status |= (FE_HAS_VITERBI + FE_HAS_SYNC);
+
+ if ( ret & CX24120_HAS_LOCK ) { // 0x08
+ *status |= FE_HAS_LOCK;
+ if ( state->need_set_mpeg_out & 1 ) { // just tuned???
+ memset(&cmd, 0, sizeof(struct cx24120_cmd));
+ cmd.id = CMD_CLOCK_READ;
+ cmd.arg[0] = 0x00;
+ cmd.len = 1; // cmd.reg != 0, so it is first register to read
+ cmd.reg = 6; // number of registers to read (0x01-0x06)
+ if ( !cx24120_message_send(state, &cmd) ) { // in cmd[0]-[5] - result
+ // 0x02-0x07
+ ret = cx24120_readreg(state, CX24120_REG_FECMODE) & 0x3F; // ntv - 0x8E(142) & 3F = 14
+ GettedFEC = ret; // 0x0d= 13
+ dbginfo("Get FEC: %d\n", ret);
+ if ( state->dvb_s2_mode & 0x01 ) { // is DVB-S2?
+ switch (ret-4) {
+ case 0:
+ mode_code = 0x01; goto mode_QPSK; // FEC_1_2 - qpsk only
+ case 1:
+ case 8:
+ mode_code = 0x64; goto mode_8PSK; // FEC_3_5 (10)- 8PSK only
+ case 2:
+ case 9:
+ mode_code = 0x02; goto mode_8PSK; // FEC_2_3
+ case 3:
+ case 10:
+ mode_code = 0x03; goto mode_8PSK; // FEC_3_4 // 14-4=10 - ntv+
+ case 4:
+ mode_code = 0x04; goto mode_QPSK; // FEC_4_5 - qpsk only
+ case 5:
+ case 11:
+ mode_code = 0x05; goto mode_8PSK; // FEC_5_6
+ case 6:
+ case 12:
+ mode_code = 0x08; goto mode_8PSK; // FEC_8_9
+ case 7:
+ case 13:
+ mode_code = 0x65; goto mode_8PSK; // FEC_9_10 (11)- 8PSK only
+ default:
+ info("Unknown DVB-S2 modefec (not QPSK or 8PSK): %d\n", ret-4);
+ mode_code = 0x01; // set like for mode 0
+ mode_8PSK:
+ if ( ret > 11 ) { // 14
+ mode_8PSK_flag = 0x63; // DVB-S2-8PSK flag
+ dbginfo("DVB-S2: 8PSK mode: %d, mode_code= 0x%x\n", ret-4, mode_code);
+ } else {
+ mode_QPSK:
+ mode_8PSK_flag = 0x00;
+ dbginfo("DVB-S2: QPSK mode: %d\n", ret-4);
+ }
+ break;
+ } // end switch
+ } // end if dvb_s2_mode // dvb-s2
+ else { // state->dvb_s2_mode & 1 = 0 -> #### DVB-S
+ switch ( ret - 2 ) {
+ case 0:
+ mode_code = 2; break; // FEC_2_3
+ case 1:
+ mode_code = 3; break; // FEC_3_4
+ case 2:
+ mode_code = 4; break; // FEC_4_5
+ case 3:
+ mode_code = 5; break; // FEC_5_6
+ case 4:
+ mode_code = 6; break; // FEC_6_7
+ case 5:
+ mode_code = 7; break; // FEC_7_8
+ default:
+ mode_code = 1;break; // FEC_1_2
+ }
+ mode_8PSK_flag = 0;
+ } // end of switch for dvb-s
+
+ attached_flag = 0x10;
+ if (state->attached == 0x10) // must be 0x10 if successfully attached in flexcop_fe_tuner
+ attached_flag = 0;
+ ret = 0;
+ if ( state->dvb_s2_mode & 0x01 ) // if dvb-s2
+ ret = (cx24120_readreg(state, CX24120_REG_FECMODE) >> 7) & 0x01; // QPSK or 8PSK ???
+ // bit 4 bit 5 bit 0 bit 3
+ clock_id = (ret << 3) | attached_flag | (state->dvb_s2_mode & 1) | 4; // possible id: 4, 5, 13. 12-impossible,
+ // ntv S2 = 0x8E -> 8 | 1 | 4 = 13 // because 7th bit of ret - is S2 flag
+ // 1/2 S2 = 0x0d -> 0 | 1 | 4 = 5
+ dbginfo("Check clock table for: clock_id=0x%x, 8PSK_mask=0x%x, mode_code=0x%x\n",
+ clock_id, mode_8PSK_flag, mode_code);
+
+ clock_seq_num = 0;
+ while ( (clock_ratios_table[clock_seq_num].ratio_id != clock_id) ||
+ (clock_ratios_table[clock_seq_num].mode_xPSK != mode_8PSK_flag) ||
+ (clock_ratios_table[clock_seq_num].fec_mode != mode_code) )
+ {
+ /* dbginfo("Check table string(%d): clock_id=%d, 8PSK_flag=%d, mode_code=%d\n", clock_seq_num,
+ * clock_ratios_table[clock_seq_num].ratio_id,
+ * clock_ratios_table[clock_seq_num].mode_xPSK,
+ * clock_ratios_table[clock_seq_num].fec_mode);
+ */
+ ++clock_seq_num;
+ if ( clock_seq_num == ARRAY_SIZE(clock_ratios_table) ) {
+ info("Check in clock table filed: unsupported modulation tuned - data reception in danger. :(\n");
+ goto settings_end;
+ }
+ }
+ //###############################
+ dbginfo("Check succesful: GetFEC: %d; post lock: m=%d, n=%d; clock_seq_idx: %d m=%d, n=%d, rate=%d\n",
+ GettedFEC,
+ cmd.arg[2] | (cmd.arg[1] << 8) | (cmd.arg[0] << 16), // registers was readed early
+ cmd.arg[5] | (cmd.arg[4] << 8) | (cmd.arg[3] << 16), // in message with id = 0x16
+ clock_seq_num,
+ clock_ratios_table[clock_seq_num].m_rat,
+ clock_ratios_table[clock_seq_num].n_rat,
+ clock_ratios_table[clock_seq_num].rate);
+ //###############################
+ cmd.id = CMD_CLOCK_SET;
+ cmd.len = 10;
+ cmd.reg = 0;
+ cmd.arg[0] = 0;
+ cmd.arg[1] = state->attached; // must be 0x10 if successfully attached in flexcop_fe_tuner
+
+ cmd.arg[2] = (clock_ratios_table[clock_seq_num].m_rat >> 16) & 0xFF;
+ cmd.arg[3] = (clock_ratios_table[clock_seq_num].m_rat >> 8) & 0xFF;
+ cmd.arg[4] = (clock_ratios_table[clock_seq_num].m_rat >> 0) & 0xFF;
+
+ cmd.arg[5] = (clock_ratios_table[clock_seq_num].n_rat >> 16) & 0xFF;
+ cmd.arg[6] = (clock_ratios_table[clock_seq_num].n_rat >> 8) & 0xFF;
+ cmd.arg[7] = (clock_ratios_table[clock_seq_num].n_rat >> 0) & 0xFF;
+
+ cmd.arg[8] = (clock_ratios_table[clock_seq_num].rate >> 8) & 0xFF;
+ cmd.arg[9] = (clock_ratios_table[clock_seq_num].rate >> 0) & 0xFF;
+
+ cx24120_message_send(state, &cmd);
+
+ settings_end:
+ msleep(200);
+ cx24120_msg_mpeg_output_global_config(state, 1);
+ state->dvb_s2_mode |= 0x02; // set mpeg flag
+ state->need_set_mpeg_out &= 0xFE; // clocks set done -> clear flag
+ }
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL(cx24120_read_status); // end cx24120_read_status
+//===================================================================
+int cx24120_init(struct dvb_frontend *fe)
+{
+ const struct firmware *fw;
+ struct cx24120_state *state = fe->demodulator_priv;
+ struct cx24120_cmd cmd;
+ u8 ret, ret_EA, reg1, fL, fH;
+ u32 vco, xtal_khz;
+ u64 inv_vco, res, xxyyzz;
+ int reset_result;
+
+ if( state->cold_init ) return 0;
+
+ ret = cx24120_writereg(state, 0xEA, 0x00);
+ ret = cx24120_test_rom(state);
+ ret = cx24120_readreg(state, 0xFB) & 0xFE;
+ ret = cx24120_writereg(state, 0xFB, ret);
+ ret = cx24120_readreg(state, 0xFC) & 0xFE;
+ ret = cx24120_writereg(state, 0xFC, ret);
+ ret = cx24120_writereg(state, 0xC3, 0x04);
+ ret = cx24120_writereg(state, 0xC4, 0x04);
+ ret = cx24120_writereg(state, 0xCE, 0x00);
+ ret = cx24120_writereg(state, 0xCF, 0x00);
+ ret_EA = cx24120_readreg(state, 0xEA) & 0xFE;
+ ret = cx24120_writereg(state, 0xEA, ret_EA);
+ ret = cx24120_writereg(state, 0xEB, 0x0C);
+ ret = cx24120_writereg(state, 0xEC, 0x06);
+ ret = cx24120_writereg(state, 0xED, 0x05);
+ ret = cx24120_writereg(state, 0xEE, 0x03);
+ ret = cx24120_writereg(state, 0xEF, 0x05);
+ ret = cx24120_writereg(state, 0xF3, 0x03);
+ ret = cx24120_writereg(state, 0xF4, 0x44);
+
+ reg1 = 0xF0;
+ do {
+ cx24120_writereg(state, reg1, 0x04);
+ cx24120_writereg(state, reg1 - 10, 0x02);
+ ++reg1;
+ } while ( reg1 != 0xF3 );
+
+ ret = cx24120_writereg(state, 0xEA, (ret_EA | 0x01));
+ reg1 = 0xC5;
+ do {
+ ret = cx24120_writereg(state, reg1, 0x00);
+ ret = cx24120_writereg(state, reg1 + 1, 0x00);
+ reg1 += 2;
+ } while ( reg1 != 0xCB );
+
+ ret = cx24120_writereg(state, 0xE4, 0x03);
+ ret = cx24120_writereg(state, 0xEB, 0x0A);
+
+ dbginfo("Requesting firmware (%s) to download...\n", CX24120_FIRMWARE);
+ ret = state->config->request_firmware(fe, &fw, CX24120_FIRMWARE);
+ if (ret) {
+ err("Could not load firmware (%s): %d\n", CX24120_FIRMWARE, ret);
+ return ret;
+ }
+ dbginfo("Firmware found and it size is %d bytes (%02x %02x .. %02x %02x)\n",
+ (int)fw->size, // firmware_size in bytes u32*
+ fw->data[0], // fw 1st byte
+ fw->data[1], // fw 2d byte
+ fw->data[fw->size - 2], // fw before last byte
+ fw->data[fw->size - 1]); // fw last byte
+
+ ret = cx24120_test_rom(state);
+ ret = cx24120_readreg(state, 0xFB) & 0xFE;
+ ret = cx24120_writereg(state, 0xFB, ret);
+ ret = cx24120_writereg(state, 0xE0, 0x76);
+ ret = cx24120_writereg(state, 0xF7, 0x81);
+ ret = cx24120_writereg(state, 0xF8, 0x00);
+ ret = cx24120_writereg(state, 0xF9, 0x00);
+ ret = cx24120_writeregN(state, 0xFA, fw->data, (fw->size - 1), 0x00);
+ ret = cx24120_writereg(state, 0xF7, 0xC0);
+ ret = cx24120_writereg(state, 0xE0, 0x00);
+ ret = (fw->size - 2) & 0x00FF;
+ ret = cx24120_writereg(state, 0xF8, ret); // ret now is 0x7a
+ ret = ((fw->size - 2) >> 8) & 0x00FF;
+ ret = cx24120_writereg(state, 0xF9, ret); // ret now is 0xaf
+ ret = cx24120_writereg(state, 0xF7, 0x00);
+ ret = cx24120_writereg(state, 0xDC, 0x00);
+ ret = cx24120_writereg(state, 0xDC, 0x07);
+ msleep(500);
+
+ ret = cx24120_readreg(state, 0xE1); // now is 0xd5 - last byte of the firmware
+ if ( ret == fw->data[fw->size - 1] ) {
+ dbginfo("Firmware uploaded successfully\n");
+ reset_result = 0;
+ } else {
+ err("Firmware upload failed. Last byte returned=0x%x\n", ret );
+ reset_result = -EREMOTEIO;
+ }
+ ret = cx24120_writereg(state, 0xDC, 0x00);
+ release_firmware(fw);
+ if (reset_result)
+ return reset_result;
+
+ //================== Start tuner
+ cx24120_message_fill(&cmd, CMD_START_TUNER, &cx24120_msg_tuner_init[0], 3, 0); // 0x1B
+ if(cx24120_message_send(state, &cmd)) {
+ err("Error tuner start! :(\n");
+ return -EREMOTEIO;
+ }
+ memset(&cmd, 0, sizeof(struct cx24120_cmd));
+
+ cmd.id = CMD_VCO_SET; // 0x10
+ cmd.len = 12;
+
+ // ######################
+ // Calc VCO
+ xtal_khz = 10111;
+ xxyyzz = 0x400000000ULL; // 17179869184
+ vco = xtal_khz * 10 * 4; // 404440
+ inv_vco = xxyyzz / vco; // 42478 = 0x00A5EE
+ res = xxyyzz % vco; // 66864 = 0x010530
+
+ if( inv_vco > xtal_khz * 10 * 2) ++inv_vco;
+
+ fH = (inv_vco >> 8) & 0xFF;
+ fL = (inv_vco) & 0xFF;
+ dbginfo("vco= %d, inv_vco= %lld, res= %lld, fL= 0x%x, fH= 0x%x\n", vco, inv_vco, res, fL, fH);
+ // ######################
+
+ cmd.arg[0] = 0x06;
+ cmd.arg[1] = 0x2B;
+ cmd.arg[2] = 0xD8;
+ cmd.arg[3] = fH; // 0xA5
+ cmd.arg[4] = fL; // 0xEE
+ cmd.arg[5] = 0x03;
+ cmd.arg[6] = 0x9D;
+ cmd.arg[7] = 0xFC;
+ cmd.arg[8] = 0x06;
+ cmd.arg[9] = 0x03;
+ cmd.arg[10] = 0x27;
+ cmd.arg[11] = 0x7F;
+
+ if(cx24120_message_send(state, &cmd)) {
+ err("Error set VCO! :(\n");
+ return -EREMOTEIO;
+ }
+ memset(&cmd, 0, sizeof(struct cx24120_cmd));
+ // set bandwidth
+ cmd.id = CMD_BANDWIDTH; // 0x15
+ cmd.len = 12;
+ cmd.arg[0] = 0x00;
+ cmd.arg[1] = 0x00;
+ cmd.arg[2] = 0x00;
+ cmd.arg[3] = 0x00;
+ cmd.arg[4] = 0x05;
+ cmd.arg[5] = 0x02;
+ cmd.arg[6] = 0x02;
+ cmd.arg[7] = 0x00;
+ cmd.arg[8] = 0x05;
+ cmd.arg[9] = 0x02;
+ cmd.arg[10] = 0x02;
+ cmd.arg[11] = 0x00;
+
+ if ( cx24120_message_send(state, &cmd) ) {
+ err("Error set bandwidth! :(\n");
+ return -EREMOTEIO;
+ }
+ ret = cx24120_readreg(state, 0xBA);
+ if ( ret > 3) {
+ dbginfo("Reset-readreg 0xBA: %x\n", ret);
+ err("Error intitilizing tuner! :(\n");
+ return -EREMOTEIO;
+ }
+ dbginfo("Tuner initialized correctly.\n");
+
+ ret = cx24120_writereg(state, 0xEB, 0x0A);
+ if (cx24120_msg_mpeg_output_global_config(state, 0) ||
+ cx24120_msg_mpeg_output_config(state, 0, &initial_mpeg_config) ||
+ cx24120_msg_mpeg_output_config(state, 1, &initial_mpeg_config) ||
+ cx24120_msg_mpeg_output_config(state, 2, &initial_mpeg_config) )
+ {
+ err("Error initilizing mpeg output. :(\n");
+ return -EREMOTEIO;
+ } else {
+ cmd.id = 0x3C; // 60
+ cmd.len = 0x03;
+ cmd.arg[0] = 0x00;
+ cmd.arg[1] = 0x10;
+ cmd.arg[2] = 0x10;
+ if(cx24120_message_send(state, &cmd)) {
+ err("Error sending final init message. :(\n");
+ return -EREMOTEIO;
+ }
+ }
+ state->cold_init=1;
+ return 0;
+}
+EXPORT_SYMBOL(cx24120_init); // end cx24120_reset
+//===================================================================
+static int cx24120_tune(struct dvb_frontend *fe, bool re_tune,
+ unsigned int mode_flags, unsigned int *delay, fe_status_t *p_status)
+{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ struct cx24120_state *state = fe->demodulator_priv;
+ int delay_cnt, sd_idx = 0;
+ fe_status_t status;
+
+ if (re_tune) {
+
+// dbginfo("Compare symrate with table: symrate= %d, in table= %d\n",
+// p->u.qpsk.symbol_rate, symrates_pairs[sd_idx].symrate);
+
+ while ( p->symbol_rate > symrates_pairs[sd_idx].symrate ) {
+ ++sd_idx;
+ }
+ dbginfo("Found symrate delay = %d\n", symrates_pairs[sd_idx].delay);
+ state->dvb_s2_mode &= 0xFE; // clear bit -> try not DVB-S2
+ dbginfo("trying DVB-S =================\n");
+ cx24120_set_frontend(fe);
+
+ delay_cnt = symrates_pairs[sd_idx].delay;
+ dbginfo("Wait for LOCK for DVB-S =================\n");
+ while (delay_cnt >= 0) {
+ cx24120_read_status(fe, &status);
+ if (status & FE_HAS_LOCK) {
+ dbginfo("DVB-S LOCKED================\n");
+ break;
+ }
+ msleep(100);
+ delay_cnt -=100;
+ }
+ dbginfo("Waiting finished - NO lock for DVB-S =================\n");
+
+ cx24120_read_status(fe, &status);
+ if ( !(status & FE_HAS_LOCK) ) { // if no lock on S
+ dbginfo("trying DVB-S2 ++++++++++++++++++++++++++\n");
+ state->dvb_s2_mode |= 0x01; // may be it locked on S2 ?
+ p->fec_inner = FEC_AUTO;
+ cx24120_set_frontend(fe);
+ delay_cnt = symrates_pairs[sd_idx].delay;
+ dbginfo("Wait for LOCK for DVB-S2 ++++++++++++++++\n");
+ while (delay_cnt >= 0) {
+ cx24120_read_status(fe, &status);
+ if (status & FE_HAS_LOCK) {
+ dbginfo("DVB-S2 LOCKED++++++++++++++++\n");
+ break;
+ }
+ msleep(100);
+ delay_cnt -=100;
+ }
+ dbginfo("Waiting finished - NO lock for DVB-S2 ++++++++++++++++\n");
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL(cx24120_tune); // end of cx24120_tune
+//===================================================================
+static int cx24120_get_algo(struct dvb_frontend *fe)
+{
+ return DVBFE_ALGO_HW;
+}
+EXPORT_SYMBOL(cx24120_get_algo);
+//===================================================================
+static int cx24120_sleep(struct dvb_frontend *fe)
+{
+ return 0;
+}
+EXPORT_SYMBOL(cx24120_sleep);
+//===================================================================
+/*static int cx24120_wakeup(struct dvb_frontend *fe)
+ * {
+ * return 0;
+ * }
+ * EXPORT_SYMBOL(cx24120_wakeup);
+ */
+//===================================================================
+static int cx24120_get_frontend(struct dvb_frontend *fe)
+{
+ return 0;
+}
+EXPORT_SYMBOL(cx24120_get_frontend);
+//===================================================================
+static void cx24120_release(struct dvb_frontend *fe)
+{
+ struct cx24120_state *state = fe->demodulator_priv;
+ dbginfo("Clear state structure\n");
+ kfree(state);
+}
+EXPORT_SYMBOL(cx24120_release);
+//===================================================================
+static int cx24120_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) // UNCORRECTED_BLOCKS
+{
+ struct cx24120_state *state = fe->demodulator_priv;
+
+ *ucblocks = (cx24120_readreg(state, CX24120_REG_UCB_H) << 8) |
+ cx24120_readreg(state, CX24120_REG_UCB_L);
+ dbginfo("Blocks = %d\n", *ucblocks);
+ return 0;
+}
+EXPORT_SYMBOL(cx24120_read_ucblocks);
+// ########################################################################################
+static struct dvb_frontend_ops cx24120_ops = {
+
+ .delsys = { SYS_DVBS2 },
+ .info = {
+ .name = "Conexant CX24120/CX24118",
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 1011, /* kHz for QPSK frontends */
+ .frequency_tolerance = 5000,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ .caps = // 0x500006ff
+ FE_CAN_INVERSION_AUTO | //0x00 000 001
+ FE_CAN_FEC_1_2 | //0x00 000 002
+ FE_CAN_FEC_2_3 | //0x00 000 004
+ FE_CAN_FEC_3_4 | //0x00 000 008
+ FE_CAN_FEC_4_5 | //0x00 000 010
+ FE_CAN_FEC_5_6 | //0x00 000 020
+ FE_CAN_FEC_6_7 | //0x00 000 040
+ FE_CAN_FEC_7_8 | //0x00 000 080
+ FE_CAN_FEC_AUTO | //0x00 000 200
+ FE_CAN_QPSK | //0x00 000 400
+//??? FE_HAS_EXTENDED_CAPS | //0x00 800 000 /* We need more bitspace for newer APIs, indicate this. */
+ FE_CAN_2G_MODULATION | //0x10 000 000 /* frontend supports "2nd generation modulation" (DVB-S2) */
+ FE_CAN_RECOVER //0x40 000 000 /* frontend can recover from a cable unplug automatically */
+ }, //sum=50 000 6FF
+ .release = cx24120_release,
+
+ .init = cx24120_init,
+ .sleep = cx24120_sleep,
+
+ .tune = cx24120_tune,
+ .get_frontend_algo = cx24120_get_algo,
+ .set_frontend = cx24120_set_frontend,
+
+ .get_frontend = cx24120_get_frontend,
+ .read_status = cx24120_read_status,
+ .read_ber = cx24120_read_ber,
+ .read_signal_strength = cx24120_read_signal_strength,
+ .read_snr = cx24120_read_snr,
+ .read_ucblocks = cx24120_read_ucblocks,
+
+ .diseqc_send_master_cmd = cx24120_send_diseqc_msg,
+
+ .diseqc_send_burst = cx24120_diseqc_send_burst,
+ .set_tone = cx24120_set_tone,
+ .set_voltage = cx24120_set_voltage,
+};
+//===================================================================
+MODULE_PARM_DESC(cx24120_debug, "prints some verbose debugging information (default:0)");
+MODULE_AUTHOR("Sergey Tyurin");
+MODULE_LICENSE("GPL");
@@ -0,0 +1,259 @@
+/*
+ * Conexant CX24120/CX24118 - DVB-S/S2 demod/tuner driver
+ * DVBS/S2 Satellite demod/tuner driver static definitins
+ *
+ * Copyright (C) 2009 Sergey Tyurin <forum.free-x.de>
+ * Updated 2012 by Jannis Achstetter <jannis_achstetter@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define CX24120_FIRMWARE "dvb-fe-cx24120-1.20.58.2.fw"
+
+// ##############################
+// ### cx24120 i2c registers ###
+#define CX24120_REG_CMD_START (0x00) // write cmd_id, and then start write args to next register:
+#define CX24120_REG_CMD_ARGS (0x01) // write command arguments, max 4 at once, then next 4, etc.
+#define CX24120_REG_CMD_END (0x1F) // write 0x01 for end, and read it for command result
+
+#define CX24120_REG_FECMODE (0x39) // FEC status
+#define CX24120_REG_STATUS (0x3A) // Tuner status - signal, carrier, sync, lock ...
+#define CX24120_REG_QUALITY_H (0x40) // SNR high byte
+#define CX24120_REG_QUALITY_L (0x41) // SNR low byte
+
+#define CX24120_REG_BER_HH (0x47) // BER high byte of high word
+#define CX24120_REG_BER_HL (0x48) // BER low byte of high word
+#define CX24120_REG_BER_LH (0x49) // BER high byte of low word
+#define CX24120_REG_BER_LL (0x4A) // BER low byte of low word
+
+#define CX24120_REG_SIGSTR_H (0x3A) // Signal strength high byte & ??? status register ???
+#define CX24120_REG_SIGSTR_L (0x3B) // Signal strength low byte
+
+#define CX24120_REG_UCB_H (0x50) // UCB high byte
+#define CX24120_REG_UCB_L (0x51) // UCB low byte
+
+#define CX24120_REG_REVISION (0xFF) // Chip revision (ro). Must be 0x7 or 0x5
+
+// ##############################
+/* Command messages */
+enum command_message_id {
+ CMD_VCO_SET = 0x10, // cmdlen = 12;
+ CMD_TUNEREQUEST = 0x11, // cmd.len = 15;
+
+ CMD_MPEG_ONOFF = 0x13, // cmd.len = 4;
+ CMD_MPEG_INIT = 0x14, // cmd.len = 7;
+ CMD_BANDWIDTH = 0x15, // cmd.len = 12;
+ CMD_CLOCK_READ = 0x16, // read clock from registers 0x01-0x06
+ CMD_CLOCK_SET = 0x17, // cmd.len = 10;
+
+ CMD_DISEQC_MSG1 = 0x20, // cmd.len = 11;
+ CMD_DISEQC_MSG2 = 0x21, // cmd.len = d->msg_len + 6;
+ CMD_SETVOLTAGE = 0x22, // cmd.len = 2;
+ CMD_SETTONE = 0x23, // cmd.len = 4;
+ CMD_DISEQC_BURST = 0x24, // cmd.len not used !!!
+
+ CMD_READ_SNR = 0x1A, // Read signal strength
+ CMD_START_TUNER = 0x1B, // ???
+
+ CMD_TUNER_INIT = 0x3C, // cmd.len = 0x03;
+};
+// ##############################
+/* signal status */
+#define CX24120_HAS_SIGNAL (0x01)
+#define CX24120_HAS_CARRIER (0x02)
+#define CX24120_HAS_VITERBI (0x04)
+#define CX24120_HAS_LOCK (0x08)
+#define CX24120_HAS_UNK1 (0x10)
+#define CX24120_HAS_UNK2 (0x20)
+#define CX24120_STATUS_MASK (0x0f)
+#define CX24120_SIGNAL_MASK (0xc0)
+
+static u8 cx24120_msg_tuner_init[] = { 0,0,0,0,0,0 };
+static u8 cx24120_msg_read_sigstr[] = {0,0};
+
+static struct cx24120_skystar2_mpeg_config {
+ u8 x1;
+ u8 x2;
+ u8 x3;
+} initial_mpeg_config = {
+ 0xA1, // 10100001
+ 0x76, // 01110110
+ 0x07, // 00000111
+};
+
+static struct cx24120_symrate_delay {
+ u32 symrate;
+ u32 delay;
+} symrates_pairs[] = {
+ { 3000000, 15000 },
+ { 6000000, 10000 },
+ { 8000000, 5000 },
+ { 10000000, 2000 },
+ {0x0FFFFFFFF, 400 },
+};
+
+static struct cx24120_clock_ratios_table {
+ u32 ratio_id;
+ u32 mode_xPSK;
+ u32 fec_mode;
+ u32 m_rat;
+ u32 n_rat;
+ u32 rate;
+} clock_ratios_table[] = {
+{ 21 , 0 , 1 , 770068 , 763515 , 258 },
+{ 21 , 0 , 100 , 97409 , 80370 , 310 },
+{ 21 , 0 , 2 , 137293 , 101802 , 345 },
+{ 21 , 0 , 3 , 4633447 , 3054060 , 388 },
+{ 21 , 0 , 4 , 2472041 , 1527030 , 414 },
+{ 21 , 0 , 5 , 85904 , 50901 , 432 },
+{ 21 , 0 , 8 , 2751229 , 1527030 , 461 },
+{ 21 , 0 , 101 , 1392872 , 763515 , 467 },
+{ 21 , 99 , 100 , 1850771 , 1019430 , 464 },
+{ 21 , 99 , 2 , 137293 , 67962 , 517 },
+{ 21 , 99 , 3 , 4633447 , 2038860 , 581 }, // was 4 - ERRORR! FEC_4_5 not in DVB-S2
+{ 21 , 99 , 5 , 85904 , 33981 , 647 },
+{ 21 , 99 , 8 , 2751229 , 1019430 , 690 },
+{ 21 , 99 , 101 , 1392872 , 509715 , 699 },
+{ 29 , 0 , 1 , 770068 , 782127 , 252 },
+{ 29 , 0 , 100 , 1850771 , 1564254 , 302 },
+{ 29 , 0 , 2 , 686465 , 521418 , 337 },
+{ 29 , 0 , 3 , 4633447 , 3128508 , 379 },
+{ 29 , 0 , 4 , 2472041 , 1564254 , 404 },
+{ 29 , 0 , 5 , 429520 , 260709 , 421 },
+{ 29 , 0 , 8 , 2751229 , 1564254 , 450 },
+{ 29 , 0 , 101 , 1392872 , 782127 , 455 },
+{ 29 , 99 , 100 , 1850771 , 1043118 , 454 },
+{ 29 , 99 , 2 , 686465 , 347706 , 505 },
+{ 29 , 99 , 3 , 4633447 , 2086236 , 568 }, // was 4 - ERRORR! FEC_4_5 not in DVB-S2
+{ 29 , 99 , 5 , 429520 , 173853 , 632 },
+{ 29 , 99 , 8 , 2751229 , 1043118 , 675 },
+{ 29 , 99 , 101 , 1392872 , 521559 , 683 },
+{ 17 , 0 , 1 , 766052 , 763515 , 256 },
+{ 17 , 0 , 100 , 96901 , 80370 , 308 },
+{ 17 , 0 , 2 , 136577 , 101802 , 343 },
+{ 17 , 0 , 3 , 4609283 , 3054060 , 386 },
+{ 17 , 0 , 4 , 2459149 , 1527030 , 412 },
+{ 17 , 0 , 5 , 85456 , 50901 , 429 },
+{ 17 , 0 , 8 , 2736881 , 1527030 , 458 },
+{ 17 , 0 , 101 , 1385608 , 763515 , 464 },
+{ 17 , 99 , 100 , 1841119 , 1019430 , 462 },
+{ 17 , 99 , 2 , 136577 , 67962 , 514 },
+{ 17 , 99 , 3 , 4609283 , 2038860 , 578 }, // was 4 - ERRORR! FEC_4_5 not in DVB-S2
+{ 17 , 99 , 5 , 85456 , 33981 , 643 },
+{ 17 , 99 , 8 , 2736881 , 1019430 , 687 },
+{ 17 , 99 , 101 , 1385608 , 509715 , 695 },
+{ 25 , 0 , 1 , 766052 , 782127 , 250 },
+{ 25 , 0 , 100 , 1841119 , 1564254 , 301 },
+{ 25 , 0 , 2 , 682885 , 521418 , 335 },
+{ 25 , 0 , 3 , 4609283 , 3128508 , 377 },
+{ 25 , 0 , 4 , 2459149 , 1564254 , 402 },
+{ 25 , 0 , 5 , 427280 , 260709 , 419 },
+{ 25 , 0 , 8 , 2736881 , 1564254 , 447 },
+{ 25 , 0 , 101 , 1385608 , 782127 , 453 },
+{ 25 , 99 , 100 , 1841119 , 1043118 , 451 },
+{ 25 , 99 , 2 , 682885 , 347706 , 502 },
+{ 25 , 99 , 3 , 4609283 , 2086236 , 565 }, // was 4 - ERRORR! FEC_4_5 not in DVB-S2
+{ 25 , 99 , 5 , 427280 , 173853 , 629 },
+{ 25 , 99 , 8 , 2736881 , 1043118 , 671 },
+{ 25 , 99 , 101 , 1385608 , 521559 , 680 },
+{ 5 , 0 , 1 , 273088 , 254505 , 274 },
+{ 5 , 0 , 100 , 17272 , 13395 , 330 },
+{ 5 , 0 , 2 , 24344 , 16967 , 367 },
+{ 5 , 0 , 3 , 410788 , 254505 , 413 },
+{ 5 , 0 , 4 , 438328 , 254505 , 440 },
+{ 5 , 0 , 5 , 30464 , 16967 , 459 },
+{ 5 , 0 , 8 , 487832 , 254505 , 490 },
+{ 5 , 0 , 101 , 493952 , 254505 , 496 },
+{ 5 , 99 , 100 , 328168 , 169905 , 494 },
+{ 5 , 99 , 2 , 24344 , 11327 , 550 }, // work for 0x0d - 11278V - DVB-S2 - 8PSK MPEG-4/HD
+{ 5 , 99 , 3 , 410788 , 169905 , 618 }, // 0x0e S2 8psk // was 4 - ERRORR! FEC_4_5 not in DVB-S2
+{ 5 , 99 , 5 , 30464 , 11327 , 688 },
+{ 5 , 99 , 8 , 487832 , 169905 , 735 },
+{ 5 , 99 , 101 , 493952 , 169905 , 744 },
+{ 13 , 0 , 1 , 273088 , 260709 , 268 },
+{ 13 , 0 , 100 , 328168 , 260709 , 322 },
+{ 13 , 0 , 2 , 121720 , 86903 , 358 },
+{ 13 , 0 , 3 , 410788 , 260709 , 403 },
+{ 13 , 0 , 4 , 438328 , 260709 , 430 },
+{ 13 , 0 , 5 , 152320 , 86903 , 448 },
+{ 13 , 0 , 8 , 487832 , 260709 , 479 },
+{ 13 , 0 , 101 , 493952 , 260709 , 485 },
+{ 13 , 99 , 100 , 328168 , 173853 , 483 },
+{ 13 , 99 , 2 , 121720 , 57951 , 537 }, // work for 0x8d - dvb-s2 8psk
+{ 13 , 99 , 3 , 410788 , 173853 , 604 }, // was 4 - ERRORR! FEC_4_5 not in DVB-S2
+{ 13 , 99 , 5 , 152320 , 57951 , 672 },
+{ 13 , 99 , 8 , 487832 , 173853 , 718 },
+{ 13 , 99 , 101 , 493952 , 173853 , 727 },
+{ 1 , 0 , 1 , 815248 , 763515 , 273 },
+{ 1 , 0 , 100 , 51562 , 40185 , 328 },
+{ 1 , 0 , 2 , 72674 , 50901 , 365 },
+{ 1 , 0 , 3 , 1226323 , 763515 , 411 },
+{ 1 , 0 , 4 , 1308538 , 763515 , 438 },
+{ 1 , 0 , 5 , 90944 , 50901 , 457 },
+{ 1 , 0 , 8 , 1456322 , 763515 , 488 },
+{ 1 , 0 , 101 , 1474592 , 763515 , 494 },
+{ 1 , 99 , 100 , 979678 , 509715 , 492 },
+{ 1 , 99 , 2 , 72674 , 33981 , 547 },
+{ 1 , 99 , 3 , 1226323 , 509715 , 615 }, // was 4 - ERRORR!? FEC_4_5 not in DVB-S2
+{ 1 , 99 , 5 , 90944 , 33981 , 685 },
+{ 1 , 99 , 8 , 1456322 , 509715 , 731 },
+{ 1 , 99 , 101 , 1474592 , 509715 , 740 },
+{ 9 , 0 , 1 , 815248 , 782127 , 266 },
+{ 9 , 0 , 100 , 979678 , 782127 , 320 },
+{ 9 , 0 , 2 , 363370 , 260709 , 356 },
+{ 9 , 0 , 3 , 1226323 , 782127 , 401 },
+{ 9 , 0 , 4 , 1308538 , 782127 , 428 },
+{ 9 , 0 , 5 , 454720 , 260709 , 446 },
+{ 9 , 0 , 8 , 1456322 , 782127 , 476 },
+{ 9 , 0 , 101 , 1474592 , 782127 , 482 },
+{ 9 , 99 , 100 , 979678 , 521559 , 480 },
+{ 9 , 99 , 2 , 363370 , 173853 , 535 },
+{ 9 , 99 , 3 , 1226323 , 521559 , 601 }, // was 4 - ERRORR! FEC_4_5 not in DVB-S2
+{ 9 , 99 , 5 , 454720 , 173853 , 669 },
+{ 9 , 99 , 8 , 1456322 , 521559 , 714 },
+{ 9 , 99 , 101 , 1474592 , 521559 , 723 },
+{ 18 , 0 , 1 , 535 , 588 , 233 },
+{ 18 , 0 , 2 , 1070 , 882 , 311 },
+{ 18 , 0 , 6 , 3210 , 2058 , 399 },
+{ 16 , 0 , 1 , 763 , 816 , 239 },
+{ 16 , 0 , 2 , 1526 , 1224 , 319 },
+{ 16 , 0 , 3 , 2289 , 1632 , 359 },
+{ 16 , 0 , 5 , 3815 , 2448 , 399 },
+{ 16 , 0 , 7 , 5341 , 3264 , 419 },
+{ 22 , 0 , 1 , 535 , 588 , 233 },
+{ 22 , 0 , 2 , 1070 , 882 , 311 },
+{ 22 , 0 , 6 , 3210 , 2058 , 399 },
+{ 20 , 0 , 1 , 143429 , 152592 , 241 },
+{ 20 , 0 , 2 , 286858 , 228888 , 321 },
+{ 20 , 0 , 3 , 430287 , 305184 , 361 },
+{ 20 , 0 , 5 , 717145 , 457776 , 401 },
+{ 20 , 0 , 7 , 1004003 , 610368 , 421 },
+{ 2 , 0 , 1 , 584 , 588 , 254 },
+{ 2 , 0 , 2 , 1169 , 882 , 339 },
+{ 2 , 0 , 6 , 3507 , 2058 , 436 },
+{ 0 , 0 , 1 , 812 , 816 , 255 },
+{ 0 , 0 , 2 , 1624 , 1224 , 340 },
+{ 0 , 0 , 3 , 2436 , 1632 , 382 },
+{ 0 , 0 , 5 , 4060 , 2448 , 425 },
+{ 0 , 0 , 7 , 5684 , 3264 , 446 },
+{ 6 , 0 , 1 , 584 , 588 , 254 },
+{ 6 , 0 , 2 , 1168 , 882 , 339 },
+{ 6 , 0 , 6 , 3504 , 2058 , 436 },
+{ 4 , 0 , 1 , 152592 , 152592 , 256 },
+{ 4 , 0 , 2 , 305184 , 228888 , 341 },
+{ 4 , 0 , 3 , 457776 , 305184 , 384 },
+{ 4 , 0 , 5 , 762960 , 457776 , 427 },
+{ 4 , 0 , 7 , 1068144 , 610368 , 448 },
+};
@@ -0,0 +1,59 @@
+/*
+ * Conexant CX24120/CX24118 - DVB-S/S2 demod/tuner driver
+ *
+ * Copyright (C) 2008 Patrick Boettcher <pb@linuxtv.org>
+ * Copyright (C) 2009 Sergey Tyurin <forum.free-x.de>
+ * Updated 2012 by Jannis Achstetter <jannis_achstetter@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef CX24120_H
+#define CX24120_H
+
+#include <linux/dvb/frontend.h>
+
+struct firmware;
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct cx24120_config
+{
+ u8 i2c_addr;
+ int (*request_firmware)(struct dvb_frontend *fe, const struct firmware **fw, char *name);
+ void (*stream_control)(struct dvb_frontend *fe, u8 onoff);
+};
+
+#if defined(CONFIG_DVB_CX24120) || \
+ (defined(CONFIG_DVB_CX24120_MODULE) && defined(MODULE))
+extern struct dvb_frontend *cx24120_attach(const struct cx24120_config *config,
+ struct i2c_adapter *i2c);
+extern int cx24120_reset(struct dvb_frontend *fe);
+#else
+static inline
+struct dvb_frontend *cx24120_attach(const struct cx24120_config *config,
+ struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+static inline int cx24120_reset(struct dvb_frontend *fe)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return -ENODEV;
+}
+#endif
+
+#endif
@@ -18,6 +18,13 @@
comment "Multistandard (satellite) frontends"
depends on DVB_CORE
+config DVB_CX24120
+ tristate "Conexant CX24120 based"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S/DVB-S2 tuner module. Say Y when you want to support this frontend.
+
config DVB_STB0899
tristate "STB0899 based"
depends on DVB_CORE && I2C
@@ -20,6 +20,7 @@
obj-$(CONFIG_DVB_CX22700) += cx22700.o
obj-$(CONFIG_DVB_S5H1432) += s5h1432.o
obj-$(CONFIG_DVB_CX24110) += cx24110.o
+obj-$(CONFIG_DVB_CX24120) += cx24120.o
obj-$(CONFIG_DVB_TDA8083) += tda8083.o
obj-$(CONFIG_DVB_L64781) += l64781.o
obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o