diff options
Diffstat (limited to 'drivers/media/dvb')
62 files changed, 6396 insertions, 792 deletions
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c index 48e48e8af55..66f52f116b6 100644 --- a/drivers/media/dvb/bt8xx/dst_ca.c +++ b/drivers/media/dvb/bt8xx/dst_ca.c @@ -477,7 +477,6 @@ static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg) { int i = 0; - unsigned int ca_message_header_len; u32 command = 0; struct ca_msg *hw_buffer; @@ -496,7 +495,6 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, if (p_ca_message->msg) { - ca_message_header_len = p_ca_message->length; /* Restore it back when you are done */ /* EN50221 tag */ command = 0; diff --git a/drivers/media/dvb/ddbridge/ddbridge-core.c b/drivers/media/dvb/ddbridge/ddbridge-core.c index d88c4aa7d24..131b938e9e8 100644 --- a/drivers/media/dvb/ddbridge/ddbridge-core.c +++ b/drivers/media/dvb/ddbridge/ddbridge-core.c @@ -31,7 +31,6 @@ #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/timer.h> -#include <linux/version.h> #include <linux/i2c.h> #include <linux/swab.h> #include <linux/vmalloc.h> @@ -1696,7 +1695,7 @@ static struct pci_driver ddb_pci_driver = { .name = "DDBridge", .id_table = ddb_id_tbl, .probe = ddb_probe, - .remove = ddb_remove, + .remove = __devexit_p(ddb_remove), }; static __init int module_init_ddbridge(void) diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index faa3671b649..d82469f842e 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -568,6 +568,16 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) } EXPORT_SYMBOL(dvb_dmx_swfilter_204); +void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count) +{ + spin_lock(&demux->lock); + + demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts, DMX_OK); + + spin_unlock(&demux->lock); +} +EXPORT_SYMBOL(dvb_dmx_swfilter_raw); + static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux) { int i; diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h index a7d876fd02d..fa7188a253a 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.h +++ b/drivers/media/dvb/dvb-core/dvb_demux.h @@ -145,5 +145,7 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count); void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count); +void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, + size_t count); #endif /* _DVB_DEMUX_H_ */ diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index cb888d835a8..aebcdf221dd 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -182,13 +182,13 @@ static enum dvbv3_emulation_type dvbv3_type(u32 delivery_system) case SYS_DMBTH: return DVBV3_OFDM; case SYS_ATSC: + case SYS_ATSCMH: case SYS_DVBC_ANNEX_B: return DVBV3_ATSC; case SYS_UNDEFINED: case SYS_ISDBC: case SYS_DVBH: case SYS_DAB: - case SYS_ATSCMH: default: /* * Doesn't know how to emulate those types and/or @@ -1030,6 +1030,25 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { _DTV_CMD(DTV_HIERARCHY, 0, 0), _DTV_CMD(DTV_ENUM_DELSYS, 0, 0), + + _DTV_CMD(DTV_ATSCMH_PARADE_ID, 1, 0), + _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 1, 0), + + _DTV_CMD(DTV_ATSCMH_FIC_VER, 0, 0), + _DTV_CMD(DTV_ATSCMH_PARADE_ID, 0, 0), + _DTV_CMD(DTV_ATSCMH_NOG, 0, 0), + _DTV_CMD(DTV_ATSCMH_TNOG, 0, 0), + _DTV_CMD(DTV_ATSCMH_SGN, 0, 0), + _DTV_CMD(DTV_ATSCMH_PRC, 0, 0), + _DTV_CMD(DTV_ATSCMH_RS_FRAME_MODE, 0, 0), + _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 0, 0), + _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_PRI, 0, 0), + _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_SEC, 0, 0), + _DTV_CMD(DTV_ATSCMH_SCCC_BLOCK_MODE, 0, 0), + _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_A, 0, 0), + _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B, 0, 0), + _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C, 0, 0), + _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D, 0, 0), }; static void dtv_property_dump(struct dtv_property *tvp) @@ -1121,6 +1140,8 @@ static int dtv_property_cache_sync(struct dvb_frontend *fe, case DVBV3_ATSC: dprintk("%s() Preparing ATSC req\n", __func__); c->modulation = p->u.vsb.modulation; + if (c->delivery_system == SYS_ATSCMH) + break; if ((c->modulation == VSB_8) || (c->modulation == VSB_16)) c->delivery_system = SYS_ATSC; else @@ -1367,6 +1388,54 @@ static int dtv_property_process_get(struct dvb_frontend *fe, case DTV_DVBT2_PLP_ID: tvp->u.data = c->dvbt2_plp_id; break; + + /* ATSC-MH */ + case DTV_ATSCMH_FIC_VER: + tvp->u.data = fe->dtv_property_cache.atscmh_fic_ver; + break; + case DTV_ATSCMH_PARADE_ID: + tvp->u.data = fe->dtv_property_cache.atscmh_parade_id; + break; + case DTV_ATSCMH_NOG: + tvp->u.data = fe->dtv_property_cache.atscmh_nog; + break; + case DTV_ATSCMH_TNOG: + tvp->u.data = fe->dtv_property_cache.atscmh_tnog; + break; + case DTV_ATSCMH_SGN: + tvp->u.data = fe->dtv_property_cache.atscmh_sgn; + break; + case DTV_ATSCMH_PRC: + tvp->u.data = fe->dtv_property_cache.atscmh_prc; + break; + case DTV_ATSCMH_RS_FRAME_MODE: + tvp->u.data = fe->dtv_property_cache.atscmh_rs_frame_mode; + break; + case DTV_ATSCMH_RS_FRAME_ENSEMBLE: + tvp->u.data = fe->dtv_property_cache.atscmh_rs_frame_ensemble; + break; + case DTV_ATSCMH_RS_CODE_MODE_PRI: + tvp->u.data = fe->dtv_property_cache.atscmh_rs_code_mode_pri; + break; + case DTV_ATSCMH_RS_CODE_MODE_SEC: + tvp->u.data = fe->dtv_property_cache.atscmh_rs_code_mode_sec; + break; + case DTV_ATSCMH_SCCC_BLOCK_MODE: + tvp->u.data = fe->dtv_property_cache.atscmh_sccc_block_mode; + break; + case DTV_ATSCMH_SCCC_CODE_MODE_A: + tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_a; + break; + case DTV_ATSCMH_SCCC_CODE_MODE_B: + tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_b; + break; + case DTV_ATSCMH_SCCC_CODE_MODE_C: + tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_c; + break; + case DTV_ATSCMH_SCCC_CODE_MODE_D: + tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_d; + break; + default: return -EINVAL; } @@ -1708,6 +1777,15 @@ static int dtv_property_process_set(struct dvb_frontend *fe, case DTV_DVBT2_PLP_ID: c->dvbt2_plp_id = tvp->u.data; break; + + /* ATSC-MH */ + case DTV_ATSCMH_PARADE_ID: + fe->dtv_property_cache.atscmh_parade_id = tvp->u.data; + break; + case DTV_ATSCMH_RS_FRAME_ENSEMBLE: + fe->dtv_property_cache.atscmh_rs_frame_ensemble = tvp->u.data; + break; + default: return -EINVAL; } diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index d63a8215fe0..e929d5697b8 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -372,6 +372,24 @@ struct dtv_frontend_properties { /* DVB-T2 specifics */ u32 dvbt2_plp_id; + + /* ATSC-MH specifics */ + u8 atscmh_fic_ver; + u8 atscmh_parade_id; + u8 atscmh_nog; + u8 atscmh_tnog; + u8 atscmh_sgn; + u8 atscmh_prc; + + u8 atscmh_rs_frame_mode; + u8 atscmh_rs_frame_ensemble; + u8 atscmh_rs_code_mode_pri; + u8 atscmh_rs_code_mode_sec; + u8 atscmh_sccc_block_mode; + u8 atscmh_sccc_code_mode_a; + u8 atscmh_sccc_code_mode_b; + u8 atscmh_sccc_code_mode_c; + u8 atscmh_sccc_code_mode_d; }; struct dvb_frontend { diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 63bf45679f9..a26949336b3 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -409,6 +409,7 @@ config DVB_USB_MXL111SF tristate "MxL111SF DTV USB2.0 support" depends on DVB_USB select DVB_LGDT3305 if !DVB_FE_CUSTOMISE + select DVB_LG2160 if !DVB_FE_CUSTOMISE select VIDEO_TVEEPROM help Say Y here to support the MxL111SF USB2.0 DTV receiver. @@ -422,3 +423,15 @@ config DVB_USB_RTL28XXU select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE help Say Y here to support the Realtek RTL28xxU DVB USB receiver. + +config DVB_USB_AF9035 + tristate "Afatech AF9035 DVB-T USB2.0 support" + depends on DVB_USB + select DVB_AF9033 + select MEDIA_TUNER_TUA9001 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_FC0011 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Afatech AF9035 based DVB USB receiver. + diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index b76acb5387e..b667ac39a4e 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -110,6 +110,9 @@ obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o dvb-usb-rtl28xxu-objs = rtl28xxu.o obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o +dvb-usb-af9035-objs = af9035.o +obj-$(CONFIG_DVB_USB_AF9035) += dvb-usb-af9035.o + ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb/frontends/ # due to tuner-xc3028 diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 7e70ea50ef2..677fed79b01 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -244,8 +244,7 @@ static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], u8 uninitialized_var(mbox), addr_len; struct req_t req; -/* TODO: implement bus lock - +/* The bus lock is needed because there is two tuners both using same I2C-address. Due to that the only way to select correct tuner is use demodulator I2C-gate. @@ -789,7 +788,7 @@ static void af9015_set_remote_config(struct usb_device *udev, /* try to load remote based USB ID */ if (!props->rc.core.rc_codes) props->rc.core.rc_codes = af9015_rc_setup_match( - (vid << 16) + pid, af9015_rc_setup_usbids); + (vid << 16) | pid, af9015_rc_setup_usbids); /* try to load remote based USB iManufacturer string */ if (!props->rc.core.rc_codes && vid == USB_VID_AFATECH) { @@ -1220,8 +1219,8 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) } /* attach demodulator */ - adap->fe_adap[0].fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id], - &adap->dev->i2c_adap); + adap->fe_adap[0].fe = dvb_attach(af9013_attach, + &af9015_af9013_config[adap->id], &adap->dev->i2c_adap); /* * AF9015 firmware does not like if it gets interrupted by I2C adapter @@ -1324,14 +1323,15 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) switch (af9015_af9013_config[adap->id].tuner) { case AF9013_TUNER_MT2060: case AF9013_TUNER_MT2060_2: - ret = dvb_attach(mt2060_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, - &af9015_mt2060_config, + ret = dvb_attach(mt2060_attach, adap->fe_adap[0].fe, + &adap->dev->i2c_adap, &af9015_mt2060_config, af9015_config.mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_QT1010: case AF9013_TUNER_QT1010A: - ret = dvb_attach(qt1010_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, + ret = dvb_attach(qt1010_attach, adap->fe_adap[0].fe, + &adap->dev->i2c_adap, &af9015_qt1010_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18271: @@ -1434,69 +1434,85 @@ enum af9015_usb_table_entry { }; static struct usb_device_id af9015_usb_table[] = { - [AFATECH_9015] = - {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015)}, - [AFATECH_9016] = - {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016)}, - [WINFAST_DTV_GOLD] = - {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD)}, - [PINNACLE_PCTV_71E] = - {USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E)}, - [KWORLD_PLUSTV_399U] = - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U)}, - [TINYTWIN] = {USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN)}, - [AZUREWAVE_TU700] = - {USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700)}, - [TERRATEC_AF9015] = {USB_DEVICE(USB_VID_TERRATEC, + [AFATECH_9015] = { + USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015)}, + [AFATECH_9016] = { + USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016)}, + [WINFAST_DTV_GOLD] = { + USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD)}, + [PINNACLE_PCTV_71E] = { + USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E)}, + [KWORLD_PLUSTV_399U] = { + USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U)}, + [TINYTWIN] = { + USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN)}, + [AZUREWAVE_TU700] = { + USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700)}, + [TERRATEC_AF9015] = { + USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2)}, - [KWORLD_PLUSTV_PC160] = - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T)}, - [AVERTV_VOLAR_X] = - {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)}, - [XTENSIONS_380U] = - {USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)}, - [MSI_DIGIVOX_DUO] = - {USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)}, - [AVERTV_VOLAR_X_REV2] = - {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)}, - [TELESTAR_STARSTICK_2] = - {USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2)}, - [AVERMEDIA_A309_USB] = - {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)}, - [MSI_DIGIVOX_MINI_III] = - {USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)}, - [KWORLD_E396] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)}, - [KWORLD_E39B] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2)}, - [KWORLD_E395] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3)}, - [TREKSTOR_DVBT] = {USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT)}, - [AVERTV_A850] = {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)}, - [AVERTV_A805] = {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)}, - [CONCEPTRONIC_CTVDIGRCU] = - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU)}, - [KWORLD_MC810] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)}, - [GENIUS_TVGO_DVB_T03] = - {USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03)}, - [KWORLD_399U_2] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2)}, - [KWORLD_PC160_T] = - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T)}, - [SVEON_STV20] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20)}, - [TINYTWIN_2] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2)}, - [WINFAST_DTV2000DS] = - {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)}, - [KWORLD_UB383_T] = - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)}, - [KWORLD_E39A] = - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)}, - [AVERMEDIA_A815M] = - {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)}, - [CINERGY_T_STICK_RC] = {USB_DEVICE(USB_VID_TERRATEC, + [KWORLD_PLUSTV_PC160] = { + USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T)}, + [AVERTV_VOLAR_X] = { + USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)}, + [XTENSIONS_380U] = { + USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)}, + [MSI_DIGIVOX_DUO] = { + USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)}, + [AVERTV_VOLAR_X_REV2] = { + USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)}, + [TELESTAR_STARSTICK_2] = { + USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2)}, + [AVERMEDIA_A309_USB] = { + USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)}, + [MSI_DIGIVOX_MINI_III] = { + USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)}, + [KWORLD_E396] = { + USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)}, + [KWORLD_E39B] = { + USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2)}, + [KWORLD_E395] = { + USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3)}, + [TREKSTOR_DVBT] = { + USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT)}, + [AVERTV_A850] = { + USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)}, + [AVERTV_A805] = { + USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)}, + [CONCEPTRONIC_CTVDIGRCU] = { + USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU)}, + [KWORLD_MC810] = { + USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)}, + [GENIUS_TVGO_DVB_T03] = { + USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03)}, + [KWORLD_399U_2] = { + USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2)}, + [KWORLD_PC160_T] = { + USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T)}, + [SVEON_STV20] = { + USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20)}, + [TINYTWIN_2] = { + USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2)}, + [WINFAST_DTV2000DS] = { + USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)}, + [KWORLD_UB383_T] = { + USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)}, + [KWORLD_E39A] = { + USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)}, + [AVERMEDIA_A815M] = { + USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)}, + [CINERGY_T_STICK_RC] = { + USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC)}, - [CINERGY_T_DUAL_RC] = {USB_DEVICE(USB_VID_TERRATEC, + [CINERGY_T_DUAL_RC] = { + USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)}, - [AVERTV_A850T] = - {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)}, - [TINYTWIN_3] = {USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3)}, - [SVEON_STV22] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22)}, + [AVERTV_A850T] = { + USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)}, + [TINYTWIN_3] = { + USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3)}, + [SVEON_STV22] = { + USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22)}, { } }; MODULE_DEVICE_TABLE(usb, af9015_usb_table); @@ -1516,43 +1532,44 @@ static struct dvb_usb_device_properties af9015_properties[] = { .num_adapters = 2, .adapter = { { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - - .pid_filter_count = 32, - .pid_filter = af9015_pid_filter, - .pid_filter_ctrl = af9015_pid_filter_ctrl, - - .frontend_attach = - af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x84, + .num_frontends = 1, + .fe = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 32, + .pid_filter = af9015_pid_filter, + .pid_filter_ctrl = af9015_pid_filter_ctrl, + + .frontend_attach = af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x84, + }, + } }, - }}, }, { - .num_frontends = 1, - .fe = {{ - .frontend_attach = - af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x85, - .u = { - .bulk = { - .buffersize = - TS_USB20_FRAME_SIZE, - } + .num_frontends = 1, + .fe = { + { + .frontend_attach = af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x85, + .u = { + .bulk = { + .buffersize = TS_USB20_FRAME_SIZE, + } + } + }, } }, - }}, } }, @@ -1575,102 +1592,67 @@ static struct dvb_usb_device_properties af9015_properties[] = { .cold_ids = { &af9015_usb_table[AFATECH_9015], &af9015_usb_table[AFATECH_9016], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "Leadtek WinFast DTV Dongle Gold", .cold_ids = { &af9015_usb_table[WINFAST_DTV_GOLD], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "Pinnacle PCTV 71e", .cold_ids = { &af9015_usb_table[PINNACLE_PCTV_71E], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "KWorld PlusTV Dual DVB-T Stick " \ "(DVB-T 399U)", .cold_ids = { &af9015_usb_table[KWORLD_PLUSTV_399U], &af9015_usb_table[KWORLD_399U_2], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "DigitalNow TinyTwin DVB-T Receiver", .cold_ids = { &af9015_usb_table[TINYTWIN], &af9015_usb_table[TINYTWIN_2], &af9015_usb_table[TINYTWIN_3], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "TwinHan AzureWave AD-TU700(704J)", .cold_ids = { &af9015_usb_table[AZUREWAVE_TU700], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "TerraTec Cinergy T USB XE", .cold_ids = { &af9015_usb_table[TERRATEC_AF9015], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "KWorld PlusTV Dual DVB-T PCI " \ "(DVB-T PC160-2T)", .cold_ids = { &af9015_usb_table[KWORLD_PLUSTV_PC160], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "AVerMedia AVerTV DVB-T Volar X", .cold_ids = { &af9015_usb_table[AVERTV_VOLAR_X], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "TerraTec Cinergy T Stick RC", .cold_ids = { &af9015_usb_table[CINERGY_T_STICK_RC], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "TerraTec Cinergy T Stick Dual RC", .cold_ids = { &af9015_usb_table[CINERGY_T_DUAL_RC], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "AverMedia AVerTV Red HD+ (A850T)", .cold_ids = { &af9015_usb_table[AVERTV_A850T], - NULL }, - .warm_ids = {NULL}, }, } }, { @@ -1686,43 +1668,44 @@ static struct dvb_usb_device_properties af9015_properties[] = { .num_adapters = 2, .adapter = { { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - - .pid_filter_count = 32, - .pid_filter = af9015_pid_filter, - .pid_filter_ctrl = af9015_pid_filter_ctrl, - - .frontend_attach = - af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x84, + .num_frontends = 1, + .fe = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 32, + .pid_filter = af9015_pid_filter, + .pid_filter_ctrl = af9015_pid_filter_ctrl, + + .frontend_attach = af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x84, + }, + } }, - }}, }, { - .num_frontends = 1, - .fe = {{ - .frontend_attach = - af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x85, - .u = { - .bulk = { - .buffersize = - TS_USB20_FRAME_SIZE, - } + .num_frontends = 1, + .fe = { + { + .frontend_attach = af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x85, + .u = { + .bulk = { + .buffersize = TS_USB20_FRAME_SIZE, + } + } + }, } }, - }}, } }, @@ -1744,51 +1727,33 @@ static struct dvb_usb_device_properties af9015_properties[] = { .name = "Xtensions XD-380", .cold_ids = { &af9015_usb_table[XTENSIONS_380U], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "MSI DIGIVOX Duo", .cold_ids = { &af9015_usb_table[MSI_DIGIVOX_DUO], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "Fujitsu-Siemens Slim Mobile USB DVB-T", .cold_ids = { &af9015_usb_table[AVERTV_VOLAR_X_REV2], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "Telestar Starstick 2", .cold_ids = { &af9015_usb_table[TELESTAR_STARSTICK_2], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "AVerMedia A309", .cold_ids = { &af9015_usb_table[AVERMEDIA_A309_USB], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "MSI Digi VOX mini III", .cold_ids = { &af9015_usb_table[MSI_DIGIVOX_MINI_III], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "KWorld USB DVB-T TV Stick II " \ "(VS-DVB-T 395U)", .cold_ids = { @@ -1796,34 +1761,23 @@ static struct dvb_usb_device_properties af9015_properties[] = { &af9015_usb_table[KWORLD_E39B], &af9015_usb_table[KWORLD_E395], &af9015_usb_table[KWORLD_E39A], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "TrekStor DVB-T USB Stick", .cold_ids = { &af9015_usb_table[TREKSTOR_DVBT], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "AverMedia AVerTV Volar Black HD " \ "(A850)", .cold_ids = { &af9015_usb_table[AVERTV_A850], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "Sveon STV22 Dual USB DVB-T Tuner HDTV", .cold_ids = { &af9015_usb_table[SVEON_STV22], - NULL }, - .warm_ids = {NULL}, }, } }, { @@ -1839,43 +1793,44 @@ static struct dvb_usb_device_properties af9015_properties[] = { .num_adapters = 2, .adapter = { { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - - .pid_filter_count = 32, - .pid_filter = af9015_pid_filter, - .pid_filter_ctrl = af9015_pid_filter_ctrl, - - .frontend_attach = - af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x84, + .num_frontends = 1, + .fe = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 32, + .pid_filter = af9015_pid_filter, + .pid_filter_ctrl = af9015_pid_filter_ctrl, + + .frontend_attach = af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x84, + }, + } }, - }}, }, { - .num_frontends = 1, - .fe = {{ - .frontend_attach = - af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x85, - .u = { - .bulk = { - .buffersize = - TS_USB20_FRAME_SIZE, - } + .num_frontends = 1, + .fe = { + { + .frontend_attach = af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x85, + .u = { + .bulk = { + .buffersize = TS_USB20_FRAME_SIZE, + } + } + }, } }, - }}, } }, @@ -1897,76 +1852,50 @@ static struct dvb_usb_device_properties af9015_properties[] = { .name = "AverMedia AVerTV Volar GPS 805 (A805)", .cold_ids = { &af9015_usb_table[AVERTV_A805], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "Conceptronic USB2.0 DVB-T CTVDIGRCU " \ "V3.0", .cold_ids = { &af9015_usb_table[CONCEPTRONIC_CTVDIGRCU], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "KWorld Digial MC-810", .cold_ids = { &af9015_usb_table[KWORLD_MC810], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "Genius TVGo DVB-T03", .cold_ids = { &af9015_usb_table[GENIUS_TVGO_DVB_T03], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "KWorld PlusTV DVB-T PCI Pro Card " \ "(DVB-T PC160-T)", .cold_ids = { &af9015_usb_table[KWORLD_PC160_T], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "Sveon STV20 Tuner USB DVB-T HDTV", .cold_ids = { &af9015_usb_table[SVEON_STV20], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "Leadtek WinFast DTV2000DS", .cold_ids = { &af9015_usb_table[WINFAST_DTV2000DS], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "KWorld USB DVB-T Stick Mobile " \ "(UB383-T)", .cold_ids = { &af9015_usb_table[KWORLD_UB383_T], - NULL }, - .warm_ids = {NULL}, - }, - { + }, { .name = "AverMedia AVerTV Volar M (A815Mac)", .cold_ids = { &af9015_usb_table[AVERMEDIA_A815M], - NULL }, - .warm_ids = {NULL}, }, } }, @@ -2019,5 +1948,5 @@ static struct usb_driver af9015_usb_driver = { module_usb_driver(af9015_usb_driver); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); -MODULE_DESCRIPTION("Driver for Afatech AF9015 DVB-T"); +MODULE_DESCRIPTION("Afatech AF9015 driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/af9035.c b/drivers/media/dvb/dvb-usb/af9035.c new file mode 100644 index 00000000000..e83b39d3993 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/af9035.c @@ -0,0 +1,1242 @@ +/* + * Afatech AF9035 DVB USB driver + * + * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> + * Copyright (C) 2012 Antti Palosaari <crope@iki.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "af9035.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); +static DEFINE_MUTEX(af9035_usb_mutex); +static struct dvb_usb_device_properties af9035_properties[2]; +static int af9035_properties_count = ARRAY_SIZE(af9035_properties); + +static u16 af9035_checksum(const u8 *buf, size_t len) +{ + size_t i; + u16 checksum = 0; + + for (i = 1; i < len; i++) { + if (i % 2) + checksum += buf[i] << 8; + else + checksum += buf[i]; + } + checksum = ~checksum; + + return checksum; +} + +static int af9035_ctrl_msg(struct usb_device *udev, struct usb_req *req) +{ +#define BUF_LEN 64 +#define REQ_HDR_LEN 4 /* send header size */ +#define ACK_HDR_LEN 3 /* rece header size */ +#define CHECKSUM_LEN 2 +#define USB_TIMEOUT 2000 + + int ret, msg_len, act_len; + u8 buf[BUF_LEN]; + static u8 seq; /* packet sequence number */ + u16 checksum, tmp_checksum; + + /* buffer overflow check */ + if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) || + req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) { + pr_debug("%s: too much data wlen=%d rlen=%d\n", __func__, + req->wlen, req->rlen); + return -EINVAL; + } + + if (mutex_lock_interruptible(&af9035_usb_mutex) < 0) + return -EAGAIN; + + buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1; + buf[1] = req->mbox; + buf[2] = req->cmd; + buf[3] = seq++; + if (req->wlen) + memcpy(&buf[4], req->wbuf, req->wlen); + + /* calc and add checksum */ + checksum = af9035_checksum(buf, buf[0] - 1); + buf[buf[0] - 1] = (checksum >> 8); + buf[buf[0] - 0] = (checksum & 0xff); + + msg_len = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN ; + + /* send req */ + ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len, + &act_len, USB_TIMEOUT); + if (ret < 0) + err("bulk message failed=%d (%d/%d)", ret, msg_len, act_len); + else + if (act_len != msg_len) + ret = -EIO; /* all data is not send */ + if (ret < 0) + goto err_mutex_unlock; + + /* no ack for those packets */ + if (req->cmd == CMD_FW_DL) + goto exit_mutex_unlock; + + /* receive ack and data if read req */ + msg_len = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN; + ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len, + &act_len, USB_TIMEOUT); + if (ret < 0) { + err("recv bulk message failed=%d", ret); + ret = -EIO; + goto err_mutex_unlock; + } + + if (act_len != msg_len) { + err("recv bulk message truncated (%d != %d)", act_len, msg_len); + ret = -EIO; + goto err_mutex_unlock; + } + + /* verify checksum */ + checksum = af9035_checksum(buf, act_len - 2); + tmp_checksum = (buf[act_len - 2] << 8) | buf[act_len - 1]; + if (tmp_checksum != checksum) { + err("%s: command=%02x checksum mismatch (%04x != %04x)", + __func__, req->cmd, tmp_checksum, checksum); + ret = -EIO; + goto err_mutex_unlock; + } + + /* check status */ + if (buf[2]) { + pr_debug("%s: command=%02x failed fw error=%d\n", __func__, + req->cmd, buf[2]); + ret = -EIO; + goto err_mutex_unlock; + } + + /* read request, copy returned data to return buf */ + if (req->rlen) + memcpy(req->rbuf, &buf[ACK_HDR_LEN], req->rlen); + +err_mutex_unlock: +exit_mutex_unlock: + mutex_unlock(&af9035_usb_mutex); + + return ret; +} + +/* write multiple registers */ +static int af9035_wr_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len) +{ + u8 wbuf[6 + len]; + u8 mbox = (reg >> 16) & 0xff; + struct usb_req req = { CMD_MEM_WR, mbox, sizeof(wbuf), wbuf, 0, NULL }; + + wbuf[0] = len; + wbuf[1] = 2; + wbuf[2] = 0; + wbuf[3] = 0; + wbuf[4] = (reg >> 8) & 0xff; + wbuf[5] = (reg >> 0) & 0xff; + memcpy(&wbuf[6], val, len); + + return af9035_ctrl_msg(d->udev, &req); +} + +/* read multiple registers */ +static int af9035_rd_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len) +{ + u8 wbuf[] = { len, 2, 0, 0, (reg >> 8) & 0xff, reg & 0xff }; + u8 mbox = (reg >> 16) & 0xff; + struct usb_req req = { CMD_MEM_RD, mbox, sizeof(wbuf), wbuf, len, val }; + + return af9035_ctrl_msg(d->udev, &req); +} + +/* write single register */ +static int af9035_wr_reg(struct dvb_usb_device *d, u32 reg, u8 val) +{ + return af9035_wr_regs(d, reg, &val, 1); +} + +/* read single register */ +static int af9035_rd_reg(struct dvb_usb_device *d, u32 reg, u8 *val) +{ + return af9035_rd_regs(d, reg, val, 1); +} + +/* write single register with mask */ +static int af9035_wr_reg_mask(struct dvb_usb_device *d, u32 reg, u8 val, + u8 mask) +{ + int ret; + u8 tmp; + + /* no need for read if whole reg is written */ + if (mask != 0xff) { + ret = af9035_rd_regs(d, reg, &tmp, 1); + if (ret) + return ret; + + val &= mask; + tmp &= ~mask; + val |= tmp; + } + + return af9035_wr_regs(d, reg, &val, 1); +} + +static int af9035_i2c_master_xfer(struct i2c_adapter *adap, + struct i2c_msg msg[], int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct state *state = d->priv; + int ret; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + /* + * I2C sub header is 5 bytes long. Meaning of those bytes are: + * 0: data len + * 1: I2C addr << 1 + * 2: reg addr len + * byte 3 and 4 can be used as reg addr + * 3: reg addr MSB + * used when reg addr len is set to 2 + * 4: reg addr LSB + * used when reg addr len is set to 1 or 2 + * + * For the simplify we do not use register addr at all. + * NOTE: As a firmware knows tuner type there is very small possibility + * there could be some tuner I2C hacks done by firmware and this may + * lead problems if firmware expects those bytes are used. + */ + if (num == 2 && !(msg[0].flags & I2C_M_RD) && + (msg[1].flags & I2C_M_RD)) { + if (msg[0].len > 40 || msg[1].len > 40) { + /* TODO: correct limits > 40 */ + ret = -EOPNOTSUPP; + } else if (msg[0].addr == state->af9033_config[0].i2c_addr) { + /* integrated demod */ + u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | + msg[0].buf[2]; + ret = af9035_rd_regs(d, reg, &msg[1].buf[0], + msg[1].len); + } else { + /* I2C */ + u8 buf[5 + msg[0].len]; + struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf), + buf, msg[1].len, msg[1].buf }; + buf[0] = msg[1].len; + buf[1] = msg[0].addr << 1; + buf[2] = 0x00; /* reg addr len */ + buf[3] = 0x00; /* reg addr MSB */ + buf[4] = 0x00; /* reg addr LSB */ + memcpy(&buf[5], msg[0].buf, msg[0].len); + ret = af9035_ctrl_msg(d->udev, &req); + } + } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) { + if (msg[0].len > 40) { + /* TODO: correct limits > 40 */ + ret = -EOPNOTSUPP; + } else if (msg[0].addr == state->af9033_config[0].i2c_addr) { + /* integrated demod */ + u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | + msg[0].buf[2]; + ret = af9035_wr_regs(d, reg, &msg[0].buf[3], + msg[0].len - 3); + } else { + /* I2C */ + u8 buf[5 + msg[0].len]; + struct usb_req req = { CMD_I2C_WR, 0, sizeof(buf), buf, + 0, NULL }; + buf[0] = msg[0].len; + buf[1] = msg[0].addr << 1; + buf[2] = 0x00; /* reg addr len */ + buf[3] = 0x00; /* reg addr MSB */ + buf[4] = 0x00; /* reg addr LSB */ + memcpy(&buf[5], msg[0].buf, msg[0].len); + ret = af9035_ctrl_msg(d->udev, &req); + } + } else { + /* + * We support only two kind of I2C transactions: + * 1) 1 x read + 1 x write + * 2) 1 x write + */ + ret = -EOPNOTSUPP; + } + + mutex_unlock(&d->i2c_mutex); + + if (ret < 0) + return ret; + else + return num; +} + +static u32 af9035_i2c_functionality(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm af9035_i2c_algo = { + .master_xfer = af9035_i2c_master_xfer, + .functionality = af9035_i2c_functionality, +}; + +#define AF9035_POLL 250 +static int af9035_rc_query(struct dvb_usb_device *d) +{ + unsigned int key; + unsigned char b[4]; + int ret; + struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, b }; + + ret = af9035_ctrl_msg(d->udev, &req); + if (ret < 0) + goto err; + + if ((b[2] + b[3]) == 0xff) { + if ((b[0] + b[1]) == 0xff) { + /* NEC */ + key = b[0] << 8 | b[2]; + } else { + /* ext. NEC */ + key = b[0] << 16 | b[1] << 8 | b[2]; + } + } else { + key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3]; + } + + rc_keydown(d->rc_dev, key, 0); + +err: + /* ignore errors */ + return 0; +} + +static int af9035_init(struct dvb_usb_device *d) +{ + struct state *state = d->priv; + int ret, i; + u16 frame_size = 87 * 188 / 4; + u8 packet_size = 512 / 4; + struct reg_val_mask tab[] = { + { 0x80f99d, 0x01, 0x01 }, + { 0x80f9a4, 0x01, 0x01 }, + { 0x00dd11, 0x00, 0x20 }, + { 0x00dd11, 0x00, 0x40 }, + { 0x00dd13, 0x00, 0x20 }, + { 0x00dd13, 0x00, 0x40 }, + { 0x00dd11, 0x20, 0x20 }, + { 0x00dd88, (frame_size >> 0) & 0xff, 0xff}, + { 0x00dd89, (frame_size >> 8) & 0xff, 0xff}, + { 0x00dd0c, packet_size, 0xff}, + { 0x00dd11, state->dual_mode << 6, 0x40 }, + { 0x00dd8a, (frame_size >> 0) & 0xff, 0xff}, + { 0x00dd8b, (frame_size >> 8) & 0xff, 0xff}, + { 0x00dd0d, packet_size, 0xff }, + { 0x80f9a3, 0x00, 0x01 }, + { 0x80f9cd, 0x00, 0x01 }, + { 0x80f99d, 0x00, 0x01 }, + { 0x80f9a4, 0x00, 0x01 }, + }; + + pr_debug("%s: USB speed=%d frame_size=%04x packet_size=%02x\n", + __func__, d->udev->speed, frame_size, packet_size); + + /* init endpoints */ + for (i = 0; i < ARRAY_SIZE(tab); i++) { + ret = af9035_wr_reg_mask(d, tab[i].reg, tab[i].val, + tab[i].mask); + if (ret < 0) + goto err; + } + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) +{ + int ret; + u8 wbuf[1] = { 1 }; + u8 rbuf[4]; + struct usb_req req = { CMD_FW_QUERYINFO, 0, sizeof(wbuf), wbuf, + sizeof(rbuf), rbuf }; + + ret = af9035_ctrl_msg(udev, &req); + if (ret < 0) + goto err; + + pr_debug("%s: reply=%02x %02x %02x %02x\n", __func__, + rbuf[0], rbuf[1], rbuf[2], rbuf[3]); + if (rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3]) + *cold = 0; + else + *cold = 1; + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_download_firmware(struct usb_device *udev, + const struct firmware *fw) +{ + int ret, i, j, len; + u8 wbuf[1]; + u8 rbuf[4]; + struct usb_req req = { 0, 0, 0, NULL, 0, NULL }; + struct usb_req req_fw_dl = { CMD_FW_DL, 0, 0, wbuf, 0, NULL }; + struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ; + u8 hdr_core; + u16 hdr_addr, hdr_data_len, hdr_checksum; + #define MAX_DATA 58 + #define HDR_SIZE 7 + + /* + * Thanks to Daniel Glöckner <daniel-gl@gmx.net> about that info! + * + * byte 0: MCS 51 core + * There are two inside the AF9035 (1=Link and 2=OFDM) with separate + * address spaces + * byte 1-2: Big endian destination address + * byte 3-4: Big endian number of data bytes following the header + * byte 5-6: Big endian header checksum, apparently ignored by the chip + * Calculated as ~(h[0]*256+h[1]+h[2]*256+h[3]+h[4]*256) + */ + + for (i = fw->size; i > HDR_SIZE;) { + hdr_core = fw->data[fw->size - i + 0]; + hdr_addr = fw->data[fw->size - i + 1] << 8; + hdr_addr |= fw->data[fw->size - i + 2] << 0; + hdr_data_len = fw->data[fw->size - i + 3] << 8; + hdr_data_len |= fw->data[fw->size - i + 4] << 0; + hdr_checksum = fw->data[fw->size - i + 5] << 8; + hdr_checksum |= fw->data[fw->size - i + 6] << 0; + + pr_debug("%s: core=%d addr=%04x data_len=%d checksum=%04x\n", + __func__, hdr_core, hdr_addr, hdr_data_len, + hdr_checksum); + + if (((hdr_core != 1) && (hdr_core != 2)) || + (hdr_data_len > i)) { + pr_debug("%s: bad firmware\n", __func__); + break; + } + + /* download begin packet */ + req.cmd = CMD_FW_DL_BEGIN; + ret = af9035_ctrl_msg(udev, &req); + if (ret < 0) + goto err; + + /* download firmware packet(s) */ + for (j = HDR_SIZE + hdr_data_len; j > 0; j -= MAX_DATA) { + len = j; + if (len > MAX_DATA) + len = MAX_DATA; + req_fw_dl.wlen = len; + req_fw_dl.wbuf = (u8 *) &fw->data[fw->size - i + + HDR_SIZE + hdr_data_len - j]; + ret = af9035_ctrl_msg(udev, &req_fw_dl); + if (ret < 0) + goto err; + } + + /* download end packet */ + req.cmd = CMD_FW_DL_END; + ret = af9035_ctrl_msg(udev, &req); + if (ret < 0) + goto err; + + i -= hdr_data_len + HDR_SIZE; + + pr_debug("%s: data uploaded=%zu\n", __func__, fw->size - i); + } + + /* firmware loaded, request boot */ + req.cmd = CMD_FW_BOOT; + ret = af9035_ctrl_msg(udev, &req); + if (ret < 0) + goto err; + + /* ensure firmware starts */ + wbuf[0] = 1; + ret = af9035_ctrl_msg(udev, &req_fw_ver); + if (ret < 0) + goto err; + + if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) { + info("firmware did not run"); + ret = -ENODEV; + goto err; + } + + info("firmware version=%d.%d.%d.%d", rbuf[0], rbuf[1], rbuf[2], + rbuf[3]); + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_download_firmware_it9135(struct usb_device *udev, + const struct firmware *fw) +{ + int ret, i, i_prev; + u8 wbuf[1]; + u8 rbuf[4]; + struct usb_req req = { 0, 0, 0, NULL, 0, NULL }; + struct usb_req req_fw_dl = { CMD_FW_SCATTER_WR, 0, 0, NULL, 0, NULL }; + struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ; + #define HDR_SIZE 7 + + /* + * There seems to be following firmware header. Meaning of bytes 0-3 + * is unknown. + * + * 0: 3 + * 1: 0, 1 + * 2: 0 + * 3: 1, 2, 3 + * 4: addr MSB + * 5: addr LSB + * 6: count of data bytes ? + */ + + for (i = HDR_SIZE, i_prev = 0; i <= fw->size; i++) { + if (i == fw->size || + (fw->data[i + 0] == 0x03 && + (fw->data[i + 1] == 0x00 || + fw->data[i + 1] == 0x01) && + fw->data[i + 2] == 0x00)) { + req_fw_dl.wlen = i - i_prev; + req_fw_dl.wbuf = (u8 *) &fw->data[i_prev]; + i_prev = i; + ret = af9035_ctrl_msg(udev, &req_fw_dl); + if (ret < 0) + goto err; + + pr_debug("%s: data uploaded=%d\n", __func__, i); + } + } + + /* firmware loaded, request boot */ + req.cmd = CMD_FW_BOOT; + ret = af9035_ctrl_msg(udev, &req); + if (ret < 0) + goto err; + + /* ensure firmware starts */ + wbuf[0] = 1; + ret = af9035_ctrl_msg(udev, &req_fw_ver); + if (ret < 0) + goto err; + + if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) { + info("firmware did not run"); + ret = -ENODEV; + goto err; + } + + info("firmware version=%d.%d.%d.%d", rbuf[0], rbuf[1], rbuf[2], + rbuf[3]); + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +/* abuse that callback as there is no better one for reading eeprom */ +static int af9035_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) +{ + struct state *state = d->priv; + int ret, i, eeprom_shift = 0; + u8 tmp; + u16 tmp16; + + /* check if there is dual tuners */ + ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp); + if (ret < 0) + goto err; + + state->dual_mode = tmp; + pr_debug("%s: dual mode=%d\n", __func__, state->dual_mode); + + for (i = 0; i < af9035_properties[0].num_adapters; i++) { + /* tuner */ + ret = af9035_rd_reg(d, EEPROM_1_TUNER_ID + eeprom_shift, &tmp); + if (ret < 0) + goto err; + + state->af9033_config[i].tuner = tmp; + pr_debug("%s: [%d]tuner=%02x\n", __func__, i, tmp); + + switch (tmp) { + case AF9033_TUNER_TUA9001: + case AF9033_TUNER_FC0011: + case AF9033_TUNER_MXL5007T: + case AF9033_TUNER_TDA18218: + state->af9033_config[i].spec_inv = 1; + break; + default: + warn("tuner ID=%02x not supported, please report!", + tmp); + }; + + /* tuner IF frequency */ + ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_L + eeprom_shift, &tmp); + if (ret < 0) + goto err; + + tmp16 = tmp; + + ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_H + eeprom_shift, &tmp); + if (ret < 0) + goto err; + + tmp16 |= tmp << 8; + + pr_debug("%s: [%d]IF=%d\n", __func__, i, tmp16); + + eeprom_shift = 0x10; /* shift for the 2nd tuner params */ + } + + /* get demod clock */ + ret = af9035_rd_reg(d, 0x00d800, &tmp); + if (ret < 0) + goto err; + + tmp = (tmp >> 0) & 0x0f; + + for (i = 0; i < af9035_properties[0].num_adapters; i++) + state->af9033_config[i].clock = clock_lut[tmp]; + + ret = af9035_rd_reg(d, EEPROM_IR_MODE, &tmp); + if (ret < 0) + goto err; + pr_debug("%s: ir_mode=%02x\n", __func__, tmp); + + /* don't activate rc if in HID mode or if not available */ + if (tmp == 5) { + ret = af9035_rd_reg(d, EEPROM_IR_TYPE, &tmp); + if (ret < 0) + goto err; + pr_debug("%s: ir_type=%02x\n", __func__, tmp); + + switch (tmp) { + case 0: /* NEC */ + default: + d->props.rc.core.protocol = RC_TYPE_NEC; + d->props.rc.core.allowed_protos = RC_TYPE_NEC; + break; + case 1: /* RC6 */ + d->props.rc.core.protocol = RC_TYPE_RC6; + d->props.rc.core.allowed_protos = RC_TYPE_RC6; + break; + } + d->props.rc.core.rc_query = af9035_rc_query; + } + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +/* abuse that callback as there is no better one for reading eeprom */ +static int af9035_read_mac_address_it9135(struct dvb_usb_device *d, u8 mac[6]) +{ + struct state *state = d->priv; + int ret, i; + u8 tmp; + + state->dual_mode = false; + + /* get demod clock */ + ret = af9035_rd_reg(d, 0x00d800, &tmp); + if (ret < 0) + goto err; + + tmp = (tmp >> 0) & 0x0f; + + for (i = 0; i < af9035_properties[0].num_adapters; i++) + state->af9033_config[i].clock = clock_lut_it9135[tmp]; + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_fc0011_tuner_callback(struct dvb_usb_device *d, + int cmd, int arg) +{ + int ret; + + switch (cmd) { + case FC0011_FE_CALLBACK_POWER: + /* Tuner enable */ + ret = af9035_wr_reg_mask(d, 0xd8eb, 1, 1); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0xd8ec, 1, 1); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0xd8ed, 1, 1); + if (ret < 0) + goto err; + + /* LED */ + ret = af9035_wr_reg_mask(d, 0xd8d0, 1, 1); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0xd8d1, 1, 1); + if (ret < 0) + goto err; + + usleep_range(10000, 50000); + break; + case FC0011_FE_CALLBACK_RESET: + ret = af9035_wr_reg(d, 0xd8e9, 1); + if (ret < 0) + goto err; + + ret = af9035_wr_reg(d, 0xd8e8, 1); + if (ret < 0) + goto err; + + ret = af9035_wr_reg(d, 0xd8e7, 1); + if (ret < 0) + goto err; + + usleep_range(10000, 20000); + + ret = af9035_wr_reg(d, 0xd8e7, 0); + if (ret < 0) + goto err; + + usleep_range(10000, 20000); + break; + default: + ret = -EINVAL; + goto err; + } + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_tuner_callback(struct dvb_usb_device *d, int cmd, int arg) +{ + struct state *state = d->priv; + + switch (state->af9033_config[0].tuner) { + case AF9033_TUNER_FC0011: + return af9035_fc0011_tuner_callback(d, cmd, arg); + default: + break; + } + + return -ENODEV; +} + +static int af9035_frontend_callback(void *adapter_priv, int component, + int cmd, int arg) +{ + struct i2c_adapter *adap = adapter_priv; + struct dvb_usb_device *d = i2c_get_adapdata(adap); + + switch (component) { + case DVB_FRONTEND_COMPONENT_TUNER: + return af9035_tuner_callback(d, cmd, arg); + default: + break; + } + + return -EINVAL; +} + +static int af9035_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct state *state = adap->dev->priv; + int ret; + + if (!state->af9033_config[adap->id].tuner) { + /* unsupported tuner */ + ret = -ENODEV; + goto err; + } + + if (adap->id == 0) { + state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB; + state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL; + + ret = af9035_wr_reg(adap->dev, 0x00417f, + state->af9033_config[1].i2c_addr); + if (ret < 0) + goto err; + + ret = af9035_wr_reg(adap->dev, 0x00d81a, + state->dual_mode); + if (ret < 0) + goto err; + } + + /* attach demodulator */ + adap->fe_adap[0].fe = dvb_attach(af9033_attach, + &state->af9033_config[adap->id], &adap->dev->i2c_adap); + if (adap->fe_adap[0].fe == NULL) { + ret = -ENODEV; + goto err; + } + + /* disable I2C-gate */ + adap->fe_adap[0].fe->ops.i2c_gate_ctrl = NULL; + adap->fe_adap[0].fe->callback = af9035_frontend_callback; + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static struct tua9001_config af9035_tua9001_config = { + .i2c_addr = 0x60, +}; + +static const struct fc0011_config af9035_fc0011_config = { + .i2c_address = 0x60, +}; + +static struct mxl5007t_config af9035_mxl5007t_config = { + .xtal_freq_hz = MxL_XTAL_24_MHZ, + .if_freq_hz = MxL_IF_4_57_MHZ, + .invert_if = 0, + .loop_thru_enable = 0, + .clk_out_enable = 0, + .clk_out_amp = MxL_CLKOUT_AMP_0_94V, +}; + +static struct tda18218_config af9035_tda18218_config = { + .i2c_address = 0x60, + .i2c_wr_max = 21, +}; + +static int af9035_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct state *state = adap->dev->priv; + int ret; + struct dvb_frontend *fe; + + switch (state->af9033_config[adap->id].tuner) { + case AF9033_TUNER_TUA9001: + /* AF9035 gpiot3 = TUA9001 RESETN + AF9035 gpiot2 = TUA9001 RXEN */ + + /* configure gpiot2 and gpiot2 as output */ + ret = af9035_wr_reg_mask(adap->dev, 0x00d8ec, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(adap->dev, 0x00d8ed, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(adap->dev, 0x00d8e8, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(adap->dev, 0x00d8e9, 0x01, 0x01); + if (ret < 0) + goto err; + + /* reset tuner */ + ret = af9035_wr_reg_mask(adap->dev, 0x00d8e7, 0x00, 0x01); + if (ret < 0) + goto err; + + usleep_range(2000, 20000); + + ret = af9035_wr_reg_mask(adap->dev, 0x00d8e7, 0x01, 0x01); + if (ret < 0) + goto err; + + /* activate tuner RX */ + /* TODO: use callback for TUA9001 RXEN */ + ret = af9035_wr_reg_mask(adap->dev, 0x00d8eb, 0x01, 0x01); + if (ret < 0) + goto err; + + /* attach tuner */ + fe = dvb_attach(tua9001_attach, adap->fe_adap[0].fe, + &adap->dev->i2c_adap, &af9035_tua9001_config); + break; + case AF9033_TUNER_FC0011: + fe = dvb_attach(fc0011_attach, adap->fe_adap[0].fe, + &adap->dev->i2c_adap, &af9035_fc0011_config); + break; + case AF9033_TUNER_MXL5007T: + ret = af9035_wr_reg(adap->dev, 0x00d8e0, 1); + if (ret < 0) + goto err; + ret = af9035_wr_reg(adap->dev, 0x00d8e1, 1); + if (ret < 0) + goto err; + ret = af9035_wr_reg(adap->dev, 0x00d8df, 0); + if (ret < 0) + goto err; + + msleep(30); + + ret = af9035_wr_reg(adap->dev, 0x00d8df, 1); + if (ret < 0) + goto err; + + msleep(300); + + ret = af9035_wr_reg(adap->dev, 0x00d8c0, 1); + if (ret < 0) + goto err; + ret = af9035_wr_reg(adap->dev, 0x00d8c1, 1); + if (ret < 0) + goto err; + ret = af9035_wr_reg(adap->dev, 0x00d8bf, 0); + if (ret < 0) + goto err; + ret = af9035_wr_reg(adap->dev, 0x00d8b4, 1); + if (ret < 0) + goto err; + ret = af9035_wr_reg(adap->dev, 0x00d8b5, 1); + if (ret < 0) + goto err; + ret = af9035_wr_reg(adap->dev, 0x00d8b3, 1); + if (ret < 0) + goto err; + + /* attach tuner */ + fe = dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe, + &adap->dev->i2c_adap, 0x60, &af9035_mxl5007t_config); + break; + case AF9033_TUNER_TDA18218: + /* attach tuner */ + fe = dvb_attach(tda18218_attach, adap->fe_adap[0].fe, + &adap->dev->i2c_adap, &af9035_tda18218_config); + break; + default: + fe = NULL; + } + + if (fe == NULL) { + ret = -ENODEV; + goto err; + } + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +enum af9035_id_entry { + AF9035_15A4_9035, + AF9035_15A4_1000, + AF9035_15A4_1001, + AF9035_15A4_1002, + AF9035_15A4_1003, + AF9035_0CCD_0093, + AF9035_07CA_A835, + AF9035_07CA_B835, + AF9035_07CA_1867, + AF9035_07CA_A867, + AF9035_07CA_0825, +}; + +static struct usb_device_id af9035_id[] = { + [AF9035_15A4_9035] = { + USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035)}, + [AF9035_15A4_1000] = { + USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1000)}, + [AF9035_15A4_1001] = { + USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1001)}, + [AF9035_15A4_1002] = { + USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1002)}, + [AF9035_15A4_1003] = { + USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1003)}, + [AF9035_0CCD_0093] = { + USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK)}, + [AF9035_07CA_A835] = { + USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835)}, + [AF9035_07CA_B835] = { + USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_B835)}, + [AF9035_07CA_1867] = { + USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_1867)}, + [AF9035_07CA_A867] = { + USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A867)}, + [AF9035_07CA_0825] = { + USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TWINSTAR)}, + {}, +}; + +MODULE_DEVICE_TABLE(usb, af9035_id); + +static struct dvb_usb_device_properties af9035_properties[] = { + { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .download_firmware = af9035_download_firmware, + .firmware = "dvb-usb-af9035-02.fw", + .no_reconnect = 1, + + .size_of_priv = sizeof(struct state), + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = { + { + .frontend_attach = af9035_frontend_attach, + .tuner_attach = af9035_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x84, + .u = { + .bulk = { + .buffersize = (87 * 188), + } + } + } + } + } + } + }, + + .identify_state = af9035_identify_state, + .read_mac_address = af9035_read_mac_address, + + .i2c_algo = &af9035_i2c_algo, + + .rc.core = { + .protocol = RC_TYPE_UNKNOWN, + .module_name = "af9035", + .rc_query = NULL, + .rc_interval = AF9035_POLL, + .allowed_protos = RC_TYPE_UNKNOWN, + .rc_codes = RC_MAP_EMPTY, + }, + .num_device_descs = 5, + .devices = { + { + .name = "Afatech AF9035 reference design", + .cold_ids = { + &af9035_id[AF9035_15A4_9035], + &af9035_id[AF9035_15A4_1000], + &af9035_id[AF9035_15A4_1001], + &af9035_id[AF9035_15A4_1002], + &af9035_id[AF9035_15A4_1003], + }, + }, { + .name = "TerraTec Cinergy T Stick", + .cold_ids = { + &af9035_id[AF9035_0CCD_0093], + }, + }, { + .name = "AVerMedia AVerTV Volar HD/PRO (A835)", + .cold_ids = { + &af9035_id[AF9035_07CA_A835], + &af9035_id[AF9035_07CA_B835], + }, + }, { + .name = "AVerMedia HD Volar (A867)", + .cold_ids = { + &af9035_id[AF9035_07CA_1867], + &af9035_id[AF9035_07CA_A867], + }, + }, { + .name = "AVerMedia Twinstar (A825)", + .cold_ids = { + &af9035_id[AF9035_07CA_0825], + }, + }, + } + }, + { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .download_firmware = af9035_download_firmware_it9135, + .firmware = "dvb-usb-it9135-01.fw", + .no_reconnect = 1, + + .size_of_priv = sizeof(struct state), + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = { + { + .frontend_attach = af9035_frontend_attach, + .tuner_attach = af9035_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x84, + .u = { + .bulk = { + .buffersize = (87 * 188), + } + } + } + } + } + } + }, + + .identify_state = af9035_identify_state, + .read_mac_address = af9035_read_mac_address_it9135, + + .i2c_algo = &af9035_i2c_algo, + + .num_device_descs = 0, /* disabled as no support for IT9135 */ + .devices = { + { + .name = "ITE Tech. IT9135 reference design", + }, + } + }, +}; + +static int af9035_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int ret, i; + struct dvb_usb_device *d = NULL; + struct usb_device *udev; + bool found; + + pr_debug("%s: interface=%d\n", __func__, + intf->cur_altsetting->desc.bInterfaceNumber); + + /* interface 0 is used by DVB-T receiver and + interface 1 is for remote controller (HID) */ + if (intf->cur_altsetting->desc.bInterfaceNumber != 0) + return 0; + + /* Dynamic USB ID support. Replaces first device ID with current one. */ + udev = interface_to_usbdev(intf); + + for (i = 0, found = false; i < ARRAY_SIZE(af9035_id) - 1; i++) { + if (af9035_id[i].idVendor == + le16_to_cpu(udev->descriptor.idVendor) && + af9035_id[i].idProduct == + le16_to_cpu(udev->descriptor.idProduct)) { + found = true; + break; + } + } + + if (!found) { + pr_debug("%s: using dynamic ID %04x:%04x\n", __func__, + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); + af9035_properties[0].devices[0].cold_ids[0]->idVendor = + le16_to_cpu(udev->descriptor.idVendor); + af9035_properties[0].devices[0].cold_ids[0]->idProduct = + le16_to_cpu(udev->descriptor.idProduct); + } + + + for (i = 0; i < af9035_properties_count; i++) { + ret = dvb_usb_device_init(intf, &af9035_properties[i], + THIS_MODULE, &d, adapter_nr); + + if (ret == -ENODEV) + continue; + else + break; + } + + if (ret < 0) + goto err; + + if (d) { + ret = af9035_init(d); + if (ret < 0) + goto err; + } + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver af9035_usb_driver = { + .name = "dvb_usb_af9035", + .probe = af9035_usb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = af9035_id, +}; + +module_usb_driver(af9035_usb_driver); + +MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("Afatech AF9035 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/af9035.h b/drivers/media/dvb/dvb-usb/af9035.h new file mode 100644 index 00000000000..481a1a43dd2 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/af9035.h @@ -0,0 +1,113 @@ +/* + * Afatech AF9035 DVB USB driver + * + * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> + * Copyright (C) 2012 Antti Palosaari <crope@iki.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef AF9035_H +#define AF9035_H + +/* prefix for dvb-usb log writings */ +#define DVB_USB_LOG_PREFIX "af9035" + +#include "dvb-usb.h" +#include "af9033.h" +#include "tua9001.h" +#include "fc0011.h" +#include "mxl5007t.h" +#include "tda18218.h" + +struct reg_val { + u32 reg; + u8 val; +}; + +struct reg_val_mask { + u32 reg; + u8 val; + u8 mask; +}; + +struct usb_req { + u8 cmd; + u8 mbox; + u8 wlen; + u8 *wbuf; + u8 rlen; + u8 *rbuf; +}; + +struct state { + bool dual_mode; + + struct af9033_config af9033_config[2]; +}; + +u32 clock_lut[] = { + 20480000, /* FPGA */ + 16384000, /* 16.38 MHz */ + 20480000, /* 20.48 MHz */ + 36000000, /* 36.00 MHz */ + 30000000, /* 30.00 MHz */ + 26000000, /* 26.00 MHz */ + 28000000, /* 28.00 MHz */ + 32000000, /* 32.00 MHz */ + 34000000, /* 34.00 MHz */ + 24000000, /* 24.00 MHz */ + 22000000, /* 22.00 MHz */ + 12000000, /* 12.00 MHz */ +}; + +u32 clock_lut_it9135[] = { + 12000000, /* 12.00 MHz */ + 20480000, /* 20.48 MHz */ + 36000000, /* 36.00 MHz */ + 30000000, /* 30.00 MHz */ + 26000000, /* 26.00 MHz */ + 28000000, /* 28.00 MHz */ + 32000000, /* 32.00 MHz */ + 34000000, /* 34.00 MHz */ + 24000000, /* 24.00 MHz */ + 22000000, /* 22.00 MHz */ +}; + +/* EEPROM locations */ +#define EEPROM_IR_MODE 0x430d +#define EEPROM_DUAL_MODE 0x4326 +#define EEPROM_IR_TYPE 0x4329 +#define EEPROM_1_IFFREQ_L 0x432d +#define EEPROM_1_IFFREQ_H 0x432e +#define EEPROM_1_TUNER_ID 0x4331 +#define EEPROM_2_IFFREQ_L 0x433d +#define EEPROM_2_IFFREQ_H 0x433e +#define EEPROM_2_TUNER_ID 0x4341 + +/* USB commands */ +#define CMD_MEM_RD 0x00 +#define CMD_MEM_WR 0x01 +#define CMD_I2C_RD 0x02 +#define CMD_I2C_WR 0x03 +#define CMD_IR_GET 0x18 +#define CMD_FW_DL 0x21 +#define CMD_FW_QUERYINFO 0x22 +#define CMD_FW_BOOT 0x23 +#define CMD_FW_DL_BEGIN 0x24 +#define CMD_FW_DL_END 0x25 +#define CMD_FW_SCATTER_WR 0x29 + +#endif diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index 02290c60f72..7e9e00fae04 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -32,7 +32,7 @@ int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, if (mutex_lock_interruptible(&d->usb_mutex) < 0) { err("could not acquire lock"); - return 0; + return -EINTR; } ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), @@ -118,7 +118,7 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_ if (mutex_lock_interruptible(&d->usb_mutex) < 0) { err("could not acquire lock"); - return 0; + return -EINTR; } st->buf[0] = REQUEST_SET_GPIO; @@ -139,7 +139,7 @@ static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets) if (st->fw_version >= 0x10201) { if (mutex_lock_interruptible(&d->usb_mutex) < 0) { err("could not acquire lock"); - return 0; + return -EINTR; } st->buf[0] = REQUEST_SET_USB_XFER_LEN; @@ -178,7 +178,7 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg, /* Ensure nobody else hits the i2c bus while we're sending our sequence of messages, (such as the remote control thread) */ if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; + return -EINTR; for (i = 0; i < num; i++) { if (i == 0) { @@ -228,7 +228,8 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg, /* Write request */ if (mutex_lock_interruptible(&d->usb_mutex) < 0) { err("could not acquire lock"); - return 0; + mutex_unlock(&d->i2c_mutex); + return -EINTR; } st->buf[0] = REQUEST_NEW_I2C_WRITE; st->buf[1] = msg[i].addr << 1; @@ -271,10 +272,11 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap, int i,len; if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; + return -EINTR; if (mutex_lock_interruptible(&d->usb_mutex) < 0) { err("could not acquire lock"); - return 0; + mutex_unlock(&d->i2c_mutex); + return -EINTR; } for (i = 0; i < num; i++) { @@ -369,7 +371,7 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll, if (mutex_lock_interruptible(&d->usb_mutex) < 0) { err("could not acquire lock"); - return 0; + return -EINTR; } st->buf[0] = REQUEST_SET_CLOCK; @@ -401,7 +403,7 @@ int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz) if (mutex_lock_interruptible(&d->usb_mutex) < 0) { err("could not acquire lock"); - return 0; + return -EINTR; } st->buf[0] = REQUEST_SET_I2C_PARAM; @@ -561,7 +563,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) { err("could not acquire lock"); - return 0; + return -EINTR; } st->buf[0] = REQUEST_ENABLE_VIDEO; @@ -611,7 +613,7 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type) if (mutex_lock_interruptible(&d->usb_mutex) < 0) { err("could not acquire lock"); - return 0; + return -EINTR; } st->buf[0] = REQUEST_SET_RC; diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index f9e966aa26e..510001da6e8 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -3569,6 +3569,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7090E) }, { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7790E) }, /* 80 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE8096P) }, + { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_2) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -3832,7 +3833,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 11, + .num_device_descs = 12, .devices = { { "DiBcom STK7070P reference design", { &dib0700_usb_id_table[15], NULL }, @@ -3878,6 +3879,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[50], NULL }, { NULL }, }, + { "Elgato EyeTV DTT rev. 2", + { &dib0700_usb_id_table[81], NULL }, + { NULL }, + }, }, .rc.core = { diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 397d8f23273..7a6160bf54b 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -76,6 +76,11 @@ #define USB_PID_AFATECH_AF9005 0x9020 #define USB_PID_AFATECH_AF9015_9015 0x9015 #define USB_PID_AFATECH_AF9015_9016 0x9016 +#define USB_PID_AFATECH_AF9035_1000 0x1000 +#define USB_PID_AFATECH_AF9035_1001 0x1001 +#define USB_PID_AFATECH_AF9035_1002 0x1002 +#define USB_PID_AFATECH_AF9035_1003 0x1003 +#define USB_PID_AFATECH_AF9035_9035 0x9035 #define USB_PID_TREKSTOR_DVBT 0x901b #define USB_VID_ALINK_DTU 0xf170 #define USB_PID_ANSONIC_DVBT_USB 0x6000 @@ -152,6 +157,7 @@ #define USB_PID_KWORLD_VSTREAM_WARM 0x17df #define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055 #define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2 0x0069 +#define USB_PID_TERRATEC_CINERGY_T_STICK 0x0093 #define USB_PID_TERRATEC_CINERGY_T_STICK_RC 0x0097 #define USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC 0x0099 #define USB_PID_TWINHAN_VP7041_COLD 0x3201 @@ -221,6 +227,11 @@ #define USB_PID_AVERMEDIA_A850T 0x850b #define USB_PID_AVERMEDIA_A805 0xa805 #define USB_PID_AVERMEDIA_A815M 0x815a +#define USB_PID_AVERMEDIA_A835 0xa835 +#define USB_PID_AVERMEDIA_B835 0xb835 +#define USB_PID_AVERMEDIA_1867 0x1867 +#define USB_PID_AVERMEDIA_A867 0xa867 +#define USB_PID_AVERMEDIA_TWINSTAR 0x0825 #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 #define USB_PID_TECHNOTREND_CONNECT_CT3650 0x300d #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a @@ -327,6 +338,7 @@ #define USB_PID_MYGICA_D689 0xd811 #define USB_PID_ELGATO_EYETV_DIVERSITY 0x0011 #define USB_PID_ELGATO_EYETV_DTT 0x0021 +#define USB_PID_ELGATO_EYETV_DTT_2 0x003f #define USB_PID_ELGATO_EYETV_DTT_Dlx 0x0020 #define USB_PID_ELGATO_EYETV_SAT 0x002a #define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD 0x5000 diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c index 53a5c30b51b..5c8f651344f 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c @@ -80,6 +80,14 @@ static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer dvb_dmx_swfilter_204(&adap->demux, buffer, length); } +static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, + u8 *buffer, size_t length) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) + dvb_dmx_swfilter_raw(&adap->demux, buffer, length); +} + int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap) { int i, ret = 0; @@ -90,6 +98,10 @@ int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap) adap->fe_adap[i].stream.complete = dvb_usb_data_complete_204; else + if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD) + adap->fe_adap[i].stream.complete = + dvb_usb_data_complete_raw; + else adap->fe_adap[i].stream.complete = dvb_usb_data_complete; adap->fe_adap[i].stream.user_priv = adap; ret = usb_urb_init(&adap->fe_adap[i].stream, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index 6d7d13f9ce6..99f94409efa 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -141,6 +141,7 @@ struct dvb_usb_adapter_fe_properties { #define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02 #define DVB_USB_ADAP_NEED_PID_FILTERING 0x04 #define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08 +#define DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD 0x10 int caps; int pid_filter_count; @@ -156,7 +157,7 @@ struct dvb_usb_adapter_fe_properties { int size_of_priv; }; -#define MAX_NO_OF_FE_PER_ADAP 2 +#define MAX_NO_OF_FE_PER_ADAP 3 struct dvb_usb_adapter_properties { int size_of_priv; diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 451c5a7adfb..9382895b1b8 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -148,7 +148,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i = 0, ret = 0; + int i = 0; u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0}; u16 value; @@ -162,7 +162,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], /* read stv0299 register */ value = msg[0].buf[0];/* register */ for (i = 0; i < msg[1].len; i++) { - ret = dw210x_op_rw(d->udev, 0xb5, value + i, 0, + dw210x_op_rw(d->udev, 0xb5, value + i, 0, buf6, 2, DW210X_READ_MSG); msg[1].buf[i] = buf6[0]; } @@ -174,7 +174,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], buf6[0] = 0x2a; buf6[1] = msg[0].buf[0]; buf6[2] = msg[0].buf[1]; - ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, + dw210x_op_rw(d->udev, 0xb2, 0, 0, buf6, 3, DW210X_WRITE_MSG); break; case 0x60: @@ -187,17 +187,17 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], buf6[4] = msg[0].buf[1]; buf6[5] = msg[0].buf[2]; buf6[6] = msg[0].buf[3]; - ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, + dw210x_op_rw(d->udev, 0xb2, 0, 0, buf6, 7, DW210X_WRITE_MSG); } else { /* read from tuner */ - ret = dw210x_op_rw(d->udev, 0xb5, 0, 0, + dw210x_op_rw(d->udev, 0xb5, 0, 0, buf6, 1, DW210X_READ_MSG); msg[0].buf[0] = buf6[0]; } break; case (DW2102_RC_QUERY): - ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, + dw210x_op_rw(d->udev, 0xb8, 0, 0, buf6, 2, DW210X_READ_MSG); msg[0].buf[0] = buf6[0]; msg[0].buf[1] = buf6[1]; @@ -205,7 +205,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], case (DW2102_VOLTAGE_CTRL): buf6[0] = 0x30; buf6[1] = msg[0].buf[0]; - ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, + dw210x_op_rw(d->udev, 0xb2, 0, 0, buf6, 2, DW210X_WRITE_MSG); break; } @@ -221,7 +221,6 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); - int ret = 0; u8 buf6[] = {0, 0, 0, 0, 0, 0, 0}; if (!d) @@ -235,10 +234,10 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, buf6[0] = msg[0].addr << 1; buf6[1] = msg[0].len; buf6[2] = msg[0].buf[0]; - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6, msg[0].len + 2, DW210X_WRITE_MSG); /* read si2109 register */ - ret = dw210x_op_rw(d->udev, 0xc3, 0xd0, 0, + dw210x_op_rw(d->udev, 0xc3, 0xd0, 0, buf6, msg[1].len + 2, DW210X_READ_MSG); memcpy(msg[1].buf, buf6 + 2, msg[1].len); @@ -250,11 +249,11 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, buf6[0] = msg[0].addr << 1; buf6[1] = msg[0].len; memcpy(buf6 + 2, msg[0].buf, msg[0].len); - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6, + dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6, msg[0].len + 2, DW210X_WRITE_MSG); break; case(DW2102_RC_QUERY): - ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, + dw210x_op_rw(d->udev, 0xb8, 0, 0, buf6, 2, DW210X_READ_MSG); msg[0].buf[0] = buf6[0]; msg[0].buf[1] = buf6[1]; @@ -262,7 +261,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, case(DW2102_VOLTAGE_CTRL): buf6[0] = 0x30; buf6[1] = msg[0].buf[0]; - ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, + dw210x_op_rw(d->udev, 0xb2, 0, 0, buf6, 2, DW210X_WRITE_MSG); break; } @@ -276,7 +275,6 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); - int ret = 0; if (!d) return -ENODEV; @@ -291,10 +289,10 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms obuf[0] = msg[0].addr << 1; obuf[1] = msg[0].len; obuf[2] = msg[0].buf[0]; - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + dw210x_op_rw(d->udev, 0xc2, 0, 0, obuf, msg[0].len + 2, DW210X_WRITE_MSG); /* second read registers */ - ret = dw210x_op_rw(d->udev, 0xc3, 0xd1 , 0, + dw210x_op_rw(d->udev, 0xc3, 0xd1 , 0, ibuf, msg[1].len + 2, DW210X_READ_MSG); memcpy(msg[1].buf, ibuf + 2, msg[1].len); @@ -308,7 +306,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms obuf[0] = msg[0].addr << 1; obuf[1] = msg[0].len; memcpy(obuf + 2, msg[0].buf, msg[0].len); - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + dw210x_op_rw(d->udev, 0xc2, 0, 0, obuf, msg[0].len + 2, DW210X_WRITE_MSG); break; } @@ -318,13 +316,13 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms obuf[0] = msg[0].addr << 1; obuf[1] = msg[0].len; memcpy(obuf + 2, msg[0].buf, msg[0].len); - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + dw210x_op_rw(d->udev, 0xc2, 0, 0, obuf, msg[0].len + 2, DW210X_WRITE_MSG); break; } case(DW2102_RC_QUERY): { u8 ibuf[2]; - ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, + dw210x_op_rw(d->udev, 0xb8, 0, 0, ibuf, 2, DW210X_READ_MSG); memcpy(msg[0].buf, ibuf , 2); break; @@ -333,7 +331,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms u8 obuf[2]; obuf[0] = 0x30; obuf[1] = msg[0].buf[0]; - ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, + dw210x_op_rw(d->udev, 0xb2, 0, 0, obuf, 2, DW210X_WRITE_MSG); break; } @@ -349,7 +347,6 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); - int ret = 0; int len, i, j; if (!d) @@ -361,7 +358,7 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i switch (msg[j].addr) { case(DW2102_RC_QUERY): { u8 ibuf[2]; - ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, + dw210x_op_rw(d->udev, 0xb8, 0, 0, ibuf, 2, DW210X_READ_MSG); memcpy(msg[j].buf, ibuf , 2); break; @@ -370,7 +367,7 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i u8 obuf[2]; obuf[0] = 0x30; obuf[1] = msg[j].buf[0]; - ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, + dw210x_op_rw(d->udev, 0xb2, 0, 0, obuf, 2, DW210X_WRITE_MSG); break; } @@ -382,7 +379,7 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i if (msg[j].flags == I2C_M_RD) { /* read registers */ u8 ibuf[msg[j].len + 2]; - ret = dw210x_op_rw(d->udev, 0xc3, + dw210x_op_rw(d->udev, 0xc3, (msg[j].addr << 1) + 1, 0, ibuf, msg[j].len + 2, DW210X_READ_MSG); @@ -402,7 +399,7 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i do { memcpy(obuf + 3, msg[j].buf + i, (len > 16 ? 16 : len)); - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + dw210x_op_rw(d->udev, 0xc2, 0, 0, obuf, (len > 16 ? 16 : len) + 3, DW210X_WRITE_MSG); i += 16; @@ -414,7 +411,7 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i obuf[0] = msg[j].addr << 1; obuf[1] = msg[j].len; memcpy(obuf + 2, msg[j].buf, msg[j].len); - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + dw210x_op_rw(d->udev, 0xc2, 0, 0, obuf, msg[j].len + 2, DW210X_WRITE_MSG); } @@ -432,7 +429,7 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); - int ret = 0, i; + int i; if (!d) return -ENODEV; @@ -447,10 +444,10 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], obuf[0] = msg[0].addr << 1; obuf[1] = msg[0].len; obuf[2] = msg[0].buf[0]; - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + dw210x_op_rw(d->udev, 0xc2, 0, 0, obuf, msg[0].len + 2, DW210X_WRITE_MSG); /* second read registers */ - ret = dw210x_op_rw(d->udev, 0xc3, 0x19 , 0, + dw210x_op_rw(d->udev, 0xc3, 0x19 , 0, ibuf, msg[1].len + 2, DW210X_READ_MSG); memcpy(msg[1].buf, ibuf + 2, msg[1].len); @@ -465,13 +462,13 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], obuf[0] = msg[0].addr << 1; obuf[1] = msg[0].len; memcpy(obuf + 2, msg[0].buf, msg[0].len); - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + dw210x_op_rw(d->udev, 0xc2, 0, 0, obuf, msg[0].len + 2, DW210X_WRITE_MSG); break; } case(DW2102_RC_QUERY): { u8 ibuf[2]; - ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, + dw210x_op_rw(d->udev, 0xb8, 0, 0, ibuf, 2, DW210X_READ_MSG); memcpy(msg[0].buf, ibuf , 2); break; @@ -496,7 +493,6 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], { struct dvb_usb_device *d = i2c_get_adapdata(adap); struct usb_device *udev; - int ret = 0; int len, i, j; if (!d) @@ -509,7 +505,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], switch (msg[j].addr) { case (DW2102_RC_QUERY): { u8 ibuf[5]; - ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, + dw210x_op_rw(d->udev, 0xb8, 0, 0, ibuf, 5, DW210X_READ_MSG); memcpy(msg[j].buf, ibuf + 3, 2); break; @@ -519,11 +515,11 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], obuf[0] = 1; obuf[1] = msg[j].buf[1];/* off-on */ - ret = dw210x_op_rw(d->udev, 0x8a, 0, 0, + dw210x_op_rw(d->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); obuf[0] = 3; obuf[1] = msg[j].buf[0];/* 13v-18v */ - ret = dw210x_op_rw(d->udev, 0x8a, 0, 0, + dw210x_op_rw(d->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); break; } @@ -532,7 +528,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], obuf[0] = 5; obuf[1] = msg[j].buf[0]; - ret = dw210x_op_rw(d->udev, 0x8a, 0, 0, + dw210x_op_rw(d->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); break; } @@ -545,7 +541,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], if (msg[j].flags == I2C_M_RD) { /* read registers */ u8 ibuf[msg[j].len]; - ret = dw210x_op_rw(d->udev, 0x91, 0, 0, + dw210x_op_rw(d->udev, 0x91, 0, 0, ibuf, msg[j].len, DW210X_READ_MSG); memcpy(msg[j].buf, ibuf, msg[j].len); @@ -563,7 +559,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], do { memcpy(obuf + 3, msg[j].buf + i, (len > 16 ? 16 : len)); - ret = dw210x_op_rw(d->udev, 0x80, 0, 0, + dw210x_op_rw(d->udev, 0x80, 0, 0, obuf, (len > 16 ? 16 : len) + 3, DW210X_WRITE_MSG); i += 16; @@ -575,7 +571,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], obuf[0] = msg[j + 1].len; obuf[1] = (msg[j].addr << 1); memcpy(obuf + 2, msg[j].buf, msg[j].len); - ret = dw210x_op_rw(d->udev, + dw210x_op_rw(d->udev, udev->descriptor.idProduct == 0x7500 ? 0x92 : 0x90, 0, 0, obuf, msg[j].len + 2, @@ -587,7 +583,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], obuf[0] = msg[j].len + 1; obuf[1] = (msg[j].addr << 1); memcpy(obuf + 2, msg[j].buf, msg[j].len); - ret = dw210x_op_rw(d->udev, 0x80, 0, 0, + dw210x_op_rw(d->udev, 0x80, 0, 0, obuf, msg[j].len + 2, DW210X_WRITE_MSG); break; diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c index 482d249ca7f..6244fe9d1a3 100644 --- a/drivers/media/dvb/dvb-usb/it913x.c +++ b/drivers/media/dvb/dvb-usb/it913x.c @@ -81,7 +81,7 @@ static int it913x_bulk_write(struct usb_device *dev, for (i = 0; i < IT913X_RETRY; i++) { ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe), snd, len , &actual_l, IT913X_SND_TIMEOUT); - if (ret == 0 || ret != -EBUSY || ret != -ETIMEDOUT) + if (ret != -EBUSY && ret != -ETIMEDOUT) break; } @@ -99,7 +99,7 @@ static int it913x_bulk_read(struct usb_device *dev, for (i = 0; i < IT913X_RETRY; i++) { ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe), rev, len , &actual_l, IT913X_RCV_TIMEOUT); - if (ret == 0 || ret != -EBUSY || ret != -ETIMEDOUT) + if (ret != -EBUSY && ret != -ETIMEDOUT) break; } diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c index 5dde06d066f..25d1031460f 100644 --- a/drivers/media/dvb/dvb-usb/lmedm04.c +++ b/drivers/media/dvb/dvb-usb/lmedm04.c @@ -373,7 +373,7 @@ static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) struct lme2510_state *st = adap->dev->priv; static u8 clear_pid_reg[] = LME_ALL_PIDS; static u8 rbuf[1]; - int ret; + int ret = 0; deb_info(1, "PID Clearing Filter"); @@ -1205,14 +1205,13 @@ static int lme2510_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(intf); - int ret = 0; usb_reset_configuration(udev); usb_set_interface(udev, intf->cur_altsetting->desc.bInterfaceNumber, 1); if (udev->speed != USB_SPEED_HIGH) { - ret = usb_reset_device(udev); + usb_reset_device(udev); info("DEV Failed to connect in HIGH SPEED mode"); return -ENODEV; } diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c index 72db6eef4b9..74da5bb1ce9 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c @@ -284,6 +284,7 @@ static int mxl111sf_tuner_set_params(struct dvb_frontend *fe) switch (delsys) { case SYS_ATSC: + case SYS_ATSCMH: bw = 0; /* ATSC */ break; case SYS_DVBC_ANNEX_B: diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb/mxl111sf.c index 81305de2fea..cd842798f5a 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf.c @@ -21,6 +21,7 @@ #include "mxl111sf-tuner.h" #include "lgdt3305.h" +#include "lg2160.h" int dvb_usb_mxl111sf_debug; module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644); @@ -31,6 +32,10 @@ int dvb_usb_mxl111sf_isoc; module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644); MODULE_PARM_DESC(isoc, "enable usb isoc xfer (0=bulk, 1=isoc)."); +int dvb_usb_mxl111sf_spi; +module_param_named(spi, dvb_usb_mxl111sf_spi, int, 0644); +MODULE_PARM_DESC(spi, "use spi rather than tp for data xfer (0=tp, 1=spi)."); + #define ANT_PATH_AUTO 0 #define ANT_PATH_EXTERNAL 1 #define ANT_PATH_INTERNAL 2 @@ -340,7 +345,6 @@ static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) struct mxl111sf_state *state = d->priv; struct mxl111sf_adap_state *adap_state = adap->fe_adap[adap->active_fe].priv; int ret = 0; - u8 tmp; deb_info("%s(%d)\n", __func__, onoff); @@ -361,6 +365,33 @@ static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) return ret; } +static int mxl111sf_ep5_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + struct dvb_usb_device *d = adap->dev; + struct mxl111sf_state *state = d->priv; + int ret = 0; + + deb_info("%s(%d)\n", __func__, onoff); + + if (onoff) { + ret = mxl111sf_enable_usb_output(state); + mxl_fail(ret); + + ret = mxl111sf_init_i2s_port(state, 200); + mxl_fail(ret); + ret = mxl111sf_config_i2s(state, 0, 15); + mxl_fail(ret); + } else { + ret = mxl111sf_disable_i2s_port(state); + mxl_fail(ret); + } + if (state->chip_rev > MXL111SF_V6) + ret = mxl111sf_config_spi(state, onoff); + mxl_fail(ret); + + return ret; +} + static int mxl111sf_ep4_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { struct dvb_usb_device *d = adap->dev; @@ -453,6 +484,255 @@ fail: return ret; } +static struct lg2160_config hauppauge_lg2160_config = { + .lg_chip = LG2160, + .i2c_addr = 0x1c >> 1, + .deny_i2c_rptr = 1, + .spectral_inversion = 0, + .if_khz = 6000, +}; + +static int mxl111sf_lg2160_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap->dev; + struct mxl111sf_state *state = d->priv; + int fe_id = adap->num_frontends_initialized; + struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv; + int ret; + + deb_adv("%s()\n", __func__); + + /* save a pointer to the dvb_usb_device in device state */ + state->d = d; + adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; + state->alt_mode = adap_state->alt_mode; + + if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0) + err("set interface failed"); + + state->gpio_mode = MXL111SF_GPIO_MOD_MH; + adap_state->gpio_mode = state->gpio_mode; + adap_state->device_mode = MXL_TUNER_MODE; + adap_state->ep6_clockphase = 1; + + ret = mxl1x1sf_soft_reset(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_init_tuner_demod(state); + if (mxl_fail(ret)) + goto fail; + + ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_enable_usb_output(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_top_master_ctrl(state, 1); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_init_port_expander(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode); + if (mxl_fail(ret)) + goto fail; + + ret = get_chip_info(state); + if (mxl_fail(ret)) + goto fail; + + adap->fe_adap[fe_id].fe = dvb_attach(lg2160_attach, + &hauppauge_lg2160_config, + &adap->dev->i2c_adap); + if (adap->fe_adap[fe_id].fe) { + adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init; + adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep; + adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep; + return 0; + } + ret = -EIO; +fail: + return ret; +} + +static struct lg2160_config hauppauge_lg2161_1019_config = { + .lg_chip = LG2161_1019, + .i2c_addr = 0x1c >> 1, + .deny_i2c_rptr = 1, + .spectral_inversion = 0, + .if_khz = 6000, + .output_if = 2, /* LG2161_OIF_SPI_MAS */ +}; + +static struct lg2160_config hauppauge_lg2161_1040_config = { + .lg_chip = LG2161_1040, + .i2c_addr = 0x1c >> 1, + .deny_i2c_rptr = 1, + .spectral_inversion = 0, + .if_khz = 6000, + .output_if = 4, /* LG2161_OIF_SPI_MAS */ +}; + +static int mxl111sf_lg2161_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap->dev; + struct mxl111sf_state *state = d->priv; + int fe_id = adap->num_frontends_initialized; + struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv; + int ret; + + deb_adv("%s()\n", __func__); + + /* save a pointer to the dvb_usb_device in device state */ + state->d = d; + adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; + state->alt_mode = adap_state->alt_mode; + + if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0) + err("set interface failed"); + + state->gpio_mode = MXL111SF_GPIO_MOD_MH; + adap_state->gpio_mode = state->gpio_mode; + adap_state->device_mode = MXL_TUNER_MODE; + adap_state->ep6_clockphase = 1; + + ret = mxl1x1sf_soft_reset(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_init_tuner_demod(state); + if (mxl_fail(ret)) + goto fail; + + ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_enable_usb_output(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_top_master_ctrl(state, 1); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_init_port_expander(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode); + if (mxl_fail(ret)) + goto fail; + + ret = get_chip_info(state); + if (mxl_fail(ret)) + goto fail; + + adap->fe_adap[fe_id].fe = dvb_attach(lg2160_attach, + (MXL111SF_V8_200 == state->chip_rev) ? + &hauppauge_lg2161_1040_config : + &hauppauge_lg2161_1019_config, + &adap->dev->i2c_adap); + if (adap->fe_adap[fe_id].fe) { + adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init; + adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep; + adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep; + return 0; + } + ret = -EIO; +fail: + return ret; +} + +static struct lg2160_config hauppauge_lg2161_1019_ep6_config = { + .lg_chip = LG2161_1019, + .i2c_addr = 0x1c >> 1, + .deny_i2c_rptr = 1, + .spectral_inversion = 0, + .if_khz = 6000, + .output_if = 1, /* LG2161_OIF_SERIAL_TS */ +}; + +static struct lg2160_config hauppauge_lg2161_1040_ep6_config = { + .lg_chip = LG2161_1040, + .i2c_addr = 0x1c >> 1, + .deny_i2c_rptr = 1, + .spectral_inversion = 0, + .if_khz = 6000, + .output_if = 7, /* LG2161_OIF_SERIAL_TS */ +}; + +static int mxl111sf_lg2161_ep6_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap->dev; + struct mxl111sf_state *state = d->priv; + int fe_id = adap->num_frontends_initialized; + struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv; + int ret; + + deb_adv("%s()\n", __func__); + + /* save a pointer to the dvb_usb_device in device state */ + state->d = d; + adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; + state->alt_mode = adap_state->alt_mode; + + if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0) + err("set interface failed"); + + state->gpio_mode = MXL111SF_GPIO_MOD_MH; + adap_state->gpio_mode = state->gpio_mode; + adap_state->device_mode = MXL_TUNER_MODE; + adap_state->ep6_clockphase = 0; + + ret = mxl1x1sf_soft_reset(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_init_tuner_demod(state); + if (mxl_fail(ret)) + goto fail; + + ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_enable_usb_output(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_top_master_ctrl(state, 1); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_init_port_expander(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode); + if (mxl_fail(ret)) + goto fail; + + ret = get_chip_info(state); + if (mxl_fail(ret)) + goto fail; + + adap->fe_adap[fe_id].fe = dvb_attach(lg2160_attach, + (MXL111SF_V8_200 == state->chip_rev) ? + &hauppauge_lg2161_1040_ep6_config : + &hauppauge_lg2161_1019_ep6_config, + &adap->dev->i2c_adap); + if (adap->fe_adap[fe_id].fe) { + adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init; + adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep; + adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep; + return 0; + } + ret = -EIO; +fail: + return ret; +} + static struct mxl111sf_demod_config mxl_demod_config = { .read_reg = mxl111sf_read_reg, .write_reg = mxl111sf_write_reg, @@ -650,6 +930,18 @@ static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties; static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties; static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties; static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties; +static struct dvb_usb_device_properties mxl111sf_atsc_mh_bulk_properties; +static struct dvb_usb_device_properties mxl111sf_atsc_mh_isoc_properties; +static struct dvb_usb_device_properties mxl111sf_mh_bulk_properties; +static struct dvb_usb_device_properties mxl111sf_mh_isoc_properties; +static struct dvb_usb_device_properties mxl111sf_mercury_spi_bulk_properties; +static struct dvb_usb_device_properties mxl111sf_mercury_spi_isoc_properties; +static struct dvb_usb_device_properties mxl111sf_mercury_tp_bulk_properties; +static struct dvb_usb_device_properties mxl111sf_mercury_tp_isoc_properties; +static struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_bulk_properties; +static struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_isoc_properties; +static struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_bulk_properties; +static struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_isoc_properties; static int mxl111sf_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -664,12 +956,50 @@ static int mxl111sf_probe(struct usb_interface *intf, THIS_MODULE, &d, adapter_nr) || 0 == dvb_usb_device_init(intf, &mxl111sf_atsc_isoc_properties, + THIS_MODULE, &d, adapter_nr) || + 0 == dvb_usb_device_init(intf, + &mxl111sf_atsc_mh_isoc_properties, + THIS_MODULE, &d, adapter_nr) || + 0 == dvb_usb_device_init(intf, + &mxl111sf_mh_isoc_properties, + THIS_MODULE, &d, adapter_nr) || + ((dvb_usb_mxl111sf_spi) && + (0 == dvb_usb_device_init(intf, + &mxl111sf_mercury_spi_isoc_properties, + THIS_MODULE, &d, adapter_nr) || + 0 == dvb_usb_device_init(intf, + &mxl111sf_mercury_mh_spi_isoc_properties, + THIS_MODULE, &d, adapter_nr))) || + 0 == dvb_usb_device_init(intf, + &mxl111sf_mercury_tp_isoc_properties, + THIS_MODULE, &d, adapter_nr) || + 0 == dvb_usb_device_init(intf, + &mxl111sf_mercury_mh_tp_isoc_properties, THIS_MODULE, &d, adapter_nr))) || 0 == dvb_usb_device_init(intf, &mxl111sf_dvbt_bulk_properties, THIS_MODULE, &d, adapter_nr) || 0 == dvb_usb_device_init(intf, &mxl111sf_atsc_bulk_properties, + THIS_MODULE, &d, adapter_nr) || + 0 == dvb_usb_device_init(intf, + &mxl111sf_atsc_mh_bulk_properties, + THIS_MODULE, &d, adapter_nr) || + 0 == dvb_usb_device_init(intf, + &mxl111sf_mh_bulk_properties, + THIS_MODULE, &d, adapter_nr) || + ((dvb_usb_mxl111sf_spi) && + (0 == dvb_usb_device_init(intf, + &mxl111sf_mercury_spi_bulk_properties, + THIS_MODULE, &d, adapter_nr) || + 0 == dvb_usb_device_init(intf, + &mxl111sf_mercury_mh_spi_bulk_properties, + THIS_MODULE, &d, adapter_nr))) || + 0 == dvb_usb_device_init(intf, + &mxl111sf_mercury_tp_bulk_properties, + THIS_MODULE, &d, adapter_nr) || + 0 == dvb_usb_device_init(intf, + &mxl111sf_mercury_mh_tp_bulk_properties, THIS_MODULE, &d, adapter_nr) || 0) { struct mxl111sf_state *state = d->priv; @@ -787,6 +1117,36 @@ MODULE_DEVICE_TABLE(usb, mxl111sf_table); } \ } +#define MXL111SF_EP5_BULK_STREAMING_CONFIG \ + .size_of_priv = sizeof(struct mxl111sf_adap_state), \ + .streaming_ctrl = mxl111sf_ep5_streaming_ctrl, \ + .stream = { \ + .type = USB_BULK, \ + .count = 5, \ + .endpoint = 0x05, \ + .u = { \ + .bulk = { \ + .buffersize = 8192, \ + } \ + } \ + } + +#define MXL111SF_EP5_ISOC_STREAMING_CONFIG \ + .size_of_priv = sizeof(struct mxl111sf_adap_state), \ + .streaming_ctrl = mxl111sf_ep5_streaming_ctrl, \ + .stream = { \ + .type = USB_ISOC, \ + .count = 5, \ + .endpoint = 0x05, \ + .u = { \ + .isoc = { \ + .framesperurb = 96, \ + .framesize = 200, \ + .interval = 1, \ + } \ + } \ + } + #define MXL111SF_EP6_BULK_STREAMING_CONFIG \ .size_of_priv = sizeof(struct mxl111sf_adap_state), \ .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \ @@ -848,7 +1208,7 @@ static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties = { } }, }, }, - .num_device_descs = 4, + .num_device_descs = 3, .devices = { { "Hauppauge 126xxx DVBT (bulk)", { NULL }, @@ -866,11 +1226,6 @@ static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties = { &mxl111sf_table[24], &mxl111sf_table[26], NULL }, }, - { "Hauppauge 126xxx (tp-bulk)", - { NULL }, - { &mxl111sf_table[28], &mxl111sf_table[30], - NULL }, - }, } }; @@ -890,7 +1245,7 @@ static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties = { } }, }, }, - .num_device_descs = 4, + .num_device_descs = 3, .devices = { { "Hauppauge 126xxx DVBT (isoc)", { NULL }, @@ -908,11 +1263,6 @@ static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties = { &mxl111sf_table[24], &mxl111sf_table[26], NULL }, }, - { "Hauppauge 126xxx (tp-isoc)", - { NULL }, - { &mxl111sf_table[28], &mxl111sf_table[30], - NULL }, - }, } }; @@ -923,33 +1273,159 @@ static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = { .adapter = { { .fe_ioctl_override = mxl111sf_fe_ioctl_override, - .num_frontends = 2, + .num_frontends = 1, .fe = {{ .frontend_attach = mxl111sf_lgdt3305_frontend_attach, .tuner_attach = mxl111sf_attach_tuner, MXL111SF_EP6_BULK_STREAMING_CONFIG, + }}, }, + }, + .num_device_descs = 2, + .devices = { + { "Hauppauge 126xxx ATSC (bulk)", + { NULL }, + { &mxl111sf_table[1], &mxl111sf_table[5], + NULL }, + }, + { "Hauppauge 117xxx ATSC (bulk)", + { NULL }, + { &mxl111sf_table[12], + NULL }, + }, + } +}; + +static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = { + MXL111SF_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { { - .frontend_attach = mxl111sf_attach_demod, + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + .num_frontends = 1, + .fe = {{ + .frontend_attach = mxl111sf_lgdt3305_frontend_attach, .tuner_attach = mxl111sf_attach_tuner, - MXL111SF_EP4_BULK_STREAMING_CONFIG, + MXL111SF_EP6_ISOC_STREAMING_CONFIG, }}, }, }, - .num_device_descs = 6, + .num_device_descs = 2, .devices = { - { "Hauppauge 126xxx ATSC (bulk)", + { "Hauppauge 126xxx ATSC (isoc)", { NULL }, { &mxl111sf_table[1], &mxl111sf_table[5], NULL }, }, - { "Hauppauge 117xxx ATSC (bulk)", + { "Hauppauge 117xxx ATSC (isoc)", { NULL }, { &mxl111sf_table[12], NULL }, }, + } +}; + +static struct dvb_usb_device_properties mxl111sf_mh_bulk_properties = { + MXL111SF_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, + + .frontend_attach = mxl111sf_lg2160_frontend_attach, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP5_BULK_STREAMING_CONFIG, + }}, + }, + }, + .num_device_descs = 2, + .devices = { + { "HCW 126xxx (bulk)", + { NULL }, + { &mxl111sf_table[2], &mxl111sf_table[6], + NULL }, + }, + { "HCW 117xxx (bulk)", + { NULL }, + { &mxl111sf_table[13], + NULL }, + }, + } +}; + +static struct dvb_usb_device_properties mxl111sf_mh_isoc_properties = { + MXL111SF_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, + + .frontend_attach = mxl111sf_lg2160_frontend_attach, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP5_ISOC_STREAMING_CONFIG, + }}, + }, + }, + .num_device_descs = 2, + .devices = { + { "HCW 126xxx (isoc)", + { NULL }, + { &mxl111sf_table[2], &mxl111sf_table[6], + NULL }, + }, + { "HCW 117xxx (isoc)", + { NULL }, + { &mxl111sf_table[13], + NULL }, + }, + } +}; + +static struct dvb_usb_device_properties mxl111sf_atsc_mh_bulk_properties = { + MXL111SF_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + .num_frontends = 3, + .fe = {{ + .frontend_attach = mxl111sf_lgdt3305_frontend_attach, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP6_BULK_STREAMING_CONFIG, + }, + { + .frontend_attach = mxl111sf_attach_demod, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP4_BULK_STREAMING_CONFIG, + }, + { + .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, + + .frontend_attach = mxl111sf_lg2160_frontend_attach, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP5_BULK_STREAMING_CONFIG, + }}, + }, + }, + .num_device_descs = 2, + .devices = { { "Hauppauge 126xxx ATSC+ (bulk)", { NULL }, { &mxl111sf_table[0], &mxl111sf_table[3], @@ -963,13 +1439,96 @@ static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = { &mxl111sf_table[32], &mxl111sf_table[33], NULL }, }, - { "Hauppauge Mercury (tp-bulk)", + } +}; + +static struct dvb_usb_device_properties mxl111sf_atsc_mh_isoc_properties = { + MXL111SF_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + .num_frontends = 3, + .fe = {{ + .frontend_attach = mxl111sf_lgdt3305_frontend_attach, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP6_ISOC_STREAMING_CONFIG, + }, + { + .frontend_attach = mxl111sf_attach_demod, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP4_ISOC_STREAMING_CONFIG, + }, + { + .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, + + .frontend_attach = mxl111sf_lg2160_frontend_attach, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP5_ISOC_STREAMING_CONFIG, + }}, + }, + }, + .num_device_descs = 2, + .devices = { + { "Hauppauge 126xxx ATSC+ (isoc)", + { NULL }, + { &mxl111sf_table[0], &mxl111sf_table[3], + &mxl111sf_table[7], &mxl111sf_table[9], + &mxl111sf_table[10], NULL }, + }, + { "Hauppauge 117xxx ATSC+ (isoc)", + { NULL }, + { &mxl111sf_table[11], &mxl111sf_table[14], + &mxl111sf_table[16], &mxl111sf_table[17], + &mxl111sf_table[32], &mxl111sf_table[33], + NULL }, + }, + } +}; + +static struct dvb_usb_device_properties mxl111sf_mercury_spi_bulk_properties = { + MXL111SF_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + .num_frontends = 3, + .fe = {{ + .frontend_attach = mxl111sf_lgdt3305_frontend_attach, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP6_BULK_STREAMING_CONFIG, + }, + { + .frontend_attach = mxl111sf_attach_demod, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP4_BULK_STREAMING_CONFIG, + }, + { + .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, + + .frontend_attach = mxl111sf_lg2161_frontend_attach, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP5_BULK_STREAMING_CONFIG, + }}, + }, + }, + .num_device_descs = 2, + .devices = { + { "Hauppauge Mercury (spi-bulk)", { NULL }, { &mxl111sf_table[19], &mxl111sf_table[21], &mxl111sf_table[23], &mxl111sf_table[25], - &mxl111sf_table[27], NULL }, + NULL }, }, - { "Hauppauge WinTV-Aero-M", + { "Hauppauge WinTV-Aero-M (spi-bulk)", { NULL }, { &mxl111sf_table[29], &mxl111sf_table[31], NULL }, @@ -977,14 +1536,14 @@ static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = { } }; -static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = { +static struct dvb_usb_device_properties mxl111sf_mercury_spi_isoc_properties = { MXL111SF_DEFAULT_DEVICE_PROPERTIES, .num_adapters = 1, .adapter = { { .fe_ioctl_override = mxl111sf_fe_ioctl_override, - .num_frontends = 2, + .num_frontends = 3, .fe = {{ .frontend_attach = mxl111sf_lgdt3305_frontend_attach, .tuner_attach = mxl111sf_attach_tuner, @@ -996,34 +1555,111 @@ static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = { .tuner_attach = mxl111sf_attach_tuner, MXL111SF_EP4_ISOC_STREAMING_CONFIG, + }, + { + .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, + + .frontend_attach = mxl111sf_lg2161_frontend_attach, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP5_ISOC_STREAMING_CONFIG, }}, }, }, - .num_device_descs = 6, + .num_device_descs = 2, .devices = { - { "Hauppauge 126xxx ATSC (isoc)", + { "Hauppauge Mercury (spi-isoc)", { NULL }, - { &mxl111sf_table[1], &mxl111sf_table[5], + { &mxl111sf_table[19], &mxl111sf_table[21], + &mxl111sf_table[23], &mxl111sf_table[25], NULL }, }, - { "Hauppauge 117xxx ATSC (isoc)", + { "Hauppauge WinTV-Aero-M (spi-isoc)", { NULL }, - { &mxl111sf_table[12], + { &mxl111sf_table[29], &mxl111sf_table[31], NULL }, }, - { "Hauppauge 126xxx ATSC+ (isoc)", + } +}; + +static struct dvb_usb_device_properties mxl111sf_mercury_tp_bulk_properties = { + MXL111SF_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + .num_frontends = 3, + .fe = {{ + .frontend_attach = mxl111sf_lgdt3305_frontend_attach, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP6_BULK_STREAMING_CONFIG, + }, + { + .frontend_attach = mxl111sf_attach_demod, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP4_BULK_STREAMING_CONFIG, + }, + { + .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, + + .frontend_attach = mxl111sf_lg2161_ep6_frontend_attach, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP6_BULK_STREAMING_CONFIG, + }}, + }, + }, + .num_device_descs = 2, + .devices = { + { "Hauppauge Mercury (tp-bulk)", { NULL }, - { &mxl111sf_table[0], &mxl111sf_table[3], - &mxl111sf_table[7], &mxl111sf_table[9], - &mxl111sf_table[10], NULL }, + { &mxl111sf_table[19], &mxl111sf_table[21], + &mxl111sf_table[23], &mxl111sf_table[25], + &mxl111sf_table[27], NULL }, }, - { "Hauppauge 117xxx ATSC+ (isoc)", + { "Hauppauge WinTV-Aero-M", { NULL }, - { &mxl111sf_table[11], &mxl111sf_table[14], - &mxl111sf_table[16], &mxl111sf_table[17], - &mxl111sf_table[32], &mxl111sf_table[33], + { &mxl111sf_table[29], &mxl111sf_table[31], NULL }, }, + } +}; + +static struct dvb_usb_device_properties mxl111sf_mercury_tp_isoc_properties = { + MXL111SF_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + .num_frontends = 3, + .fe = {{ + .frontend_attach = mxl111sf_lgdt3305_frontend_attach, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP6_ISOC_STREAMING_CONFIG, + }, + { + .frontend_attach = mxl111sf_attach_demod, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP4_ISOC_STREAMING_CONFIG, + }, + { + .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, + + .frontend_attach = mxl111sf_lg2161_ep6_frontend_attach, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP6_ISOC_STREAMING_CONFIG, + }}, + }, + }, + .num_device_descs = 2, + .devices = { { "Hauppauge Mercury (tp-isoc)", { NULL }, { &mxl111sf_table[19], &mxl111sf_table[21], @@ -1038,6 +1674,146 @@ static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = { } }; +static +struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_bulk_properties = { + MXL111SF_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + .num_frontends = 2, + .fe = {{ + .frontend_attach = mxl111sf_attach_demod, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP4_BULK_STREAMING_CONFIG, + }, + { + .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, + + .frontend_attach = mxl111sf_lg2161_ep6_frontend_attach, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP6_BULK_STREAMING_CONFIG, + }}, + }, + }, + .num_device_descs = 1, + .devices = { + { "Hauppauge 126xxx (tp-bulk)", + { NULL }, + { &mxl111sf_table[28], &mxl111sf_table[30], + NULL }, + }, + } +}; + +static +struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_isoc_properties = { + MXL111SF_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + .num_frontends = 2, + .fe = {{ + .frontend_attach = mxl111sf_attach_demod, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP4_ISOC_STREAMING_CONFIG, + }, + { + .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, + + .frontend_attach = mxl111sf_lg2161_ep6_frontend_attach, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP6_ISOC_STREAMING_CONFIG, + }}, + }, + }, + .num_device_descs = 1, + .devices = { + { "Hauppauge 126xxx (tp-isoc)", + { NULL }, + { &mxl111sf_table[28], &mxl111sf_table[30], + NULL }, + }, + } +}; + +static +struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_bulk_properties = { + MXL111SF_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + .num_frontends = 2, + .fe = {{ + .frontend_attach = mxl111sf_attach_demod, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP4_BULK_STREAMING_CONFIG, + }, + { + .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, + + .frontend_attach = mxl111sf_lg2161_frontend_attach, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP5_BULK_STREAMING_CONFIG, + }}, + }, + }, + .num_device_descs = 1, + .devices = { + { "Hauppauge 126xxx (spi-bulk)", + { NULL }, + { &mxl111sf_table[28], &mxl111sf_table[30], + NULL }, + }, + } +}; + +static +struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_isoc_properties = { + MXL111SF_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + .num_frontends = 2, + .fe = {{ + .frontend_attach = mxl111sf_attach_demod, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP4_ISOC_STREAMING_CONFIG, + }, + { + .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, + + .frontend_attach = mxl111sf_lg2161_frontend_attach, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP5_ISOC_STREAMING_CONFIG, + }}, + }, + }, + .num_device_descs = 1, + .devices = { + { "Hauppauge 126xxx (spi-isoc)", + { NULL }, + { &mxl111sf_table[28], &mxl111sf_table[30], + NULL }, + }, + } +}; + static struct usb_driver mxl111sf_driver = { .name = "dvb_usb_mxl111sf", .probe = mxl111sf_probe, diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.c b/drivers/media/dvb/dvb-usb/rtl28xxu.c index 8f4736a10fc..41e1f5537f4 100644 --- a/drivers/media/dvb/dvb-usb/rtl28xxu.c +++ b/drivers/media/dvb/dvb-usb/rtl28xxu.c @@ -322,6 +322,9 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap) * since there is some demod params needed to set according to tuner. */ + /* demod needs some time to wake up */ + msleep(20); + /* open demod I2C gate */ ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate); if (ret) @@ -909,6 +912,8 @@ static int rtl28xxu_probe(struct usb_interface *intf, int ret, i; int properties_count = ARRAY_SIZE(rtl28xxu_properties); struct dvb_usb_device *d; + struct usb_device *udev; + bool found; deb_info("%s: interface=%d\n", __func__, intf->cur_altsetting->desc.bInterfaceNumber); @@ -916,6 +921,29 @@ static int rtl28xxu_probe(struct usb_interface *intf, if (intf->cur_altsetting->desc.bInterfaceNumber != 0) return 0; + /* Dynamic USB ID support. Replaces first device ID with current one .*/ + udev = interface_to_usbdev(intf); + + for (i = 0, found = false; i < ARRAY_SIZE(rtl28xxu_table) - 1; i++) { + if (rtl28xxu_table[i].idVendor == + le16_to_cpu(udev->descriptor.idVendor) && + rtl28xxu_table[i].idProduct == + le16_to_cpu(udev->descriptor.idProduct)) { + found = true; + break; + } + } + + if (!found) { + deb_info("%s: using dynamic ID %04x:%04x\n", __func__, + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); + rtl28xxu_properties[0].devices[0].warm_ids[0]->idVendor = + le16_to_cpu(udev->descriptor.idVendor); + rtl28xxu_properties[0].devices[0].warm_ids[0]->idProduct = + le16_to_cpu(udev->descriptor.idProduct); + } + for (i = 0; i < properties_count; i++) { ret = dvb_usb_device_init(intf, &rtl28xxu_properties[i], THIS_MODULE, &d, adapter_nr); diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 21246707fbf..b98ebb264e2 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -531,6 +531,14 @@ config DVB_LGDT3305 An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. +config DVB_LG2160 + tristate "LG Electronics LG216x based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + An ATSC/MH demodulator module. Say Y when you want + to support this frontend. + config DVB_S5H1409 tristate "Samsung S5H1409 based" depends on DVB_CORE && I2C @@ -540,12 +548,26 @@ config DVB_S5H1409 to support this frontend. config DVB_AU8522 - tristate "Auvitek AU8522 based" - depends on DVB_CORE && I2C && VIDEO_V4L2 + depends on I2C + tristate + +config DVB_AU8522_DTV + tristate "Auvitek AU8522 based DTV demod" + depends on DVB_CORE && I2C + select DVB_AU8522 default m if DVB_FE_CUSTOMISE help - An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want - to support this frontend. + An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when + you want to enable DTV demodulation support for this frontend. + +config DVB_AU8522_V4L + tristate "Auvitek AU8522 based ATV demod" + depends on VIDEO_V4L2 && I2C + select DVB_AU8522 + default m if DVB_FE_CUSTOMISE + help + An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when + you want to enable ATV demodulation support for this frontend. config DVB_S5H1411 tristate "Samsung S5H1411 based" @@ -713,6 +735,11 @@ config DVB_M88RS2000 A DVB-S tuner module. Say Y when you want to support this frontend. +config DVB_AF9033 + tristate "Afatech AF9033 DVB-T demodulator" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + comment "Tools to develop new frontends" config DVB_DUMMY_FE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 86fa808bf58..cd1ac2fd577 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -7,7 +7,6 @@ ccflags-y += -I$(srctree)/drivers/media/common/tuners/ stb0899-objs = stb0899_drv.o stb0899_algo.o stv0900-objs = stv0900_core.o stv0900_sw.o -au8522-objs = au8522_dig.o au8522_decoder.o drxd-objs = drxd_firm.o drxd_hard.o cxd2820r-objs = cxd2820r_core.o cxd2820r_c.o cxd2820r_t.o cxd2820r_t2.o drxk-objs := drxk_hard.o @@ -50,6 +49,7 @@ obj-$(CONFIG_DVB_BCM3510) += bcm3510.o obj-$(CONFIG_DVB_S5H1420) += s5h1420.o obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o +obj-$(CONFIG_DVB_LG2160) += lg2160.o obj-$(CONFIG_DVB_CX24123) += cx24123.o obj-$(CONFIG_DVB_LNBP21) += lnbp21.o obj-$(CONFIG_DVB_LNBP22) += lnbp22.o @@ -63,7 +63,9 @@ obj-$(CONFIG_DVB_TUNER_DIB0090) += dib0090.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o obj-$(CONFIG_DVB_S5H1409) += s5h1409.o obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o -obj-$(CONFIG_DVB_AU8522) += au8522.o +obj-$(CONFIG_DVB_AU8522) += au8522_common.o +obj-$(CONFIG_DVB_AU8522_DTV) += au8522_dig.o +obj-$(CONFIG_DVB_AU8522_V4L) += au8522_decoder.o obj-$(CONFIG_DVB_TDA10048) += tda10048.o obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o obj-$(CONFIG_DVB_S5H1411) += s5h1411.o @@ -98,4 +100,5 @@ obj-$(CONFIG_DVB_A8293) += a8293.o obj-$(CONFIG_DVB_TDA10071) += tda10071.o obj-$(CONFIG_DVB_RTL2830) += rtl2830.o obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o +obj-$(CONFIG_DVB_AF9033) += af9033.o diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c index 6bcbcf543b3..5bc570d7784 100644 --- a/drivers/media/dvb/frontends/af9013.c +++ b/drivers/media/dvb/frontends/af9013.c @@ -514,7 +514,6 @@ err: static void af9013_statistics_work(struct work_struct *work) { - int ret; struct af9013_state *state = container_of(work, struct af9013_state, statistics_work.work); unsigned int next_msec; @@ -530,27 +529,27 @@ static void af9013_statistics_work(struct work_struct *work) default: state->statistics_step = 0; case 0: - ret = af9013_statistics_signal_strength(&state->fe); + af9013_statistics_signal_strength(&state->fe); state->statistics_step++; next_msec = 300; break; case 1: - ret = af9013_statistics_snr_start(&state->fe); + af9013_statistics_snr_start(&state->fe); state->statistics_step++; next_msec = 200; break; case 2: - ret = af9013_statistics_ber_unc_start(&state->fe); + af9013_statistics_ber_unc_start(&state->fe); state->statistics_step++; next_msec = 1000; break; case 3: - ret = af9013_statistics_snr_result(&state->fe); + af9013_statistics_snr_result(&state->fe); state->statistics_step++; next_msec = 400; break; case 4: - ret = af9013_statistics_ber_unc_result(&state->fe); + af9013_statistics_ber_unc_result(&state->fe); state->statistics_step++; next_msec = 100; break; @@ -558,8 +557,6 @@ static void af9013_statistics_work(struct work_struct *work) schedule_delayed_work(&state->statistics_work, msecs_to_jiffies(next_msec)); - - return; } static int af9013_get_tune_settings(struct dvb_frontend *fe, diff --git a/drivers/media/dvb/frontends/af9033.c b/drivers/media/dvb/frontends/af9033.c new file mode 100644 index 00000000000..a3899828626 --- /dev/null +++ b/drivers/media/dvb/frontends/af9033.c @@ -0,0 +1,980 @@ +/* + * Afatech AF9033 demodulator driver + * + * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> + * Copyright (C) 2012 Antti Palosaari <crope@iki.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "af9033_priv.h" + +struct af9033_state { + struct i2c_adapter *i2c; + struct dvb_frontend fe; + struct af9033_config cfg; + + u32 bandwidth_hz; + bool ts_mode_parallel; + bool ts_mode_serial; + + u32 ber; + u32 ucb; + unsigned long last_stat_check; +}; + +/* write multiple registers */ +static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val, + int len) +{ + int ret; + u8 buf[3 + len]; + struct i2c_msg msg[1] = { + { + .addr = state->cfg.i2c_addr, + .flags = 0, + .len = sizeof(buf), + .buf = buf, + } + }; + + buf[0] = (reg >> 16) & 0xff; + buf[1] = (reg >> 8) & 0xff; + buf[2] = (reg >> 0) & 0xff; + memcpy(&buf[3], val, len); + + ret = i2c_transfer(state->i2c, msg, 1); + if (ret == 1) { + ret = 0; + } else { + printk(KERN_WARNING "%s: i2c wr failed=%d reg=%06x len=%d\n", + __func__, ret, reg, len); + ret = -EREMOTEIO; + } + + return ret; +} + +/* read multiple registers */ +static int af9033_rd_regs(struct af9033_state *state, u32 reg, u8 *val, int len) +{ + int ret; + u8 buf[3] = { (reg >> 16) & 0xff, (reg >> 8) & 0xff, + (reg >> 0) & 0xff }; + struct i2c_msg msg[2] = { + { + .addr = state->cfg.i2c_addr, + .flags = 0, + .len = sizeof(buf), + .buf = buf + }, { + .addr = state->cfg.i2c_addr, + .flags = I2C_M_RD, + .len = len, + .buf = val + } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + if (ret == 2) { + ret = 0; + } else { + printk(KERN_WARNING "%s: i2c rd failed=%d reg=%06x len=%d\n", + __func__, ret, reg, len); + ret = -EREMOTEIO; + } + + return ret; +} + + +/* write single register */ +static int af9033_wr_reg(struct af9033_state *state, u32 reg, u8 val) +{ + return af9033_wr_regs(state, reg, &val, 1); +} + +/* read single register */ +static int af9033_rd_reg(struct af9033_state *state, u32 reg, u8 *val) +{ + return af9033_rd_regs(state, reg, val, 1); +} + +/* write single register with mask */ +static int af9033_wr_reg_mask(struct af9033_state *state, u32 reg, u8 val, + u8 mask) +{ + int ret; + u8 tmp; + + /* no need for read if whole reg is written */ + if (mask != 0xff) { + ret = af9033_rd_regs(state, reg, &tmp, 1); + if (ret) + return ret; + + val &= mask; + tmp &= ~mask; + val |= tmp; + } + + return af9033_wr_regs(state, reg, &val, 1); +} + +/* read single register with mask */ +static int af9033_rd_reg_mask(struct af9033_state *state, u32 reg, u8 *val, + u8 mask) +{ + int ret, i; + u8 tmp; + + ret = af9033_rd_regs(state, reg, &tmp, 1); + if (ret) + return ret; + + tmp &= mask; + + /* find position of the first bit */ + for (i = 0; i < 8; i++) { + if ((mask >> i) & 0x01) + break; + } + *val = tmp >> i; + + return 0; +} + +static u32 af9033_div(u32 a, u32 b, u32 x) +{ + u32 r = 0, c = 0, i; + + pr_debug("%s: a=%d b=%d x=%d\n", __func__, a, b, x); + + if (a > b) { + c = a / b; + a = a - c * b; + } + + for (i = 0; i < x; i++) { + if (a >= b) { + r += 1; + a -= b; + } + a <<= 1; + r <<= 1; + } + r = (c << (u32)x) + r; + + pr_debug("%s: a=%d b=%d x=%d r=%d r=%x\n", __func__, a, b, x, r, r); + + return r; +} + +static void af9033_release(struct dvb_frontend *fe) +{ + struct af9033_state *state = fe->demodulator_priv; + + kfree(state); +} + +static int af9033_init(struct dvb_frontend *fe) +{ + struct af9033_state *state = fe->demodulator_priv; + int ret, i, len; + const struct reg_val *init; + u8 buf[4]; + u32 adc_cw, clock_cw; + struct reg_val_mask tab[] = { + { 0x80fb24, 0x00, 0x08 }, + { 0x80004c, 0x00, 0xff }, + { 0x00f641, state->cfg.tuner, 0xff }, + { 0x80f5ca, 0x01, 0x01 }, + { 0x80f715, 0x01, 0x01 }, + { 0x00f41f, 0x04, 0x04 }, + { 0x00f41a, 0x01, 0x01 }, + { 0x80f731, 0x00, 0x01 }, + { 0x00d91e, 0x00, 0x01 }, + { 0x00d919, 0x00, 0x01 }, + { 0x80f732, 0x00, 0x01 }, + { 0x00d91f, 0x00, 0x01 }, + { 0x00d91a, 0x00, 0x01 }, + { 0x80f730, 0x00, 0x01 }, + { 0x80f778, 0x00, 0xff }, + { 0x80f73c, 0x01, 0x01 }, + { 0x80f776, 0x00, 0x01 }, + { 0x00d8fd, 0x01, 0xff }, + { 0x00d830, 0x01, 0xff }, + { 0x00d831, 0x00, 0xff }, + { 0x00d832, 0x00, 0xff }, + { 0x80f985, state->ts_mode_serial, 0x01 }, + { 0x80f986, state->ts_mode_parallel, 0x01 }, + { 0x00d827, 0x00, 0xff }, + { 0x00d829, 0x00, 0xff }, + }; + + /* program clock control */ + clock_cw = af9033_div(state->cfg.clock, 1000000ul, 19ul); + buf[0] = (clock_cw >> 0) & 0xff; + buf[1] = (clock_cw >> 8) & 0xff; + buf[2] = (clock_cw >> 16) & 0xff; + buf[3] = (clock_cw >> 24) & 0xff; + + pr_debug("%s: clock=%d clock_cw=%08x\n", __func__, state->cfg.clock, + clock_cw); + + ret = af9033_wr_regs(state, 0x800025, buf, 4); + if (ret < 0) + goto err; + + /* program ADC control */ + for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) { + if (clock_adc_lut[i].clock == state->cfg.clock) + break; + } + + adc_cw = af9033_div(clock_adc_lut[i].adc, 1000000ul, 19ul); + buf[0] = (adc_cw >> 0) & 0xff; + buf[1] = (adc_cw >> 8) & 0xff; + buf[2] = (adc_cw >> 16) & 0xff; + + pr_debug("%s: adc=%d adc_cw=%06x\n", __func__, clock_adc_lut[i].adc, + adc_cw); + + ret = af9033_wr_regs(state, 0x80f1cd, buf, 3); + if (ret < 0) + goto err; + + /* program register table */ + for (i = 0; i < ARRAY_SIZE(tab); i++) { + ret = af9033_wr_reg_mask(state, tab[i].reg, tab[i].val, + tab[i].mask); + if (ret < 0) + goto err; + } + + /* settings for TS interface */ + if (state->cfg.ts_mode == AF9033_TS_MODE_USB) { + ret = af9033_wr_reg_mask(state, 0x80f9a5, 0x00, 0x01); + if (ret < 0) + goto err; + + ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x01, 0x01); + if (ret < 0) + goto err; + } else { + ret = af9033_wr_reg_mask(state, 0x80f990, 0x00, 0x01); + if (ret < 0) + goto err; + + ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x00, 0x01); + if (ret < 0) + goto err; + } + + /* load OFSM settings */ + pr_debug("%s: load ofsm settings\n", __func__); + len = ARRAY_SIZE(ofsm_init); + init = ofsm_init; + for (i = 0; i < len; i++) { + ret = af9033_wr_reg(state, init[i].reg, init[i].val); + if (ret < 0) + goto err; + } + + /* load tuner specific settings */ + pr_debug("%s: load tuner specific settings\n", + __func__); + switch (state->cfg.tuner) { + case AF9033_TUNER_TUA9001: + len = ARRAY_SIZE(tuner_init_tua9001); + init = tuner_init_tua9001; + break; + case AF9033_TUNER_FC0011: + len = ARRAY_SIZE(tuner_init_fc0011); + init = tuner_init_fc0011; + break; + case AF9033_TUNER_MXL5007T: + len = ARRAY_SIZE(tuner_init_mxl5007t); + init = tuner_init_mxl5007t; + break; + case AF9033_TUNER_TDA18218: + len = ARRAY_SIZE(tuner_init_tda18218); + init = tuner_init_tda18218; + break; + default: + pr_debug("%s: unsupported tuner ID=%d\n", __func__, + state->cfg.tuner); + ret = -ENODEV; + goto err; + } + + for (i = 0; i < len; i++) { + ret = af9033_wr_reg(state, init[i].reg, init[i].val); + if (ret < 0) + goto err; + } + + state->bandwidth_hz = 0; /* force to program all parameters */ + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9033_sleep(struct dvb_frontend *fe) +{ + struct af9033_state *state = fe->demodulator_priv; + int ret, i; + u8 tmp; + + ret = af9033_wr_reg(state, 0x80004c, 1); + if (ret < 0) + goto err; + + ret = af9033_wr_reg(state, 0x800000, 0); + if (ret < 0) + goto err; + + for (i = 100, tmp = 1; i && tmp; i--) { + ret = af9033_rd_reg(state, 0x80004c, &tmp); + if (ret < 0) + goto err; + + usleep_range(200, 10000); + } + + pr_debug("%s: loop=%d\n", __func__, i); + + if (i == 0) { + ret = -ETIMEDOUT; + goto err; + } + + ret = af9033_wr_reg_mask(state, 0x80fb24, 0x08, 0x08); + if (ret < 0) + goto err; + + /* prevent current leak (?) */ + if (state->cfg.ts_mode == AF9033_TS_MODE_SERIAL) { + /* enable parallel TS */ + ret = af9033_wr_reg_mask(state, 0x00d917, 0x00, 0x01); + if (ret < 0) + goto err; + + ret = af9033_wr_reg_mask(state, 0x00d916, 0x01, 0x01); + if (ret < 0) + goto err; + } + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9033_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *fesettings) +{ + fesettings->min_delay_ms = 800; + fesettings->step_size = 0; + fesettings->max_drift = 0; + + return 0; +} + +static int af9033_set_frontend(struct dvb_frontend *fe) +{ + struct af9033_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret, i, spec_inv; + u8 tmp, buf[3], bandwidth_reg_val; + u32 if_frequency, freq_cw, adc_freq; + + pr_debug("%s: frequency=%d bandwidth_hz=%d\n", __func__, c->frequency, + c->bandwidth_hz); + + /* check bandwidth */ + switch (c->bandwidth_hz) { + case 6000000: + bandwidth_reg_val = 0x00; + break; + case 7000000: + bandwidth_reg_val = 0x01; + break; + case 8000000: + bandwidth_reg_val = 0x02; + break; + default: + pr_debug("%s: invalid bandwidth_hz\n", __func__); + ret = -EINVAL; + goto err; + } + + /* program tuner */ + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe); + + /* program CFOE coefficients */ + if (c->bandwidth_hz != state->bandwidth_hz) { + for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) { + if (coeff_lut[i].clock == state->cfg.clock && + coeff_lut[i].bandwidth_hz == c->bandwidth_hz) { + break; + } + } + ret = af9033_wr_regs(state, 0x800001, + coeff_lut[i].val, sizeof(coeff_lut[i].val)); + } + + /* program frequency control */ + if (c->bandwidth_hz != state->bandwidth_hz) { + spec_inv = state->cfg.spec_inv ? -1 : 1; + + for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) { + if (clock_adc_lut[i].clock == state->cfg.clock) + break; + } + adc_freq = clock_adc_lut[i].adc; + + /* get used IF frequency */ + if (fe->ops.tuner_ops.get_if_frequency) + fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); + else + if_frequency = 0; + + while (if_frequency > (adc_freq / 2)) + if_frequency -= adc_freq; + + if (if_frequency >= 0) + spec_inv *= -1; + else + if_frequency *= -1; + + freq_cw = af9033_div(if_frequency, adc_freq, 23ul); + + if (spec_inv == -1) + freq_cw *= -1; + + /* get adc multiplies */ + ret = af9033_rd_reg(state, 0x800045, &tmp); + if (ret < 0) + goto err; + + if (tmp == 1) + freq_cw /= 2; + + buf[0] = (freq_cw >> 0) & 0xff; + buf[1] = (freq_cw >> 8) & 0xff; + buf[2] = (freq_cw >> 16) & 0x7f; + ret = af9033_wr_regs(state, 0x800029, buf, 3); + if (ret < 0) + goto err; + + state->bandwidth_hz = c->bandwidth_hz; + } + + ret = af9033_wr_reg_mask(state, 0x80f904, bandwidth_reg_val, 0x03); + if (ret < 0) + goto err; + + ret = af9033_wr_reg(state, 0x800040, 0x00); + if (ret < 0) + goto err; + + ret = af9033_wr_reg(state, 0x800047, 0x00); + if (ret < 0) + goto err; + + ret = af9033_wr_reg_mask(state, 0x80f999, 0x00, 0x01); + if (ret < 0) + goto err; + + if (c->frequency <= 230000000) + tmp = 0x00; /* VHF */ + else + tmp = 0x01; /* UHF */ + + ret = af9033_wr_reg(state, 0x80004b, tmp); + if (ret < 0) + goto err; + + ret = af9033_wr_reg(state, 0x800000, 0x00); + if (ret < 0) + goto err; + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9033_get_frontend(struct dvb_frontend *fe) +{ + struct af9033_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret; + u8 buf[8]; + + pr_debug("%s\n", __func__); + + /* read all needed registers */ + ret = af9033_rd_regs(state, 0x80f900, buf, sizeof(buf)); + if (ret < 0) + goto err; + + switch ((buf[0] >> 0) & 3) { + case 0: + c->transmission_mode = TRANSMISSION_MODE_2K; + break; + case 1: + c->transmission_mode = TRANSMISSION_MODE_8K; + break; + } + + switch ((buf[1] >> 0) & 3) { + case 0: + c->guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + c->guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + c->guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + c->guard_interval = GUARD_INTERVAL_1_4; + break; + } + + switch ((buf[2] >> 0) & 7) { + case 0: + c->hierarchy = HIERARCHY_NONE; + break; + case 1: + c->hierarchy = HIERARCHY_1; + break; + case 2: + c->hierarchy = HIERARCHY_2; + break; + case 3: + c->hierarchy = HIERARCHY_4; + break; + } + + switch ((buf[3] >> 0) & 3) { + case 0: + c->modulation = QPSK; + break; + case 1: + c->modulation = QAM_16; + break; + case 2: + c->modulation = QAM_64; + break; + } + + switch ((buf[4] >> 0) & 3) { + case 0: + c->bandwidth_hz = 6000000; + break; + case 1: + c->bandwidth_hz = 7000000; + break; + case 2: + c->bandwidth_hz = 8000000; + break; + } + + switch ((buf[6] >> 0) & 7) { + case 0: + c->code_rate_HP = FEC_1_2; + break; + case 1: + c->code_rate_HP = FEC_2_3; + break; + case 2: + c->code_rate_HP = FEC_3_4; + break; + case 3: + c->code_rate_HP = FEC_5_6; + break; + case 4: + c->code_rate_HP = FEC_7_8; + break; + case 5: + c->code_rate_HP = FEC_NONE; + break; + } + + switch ((buf[7] >> 0) & 7) { + case 0: + c->code_rate_LP = FEC_1_2; + break; + case 1: + c->code_rate_LP = FEC_2_3; + break; + case 2: + c->code_rate_LP = FEC_3_4; + break; + case 3: + c->code_rate_LP = FEC_5_6; + break; + case 4: + c->code_rate_LP = FEC_7_8; + break; + case 5: + c->code_rate_LP = FEC_NONE; + break; + } + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct af9033_state *state = fe->demodulator_priv; + int ret; + u8 tmp; + + *status = 0; + + /* radio channel status, 0=no result, 1=has signal, 2=no signal */ + ret = af9033_rd_reg(state, 0x800047, &tmp); + if (ret < 0) + goto err; + + /* has signal */ + if (tmp == 0x01) + *status |= FE_HAS_SIGNAL; + + if (tmp != 0x02) { + /* TPS lock */ + ret = af9033_rd_reg_mask(state, 0x80f5a9, &tmp, 0x01); + if (ret < 0) + goto err; + + if (tmp) + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI; + + /* full lock */ + ret = af9033_rd_reg_mask(state, 0x80f999, &tmp, 0x01); + if (ret < 0) + goto err; + + if (tmp) + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | + FE_HAS_LOCK; + } + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct af9033_state *state = fe->demodulator_priv; + int ret, i, len; + u8 buf[3], tmp; + u32 snr_val; + const struct val_snr *uninitialized_var(snr_lut); + + /* read value */ + ret = af9033_rd_regs(state, 0x80002c, buf, 3); + if (ret < 0) + goto err; + + snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0]; + + /* read current modulation */ + ret = af9033_rd_reg(state, 0x80f903, &tmp); + if (ret < 0) + goto err; + + switch ((tmp >> 0) & 3) { + case 0: + len = ARRAY_SIZE(qpsk_snr_lut); + snr_lut = qpsk_snr_lut; + break; + case 1: + len = ARRAY_SIZE(qam16_snr_lut); + snr_lut = qam16_snr_lut; + break; + case 2: + len = ARRAY_SIZE(qam64_snr_lut); + snr_lut = qam64_snr_lut; + break; + default: + goto err; + } + + for (i = 0; i < len; i++) { + tmp = snr_lut[i].snr; + + if (snr_val < snr_lut[i].val) + break; + } + + *snr = tmp * 10; /* dB/10 */ + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct af9033_state *state = fe->demodulator_priv; + int ret; + u8 strength2; + + /* read signal strength of 0-100 scale */ + ret = af9033_rd_reg(state, 0x800048, &strength2); + if (ret < 0) + goto err; + + /* scale value to 0x0000-0xffff */ + *strength = strength2 * 0xffff / 100; + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9033_update_ch_stat(struct af9033_state *state) +{ + int ret = 0; + u32 err_cnt, bit_cnt; + u16 abort_cnt; + u8 buf[7]; + + /* only update data every half second */ + if (time_after(jiffies, state->last_stat_check + msecs_to_jiffies(500))) { + ret = af9033_rd_regs(state, 0x800032, buf, sizeof(buf)); + if (ret < 0) + goto err; + /* in 8 byte packets? */ + abort_cnt = (buf[1] << 8) + buf[0]; + /* in bits */ + err_cnt = (buf[4] << 16) + (buf[3] << 8) + buf[2]; + /* in 8 byte packets? always(?) 0x2710 = 10000 */ + bit_cnt = (buf[6] << 8) + buf[5]; + + if (bit_cnt < abort_cnt) { + abort_cnt = 1000; + state->ber = 0xffffffff; + } else { + /* 8 byte packets, that have not been rejected already */ + bit_cnt -= (u32)abort_cnt; + if (bit_cnt == 0) { + state->ber = 0xffffffff; + } else { + err_cnt -= (u32)abort_cnt * 8 * 8; + bit_cnt *= 8 * 8; + state->ber = err_cnt * (0xffffffff / bit_cnt); + } + } + state->ucb += abort_cnt; + state->last_stat_check = jiffies; + } + + return 0; +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +static int af9033_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct af9033_state *state = fe->demodulator_priv; + int ret; + + ret = af9033_update_ch_stat(state); + if (ret < 0) + return ret; + + *ber = state->ber; + + return 0; +} + +static int af9033_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct af9033_state *state = fe->demodulator_priv; + int ret; + + ret = af9033_update_ch_stat(state); + if (ret < 0) + return ret; + + *ucblocks = state->ucb; + + return 0; +} + +static int af9033_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct af9033_state *state = fe->demodulator_priv; + int ret; + + pr_debug("%s: enable=%d\n", __func__, enable); + + ret = af9033_wr_reg_mask(state, 0x00fa04, enable, 0x01); + if (ret < 0) + goto err; + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static struct dvb_frontend_ops af9033_ops; + +struct dvb_frontend *af9033_attach(const struct af9033_config *config, + struct i2c_adapter *i2c) +{ + int ret; + struct af9033_state *state; + u8 buf[8]; + + pr_debug("%s:\n", __func__); + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct af9033_state), GFP_KERNEL); + if (state == NULL) + goto err; + + /* setup the state */ + state->i2c = i2c; + memcpy(&state->cfg, config, sizeof(struct af9033_config)); + + if (state->cfg.clock != 12000000) { + printk(KERN_INFO "af9033: unsupported clock=%d, only " \ + "12000000 Hz is supported currently\n", + state->cfg.clock); + goto err; + } + + /* firmware version */ + ret = af9033_rd_regs(state, 0x0083e9, &buf[0], 4); + if (ret < 0) + goto err; + + ret = af9033_rd_regs(state, 0x804191, &buf[4], 4); + if (ret < 0) + goto err; + + printk(KERN_INFO "af9033: firmware version: LINK=%d.%d.%d.%d " \ + "OFDM=%d.%d.%d.%d\n", buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], buf[6], buf[7]); + + /* configure internal TS mode */ + switch (state->cfg.ts_mode) { + case AF9033_TS_MODE_PARALLEL: + state->ts_mode_parallel = true; + break; + case AF9033_TS_MODE_SERIAL: + state->ts_mode_serial = true; + break; + case AF9033_TS_MODE_USB: + /* usb mode for AF9035 */ + default: + break; + } + + /* create dvb_frontend */ + memcpy(&state->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops)); + state->fe.demodulator_priv = state; + + return &state->fe; + +err: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(af9033_attach); + +static struct dvb_frontend_ops af9033_ops = { + .delsys = { SYS_DVBT }, + .info = { + .name = "Afatech AF9033 (DVB-T)", + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 250000, + .frequency_tolerance = 0, + .caps = FE_CAN_FEC_1_2 | + FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | + FE_CAN_QAM_16 | + FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | + FE_CAN_RECOVER | + FE_CAN_MUTE_TS + }, + + .release = af9033_release, + + .init = af9033_init, + .sleep = af9033_sleep, + + .get_tune_settings = af9033_get_tune_settings, + .set_frontend = af9033_set_frontend, + .get_frontend = af9033_get_frontend, + + .read_status = af9033_read_status, + .read_snr = af9033_read_snr, + .read_signal_strength = af9033_read_signal_strength, + .read_ber = af9033_read_ber, + .read_ucblocks = af9033_read_ucblocks, + + .i2c_gate_ctrl = af9033_i2c_gate_ctrl, +}; + +MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("Afatech AF9033 DVB-T demodulator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/af9033.h b/drivers/media/dvb/frontends/af9033.h new file mode 100644 index 00000000000..9e302c3f0f7 --- /dev/null +++ b/drivers/media/dvb/frontends/af9033.h @@ -0,0 +1,75 @@ +/* + * Afatech AF9033 demodulator driver + * + * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> + * Copyright (C) 2012 Antti Palosaari <crope@iki.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef AF9033_H +#define AF9033_H + +struct af9033_config { + /* + * I2C address + */ + u8 i2c_addr; + + /* + * clock Hz + * 12000000, 22000000, 24000000, 34000000, 32000000, 28000000, 26000000, + * 30000000, 36000000, 20480000, 16384000 + */ + u32 clock; + + /* + * tuner + */ +#define AF9033_TUNER_TUA9001 0x27 /* Infineon TUA 9001 */ +#define AF9033_TUNER_FC0011 0x28 /* Fitipower FC0011 */ +#define AF9033_TUNER_MXL5007T 0xa0 /* MaxLinear MxL5007T */ +#define AF9033_TUNER_TDA18218 0xa1 /* NXP TDA 18218HN */ + u8 tuner; + + /* + * TS settings + */ +#define AF9033_TS_MODE_USB 0 +#define AF9033_TS_MODE_PARALLEL 1 +#define AF9033_TS_MODE_SERIAL 2 + u8 ts_mode:2; + + /* + * input spectrum inversion + */ + bool spec_inv; +}; + + +#if defined(CONFIG_DVB_AF9033) || \ + (defined(CONFIG_DVB_AF9033_MODULE) && defined(MODULE)) +extern struct dvb_frontend *af9033_attach(const struct af9033_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *af9033_attach( + const struct af9033_config *config, struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* AF9033_H */ diff --git a/drivers/media/dvb/frontends/af9033_priv.h b/drivers/media/dvb/frontends/af9033_priv.h new file mode 100644 index 00000000000..0b783b9ed75 --- /dev/null +++ b/drivers/media/dvb/frontends/af9033_priv.h @@ -0,0 +1,470 @@ +/* + * Afatech AF9033 demodulator driver + * + * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> + * Copyright (C) 2012 Antti Palosaari <crope@iki.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef AF9033_PRIV_H +#define AF9033_PRIV_H + +#include "dvb_frontend.h" +#include "af9033.h" + +struct reg_val { + u32 reg; + u8 val; +}; + +struct reg_val_mask { + u32 reg; + u8 val; + u8 mask; +}; + +struct coeff { + u32 clock; + u32 bandwidth_hz; + u8 val[36]; +}; + +struct clock_adc { + u32 clock; + u32 adc; +}; + +struct val_snr { + u32 val; + u8 snr; +}; + +/* Xtal clock vs. ADC clock lookup table */ +static const struct clock_adc clock_adc_lut[] = { + { 16384000, 20480000 }, + { 20480000, 20480000 }, + { 36000000, 20250000 }, + { 30000000, 20156250 }, + { 26000000, 20583333 }, + { 28000000, 20416667 }, + { 32000000, 20500000 }, + { 34000000, 20187500 }, + { 24000000, 20500000 }, + { 22000000, 20625000 }, + { 12000000, 20250000 }, +}; + +/* pre-calculated coeff lookup table */ +static const struct coeff coeff_lut[] = { + /* 12.000 MHz */ + { 12000000, 8000000, { + 0x01, 0xce, 0x55, 0xc9, 0x00, 0xe7, 0x2a, 0xe4, 0x00, 0x73, + 0x99, 0x0f, 0x00, 0x73, 0x95, 0x72, 0x00, 0x73, 0x91, 0xd5, + 0x00, 0x39, 0xca, 0xb9, 0x00, 0xe7, 0x2a, 0xe4, 0x00, 0x73, + 0x95, 0x72, 0x37, 0x02, 0xce, 0x01 } + }, + { 12000000, 7000000, { + 0x01, 0x94, 0x8b, 0x10, 0x00, 0xca, 0x45, 0x88, 0x00, 0x65, + 0x25, 0xed, 0x00, 0x65, 0x22, 0xc4, 0x00, 0x65, 0x1f, 0x9b, + 0x00, 0x32, 0x91, 0x62, 0x00, 0xca, 0x45, 0x88, 0x00, 0x65, + 0x22, 0xc4, 0x88, 0x02, 0x95, 0x01 } + }, + { 12000000, 6000000, { + 0x01, 0x5a, 0xc0, 0x56, 0x00, 0xad, 0x60, 0x2b, 0x00, 0x56, + 0xb2, 0xcb, 0x00, 0x56, 0xb0, 0x15, 0x00, 0x56, 0xad, 0x60, + 0x00, 0x2b, 0x58, 0x0b, 0x00, 0xad, 0x60, 0x2b, 0x00, 0x56, + 0xb0, 0x15, 0xf4, 0x02, 0x5b, 0x01 } + }, +}; + +/* QPSK SNR lookup table */ +static const struct val_snr qpsk_snr_lut[] = { + { 0x0b4771, 0 }, + { 0x0c1aed, 1 }, + { 0x0d0d27, 2 }, + { 0x0e4d19, 3 }, + { 0x0e5da8, 4 }, + { 0x107097, 5 }, + { 0x116975, 6 }, + { 0x1252d9, 7 }, + { 0x131fa4, 8 }, + { 0x13d5e1, 9 }, + { 0x148e53, 10 }, + { 0x15358b, 11 }, + { 0x15dd29, 12 }, + { 0x168112, 13 }, + { 0x170b61, 14 }, + { 0x17a532, 15 }, + { 0x180f94, 16 }, + { 0x186ed2, 17 }, + { 0x18b271, 18 }, + { 0x18e118, 19 }, + { 0x18ff4b, 20 }, + { 0x190af1, 21 }, + { 0x191451, 22 }, + { 0xffffff, 23 }, +}; + +/* QAM16 SNR lookup table */ +static const struct val_snr qam16_snr_lut[] = { + { 0x04f0d5, 0 }, + { 0x05387a, 1 }, + { 0x0573a4, 2 }, + { 0x05a99e, 3 }, + { 0x05cc80, 4 }, + { 0x05eb62, 5 }, + { 0x05fecf, 6 }, + { 0x060b80, 7 }, + { 0x062501, 8 }, + { 0x064865, 9 }, + { 0x069604, 10 }, + { 0x06f356, 11 }, + { 0x07706a, 12 }, + { 0x0804d3, 13 }, + { 0x089d1a, 14 }, + { 0x093e3d, 15 }, + { 0x09e35d, 16 }, + { 0x0a7c3c, 17 }, + { 0x0afaf8, 18 }, + { 0x0b719d, 19 }, + { 0x0bda6a, 20 }, + { 0x0c0c75, 21 }, + { 0x0c3f7d, 22 }, + { 0x0c5e62, 23 }, + { 0x0c6c31, 24 }, + { 0x0c7925, 25 }, + { 0xffffff, 26 }, +}; + +/* QAM64 SNR lookup table */ +static const struct val_snr qam64_snr_lut[] = { + { 0x0256d0, 0 }, + { 0x027a65, 1 }, + { 0x029873, 2 }, + { 0x02b7fe, 3 }, + { 0x02cf1e, 4 }, + { 0x02e234, 5 }, + { 0x02f409, 6 }, + { 0x030046, 7 }, + { 0x030844, 8 }, + { 0x030a02, 9 }, + { 0x030cde, 10 }, + { 0x031031, 11 }, + { 0x03144c, 12 }, + { 0x0315dd, 13 }, + { 0x031920, 14 }, + { 0x0322d0, 15 }, + { 0x0339fc, 16 }, + { 0x0364a1, 17 }, + { 0x038bcc, 18 }, + { 0x03c7d3, 19 }, + { 0x0408cc, 20 }, + { 0x043bed, 21 }, + { 0x048061, 22 }, + { 0x04be95, 23 }, + { 0x04fa7d, 24 }, + { 0x052405, 25 }, + { 0x05570d, 26 }, + { 0x059feb, 27 }, + { 0x05bf38, 28 }, + { 0xffffff, 29 }, +}; + +static const struct reg_val ofsm_init[] = { + { 0x800051, 0x01 }, + { 0x800070, 0x0a }, + { 0x80007e, 0x04 }, + { 0x800081, 0x0a }, + { 0x80008a, 0x01 }, + { 0x80008e, 0x01 }, + { 0x800092, 0x06 }, + { 0x800099, 0x01 }, + { 0x80009f, 0xe1 }, + { 0x8000a0, 0xcf }, + { 0x8000a3, 0x01 }, + { 0x8000a5, 0x01 }, + { 0x8000a6, 0x01 }, + { 0x8000a9, 0x00 }, + { 0x8000aa, 0x01 }, + { 0x8000ab, 0x01 }, + { 0x8000b0, 0x01 }, + { 0x8000c0, 0x05 }, + { 0x8000c4, 0x19 }, + { 0x80f000, 0x0f }, + { 0x80f016, 0x10 }, + { 0x80f017, 0x04 }, + { 0x80f018, 0x05 }, + { 0x80f019, 0x04 }, + { 0x80f01a, 0x05 }, + { 0x80f021, 0x03 }, + { 0x80f022, 0x0a }, + { 0x80f023, 0x0a }, + { 0x80f02b, 0x00 }, + { 0x80f02c, 0x01 }, + { 0x80f064, 0x03 }, + { 0x80f065, 0xf9 }, + { 0x80f066, 0x03 }, + { 0x80f067, 0x01 }, + { 0x80f06f, 0xe0 }, + { 0x80f070, 0x03 }, + { 0x80f072, 0x0f }, + { 0x80f073, 0x03 }, + { 0x80f078, 0x00 }, + { 0x80f087, 0x00 }, + { 0x80f09b, 0x3f }, + { 0x80f09c, 0x00 }, + { 0x80f09d, 0x20 }, + { 0x80f09e, 0x00 }, + { 0x80f09f, 0x0c }, + { 0x80f0a0, 0x00 }, + { 0x80f130, 0x04 }, + { 0x80f132, 0x04 }, + { 0x80f144, 0x1a }, + { 0x80f146, 0x00 }, + { 0x80f14a, 0x01 }, + { 0x80f14c, 0x00 }, + { 0x80f14d, 0x00 }, + { 0x80f14f, 0x04 }, + { 0x80f158, 0x7f }, + { 0x80f15a, 0x00 }, + { 0x80f15b, 0x08 }, + { 0x80f15d, 0x03 }, + { 0x80f15e, 0x05 }, + { 0x80f163, 0x05 }, + { 0x80f166, 0x01 }, + { 0x80f167, 0x40 }, + { 0x80f168, 0x0f }, + { 0x80f17a, 0x00 }, + { 0x80f17b, 0x00 }, + { 0x80f183, 0x01 }, + { 0x80f19d, 0x40 }, + { 0x80f1bc, 0x36 }, + { 0x80f1bd, 0x00 }, + { 0x80f1cb, 0xa0 }, + { 0x80f1cc, 0x01 }, + { 0x80f204, 0x10 }, + { 0x80f214, 0x00 }, + { 0x80f40e, 0x0a }, + { 0x80f40f, 0x40 }, + { 0x80f410, 0x08 }, + { 0x80f55f, 0x0a }, + { 0x80f561, 0x15 }, + { 0x80f562, 0x20 }, + { 0x80f5df, 0xfb }, + { 0x80f5e0, 0x00 }, + { 0x80f5e3, 0x09 }, + { 0x80f5e4, 0x01 }, + { 0x80f5e5, 0x01 }, + { 0x80f5f8, 0x01 }, + { 0x80f5fd, 0x01 }, + { 0x80f600, 0x05 }, + { 0x80f601, 0x08 }, + { 0x80f602, 0x0b }, + { 0x80f603, 0x0e }, + { 0x80f604, 0x11 }, + { 0x80f605, 0x14 }, + { 0x80f606, 0x17 }, + { 0x80f607, 0x1f }, + { 0x80f60e, 0x00 }, + { 0x80f60f, 0x04 }, + { 0x80f610, 0x32 }, + { 0x80f611, 0x10 }, + { 0x80f707, 0xfc }, + { 0x80f708, 0x00 }, + { 0x80f709, 0x37 }, + { 0x80f70a, 0x00 }, + { 0x80f78b, 0x01 }, + { 0x80f80f, 0x40 }, + { 0x80f810, 0x54 }, + { 0x80f811, 0x5a }, + { 0x80f905, 0x01 }, + { 0x80fb06, 0x03 }, + { 0x80fd8b, 0x00 }, +}; + +/* Infineon TUA 9001 tuner init + AF9033_TUNER_TUA9001 = 0x27 */ +static const struct reg_val tuner_init_tua9001[] = { + { 0x800046, 0x27 }, + { 0x800057, 0x00 }, + { 0x800058, 0x01 }, + { 0x80005f, 0x00 }, + { 0x800060, 0x00 }, + { 0x80006d, 0x00 }, + { 0x800071, 0x05 }, + { 0x800072, 0x02 }, + { 0x800074, 0x01 }, + { 0x800075, 0x03 }, + { 0x800076, 0x02 }, + { 0x800077, 0x00 }, + { 0x800078, 0x01 }, + { 0x800079, 0x00 }, + { 0x80007a, 0x7e }, + { 0x80007b, 0x3e }, + { 0x800093, 0x00 }, + { 0x800094, 0x01 }, + { 0x800095, 0x02 }, + { 0x800096, 0x01 }, + { 0x800098, 0x0a }, + { 0x80009b, 0x05 }, + { 0x80009c, 0x80 }, + { 0x8000b3, 0x00 }, + { 0x8000c1, 0x01 }, + { 0x8000c2, 0x00 }, + { 0x80f007, 0x00 }, + { 0x80f01f, 0x82 }, + { 0x80f020, 0x00 }, + { 0x80f029, 0x82 }, + { 0x80f02a, 0x00 }, + { 0x80f047, 0x00 }, + { 0x80f054, 0x00 }, + { 0x80f055, 0x00 }, + { 0x80f077, 0x01 }, + { 0x80f1e6, 0x00 }, +}; + +/* Fitipower fc0011 tuner init + AF9033_TUNER_FC0011 = 0x28 */ +static const struct reg_val tuner_init_fc0011[] = { + { 0x800046, AF9033_TUNER_FC0011 }, + { 0x800057, 0x00 }, + { 0x800058, 0x01 }, + { 0x80005f, 0x00 }, + { 0x800060, 0x00 }, + { 0x800068, 0xa5 }, + { 0x80006e, 0x01 }, + { 0x800071, 0x0A }, + { 0x800072, 0x02 }, + { 0x800074, 0x01 }, + { 0x800079, 0x01 }, + { 0x800093, 0x00 }, + { 0x800094, 0x00 }, + { 0x800095, 0x00 }, + { 0x800096, 0x00 }, + { 0x80009b, 0x2D }, + { 0x80009c, 0x60 }, + { 0x80009d, 0x23 }, + { 0x8000a4, 0x50 }, + { 0x8000ad, 0x50 }, + { 0x8000b3, 0x01 }, + { 0x8000b7, 0x88 }, + { 0x8000b8, 0xa6 }, + { 0x8000c3, 0x01 }, + { 0x8000c4, 0x01 }, + { 0x8000c7, 0x69 }, + { 0x80F007, 0x00 }, + { 0x80F00A, 0x1B }, + { 0x80F00B, 0x1B }, + { 0x80F00C, 0x1B }, + { 0x80F00D, 0x1B }, + { 0x80F00E, 0xFF }, + { 0x80F00F, 0x01 }, + { 0x80F010, 0x00 }, + { 0x80F011, 0x02 }, + { 0x80F012, 0xFF }, + { 0x80F013, 0x01 }, + { 0x80F014, 0x00 }, + { 0x80F015, 0x02 }, + { 0x80F01B, 0xEF }, + { 0x80F01C, 0x01 }, + { 0x80F01D, 0x0f }, + { 0x80F01E, 0x02 }, + { 0x80F01F, 0x6E }, + { 0x80F020, 0x00 }, + { 0x80F025, 0xDE }, + { 0x80F026, 0x00 }, + { 0x80F027, 0x0A }, + { 0x80F028, 0x03 }, + { 0x80F029, 0x6E }, + { 0x80F02A, 0x00 }, + { 0x80F047, 0x00 }, + { 0x80F054, 0x00 }, + { 0x80F055, 0x00 }, + { 0x80F077, 0x01 }, + { 0x80F1E6, 0x00 }, +}; + +/* MaxLinear MxL5007T tuner init + AF9033_TUNER_MXL5007T = 0xa0 */ +static const struct reg_val tuner_init_mxl5007t[] = { + { 0x800046, 0x1b }, + { 0x800057, 0x01 }, + { 0x800058, 0x01 }, + { 0x80005f, 0x00 }, + { 0x800060, 0x00 }, + { 0x800068, 0x96 }, + { 0x800071, 0x05 }, + { 0x800072, 0x02 }, + { 0x800074, 0x01 }, + { 0x800079, 0x01 }, + { 0x800093, 0x00 }, + { 0x800094, 0x00 }, + { 0x800095, 0x00 }, + { 0x800096, 0x00 }, + { 0x8000b3, 0x01 }, + { 0x8000c1, 0x01 }, + { 0x8000c2, 0x00 }, + { 0x80f007, 0x00 }, + { 0x80f00c, 0x19 }, + { 0x80f00d, 0x1a }, + { 0x80f012, 0xda }, + { 0x80f013, 0x00 }, + { 0x80f014, 0x00 }, + { 0x80f015, 0x02 }, + { 0x80f01f, 0x82 }, + { 0x80f020, 0x00 }, + { 0x80f029, 0x82 }, + { 0x80f02a, 0x00 }, + { 0x80f077, 0x02 }, + { 0x80f1e6, 0x00 }, +}; + +/* NXP TDA 18218HN tuner init + AF9033_TUNER_TDA18218 = 0xa1 */ +static const struct reg_val tuner_init_tda18218[] = { + {0x800046, 0xa1}, + {0x800057, 0x01}, + {0x800058, 0x01}, + {0x80005f, 0x00}, + {0x800060, 0x00}, + {0x800071, 0x05}, + {0x800072, 0x02}, + {0x800074, 0x01}, + {0x800079, 0x01}, + {0x800093, 0x00}, + {0x800094, 0x00}, + {0x800095, 0x00}, + {0x800096, 0x00}, + {0x8000b3, 0x01}, + {0x8000c3, 0x01}, + {0x8000c4, 0x00}, + {0x80f007, 0x00}, + {0x80f00c, 0x19}, + {0x80f00d, 0x1a}, + {0x80f012, 0xda}, + {0x80f013, 0x00}, + {0x80f014, 0x00}, + {0x80f015, 0x02}, + {0x80f01f, 0x82}, + {0x80f020, 0x00}, + {0x80f029, 0x82}, + {0x80f02a, 0x00}, + {0x80f077, 0x02}, + {0x80f1e6, 0x00}, +}; + +#endif /* AF9033_PRIV_H */ + diff --git a/drivers/media/dvb/frontends/au8522_common.c b/drivers/media/dvb/frontends/au8522_common.c new file mode 100644 index 00000000000..5cfe151ee39 --- /dev/null +++ b/drivers/media/dvb/frontends/au8522_common.c @@ -0,0 +1,259 @@ +/* + Auvitek AU8522 QAM/8VSB demodulator driver + + Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> + Copyright (C) 2008 Devin Heitmueller <dheitmueller@linuxtv.org> + Copyright (C) 2005-2008 Auvitek International, Ltd. + Copyright (C) 2012 Michael Krufky <mkrufky@linuxtv.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include <linux/i2c.h> +#include "dvb_frontend.h" +#include "au8522_priv.h" + +MODULE_LICENSE("GPL"); + +static int debug; + +#define dprintk(arg...)\ + do { if (debug)\ + printk(arg);\ + } while (0) + +/* Despite the name "hybrid_tuner", the framework works just as well for + hybrid demodulators as well... */ +static LIST_HEAD(hybrid_tuner_instance_list); +static DEFINE_MUTEX(au8522_list_mutex); + +/* 16 bit registers, 8 bit values */ +int au8522_writereg(struct au8522_state *state, u16 reg, u8 data) +{ + int ret; + u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data }; + + struct i2c_msg msg = { .addr = state->config->demod_address, + .flags = 0, .buf = buf, .len = 3 }; + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, " + "ret == %i)\n", __func__, reg, data, ret); + + return (ret != 1) ? -1 : 0; +} +EXPORT_SYMBOL(au8522_writereg); + +u8 au8522_readreg(struct au8522_state *state, u16 reg) +{ + int ret; + u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff }; + u8 b1[] = { 0 }; + + struct i2c_msg msg[] = { + { .addr = state->config->demod_address, .flags = 0, + .buf = b0, .len = 2 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, + .buf = b1, .len = 1 } }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) + printk(KERN_ERR "%s: readreg error (ret == %i)\n", + __func__, ret); + return b1[0]; +} +EXPORT_SYMBOL(au8522_readreg); + +int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct au8522_state *state = fe->demodulator_priv; + + dprintk("%s(%d)\n", __func__, enable); + + if (state->operational_mode == AU8522_ANALOG_MODE) { + /* We're being asked to manage the gate even though we're + not in digital mode. This can occur if we get switched + over to analog mode before the dvb_frontend kernel thread + has completely shutdown */ + return 0; + } + + if (enable) + return au8522_writereg(state, 0x106, 1); + else + return au8522_writereg(state, 0x106, 0); +} +EXPORT_SYMBOL(au8522_i2c_gate_ctrl); + +/* Reset the demod hardware and reset all of the configuration registers + to a default state. */ +int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c, + u8 client_address) +{ + int ret; + + mutex_lock(&au8522_list_mutex); + ret = hybrid_tuner_request_state(struct au8522_state, (*state), + hybrid_tuner_instance_list, + i2c, client_address, "au8522"); + mutex_unlock(&au8522_list_mutex); + + return ret; +} +EXPORT_SYMBOL(au8522_get_state); + +void au8522_release_state(struct au8522_state *state) +{ + mutex_lock(&au8522_list_mutex); + if (state != NULL) + hybrid_tuner_release_state(state); + mutex_unlock(&au8522_list_mutex); +} +EXPORT_SYMBOL(au8522_release_state); + +static int au8522_led_gpio_enable(struct au8522_state *state, int onoff) +{ + struct au8522_led_config *led_config = state->config->led_cfg; + u8 val; + + /* bail out if we can't control an LED */ + if (!led_config || !led_config->gpio_output || + !led_config->gpio_output_enable || !led_config->gpio_output_disable) + return 0; + + val = au8522_readreg(state, 0x4000 | + (led_config->gpio_output & ~0xc000)); + if (onoff) { + /* enable GPIO output */ + val &= ~((led_config->gpio_output_enable >> 8) & 0xff); + val |= (led_config->gpio_output_enable & 0xff); + } else { + /* disable GPIO output */ + val &= ~((led_config->gpio_output_disable >> 8) & 0xff); + val |= (led_config->gpio_output_disable & 0xff); + } + return au8522_writereg(state, 0x8000 | + (led_config->gpio_output & ~0xc000), val); +} + +/* led = 0 | off + * led = 1 | signal ok + * led = 2 | signal strong + * led < 0 | only light led if leds are currently off + */ +int au8522_led_ctrl(struct au8522_state *state, int led) +{ + struct au8522_led_config *led_config = state->config->led_cfg; + int i, ret = 0; + + /* bail out if we can't control an LED */ + if (!led_config || !led_config->gpio_leds || + !led_config->num_led_states || !led_config->led_states) + return 0; + + if (led < 0) { + /* if LED is already lit, then leave it as-is */ + if (state->led_state) + return 0; + else + led *= -1; + } + + /* toggle LED if changing state */ + if (state->led_state != led) { + u8 val; + + dprintk("%s: %d\n", __func__, led); + + au8522_led_gpio_enable(state, 1); + + val = au8522_readreg(state, 0x4000 | + (led_config->gpio_leds & ~0xc000)); + + /* start with all leds off */ + for (i = 0; i < led_config->num_led_states; i++) + val &= ~led_config->led_states[i]; + + /* set selected LED state */ + if (led < led_config->num_led_states) + val |= led_config->led_states[led]; + else if (led_config->num_led_states) + val |= + led_config->led_states[led_config->num_led_states - 1]; + + ret = au8522_writereg(state, 0x8000 | + (led_config->gpio_leds & ~0xc000), val); + if (ret < 0) + return ret; + + state->led_state = led; + + if (led == 0) + au8522_led_gpio_enable(state, 0); + } + + return 0; +} +EXPORT_SYMBOL(au8522_led_ctrl); + +int au8522_init(struct dvb_frontend *fe) +{ + struct au8522_state *state = fe->demodulator_priv; + dprintk("%s()\n", __func__); + + state->operational_mode = AU8522_DIGITAL_MODE; + + /* Clear out any state associated with the digital side of the + chip, so that when it gets powered back up it won't think + that it is already tuned */ + state->current_frequency = 0; + + au8522_writereg(state, 0xa4, 1 << 5); + + au8522_i2c_gate_ctrl(fe, 1); + + return 0; +} +EXPORT_SYMBOL(au8522_init); + +int au8522_sleep(struct dvb_frontend *fe) +{ + struct au8522_state *state = fe->demodulator_priv; + dprintk("%s()\n", __func__); + + /* Only power down if the digital side is currently using the chip */ + if (state->operational_mode == AU8522_ANALOG_MODE) { + /* We're not in one of the expected power modes, which means + that the DVB thread is probably telling us to go to sleep + even though the analog frontend has already started using + the chip. So ignore the request */ + return 0; + } + + /* turn off led */ + au8522_led_ctrl(state, 0); + + /* Power down the chip */ + au8522_writereg(state, 0xa4, 1 << 5); + + state->current_frequency = 0; + + return 0; +} +EXPORT_SYMBOL(au8522_sleep); diff --git a/drivers/media/dvb/frontends/au8522_dig.c b/drivers/media/dvb/frontends/au8522_dig.c index 25f650934c7..5fc70d6cd04 100644 --- a/drivers/media/dvb/frontends/au8522_dig.c +++ b/drivers/media/dvb/frontends/au8522_dig.c @@ -30,74 +30,11 @@ static int debug; -/* Despite the name "hybrid_tuner", the framework works just as well for - hybrid demodulators as well... */ -static LIST_HEAD(hybrid_tuner_instance_list); -static DEFINE_MUTEX(au8522_list_mutex); - #define dprintk(arg...)\ do { if (debug)\ printk(arg);\ } while (0) -/* 16 bit registers, 8 bit values */ -int au8522_writereg(struct au8522_state *state, u16 reg, u8 data) -{ - int ret; - u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data }; - - struct i2c_msg msg = { .addr = state->config->demod_address, - .flags = 0, .buf = buf, .len = 3 }; - - ret = i2c_transfer(state->i2c, &msg, 1); - - if (ret != 1) - printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, " - "ret == %i)\n", __func__, reg, data, ret); - - return (ret != 1) ? -1 : 0; -} - -u8 au8522_readreg(struct au8522_state *state, u16 reg) -{ - int ret; - u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff }; - u8 b1[] = { 0 }; - - struct i2c_msg msg[] = { - { .addr = state->config->demod_address, .flags = 0, - .buf = b0, .len = 2 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, - .buf = b1, .len = 1 } }; - - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) - printk(KERN_ERR "%s: readreg error (ret == %i)\n", - __func__, ret); - return b1[0]; -} - -static int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct au8522_state *state = fe->demodulator_priv; - - dprintk("%s(%d)\n", __func__, enable); - - if (state->operational_mode == AU8522_ANALOG_MODE) { - /* We're being asked to manage the gate even though we're - not in digital mode. This can occur if we get switched - over to analog mode before the dvb_frontend kernel thread - has completely shutdown */ - return 0; - } - - if (enable) - return au8522_writereg(state, 0x106, 1); - else - return au8522_writereg(state, 0x106, 0); -} - struct mse2snr_tab { u16 val; u16 data; @@ -609,136 +546,6 @@ static int au8522_set_frontend(struct dvb_frontend *fe) return 0; } -/* Reset the demod hardware and reset all of the configuration registers - to a default state. */ -int au8522_init(struct dvb_frontend *fe) -{ - struct au8522_state *state = fe->demodulator_priv; - dprintk("%s()\n", __func__); - - state->operational_mode = AU8522_DIGITAL_MODE; - - /* Clear out any state associated with the digital side of the - chip, so that when it gets powered back up it won't think - that it is already tuned */ - state->current_frequency = 0; - - au8522_writereg(state, 0xa4, 1 << 5); - - au8522_i2c_gate_ctrl(fe, 1); - - return 0; -} - -static int au8522_led_gpio_enable(struct au8522_state *state, int onoff) -{ - struct au8522_led_config *led_config = state->config->led_cfg; - u8 val; - - /* bail out if we can't control an LED */ - if (!led_config || !led_config->gpio_output || - !led_config->gpio_output_enable || !led_config->gpio_output_disable) - return 0; - - val = au8522_readreg(state, 0x4000 | - (led_config->gpio_output & ~0xc000)); - if (onoff) { - /* enable GPIO output */ - val &= ~((led_config->gpio_output_enable >> 8) & 0xff); - val |= (led_config->gpio_output_enable & 0xff); - } else { - /* disable GPIO output */ - val &= ~((led_config->gpio_output_disable >> 8) & 0xff); - val |= (led_config->gpio_output_disable & 0xff); - } - return au8522_writereg(state, 0x8000 | - (led_config->gpio_output & ~0xc000), val); -} - -/* led = 0 | off - * led = 1 | signal ok - * led = 2 | signal strong - * led < 0 | only light led if leds are currently off - */ -static int au8522_led_ctrl(struct au8522_state *state, int led) -{ - struct au8522_led_config *led_config = state->config->led_cfg; - int i, ret = 0; - - /* bail out if we can't control an LED */ - if (!led_config || !led_config->gpio_leds || - !led_config->num_led_states || !led_config->led_states) - return 0; - - if (led < 0) { - /* if LED is already lit, then leave it as-is */ - if (state->led_state) - return 0; - else - led *= -1; - } - - /* toggle LED if changing state */ - if (state->led_state != led) { - u8 val; - - dprintk("%s: %d\n", __func__, led); - - au8522_led_gpio_enable(state, 1); - - val = au8522_readreg(state, 0x4000 | - (led_config->gpio_leds & ~0xc000)); - - /* start with all leds off */ - for (i = 0; i < led_config->num_led_states; i++) - val &= ~led_config->led_states[i]; - - /* set selected LED state */ - if (led < led_config->num_led_states) - val |= led_config->led_states[led]; - else if (led_config->num_led_states) - val |= - led_config->led_states[led_config->num_led_states - 1]; - - ret = au8522_writereg(state, 0x8000 | - (led_config->gpio_leds & ~0xc000), val); - if (ret < 0) - return ret; - - state->led_state = led; - - if (led == 0) - au8522_led_gpio_enable(state, 0); - } - - return 0; -} - -int au8522_sleep(struct dvb_frontend *fe) -{ - struct au8522_state *state = fe->demodulator_priv; - dprintk("%s()\n", __func__); - - /* Only power down if the digital side is currently using the chip */ - if (state->operational_mode == AU8522_ANALOG_MODE) { - /* We're not in one of the expected power modes, which means - that the DVB thread is probably telling us to go to sleep - even though the analog frontend has already started using - the chip. So ignore the request */ - return 0; - } - - /* turn off led */ - au8522_led_ctrl(state, 0); - - /* Power down the chip */ - au8522_writereg(state, 0xa4, 1 << 5); - - state->current_frequency = 0; - - return 0; -} - static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status) { struct au8522_state *state = fe->demodulator_priv; @@ -931,28 +738,6 @@ static int au8522_get_tune_settings(struct dvb_frontend *fe, static struct dvb_frontend_ops au8522_ops; -int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c, - u8 client_address) -{ - int ret; - - mutex_lock(&au8522_list_mutex); - ret = hybrid_tuner_request_state(struct au8522_state, (*state), - hybrid_tuner_instance_list, - i2c, client_address, "au8522"); - mutex_unlock(&au8522_list_mutex); - - return ret; -} - -void au8522_release_state(struct au8522_state *state) -{ - mutex_lock(&au8522_list_mutex); - if (state != NULL) - hybrid_tuner_release_state(state); - mutex_unlock(&au8522_list_mutex); -} - static void au8522_release(struct dvb_frontend *fe) { diff --git a/drivers/media/dvb/frontends/au8522_priv.h b/drivers/media/dvb/frontends/au8522_priv.h index 751e17d692a..6e4a438732b 100644 --- a/drivers/media/dvb/frontends/au8522_priv.h +++ b/drivers/media/dvb/frontends/au8522_priv.h @@ -81,6 +81,8 @@ int au8522_sleep(struct dvb_frontend *fe); int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c, u8 client_address); void au8522_release_state(struct au8522_state *state); +int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable); +int au8522_led_ctrl(struct au8522_state *state, int led); /* REGISTERS */ #define AU8522_INPUT_CONTROL_REG081H 0x081 diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index 5101f10f2d7..98ecaf0900d 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -512,14 +512,13 @@ static int cx24110_read_snr(struct dvb_frontend* fe, u16* snr) static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { struct cx24110_state *state = fe->demodulator_priv; - u32 lastbyer; if(cx24110_readreg(state,0x10)&0x40) { /* the RS error counter has finished one counting window */ cx24110_writereg(state,0x10,0x60); /* select the byer reg */ - lastbyer=cx24110_readreg(state,0x12)| - (cx24110_readreg(state,0x13)<<8)| - (cx24110_readreg(state,0x14)<<16); + cx24110_readreg(state, 0x12) | + (cx24110_readreg(state, 0x13) << 8) | + (cx24110_readreg(state, 0x14) << 16); cx24110_writereg(state,0x10,0x70); /* select the bler reg */ state->lastbler=cx24110_readreg(state,0x12)| (cx24110_readreg(state,0x13)<<8)| diff --git a/drivers/media/dvb/frontends/cxd2820r_core.c b/drivers/media/dvb/frontends/cxd2820r_core.c index 5c7c2aaf9bf..3bba37d74f5 100644 --- a/drivers/media/dvb/frontends/cxd2820r_core.c +++ b/drivers/media/dvb/frontends/cxd2820r_core.c @@ -526,12 +526,12 @@ static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe) if (ret) goto error; - if (status & FE_HAS_SIGNAL) + if (status & FE_HAS_LOCK) break; } /* check if we have a valid signal */ - if (status) { + if (status & FE_HAS_LOCK) { priv->last_tune_failed = 0; return DVBFE_ALGO_SEARCH_SUCCESS; } else { diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index 5ceadc285b3..3e1eefada0e 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -2396,11 +2396,6 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, more common) */ st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent; - /* FIXME: make sure the dev.parent field is initialized, or else - request_firmware() will hit an OOPS (this should be moved somewhere - more common) */ - st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent; - dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr); /* init 7090 tuner adapter */ diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c index 80848b4c15d..6201c59a78d 100644 --- a/drivers/media/dvb/frontends/dib9000.c +++ b/drivers/media/dvb/frontends/dib9000.c @@ -31,13 +31,6 @@ struct i2c_device { u8 *i2c_write_buffer; }; -/* lock */ -#define DIB_LOCK struct mutex -#define DibAcquireLock(lock) mutex_lock_interruptible(lock) -#define DibReleaseLock(lock) mutex_unlock(lock) -#define DibInitLock(lock) mutex_init(lock) -#define DibFreeLock(lock) - struct dib9000_pid_ctrl { #define DIB9000_PID_FILTER_CTRL 0 #define DIB9000_PID_FILTER 1 @@ -82,11 +75,11 @@ struct dib9000_state { } fe_mm[18]; u8 memcmd; - DIB_LOCK mbx_if_lock; /* to protect read/write operations */ - DIB_LOCK mbx_lock; /* to protect the whole mailbox handling */ + struct mutex mbx_if_lock; /* to protect read/write operations */ + struct mutex mbx_lock; /* to protect the whole mailbox handling */ - DIB_LOCK mem_lock; /* to protect the memory accesses */ - DIB_LOCK mem_mbx_lock; /* to protect the memory-based mailbox */ + struct mutex mem_lock; /* to protect the memory accesses */ + struct mutex mem_mbx_lock; /* to protect the memory-based mailbox */ #define MBX_MAX_WORDS (256 - 200 - 2) #define DIB9000_MSG_CACHE_SIZE 2 @@ -108,7 +101,7 @@ struct dib9000_state { struct i2c_msg msg[2]; u8 i2c_write_buffer[255]; u8 i2c_read_buffer[255]; - DIB_LOCK demod_lock; + struct mutex demod_lock; u8 get_frontend_internal; struct dib9000_pid_ctrl pid_ctrl[10]; s8 pid_ctrl_index; /* -1: empty list; -2: do not use the list */ @@ -446,13 +439,13 @@ static int dib9000_risc_mem_read(struct dib9000_state *state, u8 cmd, u8 * b, u1 if (!state->platform.risc.fw_is_running) return -EIO; - if (DibAcquireLock(&state->platform.risc.mem_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } dib9000_risc_mem_setup(state, cmd | 0x80); dib9000_risc_mem_read_chunks(state, b, len); - DibReleaseLock(&state->platform.risc.mem_lock); + mutex_unlock(&state->platform.risc.mem_lock); return 0; } @@ -462,13 +455,13 @@ static int dib9000_risc_mem_write(struct dib9000_state *state, u8 cmd, const u8 if (!state->platform.risc.fw_is_running) return -EIO; - if (DibAcquireLock(&state->platform.risc.mem_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } dib9000_risc_mem_setup(state, cmd); dib9000_risc_mem_write_chunks(state, b, m->size); - DibReleaseLock(&state->platform.risc.mem_lock); + mutex_unlock(&state->platform.risc.mem_lock); return 0; } @@ -537,7 +530,7 @@ static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data, if (!state->platform.risc.fw_is_running) return -EINVAL; - if (DibAcquireLock(&state->platform.risc.mbx_if_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } @@ -584,7 +577,7 @@ static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data, ret = (u8) dib9000_write_word_attr(state, 1043, 1 << 14, attr); out: - DibReleaseLock(&state->platform.risc.mbx_if_lock); + mutex_unlock(&state->platform.risc.mbx_if_lock); return ret; } @@ -602,7 +595,7 @@ static u8 dib9000_mbx_read(struct dib9000_state *state, u16 * data, u8 risc_id, if (!state->platform.risc.fw_is_running) return 0; - if (DibAcquireLock(&state->platform.risc.mbx_if_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) { dprintk("could not get the lock"); return 0; } @@ -643,7 +636,7 @@ static u8 dib9000_mbx_read(struct dib9000_state *state, u16 * data, u8 risc_id, /* Update register nb_mes_in_TX */ dib9000_write_word_attr(state, 1028 + mc_base, 1 << 14, attr); - DibReleaseLock(&state->platform.risc.mbx_if_lock); + mutex_unlock(&state->platform.risc.mbx_if_lock); return size + 1; } @@ -708,12 +701,11 @@ static u8 dib9000_mbx_count(struct dib9000_state *state, u8 risc_id, u16 attr) static int dib9000_mbx_process(struct dib9000_state *state, u16 attr) { int ret = 0; - u16 tmp; if (!state->platform.risc.fw_is_running) return -1; - if (DibAcquireLock(&state->platform.risc.mbx_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mbx_lock) < 0) { dprintk("could not get the lock"); return -1; } @@ -721,10 +713,10 @@ static int dib9000_mbx_process(struct dib9000_state *state, u16 attr) if (dib9000_mbx_count(state, 1, attr)) /* 1=RiscB */ ret = dib9000_mbx_fetch_to_cache(state, attr); - tmp = dib9000_read_word_attr(state, 1229, attr); /* Clear the IRQ */ + dib9000_read_word_attr(state, 1229, attr); /* Clear the IRQ */ /* if (tmp) */ /* dprintk( "cleared IRQ: %x", tmp); */ - DibReleaseLock(&state->platform.risc.mbx_lock); + mutex_unlock(&state->platform.risc.mbx_lock); return ret; } @@ -1193,7 +1185,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe) struct dibDVBTChannel *ch; int ret = 0; - if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } @@ -1323,7 +1315,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe) } error: - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); return ret; } @@ -1678,7 +1670,7 @@ static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2 p[12] = 0; } - if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { dprintk("could not get the lock"); return 0; } @@ -1692,7 +1684,7 @@ static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2 /* do the transaction */ if (dib9000_fw_memmbx_sync(state, FE_SYNC_COMPONENT_ACCESS) < 0) { - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); return 0; } @@ -1700,7 +1692,7 @@ static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2 if ((num > 1) && (msg[1].flags & I2C_M_RD)) dib9000_risc_mem_read(state, FE_MM_RW_COMPONENT_ACCESS_BUFFER, msg[1].buf, msg[1].len); - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); return num; } @@ -1789,7 +1781,7 @@ int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) return 0; } - if (DibAcquireLock(&state->demod_lock) < 0) { + if (mutex_lock_interruptible(&state->demod_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } @@ -1799,7 +1791,7 @@ int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) dprintk("PID filter enabled %d", onoff); ret = dib9000_write_word(state, 294 + 1, val); - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); return ret; } @@ -1824,14 +1816,14 @@ int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) return 0; } - if (DibAcquireLock(&state->demod_lock) < 0) { + if (mutex_lock_interruptible(&state->demod_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); ret = dib9000_write_word(state, 300 + 1 + id, onoff ? (1 << 13) | pid : 0); - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); return ret; } EXPORT_SYMBOL(dib9000_fw_pid_filter); @@ -1851,11 +1843,6 @@ static void dib9000_release(struct dvb_frontend *demod) for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++) dvb_frontend_detach(st->fe[index_frontend]); - DibFreeLock(&state->platform.risc.mbx_if_lock); - DibFreeLock(&state->platform.risc.mbx_lock); - DibFreeLock(&state->platform.risc.mem_lock); - DibFreeLock(&state->platform.risc.mem_mbx_lock); - DibFreeLock(&state->demod_lock); dibx000_exit_i2c_master(&st->i2c_master); i2c_del_adapter(&st->tuner_adap); @@ -1875,7 +1862,7 @@ static int dib9000_sleep(struct dvb_frontend *fe) u8 index_frontend; int ret = 0; - if (DibAcquireLock(&state->demod_lock) < 0) { + if (mutex_lock_interruptible(&state->demod_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } @@ -1887,7 +1874,7 @@ static int dib9000_sleep(struct dvb_frontend *fe) ret = dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0); error: - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); return ret; } @@ -1905,7 +1892,7 @@ static int dib9000_get_frontend(struct dvb_frontend *fe) int ret = 0; if (state->get_frontend_internal == 0) { - if (DibAcquireLock(&state->demod_lock) < 0) { + if (mutex_lock_interruptible(&state->demod_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } @@ -1964,7 +1951,7 @@ static int dib9000_get_frontend(struct dvb_frontend *fe) return_value: if (state->get_frontend_internal == 0) - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); return ret; } @@ -2012,7 +1999,7 @@ static int dib9000_set_frontend(struct dvb_frontend *fe) } state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */ - if (DibAcquireLock(&state->demod_lock) < 0) { + if (mutex_lock_interruptible(&state->demod_lock) < 0) { dprintk("could not get the lock"); return 0; } @@ -2081,7 +2068,7 @@ static int dib9000_set_frontend(struct dvb_frontend *fe) /* check the tune result */ if (exit_condition == 1) { /* tune failed */ dprintk("tune failed"); - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); /* tune failed; put all the pid filtering cmd to junk */ state->pid_ctrl_index = -1; return 0; @@ -2137,7 +2124,7 @@ static int dib9000_set_frontend(struct dvb_frontend *fe) /* turn off the diversity for the last frontend */ dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0); - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); if (state->pid_ctrl_index >= 0) { u8 index_pid_filter_cmd; u8 pid_ctrl_index = state->pid_ctrl_index; @@ -2175,7 +2162,7 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat) u8 index_frontend; u16 lock = 0, lock_slave = 0; - if (DibAcquireLock(&state->demod_lock) < 0) { + if (mutex_lock_interruptible(&state->demod_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } @@ -2197,7 +2184,7 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat) if ((lock & 0x0008) || (lock_slave & 0x0008)) *stat |= FE_HAS_LOCK; - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); return 0; } @@ -2208,30 +2195,30 @@ static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber) u16 *c; int ret = 0; - if (DibAcquireLock(&state->demod_lock) < 0) { + if (mutex_lock_interruptible(&state->demod_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } - if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { dprintk("could not get the lock"); ret = -EINTR; goto error; } if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); ret = -EIO; goto error; } dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, state->i2c_read_buffer, 16 * 2); - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); c = (u16 *)state->i2c_read_buffer; *ber = c[10] << 16 | c[11]; error: - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); return ret; } @@ -2243,7 +2230,7 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) u16 val; int ret = 0; - if (DibAcquireLock(&state->demod_lock) < 0) { + if (mutex_lock_interruptible(&state->demod_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } @@ -2256,18 +2243,18 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) *strength += val; } - if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { dprintk("could not get the lock"); ret = -EINTR; goto error; } if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); ret = -EIO; goto error; } dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); val = 65535 - c[4]; if (val > 65535 - *strength) @@ -2276,7 +2263,7 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) *strength += val; error: - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); return ret; } @@ -2287,16 +2274,16 @@ static u32 dib9000_get_snr(struct dvb_frontend *fe) u32 n, s, exp; u16 val; - if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { dprintk("could not get the lock"); return 0; } if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); return 0; } dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); val = c[7]; n = (val >> 4) & 0xff; @@ -2326,7 +2313,7 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr) u8 index_frontend; u32 snr_master; - if (DibAcquireLock(&state->demod_lock) < 0) { + if (mutex_lock_interruptible(&state->demod_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } @@ -2340,7 +2327,7 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr) } else *snr = 0; - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); return 0; } @@ -2351,27 +2338,27 @@ static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) u16 *c = (u16 *)state->i2c_read_buffer; int ret = 0; - if (DibAcquireLock(&state->demod_lock) < 0) { + if (mutex_lock_interruptible(&state->demod_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } - if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { dprintk("could not get the lock"); ret = -EINTR; goto error; } if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); ret = -EIO; goto error; } dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); *unc = c[12]; error: - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); return ret; } @@ -2514,11 +2501,11 @@ struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, c st->gpio_val = DIB9000_GPIO_DEFAULT_VALUES; st->gpio_pwm_pos = DIB9000_GPIO_DEFAULT_PWM_POS; - DibInitLock(&st->platform.risc.mbx_if_lock); - DibInitLock(&st->platform.risc.mbx_lock); - DibInitLock(&st->platform.risc.mem_lock); - DibInitLock(&st->platform.risc.mem_mbx_lock); - DibInitLock(&st->demod_lock); + mutex_init(&st->platform.risc.mbx_if_lock); + mutex_init(&st->platform.risc.mbx_lock); + mutex_init(&st->platform.risc.mem_lock); + mutex_init(&st->platform.risc.mem_mbx_lock); + mutex_init(&st->demod_lock); st->get_frontend_internal = 0; st->pid_ctrl_index = -2; diff --git a/drivers/media/dvb/frontends/drxd.h b/drivers/media/dvb/frontends/drxd.h index 34398738f9b..216c8c3702f 100644 --- a/drivers/media/dvb/frontends/drxd.h +++ b/drivers/media/dvb/frontends/drxd.h @@ -51,9 +51,23 @@ struct drxd_config { s16(*osc_deviation) (void *priv, s16 dev, int flag); }; +#if defined(CONFIG_DVB_DRXD) || \ + (defined(CONFIG_DVB_DRXD_MODULE) && defined(MODULE)) extern struct dvb_frontend *drxd_attach(const struct drxd_config *config, void *priv, struct i2c_adapter *i2c, struct device *dev); +#else +static inline +struct dvb_frontend *drxd_attach(const struct drxd_config *config, + void *priv, struct i2c_adapter *i2c, + struct device *dev) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __func__); + return NULL; +} +#endif + extern int drxd_config_i2c(struct dvb_frontend *, int); #endif diff --git a/drivers/media/dvb/frontends/drxk_hard.c b/drivers/media/dvb/frontends/drxk_hard.c index a414b1f2b6a..60b868faeac 100644 --- a/drivers/media/dvb/frontends/drxk_hard.c +++ b/drivers/media/dvb/frontends/drxk_hard.c @@ -1380,20 +1380,20 @@ static int DownloadMicrocode(struct drxk_state *state, const u8 pMCImage[], u32 Length) { const u8 *pSrc = pMCImage; - u16 Flags; - u16 Drain; u32 Address; u16 nBlocks; u16 BlockSize; - u16 BlockCRC; u32 offset = 0; u32 i; int status = 0; dprintk(1, "\n"); - /* down the drain (we don care about MAGIC_WORD) */ + /* down the drain (we don't care about MAGIC_WORD) */ +#if 0 + /* For future reference */ Drain = (pSrc[0] << 8) | pSrc[1]; +#endif pSrc += sizeof(u16); offset += sizeof(u16); nBlocks = (pSrc[0] << 8) | pSrc[1]; @@ -1410,11 +1410,17 @@ static int DownloadMicrocode(struct drxk_state *state, pSrc += sizeof(u16); offset += sizeof(u16); +#if 0 + /* For future reference */ Flags = (pSrc[0] << 8) | pSrc[1]; +#endif pSrc += sizeof(u16); offset += sizeof(u16); +#if 0 + /* For future reference */ BlockCRC = (pSrc[0] << 8) | pSrc[1]; +#endif pSrc += sizeof(u16); offset += sizeof(u16); @@ -5829,7 +5835,7 @@ static int WriteGPIO(struct drxk_state *state) } if (state->UIO_mask & 0x0002) { /* UIO-2 */ /* write to io pad configuration register - output mode */ - status = write16(state, SIO_PDR_SMA_TX_CFG__A, state->m_GPIOCfg); + status = write16(state, SIO_PDR_SMA_RX_CFG__A, state->m_GPIOCfg); if (status < 0) goto error; @@ -5848,7 +5854,7 @@ static int WriteGPIO(struct drxk_state *state) } if (state->UIO_mask & 0x0004) { /* UIO-3 */ /* write to io pad configuration register - output mode */ - status = write16(state, SIO_PDR_SMA_TX_CFG__A, state->m_GPIOCfg); + status = write16(state, SIO_PDR_GPIO_CFG__A, state->m_GPIOCfg); if (status < 0) goto error; diff --git a/drivers/media/dvb/frontends/drxk_map.h b/drivers/media/dvb/frontends/drxk_map.h index 9b11a832886..23e16c12f23 100644 --- a/drivers/media/dvb/frontends/drxk_map.h +++ b/drivers/media/dvb/frontends/drxk_map.h @@ -432,6 +432,7 @@ #define SIO_PDR_UIO_OUT_LO__A 0x7F0016 #define SIO_PDR_OHW_CFG__A 0x7F001F #define SIO_PDR_OHW_CFG_FREF_SEL__M 0x3 +#define SIO_PDR_GPIO_CFG__A 0x7F0021 #define SIO_PDR_MSTRT_CFG__A 0x7F0025 #define SIO_PDR_MERR_CFG__A 0x7F0026 #define SIO_PDR_MCLK_CFG__A 0x7F0028 @@ -446,4 +447,5 @@ #define SIO_PDR_MD5_CFG__A 0x7F0030 #define SIO_PDR_MD6_CFG__A 0x7F0031 #define SIO_PDR_MD7_CFG__A 0x7F0032 +#define SIO_PDR_SMA_RX_CFG__A 0x7F0037 #define SIO_PDR_SMA_TX_CFG__A 0x7F0038 diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c index af65d013db1..4c8ac2657c4 100644 --- a/drivers/media/dvb/frontends/ds3000.c +++ b/drivers/media/dvb/frontends/ds3000.c @@ -1114,7 +1114,10 @@ static int ds3000_set_frontend(struct dvb_frontend *fe) ds3000_writereg(state, ds3000_dvbs2_init_tab[i], ds3000_dvbs2_init_tab[i + 1]); - ds3000_writereg(state, 0xfe, 0x98); + if (c->symbol_rate >= 30000000) + ds3000_writereg(state, 0xfe, 0x54); + else + ds3000_writereg(state, 0xfe, 0x98); break; default: return 1; diff --git a/drivers/media/dvb/frontends/it913x-fe.c b/drivers/media/dvb/frontends/it913x-fe.c index 84df03c2917..708cbf19791 100644 --- a/drivers/media/dvb/frontends/it913x-fe.c +++ b/drivers/media/dvb/frontends/it913x-fe.c @@ -633,10 +633,9 @@ static int it913x_fe_read_snr(struct dvb_frontend *fe, u16 *snr) static int it913x_fe_read_ber(struct dvb_frontend *fe, u32 *ber) { struct it913x_fe_state *state = fe->demodulator_priv; - int ret; u8 reg[5]; /* Read Aborted Packets and Pre-Viterbi error rate 5 bytes */ - ret = it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg)); + it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg)); state->ucblocks += (u32)(reg[1] << 8) | reg[0]; *ber = (u32)(reg[4] << 16) | (reg[3] << 8) | reg[2]; return 0; @@ -658,10 +657,9 @@ static int it913x_fe_get_frontend(struct dvb_frontend *fe) { struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct it913x_fe_state *state = fe->demodulator_priv; - int ret; u8 reg[8]; - ret = it913x_read_reg(state, REG_TPSD_TX_MODE, reg, sizeof(reg)); + it913x_read_reg(state, REG_TPSD_TX_MODE, reg, sizeof(reg)); if (reg[3] < 3) p->modulation = fe_con[reg[3]]; @@ -691,25 +689,25 @@ static int it913x_fe_set_frontend(struct dvb_frontend *fe) { struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct it913x_fe_state *state = fe->demodulator_priv; - int ret, i; + int i; u8 empty_ch, last_ch; state->it913x_status = 0; /* Set bw*/ - ret = it913x_fe_select_bw(state, p->bandwidth_hz, + it913x_fe_select_bw(state, p->bandwidth_hz, state->adcFrequency); /* Training Mode Off */ - ret = it913x_write_reg(state, PRO_LINK, TRAINING_MODE, 0x0); + it913x_write_reg(state, PRO_LINK, TRAINING_MODE, 0x0); /* Clear Empty Channel */ - ret = it913x_write_reg(state, PRO_DMOD, EMPTY_CHANNEL_STATUS, 0x0); + it913x_write_reg(state, PRO_DMOD, EMPTY_CHANNEL_STATUS, 0x0); /* Clear bits */ - ret = it913x_write_reg(state, PRO_DMOD, MP2IF_SYNC_LK, 0x0); + it913x_write_reg(state, PRO_DMOD, MP2IF_SYNC_LK, 0x0); /* LED on */ - ret = it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1); + it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1); /* Select Band*/ if ((p->frequency >= 51000000) && (p->frequency <= 230000000)) i = 0; @@ -720,7 +718,7 @@ static int it913x_fe_set_frontend(struct dvb_frontend *fe) else return -EOPNOTSUPP; - ret = it913x_write_reg(state, PRO_DMOD, FREE_BAND, i); + it913x_write_reg(state, PRO_DMOD, FREE_BAND, i); deb_info("Frontend Set Tuner Type %02x", state->tuner_type); switch (state->tuner_type) { @@ -730,7 +728,7 @@ static int it913x_fe_set_frontend(struct dvb_frontend *fe) case IT9135_60: case IT9135_61: case IT9135_62: - ret = it9137_set_tuner(state, + it9137_set_tuner(state, p->bandwidth_hz, p->frequency); break; default: @@ -742,9 +740,9 @@ static int it913x_fe_set_frontend(struct dvb_frontend *fe) break; } /* LED off */ - ret = it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0); + it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0); /* Trigger ofsm */ - ret = it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0); + it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0); last_ch = 2; for (i = 0; i < 40; ++i) { empty_ch = it913x_read_reg_u8(state, EMPTY_CHANNEL_STATUS); diff --git a/drivers/media/dvb/frontends/lg2160.c b/drivers/media/dvb/frontends/lg2160.c new file mode 100644 index 00000000000..a3ab1a5b659 --- /dev/null +++ b/drivers/media/dvb/frontends/lg2160.c @@ -0,0 +1,1468 @@ +/* + * Support for LG2160 - ATSC/MH + * + * Copyright (C) 2010 Michael Krufky <mkrufky@linuxtv.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <linux/jiffies.h> +#include <linux/dvb/frontend.h> +#include "lg2160.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))"); + +#define DBG_INFO 1 +#define DBG_REG 2 + +#define lg_printk(kern, fmt, arg...) \ + printk(kern "%s: " fmt, __func__, ##arg) + +#define lg_info(fmt, arg...) printk(KERN_INFO "lg2160: " fmt, ##arg) +#define lg_warn(fmt, arg...) lg_printk(KERN_WARNING, fmt, ##arg) +#define lg_err(fmt, arg...) lg_printk(KERN_ERR, fmt, ##arg) +#define lg_dbg(fmt, arg...) if (debug & DBG_INFO) \ + lg_printk(KERN_DEBUG, fmt, ##arg) +#define lg_reg(fmt, arg...) if (debug & DBG_REG) \ + lg_printk(KERN_DEBUG, fmt, ##arg) + +#define lg_fail(ret) \ +({ \ + int __ret; \ + __ret = (ret < 0); \ + if (__ret) \ + lg_err("error %d on line %d\n", ret, __LINE__); \ + __ret; \ +}) + +struct lg216x_state { + struct i2c_adapter *i2c_adap; + const struct lg2160_config *cfg; + + struct dvb_frontend frontend; + + u32 current_frequency; + u8 parade_id; + u8 fic_ver; + unsigned int last_reset; +}; + +/* ------------------------------------------------------------------------ */ + +static int lg216x_write_reg(struct lg216x_state *state, u16 reg, u8 val) +{ + int ret; + u8 buf[] = { reg >> 8, reg & 0xff, val }; + struct i2c_msg msg = { + .addr = state->cfg->i2c_addr, .flags = 0, + .buf = buf, .len = 3, + }; + + lg_reg("reg: 0x%04x, val: 0x%02x\n", reg, val); + + ret = i2c_transfer(state->i2c_adap, &msg, 1); + + if (ret != 1) { + lg_err("error (addr %02x %02x <- %02x, err = %i)\n", + msg.buf[0], msg.buf[1], msg.buf[2], ret); + if (ret < 0) + return ret; + else + return -EREMOTEIO; + } + return 0; +} + +static int lg216x_read_reg(struct lg216x_state *state, u16 reg, u8 *val) +{ + int ret; + u8 reg_buf[] = { reg >> 8, reg & 0xff }; + struct i2c_msg msg[] = { + { .addr = state->cfg->i2c_addr, + .flags = 0, .buf = reg_buf, .len = 2 }, + { .addr = state->cfg->i2c_addr, + .flags = I2C_M_RD, .buf = val, .len = 1 }, + }; + + lg_reg("reg: 0x%04x\n", reg); + + ret = i2c_transfer(state->i2c_adap, msg, 2); + + if (ret != 2) { + lg_err("error (addr %02x reg %04x error (ret == %i)\n", + state->cfg->i2c_addr, reg, ret); + if (ret < 0) + return ret; + else + return -EREMOTEIO; + } + return 0; +} + +struct lg216x_reg { + u16 reg; + u8 val; +}; + +static int lg216x_write_regs(struct lg216x_state *state, + struct lg216x_reg *regs, int len) +{ + int i, ret; + + lg_reg("writing %d registers...\n", len); + + for (i = 0; i < len - 1; i++) { + ret = lg216x_write_reg(state, regs[i].reg, regs[i].val); + if (lg_fail(ret)) + return ret; + } + return 0; +} + +static int lg216x_set_reg_bit(struct lg216x_state *state, + u16 reg, int bit, int onoff) +{ + u8 val; + int ret; + + lg_reg("reg: 0x%04x, bit: %d, level: %d\n", reg, bit, onoff); + + ret = lg216x_read_reg(state, reg, &val); + if (lg_fail(ret)) + goto fail; + + val &= ~(1 << bit); + val |= (onoff & 1) << bit; + + ret = lg216x_write_reg(state, reg, val); + lg_fail(ret); +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int lg216x_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct lg216x_state *state = fe->demodulator_priv; + int ret; + + if (state->cfg->deny_i2c_rptr) + return 0; + + lg_dbg("(%d)\n", enable); + + ret = lg216x_set_reg_bit(state, 0x0000, 0, enable ? 0 : 1); + + msleep(1); + + return ret; +} + +static int lg216x_soft_reset(struct lg216x_state *state) +{ + int ret; + + lg_dbg("\n"); + + ret = lg216x_write_reg(state, 0x0002, 0x00); + if (lg_fail(ret)) + goto fail; + + msleep(20); + ret = lg216x_write_reg(state, 0x0002, 0x01); + if (lg_fail(ret)) + goto fail; + + state->last_reset = jiffies_to_msecs(jiffies); +fail: + return ret; +} + +static int lg216x_initialize(struct lg216x_state *state) +{ + int ret; + + static struct lg216x_reg lg2160_init[] = { +#if 0 + { .reg = 0x0015, .val = 0xe6 }, +#else + { .reg = 0x0015, .val = 0xf7 }, + { .reg = 0x001b, .val = 0x52 }, + { .reg = 0x0208, .val = 0x00 }, + { .reg = 0x0209, .val = 0x82 }, + { .reg = 0x0210, .val = 0xf9 }, + { .reg = 0x020a, .val = 0x00 }, + { .reg = 0x020b, .val = 0x82 }, + { .reg = 0x020d, .val = 0x28 }, + { .reg = 0x020f, .val = 0x14 }, +#endif + }; + + static struct lg216x_reg lg2161_init[] = { + { .reg = 0x0000, .val = 0x41 }, + { .reg = 0x0001, .val = 0xfb }, + { .reg = 0x0216, .val = 0x00 }, + { .reg = 0x0219, .val = 0x00 }, + { .reg = 0x021b, .val = 0x55 }, + { .reg = 0x0606, .val = 0x0a }, + }; + + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg216x_write_regs(state, + lg2160_init, ARRAY_SIZE(lg2160_init)); + break; + case LG2161: + ret = lg216x_write_regs(state, + lg2161_init, ARRAY_SIZE(lg2161_init)); + break; + default: + ret = -EINVAL; + break; + } + if (lg_fail(ret)) + goto fail; + + ret = lg216x_soft_reset(state); + lg_fail(ret); +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int lg216x_set_if(struct lg216x_state *state) +{ + u8 val; + int ret; + + lg_dbg("%d KHz\n", state->cfg->if_khz); + + ret = lg216x_read_reg(state, 0x0132, &val); + if (lg_fail(ret)) + goto fail; + + val &= 0xfb; + val |= (0 == state->cfg->if_khz) ? 0x04 : 0x00; + + ret = lg216x_write_reg(state, 0x0132, val); + lg_fail(ret); + + /* if NOT zero IF, 6 MHz is the default */ +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int lg2160_agc_fix(struct lg216x_state *state, + int if_agc_fix, int rf_agc_fix) +{ + u8 val; + int ret; + + ret = lg216x_read_reg(state, 0x0100, &val); + if (lg_fail(ret)) + goto fail; + + val &= 0xf3; + val |= (if_agc_fix) ? 0x08 : 0x00; + val |= (rf_agc_fix) ? 0x04 : 0x00; + + ret = lg216x_write_reg(state, 0x0100, val); + lg_fail(ret); +fail: + return ret; +} + +#if 0 +static int lg2160_agc_freeze(struct lg216x_state *state, + int if_agc_freeze, int rf_agc_freeze) +{ + u8 val; + int ret; + + ret = lg216x_read_reg(state, 0x0100, &val); + if (lg_fail(ret)) + goto fail; + + val &= 0xcf; + val |= (if_agc_freeze) ? 0x20 : 0x00; + val |= (rf_agc_freeze) ? 0x10 : 0x00; + + ret = lg216x_write_reg(state, 0x0100, val); + lg_fail(ret); +fail: + return ret; +} +#endif + +static int lg2160_agc_polarity(struct lg216x_state *state, + int if_agc_polarity, int rf_agc_polarity) +{ + u8 val; + int ret; + + ret = lg216x_read_reg(state, 0x0100, &val); + if (lg_fail(ret)) + goto fail; + + val &= 0xfc; + val |= (if_agc_polarity) ? 0x02 : 0x00; + val |= (rf_agc_polarity) ? 0x01 : 0x00; + + ret = lg216x_write_reg(state, 0x0100, val); + lg_fail(ret); +fail: + return ret; +} + +static int lg2160_tuner_pwr_save_polarity(struct lg216x_state *state, + int polarity) +{ + u8 val; + int ret; + + ret = lg216x_read_reg(state, 0x0008, &val); + if (lg_fail(ret)) + goto fail; + + val &= 0xfe; + val |= (polarity) ? 0x01 : 0x00; + + ret = lg216x_write_reg(state, 0x0008, val); + lg_fail(ret); +fail: + return ret; +} + +static int lg2160_spectrum_polarity(struct lg216x_state *state, + int inverted) +{ + u8 val; + int ret; + + ret = lg216x_read_reg(state, 0x0132, &val); + if (lg_fail(ret)) + goto fail; + + val &= 0xfd; + val |= (inverted) ? 0x02 : 0x00; + + ret = lg216x_write_reg(state, 0x0132, val); + lg_fail(ret); +fail: + return lg216x_soft_reset(state); +} + +static int lg2160_tuner_pwr_save(struct lg216x_state *state, int onoff) +{ + u8 val; + int ret; + + ret = lg216x_read_reg(state, 0x0007, &val); + if (lg_fail(ret)) + goto fail; + + val &= 0xbf; + val |= (onoff) ? 0x40 : 0x00; + + ret = lg216x_write_reg(state, 0x0007, val); + lg_fail(ret); +fail: + return ret; +} + +static int lg216x_set_parade(struct lg216x_state *state, int id) +{ + int ret; + + ret = lg216x_write_reg(state, 0x013e, id & 0x7f); + if (lg_fail(ret)) + goto fail; + + state->parade_id = id & 0x7f; +fail: + return ret; +} + +static int lg216x_set_ensemble(struct lg216x_state *state, int id) +{ + int ret; + u16 reg; + u8 val; + + switch (state->cfg->lg_chip) { + case LG2160: + reg = 0x0400; + break; + case LG2161: + default: + reg = 0x0500; + break; + } + + ret = lg216x_read_reg(state, reg, &val); + if (lg_fail(ret)) + goto fail; + + val &= 0xfe; + val |= (id) ? 0x01 : 0x00; + + ret = lg216x_write_reg(state, reg, val); + lg_fail(ret); +fail: + return ret; +} + +static int lg2160_set_spi_clock(struct lg216x_state *state) +{ + u8 val; + int ret; + + ret = lg216x_read_reg(state, 0x0014, &val); + if (lg_fail(ret)) + goto fail; + + val &= 0xf3; + val |= (state->cfg->spi_clock << 2); + + ret = lg216x_write_reg(state, 0x0014, val); + lg_fail(ret); +fail: + return ret; +} + +static int lg2161_set_output_interface(struct lg216x_state *state) +{ + u8 val; + int ret; + + ret = lg216x_read_reg(state, 0x0014, &val); + if (lg_fail(ret)) + goto fail; + + val &= ~0x07; + val |= state->cfg->output_if; /* FIXME: needs sanity check */ + + ret = lg216x_write_reg(state, 0x0014, val); + lg_fail(ret); +fail: + return ret; +} + +static int lg216x_enable_fic(struct lg216x_state *state, int onoff) +{ + int ret; + + ret = lg216x_write_reg(state, 0x0017, 0x23); + if (lg_fail(ret)) + goto fail; + + ret = lg216x_write_reg(state, 0x0016, 0xfc); + if (lg_fail(ret)) + goto fail; + + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg216x_write_reg(state, 0x0016, + 0xfc | ((onoff) ? 0x02 : 0x00)); + break; + case LG2161: + ret = lg216x_write_reg(state, 0x0016, (onoff) ? 0x10 : 0x00); + break; + } + if (lg_fail(ret)) + goto fail; + + ret = lg216x_initialize(state); + if (lg_fail(ret)) + goto fail; + + if (onoff) { + ret = lg216x_write_reg(state, 0x0017, 0x03); + lg_fail(ret); + } +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int lg216x_get_fic_version(struct lg216x_state *state, u8 *ficver) +{ + u8 val; + int ret; + + *ficver = 0xff; /* invalid value */ + + ret = lg216x_read_reg(state, 0x0128, &val); + if (lg_fail(ret)) + goto fail; + + *ficver = (val >> 3) & 0x1f; +fail: + return ret; +} + +#if 0 +static int lg2160_get_parade_id(struct lg216x_state *state, u8 *id) +{ + u8 val; + int ret; + + *id = 0xff; /* invalid value */ + + ret = lg216x_read_reg(state, 0x0123, &val); + if (lg_fail(ret)) + goto fail; + + *id = val & 0x7f; +fail: + return ret; +} +#endif + +static int lg216x_get_nog(struct lg216x_state *state, u8 *nog) +{ + u8 val; + int ret; + + *nog = 0xff; /* invalid value */ + + ret = lg216x_read_reg(state, 0x0124, &val); + if (lg_fail(ret)) + goto fail; + + *nog = ((val >> 4) & 0x07) + 1; +fail: + return ret; +} + +static int lg216x_get_tnog(struct lg216x_state *state, u8 *tnog) +{ + u8 val; + int ret; + + *tnog = 0xff; /* invalid value */ + + ret = lg216x_read_reg(state, 0x0125, &val); + if (lg_fail(ret)) + goto fail; + + *tnog = val & 0x1f; +fail: + return ret; +} + +static int lg216x_get_sgn(struct lg216x_state *state, u8 *sgn) +{ + u8 val; + int ret; + + *sgn = 0xff; /* invalid value */ + + ret = lg216x_read_reg(state, 0x0124, &val); + if (lg_fail(ret)) + goto fail; + + *sgn = val & 0x0f; +fail: + return ret; +} + +static int lg216x_get_prc(struct lg216x_state *state, u8 *prc) +{ + u8 val; + int ret; + + *prc = 0xff; /* invalid value */ + + ret = lg216x_read_reg(state, 0x0125, &val); + if (lg_fail(ret)) + goto fail; + + *prc = ((val >> 5) & 0x07) + 1; +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int lg216x_get_rs_frame_mode(struct lg216x_state *state, + enum atscmh_rs_frame_mode *rs_framemode) +{ + u8 val; + int ret; + + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg216x_read_reg(state, 0x0410, &val); + break; + case LG2161: + ret = lg216x_read_reg(state, 0x0513, &val); + break; + default: + ret = -EINVAL; + } + if (lg_fail(ret)) + goto fail; + + switch ((val >> 4) & 0x03) { +#if 1 + default: +#endif + case 0x00: + *rs_framemode = ATSCMH_RSFRAME_PRI_ONLY; + break; + case 0x01: + *rs_framemode = ATSCMH_RSFRAME_PRI_SEC; + break; +#if 0 + default: + *rs_framemode = ATSCMH_RSFRAME_RES; + break; +#endif + } +fail: + return ret; +} + +static +int lg216x_get_rs_frame_ensemble(struct lg216x_state *state, + enum atscmh_rs_frame_ensemble *rs_frame_ens) +{ + u8 val; + int ret; + + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg216x_read_reg(state, 0x0400, &val); + break; + case LG2161: + ret = lg216x_read_reg(state, 0x0500, &val); + break; + default: + ret = -EINVAL; + } + if (lg_fail(ret)) + goto fail; + + val &= 0x01; + *rs_frame_ens = (enum atscmh_rs_frame_ensemble) val; +fail: + return ret; +} + +static int lg216x_get_rs_code_mode(struct lg216x_state *state, + enum atscmh_rs_code_mode *rs_code_pri, + enum atscmh_rs_code_mode *rs_code_sec) +{ + u8 val; + int ret; + + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg216x_read_reg(state, 0x0410, &val); + break; + case LG2161: + ret = lg216x_read_reg(state, 0x0513, &val); + break; + default: + ret = -EINVAL; + } + if (lg_fail(ret)) + goto fail; + + *rs_code_pri = (enum atscmh_rs_code_mode) ((val >> 2) & 0x03); + *rs_code_sec = (enum atscmh_rs_code_mode) (val & 0x03); +fail: + return ret; +} + +static int lg216x_get_sccc_block_mode(struct lg216x_state *state, + enum atscmh_sccc_block_mode *sccc_block) +{ + u8 val; + int ret; + + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg216x_read_reg(state, 0x0315, &val); + break; + case LG2161: + ret = lg216x_read_reg(state, 0x0511, &val); + break; + default: + ret = -EINVAL; + } + if (lg_fail(ret)) + goto fail; + + switch (val & 0x03) { + case 0x00: + *sccc_block = ATSCMH_SCCC_BLK_SEP; + break; + case 0x01: + *sccc_block = ATSCMH_SCCC_BLK_COMB; + break; + default: + *sccc_block = ATSCMH_SCCC_BLK_RES; + break; + } +fail: + return ret; +} + +static int lg216x_get_sccc_code_mode(struct lg216x_state *state, + enum atscmh_sccc_code_mode *mode_a, + enum atscmh_sccc_code_mode *mode_b, + enum atscmh_sccc_code_mode *mode_c, + enum atscmh_sccc_code_mode *mode_d) +{ + u8 val; + int ret; + + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg216x_read_reg(state, 0x0316, &val); + break; + case LG2161: + ret = lg216x_read_reg(state, 0x0512, &val); + break; + default: + ret = -EINVAL; + } + if (lg_fail(ret)) + goto fail; + + switch ((val >> 6) & 0x03) { + case 0x00: + *mode_a = ATSCMH_SCCC_CODE_HLF; + break; + case 0x01: + *mode_a = ATSCMH_SCCC_CODE_QTR; + break; + default: + *mode_a = ATSCMH_SCCC_CODE_RES; + break; + } + + switch ((val >> 4) & 0x03) { + case 0x00: + *mode_b = ATSCMH_SCCC_CODE_HLF; + break; + case 0x01: + *mode_b = ATSCMH_SCCC_CODE_QTR; + break; + default: + *mode_b = ATSCMH_SCCC_CODE_RES; + break; + } + + switch ((val >> 2) & 0x03) { + case 0x00: + *mode_c = ATSCMH_SCCC_CODE_HLF; + break; + case 0x01: + *mode_c = ATSCMH_SCCC_CODE_QTR; + break; + default: + *mode_c = ATSCMH_SCCC_CODE_RES; + break; + } + + switch (val & 0x03) { + case 0x00: + *mode_d = ATSCMH_SCCC_CODE_HLF; + break; + case 0x01: + *mode_d = ATSCMH_SCCC_CODE_QTR; + break; + default: + *mode_d = ATSCMH_SCCC_CODE_RES; + break; + } +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +#if 0 +static int lg216x_read_fic_err_count(struct lg216x_state *state, u8 *err) +{ + u8 fic_err; + int ret; + + *err = 0; + + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg216x_read_reg(state, 0x0012, &fic_err); + break; + case LG2161: + ret = lg216x_read_reg(state, 0x001e, &fic_err); + break; + } + if (lg_fail(ret)) + goto fail; + + *err = fic_err; +fail: + return ret; +} + +static int lg2160_read_crc_err_count(struct lg216x_state *state, u16 *err) +{ + u8 crc_err1, crc_err2; + int ret; + + *err = 0; + + ret = lg216x_read_reg(state, 0x0411, &crc_err1); + if (lg_fail(ret)) + goto fail; + + ret = lg216x_read_reg(state, 0x0412, &crc_err2); + if (lg_fail(ret)) + goto fail; + + *err = (u16)(((crc_err2 & 0x0f) << 8) | crc_err1); +fail: + return ret; +} + +static int lg2161_read_crc_err_count(struct lg216x_state *state, u16 *err) +{ + u8 crc_err; + int ret; + + *err = 0; + + ret = lg216x_read_reg(state, 0x0612, &crc_err); + if (lg_fail(ret)) + goto fail; + + *err = (u16)crc_err; +fail: + return ret; +} + +static int lg216x_read_crc_err_count(struct lg216x_state *state, u16 *err) +{ + int ret; + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg2160_read_crc_err_count(state, err); + break; + case LG2161: + ret = lg2161_read_crc_err_count(state, err); + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int lg2160_read_rs_err_count(struct lg216x_state *state, u16 *err) +{ + u8 rs_err1, rs_err2; + int ret; + + *err = 0; + + ret = lg216x_read_reg(state, 0x0413, &rs_err1); + if (lg_fail(ret)) + goto fail; + + ret = lg216x_read_reg(state, 0x0414, &rs_err2); + if (lg_fail(ret)) + goto fail; + + *err = (u16)(((rs_err2 & 0x0f) << 8) | rs_err1); +fail: + return ret; +} + +static int lg2161_read_rs_err_count(struct lg216x_state *state, u16 *err) +{ + u8 rs_err1, rs_err2; + int ret; + + *err = 0; + + ret = lg216x_read_reg(state, 0x0613, &rs_err1); + if (lg_fail(ret)) + goto fail; + + ret = lg216x_read_reg(state, 0x0614, &rs_err2); + if (lg_fail(ret)) + goto fail; + + *err = (u16)((rs_err1 << 8) | rs_err2); +fail: + return ret; +} + +static int lg216x_read_rs_err_count(struct lg216x_state *state, u16 *err) +{ + int ret; + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg2160_read_rs_err_count(state, err); + break; + case LG2161: + ret = lg2161_read_rs_err_count(state, err); + break; + default: + ret = -EINVAL; + break; + } + return ret; +} +#endif + +/* ------------------------------------------------------------------------ */ + +static int lg216x_get_frontend(struct dvb_frontend *fe) +{ + struct lg216x_state *state = fe->demodulator_priv; + int ret; + + lg_dbg("\n"); + + fe->dtv_property_cache.modulation = VSB_8; + fe->dtv_property_cache.frequency = state->current_frequency; + fe->dtv_property_cache.delivery_system = SYS_ATSCMH; + + ret = lg216x_get_fic_version(state, + &fe->dtv_property_cache.atscmh_fic_ver); + if (lg_fail(ret)) + goto fail; + if (state->fic_ver != fe->dtv_property_cache.atscmh_fic_ver) { + state->fic_ver = fe->dtv_property_cache.atscmh_fic_ver; + +#if 0 + ret = lg2160_get_parade_id(state, + &fe->dtv_property_cache.atscmh_parade_id); + if (lg_fail(ret)) + goto fail; +/* #else */ + fe->dtv_property_cache.atscmh_parade_id = state->parade_id; +#endif + ret = lg216x_get_nog(state, + &fe->dtv_property_cache.atscmh_nog); + if (lg_fail(ret)) + goto fail; + ret = lg216x_get_tnog(state, + &fe->dtv_property_cache.atscmh_tnog); + if (lg_fail(ret)) + goto fail; + ret = lg216x_get_sgn(state, + &fe->dtv_property_cache.atscmh_sgn); + if (lg_fail(ret)) + goto fail; + ret = lg216x_get_prc(state, + &fe->dtv_property_cache.atscmh_prc); + if (lg_fail(ret)) + goto fail; + + ret = lg216x_get_rs_frame_mode(state, + (enum atscmh_rs_frame_mode *) + &fe->dtv_property_cache.atscmh_rs_frame_mode); + if (lg_fail(ret)) + goto fail; + ret = lg216x_get_rs_frame_ensemble(state, + (enum atscmh_rs_frame_ensemble *) + &fe->dtv_property_cache.atscmh_rs_frame_ensemble); + if (lg_fail(ret)) + goto fail; + ret = lg216x_get_rs_code_mode(state, + (enum atscmh_rs_code_mode *) + &fe->dtv_property_cache.atscmh_rs_code_mode_pri, + (enum atscmh_rs_code_mode *) + &fe->dtv_property_cache.atscmh_rs_code_mode_sec); + if (lg_fail(ret)) + goto fail; + ret = lg216x_get_sccc_block_mode(state, + (enum atscmh_sccc_block_mode *) + &fe->dtv_property_cache.atscmh_sccc_block_mode); + if (lg_fail(ret)) + goto fail; + ret = lg216x_get_sccc_code_mode(state, + (enum atscmh_sccc_code_mode *) + &fe->dtv_property_cache.atscmh_sccc_code_mode_a, + (enum atscmh_sccc_code_mode *) + &fe->dtv_property_cache.atscmh_sccc_code_mode_b, + (enum atscmh_sccc_code_mode *) + &fe->dtv_property_cache.atscmh_sccc_code_mode_c, + (enum atscmh_sccc_code_mode *) + &fe->dtv_property_cache.atscmh_sccc_code_mode_d); + if (lg_fail(ret)) + goto fail; + } +#if 0 + ret = lg216x_read_fic_err_count(state, + (u8 *)&fe->dtv_property_cache.atscmh_fic_err); + if (lg_fail(ret)) + goto fail; + ret = lg216x_read_crc_err_count(state, + &fe->dtv_property_cache.atscmh_crc_err); + if (lg_fail(ret)) + goto fail; + ret = lg216x_read_rs_err_count(state, + &fe->dtv_property_cache.atscmh_rs_err); + if (lg_fail(ret)) + goto fail; + + switch (state->cfg->lg_chip) { + case LG2160: + if (((fe->dtv_property_cache.atscmh_rs_err >= 240) && + (fe->dtv_property_cache.atscmh_crc_err >= 240)) && + ((jiffies_to_msecs(jiffies) - state->last_reset) > 6000)) + ret = lg216x_soft_reset(state); + break; + case LG2161: + /* no fix needed here (as far as we know) */ + ret = 0; + break; + } + lg_fail(ret); +#endif +fail: + return ret; +} + +static int lg216x_get_property(struct dvb_frontend *fe, + struct dtv_property *tvp) +{ + return (DTV_ATSCMH_FIC_VER == tvp->cmd) ? + lg216x_get_frontend(fe) : 0; +} + + +static int lg2160_set_frontend(struct dvb_frontend *fe) +{ + struct lg216x_state *state = fe->demodulator_priv; + int ret; + + lg_dbg("(%d)\n", fe->dtv_property_cache.frequency); + + if (fe->ops.tuner_ops.set_params) { + ret = fe->ops.tuner_ops.set_params(fe); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + if (lg_fail(ret)) + goto fail; + state->current_frequency = fe->dtv_property_cache.frequency; + } + + ret = lg2160_agc_fix(state, 0, 0); + if (lg_fail(ret)) + goto fail; + ret = lg2160_agc_polarity(state, 0, 0); + if (lg_fail(ret)) + goto fail; + ret = lg2160_tuner_pwr_save_polarity(state, 1); + if (lg_fail(ret)) + goto fail; + ret = lg216x_set_if(state); + if (lg_fail(ret)) + goto fail; + ret = lg2160_spectrum_polarity(state, state->cfg->spectral_inversion); + if (lg_fail(ret)) + goto fail; + + /* be tuned before this point */ + ret = lg216x_soft_reset(state); + if (lg_fail(ret)) + goto fail; + + ret = lg2160_tuner_pwr_save(state, 0); + if (lg_fail(ret)) + goto fail; + + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg2160_set_spi_clock(state); + if (lg_fail(ret)) + goto fail; + break; + case LG2161: + ret = lg2161_set_output_interface(state); + if (lg_fail(ret)) + goto fail; + break; + } + + ret = lg216x_set_parade(state, fe->dtv_property_cache.atscmh_parade_id); + if (lg_fail(ret)) + goto fail; + + ret = lg216x_set_ensemble(state, + fe->dtv_property_cache.atscmh_rs_frame_ensemble); + if (lg_fail(ret)) + goto fail; + + ret = lg216x_initialize(state); + if (lg_fail(ret)) + goto fail; + + ret = lg216x_enable_fic(state, 1); + lg_fail(ret); + + lg216x_get_frontend(fe); +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int lg2160_read_lock_status(struct lg216x_state *state, + int *acq_lock, int *sync_lock) +{ + u8 val; + int ret; + + *acq_lock = 0; + *sync_lock = 0; + + ret = lg216x_read_reg(state, 0x011b, &val); + if (lg_fail(ret)) + goto fail; + + *sync_lock = (val & 0x20) ? 0 : 1; + *acq_lock = (val & 0x40) ? 0 : 1; +fail: + return ret; +} + +#ifdef USE_LG2161_LOCK_BITS +static int lg2161_read_lock_status(struct lg216x_state *state, + int *acq_lock, int *sync_lock) +{ + u8 val; + int ret; + + *acq_lock = 0; + *sync_lock = 0; + + ret = lg216x_read_reg(state, 0x0304, &val); + if (lg_fail(ret)) + goto fail; + + *sync_lock = (val & 0x80) ? 0 : 1; + + ret = lg216x_read_reg(state, 0x011b, &val); + if (lg_fail(ret)) + goto fail; + + *acq_lock = (val & 0x40) ? 0 : 1; +fail: + return ret; +} +#endif + +static int lg216x_read_lock_status(struct lg216x_state *state, + int *acq_lock, int *sync_lock) +{ +#ifdef USE_LG2161_LOCK_BITS + int ret; + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg2160_read_lock_status(state, acq_lock, sync_lock); + break; + case LG2161: + ret = lg2161_read_lock_status(state, acq_lock, sync_lock); + break; + default: + ret = -EINVAL; + break; + } + return ret; +#else + return lg2160_read_lock_status(state, acq_lock, sync_lock); +#endif +} + +static int lg216x_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct lg216x_state *state = fe->demodulator_priv; + int ret, acq_lock, sync_lock; + + *status = 0; + + ret = lg216x_read_lock_status(state, &acq_lock, &sync_lock); + if (lg_fail(ret)) + goto fail; + + lg_dbg("%s%s\n", + acq_lock ? "SIGNALEXIST " : "", + sync_lock ? "SYNCLOCK" : ""); + + if (acq_lock) + *status |= FE_HAS_SIGNAL; + if (sync_lock) + *status |= FE_HAS_SYNC; + + if (*status) + *status |= FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_LOCK; + +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int lg2160_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct lg216x_state *state = fe->demodulator_priv; + u8 snr1, snr2; + int ret; + + *snr = 0; + + ret = lg216x_read_reg(state, 0x0202, &snr1); + if (lg_fail(ret)) + goto fail; + + ret = lg216x_read_reg(state, 0x0203, &snr2); + if (lg_fail(ret)) + goto fail; + + if ((snr1 == 0xba) || (snr2 == 0xdf)) + *snr = 0; + else +#if 1 + *snr = ((snr1 >> 4) * 100) + ((snr1 & 0x0f) * 10) + (snr2 >> 4); +#else /* BCD */ + *snr = (snr2 | (snr1 << 8)); +#endif +fail: + return ret; +} + +static int lg2161_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct lg216x_state *state = fe->demodulator_priv; + u8 snr1, snr2; + int ret; + + *snr = 0; + + ret = lg216x_read_reg(state, 0x0302, &snr1); + if (lg_fail(ret)) + goto fail; + + ret = lg216x_read_reg(state, 0x0303, &snr2); + if (lg_fail(ret)) + goto fail; + + if ((snr1 == 0xba) || (snr2 == 0xfd)) + *snr = 0; + else + + *snr = ((snr1 >> 4) * 100) + ((snr1 & 0x0f) * 10) + (snr2 & 0x0f); +fail: + return ret; +} + +static int lg216x_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) +{ +#if 0 + /* borrowed from lgdt330x.c + * + * Calculate strength from SNR up to 35dB + * Even though the SNR can go higher than 35dB, + * there is some comfort factor in having a range of + * strong signals that can show at 100% + */ + struct lg216x_state *state = fe->demodulator_priv; + u16 snr; + int ret; +#endif + *strength = 0; +#if 0 + ret = fe->ops.read_snr(fe, &snr); + if (lg_fail(ret)) + goto fail; + /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */ + /* scale the range 0 - 35*2^24 into 0 - 65535 */ + if (state->snr >= 8960 * 0x10000) + *strength = 0xffff; + else + *strength = state->snr / 8960; +fail: + return ret; +#else + return 0; +#endif +} + +/* ------------------------------------------------------------------------ */ + +static int lg216x_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ +#if 0 + struct lg216x_state *state = fe->demodulator_priv; + int ret; + + ret = lg216x_read_rs_err_count(state, + &fe->dtv_property_cache.atscmh_rs_err); + if (lg_fail(ret)) + goto fail; + + *ucblocks = fe->dtv_property_cache.atscmh_rs_err; +fail: +#else + *ucblocks = 0; +#endif + return 0; +} + +static int lg216x_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings + *fe_tune_settings) +{ + fe_tune_settings->min_delay_ms = 500; + lg_dbg("\n"); + return 0; +} + +static void lg216x_release(struct dvb_frontend *fe) +{ + struct lg216x_state *state = fe->demodulator_priv; + lg_dbg("\n"); + kfree(state); +} + +static struct dvb_frontend_ops lg2160_ops = { + .delsys = { SYS_ATSCMH }, + .info = { + .name = "LG Electronics LG2160 ATSC/MH Frontend", + .frequency_min = 54000000, + .frequency_max = 858000000, + .frequency_stepsize = 62500, + }, + .i2c_gate_ctrl = lg216x_i2c_gate_ctrl, +#if 0 + .init = lg216x_init, + .sleep = lg216x_sleep, +#endif + .get_property = lg216x_get_property, + + .set_frontend = lg2160_set_frontend, + .get_frontend = lg216x_get_frontend, + .get_tune_settings = lg216x_get_tune_settings, + .read_status = lg216x_read_status, +#if 0 + .read_ber = lg216x_read_ber, +#endif + .read_signal_strength = lg216x_read_signal_strength, + .read_snr = lg2160_read_snr, + .read_ucblocks = lg216x_read_ucblocks, + .release = lg216x_release, +}; + +static struct dvb_frontend_ops lg2161_ops = { + .delsys = { SYS_ATSCMH }, + .info = { + .name = "LG Electronics LG2161 ATSC/MH Frontend", + .frequency_min = 54000000, + .frequency_max = 858000000, + .frequency_stepsize = 62500, + }, + .i2c_gate_ctrl = lg216x_i2c_gate_ctrl, +#if 0 + .init = lg216x_init, + .sleep = lg216x_sleep, +#endif + .get_property = lg216x_get_property, + + .set_frontend = lg2160_set_frontend, + .get_frontend = lg216x_get_frontend, + .get_tune_settings = lg216x_get_tune_settings, + .read_status = lg216x_read_status, +#if 0 + .read_ber = lg216x_read_ber, +#endif + .read_signal_strength = lg216x_read_signal_strength, + .read_snr = lg2161_read_snr, + .read_ucblocks = lg216x_read_ucblocks, + .release = lg216x_release, +}; + +struct dvb_frontend *lg2160_attach(const struct lg2160_config *config, + struct i2c_adapter *i2c_adap) +{ + struct lg216x_state *state = NULL; + + lg_dbg("(%d-%04x)\n", + i2c_adap ? i2c_adapter_id(i2c_adap) : 0, + config ? config->i2c_addr : 0); + + state = kzalloc(sizeof(struct lg216x_state), GFP_KERNEL); + if (state == NULL) + goto fail; + + state->cfg = config; + state->i2c_adap = i2c_adap; + state->fic_ver = 0xff; + state->parade_id = 0xff; + + switch (config->lg_chip) { + default: + lg_warn("invalid chip requested, defaulting to LG2160"); + /* fall-thru */ + case LG2160: + memcpy(&state->frontend.ops, &lg2160_ops, + sizeof(struct dvb_frontend_ops)); + break; + case LG2161: + memcpy(&state->frontend.ops, &lg2161_ops, + sizeof(struct dvb_frontend_ops)); + break; + } + + state->frontend.demodulator_priv = state; + state->current_frequency = -1; + /* parade 1 by default */ + state->frontend.dtv_property_cache.atscmh_parade_id = 1; + + return &state->frontend; +fail: + lg_warn("unable to detect LG216x hardware\n"); + kfree(state); + return NULL; +} +EXPORT_SYMBOL(lg2160_attach); + +MODULE_DESCRIPTION("LG Electronics LG216x ATSC/MH Demodulator Driver"); +MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.3"); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/frontends/lg2160.h b/drivers/media/dvb/frontends/lg2160.h new file mode 100644 index 00000000000..9e2c0f41199 --- /dev/null +++ b/drivers/media/dvb/frontends/lg2160.h @@ -0,0 +1,84 @@ +/* + * Support for LG2160 - ATSC/MH + * + * Copyright (C) 2010 Michael Krufky <mkrufky@linuxtv.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _LG2160_H_ +#define _LG2160_H_ + +#include <linux/i2c.h> +#include "dvb_frontend.h" + +enum lg_chip_type { + LG2160 = 0, + LG2161 = 1, +}; + +#define LG2161_1019 LG2161 +#define LG2161_1040 LG2161 + +enum lg2160_spi_clock { + LG2160_SPI_3_125_MHZ = 0, + LG2160_SPI_6_25_MHZ = 1, + LG2160_SPI_12_5_MHZ = 2, +}; + +#if 0 +enum lg2161_oif { + LG2161_OIF_EBI2_SLA = 1, + LG2161_OIF_SDIO_SLA = 2, + LG2161_OIF_SPI_SLA = 3, + LG2161_OIF_SPI_MAS = 4, + LG2161_OIF_SERIAL_TS = 7, +}; +#endif + +struct lg2160_config { + u8 i2c_addr; + + /* user defined IF frequency in KHz */ + u16 if_khz; + + /* disable i2c repeater - 0:repeater enabled 1:repeater disabled */ + int deny_i2c_rptr:1; + + /* spectral inversion - 0:disabled 1:enabled */ + int spectral_inversion:1; + + unsigned int output_if; + enum lg2160_spi_clock spi_clock; + enum lg_chip_type lg_chip; +}; + +#if defined(CONFIG_DVB_LG2160) || (defined(CONFIG_DVB_LG2160_MODULE) && \ + defined(MODULE)) +extern +struct dvb_frontend *lg2160_attach(const struct lg2160_config *config, + struct i2c_adapter *i2c_adap); +#else +static inline +struct dvb_frontend *lg2160_attach(const struct lg2160_config *config, + struct i2c_adapter *i2c_adap) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_LG2160 */ + +#endif /* _LG2160_H_ */ diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c index 4de1d3520cd..568363a10a3 100644 --- a/drivers/media/dvb/frontends/lgs8gxx.c +++ b/drivers/media/dvb/frontends/lgs8gxx.c @@ -262,7 +262,6 @@ static int lgs8gxx_set_mode_auto(struct lgs8gxx_state *priv) static int lgs8gxx_set_mode_manual(struct lgs8gxx_state *priv) { - int ret = 0; u8 t; if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { @@ -296,7 +295,7 @@ static int lgs8gxx_set_mode_manual(struct lgs8gxx_state *priv) if (priv->config->prod == LGS8GXX_PROD_LGS8913) lgs8gxx_write_reg(priv, 0xC1, 0); - ret = lgs8gxx_read_reg(priv, 0xC5, &t); + lgs8gxx_read_reg(priv, 0xC5, &t); t = (t & 0xE0) | 0x06; lgs8gxx_write_reg(priv, 0xC5, t); diff --git a/drivers/media/dvb/frontends/m88rs2000.c b/drivers/media/dvb/frontends/m88rs2000.c index 045ee5a6f7a..312588e84da 100644 --- a/drivers/media/dvb/frontends/m88rs2000.c +++ b/drivers/media/dvb/frontends/m88rs2000.c @@ -416,9 +416,25 @@ static int m88rs2000_tab_set(struct m88rs2000_state *state, static int m88rs2000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) { - deb_info("%s: %s\n", __func__, - volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : - volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); + struct m88rs2000_state *state = fe->demodulator_priv; + u8 data; + + data = m88rs2000_demod_read(state, 0xb2); + data |= 0x03; /* bit0 V/H, bit1 off/on */ + + switch (volt) { + case SEC_VOLTAGE_18: + data &= ~0x03; + break; + case SEC_VOLTAGE_13: + data &= ~0x03; + data |= 0x01; + break; + case SEC_VOLTAGE_OFF: + break; + } + + m88rs2000_demod_write(state, 0xb2, data); return 0; } @@ -654,7 +670,6 @@ static int m88rs2000_set_tuner(struct dvb_frontend *fe, u16 *offset) static int m88rs2000_set_fec(struct m88rs2000_state *state, fe_code_rate_t fec) { - int ret; u16 fec_set; switch (fec) { /* This is not confirmed kept for reference */ @@ -677,7 +692,7 @@ static int m88rs2000_set_fec(struct m88rs2000_state *state, default: fec_set = 0x08; } - ret = m88rs2000_demod_write(state, 0x76, fec_set); + m88rs2000_demod_write(state, 0x76, fec_set); return 0; } @@ -772,13 +787,13 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe) return -ENODEV; for (i = 0; i < 25; i++) { - u8 reg = m88rs2000_demod_read(state, 0x8c); + reg = m88rs2000_demod_read(state, 0x8c); if ((reg & 0x7) == 0x7) { status = FE_HAS_LOCK; break; } state->no_lock_count++; - if (state->no_lock_count > 15) { + if (state->no_lock_count == 15) { reg = m88rs2000_demod_read(state, 0x70); reg ^= 0x4; m88rs2000_demod_write(state, 0x70, reg); diff --git a/drivers/media/dvb/frontends/rtl2830.c b/drivers/media/dvb/frontends/rtl2830.c index 45196c5b073..93612ebac51 100644 --- a/drivers/media/dvb/frontends/rtl2830.c +++ b/drivers/media/dvb/frontends/rtl2830.c @@ -374,6 +374,118 @@ err: return ret; } +static int rtl2830_get_frontend(struct dvb_frontend *fe) +{ + struct rtl2830_priv *priv = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret; + u8 buf[3]; + + if (priv->sleeping) + return 0; + + ret = rtl2830_rd_regs(priv, 0x33c, buf, 2); + if (ret) + goto err; + + ret = rtl2830_rd_reg(priv, 0x351, &buf[2]); + if (ret) + goto err; + + dbg("%s: TPS=%02x %02x %02x", __func__, buf[0], buf[1], buf[2]); + + switch ((buf[0] >> 2) & 3) { + case 0: + c->modulation = QPSK; + break; + case 1: + c->modulation = QAM_16; + break; + case 2: + c->modulation = QAM_64; + break; + } + + switch ((buf[2] >> 2) & 1) { + case 0: + c->transmission_mode = TRANSMISSION_MODE_2K; + break; + case 1: + c->transmission_mode = TRANSMISSION_MODE_8K; + } + + switch ((buf[2] >> 0) & 3) { + case 0: + c->guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + c->guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + c->guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + c->guard_interval = GUARD_INTERVAL_1_4; + break; + } + + switch ((buf[0] >> 4) & 7) { + case 0: + c->hierarchy = HIERARCHY_NONE; + break; + case 1: + c->hierarchy = HIERARCHY_1; + break; + case 2: + c->hierarchy = HIERARCHY_2; + break; + case 3: + c->hierarchy = HIERARCHY_4; + break; + } + + switch ((buf[1] >> 3) & 7) { + case 0: + c->code_rate_HP = FEC_1_2; + break; + case 1: + c->code_rate_HP = FEC_2_3; + break; + case 2: + c->code_rate_HP = FEC_3_4; + break; + case 3: + c->code_rate_HP = FEC_5_6; + break; + case 4: + c->code_rate_HP = FEC_7_8; + break; + } + + switch ((buf[1] >> 0) & 7) { + case 0: + c->code_rate_LP = FEC_1_2; + break; + case 1: + c->code_rate_LP = FEC_2_3; + break; + case 2: + c->code_rate_LP = FEC_3_4; + break; + case 3: + c->code_rate_LP = FEC_5_6; + break; + case 4: + c->code_rate_LP = FEC_7_8; + break; + } + + return 0; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status) { struct rtl2830_priv *priv = fe->demodulator_priv; @@ -404,14 +516,72 @@ err: static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr) { - *snr = 0; + struct rtl2830_priv *priv = fe->demodulator_priv; + int ret, hierarchy, constellation; + u8 buf[2], tmp; + u16 tmp16; +#define CONSTELLATION_NUM 3 +#define HIERARCHY_NUM 4 + static const u32 snr_constant[CONSTELLATION_NUM][HIERARCHY_NUM] = { + { 70705899, 70705899, 70705899, 70705899 }, + { 82433173, 82433173, 87483115, 94445660 }, + { 92888734, 92888734, 95487525, 99770748 }, + }; + + if (priv->sleeping) + return 0; + + /* reports SNR in resolution of 0.1 dB */ + + ret = rtl2830_rd_reg(priv, 0x33c, &tmp); + if (ret) + goto err; + + constellation = (tmp >> 2) & 0x03; /* [3:2] */ + if (constellation > CONSTELLATION_NUM - 1) + goto err; + + hierarchy = (tmp >> 4) & 0x07; /* [6:4] */ + if (hierarchy > HIERARCHY_NUM - 1) + goto err; + + ret = rtl2830_rd_regs(priv, 0x40c, buf, 2); + if (ret) + goto err; + + tmp16 = buf[0] << 8 | buf[1]; + + if (tmp16) + *snr = (snr_constant[constellation][hierarchy] - + intlog10(tmp16)) / ((1 << 24) / 100); + else + *snr = 0; + return 0; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; } static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber) { - *ber = 0; + struct rtl2830_priv *priv = fe->demodulator_priv; + int ret; + u8 buf[2]; + + if (priv->sleeping) + return 0; + + ret = rtl2830_rd_regs(priv, 0x34e, buf, 2); + if (ret) + goto err; + + *ber = buf[0] << 8 | buf[1]; + return 0; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; } static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) @@ -422,8 +592,32 @@ static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { - *strength = 0; + struct rtl2830_priv *priv = fe->demodulator_priv; + int ret; + u8 buf[2]; + u16 if_agc_raw, if_agc; + + if (priv->sleeping) + return 0; + + ret = rtl2830_rd_regs(priv, 0x359, buf, 2); + if (ret) + goto err; + + if_agc_raw = (buf[0] << 8 | buf[1]) & 0x3fff; + + if (if_agc_raw & (1 << 9)) + if_agc = -(~(if_agc_raw - 1) & 0x1ff); + else + if_agc = if_agc_raw; + + *strength = (u8) (55 - if_agc / 182); + *strength |= *strength << 8; + return 0; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; } static struct dvb_frontend_ops rtl2830_ops; @@ -549,6 +743,7 @@ static struct dvb_frontend_ops rtl2830_ops = { .get_tune_settings = rtl2830_get_tune_settings, .set_frontend = rtl2830_set_frontend, + .get_frontend = rtl2830_get_frontend, .read_status = rtl2830_read_status, .read_snr = rtl2830_read_snr, diff --git a/drivers/media/dvb/frontends/rtl2830_priv.h b/drivers/media/dvb/frontends/rtl2830_priv.h index 4a464761b5b..9b20557ccf6 100644 --- a/drivers/media/dvb/frontends/rtl2830_priv.h +++ b/drivers/media/dvb/frontends/rtl2830_priv.h @@ -22,6 +22,7 @@ #define RTL2830_PRIV_H #include "dvb_frontend.h" +#include "dvb_math.h" #include "rtl2830.h" #define LOG_PREFIX "rtl2830" diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb/frontends/stb0899_drv.c index dd08f4ac64a..8b0dc74a329 100644 --- a/drivers/media/dvb/frontends/stb0899_drv.c +++ b/drivers/media/dvb/frontends/stb0899_drv.c @@ -637,11 +637,9 @@ static void stb0899_init_calc(struct stb0899_state *state) struct stb0899_internal *internal = &state->internal; int master_clk; u8 agc[2]; - u8 agc1cn; u32 reg; /* Read registers (in burst mode) */ - agc1cn = stb0899_read_reg(state, STB0899_AGC1CN); stb0899_read_regs(state, STB0899_AGC1REF, agc, 2); /* AGC1R and AGC2O */ /* Initial calculations */ @@ -823,15 +821,12 @@ static int stb0899_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t static int stb0899_diseqc_init(struct stb0899_state *state) { - struct dvb_diseqc_master_cmd tx_data; /* struct dvb_diseqc_slave_reply rx_data; */ - u8 f22_tx, f22_rx, reg; + u8 f22_tx, reg; u32 mclk, tx_freq = 22000;/* count = 0, i; */ - tx_data.msg[0] = 0xe2; - tx_data.msg_len = 3; reg = stb0899_read_reg(state, STB0899_DISCNTRL2); STB0899_SETFIELD_VAL(ONECHIP_TRX, reg, 0); stb0899_write_reg(state, STB0899_DISCNTRL2, reg); @@ -849,7 +844,6 @@ static int stb0899_diseqc_init(struct stb0899_state *state) f22_tx = mclk / (tx_freq * 32); stb0899_write_reg(state, STB0899_DISF22, f22_tx); /* DiSEqC Tx freq */ state->rx_freq = 20000; - f22_rx = mclk / (state->rx_freq * 32); return 0; } diff --git a/drivers/media/dvb/frontends/stb6100.c b/drivers/media/dvb/frontends/stb6100.c index def88abb30b..2e93e65d2cd 100644 --- a/drivers/media/dvb/frontends/stb6100.c +++ b/drivers/media/dvb/frontends/stb6100.c @@ -158,7 +158,6 @@ static int stb6100_read_regs(struct stb6100_state *state, u8 regs[]) static int stb6100_read_reg(struct stb6100_state *state, u8 reg) { u8 regs[STB6100_NUMREGS]; - int rc; struct i2c_msg msg = { .addr = state->config->tuner_address + reg, @@ -167,7 +166,7 @@ static int stb6100_read_reg(struct stb6100_state *state, u8 reg) .len = 1 }; - rc = i2c_transfer(state->i2c, &msg, 1); + i2c_transfer(state->i2c, &msg, 1); if (unlikely(reg >= STB6100_NUMREGS)) { dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg); diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c index 85c157a1fe5..d40f226160e 100644 --- a/drivers/media/dvb/frontends/stv0297.c +++ b/drivers/media/dvb/frontends/stv0297.c @@ -414,7 +414,6 @@ static int stv0297_set_frontend(struct dvb_frontend *fe) int delay; int sweeprate; int carrieroffset; - unsigned long starttime; unsigned long timeout; fe_spectral_inversion_t inversion; @@ -543,7 +542,6 @@ static int stv0297_set_frontend(struct dvb_frontend *fe) stv0297_writereg_mask(state, 0x43, 0x10, 0x10); /* wait for WGAGC lock */ - starttime = jiffies; timeout = jiffies + msecs_to_jiffies(2000); while (time_before(jiffies, timeout)) { msleep(10); diff --git a/drivers/media/dvb/frontends/stv0900_sw.c b/drivers/media/dvb/frontends/stv0900_sw.c index ba0709b2d43..4af20780fb9 100644 --- a/drivers/media/dvb/frontends/stv0900_sw.c +++ b/drivers/media/dvb/frontends/stv0900_sw.c @@ -835,7 +835,6 @@ static void stv0900_track_optimization(struct dvb_frontend *fe) blind_tun_sw = 0, modulation; - enum fe_stv0900_rolloff rolloff; enum fe_stv0900_modcode foundModcod; dprintk("%s\n", __func__); @@ -940,7 +939,6 @@ static void stv0900_track_optimization(struct dvb_frontend *fe) freq1 = stv0900_read_reg(intp, CFR2); freq0 = stv0900_read_reg(intp, CFR1); - rolloff = stv0900_get_bits(intp, ROLLOFF_STATUS); if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH) { stv0900_write_reg(intp, SFRSTEP, 0x00); stv0900_write_bits(intp, SCAN_ENABLE, 0); diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c index 4aef1877ed4..d79e69f65cb 100644 --- a/drivers/media/dvb/frontends/stv090x.c +++ b/drivers/media/dvb/frontends/stv090x.c @@ -2842,7 +2842,6 @@ static int stv090x_optimize_track(struct stv090x_state *state) { struct dvb_frontend *fe = &state->frontend; - enum stv090x_rolloff rolloff; enum stv090x_modcod modcod; s32 srate, pilots, aclc, f_1, f_0, i = 0, blind_tune = 0; @@ -2966,7 +2965,6 @@ static int stv090x_optimize_track(struct stv090x_state *state) f_1 = STV090x_READ_DEMOD(state, CFR2); f_0 = STV090x_READ_DEMOD(state, CFR1); reg = STV090x_READ_DEMOD(state, TMGOBS); - rolloff = STV090x_GETFIELD_Px(reg, ROLLOFF_STATUS_FIELD); if (state->algo == STV090x_BLIND_SEARCH) { STV090x_WRITE_DEMOD(state, SFRSTEP, 0x00); diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c index ac723789137..82946cd517f 100644 --- a/drivers/media/dvb/frontends/zl10353.c +++ b/drivers/media/dvb/frontends/zl10353.c @@ -525,7 +525,7 @@ static int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr) zl10353_dump_regs(fe); _snr = zl10353_read_register(state, SNR); - *snr = (_snr << 8) | _snr; + *snr = 10 * _snr / 8; return 0; } @@ -559,7 +559,6 @@ static int zl10353_init(struct dvb_frontend *fe) { struct zl10353_state *state = fe->demodulator_priv; u8 zl10353_reset_attach[6] = { 0x50, 0x03, 0x64, 0x46, 0x15, 0x0F }; - int rc = 0; if (debug_regs) zl10353_dump_regs(fe); @@ -573,7 +572,7 @@ static int zl10353_init(struct dvb_frontend *fe) /* Do a "hard" reset if not already done */ if (zl10353_read_register(state, 0x50) != zl10353_reset_attach[1] || zl10353_read_register(state, 0x51) != zl10353_reset_attach[2]) { - rc = zl10353_write(fe, zl10353_reset_attach, + zl10353_write(fe, zl10353_reset_attach, sizeof(zl10353_reset_attach)); if (debug_regs) zl10353_dump_regs(fe); diff --git a/drivers/media/dvb/mantis/hopper_cards.c b/drivers/media/dvb/mantis/hopper_cards.c index 71622f65c03..cc0251e0107 100644 --- a/drivers/media/dvb/mantis/hopper_cards.c +++ b/drivers/media/dvb/mantis/hopper_cards.c @@ -65,7 +65,7 @@ static int devs; static irqreturn_t hopper_irq_handler(int irq, void *dev_id) { - u32 stat = 0, mask = 0, lstat = 0; + u32 stat = 0, mask = 0; u32 rst_stat = 0, rst_mask = 0; struct mantis_pci *mantis; @@ -80,7 +80,6 @@ static irqreturn_t hopper_irq_handler(int irq, void *dev_id) stat = mmread(MANTIS_INT_STAT); mask = mmread(MANTIS_INT_MASK); - lstat = stat & ~MANTIS_INT_RISCSTAT; if (!(stat & mask)) return IRQ_NONE; diff --git a/drivers/media/dvb/mantis/mantis_cards.c b/drivers/media/dvb/mantis/mantis_cards.c index c2bb90b3e52..095cf3a994e 100644 --- a/drivers/media/dvb/mantis/mantis_cards.c +++ b/drivers/media/dvb/mantis/mantis_cards.c @@ -73,7 +73,7 @@ static char *label[10] = { static irqreturn_t mantis_irq_handler(int irq, void *dev_id) { - u32 stat = 0, mask = 0, lstat = 0; + u32 stat = 0, mask = 0; u32 rst_stat = 0, rst_mask = 0; struct mantis_pci *mantis; @@ -88,7 +88,6 @@ static irqreturn_t mantis_irq_handler(int irq, void *dev_id) stat = mmread(MANTIS_INT_STAT); mask = mmread(MANTIS_INT_MASK); - lstat = stat & ~MANTIS_INT_RISCSTAT; if (!(stat & mask)) return IRQ_NONE; diff --git a/drivers/media/dvb/mantis/mantis_dma.c b/drivers/media/dvb/mantis/mantis_dma.c index c61ca7d3dae..566c407175a 100644 --- a/drivers/media/dvb/mantis/mantis_dma.c +++ b/drivers/media/dvb/mantis/mantis_dma.c @@ -199,10 +199,6 @@ void mantis_dma_start(struct mantis_pci *mantis) void mantis_dma_stop(struct mantis_pci *mantis) { - u32 stat = 0, mask = 0; - - stat = mmread(MANTIS_INT_STAT); - mask = mmread(MANTIS_INT_MASK); dprintk(MANTIS_DEBUG, 1, "Mantis Stop DMA engine"); mmwrite((mmread(MANTIS_GPIF_ADDR) & (~(MANTIS_GPIF_HIFRDWRN))), MANTIS_GPIF_ADDR); diff --git a/drivers/media/dvb/mantis/mantis_evm.c b/drivers/media/dvb/mantis/mantis_evm.c index 36f2256ebb0..71ce52875c3 100644 --- a/drivers/media/dvb/mantis/mantis_evm.c +++ b/drivers/media/dvb/mantis/mantis_evm.c @@ -41,10 +41,9 @@ static void mantis_hifevm_work(struct work_struct *work) struct mantis_ca *ca = container_of(work, struct mantis_ca, hif_evm_work); struct mantis_pci *mantis = ca->ca_priv; - u32 gpif_stat, gpif_mask; + u32 gpif_stat; gpif_stat = mmread(MANTIS_GPIF_STATUS); - gpif_mask = mmread(MANTIS_GPIF_IRQCFG); if (gpif_stat & MANTIS_GPIF_DETSTAT) { if (gpif_stat & MANTIS_CARD_PLUGIN) { diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index f129a9303f8..39857384af1 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -1409,10 +1409,8 @@ static int ngene_start(struct ngene *dev) if (stat < 0) goto fail; - if (!stat) - return stat; + return 0; - /* otherwise error: fall through */ fail: ngwritel(0, NGENE_INT_ENABLE); free_irq(dev->pci_dev->irq, dev); diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c index e1f20c23698..f148b19a206 100644 --- a/drivers/media/dvb/pluto2/pluto2.c +++ b/drivers/media/dvb/pluto2/pluto2.c @@ -481,14 +481,6 @@ static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe) if (p->bandwidth_hz == 8000000) buf[3] |= 0x08; - if (sizeof(buf) == 6) { - buf[4] = buf[2]; - buf[4] &= ~0x1c; - buf[4] |= 0x18; - - buf[5] = (0 << 7) | (2 << 4); - } - msg.addr = I2C_ADDR_TUA6034 >> 1; msg.flags = 0; msg.buf = buf; diff --git a/drivers/media/dvb/siano/smssdio.c b/drivers/media/dvb/siano/smssdio.c index 91f8c8291e2..d6f3f100699 100644 --- a/drivers/media/dvb/siano/smssdio.c +++ b/drivers/media/dvb/siano/smssdio.c @@ -114,7 +114,7 @@ out: static void smssdio_interrupt(struct sdio_func *func) { - int ret, isr; + int ret; struct smssdio_device *smsdev; struct smscore_buffer_t *cb; @@ -127,7 +127,7 @@ static void smssdio_interrupt(struct sdio_func *func) * The interrupt register has no defined meaning. It is just * a way of turning of the level triggered interrupt. */ - isr = sdio_readb(func, SMSSDIO_INT, &ret); + (void)sdio_readb(func, SMSSDIO_INT, &ret); if (ret) { sms_err("Unable to read interrupt register!\n"); return; diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c index b1fe5137df0..63c004a25e0 100644 --- a/drivers/media/dvb/siano/smsusb.c +++ b/drivers/media/dvb/siano/smsusb.c @@ -542,6 +542,8 @@ static const struct usb_device_id smsusb_id_table[] __devinitconst = { .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { USB_DEVICE(0x2040, 0xc090), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xc0a0), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { } /* Terminating entry */ }; diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index ee8ee1d481f..1b2d15140a1 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -107,7 +107,7 @@ static struct v4l2_input inputs[4] = { .index = 1, .name = "Television", .type = V4L2_INPUT_TYPE_TUNER, - .audioset = 2, + .audioset = 1, .tuner = 0, .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, .status = 0, @@ -494,7 +494,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input) dprintk(2, "VIDIOC_S_INPUT: %d\n", input); if (!av7110->analog_tuner_flags) - return 0; + return input ? -EINVAL : 0; if (input >= 4) return -EINVAL; @@ -503,19 +503,38 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input) return av7110_dvb_c_switch(fh); } +static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a) +{ + dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index); + if (a->index != 0) + return -EINVAL; + *a = msp3400_v4l2_audio; + return 0; +} + static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) { + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index); if (a->index != 0) return -EINVAL; - memcpy(a, &msp3400_v4l2_audio, sizeof(struct v4l2_audio)); + if (av7110->current_input >= 2) + return -EINVAL; + *a = msp3400_v4l2_audio; return 0; } static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a) { + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index); - return 0; + if (av7110->current_input >= 2) + return -EINVAL; + return a->index ? -EINVAL : 0; } static int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, @@ -802,26 +821,39 @@ int av7110_init_v4l(struct av7110 *av7110) ERR("cannot init capture device. skipping\n"); return -ENODEV; } - vv_data->ops.vidioc_enum_input = vidioc_enum_input; - vv_data->ops.vidioc_g_input = vidioc_g_input; - vv_data->ops.vidioc_s_input = vidioc_s_input; - vv_data->ops.vidioc_g_tuner = vidioc_g_tuner; - vv_data->ops.vidioc_s_tuner = vidioc_s_tuner; - vv_data->ops.vidioc_g_frequency = vidioc_g_frequency; - vv_data->ops.vidioc_s_frequency = vidioc_s_frequency; - vv_data->ops.vidioc_g_audio = vidioc_g_audio; - vv_data->ops.vidioc_s_audio = vidioc_s_audio; - vv_data->ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap; - vv_data->ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out; - vv_data->ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out; + vv_data->vid_ops.vidioc_enum_input = vidioc_enum_input; + vv_data->vid_ops.vidioc_g_input = vidioc_g_input; + vv_data->vid_ops.vidioc_s_input = vidioc_s_input; + vv_data->vid_ops.vidioc_g_tuner = vidioc_g_tuner; + vv_data->vid_ops.vidioc_s_tuner = vidioc_s_tuner; + vv_data->vid_ops.vidioc_g_frequency = vidioc_g_frequency; + vv_data->vid_ops.vidioc_s_frequency = vidioc_s_frequency; + vv_data->vid_ops.vidioc_enumaudio = vidioc_enumaudio; + vv_data->vid_ops.vidioc_g_audio = vidioc_g_audio; + vv_data->vid_ops.vidioc_s_audio = vidioc_s_audio; + vv_data->vid_ops.vidioc_g_fmt_vbi_cap = NULL; + + vv_data->vbi_ops.vidioc_g_tuner = vidioc_g_tuner; + vv_data->vbi_ops.vidioc_s_tuner = vidioc_s_tuner; + vv_data->vbi_ops.vidioc_g_frequency = vidioc_g_frequency; + vv_data->vbi_ops.vidioc_s_frequency = vidioc_s_frequency; + vv_data->vbi_ops.vidioc_g_fmt_vbi_cap = NULL; + vv_data->vbi_ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap; + vv_data->vbi_ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out; + vv_data->vbi_ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out; + + if (FW_VERSION(av7110->arm_app) < 0x2623) + vv_data->capabilities &= ~V4L2_CAP_SLICED_VBI_OUTPUT; if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) { ERR("cannot register capture device. skipping\n"); saa7146_vv_release(dev); return -ENODEV; } - if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) - ERR("cannot register vbi v4l2 device. skipping\n"); + if (FW_VERSION(av7110->arm_app) >= 0x2623) { + if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) + ERR("cannot register vbi v4l2 device. skipping\n"); + } return 0; } @@ -905,7 +937,7 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std) static struct saa7146_ext_vv av7110_vv_data_st = { .inputs = 1, .audios = 1, - .capabilities = V4L2_CAP_SLICED_VBI_OUTPUT, + .capabilities = V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO, .flags = 0, .stds = &standard[0], @@ -920,7 +952,7 @@ static struct saa7146_ext_vv av7110_vv_data_st = { static struct saa7146_ext_vv av7110_vv_data_c = { .inputs = 1, .audios = 1, - .capabilities = V4L2_CAP_TUNER | V4L2_CAP_SLICED_VBI_OUTPUT, + .capabilities = V4L2_CAP_TUNER | V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO, .flags = SAA7146_USE_PORT_B_FOR_VBI, .stds = &standard[0], diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 8b32e282bf5..12ddb53c58d 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -1483,9 +1483,9 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio ERR("cannot init vv subsystem\n"); return err; } - vv_data.ops.vidioc_enum_input = vidioc_enum_input; - vv_data.ops.vidioc_g_input = vidioc_g_input; - vv_data.ops.vidioc_s_input = vidioc_s_input; + vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input; + vv_data.vid_ops.vidioc_g_input = vidioc_g_input; + vv_data.vid_ops.vidioc_s_input = vidioc_s_input; if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) { /* fixme: proper cleanup here */ |