Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: dib0700: add support for Xbox One Digital TV Tuner

Xbox One Digital TV Tuner is a low-cost USB 2.0 multistandard TV tuner. It supports DVB-T, DVB-T2 and DVB-C broadcast standards.

USB bridge: DibCom 0700C
Demodulator: Panasonic MN88472
Tuner: TDA18250BHN

The demodulator requires firmware. Download one from here:
http://palosaari.fi/linux/v4l-dvb/firmware/MN88472/02/latest/

Signed-off-by: Olli Salonen <olli.salonen@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>

authored by

Olli Salonen and committed by
Mauro Carvalho Chehab
c4d84547 148abd3b

+139 -2
+2
drivers/media/dvb-core/dvb-usb-ids.h
··· 81 81 #define USB_VID_AZUREWAVE 0x13d3 82 82 #define USB_VID_TECHNISAT 0x14f7 83 83 #define USB_VID_HAMA 0x147f 84 + #define USB_VID_MICROSOFT 0x045e 84 85 85 86 /* Product IDs */ 86 87 #define USB_PID_ADSTECH_USB2_COLD 0xa333 ··· 419 418 #define USB_PID_WINTV_SOLOHD 0x0264 420 419 #define USB_PID_EVOLVEO_XTRATV_STICK 0xa115 421 420 #define USB_PID_HAMA_DVBT_HYBRID 0x2758 421 + #define USB_PID_XBOX_ONE_TUNER 0x02d5 422 422 #endif
+2
drivers/media/usb/dvb-usb/Kconfig
··· 86 86 select DVB_USB_DIB3000MC if MEDIA_SUBDRV_AUTOSELECT 87 87 select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT 88 88 select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT 89 + select DVB_MN88472 if MEDIA_SUBDRV_AUTOSELECT 89 90 select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT 90 91 select DVB_TUNER_DIB0090 if MEDIA_SUBDRV_AUTOSELECT 91 92 select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT ··· 95 94 select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT 96 95 select MEDIA_TUNER_XC4000 if MEDIA_SUBDRV_AUTOSELECT 97 96 select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT 97 + select MEDIA_TUNER_TDA18250 if MEDIA_SUBDRV_AUTOSELECT 98 98 help 99 99 Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The 100 100 USB bridge is also present in devices having the DiB7700 DVB-T-USB
+2
drivers/media/usb/dvb-usb/dib0700.h
··· 51 51 int (*read_status)(struct dvb_frontend *, enum fe_status *); 52 52 int (*sleep)(struct dvb_frontend* fe); 53 53 u8 buf[255]; 54 + struct i2c_client *i2c_client_demod; 55 + struct i2c_client *i2c_client_tuner; 54 56 }; 55 57 56 58 extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
+25 -1
drivers/media/usb/dvb-usb/dib0700_core.c
··· 911 911 return -ENODEV; 912 912 } 913 913 914 + static void dib0700_disconnect(struct usb_interface *intf) 915 + { 916 + struct dvb_usb_device *d = usb_get_intfdata(intf); 917 + struct dib0700_state *st = d->priv; 918 + struct i2c_client *client; 919 + 920 + /* remove I2C client for tuner */ 921 + client = st->i2c_client_tuner; 922 + if (client) { 923 + module_put(client->dev.driver->owner); 924 + i2c_unregister_device(client); 925 + } 926 + 927 + /* remove I2C client for demodulator */ 928 + client = st->i2c_client_demod; 929 + if (client) { 930 + module_put(client->dev.driver->owner); 931 + i2c_unregister_device(client); 932 + } 933 + 934 + dvb_usb_device_exit(intf); 935 + } 936 + 937 + 914 938 static struct usb_driver dib0700_driver = { 915 939 .name = "dvb_usb_dib0700", 916 940 .probe = dib0700_probe, 917 - .disconnect = dvb_usb_device_exit, 941 + .disconnect = dib0700_disconnect, 918 942 .id_table = dib0700_usb_id_table, 919 943 }; 920 944
+108 -1
drivers/media/usb/dvb-usb/dib0700_devices.c
··· 23 23 #include "dib0090.h" 24 24 #include "lgdt3305.h" 25 25 #include "mxl5007t.h" 26 + #include "mn88472.h" 27 + #include "tda18250.h" 28 + 26 29 27 30 static int force_lna_activation; 28 31 module_param(force_lna_activation, int, 0644); ··· 3728 3725 &hcw_mxl5007t_config) == NULL ? -ENODEV : 0; 3729 3726 } 3730 3727 3728 + static int xbox_one_attach(struct dvb_usb_adapter *adap) 3729 + { 3730 + struct dib0700_state *st = adap->dev->priv; 3731 + struct i2c_client *client_demod, *client_tuner; 3732 + struct dvb_usb_device *d = adap->dev; 3733 + struct mn88472_config mn88472_config = { }; 3734 + struct tda18250_config tda18250_config; 3735 + struct i2c_board_info info; 3736 + 3737 + st->fw_use_new_i2c_api = 1; 3738 + st->disable_streaming_master_mode = 1; 3739 + 3740 + /* fe power enable */ 3741 + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); 3742 + msleep(30); 3743 + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); 3744 + msleep(30); 3745 + 3746 + /* demod reset */ 3747 + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); 3748 + msleep(30); 3749 + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); 3750 + msleep(30); 3751 + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); 3752 + msleep(30); 3753 + 3754 + /* attach demod */ 3755 + mn88472_config.fe = &adap->fe_adap[0].fe; 3756 + mn88472_config.i2c_wr_max = 22; 3757 + mn88472_config.xtal = 20500000; 3758 + mn88472_config.ts_mode = PARALLEL_TS_MODE; 3759 + mn88472_config.ts_clock = FIXED_TS_CLOCK; 3760 + memset(&info, 0, sizeof(struct i2c_board_info)); 3761 + strlcpy(info.type, "mn88472", I2C_NAME_SIZE); 3762 + info.addr = 0x18; 3763 + info.platform_data = &mn88472_config; 3764 + request_module(info.type); 3765 + client_demod = i2c_new_device(&d->i2c_adap, &info); 3766 + if (client_demod == NULL || client_demod->dev.driver == NULL) 3767 + goto fail_demod_device; 3768 + if (!try_module_get(client_demod->dev.driver->owner)) 3769 + goto fail_demod_module; 3770 + 3771 + st->i2c_client_demod = client_demod; 3772 + 3773 + adap->fe_adap[0].fe = mn88472_config.get_dvb_frontend(client_demod); 3774 + 3775 + /* attach tuner */ 3776 + memset(&tda18250_config, 0, sizeof(tda18250_config)); 3777 + tda18250_config.if_dvbt_6 = 3950; 3778 + tda18250_config.if_dvbt_7 = 4450; 3779 + tda18250_config.if_dvbt_8 = 4950; 3780 + tda18250_config.if_dvbc_6 = 4950; 3781 + tda18250_config.if_dvbc_8 = 4950; 3782 + tda18250_config.if_atsc = 4079; 3783 + tda18250_config.loopthrough = true; 3784 + tda18250_config.xtal_freq = TDA18250_XTAL_FREQ_27MHZ; 3785 + tda18250_config.fe = adap->fe_adap[0].fe; 3786 + 3787 + memset(&info, 0, sizeof(struct i2c_board_info)); 3788 + strlcpy(info.type, "tda18250", I2C_NAME_SIZE); 3789 + info.addr = 0x60; 3790 + info.platform_data = &tda18250_config; 3791 + 3792 + request_module(info.type); 3793 + client_tuner = i2c_new_device(&adap->dev->i2c_adap, &info); 3794 + if (client_tuner == NULL || client_tuner->dev.driver == NULL) 3795 + goto fail_tuner_device; 3796 + if (!try_module_get(client_tuner->dev.driver->owner)) 3797 + goto fail_tuner_module; 3798 + 3799 + st->i2c_client_tuner = client_tuner; 3800 + return 0; 3801 + 3802 + fail_tuner_module: 3803 + i2c_unregister_device(client_tuner); 3804 + fail_tuner_device: 3805 + module_put(client_demod->dev.driver->owner); 3806 + fail_demod_module: 3807 + i2c_unregister_device(client_demod); 3808 + fail_demod_device: 3809 + return -ENODEV; 3810 + } 3811 + 3731 3812 3732 3813 /* DVB-USB and USB stuff follows */ 3733 3814 struct usb_device_id dib0700_usb_id_table[] = { ··· 3903 3816 { USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_2002E_SE) }, 3904 3817 { USB_DEVICE(USB_VID_PCTV, USB_PID_DIBCOM_STK8096PVR) }, 3905 3818 { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK8096PVR) }, 3906 - { USB_DEVICE(USB_VID_HAMA, USB_PID_HAMA_DVBT_HYBRID) }, 3819 + /* 85 */{ USB_DEVICE(USB_VID_HAMA, USB_PID_HAMA_DVBT_HYBRID) }, 3820 + { USB_DEVICE(USB_VID_MICROSOFT, USB_PID_XBOX_ONE_TUNER) }, 3907 3821 { 0 } /* Terminating entry */ 3908 3822 }; 3909 3823 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); ··· 5127 5039 RC_PROTO_BIT_RC6_MCE | 5128 5040 RC_PROTO_BIT_NEC, 5129 5041 .change_protocol = dib0700_change_protocol, 5042 + }, 5043 + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, 5044 + .num_adapters = 1, 5045 + .adapter = { 5046 + { 5047 + DIB0700_NUM_FRONTENDS(1), 5048 + .fe = {{ 5049 + .frontend_attach = xbox_one_attach, 5050 + 5051 + DIB0700_DEFAULT_STREAMING_CONFIG(0x82), 5052 + } }, 5053 + }, 5054 + }, 5055 + .num_device_descs = 1, 5056 + .devices = { 5057 + { "Microsoft Xbox One Digital TV Tuner", 5058 + { &dib0700_usb_id_table[86], NULL }, 5059 + { NULL }, 5060 + }, 5130 5061 }, 5131 5062 }, 5132 5063 };