@@ -67,6 +67,7 @@ config DVB_TDA18271C2DD
config DVB_SI2165
tristate "Silicon Labs si2165 based"
depends on DVB_CORE && I2C
+ select REGMAP_I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-C/T demodulator.
@@ -25,6 +25,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/firmware.h>
+#include <linux/regmap.h>
#include "dvb_frontend.h"
#include "dvb_math.h"
@@ -40,7 +41,9 @@
*/
struct si2165_state {
- struct i2c_adapter *i2c;
+ struct i2c_client *client;
+
+ struct regmap *regmap;
struct dvb_frontend fe;
@@ -108,61 +111,27 @@ static int si2165_write(struct si2165_state *state, const u16 reg,
const u8 *src, const int count)
{
int ret;
- struct i2c_msg msg;
- u8 buf[2 + 4]; /* write a maximum of 4 bytes of data */
-
- if (count + 2 > sizeof(buf)) {
- dev_warn(&state->i2c->dev,
- "%s: i2c wr reg=%04x: count=%d is too big!\n",
- KBUILD_MODNAME, reg, count);
- return -EINVAL;
- }
- buf[0] = reg >> 8;
- buf[1] = reg & 0xff;
- memcpy(buf + 2, src, count);
-
- msg.addr = state->config.i2c_addr;
- msg.flags = 0;
- msg.buf = buf;
- msg.len = count + 2;
if (debug & DEBUG_I2C_WRITE)
deb_i2c_write("reg: 0x%04x, data: %*ph\n", reg, count, src);
- ret = i2c_transfer(state->i2c, &msg, 1);
+ ret = regmap_bulk_write(state->regmap, reg, src, count);
- if (ret != 1) {
- dev_err(&state->i2c->dev, "%s: ret == %d\n", __func__, ret);
- if (ret < 0)
- return ret;
- else
- return -EREMOTEIO;
- }
+ if (ret)
+ dev_err(&state->client->dev, "%s: ret == %d\n", __func__, ret);
- return 0;
+ return ret;
}
static int si2165_read(struct si2165_state *state,
const u16 reg, u8 *val, const int count)
{
- int ret;
- u8 reg_buf[] = { reg >> 8, reg & 0xff };
- struct i2c_msg msg[] = {
- { .addr = state->config.i2c_addr,
- .flags = 0, .buf = reg_buf, .len = 2 },
- { .addr = state->config.i2c_addr,
- .flags = I2C_M_RD, .buf = val, .len = count },
- };
-
- ret = i2c_transfer(state->i2c, msg, 2);
+ int ret = regmap_bulk_read(state->regmap, reg, val, count);
- if (ret != 2) {
- dev_err(&state->i2c->dev, "%s: error (addr %02x reg %04x error (ret == %i)\n",
+ if (ret) {
+ dev_err(&state->client->dev, "%s: error (addr %02x reg %04x error (ret == %i)\n",
__func__, state->config.i2c_addr, reg, ret);
- if (ret < 0)
- return ret;
- else
- return -EREMOTEIO;
+ return ret;
}
if (debug & DEBUG_I2C_READ)
@@ -174,9 +143,9 @@ static int si2165_read(struct si2165_state *state,
static int si2165_readreg8(struct si2165_state *state,
const u16 reg, u8 *val)
{
- int ret;
-
- ret = si2165_read(state, reg, val, 1);
+ unsigned int val_tmp;
+ int ret = regmap_read(state->regmap, reg, &val_tmp);
+ *val = (u8)val_tmp;
deb_readreg("R(0x%04x)=0x%02x\n", reg, *val);
return ret;
}
@@ -194,7 +163,7 @@ static int si2165_readreg16(struct si2165_state *state,
static int si2165_writereg8(struct si2165_state *state, const u16 reg, u8 val)
{
- return si2165_write(state, reg, &val, 1);
+ return regmap_write(state->regmap, reg, val);
}
static int si2165_writereg16(struct si2165_state *state, const u16 reg, u16 val)
@@ -206,20 +175,23 @@ static int si2165_writereg16(struct si2165_state *state, const u16 reg, u16 val)
static int si2165_writereg24(struct si2165_state *state, const u16 reg, u32 val)
{
+ int ret;
u8 buf[3] = { val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff };
- return si2165_write(state, reg, buf, 3);
+ ret = si2165_write(state, reg, buf, 2);
+ if (ret == 0)
+ return si2165_write(state, reg+2, buf+2, 1);
+ return ret;
}
static int si2165_writereg32(struct si2165_state *state, const u16 reg, u32 val)
{
- u8 buf[4] = {
- val & 0xff,
- (val >> 8) & 0xff,
- (val >> 16) & 0xff,
- (val >> 24) & 0xff
- };
- return si2165_write(state, reg, buf, 4);
+ int ret;
+ ret = si2165_writereg16(state, reg, val & 0xffff);
+ if (ret == 0) {
+ ret = si2165_writereg16(state, reg+2, (val >> 16) & 0xffff);
+ }
+ return ret;
}
static int si2165_writereg_mask8(struct si2165_state *state, const u16 reg,
@@ -276,6 +248,7 @@ static int si2165_init_pll(struct si2165_state *state)
u8 divm = 8;
u8 divl = 12;
u8 buf[4];
+ int ret;
/*
* hardcoded values can be deleted if calculation is verified
@@ -316,9 +289,18 @@ static int si2165_init_pll(struct si2165_state *state)
/* write pll registers 0x00a0..0x00a3 at once */
buf[0] = divl;
buf[1] = divm;
+ /*
buf[2] = (divn & 0x3f) | ((divp == 1) ? 0x40 : 0x00) | 0x80;
buf[3] = divr;
return si2165_write(state, 0x00a0, buf, 4);
+ */
+ ret = si2165_write(state, 0x00a0, buf, 2);
+ if (ret == 0) {
+ buf[0] = (divn & 0x3f) | ((divp == 1) ? 0x40 : 0x00) | 0x80;
+ buf[1] = divr;
+ ret = si2165_write(state, 0x00a2, buf, 2);
+ }
+ return ret;
}
static int si2165_adjust_pll_divl(struct si2165_state *state, u8 divl)
@@ -345,7 +327,7 @@ static int si2165_wait_init_done(struct si2165_state *state)
return 0;
usleep_range(1000, 50000);
}
- dev_err(&state->i2c->dev, "%s: init_done was not set\n",
+ dev_err(&state->client->dev, "%s: init_done was not set\n",
KBUILD_MODNAME);
return ret;
}
@@ -374,14 +356,14 @@ static int si2165_upload_firmware_block(struct si2165_state *state,
wordcount = data[offset];
if (wordcount < 1 || data[offset+1] ||
data[offset+2] || data[offset+3]) {
- dev_warn(&state->i2c->dev,
+ dev_warn(&state->client->dev,
"%s: bad fw data[0..3] = %*ph\n",
KBUILD_MODNAME, 4, data);
return -EINVAL;
}
if (offset + 8 + wordcount * 4 > len) {
- dev_warn(&state->i2c->dev,
+ dev_warn(&state->client->dev,
"%s: len is too small for block len=%d, wordcount=%d\n",
KBUILD_MODNAME, len, wordcount);
return -EINVAL;
@@ -389,17 +371,26 @@ static int si2165_upload_firmware_block(struct si2165_state *state,
buf_ctrl[0] = wordcount - 1;
- ret = si2165_write(state, 0x0364, buf_ctrl, 4);
+ ret = si2165_write(state, 0x0364, buf_ctrl, 2);
+ if (ret < 0)
+ goto error;
+ ret = si2165_write(state, 0x0366, buf_ctrl+2, 2);
if (ret < 0)
goto error;
- ret = si2165_write(state, 0x0368, data+offset+4, 4);
+ ret = si2165_write(state, 0x0368, data+offset+4, 2);
+ if (ret < 0)
+ goto error;
+ ret = si2165_write(state, 0x036a, data+offset+6, 2);
if (ret < 0)
goto error;
offset += 8;
while (wordcount > 0) {
- ret = si2165_write(state, 0x36c, data+offset, 4);
+ ret = si2165_write(state, 0x36c, data+offset, 2);
+ if (ret < 0)
+ goto error;
+ ret = si2165_write(state, 0x36e, data+offset+2, 2);
if (ret < 0)
goto error;
wordcount--;
@@ -444,15 +435,15 @@ static int si2165_upload_firmware(struct si2165_state *state)
fw_file = SI2165_FIRMWARE_REV_D;
break;
default:
- dev_info(&state->i2c->dev, "%s: no firmware file for revision=%d\n",
+ dev_info(&state->client->dev, "%s: no firmware file for revision=%d\n",
KBUILD_MODNAME, state->chip_revcode);
return 0;
}
/* request the firmware, this will block and timeout */
- ret = request_firmware(&fw, fw_file, state->i2c->dev.parent);
+ ret = request_firmware(&fw, fw_file, &state->client->dev);
if (ret) {
- dev_warn(&state->i2c->dev, "%s: firmware file '%s' not found\n",
+ dev_warn(&state->client->dev, "%s: firmware file '%s' not found\n",
KBUILD_MODNAME, fw_file);
goto error;
}
@@ -460,11 +451,11 @@ static int si2165_upload_firmware(struct si2165_state *state)
data = fw->data;
len = fw->size;
- dev_info(&state->i2c->dev, "%s: downloading firmware from file '%s' size=%d\n",
+ dev_info(&state->client->dev, "%s: downloading firmware from file '%s' size=%d\n",
KBUILD_MODNAME, fw_file, len);
if (len % 4 != 0) {
- dev_warn(&state->i2c->dev, "%s: firmware size is not multiple of 4\n",
+ dev_warn(&state->client->dev, "%s: firmware size is not multiple of 4\n",
KBUILD_MODNAME);
ret = -EINVAL;
goto error;
@@ -472,14 +463,14 @@ static int si2165_upload_firmware(struct si2165_state *state)
/* check header (8 bytes) */
if (len < 8) {
- dev_warn(&state->i2c->dev, "%s: firmware header is missing\n",
+ dev_warn(&state->client->dev, "%s: firmware header is missing\n",
KBUILD_MODNAME);
ret = -EINVAL;
goto error;
}
if (data[0] != 1 || data[1] != 0) {
- dev_warn(&state->i2c->dev, "%s: firmware file version is wrong\n",
+ dev_warn(&state->client->dev, "%s: firmware file version is wrong\n",
KBUILD_MODNAME);
ret = -EINVAL;
goto error;
@@ -517,7 +508,7 @@ static int si2165_upload_firmware(struct si2165_state *state)
/* start right after the header */
offset = 8;
- dev_info(&state->i2c->dev, "%s: si2165_upload_firmware extracted patch_version=0x%02x, block_count=0x%02x, crc_expected=0x%04x\n",
+ dev_info(&state->client->dev, "%s: si2165_upload_firmware extracted patch_version=0x%02x, block_count=0x%02x, crc_expected=0x%04x\n",
KBUILD_MODNAME, patch_version, block_count, crc_expected);
ret = si2165_upload_firmware_block(state, data, len, &offset, 1);
@@ -536,7 +527,7 @@ static int si2165_upload_firmware(struct si2165_state *state)
ret = si2165_upload_firmware_block(state, data, len,
&offset, block_count);
if (ret < 0) {
- dev_err(&state->i2c->dev,
+ dev_err(&state->client->dev,
"%s: firmware could not be uploaded\n",
KBUILD_MODNAME);
goto error;
@@ -548,7 +539,7 @@ static int si2165_upload_firmware(struct si2165_state *state)
goto error;
if (val16 != crc_expected) {
- dev_err(&state->i2c->dev,
+ dev_err(&state->client->dev,
"%s: firmware crc mismatch %04x != %04x\n",
KBUILD_MODNAME, val16, crc_expected);
ret = -EINVAL;
@@ -560,7 +551,7 @@ static int si2165_upload_firmware(struct si2165_state *state)
goto error;
if (len != offset) {
- dev_err(&state->i2c->dev,
+ dev_err(&state->client->dev,
"%s: firmware len mismatch %04x != %04x\n",
KBUILD_MODNAME, len, offset);
ret = -EINVAL;
@@ -577,7 +568,7 @@ static int si2165_upload_firmware(struct si2165_state *state)
if (ret < 0)
goto error;
- dev_info(&state->i2c->dev, "%s: fw load finished\n", KBUILD_MODNAME);
+ dev_info(&state->client->dev, "%s: fw load finished\n", KBUILD_MODNAME);
ret = 0;
state->firmware_loaded = true;
@@ -611,7 +602,7 @@ static int si2165_init(struct dvb_frontend *fe)
if (ret < 0)
goto error;
if (val != state->config.chip_mode) {
- dev_err(&state->i2c->dev, "%s: could not set chip_mode\n",
+ dev_err(&state->client->dev, "%s: could not set chip_mode\n",
KBUILD_MODNAME);
return -EINVAL;
}
@@ -672,9 +663,13 @@ static int si2165_init(struct dvb_frontend *fe)
goto error;
/* dsp_addr_jump */
- ret = si2165_writereg32(state, 0x0348, 0xf4000000);
+ ret = si2165_writereg16(state, 0x0348, 0x0000);
+ if (ret < 0)
+ goto error;
+ ret = si2165_writereg16(state, 0x034a, 0xf400);
if (ret < 0)
goto error;
+
/* boot/wdog status */
ret = si2165_readreg8(state, 0x0341, &val);
if (ret < 0)
@@ -751,6 +746,9 @@ static int si2165_set_oversamp(struct si2165_state *state, u32 dvb_rate)
u64 oversamp;
u32 reg_value;
+ if (!dvb_rate)
+ return -EINVAL;
+
oversamp = si2165_get_fe_clk(state);
oversamp <<= 23;
do_div(oversamp, dvb_rate);
@@ -769,12 +767,15 @@ static int si2165_set_if_freq_shift(struct si2165_state *state)
u32 IF = 0;
if (!fe->ops.tuner_ops.get_if_frequency) {
- dev_err(&state->i2c->dev,
+ dev_err(&state->client->dev,
"%s: Error: get_if_frequency() not defined at tuner. Can't work without it!\n",
KBUILD_MODNAME);
return -EINVAL;
}
+ if (!fe_clk)
+ return -EINVAL;
+
fe->ops.tuner_ops.get_if_frequency(fe, &IF);
if_freq_shift = IF;
if_freq_shift <<= 29;
@@ -1003,14 +1004,6 @@ static int si2165_set_frontend(struct dvb_frontend *fe)
return 0;
}
-static void si2165_release(struct dvb_frontend *fe)
-{
- struct si2165_state *state = fe->demodulator_priv;
-
- dprintk("%s: called\n", __func__);
- kfree(state);
-}
-
static struct dvb_frontend_ops si2165_ops = {
.info = {
.name = "Silicon Labs ",
@@ -1046,67 +1039,83 @@ static struct dvb_frontend_ops si2165_ops = {
.set_frontend = si2165_set_frontend,
.read_status = si2165_read_status,
-
- .release = si2165_release,
};
-struct dvb_frontend *si2165_attach(const struct si2165_config *config,
- struct i2c_adapter *i2c)
+static int si2165_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct si2165_state *state = NULL;
+ struct si2165_platform_data *pdata = client->dev.platform_data;
int n;
- int io_ret;
+ int ret = 0;
u8 val;
char rev_char;
const char *chip_name;
-
- if (config == NULL || i2c == NULL)
- goto error;
+ static const struct regmap_config regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = 0x08ff,
+ };
/* allocate memory for the internal state */
state = kzalloc(sizeof(struct si2165_state), GFP_KERNEL);
- if (state == NULL)
+ if (state == NULL) {
+ ret = -ENOMEM;
goto error;
+ }
+
+ /* create regmap */
+ state->regmap = devm_regmap_init_i2c(client, ®map_config);
+ if (IS_ERR(state->regmap)) {
+ ret = PTR_ERR(state->regmap);
+ goto error;
+ }
/* setup the state */
- state->i2c = i2c;
- state->config = *config;
+ state->client = client;
+ state->config.i2c_addr = client->addr;
+ state->config.chip_mode = pdata->chip_mode;
+ state->config.ref_freq_Hz = pdata->ref_freq_Hz;
+ state->config.inversion = pdata->inversion;
if (state->config.ref_freq_Hz < 4000000
|| state->config.ref_freq_Hz > 27000000) {
- dev_err(&state->i2c->dev, "%s: ref_freq of %d Hz not supported by this driver\n",
+ dev_err(&state->client->dev, "%s: ref_freq of %d Hz not supported by this driver\n",
KBUILD_MODNAME, state->config.ref_freq_Hz);
+ ret = -EINVAL;
goto error;
}
/* create dvb_frontend */
memcpy(&state->fe.ops, &si2165_ops,
sizeof(struct dvb_frontend_ops));
+ state->fe.ops.release = NULL;
state->fe.demodulator_priv = state;
+ i2c_set_clientdata(client, state);
/* powerup */
- io_ret = si2165_writereg8(state, 0x0000, state->config.chip_mode);
- if (io_ret < 0)
- goto error;
+ ret = si2165_writereg8(state, 0x0000, state->config.chip_mode);
+ if (ret < 0)
+ goto nodev_error;
- io_ret = si2165_readreg8(state, 0x0000, &val);
- if (io_ret < 0)
- goto error;
+ ret = si2165_readreg8(state, 0x0000, &val);
+ if (ret < 0)
+ goto nodev_error;
if (val != state->config.chip_mode)
- goto error;
+ goto nodev_error;
- io_ret = si2165_readreg8(state, 0x0023, &state->chip_revcode);
- if (io_ret < 0)
- goto error;
+ ret = si2165_readreg8(state, 0x0023, &state->chip_revcode);
+ if (ret < 0)
+ goto nodev_error;
- io_ret = si2165_readreg8(state, 0x0118, &state->chip_type);
- if (io_ret < 0)
- goto error;
+ ret = si2165_readreg8(state, 0x0118, &state->chip_type);
+ if (ret < 0)
+ goto nodev_error;
/* powerdown */
- io_ret = si2165_writereg8(state, 0x0000, SI2165_MODE_OFF);
- if (io_ret < 0)
- goto error;
+ ret = si2165_writereg8(state, 0x0000, SI2165_MODE_OFF);
+ if (ret < 0)
+ goto nodev_error;
if (state->chip_revcode < 26)
rev_char = 'A' + state->chip_revcode;
@@ -1124,12 +1133,12 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config,
state->has_dvbc = true;
break;
default:
- dev_err(&state->i2c->dev, "%s: Unsupported Silicon Labs chip (type %d, rev %d)\n",
+ dev_err(&state->client->dev, "%s: Unsupported Silicon Labs chip (type %d, rev %d)\n",
KBUILD_MODNAME, state->chip_type, state->chip_revcode);
- goto error;
+ goto nodev_error;
}
- dev_info(&state->i2c->dev,
+ dev_info(&state->client->dev,
"%s: Detected Silicon Labs %s-%c (type %d, rev %d)\n",
KBUILD_MODNAME, chip_name, rev_char, state->chip_type,
state->chip_revcode);
@@ -1149,13 +1158,46 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config,
sizeof(state->fe.ops.info.name));
}
- return &state->fe;
+ /* return fe pointer */
+ *pdata->fe = &state->fe;
+ return 0;
+
+nodev_error:
+ ret = -ENODEV;
error:
kfree(state);
- return NULL;
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+ return ret;
+}
+
+static int si2165_remove(struct i2c_client *client)
+{
+ struct si2165_state *state = i2c_get_clientdata(client);
+
+ dev_dbg(&client->dev, "\n");
+
+ kfree(state);
+ return 0;
}
-EXPORT_SYMBOL(si2165_attach);
+
+static const struct i2c_device_id si2165_id_table[] = {
+ {"si2165", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, si2165_id_table);
+
+static struct i2c_driver si2165_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "si2165",
+ },
+ .probe = si2165_probe,
+ .remove = si2165_remove,
+ .id_table = si2165_id_table,
+};
+
+module_i2c_driver(si2165_driver);
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
@@ -28,10 +28,15 @@ enum {
SI2165_MODE_PLL_XTAL = 0x21
};
-struct si2165_config {
- /* i2c addr
- * possible values: 0x64,0x65,0x66,0x67 */
- u8 i2c_addr;
+/* I2C addresses
+ * possible values: 0x64,0x65,0x66,0x67
+ */
+struct si2165_platform_data {
+ /*
+ * frontend
+ * returned by driver
+ */
+ struct dvb_frontend **fe;
/* external clock or XTAL */
u8 chip_mode;
@@ -45,18 +50,4 @@ struct si2165_config {
bool inversion;
};
-#if IS_REACHABLE(CONFIG_DVB_SI2165)
-struct dvb_frontend *si2165_attach(
- const struct si2165_config *config,
- struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *si2165_attach(
- const struct si2165_config *config,
- struct i2c_adapter *i2c)
-{
- pr_warn("%s: driver disabled by Kconfig\n", __func__);
- return NULL;
-}
-#endif /* CONFIG_DVB_SI2165 */
-
#endif /* _DVB_SI2165_H */
@@ -20,4 +20,21 @@
#define SI2165_FIRMWARE_REV_D "dvb-demod-si2165.fw"
+struct si2165_config {
+ /* i2c addr
+ * possible values: 0x64,0x65,0x66,0x67 */
+ u8 i2c_addr;
+
+ /* external clock or XTAL */
+ u8 chip_mode;
+
+ /* frequency of external clock or xtal in Hz
+ * possible values: 4000000, 16000000, 20000000, 240000000, 27000000
+ */
+ u32 ref_freq_Hz;
+
+ /* invert the spectrum */
+ bool inversion;
+};
+
#endif /* _DVB_SI2165_PRIV */
@@ -867,12 +867,6 @@ static const struct tda10071_platform_data hauppauge_tda10071_pdata = {
.tuner_i2c_addr = 0x54,
};
-static const struct si2165_config hauppauge_hvr4400_si2165_config = {
- .i2c_addr = 0x64,
- .chip_mode = SI2165_MODE_PLL_XTAL,
- .ref_freq_Hz = 16000000,
-};
-
static const struct m88ds3103_config dvbsky_t9580_m88ds3103_config = {
.i2c_addr = 0x68,
.clock = 27000000,
@@ -1182,6 +1176,7 @@ static int dvb_register(struct cx23885_tsport *port)
struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL;
struct vb2_dvb_frontend *fe0, *fe1 = NULL;
struct si2168_config si2168_config;
+ struct si2165_platform_data si2165_pdata;
struct si2157_config si2157_config;
struct ts2020_config ts2020_config;
struct i2c_board_info info;
@@ -1839,9 +1834,26 @@ static int dvb_register(struct cx23885_tsport *port)
break;
/* port c */
case 2:
- fe0->dvb.frontend = dvb_attach(si2165_attach,
- &hauppauge_hvr4400_si2165_config,
- &i2c_bus->i2c_adap);
+ /* attach frontend */
+ memset(&si2165_pdata, 0, sizeof(si2165_pdata));
+ si2165_pdata.fe = &fe0->dvb.frontend;
+ si2165_pdata.chip_mode = SI2165_MODE_PLL_XTAL,
+ si2165_pdata.ref_freq_Hz = 16000000,
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2165", I2C_NAME_SIZE);
+ info.addr = 0x64;
+ info.platform_data = &si2165_pdata;
+ request_module(info.type);
+ client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info);
+ if (client_demod == NULL ||
+ client_demod->dev.driver == NULL)
+ goto frontend_detach;
+ if (!try_module_get(client_demod->dev.driver->owner)) {
+ i2c_unregister_device(client_demod);
+ goto frontend_detach;
+ }
+ port->i2c_client_demod = client_demod;
+
if (fe0->dvb.frontend == NULL)
break;
fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
@@ -80,7 +80,7 @@ static int si2157_init(struct dvb_frontend *fe)
struct i2c_client *client = fe->tuner_priv;
struct si2157_dev *dev = i2c_get_clientdata(client);
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- int ret, len, remaining;
+ int ret, len, remaining, fw_chunk, inc;
struct si2157_cmd cmd;
const struct firmware *fw;
const char *fw_name;
@@ -103,12 +103,12 @@ static int si2157_init(struct dvb_frontend *fe)
goto warm;
/* power up */
- if (dev->chiptype == SI2157_CHIPTYPE_SI2146) {
- memcpy(cmd.args, "\xc0\x05\x01\x00\x00\x0b\x00\x00\x01", 9);
- cmd.wlen = 9;
- } else {
+ if (dev->chiptype == SI2157_CHIPTYPE_SI2157) {
memcpy(cmd.args, "\xc0\x00\x0c\x00\x00\x01\x01\x01\x01\x01\x01\x02\x00\x00\x01", 15);
cmd.wlen = 15;
+ } else {
+ memcpy(cmd.args, "\xc0\x05\x01\x00\x00\x0b\x00\x00\x01", 9);
+ cmd.wlen = 9;
}
cmd.rlen = 1;
ret = si2157_cmd_execute(client, &cmd);
@@ -131,11 +131,17 @@ static int si2157_init(struct dvb_frontend *fe)
#define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0)
#define SI2147_A30 ('A' << 24 | 47 << 16 | '3' << 8 | '0' << 0)
#define SI2146_A10 ('A' << 24 | 46 << 16 | '1' << 8 | '0' << 0)
+ #define SI2173_A31 ('A' << 24 | 73 << 16 | '3' << 8 | '1' << 0)
switch (chip_id) {
case SI2158_A20:
case SI2148_A20:
fw_name = SI2158_A20_FIRMWARE;
+ fw_chunk = 17;
+ break;
+ case SI2173_A31:
+ fw_name = SI2173_A31_FIRMWARE;
+ fw_chunk = 8;
break;
case SI2157_A30:
case SI2147_A30:
@@ -164,25 +170,29 @@ static int si2157_init(struct dvb_frontend *fe)
goto err;
}
- /* firmware should be n chunks of 17 bytes */
- if (fw->size % 17 != 0) {
+ /* firmware should be n chunks of 8 or 17 bytes */
+ if (fw->size % fw_chunk != 0) {
dev_err(&client->dev, "firmware file '%s' is invalid\n",
fw_name);
ret = -EINVAL;
goto err_release_firmware;
}
- dev_info(&client->dev, "downloading firmware from file '%s'\n",
- fw_name);
+ dev_info(&client->dev, "downloading firmware from file '%s', size %zu bytes\n",
+ fw_name, fw->size);
- for (remaining = fw->size; remaining > 0; remaining -= 17) {
- len = fw->data[fw->size - remaining];
+ if (fw_chunk == 8)
+ inc = 0;
+ else
+ inc = 1;
+ for (remaining = fw->size; remaining > 0; remaining -= fw_chunk) {
+ len = fw_chunk == 8 ? 8 : fw->data[fw->size - remaining];
if (len > SI2157_ARGLEN) {
dev_err(&client->dev, "Bad firmware length\n");
ret = -EINVAL;
goto err_release_firmware;
}
- memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len);
+ memcpy(cmd.args, &fw->data[(fw->size - remaining) + inc], len);
cmd.wlen = len;
cmd.rlen = 1;
ret = si2157_cmd_execute(client, &cmd);
@@ -371,7 +381,7 @@ static int si2157_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
static const struct dvb_tuner_ops si2157_ops = {
.info = {
- .name = "Silicon Labs Si2146/2147/2148/2157/2158",
+ .name = "Silicon Labs Si2146/2147/2148/2157/2158/2173",
.frequency_min = 42000000,
.frequency_max = 870000000,
},
@@ -395,7 +405,11 @@ static void si2157_stat_work(struct work_struct *work)
memcpy(cmd.args, "\x42\x00", 2);
cmd.wlen = 2;
- cmd.rlen = 12;
+ if (dev->chiptype == SI2157_CHIPTYPE_SI2173) {
+ cmd.rlen = 9;
+ } else {
+ cmd.rlen = 12;
+ }
ret = si2157_cmd_execute(client, &cmd);
if (ret)
goto err;
@@ -470,9 +484,13 @@ static int si2157_probe(struct i2c_client *client,
}
#endif
- dev_info(&client->dev, "Silicon Labs %s successfully attached\n",
+ dev_info(&client->dev, "Silicon Labs %s (chiptype %d) successfully attached\n",
dev->chiptype == SI2157_CHIPTYPE_SI2146 ?
- "Si2146" : "Si2147/2148/2157/2158");
+ "Si2146" :
+ dev->chiptype == SI2157_CHIPTYPE_SI2173 ?
+ "Si2173" :
+ "Si2147/2148/2157/2158",
+ dev->chiptype);
return 0;
@@ -506,6 +524,7 @@ static int si2157_remove(struct i2c_client *client)
}
static const struct i2c_device_id si2157_id_table[] = {
+ {"si2173", SI2157_CHIPTYPE_SI2173},
{"si2157", SI2157_CHIPTYPE_SI2157},
{"si2146", SI2157_CHIPTYPE_SI2146},
{}
@@ -528,3 +547,4 @@ MODULE_DESCRIPTION("Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(SI2158_A20_FIRMWARE);
+MODULE_FIRMWARE(SI2173_A31_FIRMWARE);
@@ -42,6 +42,7 @@ struct si2157_dev {
#define SI2157_CHIPTYPE_SI2157 0
#define SI2157_CHIPTYPE_SI2146 1
+#define SI2157_CHIPTYPE_SI2173 2
/* firmware command struct */
#define SI2157_ARGLEN 30
@@ -52,5 +53,6 @@ struct si2157_cmd {
};
#define SI2158_A20_FIRMWARE "dvb-tuner-si2158-a20-01.fw"
+#define SI2173_A31_FIRMWARE "terratec_cinergy_htc_stick_hd0101.fw"
#endif
@@ -1941,6 +1941,10 @@ struct tunertype tuners[] = {
.params = tuner_sony_btf_pg463z_params,
.count = ARRAY_SIZE(tuner_sony_btf_pg463z_params),
},
+ [TUNER_SI2173] = { /* Silicon Labs 2173 */
+ .name = "Silicon Labs 2173",
+ },
+
};
EXPORT_SYMBOL(tuners);
@@ -360,6 +360,7 @@ int cx231xx_afe_update_power_control(struct cx231xx *dev,
case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
case CX231XX_BOARD_OTG102:
+ case CX231XX_BOARD_TERRATEC_CNRG_HTC_HD:
if (avmode == POLARIS_AVMODE_ANALOGT_TV) {
while (afe_power_status != (FLD_PWRDN_TUNING_BIAS |
FLD_PWRDN_ENABLE_PLL)) {
@@ -599,7 +600,8 @@ int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input)
return status;
}
}
- if (dev->tuner_type == TUNER_NXP_TDA18271)
+ if ((dev->tuner_type == TUNER_NXP_TDA18271) ||
+ (dev->tuner_type == TUNER_SI2173))
status = cx231xx_set_decoder_video_input(dev,
CX231XX_VMUX_TELEVISION,
INPUT(input)->vmux);
@@ -906,7 +908,8 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
status = vid_blk_write_word(dev, AFE_CTRL, value);
- if (dev->tuner_type == TUNER_NXP_TDA18271) {
+ if ((dev->tuner_type == TUNER_NXP_TDA18271) ||
+ (dev->tuner_type == TUNER_SI2173)) {
status = vid_blk_read_word(dev, PIN_CTRL,
&value);
status = vid_blk_write_word(dev, PIN_CTRL,
@@ -1197,6 +1200,7 @@ int cx231xx_set_audio_decoder_input(struct cx231xx *dev,
cx231xx_set_field(FLD_SIF_EN, 1));
break;
case TUNER_NXP_TDA18271:
+ case TUNER_SI2173:
/* Normal mode: SIF passthrough at 14.32 MHz */
status = cx231xx_read_modify_write_i2c_dword(dev,
VID_BLK_I2C_ADDRESS,
@@ -815,6 +815,52 @@ struct cx231xx_board cx231xx_boards[] = {
.gpio = NULL,
} },
},
+ [CX231XX_BOARD_TERRATEC_CNRG_HTC_HD] = {
+ .name = "Terratec Cinergy HTC Stick HD",
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = 0x60,
+ .tuner_gpio = RDE250_XCV_TUNER,
+ .tuner_sif_gpio = 0x05,
+ .tuner_scl_gpio = 0x1a,
+ .tuner_sda_gpio = 0x1b,
+ .tuner_i2c_master = I2C_1_MUX_3,
+ .demod_addr = 0x64,
+ .demod_i2c_master = I2C_2,
+ .has_dvb = 1,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x1c,
+ .gpio_pin_status_mask = 0x4001000,
+ .norm = V4L2_STD_PAL,
+ .no_alt_vanc = 1,
+ .external_av = 1,
+ /* Actually, it has a 417, but it isn't working correctly.
+ * So set to 0 for now until someone can manage to get this
+ * to work reliably. */
+ .has_417 = 0,
+ .gpio_pin_status_mask = 0x4001000,
+ .agc_analog_digital_select_gpio = 0x1c,
+ .input = {{
+ .type = CX231XX_VMUX_TELEVISION,
+ .vmux = CX231XX_VIN_3_1,
+ .amux = CX231XX_AMUX_VIDEO,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }
+ },
+ },
[CX231XX_BOARD_TERRATEC_GRABBY] = {
.name = "Terratec Grabby",
.tuner_type = TUNER_ABSENT,
@@ -864,6 +910,8 @@ struct usb_device_id cx231xx_id_table[] = {
.driver_info = CX231XX_BOARD_CNXT_RDE_250},
{USB_DEVICE(0x0572, 0x58A0),
.driver_info = CX231XX_BOARD_CNXT_RDU_250},
+ {USB_DEVICE(0x0ccd, 0x0101),
+ .driver_info = CX231XX_BOARD_TERRATEC_CNRG_HTC_HD},
{USB_DEVICE(0x2040, 0xb110),
.driver_info = CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL},
{USB_DEVICE(0x2040, 0xb111),
@@ -937,6 +985,11 @@ int cx231xx_tuner_callback(void *ptr, int component, int command, int arg)
1);
msleep(10);
}
+ } else if (dev->tuner_type == TUNER_SI2173) {
+ dev_dbg(dev->dev,
+ "Tuner CB: RESET: cmd %d : tuner type %d\n",
+ command, dev->tuner_type);
+ rc = cx231xx_set_agc_analog_digital_mux_select(dev, arg);
} else if (dev->tuner_type == TUNER_NXP_TDA18271) {
switch (command) {
case TDA18271_CALLBACK_CMD_AGC_ENABLE:
@@ -1263,6 +1316,7 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
/*To workaround error number=-71 on EP0 for VideoGrabber,
need set alt here.*/
if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER ||
+ dev->model == CX231XX_BOARD_TERRATEC_CNRG_HTC_HD ||
dev->model == CX231XX_BOARD_HAUPPAUGE_USBLIVE2) {
cx231xx_set_alt_setting(dev, INDEX_VIDEO, 3);
cx231xx_set_alt_setting(dev, INDEX_VANC, 1);
@@ -1674,7 +1728,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
}
}
- if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER) {
+ if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER ||
+ dev->model == CX231XX_BOARD_TERRATEC_CNRG_HTC_HD) {
cx231xx_enable_OSC(dev);
cx231xx_reset_out(dev);
cx231xx_set_alt_setting(dev, INDEX_VIDEO, 3);
@@ -52,7 +52,7 @@ MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
#define cx231xx_isocdbg(fmt, arg...) do { if (core_debug) - printk(KERN_INFO "%s %s :"fmt, + printk(KERN_INFO "%s %s :"fmt" ", dev->name, __func__ , ##arg); } while (0)
/*****************************************************************
@@ -272,6 +272,7 @@ static int __usb_control_msg(struct cx231xx *dev, unsigned int pipe,
if (reg_debug) {
if (unlikely(rc < 0)) {
printk(KERN_CONT "FAILED!\n");
+ dump_stack();
return rc;
}
@@ -65,6 +65,7 @@ struct cx231xx_dvb {
struct dmx_frontend fe_hw;
struct dmx_frontend fe_mem;
struct dvb_net net;
+ struct i2c_client *i2c_client_demod;
struct i2c_client *i2c_client_tuner;
};
@@ -150,18 +151,6 @@ static struct tda18271_config pv_tda18271_config = {
.small_i2c = TDA18271_03_BYTE_CHUNK_INIT,
};
-static const struct si2165_config hauppauge_930C_HD_1113xx_si2165_config = {
- .i2c_addr = 0x64,
- .chip_mode = SI2165_MODE_PLL_XTAL,
- .ref_freq_Hz = 16000000,
-};
-
-static const struct si2165_config pctv_quatro_stick_1114xx_si2165_config = {
- .i2c_addr = 0x64,
- .chip_mode = SI2165_MODE_PLL_EXT,
- .ref_freq_Hz = 24000000,
-};
-
static struct lgdt3306a_config hauppauge_955q_lgdt3306a_config = {
.i2c_addr = 0x59,
.qam_if_khz = 4000,
@@ -586,8 +575,14 @@ static void unregister_dvb(struct cx231xx_dvb *dvb)
dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
dvb_dmxdev_release(&dvb->dmxdev);
dvb_dmx_release(&dvb->demux);
- client = dvb->i2c_client_tuner;
/* remove I2C tuner */
+ client = dvb->i2c_client_tuner;
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+ /* remove I2C demod */
+ client = dvb->i2c_client_demod;
if (client) {
module_put(client->dev.driver->owner);
i2c_unregister_device(client);
@@ -749,19 +744,38 @@ static int dvb_init(struct cx231xx *dev)
break;
case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx:
+ {
+ struct i2c_client *client;
+ struct i2c_board_info info;
+ struct si2165_platform_data si2165_pdata;
- dev->dvb->frontend = dvb_attach(si2165_attach,
- &hauppauge_930C_HD_1113xx_si2165_config,
- demod_i2c
- );
+ /* attach demod */
+ memset(&si2165_pdata, 0, sizeof(si2165_pdata));
+ si2165_pdata.fe = &dev->dvb->frontend;
+ si2165_pdata.chip_mode = SI2165_MODE_PLL_XTAL,
+ si2165_pdata.ref_freq_Hz = 16000000,
- if (dev->dvb->frontend == NULL) {
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2165", I2C_NAME_SIZE);
+ info.addr = 0x64;
+ info.platform_data = &si2165_pdata;
+ request_module(info.type);
+ client = i2c_new_device(demod_i2c, &info);
+ if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) {
dev_err(dev->dev,
"Failed to attach SI2165 front end\n");
result = -EINVAL;
goto out_free;
}
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ dvb->i2c_client_demod = client;
+
dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
/* define general-purpose callback pointer */
@@ -774,27 +788,131 @@ static int dvb_init(struct cx231xx *dev)
dev->cx231xx_reset_analog_tuner = NULL;
break;
+ }
+
+ case CX231XX_BOARD_TERRATEC_CNRG_HTC_HD:
+ {
+ struct i2c_client *client;
+ struct i2c_board_info info;
+ struct si2165_platform_data si2165_pdata;
+ struct si2157_config si2157_config;
+
+ /* attach demod */
+ dev_info(dev->dev,
+ "%s: attach demod\n",
+ __func__);
+ memset(&si2165_pdata, 0, sizeof(si2165_pdata));
+ si2165_pdata.fe = &dev->dvb->frontend;
+ si2165_pdata.chip_mode = SI2165_MODE_PLL_EXT,
+ si2165_pdata.ref_freq_Hz = 24000000,
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2165", I2C_NAME_SIZE);
+ info.addr = 0x64;
+ info.platform_data = &si2165_pdata;
+ request_module(info.type);
+ client = i2c_new_device(demod_i2c, &info);
+ if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) {
+ dev_err(dev->dev,
+ "Failed to attach SI2165 front end\n");
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ result = -ENODEV;
+ goto out_free;
+ }
+ dev_info(dev->dev,
+ "%s: demod attached\n",
+ __func__);
+
+ dvb->i2c_client_demod = client;
+ memset(&info, 0, sizeof(struct i2c_board_info));
+
+ dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
+
+ /* define general-purpose callback pointer */
+ dvb->frontend->callback = cx231xx_tuner_callback;
+
+ /* attach tuner */
+ dev_info(dev->dev,
+ "%s: attach tuner\n",
+ __func__);
+ memset(&si2157_config, 0, sizeof(si2157_config));
+ si2157_config.fe = dev->dvb->frontend;
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ si2157_config.mdev = dev->media_dev;
+#endif
+ si2157_config.if_port = 0;
+ si2157_config.inversion = true;
+ strlcpy(info.type, "si2173", I2C_NAME_SIZE);
+ info.addr = 0x60;
+ info.platform_data = &si2157_config;
+ request_module("si2157");
+
+ client = i2c_new_device(
+ tuner_i2c,
+ &info);
+ if (client == NULL || client->dev.driver == NULL) {
+ dvb_frontend_detach(dev->dvb->frontend);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ dvb_frontend_detach(dev->dvb->frontend);
+ result = -ENODEV;
+ goto out_free;
+ }
+ dev_info(dev->dev,
+ "%s: tuner attached\n",
+ __func__);
+
+ dev->cx231xx_reset_analog_tuner = NULL;
+
+ dev->dvb->i2c_client_tuner = client;
+ break;
+ }
case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
{
struct i2c_client *client;
struct i2c_board_info info;
+ struct si2165_platform_data si2165_pdata;
struct si2157_config si2157_config;
- memset(&info, 0, sizeof(struct i2c_board_info));
+ /* attach demod */
+ memset(&si2165_pdata, 0, sizeof(si2165_pdata));
+ si2165_pdata.fe = &dev->dvb->frontend;
+ si2165_pdata.chip_mode = SI2165_MODE_PLL_EXT,
+ si2165_pdata.ref_freq_Hz = 24000000,
- dev->dvb->frontend = dvb_attach(si2165_attach,
- &pctv_quatro_stick_1114xx_si2165_config,
- demod_i2c
- );
-
- if (dev->dvb->frontend == NULL) {
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2165", I2C_NAME_SIZE);
+ info.addr = 0x64;
+ info.platform_data = &si2165_pdata;
+ request_module(info.type);
+ client = i2c_new_device(demod_i2c, &info);
+ if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) {
dev_err(dev->dev,
"Failed to attach SI2165 front end\n");
result = -EINVAL;
goto out_free;
}
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ dvb->i2c_client_demod = client;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+
dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
/* define general-purpose callback pointer */
@@ -78,6 +78,8 @@
#define CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx 20
#define CX231XX_BOARD_HAUPPAUGE_955Q 21
#define CX231XX_BOARD_TERRATEC_GRABBY 22
+#define CX231XX_BOARD_TERRATEC_CNRG_HTC_HD 23
+
/* Limits minimum and default number of buffers */
#define CX231XX_MIN_BUF 4
@@ -141,6 +141,8 @@
#define TUNER_SONY_BTF_PG472Z 89 /* PAL+SECAM */
#define TUNER_SONY_BTF_PK467Z 90 /* NTSC_JP */
#define TUNER_SONY_BTF_PB463Z 91 /* NTSC */
+#define TUNER_SI2173 92 /* Silicon Labs 2173 */
+
/* tv card specific */
#define TDA9887_PRESENT (1<<0)
This patch allows the Terratec Cinergy HTC Stick HD (0ccb:0101) to be used to watch DVB-T with Kaffeine, and to use its "grabber" functionality with Mplayer. For the latter, no code had to be modified, it acts exactly as a "connexant video grabber". The patch is generated from a Linux kernel 4.6.1, to which I applied Matthias Schwarzott's patches from 26/07/2016 - as a consequence, his work is included here, please tell me how to separate it when that's necessary. My patch will conflict with the one from Oleh Kravchenko 04/08/2016. I haven't got a clue what I am messing with: no experience with TV hardware, no understanding of I2C programming, my changes are based on USB snooping and what I found in the Windows driver's .inf. Eg. "write pll registers 0x00a0..0x00a3 at once" is no longer true. Won't this break other HW? Signed-off-by: Gerard H. Pille <g.h.p@skynet.be> --- drivers/media/dvb-frontends/Kconfig | 1 + drivers/media/dvb-frontends/si2165.c | 278 +++++++++++++++++------------ drivers/media/dvb-frontends/si2165.h | 27 +-- drivers/media/dvb-frontends/si2165_priv.h | 17 ++ drivers/media/pci/cx23885/cx23885-dvb.c | 30 +++- drivers/media/tuners/si2157.c | 52 ++++-- drivers/media/tuners/si2157_priv.h | 2 + drivers/media/tuners/tuner-types.c | 4 + drivers/media/usb/cx231xx/cx231xx-avcore.c | 8 +- drivers/media/usb/cx231xx/cx231xx-cards.c | 57 +++++- drivers/media/usb/cx231xx/cx231xx-core.c | 3 +- drivers/media/usb/cx231xx/cx231xx-dvb.c | 168 ++++++++++++++--- drivers/media/usb/cx231xx/cx231xx.h | 2 + include/media/tuner.h | 2 + 14 files changed, 461 insertions(+), 190 deletions(-)