mirror of https://gitee.com/openkylin/linux.git
V4L/DVB (13583): DiB8090: Add the DiB0090 tuner driver and STK8096GP-board
This patchs adds support for the DiBcom DiB0090 RF tuner and for DiBcom's reference design STK8096GP. Small extracts of the DiB0070 and the DiB8000-driver into a common codebase. Signed-off-by: Patrick Boettcher <pboettcher@kernellabs.com> Signed-off-by: Olivier Grenie <Olivier.Grenie@dibcom.fr> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
20232c4791
commit
03245a5ee6
|
@ -18,6 +18,7 @@
|
|||
#include "xc5000.h"
|
||||
#include "s5h1411.h"
|
||||
#include "dib0070.h"
|
||||
#include "dib0090.h"
|
||||
#include "lgdt3305.h"
|
||||
#include "mxl5007t.h"
|
||||
|
||||
|
@ -605,17 +606,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 +633,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 +642,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;
|
||||
}
|
||||
|
@ -1476,12 +1477,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 +1495,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 +1509,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 +1567,12 @@ 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);
|
||||
}
|
||||
|
@ -1643,6 +1644,246 @@ 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), // setup
|
||||
|
||||
787,// inv_gain = 1/ 90.4dB // no boost, lower gain due to ramp quantification
|
||||
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
|
||||
32, // agc1_pt2
|
||||
114, // agc1_pt3 // 40.4dB
|
||||
143, // agc1_slope1
|
||||
144, // agc1_slope2
|
||||
114, // agc2_pt1
|
||||
227, // agc2_pt2
|
||||
116, // agc2_slope1
|
||||
117, // agc2_slope2
|
||||
|
||||
28, // alpha_mant // 5Hz with 90.2dB
|
||||
26, // alpha_exp
|
||||
31, // beta_mant
|
||||
51, // beta_exp
|
||||
|
||||
0, // perform_agc_softsplit
|
||||
},
|
||||
{
|
||||
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), // setup
|
||||
|
||||
787,// inv_gain = 1/ 90.4dB // no boost, lower gain due to ramp quantification
|
||||
10, // time_stabiliz
|
||||
|
||||
0, // alpha_level
|
||||
118, // thlock
|
||||
|
||||
0, // wbd_inv
|
||||
3530, // wbd_ref
|
||||
1, // wbd_sel
|
||||
5, // wbd_alpha
|
||||
|
||||
0, // agc1_max
|
||||
0, // agc1_min
|
||||
|
||||
65535, // agc2_max
|
||||
0, // agc2_min
|
||||
|
||||
0, // agc1_pt1
|
||||
32, // agc1_pt2
|
||||
114, // agc1_pt3 // 40.4dB
|
||||
143, // agc1_slope1
|
||||
144, // agc1_slope2
|
||||
114, // agc2_pt1
|
||||
227, // agc2_pt2
|
||||
116, // agc2_slope1
|
||||
117, // agc2_slope2
|
||||
|
||||
28, // alpha_mant // 5Hz with 90.2dB
|
||||
26, // alpha_exp
|
||||
31, // beta_mant
|
||||
51, // beta_exp
|
||||
|
||||
0, // perform_agc_softsplit
|
||||
}
|
||||
};
|
||||
|
||||
static struct dibx000_bandwidth_config dib8090_pll_config_12mhz = {
|
||||
54000, 13500, // internal, sampling
|
||||
1, 18, 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) | (599 << 0), // sad_cfg: refsel, sel, freq_15k
|
||||
(0 << 25) | 0, // ifreq = 0 MHz
|
||||
20199727, // timf
|
||||
12000000, // xtal_hz
|
||||
};
|
||||
|
||||
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] = {
|
||||
|
@ -1939,6 +2180,7 @@ struct usb_device_id dib0700_usb_id_table[] = {
|
|||
{ 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);
|
||||
|
@ -2473,8 +2715,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,
|
||||
|
||||
|
@ -2512,8 +2754,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,
|
||||
|
||||
|
@ -2525,8 +2767,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,
|
||||
|
||||
|
@ -2545,6 +2787,37 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
},
|
||||
},
|
||||
|
||||
.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
|
||||
}, { 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),
|
||||
|
|
|
@ -102,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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
/* 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 & 0xfffc);
|
||||
tmp = dib0070_read_reg(state, 0x01) & 0x01ff;
|
||||
dib0070_write_reg(state, 0x01, tmp | (60 << 9));
|
||||
|
||||
dib0070_write_reg(state, 0x17, value);
|
||||
}
|
||||
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;
|
||||
|
@ -189,10 +174,12 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state
|
|||
}
|
||||
|
||||
if (adc < state->adc_diff) {
|
||||
dprintk("CAPTRIM=%hd is closer to target (%hd/%hd)", state->captrim, adc, state->adc_diff);
|
||||
dprintk( "CAPTRIM=%hd is closer to target (%hd/%hd)", state->captrim, adc, state->adc_diff);
|
||||
state->adc_diff = adc;
|
||||
state->fcaptrim = state->captrim;
|
||||
|
||||
|
||||
|
||||
}
|
||||
state->captrim += (step_sign * state->step);
|
||||
|
||||
|
@ -213,8 +200,8 @@ 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);
|
||||
dprintk("CTRL_LO5: 0x%x", lo5);
|
||||
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,171 +214,175 @@ 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 // define for the loop filter 100kHz by default 16-07-06
|
||||
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)
|
||||
&& (state->fe->dtv_property_cache.isdbt_sb_segment_idx == (state->fe->dtv_property_cache.isdbt_sb_segment_count / 2)))
|
||||
|| (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
|
||||
&& (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))))
|
||||
freq += 850;
|
||||
freq += 850;
|
||||
#endif
|
||||
if (state->current_rf != freq) {
|
||||
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;
|
||||
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++;
|
||||
|
||||
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_tune_table_index = tune;
|
||||
state->lna_match = lna_match;
|
||||
}
|
||||
|
||||
state->current_rf = freq;
|
||||
state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7);
|
||||
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;
|
||||
|
||||
dib0070_write_reg(state, 0x17, 0x30);
|
||||
state->current_rf = freq;
|
||||
state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7);
|
||||
|
||||
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;
|
||||
dib0070_write_reg(state, 0x17, 0x30);
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
@ -402,98 +393,102 @@ static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_par
|
|||
FBDiv += 1;
|
||||
} else if (Rest > (FREF - 2 * LPF))
|
||||
Rest = FREF - 2 * LPF;
|
||||
Rest = (Rest * 6528) / (FREF / 10);
|
||||
Rest = (Rest * 6528) / (FREF / 10);
|
||||
|
||||
Den = 1;
|
||||
if (Rest > 0) {
|
||||
state->lo4 |= (1 << 14) | (1 << 12);
|
||||
Den = 255;
|
||||
}
|
||||
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) {
|
||||
dib0070_write_reg(state, 0x11, (u16)FBDiv);
|
||||
dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV);
|
||||
dib0070_write_reg(state, 0x13, (u16) Rest);
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
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)) {
|
||||
*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);
|
||||
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++;
|
||||
} 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 {
|
||||
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,111 @@ 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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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,13 +619,13 @@ 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);
|
||||
dprintk( "Revision: %x", state->revision);
|
||||
|
||||
if (state->revision == DIB0070_P1D) {
|
||||
dprintk("Error: this driver is not to be used meant for P1D or earlier");
|
||||
dprintk( "Error: this driver is not to be used meant for P1D or earlier");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -620,7 +634,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 +647,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 +658,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,22 +687,22 @@ 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,
|
||||
.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,
|
||||
.init = dib0070_wakeup,
|
||||
.sleep = dib0070_sleep,
|
||||
.set_params = dib0070_tune,
|
||||
|
||||
// .get_frequency = dib0070_get_frequency,
|
||||
.get_frequency = dib0070_get_frequency,
|
||||
// .get_bandwidth = dib0070_get_bandwidth
|
||||
};
|
||||
|
||||
struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
|
||||
struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
|
||||
{
|
||||
struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
|
@ -687,7 +710,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 +722,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>");
|
||||
|
|
|
@ -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)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* 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; // internal loop filt value. If not fill in , default is 8165
|
||||
};
|
||||
|
||||
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 enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe);
|
||||
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 num frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return CT_SHUTDOWN,}
|
||||
|
||||
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
|
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -1854,6 +1876,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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue