mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-01-22 08:53:18 +07:00
[media] r820t: add IMR calibrate code
This code seems to calibrate I/Q phase and gain during the device initialization. This is done only once, and it doesn't seem to be needed to happen after resuming. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> Tested-by: Antti Palosaari <crope@iki.fi>
This commit is contained in:
parent
d75d538899
commit
25cf4d462a
@ -47,6 +47,8 @@
|
||||
*/
|
||||
#define REG_SHADOW_START 5
|
||||
#define NUM_REGS 27
|
||||
#define NUM_IMR 5
|
||||
#define IMR_TRIAL 9
|
||||
|
||||
#define VER_NUM 49
|
||||
|
||||
@ -66,6 +68,12 @@ enum xtal_cap_value {
|
||||
XTAL_HIGH_CAP_0P
|
||||
};
|
||||
|
||||
struct r820t_sect_type {
|
||||
u8 phase_y;
|
||||
u8 gain_x;
|
||||
u16 value;
|
||||
};
|
||||
|
||||
struct r820t_priv {
|
||||
struct list_head hybrid_tuner_instance_list;
|
||||
const struct r820t_config *cfg;
|
||||
@ -80,6 +88,8 @@ struct r820t_priv {
|
||||
u8 fil_cal_code;
|
||||
bool imr_done;
|
||||
|
||||
struct r820t_sect_type imr_data[NUM_IMR];
|
||||
|
||||
/* Store current mode */
|
||||
u32 delsys;
|
||||
enum v4l2_tuner_type type;
|
||||
@ -459,7 +469,7 @@ static int r820t_set_mux(struct r820t_priv *priv, u32 freq)
|
||||
{
|
||||
const struct r820t_freq_range *range;
|
||||
int i, rc;
|
||||
u8 val;
|
||||
u8 val, reg08, reg09;
|
||||
|
||||
/* Get the proper frequency range */
|
||||
freq = freq / 1000000;
|
||||
@ -507,17 +517,18 @@ static int r820t_set_mux(struct r820t_priv *priv, u32 freq)
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* FIXME: the original driver has a logic there with preserves
|
||||
* gain/phase from registers 8 and 9 reading the data from the
|
||||
* registers before writing, if "IMF done". That code was sort of
|
||||
* commented there, as the flag is always false.
|
||||
*/
|
||||
rc = r820t_write_reg_mask(priv, 0x08, 0, 0x3f);
|
||||
if (priv->imr_done) {
|
||||
reg08 = priv->imr_data[range->imr_mem].gain_x;
|
||||
reg09 = priv->imr_data[range->imr_mem].phase_y;
|
||||
} else {
|
||||
reg08 = 0;
|
||||
reg09 = 0;
|
||||
}
|
||||
rc = r820t_write_reg_mask(priv, 0x08, reg08, 0x3f);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = r820t_write_reg_mask(priv, 0x09, 0, 0x3f);
|
||||
rc = r820t_write_reg_mask(priv, 0x09, reg09, 0x3f);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -1383,6 +1394,667 @@ static int r820t_xtal_check(struct r820t_priv *priv)
|
||||
return r820t_xtal_capacitor[i][1];
|
||||
}
|
||||
|
||||
static int r820t_imr_prepare(struct r820t_priv *priv)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Initialize the shadow registers */
|
||||
memcpy(priv->regs, r820t_init_array, sizeof(r820t_init_array));
|
||||
|
||||
/* lna off (air-in off) */
|
||||
rc = r820t_write_reg_mask(priv, 0x05, 0x20, 0x20);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* mixer gain mode = manual */
|
||||
rc = r820t_write_reg_mask(priv, 0x07, 0, 0x10);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* filter corner = lowest */
|
||||
rc = r820t_write_reg_mask(priv, 0x0a, 0x0f, 0x0f);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* filter bw=+2cap, hp=5M */
|
||||
rc = r820t_write_reg_mask(priv, 0x0b, 0x60, 0x6f);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* adc=on, vga code mode, gain = 26.5dB */
|
||||
rc = r820t_write_reg_mask(priv, 0x0c, 0x0b, 0x9f);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* ring clk = on */
|
||||
rc = r820t_write_reg_mask(priv, 0x0f, 0, 0x08);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* ring power = on */
|
||||
rc = r820t_write_reg_mask(priv, 0x18, 0x10, 0x10);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* from ring = ring pll in */
|
||||
rc = r820t_write_reg_mask(priv, 0x1c, 0x02, 0x02);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* sw_pdect = det3 */
|
||||
rc = r820t_write_reg_mask(priv, 0x1e, 0x80, 0x80);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Set filt_3dB */
|
||||
rc = r820t_write_reg_mask(priv, 0x06, 0x20, 0x20);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int r820t_multi_read(struct r820t_priv *priv)
|
||||
{
|
||||
int rc, i;
|
||||
u8 data[2], min = 0, max = 255, sum = 0;
|
||||
|
||||
usleep_range(5000, 6000);
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
rc = r820t_read(priv, 0x00, data, sizeof(data));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
sum += data[1];
|
||||
|
||||
if (data[1] < min)
|
||||
min = data[1];
|
||||
|
||||
if (data[1] > max)
|
||||
max = data[1];
|
||||
}
|
||||
rc = sum - max - min;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int r820t_imr_cross(struct r820t_priv *priv,
|
||||
struct r820t_sect_type iq_point[3],
|
||||
u8 *x_direct)
|
||||
{
|
||||
struct r820t_sect_type cross[5]; /* (0,0)(0,Q-1)(0,I-1)(Q-1,0)(I-1,0) */
|
||||
struct r820t_sect_type tmp;
|
||||
int i, rc;
|
||||
u8 reg08, reg09;
|
||||
|
||||
reg08 = r820t_read_cache_reg(priv, 8) & 0xc0;
|
||||
reg09 = r820t_read_cache_reg(priv, 9) & 0xc0;
|
||||
|
||||
tmp.gain_x = 0;
|
||||
tmp.phase_y = 0;
|
||||
tmp.value = 255;
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
cross[i].gain_x = reg08;
|
||||
cross[i].phase_y = reg09;
|
||||
break;
|
||||
case 1:
|
||||
cross[i].gain_x = reg08; /* 0 */
|
||||
cross[i].phase_y = reg09 + 1; /* Q-1 */
|
||||
break;
|
||||
case 2:
|
||||
cross[i].gain_x = reg08; /* 0 */
|
||||
cross[i].phase_y = (reg09 | 0x20) + 1; /* I-1 */
|
||||
break;
|
||||
case 3:
|
||||
cross[i].gain_x = reg08 + 1; /* Q-1 */
|
||||
cross[i].phase_y = reg09;
|
||||
break;
|
||||
default:
|
||||
cross[i].gain_x = (reg08 | 0x20) + 1; /* I-1 */
|
||||
cross[i].phase_y = reg09;
|
||||
}
|
||||
|
||||
rc = r820t_write_reg(priv, 0x08, cross[i].gain_x);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = r820t_write_reg(priv, 0x09, cross[i].phase_y);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = r820t_multi_read(priv);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
cross[i].value = rc;
|
||||
|
||||
if (cross[i].value < tmp.value)
|
||||
memcpy(&tmp, &cross[i], sizeof(tmp));
|
||||
}
|
||||
|
||||
if ((tmp.phase_y & 0x1f) == 1) { /* y-direction */
|
||||
*x_direct = 0;
|
||||
|
||||
iq_point[0] = cross[0];
|
||||
iq_point[1] = cross[1];
|
||||
iq_point[2] = cross[2];
|
||||
} else { /* (0,0) or x-direction */
|
||||
*x_direct = 1;
|
||||
|
||||
iq_point[0] = cross[0];
|
||||
iq_point[1] = cross[3];
|
||||
iq_point[2] = cross[4];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void r820t_compre_cor(struct r820t_sect_type iq[3])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 3; i > 0; i--) {
|
||||
if (iq[0].value > iq[i - 1].value)
|
||||
swap(iq[0], iq[i - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
static int r820t_compre_step(struct r820t_priv *priv,
|
||||
struct r820t_sect_type iq[3], u8 reg)
|
||||
{
|
||||
int rc;
|
||||
struct r820t_sect_type tmp;
|
||||
|
||||
/*
|
||||
* Purpose: if (Gain<9 or Phase<9), Gain+1 or Phase+1 and compare
|
||||
* with min value:
|
||||
* new < min => update to min and continue
|
||||
* new > min => Exit
|
||||
*/
|
||||
|
||||
/* min value already saved in iq[0] */
|
||||
tmp.phase_y = iq[0].phase_y;
|
||||
tmp.gain_x = iq[0].gain_x;
|
||||
|
||||
while (((tmp.gain_x & 0x1f) < IMR_TRIAL) &&
|
||||
((tmp.phase_y & 0x1f) < IMR_TRIAL)) {
|
||||
if (reg == 0x08)
|
||||
tmp.gain_x++;
|
||||
else
|
||||
tmp.phase_y++;
|
||||
|
||||
rc = r820t_write_reg(priv, 0x08, tmp.gain_x);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = r820t_write_reg(priv, 0x09, tmp.phase_y);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = r820t_multi_read(priv);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
tmp.value = rc;
|
||||
|
||||
if (tmp.value <= iq[0].value) {
|
||||
iq[0].gain_x = tmp.gain_x;
|
||||
iq[0].phase_y = tmp.phase_y;
|
||||
iq[0].value = tmp.value;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int r820t_iq_tree(struct r820t_priv *priv,
|
||||
struct r820t_sect_type iq[3],
|
||||
u8 fix_val, u8 var_val, u8 fix_reg)
|
||||
{
|
||||
int rc, i;
|
||||
u8 tmp, var_reg;
|
||||
|
||||
/*
|
||||
* record IMC results by input gain/phase location then adjust
|
||||
* gain or phase positive 1 step and negtive 1 step,
|
||||
* both record results
|
||||
*/
|
||||
|
||||
if (fix_reg == 0x08)
|
||||
var_reg = 0x09;
|
||||
else
|
||||
var_reg = 0x08;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
rc = r820t_write_reg(priv, fix_reg, fix_val);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = r820t_write_reg(priv, var_reg, var_val);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = r820t_multi_read(priv);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
iq[i].value = rc;
|
||||
|
||||
if (fix_reg == 0x08) {
|
||||
iq[i].gain_x = fix_val;
|
||||
iq[i].phase_y = var_val;
|
||||
} else {
|
||||
iq[i].phase_y = fix_val;
|
||||
iq[i].gain_x = var_val;
|
||||
}
|
||||
|
||||
if (i == 0) { /* try right-side point */
|
||||
var_val++;
|
||||
} else if (i == 1) { /* try left-side point */
|
||||
/* if absolute location is 1, change I/Q direction */
|
||||
if ((var_val & 0x1f) < 0x02) {
|
||||
tmp = 2 - (var_val & 0x1f);
|
||||
|
||||
/* b[5]:I/Q selection. 0:Q-path, 1:I-path */
|
||||
if (var_val & 0x20) {
|
||||
var_val &= 0xc0;
|
||||
var_val |= tmp;
|
||||
} else {
|
||||
var_val |= 0x20 | tmp;
|
||||
}
|
||||
} else {
|
||||
var_val -= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int r820t_section(struct r820t_priv *priv,
|
||||
struct r820t_sect_type *iq_point)
|
||||
{
|
||||
int rc;
|
||||
struct r820t_sect_type compare_iq[3], compare_bet[3];
|
||||
|
||||
/* Try X-1 column and save min result to compare_bet[0] */
|
||||
if (!(iq_point->gain_x & 0x1f))
|
||||
compare_iq[0].gain_x = ((iq_point->gain_x) & 0xdf) + 1; /* Q-path, Gain=1 */
|
||||
else
|
||||
compare_iq[0].gain_x = iq_point->gain_x - 1; /* left point */
|
||||
compare_iq[0].phase_y = iq_point->phase_y;
|
||||
|
||||
/* y-direction */
|
||||
rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x,
|
||||
compare_iq[0].phase_y, 0x08);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
r820t_compre_cor(compare_iq);
|
||||
|
||||
compare_bet[0] = compare_iq[0];
|
||||
|
||||
/* Try X column and save min result to compare_bet[1] */
|
||||
compare_iq[0].gain_x = iq_point->gain_x;
|
||||
compare_iq[0].phase_y = iq_point->phase_y;
|
||||
|
||||
rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x,
|
||||
compare_iq[0].phase_y, 0x08);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
r820t_compre_cor(compare_iq);
|
||||
|
||||
compare_bet[1] = compare_iq[0];
|
||||
|
||||
/* Try X+1 column and save min result to compare_bet[2] */
|
||||
if ((iq_point->gain_x & 0x1f) == 0x00)
|
||||
compare_iq[0].gain_x = ((iq_point->gain_x) | 0x20) + 1; /* I-path, Gain=1 */
|
||||
else
|
||||
compare_iq[0].gain_x = iq_point->gain_x + 1;
|
||||
compare_iq[0].phase_y = iq_point->phase_y;
|
||||
|
||||
rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x,
|
||||
compare_iq[0].phase_y, 0x08);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
r820t_compre_cor(compare_iq);
|
||||
|
||||
compare_bet[2] = compare_iq[0];
|
||||
|
||||
r820t_compre_cor(compare_bet);
|
||||
|
||||
*iq_point = compare_bet[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int r820t_vga_adjust(struct r820t_priv *priv)
|
||||
{
|
||||
int rc;
|
||||
u8 vga_count;
|
||||
|
||||
/* increase vga power to let image significant */
|
||||
for (vga_count = 12; vga_count < 16; vga_count++) {
|
||||
rc = r820t_write_reg_mask(priv, 0x0c, vga_count, 0x0f);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
usleep_range(10000, 11000);
|
||||
|
||||
rc = r820t_multi_read(priv);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (rc > 40 * 4)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int r820t_iq(struct r820t_priv *priv, struct r820t_sect_type *iq_pont)
|
||||
{
|
||||
struct r820t_sect_type compare_iq[3];
|
||||
int rc;
|
||||
u8 x_direction = 0; /* 1:x, 0:y */
|
||||
u8 dir_reg, other_reg;
|
||||
|
||||
r820t_vga_adjust(priv);
|
||||
|
||||
rc = r820t_imr_cross(priv, compare_iq, &x_direction);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (x_direction == 1) {
|
||||
dir_reg = 0x08;
|
||||
other_reg = 0x09;
|
||||
} else {
|
||||
dir_reg = 0x09;
|
||||
other_reg = 0x08;
|
||||
}
|
||||
|
||||
/* compare and find min of 3 points. determine i/q direction */
|
||||
r820t_compre_cor(compare_iq);
|
||||
|
||||
/* increase step to find min value of this direction */
|
||||
rc = r820t_compre_step(priv, compare_iq, dir_reg);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* the other direction */
|
||||
rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x,
|
||||
compare_iq[0].phase_y, dir_reg);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* compare and find min of 3 points. determine i/q direction */
|
||||
r820t_compre_cor(compare_iq);
|
||||
|
||||
/* increase step to find min value on this direction */
|
||||
rc = r820t_compre_step(priv, compare_iq, other_reg);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* check 3 points again */
|
||||
rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x,
|
||||
compare_iq[0].phase_y, other_reg);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
r820t_compre_cor(compare_iq);
|
||||
|
||||
/* section-9 check */
|
||||
rc = r820t_section(priv, compare_iq);
|
||||
|
||||
*iq_pont = compare_iq[0];
|
||||
|
||||
/* reset gain/phase control setting */
|
||||
rc = r820t_write_reg_mask(priv, 0x08, 0, 0x3f);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = r820t_write_reg_mask(priv, 0x09, 0, 0x3f);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int r820t_f_imr(struct r820t_priv *priv, struct r820t_sect_type *iq_pont)
|
||||
{
|
||||
int rc;
|
||||
|
||||
r820t_vga_adjust(priv);
|
||||
|
||||
/*
|
||||
* search surrounding points from previous point
|
||||
* try (x-1), (x), (x+1) columns, and find min IMR result point
|
||||
*/
|
||||
rc = r820t_section(priv, iq_pont);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int r820t_imr(struct r820t_priv *priv, unsigned imr_mem, bool im_flag)
|
||||
{
|
||||
struct r820t_sect_type imr_point;
|
||||
int rc;
|
||||
u32 ring_vco, ring_freq, ring_ref;
|
||||
u8 n_ring, n;
|
||||
int reg18, reg19, reg1f;
|
||||
|
||||
if (priv->cfg->xtal > 24000000)
|
||||
ring_ref = priv->cfg->xtal / 2;
|
||||
else
|
||||
ring_ref = priv->cfg->xtal;
|
||||
|
||||
for (n = 0; n < 16; n++) {
|
||||
if ((16 + n) * 8 * ring_ref >= 3100000) {
|
||||
n_ring = n;
|
||||
break;
|
||||
}
|
||||
|
||||
/* n_ring not found */
|
||||
if (n == 15)
|
||||
n_ring = n;
|
||||
}
|
||||
|
||||
reg18 = r820t_read_cache_reg(priv, 0x18);
|
||||
reg19 = r820t_read_cache_reg(priv, 0x19);
|
||||
reg1f = r820t_read_cache_reg(priv, 0x1f);
|
||||
|
||||
reg18 &= 0xf0; /* set ring[3:0] */
|
||||
reg18 |= n_ring;
|
||||
|
||||
ring_vco = (16 + n_ring) * 8 * ring_ref;
|
||||
|
||||
reg18 &= 0xdf; /* clear ring_se23 */
|
||||
reg19 &= 0xfc; /* clear ring_seldiv */
|
||||
reg1f &= 0xfc; /* clear ring_att */
|
||||
|
||||
switch (imr_mem) {
|
||||
case 0:
|
||||
ring_freq = ring_vco / 48;
|
||||
reg18 |= 0x20; /* ring_se23 = 1 */
|
||||
reg19 |= 0x03; /* ring_seldiv = 3 */
|
||||
reg1f |= 0x02; /* ring_att 10 */
|
||||
break;
|
||||
case 1:
|
||||
ring_freq = ring_vco / 16;
|
||||
reg18 |= 0x00; /* ring_se23 = 0 */
|
||||
reg19 |= 0x02; /* ring_seldiv = 2 */
|
||||
reg1f |= 0x00; /* pw_ring 00 */
|
||||
break;
|
||||
case 2:
|
||||
ring_freq = ring_vco / 8;
|
||||
reg18 |= 0x00; /* ring_se23 = 0 */
|
||||
reg19 |= 0x01; /* ring_seldiv = 1 */
|
||||
reg1f |= 0x03; /* pw_ring 11 */
|
||||
break;
|
||||
case 3:
|
||||
ring_freq = ring_vco / 6;
|
||||
reg18 |= 0x20; /* ring_se23 = 1 */
|
||||
reg19 |= 0x00; /* ring_seldiv = 0 */
|
||||
reg1f |= 0x03; /* pw_ring 11 */
|
||||
break;
|
||||
case 4:
|
||||
ring_freq = ring_vco / 4;
|
||||
reg18 |= 0x00; /* ring_se23 = 0 */
|
||||
reg19 |= 0x00; /* ring_seldiv = 0 */
|
||||
reg1f |= 0x01; /* pw_ring 01 */
|
||||
break;
|
||||
default:
|
||||
ring_freq = ring_vco / 4;
|
||||
reg18 |= 0x00; /* ring_se23 = 0 */
|
||||
reg19 |= 0x00; /* ring_seldiv = 0 */
|
||||
reg1f |= 0x01; /* pw_ring 01 */
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* write pw_ring, n_ring, ringdiv2 registers */
|
||||
|
||||
/* n_ring, ring_se23 */
|
||||
rc = r820t_write_reg(priv, 0x18, reg18);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* ring_sediv */
|
||||
rc = r820t_write_reg(priv, 0x19, reg19);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* pw_ring */
|
||||
rc = r820t_write_reg(priv, 0x1f, reg1f);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* mux input freq ~ rf_in freq */
|
||||
rc = r820t_set_mux(priv, (ring_freq - 5300) * 1000);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = r820t_set_pll(priv, V4L2_TUNER_DIGITAL_TV,
|
||||
(ring_freq - 5300) * 1000);
|
||||
if (!priv->has_lock)
|
||||
rc = -EINVAL;
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (im_flag) {
|
||||
rc = r820t_iq(priv, &imr_point);
|
||||
} else {
|
||||
imr_point.gain_x = priv->imr_data[3].gain_x;
|
||||
imr_point.phase_y = priv->imr_data[3].phase_y;
|
||||
imr_point.value = priv->imr_data[3].value;
|
||||
|
||||
rc = r820t_f_imr(priv, &imr_point);
|
||||
}
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* save IMR value */
|
||||
switch (imr_mem) {
|
||||
case 0:
|
||||
priv->imr_data[0].gain_x = imr_point.gain_x;
|
||||
priv->imr_data[0].phase_y = imr_point.phase_y;
|
||||
priv->imr_data[0].value = imr_point.value;
|
||||
break;
|
||||
case 1:
|
||||
priv->imr_data[1].gain_x = imr_point.gain_x;
|
||||
priv->imr_data[1].phase_y = imr_point.phase_y;
|
||||
priv->imr_data[1].value = imr_point.value;
|
||||
break;
|
||||
case 2:
|
||||
priv->imr_data[2].gain_x = imr_point.gain_x;
|
||||
priv->imr_data[2].phase_y = imr_point.phase_y;
|
||||
priv->imr_data[2].value = imr_point.value;
|
||||
break;
|
||||
case 3:
|
||||
priv->imr_data[3].gain_x = imr_point.gain_x;
|
||||
priv->imr_data[3].phase_y = imr_point.phase_y;
|
||||
priv->imr_data[3].value = imr_point.value;
|
||||
break;
|
||||
case 4:
|
||||
priv->imr_data[4].gain_x = imr_point.gain_x;
|
||||
priv->imr_data[4].phase_y = imr_point.phase_y;
|
||||
priv->imr_data[4].value = imr_point.value;
|
||||
break;
|
||||
default:
|
||||
priv->imr_data[4].gain_x = imr_point.gain_x;
|
||||
priv->imr_data[4].phase_y = imr_point.phase_y;
|
||||
priv->imr_data[4].value = imr_point.value;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int r820t_imr_callibrate(struct r820t_priv *priv)
|
||||
{
|
||||
int rc, i;
|
||||
int xtal_cap = 0;
|
||||
|
||||
if (priv->imr_done)
|
||||
return 0;
|
||||
|
||||
/* Initialize registers */
|
||||
rc = r820t_write(priv, 0x05,
|
||||
r820t_init_array, sizeof(r820t_init_array));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Detect Xtal capacitance */
|
||||
if ((priv->cfg->rafael_chip == CHIP_R820T) ||
|
||||
(priv->cfg->rafael_chip == CHIP_R828S) ||
|
||||
(priv->cfg->rafael_chip == CHIP_R820C)) {
|
||||
priv->xtal_cap_sel = XTAL_HIGH_CAP_0P;
|
||||
} else {
|
||||
for (i = 0; i < 3; i++) {
|
||||
rc = r820t_xtal_check(priv);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (!i || rc > xtal_cap)
|
||||
xtal_cap = rc;
|
||||
}
|
||||
priv->xtal_cap_sel = xtal_cap;
|
||||
}
|
||||
|
||||
/* Initialize registers */
|
||||
rc = r820t_write(priv, 0x05,
|
||||
r820t_init_array, sizeof(r820t_init_array));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = r820t_imr_prepare(priv);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = r820t_imr(priv, 3, true);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
rc = r820t_imr(priv, 1, false);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
rc = r820t_imr(priv, 0, false);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
rc = r820t_imr(priv, 2, false);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
rc = r820t_imr(priv, 4, false);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
priv->imr_done = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* r820t frontend operations and tuner attach code
|
||||
*
|
||||
@ -1392,8 +2064,7 @@ static int r820t_xtal_check(struct r820t_priv *priv)
|
||||
static int r820t_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct r820t_priv *priv = fe->tuner_priv;
|
||||
int rc, i;
|
||||
int xtal_cap = 0;
|
||||
int rc;
|
||||
|
||||
tuner_dbg("%s:\n", __func__);
|
||||
|
||||
@ -1401,20 +2072,9 @@ static int r820t_init(struct dvb_frontend *fe)
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
|
||||
if ((priv->cfg->rafael_chip == CHIP_R820T) ||
|
||||
(priv->cfg->rafael_chip == CHIP_R828S) ||
|
||||
(priv->cfg->rafael_chip == CHIP_R820C)) {
|
||||
priv->xtal_cap_sel = XTAL_HIGH_CAP_0P;
|
||||
} else {
|
||||
for (i = 0; i < 3; i++) {
|
||||
rc = r820t_xtal_check(priv);
|
||||
if (rc < 0)
|
||||
goto err;
|
||||
if (!i || rc > xtal_cap)
|
||||
xtal_cap = rc;
|
||||
}
|
||||
priv->xtal_cap_sel = xtal_cap;
|
||||
}
|
||||
rc = r820t_imr_callibrate(priv);
|
||||
if (rc < 0)
|
||||
goto err;
|
||||
|
||||
/* Initialize registers */
|
||||
rc = r820t_write(priv, 0x05,
|
||||
|
Loading…
Reference in New Issue
Block a user