From ba38c1caa188f031a13a181f39d58da09e4364e5 Mon Sep 17 00:00:00 2001 From: "nengwen.chen" Date: Mon, 15 Apr 2019 11:29:26 +0800 Subject: [PATCH] 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 --- drivers/amlogic/atv_demod/atv_demod_ops.c | 272 +++++++++++++++++++---------- drivers/amlogic/atv_demod/atv_demod_ops.h | 2 + drivers/amlogic/atv_demod/atv_demod_v4l2.c | 51 +++++- drivers/amlogic/atv_demod/atv_demod_v4l2.h | 33 +++- 4 files changed, 258 insertions(+), 100 deletions(-) diff --git a/drivers/amlogic/atv_demod/atv_demod_ops.c b/drivers/amlogic/atv_demod/atv_demod_ops.c index 685b94a..f2ccf45 100644 --- a/drivers/amlogic/atv_demod/atv_demod_ops.c +++ b/drivers/amlogic/atv_demod/atv_demod_ops.c @@ -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, ¶ms); + + *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, + ¶ms); + + 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, + ¶ms); + + 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, ¶ms); - 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, - ¶ms); - - 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, - ¶ms); - - 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, }; diff --git a/drivers/amlogic/atv_demod/atv_demod_ops.h b/drivers/amlogic/atv_demod/atv_demod_ops.h index 66d8c32..08448fb 100644 --- a/drivers/amlogic/atv_demod/atv_demod_ops.h +++ b/drivers/amlogic/atv_demod/atv_demod_ops.h @@ -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; diff --git a/drivers/amlogic/atv_demod/atv_demod_v4l2.c b/drivers/amlogic/atv_demod/atv_demod_v4l2.c index 2db6a35..8fc5207 100644 --- a/drivers/amlogic/atv_demod/atv_demod_v4l2.c +++ b/drivers/amlogic/atv_demod/atv_demod_v4l2.c @@ -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; diff --git a/drivers/amlogic/atv_demod/atv_demod_v4l2.h b/drivers/amlogic/atv_demod/atv_demod_v4l2.h index b944ab9..331a7f9 100644 --- a/drivers/amlogic/atv_demod/atv_demod_v4l2.h +++ b/drivers/amlogic/atv_demod/atv_demod_v4l2.h @@ -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); }; -- 2.7.4