|
@@ -1431,13 +1431,22 @@ static int dib8090_get_adc_power(struct dvb_frontend *fe)
|
|
|
return dib8000_get_adc_power(fe, 1);
|
|
|
}
|
|
|
|
|
|
+static void dib8090_agc_control(struct dvb_frontend *fe, u8 restart)
|
|
|
+{
|
|
|
+ deb_info("AGC control callback: %i\n", restart);
|
|
|
+ dib0090_dcc_freq(fe, restart);
|
|
|
+
|
|
|
+ if (restart == 0) /* before AGC startup */
|
|
|
+ dib0090_set_dc_servo(fe, 1);
|
|
|
+}
|
|
|
+
|
|
|
static struct dib8000_config dib809x_dib8000_config[2] = {
|
|
|
{
|
|
|
.output_mpeg2_in_188_bytes = 1,
|
|
|
|
|
|
.agc_config_count = 2,
|
|
|
.agc = dib8090_agc_config,
|
|
|
- .agc_control = dib0090_dcc_freq,
|
|
|
+ .agc_control = dib8090_agc_control,
|
|
|
.pll = &dib8090_pll_config_12mhz,
|
|
|
.tuner_is_baseband = 1,
|
|
|
|
|
@@ -1456,7 +1465,7 @@ static struct dib8000_config dib809x_dib8000_config[2] = {
|
|
|
|
|
|
.agc_config_count = 2,
|
|
|
.agc = dib8090_agc_config,
|
|
|
- .agc_control = dib0090_dcc_freq,
|
|
|
+ .agc_control = dib8090_agc_control,
|
|
|
.pll = &dib8090_pll_config_12mhz,
|
|
|
.tuner_is_baseband = 1,
|
|
|
|
|
@@ -1504,28 +1513,89 @@ static struct dib0090_config dib809x_dib0090_config = {
|
|
|
.fref_clock_ratio = 6,
|
|
|
};
|
|
|
|
|
|
+static u8 dib8090_compute_pll_parameters(struct dvb_frontend *fe)
|
|
|
+{
|
|
|
+ u8 optimal_pll_ratio = 20;
|
|
|
+ u32 freq_adc, ratio, rest, max = 0;
|
|
|
+ u8 pll_ratio;
|
|
|
+
|
|
|
+ for (pll_ratio = 17; pll_ratio <= 20; pll_ratio++) {
|
|
|
+ freq_adc = 12 * pll_ratio * (1 << 8) / 16;
|
|
|
+ ratio = ((fe->dtv_property_cache.frequency / 1000) * (1 << 8) / 1000) / freq_adc;
|
|
|
+ rest = ((fe->dtv_property_cache.frequency / 1000) * (1 << 8) / 1000) - ratio * freq_adc;
|
|
|
+
|
|
|
+ if (rest > freq_adc / 2)
|
|
|
+ rest = freq_adc - rest;
|
|
|
+ deb_info("PLL ratio=%i rest=%i\n", pll_ratio, rest);
|
|
|
+ if ((rest > max) && (rest > 717)) {
|
|
|
+ optimal_pll_ratio = pll_ratio;
|
|
|
+ max = rest;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ deb_info("optimal PLL ratio=%i\n", optimal_pll_ratio);
|
|
|
+
|
|
|
+ return optimal_pll_ratio;
|
|
|
+}
|
|
|
+
|
|
|
static int dib8096_set_param_override(struct dvb_frontend *fe)
|
|
|
{
|
|
|
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
|
|
struct dvb_usb_adapter *adap = fe->dvb->priv;
|
|
|
struct dib0700_adapter_state *state = adap->priv;
|
|
|
- u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
|
|
|
- u16 target;
|
|
|
+ u8 pll_ratio, band = BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000);
|
|
|
+ u16 target, ltgain, rf_gain_limit;
|
|
|
+ u32 timf;
|
|
|
int ret = 0;
|
|
|
enum frontend_tune_state tune_state = CT_SHUTDOWN;
|
|
|
- u16 ltgain, rf_gain_limit;
|
|
|
+
|
|
|
+ switch (band) {
|
|
|
+ default:
|
|
|
+ deb_info("Warning : Rf frequency (%iHz) is not in the supported range, using VHF switch ", fe->dtv_property_cache.frequency);
|
|
|
+ case BAND_VHF:
|
|
|
+ dib8000_set_gpio(fe, 3, 0, 1);
|
|
|
+ break;
|
|
|
+ case BAND_UHF:
|
|
|
+ dib8000_set_gpio(fe, 3, 0, 0);
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
ret = state->set_param_save(fe);
|
|
|
if (ret < 0)
|
|
|
return ret;
|
|
|
|
|
|
- target = (dib0090_get_wbd_target(fe) * 8 * 18 / 33 + 1) / 2;
|
|
|
- dib8000_set_wbd_ref(fe, target);
|
|
|
+ if (fe->dtv_property_cache.bandwidth_hz != 6000000) {
|
|
|
+ deb_info("only 6MHz bandwidth is supported\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
|
|
|
+ /** Update PLL if needed ratio **/
|
|
|
+ dib8000_update_pll(fe, &dib8090_pll_config_12mhz, fe->dtv_property_cache.bandwidth_hz / 1000, 0);
|
|
|
+
|
|
|
+ /** Get optimize PLL ratio to remove spurious **/
|
|
|
+ pll_ratio = dib8090_compute_pll_parameters(fe);
|
|
|
+ if (pll_ratio == 17)
|
|
|
+ timf = 21387946;
|
|
|
+ else if (pll_ratio == 18)
|
|
|
+ timf = 20199727;
|
|
|
+ else if (pll_ratio == 19)
|
|
|
+ timf = 19136583;
|
|
|
+ else
|
|
|
+ timf = 18179756;
|
|
|
+
|
|
|
+ /** Update ratio **/
|
|
|
+ dib8000_update_pll(fe, &dib8090_pll_config_12mhz, fe->dtv_property_cache.bandwidth_hz / 1000, pll_ratio);
|
|
|
+
|
|
|
+ dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, timf);
|
|
|
+
|
|
|
+ if (band != BAND_CBAND) {
|
|
|
+ /* dib0090_get_wbd_target is returning any possible temperature compensated wbd-target */
|
|
|
+ target = (dib0090_get_wbd_target(fe) * 8 * 18 / 33 + 1) / 2;
|
|
|
+ dib8000_set_wbd_ref(fe, target);
|
|
|
+ }
|
|
|
|
|
|
if (band == BAND_CBAND) {
|
|
|
deb_info("tuning in CBAND - soft-AGC startup\n");
|
|
|
dib0090_set_tune_state(fe, CT_AGC_START);
|
|
|
+
|
|
|
do {
|
|
|
ret = dib0090_gain_control(fe);
|
|
|
msleep(ret);
|
|
@@ -1534,14 +1604,17 @@ static int dib8096_set_param_override(struct dvb_frontend *fe)
|
|
|
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)
|
|
|
+ if (rf_gain_limit < 2000) /* activate the external attenuator in case of very high input power */
|
|
|
dib8000_set_gpio(fe, 6, 0, 0);
|
|
|
}
|
|
|
} while (tune_state < CT_AGC_STOP);
|
|
|
+
|
|
|
+ deb_info("switching to PWM AGC\n");
|
|
|
dib0090_pwm_gain_reset(fe);
|
|
|
dib8000_pwm_agc_reset(fe);
|
|
|
dib8000_set_tune_state(fe, CT_DEMOD_START);
|
|
|
} else {
|
|
|
+ /* for everything else than CBAND we are using standard AGC */
|
|
|
deb_info("not tuning in CBAND - standard AGC startup\n");
|
|
|
dib0090_pwm_gain_reset(fe);
|
|
|
}
|
|
@@ -1814,21 +1887,92 @@ struct dibx090p_adc {
|
|
|
u32 pll_prediv; /* New loopdiv */
|
|
|
};
|
|
|
|
|
|
-struct dibx090p_adc dib8090p_adc_tab[] = {
|
|
|
- { 50000, 17043521, 16, 3}, /* 64 MHz */
|
|
|
- {878000, 20199729, 9, 1}, /* 60 MHz */
|
|
|
- {0xffffffff, 0, 0, 0}, /* 60 MHz */
|
|
|
+struct dibx090p_best_adc {
|
|
|
+ u32 timf;
|
|
|
+ u32 pll_loopdiv;
|
|
|
+ u32 pll_prediv;
|
|
|
};
|
|
|
|
|
|
+static int dib8096p_get_best_sampling(struct dvb_frontend *fe, struct dibx090p_best_adc *adc)
|
|
|
+{
|
|
|
+ u8 spur = 0, prediv = 0, loopdiv = 0, min_prediv = 1, max_prediv = 1;
|
|
|
+ u16 xtal = 12000;
|
|
|
+ u16 fcp_min = 1900; /* PLL, Minimum Frequency of phase comparator (KHz) */
|
|
|
+ u16 fcp_max = 20000; /* PLL, Maximum Frequency of phase comparator (KHz) */
|
|
|
+ u32 fmem_max = 140000; /* 140MHz max SDRAM freq */
|
|
|
+ u32 fdem_min = 66000;
|
|
|
+ u32 fcp = 0, fs = 0, fdem = 0, fmem = 0;
|
|
|
+ u32 harmonic_id = 0;
|
|
|
+
|
|
|
+ adc->timf = 0;
|
|
|
+ adc->pll_loopdiv = loopdiv;
|
|
|
+ adc->pll_prediv = prediv;
|
|
|
+
|
|
|
+ deb_info("bandwidth = %d", fe->dtv_property_cache.bandwidth_hz);
|
|
|
+
|
|
|
+ /* Find Min and Max prediv */
|
|
|
+ while ((xtal / max_prediv) >= fcp_min)
|
|
|
+ max_prediv++;
|
|
|
+
|
|
|
+ max_prediv--;
|
|
|
+ min_prediv = max_prediv;
|
|
|
+ while ((xtal / min_prediv) <= fcp_max) {
|
|
|
+ min_prediv--;
|
|
|
+ if (min_prediv == 1)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ deb_info("MIN prediv = %d : MAX prediv = %d", min_prediv, max_prediv);
|
|
|
+
|
|
|
+ min_prediv = 1;
|
|
|
+
|
|
|
+ for (prediv = min_prediv; prediv < max_prediv; prediv++) {
|
|
|
+ fcp = xtal / prediv;
|
|
|
+ if (fcp > fcp_min && fcp < fcp_max) {
|
|
|
+ for (loopdiv = 1; loopdiv < 64; loopdiv++) {
|
|
|
+ fmem = ((xtal/prediv) * loopdiv);
|
|
|
+ fdem = fmem / 2;
|
|
|
+ fs = fdem / 4;
|
|
|
+
|
|
|
+ /* test min/max system restrictions */
|
|
|
+ if ((fdem >= fdem_min) && (fmem <= fmem_max) && (fs >= fe->dtv_property_cache.bandwidth_hz / 1000)) {
|
|
|
+ spur = 0;
|
|
|
+ /* test fs harmonics positions */
|
|
|
+ for (harmonic_id = (fe->dtv_property_cache.frequency / (1000 * fs)); harmonic_id <= ((fe->dtv_property_cache.frequency / (1000 * fs)) + 1); harmonic_id++) {
|
|
|
+ if (((fs * harmonic_id) >= (fe->dtv_property_cache.frequency / 1000 - (fe->dtv_property_cache.bandwidth_hz / 2000))) && ((fs * harmonic_id) <= (fe->dtv_property_cache.frequency / 1000 + (fe->dtv_property_cache.bandwidth_hz / 2000)))) {
|
|
|
+ spur = 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!spur) {
|
|
|
+ adc->pll_loopdiv = loopdiv;
|
|
|
+ adc->pll_prediv = prediv;
|
|
|
+ adc->timf = (4260880253U / fdem) * (1 << 8);
|
|
|
+ adc->timf += ((4260880253U % fdem) << 8) / fdem;
|
|
|
+
|
|
|
+ deb_info("RF %6d; BW %6d; Xtal %6d; Fmem %6d; Fdem %6d; Fs %6d; Prediv %2d; Loopdiv %2d; Timf %8d;", fe->dtv_property_cache.frequency, fe->dtv_property_cache.bandwidth_hz, xtal, fmem, fdem, fs, prediv, loopdiv, adc->timf);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!spur)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (adc->pll_loopdiv == 0 && adc->pll_prediv == 0)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int dib8096p_agc_startup(struct dvb_frontend *fe)
|
|
|
{
|
|
|
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
|
|
struct dvb_usb_adapter *adap = fe->dvb->priv;
|
|
|
struct dib0700_adapter_state *state = adap->priv;
|
|
|
struct dibx000_bandwidth_config pll;
|
|
|
+ struct dibx090p_best_adc adc;
|
|
|
u16 target;
|
|
|
- int better_sampling_freq = 0, ret;
|
|
|
- struct dibx090p_adc *adc_table = &dib8090p_adc_tab[0];
|
|
|
+ int ret;
|
|
|
|
|
|
ret = state->set_param_save(fe);
|
|
|
if (ret < 0)
|
|
@@ -1841,23 +1985,27 @@ static int dib8096p_agc_startup(struct dvb_frontend *fe)
|
|
|
target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2;
|
|
|
dib8000_set_wbd_ref(fe, target);
|
|
|
|
|
|
+ if (dib8096p_get_best_sampling(fe, &adc) == 0) {
|
|
|
+ pll.pll_ratio = adc.pll_loopdiv;
|
|
|
+ pll.pll_prediv = adc.pll_prediv;
|
|
|
|
|
|
- while (p->frequency / 1000 > adc_table->freq) {
|
|
|
- better_sampling_freq = 1;
|
|
|
- adc_table++;
|
|
|
- }
|
|
|
-
|
|
|
- if ((adc_table->freq != 0xffffffff) && better_sampling_freq) {
|
|
|
- pll.pll_ratio = adc_table->pll_loopdiv;
|
|
|
- pll.pll_prediv = adc_table->pll_prediv;
|
|
|
+ dib0700_set_i2c_speed(adap->dev, 200);
|
|
|
dib8000_update_pll(fe, &pll, fe->dtv_property_cache.bandwidth_hz / 1000, 0);
|
|
|
- dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, adc_table->timf);
|
|
|
+ dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf);
|
|
|
+ dib0700_set_i2c_speed(adap->dev, 1000);
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static int tfe8096p_frontend_attach(struct dvb_usb_adapter *adap)
|
|
|
{
|
|
|
+ struct dib0700_state *st = adap->dev->priv;
|
|
|
+ u32 fw_version;
|
|
|
+
|
|
|
+ dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL);
|
|
|
+ if (fw_version >= 0x10200)
|
|
|
+ st->fw_use_new_i2c_api = 1;
|
|
|
+
|
|
|
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
|
|
|
msleep(20);
|
|
|
dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
|
|
@@ -2242,13 +2390,7 @@ static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap)
|
|
|
}
|
|
|
|
|
|
/* NIM7090 */
|
|
|
-struct dib7090p_best_adc {
|
|
|
- u32 timf;
|
|
|
- u32 pll_loopdiv;
|
|
|
- u32 pll_prediv;
|
|
|
-};
|
|
|
-
|
|
|
-static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dib7090p_best_adc *adc)
|
|
|
+static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dibx090p_best_adc *adc)
|
|
|
{
|
|
|
u8 spur = 0, prediv = 0, loopdiv = 0, min_prediv = 1, max_prediv = 1;
|
|
|
|
|
@@ -2327,7 +2469,7 @@ static int dib7090_agc_startup(struct dvb_frontend *fe)
|
|
|
struct dib0700_adapter_state *state = adap->priv;
|
|
|
struct dibx000_bandwidth_config pll;
|
|
|
u16 target;
|
|
|
- struct dib7090p_best_adc adc;
|
|
|
+ struct dibx090p_best_adc adc;
|
|
|
int ret;
|
|
|
|
|
|
ret = state->set_param_save(fe);
|