Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff -uraBN a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
- --- a/drivers/i2c/i2c-core-base.c
- +++ b/drivers/i2c/i2c-core-base.c
- @@ -1018,15 +1018,14 @@
- { },
- };
- -static int dummy_probe(struct i2c_client *client,
- - const struct i2c_device_id *id)
- +static int dummy_probe(struct i2c_client *client)
- {
- return 0;
- }
- static struct i2c_driver dummy_driver = {
- .driver.name = "dummy",
- - .probe = dummy_probe,
- + .probe_new = dummy_probe,
- .id_table = dummy_id,
- };
- @@ -2237,6 +2236,20 @@
- }
- EXPORT_SYMBOL_GPL(i2c_get_device_id);
- +/**
- + * i2c_client_get_device_id - get the driver match table entry of a device
- + * @client: the device to query. The device must be bound to a driver
- + *
- + * Returns a pointer to the matching entry if found, NULL otherwise.
- + */
- +const struct i2c_device_id *i2c_client_get_device_id(const struct i2c_client *client)
- +{
- + const struct i2c_driver *drv = to_i2c_driver(client->dev.driver);
- +
- + return i2c_match_id(drv->id_table, client);
- +}
- +EXPORT_SYMBOL_GPL(i2c_client_get_device_id);
- +
- /* ----------------------------------------------------
- * the i2c address scanning function
- * Will not work for 10-bit addresses!
- diff -uraBN a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
- --- a/drivers/media/dvb-core/dvb_frontend.c
- +++ b/drivers/media/dvb-core/dvb_frontend.c
- @@ -40,7 +40,7 @@
- static int dvb_shutdown_timeout;
- static int dvb_force_auto_inversion;
- static int dvb_override_tune_delay;
- -static int dvb_powerdown_on_sleep = 1;
- +static int dvb_powerdown_on_sleep;
- static int dvb_mfe_wait_time = 5;
- module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
- @@ -918,6 +918,7 @@
- /* If the standard is for satellite, convert frequencies to kHz */
- switch (c->delivery_system) {
- + case SYS_DSS:
- case SYS_DVBS:
- case SYS_DVBS2:
- case SYS_TURBO:
- @@ -943,6 +944,7 @@
- u32 step = max(fe_step, tuner_step);
- switch (c->delivery_system) {
- + case SYS_DSS:
- case SYS_DVBS:
- case SYS_DVBS2:
- case SYS_TURBO:
- @@ -974,6 +976,7 @@
- /* range check: symbol rate */
- switch (c->delivery_system) {
- + case SYS_DSS:
- case SYS_DVBS:
- case SYS_DVBS2:
- case SYS_TURBO:
- @@ -1037,9 +1040,14 @@
- }
- c->stream_id = NO_STREAM_ID_FILTER;
- + c->modcode = MODCODE_ALL;
- c->scrambling_sequence_index = 0;/* default sequence */
- switch (c->delivery_system) {
- + case SYS_DSS:
- + c->modulation = QPSK;
- + c->rolloff = ROLLOFF_20;
- + break;
- case SYS_DVBS:
- case SYS_DVBS2:
- case SYS_TURBO:
- @@ -1111,7 +1119,7 @@
- _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING),
- _DTV_CMD(DTV_STREAM_ID),
- - _DTV_CMD(DTV_DVBT2_PLP_ID_LEGACY),
- + _DTV_CMD(DTV_MODCODE),
- _DTV_CMD(DTV_SCRAMBLING_SEQUENCE_INDEX),
- _DTV_CMD(DTV_LNA),
- @@ -1462,8 +1470,12 @@
- /* Multistream support */
- case DTV_STREAM_ID:
- - case DTV_DVBT2_PLP_ID_LEGACY:
- tvp->u.data = c->stream_id;
- + break;
- +
- + /* Modcode support */
- + case DTV_MODCODE:
- + tvp->u.data = c->modcode;
- break;
- /* Physical layer scrambling support */
- @@ -1821,6 +1833,7 @@
- } else {
- /* default values */
- switch (c->delivery_system) {
- + case SYS_DSS:
- case SYS_DVBS:
- case SYS_DVBS2:
- case SYS_ISDBS:
- @@ -1883,6 +1896,14 @@
- dev_dbg(fe->dvb->device,
- "%s: SET cmd 0x%08x (%s) to 0x%08x\n",
- __func__, cmd, dtv_cmd_name(cmd), data);
- +
- + /* Allow the frontend to validate incoming properties */
- + if (fe->ops.set_property) {
- + r = fe->ops.set_property(fe, cmd, data);
- + if (r < 0)
- + return r;
- + }
- +
- switch (cmd) {
- case DTV_CLEAR:
- /*
- @@ -2016,8 +2037,12 @@
- /* Multistream support */
- case DTV_STREAM_ID:
- - case DTV_DVBT2_PLP_ID_LEGACY:
- c->stream_id = data;
- + break;
- +
- + /* Modcode support */
- + case DTV_MODCODE:
- + c->modcode = data;
- break;
- /* Physical layer scrambling support */
- @@ -2288,6 +2313,9 @@
- case SYS_DVBC_ANNEX_C:
- rolloff = 113;
- break;
- + case SYS_DSS:
- + rolloff = 120;
- + break;
- case SYS_DVBS:
- case SYS_TURBO:
- case SYS_ISDBS:
- @@ -2422,6 +2450,77 @@
- dev_dbg(fe->dvb->device, "%s:\n", __func__);
- switch (cmd) {
- +
- + case FE_READ_TEMP:
- + if (fe->ops.read_temp) {
- + err = fe->ops.read_temp(fe, parg);
- + }
- + break;
- +
- + case FE_ECP3FW_READ:
- + //printk("FE_ECP3FW_READ *****************");
- + if (fe->ops.spi_read) {
- + struct ecp3_info *info = parg;
- + fe->ops.spi_read(fe, info);
- + }
- + err = 0;
- + break;
- + case FE_ECP3FW_WRITE:
- + //printk("FE_ECP3FW_WRITE *****************");
- + if (fe->ops.spi_write) {
- + struct ecp3_info *info = parg;
- + fe->ops.spi_write(fe, info);
- +
- + }
- + err = 0;
- + break;
- +
- + case FE_24CXX_READ:
- + //printk("FE_24CXX_READ *****************");
- + if (fe->ops.mcu_read) {
- + struct mcu24cxx_info *info = parg;
- + fe->ops.mcu_read(fe, info);
- + }
- + err = 0;
- + break;
- + case FE_24CXX_WRITE:
- + //printk("FE_24CXX_WRITE *****************");
- + if (fe->ops.mcu_write) {
- + struct mcu24cxx_info *info = parg;
- + fe->ops.mcu_write(fe, info);
- +
- + }
- + err = 0;
- + break;
- + case FE_REGI2C_READ:
- + if (fe->ops.reg_i2cread) {
- + struct usbi2c_access *info = parg;
- + fe->ops.reg_i2cread(fe, info);
- + }
- + err = 0;
- + break;
- + case FE_REGI2C_WRITE:
- + if (fe->ops.reg_i2cwrite) {
- + struct usbi2c_access *info = parg;
- + fe->ops.reg_i2cwrite(fe, info);
- + }
- + err = 0;
- + break;
- + case FE_EEPROM_READ:
- + if (fe->ops.eeprom_read) {
- + struct eeprom_info *info = parg;
- + fe->ops.eeprom_read(fe, info);
- + }
- + err = 0;
- + break;
- + case FE_EEPROM_WRITE:
- + if (fe->ops.eeprom_write) {
- + struct eeprom_info *info = parg;
- + fe->ops.eeprom_write(fe, info);
- + }
- + err = 0;
- + break;
- +
- case FE_SET_PROPERTY: {
- struct dtv_properties *tvps = parg;
- struct dtv_property *tvp = NULL;
- @@ -2664,37 +2763,25 @@
- case FE_READ_BER:
- if (fe->ops.read_ber) {
- - if (fepriv->thread)
- err = fe->ops.read_ber(fe, parg);
- - else
- - err = -EAGAIN;
- }
- break;
- case FE_READ_SIGNAL_STRENGTH:
- if (fe->ops.read_signal_strength) {
- - if (fepriv->thread)
- err = fe->ops.read_signal_strength(fe, parg);
- - else
- - err = -EAGAIN;
- }
- break;
- case FE_READ_SNR:
- if (fe->ops.read_snr) {
- - if (fepriv->thread)
- err = fe->ops.read_snr(fe, parg);
- - else
- - err = -EAGAIN;
- }
- break;
- case FE_READ_UNCORRECTED_BLOCKS:
- if (fe->ops.read_ucblocks) {
- - if (fepriv->thread)
- err = fe->ops.read_ucblocks(fe, parg);
- - else
- - err = -EAGAIN;
- }
- break;
- @@ -2754,7 +2841,17 @@
- if (fe->exit == DVB_FE_DEVICE_REMOVED)
- return -ENODEV;
- - if (adapter->mfe_shared) {
- + if (adapter->mfe_shared == 2) {
- + mutex_lock(&adapter->mfe_lock);
- + if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
- + if (adapter->mfe_dvbdev &&
- + !adapter->mfe_dvbdev->writers) {
- + mutex_unlock(&adapter->mfe_lock);
- + return -EBUSY;
- + }
- + adapter->mfe_dvbdev = dvbdev;
- + }
- + } else if (adapter->mfe_shared) {
- mutex_lock(&adapter->mfe_lock);
- if (!adapter->mfe_dvbdev)
- diff -uraBN a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
- --- a/drivers/media/dvb-frontends/Kconfig
- +++ b/drivers/media/dvb-frontends/Kconfig
- @@ -922,6 +922,14 @@
- source "drivers/media/dvb-frontends/drx39xyj/Kconfig"
- +config DVB_SI2183
- + tristate "Silicon Labs Si2183 DVB-T/T2/C/C2/S/S2/S2X/ISDB-T demodulator"
- + depends on DVB_CORE && I2C
- + default m if !MEDIA_SUBDRV_AUTOSELECT
- + help
- + Say Y when you want to support this frontend.
- +
- +
- comment "Common Interface (EN50221) controller drivers"
- depends on DVB_CORE
- diff -uraBN a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile
- --- a/drivers/media/dvb-frontends/Makefile
- +++ b/drivers/media/dvb-frontends/Makefile
- @@ -136,3 +136,4 @@
- obj-$(CONFIG_DVB_ZL10036) += zl10036.o
- obj-$(CONFIG_DVB_ZL10039) += zl10039.o
- obj-$(CONFIG_DVB_ZL10353) += zl10353.o
- +obj-$(CONFIG_DVB_SI2183) += si2183.o
- diff -uraBN a/drivers/media/dvb-frontends/si2183.c b/drivers/media/dvb-frontends/si2183.c
- --- a/drivers/media/dvb-frontends/si2183.c
- +++ b/drivers/media/dvb-frontends/si2183.c
- @@ -0,0 +1,1843 @@
- +/*
- + * Silicon Labs Si2183(2) DVB-T/T2/C/C2/S/S2 demodulator driver
- + *
- + * 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.
- + */
- +
- +#include "si2183.h"
- +#include <media/dvb_frontend.h>
- +#include <linux/firmware.h>
- +#include <linux/i2c-mux.h>
- +#include <linux/version.h>
- +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)
- +#define SI2183_USE_I2C_MUX
- +#endif
- +
- +#define SI2183_B60_FIRMWARE "dvb-demod-si2183-b60-01.fw"
- +
- +#define SI2183_PROP_MODE 0x100a
- +#define SI2183_PROP_DVBC_CONST 0x1101
- +#define SI2183_PROP_DVBC_SR 0x1102
- +#define SI2183_PROP_DVBT_HIER 0x1201
- +#define SI2183_PROP_DVBT2_MODE 0x1304
- +#define SI2183_PROP_DVBS2_SR 0x1401
- +#define SI2183_PROP_DVBS_SR 0x1501
- +#define SI2183_PROP_MCNS_CONST 0x1601
- +#define SI2183_PROP_MCNS_SR 0x1602
- +
- +#define SI2183_ARGLEN 30
- +struct si2183_cmd {
- + u8 args[SI2183_ARGLEN];
- + unsigned wlen;
- + unsigned rlen;
- +};
- +
- +static const struct dvb_frontend_ops si2183_ops;
- +
- +LIST_HEAD(silist);
- +
- +struct si_base {
- + struct mutex i2c_mutex;
- +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
- + struct i2c_mux_core *muxc;
- +#endif
- + struct list_head silist;
- +
- + u8 adr;
- + struct i2c_adapter *i2c;
- + u32 count;
- +
- + struct i2c_adapter *tuner_adapter;
- +
- +#ifndef SI2183_USE_I2C_MUX
- + struct i2c_client *i2c_gate_client;
- +#endif
- +};
- +
- +/* state struct */
- +struct si2183_dev {
- + struct dvb_frontend fe;
- + enum fe_delivery_system delivery_system;
- + enum fe_status fe_status;
- + u8 stat_resp;
- + u16 snr;
- + bool fw_loaded;
- + u8 ts_mode;
- + bool ts_clock_inv;
- + bool ts_clock_gapped;
- + int start_clk_mode;
- + u8 agc_mode;
- + struct si_base *base;
- + void (*RF_switch)(struct i2c_adapter * i2c,u8 rf_in,u8 flag);
- + u8 rf_in;
- + u8 active_fe;
- + void (*TS_switch)(struct i2c_adapter * i2c,u8 flag);
- + void (*LED_switch)(struct i2c_adapter * i2c,u8 flag);
- +
- + void (*write_properties) (struct i2c_adapter *i2c,u8 reg, u32 buf);
- + void (*read_properties) (struct i2c_adapter *i2c,u8 reg, u32 *buf);
- +
- + void (*write_eeprom) (struct i2c_adapter *i2c,u8 reg, u8 buf);
- + void (*read_eeprom) (struct i2c_adapter *i2c,u8 reg, u8 *buf);
- +};
- +
- +/* Own I2C adapter locking is needed because of I2C gate logic. */
- +static int si2183_i2c_master_send_unlocked(const struct i2c_client *client,
- + const char *buf, int count)
- +{
- + int ret;
- + struct i2c_msg msg = {
- + .addr = client->addr,
- + .flags = 0,
- + .len = count,
- + .buf = (char *)buf,
- + };
- +
- + ret = __i2c_transfer(client->adapter, &msg, 1);
- + return (ret == 1) ? count : ret;
- +}
- +
- +static int si2183_i2c_master_recv_unlocked(const struct i2c_client *client,
- + char *buf, int count)
- +{
- + int ret;
- + struct i2c_msg msg = {
- + .addr = client->addr,
- + .flags = I2C_M_RD,
- + .len = count,
- + .buf = buf,
- + };
- +
- + ret = __i2c_transfer(client->adapter, &msg, 1);
- + return (ret == 1) ? count : ret;
- +}
- +
- +/* execute firmware command */
- +static int si2183_cmd_execute_unlocked(struct i2c_client *client,
- + struct si2183_cmd *cmd)
- +{
- + int ret;
- + unsigned long timeout;
- +
- + if (cmd->wlen) {
- + /* write cmd and args for firmware */
- + ret = si2183_i2c_master_send_unlocked(client, cmd->args,
- + cmd->wlen);
- + if (ret < 0) {
- + goto err;
- + } else if (ret != cmd->wlen) {
- + ret = -EREMOTEIO;
- + goto err;
- + }
- + }
- +
- + if (cmd->rlen) {
- + /* wait cmd execution terminate */
- + #define TIMEOUT 500
- + timeout = jiffies + msecs_to_jiffies(TIMEOUT);
- + while (!time_after(jiffies, timeout)) {
- + ret = si2183_i2c_master_recv_unlocked(client, cmd->args,
- + cmd->rlen);
- + if (ret < 0) {
- + goto err;
- + } else if (ret != cmd->rlen) {
- + ret = -EREMOTEIO;
- + goto err;
- + }
- +
- + /* firmware ready? */
- + if ((cmd->args[0] >> 7) & 0x01)
- + break;
- + }
- +
- + dev_dbg(&client->dev, "cmd execution took %d ms\n",
- + jiffies_to_msecs(jiffies) -
- + (jiffies_to_msecs(timeout) - TIMEOUT));
- +
- + /* error bit set? */
- + if ((cmd->args[0] >> 6) & 0x01) {
- + ret = -EREMOTEIO;
- + goto err;
- + }
- +
- + if (!((cmd->args[0] >> 7) & 0x01)) {
- + ret = -ETIMEDOUT;
- + goto err;
- + }
- + }
- +
- + return 0;
- +err:
- + dev_dbg(&client->dev, "failed=%d\n", ret);
- + return ret;
- +}
- +
- +static int si2183_cmd_execute(struct i2c_client *client, struct si2183_cmd *cmd)
- +{
- + struct si2183_dev *dev = i2c_get_clientdata(client);
- + int ret;
- +
- +
- + mutex_lock(&dev->base->i2c_mutex);
- + ret = si2183_cmd_execute_unlocked(client, cmd);
- + mutex_unlock(&dev->base->i2c_mutex);
- +
- + return ret;
- +}
- +
- +static int si2183_set_prop(struct i2c_client *client, u16 prop, u16 *val)
- +{
- + struct si2183_cmd cmd;
- + int ret;
- +
- + cmd.args[0] = 0x14;
- + cmd.args[1] = 0x00;
- + cmd.args[2] = (u8) prop;
- + cmd.args[3] = (u8) (prop >> 8);
- + cmd.args[4] = (u8) (*val);
- + cmd.args[5] = (u8) (*val >> 8);
- + cmd.wlen = 6;
- + cmd.rlen = 4;
- + ret = si2183_cmd_execute(client, &cmd);
- + *val = (cmd.args[2] | (cmd.args[3] << 8));
- + return ret;
- +}
- +#if 0
- +static int si2183_get_prop(struct i2c_client *client, u16 prop, u16 *val)
- +{
- + struct si2183_cmd cmd;
- + int ret;
- +
- + cmd.args[0] = 0x15;
- + cmd.args[1] = 0x00;
- + cmd.args[2] = (u8) prop;
- + cmd.args[3] = (u8) (prop >> 8);
- + cmd.wlen = 4;
- + cmd.rlen = 4;
- + ret = si2183_cmd_execute(client, &cmd);
- + *val = (cmd.args[2] | (cmd.args[3] << 8));
- + return ret;
- +}
- +#endif
- +
- +static int si2183_read_status(struct dvb_frontend *fe, enum fe_status *status)
- +{
- + struct i2c_client *client = fe->demodulator_priv;
- + struct si2183_dev *dev = i2c_get_clientdata(client);
- + struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- + int ret;
- + struct si2183_cmd cmd;
- + u16 agc;
- +
- + *status = 0;
- +
- + if (!dev->active_fe) {
- + ret = -EAGAIN;
- + goto err;
- + }
- +
- + if ((dev->delivery_system != c->delivery_system) || (dev->delivery_system == 0))
- + return 0;
- +
- + switch (c->delivery_system) {
- + case SYS_DVBT:
- + memcpy(cmd.args, "\xa0\x01", 2);
- + cmd.wlen = 2;
- + cmd.rlen = 13;
- + dev->snr = 2;
- + break;
- + case SYS_DVBC_ANNEX_A:
- + memcpy(cmd.args, "\x90\x01", 2);
- + cmd.wlen = 2;
- + cmd.rlen = 9;
- + dev->snr = 2;
- + break;
- + case SYS_DVBC_ANNEX_B:
- + memcpy(cmd.args, "\x98\x01", 2);
- + cmd.wlen = 2;
- + cmd.rlen = 10;
- + dev->snr = 2;
- + break;
- + case SYS_DVBT2:
- + memcpy(cmd.args, "\x50\x01", 2);
- + cmd.wlen = 2;
- + cmd.rlen = 14;
- + dev->snr = 2;
- + break;
- + case SYS_DVBS:
- + memcpy(cmd.args, "\x60\x01", 2);
- + cmd.wlen = 2;
- + cmd.rlen = 10;
- + dev->snr = 5;
- + break;
- + case SYS_DVBS2:
- + memcpy(cmd.args, "\x70\x01", 2);
- + cmd.wlen = 2;
- + cmd.rlen = 13;
- + dev->snr = 5;
- + break;
- + case SYS_ISDBT:
- + memcpy(cmd.args, "\xa4\x01", 2);
- + cmd.wlen = 2;
- + cmd.rlen = 14;
- + dev->snr = 2;
- + break;
- + default:
- + ret = -EINVAL;
- + goto err;
- + }
- +
- + ret = si2183_cmd_execute(client, &cmd);
- + if (ret) {
- + dev_err(&client->dev, "read_status fe%d cmd_exec failed=%d\n", fe->id, ret);
- + goto err;
- + }
- +
- + dev->stat_resp = cmd.args[2];
- + switch ((dev->stat_resp >> 1) & 0x03) {
- + case 0x01:
- + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
- + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
- + break;
- + case 0x03:
- + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
- + FE_HAS_SYNC | FE_HAS_LOCK;
- + dev->snr *= cmd.args[3] * 164;
- + c->cnr.len = 2;
- + c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
- + c->cnr.stat[0].svalue = (s64) cmd.args[3] * 250;
- + c->cnr.stat[1].scale = FE_SCALE_RELATIVE;
- + c->cnr.stat[1].svalue = dev->snr;
- +
- + // writing missing properties
- + // CONSTELLATION or modulation
- + switch (cmd.args[8] & 0x3f){
- + case 0x03:
- + c->modulation = QPSK;
- + break;
- + case 0x07:
- + c->modulation = QAM_16;
- + break;
- + case 0x08:
- + c->modulation = QAM_32;
- + break;
- + case 0x09:
- + c->modulation = QAM_64;
- + break;
- + case 0x0a:
- + c->modulation = QAM_128;
- + break;
- + case 0x0b:
- + c->modulation = QAM_256;
- + break;
- + case 0x0e:
- + c->modulation = PSK_8;
- + break;
- + case 0x14:
- + c->modulation = APSK_16;
- + break;
- + case 0x17:
- + c->modulation = APSK_8L;
- + break;
- + case 0x18:
- + c->modulation = APSK_16L;
- + break;
- + case 0x15:
- + c->modulation = APSK_32;
- + break;
- + case 0x19:
- + c->modulation = APSK_32L;
- + break;
- + case 0x1a:
- + c->modulation = APSK_32;
- + break;
- + default:
- + c->modulation = QPSK;
- + break;
- + }
- + // fec_inner
- + switch (c->delivery_system) {
- + case SYS_DVBT2:
- + switch (cmd.args[12] & 0x0f){
- + case 0x01:
- + c->fec_inner = FEC_1_2;
- + break;
- + case 0x02:
- + c->fec_inner = FEC_2_3;
- + break;
- + case 0x03:
- + c->fec_inner = FEC_3_4;
- + break;
- + case 0x04:
- + c->fec_inner = FEC_4_5;
- + break;
- + case 0x05:
- + c->fec_inner = FEC_5_6;
- + break;
- + case 0x0a:
- + c->fec_inner = FEC_1_3;
- + break;
- + case 0x0c:
- + c->fec_inner = FEC_2_5;
- + break;
- + case 0x0d:
- + c->fec_inner = FEC_3_5;
- + break;
- + default:
- + c->fec_inner = FEC_AUTO;
- + break;
- + }
- + break;
- + case SYS_DVBS:
- + switch (cmd.args[9] & 0x0f){
- + case 0x01:
- + c->fec_inner = FEC_1_2;
- + break;
- + case 0x02:
- + c->fec_inner = FEC_2_3;
- + break;
- + case 0x03:
- + c->fec_inner = FEC_3_4;
- + break;
- + case 0x04:
- + c->fec_inner = FEC_4_5;
- + break;
- + case 0x05:
- + c->fec_inner = FEC_5_6;
- + break;
- + case 0x06:
- + c->fec_inner = FEC_6_7;
- + break;
- + case 0x07:
- + c->fec_inner = FEC_7_8;
- + break;
- + default:
- + c->fec_inner = FEC_AUTO;
- + break;
- + }
- + break;
- + case SYS_DVBS2:
- + switch (cmd.args[9] & 0x1f){
- + case 0x01:
- + c->fec_inner = FEC_1_2;
- + break;
- + case 0x02:
- + c->fec_inner = FEC_2_3;
- + break;
- + case 0x03:
- + c->fec_inner = FEC_3_4;
- + break;
- + case 0x04:
- + c->fec_inner = FEC_4_5;
- + break;
- + case 0x05:
- + c->fec_inner = FEC_5_6;
- + break;
- + case 0x08:
- + c->fec_inner = FEC_8_9;
- + break;
- + case 0x09:
- + c->fec_inner = FEC_9_10;
- + break;
- + case 0x0a:
- + c->fec_inner = FEC_1_3;
- + break;
- + case 0x0b:
- + c->fec_inner = FEC_1_4;
- + break;
- + case 0x0c:
- + c->fec_inner = FEC_2_5;
- + break;
- + case 0x0d:
- + c->fec_inner = FEC_3_5;
- + break;
- + default:
- + c->fec_inner = FEC_AUTO;
- + break;
- + }
- + break;
- + default:
- + c->fec_inner = FEC_AUTO;
- + break;
- + }
- + // rolloff and pilot (only available for dvb s2)
- + switch (c->delivery_system) {
- + case SYS_DVBS2:
- + // rolloff
- + switch (cmd.args[10] & 0x07){
- + case 0x00:
- + c->rolloff = ROLLOFF_35;
- + break;
- + case 0x01:
- + c->rolloff = ROLLOFF_25;
- + break;
- + case 0x02:
- + c->rolloff = ROLLOFF_20;
- + break;
- + case 0x04:
- + c->rolloff = ROLLOFF_15;
- + break;
- + case 0x05:
- + c->rolloff = ROLLOFF_10;
- + break;
- + case 0x06:
- + c->rolloff = ROLLOFF_5;
- + break;
- + default:
- + c->rolloff = ROLLOFF_AUTO;
- + break;
- + }
- + // pilot
- + switch ((cmd.args[8] >> 7) & 0x01){
- + case 0x01:
- + c->pilot = PILOT_ON;
- + break;
- + case 0x00:
- + c->pilot = PILOT_OFF;
- + break;
- + default:
- + c->pilot = PILOT_AUTO;
- + break;
- + }
- + break;
- + default:
- + c->rolloff = ROLLOFF_AUTO;
- + c->pilot = PILOT_AUTO;
- + break;
- + }
- + break;
- + default:
- + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
- + break;
- + }
- +
- + dev->fe_status = *status;
- +
- + dev_dbg(&client->dev, "status=%02x args=%*ph\n",
- + *status, cmd.rlen, cmd.args);
- +
- + if (fe->ops.tuner_ops.get_rf_strength)
- + {
- + memcpy(cmd.args, "\x8a\x00\x00\x00\x00\x00", 6);
- + cmd.wlen = 6;
- + cmd.rlen = 3;
- + ret = si2183_cmd_execute(client, &cmd);
- + if (ret) {
- + dev_err(&client->dev, "read_status fe%d cmd_exec failed=%d\n", fe->id, ret);
- + goto err;
- + }
- + dev_dbg(&client->dev, "status=%02x args=%*ph\n",
- + *status, cmd.rlen, cmd.args);
- +
- + agc = cmd.args[1];
- + fe->ops.tuner_ops.get_rf_strength(fe, &agc);
- + }
- +
- + if ( c->strength.len == 1 && c->strength.stat[0].scale == FE_SCALE_DECIBEL) {
- + c->strength.len ++;
- + c->strength.stat[1].scale = FE_SCALE_RELATIVE;
- + c->strength.stat[1].svalue = ((100000 + (s32)c->strength.stat[0].svalue) / 1000) * 656;
- + }
- +
- + return 0;
- +err:
- + dev_err(&client->dev, "read_status failed=%d\n", ret);
- + return ret;
- +}
- +
- +static int si2183_read_snr(struct dvb_frontend *fe, u16 *snr)
- +{
- + struct i2c_client *client = fe->demodulator_priv;
- + struct si2183_dev *dev = i2c_get_clientdata(client);
- +
- + *snr = (dev->fe_status & FE_HAS_LOCK) ? dev->snr : 0;
- +
- + return 0;
- +}
- +
- +static int si2183_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
- +{
- + struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- + int i;
- +
- + *strength = 0;
- + for (i=0; i < c->strength.len; i++)
- + {
- + if (c->strength.stat[i].scale == FE_SCALE_RELATIVE)
- + *strength = (u16)c->strength.stat[i].uvalue;
- + else if (c->strength.stat[i].scale == FE_SCALE_DECIBEL)
- + *strength = ((100000 + (s32)c->strength.stat[i].svalue)/1000) * 656;
- + }
- +
- + return 0;
- +}
- +
- +static int si2183_read_ber(struct dvb_frontend *fe, u32 *ber)
- +{
- + struct i2c_client *client = fe->demodulator_priv;
- + struct si2183_dev *dev = i2c_get_clientdata(client);
- + struct si2183_cmd cmd;
- + int ret;
- +
- + if (dev->fe_status & FE_HAS_LOCK) {
- + memcpy(cmd.args, "\x82\x00", 2);
- + cmd.wlen = 2;
- + cmd.rlen = 3;
- + ret = si2183_cmd_execute(client, &cmd);
- + if (ret) {
- + dev_err(&client->dev, "read_ber fe%d cmd_exec failed=%d\n", fe->id, ret);
- + goto err;
- + }
- + *ber = (u32)cmd.args[2] * cmd.args[1] & 0xf;
- + } else *ber = 1;
- +
- + return 0;
- +err:
- + dev_err(&client->dev, "read_ber failed=%d\n", ret);
- + return ret;
- +}
- +
- +static int si2183_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
- +{
- + struct i2c_client *client = fe->demodulator_priv;
- + struct si2183_dev *dev = i2c_get_clientdata(client);
- + struct si2183_cmd cmd;
- + int ret;
- +
- + if (dev->stat_resp & 0x10) {
- + memcpy(cmd.args, "\x84\x00", 2);
- + cmd.wlen = 2;
- + cmd.rlen = 3;
- + ret = si2183_cmd_execute(client, &cmd);
- + if (ret) {
- + dev_err(&client->dev, "read_ucblocks fe%d cmd_exec failed=%d\n", fe->id, ret);
- + goto err;
- + }
- +
- + *ucblocks = (u16)cmd.args[2] << 8 | cmd.args[1];
- + } else *ucblocks = 0;
- +
- + return 0;
- +err:
- + dev_err(&client->dev, "read_ucblocks failed=%d\n", ret);
- + return ret;
- +}
- +
- +
- +static int si2183_set_dvbc(struct dvb_frontend *fe)
- +{
- + struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- + struct i2c_client *client = fe->demodulator_priv;
- + struct si2183_dev *dev = i2c_get_clientdata(client);
- + struct si2183_cmd cmd;
- + int ret;
- + u16 prop;
- +
- + if(dev->LED_switch)
- + dev->LED_switch(dev->base->i2c,6);
- +
- + memcpy(cmd.args, "\x89\x41\x06\x12\x0\x0", 6);
- + cmd.args[1]= (dev->agc_mode &0x07)<<4 |0x1;
- + cmd.wlen = 6;
- + cmd.rlen = 3;
- + ret = si2183_cmd_execute(client, &cmd);
- + if(ret){
- + dev_err(&client->dev, "err set agc mode\n");
- + }
- + /* dvb-c mode */
- + prop = 0x38;
- + ret = si2183_set_prop(client, SI2183_PROP_MODE, &prop);
- + if (ret) {
- + dev_err(&client->dev, "err set dvb-c mode\n");
- + return ret;
- + }
- +
- + switch (c->modulation) {
- + default:
- + case QAM_AUTO:
- + prop = 0;
- + break;
- + case QAM_16:
- + prop = 7;
- + break;
- + case QAM_32:
- + prop = 8;
- + break;
- + case QAM_64:
- + prop = 9;
- + break;
- + case QAM_128:
- + prop = 10;
- + break;
- + case QAM_256:
- + prop = 11;
- + break;
- + }
- + ret = si2183_set_prop(client, SI2183_PROP_DVBC_CONST, &prop);
- + if (ret) {
- + dev_err(&client->dev, "err set dvb-c constelation\n");
- + return ret;
- + }
- +
- + /* symbol rate */
- + prop = c->symbol_rate / 1000;
- + ret = si2183_set_prop(client, SI2183_PROP_DVBC_SR, &prop);
- + if (ret) {
- + dev_err(&client->dev, "err set dvb-c symbol rate\n");
- + return ret;
- + }
- +
- + return 0;
- +}
- +
- +static int si2183_set_mcns(struct dvb_frontend *fe)
- +{
- + struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- + struct i2c_client *client = fe->demodulator_priv;
- + struct si2183_dev *dev = i2c_get_clientdata(client);
- + struct si2183_cmd cmd;
- + int ret;
- + u16 prop,symb;
- +
- + if(dev->LED_switch)
- + dev->LED_switch(dev->base->i2c,6);
- +
- + memcpy(cmd.args, "\x89\x41\x06\x12\x0\x0", 6);
- + cmd.args[1]= (dev->agc_mode &0x07)<<4 |0x1;
- + cmd.wlen = 6;
- + cmd.rlen = 3;
- + ret = si2183_cmd_execute(client, &cmd);
- + if(ret){
- + dev_err(&client->dev, "err set agc mode\n");
- + }
- + /* mcns mode */
- + prop = 0x18;
- + ret = si2183_set_prop(client, SI2183_PROP_MODE, &prop);
- + if (ret) {
- + dev_err(&client->dev, "err set mcns mode\n");
- + return ret;
- + }
- +
- + switch (c->modulation) {
- + default:
- + case QAM_64:
- + prop = 9;
- + symb = 5057;
- + break;
- + case QAM_256:
- + prop = 11;
- + symb = 5361;
- + break;
- + }
- + ret = si2183_set_prop(client, SI2183_PROP_MCNS_CONST, &prop);
- + if (ret) {
- + dev_err(&client->dev, "err set mcns constelation\n");
- + return ret;
- + }
- +
- + /* symbol rate */
- + ret = si2183_set_prop(client, SI2183_PROP_MCNS_SR, &symb);
- + if (ret) {
- + dev_err(&client->dev, "err set mcns symbol rate\n");
- + return ret;
- + }
- +
- + return 0;
- +}
- +
- +static int gold_code_index (int gold_sequence_index)
- +{
- + unsigned int i, k , x_init;
- + u8 GOLD_PRBS[19] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- + for (k=0; k<gold_sequence_index; k++) {
- + GOLD_PRBS[18] = (GOLD_PRBS[0] + GOLD_PRBS[7])%2;
- + /* Shifting 18 first values */
- + for (i=0; i<18; i++)
- + GOLD_PRBS[i] = GOLD_PRBS[i+1];
- + }
- + x_init = 0;
- + for (i=0; i<18; i++) { x_init = x_init + GOLD_PRBS[i]*(1<<i); }
- +
- + return x_init;
- +}
- +
- +static int si2183_set_dvbs(struct dvb_frontend *fe)
- +{
- + struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- + struct i2c_client *client = fe->demodulator_priv;
- + struct si2183_dev *dev = i2c_get_clientdata(client);
- + struct si2183_cmd cmd;
- + int ret;
- + u16 prop;
- + u32 pls_mode, pls_code;
- +
- + if(dev->LED_switch)
- + dev->LED_switch(dev->base->i2c,2);
- +
- + /*set SAT agc*/
- + memcpy(cmd.args, "\x8a\x1d\x12\x0\x0\x0", 6);
- + cmd.args[1]= dev->agc_mode|0x18;
- + cmd.wlen = 6;
- + cmd.rlen = 3;
- + ret = si2183_cmd_execute(client, &cmd);
- + if(ret){
- + dev_err(&client->dev, "err set agc mode\n");
- + }
- +
- + /* set mode */
- + prop = 0x8;
- + switch (c->delivery_system) {
- + default:
- + case SYS_DVBS:
- + prop |= 0x80;
- + break;
- + case SYS_DVBS2:
- + prop |= 0x90;
- + break;
- + case SYS_DSS:
- + prop |= 0xa0;
- + break;
- + }
- + if (c->inversion)
- + prop |= 0x100;
- + ret = si2183_set_prop(client, SI2183_PROP_MODE, &prop);
- + if (ret) {
- + dev_err(&client->dev, "err set dvb-s/s2 mode\n");
- + return ret;
- + }
- +
- + /* symbol rate */
- + prop = c->symbol_rate / 1000;
- + switch (c->delivery_system) {
- + default:
- + case SYS_DSS:
- + case SYS_DVBS:
- + ret = si2183_set_prop(client, SI2183_PROP_DVBS_SR, &prop);
- + break;
- + case SYS_DVBS2:
- + ret = si2183_set_prop(client, SI2183_PROP_DVBS2_SR, &prop);
- + /* stream_id selection */
- + cmd.args[0] = 0x71;
- + cmd.args[1] = (u8) c->stream_id;
- + cmd.args[2] = c->stream_id == NO_STREAM_ID_FILTER ? 0 : 1;
- + cmd.wlen = 3;
- + cmd.rlen = 1;
- + ret = si2183_cmd_execute(client, &cmd);
- + if (ret)
- + dev_warn(&client->dev, "dvb-s2: err selecting stream_id\n");
- +
- + /* pls selection */
- + pls_mode = c->stream_id == NO_STREAM_ID_FILTER ? 0 : (c->stream_id >> 26) & 3;
- + pls_code = c->stream_id == NO_STREAM_ID_FILTER ? 0 : (c->stream_id >> 8) & 0x3FFFF;
- + if (pls_mode)
- + pls_code = gold_code_index(pls_code);
- + cmd.args[0] = 0x73;
- + cmd.args[1] = pls_code > 0;
- + cmd.args[2] = cmd.args[3] = 0;
- + cmd.args[4] = (u8) pls_code;
- + cmd.args[5] = (u8) (pls_code >> 8);
- + cmd.args[6] = (u8) (pls_code >> 16);
- + cmd.args[7] = (u8) (pls_code >> 24);
- + cmd.wlen = 8;
- + cmd.rlen = 1;
- + ret = si2183_cmd_execute(client, &cmd);
- + if (ret)
- + dev_warn(&client->dev, "dvb-s2: err set pls\n");
- + }
- +
- + return 0;
- +}
- +
- +static int si2183_set_dvbt(struct dvb_frontend *fe)
- +{
- + struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- + struct i2c_client *client = fe->demodulator_priv;
- + struct si2183_dev *dev = i2c_get_clientdata(client);
- + struct si2183_cmd cmd;
- + int ret;
- + u16 prop;
- +
- + if(dev->LED_switch)
- + dev->LED_switch(dev->base->i2c,1);
- +
- + memcpy(cmd.args, "\x89\x41\x06\x12\x0\x0", 6);
- + cmd.args[1]= (dev->agc_mode &0x07)<<4 |0x1;
- + cmd.wlen = 6;
- + cmd.rlen = 3;
- + ret = si2183_cmd_execute(client, &cmd);
- + if(ret){
- + dev_err(&client->dev, "err set agc mode\n");
- + }
- +
- + if (c->bandwidth_hz == 0) {
- + return -EINVAL;
- + } else if (c->bandwidth_hz <= 2000000)
- + prop = 0x02;
- + else if (c->bandwidth_hz <= 5000000)
- + prop = 0x05;
- + else if (c->bandwidth_hz <= 6000000)
- + prop = 0x06;
- + else if (c->bandwidth_hz <= 7000000)
- + prop = 0x07;
- + else if (c->bandwidth_hz <= 8000000)
- + prop = 0x08;
- + else if (c->bandwidth_hz <= 9000000)
- + prop = 0x09;
- + else if (c->bandwidth_hz <= 10000000)
- + prop = 0x0a;
- + else
- + prop = 0x0f;
- +
- + switch (c->delivery_system) {
- + default:
- + case SYS_DVBT:
- + prop |= 0x20;
- + break;
- + case SYS_DVBT2:
- + prop |= 0x70;
- + break;
- + }
- + ret = si2183_set_prop(client, SI2183_PROP_MODE, &prop);
- + if (ret) {
- + dev_err(&client->dev, "err set dvb-t mode\n");
- + return ret;
- + }
- +
- + /* hierarchy - HP = 0 / LP = 1 */
- + prop = c->hierarchy == HIERARCHY_1 ? 1 : 0;
- + ret = si2183_set_prop(client, SI2183_PROP_DVBT_HIER, &prop);
- + if (ret)
- + dev_warn(&client->dev, "dvb-t: err set hierarchy\n");
- +
- + if (c->delivery_system == SYS_DVBT2) {
- + /* stream_id selection */
- + cmd.args[0] = 0x52;
- + cmd.args[1] = (u8) c->stream_id;
- + cmd.args[2] = c->stream_id == NO_STREAM_ID_FILTER ? 0 : 1;
- + cmd.wlen = 3;
- + cmd.rlen = 1;
- + ret = si2183_cmd_execute(client, &cmd);
- + if (ret)
- + dev_warn(&client->dev, "dvb-t2: err selecting stream_id\n");
- +
- + /* dvb-t2 mode - any=0 / base=1 / lite=2 */
- + prop = 0;
- + ret = si2183_set_prop(client, SI2183_PROP_DVBT2_MODE, &prop);
- + if (ret)
- + dev_warn(&client->dev, "dvb-t2: err set mode\n");
- + }
- +
- + return 0;
- +}
- +
- +static int si2183_set_isdbt(struct dvb_frontend *fe)
- +{
- + struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- + struct i2c_client *client = fe->demodulator_priv;
- + struct si2183_dev *dev = i2c_get_clientdata(client);
- + struct si2183_cmd cmd;
- + int ret;
- + u16 prop;
- +
- + if(dev->LED_switch)
- + dev->LED_switch(dev->base->i2c,5);
- +
- +
- + memcpy(cmd.args, "\x89\x41\x06\x12\x0\x0", 6);
- + cmd.args[1]= (dev->agc_mode &0x07)<<4 |0x1;
- + cmd.wlen = 6;
- + cmd.rlen = 3;
- + ret = si2183_cmd_execute(client, &cmd);
- + if(ret){
- + dev_err(&client->dev, "err set agc mode\n");
- + }
- + if (c->bandwidth_hz == 0) {
- + return -EINVAL;
- + } else if (c->bandwidth_hz <= 2000000)
- + prop = 0x02;
- + else if (c->bandwidth_hz <= 5000000)
- + prop = 0x05;
- + else if (c->bandwidth_hz <= 6000000)
- + prop = 0x06;
- + else if (c->bandwidth_hz <= 7000000)
- + prop = 0x07;
- + else if (c->bandwidth_hz <= 8000000)
- + prop = 0x08;
- + else if (c->bandwidth_hz <= 9000000)
- + prop = 0x09;
- + else if (c->bandwidth_hz <= 10000000)
- + prop = 0x0a;
- + else
- + prop = 0x0f;
- +
- + /* ISDB-T mode */
- + prop |= 0x40;
- + ret = si2183_set_prop(client, SI2183_PROP_MODE, &prop);
- + if (ret) {
- + dev_err(&client->dev, "err set dvb-t mode\n");
- + return ret;
- + }
- + return 0;
- +}
- +
- +static int si2183_set_frontend(struct dvb_frontend *fe)
- +{
- + struct i2c_client *client = fe->demodulator_priv;
- + struct si2183_dev *dev = i2c_get_clientdata(client);
- + struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- + int ret;
- + struct si2183_cmd cmd;
- +
- + dev_dbg(&client->dev,
- + "delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u stream_id=%d\n",
- + c->delivery_system, c->modulation, c->frequency,
- + c->bandwidth_hz, c->symbol_rate, c->inversion,
- + c->stream_id);
- +
- + if (!dev->active_fe) {
- + ret = -EAGAIN;
- + goto err;
- + }
- + if(dev->RF_switch)
- + {
- + switch (c->delivery_system) {
- + case SYS_DVBT:
- + case SYS_DVBT2:
- + case SYS_DVBC_ANNEX_A:
- + case SYS_DVBC_ANNEX_B:
- + case SYS_ISDBT:
- + dev->RF_switch(dev->base->i2c,dev->rf_in,1);
- +
- + break;
- +
- + case SYS_DVBS:
- + case SYS_DVBS2:
- + case SYS_DSS:
- + default:
- + dev->RF_switch(dev->base->i2c,dev->rf_in,0);
- + break;
- +
- + }
- + }
- +
- + if(dev->TS_switch)
- + dev->TS_switch(dev->base->i2c,1);
- +
- + if (fe->ops.tuner_ops.set_params) {
- +#ifndef SI2183_USE_I2C_MUX
- + if (fe->ops.i2c_gate_ctrl)
- + fe->ops.i2c_gate_ctrl(fe, 1);
- +#endif
- + ret = fe->ops.tuner_ops.set_params(fe);
- +#ifndef SI2183_USE_I2C_MUX
- + if (fe->ops.i2c_gate_ctrl)
- + fe->ops.i2c_gate_ctrl(fe, 0);
- +#endif
- + if (ret) {
- + dev_err(&client->dev, "err setting tuner params\n");
- + goto err;
- + }
- + }
- +
- + switch (c->delivery_system) {
- + case SYS_DVBT:
- + case SYS_DVBT2:
- + ret = si2183_set_dvbt(fe);
- + break;
- + case SYS_DVBC_ANNEX_A:
- + ret = si2183_set_dvbc(fe);
- + break;
- + case SYS_DVBC_ANNEX_B:
- + ret= si2183_set_mcns(fe);
- + break;
- + case SYS_ISDBT:
- + ret = si2183_set_isdbt(fe);
- + break;
- + case SYS_DVBS:
- + case SYS_DVBS2:
- + case SYS_DSS:
- + ret = si2183_set_dvbs(fe);
- + break;
- + default:
- + ret = -EINVAL;
- + goto err;
- + }
- +
- + /* dsp restart */
- + memcpy(cmd.args, "\x85", 1);
- + cmd.wlen = 1;
- + cmd.rlen = 1;
- + ret = si2183_cmd_execute(client, &cmd);
- + if (ret) {
- + dev_err(&client->dev, "err restarting dsp\n");
- + return ret;
- + }
- +
- + dev->delivery_system = c->delivery_system;
- + return 0;
- +err:
- + dev_err(&client->dev, "set_params failed=%d\n", ret);
- + return ret;
- +}
- +
- +static int si2183_init(struct dvb_frontend *fe)
- +{
- + struct i2c_client *client = fe->demodulator_priv;
- + struct si2183_dev *dev = i2c_get_clientdata(client);
- + struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- + int ret = 0, len, remaining;
- + const struct firmware *fw;
- + const char *fw_name;
- + struct si2183_cmd cmd;
- + unsigned int chip_id;
- + u16 prop;
- +
- + dev_dbg(&client->dev, "\n");
- +
- + if (dev->active_fe) {
- + dev->active_fe |= (1 << fe->id);
- + return 0;
- + }
- +
- + c->cnr.len = 1;
- + c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
- +
- + /* initialize */
- + memcpy(cmd.args, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", 13);
- + if(dev->start_clk_mode == 1){
- + cmd.args[3] =0;
- + cmd.args[5] = 0x6;
- + }
- +
- + cmd.wlen = 13;
- + cmd.rlen = 0;
- + ret = si2183_cmd_execute(client, &cmd);
- + if (ret)
- + goto err;
- +
- + if (dev->fw_loaded) {
- + /* resume */
- + memcpy(cmd.args, "\xc0\x06\x08\x0f\x00\x20\x21\x01", 8);
- +
- + if(dev->start_clk_mode==1)
- + cmd.args[6]=0x31;
- + cmd.wlen = 8;
- + cmd.rlen = 1;
- + ret = si2183_cmd_execute(client, &cmd);
- + if (ret)
- + goto err;
- +
- + memcpy(cmd.args, "\x85", 1);
- + cmd.wlen = 1;
- + cmd.rlen = 1;
- + ret = si2183_cmd_execute(client, &cmd);
- + if (ret)
- + goto err;
- +
- + goto warm;
- + }
- +
- + /* power up */
- + memcpy(cmd.args, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8);
- + if(dev->start_clk_mode ==1 ){
- + cmd.args[6] = 0x30;
- + }
- + cmd.wlen = 8;
- + cmd.rlen = 1;
- + ret = si2183_cmd_execute(client, &cmd);
- + if (ret)
- + goto err;
- +
- + /* query chip revision */
- + memcpy(cmd.args, "\x02", 1);
- + cmd.wlen = 1;
- + cmd.rlen = 13;
- + ret = si2183_cmd_execute(client, &cmd);
- + if (ret)
- + goto err;
- +
- + chip_id = cmd.args[1] << 24 | cmd.args[2] << 16 | cmd.args[3] << 8 |
- + cmd.args[4] << 0;
- +
- + #define SI2183_B60 ('B' << 24 | 83 << 16 | '6' << 8 | '0' << 0)
- +
- + switch (chip_id) {
- + case SI2183_B60:
- + fw_name = SI2183_B60_FIRMWARE;
- + break;
- + default:
- + dev_err(&client->dev, "unknown chip version Si21%d-%c%c%c\n",
- + cmd.args[2], cmd.args[1],
- + cmd.args[3], cmd.args[4]);
- + ret = -EINVAL;
- + goto err;
- + }
- +
- + dev_info(&client->dev, "found a 'Silicon Labs Si21%d-%c%c%c'\n",
- + cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]);
- +
- + ret = request_firmware(&fw, fw_name, &client->dev);
- + if (ret) {
- + dev_err(&client->dev,
- + "firmware file '%s' not found\n",
- + fw_name);
- + goto err;
- + }
- +
- + dev_info(&client->dev, "downloading firmware from file '%s'\n",
- + fw_name);
- +
- + for (remaining = fw->size; remaining > 0; remaining -= 17) {
- + len = fw->data[fw->size - remaining];
- + if (len > SI2183_ARGLEN) {
- + ret = -EINVAL;
- + break;
- + }
- + memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len);
- + cmd.wlen = len;
- + cmd.rlen = 1;
- + ret = si2183_cmd_execute(client, &cmd);
- + if (ret)
- + break;
- + }
- + release_firmware(fw);
- +
- + if (ret) {
- + dev_err(&client->dev, "firmware download failed %d\n", ret);
- + goto err;
- + }
- +
- + memcpy(cmd.args, "\x01\x01", 2);
- + cmd.wlen = 2;
- + cmd.rlen = 1;
- + ret = si2183_cmd_execute(client, &cmd);
- + if (ret)
- + goto err;
- +
- + /* query firmware version */
- + memcpy(cmd.args, "\x11", 1);
- + cmd.wlen = 1;
- + cmd.rlen = 10;
- + ret = si2183_cmd_execute(client, &cmd);
- + if (ret)
- + goto err;
- +
- + dev_info(&client->dev, "firmware version: %c.%c.%d\n",
- + cmd.args[6], cmd.args[7], cmd.args[8]);
- +
- + /* set ts mode */
- + prop = 0x10 | dev->ts_mode | (dev->ts_clock_gapped ? 0x40 : 0);
- + ret = si2183_set_prop(client, 0x1001, &prop);
- + if (ret) {
- + dev_err(&client->dev, "err set ts mode\n");
- + }
- +
- + /* FER resol */
- + prop = 0x12;
- + ret = si2183_set_prop(client, 0x100c, &prop);
- + if (ret) {
- + dev_err(&client->dev, "err set FER resol\n");
- + return ret;
- + }
- +
- + /* DD IEN */
- + prop = 0x00;
- + ret = si2183_set_prop(client, 0x1006, &prop);
- + if (ret) {
- + dev_err(&client->dev, "err set dd ien\n");
- + return ret;
- + }
- +
- + /* int sense */
- + prop = 0x2000;
- + ret = si2183_set_prop(client, 0x1007, &prop);
- + if (ret) {
- + dev_err(&client->dev, "err set int sense\n");
- + return ret;
- + }
- +
- + /* Control of SQI computation */
- + prop = 0x1e;
- + ret = si2183_set_prop(client, 0x100f, &prop);
- + if (ret) {
- + dev_err(&client->dev, "err set sqi comp\n");
- + return ret;
- + }
- +
- + /* Transport Stream setting for parallel mode */
- + prop = 0x0104 | (dev->ts_clock_inv ? 0x0000 : 0x1000);
- + ret = si2183_set_prop(client, 0x1009, &prop);
- + if (ret) {
- + dev_err(&client->dev, "err set par_ts\n");
- + return ret;
- + }
- +
- + /* Transport Stream setting for serial mode */
- + prop = 0x230C | (dev->ts_clock_inv ? 0x0000 : 0x1000);
- + ret = si2183_set_prop(client, 0x1008, &prop);
- + if (ret) {
- + dev_err(&client->dev, "err set ser_ts\n");
- + return ret;
- + }
- +
- + /* Transport Stream setting for parallel mode - secondary*/
- + prop = 0x08e3;
- + ret = si2183_set_prop(client, 0x1015, &prop);
- + if (ret) {
- + dev_err(&client->dev, "err set int par_ts_sec\n");
- + return ret;
- + }
- +
- + /* Transport Stream setting for serial mode - secondary*/
- + prop = 0x01c7;
- + ret = si2183_set_prop(client, 0x1016, &prop);
- + if (ret) {
- + dev_err(&client->dev, "err set int ser_ts_sec\n");
- + return ret;
- + }
- +
- + dev->fw_loaded = true;
- +warm:
- + dev->active_fe |= (1 << fe->id);
- + return 0;
- +
- +err:
- + dev_dbg(&client->dev, "init failed=%d\n", ret);
- + return ret;
- +}
- +
- +static int si2183_sleep(struct dvb_frontend *fe)
- +{
- + struct i2c_client *client = fe->demodulator_priv;
- + struct si2183_dev *dev = i2c_get_clientdata(client);
- + int ret;
- + struct si2183_cmd cmd;
- +
- + dev_dbg(&client->dev, "\n");
- +
- + dev->active_fe &= ~(1 << fe->id);
- + if (dev->active_fe)
- + return 0;
- +
- + memcpy(cmd.args, "\x13", 1);
- + cmd.wlen = 1;
- + cmd.rlen = 0;
- + ret = si2183_cmd_execute(client, &cmd);
- + if (ret)
- + goto err;
- +
- + return 0;
- +err:
- + dev_dbg(&client->dev, "failed=%d\n", ret);
- + return ret;
- +}
- +
- +static int si2183_get_tune_settings(struct dvb_frontend *fe,
- + struct dvb_frontend_tune_settings *s)
- +{
- + s->min_delay_ms = 900;
- +
- + return 0;
- +}
- +
- +#ifdef SI2183_USE_I2C_MUX
- +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
- +static int si2183_select(struct i2c_mux_core *muxc, u32 chan)
- +{
- + struct i2c_client *client = i2c_mux_priv(muxc);
- +#else
- +static int si2183_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
- +{
- + struct i2c_client *client = mux_priv;
- +#endif
- + int ret;
- + struct si2183_cmd cmd;
- +
- + /* open I2C gate */
- + memcpy(cmd.args, "\xc0\x0d\x01", 3);
- + cmd.wlen = 3;
- + cmd.rlen = 0;
- + ret = si2183_cmd_execute_unlocked(client, &cmd);
- + if (ret)
- + goto err;
- +
- + return 0;
- +err:
- + dev_dbg(&client->dev, "failed=%d\n", ret);
- + return ret;
- +}
- +
- +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
- +static int si2183_deselect(struct i2c_mux_core *muxc, u32 chan)
- +{
- + struct i2c_client *client = i2c_mux_priv(muxc);
- +#else
- +static int si2183_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan)
- +{
- + struct i2c_client *client = mux_priv;
- +#endif
- + int ret;
- + struct si2183_cmd cmd;
- +
- + /* close I2C gate */
- + memcpy(cmd.args, "\xc0\x0d\x00", 3);
- + cmd.wlen = 3;
- + cmd.rlen = 0;
- + ret = si2183_cmd_execute_unlocked(client, &cmd);
- + if (ret)
- + goto err;
- +
- + return 0;
- +err:
- + dev_dbg(&client->dev, "failed=%d\n", ret);
- + return ret;
- +}
- +#else
- +static int i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
- +{
- + struct i2c_client *client = fe->demodulator_priv;
- + struct si2183_dev *dev = i2c_get_clientdata(client);
- + struct si2183_cmd cmd;
- +
- + memcpy(cmd.args, "\xc0\x0d\x00", 3);
- + if (enable)
- + cmd.args[2] = 1;
- + cmd.wlen = 3;
- + cmd.rlen = 0;
- + return si2183_cmd_execute(dev->base->i2c_gate_client, &cmd);
- +}
- +#endif
- +
- +static int si2183_tune(struct dvb_frontend *fe, bool re_tune,
- + unsigned int mode_flags, unsigned int *delay, enum fe_status *status)
- +{
- + *delay = HZ / 5;
- + if (re_tune) {
- + int ret = si2183_set_frontend(fe);
- + if (ret)
- + return ret;
- + }
- + return si2183_read_status(fe, status);
- +}
- +
- +static enum dvbfe_algo si2183_get_algo(struct dvb_frontend *fe)
- +{
- + return DVBFE_ALGO_HW;
- +}
- +
- +static int si2183_set_property(struct dvb_frontend *fe,
- + u32 cmd, u32 data)
- +{
- + int ret = 0;
- +
- + switch (cmd) {
- + case DTV_DELIVERY_SYSTEM:
- + switch (data) {
- + case SYS_DVBS:
- + case SYS_DVBS2:
- + case SYS_DSS:
- + fe->ops.info.frequency_min_hz = 950 * MHz;
- + fe->ops.info.frequency_max_hz = 2150 * MHz;
- + fe->ops.info.frequency_stepsize_hz = 0;
- + break;
- + case SYS_ISDBT:
- + fe->ops.info.frequency_min_hz = 42 * MHz;
- + fe->ops.info.frequency_max_hz = 1002 * MHz;
- + fe->ops.info.frequency_stepsize_hz = 0;
- + break;
- + case SYS_DVBC_ANNEX_A:
- + case SYS_DVBC_ANNEX_B:
- + fe->ops.info.frequency_min_hz = 47 * MHz;
- + fe->ops.info.frequency_max_hz = 862 * MHz;
- + fe->ops.info.frequency_stepsize_hz = 62500;
- + break;
- + case SYS_DVBT:
- + case SYS_DVBT2:
- + default:
- + fe->ops.info.frequency_min_hz = 174 * MHz;
- + fe->ops.info.frequency_max_hz = 862 * MHz;
- + fe->ops.info.frequency_stepsize_hz = 250000;
- + break;
- + }
- + break;
- + default:
- + break;
- + }
- +
- + return ret;
- +}
- +
- +
- +static int send_diseqc_cmd(struct dvb_frontend *fe,
- + u8 cont_tone, u8 tone_burst, u8 burst_sel,
- + u8 end_seq, u8 msg_len, u8 *msg)
- +{
- + struct i2c_client *client = fe->demodulator_priv;
- + struct si2183_cmd cmd;
- + u8 enable = 1;
- +
- + cmd.args[0] = 0x8c;
- + cmd.args[1] = enable | (cont_tone << 1)
- + | (tone_burst << 2) | (burst_sel << 3)
- + | (end_seq << 4) | (msg_len << 5);
- +
- + if (msg_len > 0)
- + memcpy(&cmd.args[2], msg, msg_len);
- +
- + cmd.wlen = 8;
- + cmd.rlen = 1;
- + return si2183_cmd_execute(client, &cmd);
- +}
- +
- +static int si2183_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone)
- +{
- + struct i2c_client *client = fe->demodulator_priv;
- + int ret;
- + u8 cont_tone;
- +
- + switch (tone) {
- + case SEC_TONE_ON:
- + cont_tone = 1;
- + break;
- + case SEC_TONE_OFF:
- + cont_tone = 0;
- + break;
- + default:
- + return -EINVAL;
- + }
- +
- + ret = send_diseqc_cmd(fe, cont_tone, 0, 0, 1, 0, NULL);
- + if (ret)
- + goto err;
- +
- + return 0;
- +err:
- + dev_err(&client->dev, "set_tone failed=%d\n", ret);
- + return ret;
- +}
- +
- +static int si2183_diseqc_send_burst(struct dvb_frontend *fe,
- + enum fe_sec_mini_cmd burst)
- +{
- + struct i2c_client *client = fe->demodulator_priv;
- + int ret;
- + u8 burst_sel;
- +
- + switch (burst) {
- + case SEC_MINI_A:
- + burst_sel = 0;
- + break;
- + case SEC_MINI_B:
- + burst_sel = 1;
- + break;
- + default:
- + return -EINVAL;
- + }
- +
- + ret = send_diseqc_cmd(fe, 0, 1, burst_sel, 1, 0, NULL);
- + if (ret)
- + goto err;
- +
- + return 0;
- +err:
- + dev_err(&client->dev, "set_tone failed=%d\n", ret);
- + return ret;
- +}
- +
- +static int si2183_diseqc_send_msg(struct dvb_frontend *fe,
- + struct dvb_diseqc_master_cmd *d)
- +{
- + struct i2c_client *client = fe->demodulator_priv;
- + int ret;
- + u8 remaining = d->msg_len;
- + u8 *p = d->msg;
- + u8 len = 0;
- +
- + while (remaining > 0) {
- + p += len;
- + len = (remaining > 6) ? 6 : remaining;
- + remaining -= len;
- + ret = send_diseqc_cmd(fe, 0, 0, 0,
- + (remaining == 0) ? 1 : 0, len, p);
- + if (ret)
- + goto err;
- + msleep(50);
- + }
- +
- + return 0;
- +err:
- + dev_err(&client->dev, "set_tone failed=%d\n", ret);
- + return ret;
- +}
- +
- +static void spi_read(struct dvb_frontend *fe, struct ecp3_info *ecp3inf)
- +{
- + struct i2c_client *client = fe->demodulator_priv;
- + struct si2183_dev *dev = i2c_get_clientdata(client);
- +
- +
- + if (dev->read_properties)
- + dev->read_properties(client->adapter,ecp3inf->reg, &(ecp3inf->data));
- +
- + return ;
- +}
- +
- +static void spi_write(struct dvb_frontend *fe,struct ecp3_info *ecp3inf)
- +{
- + struct i2c_client *client = fe->demodulator_priv;
- + struct si2183_dev *dev = i2c_get_clientdata(client);
- +
- + if (dev->write_properties)
- + dev->write_properties(client->adapter,ecp3inf->reg, ecp3inf->data);
- + return ;
- +}
- +
- +static void eeprom_read(struct dvb_frontend *fe, struct eeprom_info *eepinf)
- +{
- + struct i2c_client *client = fe->demodulator_priv;
- + struct si2183_dev *dev = i2c_get_clientdata(client);
- +
- + if (dev->read_eeprom)
- + dev->read_eeprom(client->adapter,eepinf->reg, &(eepinf->data));
- + return ;
- +}
- +
- +static void eeprom_write(struct dvb_frontend *fe,struct eeprom_info *eepinf)
- +{
- + struct i2c_client *client = fe->demodulator_priv;
- + struct si2183_dev *dev = i2c_get_clientdata(client);
- +
- + if (dev->write_eeprom)
- + dev->write_eeprom(client->adapter,eepinf->reg, eepinf->data);
- + return ;
- +}
- +
- +static const struct dvb_frontend_ops si2183_ops = {
- + .delsys = {SYS_DVBT, SYS_DVBT2,
- + SYS_ISDBT,
- + SYS_DVBC_ANNEX_A,SYS_DVBC_ANNEX_B,
- + SYS_DVBS, SYS_DVBS2, SYS_DSS},
- + .info = {
- + .name = "Silicon Labs Si2183",
- + .symbol_rate_min = 1000000,
- + .symbol_rate_max = 45000000,
- + .caps = FE_CAN_FEC_1_2 |
- + FE_CAN_FEC_2_3 |
- + FE_CAN_FEC_3_4 |
- + FE_CAN_FEC_5_6 |
- + FE_CAN_FEC_7_8 |
- + FE_CAN_FEC_AUTO |
- + FE_CAN_QPSK |
- + FE_CAN_QAM_16 |
- + FE_CAN_QAM_32 |
- + FE_CAN_QAM_64 |
- + FE_CAN_QAM_128 |
- + FE_CAN_QAM_256 |
- + FE_CAN_QAM_AUTO |
- + FE_CAN_TRANSMISSION_MODE_AUTO |
- + FE_CAN_GUARD_INTERVAL_AUTO |
- + FE_CAN_HIERARCHY_AUTO |
- + FE_CAN_MUTE_TS |
- + FE_CAN_2G_MODULATION |
- + FE_CAN_MULTISTREAM
- + },
- +
- + .get_tune_settings = si2183_get_tune_settings,
- +
- + .init = si2183_init,
- + .sleep = si2183_sleep,
- +
- + .set_frontend = si2183_set_frontend,
- +
- + .read_status = si2183_read_status,
- + .read_signal_strength = si2183_read_signal_strength,
- + .read_snr = si2183_read_snr,
- + .read_ber = si2183_read_ber,
- + .read_ucblocks = si2183_read_ucblocks,
- +
- + .get_frontend_algo = si2183_get_algo,
- + .tune = si2183_tune,
- +
- + .set_property = si2183_set_property,
- +
- + .set_tone = si2183_set_tone,
- + .diseqc_send_burst = si2183_diseqc_send_burst,
- + .diseqc_send_master_cmd = si2183_diseqc_send_msg,
- +#ifndef SI2183_USE_I2C_MUX
- + .i2c_gate_ctrl = i2c_gate_ctrl,
- +#endif
- +
- + .spi_read = spi_read,
- + .spi_write = spi_write,
- + .eeprom_read = eeprom_read,
- + .eeprom_write = eeprom_write,
- +};
- +
- +
- +static struct si_base *match_base(struct i2c_adapter *i2c, u8 adr)
- +{
- + struct si_base *p;
- +
- + list_for_each_entry(p, &silist, silist)
- + if (p->i2c == i2c)// && p->adr == adr) lja: TO FIX
- + return p;
- + return NULL;
- +}
- +
- +static int si2183_probe(struct i2c_client *client,
- + const struct i2c_device_id *id)
- +{
- + struct si2183_config *config = client->dev.platform_data;
- + struct si2183_dev *dev;
- + struct si_base *base;
- + int ret;
- +
- + dev_dbg(&client->dev, "\n");
- +
- + dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- + if (!dev) {
- + ret = -ENOMEM;
- + dev_err(&client->dev, "kzalloc() failed\n");
- + goto err;
- + }
- +
- + base = match_base(client->adapter, client->addr);
- + if (base) {
- + base->count++;
- + dev->base = base;
- + } else {
- + base = kzalloc(sizeof(struct si_base), GFP_KERNEL);
- + if (!base)
- + goto err_kfree;
- + base->i2c = client->adapter;
- + base->adr = client->addr;
- + base->count = 1;
- + dev->base = base;
- + list_add(&base->silist, &silist);
- +
- + mutex_init(&base->i2c_mutex);
- +#ifdef SI2183_USE_I2C_MUX
- +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
- + /* create mux i2c adapter for tuner */
- + base->muxc = i2c_mux_alloc(client->adapter, &client->adapter->dev,
- + 1, 0, I2C_MUX_LOCKED,
- + si2183_select, si2183_deselect);
- + if (!base->muxc) {
- + ret = -ENOMEM;
- + goto err_base_kfree;
- + }
- + base->muxc->priv = client;
- + ret = i2c_mux_add_adapter(base->muxc, 0, 0, 0);
- + if (ret)
- + goto err_base_kfree;
- + base->tuner_adapter = base->muxc->adapter[0];
- +#else
- + /* create mux i2c adapter for tuners */
- + base->tuner_adapter = i2c_add_mux_adapter(client->adapter, &client->adapter->dev,
- + client, 0, 0, 0, si2183_select, si2183_deselect);
- + if (base->tuner_adapter == NULL) {
- + ret = -ENODEV;
- + goto err_base_kfree;
- + }
- +#endif
- +#else
- + base->tuner_adapter = client->adapter;
- + base->i2c_gate_client = client;
- +#endif
- + }
- +
- + /* create dvb_frontend */
- + memcpy(&dev->fe.ops, &si2183_ops, sizeof(struct dvb_frontend_ops));
- + dev->fe.demodulator_priv = client;
- + *config->i2c_adapter = base->tuner_adapter;
- + *config->fe = &dev->fe;
- + dev->ts_mode = config->ts_mode;
- + dev->ts_clock_inv = config->ts_clock_inv;
- + dev->ts_clock_gapped = config->ts_clock_gapped;
- + dev->agc_mode = config->agc_mode;
- + dev->RF_switch = config->RF_switch;
- + dev->rf_in = config->rf_in;
- + dev->fw_loaded = false;
- + dev->delivery_system = 0;
- + dev->snr = 0;
- + dev->stat_resp = 0;
- + dev->active_fe = 0;
- + dev->start_clk_mode = config->start_clk_mode;
- + dev->TS_switch = config->TS_switch;
- + dev->LED_switch = config->LED_switch;
- +
- + dev->write_properties = config->write_properties;
- + dev->read_properties = config->read_properties;
- + dev->write_eeprom = config->write_eeprom;
- + dev->read_eeprom = config->read_eeprom;
- +
- + i2c_set_clientdata(client, dev);
- +
- +#ifndef SI2183_USE_I2C_MUX
- + /* leave gate open for tuner to init */
- + i2c_gate_ctrl(&dev->fe, 1);
- +#endif
- + dev_info(&client->dev, "Silicon Labs Si2183 successfully attached\n");
- + return 0;
- +err_base_kfree:
- + kfree(base);
- +err_kfree:
- + kfree(dev);
- +err:
- + dev_dbg(&client->dev, "probe failed=%d\n", ret);
- + return ret;
- +}
- +
- +static void si2183_remove(struct i2c_client *client)
- +{
- + struct si2183_dev *dev = i2c_get_clientdata(client);
- +
- + dev_dbg(&client->dev, "\n");
- +
- + dev->base->count--;
- + if (dev->base->count == 0) {
- +#ifdef SI2183_USE_I2C_MUX
- +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
- + i2c_mux_del_adapters(dev->base->muxc);
- +#else
- + i2c_del_mux_adapter(dev->base->tuner_adapter);
- +#endif
- +#endif
- + list_del(&dev->base->silist);
- + kfree(dev->base);
- + }
- +
- + dev->fe.ops.release = NULL;
- + dev->fe.demodulator_priv = NULL;
- +
- + kfree(dev);
- +}
- +
- +static const struct i2c_device_id si2183_id_table[] = {
- + {"si2183", 0},
- + {}
- +};
- +MODULE_DEVICE_TABLE(i2c, si2183_id_table);
- +
- +static struct i2c_driver si2183_driver = {
- + .driver = {
- + .name = "si2183",
- + },
- + .probe = si2183_probe,
- + .remove = si2183_remove,
- + .id_table = si2183_id_table,
- +};
- +
- +module_i2c_driver(si2183_driver);
- +
- +MODULE_AUTHOR("Luis Alves <ljalvs@gmail.com>");
- +MODULE_DESCRIPTION("Silicon Labs Si2183 DVB-T/T2/C/C2/S/S2 demodulator driver");
- +MODULE_LICENSE("GPL");
- diff -uraBN a/drivers/media/dvb-frontends/si2183.h b/drivers/media/dvb-frontends/si2183.h
- --- a/drivers/media/dvb-frontends/si2183.h
- +++ b/drivers/media/dvb-frontends/si2183.h
- @@ -0,0 +1,66 @@
- +/*
- + * Silicon Labs Si2183(2) DVB-T/T2/C/C2/S/S2 demodulator driver
- + *
- + * 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.
- + */
- +
- +#ifndef SI2183_H
- +#define SI2183_H
- +
- +#include <linux/dvb/frontend.h>
- +/*
- + * I2C address
- + * 0x64
- + */
- +struct si2183_config {
- + /*
- + * frontend
- + * returned by driver
- + */
- + struct dvb_frontend **fe;
- +
- + /*
- + * tuner I2C adapter
- + * returned by driver
- + */
- + struct i2c_adapter **i2c_adapter;
- +
- + /* TS mode */
- +#define SI2183_TS_PARALLEL 0x06
- +#define SI2183_TS_SERIAL 0x03
- + u8 ts_mode;
- +
- + /* TS clock inverted */
- + bool ts_clock_inv;
- +
- + int start_clk_mode; //0 terrestrial mode 1: satellite mode
- +
- + /* TS clock gapped */
- + bool ts_clock_gapped;
- + /*agc*/
- + u8 agc_mode;
- +
- + /*rf switch*/
- + void (*RF_switch)(struct i2c_adapter * i2c,u8 rf_in,u8 flag);
- + /*rf no.*/
- + u8 rf_in;
- +
- + void (*TS_switch)(struct i2c_adapter * i2c,u8 flag);
- + void (*LED_switch)(struct i2c_adapter * i2c,u8 flag);
- + //update the FW.
- + void (*write_properties) (struct i2c_adapter *i2c,u8 reg, u32 buf);
- + void (*read_properties) (struct i2c_adapter *i2c,u8 reg, u32 *buf);
- + // EEPROM access
- + void (*write_eeprom) (struct i2c_adapter *i2c,u8 reg, u8 buf);
- + void (*read_eeprom) (struct i2c_adapter *i2c,u8 reg, u8 *buf);
- +};
- +
- +#endif
- diff -uraBN a/drivers/media/tuners/av201x.c b/drivers/media/tuners/av201x.c
- --- a/drivers/media/tuners/av201x.c
- +++ b/drivers/media/tuners/av201x.c
- @@ -0,0 +1,302 @@
- +/*
- + * AV201x Airoha Technology silicon tuner driver
- + *
- + * Copyright (C) 2014 Luis Alves <ljalvs@gmail.com>
- + *
- + * 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.,
- + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- + */
- +
- +#include "av201x.h"
- +#include "av201x_priv.h"
- +
- +/* write multiple (continuous) registers */
- +static int av201x_wrm(struct av201x_priv *priv, u8 *buf, int len)
- +{
- + int ret;
- + struct i2c_msg msg = {
- + .addr = priv->cfg->i2c_address,
- + .flags = 0, .buf = buf, .len = len };
- +
- + dev_dbg(&priv->i2c->dev, "%s() i2c wrm @0x%02x (len=%d) ",
- + __func__, buf[0], len);
- +
- + ret = i2c_transfer(priv->i2c, &msg, 1);
- + if (ret < 0) {
- + dev_warn(&priv->i2c->dev,
- + "%s: i2c wrm err(%i) @0x%02x (len=%d)\n",
- + KBUILD_MODNAME, ret, buf[0], len);
- + return ret;
- + }
- + return 0;
- +}
- +
- +/* write one register */
- +static int av201x_wr(struct av201x_priv *priv, u8 addr, u8 data)
- +{
- + u8 buf[] = { addr, data };
- + return av201x_wrm(priv, buf, 2);
- +}
- +
- +/* read multiple (continuous) registers starting at addr */
- +static int av201x_rdm(struct av201x_priv *priv, u8 addr, u8 *buf, int len)
- +{
- + int ret;
- + struct i2c_msg msg[] = {
- + { .addr = priv->cfg->i2c_address, .flags = 0,
- + .buf = &addr, .len = 1 },
- + { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD,
- + .buf = buf, .len = len }
- + };
- +
- + dev_dbg(&priv->i2c->dev, "%s() i2c rdm @0x%02x (len=%d)\n",
- + __func__, addr, len);
- +
- + ret = i2c_transfer(priv->i2c, msg, 2);
- + if (ret < 0) {
- + dev_warn(&priv->i2c->dev,
- + "%s: i2c rdm err(%i) @0x%02x (len=%d)\n",
- + KBUILD_MODNAME, ret, addr, len);
- + return ret;
- + }
- + return 0;
- +}
- +
- +/* read one register */
- +static int av201x_rd(struct av201x_priv *priv, u8 addr, u8 *data)
- +{
- + return av201x_rdm(priv, addr, data, 1);
- +}
- +
- +/* read register, apply masks, write back */
- +static int av201x_regmask(struct av201x_priv *priv,
- + u8 reg, u8 setmask, u8 clrmask)
- +{
- + int ret;
- + u8 b = 0;
- + if (clrmask != 0xff) {
- + ret = av201x_rd(priv, reg, &b);
- + if (ret)
- + return ret;
- + b &= ~clrmask;
- + }
- + return av201x_wr(priv, reg, b | setmask);
- +}
- +
- +static int av201x_wrtable(struct av201x_priv *priv,
- + struct av201x_regtable *regtable, int len)
- +{
- + int ret, i;
- +
- + for (i = 0; i < len; i++) {
- + ret = av201x_regmask(priv, regtable[i].addr,
- + regtable[i].setmask, regtable[i].clrmask);
- + if (ret)
- + return ret;
- + if (regtable[i].sleep)
- + msleep(regtable[i].sleep);
- + }
- + return 0;
- +}
- +
- +static void av201x_release(struct dvb_frontend *fe)
- +{
- + struct av201x_priv *priv = fe->tuner_priv;
- + dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
- +
- + kfree(fe->tuner_priv);
- + fe->tuner_priv = NULL;
- +}
- +
- +static int av201x_init(struct dvb_frontend *fe)
- +{
- + struct av201x_priv *priv = fe->tuner_priv;
- + int ret;
- + dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
- +
- + ret = av201x_wrtable(priv, av201x_inittuner0,
- + ARRAY_SIZE(av201x_inittuner0));
- +
- + switch (priv->cfg->id) {
- + case ID_AV2011:
- + ret |= av201x_wrtable(priv, av201x_inittuner1a,
- + ARRAY_SIZE(av201x_inittuner1a));
- + break;
- + case ID_AV2012:
- + default:
- + ret |= av201x_wrtable(priv, av201x_inittuner1b,
- + ARRAY_SIZE(av201x_inittuner1b));
- + break;
- + }
- +
- + ret |= av201x_wrtable(priv, av201x_inittuner2,
- + ARRAY_SIZE(av201x_inittuner2));
- +
- + ret |= av201x_wr(priv, REG_TUNER_CTRL, 0x96);
- +
- + msleep(120);
- +
- + if (ret)
- + dev_dbg(&priv->i2c->dev, "%s() failed\n", __func__);
- + return ret;
- +}
- +
- +static int av201x_sleep(struct dvb_frontend *fe)
- +{
- + struct av201x_priv *priv = fe->tuner_priv;
- + int ret;
- + dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
- +
- + ret = av201x_regmask(priv, REG_TUNER_CTRL, AV201X_SLEEP, 0);
- + if (ret)
- + dev_dbg(&priv->i2c->dev, "%s() failed\n", __func__);
- + return ret;
- +}
- +
- +static int av201x_set_params(struct dvb_frontend *fe)
- +{
- + struct av201x_priv *priv = fe->tuner_priv;
- + struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- + u32 n, bw, bf;
- + u8 buf[5];
- + int ret;
- +
- + dev_dbg(&priv->i2c->dev, "%s() delivery_system=%d frequency=%d " \
- + "symbol_rate=%d\n", __func__,
- + c->delivery_system, c->frequency, c->symbol_rate);
- +
- + /*
- + ** PLL setup **
- + RF = (pll_N * ref_freq) / pll_M
- + pll_M = fixed 0x10000
- + PLL output is divided by 2
- + REG_FN = pll_M<24:0>
- + */
- + buf[0] = REG_FN;
- + n = DIV_ROUND_CLOSEST(c->frequency, priv->cfg->xtal_freq);
- + buf[1] = (n > 0xff) ? 0xff : (u8) n;
- + n = DIV_ROUND_CLOSEST((c->frequency / 1000) << 17, priv->cfg->xtal_freq / 1000);
- + buf[2] = (u8) (n >> 9);
- + buf[3] = (u8) (n >> 1);
- + buf[4] = (u8) (((n << 7) & 0x80) | 0x50);
- + ret = av201x_wrm(priv, buf, 5);
- + if (ret)
- + goto exit;
- +
- + msleep(20);
- +
- + /* set bandwidth */
- + bw = (c->symbol_rate / 1000) * 135/200;
- + if (c->symbol_rate < 6500000)
- + bw += 6000;
- + bw += 2000;
- + bw *= 108/100;
- +
- + /* check limits (4MHz < bw < 40MHz) */
- + if (bw > 40000)
- + bw = 40000;
- + else if (bw < 4000)
- + bw = 4000;
- +
- + /* bandwidth step = 211kHz */
- + bf = DIV_ROUND_CLOSEST(bw * 127, 21100);
- + ret = av201x_wr(priv, REG_BWFILTER, (u8) bf);
- +
- + /* enable fine tune agc */
- + ret |= av201x_wr(priv, REG_FT_CTRL, AV201X_FT_EN | AV201X_FT_BLK);
- +
- + ret |= av201x_wr(priv, REG_TUNER_CTRL, 0x96);
- + msleep(20);
- +exit:
- + if (ret)
- + dev_dbg(&priv->i2c->dev, "%s() failed\n", __func__);
- + return ret;
- +}
- +
- +static int AV201x_agc [] = { 0, 82, 100, 116, 140, 162, 173, 187, 210, 223, 254, 255};
- +static int AV201x_level_dBm_10[] = { 90, -50, -263, -361, -463, -563, -661, -761, -861, -891, -904, -910};
- +
- +static int av201x_get_rf_strength(struct dvb_frontend *fe, u16 *st)
- +{
- + struct av201x_priv *priv = fe->tuner_priv;
- + struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- + int if_agc, index, table_length, slope, *x, *y;
- +
- + if_agc = *st;
- + x = AV201x_agc;
- + y = AV201x_level_dBm_10;
- + table_length = sizeof(AV201x_agc)/sizeof(int);
- +
- +
- + /* Finding in which segment the if_agc value is */
- + for (index = 0; index < table_length; index ++)
- + if (x[index] > if_agc ) break;
- +
- + /* Computing segment slope */
- + slope = ((y[index]-y[index-1])*1000)/(x[index]-x[index-1]);
- + /* Linear approximation of rssi value in segment (rssi values will be in 0.1dBm unit: '-523' means -52.3 dBm) */
- + *st = 1000 + ((y[index-1] + ((if_agc - x[index-1])*slope + 500)/1000))/10;
- +
- + c->strength.len = 1;
- + c->strength.stat[0].scale = FE_SCALE_DECIBEL;
- + c->strength.stat[0].svalue = ((y[index-1] + ((if_agc - x[index-1])*slope + 500)/1000)) * 100;
- +
- + return 0;
- +}
- +
- +
- +static const struct dvb_tuner_ops av201x_tuner_ops = {
- + .info = {
- + .name = "Airoha Technology AV201x",
- + .frequency_min_hz = 850 * MHz,
- + .frequency_max_hz = 2300 * MHz,
- + },
- +
- + .release = av201x_release,
- +
- + .init = av201x_init,
- + .sleep = av201x_sleep,
- + .set_params = av201x_set_params,
- + .get_rf_strength = av201x_get_rf_strength,
- +};
- +
- +struct dvb_frontend *av201x_attach(struct dvb_frontend *fe,
- + struct av201x_config *cfg, struct i2c_adapter *i2c)
- +{
- + struct av201x_priv *priv = NULL;
- +
- + priv = kzalloc(sizeof(struct av201x_priv), GFP_KERNEL);
- + if (priv == NULL) {
- + dev_dbg(&i2c->dev, "%s() attach failed\n", __func__);
- + return NULL;
- + }
- +
- + priv->cfg = cfg;
- + priv->i2c = i2c;
- +
- + dev_info(&priv->i2c->dev,
- + "%s: Airoha Technology AV201x successfully attached\n",
- + KBUILD_MODNAME);
- +
- + memcpy(&fe->ops.tuner_ops, &av201x_tuner_ops,
- + sizeof(struct dvb_tuner_ops));
- +
- + fe->tuner_priv = priv;
- + return fe;
- +}
- +EXPORT_SYMBOL(av201x_attach);
- +
- +MODULE_DESCRIPTION("Airoha Technology AV201x silicon tuner driver");
- +MODULE_AUTHOR("Luis Alves <ljalvs@gmail.com>");
- +MODULE_LICENSE("GPL");
- diff -uraBN a/drivers/media/tuners/av201x.h b/drivers/media/tuners/av201x.h
- --- a/drivers/media/tuners/av201x.h
- +++ b/drivers/media/tuners/av201x.h
- @@ -0,0 +1,55 @@
- +/*
- + * AV201x Airoha Technology silicon tuner driver
- + *
- + * Copyright (C) 2014 Luis Alves <ljalvs@gmail.com>
- + *
- + * 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.,
- + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- + */
- +
- +#ifndef AV201X_H
- +#define AV201X_H
- +
- +#include <linux/kconfig.h>
- +#include <media/dvb_frontend.h>
- +
- +typedef enum av201x_id {
- + ID_AV2011,
- + ID_AV2012,
- + ID_AV2018,
- +} av201x_id_t;
- +
- +struct av201x_config {
- + /* tuner i2c address */
- + u8 i2c_address;
- + /* tuner type */
- + av201x_id_t id;
- +
- + /* crystal freq in kHz */
- + u32 xtal_freq;
- +};
- +
- +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_AV201X)
- +extern struct dvb_frontend *av201x_attach(struct dvb_frontend *fe,
- + struct av201x_config *cfg, struct i2c_adapter *i2c);
- +#else
- +static inline struct dvb_frontend *av201x_attach(struct dvb_frontend *fe,
- + struct av201x_config *cfg, struct i2c_adapter *i2c)
- +{
- + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- + return NULL;
- +}
- +#endif
- +
- +#endif /* AV201X_H */
- diff -uraBN a/drivers/media/tuners/av201x_priv.h b/drivers/media/tuners/av201x_priv.h
- --- a/drivers/media/tuners/av201x_priv.h
- +++ b/drivers/media/tuners/av201x_priv.h
- @@ -0,0 +1,110 @@
- +/*
- + * AV201x Airoha Technology silicon tuner driver
- + *
- + * Copyright (C) 2014 Luis Alves <ljalvs@gmail.com>
- + *
- + * 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.,
- + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- + */
- +
- +#ifndef AV201X_PRIV_H
- +#define AV201X_PRIV_H
- +
- +struct av201x_priv {
- + struct av201x_config *cfg;
- + struct i2c_adapter *i2c;
- +};
- +
- +enum av201x_regs_addr {
- + REG_FN = 0x00,
- + REG_BWFILTER = 0x05,
- + REG_TUNER_STAT = 0x0b,
- + REG_TUNER_CTRL = 0x0c,
- + REG_FT_CTRL = 0x25,
- +};
- +
- +/* REG_TUNER_STAT */
- +#define AV201X_PLLLOCK (1<<0)
- +
- +/* REG_TUNER_CTRL */
- +#define AV201X_SLEEP (1<<5)
- +#define AV201X_RFLP (1<<6)
- +
- +/* REG_FT_CTRL */
- +#define AV201X_FT_EN (1<<1)
- +#define AV201X_FT_BLK (1<<2)
- +
- +struct av201x_regtable {
- + u8 addr;
- + u8 setmask;
- + u8 clrmask;
- + int sleep;
- +};
- +
- +static struct av201x_regtable av201x_inittuner0[] = {
- + {0x00, 0x38, 0xff, 0},
- + {0x01, 0x00, 0xff, 0},
- + {0x02, 0x00, 0xff, 0},
- + {0x03, 0x50, 0xff, 0},
- + {0x04, 0x1f, 0xff, 0},
- + {0x05, 0xa3, 0xff, 0},
- + {0x06, 0xfd, 0xff, 0},
- + {0x07, 0x58, 0xff, 0},
- + {0x08, 0x36, 0xff, 0},
- + {0x09, 0xc2, 0xff, 0},
- + {0x0a, 0x88, 0xff, 0},
- + {0x0b, 0xb4, 0xff, 20},
- + {0x0d, 0x40, 0xff, 0},
- +};
- +
- +static struct av201x_regtable av201x_inittuner1a[] = {
- + {0x0e, 0x94, 0xff, 0},
- + {0x0f, 0x9a, 0xff, 0},
- +};
- +
- +static struct av201x_regtable av201x_inittuner1b[] = {
- + {0x0e, 0x5b, 0xff, 0},
- + {0x0f, 0x6a, 0xff, 0},
- +};
- +
- +static struct av201x_regtable av201x_inittuner2[] = {
- + {0x10, 0x66, 0xff, 0},
- + {0x11, 0x40, 0xff, 0},
- + {0x12, 0x80, 0xff, 0},
- + {0x13, 0x2b, 0xff, 0},
- + {0x14, 0x6a, 0xff, 0},
- + {0x15, 0x50, 0xff, 0},
- + {0x16, 0x91, 0xff, 0},
- + {0x17, 0x27, 0xff, 0},
- + {0x18, 0x8f, 0xff, 0},
- + {0x19, 0xcc, 0xff, 0},
- + {0x1a, 0x21, 0xff, 0},
- + {0x1b, 0x10, 0xff, 0},
- + {0x1c, 0x80, 0xff, 0},
- + {0x1d, 0x02, 0xff, 0},
- + {0x1e, 0xf5, 0xff, 0},
- + {0x1f, 0x7f, 0xff, 0},
- + {0x20, 0x4a, 0xff, 0},
- + {0x21, 0x9b, 0xff, 0},
- + {0x22, 0xe0, 0xff, 0},
- + {0x23, 0xe0, 0xff, 0},
- + {0x24, 0x36, 0xff, 0},
- + {0x25, 0x00, 0xff, 0},
- + {0x26, 0xab, 0xff, 0},
- + {0x27, 0x97, 0xff, 0},
- + {0x28, 0xc5, 0xff, 0},
- + {0x29, 0xa8, 0xff, 20},
- +};
- +
- +#endif /* AV201X_PRIV_H */
- diff -uraBN a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig
- --- a/drivers/media/tuners/Kconfig
- +++ b/drivers/media/tuners/Kconfig
- @@ -297,4 +297,11 @@
- This device is only used inside a SiP called together with a
- demodulator for now.
- +config MEDIA_TUNER_AV201X
- + tristate "Airoha Technology AV201x silicon tuner"
- + depends on MEDIA_SUPPORT && I2C
- + default m if !MEDIA_SUBDRV_AUTOSELECT
- + help
- + Airoha Technology AV201x silicon tuner driver.
- +
- endmenu
- diff -uraBN a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile
- --- a/drivers/media/tuners/Makefile
- +++ b/drivers/media/tuners/Makefile
- @@ -46,3 +46,4 @@
- obj-$(CONFIG_MEDIA_TUNER_XC2028) += xc2028.o
- obj-$(CONFIG_MEDIA_TUNER_XC4000) += xc4000.o
- obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o
- +obj-$(CONFIG_MEDIA_TUNER_AV201X) += av201x.o
- diff -uraBN a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
- --- a/drivers/media/tuners/si2157.c
- +++ b/drivers/media/tuners/si2157.c
- @@ -1,4 +1,4 @@
- -// SPDX-License-Identifier: GPL-2.0-or-later
- +// // SPDX-License-Identifier: GPL-2.0-or-later
- /*
- * Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver
- *
- @@ -35,7 +35,7 @@
- if (cmd->rlen) {
- /* wait cmd execution terminate */
- - #define TIMEOUT 80
- + #define TIMEOUT 500
- timeout = jiffies + msecs_to_jiffies(TIMEOUT);
- while (!time_after(jiffies, timeout)) {
- ret = i2c_master_recv(client, cmd->args, cmd->rlen);
- @@ -188,9 +188,9 @@
- /* Update the part id based on device's report */
- dev->part_id = part_id;
- - dev_info(&client->dev,
- - "found a 'Silicon Labs Si21%d-%c%c%c ROM 0x%02x'\n",
- - part_id, cmd.args[1], cmd.args[3], cmd.args[4], rom_id);
- + //dev_info(&client->dev,
- + // "found a 'Silicon Labs Si21%d-%c%c%c ROM 0x%02x'\n",
- + // part_id, cmd.args[1], cmd.args[3], cmd.args[4], rom_id);
- if (fw_name)
- ret = si2157_load_firmware(fe, fw_name);
- @@ -223,6 +223,9 @@
- int ret;
- dev_dbg(&client->dev, "\n");
- +
- + if (dev->active)
- + return 0;
- /* Try to get Xtal trim property, to verify tuner still running */
- memcpy(cmd.args, "\x15\x00\x02\x04", 4);
- @@ -285,8 +288,8 @@
- if (ret)
- goto err;
- - dev_info(&client->dev, "firmware version: %c.%c.%d\n",
- - cmd.args[6], cmd.args[7], cmd.args[8]);
- + //dev_info(&client->dev, "firmware version: %c.%c.%d\n",
- + // cmd.args[6], cmd.args[7], cmd.args[8]);
- /* enable tuner status flags */
- memcpy(cmd.args, "\x14\x00\x01\x05\x01\x00", 6);
- @@ -478,30 +481,27 @@
- switch (c->delivery_system) {
- case SYS_ATSC:
- - delivery_system = 0x00;
- - if_frequency = 3250000;
- - break;
- - case SYS_DVBC_ANNEX_B:
- - delivery_system = 0x10;
- - if_frequency = 4000000;
- - break;
- + delivery_system = 0x00;
- + if_frequency = 3250000;
- + break;
- case SYS_DVBT:
- case SYS_DVBT2: /* it seems DVB-T and DVB-T2 both are 0x20 here */
- - delivery_system = 0x20;
- - break;
- + delivery_system = 0x20;
- + break;
- case SYS_DVBC_ANNEX_A:
- + case SYS_DVBC_ANNEX_B:
- case SYS_DVBC_ANNEX_C:
- - delivery_system = 0x30;
- - break;
- + delivery_system = 0x30;
- + break;
- case SYS_ISDBT:
- - delivery_system = 0x40;
- - break;
- + delivery_system = 0x40;
- + break;
- case SYS_DTMB:
- - delivery_system = 0x60;
- - break;
- + delivery_system = 0x60;
- + break;
- default:
- - ret = -EINVAL;
- - goto err;
- + ret = -EINVAL;
- + goto err;
- }
- memcpy(cmd.args, "\x14\x00\x03\x07\x00\x00", 6);
- @@ -525,6 +525,16 @@
- ret = si2157_cmd_execute(client, &cmd);
- if (ret)
- goto err;
- +
- +#if 0 /* set LIF out amp */
- + memcpy(cmd.args, "\x14\x00\x07\x07\x94\x20", 6);
- + cmd.args[5] = delivery_system == 0x30 ? 0x2B : 0x20;
- + cmd.wlen = 6;
- + cmd.rlen = 4;
- + ret = si2157_cmd_execute(client, &cmd);
- + if (ret)
- + goto err;
- +#endif
- /* set digital if frequency if needed */
- if (if_frequency != dev->if_frequency) {
- @@ -865,19 +875,24 @@
- if (ret)
- goto err;
- + c->strength.len = 2;
- c->strength.stat[0].scale = FE_SCALE_DECIBEL;
- - c->strength.stat[0].svalue = (s8) cmd.args[3] * 1000;
- + c->strength.stat[0].svalue = (s8)cmd.args[3] * 1000;
- +
- + c->strength.stat[1].scale = FE_SCALE_RELATIVE;
- + c->strength.stat[1].uvalue = (100 + (s8)cmd.args[3]) * 656;
- schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
- return;
- err:
- + c->strength.len = 1;
- c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
- dev_dbg(&client->dev, "failed=%d\n", ret);
- }
- -static int si2157_probe(struct i2c_client *client,
- - const struct i2c_device_id *id)
- -{
- +static int si2157_probe(struct i2c_client *client)
- +{
- + const struct i2c_device_id *id = i2c_client_get_device_id(client);
- struct si2157_config *cfg = client->dev.platform_data;
- struct dvb_frontend *fe = cfg->fe;
- struct si2157_dev *dev;
- @@ -990,7 +1005,7 @@
- .name = "si2157",
- .suppress_bind_attrs = true,
- },
- - .probe = si2157_probe,
- + .probe_new = si2157_probe,
- .remove = si2157_remove,
- .id_table = si2157_id_table,
- };
- @@ -1000,6 +1015,7 @@
- MODULE_DESCRIPTION("Silicon Labs Si2141/Si2146/2147/2148/2157/2158 silicon tuner driver");
- MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
- MODULE_LICENSE("GPL");
- +MODULE_FIRMWARE(SI2157_A30_FIRMWARE);
- MODULE_FIRMWARE(SI2158_A20_FIRMWARE);
- MODULE_FIRMWARE(SI2141_A10_FIRMWARE);
- MODULE_FIRMWARE(SI2157_A30_FIRMWARE);
- diff -uraBN a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
- --- a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
- +++ b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
- @@ -9,6 +9,8 @@
- */
- #include "dvb-usb-common.h"
- #include <media/media-device.h>
- +
- +#undef CONFIG_MEDIA_CONTROLLER_DVB
- /* does the complete input transfer handling */
- static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
- @@ -317,6 +319,22 @@
- return 0;
- }
- + if(adap->fe_adap[i].fe2!=NULL){
- + if (dvb_register_frontend(&adap->dvb_adap, adap->fe_adap[i].fe2)) {
- + err("Frontend %d registration failed.", i);
- + dvb_frontend_detach(adap->fe_adap[i].fe2);
- + adap->fe_adap[i].fe2 = NULL;
- + /* In error case, do not try register more FEs,
- + * still leaving already registered FEs alive. */
- + if (i == 0)
- + return -ENODEV;
- + else
- + return 0;
- + }
- +
- +
- + }
- +
- /* only attach the tuner if the demod is there */
- if (adap->props.fe[i].tuner_attach != NULL)
- adap->props.fe[i].tuner_attach(adap);
- @@ -343,6 +361,10 @@
- dvb_unregister_frontend(adap->fe_adap[i].fe);
- dvb_frontend_detach(adap->fe_adap[i].fe);
- }
- + if (adap->fe_adap[i].fe2 != NULL) {
- + dvb_unregister_frontend(adap->fe_adap[i].fe2);
- + dvb_frontend_detach(adap->fe_adap[i].fe2);
- + }
- }
- adap->num_frontends_initialized = 0;
- diff -uraBN a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h
- --- a/drivers/media/usb/dvb-usb/dvb-usb.h
- +++ b/drivers/media/usb/dvb-usb/dvb-usb.h
- @@ -372,7 +372,8 @@
- */
- struct dvb_usb_fe_adapter {
- struct dvb_frontend *fe;
- -
- + struct dvb_frontend *fe2;
- + struct dvb_frontend _fe2;
- int (*fe_init) (struct dvb_frontend *);
- int (*fe_sleep) (struct dvb_frontend *);
- diff -uraBN a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig
- --- a/drivers/media/usb/dvb-usb/Kconfig
- +++ b/drivers/media/usb/dvb-usb/Kconfig
- @@ -346,4 +346,13 @@
- DVB-T USB2.0 receivers.
- +config DVB_USB_TBS5580
- + tristate "Turbosight TBS5580 CI support"
- + depends on DVB_USB
- + select DVB_SI2183 if MEDIA_SUBDRV_AUTOSELECT
- + select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
- + select MEDIA_TUNER_AV201X if MEDIA_SUBDRV_AUTOSELECT
- + help
- + Say Y here to support the Turbosight TBS5580 CI USB2 DVB-T/T2/C/C2/S/S2/S2x device
- +
- endif
- diff -uraBN a/drivers/media/usb/dvb-usb/Makefile b/drivers/media/usb/dvb-usb/Makefile
- --- a/drivers/media/usb/dvb-usb/Makefile
- +++ b/drivers/media/usb/dvb-usb/Makefile
- @@ -80,6 +80,9 @@
- dvb-usb-technisat-usb2-objs := technisat-usb2.o
- obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o
- +dvb-usb-tbs5580-objs = tbs5580.o
- +obj-$(CONFIG_DVB_USB_TBS5580) += dvb-usb-tbs5580.o
- +
- ccflags-y += -I$(srctree)/drivers/media/dvb-frontends/
- # due to tuner-xc3028
- ccflags-y += -I$(srctree)/drivers/media/tuners
- diff -uraBN a/drivers/media/usb/dvb-usb/tbs5580.c b/drivers/media/usb/dvb-usb/tbs5580.c
- --- a/drivers/media/usb/dvb-usb/tbs5580.c
- +++ b/drivers/media/usb/dvb-usb/tbs5580.c
- @@ -0,0 +1,793 @@
- +/*
- + * TurboSight TBS 5580se driver
- + *
- + * Copyright (c) 2017 Davin zhang <smiledavin@gmail.com>
- + *
- + * 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, version 2.
- + *
- + */
- +
- +#include <linux/version.h>
- +#include "tbs5580.h"
- +#include "si2183.h"
- +#include "si2157.h"
- +#include "av201x.h"
- +#include <media/dvb_ca_en50221.h>
- +
- +#define TBS5580_READ_MSG 0
- +#define TBS5580_WRITE_MSG 1
- +
- +#define TBS5580_VOLTAGE_CTRL (0x1800)
- +
- +
- +struct tbs5580_state {
- + struct i2c_client *i2c_client_demod;
- + struct i2c_client *i2c_client_tuner;
- + struct dvb_ca_en50221 ca;
- + struct mutex ca_mutex;
- +};
- +
- +static struct av201x_config tbs5580_av201x_cfg = {
- + .i2c_address = 0x62,
- + .id = ID_AV2018,
- + .xtal_freq = 27000,
- +};
- +
- +/* debug */
- +static int dvb_usb_tbs5580_debug;
- +module_param_named(debug, dvb_usb_tbs5580_debug, int, 0644);
- +MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer (or-able))."
- + DVB_USB_DEBUG_STATUS);
- +
- +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
- +
- +static int tbs5580_op_rw(struct usb_device *dev, u8 request, u16 value,
- + u16 index, u8 * data, u16 len, int flags)
- +{
- + int ret;
- + void *u8buf;
- +
- + unsigned int pipe = (flags == TBS5580_READ_MSG) ?
- + usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
- + u8 request_type = (flags == TBS5580_READ_MSG) ? USB_DIR_IN :
- + USB_DIR_OUT;
- + u8buf = kmalloc(len, GFP_KERNEL);
- + if (!u8buf)
- + return -ENOMEM;
- +
- + if (flags == TBS5580_WRITE_MSG)
- + memcpy(u8buf, data, len);
- + ret = usb_control_msg(dev, pipe, request, request_type |
- + USB_TYPE_VENDOR, value, index , u8buf, len, 2000);
- +
- + if (flags == TBS5580_READ_MSG)
- + memcpy(data, u8buf, len);
- + kfree(u8buf);
- + return ret;
- +}
- +
- +static int tbs5580_read_attribute_mem(struct dvb_ca_en50221 *ca,
- + int slot, int address)
- +{
- + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
- + struct tbs5580_state *state = (struct tbs5580_state *)d->priv;
- + u8 buf[4], rbuf[3];
- + int ret;
- +
- + if (0 != slot)
- + return -EINVAL;
- +
- + buf[0] = 1;
- + buf[1] = 0;
- + buf[2] = (address >> 8) & 0x0f;
- + buf[3] = address;
- +
- + //msleep(10);
- +
- + mutex_lock(&state->ca_mutex);
- +
- + ret = tbs5580_op_rw(d->udev, 0xa4, 0, 0,
- + buf, 4, TBS5580_WRITE_MSG);
- +
- + //msleep(1);
- +
- + ret = tbs5580_op_rw(d->udev, 0xa5, 0, 0,
- + rbuf, 1, TBS5580_READ_MSG);
- +
- + mutex_unlock(&state->ca_mutex);
- +
- + if (ret < 0)
- + return ret;
- +
- + return rbuf[0];
- +}
- +
- +static int tbs5580_write_attribute_mem(struct dvb_ca_en50221 *ca,
- + int slot, int address, u8 value)
- +{
- + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
- + struct tbs5580_state *state = (struct tbs5580_state *)d->priv;
- + u8 buf[5];//, rbuf[1];
- + int ret;
- +
- + if (0 != slot)
- + return -EINVAL;
- +
- + buf[0] = 1;
- + buf[1] = 0;
- + buf[2] = (address >> 8) & 0x0f;
- + buf[3] = address;
- + buf[4] = value;
- +
- + mutex_lock(&state->ca_mutex);
- +
- + ret = tbs5580_op_rw(d->udev, 0xa2, 0, 0,
- + buf, 5, TBS5580_WRITE_MSG);
- +
- + //msleep(1);
- +
- + //ret = tbs5580_op_rw(d->udev, 0xa5, 0, 0,
- + // rbuf, 1, TBS5580_READ_MSG);
- +
- + mutex_unlock(&state->ca_mutex);
- +
- + if (ret < 0)
- + return ret;
- +
- + return 0;
- +}
- +
- +static int tbs5580_read_cam_control(struct dvb_ca_en50221 *ca, int slot,
- + u8 address)
- +{
- + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
- + struct tbs5580_state *state = (struct tbs5580_state *)d->priv;
- + u8 buf[4], rbuf[1];
- + int ret;
- +
- + if (0 != slot)
- + return -EINVAL;
- +
- + buf[0] = 1;
- + buf[1] = 1;
- + buf[2] = (address >> 8) & 0x0f;
- + buf[3] = address;
- +
- + mutex_lock(&state->ca_mutex);
- +
- + ret = tbs5580_op_rw(d->udev, 0xa4, 0, 0,
- + buf, 4, TBS5580_WRITE_MSG);
- +
- + //msleep(10);
- +
- + ret = tbs5580_op_rw(d->udev, 0xa5, 0, 0,
- + rbuf, 1, TBS5580_READ_MSG);
- +
- + mutex_unlock(&state->ca_mutex);
- +
- + if (ret < 0)
- + return ret;
- +
- + return rbuf[0];
- +}
- +
- +static int tbs5580_write_cam_control(struct dvb_ca_en50221 *ca, int slot,
- + u8 address, u8 value)
- +{
- + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
- + struct tbs5580_state *state = (struct tbs5580_state *)d->priv;
- + u8 buf[5];//, rbuf[1];
- + int ret;
- +
- + if (0 != slot)
- + return -EINVAL;
- +
- + buf[0] = 1;
- + buf[1] = 1;
- + buf[2] = (address >> 8) & 0x0f;
- + buf[3] = address;
- + buf[4] = value;
- +
- + mutex_lock(&state->ca_mutex);
- +
- + ret = tbs5580_op_rw(d->udev, 0xa2, 0, 0,
- + buf, 5, TBS5580_WRITE_MSG);
- +
- + //msleep(1);
- +
- + //ret = tbs5580_op_rw(d->udev, 0xa5, 0, 0,
- + // rbuf, 1, TBS5580_READ_MSG);
- +
- + mutex_unlock(&state->ca_mutex);
- +
- + if (ret < 0)
- + return ret;
- +
- + return 0;
- +}
- +
- +static int tbs5580_set_video_port(struct dvb_ca_en50221 *ca,
- + int slot, int enable)
- +{
- + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
- + struct tbs5580_state *state = (struct tbs5580_state *)d->priv;
- + u8 buf[2];
- + int ret;
- +
- + if (0 != slot)
- + return -EINVAL;
- +
- + buf[0] = 2;
- + buf[1] = enable;
- +
- + mutex_lock(&state->ca_mutex);
- +
- + ret = tbs5580_op_rw(d->udev, 0xa6, 0, 0,
- + buf, 2, TBS5580_WRITE_MSG);
- +
- + mutex_unlock(&state->ca_mutex);
- +
- + if (ret < 0)
- + return ret;
- +
- + if (enable != buf[1]) {
- + err("CI not %sabled.", enable ? "en" : "dis");
- + return -EIO;
- + }
- +
- + info("CI %sabled.", enable ? "en" : "dis");
- + return 0;
- +}
- +
- +static int tbs5580_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
- +{
- + return tbs5580_set_video_port(ca, slot, /* enable */ 0);
- +}
- +
- +static int tbs5580_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
- +{
- + return tbs5580_set_video_port(ca, slot, /* enable */ 1);
- +}
- +
- +static int tbs5580_slot_reset(struct dvb_ca_en50221 *ca, int slot)
- +{
- + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
- + struct tbs5580_state *state = (struct tbs5580_state *)d->priv;
- + u8 buf[2];
- + int ret;
- +
- + if (0 != slot) {
- + return -EINVAL;
- + }
- +
- + buf[0] = 1;
- + buf[1] = 0;
- +
- + mutex_lock (&state->ca_mutex);
- +
- + ret = tbs5580_op_rw(d->udev, 0xa6, 0, 0,
- + buf, 2, TBS5580_WRITE_MSG);
- +
- + msleep (5);
- +
- + buf[1] = 1;
- +
- + ret = tbs5580_op_rw(d->udev, 0xa6, 0, 0,
- + buf, 2, TBS5580_WRITE_MSG);
- +
- + msleep (1400);
- +
- + mutex_unlock (&state->ca_mutex);
- +
- + if (ret < 0)
- + return ret;
- +
- + return 0;
- +}
- +
- +static int tbs5580_poll_slot_status(struct dvb_ca_en50221 *ca,
- + int slot, int open)
- +{
- + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
- + struct tbs5580_state *state = (struct tbs5580_state *)d->priv;
- + u8 buf[3];
- +
- + if (0 != slot)
- + return -EINVAL;
- +
- + mutex_lock(&state->ca_mutex);
- +
- + tbs5580_op_rw(d->udev, 0xa8, 0, 0,
- + buf, 3, TBS5580_READ_MSG);
- +
- + mutex_unlock(&state->ca_mutex);
- +
- + if ((1 == buf[2]) && (1 == buf[1]) && (0xa9 == buf[0])) {
- + return (DVB_CA_EN50221_POLL_CAM_PRESENT |
- + DVB_CA_EN50221_POLL_CAM_READY);
- + } else {
- + return 0;
- + }
- +}
- +
- +static void tbs5580_uninit(struct dvb_usb_device *d)
- +{
- + struct tbs5580_state *state;
- +
- + if (NULL == d)
- + return;
- +
- + state = (struct tbs5580_state *)d->priv;
- + if (NULL == state)
- + return;
- +
- + if (NULL == state->ca.data)
- + return;
- +
- + /* Error ignored. */
- + tbs5580_set_video_port(&state->ca, /* slot */ 0, /* enable */ 0);
- +
- + dvb_ca_en50221_release(&state->ca);
- +
- + memset(&state->ca, 0, sizeof(state->ca));
- +}
- +
- +static int tbs5580_init(struct dvb_usb_adapter *a)
- +{
- +
- + struct dvb_usb_device *d = a->dev;
- + struct tbs5580_state *state = (struct tbs5580_state *)d->priv;
- + int ret;
- +
- + state->ca.owner = THIS_MODULE;
- + state->ca.read_attribute_mem = tbs5580_read_attribute_mem;
- + state->ca.write_attribute_mem = tbs5580_write_attribute_mem;
- + state->ca.read_cam_control = tbs5580_read_cam_control;
- + state->ca.write_cam_control = tbs5580_write_cam_control;
- + state->ca.slot_reset = tbs5580_slot_reset;
- + state->ca.slot_shutdown = tbs5580_slot_shutdown;
- + state->ca.slot_ts_enable = tbs5580_slot_ts_enable;
- + state->ca.poll_slot_status = tbs5580_poll_slot_status;
- + state->ca.data = d;
- +
- + ret = dvb_ca_en50221_init (&a->dvb_adap, &state->ca,
- + /* flags */ 0, /* n_slots */ 1);
- +
- + if (0 != ret) {
- + err ("Cannot initialize CI: Error %d.", ret);
- + memset (&state->ca, 0, sizeof (state->ca));
- + return ret;
- + }
- +
- + info ("CI initialized.");
- +
- + ret = tbs5580_poll_slot_status(&state->ca, 0, 0);
- + if (0 == ret)
- + tbs5580_set_video_port(&state->ca, /* slot */ 0, /* enable */ 0);
- +
- + return 0;
- +}
- +
- +/* I2C */
- +static int tbs5580_i2c_transfer(struct i2c_adapter *adap,
- + struct i2c_msg msg[], int num)
- +{
- + struct dvb_usb_device *d = i2c_get_adapdata(adap);
- + struct tbs5580_state *state = (struct tbs5580_state *)d->priv;
- + int i = 0;
- + u8 buf6[20];
- + u8 inbuf[20];
- +
- + if (!d)
- + return -ENODEV;
- + mutex_lock(&state->ca_mutex);
- + if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
- + return -EAGAIN;
- +
- + switch (num) {
- + case 2:
- + buf6[0]=msg[1].len;//lenth
- + buf6[1]=msg[0].addr<<1;//demod addr
- + //register
- + buf6[2] = msg[0].buf[0];
- +
- + tbs5580_op_rw(d->udev, 0x90, 0, 0,
- + buf6, 3, TBS5580_WRITE_MSG);
- + //msleep(5);
- + tbs5580_op_rw(d->udev, 0x91, 0, 0,
- + inbuf, buf6[0], TBS5580_READ_MSG);
- + memcpy(msg[1].buf, inbuf, msg[1].len);
- + break;
- + case 1:
- + switch (msg[0].addr) {
- + case 0x67:
- + case 0x62:
- + case 0x61:
- + if (msg[0].flags == 0) {
- + buf6[0] = msg[0].len+1;//lenth
- + buf6[1] = msg[0].addr<<1;//addr
- + for(i=0;i<msg[0].len;i++) {
- + buf6[2+i] = msg[0].buf[i];//register
- + }
- + tbs5580_op_rw(d->udev, 0x80, 0, 0,
- + buf6, msg[0].len+2, TBS5580_WRITE_MSG);
- + } else {
- + buf6[0] = msg[0].len;//length
- + buf6[1] = (msg[0].addr<<1) | 0x01;//addr
- + tbs5580_op_rw(d->udev, 0x93, 0, 0,
- + buf6, 2, TBS5580_WRITE_MSG);
- + //msleep(5);
- + tbs5580_op_rw(d->udev, 0x91, 0, 0,
- + inbuf, buf6[0], TBS5580_READ_MSG);
- + memcpy(msg[0].buf, inbuf, msg[0].len);
- + }
- + //msleep(3);
- + break;
- + case (TBS5580_VOLTAGE_CTRL):
- + buf6[0] = 3;
- + buf6[1] = msg[0].buf[0];
- + tbs5580_op_rw(d->udev, 0x8a, 0, 0,
- + buf6, 2, TBS5580_WRITE_MSG);
- + break;
- + }
- +
- + break;
- + }
- +
- + mutex_unlock(&d->i2c_mutex);
- + mutex_unlock(&state->ca_mutex);
- + return num;
- +}
- +
- +static u32 tbs5580_i2c_func(struct i2c_adapter *adapter)
- +{
- + return I2C_FUNC_I2C;
- +}
- +
- +static struct i2c_algorithm tbs5580_i2c_algo = {
- + .master_xfer = tbs5580_i2c_transfer,
- + .functionality = tbs5580_i2c_func,
- +};
- +
- +static int tbs5580_set_voltage(struct dvb_frontend *fe,
- + enum fe_sec_voltage voltage)
- +{
- + static u8 command_13v[1] = {0x00};
- + static u8 command_18v[1] = {0x01};
- + struct i2c_msg msg[] = {
- + {.addr = TBS5580_VOLTAGE_CTRL, .flags = 0,
- + .buf = command_13v, .len = 1},
- + };
- +
- + struct dvb_usb_adapter *udev_adap =
- + (struct dvb_usb_adapter *)(fe->dvb->priv);
- + if (voltage == SEC_VOLTAGE_18)
- + msg[0].buf = command_18v;
- +
- +
- + i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1);
- +
- + return 0;
- +}
- +
- +static int tbs5580_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
- +{
- + int i,ret;
- + u8 ibuf[3] = {0, 0,0};
- + u8 eeprom[256], eepromline[16];
- +
- + for (i = 0; i < 256; i++) {
- + ibuf[0]=1;//lenth
- + ibuf[1]=0xa0;//eeprom addr
- + ibuf[2]=i;//register
- + ret = tbs5580_op_rw(d->udev, 0x90, 0, 0,
- + ibuf, 3, TBS5580_WRITE_MSG);
- + ret = tbs5580_op_rw(d->udev, 0x91, 0, 0,
- + ibuf, 1, TBS5580_READ_MSG);
- + if (ret < 0) {
- + err("read eeprom failed.");
- + return -1;
- + } else {
- + eepromline[i%16] = ibuf[0];
- + eeprom[i] = ibuf[0];
- + }
- +
- + if ((i % 16) == 15) {
- + deb_xfer("%02x: ", i - 15);
- + debug_dump(eepromline, 16, deb_xfer);
- + }
- + }
- + memcpy(mac, eeprom + 16, 6);
- + return 0;
- +};
- +
- +static struct dvb_usb_device_properties tbs5580_properties;
- +
- +static int tbs5580_frontend_attach(struct dvb_usb_adapter *adap)
- +{
- + struct dvb_usb_device *d = adap->dev;
- + struct tbs5580_state *st = d->priv;
- + struct i2c_adapter *adapter;
- + struct i2c_client *client_demod;
- + struct i2c_client *client_tuner;
- + struct i2c_board_info info;
- + struct si2183_config si2183_config;
- + struct si2157_config si2157_config;
- + u8 buf[20];
- +
- + mutex_init(&st->ca_mutex);
- + /* attach frontend */
- + memset(&si2183_config,0,sizeof(si2183_config));
- + si2183_config.i2c_adapter = &adapter;
- + si2183_config.fe = &adap->fe_adap[0].fe;
- + si2183_config.ts_mode = SI2183_TS_PARALLEL;
- + si2183_config.ts_clock_gapped = true;
- + si2183_config.rf_in = 0;
- + si2183_config.RF_switch = NULL;
- + si2183_config.agc_mode = 0x5 ;
- + memset(&info, 0, sizeof(struct i2c_board_info));
- + strlcpy(info.type, "si2183", I2C_NAME_SIZE);
- + info.addr = 0x67;
- + info.platform_data = &si2183_config;
- + request_module(info.type);
- + client_demod = i2c_new_client_device(&d->i2c_adap, &info);
- + if (!i2c_client_has_driver(client_demod))
- + return -ENODEV;
- +
- + if (!try_module_get(client_demod->dev.driver->owner)) {
- + i2c_unregister_device(client_demod);
- + return -ENODEV;
- + }
- + st->i2c_client_demod = client_demod;
- +
- + /* dvb core doesn't support 2 tuners for 1 demod so
- + we split the adapter in 2 frontends */
- +
- + adap->fe_adap[0].fe2 = &adap->fe_adap[0]._fe2;
- + memcpy(adap->fe_adap[0].fe2, adap->fe_adap[0].fe, sizeof(struct dvb_frontend));
- +
- + /* terrestrial tuner */
- + memset(adap->fe_adap[0].fe->ops.delsys, 0, MAX_DELSYS);
- + adap->fe_adap[0].fe->ops.delsys[0] = SYS_DVBT;
- + adap->fe_adap[0].fe->ops.delsys[1] = SYS_DVBT2;
- + adap->fe_adap[0].fe->ops.delsys[2] = SYS_DVBC_ANNEX_A;
- + adap->fe_adap[0].fe->ops.delsys[3] = SYS_ISDBT;
- + adap->fe_adap[0].fe->ops.delsys[4] = SYS_DVBC_ANNEX_B;
- +
- + /* attach ter tuner */
- + memset(&si2157_config, 0, sizeof(si2157_config));
- + si2157_config.fe = adap->fe_adap[0].fe;
- + si2157_config.if_port = 1;
- + memset(&info, 0, sizeof(struct i2c_board_info));
- + strlcpy(info.type, "si2157", I2C_NAME_SIZE);
- + info.addr = 0x61;
- + info.platform_data = &si2157_config;
- + request_module(info.type);
- + client_tuner = i2c_new_client_device(adapter, &info);
- + if (!i2c_client_has_driver(client_tuner)) {
- + module_put(client_demod->dev.driver->owner);
- + i2c_unregister_device(client_demod);
- + return -ENODEV;
- + }
- + if (!try_module_get(client_tuner->dev.driver->owner)) {
- + i2c_unregister_device(client_tuner);
- + module_put(client_demod->dev.driver->owner);
- + i2c_unregister_device(client_demod);
- + return -ENODEV;
- + }
- +
- + st->i2c_client_tuner = client_tuner;
- +
- + /*attach SAT tuner*/
- + memset(adap->fe_adap[0].fe2->ops.delsys, 0, MAX_DELSYS);
- + adap->fe_adap[0].fe2->ops.delsys[0] = SYS_DVBS;
- + adap->fe_adap[0].fe2->ops.delsys[1] = SYS_DVBS2;
- + adap->fe_adap[0].fe2->ops.delsys[2] = SYS_DSS;
- + adap->fe_adap[0].fe2->id = 1;
- +
- + if (dvb_attach(av201x_attach, adap->fe_adap[0].fe2, &tbs5580_av201x_cfg,
- + adapter) == NULL) {
- + return -ENODEV;
- + }
- + else {
- + buf[0] = 1;
- + buf[1] = 0;
- + tbs5580_op_rw(d->udev, 0x8a, 0, 0,
- + buf, 2, TBS5580_WRITE_MSG);
- +
- + adap->fe_adap[0].fe2->ops.set_voltage = tbs5580_set_voltage;
- +
- + }
- +
- + buf[0] = 0;
- + buf[1] = 0;
- + tbs5580_op_rw(d->udev, 0xb7, 0, 0,
- + buf, 2, TBS5580_WRITE_MSG);
- + buf[0] = 8;
- + buf[1] = 1;
- + tbs5580_op_rw(d->udev, 0x8a, 0, 0,
- + buf, 2, TBS5580_WRITE_MSG);
- +
- + tbs5580_init(adap);
- +
- + strlcpy(adap->fe_adap[0].fe->ops.info.name,d->props.devices[0].name,52);
- + strcat(adap->fe_adap[0].fe->ops.info.name," DVB-T/T2/C/C2/ISDB-T");
- + strlcpy(adap->fe_adap[0].fe2->ops.info.name,d->props.devices[0].name,52);
- + strcat(adap->fe_adap[0].fe2->ops.info.name," DVB-S/S2/S2X");
- +
- + return 0;
- +}
- +
- +static struct usb_device_id tbs5580_table[] = {
- + {USB_DEVICE(0x734c, 0x5580)},
- + { }
- +};
- +
- +MODULE_DEVICE_TABLE(usb, tbs5580_table);
- +
- +static int tbs5580_load_firmware(struct usb_device *dev,
- + const struct firmware *frmwr)
- +{
- + u8 *b, *p;
- + int ret = 0, i;
- + u8 reset;
- + const struct firmware *fw;
- + switch (dev->descriptor.idProduct) {
- + case 0x5580:
- + ret = request_firmware(&fw, tbs5580_properties.firmware, &dev->dev);
- + if (ret != 0) {
- + err("did not find the firmware file. (%s) "
- + "Please see linux/Documentation/dvb/ for more details "
- + "on firmware-problems.", tbs5580_properties.firmware);
- + return ret;
- + }
- + break;
- + default:
- + fw = frmwr;
- + break;
- + }
- + info("start downloading TBS5580 firmware");
- + p = kmalloc(fw->size, GFP_KERNEL);
- + reset = 1;
- + /*stop the CPU*/
- + tbs5580_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, TBS5580_WRITE_MSG);
- + tbs5580_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, TBS5580_WRITE_MSG);
- +
- + if (p != NULL) {
- + memcpy(p, fw->data, fw->size);
- + for (i = 0; i < fw->size; i += 0x40) {
- + b = (u8 *) p + i;
- + if (tbs5580_op_rw(dev, 0xa0, i, 0, b , 0x40,
- + TBS5580_WRITE_MSG) != 0x40) {
- + err("error while transferring firmware");
- + ret = -EINVAL;
- + break;
- + }
- + }
- + /* restart the CPU */
- + reset = 0;
- + if (ret || tbs5580_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1,
- + TBS5580_WRITE_MSG) != 1) {
- + err("could not restart the USB controller CPU.");
- + ret = -EINVAL;
- + }
- + if (ret || tbs5580_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1,
- + TBS5580_WRITE_MSG) != 1) {
- + err("could not restart the USB controller CPU.");
- + ret = -EINVAL;
- + }
- +
- + msleep(100);
- + kfree(p);
- + }
- + return ret;
- +}
- +
- +static struct dvb_usb_device_properties tbs5580_properties = {
- + .caps = DVB_USB_IS_AN_I2C_ADAPTER,
- + .usb_ctrl = DEVICE_SPECIFIC,
- + .firmware = "dvb-usb-id5580.fw",
- + .size_of_priv = sizeof(struct tbs5580_state),
- + .no_reconnect = 1,
- +
- + .i2c_algo = &tbs5580_i2c_algo,
- +
- + .generic_bulk_ctrl_endpoint = 0x81,
- + /* parameter for the MPEG2-data transfer */
- + .num_adapters = 1,
- + .download_firmware = tbs5580_load_firmware,
- + .read_mac_address = tbs5580_read_mac_address,
- + .adapter = {{
- + .num_frontends = 1,
- + .fe = {{
- + .frontend_attach = tbs5580_frontend_attach,
- + .streaming_ctrl = NULL,
- + .tuner_attach = NULL,
- + .stream = {
- + .type = USB_BULK,
- + .count = 8,
- + .endpoint = 0x82,
- + .u = {
- + .bulk = {
- + .buffersize = 4096,
- + }
- + }
- + },
- + }},
- + }},
- +
- + .num_device_descs = 1,
- + .devices = {
- + {"TBS 5580 CI USB2.0",
- + {&tbs5580_table[0], NULL},
- + {NULL},
- + }
- + }
- +};
- +
- +static int tbs5580_probe(struct usb_interface *intf,
- + const struct usb_device_id *id)
- +{
- + if (0 == dvb_usb_device_init(intf, &tbs5580_properties,
- + THIS_MODULE, NULL, adapter_nr)) {
- + return 0;
- + }
- + return -ENODEV;
- +}
- +
- +static void tbs5580_disconnect(struct usb_interface *intf)
- +{
- +
- + struct dvb_usb_device *d = usb_get_intfdata(intf);
- +#if 0
- + struct tbs5580_state *st = d->priv;
- + struct i2c_client *client;
- +
- + /* remove I2C client for tuner */
- + client = st->i2c_client_tuner;
- + if (client) {
- + module_put(client->dev.driver->owner);
- + i2c_unregister_device(client);
- + }
- +
- + /* remove I2C client for demodulator */
- + client = st->i2c_client_demod;
- + if (client) {
- + module_put(client->dev.driver->owner);
- + i2c_unregister_device(client);
- + }
- +#endif
- + tbs5580_uninit(d);
- + dvb_usb_device_exit(intf);
- +}
- +
- +static struct usb_driver tbs5580_driver = {
- + .name = "tbs5580",
- + .probe = tbs5580_probe,
- + .disconnect = tbs5580_disconnect,
- + .id_table = tbs5580_table,
- +};
- +
- +static int __init tbs5580_module_init(void)
- +{
- + int ret = usb_register(&tbs5580_driver);
- + if (ret)
- + err("usb_register failed. Error number %d", ret);
- +
- + return ret;
- +}
- +
- +static void __exit tbs5580_module_exit(void)
- +{
- + usb_deregister(&tbs5580_driver);
- +}
- +
- +module_init(tbs5580_module_init);
- +module_exit(tbs5580_module_exit);
- +
- +MODULE_AUTHOR("Davin zhang <smiledavin@gmail.com>");
- +MODULE_DESCRIPTION("TurboSight TBS 5580 driver");
- +MODULE_VERSION("1.0");
- +MODULE_LICENSE("GPL");
- diff -uraBN a/drivers/media/usb/dvb-usb/tbs5580.h b/drivers/media/usb/dvb-usb/tbs5580.h
- --- a/drivers/media/usb/dvb-usb/tbs5580.h
- +++ b/drivers/media/usb/dvb-usb/tbs5580.h
- @@ -0,0 +1,8 @@
- +#ifndef _TBS5580_H_
- +#define _TBS5580_H_
- +
- +#define DVB_USB_LOG_PREFIX "tbs5580"
- +#include "dvb-usb.h"
- +
- +#define deb_xfer(args...) dprintk(dvb_usb_tbs5580_debug, 0x02, args)
- +#endif
- diff -uraBN a/include/linux/i2c.h b/include/linux/i2c.h
- --- a/include/linux/i2c.h
- +++ b/include/linux/i2c.h
- @@ -189,6 +189,7 @@
- u8 *values);
- int i2c_get_device_id(const struct i2c_client *client,
- struct i2c_device_identity *id);
- +const struct i2c_device_id *i2c_client_get_device_id(const struct i2c_client *client);
- #endif /* I2C */
- /**
- diff -uraBN a/include/media/dvb_frontend.h b/include/media/dvb_frontend.h
- --- a/include/media/dvb_frontend.h
- +++ b/include/media/dvb_frontend.h
- @@ -433,8 +433,10 @@
- * @ts_bus_ctrl: callback function used to take control of the TS bus.
- * @set_lna: callback function to power on/off/auto the LNA.
- * @search: callback function used on some custom algo search algos.
- - * @tuner_ops: pointer to &struct dvb_tuner_ops
- - * @analog_ops: pointer to &struct analog_demod_ops
- + * @tuner_ops: pointer to struct dvb_tuner_ops
- + * @analog_ops: pointer to struct analog_demod_ops
- + * @set_property: callback function to allow the frontend to validade
- + * incoming properties. Should not be used on new drivers.
- */
- struct dvb_frontend_ops {
- struct dvb_frontend_internal_info info;
- @@ -497,6 +499,22 @@
- struct dvb_tuner_ops tuner_ops;
- struct analog_demod_ops analog_ops;
- +
- + int (*set_property)(struct dvb_frontend* fe, u32 cmd, u32 data);
- +
- + void(*spi_read)( struct dvb_frontend *fe,struct ecp3_info *ecp3inf);
- + void(*spi_write)( struct dvb_frontend *fe,struct ecp3_info *ecp3inf);
- +
- + void(*mcu_read)( struct dvb_frontend *fe,struct mcu24cxx_info *mcu24cxxinf);
- + void(*mcu_write)( struct dvb_frontend *fe,struct mcu24cxx_info *mcu24cxxinf);
- +
- + void(*reg_i2cread)( struct dvb_frontend *fe,struct usbi2c_access *pi2cinf);
- + void(*reg_i2cwrite)( struct dvb_frontend *fe,struct usbi2c_access *pi2cinf);
- +
- + void(*eeprom_read)( struct dvb_frontend *fe,struct eeprom_info *peepinf);
- + void(*eeprom_write)( struct dvb_frontend *fe,struct eeprom_info *peepinf);
- +
- + int (*read_temp)(struct dvb_frontend* fe, s16* temp);
- };
- #ifdef __DVB_CORE__
- @@ -628,8 +646,9 @@
- /* Multistream specifics */
- u32 stream_id;
- -
- - /* Physical Layer Scrambling specifics */
- + u32 modcode;
- +
- + /* Physical Layer Scrambling specifics */
- u32 scrambling_sequence_index;
- /* ATSC-MH specifics */
- diff -uraBN a/include/uapi/linux/dvb/frontend.h b/include/uapi/linux/dvb/frontend.h
- --- a/include/uapi/linux/dvb/frontend.h
- +++ b/include/uapi/linux/dvb/frontend.h
- @@ -7,21 +7,6 @@
- * Holger Waechtler <holger@convergence.de>
- * Andre Draszik <ad@convergence.de>
- * for convergence integrated media GmbH
- - *
- - * This program is free software; you can redistribute it and/or
- - * modify it under the terms of the GNU Lesser General Public License
- - * as published by the Free Software Foundation; either version 2.1
- - * 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 Lesser General Public License
- - * along with this program; if not, write to the Free Software
- - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- - *
- */
- #ifndef _DVBFRONTEND_H_
- @@ -69,6 +54,7 @@
- * automatically
- * @FE_CAN_MUTE_TS: Can stop spurious TS data output
- */
- +
- enum fe_caps {
- FE_IS_STUPID = 0,
- FE_CAN_INVERSION_AUTO = 0x1,
- @@ -282,7 +268,6 @@
- /**
- * enum fe_code_rate - Type of Forward Error Correction (FEC)
- *
- - *
- * @FEC_NONE: No Forward Error Correction Code
- * @FEC_1_2: Forward Error Correction Code 1/2
- * @FEC_2_3: Forward Error Correction Code 2/3
- @@ -296,6 +281,22 @@
- * @FEC_3_5: Forward Error Correction Code 3/5
- * @FEC_9_10: Forward Error Correction Code 9/10
- * @FEC_2_5: Forward Error Correction Code 2/5
- + * @FEC_1_3: Forward Error Correction Code 1/3
- + * @FEC_1_4: Forward Error Correction Code 1/4
- + * @FEC_5_9: Forward Error Correction Code 5/9
- + * @FEC_7_9: Forward Error Correction Code 7/9
- + * @FEC_8_15: Forward Error Correction Code 8/15
- + * @FEC_11_15: Forward Error Correction Code 11/15
- + * @FEC_13_18: Forward Error Correction Code 13/18
- + * @FEC_9_20: Forward Error Correction Code 9/20
- + * @FEC_11_20: Forward Error Correction Code 11/20
- + * @FEC_23_36: Forward Error Correction Code 23/36
- + * @FEC_25_36: Forward Error Correction Code 25/36
- + * @FEC_13_45: Forward Error Correction Code 13/45
- + * @FEC_26_45: Forward Error Correction Code 26/45
- + * @FEC_28_45: Forward Error Correction Code 28/45
- + * @FEC_32_45: Forward Error Correction Code 32/45
- + * @FEC_77_90: Forward Error Correction Code 77/90
- *
- * Please note that not all FEC types are supported by a given standard.
- */
- @@ -313,6 +314,32 @@
- FEC_3_5,
- FEC_9_10,
- FEC_2_5,
- + FEC_1_3,
- + FEC_1_4,
- + FEC_5_9,
- + FEC_7_9,
- + FEC_4_15,
- + FEC_7_15,
- + FEC_8_15,
- + FEC_11_15,
- + FEC_13_18,
- + FEC_9_20,
- + FEC_11_20,
- + FEC_23_36,
- + FEC_25_36,
- + FEC_11_45,
- + FEC_13_45,
- + FEC_14_45,
- + FEC_26_45,
- + FEC_28_45,
- + FEC_29_45,
- + FEC_31_45,
- + FEC_32_45,
- + FEC_77_90,
- + FEC_R_58,
- + FEC_R_60,
- + FEC_R_62,
- + FEC_R_5E,
- };
- /**
- @@ -331,6 +358,13 @@
- * @APSK_32: 32-APSK modulation
- * @DQPSK: DQPSK modulation
- * @QAM_4_NR: 4-QAM-NR modulation
- + * @QAM_1024: 1024-QAM modulation
- + * @QAM_4096: 4096-QAM modulation
- + * @APSK_8_L: 8APSK-L modulation
- + * @APSK_16_L: 16APSK-L modulation
- + * @APSK_32_L: 32APSK-L modulation
- + * @APSK_64: 64APSK modulation
- + * @APSK_64_L: 64APSK-L modulation
- *
- * Please note that not all modulations are supported by a given standard.
- *
- @@ -350,6 +384,19 @@
- APSK_32,
- DQPSK,
- QAM_4_NR,
- + QAM_512,
- + QAM_1024,
- + QAM_4096,
- + APSK_64,
- + APSK_128,
- + APSK_256,
- + APSK_8L,
- + APSK_16L,
- + APSK_32L,
- + APSK_64L,
- + APSK_128L,
- + APSK_256L,
- + APSK_1024,
- };
- /**
- @@ -404,6 +451,7 @@
- * @GUARD_INTERVAL_PN420: PN length 420 (1/4)
- * @GUARD_INTERVAL_PN595: PN length 595 (1/6)
- * @GUARD_INTERVAL_PN945: PN length 945 (1/9)
- + * @GUARD_INTERVAL_1_64: Guard interval 1/64
- *
- * Please note that not all guard intervals are supported by a given standard.
- */
- @@ -419,6 +467,7 @@
- GUARD_INTERVAL_PN420,
- GUARD_INTERVAL_PN595,
- GUARD_INTERVAL_PN945,
- + GUARD_INTERVAL_1_64,
- };
- /**
- @@ -513,7 +562,8 @@
- #define DTV_STREAM_ID 42
- #define DTV_ISDBS_TS_ID_LEGACY DTV_STREAM_ID
- -#define DTV_DVBT2_PLP_ID_LEGACY 43
- +#define DTV_DVBT2_PLP_ID_LEGACY DTV_STREAM_ID
- +#define DTV_MODCODE 43
- #define DTV_ENUM_DELSYS 44
- @@ -571,6 +621,9 @@
- * @ROLLOFF_20: Roloff factor: α=20%
- * @ROLLOFF_25: Roloff factor: α=25%
- * @ROLLOFF_AUTO: Auto-detect the roloff factor.
- + * @ROLLOFF_15: Rolloff factor: α=15%
- + * @ROLLOFF_10: Rolloff factor: α=10%
- + * @ROLLOFF_5: Rolloff factor: α=5%
- *
- * .. note:
- *
- @@ -581,6 +634,9 @@
- ROLLOFF_20,
- ROLLOFF_25,
- ROLLOFF_AUTO,
- + ROLLOFF_15,
- + ROLLOFF_10,
- + ROLLOFF_5,
- };
- /**
- @@ -594,6 +650,8 @@
- * Cable TV: DVB-C following ITU-T J.83 Annex B spec (ClearQAM)
- * @SYS_DVBC_ANNEX_C:
- * Cable TV: DVB-C following ITU-T J.83 Annex C spec
- + * @SYS_DVBC2:
- + * Cable TV: DVB-C2
- * @SYS_ISDBC:
- * Cable TV: ISDB-C (no drivers yet)
- * @SYS_DVBT:
- @@ -611,7 +669,7 @@
- * @SYS_DVBS:
- * Satellite TV: DVB-S
- * @SYS_DVBS2:
- - * Satellite TV: DVB-S2
- + * Satellite TV: DVB-S2 and DVB-S2X
- * @SYS_TURBO:
- * Satellite TV: DVB-S Turbo
- * @SYS_ISDBS:
- @@ -645,6 +703,7 @@
- SYS_DVBT2,
- SYS_TURBO,
- SYS_DVBC_ANNEX_C,
- + SYS_DVBC2,
- };
- /* backward compatibility definitions for delivery systems */
- @@ -720,7 +779,7 @@
- };
- /**
- - * enum atscmh_rs_code_mode
- + * enum atscmh_rs_code_mode - ATSC-M/H Reed Solomon modes
- * @ATSCMH_RSCODE_211_187: Reed Solomon code (211,187).
- * @ATSCMH_RSCODE_223_187: Reed Solomon code (223,187).
- * @ATSCMH_RSCODE_235_187: Reed Solomon code (235,187).
- @@ -734,7 +793,8 @@
- };
- #define NO_STREAM_ID_FILTER (~0U)
- -#define LNA_AUTO (~0U)
- +#define LNA_AUTO (~0U)
- +#define MODCODE_ALL (~0U)
- /**
- * enum fecap_scale_params - scale types for the quality parameters.
- @@ -1008,4 +1068,45 @@
- #endif
- -#endif /*_DVBFRONTEND_H_*/
- +struct ecp3_info
- +{
- + __u8 reg;
- + __u32 data;
- +};
- +
- +struct mcu24cxx_info
- +{
- + __u32 bassaddr;
- + __u8 reg;
- + __u32 data;
- +};
- +
- +struct usbi2c_access
- +{
- + __u8 chip_addr;
- + __u8 reg;
- + __u8 num;
- + __u8 buf[8];
- +};
- +
- +struct eeprom_info
- +{
- + __u8 reg;
- + __u8 data;
- +};
- +
- +#define FE_ECP3FW_READ _IOR('o', 90, struct ecp3_info)
- +#define FE_ECP3FW_WRITE _IOW('o', 91, struct ecp3_info)
- +
- +#define FE_24CXX_READ _IOR('o', 92, struct mcu24cxx_info)
- +#define FE_24CXX_WRITE _IOW('o', 93, struct mcu24cxx_info)
- +
- +#define FE_REGI2C_READ _IOR('o', 94, struct usbi2c_access)
- +#define FE_REGI2C_WRITE _IOW('o', 95, struct usbi2c_access)
- +
- +#define FE_EEPROM_READ _IOR('o', 96, struct eeprom_info)
- +#define FE_EEPROM_WRITE _IOW('o', 97, struct eeprom_info)
- +
- +#define FE_READ_TEMP _IOR('o', 98, __s16)
- +
- +#endif /* _DVBFRONTEND_H_ */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement