aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/usb/dvb-usb-v2
diff options
context:
space:
mode:
authorAntti Palosaari <crope@iki.fi>2013-12-01 11:44:23 -0500
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>2014-11-21 13:05:10 -0500
commit80f189a1d081f9e8701b974ea6bb59ce89a8d0f9 (patch)
treef623c20e09d257f4d50a953d7cc3018080193a0d /drivers/media/usb/dvb-usb-v2
parentfe37b38bbb7145e080b094b790ba8427945c6ecc (diff)
[media] rtl28xxu: add support for Panasonic MN88472 slave demod
There is RTL2832P devices having extra MN88472 demodulator. This patch add support for such configuration. Logically MN88472 slave demodulator is connected to RTL2832 master demodulator, both I2C bus and TS input. RTL2832 is integrated to RTL2832U and RTL2832P chips. Chip version RTL2832P has extra TS interface for connecting slave demodulator. Signed-off-by: Antti Palosaari <crope@iki.fi> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Diffstat (limited to 'drivers/media/usb/dvb-usb-v2')
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.c135
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.h4
2 files changed, 108 insertions, 31 deletions
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index 5ea52c7616f1..d9ee1a9c5cbe 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -24,6 +24,7 @@
24 24
25#include "rtl2830.h" 25#include "rtl2830.h"
26#include "rtl2832.h" 26#include "rtl2832.h"
27#include "mn88472.h"
27 28
28#include "qt1010.h" 29#include "qt1010.h"
29#include "mt2060.h" 30#include "mt2060.h"
@@ -420,6 +421,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
420 struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf}; 421 struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf};
421 struct rtl28xxu_req req_r820t = {0x0034, CMD_I2C_RD, 1, buf}; 422 struct rtl28xxu_req req_r820t = {0x0034, CMD_I2C_RD, 1, buf};
422 struct rtl28xxu_req req_r828d = {0x0074, CMD_I2C_RD, 1, buf}; 423 struct rtl28xxu_req req_r828d = {0x0074, CMD_I2C_RD, 1, buf};
424 struct rtl28xxu_req req_mn88472 = {0xff38, CMD_I2C_RD, 1, buf};
423 425
424 dev_dbg(&d->udev->dev, "%s:\n", __func__); 426 dev_dbg(&d->udev->dev, "%s:\n", __func__);
425 427
@@ -449,7 +451,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
449 if (ret == 0 && buf[0] == 0xa1) { 451 if (ret == 0 && buf[0] == 0xa1) {
450 priv->tuner = TUNER_RTL2832_FC0012; 452 priv->tuner = TUNER_RTL2832_FC0012;
451 priv->tuner_name = "FC0012"; 453 priv->tuner_name = "FC0012";
452 goto found; 454 goto tuner_found;
453 } 455 }
454 456
455 /* check FC0013 ID register; reg=00 val=a3 */ 457 /* check FC0013 ID register; reg=00 val=a3 */
@@ -457,7 +459,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
457 if (ret == 0 && buf[0] == 0xa3) { 459 if (ret == 0 && buf[0] == 0xa3) {
458 priv->tuner = TUNER_RTL2832_FC0013; 460 priv->tuner = TUNER_RTL2832_FC0013;
459 priv->tuner_name = "FC0013"; 461 priv->tuner_name = "FC0013";
460 goto found; 462 goto tuner_found;
461 } 463 }
462 464
463 /* check MT2266 ID register; reg=00 val=85 */ 465 /* check MT2266 ID register; reg=00 val=85 */
@@ -465,7 +467,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
465 if (ret == 0 && buf[0] == 0x85) { 467 if (ret == 0 && buf[0] == 0x85) {
466 priv->tuner = TUNER_RTL2832_MT2266; 468 priv->tuner = TUNER_RTL2832_MT2266;
467 priv->tuner_name = "MT2266"; 469 priv->tuner_name = "MT2266";
468 goto found; 470 goto tuner_found;
469 } 471 }
470 472
471 /* check FC2580 ID register; reg=01 val=56 */ 473 /* check FC2580 ID register; reg=01 val=56 */
@@ -473,7 +475,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
473 if (ret == 0 && buf[0] == 0x56) { 475 if (ret == 0 && buf[0] == 0x56) {
474 priv->tuner = TUNER_RTL2832_FC2580; 476 priv->tuner = TUNER_RTL2832_FC2580;
475 priv->tuner_name = "FC2580"; 477 priv->tuner_name = "FC2580";
476 goto found; 478 goto tuner_found;
477 } 479 }
478 480
479 /* check MT2063 ID register; reg=00 val=9e || 9c */ 481 /* check MT2063 ID register; reg=00 val=9e || 9c */
@@ -481,7 +483,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
481 if (ret == 0 && (buf[0] == 0x9e || buf[0] == 0x9c)) { 483 if (ret == 0 && (buf[0] == 0x9e || buf[0] == 0x9c)) {
482 priv->tuner = TUNER_RTL2832_MT2063; 484 priv->tuner = TUNER_RTL2832_MT2063;
483 priv->tuner_name = "MT2063"; 485 priv->tuner_name = "MT2063";
484 goto found; 486 goto tuner_found;
485 } 487 }
486 488
487 /* check MAX3543 ID register; reg=00 val=38 */ 489 /* check MAX3543 ID register; reg=00 val=38 */
@@ -489,7 +491,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
489 if (ret == 0 && buf[0] == 0x38) { 491 if (ret == 0 && buf[0] == 0x38) {
490 priv->tuner = TUNER_RTL2832_MAX3543; 492 priv->tuner = TUNER_RTL2832_MAX3543;
491 priv->tuner_name = "MAX3543"; 493 priv->tuner_name = "MAX3543";
492 goto found; 494 goto tuner_found;
493 } 495 }
494 496
495 /* check TUA9001 ID register; reg=7e val=2328 */ 497 /* check TUA9001 ID register; reg=7e val=2328 */
@@ -497,7 +499,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
497 if (ret == 0 && buf[0] == 0x23 && buf[1] == 0x28) { 499 if (ret == 0 && buf[0] == 0x23 && buf[1] == 0x28) {
498 priv->tuner = TUNER_RTL2832_TUA9001; 500 priv->tuner = TUNER_RTL2832_TUA9001;
499 priv->tuner_name = "TUA9001"; 501 priv->tuner_name = "TUA9001";
500 goto found; 502 goto tuner_found;
501 } 503 }
502 504
503 /* check MXL5007R ID register; reg=d9 val=14 */ 505 /* check MXL5007R ID register; reg=d9 val=14 */
@@ -505,7 +507,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
505 if (ret == 0 && buf[0] == 0x14) { 507 if (ret == 0 && buf[0] == 0x14) {
506 priv->tuner = TUNER_RTL2832_MXL5007T; 508 priv->tuner = TUNER_RTL2832_MXL5007T;
507 priv->tuner_name = "MXL5007T"; 509 priv->tuner_name = "MXL5007T";
508 goto found; 510 goto tuner_found;
509 } 511 }
510 512
511 /* check E4000 ID register; reg=02 val=40 */ 513 /* check E4000 ID register; reg=02 val=40 */
@@ -513,7 +515,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
513 if (ret == 0 && buf[0] == 0x40) { 515 if (ret == 0 && buf[0] == 0x40) {
514 priv->tuner = TUNER_RTL2832_E4000; 516 priv->tuner = TUNER_RTL2832_E4000;
515 priv->tuner_name = "E4000"; 517 priv->tuner_name = "E4000";
516 goto found; 518 goto tuner_found;
517 } 519 }
518 520
519 /* check TDA18272 ID register; reg=00 val=c760 */ 521 /* check TDA18272 ID register; reg=00 val=c760 */
@@ -521,7 +523,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
521 if (ret == 0 && (buf[0] == 0xc7 || buf[1] == 0x60)) { 523 if (ret == 0 && (buf[0] == 0xc7 || buf[1] == 0x60)) {
522 priv->tuner = TUNER_RTL2832_TDA18272; 524 priv->tuner = TUNER_RTL2832_TDA18272;
523 priv->tuner_name = "TDA18272"; 525 priv->tuner_name = "TDA18272";
524 goto found; 526 goto tuner_found;
525 } 527 }
526 528
527 /* check R820T ID register; reg=00 val=69 */ 529 /* check R820T ID register; reg=00 val=69 */
@@ -529,7 +531,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
529 if (ret == 0 && buf[0] == 0x69) { 531 if (ret == 0 && buf[0] == 0x69) {
530 priv->tuner = TUNER_RTL2832_R820T; 532 priv->tuner = TUNER_RTL2832_R820T;
531 priv->tuner_name = "R820T"; 533 priv->tuner_name = "R820T";
532 goto found; 534 goto tuner_found;
533 } 535 }
534 536
535 /* check R828D ID register; reg=00 val=69 */ 537 /* check R828D ID register; reg=00 val=69 */
@@ -537,13 +539,37 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
537 if (ret == 0 && buf[0] == 0x69) { 539 if (ret == 0 && buf[0] == 0x69) {
538 priv->tuner = TUNER_RTL2832_R828D; 540 priv->tuner = TUNER_RTL2832_R828D;
539 priv->tuner_name = "R828D"; 541 priv->tuner_name = "R828D";
540 goto found; 542 goto tuner_found;
541 } 543 }
542 544
543 545tuner_found:
544found:
545 dev_dbg(&d->udev->dev, "%s: tuner=%s\n", __func__, priv->tuner_name); 546 dev_dbg(&d->udev->dev, "%s: tuner=%s\n", __func__, priv->tuner_name);
546 547
548 /* probe slave demod */
549 if (priv->tuner == TUNER_RTL2832_R828D) {
550 /* power on MN88472 demod on GPIO0 */
551 ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x01, 0x01);
552 if (ret)
553 goto err;
554
555 ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x01);
556 if (ret)
557 goto err;
558
559 ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x01, 0x01);
560 if (ret)
561 goto err;
562
563 /* check MN88472 answers */
564 ret = rtl28xxu_ctrl_msg(d, &req_mn88472);
565 if (ret == 0 && buf[0] == 0x02) {
566 dev_dbg(&d->udev->dev, "%s: MN88472 found\n", __func__);
567 priv->slave_demod = SLAVE_DEMOD_MN88472;
568 goto demod_found;
569 }
570 }
571
572demod_found:
547 /* close demod I2C gate */ 573 /* close demod I2C gate */
548 ret = rtl28xxu_ctrl_msg(d, &req_gate_close); 574 ret = rtl28xxu_ctrl_msg(d, &req_gate_close);
549 if (ret < 0) 575 if (ret < 0)
@@ -818,7 +844,44 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
818 /* set fe callback */ 844 /* set fe callback */
819 adap->fe[0]->callback = rtl2832u_frontend_callback; 845 adap->fe[0]->callback = rtl2832u_frontend_callback;
820 846
847 if (priv->slave_demod) {
848 struct i2c_board_info info = {};
849 struct i2c_client *client;
850
851 /*
852 * We continue on reduced mode, without DVB-T2/C, using master
853 * demod, when slave demod fails.
854 */
855 ret = 0;
856
857 /* attach slave demodulator */
858 if (priv->slave_demod == SLAVE_DEMOD_MN88472) {
859 struct mn88472_config mn88472_config = {};
860
861 mn88472_config.fe = &adap->fe[1];
862 mn88472_config.i2c_wr_max = 22,
863 strlcpy(info.type, "mn88472", I2C_NAME_SIZE);
864 info.addr = 0x18;
865 info.platform_data = &mn88472_config;
866 request_module(info.type);
867 client = i2c_new_device(priv->demod_i2c_adapter, &info);
868 if (client == NULL || client->dev.driver == NULL) {
869 priv->slave_demod = SLAVE_DEMOD_NONE;
870 goto err_slave_demod_failed;
871 }
872
873 if (!try_module_get(client->dev.driver->owner)) {
874 i2c_unregister_device(client);
875 priv->slave_demod = SLAVE_DEMOD_NONE;
876 goto err_slave_demod_failed;
877 }
878
879 priv->i2c_client_slave_demod = client;
880 }
881 }
882
821 return 0; 883 return 0;
884err_slave_demod_failed:
822err: 885err:
823 dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); 886 dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
824 return ret; 887 return ret;
@@ -1024,25 +1087,19 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
1024 &rtl28xxu_rtl2832_r820t_config, NULL); 1087 &rtl28xxu_rtl2832_r820t_config, NULL);
1025 break; 1088 break;
1026 case TUNER_RTL2832_R828D: 1089 case TUNER_RTL2832_R828D:
1027 /* power off mn88472 demod on GPIO0 */ 1090 fe = dvb_attach(r820t_attach, adap->fe[0],
1028 ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x00, 0x01); 1091 priv->demod_i2c_adapter,
1029 if (ret)
1030 goto err;
1031
1032 ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x01);
1033 if (ret)
1034 goto err;
1035
1036 ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x01, 0x01);
1037 if (ret)
1038 goto err;
1039
1040 fe = dvb_attach(r820t_attach, adap->fe[0], &d->i2c_adap,
1041 &rtl2832u_r828d_config); 1092 &rtl2832u_r828d_config);
1042
1043 /* Use tuner to get the signal strength */
1044 adap->fe[0]->ops.read_signal_strength = 1093 adap->fe[0]->ops.read_signal_strength =
1045 adap->fe[0]->ops.tuner_ops.get_rf_strength; 1094 adap->fe[0]->ops.tuner_ops.get_rf_strength;
1095
1096 if (adap->fe[1]) {
1097 fe = dvb_attach(r820t_attach, adap->fe[1],
1098 priv->demod_i2c_adapter,
1099 &rtl2832u_r828d_config);
1100 adap->fe[1]->ops.read_signal_strength =
1101 adap->fe[1]->ops.tuner_ops.get_rf_strength;
1102 }
1046 break; 1103 break;
1047 default: 1104 default:
1048 dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME, 1105 dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME,
@@ -1097,11 +1154,19 @@ err:
1097static void rtl28xxu_exit(struct dvb_usb_device *d) 1154static void rtl28xxu_exit(struct dvb_usb_device *d)
1098{ 1155{
1099 struct rtl28xxu_priv *priv = d->priv; 1156 struct rtl28xxu_priv *priv = d->priv;
1100 struct i2c_client *client = priv->client; 1157 struct i2c_client *client;
1101 1158
1102 dev_dbg(&d->udev->dev, "%s:\n", __func__); 1159 dev_dbg(&d->udev->dev, "%s:\n", __func__);
1103 1160
1104 /* remove I2C tuner */ 1161 /* remove I2C tuner */
1162 client = priv->client;
1163 if (client) {
1164 module_put(client->dev.driver->owner);
1165 i2c_unregister_device(client);
1166 }
1167
1168 /* remove I2C slave demod */
1169 client = priv->i2c_client_slave_demod;
1105 if (client) { 1170 if (client) {
1106 module_put(client->dev.driver->owner); 1171 module_put(client->dev.driver->owner);
1107 i2c_unregister_device(client); 1172 i2c_unregister_device(client);
@@ -1235,6 +1300,7 @@ err:
1235static int rtl2832u_frontend_ctrl(struct dvb_frontend *fe, int onoff) 1300static int rtl2832u_frontend_ctrl(struct dvb_frontend *fe, int onoff)
1236{ 1301{
1237 struct dvb_usb_device *d = fe_to_d(fe); 1302 struct dvb_usb_device *d = fe_to_d(fe);
1303 struct dvb_usb_adapter *adap = fe_to_adap(fe);
1238 int ret; 1304 int ret;
1239 u8 val; 1305 u8 val;
1240 1306
@@ -1250,6 +1316,13 @@ static int rtl2832u_frontend_ctrl(struct dvb_frontend *fe, int onoff)
1250 if (ret) 1316 if (ret)
1251 goto err; 1317 goto err;
1252 1318
1319 /* bypass slave demod TS through master demod */
1320 if (fe->id == 1 && onoff) {
1321 ret = rtl2832_enable_external_ts_if(adap->fe[0]);
1322 if (ret)
1323 goto err;
1324 }
1325
1253 return 0; 1326 return 0;
1254err: 1327err:
1255 dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); 1328 dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
index a26cab10f382..c1b00b9831c9 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
@@ -58,6 +58,10 @@ struct rtl28xxu_priv {
58 struct i2c_adapter *demod_i2c_adapter; 58 struct i2c_adapter *demod_i2c_adapter;
59 bool rc_active; 59 bool rc_active;
60 struct i2c_client *client; 60 struct i2c_client *client;
61 struct i2c_client *i2c_client_slave_demod;
62 #define SLAVE_DEMOD_NONE 0
63 #define SLAVE_DEMOD_MN88472 1
64 unsigned int slave_demod:1;
61}; 65};
62 66
63enum rtl28xxu_chip_id { 67enum rtl28xxu_chip_id {