From 744cfab5dea4d4247ecf51ee4ed49be62d6c55e2 Mon Sep 17 00:00:00 2001 From: CvH Date: Sat, 20 Jul 2019 11:01:55 +0200 Subject: [PATCH] dvb-latest: update to 2019-07-11 --- .../dvb/depends/media_tree/package.mk | 4 +- .../patches/media_tree-01-hauppauge.patch | 2083 ----------------- .../patches/media_tree-01-m88ds3103b.patch | 747 ++++++ .../dvb/dvb-latest/package.mk | 4 +- 4 files changed, 751 insertions(+), 2087 deletions(-) delete mode 100644 packages/linux-driver-addons/dvb/depends/media_tree/patches/media_tree-01-hauppauge.patch create mode 100644 packages/linux-driver-addons/dvb/depends/media_tree/patches/media_tree-01-m88ds3103b.patch diff --git a/packages/linux-driver-addons/dvb/depends/media_tree/package.mk b/packages/linux-driver-addons/dvb/depends/media_tree/package.mk index cb01052f26..95cfb17466 100644 --- a/packages/linux-driver-addons/dvb/depends/media_tree/package.mk +++ b/packages/linux-driver-addons/dvb/depends/media_tree/package.mk @@ -2,8 +2,8 @@ # Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv) PKG_NAME="media_tree" -PKG_VERSION="2017-08-20-3b6471c7becd" -PKG_SHA256="7fa8d0be68991d1bc6a244888cf2308d2f6152748c1d417efa0784d101ba262b" +PKG_VERSION="2019-07-11-22be8233b34f" +PKG_SHA256="14363b1aacfe59805a1fe93739caed53036879e7b871f1d8d7061527c3cb9eb8" PKG_LICENSE="GPL" PKG_SITE="https://git.linuxtv.org/media_tree.git" PKG_URL="http://linuxtv.org/downloads/drivers/linux-media-${PKG_VERSION}.tar.bz2" diff --git a/packages/linux-driver-addons/dvb/depends/media_tree/patches/media_tree-01-hauppauge.patch b/packages/linux-driver-addons/dvb/depends/media_tree/patches/media_tree-01-hauppauge.patch deleted file mode 100644 index 458849c01b..0000000000 --- a/packages/linux-driver-addons/dvb/depends/media_tree/patches/media_tree-01-hauppauge.patch +++ /dev/null @@ -1,2083 +0,0 @@ -Combined patches from https://github.com/b-rad-NDi/Ubuntu-media-tree-kernel-builder -to support all kind of Hauppauge DVB cards. - -diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c -index 99c6289..ceaf617 100644 ---- a/drivers/media/dvb-frontends/lgdt3306a.c -+++ b/drivers/media/dvb-frontends/lgdt3306a.c -@@ -855,6 +855,7 @@ static int lgdt3306a_fe_sleep(struct dvb_frontend *fe) - static int lgdt3306a_init(struct dvb_frontend *fe) - { - struct lgdt3306a_state *state = fe->demodulator_priv; -+ struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u8 val; - int ret; - -@@ -1006,6 +1007,9 @@ static int lgdt3306a_init(struct dvb_frontend *fe) - ret = lgdt3306a_sleep(state); - lg_chkerr(ret); - -+ c->cnr.len = 1; -+ c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; -+ - fail: - return ret; - } -@@ -1606,6 +1610,7 @@ static int lgdt3306a_read_status(struct dvb_frontend *fe, - enum fe_status *status) - { - struct lgdt3306a_state *state = fe->demodulator_priv; -+ struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u16 strength = 0; - int ret = 0; - -@@ -1646,6 +1651,15 @@ static int lgdt3306a_read_status(struct dvb_frontend *fe, - default: - ret = -EINVAL; - } -+ -+ if (*status & FE_HAS_SYNC) { -+ c->cnr.len = 1; -+ c->cnr.stat[0].scale = FE_SCALE_DECIBEL; -+ c->cnr.stat[0].svalue = lgdt3306a_calculate_snr_x100(state) * 10; -+ } else { -+ c->cnr.len = 1; -+ c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; -+ } - } - return ret; - } -diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c -index 17301c6..9b021ac 100644 ---- a/drivers/media/dvb-frontends/si2168.c -+++ b/drivers/media/dvb-frontends/si2168.c -@@ -18,6 +18,10 @@ - - #include "si2168_priv.h" - -+static int dvbt_auto_plp = 1; -+module_param(dvbt_auto_plp, int, 0644); -+MODULE_PARM_DESC(dvbt_auto_plp, "if set, the PLP is set to auto detect DVB-T and DVB-T2 signals"); -+ - static const struct dvb_frontend_ops si2168_ops; - - /* execute firmware command */ -@@ -106,13 +110,12 @@ static int si2168_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) - return ret; - } - --static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status) -+static int si2168_get_status(struct dvb_frontend *fe, enum fe_status *status) - { - struct i2c_client *client = fe->demodulator_priv; - struct si2168_dev *dev = i2c_get_clientdata(client); - struct dtv_frontend_properties *c = &fe->dtv_property_cache; -- int ret, i; -- unsigned int utmp, utmp1, utmp2; -+ int ret, sys; - struct si2168_cmd cmd; - - *status = 0; -@@ -122,7 +125,23 @@ static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status) - goto err; - } - -- switch (c->delivery_system) { -+ sys = c->delivery_system; -+ -+ /* check if we found DVB-T2 during DVB-T tuning */ -+ if (dvbt_auto_plp && sys == SYS_DVBT) { -+ memcpy(cmd.args, "\x87\x01", 2); -+ cmd.wlen = 2; -+ cmd.rlen = 8; -+ -+ ret = si2168_cmd_execute(client, &cmd); -+ if (ret) -+ goto err; -+ -+ if ((cmd.args[3] & 0x0f) == 7) -+ sys = SYS_DVBT2; -+ } -+ -+ switch (sys) { - case SYS_DVBT: - memcpy(cmd.args, "\xa0\x01", 2); - cmd.wlen = 2; -@@ -144,9 +163,29 @@ static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status) - } - - ret = si2168_cmd_execute(client, &cmd); -+ if (dvbt_auto_plp && (ret == -EREMOTEIO)) { -+ /* In auto-PLP mode it is possible to read 0x8701 while -+ * the frontend is in switchover transition. This causes -+ * a status read failure, due to incorrect system. Check -+ * the other sys if we hit this race condition. -+ */ -+ if (sys == SYS_DVBT) { -+ memcpy(cmd.args, "\x50\x01", 2); /* DVB-T2 */ -+ cmd.wlen = 2; -+ cmd.rlen = 14; -+ ret = si2168_cmd_execute(client, &cmd); -+ } else if (sys == SYS_DVBT2) { -+ memcpy(cmd.args, "\xa0\x01", 2); /* DVB-T */ -+ cmd.wlen = 2; -+ cmd.rlen = 13; -+ ret = si2168_cmd_execute(client, &cmd); -+ } -+ } - if (ret) - goto err; - -+ //c->delivery_system = sys; /* update delivery system in case auto-PLP */ -+ - switch ((cmd.args[2] >> 1) & 0x03) { - case 0x01: - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; -@@ -157,8 +196,6 @@ static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status) - break; - } - -- dev->fe_status = *status; -- - if (*status & FE_HAS_LOCK) { - c->cnr.len = 1; - c->cnr.stat[0].scale = FE_SCALE_DECIBEL; -@@ -171,8 +208,120 @@ static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status) - dev_dbg(&client->dev, "status=%02x args=%*ph\n", - *status, cmd.rlen, cmd.args); - -+ dev->fe_status = *status; -+ -+ return 0; -+err: -+ dev_dbg(&client->dev, "failed=%d\n", ret); -+ return ret; -+} -+ -+static int si2168_read_snr(struct dvb_frontend *fe, u16 *snr) -+{ -+ struct i2c_client *client = fe->demodulator_priv; -+ struct si2168_dev *dev = i2c_get_clientdata(client); -+ struct dtv_frontend_properties *c = &fe->dtv_property_cache; -+ enum fe_status status = 0; -+ u64 stat_snr; -+ int ret; -+ -+ *snr = 0; -+ -+ if (!dev->active) { -+ ret = -EAGAIN; -+ goto err; -+ } -+ -+ ret = si2168_get_status(fe, &status); -+ if (ret) -+ goto err; -+ -+ if (status & FE_HAS_LOCK) { -+ stat_snr = c->cnr.stat[0].svalue; -+ do_div(stat_snr, 100); -+ *snr = (u16)stat_snr; -+ } -+ -+ dev_dbg(&client->dev, "snr=%02x\n", *snr); -+ -+ return 0; -+err: -+ dev_dbg(&client->dev, "failed=%d\n", ret); -+ return ret; -+} -+ -+static int si2168_read_signal_strength(struct dvb_frontend *fe, u16 *rssi) -+{ -+ int ret = -ENOSYS; -+ struct i2c_client *client = fe->demodulator_priv; -+ struct si2168_dev *dev = i2c_get_clientdata(client); -+ struct dtv_frontend_properties *c = &fe->dtv_property_cache; -+ enum fe_status status = 0; -+ u64 stat_strength; -+ -+ *rssi = 0; -+ -+ if (!dev->active) { -+ ret = -EAGAIN; -+ goto err; -+ } -+ -+ ret = si2168_get_status(fe, &status); -+ if (ret) -+ goto err; -+ -+ if (status & FE_HAS_LOCK) { -+ if (fe->ops.tuner_ops.get_rf_strength) -+ ret = fe->ops.tuner_ops.get_rf_strength(fe, rssi); -+ else if (c->strength.len > 0) { -+ if (c->strength.stat[0].svalue < -80000) -+ *rssi = 0; -+ else { -+ stat_strength = c->strength.stat[0].svalue; -+ do_div(stat_strength, 1000); -+ *rssi = (u16)(stat_strength + 100); -+ *rssi = (*rssi > 100) ? 0xffff : -+ (u16)(((u32)*rssi) * 0xffff / 100); -+ } -+ } -+ } else { -+ c->strength.len = 1; -+ c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; -+ } -+ -+ dev_dbg(&client->dev, "rssi=%02x\n", *rssi); -+ -+ return 0; -+err: -+ dev_dbg(&client->dev, "failed=%d\n", ret); -+ return ret; -+} -+ -+/* ------------------------------------------------------------------------ */ -+ -+static int si2168_read_ber(struct dvb_frontend *fe, u32 *ber) -+{ -+ struct i2c_client *client = fe->demodulator_priv; -+ struct si2168_dev *dev = i2c_get_clientdata(client); -+ struct dtv_frontend_properties *c = &fe->dtv_property_cache; -+ enum fe_status status = 0; -+ int ret, i; -+ unsigned int utmp, utmp1, utmp2; -+ struct si2168_cmd cmd; -+ -+ *ber = 0; -+ -+ if (!dev->active) { -+ ret = -EAGAIN; -+ goto err; -+ } -+ -+ ret = si2168_get_status(fe, &status); -+ if (ret) -+ goto err; -+ - /* BER */ -- if (*status & FE_HAS_VITERBI) { -+ if (status & FE_HAS_VITERBI) { - memcpy(cmd.args, "\x82\x00", 2); - cmd.wlen = 2; - cmd.rlen = 3; -@@ -191,6 +340,9 @@ static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status) - utmp1 = cmd.args[2] * utmp1; - utmp2 = 100000000; /* 10^8 */ - -+ if (cmd.args[1] != 0) -+ *ber = (cmd.args[2] * utmp1) / utmp2; -+ - dev_dbg(&client->dev, - "post_bit_error=%u post_bit_count=%u ber=%u*10^-%u\n", - utmp1, utmp2, cmd.args[2], cmd.args[1]); -@@ -204,8 +356,35 @@ static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status) - c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - } - -+ return 0; -+err: -+ dev_dbg(&client->dev, "failed=%d\n", ret); -+ return ret; -+} -+ -+static int si2168_read_ucblocks(struct dvb_frontend *fe, u32 *ucb) -+{ -+ struct i2c_client *client = fe->demodulator_priv; -+ struct si2168_dev *dev = i2c_get_clientdata(client); -+ struct dtv_frontend_properties *c = &fe->dtv_property_cache; -+ enum fe_status status = 0; -+ int ret; -+ unsigned int utmp1; -+ struct si2168_cmd cmd; -+ -+ *ucb = 0; -+ -+ if (!dev->active) { -+ ret = -EAGAIN; -+ goto err; -+ } -+ -+ ret = si2168_get_status(fe, &status); -+ if (ret) -+ goto err; -+ - /* UCB */ -- if (*status & FE_HAS_SYNC) { -+ if (status & FE_HAS_SYNC) { - memcpy(cmd.args, "\x84\x01", 2); - cmd.wlen = 2; - cmd.rlen = 3; -@@ -220,11 +399,61 @@ static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status) - if (utmp1 == 0xffff) - utmp1 = 0; - -+ *ucb = utmp1; -+ - c->block_error.stat[0].scale = FE_SCALE_COUNTER; - c->block_error.stat[0].uvalue += utmp1; - } else { - c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - } -+ return 0; -+err: -+ dev_dbg(&client->dev, "failed=%d\n", ret); -+ return ret; -+} -+ -+ -+static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status) -+{ -+ struct i2c_client *client = fe->demodulator_priv; -+ struct si2168_dev *dev = i2c_get_clientdata(client); -+ struct dtv_frontend_properties *c = &fe->dtv_property_cache; -+ int ret; -+ u16 rssi; -+ u32 ber, ucb; -+ -+ *status = 0; -+ -+ if (!dev->active) { -+ ret = -EAGAIN; -+ goto err; -+ } -+ -+ ret = si2168_get_status(fe, status); -+ if (ret) -+ goto err; -+ -+ if ((*status & FE_HAS_LOCK) == 0) { -+ /* No lock, reset all statistics */ -+ c->strength.len = 1; -+ c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; -+ c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; -+ c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; -+ c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; -+ return 0; -+ } -+ -+ ret = si2168_read_signal_strength(fe, &rssi); -+ if (ret) -+ goto err; -+ -+ ret = si2168_read_ber(fe, &ber); -+ if (ret) -+ goto err; -+ -+ ret = si2168_read_ucblocks(fe, &ucb); -+ if (ret) -+ goto err; - - return 0; - err: -@@ -254,7 +483,10 @@ static int si2168_set_frontend(struct dvb_frontend *fe) - - switch (c->delivery_system) { - case SYS_DVBT: -- delivery_system = 0x20; -+ if (dvbt_auto_plp) -+ delivery_system = 0xf0; /* T/T2 auto-detect is user friendly */ -+ else -+ delivery_system = 0x20; - break; - case SYS_DVBC_ANNEX_A: - delivery_system = 0x30; -@@ -324,6 +556,16 @@ static int si2168_set_frontend(struct dvb_frontend *fe) - ret = si2168_cmd_execute(client, &cmd); - if (ret) - goto err; -+ } else if (dvbt_auto_plp && (c->delivery_system == SYS_DVBT)) { -+ /* select Auto PLP */ -+ cmd.args[0] = 0x52; -+ cmd.args[1] = 0; -+ cmd.args[2] = 0; /* Auto PLP */ -+ cmd.wlen = 3; -+ cmd.rlen = 1; -+ ret = si2168_cmd_execute(client, &cmd); -+ if (ret) -+ goto err; - } - - memcpy(cmd.args, "\x51\x03", 2); -@@ -363,6 +605,8 @@ static int si2168_set_frontend(struct dvb_frontend *fe) - - memcpy(cmd.args, "\x14\x00\x0a\x10\x00\x00", 6); - cmd.args[4] = delivery_system | bandwidth; -+ if (delivery_system == 0xf0) -+ cmd.args[5] |= 2; /* Auto detect DVB-T/T2 */ - if (dev->spectral_inversion) - cmd.args[5] |= 1; - cmd.wlen = 6; -@@ -384,6 +628,8 @@ static int si2168_set_frontend(struct dvb_frontend *fe) - } - - memcpy(cmd.args, "\x14\x00\x0f\x10\x10\x00", 6); -+ /* BUGBUG? FW defaults to 1, but windows driver uses 30; above is 0? */ -+ cmd.args[5] = 30; - cmd.wlen = 6; - cmd.rlen = 4; - ret = si2168_cmd_execute(client, &cmd); -@@ -717,6 +963,11 @@ static const struct dvb_frontend_ops si2168_ops = { - .set_frontend = si2168_set_frontend, - - .read_status = si2168_read_status, -+ -+ .read_ber = si2168_read_ber, -+ .read_signal_strength = si2168_read_signal_strength, -+ .read_snr = si2168_read_snr, -+ .read_ucblocks = si2168_read_ucblocks, - }; - - static int si2168_probe(struct i2c_client *client, -diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c -index f071a94..14ce009 100644 ---- a/drivers/media/i2c/cx25840/cx25840-core.c -+++ b/drivers/media/i2c/cx25840/cx25840-core.c -@@ -1495,23 +1495,25 @@ static int set_input(struct i2c_client *client, - cx25840_write4(client, 0x410, 0xffff0dbf); - cx25840_write4(client, 0x414, 0x00137d03); - -- cx25840_write4(client, state->vbi_regs_offset + 0x42c, -- 0x42600000); -- cx25840_write4(client, state->vbi_regs_offset + 0x430, -- 0x0000039b); -- cx25840_write4(client, state->vbi_regs_offset + 0x438, -- 0x00000000); -- -- cx25840_write4(client, state->vbi_regs_offset + 0x440, -- 0xF8E3E824); -- cx25840_write4(client, state->vbi_regs_offset + 0x444, -- 0x401040dc); -- cx25840_write4(client, state->vbi_regs_offset + 0x448, -- 0xcd3f02a0); -- cx25840_write4(client, state->vbi_regs_offset + 0x44c, -- 0x161f1000); -- cx25840_write4(client, state->vbi_regs_offset + 0x450, -- 0x00000802); -+ /* These are not VBI controls */ -+ if (is_cx23888(state)) { -+ /* 888 MISC_TIM_CTRL */ -+ cx25840_write4(client, 0x42c, 0x42600000); -+ /* 888 FIELD_COUNT */ -+ cx25840_write4(client, 0x430, 0x0000039b); -+ /* 888 VSCALE_CTRL */ -+ cx25840_write4(client, 0x438, 0x00000000); -+ /* 888 DFE_CTRL1 */ -+ cx25840_write4(client, 0x440, 0xF8E3E824); -+ /* 888 DFE_CTRL2 */ -+ cx25840_write4(client, 0x444, 0x401040dc); -+ /* 888 DFE_CTRL3 */ -+ cx25840_write4(client, 0x448, 0xcd3f02a0); -+ /* 888 PLL_CTRL */ -+ cx25840_write4(client, 0x44c, 0x161f1000); -+ /* 888 HTL_CTRL */ -+ cx25840_write4(client, 0x450, 0x00000802); -+ } - - cx25840_write4(client, 0x91c, 0x01000000); - cx25840_write4(client, 0x8e0, 0x03063870); -diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c -index ed3210d..9598b99 100644 ---- a/drivers/media/pci/cx23885/cx23885-cards.c -+++ b/drivers/media/pci/cx23885/cx23885-cards.c -@@ -325,8 +325,7 @@ struct cx23885_board cx23885_boards[] = { - .name = "Hauppauge WinTV-HVR1255", - .porta = CX23885_ANALOG_VIDEO, - .portc = CX23885_MPEG_DVB, -- .tuner_type = TUNER_ABSENT, -- .tuner_addr = 0x42, /* 0x84 >> 1 */ -+ .tuner_type = TUNER_NXP_TDA18271, - .force_bff = 1, - .input = {{ - .type = CX23885_VMUX_TELEVISION, -@@ -354,8 +353,7 @@ struct cx23885_board cx23885_boards[] = { - .name = "Hauppauge WinTV-HVR1255", - .porta = CX23885_ANALOG_VIDEO, - .portc = CX23885_MPEG_DVB, -- .tuner_type = TUNER_ABSENT, -- .tuner_addr = 0x42, /* 0x84 >> 1 */ -+ .tuner_type = TUNER_NXP_TDA18271, - .force_bff = 1, - .input = {{ - .type = CX23885_VMUX_TELEVISION, -@@ -767,24 +765,48 @@ struct cx23885_board cx23885_boards[] = { - } }, - }, - [CX23885_BOARD_HAUPPAUGE_QUADHD_DVB] = { -- .name = "Hauppauge WinTV-QuadHD-DVB", -+ .name = "Hauppauge WinTV-QuadHD-DVB", -+ .porta = CX23885_ANALOG_VIDEO, - .portb = CX23885_MPEG_DVB, - .portc = CX23885_MPEG_DVB, -+ .tuner_type = TUNER_ABSENT, -+ .force_bff = 1, -+ .input = {{ -+ .type = CX23885_VMUX_TELEVISION, -+ .vmux = CX25840_VIN7_CH3 | -+ CX25840_VIN5_CH2 | -+ CX25840_VIN2_CH1 | -+ CX25840_DIF_ON, -+ .amux = CX25840_AUDIO8, -+ } }, - }, - [CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885] = { -- .name = "Hauppauge WinTV-QuadHD-DVB(885)", -+ .name = "Hauppauge WinTV-QuadHD-DVB(885)", - .portb = CX23885_MPEG_DVB, - .portc = CX23885_MPEG_DVB, -+ .tuner_type = TUNER_ABSENT, - }, - [CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC] = { -- .name = "Hauppauge WinTV-QuadHD-ATSC", -+ .name = "Hauppauge WinTV-QuadHD-ATSC", -+ .porta = CX23885_ANALOG_VIDEO, - .portb = CX23885_MPEG_DVB, - .portc = CX23885_MPEG_DVB, -+ .tuner_type = TUNER_ABSENT, -+ .force_bff = 1, -+ .input = {{ -+ .type = CX23885_VMUX_TELEVISION, -+ .vmux = CX25840_VIN7_CH3 | -+ CX25840_VIN5_CH2 | -+ CX25840_VIN2_CH1 | -+ CX25840_DIF_ON, -+ .amux = CX25840_AUDIO8, -+ } }, - }, - [CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885] = { -- .name = "Hauppauge WinTV-QuadHD-ATSC(885)", -+ .name = "Hauppauge WinTV-QuadHD-ATSC(885)", - .portb = CX23885_MPEG_DVB, - .portc = CX23885_MPEG_DVB, -+ .tuner_type = TUNER_ABSENT, - }, - [CX23885_BOARD_HAUPPAUGE_HVR1265_K4] = { - .name = "Hauppauge WinTV-HVR-1265(161111)", -@@ -793,6 +815,13 @@ struct cx23885_board cx23885_boards[] = { - .tuner_type = TUNER_ABSENT, - .force_bff = 1, - .input = {{ -+ .type = CX23885_VMUX_TELEVISION, -+ .vmux = CX25840_VIN7_CH3 | -+ CX25840_VIN5_CH2 | -+ CX25840_VIN2_CH1 | -+ CX25840_DIF_ON, -+ .amux = CX25840_AUDIO8, -+ }, { - .type = CX23885_VMUX_COMPOSITE1, - .vmux = CX25840_VIN7_CH3 | - CX25840_VIN4_CH2 | -diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c -index e2e63f0..aea7738 100644 ---- a/drivers/media/pci/cx23885/cx23885-dvb.c -+++ b/drivers/media/pci/cx23885/cx23885-dvb.c -@@ -2383,6 +2383,16 @@ static int dvb_register(struct cx23885_tsport *port) - goto frontend_detach; - } - port->i2c_client_tuner = client_tuner; -+ -+ /* we only attach tuner for analog on the 888 version */ -+ if (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_DVB) { -+ pr_info("%s(): QUADHD_DVB analog setup\n", -+ __func__); -+ dev->ts1.analog_fe.tuner_priv = client_tuner; -+ memcpy(&dev->ts1.analog_fe.ops.tuner_ops, -+ &fe0->dvb.frontend->ops.tuner_ops, -+ sizeof(struct dvb_tuner_ops)); -+ } - break; - - /* port c - terrestrial/cable */ -@@ -2472,6 +2482,16 @@ static int dvb_register(struct cx23885_tsport *port) - goto frontend_detach; - } - port->i2c_client_tuner = client_tuner; -+ -+ /* we only attach tuner for analog on the 888 version */ -+ if (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC) { -+ pr_info("%s(): QUADHD_ATSC analog setup\n", -+ __func__); -+ dev->ts1.analog_fe.tuner_priv = client_tuner; -+ memcpy(&dev->ts1.analog_fe.ops.tuner_ops, -+ &fe0->dvb.frontend->ops.tuner_ops, -+ sizeof(struct dvb_tuner_ops)); -+ } - break; - - /* port c - terrestrial/cable */ -@@ -2543,6 +2563,11 @@ static int dvb_register(struct cx23885_tsport *port) - goto frontend_detach; - } - port->i2c_client_tuner = client_tuner; -+ -+ dev->ts1.analog_fe.tuner_priv = client_tuner; -+ memcpy(&dev->ts1.analog_fe.ops.tuner_ops, -+ &fe0->dvb.frontend->ops.tuner_ops, -+ sizeof(struct dvb_tuner_ops)); - break; - } - break; -diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c -index 168178c..6d6e7fb 100644 ---- a/drivers/media/pci/cx23885/cx23885-video.c -+++ b/drivers/media/pci/cx23885/cx23885-video.c -@@ -264,6 +264,8 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) - (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) || - (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) || - (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1265_K4) || -+ (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC) || -+ (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_DVB) || - (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) || - (dev->board == CX23885_BOARD_MYGICA_X8507) || - (dev->board == CX23885_BOARD_AVERMEDIA_HC81R) || -@@ -644,8 +646,17 @@ static int vidioc_querycap(struct file *file, void *priv, - sizeof(cap->card)); - sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); - cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_AUDIO; -- if (dev->tuner_type != TUNER_ABSENT) -+ switch (dev->board) { /* i2c device tuners */ -+ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: -+ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: -+ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: - cap->device_caps |= V4L2_CAP_TUNER; -+ break; -+ default: -+ if (dev->tuner_type != TUNER_ABSENT) -+ cap->device_caps |= V4L2_CAP_TUNER; -+ break; -+ } - if (vdev->vfl_type == VFL_TYPE_VBI) - cap->device_caps |= V4L2_CAP_VBI_CAPTURE; - else -@@ -899,8 +910,16 @@ static int vidioc_g_tuner(struct file *file, void *priv, - { - struct cx23885_dev *dev = video_drvdata(file); - -- if (dev->tuner_type == TUNER_ABSENT) -- return -EINVAL; -+ switch (dev->board) { /* i2c device tuners */ -+ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: -+ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: -+ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: -+ break; -+ default: -+ if (dev->tuner_type == TUNER_ABSENT) -+ return -EINVAL; -+ break; -+ } - if (0 != t->index) - return -EINVAL; - -@@ -915,8 +934,16 @@ static int vidioc_s_tuner(struct file *file, void *priv, - { - struct cx23885_dev *dev = video_drvdata(file); - -- if (dev->tuner_type == TUNER_ABSENT) -- return -EINVAL; -+ switch (dev->board) { /* i2c device tuners */ -+ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: -+ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: -+ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: -+ break; -+ default: -+ if (dev->tuner_type == TUNER_ABSENT) -+ return -EINVAL; -+ break; -+ } - if (0 != t->index) - return -EINVAL; - /* Update the A/V core */ -@@ -930,9 +957,16 @@ static int vidioc_g_frequency(struct file *file, void *priv, - { - struct cx23885_dev *dev = video_drvdata(file); - -- if (dev->tuner_type == TUNER_ABSENT) -- return -EINVAL; -- -+ switch (dev->board) { /* i2c device tuners */ -+ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: -+ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: -+ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: -+ break; -+ default: -+ if (dev->tuner_type == TUNER_ABSENT) -+ return -EINVAL; -+ break; -+ } - f->type = V4L2_TUNER_ANALOG_TV; - f->frequency = dev->freq; - -@@ -946,8 +980,16 @@ static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency - struct v4l2_ctrl *mute; - int old_mute_val = 1; - -- if (dev->tuner_type == TUNER_ABSENT) -- return -EINVAL; -+ switch (dev->board) { /* i2c device tuners */ -+ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: -+ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: -+ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: -+ break; -+ default: -+ if (dev->tuner_type == TUNER_ABSENT) -+ return -EINVAL; -+ break; -+ } - if (unlikely(f->tuner != 0)) - return -EINVAL; - -@@ -1012,7 +1054,9 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, - if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) || - (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) || - (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) || -- (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1265_K4)) -+ (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1265_K4) || -+ (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_DVB) || -+ (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC)) - fe = &dev->ts1.analog_fe; - - if (fe && fe->ops.tuner_ops.set_analog_params) { -@@ -1043,6 +1087,8 @@ int cx23885_set_frequency(struct file *file, void *priv, - case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: - case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: - case CX23885_BOARD_HAUPPAUGE_HVR1850: -+ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: -+ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: - ret = cx23885_set_freq_via_ops(dev, f); - break; - default: -diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c -index d389f1f..2563ab4 100644 ---- a/drivers/media/tuners/si2157.c -+++ b/drivers/media/tuners/si2157.c -@@ -1,5 +1,5 @@ - /* -- * Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver -+ * Silicon Labs Si2141/2146/2147/2148/2157/2158 silicon tuner driver - * - * Copyright (C) 2014 Antti Palosaari - * -@@ -56,14 +56,20 @@ static int si2157_cmd_execute(struct i2c_client *client, struct si2157_cmd *cmd) - break; - } - -- dev_dbg(&client->dev, "cmd execution took %d ms\n", -+ dev_dbg(&client->dev, "cmd execution took %d ms, status=%x\n", - jiffies_to_msecs(jiffies) - -- (jiffies_to_msecs(timeout) - TIMEOUT)); -+ (jiffies_to_msecs(timeout) - TIMEOUT), -+ cmd->args[0]); - - if (!((cmd->args[0] >> 7) & 0x01)) { - ret = -ETIMEDOUT; - goto err_mutex_unlock; - } -+ /* check error status bit */ -+ if (cmd->args[0] & 0x40) { -+ ret = -EAGAIN; -+ goto err_mutex_unlock; -+ } - } - - mutex_unlock(&dev->i2c_mutex); -@@ -84,24 +90,23 @@ static int si2157_init(struct dvb_frontend *fe) - struct si2157_cmd cmd; - const struct firmware *fw; - const char *fw_name; -- unsigned int uitmp, chip_id; -+ unsigned int chip_id, xtal_trim; - - dev_dbg(&client->dev, "\n"); - -- /* Returned IF frequency is garbage when firmware is not running */ -- memcpy(cmd.args, "\x15\x00\x06\x07", 4); -+ /* Try to get Xtal trim property, to verify tuner still running */ -+ memcpy(cmd.args, "\x15\x00\x04\x02", 4); - cmd.wlen = 4; - cmd.rlen = 4; - ret = si2157_cmd_execute(client, &cmd); -- if (ret) -- goto err; - -- uitmp = cmd.args[2] << 0 | cmd.args[3] << 8; -- dev_dbg(&client->dev, "if_frequency kHz=%u\n", uitmp); -+ xtal_trim = cmd.args[2] | (cmd.args[3] << 8); - -- if (uitmp == dev->if_frequency / 1000) -+ if ((ret == 0) && (xtal_trim < 16)) - goto warm; - -+ dev->if_frequency = 0; /* we no longer know current tuner state */ -+ - /* power up */ - if (dev->chiptype == SI2157_CHIPTYPE_SI2146) { - memcpy(cmd.args, "\xc0\x05\x01\x00\x00\x0b\x00\x00\x01", 9); -@@ -138,6 +143,7 @@ static int si2157_init(struct dvb_frontend *fe) - chip_id = cmd.args[1] << 24 | cmd.args[2] << 16 | cmd.args[3] << 8 | - cmd.args[4] << 0; - -+ #define SI2177_A30 ('A' << 24 | 77 << 16 | '3' << 8 | '0' << 0) - #define SI2158_A20 ('A' << 24 | 58 << 16 | '2' << 8 | '0' << 0) - #define SI2148_A20 ('A' << 24 | 48 << 16 | '2' << 8 | '0' << 0) - #define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0) -@@ -153,6 +159,9 @@ static int si2157_init(struct dvb_frontend *fe) - case SI2141_A10: - fw_name = SI2141_A10_FIRMWARE; - break; -+ case SI2177_A30: -+ fw_name = SI2157_A30_FIRMWARE; -+ break; - case SI2157_A30: - case SI2147_A30: - case SI2146_A10: -@@ -230,6 +239,45 @@ skip_fw_download: - - dev_info(&client->dev, "firmware version: %c.%c.%d\n", - cmd.args[6], cmd.args[7], cmd.args[8]); -+ -+ if (dev->chiptype == SI2157_CHIPTYPE_SI2141) { -+ /* set clock */ -+ memcpy(cmd.args, "\xc0\x00\x0d", 3); -+ cmd.wlen = 3; -+ cmd.rlen = 1; -+ ret = si2157_cmd_execute(client, &cmd); -+ if (ret) -+ goto err; -+ /* setup PIN */ -+ memcpy(cmd.args, "\x12\x80\x80\x85\x00\x81\x00", 7); -+ cmd.wlen = 7; -+ cmd.rlen = 7; -+ ret = si2157_cmd_execute(client, &cmd); -+ if (ret) -+ goto err; -+ } -+ -+ /* enable tuner status flags */ -+ memcpy(cmd.args, "\x14\x00\x01\x05\x01\x00", 6); -+ cmd.wlen = 6; -+ cmd.rlen = 1; -+ ret = si2157_cmd_execute(client, &cmd); -+ if (ret) -+ goto err; -+ -+ memcpy(cmd.args, "\x14\x00\x01\x06\x01\x00", 6); -+ cmd.wlen = 6; -+ cmd.rlen = 1; -+ ret = si2157_cmd_execute(client, &cmd); -+ if (ret) -+ goto err; -+ -+ memcpy(cmd.args, "\x14\x00\x01\x07\x01\x00", 6); -+ cmd.wlen = 6; -+ cmd.rlen = 1; -+ ret = si2157_cmd_execute(client, &cmd); -+ if (ret) -+ goto err; - warm: - /* init statistics in order signal app which are supported */ - c->strength.len = 1; -@@ -274,6 +322,84 @@ err: - return ret; - } - -+static int si2157_tune_wait(struct i2c_client *client, u8 is_digital) -+{ -+#define TUN_TIMEOUT 40 -+#define DIG_TIMEOUT 30 -+#define ANALOG_TIMEOUT 150 -+ struct si2157_dev *dev = i2c_get_clientdata(client); -+ int ret; -+ unsigned long timeout; -+ unsigned long start_time; -+ u8 wait_status; -+ u8 tune_lock_mask; -+ -+ if (is_digital) -+ tune_lock_mask = 0x04; -+ else -+ tune_lock_mask = 0x02; -+ -+ mutex_lock(&dev->i2c_mutex); -+ -+ /* wait tuner command complete */ -+ start_time = jiffies; -+ timeout = start_time + msecs_to_jiffies(TUN_TIMEOUT); -+ while (!time_after(jiffies, timeout)) { -+ ret = i2c_master_recv(client, &wait_status, -+ sizeof(wait_status)); -+ if (ret < 0) { -+ goto err_mutex_unlock; -+ } else if (ret != sizeof(wait_status)) { -+ ret = -EREMOTEIO; -+ goto err_mutex_unlock; -+ } -+ -+ /* tuner done? */ -+ if ((wait_status & 0x81) == 0x81) -+ break; -+ usleep_range(5000, 10000); -+ } -+ /* if we tuned ok, wait a bit for tuner lock */ -+ if ((wait_status & 0x81) == 0x81) { -+ if (is_digital) -+ timeout = jiffies + msecs_to_jiffies(DIG_TIMEOUT); -+ else -+ timeout = jiffies + msecs_to_jiffies(ANALOG_TIMEOUT); -+ while (!time_after(jiffies, timeout)) { -+ ret = i2c_master_recv(client, &wait_status, -+ sizeof(wait_status)); -+ if (ret < 0) { -+ goto err_mutex_unlock; -+ } else if (ret != sizeof(wait_status)) { -+ ret = -EREMOTEIO; -+ goto err_mutex_unlock; -+ } -+ -+ /* tuner locked? */ -+ if (wait_status & tune_lock_mask) -+ break; -+ usleep_range(5000, 10000); -+ } -+ } -+ -+ dev_dbg(&client->dev, "tuning took %d ms, status=0x%x\n", -+ jiffies_to_msecs(jiffies) - jiffies_to_msecs(start_time), -+ wait_status); -+ -+ if ((wait_status & 0xc0) != 0x80) { -+ ret = -ETIMEDOUT; -+ goto err_mutex_unlock; -+ } -+ -+ mutex_unlock(&dev->i2c_mutex); -+ return 0; -+ -+err_mutex_unlock: -+ mutex_unlock(&dev->i2c_mutex); -+ dev_dbg(&client->dev, "failed=%d\n", ret); -+ return ret; -+} -+ - static int si2157_set_params(struct dvb_frontend *fe) - { - struct i2c_client *client = fe->tuner_priv; -@@ -344,7 +470,7 @@ static int si2157_set_params(struct dvb_frontend *fe) - if (ret) - goto err; - -- /* set if frequency if needed */ -+ /* set digital if frequency if needed */ - if (if_frequency != dev->if_frequency) { - memcpy(cmd.args, "\x14\x00\x06\x07", 4); - cmd.args[4] = (if_frequency / 1000) & 0xff; -@@ -358,7 +484,7 @@ static int si2157_set_params(struct dvb_frontend *fe) - dev->if_frequency = if_frequency; - } - -- /* set frequency */ -+ /* set digital frequency */ - memcpy(cmd.args, "\x41\x00\x00\x00\x00\x00\x00\x00", 8); - cmd.args[4] = (c->frequency >> 0) & 0xff; - cmd.args[5] = (c->frequency >> 8) & 0xff; -@@ -370,24 +496,298 @@ static int si2157_set_params(struct dvb_frontend *fe) - if (ret) - goto err; - -+ dev->bandwidth = bandwidth; -+ dev->frequency = c->frequency; -+ -+ si2157_tune_wait(client, 1); /* wait to complete, ignore any errors */ -+ - return 0; - err: -+ dev->bandwidth = 0; -+ dev->frequency = 0; -+ dev->if_frequency = 0; - dev_dbg(&client->dev, "failed=%d\n", ret); - return ret; - } - -+static int si2157_set_analog_params(struct dvb_frontend *fe, -+ struct analog_parameters *params) -+{ -+ struct i2c_client *client = fe->tuner_priv; -+ struct si2157_dev *dev = i2c_get_clientdata(client); -+ char *std; /* for debugging */ -+ int ret; -+ struct si2157_cmd cmd; -+ u32 bandwidth = 0; -+ u32 if_frequency = 0; -+ u32 freq = 0; -+ u64 tmp_lval = 0; -+ u8 system = 0; -+ u8 color = 0; /* 0=NTSC/PAL, 0x10=SECAM */ -+ u8 invert_analog = 1; /* analog tuner spectrum; 0=normal, 1=inverted */ -+ -+ if (dev->chiptype != SI2157_CHIPTYPE_SI2157) { -+ dev_info(&client->dev, "%s: Analog tuning not supported for chiptype=%u\n", -+ __func__, dev->chiptype); -+ ret = -EINVAL; -+ goto err; -+ } -+ -+ if (!dev->active) -+ si2157_init(fe); -+ -+ if (!dev->active) { -+ ret = -EAGAIN; -+ goto err; -+ } -+ if (params->mode == V4L2_TUNER_RADIO) { -+ /* -+ * std = "fm"; -+ * bandwidth = 1700000; //best can do for FM, AGC will be a mess though -+ * if_frequency = 1250000; //HVR-225x(saa7164), HVR-12xx(cx23885) -+ * if_frequency = 6600000; //HVR-9xx(cx231xx) -+ * if_frequency = 5500000; //HVR-19xx(pvrusb2) -+ */ -+ dev_dbg(&client->dev, "si2157 does not currently support FM radio\n"); -+ ret = -EINVAL; -+ goto err; -+ } -+ tmp_lval = params->frequency * 625LL; -+ do_div(tmp_lval, 10); /* convert to HZ */ -+ freq = (u32)tmp_lval; -+ -+ if (freq < 1000000) /* is freq in KHz */ -+ freq = freq * 1000; -+ dev->frequency = freq; -+ -+ /* if_frequency values based on tda187271C2 */ -+ if (params->std & (V4L2_STD_B|V4L2_STD_GH)) { -+ if (freq >= 470000000) { -+ std = "palGH"; -+ bandwidth = 8000000; -+ if_frequency = 6000000; -+ system = 1; -+ if (params->std & (V4L2_STD_SECAM_G|V4L2_STD_SECAM_H)) { -+ std = "secamGH"; -+ color = 0x10; -+ } -+ } else { -+ std = "palB"; -+ bandwidth = 7000000; -+ if_frequency = 6000000; -+ system = 0; -+ if (params->std & V4L2_STD_SECAM_B) { -+ std = "secamB"; -+ color = 0x10; -+ } -+ } -+ } else if (params->std & V4L2_STD_MN) { -+ std = "MN"; -+ bandwidth = 6000000; -+ if_frequency = 5400000; -+ system = 2; -+ } else if (params->std & V4L2_STD_PAL_I) { -+ std = "palI"; -+ bandwidth = 8000000; -+ if_frequency = 7250000; /* TODO: does not work yet */ -+ system = 4; -+ } else if (params->std & V4L2_STD_DK) { -+ std = "palDK"; -+ bandwidth = 8000000; -+ if_frequency = 6900000; /* TODO: does not work yet */ -+ system = 5; -+ if (params->std & V4L2_STD_SECAM_DK) { -+ std = "secamDK"; -+ color = 0x10; -+ } -+ } else if (params->std & V4L2_STD_SECAM_L) { -+ std = "secamL"; -+ bandwidth = 8000000; -+ if_frequency = 6750000; /* TODO: untested */ -+ system = 6; -+ color = 0x10; -+ } else if (params->std & V4L2_STD_SECAM_LC) { -+ std = "secamL'"; -+ bandwidth = 7000000; -+ if_frequency = 1250000; /* TODO: untested */ -+ system = 7; -+ color = 0x10; -+ } else { -+ std = "unknown"; -+ } -+ /* calc channel center freq */ -+ freq = freq - 1250000 + (bandwidth/2); -+ -+ dev_dbg(&client->dev, -+ "mode=%d system=%u std='%s' params->frequency=%u center freq=%u if=%u bandwidth=%u\n", -+ params->mode, system, std, params->frequency, -+ freq, if_frequency, bandwidth); -+ -+ /* set analog IF port */ -+ memcpy(cmd.args, "\x14\x00\x03\x06\x08\x02", 6); -+ /* in using dev->if_port, we assume analog and digital IF's */ -+ /* are always on different ports */ -+ /* assumes if_port definition is 0 or 1 for digital out */ -+ cmd.args[4] = (dev->if_port == 1)?8:10; -+ cmd.args[5] = (dev->if_port == 1)?2:1; /* Analog AGC assumed external */ -+ cmd.wlen = 6; -+ cmd.rlen = 4; -+ ret = si2157_cmd_execute(client, &cmd); -+ if (ret) -+ goto err; -+ -+ /* set analog IF output config */ -+ memcpy(cmd.args, "\x14\x00\x0d\x06\x94\x64", 6); -+ cmd.wlen = 6; -+ cmd.rlen = 4; -+ ret = si2157_cmd_execute(client, &cmd); -+ if (ret) -+ goto err; -+ -+ /* make this distinct from a digital IF */ -+ dev->if_frequency = if_frequency | 1; -+ -+ /* calc and set tuner analog if center frequency */ -+ if_frequency = if_frequency + 1250000 - (bandwidth/2); -+ dev_dbg(&client->dev, "IF Ctr freq=%d\n", if_frequency); -+ -+ memcpy(cmd.args, "\x14\x00\x0C\x06", 4); -+ cmd.args[4] = (if_frequency / 1000) & 0xff; -+ cmd.args[5] = ((if_frequency / 1000) >> 8) & 0xff; -+ cmd.wlen = 6; -+ cmd.rlen = 4; -+ ret = si2157_cmd_execute(client, &cmd); -+ if (ret) -+ goto err; -+ -+ /* set analog AGC config */ -+ memcpy(cmd.args, "\x14\x00\x07\x06\x32\xc8", 6); -+ cmd.wlen = 6; -+ cmd.rlen = 4; -+ ret = si2157_cmd_execute(client, &cmd); -+ if (ret) -+ goto err; -+ -+ /* set analog video mode */ -+ memcpy(cmd.args, "\x14\x00\x04\x06\x00\x00", 6); -+ cmd.args[4] = system | color; -+#if 1 /* can use dev->inversion if assumed it applies to both digital/analog */ -+ if (invert_analog) -+ cmd.args[5] |= 0x02; -+#else -+ if (dev->inversion) -+ cmd.args[5] |= 0x02; -+#endif -+ cmd.wlen = 6; -+ cmd.rlen = 1; -+ ret = si2157_cmd_execute(client, &cmd); -+ if (ret) -+ goto err; -+ -+ /* set analog frequency */ -+ memcpy(cmd.args, "\x41\x01\x00\x00\x00\x00\x00\x00", 8); -+ cmd.args[4] = (freq >> 0) & 0xff; -+ cmd.args[5] = (freq >> 8) & 0xff; -+ cmd.args[6] = (freq >> 16) & 0xff; -+ cmd.args[7] = (freq >> 24) & 0xff; -+ cmd.wlen = 8; -+ cmd.rlen = 1; -+ ret = si2157_cmd_execute(client, &cmd); -+ if (ret) -+ goto err; -+ -+#if 1 /* testing */ -+ /* get tuner status, RSSI values */ -+ memcpy(cmd.args, "\x42\x01", 2); -+ cmd.wlen = 2; -+ cmd.rlen = 12; -+ ret = si2157_cmd_execute(client, &cmd); -+ -+ dev_info(&client->dev, "%s: tuner status: ret=%d rssi=%d mode=%x freq=%d\n", -+ __func__, ret, cmd.args[3], cmd.args[8], -+ (cmd.args[7]<<24 | cmd.args[6]<<16 | -+ cmd.args[5]<<8 | cmd.args[4])); -+#endif -+ dev->bandwidth = bandwidth; -+ -+ si2157_tune_wait(client, 0); /* wait to complete, ignore any errors */ -+ -+ return 0; -+err: -+ dev->bandwidth = 0; -+ dev->frequency = 0; -+ dev->if_frequency = 0; -+ dev_dbg(&client->dev, "failed=%d\n", ret); -+ return ret; -+} -+ -+static int si2157_get_frequency(struct dvb_frontend *fe, u32 *frequency) -+{ -+ struct i2c_client *client = fe->tuner_priv; -+ struct si2157_dev *dev = i2c_get_clientdata(client); -+ -+ *frequency = dev->frequency; -+ dev_info(&client->dev, "%s: freq=%u\n", __func__, dev->frequency); -+ return 0; -+} -+ -+static int si2157_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -+{ -+ struct i2c_client *client = fe->tuner_priv; -+ struct si2157_dev *dev = i2c_get_clientdata(client); -+ -+ *bandwidth = dev->bandwidth; -+ dev_info(&client->dev, "%s: bandwidth=%u\n", __func__, dev->bandwidth); -+ return 0; -+} -+ - static int si2157_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) - { - struct i2c_client *client = fe->tuner_priv; - struct si2157_dev *dev = i2c_get_clientdata(client); - -- *frequency = dev->if_frequency; -+ *frequency = dev->if_frequency & ~1; /* strip analog IF indicator bit */ -+ dev_info(&client->dev, "%s: if_frequency=%u\n", __func__, *frequency); - return 0; - } - -+static int si2157_get_rf_strength(struct dvb_frontend *fe, u16 *rssi) -+{ -+ struct i2c_client *client = fe->tuner_priv; -+ struct dtv_frontend_properties *c = &fe->dtv_property_cache; -+ struct si2157_cmd cmd; -+ int ret; -+ int strength; -+ -+ dev_dbg(&client->dev, "\n"); -+ -+ memcpy(cmd.args, "\x42\x00", 2); -+ cmd.wlen = 2; -+ cmd.rlen = 12; -+ ret = si2157_cmd_execute(client, &cmd); -+ if (ret) -+ goto err; -+ -+ c->strength.stat[0].scale = FE_SCALE_DECIBEL; -+ c->strength.stat[0].svalue = (s8) cmd.args[3] * 1000; -+ -+ strength = (s8)cmd.args[3]; -+ strength = (strength > -80) ? (u16)(strength + 100) : 0; -+ strength = strength > 80 ? 100 : strength; -+ -+ *rssi = (u16)(strength * 0xffff / 100); -+ dev_dbg(&client->dev, "%s: strength=%d rssi=%u\n", -+ __func__, (s8)cmd.args[3], *rssi); -+ -+ return 0; -+err: -+ dev_dbg(&client->dev, "failed=%d\n", ret); -+ return ret; -+} -+ - static const struct dvb_tuner_ops si2157_ops = { - .info = { -- .name = "Silicon Labs Si2141/Si2146/2147/2148/2157/2158", -+ .name = "Silicon Labs Si2141/2146/2147/2148/2157/2158", - .frequency_min_hz = 42 * MHz, - .frequency_max_hz = 870 * MHz, - }, -@@ -395,7 +795,12 @@ static const struct dvb_tuner_ops si2157_ops = { - .init = si2157_init, - .sleep = si2157_sleep, - .set_params = si2157_set_params, -- .get_if_frequency = si2157_get_if_frequency, -+ .set_analog_params = si2157_set_analog_params, -+ .get_frequency = si2157_get_frequency, -+ .get_bandwidth = si2157_get_bandwidth, -+ .get_if_frequency = si2157_get_if_frequency, -+ -+ .get_rf_strength = si2157_get_rf_strength, - }; - - static void si2157_stat_work(struct work_struct *work) -@@ -455,7 +860,7 @@ static int si2157_probe(struct i2c_client *client, - cmd.wlen = 0; - cmd.rlen = 1; - ret = si2157_cmd_execute(client, &cmd); -- if (ret) -+ if (ret && (ret != -EAGAIN)) - goto err_kfree; - - memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct dvb_tuner_ops)); -@@ -529,6 +934,7 @@ static const struct i2c_device_id si2157_id_table[] = { - {"si2157", SI2157_CHIPTYPE_SI2157}, - {"si2146", SI2157_CHIPTYPE_SI2146}, - {"si2141", SI2157_CHIPTYPE_SI2141}, -+ {"si2177", SI2157_CHIPTYPE_SI2177}, - {} - }; - MODULE_DEVICE_TABLE(i2c, si2157_id_table); -@@ -550,3 +956,4 @@ MODULE_AUTHOR("Antti Palosaari "); - MODULE_LICENSE("GPL"); - MODULE_FIRMWARE(SI2158_A20_FIRMWARE); - MODULE_FIRMWARE(SI2141_A10_FIRMWARE); -+MODULE_FIRMWARE(SI2157_A30_FIRMWARE); -diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h -index 50f8630..84ed808 100644 ---- a/drivers/media/tuners/si2157_priv.h -+++ b/drivers/media/tuners/si2157_priv.h -@@ -37,6 +37,8 @@ struct si2157_dev { - u8 chiptype; - u8 if_port; - u32 if_frequency; -+ u32 bandwidth; -+ u32 frequency; - struct delayed_work stat_work; - - #if defined(CONFIG_MEDIA_CONTROLLER) -@@ -50,6 +52,7 @@ struct si2157_dev { - #define SI2157_CHIPTYPE_SI2157 0 - #define SI2157_CHIPTYPE_SI2146 1 - #define SI2157_CHIPTYPE_SI2141 2 -+#define SI2157_CHIPTYPE_SI2177 3 - - /* firmware command struct */ - #define SI2157_ARGLEN 30 -@@ -61,5 +64,5 @@ struct si2157_cmd { - - #define SI2158_A20_FIRMWARE "dvb-tuner-si2158-a20-01.fw" - #define SI2141_A10_FIRMWARE "dvb-tuner-si2141-a10-01.fw" -- -+#define SI2157_A30_FIRMWARE "dvb-tuner-si2157-a30-05.fw" - #endif -diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c -index d417b5f..f575ae0 100644 ---- a/drivers/media/usb/cx231xx/cx231xx-avcore.c -+++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c -@@ -587,14 +587,27 @@ int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input) - return status; - } - } -- if (dev->tuner_type == TUNER_NXP_TDA18271) -+ switch (dev->model) { /* i2c device tuners */ -+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx: -+ case CX231XX_BOARD_HAUPPAUGE_935C: -+ case CX231XX_BOARD_HAUPPAUGE_955Q: -+ case CX231XX_BOARD_HAUPPAUGE_975: -+ case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD: - status = cx231xx_set_decoder_video_input(dev, - CX231XX_VMUX_TELEVISION, - INPUT(input)->vmux); -- else -- status = cx231xx_set_decoder_video_input(dev, -+ break; -+ default: -+ if (dev->tuner_type == TUNER_NXP_TDA18271) -+ status = cx231xx_set_decoder_video_input(dev, -+ CX231XX_VMUX_TELEVISION, -+ INPUT(input)->vmux); -+ else -+ status = cx231xx_set_decoder_video_input(dev, - CX231XX_VMUX_COMPOSITE1, - INPUT(input)->vmux); -+ break; -+ }; - - break; - default: -@@ -1193,12 +1206,22 @@ int cx231xx_set_audio_decoder_input(struct cx231xx *dev, - cx231xx_set_field(FLD_SIF_EN, 0)); - break; - default: -+ switch (dev->model) { /* i2c device tuners */ -+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx: -+ case CX231XX_BOARD_HAUPPAUGE_935C: -+ case CX231XX_BOARD_HAUPPAUGE_955Q: -+ case CX231XX_BOARD_HAUPPAUGE_975: -+ case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD: -+ /* TODO: Normal mode: SIF passthrough at 14.32 MHz ??? */ -+ break; -+ default: - /* This is just a casual suggestion to people adding - new boards in case they use a tuner type we don't - currently know about */ -- dev_info(dev->dev, -- "Unknown tuner type configuring SIF"); -- break; -+ dev_info(dev->dev, -+ "Unknown tuner type configuring SIF"); -+ break; -+ } - } - break; - -diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c -index f882047..77c118b 100644 ---- a/drivers/media/usb/cx231xx/cx231xx-video.c -+++ b/drivers/media/usb/cx231xx/cx231xx-video.c -@@ -1281,7 +1281,7 @@ int cx231xx_s_frequency(struct file *file, void *priv, - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - struct v4l2_frequency new_freq = *f; -- int rc; -+ int rc, need_if_freq = 0; - u32 if_frequency = 5400000; - - dev_dbg(dev->dev, -@@ -1298,14 +1298,30 @@ int cx231xx_s_frequency(struct file *file, void *priv, - /* set pre channel change settings in DIF first */ - rc = cx231xx_tuner_pre_channel_change(dev); - -- call_all(dev, tuner, s_frequency, f); -- call_all(dev, tuner, g_frequency, &new_freq); -- dev->ctl_freq = new_freq.frequency; -+ switch (dev->model) { /* i2c device tuners */ -+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx: -+ case CX231XX_BOARD_HAUPPAUGE_935C: -+ case CX231XX_BOARD_HAUPPAUGE_955Q: -+ case CX231XX_BOARD_HAUPPAUGE_975: -+ case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD: -+ if (dev->cx231xx_set_analog_freq) -+ dev->cx231xx_set_analog_freq(dev, f->frequency); -+ dev->ctl_freq = f->frequency; -+ need_if_freq = 1; -+ break; -+ default: -+ call_all(dev, tuner, s_frequency, f); -+ call_all(dev, tuner, g_frequency, &new_freq); -+ dev->ctl_freq = new_freq.frequency; -+ break; -+ } -+ -+ pr_err("%s() %u : %u\n", __func__, f->frequency, dev->ctl_freq); - - /* set post channel change settings in DIF first */ - rc = cx231xx_tuner_post_channel_change(dev); - -- if (dev->tuner_type == TUNER_NXP_TDA18271) { -+ if (need_if_freq || dev->tuner_type == TUNER_NXP_TDA18271) { - if (dev->norm & (V4L2_STD_MN | V4L2_STD_NTSC_443)) - if_frequency = 5400000; /*5.4MHz */ - else if (dev->norm & V4L2_STD_B) -@@ -1572,8 +1588,19 @@ int cx231xx_querycap(struct file *file, void *priv, - else - cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; - } -- if (dev->tuner_type != TUNER_ABSENT) -+ switch (dev->model) { /* i2c device tuners */ -+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx: -+ case CX231XX_BOARD_HAUPPAUGE_935C: -+ case CX231XX_BOARD_HAUPPAUGE_955Q: -+ case CX231XX_BOARD_HAUPPAUGE_975: -+ case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD: - cap->device_caps |= V4L2_CAP_TUNER; -+ break; -+ default: -+ if (dev->tuner_type != TUNER_ABSENT) -+ cap->device_caps |= V4L2_CAP_TUNER; -+ break; -+ } - cap->capabilities = cap->device_caps | V4L2_CAP_READWRITE | - V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; -@@ -2179,10 +2206,20 @@ static void cx231xx_vdev_init(struct cx231xx *dev, - - video_set_drvdata(vfd, dev); - if (dev->tuner_type == TUNER_ABSENT) { -- v4l2_disable_ioctl(vfd, VIDIOC_G_FREQUENCY); -- v4l2_disable_ioctl(vfd, VIDIOC_S_FREQUENCY); -- v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER); -- v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER); -+ switch (dev->model) { -+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx: -+ case CX231XX_BOARD_HAUPPAUGE_935C: -+ case CX231XX_BOARD_HAUPPAUGE_955Q: -+ case CX231XX_BOARD_HAUPPAUGE_975: -+ case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD: -+ break; -+ default: -+ v4l2_disable_ioctl(vfd, VIDIOC_G_FREQUENCY); -+ v4l2_disable_ioctl(vfd, VIDIOC_S_FREQUENCY); -+ v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER); -+ v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER); -+ break; -+ } - } - } - -diff --git a/drivers/media/usb/pvrusb2/Kconfig b/drivers/media/usb/pvrusb2/Kconfig -index 64f9df0..e6a4f73 100644 ---- a/drivers/media/usb/pvrusb2/Kconfig -+++ b/drivers/media/usb/pvrusb2/Kconfig -@@ -41,6 +41,8 @@ config VIDEO_PVRUSB2_DVB - select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT - select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT -+ select DVB_LGDT3306A if MEDIA_SUBDRV_AUTOSELECT -+ select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT -diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c -index d5bec0f..36016ab 100644 ---- a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c -+++ b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c -@@ -111,10 +111,35 @@ static const struct routing_scheme routing_defav400 = { - .cnt = ARRAY_SIZE(routing_schemeav400), - }; - -+static const struct routing_scheme_item routing_scheme160xxx[] = { -+ [PVR2_CVAL_INPUT_TV] = { -+ .vid = CX25840_COMPOSITE7, -+ .aud = CX25840_AUDIO8, -+ }, -+ [PVR2_CVAL_INPUT_RADIO] = { -+ .vid = CX25840_COMPOSITE4, -+ .aud = CX25840_AUDIO6, -+ }, -+ [PVR2_CVAL_INPUT_COMPOSITE] = { -+ .vid = CX25840_COMPOSITE3, -+ .aud = CX25840_AUDIO_SERIAL, -+ }, -+ [PVR2_CVAL_INPUT_SVIDEO] = { -+ .vid = CX25840_SVIDEO1, -+ .aud = CX25840_AUDIO_SERIAL, -+ }, -+}; -+ -+static const struct routing_scheme routing_def160xxx = { -+ .def = routing_scheme160xxx, -+ .cnt = ARRAY_SIZE(routing_scheme160xxx), -+}; -+ - static const struct routing_scheme *routing_schemes[] = { - [PVR2_ROUTING_SCHEME_HAUPPAUGE] = &routing_def0, - [PVR2_ROUTING_SCHEME_GOTVIEW] = &routing_defgv, - [PVR2_ROUTING_SCHEME_AV400] = &routing_defav400, -+ [PVR2_ROUTING_SCHEME_HAUP160XXX] = &routing_def160xxx, - }; - - void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) -diff --git a/drivers/media/usb/pvrusb2/pvrusb2-devattr.c b/drivers/media/usb/pvrusb2/pvrusb2-devattr.c -index 06de1c8..97b4fc8 100644 ---- a/drivers/media/usb/pvrusb2/pvrusb2-devattr.c -+++ b/drivers/media/usb/pvrusb2/pvrusb2-devattr.c -@@ -37,6 +37,9 @@ pvr2_device_desc structures. - #include "tda18271.h" - #include "tda8290.h" - #include "tuner-simple.h" -+#include "si2157.h" -+#include "lgdt3306a.h" -+#include "si2168.h" - #endif - - -@@ -188,10 +191,10 @@ static struct lgdt330x_config pvr2_lgdt3303_config = { - - static int pvr2_lgdt3303_attach(struct pvr2_dvb_adapter *adap) - { -- adap->fe = dvb_attach(lgdt330x_attach, &pvr2_lgdt3303_config, -- 0x0e, -- &adap->channel.hdw->i2c_adap); -- if (adap->fe) -+ adap->fe[0] = dvb_attach(lgdt330x_attach, &pvr2_lgdt3303_config, -+ 0x0e, -+ &adap->channel.hdw->i2c_adap); -+ if (adap->fe[0]) - return 0; - - return -EIO; -@@ -199,7 +202,7 @@ static int pvr2_lgdt3303_attach(struct pvr2_dvb_adapter *adap) - - static int pvr2_lgh06xf_attach(struct pvr2_dvb_adapter *adap) - { -- dvb_attach(simple_tuner_attach, adap->fe, -+ dvb_attach(simple_tuner_attach, adap->fe[0], - &adap->channel.hdw->i2c_adap, 0x61, - TUNER_LG_TDVS_H06XF); - -@@ -248,10 +251,10 @@ static struct lgdt330x_config pvr2_lgdt3302_config = { - - static int pvr2_lgdt3302_attach(struct pvr2_dvb_adapter *adap) - { -- adap->fe = dvb_attach(lgdt330x_attach, &pvr2_lgdt3302_config, -+ adap->fe[0] = dvb_attach(lgdt330x_attach, &pvr2_lgdt3302_config, - 0x0e, - &adap->channel.hdw->i2c_adap); -- if (adap->fe) -+ if (adap->fe[0]) - return 0; - - return -EIO; -@@ -259,7 +262,7 @@ static int pvr2_lgdt3302_attach(struct pvr2_dvb_adapter *adap) - - static int pvr2_fcv1236d_attach(struct pvr2_dvb_adapter *adap) - { -- dvb_attach(simple_tuner_attach, adap->fe, -+ dvb_attach(simple_tuner_attach, adap->fe[0], - &adap->channel.hdw->i2c_adap, 0x61, - TUNER_PHILIPS_FCV1236D); - -@@ -335,9 +338,9 @@ static struct tda18271_config hauppauge_tda18271_dvb_config = { - - static int pvr2_tda10048_attach(struct pvr2_dvb_adapter *adap) - { -- adap->fe = dvb_attach(tda10048_attach, &hauppauge_tda10048_config, -+ adap->fe[0] = dvb_attach(tda10048_attach, &hauppauge_tda10048_config, - &adap->channel.hdw->i2c_adap); -- if (adap->fe) -+ if (adap->fe[0]) - return 0; - - return -EIO; -@@ -345,10 +348,10 @@ static int pvr2_tda10048_attach(struct pvr2_dvb_adapter *adap) - - static int pvr2_73xxx_tda18271_8295_attach(struct pvr2_dvb_adapter *adap) - { -- dvb_attach(tda829x_attach, adap->fe, -+ dvb_attach(tda829x_attach, adap->fe[0], - &adap->channel.hdw->i2c_adap, 0x42, - &tda829x_no_probe); -- dvb_attach(tda18271_attach, adap->fe, 0x60, -+ dvb_attach(tda18271_attach, adap->fe[0], 0x60, - &adap->channel.hdw->i2c_adap, - &hauppauge_tda18271_dvb_config); - -@@ -433,9 +436,9 @@ static struct tda18271_config hauppauge_tda18271_config = { - - static int pvr2_s5h1409_attach(struct pvr2_dvb_adapter *adap) - { -- adap->fe = dvb_attach(s5h1409_attach, &pvr2_s5h1409_config, -+ adap->fe[0] = dvb_attach(s5h1409_attach, &pvr2_s5h1409_config, - &adap->channel.hdw->i2c_adap); -- if (adap->fe) -+ if (adap->fe[0]) - return 0; - - return -EIO; -@@ -443,9 +446,9 @@ static int pvr2_s5h1409_attach(struct pvr2_dvb_adapter *adap) - - static int pvr2_s5h1411_attach(struct pvr2_dvb_adapter *adap) - { -- adap->fe = dvb_attach(s5h1411_attach, &pvr2_s5h1411_config, -+ adap->fe[0] = dvb_attach(s5h1411_attach, &pvr2_s5h1411_config, - &adap->channel.hdw->i2c_adap); -- if (adap->fe) -+ if (adap->fe[0]) - return 0; - - return -EIO; -@@ -453,10 +456,10 @@ static int pvr2_s5h1411_attach(struct pvr2_dvb_adapter *adap) - - static int pvr2_tda18271_8295_attach(struct pvr2_dvb_adapter *adap) - { -- dvb_attach(tda829x_attach, adap->fe, -+ dvb_attach(tda829x_attach, adap->fe[0], - &adap->channel.hdw->i2c_adap, 0x42, - &tda829x_no_probe); -- dvb_attach(tda18271_attach, adap->fe, 0x60, -+ dvb_attach(tda18271_attach, adap->fe[0], 0x60, - &adap->channel.hdw->i2c_adap, - &hauppauge_tda18271_config); - -@@ -525,7 +528,164 @@ static const struct pvr2_device_desc pvr2_device_751xx = { - #endif - }; - -+/*------------------------------------------------------------------------*/ -+/* Hauppauge PVR-USB2 Model 160000 / 160111 -- HVR-1955 / HVR-1975 */ -+ -+#ifdef CONFIG_VIDEO_PVRUSB2_DVB -+static int pvr2_si2157_attach(struct pvr2_dvb_adapter *adap); -+static int pvr2_si2168_attach(struct pvr2_dvb_adapter *adap); -+static int pvr2_dual_fe_attach(struct pvr2_dvb_adapter *adap); -+static int pvr2_lgdt3306a_attach(struct pvr2_dvb_adapter *adap); -+ -+static const struct pvr2_dvb_props pvr2_160000_dvb_props = { -+ .frontend_attach = pvr2_dual_fe_attach, -+ .tuner_attach = pvr2_si2157_attach, -+}; -+static const struct pvr2_dvb_props pvr2_160111_dvb_props = { -+ .frontend_attach = pvr2_lgdt3306a_attach, -+ .tuner_attach = pvr2_si2157_attach, -+}; -+ -+static int pvr2_si2157_attach(struct pvr2_dvb_adapter *adap) -+{ -+ struct si2157_config si2157_config = {}; -+ -+ si2157_config.inversion = 1; -+ si2157_config.fe = adap->fe[0]; -+ -+ adap->i2c_client_tuner = dvb_module_probe("si2157", "si2177", -+ &adap->channel.hdw->i2c_adap, -+ 0x60, &si2157_config); -+ -+ if (!adap->i2c_client_tuner) -+ return -ENODEV; -+ -+ return 0; -+} -+ -+static int pvr2_si2168_attach(struct pvr2_dvb_adapter *adap) -+{ -+ struct si2168_config si2168_config = {}; -+ struct i2c_adapter *adapter; -+ -+ pr_debug("%s()\n", __func__); -+ -+ si2168_config.fe = &adap->fe[1]; -+ si2168_config.i2c_adapter = &adapter; -+ si2168_config.ts_mode = SI2168_TS_PARALLEL; /*2, 1-serial, 2-parallel.*/ -+ si2168_config.ts_clock_gapped = 1; /*0-disabled, 1-enabled.*/ -+ si2168_config.ts_clock_inv = 0; /*0-not-invert, 1-invert*/ -+ si2168_config.spectral_inversion = 1; /*0-not-invert, 1-invert*/ -+ -+ adap->i2c_client_demod[1] = dvb_module_probe("si2168", NULL, -+ &adap->channel.hdw->i2c_adap, -+ 0x64, &si2168_config); -+ -+ if (!adap->i2c_client_demod[1]) -+ return -ENODEV; -+ -+ return 0; -+} -+ -+static int pvr2_lgdt3306a_attach(struct pvr2_dvb_adapter *adap) -+{ -+ struct lgdt3306a_config lgdt3306a_config; -+ struct i2c_adapter *adapter; -+ -+ pr_debug("%s()\n", __func__); -+ -+ lgdt3306a_config.fe = &adap->fe[0]; -+ lgdt3306a_config.i2c_adapter = &adapter; -+ lgdt3306a_config.deny_i2c_rptr = 1; -+ lgdt3306a_config.spectral_inversion = 1; -+ lgdt3306a_config.qam_if_khz = 4000; -+ lgdt3306a_config.vsb_if_khz = 3250; -+ lgdt3306a_config.mpeg_mode = LGDT3306A_MPEG_PARALLEL; -+ lgdt3306a_config.tpclk_edge = LGDT3306A_TPCLK_FALLING_EDGE; -+ lgdt3306a_config.tpvalid_polarity = LGDT3306A_TP_VALID_LOW; -+ lgdt3306a_config.xtalMHz = 25, /* demod clock MHz; 24/25 supported */ -+ -+ adap->i2c_client_demod[0] = dvb_module_probe("lgdt3306a", NULL, -+ &adap->channel.hdw->i2c_adap, -+ 0x59, &lgdt3306a_config); -+ -+ if (!adap->i2c_client_demod[0]) -+ return -ENODEV; -+ -+ return 0; -+} -+ -+static int pvr2_dual_fe_attach(struct pvr2_dvb_adapter *adap) -+{ -+ pr_debug("%s()\n", __func__); -+ -+ if (pvr2_lgdt3306a_attach(adap) != 0) -+ return -ENODEV; -+ -+ if (pvr2_si2168_attach(adap) != 0) { -+ dvb_module_release(adap->i2c_client_demod[0]); -+ return -ENODEV; -+ } - -+ return 0; -+} -+#endif -+ -+#define PVR2_FIRMWARE_160xxx "v4l-pvrusb2-160xxx-01.fw" -+static const char *pvr2_fw1_names_160xxx[] = { -+ PVR2_FIRMWARE_160xxx, -+}; -+ -+static const struct pvr2_device_client_desc pvr2_cli_160xxx[] = { -+ { .module_id = PVR2_CLIENT_ID_CX25840 }, -+}; -+ -+static const struct pvr2_device_desc pvr2_device_160000 = { -+ .description = "WinTV HVR-1975 Model 160000", -+ .shortname = "160000", -+ .client_table.lst = pvr2_cli_160xxx, -+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_160xxx), -+ .fx2_firmware.lst = pvr2_fw1_names_160xxx, -+ .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_160xxx), -+ .default_tuner_type = TUNER_ABSENT, -+ .flag_has_cx25840 = !0, -+ .flag_has_hauppauge_rom = !0, -+ .flag_has_analogtuner = !0, -+ .flag_has_composite = !0, -+ .flag_has_svideo = !0, -+ .flag_fx2_16kb = !0, -+ .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, -+ .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE, -+ .default_std_mask = V4L2_STD_NTSC_M, -+ .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE, -+ .ir_scheme = PVR2_IR_SCHEME_ZILOG, -+#ifdef CONFIG_VIDEO_PVRUSB2_DVB -+ .dvb_props = &pvr2_160000_dvb_props, -+#endif -+}; -+static const struct pvr2_device_desc pvr2_device_160111 = { -+ .description = "WinTV HVR-1955 Model 160111", -+ .shortname = "160111", -+ .client_table.lst = pvr2_cli_160xxx, -+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_160xxx), -+ .fx2_firmware.lst = pvr2_fw1_names_160xxx, -+ .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_160xxx), -+ .default_tuner_type = TUNER_ABSENT, -+ .flag_has_cx25840 = !0, -+ .flag_has_hauppauge_rom = !0, -+ .flag_has_analogtuner = !0, -+ .flag_has_composite = !0, -+ .flag_has_svideo = !0, -+ .flag_fx2_16kb = !0, -+ .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, -+ .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE, -+ .default_std_mask = V4L2_STD_NTSC_M, -+ .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE, -+ .ir_scheme = PVR2_IR_SCHEME_ZILOG, -+#ifdef CONFIG_VIDEO_PVRUSB2_DVB -+ .dvb_props = &pvr2_160111_dvb_props, -+#endif -+}; - - /*------------------------------------------------------------------------*/ - -@@ -552,6 +712,10 @@ struct usb_device_id pvr2_device_table[] = { - .driver_info = (kernel_ulong_t)&pvr2_device_751xx}, - { USB_DEVICE(0x0ccd, 0x0039), - .driver_info = (kernel_ulong_t)&pvr2_device_av400}, -+ { USB_DEVICE(0x2040, 0x7502), -+ .driver_info = (kernel_ulong_t)&pvr2_device_160111}, -+ { USB_DEVICE(0x2040, 0x7510), -+ .driver_info = (kernel_ulong_t)&pvr2_device_160000}, - { } - }; - -diff --git a/drivers/media/usb/pvrusb2/pvrusb2-devattr.h b/drivers/media/usb/pvrusb2/pvrusb2-devattr.h -index c1e7d48..ea0b2bf 100644 ---- a/drivers/media/usb/pvrusb2/pvrusb2-devattr.h -+++ b/drivers/media/usb/pvrusb2/pvrusb2-devattr.h -@@ -66,6 +66,7 @@ struct pvr2_string_table { - #define PVR2_ROUTING_SCHEME_GOTVIEW 1 - #define PVR2_ROUTING_SCHEME_ONAIR 2 - #define PVR2_ROUTING_SCHEME_AV400 3 -+#define PVR2_ROUTING_SCHEME_HAUP160XXX 4 - - #define PVR2_DIGITAL_SCHEME_NONE 0 - #define PVR2_DIGITAL_SCHEME_HAUPPAUGE 1 -diff --git a/drivers/media/usb/pvrusb2/pvrusb2-dvb.c b/drivers/media/usb/pvrusb2/pvrusb2-dvb.c -index 4b32b21..8f492ec 100644 ---- a/drivers/media/usb/pvrusb2/pvrusb2-dvb.c -+++ b/drivers/media/usb/pvrusb2/pvrusb2-dvb.c -@@ -343,26 +343,19 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) - goto done; - } - -- if ((dvb_props->frontend_attach(adap) == 0) && (adap->fe)) { -- -- if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) { -+ if (dvb_props->frontend_attach(adap) == 0 && adap->fe[0]) { -+ if (dvb_register_frontend(&adap->dvb_adap, adap->fe[0])) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "frontend registration failed!"); -- dvb_frontend_detach(adap->fe); -- adap->fe = NULL; - ret = -ENODEV; -- goto done; -+ goto fail_frontend0; - } -+ if (adap->fe[0]->ops.analog_ops.standby) -+ adap->fe[0]->ops.analog_ops.standby(adap->fe[0]); - -- if (dvb_props->tuner_attach) -- dvb_props->tuner_attach(adap); -- -- if (adap->fe->ops.analog_ops.standby) -- adap->fe->ops.analog_ops.standby(adap->fe); -- -- /* Ensure all frontends negotiate bus access */ -- adap->fe->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl; -- -+ pvr2_trace(PVR2_TRACE_INFO, "transferring fe[%d] ts_bus_ctrl() to pvr2_dvb_bus_ctrl()", -+ adap->fe[0]->id); -+ adap->fe[0]->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl; - } else { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "no frontend was attached!"); -@@ -370,17 +363,74 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) - return ret; - } - -- done: -+ if (dvb_props->tuner_attach && dvb_props->tuner_attach(adap)) { -+ pvr2_trace(PVR2_TRACE_ERROR_LEGS, "tuner attach failed"); -+ ret = -ENODEV; -+ goto fail_tuner; -+ } -+ -+ if (adap->fe[1]) { -+ adap->fe[1]->id = 1; -+ adap->fe[1]->tuner_priv = adap->fe[0]->tuner_priv; -+ memcpy(&adap->fe[1]->ops.tuner_ops, -+ &adap->fe[0]->ops.tuner_ops, -+ sizeof(struct dvb_tuner_ops)); -+ -+ if (dvb_register_frontend(&adap->dvb_adap, adap->fe[1])) { -+ pvr2_trace(PVR2_TRACE_ERROR_LEGS, -+ "frontend registration failed!"); -+ ret = -ENODEV; -+ goto fail_frontend1; -+ } -+ /* MFE lock */ -+ adap->dvb_adap.mfe_shared = 1; -+ -+ if (adap->fe[1]->ops.analog_ops.standby) -+ adap->fe[1]->ops.analog_ops.standby(adap->fe[1]); -+ -+ pvr2_trace(PVR2_TRACE_INFO, "transferring fe[%d] ts_bus_ctrl() to pvr2_dvb_bus_ctrl()", -+ adap->fe[1]->id); -+ adap->fe[1]->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl; -+ } -+done: - pvr2_channel_limit_inputs(&adap->channel, 0); - return ret; -+ -+fail_frontend1: -+ dvb_frontend_detach(adap->fe[1]); -+ adap->fe[1] = NULL; -+fail_tuner: -+ dvb_unregister_frontend(adap->fe[0]); -+fail_frontend0: -+ dvb_frontend_detach(adap->fe[0]); -+ adap->fe[0] = NULL; -+ dvb_module_release(adap->i2c_client_tuner); -+ dvb_module_release(adap->i2c_client_demod[1]); -+ dvb_module_release(adap->i2c_client_demod[0]); -+ -+ return ret; - } - - static int pvr2_dvb_frontend_exit(struct pvr2_dvb_adapter *adap) - { -- if (adap->fe != NULL) { -- dvb_unregister_frontend(adap->fe); -- dvb_frontend_detach(adap->fe); -+ if (adap->fe[1]) { -+ dvb_unregister_frontend(adap->fe[1]); -+ dvb_frontend_detach(adap->fe[1]); -+ adap->fe[1] = NULL; -+ } -+ if (adap->fe[0]) { -+ dvb_unregister_frontend(adap->fe[0]); -+ dvb_frontend_detach(adap->fe[0]); -+ adap->fe[0] = NULL; - } -+ -+ dvb_module_release(adap->i2c_client_tuner); -+ adap->i2c_client_tuner = NULL; -+ dvb_module_release(adap->i2c_client_demod[1]); -+ adap->i2c_client_demod[1] = NULL; -+ dvb_module_release(adap->i2c_client_demod[0]); -+ adap->i2c_client_demod[0] = NULL; -+ - return 0; - } - -diff --git a/drivers/media/usb/pvrusb2/pvrusb2-dvb.h b/drivers/media/usb/pvrusb2/pvrusb2-dvb.h -index e7f71fb..c0b27f5 100644 ---- a/drivers/media/usb/pvrusb2/pvrusb2-dvb.h -+++ b/drivers/media/usb/pvrusb2/pvrusb2-dvb.h -@@ -18,7 +18,10 @@ struct pvr2_dvb_adapter { - struct dmxdev dmxdev; - struct dvb_demux demux; - struct dvb_net dvb_net; -- struct dvb_frontend *fe; -+ struct dvb_frontend *fe[2]; -+ -+ struct i2c_client *i2c_client_demod[2]; -+ struct i2c_client *i2c_client_tuner; - - int feedcount; - int max_feed_count; -diff --git a/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h b/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h -index 0a01de4..640b033 100644 ---- a/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h -+++ b/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h -@@ -38,6 +38,10 @@ - - #define FX2CMD_FWPOST1 0x52u - -+/* These 2 only exist on Model 160xxx */ -+#define FX2CMD_HCW_DEMOD_RESET_PIN 0xd4u -+#define FX2CMD_HCW_MAKO_SLEEP_PIN 0xd5u -+ - #define FX2CMD_POWER_OFF 0xdcu - #define FX2CMD_POWER_ON 0xdeu - -diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c -index 1914391..63916ca 100644 ---- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c -+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c -@@ -316,6 +316,8 @@ static const struct pvr2_fx2cmd_descdef pvr2_fx2cmd_desc[] = { - {FX2CMD_ONAIR_DTV_STREAMING_OFF, "onair dtv stream off"}, - {FX2CMD_ONAIR_DTV_POWER_ON, "onair dtv power on"}, - {FX2CMD_ONAIR_DTV_POWER_OFF, "onair dtv power off"}, -+ {FX2CMD_HCW_DEMOD_RESET_PIN, "hcw demod reset pin"}, -+ {FX2CMD_HCW_MAKO_SLEEP_PIN, "hcw mako sleep pin"}, - }; - - -@@ -2139,10 +2141,28 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) - ((0) << 16)); - } - -- // This step MUST happen after the earlier powerup step. -+ /* This step MUST happen after the earlier powerup step */ - pvr2_i2c_core_init(hdw); - if (!pvr2_hdw_dev_ok(hdw)) return; - -+ /* Reset demod only on Hauppauge 160xxx platform */ -+ if (hdw->usb_dev->descriptor.idVendor == 0x2040 && -+ (hdw->usb_dev->descriptor.idProduct == 0x7502 || -+ hdw->usb_dev->descriptor.idProduct == 0x7510)) { -+ pr_info("%s(): resetting 160xxx demod\n", __func__); -+ /* TODO: not sure this is proper place to reset once only */ -+ pvr2_issue_simple_cmd(hdw, -+ FX2CMD_HCW_DEMOD_RESET_PIN | -+ (1 << 8) | -+ ((0) << 16)); -+ msleep(10); -+ pvr2_issue_simple_cmd(hdw, -+ FX2CMD_HCW_DEMOD_RESET_PIN | -+ (1 << 8) | -+ ((1) << 16)); -+ msleep(10); -+ } -+ - pvr2_hdw_load_modules(hdw); - if (!pvr2_hdw_dev_ok(hdw)) return; - -@@ -4012,6 +4032,20 @@ int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw) - static int pvr2_hdw_cmd_hcw_demod_reset(struct pvr2_hdw *hdw, int onoff) - { - hdw->flag_ok = !0; -+ -+ /* Use this for Hauppauge 160xxx only */ -+ if (hdw->usb_dev->descriptor.idVendor == 0x2040 && -+ (hdw->usb_dev->descriptor.idProduct == 0x7502 || -+ hdw->usb_dev->descriptor.idProduct == 0x7510)) { -+ pr_debug("%s(): resetting demod on Hauppauge 160xxx platform skipped\n", -+ __func__); -+ /* Can't reset 160xxx or it will trash Demod tristate */ -+ return pvr2_issue_simple_cmd(hdw, -+ FX2CMD_HCW_MAKO_SLEEP_PIN | -+ (1 << 8) | -+ ((onoff ? 1 : 0) << 16)); -+ } -+ - return pvr2_issue_simple_cmd(hdw, - FX2CMD_HCW_DEMOD_RESETIN | - (1 << 8) | --- -2.17.1 - diff --git a/packages/linux-driver-addons/dvb/depends/media_tree/patches/media_tree-01-m88ds3103b.patch b/packages/linux-driver-addons/dvb/depends/media_tree/patches/media_tree-01-m88ds3103b.patch new file mode 100644 index 0000000000..5a9d93737b --- /dev/null +++ b/packages/linux-driver-addons/dvb/depends/media_tree/patches/media_tree-01-m88ds3103b.patch @@ -0,0 +1,747 @@ +From: Brad Love +https://git.linuxtv.org/brad/media_tree.git/log/?h=Montage-3103b.v2 +support for m88ds3103b + +diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c +index 3a367a5..0d3b81d 100644 +--- a/drivers/media/dvb-frontends/m88ds3103.c ++++ b/drivers/media/dvb-frontends/m88ds3103.c +@@ -64,6 +64,92 @@ err: + return ret; + } + ++/* ++ * m88ds3103b demod has an internal device related to clocking. First the i2c ++ * gate must be opened, for one transaction, then writes will be allowed. ++ */ ++static int m88ds3103b_dt_write(struct m88ds3103_dev *dev, int reg, int data) ++{ ++ struct i2c_client *client = dev->client; ++ u8 buf[] = {reg, data}; ++ u8 val; ++ int ret; ++ struct i2c_msg msg = { ++ .addr = dev->dt_addr, .flags = 0, .buf = buf, .len = 2 ++ }; ++ ++ m88ds3103_update_bits(dev, 0x11, 0x01, 0x00); ++ ++ val = 0x11; ++ ret = regmap_write(dev->regmap, 0x03, val); ++ if (ret) ++ dev_dbg(&client->dev, "fail=%d\n", ret); ++ ++ ret = i2c_transfer(dev->client->adapter, &msg, 1); ++ if (ret != 1) { ++ dev_dbg(&client->dev, "0x%02x (ret=%i, reg=0x%02x, value=0x%02x)\n", ++ dev->dt_addr, ret, reg, data); ++ ++ m88ds3103_update_bits(dev, 0x11, 0x01, 0x01); ++ return -EREMOTEIO; ++ } ++ m88ds3103_update_bits(dev, 0x11, 0x01, 0x01); ++ ++ dev_dbg(&client->dev, "0x%02x reg 0x%02x, value 0x%02x\n", ++ dev->dt_addr, reg, data); ++ ++ return 0; ++} ++ ++/* ++ * m88ds3103b demod has an internal device related to clocking. First the i2c ++ * gate must be opened, for two transactions, then reads will be allowed. ++ */ ++static int m88ds3103b_dt_read(struct m88ds3103_dev *dev, u8 reg) ++{ ++ struct i2c_client *client = dev->client; ++ int ret; ++ u8 val; ++ u8 b0[] = { reg }; ++ u8 b1[] = { 0 }; ++ struct i2c_msg msg[] = { ++ { ++ .addr = dev->dt_addr, ++ .flags = 0, ++ .buf = b0, ++ .len = 1 ++ }, ++ { ++ .addr = dev->dt_addr, ++ .flags = I2C_M_RD, ++ .buf = b1, ++ .len = 1 ++ } ++ }; ++ ++ m88ds3103_update_bits(dev, 0x11, 0x01, 0x00); ++ ++ val = 0x12; ++ ret = regmap_write(dev->regmap, 0x03, val); ++ if (ret) ++ dev_dbg(&client->dev, "fail=%d\n", ret); ++ ++ ret = i2c_transfer(dev->client->adapter, msg, 2); ++ if (ret != 2) { ++ dev_dbg(&client->dev, "0x%02x (err=%d, reg=0x%02x)\n", ++ dev->dt_addr, ret, reg); ++ ++ m88ds3103_update_bits(dev, 0x11, 0x01, 0x01); ++ return -EREMOTEIO; ++ } ++ m88ds3103_update_bits(dev, 0x11, 0x01, 0x01); ++ ++ dev_dbg(&client->dev, "0x%02x reg 0x%02x, value 0x%02x\n", ++ dev->dt_addr, reg, b1[0]); ++ ++ return b1[0]; ++} ++ + /* + * Get the demodulator AGC PWM voltage setting supplied to the tuner. + */ +@@ -288,6 +374,253 @@ err: + return ret; + } + ++static int m88ds3103b_select_mclk(struct m88ds3103_dev *dev) ++{ ++ struct i2c_client *client = dev->client; ++ struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache; ++ u32 adc_Freq_MHz[3] = {96, 93, 99}; ++ u8 reg16_list[3] = {96, 92, 100}, reg16, reg15; ++ u32 offset_MHz[3]; ++ u32 max_offset = 0; ++ u32 old_setting = dev->mclk; ++ u32 tuner_freq_MHz = c->frequency / 1000; ++ u8 i; ++ char big_symbol = 0; ++ ++ big_symbol = (c->symbol_rate > 45010000) ? 1 : 0; ++ ++ if (big_symbol) { ++ reg16 = 115; ++ } else { ++ reg16 = 96; ++ ++ /* TODO: IS THIS NECESSARY ? */ ++ for (i = 0; i < 3; i++) { ++ offset_MHz[i] = tuner_freq_MHz % adc_Freq_MHz[i]; ++ ++ if (offset_MHz[i] > (adc_Freq_MHz[i] / 2)) ++ offset_MHz[i] = adc_Freq_MHz[i] - offset_MHz[i]; ++ ++ if (offset_MHz[i] > max_offset) { ++ max_offset = offset_MHz[i]; ++ reg16 = reg16_list[i]; ++ dev->mclk = adc_Freq_MHz[i] * 1000 * 1000; ++ ++ if (big_symbol) ++ dev->mclk /= 2; ++ ++ dev_dbg(&client->dev, "modifying mclk %u -> %u\n", ++ old_setting, dev->mclk); ++ } ++ } ++ } ++ ++ if (dev->mclk == 93000000) ++ regmap_write(dev->regmap, 0xA0, 0x42); ++ else if (dev->mclk == 96000000) ++ regmap_write(dev->regmap, 0xA0, 0x44); ++ else if (dev->mclk == 99000000) ++ regmap_write(dev->regmap, 0xA0, 0x46); ++ else if (dev->mclk == 110250000) ++ regmap_write(dev->regmap, 0xA0, 0x4E); ++ else ++ regmap_write(dev->regmap, 0xA0, 0x44); ++ ++ reg15 = m88ds3103b_dt_read(dev, 0x15); ++ ++ m88ds3103b_dt_write(dev, 0x05, 0x40); ++ m88ds3103b_dt_write(dev, 0x11, 0x08); ++ ++ if (big_symbol) ++ reg15 |= 0x02; ++ else ++ reg15 &= ~0x02; ++ ++ m88ds3103b_dt_write(dev, 0x15, reg15); ++ m88ds3103b_dt_write(dev, 0x16, reg16); ++ ++ usleep_range(5000, 5500); ++ ++ m88ds3103b_dt_write(dev, 0x05, 0x00); ++ m88ds3103b_dt_write(dev, 0x11, (u8)(big_symbol ? 0x0E : 0x0A)); ++ ++ usleep_range(5000, 5500); ++ ++ return 0; ++} ++ ++static int m88ds3103b_set_mclk(struct m88ds3103_dev *dev, u32 mclk_khz) ++{ ++ u8 reg11 = 0x0A, reg15, reg16, reg1D, reg1E, reg1F, tmp; ++ u8 sm, f0 = 0, f1 = 0, f2 = 0, f3 = 0, pll_ldpc_mode; ++ u16 pll_div_fb, N; ++ u32 div; ++ ++ reg15 = m88ds3103b_dt_read(dev, 0x15); ++ reg16 = m88ds3103b_dt_read(dev, 0x16); ++ reg1D = m88ds3103b_dt_read(dev, 0x1D); ++ ++ if (dev->cfg->ts_mode != M88DS3103_TS_SERIAL) { ++ if (reg16 == 92) ++ tmp = 93; ++ else if (reg16 == 100) ++ tmp = 99; ++ else ++ tmp = 96; ++ ++ mclk_khz *= tmp; ++ mclk_khz /= 96; ++ } ++ ++ pll_ldpc_mode = (reg15 >> 1) & 0x01; ++ ++ pll_div_fb = (reg15 & 0x01) << 8; ++ pll_div_fb += reg16; ++ pll_div_fb += 32; ++ ++ div = 9000 * pll_div_fb * 4; ++ div /= mclk_khz; ++ ++ if (dev->cfg->ts_mode == M88DS3103_TS_SERIAL) { ++ reg11 |= 0x02; ++ ++ if (div <= 32) { ++ N = 2; ++ ++ f0 = 0; ++ f1 = div / N; ++ f2 = div - f1; ++ f3 = 0; ++ } else if (div <= 34) { ++ N = 3; ++ ++ f0 = div / N; ++ f1 = (div - f0) / (N - 1); ++ f2 = div - f0 - f1; ++ f3 = 0; ++ } else if (div <= 64) { ++ N = 4; ++ ++ f0 = div / N; ++ f1 = (div - f0) / (N - 1); ++ f2 = (div - f0 - f1) / (N - 2); ++ f3 = div - f0 - f1 - f2; ++ } else { ++ N = 4; ++ ++ f0 = 16; ++ f1 = 16; ++ f2 = 16; ++ f3 = 16; ++ } ++ ++ if (f0 == 16) ++ f0 = 0; ++ else if ((f0 < 8) && (f0 != 0)) ++ f0 = 8; ++ ++ if (f1 == 16) ++ f1 = 0; ++ else if ((f1 < 8) && (f1 != 0)) ++ f1 = 8; ++ ++ if (f2 == 16) ++ f2 = 0; ++ else if ((f2 < 8) && (f2 != 0)) ++ f2 = 8; ++ ++ if (f3 == 16) ++ f3 = 0; ++ else if ((f3 < 8) && (f3 != 0)) ++ f3 = 8; ++ } else { ++ reg11 &= ~0x02; ++ ++ if (div <= 32) { ++ N = 2; ++ ++ f0 = 0; ++ f1 = div / N; ++ f2 = div - f1; ++ f3 = 0; ++ } else if (div <= 48) { ++ N = 3; ++ ++ f0 = div / N; ++ f1 = (div - f0) / (N - 1); ++ f2 = div - f0 - f1; ++ f3 = 0; ++ } else if (div <= 64) { ++ N = 4; ++ ++ f0 = div / N; ++ f1 = (div - f0) / (N - 1); ++ f2 = (div - f0 - f1) / (N - 2); ++ f3 = div - f0 - f1 - f2; ++ } else { ++ N = 4; ++ ++ f0 = 16; ++ f1 = 16; ++ f2 = 16; ++ f3 = 16; ++ } ++ ++ if (f0 == 16) ++ f0 = 0; ++ else if ((f0 < 9) && (f0 != 0)) ++ f0 = 9; ++ ++ if (f1 == 16) ++ f1 = 0; ++ else if ((f1 < 9) && (f1 != 0)) ++ f1 = 9; ++ ++ if (f2 == 16) ++ f2 = 0; ++ else if ((f2 < 9) && (f2 != 0)) ++ f2 = 9; ++ ++ if (f3 == 16) ++ f3 = 0; ++ else if ((f3 < 9) && (f3 != 0)) ++ f3 = 9; ++ } ++ ++ sm = N - 1; ++ ++ /* Write to registers */ ++ //reg15 &= 0x01; ++ //reg15 |= (pll_div_fb >> 8) & 0x01; ++ ++ //reg16 = pll_div_fb & 0xFF; ++ ++ reg1D &= ~0x03; ++ reg1D |= sm; ++ reg1D |= 0x80; ++ ++ reg1E = ((f3 << 4) + f2) & 0xFF; ++ reg1F = ((f1 << 4) + f0) & 0xFF; ++ ++ m88ds3103b_dt_write(dev, 0x05, 0x40); ++ m88ds3103b_dt_write(dev, 0x11, 0x08); ++ m88ds3103b_dt_write(dev, 0x1D, reg1D); ++ m88ds3103b_dt_write(dev, 0x1E, reg1E); ++ m88ds3103b_dt_write(dev, 0x1F, reg1F); ++ ++ m88ds3103b_dt_write(dev, 0x17, 0xc1); ++ m88ds3103b_dt_write(dev, 0x17, 0x81); ++ ++ usleep_range(5000, 5500); ++ ++ m88ds3103b_dt_write(dev, 0x05, 0x00); ++ m88ds3103b_dt_write(dev, 0x11, 0x0A); ++ ++ usleep_range(5000, 5500); ++ ++ return 0; ++} ++ + static int m88ds3103_set_frontend(struct dvb_frontend *fe) + { + struct m88ds3103_dev *dev = fe->demodulator_priv; +@@ -298,7 +631,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) + u8 u8tmp, u8tmp1 = 0, u8tmp2 = 0; /* silence compiler warning */ + u8 buf[3]; + u16 u16tmp; +- u32 tuner_frequency_khz, target_mclk; ++ u32 tuner_frequency_khz, target_mclk, u32tmp; + s32 s32tmp; + static const struct reg_sequence reset_buf[] = { + {0x07, 0x80}, {0x07, 0x00} +@@ -321,6 +654,20 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) + + /* Disable demod clock path */ + if (dev->chip_id == M88RS6000_CHIP_ID) { ++ if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { ++ ret = regmap_read(dev->regmap, 0xb2, &u32tmp); ++ if (ret) ++ goto err; ++ if (u32tmp == 0x01) { ++ ret = regmap_write(dev->regmap, 0x00, 0x00); ++ if (ret) ++ goto err; ++ ret = regmap_write(dev->regmap, 0xb2, 0x00); ++ if (ret) ++ goto err; ++ } ++ } ++ + ret = regmap_write(dev->regmap, 0x06, 0xe0); + if (ret) + goto err; +@@ -346,7 +693,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) + tuner_frequency_khz = c->frequency; + } + +- /* select M88RS6000 demod main mclk and ts mclk from tuner die. */ ++ /* set M88RS6000/DS3103B demod main mclk and ts mclk from tuner die */ + if (dev->chip_id == M88RS6000_CHIP_ID) { + if (c->symbol_rate > 45010000) + dev->mclk = 110250000; +@@ -358,6 +705,11 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) + else + target_mclk = 144000000; + ++ if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { ++ m88ds3103b_select_mclk(dev); ++ m88ds3103b_set_mclk(dev, target_mclk / 1000); ++ } ++ + /* Enable demod clock path */ + ret = regmap_write(dev->regmap, 0x06, 0x00); + if (ret) +@@ -469,12 +821,42 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) + ret = m88ds3103_update_bits(dev, 0x9d, 0x08, 0x08); + if (ret) + goto err; ++ ++ if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { ++ buf[0] = m88ds3103b_dt_read(dev, 0x15); ++ buf[1] = m88ds3103b_dt_read(dev, 0x16); ++ ++ if (c->symbol_rate > 45010000) { ++ buf[0] &= ~0x03; ++ buf[0] |= 0x02; ++ buf[0] |= ((147 - 32) >> 8) & 0x01; ++ buf[1] = (147 - 32) & 0xFF; ++ ++ dev->mclk = 110250 * 1000; ++ } else { ++ buf[0] &= ~0x03; ++ buf[0] |= ((128 - 32) >> 8) & 0x01; ++ buf[1] = (128 - 32) & 0xFF; ++ ++ dev->mclk = 96000 * 1000; ++ } ++ m88ds3103b_dt_write(dev, 0x15, buf[0]); ++ m88ds3103b_dt_write(dev, 0x16, buf[1]); ++ ++ regmap_read(dev->regmap, 0x30, &u32tmp); ++ u32tmp &= ~0x80; ++ regmap_write(dev->regmap, 0x30, u32tmp & 0xff); ++ } ++ + ret = regmap_write(dev->regmap, 0xf1, 0x01); + if (ret) + goto err; +- ret = m88ds3103_update_bits(dev, 0x30, 0x80, 0x80); +- if (ret) +- goto err; ++ ++ if (dev->chiptype != M88DS3103_CHIPTYPE_3103B) { ++ ret = m88ds3103_update_bits(dev, 0x30, 0x80, 0x80); ++ if (ret) ++ goto err; ++ } + } + + switch (dev->cfg->ts_mode) { +@@ -488,6 +870,10 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) + break; + case M88DS3103_TS_PARALLEL: + u8tmp = 0x02; ++ if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { ++ u8tmp = 0x01; ++ u8tmp1 = 0x01; ++ } + break; + case M88DS3103_TS_CI: + u8tmp = 0x03; +@@ -516,6 +902,12 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) + u8tmp1 = 0x3f; + u8tmp2 = 0x3f; + break; ++ case M88DS3103_TS_PARALLEL: ++ if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { ++ ret = m88ds3103_update_bits(dev, 0x29, 0x01, u8tmp1); ++ if (ret) ++ goto err; ++ } + default: + u16tmp = DIV_ROUND_UP(target_mclk, dev->cfg->ts_clk); + u8tmp1 = u16tmp / 2 - 1; +@@ -543,6 +935,9 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) + else + u8tmp = 0x06; + ++ if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) ++ m88ds3103b_set_mclk(dev, target_mclk / 1000); ++ + ret = regmap_write(dev->regmap, 0xc3, 0x08); + if (ret) + goto err; +@@ -578,6 +973,16 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) + if (ret) + goto err; + ++ if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { ++ /* enable/disable 192M LDPC clock */ ++ ret = m88ds3103_update_bits(dev, 0x29, 0x10, ++ (c->delivery_system == SYS_DVBS) ? 0x10 : 0x0); ++ if (ret) ++ goto err; ++ ++ ret = m88ds3103_update_bits(dev, 0xc9, 0x08, 0x08); ++ } ++ + dev_dbg(&client->dev, "carrier offset=%d\n", + (tuner_frequency_khz - c->frequency)); + +@@ -654,10 +1059,13 @@ static int m88ds3103_init(struct dvb_frontend *fe) + dev_info(&client->dev, "found a '%s' in cold state\n", + m88ds3103_ops.info.name); + +- if (dev->chip_id == M88RS6000_CHIP_ID) ++ if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) ++ name = M88DS3103B_FIRMWARE; ++ else if (dev->chip_id == M88RS6000_CHIP_ID) + name = M88RS6000_FIRMWARE; + else + name = M88DS3103_FIRMWARE; ++ + /* request the firmware, this will block and timeout */ + ret = request_firmware(&firmware, name, &client->dev); + if (ret) { +@@ -704,6 +1112,12 @@ static int m88ds3103_init(struct dvb_frontend *fe) + dev_info(&client->dev, "firmware version: %X.%X\n", + (utmp >> 4) & 0xf, (utmp >> 0 & 0xf)); + ++ if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { ++ m88ds3103b_dt_write(dev, 0x21, 0x92); ++ m88ds3103b_dt_write(dev, 0x15, 0x6C); ++ m88ds3103b_dt_write(dev, 0x17, 0xC1); ++ m88ds3103b_dt_write(dev, 0x17, 0x81); ++ } + warm: + /* warm state */ + dev->warm = true; +@@ -1393,6 +1807,8 @@ static int m88ds3103_probe(struct i2c_client *client, + goto err_kfree; + + dev->chip_id = utmp >> 1; ++ dev->chiptype = (u8)id->driver_data; ++ + dev_dbg(&client->dev, "chip_id=%02x\n", dev->chip_id); + + switch (dev->chip_id) { +@@ -1470,6 +1886,19 @@ static int m88ds3103_probe(struct i2c_client *client, + /* setup callbacks */ + pdata->get_dvb_frontend = m88ds3103_get_dvb_frontend; + pdata->get_i2c_adapter = m88ds3103_get_i2c_adapter; ++ ++ if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { ++ /* enable i2c repeater for tuner */ ++ m88ds3103_update_bits(dev, 0x11, 0x01, 0x01); ++ ++ /* get frontend address */ ++ ret = regmap_read(dev->regmap, 0x29, &utmp); ++ if (ret) ++ goto err_kfree; ++ dev->dt_addr = ((utmp & 0x80) == 0) ? 0x42 >> 1 : 0x40 >> 1; ++ dev_err(&client->dev, "dt addr is 0x%02x", dev->dt_addr); ++ } ++ + return 0; + err_kfree: + kfree(dev); +@@ -1491,7 +1920,9 @@ static int m88ds3103_remove(struct i2c_client *client) + } + + static const struct i2c_device_id m88ds3103_id_table[] = { +- {"m88ds3103", 0}, ++ {"m88ds3103", M88DS3103_CHIPTYPE_3103}, ++ {"m88rs6000", M88DS3103_CHIPTYPE_RS6000}, ++ {"m88ds3103b", M88DS3103_CHIPTYPE_3103B}, + {} + }; + MODULE_DEVICE_TABLE(i2c, m88ds3103_id_table); +@@ -1513,3 +1944,4 @@ MODULE_DESCRIPTION("Montage Technology M88DS3103 DVB-S/S2 demodulator driver"); + MODULE_LICENSE("GPL"); + MODULE_FIRMWARE(M88DS3103_FIRMWARE); + MODULE_FIRMWARE(M88RS6000_FIRMWARE); ++MODULE_FIRMWARE(M88DS3103B_FIRMWARE); +diff --git a/drivers/media/dvb-frontends/m88ds3103_priv.h b/drivers/media/dvb-frontends/m88ds3103_priv.h +index c825032..d656ec2 100644 +--- a/drivers/media/dvb-frontends/m88ds3103_priv.h ++++ b/drivers/media/dvb-frontends/m88ds3103_priv.h +@@ -16,11 +16,17 @@ + #include + #include + +-#define M88DS3103_FIRMWARE "dvb-demod-m88ds3103.fw" +-#define M88RS6000_FIRMWARE "dvb-demod-m88rs6000.fw" ++#define M88DS3103B_FIRMWARE "dvb-demod-m88ds3103b.fw" ++#define M88DS3103_FIRMWARE "dvb-demod-m88ds3103.fw" ++#define M88RS6000_FIRMWARE "dvb-demod-m88rs6000.fw" ++ + #define M88RS6000_CHIP_ID 0x74 + #define M88DS3103_CHIP_ID 0x70 + ++#define M88DS3103_CHIPTYPE_3103 0 ++#define M88DS3103_CHIPTYPE_RS6000 1 ++#define M88DS3103_CHIPTYPE_3103B 2 ++ + struct m88ds3103_dev { + struct i2c_client *client; + struct regmap_config regmap_config; +@@ -35,10 +41,13 @@ struct m88ds3103_dev { + struct i2c_mux_core *muxc; + /* auto detect chip id to do different config */ + u8 chip_id; ++ /* chip type to differentiate m88rs6000 from m88ds3103b */ ++ u8 chiptype; + /* main mclk is calculated for M88RS6000 dynamically */ + s32 mclk; + u64 post_bit_error; + u64 post_bit_count; ++ u8 dt_addr; + }; + + struct m88ds3103_reg_val { +diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c +index 1283c7c..6561f7b 100644 +--- a/drivers/media/usb/em28xx/em28xx-cards.c ++++ b/drivers/media/usb/em28xx/em28xx-cards.c +@@ -2397,6 +2397,20 @@ const struct em28xx_board em28xx_boards[] = { + .has_dvb = 1, + .ir_codes = RC_MAP_PINNACLE_PCTV_HD, + }, ++ /* ++ * 2013:0259 PCTV DVB-S2 Stick (461e_v2) ++ * Empia EM28178, Montage M88DS3103b, Montage M88TS2022, Allegro A8293 ++ */ ++ [EM28178_BOARD_PCTV_461E_V2] = { ++ .def_i2c_bus = 1, ++ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | ++ EM28XX_I2C_FREQ_400_KHZ, ++ .name = "PCTV DVB-S2 Stick (461e v2)", ++ .tuner_type = TUNER_ABSENT, ++ .tuner_gpio = pctv_461e, ++ .has_dvb = 1, ++ .ir_codes = RC_MAP_PINNACLE_PCTV_HD, ++ }, + /* + * 2013:025f PCTV tripleStick (292e). + * Empia EM28178, Silicon Labs Si2168, Silicon Labs Si2157 +@@ -2678,6 +2692,10 @@ struct usb_device_id em28xx_id_table[] = { + .driver_info = EM2765_BOARD_SPEEDLINK_VAD_LAPLACE }, + { USB_DEVICE(0x2013, 0x0258), + .driver_info = EM28178_BOARD_PCTV_461E }, ++ { USB_DEVICE(0x2013, 0x0461), ++ .driver_info = EM28178_BOARD_PCTV_461E_V2 }, ++ { USB_DEVICE(0x2013, 0x0259), ++ .driver_info = EM28178_BOARD_PCTV_461E_V2 }, + { USB_DEVICE(0x2013, 0x025f), + .driver_info = EM28178_BOARD_PCTV_292E }, + { USB_DEVICE(0x2013, 0x0264), /* Hauppauge WinTV-soloHD 292e SE */ +diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c +index a73faf1..e2ddc25 100644 +--- a/drivers/media/usb/em28xx/em28xx-dvb.c ++++ b/drivers/media/usb/em28xx/em28xx-dvb.c +@@ -1219,6 +1219,65 @@ static int em28178_dvb_init_pctv_461e(struct em28xx *dev) + return 0; + } + ++static int em28178_dvb_init_pctv_461e_v2(struct em28xx *dev) ++{ ++ struct em28xx_dvb *dvb = dev->dvb; ++ struct i2c_adapter *i2c_adapter; ++ struct m88ds3103_platform_data m88ds3103_pdata = {}; ++ struct ts2020_config ts2020_config = {}; ++ struct a8293_platform_data a8293_pdata = {}; ++ ++ /* attach demod */ ++ m88ds3103_pdata.clk = 27000000; ++ m88ds3103_pdata.i2c_wr_max = 33; ++ m88ds3103_pdata.ts_mode = M88DS3103_TS_PARALLEL; ++ m88ds3103_pdata.ts_clk = 16000; ++ m88ds3103_pdata.ts_clk_pol = 1; ++ m88ds3103_pdata.agc = 0x99; ++ m88ds3103_pdata.agc_inv = 1; ++ m88ds3103_pdata.spec_inv = 1; ++ dvb->i2c_client_demod = dvb_module_probe("m88ds3103", "m88ds3103b", ++ &dev->i2c_adap[dev->def_i2c_bus], ++ 0x6a, &m88ds3103_pdata); ++ ++ if (!dvb->i2c_client_demod) { ++ pr_err("%s() FUCK\n", __func__); ++ return -ENODEV; ++ } ++ ++ dvb->fe[0] = m88ds3103_pdata.get_dvb_frontend(dvb->i2c_client_demod); ++ i2c_adapter = m88ds3103_pdata.get_i2c_adapter(dvb->i2c_client_demod); ++ ++ /* attach tuner */ ++ ts2020_config.fe = dvb->fe[0]; ++ dvb->i2c_client_tuner = dvb_module_probe("ts2020", "ts2022", ++ i2c_adapter, ++ 0x60, &ts2020_config); ++ if (!dvb->i2c_client_tuner) { ++ pr_err("%s() FUCK2\n", __func__); ++ dvb_module_release(dvb->i2c_client_demod); ++ return -ENODEV; ++ } ++ ++ /* delegate signal strength measurement to tuner */ ++ dvb->fe[0]->ops.read_signal_strength = ++ dvb->fe[0]->ops.tuner_ops.get_rf_strength; ++ ++ /* attach SEC */ ++ a8293_pdata.dvb_frontend = dvb->fe[0]; ++ dvb->i2c_client_sec = dvb_module_probe("a8293", NULL, ++ &dev->i2c_adap[dev->def_i2c_bus], ++ 0x08, &a8293_pdata); ++ if (!dvb->i2c_client_sec) { ++ pr_err("%s() FUCK3\n", __func__); ++ dvb_module_release(dvb->i2c_client_tuner); ++ dvb_module_release(dvb->i2c_client_demod); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ + static int em28178_dvb_init_pctv_292e(struct em28xx *dev) + { + struct em28xx_dvb *dvb = dev->dvb; +@@ -1860,6 +1919,11 @@ static int em28xx_dvb_init(struct em28xx *dev) + if (result) + goto out_free; + break; ++ case EM28178_BOARD_PCTV_461E_V2: ++ result = em28178_dvb_init_pctv_461e_v2(dev); ++ if (result) ++ goto out_free; ++ break; + case EM28178_BOARD_PCTV_292E: + result = em28178_dvb_init_pctv_292e(dev); + if (result) +diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h +index a551072..1affdd1 100644 +--- a/drivers/media/usb/em28xx/em28xx.h ++++ b/drivers/media/usb/em28xx/em28xx.h +@@ -149,6 +149,7 @@ + #define EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 100 + #define EM2884_BOARD_TERRATEC_H6 101 + #define EM2882_BOARD_ZOLID_HYBRID_TV_STICK 102 ++#define EM28178_BOARD_PCTV_461E_V2 103 + + /* Limits minimum and default number of buffers */ + #define EM28XX_MIN_BUF 4 +-- +2.17.1 + diff --git a/packages/linux-driver-addons/dvb/dvb-latest/package.mk b/packages/linux-driver-addons/dvb/dvb-latest/package.mk index 9685def240..76ab9cdd35 100644 --- a/packages/linux-driver-addons/dvb/dvb-latest/package.mk +++ b/packages/linux-driver-addons/dvb/dvb-latest/package.mk @@ -2,8 +2,8 @@ # Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv) PKG_NAME="dvb-latest" -PKG_VERSION="d121a2bedf6dd541c6182041142ec54fd94760ab" -PKG_SHA256="45dcd91f283ee9cfd7a75b291ab40c6b25d054362960c63d5a806db9b9489f70" +PKG_VERSION="0f25e6fb13b6bc345218800ad9ac863deb2ee9c8" +PKG_SHA256="71294995cff2bc556bcf9aa7ade595a4ccd91a1972b73d1e537d99d2ce86dbed" PKG_LICENSE="GPL" PKG_SITE="http://git.linuxtv.org/media_build.git" PKG_URL="https://git.linuxtv.org/media_build.git/snapshot/${PKG_VERSION}.tar.gz"