diff options
Diffstat (limited to 'drivers/media/dvb')
30 files changed, 3230 insertions, 845 deletions
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c index 53e3f2a7d31..f0f483ac8b8 100644 --- a/drivers/media/dvb/dm1105/dm1105.c +++ b/drivers/media/dvb/dm1105/dm1105.c @@ -589,7 +589,7 @@ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105) snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys), "pci-%s/ir0", pci_name(dm1105->pdev)); - err = ir_input_init(input_dev, &dm1105->ir.ir, ir_type, ir_codes); + err = ir_input_init(input_dev, &dm1105->ir.ir, ir_type); if (err < 0) { input_free_device(input_dev); return err; @@ -611,20 +611,14 @@ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105) INIT_WORK(&dm1105->ir.work, dm1105_emit_key); - err = input_register_device(input_dev); - if (err) { - ir_input_free(input_dev); - input_free_device(input_dev); - return err; - } + err = ir_input_register(input_dev, ir_codes); - return 0; + return err; } void __devexit dm1105_ir_exit(struct dm1105dvb *dm1105) { - ir_input_free(dm1105->ir.input_dev); - input_unregister_device(dm1105->ir.input_dev); + ir_input_unregister(dm1105->ir.input_dev); } static int __devinit dm1105dvb_hw_init(struct dm1105dvb *dm1105dvb) diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 2dee1bf7357..1b249897c9f 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -265,9 +265,13 @@ config DVB_USB_DW2102 select DVB_TDA10021 if !DVB_FE_CUSTOMISE select DVB_MT312 if !DVB_FE_CUSTOMISE select DVB_ZL10039 if !DVB_FE_CUSTOMISE + select DVB_DS3000 if !DVB_FE_CUSTOMISE + select DVB_STB6100 if !DVB_FE_CUSTOMISE + select DVB_STV6110 if !DVB_FE_CUSTOMISE + select DVB_STV0900 if !DVB_FE_CUSTOMISE help - Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers - and the TeVii S650, S630. + Say Y here to support the DvbWorld, TeVii, Prof DVB-S/S2 USB2.0 + receivers. config DVB_USB_CINERGY_T2 tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver" diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h index 8b544fe79b0..495a90577c5 100644 --- a/drivers/media/dvb/dvb-usb/dib0700.h +++ b/drivers/media/dvb/dvb-usb/dib0700.h @@ -20,20 +20,22 @@ extern int dvb_usb_dib0700_debug; #define deb_fwdata(args...) dprintk(dvb_usb_dib0700_debug,0x04,args) #define deb_data(args...) dprintk(dvb_usb_dib0700_debug,0x08,args) -#define REQUEST_I2C_READ 0x2 -#define REQUEST_I2C_WRITE 0x3 -#define REQUEST_POLL_RC 0x4 /* deprecated in firmware v1.20 */ -#define REQUEST_JUMPRAM 0x8 -#define REQUEST_SET_CLOCK 0xB -#define REQUEST_SET_GPIO 0xC -#define REQUEST_ENABLE_VIDEO 0xF +#define REQUEST_SET_USB_XFER_LEN 0x0 /* valid only for firmware version */ + /* higher than 1.21 */ +#define REQUEST_I2C_READ 0x2 +#define REQUEST_I2C_WRITE 0x3 +#define REQUEST_POLL_RC 0x4 /* deprecated in firmware v1.20 */ +#define REQUEST_JUMPRAM 0x8 +#define REQUEST_SET_CLOCK 0xB +#define REQUEST_SET_GPIO 0xC +#define REQUEST_ENABLE_VIDEO 0xF // 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog) // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1) // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " ) -#define REQUEST_SET_RC 0x11 -#define REQUEST_NEW_I2C_READ 0x12 -#define REQUEST_NEW_I2C_WRITE 0x13 -#define REQUEST_GET_VERSION 0x15 +#define REQUEST_SET_RC 0x11 +#define REQUEST_NEW_I2C_READ 0x12 +#define REQUEST_NEW_I2C_WRITE 0x13 +#define REQUEST_GET_VERSION 0x15 struct dib0700_state { u8 channel_state; @@ -44,6 +46,8 @@ struct dib0700_state { u8 is_dib7000pc; u8 fw_use_new_i2c_api; u8 disable_streaming_master_mode; + u32 fw_version; + u32 nb_packet_buffer_size; }; extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index db7f7f79a66..0d3c9a9a33b 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -17,6 +17,14 @@ int dvb_usb_dib0700_ir_proto = 1; module_param(dvb_usb_dib0700_ir_proto, int, 0644); MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (default), 2=RC6)."); +static int nb_packet_buffer_size = 21; +module_param(nb_packet_buffer_size, int, 0644); +MODULE_PARM_DESC(nb_packet_buffer_size, + "Set the dib0700 driver data buffer size. This parameter " + "corresponds to the number of TS packets. The actual size of " + "the data buffer corresponds to this parameter " + "multiplied by 188 (default: 21)"); + DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); @@ -28,10 +36,14 @@ int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, b, sizeof(b), USB_CTRL_GET_TIMEOUT); - *hwversion = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; - *romversion = (b[4] << 24) | (b[5] << 16) | (b[6] << 8) | b[7]; - *ramversion = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11]; - *fwtype = (b[12] << 24) | (b[13] << 16) | (b[14] << 8) | b[15]; + if (hwversion != NULL) + *hwversion = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; + if (romversion != NULL) + *romversion = (b[4] << 24) | (b[5] << 16) | (b[6] << 8) | b[7]; + if (ramversion != NULL) + *ramversion = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11]; + if (fwtype != NULL) + *fwtype = (b[12] << 24) | (b[13] << 16) | (b[14] << 8) | b[15]; return ret; } @@ -97,6 +109,27 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_ return dib0700_ctrl_wr(d,buf,3); } +static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets) +{ + struct dib0700_state *st = d->priv; + u8 b[3]; + int ret; + + if (st->fw_version >= 0x10201) { + b[0] = REQUEST_SET_USB_XFER_LEN; + b[1] = (nb_ts_packets >> 8)&0xff; + b[2] = nb_ts_packets & 0xff; + + deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets); + + ret = dib0700_ctrl_wr(d, b, 3); + } else { + deb_info("this firmware does not allow to change the USB xfer len\n"); + ret = -EIO; + } + return ret; +} + /* * I2C master xfer function (supported in 1.20 firmware) */ @@ -328,7 +361,9 @@ static int dib0700_jumpram(struct usb_device *udev, u32 address) int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw) { struct hexline hx; - int pos = 0, ret, act_len; + int pos = 0, ret, act_len, i, adap_num; + u8 b[16]; + u32 fw_version; u8 buf[260]; @@ -364,6 +399,34 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw } else ret = -EIO; + /* the number of ts packet has to be at least 1 */ + if (nb_packet_buffer_size < 1) + nb_packet_buffer_size = 1; + + /* get the fimware version */ + usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + REQUEST_GET_VERSION, + USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, + b, sizeof(b), USB_CTRL_GET_TIMEOUT); + fw_version = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11]; + + /* set the buffer size - DVB-USB is allocating URB buffers + * only after the firwmare download was successful */ + for (i = 0; i < dib0700_device_count; i++) { + for (adap_num = 0; adap_num < dib0700_devices[i].num_adapters; + adap_num++) { + if (fw_version >= 0x10201) + dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 188*nb_packet_buffer_size; + else { + /* for fw version older than 1.20.1, + * the buffersize has to be n times 512 */ + dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512; + if (dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize < 512) + dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 512; + } + } + } + return ret; } @@ -371,6 +434,18 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { struct dib0700_state *st = adap->dev->priv; u8 b[4]; + int ret; + + if ((onoff != 0) && (st->fw_version >= 0x10201)) { + /* for firmware later than 1.20.1, + * the USB xfer length can be set */ + ret = dib0700_set_usb_xfer_len(adap->dev, + st->nb_packet_buffer_size); + if (ret < 0) { + deb_info("can not set the USB xfer len\n"); + return ret; + } + } b[0] = REQUEST_ENABLE_VIDEO; b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */ @@ -415,9 +490,21 @@ static int dib0700_probe(struct usb_interface *intf, for (i = 0; i < dib0700_device_count; i++) if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, - &dev, adapter_nr) == 0) - { + &dev, adapter_nr) == 0) { + struct dib0700_state *st = dev->priv; + u32 hwversion, romversion, fw_version, fwtype; + + dib0700_get_version(dev, &hwversion, &romversion, + &fw_version, &fwtype); + + deb_info("Firmware version: %x, %d, 0x%x, %d\n", + hwversion, romversion, fw_version, fwtype); + + st->fw_version = fw_version; + st->nb_packet_buffer_size = (u32)nb_packet_buffer_size; + dib0700_rc_setup(dev); + return 0; } diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 684146f98eb..44972d01bbd 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -18,6 +18,7 @@ #include "xc5000.h" #include "s5h1411.h" #include "dib0070.h" +#include "dib0090.h" #include "lgdt3305.h" #include "mxl5007t.h" @@ -130,93 +131,95 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap) /* MT226x */ static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = { { - BAND_UHF, // band_caps + BAND_UHF, /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup - - 1130, // inv_gain - 21, // time_stabiliz - - 0, // alpha_level - 118, // thlock - - 0, // wbd_inv - 3530, // wbd_ref - 1, // wbd_sel - 0, // wbd_alpha - - 65535, // agc1_max - 33770, // agc1_min - 65535, // agc2_max - 23592, // agc2_min - - 0, // agc1_pt1 - 62, // agc1_pt2 - 255, // agc1_pt3 - 64, // agc1_slope1 - 64, // agc1_slope2 - 132, // agc2_pt1 - 192, // agc2_pt2 - 80, // agc2_slope1 - 80, // agc2_slope2 - - 17, // alpha_mant - 27, // alpha_exp - 23, // beta_mant - 51, // beta_exp - - 1, // perform_agc_softsplit + (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + + 1130, + 21, + + 0, + 118, + + 0, + 3530, + 1, + 0, + + 65535, + 33770, + 65535, + 23592, + + 0, + 62, + 255, + 64, + 64, + 132, + 192, + 80, + 80, + + 17, + 27, + 23, + 51, + + 1, }, { - BAND_VHF | BAND_LBAND, // band_caps + BAND_VHF | BAND_LBAND, /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup - - 2372, // inv_gain - 21, // time_stabiliz - - 0, // alpha_level - 118, // thlock - - 0, // wbd_inv - 3530, // wbd_ref - 1, // wbd_sel - 0, // wbd_alpha - - 65535, // agc1_max - 0, // agc1_min - 65535, // agc2_max - 23592, // agc2_min - - 0, // agc1_pt1 - 128, // agc1_pt2 - 128, // agc1_pt3 - 128, // agc1_slope1 - 0, // agc1_slope2 - 128, // agc2_pt1 - 253, // agc2_pt2 - 81, // agc2_slope1 - 0, // agc2_slope2 - - 17, // alpha_mant - 27, // alpha_exp - 23, // beta_mant - 51, // beta_exp - - 1, // perform_agc_softsplit + (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), + + 2372, + 21, + + 0, + 118, + + 0, + 3530, + 1, + 0, + + 65535, + 0, + 65535, + 23592, + + 0, + 128, + 128, + 128, + 0, + 128, + 253, + 81, + 0, + + 17, + 27, + 23, + 51, + + 1, } }; static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = { - 60000, 30000, // internal, sampling - 1, 8, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass - 0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo - (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k - 0, // ifreq - 20452225, // timf + 60000, 30000, + 1, 8, 3, 1, 0, + 0, 0, 1, 1, 2, + (3 << 14) | (1 << 12) | (524 << 0), + 0, + 20452225, }; static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = { @@ -605,17 +608,17 @@ static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event, } break; default: - if (actlen != sizeof(buf)) { - /* We didn't get back the 6 byte message we expected */ - err("Unexpected RC response size [%d]", actlen); - return -1; - } + if (actlen != sizeof(buf)) { + /* We didn't get back the 6 byte message we expected */ + err("Unexpected RC response size [%d]", actlen); + return -1; + } - poll_reply.report_id = buf[0]; - poll_reply.data_state = buf[1]; + poll_reply.report_id = buf[0]; + poll_reply.data_state = buf[1]; poll_reply.system = (buf[2] << 8) | buf[3]; - poll_reply.data = buf[4]; - poll_reply.not_data = buf[5]; + poll_reply.data = buf[4]; + poll_reply.not_data = buf[5]; break; } @@ -632,7 +635,7 @@ static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event, /* Find the key in the map */ for (i = 0; i < d->props.rc_key_map_size; i++) { if (rc5_custom(&keymap[i]) == (poll_reply.system & 0xff) && - rc5_data(&keymap[i]) == poll_reply.data) { + rc5_data(&keymap[i]) == poll_reply.data) { *event = keymap[i].event; found = 1; break; @@ -641,8 +644,8 @@ static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event, if (found == 0) { err("Unknown remote controller key: %04x %02x %02x", - poll_reply.system, - poll_reply.data, poll_reply.not_data); + poll_reply.system, + poll_reply.data, poll_reply.not_data); d->last_event = 0; return 0; } @@ -933,47 +936,48 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = { /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = { - BAND_UHF | BAND_VHF, // band_caps + BAND_UHF | BAND_VHF, /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup - - 712, // inv_gain - 41, // time_stabiliz - - 0, // alpha_level - 118, // thlock - - 0, // wbd_inv - 4095, // wbd_ref - 0, // wbd_sel - 0, // wbd_alpha - - 42598, // agc1_max - 17694, // agc1_min - 45875, // agc2_max - 2621, // agc2_min - 0, // agc1_pt1 - 76, // agc1_pt2 - 139, // agc1_pt3 - 52, // agc1_slope1 - 59, // agc1_slope2 - 107, // agc2_pt1 - 172, // agc2_pt2 - 57, // agc2_slope1 - 70, // agc2_slope2 - - 21, // alpha_mant - 25, // alpha_exp - 28, // beta_mant - 48, // beta_exp - - 1, // perform_agc_softsplit - { 0, // split_min - 107, // split_max - 51800, // global_split_min - 24700 // global_split_max + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), + + 712, + 41, + + 0, + 118, + + 0, + 4095, + 0, + 0, + + 42598, + 17694, + 45875, + 2621, + 0, + 76, + 139, + 52, + 59, + 107, + 172, + 57, + 70, + + 21, + 25, + 28, + 48, + + 1, + { 0, + 107, + 51800, + 24700 }, }; @@ -982,54 +986,55 @@ static struct dibx000_agc_config stk7700p_7000p_mt2060_agc_config = { /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), - 712, // inv_gain - 41, // time_stabiliz + 712, + 41, - 0, // alpha_level - 118, // thlock + 0, + 118, - 0, // wbd_inv - 4095, // wbd_ref - 0, // wbd_sel - 0, // wbd_alpha + 0, + 4095, + 0, + 0, - 42598, // agc1_max - 16384, // agc1_min - 42598, // agc2_max - 0, // agc2_min + 42598, + 16384, + 42598, + 0, - 0, // agc1_pt1 - 137, // agc1_pt2 - 255, // agc1_pt3 + 0, + 137, + 255, - 0, // agc1_slope1 - 255, // agc1_slope2 + 0, + 255, - 0, // agc2_pt1 - 0, // agc2_pt2 + 0, + 0, - 0, // agc2_slope1 - 41, // agc2_slope2 + 0, + 41, - 15, // alpha_mant - 25, // alpha_exp + 15, + 25, - 28, // beta_mant - 48, // beta_exp + 28, + 48, - 0, // perform_agc_softsplit + 0, }; static struct dibx000_bandwidth_config stk7700p_pll_config = { - 60000, 30000, // internal, sampling - 1, 8, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass - 0, 0, 1, 1, 0, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo - (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k - 60258167, // ifreq - 20452225, // timf - 30000000, // xtal + 60000, 30000, + 1, 8, 3, 1, 0, + 0, 0, 1, 1, 0, + (3 << 14) | (1 << 12) | (524 << 0), + 60258167, + 20452225, + 30000000, }; static struct dib7000m_config stk7700p_dib7000m_config = { @@ -1115,41 +1120,42 @@ static struct dibx000_agc_config dib7070_agc_config = { BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup - - 600, // inv_gain - 10, // time_stabiliz - - 0, // alpha_level - 118, // thlock - - 0, // wbd_inv - 3530, // wbd_ref - 1, // wbd_sel - 5, // wbd_alpha - - 65535, // agc1_max - 0, // agc1_min - - 65535, // agc2_max - 0, // agc2_min - - 0, // agc1_pt1 - 40, // agc1_pt2 - 183, // agc1_pt3 - 206, // agc1_slope1 - 255, // agc1_slope2 - 72, // agc2_pt1 - 152, // agc2_pt2 - 88, // agc2_slope1 - 90, // agc2_slope2 - - 17, // alpha_mant - 27, // alpha_exp - 23, // beta_mant - 51, // beta_exp - - 0, // perform_agc_softsplit + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + + 600, + 10, + + 0, + 118, + + 0, + 3530, + 1, + 5, + + 65535, + 0, + + 65535, + 0, + + 0, + 40, + 183, + 206, + 255, + 72, + 152, + 88, + 90, + + 17, + 27, + 23, + 51, + + 0, }; static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) @@ -1276,13 +1282,13 @@ static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) } static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { - 60000, 15000, // internal, sampling - 1, 20, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass - 0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo - (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k - (0 << 25) | 0, // ifreq = 0.000000 MHz - 20452225, // timf - 12000000, // xtal_hz + 60000, 15000, + 1, 20, 3, 1, 0, + 0, 0, 1, 1, 2, + (3 << 14) | (1 << 12) | (524 << 0), + (0 << 25) | 0, + 20452225, + 12000000, }; static struct dib7000p_config dib7070p_dib7000p_config = { @@ -1476,12 +1482,12 @@ static struct dib8000_config dib807x_dib8000_config[2] = { } }; -static int dib807x_tuner_reset(struct dvb_frontend *fe, int onoff) +static int dib80xx_tuner_reset(struct dvb_frontend *fe, int onoff) { return dib8000_set_gpio(fe, 5, 0, !onoff); } -static int dib807x_tuner_sleep(struct dvb_frontend *fe, int onoff) +static int dib80xx_tuner_sleep(struct dvb_frontend *fe, int onoff) { return dib8000_set_gpio(fe, 0, 0, onoff); } @@ -1494,8 +1500,8 @@ static const struct dib0070_wbd_gain_cfg dib8070_wbd_gain_cfg[] = { static struct dib0070_config dib807x_dib0070_config[2] = { { .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, - .reset = dib807x_tuner_reset, - .sleep = dib807x_tuner_sleep, + .reset = dib80xx_tuner_reset, + .sleep = dib80xx_tuner_sleep, .clock_khz = 12000, .clock_pad_drive = 4, .vga_filter = 1, @@ -1508,8 +1514,8 @@ static struct dib0070_config dib807x_dib0070_config[2] = { .freq_offset_khz_vhf = -100, }, { .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, - .reset = dib807x_tuner_reset, - .sleep = dib807x_tuner_sleep, + .reset = dib80xx_tuner_reset, + .sleep = dib80xx_tuner_sleep, .clock_khz = 12000, .clock_pad_drive = 2, .vga_filter = 1, @@ -1566,12 +1572,14 @@ static int dib807x_tuner_attach(struct dvb_usb_adapter *adap) return 0; } -static int stk807x_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) +static int stk80xx_pid_filter(struct dvb_usb_adapter *adapter, int index, + u16 pid, int onoff) { return dib8000_pid_filter(adapter->fe, index, pid, onoff); } -static int stk807x_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) +static int stk80xx_pid_filter_ctrl(struct dvb_usb_adapter *adapter, + int onoff) { return dib8000_pid_filter_ctrl(adapter->fe, onoff); } @@ -1624,7 +1632,7 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap) dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); /* initialize IC 0 */ - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x80); + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80); adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib807x_dib8000_config[0]); @@ -1635,7 +1643,7 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap) static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) { /* initialize IC 1 */ - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x82); + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82); adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib807x_dib8000_config[1]); @@ -1643,6 +1651,245 @@ static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) return adap->fe == NULL ? -ENODEV : 0; } +/* STK8096GP */ +struct dibx000_agc_config dib8090_agc_config[2] = { + { + BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, + * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + + 787, + 10, + + 0, + 118, + + 0, + 3530, + 1, + 5, + + 65535, + 0, + + 65535, + 0, + + 0, + 32, + 114, + 143, + 144, + 114, + 227, + 116, + 117, + + 28, + 26, + 31, + 51, + + 0, + }, + { + BAND_CBAND, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, + * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + + 787, + 10, + + 0, + 118, + + 0, + 3530, + 1, + 5, + + 0, + 0, + + 65535, + 0, + + 0, + 32, + 114, + 143, + 144, + 114, + 227, + 116, + 117, + + 28, + 26, + 31, + 51, + + 0, + } +}; + +static struct dibx000_bandwidth_config dib8090_pll_config_12mhz = { + 54000, 13500, + 1, 18, 3, 1, 0, + 0, 0, 1, 1, 2, + (3 << 14) | (1 << 12) | (599 << 0), + (0 << 25) | 0, + 20199727, + 12000000, +}; + +static int dib8090_get_adc_power(struct dvb_frontend *fe) +{ + return dib8000_get_adc_power(fe, 1); +} + +static struct dib8000_config dib809x_dib8000_config = { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 2, + .agc = dib8090_agc_config, + .agc_control = dib0090_dcc_freq, + .pll = &dib8090_pll_config_12mhz, + .tuner_is_baseband = 1, + + .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + .div_cfg = 0x31, + .output_mode = OUTMODE_MPEG2_FIFO, + .drives = 0x2d98, + .diversity_delay = 144, + .refclksel = 3, +}; + +static struct dib0090_config dib809x_dib0090_config = { + .io.pll_bypass = 1, + .io.pll_range = 1, + .io.pll_prediv = 1, + .io.pll_loopdiv = 20, + .io.adc_clock_ratio = 8, + .io.pll_int_loop_filt = 0, + .io.clock_khz = 12000, + .reset = dib80xx_tuner_reset, + .sleep = dib80xx_tuner_sleep, + .clkouttobamse = 1, + .analog_output = 1, + .i2c_address = DEFAULT_DIB0090_I2C_ADDRESS, + .wbd_vhf_offset = 100, + .wbd_cband_offset = 450, + .use_pwm_agc = 1, + .clkoutdrive = 1, + .get_adc_power = dib8090_get_adc_power, + .freq_offset_khz_uhf = 0, + .freq_offset_khz_vhf = -143, +}; + +static int dib8096_set_param_override(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + u16 offset; + int ret = 0; + enum frontend_tune_state tune_state = CT_SHUTDOWN; + u16 ltgain, rf_gain_limit; + + ret = state->set_param_save(fe, fep); + if (ret < 0) + return ret; + + switch (band) { + case BAND_VHF: + offset = 100; + break; + case BAND_UHF: + offset = 550; + break; + default: + offset = 0; + break; + } + offset += (dib0090_get_wbd_offset(fe) * 8 * 18 / 33 + 1) / 2; + dib8000_set_wbd_ref(fe, offset); + + + if (band == BAND_CBAND) { + deb_info("tuning in CBAND - soft-AGC startup\n"); + /* TODO specific wbd target for dib0090 - needed for startup ? */ + dib0090_set_tune_state(fe, CT_AGC_START); + do { + ret = dib0090_gain_control(fe); + msleep(ret); + tune_state = dib0090_get_tune_state(fe); + if (tune_state == CT_AGC_STEP_0) + dib8000_set_gpio(fe, 6, 0, 1); + else if (tune_state == CT_AGC_STEP_1) { + dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, <gain); + if (rf_gain_limit == 0) + dib8000_set_gpio(fe, 6, 0, 0); + } + } while (tune_state < CT_AGC_STOP); + dib0090_pwm_gain_reset(fe); + dib8000_pwm_agc_reset(fe); + dib8000_set_tune_state(fe, CT_DEMOD_START); + } else { + deb_info("not tuning in CBAND - standard AGC startup\n"); + dib0090_pwm_gain_reset(fe); + } + + return 0; +} + +static int dib809x_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + + if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL) + return -ENODEV; + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override; + return 0; +} + +static int stk809x_frontend_attach(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80); + + adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config); + + return adap->fe == NULL ? -ENODEV : 0; +} /* STK7070PD */ static struct dib7000p_config stk7070pd_dib7000p_config[2] = { @@ -1929,14 +2176,17 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D) }, /* 55 */{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D_2) }, { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73A) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73ESE) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV282E) }, + { USB_DEVICE(USB_VID_PCTV, USB_PID_PINNACLE_PCTV73ESE) }, + { USB_DEVICE(USB_VID_PCTV, USB_PID_PINNACLE_PCTV282E) }, { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7770P) }, /* 60 */{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS_2) }, { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XPVR) }, { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XP) }, { USB_DEVICE(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD) }, { USB_DEVICE(USB_VID_EVOLUTEPC, USB_PID_TVWAY_PLUS) }, +/* 65 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73ESE) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV282E) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK8096GP) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -2238,11 +2488,11 @@ struct dvb_usb_device_properties dib0700_devices[] = { { NULL }, }, { "Pinnacle PCTV 73e SE", - { &dib0700_usb_id_table[57], NULL }, + { &dib0700_usb_id_table[57], &dib0700_usb_id_table[65], NULL }, { NULL }, }, { "Pinnacle PCTV 282e", - { &dib0700_usb_id_table[58], NULL }, + { &dib0700_usb_id_table[58], &dib0700_usb_id_table[66], NULL }, { NULL }, }, }, @@ -2471,8 +2721,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { { .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, - .pid_filter = stk807x_pid_filter, - .pid_filter_ctrl = stk807x_pid_filter_ctrl, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, .frontend_attach = stk807x_frontend_attach, .tuner_attach = dib807x_tuner_attach, @@ -2510,8 +2760,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { { .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, - .pid_filter = stk807x_pid_filter, - .pid_filter_ctrl = stk807x_pid_filter_ctrl, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, .frontend_attach = stk807xpvr_frontend_attach0, .tuner_attach = dib807x_tuner_attach, @@ -2523,8 +2773,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { { .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, - .pid_filter = stk807x_pid_filter, - .pid_filter_ctrl = stk807x_pid_filter_ctrl, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, .frontend_attach = stk807xpvr_frontend_attach1, .tuner_attach = dib807x_tuner_attach, @@ -2547,6 +2797,37 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_key_map = dib0700_rc_keys, .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), .rc_query = dib0700_rc_query + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, + .frontend_attach = stk809x_frontend_attach, + .tuner_attach = dib809x_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom STK8096GP reference design", + { &dib0700_usb_id_table[67], NULL }, + { NULL }, + }, + }, + + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = dib0700_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), + .rc_query = dib0700_rc_query }, }; diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c index da34979b533..9143b5631e8 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-common.c +++ b/drivers/media/dvb/dvb-usb/dibusb-common.c @@ -142,8 +142,13 @@ static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num } else if ((msg[i].flags & I2C_M_RD) == 0) { if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0) break; - } else - break; + } else if (msg[i].addr != 0x50) { + /* 0x50 is the address of the eeprom - we need to protect it + * from dibusb's bad i2c implementation: reads without + * writing the offset before are forbidden */ + if (dibusb_i2c_msg(d, msg[i].addr, NULL, 0, msg[i].buf, msg[i].len) < 0) + break; + } } mutex_unlock(&d->i2c_mutex); @@ -243,6 +248,12 @@ static struct dib3000mc_config mod3000p_dib3000p_config = { int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap) { + if (adap->dev->udev->descriptor.idVendor == USB_VID_LITEON && + adap->dev->udev->descriptor.idProduct == + USB_PID_LITEON_DVB_T_WARM) { + msleep(1000); + } + if ((adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL || (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) { if (adap->priv != NULL) { diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index f1602d4ace6..bc3581d58ce 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -47,6 +47,7 @@ #define USB_VID_MSI_2 0x1462 #define USB_VID_OPERA1 0x695c #define USB_VID_PINNACLE 0x2304 +#define USB_VID_PCTV 0x2013 #define USB_VID_PIXELVIEW 0x1554 #define USB_VID_TECHNOTREND 0x0b48 #define USB_VID_TERRATEC 0x0ccd @@ -101,6 +102,7 @@ #define USB_PID_DIBCOM_STK7070PD 0x1ebe #define USB_PID_DIBCOM_STK807XP 0x1f90 #define USB_PID_DIBCOM_STK807XPVR 0x1f98 +#define USB_PID_DIBCOM_STK8096GP 0x1fa0 #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 #define USB_PID_DIBCOM_STK7770P 0x1e80 #define USB_PID_DPOSH_M9206_COLD 0x9206 @@ -211,6 +213,7 @@ #define USB_PID_PINNACLE_PCTV801E_SE 0x023b #define USB_PID_PINNACLE_PCTV73A 0x0243 #define USB_PID_PINNACLE_PCTV73ESE 0x0245 +#define USB_PID_PINNACLE_PCTV74E 0x0246 #define USB_PID_PINNACLE_PCTV282E 0x0248 #define USB_PID_PIXELVIEW_SBTVD 0x5010 #define USB_PID_PCTV_200E 0x020e diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 5bb9479d154..64132c0cf80 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -20,6 +20,11 @@ #include "tda1002x.h" #include "mt312.h" #include "zl10039.h" +#include "ds3000.h" +#include "stv0900.h" +#include "stv6110.h" +#include "stb6100.h" +#include "stb6100_proc.h" #ifndef USB_PID_DW2102 #define USB_PID_DW2102 0x2102 @@ -37,12 +42,20 @@ #define USB_PID_CINERGY_S 0x0064 #endif +#ifndef USB_PID_TEVII_S630 +#define USB_PID_TEVII_S630 0xd630 +#endif + #ifndef USB_PID_TEVII_S650 #define USB_PID_TEVII_S650 0xd650 #endif -#ifndef USB_PID_TEVII_S630 -#define USB_PID_TEVII_S630 0xd630 +#ifndef USB_PID_TEVII_S660 +#define USB_PID_TEVII_S660 0xd660 +#endif + +#ifndef USB_PID_PROF_1100 +#define USB_PID_PROF_1100 0xb012 #endif #define DW210X_READ_MSG 0 @@ -55,6 +68,10 @@ #define DW2102_VOLTAGE_CTRL (0x1800) #define DW2102_RC_QUERY (0x1a00) +#define err_str "did not find the firmware file. (%s) " \ + "Please see linux/Documentation/dvb/ for more details " \ + "on firmware-problems." + struct dvb_usb_rc_keys_table { struct dvb_usb_rc_key *rc_keys; int rc_keys_size; @@ -71,6 +88,12 @@ static int ir_keymap; module_param_named(keymap, ir_keymap, int, 0644); MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs ..."); +/* demod probe */ +static int demod_probe = 1; +module_param_named(demod, demod_probe, int, 0644); +MODULE_PARM_DESC(demod, "demod to probe (1=cx24116 2=stv0903+stv6110 " + "4=stv0903+stb6100(or-able))."); + DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value, @@ -183,7 +206,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, switch (num) { case 2: /* read si2109 register by number */ - buf6[0] = 0xd0; + 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, @@ -198,7 +221,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, switch (msg[0].addr) { case 0x68: /* write to si2109 register */ - buf6[0] = 0xd0; + 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, @@ -239,7 +262,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms /* read */ /* first write first register number */ u8 ibuf[msg[1].len + 2], obuf[3]; - obuf[0] = 0xd0; + 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, @@ -256,7 +279,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms case 0x68: { /* write to register */ u8 obuf[msg[0].len + 2]; - obuf[0] = 0xd0; + 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, @@ -266,7 +289,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms case 0x61: { /* write to tuner */ u8 obuf[msg[0].len + 2]; - obuf[0] = 0xc2; + 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, @@ -301,78 +324,78 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i { struct dvb_usb_device *d = i2c_get_adapdata(adap); int ret = 0; - int len, i; + int len, i, j; if (!d) return -ENODEV; if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; - switch (num) { - case 2: { - /* read */ - /* first write first register number */ - u8 ibuf[msg[1].len + 2], obuf[3]; - obuf[0] = 0xaa; - obuf[1] = msg[0].len; - obuf[2] = msg[0].buf[0]; - ret = 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, 0xab , 0, - ibuf, msg[1].len + 2, DW210X_READ_MSG); - memcpy(msg[1].buf, ibuf + 2, msg[1].len); - - break; - } - case 1: - switch (msg[0].addr) { - case 0x55: { - if (msg[0].buf[0] == 0xf7) { - /* firmware */ - /* Write in small blocks */ - u8 obuf[19]; - obuf[0] = 0xaa; - obuf[1] = 0x11; - obuf[2] = 0xf7; - len = msg[0].len - 1; - i = 1; - do { - memcpy(obuf + 3, msg[0].buf + i, (len > 16 ? 16 : len)); - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, (len > 16 ? 16 : len) + 3, DW210X_WRITE_MSG); - i += 16; - len -= 16; - } while (len > 0); - } else { - /* write to register */ - u8 obuf[msg[0].len + 2]; - obuf[0] = 0xaa; - obuf[1] = msg[0].len; - memcpy(obuf + 2, msg[0].buf, msg[0].len); - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[0].len + 2, DW210X_WRITE_MSG); - } - break; - } + for (j = 0; j < num; j++) { + switch (msg[j].addr) { case(DW2102_RC_QUERY): { u8 ibuf[2]; ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, ibuf, 2, DW210X_READ_MSG); - memcpy(msg[0].buf, ibuf , 2); + memcpy(msg[j].buf, ibuf , 2); break; } case(DW2102_VOLTAGE_CTRL): { u8 obuf[2]; obuf[0] = 0x30; - obuf[1] = msg[0].buf[0]; + obuf[1] = msg[j].buf[0]; ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, obuf, 2, DW210X_WRITE_MSG); break; } + /*case 0x55: cx24116 + case 0x6a: stv0903 + case 0x68: ds3000, stv0903 + case 0x60: ts2020, stv6110, stb6100 */ + default: { + if (msg[j].flags == I2C_M_RD) { + /* read registers */ + u8 ibuf[msg[j].len + 2]; + ret = dw210x_op_rw(d->udev, 0xc3, + (msg[j].addr << 1) + 1, 0, + ibuf, msg[j].len + 2, + DW210X_READ_MSG); + memcpy(msg[j].buf, ibuf + 2, msg[j].len); + mdelay(10); + } else if (((msg[j].buf[0] == 0xb0) && + (msg[j].addr == 0x68)) || + ((msg[j].buf[0] == 0xf7) && + (msg[j].addr == 0x55))) { + /* write firmware */ + u8 obuf[19]; + obuf[0] = msg[j].addr << 1; + obuf[1] = (msg[j].len > 15 ? 17 : msg[j].len); + obuf[2] = msg[j].buf[0]; + len = msg[j].len - 1; + i = 1; + do { + memcpy(obuf + 3, msg[j].buf + i, + (len > 16 ? 16 : len)); + ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, (len > 16 ? 16 : len) + 3, + DW210X_WRITE_MSG); + i += 16; + len -= 16; + } while (len > 0); + } else { + /* write registers */ + u8 obuf[msg[j].len + 2]; + 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, + obuf, msg[j].len + 2, + DW210X_WRITE_MSG); + } + break; + } } - break; } mutex_unlock(&d->i2c_mutex); @@ -442,63 +465,85 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], return num; } -static int s630_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], +static int s6x0_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) return -ENODEV; if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; - switch (num) { - case 2: { /* read */ - u8 ibuf[msg[1].len], obuf[3]; - obuf[0] = msg[1].len; - obuf[1] = (msg[0].addr << 1); - obuf[2] = msg[0].buf[0]; - - ret = dw210x_op_rw(d->udev, 0x90, 0, 0, - obuf, 3, DW210X_WRITE_MSG); - msleep(5); - ret = dw210x_op_rw(d->udev, 0x91, 0, 0, - ibuf, msg[1].len, DW210X_READ_MSG); - memcpy(msg[1].buf, ibuf, msg[1].len); - break; - } - case 1: - switch (msg[0].addr) { - case 0x60: - case 0x0e: { - /* write to zl10313, zl10039 register, */ - u8 obuf[msg[0].len + 2]; - obuf[0] = msg[0].len + 1; - obuf[1] = (msg[0].addr << 1); - memcpy(obuf + 2, msg[0].buf, msg[0].len); - ret = dw210x_op_rw(d->udev, 0x80, 0, 0, - obuf, msg[0].len + 2, DW210X_WRITE_MSG); - break; - } + for (j = 0; j < num; j++) { + switch (msg[j].addr) { case (DW2102_RC_QUERY): { u8 ibuf[4]; ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, ibuf, 4, DW210X_READ_MSG); - msg[0].buf[0] = ibuf[3]; + memcpy(msg[j].buf, ibuf + 1, 2); break; } case (DW2102_VOLTAGE_CTRL): { u8 obuf[2]; - obuf[0] = 0x03; - obuf[1] = msg[0].buf[0]; + obuf[0] = 3; + obuf[1] = msg[j].buf[0]; ret = dw210x_op_rw(d->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); break; } + /*case 0x55: cx24116 + case 0x6a: stv0903 + case 0x68: ds3000, stv0903 + case 0x60: ts2020, stv6110, stb6100 + case 0xa0: eeprom */ + default: { + if (msg[j].flags == I2C_M_RD) { + /* read registers */ + u8 ibuf[msg[j].len]; + ret = dw210x_op_rw(d->udev, 0x91, 0, 0, + ibuf, msg[j].len, + DW210X_READ_MSG); + memcpy(msg[j].buf, ibuf, msg[j].len); + break; + } else if ((msg[j].buf[0] == 0xb0) && + (msg[j].addr == 0x68)) { + /* write firmware */ + u8 obuf[19]; + obuf[0] = (msg[j].len > 16 ? + 18 : msg[j].len + 1); + obuf[1] = msg[j].addr << 1; + obuf[2] = msg[j].buf[0]; + len = msg[j].len - 1; + i = 1; + do { + memcpy(obuf + 3, msg[j].buf + i, + (len > 16 ? 16 : len)); + ret = dw210x_op_rw(d->udev, 0x80, 0, 0, + obuf, (len > 16 ? 16 : len) + 3, + DW210X_WRITE_MSG); + i += 16; + len -= 16; + } while (len > 0); + } else { + /* write registers */ + u8 obuf[msg[j].len + 2]; + 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, + (num > 1 ? 0x90 : 0x80), 0, 0, + obuf, msg[j].len + 2, + DW210X_WRITE_MSG); + break; + } + break; + } } - break; + msleep(3); } mutex_unlock(&d->i2c_mutex); @@ -535,8 +580,8 @@ static struct i2c_algorithm dw3101_i2c_algo = { .functionality = dw210x_i2c_func, }; -static struct i2c_algorithm s630_i2c_algo = { - .master_xfer = s630_i2c_transfer, +static struct i2c_algorithm s6x0_i2c_algo = { + .master_xfer = s6x0_i2c_transfer, .functionality = dw210x_i2c_func, }; @@ -564,25 +609,34 @@ static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) return 0; }; -static int s630_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) +static int s6x0_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) { int i, ret; - u8 buf[3], eeprom[256], eepromline[16]; + u8 ibuf[] = { 0 }, obuf[] = { 0 }; + u8 eeprom[256], eepromline[16]; + struct i2c_msg msg[] = { + { + .addr = 0xa0 >> 1, + .flags = 0, + .buf = obuf, + .len = 1, + }, { + .addr = 0xa0 >> 1, + .flags = I2C_M_RD, + .buf = ibuf, + .len = 1, + } + }; for (i = 0; i < 256; i++) { - buf[0] = 1; - buf[1] = 0xa0; - buf[2] = i; - ret = dw210x_op_rw(d->udev, 0x90, 0, 0, - buf, 3, DW210X_WRITE_MSG); - ret = dw210x_op_rw(d->udev, 0x91, 0, 0, - buf, 1, DW210X_READ_MSG); - if (ret < 0) { + obuf[0] = i; + ret = s6x0_i2c_transfer(&d->i2c_adap, msg, 2); + if (ret != 2) { err("read eeprom failed."); return -1; } else { - eepromline[i % 16] = buf[0]; - eeprom[i] = buf[0]; + eepromline[i % 16] = ibuf[0]; + eeprom[i] = ibuf[0]; } if ((i % 16) == 15) { @@ -644,19 +698,104 @@ static struct mt312_config zl313_config = { .demod_address = 0x0e, }; +static struct ds3000_config dw2104_ds3000_config = { + .demod_address = 0x68, +}; + +static struct stv0900_config dw2104a_stv0900_config = { + .demod_address = 0x6a, + .demod_mode = 0, + .xtal = 27000000, + .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */ + .diseqc_mode = 2,/* 2/3 PWM */ + .tun1_maddress = 0,/* 0x60 */ + .tun1_adc = 0,/* 2 Vpp */ + .path1_mode = 3, +}; + +static struct stb6100_config dw2104a_stb6100_config = { + .tuner_address = 0x60, + .refclock = 27000000, +}; + +static struct stv0900_config dw2104_stv0900_config = { + .demod_address = 0x68, + .demod_mode = 0, + .xtal = 8000000, + .clkmode = 3, + .diseqc_mode = 2, + .tun1_maddress = 0, + .tun1_adc = 1,/* 1 Vpp */ + .path1_mode = 3, +}; + +static struct stv6110_config dw2104_stv6110_config = { + .i2c_address = 0x60, + .mclk = 16000000, + .clk_div = 1, +}; + static int dw2104_frontend_attach(struct dvb_usb_adapter *d) { - if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config, - &d->dev->i2c_adap)) != NULL) { + struct dvb_tuner_ops *tuner_ops = NULL; + + if (demod_probe & 4) { + d->fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config, + &d->dev->i2c_adap, 0); + if (d->fe != NULL) { + if (dvb_attach(stb6100_attach, d->fe, + &dw2104a_stb6100_config, + &d->dev->i2c_adap)) { + tuner_ops = &d->fe->ops.tuner_ops; + tuner_ops->set_frequency = stb6100_set_freq; + tuner_ops->get_frequency = stb6100_get_freq; + tuner_ops->set_bandwidth = stb6100_set_bandw; + tuner_ops->get_bandwidth = stb6100_get_bandw; + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached STV0900+STB6100!\n"); + return 0; + } + } + } + + if (demod_probe & 2) { + d->fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config, + &d->dev->i2c_adap, 0); + if (d->fe != NULL) { + if (dvb_attach(stv6110_attach, d->fe, + &dw2104_stv6110_config, + &d->dev->i2c_adap)) { + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached STV0900+STV6110A!\n"); + return 0; + } + } + } + + if (demod_probe & 1) { + d->fe = dvb_attach(cx24116_attach, &dw2104_config, + &d->dev->i2c_adap); + if (d->fe != NULL) { + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached cx24116!\n"); + return 0; + } + } + + d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, + &d->dev->i2c_adap); + if (d->fe != NULL) { d->fe->ops.set_voltage = dw210x_set_voltage; - info("Attached cx24116!\n"); + info("Attached DS3000!\n"); return 0; } + return -EIO; } static struct dvb_usb_device_properties dw2102_properties; static struct dvb_usb_device_properties dw2104_properties; +static struct dvb_usb_device_properties s6x0_properties; static int dw2102_frontend_attach(struct dvb_usb_adapter *d) { @@ -670,14 +809,17 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d) return 0; } } + if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) { - /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/ d->fe = dvb_attach(stv0288_attach, &earda_config, &d->dev->i2c_adap); if (d->fe != NULL) { - d->fe->ops.set_voltage = dw210x_set_voltage; - info("Attached stv0288!\n"); - return 0; + if (dvb_attach(stb6000_attach, d->fe, 0x61, + &d->dev->i2c_adap)) { + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached stv0288!\n"); + return 0; + } } } @@ -705,15 +847,38 @@ static int dw3101_frontend_attach(struct dvb_usb_adapter *d) return -EIO; } -static int s630_frontend_attach(struct dvb_usb_adapter *d) +static int s6x0_frontend_attach(struct dvb_usb_adapter *d) { d->fe = dvb_attach(mt312_attach, &zl313_config, - &d->dev->i2c_adap); + &d->dev->i2c_adap); + if (d->fe != NULL) { + if (dvb_attach(zl10039_attach, d->fe, 0x60, + &d->dev->i2c_adap)) { + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached zl100313+zl10039!\n"); + return 0; + } + } + + d->fe = dvb_attach(stv0288_attach, &earda_config, + &d->dev->i2c_adap); + if (d->fe != NULL) { + if (dvb_attach(stb6000_attach, d->fe, 0x61, + &d->dev->i2c_adap)) { + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached stv0288+stb6000!\n"); + return 0; + } + } + + d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, + &d->dev->i2c_adap); if (d->fe != NULL) { d->fe->ops.set_voltage = dw210x_set_voltage; - info("Attached zl10313!\n"); + info("Attached ds3000+ds2020!\n"); return 0; } + return -EIO; } @@ -724,14 +889,6 @@ static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) return 0; } -static int dw2102_earda_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(stb6000_attach, adap->fe, 0x61, - &adap->dev->i2c_adap); - - return 0; -} - static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) { dvb_attach(dvb_pll_attach, adap->fe, 0x60, @@ -740,14 +897,6 @@ static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) return 0; } -static int s630_zl10039_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(zl10039_attach, adap->fe, 0x60, - &adap->dev->i2c_adap); - - return 0; -} - static struct dvb_usb_rc_key dw210x_rc_keys[] = { { 0xf80a, KEY_Q }, /*power*/ { 0xf80c, KEY_M }, /*mute*/ @@ -922,6 +1071,8 @@ static struct usb_device_id dw2102_table[] = { {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)}, {USB_DEVICE(0x9022, USB_PID_TEVII_S630)}, + {USB_DEVICE(0x3011, USB_PID_PROF_1100)}, + {USB_DEVICE(0x9022, USB_PID_TEVII_S660)}, { } }; @@ -935,15 +1086,13 @@ static int dw2102_load_firmware(struct usb_device *dev, u8 reset; u8 reset16[] = {0, 0, 0, 0, 0, 0, 0}; const struct firmware *fw; - const char *filename = "dvb-usb-dw2101.fw"; + const char *fw_2101 = "dvb-usb-dw2101.fw"; switch (dev->descriptor.idProduct) { case 0x2101: - ret = request_firmware(&fw, filename, &dev->dev); + ret = request_firmware(&fw, fw_2101, &dev->dev); if (ret != 0) { - err("did not find the firmware file. (%s) " - "Please see linux/Documentation/dvb/ for more details " - "on firmware-problems.", filename); + err(err_str, fw_2101); return ret; } break; @@ -983,6 +1132,11 @@ static int dw2102_load_firmware(struct usb_device *dev, } /* init registers */ switch (dev->descriptor.idProduct) { + case USB_PID_PROF_1100: + s6x0_properties.rc_key_map = tbs_rc_keys; + s6x0_properties.rc_key_map_size = + ARRAY_SIZE(tbs_rc_keys); + break; case USB_PID_TEVII_S650: dw2104_properties.rc_key_map = tevii_rc_keys; dw2104_properties.rc_key_map_size = @@ -1021,7 +1175,6 @@ static int dw2102_load_firmware(struct usb_device *dev, DW210X_READ_MSG); if (reset16[2] == 0x11) { dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo; - dw2102_properties.adapter->tuner_attach = &dw2102_earda_tuner_attach; break; } } @@ -1184,13 +1337,13 @@ static struct dvb_usb_device_properties dw3101_properties = { } }; -static struct dvb_usb_device_properties s630_properties = { +static struct dvb_usb_device_properties s6x0_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = DEVICE_SPECIFIC, .firmware = "dvb-usb-s630.fw", .no_reconnect = 1, - .i2c_algo = &s630_i2c_algo, + .i2c_algo = &s6x0_i2c_algo, .rc_key_map = tevii_rc_keys, .rc_key_map_size = ARRAY_SIZE(tevii_rc_keys), .rc_interval = 150, @@ -1199,12 +1352,12 @@ static struct dvb_usb_device_properties s630_properties = { .generic_bulk_ctrl_endpoint = 0x81, .num_adapters = 1, .download_firmware = dw2102_load_firmware, - .read_mac_address = s630_read_mac_address, + .read_mac_address = s6x0_read_mac_address, .adapter = { { - .frontend_attach = s630_frontend_attach, + .frontend_attach = s6x0_frontend_attach, .streaming_ctrl = NULL, - .tuner_attach = s630_zl10039_tuner_attach, + .tuner_attach = NULL, .stream = { .type = USB_BULK, .count = 8, @@ -1217,12 +1370,20 @@ static struct dvb_usb_device_properties s630_properties = { }, } }, - .num_device_descs = 1, + .num_device_descs = 3, .devices = { {"TeVii S630 USB", {&dw2102_table[6], NULL}, {NULL}, }, + {"Prof 1100 USB ", + {&dw2102_table[7], NULL}, + {NULL}, + }, + {"TeVii S660 USB", + {&dw2102_table[8], NULL}, + {NULL}, + }, } }; @@ -1235,10 +1396,10 @@ static int dw2102_probe(struct usb_interface *intf, THIS_MODULE, NULL, adapter_nr) || 0 == dvb_usb_device_init(intf, &dw3101_properties, THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &s630_properties, - THIS_MODULE, NULL, adapter_nr)) { + 0 == dvb_usb_device_init(intf, &s6x0_properties, + THIS_MODULE, NULL, adapter_nr)) return 0; - } + return -ENODEV; } @@ -1269,6 +1430,7 @@ module_exit(dw2102_module_exit); MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104," " DVB-C 3101 USB2.0," - " TeVii S600, S630, S650 USB2.0 devices"); + " TeVii S600, S630, S650, S660 USB2.0," + " Prof 1100 USB2.0 devices"); MODULE_VERSION("0.1"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/friio-fe.c b/drivers/media/dvb/dvb-usb/friio-fe.c index 9cbbe42ca44..ebb7b9fd115 100644 --- a/drivers/media/dvb/dvb-usb/friio-fe.c +++ b/drivers/media/dvb/dvb-usb/friio-fe.c @@ -134,11 +134,13 @@ static int jdvbt90502_pll_set_freq(struct jdvbt90502_state *state, u32 freq) deb_fe("%s: freq=%d, step=%d\n", __func__, freq, state->frontend.ops.info.frequency_stepsize); /* freq -> oscilator frequency conversion. */ - /* freq: 473,000,000 + n*6,000,000 (no 1/7MHz shift to center freq) */ - /* add 400[1/7 MHZ] = 57.142857MHz. 57MHz for the IF, */ - /* 1/7MHz for center freq shift */ + /* freq: 473,000,000 + n*6,000,000 [+ 142857 (center freq. shift)] */ f = freq / state->frontend.ops.info.frequency_stepsize; - f += 400; + /* add 399[1/7 MHZ] = 57MHz for the IF */ + f += 399; + /* add center frequency shift if necessary */ + if (f % 7 == 0) + f++; pll_freq_cmd[DEMOD_REDIRECT_REG] = JDVBT90502_2ND_I2C_REG; /* 0xFE */ pll_freq_cmd[ADDRESS_BYTE] = state->config.pll_address << 1; pll_freq_cmd[DIVIDER_BYTE1] = (f >> 8) & 0x7F; diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c index 20eadf9318e..7a7f1b2b681 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c +++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c @@ -146,8 +146,8 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe, switch (c->delivery_system) { case SYS_DVBS: - /* Only QPSK is supported for DVB-S */ - if (c->modulation != QPSK) { + /* Allow QPSK and 8PSK (even for DVB-S) */ + if (c->modulation != QPSK && c->modulation != PSK_8) { deb_fe("%s: unsupported modulation selected (%d)\n", __func__, c->modulation); return -EOPNOTSUPP; diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 58aac018f10..a3b8b697349 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -526,6 +526,15 @@ config DVB_TUNER_DIB0070 This device is only used inside a SiP called together with a demodulator for now. +config DVB_TUNER_DIB0090 + tristate "DiBcom DiB0090 silicon base-band tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner DiB0090 from DiBcom. + This device is only used inside a SiP called together with a + demodulator for now. + comment "SEC control devices for DVB-S" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 823482535d1..47575cc7b69 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_DVB_TDA10086) += tda10086.o obj-$(CONFIG_DVB_TDA826X) += tda826x.o obj-$(CONFIG_DVB_TDA8261) += tda8261.o obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o +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 diff --git a/drivers/media/dvb/frontends/au8522_decoder.c b/drivers/media/dvb/frontends/au8522_decoder.c index 2dc2723b724..24268ef2753 100644 --- a/drivers/media/dvb/frontends/au8522_decoder.c +++ b/drivers/media/dvb/frontends/au8522_decoder.c @@ -62,7 +62,7 @@ struct au8522_register_config { The values are as follows from left to right 0="ATV RF" 1="ATV RF13" 2="CVBS" 3="S-Video" 4="PAL" 5=CVBS13" 6="SVideo13" */ -struct au8522_register_config filter_coef[] = { +static const struct au8522_register_config filter_coef[] = { {AU8522_FILTER_COEF_R410, {0x25, 0x00, 0x25, 0x25, 0x00, 0x00, 0x00} }, {AU8522_FILTER_COEF_R411, {0x20, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00} }, {AU8522_FILTER_COEF_R412, {0x03, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00} }, @@ -104,7 +104,7 @@ struct au8522_register_config filter_coef[] = { 0="SIF" 1="ATVRF/ATVRF13" Note: the "ATVRF/ATVRF13" mode has never been tested */ -struct au8522_register_config lpfilter_coef[] = { +static const struct au8522_register_config lpfilter_coef[] = { {0x060b, {0x21, 0x0b} }, {0x060c, {0xad, 0xad} }, {0x060d, {0x70, 0xf0} }, diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c index 2be17b93e0b..0d12763603b 100644 --- a/drivers/media/dvb/frontends/dib0070.c +++ b/drivers/media/dvb/frontends/dib0070.c @@ -49,21 +49,6 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); #define DIB0070_P1G 0x03 #define DIB0070S_P1A 0x02 -enum frontend_tune_state { - CT_TUNER_START = 10, - CT_TUNER_STEP_0, - CT_TUNER_STEP_1, - CT_TUNER_STEP_2, - CT_TUNER_STEP_3, - CT_TUNER_STEP_4, - CT_TUNER_STEP_5, - CT_TUNER_STEP_6, - CT_TUNER_STEP_7, - CT_TUNER_STOP, -}; - -#define FE_CALLBACK_TIME_NEVER 0xffffffff - struct dib0070_state { struct i2c_adapter *i2c; struct dvb_frontend *fe; @@ -71,10 +56,10 @@ struct dib0070_state { u16 wbd_ff_offset; u8 revision; - enum frontend_tune_state tune_state; - u32 current_rf; + enum frontend_tune_state tune_state; + u32 current_rf; - /* for the captrim binary search */ + /* for the captrim binary search */ s8 step; u16 adc_diff; @@ -85,7 +70,7 @@ struct dib0070_state { const struct dib0070_tuning *current_tune_table_index; const struct dib0070_lna_match *lna_match; - u8 wbd_gain_current; + u8 wbd_gain_current; u16 wbd_offset_3_3[2]; }; @@ -93,8 +78,8 @@ static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) { u8 b[2]; struct i2c_msg msg[2] = { - {.addr = state->cfg->i2c_address,.flags = 0,.buf = ®,.len = 1}, - {.addr = state->cfg->i2c_address,.flags = I2C_M_RD,.buf = b,.len = 2}, + { .addr = state->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2 }, }; if (i2c_transfer(state->i2c, msg, 2) != 2) { printk(KERN_WARNING "DiB0070 I2C read failed\n"); @@ -106,7 +91,7 @@ static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) { u8 b[3] = { reg, val >> 8, val & 0xff }; - struct i2c_msg msg = {.addr = state->cfg->i2c_address,.flags = 0,.buf = b,.len = 3 }; + struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 }; if (i2c_transfer(state->i2c, &msg, 1) != 1) { printk(KERN_WARNING "DiB0070 I2C write failed\n"); return -EREMOTEIO; @@ -124,30 +109,30 @@ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) { - struct dib0070_state *state = fe->tuner_priv; - u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff; - - if (state->fe->dtv_property_cache.bandwidth_hz / 1000 > 7000) - tmp |= (0 << 14); - else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 > 6000) - tmp |= (1 << 14); - else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 > 5000) - tmp |= (2 << 14); - else - tmp |= (3 << 14); - - dib0070_write_reg(state, 0x02, tmp); - - /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */ - if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) { - u16 value = dib0070_read_reg(state, 0x17); - - dib0070_write_reg(state, 0x17, value & 0xfffc); - tmp = dib0070_read_reg(state, 0x01) & 0x01ff; - dib0070_write_reg(state, 0x01, tmp | (60 << 9)); - - dib0070_write_reg(state, 0x17, value); - } + struct dib0070_state *state = fe->tuner_priv; + u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff; + + if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 7000) + tmp |= (0 << 14); + else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 6000) + tmp |= (1 << 14); + else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 5000) + tmp |= (2 << 14); + else + tmp |= (3 << 14); + + dib0070_write_reg(state, 0x02, tmp); + + /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */ + if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) { + u16 value = dib0070_read_reg(state, 0x17); + + dib0070_write_reg(state, 0x17, value & 0xfffc); + tmp = dib0070_read_reg(state, 0x01) & 0x01ff; + dib0070_write_reg(state, 0x01, tmp | (60 << 9)); + + dib0070_write_reg(state, 0x17, value); + } return 0; } @@ -160,14 +145,14 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state if (*tune_state == CT_TUNER_STEP_0) { dib0070_write_reg(state, 0x0f, 0xed10); - dib0070_write_reg(state, 0x17, 0x0034); + dib0070_write_reg(state, 0x17, 0x0034); dib0070_write_reg(state, 0x18, 0x0032); state->step = state->captrim = state->fcaptrim = 64; state->adc_diff = 3000; ret = 20; - *tune_state = CT_TUNER_STEP_1; + *tune_state = CT_TUNER_STEP_1; } else if (*tune_state == CT_TUNER_STEP_1) { state->step /= 2; dib0070_write_reg(state, 0x14, state->lo4 | state->captrim); @@ -178,7 +163,7 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state adc = dib0070_read_reg(state, 0x19); - dprintk("CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", state->captrim, adc, (u32) adc * (u32) 1800 / (u32) 1024); + dprintk("CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", state->captrim, adc, (u32) adc*(u32)1800/(u32)1024); if (adc >= 400) { adc -= 400; @@ -193,6 +178,8 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state state->adc_diff = adc; state->fcaptrim = state->captrim; + + } state->captrim += (step_sign * state->step); @@ -213,7 +200,7 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt) { struct dib0070_state *state = fe->tuner_priv; - u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0); + u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0); dprintk("CTRL_LO5: 0x%x", lo5); return dib0070_write_reg(state, 0x15, lo5); } @@ -227,99 +214,99 @@ void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open) dib0070_write_reg(state, 0x1a, 0x0000); } else { dib0070_write_reg(state, 0x1b, 0x4112); - if (state->cfg->vga_filter != 0) { - dib0070_write_reg(state, 0x1a, state->cfg->vga_filter); - dprintk("vga filter register is set to %x", state->cfg->vga_filter); - } else - dib0070_write_reg(state, 0x1a, 0x0009); + if (state->cfg->vga_filter != 0) { + dib0070_write_reg(state, 0x1a, state->cfg->vga_filter); + dprintk("vga filter register is set to %x", state->cfg->vga_filter); + } else + dib0070_write_reg(state, 0x1a, 0x0009); } } EXPORT_SYMBOL(dib0070_ctrl_agc_filter); struct dib0070_tuning { - u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ - u8 switch_trim; - u8 vco_band; - u8 hfdiv; - u8 vco_multi; - u8 presc; - u8 wbdmux; - u16 tuner_enable; + u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ + u8 switch_trim; + u8 vco_band; + u8 hfdiv; + u8 vco_multi; + u8 presc; + u8 wbdmux; + u16 tuner_enable; }; struct dib0070_lna_match { - u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ - u8 lna_band; + u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ + u8 lna_band; }; static const struct dib0070_tuning dib0070s_tuning_table[] = { - {570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800}, /* UHF */ - {700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800}, - {863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800}, - {1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400}, /* LBAND */ - {1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400}, - {2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400}, - {0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000}, /* SBAND */ + { 570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800 }, /* UHF */ + { 700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800 }, + { 863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800 }, + { 1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND */ + { 1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, + { 2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, + { 0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000 }, /* SBAND */ }; static const struct dib0070_tuning dib0070_tuning_table[] = { - {115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000}, /* FM below 92MHz cannot be tuned */ - {179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000}, /* VHF */ - {189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000}, - {250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000}, - {569999, 2, 1, 5, 6, 2, 2, 0x4000 | 0x0800}, /* UHF */ - {699999, 2, 0, 1, 4, 2, 2, 0x4000 | 0x0800}, - {863999, 2, 1, 1, 4, 2, 2, 0x4000 | 0x0800}, - {0xffffffff, 0, 1, 0, 2, 2, 4, 0x2000 | 0x0400}, /* LBAND or everything higher than UHF */ + { 115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000 }, /* FM below 92MHz cannot be tuned */ + { 179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000 }, /* VHF */ + { 189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000 }, + { 250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000 }, + { 569999, 2, 1, 5, 6, 2, 2, 0x4000 | 0x0800 }, /* UHF */ + { 699999, 2, 0, 1, 4, 2, 2, 0x4000 | 0x0800 }, + { 863999, 2, 1, 1, 4, 2, 2, 0x4000 | 0x0800 }, + { 0xffffffff, 0, 1, 0, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND or everything higher than UHF */ }; static const struct dib0070_lna_match dib0070_lna_flip_chip[] = { - {180000, 0}, /* VHF */ - {188000, 1}, - {196400, 2}, - {250000, 3}, - {550000, 0}, /* UHF */ - {590000, 1}, - {666000, 3}, - {864000, 5}, - {1500000, 0}, /* LBAND or everything higher than UHF */ - {1600000, 1}, - {2000000, 3}, - {0xffffffff, 7}, + { 180000, 0 }, /* VHF */ + { 188000, 1 }, + { 196400, 2 }, + { 250000, 3 }, + { 550000, 0 }, /* UHF */ + { 590000, 1 }, + { 666000, 3 }, + { 864000, 5 }, + { 1500000, 0 }, /* LBAND or everything higher than UHF */ + { 1600000, 1 }, + { 2000000, 3 }, + { 0xffffffff, 7 }, }; static const struct dib0070_lna_match dib0070_lna[] = { - {180000, 0}, /* VHF */ - {188000, 1}, - {196400, 2}, - {250000, 3}, - {550000, 2}, /* UHF */ - {650000, 3}, - {750000, 5}, - {850000, 6}, - {864000, 7}, - {1500000, 0}, /* LBAND or everything higher than UHF */ - {1600000, 1}, - {2000000, 3}, - {0xffffffff, 7}, + { 180000, 0 }, /* VHF */ + { 188000, 1 }, + { 196400, 2 }, + { 250000, 3 }, + { 550000, 2 }, /* UHF */ + { 650000, 3 }, + { 750000, 5 }, + { 850000, 6 }, + { 864000, 7 }, + { 1500000, 0 }, /* LBAND or everything higher than UHF */ + { 1600000, 1 }, + { 2000000, 3 }, + { 0xffffffff, 7 }, }; -#define LPF 100 // define for the loop filter 100kHz by default 16-07-06 +#define LPF 100 static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) { - struct dib0070_state *state = fe->tuner_priv; + struct dib0070_state *state = fe->tuner_priv; - const struct dib0070_tuning *tune; - const struct dib0070_lna_match *lna_match; + const struct dib0070_tuning *tune; + const struct dib0070_lna_match *lna_match; - enum frontend_tune_state *tune_state = &state->tune_state; - int ret = 10; /* 1ms is the default delay most of the time */ + enum frontend_tune_state *tune_state = &state->tune_state; + int ret = 10; /* 1ms is the default delay most of the time */ - u8 band = (u8) BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000); - u32 freq = fe->dtv_property_cache.frequency / 1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf); + u8 band = (u8)BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency/1000); + u32 freq = fe->dtv_property_cache.frequency/1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf); #ifdef CONFIG_SYS_ISDBT - if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1) + if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1) if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) @@ -328,172 +315,180 @@ static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_par && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))) freq += 850; #endif + if (state->current_rf != freq) { + + switch (state->revision) { + case DIB0070S_P1A: + tune = dib0070s_tuning_table; + lna_match = dib0070_lna; + break; + default: + tune = dib0070_tuning_table; + if (state->cfg->flip_chip) + lna_match = dib0070_lna_flip_chip; + else + lna_match = dib0070_lna; + break; + } + while (freq > tune->max_freq) /* find the right one */ + tune++; + while (freq > lna_match->max_freq) /* find the right one */ + lna_match++; + + state->current_tune_table_index = tune; + state->lna_match = lna_match; + } + + if (*tune_state == CT_TUNER_START) { + dprintk("Tuning for Band: %hd (%d kHz)", band, freq); if (state->current_rf != freq) { + u8 REFDIV; + u32 FBDiv, Rest, FREF, VCOF_kHz; + u8 Den; + + state->current_rf = freq; + state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7); + + + dib0070_write_reg(state, 0x17, 0x30); + + + VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2; + + switch (band) { + case BAND_VHF: + REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000); + break; + case BAND_FM: + REFDIV = (u8) ((state->cfg->clock_khz) / 1000); + break; + default: + REFDIV = (u8) (state->cfg->clock_khz / 10000); + break; + } + FREF = state->cfg->clock_khz / REFDIV; + + switch (state->revision) { case DIB0070S_P1A: - tune = dib0070s_tuning_table; - lna_match = dib0070_lna; + FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF); + Rest = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF; break; + + case DIB0070_P1G: + case DIB0070_P1F: default: - tune = dib0070_tuning_table; - if (state->cfg->flip_chip) - lna_match = dib0070_lna_flip_chip; - else - lna_match = dib0070_lna; + FBDiv = (freq / (FREF / 2)); + Rest = 2 * freq - FBDiv * FREF; break; } - while (freq > tune->max_freq) /* find the right one */ - tune++; - while (freq > lna_match->max_freq) /* find the right one */ - lna_match++; - state->current_tune_table_index = tune; - state->lna_match = lna_match; - } + if (Rest < LPF) + Rest = 0; + else if (Rest < 2 * LPF) + Rest = 2 * LPF; + else if (Rest > (FREF - LPF)) { + Rest = 0; + FBDiv += 1; + } else if (Rest > (FREF - 2 * LPF)) + Rest = FREF - 2 * LPF; + Rest = (Rest * 6528) / (FREF / 10); + + Den = 1; + if (Rest > 0) { + state->lo4 |= (1 << 14) | (1 << 12); + Den = 255; + } + - if (*tune_state == CT_TUNER_START) { - dprintk("Tuning for Band: %hd (%d kHz)", band, freq); - if (state->current_rf != freq) { - u8 REFDIV; - u32 FBDiv, Rest, FREF, VCOF_kHz; - u8 Den; - - state->current_rf = freq; - state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7); - - dib0070_write_reg(state, 0x17, 0x30); - - VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2; - - switch (band) { - case BAND_VHF: - REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000); - break; - case BAND_FM: - REFDIV = (u8) ((state->cfg->clock_khz) / 1000); - break; - default: - REFDIV = (u8) (state->cfg->clock_khz / 10000); - break; - } - FREF = state->cfg->clock_khz / REFDIV; - - switch (state->revision) { - case DIB0070S_P1A: - FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF); - Rest = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF; - break; - - case DIB0070_P1G: - case DIB0070_P1F: - default: - FBDiv = (freq / (FREF / 2)); - Rest = 2 * freq - FBDiv * FREF; - break; - } - - if (Rest < LPF) - Rest = 0; - else if (Rest < 2 * LPF) - Rest = 2 * LPF; - else if (Rest > (FREF - LPF)) { - Rest = 0; - FBDiv += 1; - } else if (Rest > (FREF - 2 * LPF)) - Rest = FREF - 2 * LPF; - Rest = (Rest * 6528) / (FREF / 10); - - Den = 1; - if (Rest > 0) { - state->lo4 |= (1 << 14) | (1 << 12); - Den = 255; - } - - dib0070_write_reg(state, 0x11, (u16) FBDiv); - dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV); - dib0070_write_reg(state, 0x13, (u16) Rest); - - if (state->revision == DIB0070S_P1A) { - - if (band == BAND_SBAND) { - dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); - dib0070_write_reg(state, 0x1d, 0xFFFF); - } else - dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1); - } - - dib0070_write_reg(state, 0x20, - 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable); - - dprintk("REFDIV: %hd, FREF: %d", REFDIV, FREF); - dprintk("FBDIV: %d, Rest: %d", FBDiv, Rest); - dprintk("Num: %hd, Den: %hd, SD: %hd", (u16) Rest, Den, (state->lo4 >> 12) & 0x1); - dprintk("HFDIV code: %hd", state->current_tune_table_index->hfdiv); - dprintk("VCO = %hd", state->current_tune_table_index->vco_band); - dprintk("VCOF: ((%hd*%d) << 1))", state->current_tune_table_index->vco_multi, freq); - - *tune_state = CT_TUNER_STEP_0; - } else { /* we are already tuned to this frequency - the configuration is correct */ - ret = 50; /* wakeup time */ - *tune_state = CT_TUNER_STEP_5; + dib0070_write_reg(state, 0x11, (u16)FBDiv); + dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV); + dib0070_write_reg(state, 0x13, (u16) Rest); + + if (state->revision == DIB0070S_P1A) { + + if (band == BAND_SBAND) { + dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); + dib0070_write_reg(state, 0x1d, 0xFFFF); + } else + dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1); } - } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) { - ret = dib0070_captrim(state, tune_state); + dib0070_write_reg(state, 0x20, + 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable); - } else if (*tune_state == CT_TUNER_STEP_4) { - const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; - if (tmp != NULL) { - while (freq / 1000 > tmp->freq) /* find the right one */ - tmp++; - dib0070_write_reg(state, 0x0f, - (0 << 15) | (1 << 14) | (3 << 12) | (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7) | (state-> - current_tune_table_index-> - wbdmux << 0)); - state->wbd_gain_current = tmp->wbd_gain_val; - } else { + dprintk("REFDIV: %hd, FREF: %d", REFDIV, FREF); + dprintk("FBDIV: %d, Rest: %d", FBDiv, Rest); + dprintk("Num: %hd, Den: %hd, SD: %hd", (u16) Rest, Den, (state->lo4 >> 12) & 0x1); + dprintk("HFDIV code: %hd", state->current_tune_table_index->hfdiv); + dprintk("VCO = %hd", state->current_tune_table_index->vco_band); + dprintk("VCOF: ((%hd*%d) << 1))", state->current_tune_table_index->vco_multi, freq); + + *tune_state = CT_TUNER_STEP_0; + } else { /* we are already tuned to this frequency - the configuration is correct */ + ret = 50; /* wakeup time */ + *tune_state = CT_TUNER_STEP_5; + } + } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) { + + ret = dib0070_captrim(state, tune_state); + + } else if (*tune_state == CT_TUNER_STEP_4) { + const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; + if (tmp != NULL) { + while (freq/1000 > tmp->freq) /* find the right one */ + tmp++; + dib0070_write_reg(state, 0x0f, + (0 << 15) | (1 << 14) | (3 << 12) + | (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7) + | (state->current_tune_table_index->wbdmux << 0)); + state->wbd_gain_current = tmp->wbd_gain_val; + } else { dib0070_write_reg(state, 0x0f, (0 << 15) | (1 << 14) | (3 << 12) | (6 << 9) | (0 << 8) | (1 << 7) | (state->current_tune_table_index-> wbdmux << 0)); - state->wbd_gain_current = 6; - } + state->wbd_gain_current = 6; + } - dib0070_write_reg(state, 0x06, 0x3fff); + dib0070_write_reg(state, 0x06, 0x3fff); dib0070_write_reg(state, 0x07, (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0)); - dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127)); - dib0070_write_reg(state, 0x0d, 0x0d80); + dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127)); + dib0070_write_reg(state, 0x0d, 0x0d80); - dib0070_write_reg(state, 0x18, 0x07ff); - dib0070_write_reg(state, 0x17, 0x0033); - *tune_state = CT_TUNER_STEP_5; - } else if (*tune_state == CT_TUNER_STEP_5) { - dib0070_set_bandwidth(fe, ch); - *tune_state = CT_TUNER_STOP; - } else { - ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */ - } - return ret; + dib0070_write_reg(state, 0x18, 0x07ff); + dib0070_write_reg(state, 0x17, 0x0033); + + + *tune_state = CT_TUNER_STEP_5; + } else if (*tune_state == CT_TUNER_STEP_5) { + dib0070_set_bandwidth(fe, ch); + *tune_state = CT_TUNER_STOP; + } else { + ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */ + } + return ret; } + static int dib0070_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { - struct dib0070_state *state = fe->tuner_priv; - uint32_t ret; + struct dib0070_state *state = fe->tuner_priv; + uint32_t ret; - state->tune_state = CT_TUNER_START; + state->tune_state = CT_TUNER_START; - do { - ret = dib0070_tune_digital(fe, p); - if (ret != FE_CALLBACK_TIME_NEVER) - msleep(ret / 10); - else - break; - } while (state->tune_state != CT_TUNER_STOP); + do { + ret = dib0070_tune_digital(fe, p); + if (ret != FE_CALLBACK_TIME_NEVER) + msleep(ret/10); + else + break; + } while (state->tune_state != CT_TUNER_STOP); - return 0; + return 0; } static int dib0070_wakeup(struct dvb_frontend *fe) @@ -512,92 +507,113 @@ static int dib0070_sleep(struct dvb_frontend *fe) return 0; } -static const u16 dib0070_p1f_defaults[] = { +u8 dib0070_get_rf_output(struct dvb_frontend *fe) +{ + struct dib0070_state *state = fe->tuner_priv; + return (dib0070_read_reg(state, 0x07) >> 11) & 0x3; +} +EXPORT_SYMBOL(dib0070_get_rf_output); + +int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no) +{ + struct dib0070_state *state = fe->tuner_priv; + u16 rxrf2 = dib0070_read_reg(state, 0x07) & 0xfe7ff; + if (no > 3) + no = 3; + if (no < 1) + no = 1; + return dib0070_write_reg(state, 0x07, rxrf2 | (no << 11)); +} +EXPORT_SYMBOL(dib0070_set_rf_output); + +static const u16 dib0070_p1f_defaults[] = + +{ 7, 0x02, - 0x0008, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0002, - 0x0100, + 0x0008, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0002, + 0x0100, 3, 0x0d, - 0x0d80, - 0x0001, - 0x0000, + 0x0d80, + 0x0001, + 0x0000, 4, 0x11, - 0x0000, - 0x0103, - 0x0000, - 0x0000, + 0x0000, + 0x0103, + 0x0000, + 0x0000, 3, 0x16, - 0x0004 | 0x0040, - 0x0030, - 0x07ff, + 0x0004 | 0x0040, + 0x0030, + 0x07ff, 6, 0x1b, - 0x4112, - 0xff00, - 0xc07f, - 0x0000, - 0x0180, - 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001, + 0x4112, + 0xff00, + 0xc07f, + 0x0000, + 0x0180, + 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001, 0, }; static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain) { - u16 tuner_en = dib0070_read_reg(state, 0x20); - u16 offset; - - dib0070_write_reg(state, 0x18, 0x07ff); - dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001); - dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0)); - msleep(9); - offset = dib0070_read_reg(state, 0x19); - dib0070_write_reg(state, 0x20, tuner_en); - return offset; + u16 tuner_en = dib0070_read_reg(state, 0x20); + u16 offset; + + dib0070_write_reg(state, 0x18, 0x07ff); + dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001); + dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0)); + msleep(9); + offset = dib0070_read_reg(state, 0x19); + dib0070_write_reg(state, 0x20, tuner_en); + return offset; } static void dib0070_wbd_offset_calibration(struct dib0070_state *state) { - u8 gain; - for (gain = 6; gain < 8; gain++) { - state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2); - dprintk("Gain: %d, WBDOffset (3.3V) = %hd", gain, state->wbd_offset_3_3[gain - 6]); - } + u8 gain; + for (gain = 6; gain < 8; gain++) { + state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2); + dprintk("Gain: %d, WBDOffset (3.3V) = %hd", gain, state->wbd_offset_3_3[gain-6]); + } } u16 dib0070_wbd_offset(struct dvb_frontend *fe) { - struct dib0070_state *state = fe->tuner_priv; - const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; - u32 freq = fe->dtv_property_cache.frequency / 1000; - - if (tmp != NULL) { - while (freq / 1000 > tmp->freq) /* find the right one */ - tmp++; - state->wbd_gain_current = tmp->wbd_gain_val; + struct dib0070_state *state = fe->tuner_priv; + const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; + u32 freq = fe->dtv_property_cache.frequency/1000; + + if (tmp != NULL) { + while (freq/1000 > tmp->freq) /* find the right one */ + tmp++; + state->wbd_gain_current = tmp->wbd_gain_val; } else - state->wbd_gain_current = 6; + state->wbd_gain_current = 6; - return state->wbd_offset_3_3[state->wbd_gain_current - 6]; + return state->wbd_offset_3_3[state->wbd_gain_current - 6]; } - EXPORT_SYMBOL(dib0070_wbd_offset); #define pgm_read_word(w) (*w) static int dib0070_reset(struct dvb_frontend *fe) { - struct dib0070_state *state = fe->tuner_priv; + struct dib0070_state *state = fe->tuner_priv; u16 l, r, *n; HARD_RESET(state); + #ifndef FORCE_SBAND_TUNER if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1) state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff; @@ -605,7 +621,7 @@ static int dib0070_reset(struct dvb_frontend *fe) #else #warning forcing SBAND #endif - state->revision = DIB0070S_P1A; + state->revision = DIB0070S_P1A; /* P1F or not */ dprintk("Revision: %x", state->revision); @@ -620,7 +636,7 @@ static int dib0070_reset(struct dvb_frontend *fe) while (l) { r = pgm_read_word(n++); do { - dib0070_write_reg(state, (u8) r, pgm_read_word(n++)); + dib0070_write_reg(state, (u8)r, pgm_read_word(n++)); r++; } while (--l); l = pgm_read_word(n++); @@ -633,6 +649,7 @@ static int dib0070_reset(struct dvb_frontend *fe) else r = 2; + r |= state->cfg->osc_buffer_state << 3; dib0070_write_reg(state, 0x10, r); @@ -643,16 +660,24 @@ static int dib0070_reset(struct dvb_frontend *fe) dib0070_write_reg(state, 0x02, r | (1 << 5)); } - if (state->revision == DIB0070S_P1A) - dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); - else + if (state->revision == DIB0070S_P1A) + dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); + else dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump, state->cfg->enable_third_order_filter); dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8); - dib0070_wbd_offset_calibration(state); + dib0070_wbd_offset_calibration(state); - return 0; + return 0; +} + +static int dib0070_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct dib0070_state *state = fe->tuner_priv; + + *frequency = 1000 * state->current_rf; + return 0; } static int dib0070_release(struct dvb_frontend *fe) @@ -664,18 +689,18 @@ static int dib0070_release(struct dvb_frontend *fe) static const struct dvb_tuner_ops dib0070_ops = { .info = { - .name = "DiBcom DiB0070", - .frequency_min = 45000000, - .frequency_max = 860000000, - .frequency_step = 1000, - }, - .release = dib0070_release, - - .init = dib0070_wakeup, - .sleep = dib0070_sleep, - .set_params = dib0070_tune, - -// .get_frequency = dib0070_get_frequency, + .name = "DiBcom DiB0070", + .frequency_min = 45000000, + .frequency_max = 860000000, + .frequency_step = 1000, + }, + .release = dib0070_release, + + .init = dib0070_wakeup, + .sleep = dib0070_sleep, + .set_params = dib0070_tune, + + .get_frequency = dib0070_get_frequency, // .get_bandwidth = dib0070_get_bandwidth }; @@ -687,7 +712,7 @@ struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter state->cfg = cfg; state->i2c = i2c; - state->fe = fe; + state->fe = fe; fe->tuner_priv = state; if (dib0070_reset(fe) != 0) @@ -699,12 +724,11 @@ struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter fe->tuner_priv = state; return fe; - free_mem: +free_mem: kfree(state); fe->tuner_priv = NULL; return NULL; } - EXPORT_SYMBOL(dib0070_attach); MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); diff --git a/drivers/media/dvb/frontends/dib0070.h b/drivers/media/dvb/frontends/dib0070.h index eec9e52ffa7..45c31fae396 100644 --- a/drivers/media/dvb/frontends/dib0070.h +++ b/drivers/media/dvb/frontends/dib0070.h @@ -52,6 +52,8 @@ struct dib0070_config { extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg); extern u16 dib0070_wbd_offset(struct dvb_frontend *); extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, u8 open); +extern u8 dib0070_get_rf_output(struct dvb_frontend *fe); +extern int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no); #else static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg) { @@ -62,7 +64,7 @@ static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struc static inline u16 dib0070_wbd_offset(struct dvb_frontend *fe) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; + return 0; } static inline void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open) diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb/frontends/dib0090.c new file mode 100644 index 00000000000..614552709a6 --- /dev/null +++ b/drivers/media/dvb/frontends/dib0090.c @@ -0,0 +1,1522 @@ +/* + * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner. + * + * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/) + * + * 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. + * + * + * This code is more or less generated from another driver, please + * excuse some codingstyle oddities. + * + */ + +#include <linux/kernel.h> +#include <linux/i2c.h> + +#include "dvb_frontend.h" + +#include "dib0090.h" +#include "dibx000_common.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); + +#define dprintk(args...) do { \ + if (debug) { \ + printk(KERN_DEBUG "DiB0090: "); \ + printk(args); \ + printk("\n"); \ + } \ +} while (0) + +#define CONFIG_SYS_ISDBT +#define CONFIG_BAND_CBAND +#define CONFIG_BAND_VHF +#define CONFIG_BAND_UHF +#define CONFIG_DIB0090_USE_PWM_AGC + +#define EN_LNA0 0x8000 +#define EN_LNA1 0x4000 +#define EN_LNA2 0x2000 +#define EN_LNA3 0x1000 +#define EN_MIX0 0x0800 +#define EN_MIX1 0x0400 +#define EN_MIX2 0x0200 +#define EN_MIX3 0x0100 +#define EN_IQADC 0x0040 +#define EN_PLL 0x0020 +#define EN_TX 0x0010 +#define EN_BB 0x0008 +#define EN_LO 0x0004 +#define EN_BIAS 0x0001 + +#define EN_IQANA 0x0002 +#define EN_DIGCLK 0x0080 /* not in the 0x24 reg, only in 0x1b */ +#define EN_CRYSTAL 0x0002 + +#define EN_UHF 0x22E9 +#define EN_VHF 0x44E9 +#define EN_LBD 0x11E9 +#define EN_SBD 0x44E9 +#define EN_CAB 0x88E9 + +#define pgm_read_word(w) (*w) + +struct dc_calibration; + +struct dib0090_tuning { + u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ + u8 switch_trim; + u8 lna_tune; + u8 lna_bias; + u16 v2i; + u16 mix; + u16 load; + u16 tuner_enable; +}; + +struct dib0090_pll { + u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ + u8 vco_band; + u8 hfdiv_code; + u8 hfdiv; + u8 topresc; +}; + +struct dib0090_state { + struct i2c_adapter *i2c; + struct dvb_frontend *fe; + const struct dib0090_config *config; + + u8 current_band; + u16 revision; + enum frontend_tune_state tune_state; + u32 current_rf; + + u16 wbd_offset; + s16 wbd_target; /* in dB */ + + s16 rf_gain_limit; /* take-over-point: where to split between bb and rf gain */ + s16 current_gain; /* keeps the currently programmed gain */ + u8 agc_step; /* new binary search */ + + u16 gain[2]; /* for channel monitoring */ + + const u16 *rf_ramp; + const u16 *bb_ramp; + + /* for the software AGC ramps */ + u16 bb_1_def; + u16 rf_lt_def; + u16 gain_reg[4]; + + /* for the captrim/dc-offset search */ + s8 step; + s16 adc_diff; + s16 min_adc_diff; + + s8 captrim; + s8 fcaptrim; + + const struct dc_calibration *dc; + u16 bb6, bb7; + + const struct dib0090_tuning *current_tune_table_index; + const struct dib0090_pll *current_pll_table_index; + + u8 tuner_is_tuned; + u8 agc_freeze; + + u8 reset; +}; + +static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg) +{ + u8 b[2]; + struct i2c_msg msg[2] = { + {.addr = state->config->i2c_address, .flags = 0, .buf = ®, .len = 1}, + {.addr = state->config->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2}, + }; + if (i2c_transfer(state->i2c, msg, 2) != 2) { + printk(KERN_WARNING "DiB0090 I2C read failed\n"); + return 0; + } + return (b[0] << 8) | b[1]; +} + +static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val) +{ + u8 b[3] = { reg & 0xff, val >> 8, val & 0xff }; + struct i2c_msg msg = {.addr = state->config->i2c_address, .flags = 0, .buf = b, .len = 3 }; + if (i2c_transfer(state->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "DiB0090 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +#define HARD_RESET(state) do { if (cfg->reset) { if (cfg->sleep) cfg->sleep(fe, 0); msleep(10); cfg->reset(fe, 1); msleep(10); cfg->reset(fe, 0); msleep(10); } } while (0) +#define ADC_TARGET -220 +#define GAIN_ALPHA 5 +#define WBD_ALPHA 6 +#define LPF 100 +static void dib0090_write_regs(struct dib0090_state *state, u8 r, const u16 * b, u8 c) +{ + do { + dib0090_write_reg(state, r++, *b++); + } while (--c); +} + +static u16 dib0090_identify(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + u16 v; + + v = dib0090_read_reg(state, 0x1a); + +#ifdef FIRMWARE_FIREFLY + /* pll is not locked locked */ + if (!(v & 0x800)) + dprintk("FE%d : Identification : pll is not yet locked", fe->id); +#endif + + /* without PLL lock info */ + v &= 0x3ff; + dprintk("P/V: %04x:", v); + + if ((v >> 8) & 0xf) + dprintk("FE%d : Product ID = 0x%x : KROSUS", fe->id, (v >> 8) & 0xf); + else + return 0xff; + + v &= 0xff; + if (((v >> 5) & 0x7) == 0x1) + dprintk("FE%d : MP001 : 9090/8096", fe->id); + else if (((v >> 5) & 0x7) == 0x4) + dprintk("FE%d : MP005 : Single Sband", fe->id); + else if (((v >> 5) & 0x7) == 0x6) + dprintk("FE%d : MP008 : diversity VHF-UHF-LBAND", fe->id); + else if (((v >> 5) & 0x7) == 0x7) + dprintk("FE%d : MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND", fe->id); + else + return 0xff; + + /* revision only */ + if ((v & 0x1f) == 0x3) + dprintk("FE%d : P1-D/E/F detected", fe->id); + else if ((v & 0x1f) == 0x1) + dprintk("FE%d : P1C detected", fe->id); + else if ((v & 0x1f) == 0x0) { +#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT + dprintk("FE%d : P1-A/B detected: using previous driver - support will be removed soon", fe->id); + dib0090_p1b_register(fe); +#else + dprintk("FE%d : P1-A/B detected: driver is deactivated - not available", fe->id); + return 0xff; +#endif + } + + return v; +} + +static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg) +{ + struct dib0090_state *state = fe->tuner_priv; + + HARD_RESET(state); + + dib0090_write_reg(state, 0x24, EN_PLL); + dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */ + + /* adcClkOutRatio=8->7, release reset */ + dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0); + if (cfg->clkoutdrive != 0) + dib0090_write_reg(state, 0x23, + (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 10) | (1 << 9) | (0 << 8) | (cfg->clkoutdrive << 5) | (cfg-> + clkouttobamse + << 4) | (0 + << + 2) + | (0)); + else + dib0090_write_reg(state, 0x23, + (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 10) | (1 << 9) | (0 << 8) | (7 << 5) | (cfg-> + clkouttobamse << 4) | (0 + << + 2) + | (0)); + + /* enable pll, de-activate reset, ratio: 2/1 = 60MHz */ + dib0090_write_reg(state, 0x21, + (cfg->io.pll_bypass << 15) | (1 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)); + +} + +static int dib0090_wakeup(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + if (state->config->sleep) + state->config->sleep(fe, 0); + return 0; +} + +static int dib0090_sleep(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + if (state->config->sleep) + state->config->sleep(fe, 1); + return 0; +} + +extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast) +{ + struct dib0090_state *state = fe->tuner_priv; + if (fast) + dib0090_write_reg(state, 0x04, 0); + else + dib0090_write_reg(state, 0x04, 1); +} +EXPORT_SYMBOL(dib0090_dcc_freq); + +static const u16 rf_ramp_pwm_cband[] = { + 0, /* max RF gain in 10th of dB */ + 0, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ + 0, /* ramp_max = maximum X used on the ramp */ + (0 << 10) | 0, /* 0x2c, LNA 1 = 0dB */ + (0 << 10) | 0, /* 0x2d, LNA 1 */ + (0 << 10) | 0, /* 0x2e, LNA 2 = 0dB */ + (0 << 10) | 0, /* 0x2f, LNA 2 */ + (0 << 10) | 0, /* 0x30, LNA 3 = 0dB */ + (0 << 10) | 0, /* 0x31, LNA 3 */ + (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */ + (0 << 10) | 0, /* GAIN_4_2, LNA 4 */ +}; + +static const u16 rf_ramp_vhf[] = { + 412, /* max RF gain in 10th of dB */ + 132, 307, 127, /* LNA1, 13.2dB */ + 105, 412, 255, /* LNA2, 10.5dB */ + 50, 50, 127, /* LNA3, 5dB */ + 125, 175, 127, /* LNA4, 12.5dB */ + 0, 0, 127, /* CBAND, 0dB */ +}; + +static const u16 rf_ramp_uhf[] = { + 412, /* max RF gain in 10th of dB */ + 132, 307, 127, /* LNA1 : total gain = 13.2dB, point on the ramp where this amp is full gain, value to write to get full gain */ + 105, 412, 255, /* LNA2 : 10.5 dB */ + 50, 50, 127, /* LNA3 : 5.0 dB */ + 125, 175, 127, /* LNA4 : 12.5 dB */ + 0, 0, 127, /* CBAND : 0.0 dB */ +}; + +static const u16 rf_ramp_cband[] = { + 332, /* max RF gain in 10th of dB */ + 132, 252, 127, /* LNA1, dB */ + 80, 332, 255, /* LNA2, dB */ + 0, 0, 127, /* LNA3, dB */ + 0, 0, 127, /* LNA4, dB */ + 120, 120, 127, /* LT1 CBAND */ +}; + +static const u16 rf_ramp_pwm_vhf[] = { + 404, /* max RF gain in 10th of dB */ + 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ + 1011, /* ramp_max = maximum X used on the ramp */ + (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */ + (0 << 10) | 756, /* 0x2d, LNA 1 */ + (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */ + (0 << 10) | 1011, /* 0x2f, LNA 2 */ + (16 << 10) | 290, /* 0x30, LNA 3 = 5dB */ + (0 << 10) | 417, /* 0x31, LNA 3 */ + (7 << 10) | 0, /* GAIN_4_1, LNA 4 = 12.5dB */ + (0 << 10) | 290, /* GAIN_4_2, LNA 4 */ +}; + +static const u16 rf_ramp_pwm_uhf[] = { + 404, /* max RF gain in 10th of dB */ + 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ + 1011, /* ramp_max = maximum X used on the ramp */ + (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */ + (0 << 10) | 756, /* 0x2d, LNA 1 */ + (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */ + (0 << 10) | 1011, /* 0x2f, LNA 2 */ + (16 << 10) | 0, /* 0x30, LNA 3 = 5dB */ + (0 << 10) | 127, /* 0x31, LNA 3 */ + (7 << 10) | 127, /* GAIN_4_1, LNA 4 = 12.5dB */ + (0 << 10) | 417, /* GAIN_4_2, LNA 4 */ +}; + +static const u16 bb_ramp_boost[] = { + 550, /* max BB gain in 10th of dB */ + 260, 260, 26, /* BB1, 26dB */ + 290, 550, 29, /* BB2, 29dB */ +}; + +static const u16 bb_ramp_pwm_normal[] = { + 500, /* max RF gain in 10th of dB */ + 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x34 */ + 400, + (2 << 9) | 0, /* 0x35 = 21dB */ + (0 << 9) | 168, /* 0x36 */ + (2 << 9) | 168, /* 0x37 = 29dB */ + (0 << 9) | 400, /* 0x38 */ +}; + +struct slope { + int16_t range; + int16_t slope; +}; +static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val) +{ + u8 i; + u16 rest; + u16 ret = 0; + for (i = 0; i < num; i++) { + if (val > slopes[i].range) + rest = slopes[i].range; + else + rest = val; + ret += (rest * slopes[i].slope) / slopes[i].range; + val -= rest; + } + return ret; +} + +static const struct slope dib0090_wbd_slopes[3] = { + {66, 120}, /* -64,-52: offset - 65 */ + {600, 170}, /* -52,-35: 65 - 665 */ + {170, 250}, /* -45,-10: 665 - 835 */ +}; + +static s16 dib0090_wbd_to_db(struct dib0090_state *state, u16 wbd) +{ + wbd &= 0x3ff; + if (wbd < state->wbd_offset) + wbd = 0; + else + wbd -= state->wbd_offset; + /* -64dB is the floor */ + return -640 + (s16) slopes_to_scale(dib0090_wbd_slopes, ARRAY_SIZE(dib0090_wbd_slopes), wbd); +} + +static void dib0090_wbd_target(struct dib0090_state *state, u32 rf) +{ + u16 offset = 250; + + /* TODO : DAB digital N+/-1 interferer perfs : offset = 10 */ + + if (state->current_band == BAND_VHF) + offset = 650; +#ifndef FIRMWARE_FIREFLY + if (state->current_band == BAND_VHF) + offset = state->config->wbd_vhf_offset; + if (state->current_band == BAND_CBAND) + offset = state->config->wbd_cband_offset; +#endif + + state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + offset); + dprintk("wbd-target: %d dB", (u32) state->wbd_target); +} + +static const int gain_reg_addr[4] = { + 0x08, 0x0a, 0x0f, 0x01 +}; + +static void dib0090_gain_apply(struct dib0090_state *state, s16 gain_delta, s16 top_delta, u8 force) +{ + u16 rf, bb, ref; + u16 i, v, gain_reg[4] = { 0 }, gain; + const u16 *g; + + if (top_delta < -511) + top_delta = -511; + if (top_delta > 511) + top_delta = 511; + + if (force) { + top_delta *= (1 << WBD_ALPHA); + gain_delta *= (1 << GAIN_ALPHA); + } + + if (top_delta >= ((s16) (state->rf_ramp[0] << WBD_ALPHA) - state->rf_gain_limit)) /* overflow */ + state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA; + else + state->rf_gain_limit += top_delta; + + if (state->rf_gain_limit < 0) /*underflow */ + state->rf_gain_limit = 0; + + /* use gain as a temporary variable and correct current_gain */ + gain = ((state->rf_gain_limit >> WBD_ALPHA) + state->bb_ramp[0]) << GAIN_ALPHA; + if (gain_delta >= ((s16) gain - state->current_gain)) /* overflow */ + state->current_gain = gain; + else + state->current_gain += gain_delta; + /* cannot be less than 0 (only if gain_delta is less than 0 we can have current_gain < 0) */ + if (state->current_gain < 0) + state->current_gain = 0; + + /* now split total gain to rf and bb gain */ + gain = state->current_gain >> GAIN_ALPHA; + + /* requested gain is bigger than rf gain limit - ACI/WBD adjustment */ + if (gain > (state->rf_gain_limit >> WBD_ALPHA)) { + rf = state->rf_gain_limit >> WBD_ALPHA; + bb = gain - rf; + if (bb > state->bb_ramp[0]) + bb = state->bb_ramp[0]; + } else { /* high signal level -> all gains put on RF */ + rf = gain; + bb = 0; + } + + state->gain[0] = rf; + state->gain[1] = bb; + + /* software ramp */ + /* Start with RF gains */ + g = state->rf_ramp + 1; /* point on RF LNA1 max gain */ + ref = rf; + for (i = 0; i < 7; i++) { /* Go over all amplifiers => 5RF amps + 2 BB amps = 7 amps */ + if (g[0] == 0 || ref < (g[1] - g[0])) /* if total gain of the current amp is null or this amp is not concerned because it starts to work from an higher gain value */ + v = 0; /* force the gain to write for the current amp to be null */ + else if (ref >= g[1]) /* Gain to set is higher than the high working point of this amp */ + v = g[2]; /* force this amp to be full gain */ + else /* compute the value to set to this amp because we are somewhere in his range */ + v = ((ref - (g[1] - g[0])) * g[2]) / g[0]; + + if (i == 0) /* LNA 1 reg mapping */ + gain_reg[0] = v; + else if (i == 1) /* LNA 2 reg mapping */ + gain_reg[0] |= v << 7; + else if (i == 2) /* LNA 3 reg mapping */ + gain_reg[1] = v; + else if (i == 3) /* LNA 4 reg mapping */ + gain_reg[1] |= v << 7; + else if (i == 4) /* CBAND LNA reg mapping */ + gain_reg[2] = v | state->rf_lt_def; + else if (i == 5) /* BB gain 1 reg mapping */ + gain_reg[3] = v << 3; + else if (i == 6) /* BB gain 2 reg mapping */ + gain_reg[3] |= v << 8; + + g += 3; /* go to next gain bloc */ + + /* When RF is finished, start with BB */ + if (i == 4) { + g = state->bb_ramp + 1; /* point on BB gain 1 max gain */ + ref = bb; + } + } + gain_reg[3] |= state->bb_1_def; + gain_reg[3] |= ((bb % 10) * 100) / 125; + +#ifdef DEBUG_AGC + dprintk("GA CALC: DB: %3d(rf) + %3d(bb) = %3d gain_reg[0]=%04x gain_reg[1]=%04x gain_reg[2]=%04x gain_reg[0]=%04x", rf, bb, rf + bb, + gain_reg[0], gain_reg[1], gain_reg[2], gain_reg[3]); +#endif + + /* Write the amplifier regs */ + for (i = 0; i < 4; i++) { + v = gain_reg[i]; + if (force || state->gain_reg[i] != v) { + state->gain_reg[i] = v; + dib0090_write_reg(state, gain_reg_addr[i], v); + } + } +} + +static void dib0090_set_boost(struct dib0090_state *state, int onoff) +{ + state->bb_1_def &= 0xdfff; + state->bb_1_def |= onoff << 13; +} + +static void dib0090_set_rframp(struct dib0090_state *state, const u16 * cfg) +{ + state->rf_ramp = cfg; +} + +static void dib0090_set_rframp_pwm(struct dib0090_state *state, const u16 * cfg) +{ + state->rf_ramp = cfg; + + dib0090_write_reg(state, 0x2a, 0xffff); + + dprintk("total RF gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x2a)); + + dib0090_write_regs(state, 0x2c, cfg + 3, 6); + dib0090_write_regs(state, 0x3e, cfg + 9, 2); +} + +static void dib0090_set_bbramp(struct dib0090_state *state, const u16 * cfg) +{ + state->bb_ramp = cfg; + dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */ +} + +static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg) +{ + state->bb_ramp = cfg; + + dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */ + + dib0090_write_reg(state, 0x33, 0xffff); + dprintk("total BB gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x33)); + dib0090_write_regs(state, 0x35, cfg + 3, 4); +} + +void dib0090_pwm_gain_reset(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + /* reset the AGC */ + + if (state->config->use_pwm_agc) { +#ifdef CONFIG_BAND_SBAND + if (state->current_band == BAND_SBAND) { + dib0090_set_rframp_pwm(state, rf_ramp_pwm_sband); + dib0090_set_bbramp_pwm(state, bb_ramp_pwm_boost); + } else +#endif +#ifdef CONFIG_BAND_CBAND + if (state->current_band == BAND_CBAND) { + dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband); + dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); + } else +#endif +#ifdef CONFIG_BAND_VHF + if (state->current_band == BAND_VHF) { + dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf); + dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); + } else +#endif + { + dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf); + dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); + } + + if (state->rf_ramp[0] != 0) + dib0090_write_reg(state, 0x32, (3 << 11)); + else + dib0090_write_reg(state, 0x32, (0 << 11)); + + dib0090_write_reg(state, 0x39, (1 << 10)); + } +} +EXPORT_SYMBOL(dib0090_pwm_gain_reset); + +int dib0090_gain_control(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + enum frontend_tune_state *tune_state = &state->tune_state; + int ret = 10; + + u16 wbd_val = 0; + u8 apply_gain_immediatly = 1; + s16 wbd_error = 0, adc_error = 0; + + if (*tune_state == CT_AGC_START) { + state->agc_freeze = 0; + dib0090_write_reg(state, 0x04, 0x0); + +#ifdef CONFIG_BAND_SBAND + if (state->current_band == BAND_SBAND) { + dib0090_set_rframp(state, rf_ramp_sband); + dib0090_set_bbramp(state, bb_ramp_boost); + } else +#endif +#ifdef CONFIG_BAND_VHF + if (state->current_band == BAND_VHF) { + dib0090_set_rframp(state, rf_ramp_vhf); + dib0090_set_bbramp(state, bb_ramp_boost); + } else +#endif +#ifdef CONFIG_BAND_CBAND + if (state->current_band == BAND_CBAND) { + dib0090_set_rframp(state, rf_ramp_cband); + dib0090_set_bbramp(state, bb_ramp_boost); + } else +#endif + { + dib0090_set_rframp(state, rf_ramp_uhf); + dib0090_set_bbramp(state, bb_ramp_boost); + } + + dib0090_write_reg(state, 0x32, 0); + dib0090_write_reg(state, 0x39, 0); + + dib0090_wbd_target(state, state->current_rf); + + state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA; + state->current_gain = ((state->rf_ramp[0] + state->bb_ramp[0]) / 2) << GAIN_ALPHA; + + *tune_state = CT_AGC_STEP_0; + } else if (!state->agc_freeze) { + s16 wbd; + + int adc; + wbd_val = dib0090_read_reg(state, 0x1d); + + /* read and calc the wbd power */ + wbd = dib0090_wbd_to_db(state, wbd_val); + wbd_error = state->wbd_target - wbd; + + if (*tune_state == CT_AGC_STEP_0) { + if (wbd_error < 0 && state->rf_gain_limit > 0) { +#ifdef CONFIG_BAND_CBAND + /* in case of CBAND tune reduce first the lt_gain2 before adjusting the RF gain */ + u8 ltg2 = (state->rf_lt_def >> 10) & 0x7; + if (state->current_band == BAND_CBAND && ltg2) { + ltg2 >>= 1; + state->rf_lt_def &= ltg2 << 10; /* reduce in 3 steps from 7 to 0 */ + } +#endif + } else { + state->agc_step = 0; + *tune_state = CT_AGC_STEP_1; + } + } else { + /* calc the adc power */ + adc = state->config->get_adc_power(fe); + adc = (adc * ((s32) 355774) + (((s32) 1) << 20)) >> 21; /* included in [0:-700] */ + + adc_error = (s16) (((s32) ADC_TARGET) - adc); +#ifdef CONFIG_STANDARD_DAB + if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) + adc_error += 130; +#endif +#ifdef CONFIG_STANDARD_DVBT + if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT && + (state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16)) + adc_error += 60; +#endif +#ifdef CONFIG_SYS_ISDBT + if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) && (((state->fe->dtv_property_cache.layer[0].segment_count > + 0) + && + ((state->fe->dtv_property_cache.layer[0].modulation == + QAM_64) + || (state->fe->dtv_property_cache.layer[0]. + modulation == QAM_16))) + || + ((state->fe->dtv_property_cache.layer[1].segment_count > + 0) + && + ((state->fe->dtv_property_cache.layer[1].modulation == + QAM_64) + || (state->fe->dtv_property_cache.layer[1]. + modulation == QAM_16))) + || + ((state->fe->dtv_property_cache.layer[2].segment_count > + 0) + && + ((state->fe->dtv_property_cache.layer[2].modulation == + QAM_64) + || (state->fe->dtv_property_cache.layer[2]. + modulation == QAM_16))) + ) + ) + adc_error += 60; +#endif + + if (*tune_state == CT_AGC_STEP_1) { /* quickly go to the correct range of the ADC power */ + if (ABS(adc_error) < 50 || state->agc_step++ > 5) { + +#ifdef CONFIG_STANDARD_DAB + if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) { + dib0090_write_reg(state, 0x02, (1 << 15) | (15 << 11) | (31 << 6) | (63)); /* cap value = 63 : narrow BB filter : Fc = 1.8MHz */ + dib0090_write_reg(state, 0x04, 0x0); + } else +#endif + { + dib0090_write_reg(state, 0x02, (1 << 15) | (3 << 11) | (6 << 6) | (32)); + dib0090_write_reg(state, 0x04, 0x01); /*0 = 1KHz ; 1 = 150Hz ; 2 = 50Hz ; 3 = 50KHz ; 4 = servo fast */ + } + + *tune_state = CT_AGC_STOP; + } + } else { + /* everything higher than or equal to CT_AGC_STOP means tracking */ + ret = 100; /* 10ms interval */ + apply_gain_immediatly = 0; + } + } +#ifdef DEBUG_AGC + dprintk + ("FE: %d, tune state %d, ADC = %3ddB (ADC err %3d) WBD %3ddB (WBD err %3d, WBD val SADC: %4d), RFGainLimit (TOP): %3d, signal: %3ddBm", + (u32) fe->id, (u32) *tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val, + (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA)); +#endif + } + + /* apply gain */ + if (!state->agc_freeze) + dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly); + return ret; +} +EXPORT_SYMBOL(dib0090_gain_control); + +void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt) +{ + struct dib0090_state *state = fe->tuner_priv; + if (rf) + *rf = state->gain[0]; + if (bb) + *bb = state->gain[1]; + if (rf_gain_limit) + *rf_gain_limit = state->rf_gain_limit; + if (rflt) + *rflt = (state->rf_lt_def >> 10) & 0x7; +} +EXPORT_SYMBOL(dib0090_get_current_gain); + +u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner) +{ + struct dib0090_state *st = tuner->tuner_priv; + return st->wbd_offset; +} +EXPORT_SYMBOL(dib0090_get_wbd_offset); + +static const u16 dib0090_defaults[] = { + + 25, 0x01, + 0x0000, + 0x99a0, + 0x6008, + 0x0000, + 0x8acb, + 0x0000, + 0x0405, + 0x0000, + 0x0000, + 0x0000, + 0xb802, + 0x0300, + 0x2d12, + 0xbac0, + 0x7c00, + 0xdbb9, + 0x0954, + 0x0743, + 0x8000, + 0x0001, + 0x0040, + 0x0100, + 0x0000, + 0xe910, + 0x149e, + + 1, 0x1c, + 0xff2d, + + 1, 0x39, + 0x0000, + + 1, 0x1b, + EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL, + 2, 0x1e, + 0x07FF, + 0x0007, + + 1, 0x24, + EN_UHF | EN_CRYSTAL, + + 2, 0x3c, + 0x3ff, + 0x111, + 0 +}; + +static int dib0090_reset(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + u16 l, r, *n; + + dib0090_reset_digital(fe, state->config); + state->revision = dib0090_identify(fe); + + /* Revision definition */ + if (state->revision == 0xff) + return -EINVAL; +#ifdef EFUSE + else if ((state->revision & 0x1f) >= 3) /* Update the efuse : Only available for KROSUS > P1C */ + dib0090_set_EFUSE(state); +#endif + +#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT + if (!(state->revision & 0x1)) /* it is P1B - reset is already done */ + return 0; +#endif + + /* Upload the default values */ + n = (u16 *) dib0090_defaults; + l = pgm_read_word(n++); + while (l) { + r = pgm_read_word(n++); + do { + /* DEBUG_TUNER */ + /* dprintk("%d, %d, %d", l, r, pgm_read_word(n)); */ + dib0090_write_reg(state, r, pgm_read_word(n++)); + r++; + } while (--l); + l = pgm_read_word(n++); + } + + /* Congigure in function of the crystal */ + if (state->config->io.clock_khz >= 24000) + l = 1; + else + l = 2; + dib0090_write_reg(state, 0x14, l); + dprintk("Pll lock : %d", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1); + + state->reset = 3; /* enable iq-offset-calibration and wbd-calibration when tuning next time */ + + return 0; +} + +#define steps(u) (((u) > 15) ? ((u)-16) : (u)) +#define INTERN_WAIT 10 +static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_state *tune_state) +{ + int ret = INTERN_WAIT * 10; + + switch (*tune_state) { + case CT_TUNER_STEP_2: + /* Turns to positive */ + dib0090_write_reg(state, 0x1f, 0x7); + *tune_state = CT_TUNER_STEP_3; + break; + + case CT_TUNER_STEP_3: + state->adc_diff = dib0090_read_reg(state, 0x1d); + + /* Turns to negative */ + dib0090_write_reg(state, 0x1f, 0x4); + *tune_state = CT_TUNER_STEP_4; + break; + + case CT_TUNER_STEP_4: + state->adc_diff -= dib0090_read_reg(state, 0x1d); + *tune_state = CT_TUNER_STEP_5; + ret = 0; + break; + + default: + break; + } + + return ret; +} + +struct dc_calibration { + uint8_t addr; + uint8_t offset; + uint8_t pga:1; + uint16_t bb1; + uint8_t i:1; +}; + +static const struct dc_calibration dc_table[] = { + /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */ + {0x06, 5, 1, (1 << 13) | (0 << 8) | (26 << 3), 1}, + {0x07, 11, 1, (1 << 13) | (0 << 8) | (26 << 3), 0}, + /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */ + {0x06, 0, 0, (1 << 13) | (29 << 8) | (26 << 3), 1}, + {0x06, 10, 0, (1 << 13) | (29 << 8) | (26 << 3), 0}, + {0}, +}; + +static void dib0090_set_trim(struct dib0090_state *state) +{ + u16 *val; + + if (state->dc->addr == 0x07) + val = &state->bb7; + else + val = &state->bb6; + + *val &= ~(0x1f << state->dc->offset); + *val |= state->step << state->dc->offset; + + dib0090_write_reg(state, state->dc->addr, *val); +} + +static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state) +{ + int ret = 0; + + switch (*tune_state) { + + case CT_TUNER_START: + /* init */ + dprintk("Internal DC calibration"); + + /* the LNA is off */ + dib0090_write_reg(state, 0x24, 0x02ed); + + /* force vcm2 = 0.8V */ + state->bb6 = 0; + state->bb7 = 0x040d; + + state->dc = dc_table; + + *tune_state = CT_TUNER_STEP_0; + + /* fall through */ + + case CT_TUNER_STEP_0: + dib0090_write_reg(state, 0x01, state->dc->bb1); + dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7)); + + state->step = 0; + + state->min_adc_diff = 1023; + + *tune_state = CT_TUNER_STEP_1; + ret = 50; + break; + + case CT_TUNER_STEP_1: + dib0090_set_trim(state); + + *tune_state = CT_TUNER_STEP_2; + break; + + case CT_TUNER_STEP_2: + case CT_TUNER_STEP_3: + case CT_TUNER_STEP_4: + ret = dib0090_get_offset(state, tune_state); + break; + + case CT_TUNER_STEP_5: /* found an offset */ + dprintk("FE%d: IQC read=%d, current=%x", state->fe->id, (u32) state->adc_diff, state->step); + + /* first turn for this frequency */ + if (state->step == 0) { + if (state->dc->pga && state->adc_diff < 0) + state->step = 0x10; + if (state->dc->pga == 0 && state->adc_diff > 0) + state->step = 0x10; + } + + state->adc_diff = ABS(state->adc_diff); + + if (state->adc_diff < state->min_adc_diff && steps(state->step) < 15) { /* stop search when the delta to 0 is increasing */ + state->step++; + state->min_adc_diff = state->adc_diff; + *tune_state = CT_TUNER_STEP_1; + } else { + + /* the minimum was what we have seen in the step before */ + state->step--; + dib0090_set_trim(state); + + dprintk("FE%d: BB Offset Cal, BBreg=%hd,Offset=%hd,Value Set=%hd", state->fe->id, state->dc->addr, state->adc_diff, + state->step); + + state->dc++; + if (state->dc->addr == 0) /* done */ + *tune_state = CT_TUNER_STEP_6; + else + *tune_state = CT_TUNER_STEP_0; + + } + break; + + case CT_TUNER_STEP_6: + dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008); + dib0090_write_reg(state, 0x1f, 0x7); + *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */ + state->reset &= ~0x1; + default: + break; + } + return ret; +} + +static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state) +{ + switch (*tune_state) { + case CT_TUNER_START: + /* WBD-mode=log, Bias=2, Gain=6, Testmode=1, en=1, WBDMUX=1 */ + dib0090_write_reg(state, 0x10, 0xdb09 | (1 << 10)); + dib0090_write_reg(state, 0x24, EN_UHF & 0x0fff); + + *tune_state = CT_TUNER_STEP_0; + return 90; /* wait for the WBDMUX to switch and for the ADC to sample */ + case CT_TUNER_STEP_0: + state->wbd_offset = dib0090_read_reg(state, 0x1d); + dprintk("WBD calibration offset = %d", state->wbd_offset); + + *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */ + state->reset &= ~0x2; + break; + default: + break; + } + return 0; +} + +static void dib0090_set_bandwidth(struct dib0090_state *state) +{ + u16 tmp; + + if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 5000) + tmp = (3 << 14); + else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 6000) + tmp = (2 << 14); + else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 7000) + tmp = (1 << 14); + else + tmp = (0 << 14); + + state->bb_1_def &= 0x3fff; + state->bb_1_def |= tmp; + + dib0090_write_reg(state, 0x01, state->bb_1_def); /* be sure that we have the right bb-filter */ +} + +static const struct dib0090_pll dib0090_pll_table[] = { +#ifdef CONFIG_BAND_CBAND + {56000, 0, 9, 48, 6}, + {70000, 1, 9, 48, 6}, + {87000, 0, 8, 32, 4}, + {105000, 1, 8, 32, 4}, + {115000, 0, 7, 24, 6}, + {140000, 1, 7, 24, 6}, + {170000, 0, 6, 16, 4}, +#endif +#ifdef CONFIG_BAND_VHF + {200000, 1, 6, 16, 4}, + {230000, 0, 5, 12, 6}, + {280000, 1, 5, 12, 6}, + {340000, 0, 4, 8, 4}, + {380000, 1, 4, 8, 4}, + {450000, 0, 3, 6, 6}, +#endif +#ifdef CONFIG_BAND_UHF + {580000, 1, 3, 6, 6}, + {700000, 0, 2, 4, 4}, + {860000, 1, 2, 4, 4}, +#endif +#ifdef CONFIG_BAND_LBAND + {1800000, 1, 0, 2, 4}, +#endif +#ifdef CONFIG_BAND_SBAND + {2900000, 0, 14, 1, 4}, +#endif +}; + +static const struct dib0090_tuning dib0090_tuning_table_fm_vhf_on_cband[] = { + +#ifdef CONFIG_BAND_CBAND + {184000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, + {227000, 4, 3, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, + {380000, 4, 7, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, +#endif +#ifdef CONFIG_BAND_UHF + {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, +#endif +#ifdef CONFIG_BAND_LBAND + {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, + {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, + {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, +#endif +#ifdef CONFIG_BAND_SBAND + {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, + {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, +#endif +}; + +static const struct dib0090_tuning dib0090_tuning_table[] = { + +#ifdef CONFIG_BAND_CBAND + {170000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, +#endif +#ifdef CONFIG_BAND_VHF + {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, + {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, + {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, +#endif +#ifdef CONFIG_BAND_UHF + {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, +#endif +#ifdef CONFIG_BAND_LBAND + {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, + {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, + {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, +#endif +#ifdef CONFIG_BAND_SBAND + {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, + {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, +#endif +}; + +#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */ +static int dib0090_tune(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + const struct dib0090_tuning *tune = state->current_tune_table_index; + const struct dib0090_pll *pll = state->current_pll_table_index; + enum frontend_tune_state *tune_state = &state->tune_state; + + u32 rf; + u16 lo4 = 0xe900, lo5, lo6, Den; + u32 FBDiv, Rest, FREF, VCOF_kHz = 0; + u16 tmp, adc; + int8_t step_sign; + int ret = 10; /* 1ms is the default delay most of the time */ + u8 c, i; + + state->current_band = (u8) BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000); + rf = fe->dtv_property_cache.frequency / 1000 + (state->current_band == + BAND_UHF ? state->config->freq_offset_khz_uhf : state->config->freq_offset_khz_vhf); + /* in any case we first need to do a reset if needed */ + if (state->reset & 0x1) + return dib0090_dc_offset_calibration(state, tune_state); + else if (state->reset & 0x2) + return dib0090_wbd_calibration(state, tune_state); + + /************************* VCO ***************************/ + /* Default values for FG */ + /* from these are needed : */ + /* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv */ + +#ifdef CONFIG_SYS_ISDBT + if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1) + rf += 850; +#endif + + if (state->current_rf != rf) { + state->tuner_is_tuned = 0; + + tune = dib0090_tuning_table; + + tmp = (state->revision >> 5) & 0x7; + if (tmp == 0x4 || tmp == 0x7) { + /* CBAND tuner version for VHF */ + if (state->current_band == BAND_FM || state->current_band == BAND_VHF) { + /* Force CBAND */ + state->current_band = BAND_CBAND; + tune = dib0090_tuning_table_fm_vhf_on_cband; + } + } + + pll = dib0090_pll_table; + /* Look for the interval */ + while (rf > tune->max_freq) + tune++; + while (rf > pll->max_freq) + pll++; + state->current_tune_table_index = tune; + state->current_pll_table_index = pll; + } + + if (*tune_state == CT_TUNER_START) { + + if (state->tuner_is_tuned == 0) + state->current_rf = 0; + + if (state->current_rf != rf) { + + dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim)); + + /* external loop filter, otherwise: + * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4; + * lo6 = 0x0e34 */ + if (pll->vco_band) + lo5 = 0x049e; + else if (state->config->analog_output) + lo5 = 0x041d; + else + lo5 = 0x041c; + + lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7); /* bit 15 is the split to the slave, we do not do it here */ + + if (!state->config->io.pll_int_loop_filt) + lo6 = 0xff28; + else + lo6 = (state->config->io.pll_int_loop_filt << 3); + + VCOF_kHz = (pll->hfdiv * rf) * 2; + + FREF = state->config->io.clock_khz; + + FBDiv = (VCOF_kHz / pll->topresc / FREF); + Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF; + + if (Rest < LPF) + Rest = 0; + else if (Rest < 2 * LPF) + Rest = 2 * LPF; + else if (Rest > (FREF - LPF)) { + Rest = 0; + FBDiv += 1; + } else if (Rest > (FREF - 2 * LPF)) + Rest = FREF - 2 * LPF; + Rest = (Rest * 6528) / (FREF / 10); + + Den = 1; + + dprintk(" ***** ******* Rest value = %d", Rest); + + if (Rest > 0) { + if (state->config->analog_output) + lo6 |= (1 << 2) | 2; + else + lo6 |= (1 << 2) | 1; + Den = 255; + } +#ifdef CONFIG_BAND_SBAND + if (state->current_band == BAND_SBAND) + lo6 &= 0xfffb; +#endif + + dib0090_write_reg(state, 0x15, (u16) FBDiv); + + dib0090_write_reg(state, 0x16, (Den << 8) | 1); + + dib0090_write_reg(state, 0x17, (u16) Rest); + + dib0090_write_reg(state, 0x19, lo5); + + dib0090_write_reg(state, 0x1c, lo6); + + lo6 = tune->tuner_enable; + if (state->config->analog_output) + lo6 = (lo6 & 0xff9f) | 0x2; + + dib0090_write_reg(state, 0x24, lo6 | EN_LO +#ifdef CONFIG_DIB0090_USE_PWM_AGC + | state->config->use_pwm_agc * EN_CRYSTAL +#endif + ); + + state->current_rf = rf; + + /* prepare a complete captrim */ + state->step = state->captrim = state->fcaptrim = 64; + + } else { /* we are already tuned to this frequency - the configuration is correct */ + + /* do a minimal captrim even if the frequency has not changed */ + state->step = 4; + state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f; + } + state->adc_diff = 3000; + + dib0090_write_reg(state, 0x10, 0x2B1); + + dib0090_write_reg(state, 0x1e, 0x0032); + + ret = 20; + *tune_state = CT_TUNER_STEP_1; + } else if (*tune_state == CT_TUNER_STEP_0) { + /* nothing */ + } else if (*tune_state == CT_TUNER_STEP_1) { + state->step /= 2; + dib0090_write_reg(state, 0x18, lo4 | state->captrim); + *tune_state = CT_TUNER_STEP_2; + } else if (*tune_state == CT_TUNER_STEP_2) { + + adc = dib0090_read_reg(state, 0x1d); + dprintk("FE %d CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) fe->id, (u32) state->captrim, (u32) adc, + (u32) (adc) * (u32) 1800 / (u32) 1024); + + if (adc >= 400) { + adc -= 400; + step_sign = -1; + } else { + adc = 400 - adc; + step_sign = 1; + } + + if (adc < state->adc_diff) { + dprintk("FE %d CAPTRIM=%d is closer to target (%d/%d)", (u32) fe->id, (u32) state->captrim, (u32) adc, (u32) state->adc_diff); + state->adc_diff = adc; + state->fcaptrim = state->captrim; + + } + + state->captrim += step_sign * state->step; + if (state->step >= 1) + *tune_state = CT_TUNER_STEP_1; + else + *tune_state = CT_TUNER_STEP_3; + + ret = 15; + } else if (*tune_state == CT_TUNER_STEP_3) { + /*write the final cptrim config */ + dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim); + +#ifdef CONFIG_TUNER_DIB0090_CAPTRIM_MEMORY + state->memory[state->memory_index].cap = state->fcaptrim; +#endif + + *tune_state = CT_TUNER_STEP_4; + } else if (*tune_state == CT_TUNER_STEP_4) { + dib0090_write_reg(state, 0x1e, 0x07ff); + + dprintk("FE %d Final Captrim: %d", (u32) fe->id, (u32) state->fcaptrim); + dprintk("FE %d HFDIV code: %d", (u32) fe->id, (u32) pll->hfdiv_code); + dprintk("FE %d VCO = %d", (u32) fe->id, (u32) pll->vco_band); + dprintk("FE %d VCOF in kHz: %d ((%d*%d) << 1))", (u32) fe->id, (u32) ((pll->hfdiv * rf) * 2), (u32) pll->hfdiv, (u32) rf); + dprintk("FE %d REFDIV: %d, FREF: %d", (u32) fe->id, (u32) 1, (u32) state->config->io.clock_khz); + dprintk("FE %d FBDIV: %d, Rest: %d", (u32) fe->id, (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17)); + dprintk("FE %d Num: %d, Den: %d, SD: %d", (u32) fe->id, (u32) dib0090_read_reg(state, 0x17), + (u32) (dib0090_read_reg(state, 0x16) >> 8), (u32) dib0090_read_reg(state, 0x1c) & 0x3); + + c = 4; + i = 3; +#if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND) + if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND)) { + c = 2; + i = 2; + } +#endif + dib0090_write_reg(state, 0x10, (c << 13) | (i << 11) | (WBD +#ifdef CONFIG_DIB0090_USE_PWM_AGC + | (state->config->use_pwm_agc << 1) +#endif + )); + dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | (tune->lna_bias << 0)); + dib0090_write_reg(state, 0x0c, tune->v2i); + dib0090_write_reg(state, 0x0d, tune->mix); + dib0090_write_reg(state, 0x0e, tune->load); + + *tune_state = CT_TUNER_STEP_5; + } else if (*tune_state == CT_TUNER_STEP_5) { + + /* initialize the lt gain register */ + state->rf_lt_def = 0x7c00; + dib0090_write_reg(state, 0x0f, state->rf_lt_def); + + dib0090_set_bandwidth(state); + state->tuner_is_tuned = 1; + *tune_state = CT_TUNER_STOP; + } else + ret = FE_CALLBACK_TIME_NEVER; + return ret; +} + +static int dib0090_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + + return state->tune_state; +} +EXPORT_SYMBOL(dib0090_get_tune_state); + +int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) +{ + struct dib0090_state *state = fe->tuner_priv; + + state->tune_state = tune_state; + return 0; +} +EXPORT_SYMBOL(dib0090_set_tune_state); + +static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency) +{ + struct dib0090_state *state = fe->tuner_priv; + + *frequency = 1000 * state->current_rf; + return 0; +} + +static int dib0090_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ + struct dib0090_state *state = fe->tuner_priv; + uint32_t ret; + + state->tune_state = CT_TUNER_START; + + do { + ret = dib0090_tune(fe); + if (ret != FE_CALLBACK_TIME_NEVER) + msleep(ret / 10); + else + break; + } while (state->tune_state != CT_TUNER_STOP); + + return 0; +} + +static const struct dvb_tuner_ops dib0090_ops = { + .info = { + .name = "DiBcom DiB0090", + .frequency_min = 45000000, + .frequency_max = 860000000, + .frequency_step = 1000, + }, + .release = dib0090_release, + + .init = dib0090_wakeup, + .sleep = dib0090_sleep, + .set_params = dib0090_set_params, + .get_frequency = dib0090_get_frequency, +}; + +struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config) +{ + struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL); + if (st == NULL) + return NULL; + + st->config = config; + st->i2c = i2c; + st->fe = fe; + fe->tuner_priv = st; + + if (dib0090_reset(fe) != 0) + goto free_mem; + + printk(KERN_INFO "DiB0090: successfully identified\n"); + memcpy(&fe->ops.tuner_ops, &dib0090_ops, sizeof(struct dvb_tuner_ops)); + + return fe; + free_mem: + kfree(st); + fe->tuner_priv = NULL; + return NULL; +} +EXPORT_SYMBOL(dib0090_register); + +MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); +MODULE_AUTHOR("Olivier Grenie <olivier.grenie@dibcom.fr>"); +MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/dib0090.h b/drivers/media/dvb/frontends/dib0090.h new file mode 100644 index 00000000000..aa7711e8877 --- /dev/null +++ b/drivers/media/dvb/frontends/dib0090.h @@ -0,0 +1,108 @@ +/* + * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner. + * + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) + * + * 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, version 2. + */ +#ifndef DIB0090_H +#define DIB0090_H + +struct dvb_frontend; +struct i2c_adapter; + +#define DEFAULT_DIB0090_I2C_ADDRESS 0x60 + +struct dib0090_io_config { + u32 clock_khz; + + u8 pll_bypass:1; + u8 pll_range:1; + u8 pll_prediv:6; + u8 pll_loopdiv:6; + + u8 adc_clock_ratio; /* valid is 8, 7 ,6 */ + u16 pll_int_loop_filt; +}; + +struct dib0090_config { + struct dib0090_io_config io; + int (*reset) (struct dvb_frontend *, int); + int (*sleep) (struct dvb_frontend *, int); + + /* offset in kHz */ + int freq_offset_khz_uhf; + int freq_offset_khz_vhf; + + int (*get_adc_power) (struct dvb_frontend *); + + u8 clkouttobamse:1; /* activate or deactivate clock output */ + u8 analog_output; + + u8 i2c_address; + /* add drives and other things if necessary */ + u16 wbd_vhf_offset; + u16 wbd_cband_offset; + u8 use_pwm_agc; + u8 clkoutdrive; +}; + +#if defined(CONFIG_DVB_TUNER_DIB0090) || (defined(CONFIG_DVB_TUNER_DIB0090_MODULE) && defined(MODULE)) +extern struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config); +extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast); +extern void dib0090_pwm_gain_reset(struct dvb_frontend *fe); +extern u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner); +extern int dib0090_gain_control(struct dvb_frontend *fe); +extern enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe); +extern int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state); +extern void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt); +#else +static inline struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0090_config *config) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); +} + +static inline void dib0090_pwm_gain_reset(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); +} + +static inline u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} + +static inline int dib0090_gain_control(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return CT_DONE; +} + +static inline int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); +} +#endif + +#endif diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c index 898400d331a..6f6fa29d9ea 100644 --- a/drivers/media/dvb/frontends/dib8000.c +++ b/drivers/media/dvb/frontends/dib8000.c @@ -28,18 +28,6 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0) -enum frontend_tune_state { - CT_AGC_START = 20, - CT_AGC_STEP_0, - CT_AGC_STEP_1, - CT_AGC_STEP_2, - CT_AGC_STEP_3, - CT_AGC_STEP_4, - CT_AGC_STOP, - - CT_DEMOD_START = 30, -}; - #define FE_STATUS_TUNE_FAILED 0 struct i2c_device { @@ -133,104 +121,104 @@ static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val) return dib8000_i2c_write16(&state->i2c, reg, val); } -const int16_t coeff_2k_sb_1seg_dqpsk[8] = { +static const int16_t coeff_2k_sb_1seg_dqpsk[8] = { (769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c, (920 << 5) | 0x09 }; -const int16_t coeff_2k_sb_1seg[8] = { +static const int16_t coeff_2k_sb_1seg[8] = { (692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f }; -const int16_t coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = { +static const int16_t coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = { (832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11, (-931 << 5) | 0x0f }; -const int16_t coeff_2k_sb_3seg_0dqpsk[8] = { +static const int16_t coeff_2k_sb_3seg_0dqpsk[8] = { (622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e, (982 << 5) | 0x0c }; -const int16_t coeff_2k_sb_3seg_1dqpsk[8] = { +static const int16_t coeff_2k_sb_3seg_1dqpsk[8] = { (699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12, (-720 << 5) | 0x0d }; -const int16_t coeff_2k_sb_3seg[8] = { +static const int16_t coeff_2k_sb_3seg[8] = { (664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e, (-610 << 5) | 0x0a }; -const int16_t coeff_4k_sb_1seg_dqpsk[8] = { +static const int16_t coeff_4k_sb_1seg_dqpsk[8] = { (-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f, (-922 << 5) | 0x0d }; -const int16_t coeff_4k_sb_1seg[8] = { +static const int16_t coeff_4k_sb_1seg[8] = { (638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d, (-655 << 5) | 0x0a }; -const int16_t coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = { +static const int16_t coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = { (-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14, (-958 << 5) | 0x13 }; -const int16_t coeff_4k_sb_3seg_0dqpsk[8] = { +static const int16_t coeff_4k_sb_3seg_0dqpsk[8] = { (-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12, (-568 << 5) | 0x0f }; -const int16_t coeff_4k_sb_3seg_1dqpsk[8] = { +static const int16_t coeff_4k_sb_3seg_1dqpsk[8] = { (-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14, (-848 << 5) | 0x13 }; -const int16_t coeff_4k_sb_3seg[8] = { +static const int16_t coeff_4k_sb_3seg[8] = { (612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12, (-869 << 5) | 0x13 }; -const int16_t coeff_8k_sb_1seg_dqpsk[8] = { +static const int16_t coeff_8k_sb_1seg_dqpsk[8] = { (-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13, (-598 << 5) | 0x10 }; -const int16_t coeff_8k_sb_1seg[8] = { +static const int16_t coeff_8k_sb_1seg[8] = { (673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f, (585 << 5) | 0x0f }; -const int16_t coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = { +static const int16_t coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = { (863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18, (0 << 5) | 0x14 }; -const int16_t coeff_8k_sb_3seg_0dqpsk[8] = { +static const int16_t coeff_8k_sb_3seg_0dqpsk[8] = { (-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15, (-877 << 5) | 0x15 }; -const int16_t coeff_8k_sb_3seg_1dqpsk[8] = { +static const int16_t coeff_8k_sb_3seg_1dqpsk[8] = { (-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18, (-921 << 5) | 0x14 }; -const int16_t coeff_8k_sb_3seg[8] = { +static const int16_t coeff_8k_sb_3seg[8] = { (514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15, (690 << 5) | 0x14 }; -const int16_t ana_fe_coeff_3seg[24] = { +static const int16_t ana_fe_coeff_3seg[24] = { 81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017 }; -const int16_t ana_fe_coeff_1seg[24] = { +static const int16_t ana_fe_coeff_1seg[24] = { 249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003 }; -const int16_t ana_fe_coeff_13seg[24] = { +static const int16_t ana_fe_coeff_13seg[24] = { 396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1 }; @@ -852,6 +840,14 @@ static int dib8000_set_agc_config(struct dib8000_state *state, u8 band) return 0; } +void dib8000_pwm_agc_reset(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + dib8000_set_adc_state(state, DIBX000_ADC_ON); + dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))); +} +EXPORT_SYMBOL(dib8000_pwm_agc_reset); + static int dib8000_agc_soft_split(struct dib8000_state *state) { u16 agc, split_offset; @@ -939,6 +935,32 @@ static int dib8000_agc_startup(struct dvb_frontend *fe) } +static const int32_t lut_1000ln_mant[] = +{ + 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600 +}; + +int32_t dib8000_get_adc_power(struct dvb_frontend *fe, uint8_t mode) +{ + struct dib8000_state *state = fe->demodulator_priv; + uint32_t ix = 0, tmp_val = 0, exp = 0, mant = 0; + int32_t val; + + val = dib8000_read32(state, 384); + /* mode = 1 : ln_agcpower calc using mant-exp conversion and mantis look up table */ + if (mode) { + tmp_val = val; + while (tmp_val >>= 1) + exp++; + mant = (val * 1000 / (1<<exp)); + ix = (uint8_t)((mant-1000)/100); /* index of the LUT */ + val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908); /* 1000 * ln(adcpower_real) ; 693 = 1000ln(2) ; 6908 = 1000*ln(1000) ; 20 comes from adc_real = adc_pow_int / 2**20 */ + val = (val*256)/1000; + } + return val; +} +EXPORT_SYMBOL(dib8000_get_adc_power); + static void dib8000_update_timf(struct dib8000_state *state) { u32 timf = state->timf = dib8000_read32(state, 435); @@ -1401,10 +1423,9 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear } break; } - } - if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) for (i = 0; i < 8; i++) dib8000_write_word(state, 343 + i, ncoeff[i]); + } // P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5 dib8000_write_word(state, 351, @@ -1854,6 +1875,24 @@ static int dib8000_sleep(struct dvb_frontend *fe) } } +enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + return state->tune_state; +} +EXPORT_SYMBOL(dib8000_get_tune_state); + +int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) +{ + struct dib8000_state *state = fe->demodulator_priv; + state->tune_state = tune_state; + return 0; +} +EXPORT_SYMBOL(dib8000_set_tune_state); + + + + static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) { struct dib8000_state *state = fe->demodulator_priv; @@ -2043,29 +2082,31 @@ static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat) *stat = 0; - if ((lock >> 14) & 1) // AGC + if ((lock >> 13) & 1) *stat |= FE_HAS_SIGNAL; - if ((lock >> 8) & 1) // Equal + if ((lock >> 8) & 1) /* Equal */ *stat |= FE_HAS_CARRIER; - if ((lock >> 3) & 1) // TMCC_SYNC + if (((lock >> 1) & 0xf) == 0xf) /* TMCC_SYNC */ *stat |= FE_HAS_SYNC; - if ((lock >> 5) & 7) // FEC MPEG + if (((lock >> 12) & 1) && ((lock >> 5) & 7)) /* FEC MPEG */ *stat |= FE_HAS_LOCK; - lock = dib8000_read_word(state, 554); // Viterbi Layer A - if (lock & 0x01) - *stat |= FE_HAS_VITERBI; + if ((lock >> 12) & 1) { + lock = dib8000_read_word(state, 554); /* Viterbi Layer A */ + if (lock & 0x01) + *stat |= FE_HAS_VITERBI; - lock = dib8000_read_word(state, 555); // Viterbi Layer B - if (lock & 0x01) - *stat |= FE_HAS_VITERBI; + lock = dib8000_read_word(state, 555); /* Viterbi Layer B */ + if (lock & 0x01) + *stat |= FE_HAS_VITERBI; - lock = dib8000_read_word(state, 556); // Viterbi Layer C - if (lock & 0x01) - *stat |= FE_HAS_VITERBI; + lock = dib8000_read_word(state, 556); /* Viterbi Layer C */ + if (lock & 0x01) + *stat |= FE_HAS_VITERBI; + } return 0; } diff --git a/drivers/media/dvb/frontends/dib8000.h b/drivers/media/dvb/frontends/dib8000.h index 8c89482b738..d99619ae983 100644 --- a/drivers/media/dvb/frontends/dib8000.h +++ b/drivers/media/dvb/frontends/dib8000.h @@ -46,6 +46,10 @@ extern int dib8000_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); extern int dib8000_set_wbd_ref(struct dvb_frontend *, u16 value); extern int dib8000_pid_filter_ctrl(struct dvb_frontend *, u8 onoff); extern int dib8000_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff); +extern int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state); +extern enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe); +extern void dib8000_pwm_agc_reset(struct dvb_frontend *fe); +extern s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode); #else static inline struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg) { @@ -59,35 +63,53 @@ static inline struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe return NULL; } -int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr) +static inline int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; } -int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) +static inline int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; } -int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value) +static inline int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; } -int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) +static inline int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; } -int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) +static inline int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; } +static inline int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} +static inline enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return CT_SHUTDOWN, +} +static inline void dib8000_pwm_agc_reset(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); +} +static inline s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); +} #endif #endif diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c index 4efca30d212..e6f3d73db9d 100644 --- a/drivers/media/dvb/frontends/dibx000_common.c +++ b/drivers/media/dvb/frontends/dibx000_common.c @@ -6,7 +6,7 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiBX000: "); printk(args); } } while (0) +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiBX000: "); printk(args); printk("\n"); } } while (0) static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val) { @@ -25,7 +25,7 @@ static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf) { if (mst->device_rev > DIB3000MC && mst->selected_interface != intf) { - dprintk("selecting interface: %d\n", intf); + dprintk("selecting interface: %d", intf); mst->selected_interface = intf; return dibx000_write_word(mst, mst->base_reg + 4, intf); } @@ -171,9 +171,18 @@ void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst) { i2c_del_adapter(&mst->gated_tuner_i2c_adap); } - EXPORT_SYMBOL(dibx000_exit_i2c_master); + +u32 systime() +{ + struct timespec t; + + t = current_kernel_time(); + return (t.tv_sec * 10000) + (t.tv_nsec / 100000); +} +EXPORT_SYMBOL(systime); + MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); MODULE_DESCRIPTION("Common function the DiBcom demodulator family"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h index 5be10eca07c..4f5d141a308 100644 --- a/drivers/media/dvb/frontends/dibx000_common.h +++ b/drivers/media/dvb/frontends/dibx000_common.h @@ -36,13 +36,17 @@ extern struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst); extern void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst); +extern u32 systime(void); + #define BAND_LBAND 0x01 #define BAND_UHF 0x02 #define BAND_VHF 0x04 #define BAND_SBAND 0x08 -#define BAND_FM 0x10 +#define BAND_FM 0x10 +#define BAND_CBAND 0x20 -#define BAND_OF_FREQUENCY(freq_kHz) ( (freq_kHz) <= 115000 ? BAND_FM : \ +#define BAND_OF_FREQUENCY(freq_kHz) ((freq_kHz) <= 170000 ? BAND_CBAND : \ + (freq_kHz) <= 115000 ? BAND_FM : \ (freq_kHz) <= 250000 ? BAND_VHF : \ (freq_kHz) <= 863000 ? BAND_UHF : \ (freq_kHz) <= 2000000 ? BAND_LBAND : BAND_SBAND ) @@ -149,4 +153,67 @@ enum dibx000_adc_states { #define OUTMODE_MPEG2_FIFO 5 #define OUTMODE_ANALOG_ADC 6 +enum frontend_tune_state { + CT_TUNER_START = 10, + CT_TUNER_STEP_0, + CT_TUNER_STEP_1, + CT_TUNER_STEP_2, + CT_TUNER_STEP_3, + CT_TUNER_STEP_4, + CT_TUNER_STEP_5, + CT_TUNER_STEP_6, + CT_TUNER_STEP_7, + CT_TUNER_STOP, + + CT_AGC_START = 20, + CT_AGC_STEP_0, + CT_AGC_STEP_1, + CT_AGC_STEP_2, + CT_AGC_STEP_3, + CT_AGC_STEP_4, + CT_AGC_STOP, + + CT_DEMOD_START = 30, + CT_DEMOD_STEP_1, + CT_DEMOD_STEP_2, + CT_DEMOD_STEP_3, + CT_DEMOD_STEP_4, + CT_DEMOD_STEP_5, + CT_DEMOD_STEP_6, + CT_DEMOD_STEP_7, + CT_DEMOD_STEP_8, + CT_DEMOD_STEP_9, + CT_DEMOD_STEP_10, + CT_DEMOD_SEARCH_NEXT = 41, + CT_DEMOD_STEP_LOCKED, + CT_DEMOD_STOP, + + CT_DONE = 100, + CT_SHUTDOWN, + +}; + +struct dvb_frontend_parametersContext { +#define CHANNEL_STATUS_PARAMETERS_UNKNOWN 0x01 +#define CHANNEL_STATUS_PARAMETERS_SET 0x02 + u8 status; + u32 tune_time_estimation[2]; + s32 tps_available; + u16 tps[9]; +}; + +#define FE_STATUS_TUNE_FAILED 0 +#define FE_STATUS_TUNE_TIMED_OUT -1 +#define FE_STATUS_TUNE_TIME_TOO_SHORT -2 +#define FE_STATUS_TUNE_PENDING -3 +#define FE_STATUS_STD_SUCCESS -4 +#define FE_STATUS_FFT_SUCCESS -5 +#define FE_STATUS_DEMOD_SUCCESS -6 +#define FE_STATUS_LOCKED -7 +#define FE_STATUS_DATA_LOCKED -8 + +#define FE_CALLBACK_TIME_NEVER 0xffffffff + +#define ABS(x) ((x < 0) ? (-x) : (x)) + #endif diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c index eabcadc425d..dee53960e7e 100644 --- a/drivers/media/dvb/frontends/lgs8gxx.c +++ b/drivers/media/dvb/frontends/lgs8gxx.c @@ -199,7 +199,7 @@ static int lgs8gxx_set_if_freq(struct lgs8gxx_state *priv, u32 freq /*in kHz*/) val = freq; if (freq != 0) { - val *= (u64)1 << 32; + val <<= 32; if (if_clk != 0) do_div(val, if_clk); v32 = val & 0xFFFFFFFF; @@ -246,7 +246,7 @@ static int lgs8gxx_get_afc_phase(struct lgs8gxx_state *priv) val = v32; val *= priv->config->if_clk_freq; - val /= (u64)1 << 32; + val >>= 32; dprintk("AFC = %u kHz\n", (u32)val); return 0; } diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c index 71f607fe8fc..b181bf023ad 100644 --- a/drivers/media/dvb/frontends/lnbp21.c +++ b/drivers/media/dvb/frontends/lnbp21.c @@ -1,7 +1,7 @@ /* * lnbp21.c - driver for lnb supply and control ic lnbp21 * - * Copyright (C) 2006 Oliver Endriss + * Copyright (C) 2006, 2009 Oliver Endriss <o.endriss@gmx.de> * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru> * * This program is free software; you can redistribute it and/or @@ -91,6 +91,31 @@ static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO; } +static int lnbp21_set_tone(struct dvb_frontend *fe, + fe_sec_tone_mode_t tone) +{ + struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv; + struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0, + .buf = &lnbp21->config, + .len = sizeof(lnbp21->config) }; + + switch (tone) { + case SEC_TONE_OFF: + lnbp21->config &= ~LNBP21_TEN; + break; + case SEC_TONE_ON: + lnbp21->config |= LNBP21_TEN; + break; + default: + return -EINVAL; + }; + + lnbp21->config |= lnbp21->override_or; + lnbp21->config &= lnbp21->override_and; + + return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO; +} + static void lnbp21_release(struct dvb_frontend *fe) { /* LNBP power off */ @@ -133,6 +158,7 @@ static struct dvb_frontend *lnbx2x_attach(struct dvb_frontend *fe, /* override frontend ops */ fe->ops.set_voltage = lnbp21_set_voltage; fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage; + fe->ops.set_tone = lnbp21_set_tone; printk(KERN_INFO "LNBx2x attached on addr=%x\n", lnbp21->i2c_addr); return fe; diff --git a/drivers/media/dvb/frontends/stv0900_core.c b/drivers/media/dvb/frontends/stv0900_core.c index df49ea0983b..8762c86044a 100644 --- a/drivers/media/dvb/frontends/stv0900_core.c +++ b/drivers/media/dvb/frontends/stv0900_core.c @@ -1451,6 +1451,8 @@ static int stv0900_status(struct stv0900_internal *intp, { enum fe_stv0900_search_state demod_state; int locked = FALSE; + u8 tsbitrate0_val, tsbitrate1_val; + s32 bitrate; demod_state = stv0900_get_bits(intp, HEADER_MODE); switch (demod_state) { @@ -1473,6 +1475,17 @@ static int stv0900_status(struct stv0900_internal *intp, dprintk("%s: locked = %d\n", __func__, locked); + if (stvdebug) { + /* Print TS bitrate */ + tsbitrate0_val = stv0900_read_reg(intp, TSBITRATE0); + tsbitrate1_val = stv0900_read_reg(intp, TSBITRATE1); + /* Formula Bit rate = Mclk * px_tsfifo_bitrate / 16384 */ + bitrate = (stv0900_get_mclk_freq(intp, intp->quartz)/1000000) + * (tsbitrate1_val << 8 | tsbitrate0_val); + bitrate /= 16384; + dprintk("TS bitrate = %d Mbit/sec \n", bitrate); + }; + return locked; } diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c index 48edd542242..1573466a5c7 100644 --- a/drivers/media/dvb/frontends/stv090x.c +++ b/drivers/media/dvb/frontends/stv090x.c @@ -3597,7 +3597,8 @@ static int stv090x_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_ma reg = STV090x_READ_DEMOD(state, DISTXCTL); - STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 2); + STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, + (state->config->diseqc_envelope_mode) ? 4 : 2); STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1); if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) goto err; @@ -3649,10 +3650,10 @@ static int stv090x_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t reg = STV090x_READ_DEMOD(state, DISTXCTL); if (burst == SEC_MINI_A) { - mode = 3; + mode = (state->config->diseqc_envelope_mode) ? 5 : 3; value = 0x00; } else { - mode = 2; + mode = (state->config->diseqc_envelope_mode) ? 4 : 2; value = 0xFF; } diff --git a/drivers/media/dvb/frontends/stv090x.h b/drivers/media/dvb/frontends/stv090x.h index e968c98bb70..b133807663e 100644 --- a/drivers/media/dvb/frontends/stv090x.h +++ b/drivers/media/dvb/frontends/stv090x.h @@ -75,6 +75,8 @@ struct stv090x_config { enum stv090x_i2crpt repeater_level; + bool diseqc_envelope_mode; + int (*tuner_init) (struct dvb_frontend *fe); int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode); int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency); diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c index 266033ae278..68bf9fbd8fe 100644 --- a/drivers/media/dvb/siano/smsdvb.c +++ b/drivers/media/dvb/siano/smsdvb.c @@ -662,7 +662,7 @@ adapter_error: return rc; } -int smsdvb_module_init(void) +static int __init smsdvb_module_init(void) { int rc; @@ -676,7 +676,7 @@ int smsdvb_module_init(void) return rc; } -void smsdvb_module_exit(void) +static void __exit smsdvb_module_exit(void) { smscore_unregister_hotplug(smsdvb_hotplug); diff --git a/drivers/media/dvb/siano/smssdio.c b/drivers/media/dvb/siano/smssdio.c index 24206cbda26..195244a3e69 100644 --- a/drivers/media/dvb/siano/smssdio.c +++ b/drivers/media/dvb/siano/smssdio.c @@ -48,7 +48,7 @@ #define SMSSDIO_INT 0x04 #define SMSSDIO_BLOCK_SIZE 128 -static const struct sdio_device_id smssdio_ids[] = { +static const struct sdio_device_id smssdio_ids[] __devinitconst = { {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR), .driver_data = SMS1XXX_BOARD_SIANO_STELLAR}, {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0), @@ -222,7 +222,7 @@ static void smssdio_interrupt(struct sdio_func *func) smscore_onresponse(smsdev->coredev, cb); } -static int smssdio_probe(struct sdio_func *func, +static int __devinit smssdio_probe(struct sdio_func *func, const struct sdio_device_id *id) { int ret; @@ -338,7 +338,7 @@ static struct sdio_driver smssdio_driver = { /* Module functions */ /*******************************************************************/ -int smssdio_module_init(void) +static int __init smssdio_module_init(void) { int ret = 0; @@ -350,7 +350,7 @@ int smssdio_module_init(void) return ret; } -void smssdio_module_exit(void) +static void __exit smssdio_module_exit(void) { sdio_unregister_driver(&smssdio_driver); } diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c index 8f88a586b0d..5eac27287d9 100644 --- a/drivers/media/dvb/siano/smsusb.c +++ b/drivers/media/dvb/siano/smsusb.c @@ -390,7 +390,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) return rc; } -static int smsusb_probe(struct usb_interface *intf, +static int __devinit smsusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(intf); @@ -484,7 +484,7 @@ static int smsusb_resume(struct usb_interface *intf) return 0; } -struct usb_device_id smsusb_id_table[] = { +static const struct usb_device_id smsusb_id_table[] __devinitconst = { { USB_DEVICE(0x187f, 0x0010), .driver_info = SMS1XXX_BOARD_SIANO_STELLAR }, { USB_DEVICE(0x187f, 0x0100), @@ -533,8 +533,18 @@ struct usb_device_id smsusb_id_table[] = { .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { USB_DEVICE(0x2040, 0xb910), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xb980), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xb990), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { USB_DEVICE(0x2040, 0xc000), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xc010), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xc080), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xc090), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { } /* Terminating entry */ }; @@ -550,7 +560,7 @@ static struct usb_driver smsusb_driver = { .resume = smsusb_resume, }; -int smsusb_module_init(void) +static int __init smsusb_module_init(void) { int rc = usb_register(&smsusb_driver); if (rc) @@ -561,7 +571,7 @@ int smsusb_module_init(void) return rc; } -void smsusb_module_exit(void) +static void __exit smsusb_module_exit(void) { /* Regular USB Cleanup */ usb_deregister(&smsusb_driver); diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 7d193ebc0ae..9782e059373 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -190,12 +190,13 @@ static int msp430_ir_init(struct budget_ci *budget_ci) struct saa7146_dev *saa = budget_ci->budget.dev; struct input_dev *input_dev = budget_ci->ir.dev; int error; + struct ir_scancode_table *ir_codes; + budget_ci->ir.dev = input_dev = input_allocate_device(); if (!input_dev) { printk(KERN_ERR "budget_ci: IR interface initialisation failed\n"); - error = -ENOMEM; - goto out1; + return -ENOMEM; } snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name), @@ -217,6 +218,11 @@ static int msp430_ir_init(struct budget_ci *budget_ci) } input_dev->dev.parent = &saa->pci->dev; + if (rc5_device < 0) + budget_ci->ir.rc5_device = IR_DEVICE_ANY; + else + budget_ci->ir.rc5_device = rc5_device; + /* Select keymap and address */ switch (budget_ci->budget.dev->pci->subsystem_device) { case 0x100c: @@ -224,53 +230,34 @@ static int msp430_ir_init(struct budget_ci *budget_ci) case 0x1011: case 0x1012: /* The hauppauge keymap is a superset of these remotes */ - error = ir_input_init(input_dev, &budget_ci->ir.state, - IR_TYPE_RC5, &ir_codes_hauppauge_new_table); - if (error < 0) - goto out2; + ir_codes = &ir_codes_hauppauge_new_table; if (rc5_device < 0) budget_ci->ir.rc5_device = 0x1f; - else - budget_ci->ir.rc5_device = rc5_device; break; case 0x1010: case 0x1017: case 0x101a: /* for the Technotrend 1500 bundled remote */ - error = ir_input_init(input_dev, &budget_ci->ir.state, - IR_TYPE_RC5, &ir_codes_tt_1500_table); - if (error < 0) - goto out2; - - if (rc5_device < 0) - budget_ci->ir.rc5_device = IR_DEVICE_ANY; - else - budget_ci->ir.rc5_device = rc5_device; + ir_codes = &ir_codes_tt_1500_table; break; default: /* unknown remote */ - error = ir_input_init(input_dev, &budget_ci->ir.state, - IR_TYPE_RC5, &ir_codes_budget_ci_old_table); - if (error < 0) - goto out2; - - if (rc5_device < 0) - budget_ci->ir.rc5_device = IR_DEVICE_ANY; - else - budget_ci->ir.rc5_device = rc5_device; + ir_codes = &ir_codes_budget_ci_old_table; break; } + ir_input_init(input_dev, &budget_ci->ir.state, IR_TYPE_RC5); + /* initialise the key-up timeout handler */ init_timer(&budget_ci->ir.timer_keyup); budget_ci->ir.timer_keyup.function = msp430_ir_keyup; budget_ci->ir.timer_keyup.data = (unsigned long) &budget_ci->ir; budget_ci->ir.last_raw = 0xffff; /* An impossible value */ - error = input_register_device(input_dev); + error = ir_input_register(input_dev, ir_codes); if (error) { printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error); - goto out2; + return error; } /* note: these must be after input_register_device */ @@ -284,12 +271,6 @@ static int msp430_ir_init(struct budget_ci *budget_ci) saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI); return 0; - -out2: - ir_input_free(input_dev); - input_free_device(input_dev); -out1: - return error; } static void msp430_ir_deinit(struct budget_ci *budget_ci) @@ -304,8 +285,7 @@ static void msp430_ir_deinit(struct budget_ci *budget_ci) del_timer_sync(&dev->timer); ir_input_nokey(dev, &budget_ci->ir.state); - ir_input_free(dev); - input_unregister_device(dev); + ir_input_unregister(dev); } static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) |