atv_demod: add atv demod tune interface [1/2]

PD#TV-4499

Problem:
add atv demod tune interface.

Solution:
add atv demod tune interface.

Verify:
Verified by x301.

Change-Id: I4b62ee8b87d218bf639c02a34ba7e1c116a22249
Signed-off-by: nengwen.chen <nengwen.chen@amlogic.com>
This commit is contained in:
nengwen.chen
2019-04-15 11:29:26 +08:00
committed by Tao Zeng
parent 09992d83b9
commit ba38c1caa1
4 changed files with 258 additions and 100 deletions

View File

@@ -242,11 +242,6 @@ static void atv_demod_set_params(struct dvb_frontend *fe,
p->if_inv = if_info[0];
p->if_freq = if_info[1];
#if 0 /* unused */
last_frq = p->param.frequency;
last_std = p->param.std;
#endif
if ((p->tuner_id == AM_TUNER_R840) ||
(p->tuner_id == AM_TUNER_R842) ||
(p->tuner_id == AM_TUNER_SI2151) ||
@@ -561,7 +556,7 @@ static void atvdemod_fe_try_analog_format(struct v4l2_frontend *v4l2_fe,
unsigned int broad_std = 0;
unsigned int audio = 0;
if (auto_search_std & 0x01) {
if (auto_search_std & AUTO_DETECT_COLOR) {
for (i = 0; i < try_vfmt_cnt; i++) {
if (aml_fe_hook_get_fmt == NULL) {
pr_err("%s: aml_fe_hook_get_fmt == NULL.\n",
@@ -641,7 +636,7 @@ static void atvdemod_fe_try_analog_format(struct v4l2_frontend *v4l2_fe,
*video_fmt = std_bk;
if (!(auto_search_std & 0x02)) {
if (!(auto_search_std & AUTO_DETECT_AUDIO)) {
*audio_fmt = p->audmode;
return;
}
@@ -703,10 +698,106 @@ static void atvdemod_fe_try_analog_format(struct v4l2_frontend *v4l2_fe,
} else
*soundsys = 0xFFFFFF;
pr_info("autodet audio broad_std %d, [%s][0x%x] soundsys[0x%x]\n",
pr_info("auto detect audio broad_std %d, [%s][0x%x] soundsys[0x%x]\n",
broad_std, v4l2_std_to_str(audio), audio, *soundsys);
}
static void atvdemod_fe_try_signal(struct v4l2_frontend *v4l2_fe,
int auto_search_std, bool *lock)
{
struct analog_parameters params;
struct dvb_frontend *fe = &v4l2_fe->fe;
struct atv_demod_priv *priv = fe->analog_demod_priv;
struct v4l2_analog_parameters *p = &v4l2_fe->params;
enum v4l2_status tuner_state = V4L2_TIMEDOUT;
enum v4l2_status ade_state = V4L2_TIMEDOUT;
int try_cnt = tuner_status_cnt;
/* v4l2_std_id std_bk = 0; */
/* unsigned int audio = 0; */
/* bool try_secam = false; */
unsigned int tuner_id = priv->atvdemod_param.tuner_id;
params.frequency = p->frequency;
params.mode = p->afc_range;
params.audmode = p->audmode;
params.std = p->std;
fe->ops.analog_ops.set_params(fe, &params);
*lock = false;
do {
if (tuner_id == AM_TUNER_MXL661) {
usleep_range(30 * 1000, 30 * 1000 + 100);
} else if (tuner_id == AM_TUNER_R840 ||
tuner_id == AM_TUNER_R842) {
usleep_range(10 * 1000, 10 * 1000 + 100);
fe->ops.tuner_ops.get_status(fe, (u32 *)&tuner_state);
} else {
/* AM_TUNER_SI2151 and AM_TUNER_SI2159 */
usleep_range(10 * 1000, 10 * 1000 + 100);
}
fe->ops.analog_ops.has_signal(fe, (u16 *)&ade_state);
try_cnt--;
if (((ade_state == V4L2_HAS_LOCK ||
tuner_state == V4L2_HAS_LOCK) &&
(tuner_id != AM_TUNER_R840 &&
tuner_id != AM_TUNER_R842)) ||
((ade_state == V4L2_HAS_LOCK &&
tuner_state == V4L2_HAS_LOCK) &&
(tuner_id == AM_TUNER_R840 ||
tuner_id == AM_TUNER_R842))) {
*lock = true;
break;
}
if (try_cnt == 0) {
#if 0 /* when need to support secam-l, will enable it */
if (auto_search_std &&
try_secam == false &&
!(p->std & V4L2_COLOR_STD_SECAM) &&
!(p->std & V4L2_STD_SECAM_L)) {
/* backup the std and audio mode */
std_bk = p->std;
audio = p->audmode;
p->std = (V4L2_COLOR_STD_SECAM
| V4L2_STD_SECAM_L);
p->audmode = V4L2_STD_SECAM_L;
params.frequency = p->frequency;
params.mode = p->afc_range;
params.audmode = p->audmode;
params.std = p->std;
fe->ops.analog_ops.set_params(fe,
&params);
try_secam = true;
try_cnt =
tuner_status_cnt / 2;
continue;
}
if (try_secam) {
p->std = std_bk;
p->audmode = audio;
params.frequency = p->frequency;
params.mode = p->afc_range;
params.audmode = p->audmode;
params.std = p->std;
fe->ops.analog_ops.set_params(fe,
&params);
try_secam = false;
}
#endif
break;
}
} while (1);
}
static int atvdemod_fe_afc_closer(struct v4l2_frontend *v4l2_fe, int minafcfreq,
int maxafcfreq, int isAutoSearch)
{
@@ -908,7 +999,7 @@ static int atvdemod_fe_get_property(struct v4l2_frontend *v4l2_fe,
switch (tvp->cmd) {
case V4L2_SOUND_SYS:
tvp->data = ((aud_std & 0xFF) << 16)
tvp->data = ((aud_std & 0xFF) << 16)
| ((signal_audmode & 0xFF) << 8)
| (aud_mode & 0xFF);
break;
@@ -926,20 +1017,88 @@ static int atvdemod_fe_get_property(struct v4l2_frontend *v4l2_fe,
return 0;
}
static int atvdemod_fe_tune(struct v4l2_frontend *v4l2_fe,
struct v4l2_tune_status *status)
{
bool lock = 0;
int priv_cfg = 0;
int try_cnt = 4;
struct v4l2_analog_parameters *p = &v4l2_fe->params;
struct dvb_frontend *fe = &v4l2_fe->fe;
priv_cfg = AML_ATVDEMOD_SCAN_MODE;
fe->ops.analog_ops.set_config(fe, &priv_cfg);
atvdemod_fe_try_signal(v4l2_fe, 0, &lock);
if (lock) {
status->lock = 1;
while (try_cnt--) {
status->afc = retrieve_vpll_carrier_afc();
if (status->afc < 1500)
break;
usleep_range(5 * 1000, 5 * 1000 + 100);
}
} else {
status->lock = 0;
status->afc = 0;
}
pr_info("[%s] lock: [%d], afc: [%d], freq: [%d], flag: [%d].\n",
__func__, status->lock, status->afc,
p->frequency, p->flag);
priv_cfg = AML_ATVDEMOD_UNSCAN_MODE;
fe->ops.analog_ops.set_config(fe, &priv_cfg);
return 0;
}
static int atvdemod_fe_detect(struct v4l2_frontend *v4l2_fe)
{
struct v4l2_analog_parameters *p = &v4l2_fe->params;
struct dvb_frontend *fe = &v4l2_fe->fe;
int priv_cfg = 0;
v4l2_std_id std_bk = 0;
unsigned int audio = 0;
unsigned int soundsys = 0;
int auto_detect = AUTO_DETECT_COLOR | AUTO_DETECT_AUDIO;
priv_cfg = AML_ATVDEMOD_SCAN_MODE;
fe->ops.analog_ops.set_config(fe, &priv_cfg);
atvdemod_fe_try_analog_format(v4l2_fe, auto_detect,
&std_bk, &audio, &soundsys);
if (std_bk != 0) {
p->audmode = audio;
p->std = std_bk;
p->soundsys = soundsys;
std_bk = 0;
audio = 0;
}
priv_cfg = AML_ATVDEMOD_UNSCAN_MODE;
fe->ops.analog_ops.set_config(fe, &priv_cfg);
return 0;
}
static enum v4l2_search atvdemod_fe_search(struct v4l2_frontend *v4l2_fe)
{
struct analog_parameters params;
/* struct analog_parameters params; */
struct dvb_frontend *fe = &v4l2_fe->fe;
struct atv_demod_priv *priv = NULL;
struct v4l2_analog_parameters *p = &v4l2_fe->params;
enum v4l2_status tuner_state = V4L2_TIMEDOUT;
enum v4l2_status ade_state = V4L2_TIMEDOUT;
/*enum v4l2_status tuner_state = V4L2_TIMEDOUT;*/
/*enum v4l2_status ade_state = V4L2_TIMEDOUT;*/
bool pll_lock = false;
/*struct atv_status_s atv_status;*/
__u32 set_freq = 0;
__u32 minafcfreq = 0, maxafcfreq = 0;
__u32 afc_step = 0;
int tuner_status_cnt_local = tuner_status_cnt;
/* int tuner_status_cnt_local = tuner_status_cnt; */
v4l2_std_id std_bk = 0;
unsigned int audio = 0;
unsigned int soundsys = 0;
@@ -987,7 +1146,7 @@ static enum v4l2_search atvdemod_fe_search(struct v4l2_frontend *v4l2_fe)
if (p->std == 0) {
p->std = V4L2_COLOR_STD_NTSC | V4L2_STD_NTSC_M;
/* p->std = V4L2_COLOR_STD_PAL | V4L2_STD_DK; */
auto_search_std = 0x01;
auto_search_std = AUTO_DETECT_COLOR;
pr_dbg("[%s] user std is 0, so set it to NTSC | M.\n",
__func__);
}
@@ -1005,7 +1164,7 @@ static enum v4l2_search atvdemod_fe_search(struct v4l2_frontend *v4l2_fe)
p->std = (p->std & 0xFF000000) | p->audmode;
}
auto_search_std |= 0x02;
auto_search_std |= AUTO_DETECT_AUDIO;
pr_dbg("[%s] user audmode is 0, so set it to %s.\n",
__func__, v4l2_std_to_str(p->audmode));
}
@@ -1038,90 +1197,11 @@ static enum v4l2_search atvdemod_fe_search(struct v4l2_frontend *v4l2_fe)
while (minafcfreq <= p->frequency &&
p->frequency <= maxafcfreq) {
params.frequency = p->frequency;
params.mode = p->afc_range;
params.audmode = p->audmode;
params.std = p->std;
fe->ops.analog_ops.set_params(fe, &params);
pr_dbg("[%s] [%d] is processing, [min=%d, max=%d].\n",
__func__, p->frequency, minafcfreq, maxafcfreq);
pll_lock = false;
tuner_status_cnt_local = tuner_status_cnt;
do {
if (tuner_id == AM_TUNER_MXL661) {
usleep_range(30 * 1000, 30 * 1000 + 100);
} else if (tuner_id == AM_TUNER_R840 ||
tuner_id == AM_TUNER_R842) {
usleep_range(10 * 1000, 10 * 1000 + 100);
fe->ops.tuner_ops.get_status(fe,
(u32 *)&tuner_state);
} else {
/* AM_TUNER_SI2151 and AM_TUNER_SI2159 */
usleep_range(10 * 1000, 10 * 1000 + 100);
}
fe->ops.analog_ops.has_signal(fe, (u16 *)&ade_state);
tuner_status_cnt_local--;
if (((ade_state == V4L2_HAS_LOCK ||
tuner_state == V4L2_HAS_LOCK) &&
(tuner_id != AM_TUNER_R840 &&
tuner_id != AM_TUNER_R842)) ||
((ade_state == V4L2_HAS_LOCK &&
tuner_state == V4L2_HAS_LOCK) &&
(tuner_id == AM_TUNER_R840 ||
tuner_id == AM_TUNER_R842))) {
pll_lock = true;
break;
}
if (tuner_status_cnt_local == 0) {
#if 0 /* when need to support secam-l, will enable it */
if (auto_search_std &&
try_secam == false &&
!(p->std & V4L2_COLOR_STD_SECAM) &&
!(p->std & V4L2_STD_SECAM_L)) {
/* backup the std and audio mode */
std_bk = p->std;
audio = p->audmode;
p->std = (V4L2_COLOR_STD_SECAM
| V4L2_STD_SECAM_L);
p->audmode = V4L2_STD_SECAM_L;
params.frequency = p->frequency;
params.mode = p->afc_range;
params.audmode = p->audmode;
params.std = p->std;
fe->ops.analog_ops.set_params(fe,
&params);
try_secam = true;
tuner_status_cnt_local =
tuner_status_cnt / 2;
continue;
}
if (try_secam) {
p->std = std_bk;
p->audmode = audio;
params.frequency = p->frequency;
params.mode = p->afc_range;
params.audmode = p->audmode;
params.std = p->std;
fe->ops.analog_ops.set_params(fe,
&params);
try_secam = false;
}
#endif
break;
}
} while (1);
atvdemod_fe_try_signal(v4l2_fe, auto_search_std, &pll_lock);
std_bk = 0;
audio = 0;
@@ -1193,6 +1273,8 @@ static enum v4l2_search atvdemod_fe_search(struct v4l2_frontend *v4l2_fe)
static struct v4l2_frontend_ops atvdemod_fe_ops = {
.set_property = atvdemod_fe_set_property,
.get_property = atvdemod_fe_get_property,
.tune = atvdemod_fe_tune,
.detect = atvdemod_fe_detect,
.search = atvdemod_fe_search,
};

View File

@@ -44,6 +44,8 @@
#define ATVDEMOD_INTERVAL (HZ / 100) /* 10ms, #define HZ 100 */
#define AUTO_DETECT_COLOR (1 << 0)
#define AUTO_DETECT_AUDIO (1 << 1)
struct atv_demod_sound_system {
unsigned int broadcast_std;

View File

@@ -381,8 +381,9 @@ static int v4l2_set_frontend(struct v4l2_frontend *v4l2_fe,
fepriv->state = V4L2FE_STATE_RETUNE;
/* Request the search algorithm to search */
fepriv->algo_status |= V4L2_SEARCH_AGAIN;
if (params->flag & ANALOG_FLAG_ENABLE_AFC) {
fepriv->algo_status |= V4L2_SEARCH_AGAIN;
/*dvb_frontend_add_event(fe, 0); */
v4l2_frontend_clear_events(v4l2_fe);
v4l2_frontend_wakeup(v4l2_fe);
@@ -465,6 +466,34 @@ static int v4l2_frontend_read_status(struct v4l2_frontend *v4l2_fe,
return ret;
}
static int v4l2_frontend_detect_tune(struct v4l2_frontend *v4l2_fe,
struct v4l2_tune_status *status)
{
int ret = 0;
pr_dbg("%s.\n", __func__);
if (!status)
return -1;
if (v4l2_fe->ops.tune)
ret = v4l2_fe->ops.tune(v4l2_fe, status);
return ret;
}
static int v4l2_frontend_detect_standard(struct v4l2_frontend *v4l2_fe)
{
int ret = 0;
pr_dbg("%s.\n", __func__);
if (v4l2_fe->ops.detect)
ret = v4l2_fe->ops.detect(v4l2_fe);
return ret;
}
static void v4l2_frontend_vdev_release(struct video_device *dev)
{
pr_dbg("%s.\n", __func__);
@@ -655,6 +684,15 @@ static int v4l2_property_process_get(struct v4l2_frontend *v4l2_fe,
case V4L2_TUNER_IF_FREQ:
tvp->data = amlatvdemod_devp->if_freq;
break;
case V4L2_AFC:
{
s32 afc = 0;
if (v4l2_fe->fe.ops.analog_ops.get_afc)
v4l2_fe->fe.ops.analog_ops.get_afc(&v4l2_fe->fe, &afc);
tvp->data = afc;
}
break;
default:
pr_dbg("%s: V4L2 property %d doesn't exist\n",
__func__, tvp->cmd);
@@ -776,7 +814,7 @@ static long v4l2_frontend_ioctl(struct file *filp, void *fh, bool valid_prio,
(struct v4l2_analog_parameters *) arg);
break;
case V4L2_GET_FRONTEND:
case V4L2_GET_FRONTEND: /* 0x8028566a */
ret = v4l2_get_frontend(v4l2_fe,
(struct v4l2_analog_parameters *) arg);
break;
@@ -801,6 +839,15 @@ static long v4l2_frontend_ioctl(struct file *filp, void *fh, bool valid_prio,
ret = v4l2_frontend_ioctl_properties(filp, cmd, arg);
break;
case V4L2_DETECT_TUNE: /* 0x80285670 */
ret = v4l2_frontend_detect_tune(v4l2_fe,
(struct v4l2_tune_status *) arg);
break;
case V4L2_DETECT_STANDARD: /* 0x5671 */
ret = v4l2_frontend_detect_standard(v4l2_fe);
break;
default:
pr_warn("%s: Unsupport cmd = 0x%x.\n", __func__, cmd);
break;

View File

@@ -84,6 +84,8 @@
#define V4L2_READ_STATUS _IOR('V', 109, enum v4l2_status)
#define V4L2_SET_PROPERTY _IOWR('V', 110, struct v4l2_properties)
#define V4L2_GET_PROPERTY _IOWR('V', 111, struct v4l2_properties)
#define V4L2_DETECT_TUNE _IOR('V', 112, struct v4l2_tune_status)
#define V4L2_DETECT_STANDARD _IO('V', 113)
#define ANALOG_FLAG_ENABLE_AFC 0x00000001
#define ANALOG_FLAG_MANUL_SCAN 0x00000011
@@ -98,6 +100,7 @@
#define V4L2_SIF_OVER_MODULATION 7
#define V4L2_TUNER_TYPE 8
#define V4L2_TUNER_IF_FREQ 9
#define V4L2_AFC 10
struct v4l2_frontend;
@@ -105,12 +108,25 @@ struct v4l2_analog_parameters {
unsigned int frequency;
unsigned int audmode;
unsigned int soundsys; /*A2,BTSC,EIAJ,NICAM */
/* std & 0xff000000: PAL/NTSC/SECAM, std & 0x00ffffff: cvbs format */
v4l2_std_id std;
unsigned int flag;
unsigned int flag; /* for search or play */
unsigned int afc_range;
unsigned int reserved;
};
struct v4l2_tune_status {
unsigned char lock; /* unlocked: 0, locked: 1 */
v4l2_std_id std;
unsigned int audmode;
int snr;
int afc; /* KHz */
union {
void *resrvred;
__u64 reserved1;
};
};
enum v4l2_status {
V4L2_HAS_SIGNAL = 0x01, /* found something above the noise level */
V4L2_HAS_CARRIER = 0x02, /* found a DVB signal */
@@ -186,11 +202,22 @@ struct v4l2_adapter {
};
struct v4l2_frontend_ops {
int (*set_property)(struct v4l2_frontend *fe,
int (*set_property)(struct v4l2_frontend *v4l2_fe,
struct v4l2_property *tvp);
int (*get_property)(struct v4l2_frontend *fe,
int (*get_property)(struct v4l2_frontend *v4l2_fe,
struct v4l2_property *tvp);
/* for signal one shot search, return lock status and afc value */
int (*tune)(struct v4l2_frontend *v4l2_fe,
struct v4l2_tune_status *status);
/* for auto standard detection */
int (*detect)(struct v4l2_frontend *v4l2_fe);
/*
* These callbacks are for devices that implement their own
* tuning algorithms, rather than a simple tune.
*/
enum v4l2_search (*search)(struct v4l2_frontend *v4l2_fe);
};