atv_demod: add atv demod tune interface [1/2]
authornengwen.chen <nengwen.chen@amlogic.com>
Mon, 15 Apr 2019 03:29:26 +0000 (11:29 +0800)
committerTao Zeng <tao.zeng@amlogic.com>
Mon, 6 May 2019 11:13:46 +0000 (04:13 -0700)
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>
drivers/amlogic/atv_demod/atv_demod_ops.c
drivers/amlogic/atv_demod/atv_demod_ops.h
drivers/amlogic/atv_demod/atv_demod_v4l2.c
drivers/amlogic/atv_demod/atv_demod_v4l2.h

index 685b94a..f2ccf45 100644 (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,
 };
 
index 66d8c32..08448fb 100644 (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;
index 2db6a35..8fc5207 100644 (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;
index b944ab9..331a7f9 100644 (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
 #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);
 };