atv_demod: Add ATV NICAM. [1/5]
authornengwen.chen <nengwen.chen@amlogic.com>
Thu, 7 Jun 2018 12:00:39 +0000 (20:00 +0800)
committerYixun Lan <yixun.lan@amlogic.com>
Mon, 2 Jul 2018 08:20:14 +0000 (01:20 -0700)
PD#165624: Add ATV NICAM.

Change-Id: I2bcc018cd5ff7a611baa2f5473cfa1dbce28118d
Signed-off-by: nengwen.chen <nengwen.chen@amlogic.com>
15 files changed:
drivers/amlogic/atv_demod/Makefile
drivers/amlogic/atv_demod/atv_demod_debug.c
drivers/amlogic/atv_demod/atv_demod_debug.h
drivers/amlogic/atv_demod/atv_demod_driver.c
drivers/amlogic/atv_demod/atv_demod_driver.h
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
drivers/amlogic/atv_demod/atvauddemod_func.c
drivers/amlogic/atv_demod/atvauddemod_func.h
drivers/amlogic/atv_demod/atvdemod_func.c
drivers/amlogic/atv_demod/atvdemod_func.h
drivers/amlogic/atv_demod/aud_demod_reg.h
drivers/amlogic/media/vin/tvin/tvafe/tvafe_general.c

index 1f5060a..3f309c5 100644 (file)
@@ -3,4 +3,4 @@ obj-$(CONFIG_AMLOGIC_ATV_DEMOD) += atvdemod_fe.o
 atvdemod_fe-objs = atvdemod_func.o atvauddemod_func.o atv_demod_v4l2.o atv_demod_driver.o atv_demod_ops.o atv_demod_debug.o
 
 ccflags-y += -I.
-ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-core
\ No newline at end of file
index 2692a6b..83cd9dd 100644 (file)
@@ -68,6 +68,7 @@
        DEBUGFS_CREATE_NODE(if_inv, 0640, dentry, u32)\
        DEBUGFS_CREATE_NODE(ademod_debug_en, 0640, dentry, u32)\
        DEBUGFS_CREATE_NODE(btsc_detect_delay, 0640, dentry, u32)\
+       DEBUGFS_CREATE_NODE(nicam_detect_delay, 0640, dentry, u32)\
        DEBUGFS_CREATE_NODE(signal_audmode, 0640, dentry, u32)\
        DEBUGFS_CREATE_NODE(audio_thd_threshold1, 0640, dentry, u32)\
        DEBUGFS_CREATE_NODE(gde_curve, 0640, dentry, u32)\
@@ -86,6 +87,9 @@
        DEBUGFS_CREATE_NODE(audio_gain_val, 0640, dentry, u32)\
        DEBUGFS_CREATE_NODE(audio_a2_threshold, 0640, dentry, u32)\
        DEBUGFS_CREATE_NODE(audio_a2_delay, 0640, dentry, u32)\
+       DEBUGFS_CREATE_NODE(audio_nicam_delay, 0640, dentry, u32)\
+       DEBUGFS_CREATE_NODE(audio_a2_auto, 0640, dentry, u32)\
+       DEBUGFS_CREATE_NODE(audio_a2_power_threshold, 0640, dentry, u32)\
 }
 
 
index 19fc814..3a8aa4b 100644 (file)
@@ -29,7 +29,7 @@ extern unsigned int atvdemod_debug_en;
 #undef pr_dbg
 #define pr_dbg(fmt, ...)\
        do {\
-               if (atvdemod_debug_en & 01)\
+               if (atvdemod_debug_en & 0x01)\
                        printk(fmt, ##__VA_ARGS__);\
        } while (0)
 
index 8044703..e81d839 100644 (file)
@@ -39,7 +39,7 @@
 #include "atvauddemod_func.h"
 
 
-#define AMLATVDEMOD_VER "Ref.2015/09/01a"
+#define AMLATVDEMOD_VER "V2.00"
 
 struct aml_atvdemod_device *amlatvdemod_devp;
 
@@ -72,6 +72,9 @@ static ssize_t aml_atvdemod_store(struct class *class,
                parm[n++] = token;
        }
 
+       if (parm[0] == NULL)
+               goto EXIT;
+
        if (!strncmp(parm[0], "init", 4)) {
                ret = atv_demod_enter_mode();
                if (ret)
@@ -236,18 +239,16 @@ static ssize_t aml_atvdemod_store(struct class *class,
 
                retrieve_adc_power(&adc_power);
                pr_info("adc_power:%d\n", adc_power);
-       } else if (!strncmp(parm[0], "demod_set", 9)) {
-
        } else if (!strncmp(parm[0], "mode_set", 8)) {
                int priv_cfg = AML_ATVDEMOD_INIT;
                struct dvb_frontend *fe = NULL;
 
-               if (aml_atvdemod_dev == NULL)
-                       pr_info("aml_atvdemod_dev == NULL\n");
+               if (amlatvdemod_devp == NULL)
+                       pr_info("amlatvdemod_devp == NULL\n");
 
-               fe = &aml_atvdemod_dev->v4l2_fe.fe;
+               fe = &amlatvdemod_devp->v4l2_fe.fe;
 
-               if (kstrtoul(parm[1], 10, &tmp) == 0)
+               if (parm[1] && kstrtoul(parm[1], 10, &tmp) == 0)
                        priv_cfg = tmp;
 
                if (fe != NULL) {
@@ -257,9 +258,86 @@ static ssize_t aml_atvdemod_store(struct class *class,
                                pr_info("fe->ops.analog_ops.set_config == NULL\n");
                } else
                        pr_info("fe == NULL\n");
+
+               pr_info("mode_set mode %d\n", priv_cfg);
+       } else if (!strncmp(parm[0], "params_set", 8)) {
+               struct dvb_frontend *fe = NULL;
+               struct analog_parameters params;
+               struct v4l2_analog_parameters *p = NULL;
+               unsigned int std = 0;
+
+               if (amlatvdemod_devp == NULL)
+                       pr_info("amlatvdemod_devp == NULL\n");
+
+               fe = &amlatvdemod_devp->v4l2_fe.fe;
+               p = &amlatvdemod_devp->v4l2_fe.params;
+
+               if (fe != NULL && p != NULL) {
+                       if (parm[1] && kstrtoul(parm[1], 0, &tmp) == 0)
+                               std = tmp;
+                       else
+                               std = p->std;
+
+                       params.frequency = p->frequency;
+                       params.mode = p->afc_range;
+                       params.audmode = p->audmode;
+                       params.std = std;
+
+                       if (fe->ops.analog_ops.set_params != NULL)
+                               fe->ops.analog_ops.set_params(fe, &params);
+                       else
+                               pr_info("fe->ops.analog_ops.set_params == NULL\n");
+               } else
+                       pr_info("fe == NULL\n");
+
+               pr_info("params_set std 0x%x\n", std);
+       } else if (!strncmp(parm[0], "audio_set", 9)) {
+               int std = AUDIO_STANDARD_A2_K;
+
+               if (parm[1] && kstrtoul(parm[1], 10, &tmp) == 0)
+                       std = tmp;
+
+               configure_adec(std);
+               adec_soft_reset();
+
+               pr_info("audio_set std %d\n", std);
+       } else if (!strncmp(parm[0], "atvdemod_status", 15)) {
+               struct v4l2_analog_parameters *p = NULL;
+
+               if (amlatvdemod_devp != NULL) {
+                       p = &amlatvdemod_devp->v4l2_fe.params;
+                       if (p != NULL) {
+                               pr_info("[atvdemod] afc_range: %d\n",
+                                               p->afc_range);
+                               pr_info("[atvdemod] frequency: %d\n",
+                                               p->frequency);
+                               pr_info("[atvdemod] soundsys: %d\n",
+                                               p->soundsys);
+                               pr_info("[atvdemod] std: 0x%x (%s %s)\n",
+                                       (unsigned int) amlatvdemod_devp->std,
+                                       v4l2_std_to_str(
+                                       (0xff000000 & amlatvdemod_devp->std)),
+                                       v4l2_std_to_str(
+                                       (0xffffff & amlatvdemod_devp->std)));
+                               pr_info("[atvdemod] audmode: 0x%x\n",
+                                               amlatvdemod_devp->audmode);
+                               pr_info("[atvdemod] flag: %d\n", p->flag);
+                               pr_info("[atvdemod] tuner_id: %d\n",
+                                               amlatvdemod_devp->tuner_id);
+                               pr_info("[atvdemod] if_freq: %d\n",
+                                               amlatvdemod_devp->if_freq);
+                               pr_info("[atvdemod] if_inv: %d\n",
+                                               amlatvdemod_devp->if_inv);
+                               pr_info("[atvdemod] fre_offset: %d\n",
+                                               amlatvdemod_devp->fre_offset);
+                               pr_info("[atvdemod] version: %s.\n",
+                                               AMLATVDEMOD_VER);
+                       }
+               }
        } else
                pr_dbg("invalid command\n");
 
+EXIT:
        kfree(buf_orig);
 
        return count;
@@ -355,6 +433,7 @@ static void aml_atvdemod_dt_parse(struct aml_atvdemod_device *pdev)
                                pr_err("can't find tuner: %s.\n", str);
                }
 
+               /* Get i2c adapter by i2c node */
                node_i2c = of_parse_phandle(node, "tuner_i2c_ada_id", 0);
                if (node_i2c) {
                        pdev->i2c_adp = of_find_i2c_adapter_by_node(node_i2c);
@@ -363,7 +442,7 @@ static void aml_atvdemod_dt_parse(struct aml_atvdemod_device *pdev)
                        if (!pdev->i2c_adp)
                                pr_err("can't find tuner_i2c_adap.\n");
                }
-#if 0
+#if 0 /* Get adapter by ID */
                ret = of_property_read_u32(node, "tuner_i2c_ada_id", &val);
                if (ret)
                        pr_err("can't find tuner_i2c_ada_id.\n");
@@ -385,7 +464,7 @@ int aml_attach_demod_tuner(struct aml_atvdemod_device *dev)
        struct dvb_frontend *fe = &v4l2_fe->fe;
 
        if (!dev->analog_attached) {
-               p = v4l2_attach(aml_atvdemod_attach, fe,
+               p = v4l2_attach(aml_atvdemod_attach, fe, v4l2_fe,
                                dev->i2c_adp, dev->i2c_addr, dev->tuner_id);
                if (p != NULL)
                        dev->analog_attached = true;
@@ -504,6 +583,11 @@ static int aml_atvdemod_probe(struct platform_device *pdev)
 
        pr_info("periphs_reg_base = 0x%p.\n", dev->periphs_reg_base);
 
+       /* add for audio system control */
+       dev->audio_demod_reg_base = ioremap(round_down(0xffd0d340, 0x3), 4);
+
+       pr_info("audio_demod_reg_base = 0x%p.\n", dev->audio_demod_reg_base);
+
        aml_atvdemod_dt_parse(dev);
 
        aml_attach_demod_tuner(dev);
@@ -626,7 +710,7 @@ static int __init aml_atvdemod_init(void)
                return ret;
        }
 
-       pr_info("%s: OK.\n", __func__);
+       pr_info("%s: OK, atv demod version: %s.\n", __func__, AMLATVDEMOD_VER);
 
        return 0;
 }
index ad8e595..1ae9ed5 100644 (file)
@@ -61,6 +61,7 @@ struct aml_atvdemod_device {
        void __iomem *audio_reg_base;
        void __iomem *hiu_reg_base;
        void __iomem *periphs_reg_base;
+       void __iomem *audio_demod_reg_base;
 
        unsigned int reg_23cf; /* IIR filter */
        int btsc_sap_mode; /*0: off 1:monitor 2:auto */
index c4b424e..32b9d28 100644 (file)
@@ -333,13 +333,20 @@ void aml_fe_get_atvaudio_state(int *state)
                if ((vpll_lock == 0) && (line_lock == 0)) {
                        retrieve_vpll_carrier_audio_power(&power);
                        *state = 1;
-               } else
+               } else {
                        *state = 0;
+                       pr_audio("vpll_lock: 0x%x, line_lock: 0x%x\n",
+                                       vpll_lock, line_lock);
+               }
        } else {
                *state = 0;
                pr_audio("%s, atv is not work, atv_state: %d.\n",
                                __func__, atv_state);
        }
+
+       /* If the atv signal is locked, it means there is audio data,
+        * so no need to check the power value.
+        */
 #if 0
        if (power >= 150)
                *state = 1;
@@ -458,6 +465,7 @@ int atv_demod_enter_mode(void)
                                amlatvdemod_devp->pin_name);
 
        adc_set_pll_cntl(1, 0x1, NULL);
+       /* vdac_enable(1, 1); */
        usleep_range(2000, 2100);
        atvdemod_clk_init();
        err_code = atvdemod_init();
@@ -498,6 +506,7 @@ int atv_demod_leave_mode(void)
                amlatvdemod_devp->pin = NULL;
        }
 
+       /* vdac_enable(0, 1); */
        adc_set_pll_cntl(0, 0x1, NULL);
        if (is_meson_txlx_cpu() || is_meson_txhd_cpu())
                aud_demod_clk_gate(0);
@@ -521,14 +530,14 @@ static void atv_demod_set_params(struct dvb_frontend *fe,
        int ret = -1;
        u32 if_info[2] = { 0 };
        struct atv_demod_priv *priv = fe->analog_demod_priv;
-       struct aml_atvdemod_parameters *atvdemod_param = &priv->atvdemod_param;
+       struct aml_atvdemod_parameters *p = &priv->atvdemod_param;
 
        priv->standby = false;
 
-       atvdemod_param->param.frequency = params->frequency;
-       atvdemod_param->param.mode = params->mode;
-       atvdemod_param->param.audmode = params->audmode;
-       atvdemod_param->param.std = params->std;
+       p->param.frequency = params->frequency;
+       p->param.mode = params->mode;
+       p->param.audmode = params->audmode;
+       p->param.std = params->std;
 
        /* afc tune disable,must cancel wq before set tuner freq*/
        afc_timer_disable(fe);
@@ -539,14 +548,14 @@ static void atv_demod_set_params(struct dvb_frontend *fe,
        if (fe->ops.tuner_ops.get_if_frequency)
                ret = fe->ops.tuner_ops.get_if_frequency(fe, if_info);
 
-       atvdemod_param->if_inv = if_info[0];
-       atvdemod_param->if_freq = if_info[1];
+       p->if_inv = if_info[0];
+       p->if_freq = if_info[1];
 
-       if ((atvdemod_param->param.std != amlatvdemod_devp->std) ||
-               (atvdemod_param->tuner_id == AM_TUNER_R840) ||
-               (atvdemod_param->tuner_id == AM_TUNER_SI2151) ||
-               (atvdemod_param->tuner_id == AM_TUNER_MXL661) ||
-               (atvdemod_param->tuner_id == AM_TUNER_SI2159)) {
+       if ((p->param.std != amlatvdemod_devp->std) ||
+               (p->tuner_id == AM_TUNER_R840) ||
+               (p->tuner_id == AM_TUNER_SI2151) ||
+               (p->tuner_id == AM_TUNER_MXL661) ||
+               (p->tuner_id == AM_TUNER_SI2159)) {
                /* open AGC if needed */
                if (amlatvdemod_devp->pin != NULL)
                        devm_pinctrl_put(amlatvdemod_devp->pin);
@@ -555,44 +564,35 @@ static void atv_demod_set_params(struct dvb_frontend *fe,
                        amlatvdemod_devp->pin =
                        devm_pinctrl_get_select(amlatvdemod_devp->dev,
                                        amlatvdemod_devp->pin_name);
-#if 0
-               last_frq = atvdemod_param->param.frequency;
-               last_std = atvdemod_param->param.std;
+#if 0 /* unused */
+               last_frq = p->param.frequency;
+               last_std = p->param.std;
 #endif
-               if (amlatvdemod_devp->std != atvdemod_param->param.std ||
-               amlatvdemod_devp->audmode != atvdemod_param->param.audmode ||
-               amlatvdemod_devp->if_freq != atvdemod_param->if_freq ||
-               amlatvdemod_devp->if_inv != atvdemod_param->if_inv ||
-               amlatvdemod_devp->tuner_id != atvdemod_param->tuner_id) {
-                       amlatvdemod_devp->std = atvdemod_param->param.std;
-                       amlatvdemod_devp->audmode =
-                                       atvdemod_param->param.audmode;
-                       amlatvdemod_devp->if_freq = atvdemod_param->if_freq;
-                       amlatvdemod_devp->if_inv = atvdemod_param->if_inv;
-                       amlatvdemod_devp->tuner_id = atvdemod_param->tuner_id;
+               if (amlatvdemod_devp->std != p->param.std ||
+                       amlatvdemod_devp->audmode != p->param.audmode ||
+                       amlatvdemod_devp->if_freq != p->if_freq ||
+                       amlatvdemod_devp->if_inv != p->if_inv ||
+                       amlatvdemod_devp->tuner_id != p->tuner_id) {
+                       amlatvdemod_devp->std = p->param.std;
+                       amlatvdemod_devp->audmode = p->param.audmode;
+                       amlatvdemod_devp->if_freq = p->if_freq;
+                       amlatvdemod_devp->if_inv = p->if_inv;
+                       amlatvdemod_devp->tuner_id = p->tuner_id;
+
                        atv_dmd_set_std();
-               } else {
+
+               } else
                        atv_dmd_soft_reset();
-                       return;
-               }
 
                if (!atv_demod_get_scan_mode())
                        atvauddemod_init();
-
-               pr_info("[%s] set std color %s, audio type %s.\n",
-                       __func__,
-                       v4l2_std_to_str((0xff000000 & amlatvdemod_devp->std)),
-                       v4l2_std_to_str((0xffffff & amlatvdemod_devp->std)));
-               pr_info("[%s] set if_freq %d, if_inv %d.\n",
-                       __func__, amlatvdemod_devp->if_freq,
-                       amlatvdemod_devp->if_inv);
        }
 
        /* afc tune enable */
        /* analog_search_flag == 0 or afc_range != 0 means searching */
        if ((fe->ops.info.type == FE_ANALOG)
                        && (atv_demod_get_scan_mode() == 0)
-                       && (atvdemod_param->param.mode == 0))
+                       && (p->param.mode == 0))
                afc_timer_enable(fe);
 }
 
@@ -606,12 +606,14 @@ static int atv_demod_has_signal(struct dvb_frontend *fe, u16 *signal)
        /* add line lock status for atv scan */
        retrieve_vpll_carrier_line_lock(&line_lock);
 
-       if ((vpll_lock & 0x1) == 0 && line_lock == 0) {
+       if (vpll_lock == 0 && line_lock == 0) {
                *signal = V4L2_HAS_LOCK;
-               pr_info("visual carrier lock:locked\n");
+               pr_info("%s locked [vpll_lock: 0x%x, line_lock:0x%x]\n",
+                               __func__, vpll_lock, line_lock);
        } else {
                *signal = V4L2_TIMEDOUT;
-               pr_info("visual carrier lock:unlocked\n");
+               pr_info("%s unlocked [vpll_lock: 0x%x, line_lock:0x%x]\n",
+                               __func__, vpll_lock, line_lock);
        }
 
        return 0;
@@ -708,8 +710,6 @@ static int atv_demod_set_config(struct dvb_frontend *fe, void *priv_cfg)
 
        mutex_unlock(&atv_demod_list_mutex);
 
-       pr_info("%s: OK.\n", __func__);
-
        return 0;
 }
 
@@ -727,7 +727,704 @@ static struct analog_demod_ops atvdemod_ops = {
        .i2c_gate_ctrl  = NULL,
 };
 
+
+unsigned int tuner_status_cnt = 8; /* 4-->16 test on sky mxl661 */
+
+bool slow_mode;
+
+typedef int (*hook_func_t) (void);
+hook_func_t aml_fe_hook_atv_status;
+hook_func_t aml_fe_hook_hv_lock;
+hook_func_t aml_fe_hook_get_fmt;
+
+void aml_fe_hook_cvd(hook_func_t atv_mode, hook_func_t cvd_hv_lock,
+       hook_func_t get_fmt)
+{
+       aml_fe_hook_atv_status = atv_mode;
+       aml_fe_hook_hv_lock = cvd_hv_lock;
+       aml_fe_hook_get_fmt = get_fmt;
+
+       pr_info("%s: OK.\n", __func__);
+}
+EXPORT_SYMBOL(aml_fe_hook_cvd);
+
+static v4l2_std_id atvdemod_fmt_2_v4l2_std(int fmt)
+{
+       v4l2_std_id std = 0;
+
+       switch (fmt) {
+       case AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_DK:
+               std = V4L2_STD_PAL_DK;
+               break;
+       case AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_I:
+               std = V4L2_STD_PAL_I;
+               break;
+       case AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_BG:
+               std = V4L2_STD_PAL_BG;
+               break;
+       case AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_M:
+               std = V4L2_STD_PAL_M;
+               break;
+       case AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC_DK:
+       case AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC_I:
+       case AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC_BG:
+       case AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC:
+       case AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC_M:
+               std = V4L2_STD_NTSC_M;
+               break;
+       case AML_ATV_DEMOD_VIDEO_MODE_PROP_SECAM_L:
+               std = V4L2_STD_SECAM_L;
+               break;
+       case AML_ATV_DEMOD_VIDEO_MODE_PROP_SECAM_DK2:
+       case AML_ATV_DEMOD_VIDEO_MODE_PROP_SECAM_DK3:
+               std = V4L2_STD_SECAM_DK;
+               break;
+       default:
+               pr_err("%s: Unsupport fmt: 0x%0x.\n", __func__, fmt);
+       }
+
+       return std;
+}
+
+static v4l2_std_id atvdemod_fe_tvin_fmt_to_v4l2_std(int fmt)
+{
+       v4l2_std_id std = 0;
+
+       switch (fmt) {
+       case TVIN_SIG_FMT_CVBS_NTSC_M:
+               std = V4L2_COLOR_STD_NTSC | V4L2_STD_NTSC_M;
+               break;
+       case TVIN_SIG_FMT_CVBS_NTSC_443:
+               std = V4L2_COLOR_STD_NTSC | V4L2_STD_NTSC_443;
+               break;
+       case TVIN_SIG_FMT_CVBS_NTSC_50:
+               std = V4L2_COLOR_STD_NTSC | V4L2_STD_NTSC_M;
+               break;
+       case TVIN_SIG_FMT_CVBS_PAL_I:
+               std = V4L2_COLOR_STD_PAL | V4L2_STD_PAL_I;
+               break;
+       case TVIN_SIG_FMT_CVBS_PAL_M:
+               std = V4L2_COLOR_STD_PAL | V4L2_STD_PAL_M;
+               break;
+       case TVIN_SIG_FMT_CVBS_PAL_60:
+               std = V4L2_COLOR_STD_PAL | V4L2_STD_PAL_60;
+               break;
+       case TVIN_SIG_FMT_CVBS_PAL_CN:
+               std = V4L2_COLOR_STD_PAL | V4L2_STD_PAL_Nc;
+               break;
+       case TVIN_SIG_FMT_CVBS_SECAM:
+               std = V4L2_COLOR_STD_SECAM | V4L2_STD_SECAM_L;
+               break;
+       default:
+               pr_err("%s: Unsupport fmt: 0x%x\n", __func__, fmt);
+               break;
+       }
+
+       return std;
+}
+
+static void atvdemod_fe_try_analog_format(struct v4l2_frontend *v4l2_fe,
+               int auto_search_std, v4l2_std_id *video_fmt,
+               unsigned int *audio_fmt)
+{
+       struct dvb_frontend *fe = &v4l2_fe->fe;
+       struct v4l2_analog_parameters *p = &v4l2_fe->params;
+       struct analog_parameters params;
+       int i = 0;
+       int try_vfmt_cnt = 300;
+       int varify_cnt = 0;
+       v4l2_std_id std_bk = 0;
+       unsigned int audio = 0;
+
+       if (auto_search_std & 0x01) {
+               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",
+                                               __func__);
+                               break;
+                       }
+                       std_bk = aml_fe_hook_get_fmt();
+                       if (std_bk) {
+                               varify_cnt++;
+                               pr_dbg("get varify_cnt:%d, cnt:%d, std_bk:0x%x\n",
+                                               varify_cnt, i,
+                                               (unsigned int) std_bk);
+                               if ((v4l2_fe->tuner_id == AM_TUNER_R840
+                                       && varify_cnt > 0)
+                                       || varify_cnt > 3)
+                                       break;
+                       }
+
+                       if (i == (try_vfmt_cnt / 3) ||
+                               (i == (try_vfmt_cnt / 3) * 2)) {
+                               /* Before enter search,
+                                * need set the std,
+                                * then, try others std.
+                                */
+                               if (p->std & V4L2_COLOR_STD_PAL)
+                                       p->std = V4L2_COLOR_STD_NTSC
+                                       | V4L2_STD_NTSC_M;
+#if 0 /*for secam */
+                               else if (p->std & V4L2_COLOR_STD_NTSC)
+                                       p->std = V4L2_COLOR_STD_SECAM
+                                       | V4L2_STD_SECAM;
+#endif
+                               else if (p->std & V4L2_COLOR_STD_NTSC)
+                                       p->std = V4L2_COLOR_STD_PAL
+                                       | V4L2_STD_PAL_DK;
+
+                               p->frequency += 1;
+                               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);
+                       }
+                       usleep_range(30 * 1000, 30 * 1000 + 100);
+               }
+
+               pr_dbg("get std_bk cnt:%d, std_bk: 0x%x\n",
+                               i, (unsigned int) std_bk);
+
+               if (std_bk == 0) {
+                       pr_err("%s: failed to get video fmt, assume PAL.\n",
+                                       __func__);
+                       std_bk = TVIN_SIG_FMT_CVBS_PAL_I;
+                       p->std = V4L2_COLOR_STD_PAL | V4L2_STD_PAL_DK;
+                       p->frequency += 1;
+                       p->audmode = V4L2_STD_PAL_DK;
+
+                       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);
+
+                       usleep_range(20 * 1000, 20 * 1000 + 100);
+               }
+
+               std_bk = atvdemod_fe_tvin_fmt_to_v4l2_std(std_bk);
+       } else {
+               /* Only search std by user setting,
+                * so no need tvafe identify signal.
+                */
+               std_bk = p->std;
+       }
+
+       *video_fmt = std_bk;
+
+       if (!(auto_search_std & 0x02)) {
+               *audio_fmt = p->audmode;
+               return;
+       }
+
+       if (std_bk & V4L2_COLOR_STD_NTSC) {
+#if 1 /* For TV Signal Generator(TG39) test, NTSC need support other audio.*/
+               amlatvdemod_set_std(AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_DK);
+               audio = aml_audiomode_autodet(fe);
+               pr_info("autodet audmode 0x%x\n", audio);
+               audio = atvdemod_fmt_2_v4l2_std(audio);
+               pr_info("v4l2_std audmode 0x%x\n", audio);
+#if 0 /* I don't know what's going on here */
+               if (audio == V4L2_STD_PAL_M)
+                       audio = V4L2_STD_NTSC_M;
+               else
+                       std_bk = V4L2_COLOR_STD_PAL;
+#endif
+#else /* Now, force to NTSC_M, Ours demod only support M for NTSC.*/
+               audio = V4L2_STD_NTSC_M;
+               *video_fmt |= V4L2_STD_NTSC_M;
+#endif
+       } else if (std_bk & V4L2_COLOR_STD_SECAM) {
+#if 1 /* For support SECAM-DK/BG/I/L */
+               amlatvdemod_set_std(AML_ATV_DEMOD_VIDEO_MODE_PROP_SECAM_L);
+               audio = aml_audiomode_autodet(fe);
+               pr_info("autodet audmode 0x%x\n", audio);
+               audio = atvdemod_fmt_2_v4l2_std(audio);
+               pr_info("v4l2_std audmode 0x%x\n", audio);
+#else
+               audio = V4L2_STD_SECAM_L;
+#endif
+       } else {
+               /*V4L2_COLOR_STD_PAL*/
+               amlatvdemod_set_std(AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_DK);
+               audio = aml_audiomode_autodet(fe);
+               pr_info("autodet audmode 0x%x\n", audio);
+               audio = atvdemod_fmt_2_v4l2_std(audio);
+               pr_info("v4l2_std audmode 0x%x\n", audio);
+#if 0 /* Why do this to me? We need support PAL_M.*/
+               if (audio == V4L2_STD_PAL_M) {
+                       audio = atvdemod_fmt_2_v4l2_std(broad_std_except_pal_m);
+                       pr_info("select audmode 0x%x\n", audio);
+               }
+#endif
+       }
+
+       *audio_fmt = audio;
+}
+
+static int atvdemod_fe_afc_closer(struct v4l2_frontend *v4l2_fe, int minafcfreq,
+               int maxafcfreq, int isAutoSearch)
+{
+       struct dvb_frontend *fe = &v4l2_fe->fe;
+       struct v4l2_analog_parameters *p = &v4l2_fe->params;
+       struct analog_parameters params;
+       int afc = 100;
+       __u32 set_freq;
+       int count = 25;
+       int lock_cnt = 0;
+       static int freq_success;
+       static int temp_freq, temp_afc;
+       struct timespec time_now;
+       static struct timespec success_time;
+       unsigned int tuner_id = v4l2_fe->tuner_id;
+
+       pr_dbg("[%s] freq_success: %d, freq: %d, minfreq: %d, maxfreq: %d\n",
+               __func__, freq_success, p->frequency, minafcfreq, maxafcfreq);
+
+       /* avoid more search the same program, except < 45.00Mhz */
+       if (abs(p->frequency - freq_success) < 3000000
+                       && p->frequency > 45000000) {
+               ktime_get_ts(&time_now);
+               pr_err("[%s] tv_sec now:%ld,tv_sec success:%ld\n",
+                               __func__, time_now.tv_sec, success_time.tv_sec);
+               /* beyond 10s search same frequency is ok */
+               if ((time_now.tv_sec - success_time.tv_sec) < 10)
+                       return -1;
+       }
+
+       /*do the auto afc make sure the afc < 50k or the range from api */
+       if ((fe->ops.analog_ops.get_afc || fe->ops.tuner_ops.get_afc) &&
+               fe->ops.tuner_ops.set_analog_params) {
+
+               set_freq = p->frequency;
+               while (abs(afc) > AFC_BEST_LOCK) {
+                       if (tuner_id == AM_TUNER_SI2151 ||
+                               tuner_id == AM_TUNER_SI2159 ||
+                               tuner_id == AM_TUNER_R840)
+                               usleep_range(20 * 1000, 20 * 1000 + 100);
+                       else if (tuner_id == AM_TUNER_MXL661)
+                               usleep_range(30 * 1000, 30 * 1000 + 100);
+
+                       if (fe->ops.analog_ops.get_afc &&
+                       ((tuner_id == AM_TUNER_R840) ||
+                       (tuner_id == AM_TUNER_SI2151) ||
+                       (tuner_id == AM_TUNER_SI2159) ||
+                       (tuner_id == AM_TUNER_MXL661)))
+                               fe->ops.analog_ops.get_afc(fe, &afc);
+                       else if (fe->ops.tuner_ops.get_afc)
+                               fe->ops.tuner_ops.get_afc(fe, &afc);
+
+                       pr_dbg("[%s] get afc %d khz, freq %u.\n",
+                                       __func__, afc, p->frequency);
+
+                       if (afc == 0xffff) {
+                               /*last lock, but this unlock,so try get afc*/
+                               if (lock_cnt > 0) {
+                                       p->frequency = temp_freq +
+                                                       temp_afc * 1000;
+                                       pr_err("[%s] force lock, f:%d\n",
+                                                       __func__, p->frequency);
+                                       break;
+                               }
+
+                               afc = 500;
+                       } else {
+                               lock_cnt++;
+                               temp_freq = p->frequency;
+                               if (afc > 50)
+                                       temp_afc = 500;
+                               else if (afc < -50)
+                                       temp_afc = -500;
+                               else
+                                       temp_afc = afc;
+                       }
+
+                       if (((abs(afc) > (500 - AFC_BEST_LOCK))
+                               && (abs(afc) < (500 + AFC_BEST_LOCK))
+                               && (abs(afc) != 500))
+                               || ((abs(afc) == 500) && (lock_cnt > 0))) {
+                               p->frequency += afc * 1000;
+                               break;
+                       }
+
+                       if (afc >= (500 + AFC_BEST_LOCK))
+                               afc = 500;
+
+                       p->frequency += afc * 1000;
+
+                       if (unlikely(p->frequency > maxafcfreq)) {
+                               pr_err("[%s] [%d] is exceed maxafcfreq[%d]\n",
+                                       __func__, p->frequency, maxafcfreq);
+                               p->frequency = set_freq;
+                               return -1;
+                       }
+#if 0 /*if enable, it would miss program*/
+                       if (unlikely(c->frequency < minafcfreq)) {
+                               pr_dbg("[%s] [%d] is exceed minafcfreq[%d]\n",
+                                               __func__,
+                                               c->frequency, minafcfreq);
+                               c->frequency = set_freq;
+                               return -1;
+                       }
+#endif
+                       if (likely(!(count--))) {
+                               pr_err("[%s] exceed the afc count\n", __func__);
+                               p->frequency = set_freq;
+                               return -1;
+                       }
+
+                       /* delete it will miss program
+                        * when c->frequency equal program frequency
+                        */
+                       p->frequency++;
+                       if (fe->ops.tuner_ops.set_analog_params) {
+                               params.frequency = p->frequency;
+                               params.mode = p->afc_range;
+                               params.audmode = p->audmode;
+                               params.std = p->std;
+                               fe->ops.tuner_ops.set_analog_params(fe,
+                                               &params);
+                       }
+               }
+
+               freq_success = p->frequency;
+               ktime_get_ts(&success_time);
+               pr_dbg("[%s] get afc %d khz done, freq %u.\n",
+                               __func__, afc, p->frequency);
+       }
+
+       return 0;
+}
+
+static int atvdemod_fe_set_property(struct v4l2_frontend *v4l2_fe,
+               struct v4l2_property *tvp)
+{
+       struct dvb_frontend *fe = &amlatvdemod_devp->v4l2_fe.fe;
+       struct atv_demod_priv *priv = fe->analog_demod_priv;
+
+       pr_dbg("%s: cmd = 0x%x.\n", __func__, tvp->cmd);
+
+       switch (tvp->cmd) {
+       case V4L2_SOUND_SYS:
+               aud_mode = tvp->data & 0xFF;
+               priv->sound_sys.output_mode = tvp->data & 0xFF;
+               break;
+
+       case V4L2_SLOW_SEARCH_MODE:
+               tvp->data = slow_mode;
+               break;
+
+       default:
+               pr_dbg("%s: property %d doesn't exist\n",
+                               __func__, tvp->cmd);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int atvdemod_fe_get_property(struct v4l2_frontend *v4l2_fe,
+               struct v4l2_property *tvp)
+{
+       pr_dbg("%s: cmd = 0x%x.\n", __func__, tvp->cmd);
+
+       switch (tvp->cmd) {
+       case V4L2_SOUND_SYS:
+               tvp->data = ((aud_std  & 0xFF) << 16)
+                               | ((signal_audmode & 0xFF) << 8)
+                               | (aud_mode & 0xFF);
+               break;
+
+       case V4L2_SLOW_SEARCH_MODE:
+               slow_mode = tvp->data;
+               break;
+
+       default:
+               pr_dbg("%s: property %d doesn't exist\n",
+                               __func__, tvp->cmd);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static enum v4l2_search atvdemod_fe_search(struct v4l2_frontend *v4l2_fe)
+{
+       struct analog_parameters params;
+       struct dvb_frontend *fe = &v4l2_fe->fe;
+       struct v4l2_analog_parameters *p = &v4l2_fe->params;
+       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;
+       v4l2_std_id std_bk = 0;
+       unsigned int audio = 0;
+       int double_check_cnt = 1;
+       int auto_search_std = 0;
+       int search_count = 0;
+       bool try_secam = false;
+       int ret = -1;
+       unsigned int tuner_id = v4l2_fe->tuner_id;
+       int priv_cfg = 0;
+
+       if (unlikely(!fe || !p ||
+                       !fe->ops.tuner_ops.get_status ||
+                       !fe->ops.analog_ops.has_signal ||
+                       !fe->ops.analog_ops.set_params ||
+                       !fe->ops.analog_ops.set_config)) {
+               pr_err("[%s] error: NULL function or pointer.\n", __func__);
+               return V4L2_SEARCH_INVALID;
+       }
+
+       if (p->afc_range == 0) {
+               pr_err("[%s] afc_range == 0, skip the search\n", __func__);
+               return V4L2_SEARCH_INVALID;
+       }
+
+       pr_info("[%s] afc_range: [%d], tuner: [%d], freq: [%d], flag: [%d].\n",
+                       __func__, p->afc_range, tuner_id,
+                       p->frequency, p->flag);
+
+       /* backup the freq by api */
+       set_freq = p->frequency;
+
+       /* Before enter search, need set the std first.
+        * If set p->analog.std == 0, will search all std (PAL/NTSC/SECAM),
+        * and need tvafe identify signal type.
+        */
+       if (p->std == 0) {
+               p->std = V4L2_COLOR_STD_NTSC | V4L2_STD_NTSC_M;
+               auto_search_std = 0x01;
+               pr_dbg("[%s] user std is 0, so set it to NTSC | M.\n",
+                               __func__);
+       }
+
+       if (p->audmode == 0) {
+               if (auto_search_std)
+                       p->audmode = p->std & 0x00FFFFFF;
+               else {
+                       if (p->std & V4L2_COLOR_STD_PAL)
+                               p->audmode = V4L2_STD_PAL_DK;
+                       else if (p->std & V4L2_COLOR_STD_NTSC)
+                               p->audmode = V4L2_STD_NTSC_M;
+                       else if (p->std & V4L2_COLOR_STD_SECAM)
+                               p->audmode = V4L2_STD_PAL_DK;
+
+                       p->std = (p->std & 0xFF000000) | p->audmode;
+               }
+               auto_search_std |= 0x02;
+               pr_dbg("[%s] user audmode is 0, so set it to %s.\n",
+                               __func__, v4l2_std_to_str(p->audmode));
+       }
+
+       priv_cfg = AML_ATVDEMOD_SCAN_MODE;
+       fe->ops.analog_ops.set_config(fe, &priv_cfg);
+
+       /*set the afc_range and start freq*/
+       minafcfreq = p->frequency - p->afc_range;
+       maxafcfreq = p->frequency + p->afc_range;
+
+       /*from the current freq start, and set the afc_step*/
+       /*if step is 2Mhz,r840 will miss program*/
+       if (slow_mode || (tuner_id == AM_TUNER_R840)
+                       || (p->afc_range == ATV_AFC_1_0MHZ)) {
+               pr_dbg("[%s] slow mode to search the channel\n", __func__);
+               afc_step = ATV_AFC_1_0MHZ;
+       } else if (!slow_mode) {
+               afc_step = ATV_AFC_2_0MHZ;
+       } else {
+               pr_dbg("[%s] slow mode to search the channel\n", __func__);
+               afc_step = ATV_AFC_1_0MHZ;
+       }
+
+       /**enter auto search mode**/
+       pr_dbg("[%s] Auto search std: 0x%08x, audmode: 0x%08x\n",
+                       __func__, (unsigned int) p->std, p->audmode);
+
+       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) {
+                               usleep_range(20 * 1000, 20 * 1000 + 100);
+                               fe->ops.tuner_ops.get_status(fe,
+                                               &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)) ||
+                               ((ade_state == V4L2_HAS_LOCK &&
+                               tuner_state == V4L2_HAS_LOCK) &&
+                               (tuner_id == AM_TUNER_R840))) {
+                               pll_lock = true;
+                               break;
+                       }
+
+                       if (tuner_status_cnt_local == 0) {
+                               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;
+                               }
+
+                               break;
+                       }
+               } while (1);
+
+               std_bk = 0;
+               audio = 0;
+
+               if (pll_lock) {
+
+                       pr_dbg("[%s] freq: [%d] pll lock success\n",
+                                       __func__, p->frequency);
+#if 0 /* In get_pll_status has line_lock check.*/
+                       if (fee->tuner->drv->id == AM_TUNER_MXL661) {
+                               fe->ops.analog_ops.get_atv_status(fe,
+                                               &atv_status);
+                               if (atv_status.atv_lock)
+                                       usleep_range(30 * 1000,
+                                               30 * 1000 + 100);
+                       }
+#endif
+                       ret = atvdemod_fe_afc_closer(v4l2_fe, minafcfreq,
+                                       maxafcfreq + ATV_AFC_500KHZ, 1);
+                       if (ret == 0) {
+                               atvdemod_fe_try_analog_format(v4l2_fe,
+                                               auto_search_std,
+                                               &std_bk, &audio);
+
+                               pr_dbg("[%s] freq:%d, std_bk:0x%x, audmode:0x%x, search OK.\n",
+                                               __func__, p->frequency,
+                                               (unsigned int) std_bk, audio);
+
+                               if (std_bk != 0) {
+                                       p->audmode = audio;
+                                       p->std = std_bk;
+                                       /*avoid std unenable */
+                                       p->frequency -= 1;
+                                       std_bk = 0;
+                                       audio = 0;
+                               }
+
+                               /* sync param */
+                               /* aml_fe_analog_sync_frontend(fe); */
+                               priv_cfg = AML_ATVDEMOD_UNSCAN_MODE;
+                               fe->ops.analog_ops.set_config(fe, &priv_cfg);
+                               return V4L2_SEARCH_SUCCESS;
+                       }
+               }
+
+               /*avoid sound format is not match after search over */
+               if (std_bk != 0 && audio != 0) {
+                       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);
+                       std_bk = 0;
+                       audio = 0;
+               }
+
+               pr_dbg("[%s] freq[analog.std:0x%08x] is[%d] unlock\n",
+                               __func__,
+                               (uint32_t) p->std, p->frequency);
+
+               if (p->frequency >= 44200000 &&
+                       p->frequency <= 44300000 &&
+                       double_check_cnt) {
+                       double_check_cnt--;
+                       pr_err("%s 44.25Mhz double check\n", __func__);
+               } else {
+                       ++search_count;
+                       p->frequency += afc_step * ((search_count % 2) ?
+                                       -search_count : search_count);
+               }
+       }
+
+       pr_dbg("[%s] [%d] over of range [min=%d, max=%d], search failed.\n",
+                       __func__, p->frequency, minafcfreq, maxafcfreq);
+       p->frequency = set_freq;
+
+       priv_cfg = AML_ATVDEMOD_UNSCAN_MODE;
+       fe->ops.analog_ops.set_config(fe, &priv_cfg);
+
+       return DVBFE_ALGO_SEARCH_FAILED;
+}
+
+static struct v4l2_frontend_ops atvdemod_fe_ops = {
+       .set_property = atvdemod_fe_set_property,
+       .get_property = atvdemod_fe_get_property,
+       .search = atvdemod_fe_search,
+};
+
 struct dvb_frontend *aml_atvdemod_attach(struct dvb_frontend *fe,
+               struct v4l2_frontend *v4l2_fe,
                struct i2c_adapter *i2c_adap, u8 i2c_addr, u32 tuner_id)
 {
        int instance = 0;
@@ -763,6 +1460,9 @@ struct dvb_frontend *aml_atvdemod_attach(struct dvb_frontend *fe,
        memcpy(&fe->ops.analog_ops, &atvdemod_ops,
                        sizeof(struct analog_demod_ops));
 
+       memcpy(&v4l2_fe->ops, &atvdemod_fe_ops,
+                       sizeof(struct v4l2_frontend_ops));
+
        return fe;
 }
 EXPORT_SYMBOL(aml_atvdemod_attach);
index 43272b6..216fe1a 100644 (file)
 
 #include "atv_demod_driver.h"
 
+struct atv_demod_sound_system {
+       unsigned int broadcast_std;
+       unsigned int audio_std;
+       unsigned int input_mode;
+       unsigned int output_mode;
+};
+
 struct atv_demod_priv {
        struct tuner_i2c_props i2c_props;
        struct list_head hybrid_tuner_instance_list;
@@ -37,12 +44,15 @@ struct atv_demod_priv {
        bool standby;
 
        struct aml_atvdemod_parameters atvdemod_param;
+       struct atv_demod_sound_system sound_sys;
        struct work_struct demod_wq;
 };
 
 extern int atv_demod_enter_mode(void);
 
 struct dvb_frontend *aml_atvdemod_attach(struct dvb_frontend *fe,
+               struct v4l2_frontend *v4l2_fe,
                struct i2c_adapter *i2c_adap, u8 i2c_addr, u32 tuner_id);
 
+
 #endif /* __ATV_DEMOD_OPS_H__ */
index 07ca5e5..716a687 100644 (file)
 static DEFINE_MUTEX(v4l2_fe_mutex);
 /* static int v4l2_shutdown_timeout;*/
 
-unsigned int tuner_status_cnt = 8; /* 4-->16 test on sky mxl661 */
-
-bool slow_mode;
-
-typedef int (*hook_func_t) (void);
-hook_func_t aml_fe_hook_atv_status;
-hook_func_t aml_fe_hook_hv_lock;
-hook_func_t aml_fe_hook_get_fmt;
-
-void aml_fe_hook_cvd(hook_func_t atv_mode, hook_func_t cvd_hv_lock,
-       hook_func_t get_fmt)
-{
-       aml_fe_hook_atv_status = atv_mode;
-       aml_fe_hook_hv_lock = cvd_hv_lock;
-       aml_fe_hook_get_fmt = get_fmt;
-
-       pr_info("%s: OK.\n", __func__);
-}
-EXPORT_SYMBOL(aml_fe_hook_cvd);
-
-static v4l2_std_id demod_fmt_2_v4l2_std(int fmt)
-{
-       v4l2_std_id std = 0;
-
-       switch (fmt) {
-       case AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_DK:
-               std = V4L2_STD_PAL_DK;
-               break;
-       case AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_I:
-               std = V4L2_STD_PAL_I;
-               break;
-       case AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_BG:
-               std = V4L2_STD_PAL_BG;
-               break;
-       case AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_M:
-               std = V4L2_STD_PAL_M;
-               break;
-       case AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC_DK:
-       case AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC_I:
-       case AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC_BG:
-       case AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC:
-       case AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC_M:
-               std = V4L2_STD_NTSC_M;
-               break;
-       case AML_ATV_DEMOD_VIDEO_MODE_PROP_SECAM_L:
-               std = V4L2_STD_SECAM_L;
-               break;
-       case AML_ATV_DEMOD_VIDEO_MODE_PROP_SECAM_DK2:
-       case AML_ATV_DEMOD_VIDEO_MODE_PROP_SECAM_DK3:
-               std = V4L2_STD_SECAM_DK;
-               break;
-       default:
-               pr_err("%s: Unsupport fmt: 0x%0x.\n", __func__, fmt);
-       }
-
-       return std;
-}
-
-static v4l2_std_id trans_tvin_fmt_to_v4l2_std(int fmt)
-{
-       v4l2_std_id std = 0;
-
-       switch (fmt) {
-       case TVIN_SIG_FMT_CVBS_NTSC_M:
-               std = V4L2_COLOR_STD_NTSC | V4L2_STD_NTSC_M;
-               break;
-       case TVIN_SIG_FMT_CVBS_NTSC_443:
-               std = V4L2_COLOR_STD_NTSC | V4L2_STD_NTSC_443;
-               break;
-       case TVIN_SIG_FMT_CVBS_NTSC_50:
-               std = V4L2_COLOR_STD_NTSC | V4L2_STD_NTSC_M;
-               break;
-       case TVIN_SIG_FMT_CVBS_PAL_I:
-               std = V4L2_COLOR_STD_PAL | V4L2_STD_PAL_I;
-               break;
-       case TVIN_SIG_FMT_CVBS_PAL_M:
-               std = V4L2_COLOR_STD_PAL | V4L2_STD_PAL_M;
-               break;
-       case TVIN_SIG_FMT_CVBS_PAL_60:
-               std = V4L2_COLOR_STD_PAL | V4L2_STD_PAL_60;
-               break;
-       case TVIN_SIG_FMT_CVBS_PAL_CN:
-               std = V4L2_COLOR_STD_PAL | V4L2_STD_PAL_Nc;
-               break;
-       case TVIN_SIG_FMT_CVBS_SECAM:
-               std = V4L2_COLOR_STD_SECAM | V4L2_STD_SECAM_L;
-               break;
-       default:
-               pr_err("%s: Unsupport fmt: 0x%x\n", __func__, fmt);
-               break;
-       }
-
-       return std;
-}
-
-static void v4l2_fe_try_analog_format(struct v4l2_frontend *v4l2_fe,
-               int auto_search_std, v4l2_std_id *video_fmt,
-               unsigned int *audio_fmt)
-{
-       struct dvb_frontend *fe = &v4l2_fe->fe;
-       struct v4l2_analog_parameters *p = &v4l2_fe->params;
-       struct analog_parameters params;
-       int i = 0;
-       int try_vfmt_cnt = 300;
-       int varify_cnt = 0;
-       v4l2_std_id std_bk = 0;
-       unsigned int audio = 0;
-
-       if (auto_search_std & 0x01) {
-               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",
-                                               __func__);
-                               break;
-                       }
-                       std_bk = aml_fe_hook_get_fmt();
-                       if (std_bk) {
-                               varify_cnt++;
-                               pr_dbg("get varify_cnt:%d, cnt:%d, std_bk:0x%x\n",
-                                               varify_cnt, i,
-                                               (unsigned int) std_bk);
-                               if ((v4l2_fe->tuner_id == AM_TUNER_R840
-                                       && varify_cnt > 0)
-                                       || varify_cnt > 3)
-                                       break;
-                       }
-
-                       if (i == (try_vfmt_cnt / 3) ||
-                               (i == (try_vfmt_cnt / 3) * 2)) {
-                               /* Before enter search,
-                                * need set the std,
-                                * then, try others std.
-                                */
-                               if (p->std & V4L2_COLOR_STD_PAL)
-                                       p->std = V4L2_COLOR_STD_NTSC
-                                       | V4L2_STD_NTSC_M;
-/*
-                               else if (p->std & V4L2_COLOR_STD_NTSC)
-                                       p->std = V4L2_COLOR_STD_SECAM
-                                       | V4L2_STD_SECAM;
-*/
-                               else if (p->std & V4L2_COLOR_STD_NTSC)
-                                       p->std = V4L2_COLOR_STD_PAL
-                                       | V4L2_STD_PAL_DK;
-
-                               p->frequency += 1;
-                               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);
-                       }
-                       usleep_range(30 * 1000, 30 * 1000 + 100);
-               }
-
-               pr_dbg("get std_bk cnt:%d, std_bk: 0x%x\n",
-                               i, (unsigned int) std_bk);
-
-               if (std_bk == 0) {
-                       pr_err("%s: failed to get video fmt, assume PAL.\n",
-                                       __func__);
-                       std_bk = TVIN_SIG_FMT_CVBS_PAL_I;
-                       p->std = V4L2_COLOR_STD_PAL | V4L2_STD_PAL_DK;
-                       p->frequency += 1;
-                       p->audmode = V4L2_STD_PAL_DK;
-
-                       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);
-
-                       usleep_range(20 * 1000, 20 * 1000 + 100);
-               }
-
-               std_bk = trans_tvin_fmt_to_v4l2_std(std_bk);
-       } else {
-               /* Only search std by user setting,
-                * so no need tvafe identify signal.
-                */
-               std_bk = p->std;
-       }
-
-       *video_fmt = std_bk;
-
-       if (!(auto_search_std & 0x02)) {
-               *audio_fmt = p->audmode;
-               return;
-       }
-
-       if (std_bk & V4L2_COLOR_STD_NTSC) {
-#if 1 /* For TV Signal Generator(TG39) test, NTSC need support other audio.*/
-               amlatvdemod_set_std(AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_DK);
-               audio = aml_audiomode_autodet(fe);
-               pr_info("autodet audmode 0x%x\n", audio);
-               audio = demod_fmt_2_v4l2_std(audio);
-               pr_info("v4l2_std audmode 0x%x\n", audio);
-#if 0
-               if (audio == V4L2_STD_PAL_M)
-                       audio = V4L2_STD_NTSC_M;
-               else
-                       std_bk = V4L2_COLOR_STD_PAL;
-#endif
-#else /* Now, force to NTSC_M, Ours demod only support M for NTSC.*/
-               audio = V4L2_STD_NTSC_M;
-               *video_fmt |= V4L2_STD_NTSC_M;
-#endif
-       } else if (std_bk & V4L2_COLOR_STD_SECAM) {
-#if 1 /* For support SECAM-DK/BG/I/L */
-               amlatvdemod_set_std(AML_ATV_DEMOD_VIDEO_MODE_PROP_SECAM_L);
-               audio = aml_audiomode_autodet(fe);
-               pr_info("autodet audmode 0x%x\n", audio);
-               audio = demod_fmt_2_v4l2_std(audio);
-               pr_info("v4l2_std audmode 0x%x\n", audio);
-#else
-               audio = V4L2_STD_SECAM_L;
-#endif
-       } else {
-               /*V4L2_COLOR_STD_PAL*/
-               amlatvdemod_set_std(AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_DK);
-               audio = aml_audiomode_autodet(fe);
-               pr_info("autodet audmode 0x%x\n", audio);
-               audio = demod_fmt_2_v4l2_std(audio);
-               pr_info("v4l2_std audmode 0x%x\n", audio);
-#if 0 /* Why do this to me? We need support PAL_M.*/
-               if (audio == V4L2_STD_PAL_M) {
-                       audio = demod_fmt_2_v4l2_std(broad_std_except_pal_m);
-                       pr_info("select audmode 0x%x\n", audio);
-               }
-#endif
-       }
-
-       *audio_fmt = audio;
-}
-
-static int v4l2_fe_afc_closer(struct v4l2_frontend *v4l2_fe, int minafcfreq,
-               int maxafcfreq, int isAutoSearch)
-{
-       struct dvb_frontend *fe = &v4l2_fe->fe;
-       struct v4l2_analog_parameters *p = &v4l2_fe->params;
-       struct analog_parameters params;
-       int afc = 100;
-       __u32 set_freq;
-       int count = 25;
-       int lock_cnt = 0;
-       static int freq_success;
-       static int temp_freq, temp_afc;
-       struct timespec time_now;
-       static struct timespec success_time;
-       unsigned int tuner_id = v4l2_fe->tuner_id;
-
-       pr_dbg("[%s] freq_success: %d, freq: %d, minfreq: %d, maxfreq: %d\n",
-               __func__, freq_success, p->frequency, minafcfreq, maxafcfreq);
-
-       /* avoid more search the same program, except < 45.00Mhz */
-       if (abs(p->frequency - freq_success) < 3000000
-                       && p->frequency > 45000000) {
-               ktime_get_ts(&time_now);
-               pr_err("[%s] tv_sec now:%ld,tv_sec success:%ld\n",
-                               __func__, time_now.tv_sec, success_time.tv_sec);
-               /* beyond 10s search same frequency is ok */
-               if ((time_now.tv_sec - success_time.tv_sec) < 10)
-                       return -1;
-       }
-
-       /*do the auto afc make sure the afc<50k or the range from api */
-       if ((fe->ops.analog_ops.get_afc || fe->ops.tuner_ops.get_afc) &&
-               fe->ops.tuner_ops.set_analog_params) {
-
-               set_freq = p->frequency;
-               while (abs(afc) > AFC_BEST_LOCK) {
-                       if (tuner_id == AM_TUNER_SI2151 ||
-                               tuner_id == AM_TUNER_SI2159 ||
-                               tuner_id == AM_TUNER_R840)
-                               usleep_range(20 * 1000, 20 * 1000 + 100);
-                       else if (tuner_id == AM_TUNER_MXL661)
-                               usleep_range(30 * 1000, 30 * 1000 + 100);
-
-                       if (fe->ops.analog_ops.get_afc &&
-                       ((tuner_id == AM_TUNER_R840) ||
-                       (tuner_id == AM_TUNER_SI2151) ||
-                       (tuner_id == AM_TUNER_SI2159) ||
-                       (tuner_id == AM_TUNER_MXL661)))
-                               fe->ops.analog_ops.get_afc(fe, &afc);
-                       else if (fe->ops.tuner_ops.get_afc)
-                               fe->ops.tuner_ops.get_afc(fe, &afc);
-
-                       pr_dbg("[%s] get afc %d khz, freq %u.\n",
-                                       __func__, afc, p->frequency);
-
-                       if (afc == 0xffff) {
-                               /*last lock, but this unlock,so try get afc*/
-                               if (lock_cnt > 0) {
-                                       p->frequency = temp_freq +
-                                                       temp_afc * 1000;
-                                       pr_err("[%s] force lock, f:%d\n",
-                                                       __func__, p->frequency);
-                                       break;
-                               }
-
-                               afc = 500;
-                       } else {
-                               lock_cnt++;
-                               temp_freq = p->frequency;
-                               if (afc > 50)
-                                       temp_afc = 500;
-                               else if (afc < -50)
-                                       temp_afc = -500;
-                               else
-                                       temp_afc = afc;
-                       }
-
-                       if (((abs(afc) > (500 - AFC_BEST_LOCK))
-                               && (abs(afc) < (500 + AFC_BEST_LOCK))
-                               && (abs(afc) != 500))
-                               || ((abs(afc) == 500) && (lock_cnt > 0))) {
-                               p->frequency += afc * 1000;
-                               break;
-                       }
-
-                       if (afc >= (500 + AFC_BEST_LOCK))
-                               afc = 500;
-
-                       p->frequency += afc * 1000;
-
-                       if (unlikely(p->frequency > maxafcfreq)) {
-                               pr_err("[%s] [%d] is exceed maxafcfreq[%d]\n",
-                                       __func__, p->frequency, maxafcfreq);
-                               p->frequency = set_freq;
-                               return -1;
-                       }
-#if 0 /*if enable ,it would miss program*/
-                       if (unlikely(c->frequency < minafcfreq)) {
-                               pr_dbg("[%s] [%d] is exceed minafcfreq[%d]\n",
-                                      __func__, c->frequency, minafcfreq);
-                               c->frequency = set_freq;
-                               return -1;
-                       }
-#endif
-                       if (likely(!(count--))) {
-                               pr_err("[%s] exceed the afc count\n", __func__);
-                               p->frequency = set_freq;
-                               return -1;
-                       }
-
-                       /* delete it will miss program
-                        * when c->frequency equal program frequency
-                        */
-                       p->frequency++;
-                       if (fe->ops.tuner_ops.set_analog_params) {
-                               params.frequency = p->frequency;
-                               params.mode = p->afc_range;
-                               params.audmode = p->audmode;
-                               params.std = p->std;
-                               fe->ops.tuner_ops.set_analog_params(fe,
-                                               &params);
-                       }
-               }
-
-               freq_success = p->frequency;
-               ktime_get_ts(&success_time);
-               pr_dbg("[%s] get afc %d khz done, freq %u.\n",
-                               __func__, afc, p->frequency);
-       }
-
-       return 0;
-}
-
-static enum v4l2_search v4l2_frontend_search(struct v4l2_frontend *v4l2_fe)
-{
-       struct analog_parameters params;
-       struct dvb_frontend *fe = &v4l2_fe->fe;
-       struct v4l2_analog_parameters *p = &v4l2_fe->params;
-       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;
-       v4l2_std_id std_bk = 0;
-       unsigned int audio = 0;
-       int double_check_cnt = 1;
-       int auto_search_std = 0;
-       int search_count = 0;
-       bool try_secam = false;
-       int ret = -1;
-       unsigned int tuner_id = v4l2_fe->tuner_id;
-       int priv_cfg = 0;
-
-#ifdef DEBUG_TIME_CUS
-       unsigned int time_start, time_end, time_delta;
-
-       time_start = jiffies_to_msecs(jiffies);
-#endif
-
-       if (unlikely(!fe || !p ||
-                       !fe->ops.tuner_ops.get_status ||
-                       !fe->ops.analog_ops.has_signal ||
-                       !fe->ops.analog_ops.set_params ||
-                       !fe->ops.analog_ops.set_config)) {
-               pr_err("[%s] error: NULL function or pointer.\n", __func__);
-               return V4L2_SEARCH_INVALID;
-       }
-
-       if (p->afc_range == 0) {
-               pr_err("[%s] afc_range == 0, skip the search\n", __func__);
-               return V4L2_SEARCH_INVALID;
-       }
-
-       pr_info("[%s] afc_range: [%d], tuner: [%d], freq: [%d], flag: [%d].\n",
-                       __func__, p->afc_range, tuner_id,
-                       p->frequency, p->flag);
-
-       /* backup the freq by api */
-       set_freq = p->frequency;
-
-       /* Before enter search, need set the std first.
-        * If set p->analog.std == 0, will search all std (PAL/NTSC/SECAM),
-        * and need tvafe identify signal type.
-        */
-       if (p->std == 0) {
-               p->std = V4L2_COLOR_STD_NTSC | V4L2_STD_NTSC_M;
-               auto_search_std = 0x01;
-               pr_dbg("[%s] user std is 0, so set it to NTSC | M.\n",
-                               __func__);
-       }
-
-       if (p->audmode == 0) {
-               if (auto_search_std)
-                       p->audmode = p->std & 0x00FFFFFF;
-               else {
-                       if (p->std & V4L2_COLOR_STD_PAL)
-                               p->audmode = V4L2_STD_PAL_DK;
-                       else if (p->std & V4L2_COLOR_STD_NTSC)
-                               p->audmode = V4L2_STD_NTSC_M;
-                       else if (p->std & V4L2_COLOR_STD_SECAM)
-                               p->audmode = V4L2_STD_PAL_DK;
-
-                       p->std = (p->std & 0xFF000000) | p->audmode;
-               }
-               auto_search_std |= 0x02;
-               pr_dbg("[%s] user audmode is 0, so set it to %s.\n",
-                               __func__, v4l2_std_to_str(p->audmode));
-       }
-
-       priv_cfg = AML_ATVDEMOD_SCAN_MODE;
-       fe->ops.analog_ops.set_config(fe, &priv_cfg);
-
-       /*set the afc_range and start freq*/
-       minafcfreq = p->frequency - p->afc_range;
-       maxafcfreq = p->frequency + p->afc_range;
-
-       /*from the current freq start, and set the afc_step*/
-       /*if step is 2Mhz,r840 will miss program*/
-       if (slow_mode || (tuner_id == AM_TUNER_R840)
-                       || (p->afc_range == ATV_AFC_1_0MHZ)) {
-               pr_dbg("[%s] slow mode to search the channel\n", __func__);
-               afc_step = ATV_AFC_1_0MHZ;
-       } else if (!slow_mode) {
-               afc_step = ATV_AFC_2_0MHZ;
-       } else {
-               pr_dbg("[%s] slow mode to search the channel\n", __func__);
-               afc_step = ATV_AFC_1_0MHZ;
-       }
-
-       /**enter auto search mode**/
-       pr_dbg("[%s] Auto search std: 0x%08x, audmode: 0x%08x\n",
-                       __func__, (unsigned int) p->std, p->audmode);
-
-#ifdef DEBUG_TIME_CUS
-       time_end = jiffies_to_msecs(jiffies);
-       time_delta = time_end - time_start;
-       pr_dbg("[%s]: time_delta_001:%d ms,afc_step:%d\n",
-                       __func__, time_delta, afc_step);
-#endif
-
-       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) {
-                               usleep_range(20 * 1000, 20 * 1000 + 100);
-                               fe->ops.tuner_ops.get_status(fe,
-                                               &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)) ||
-                               ((ade_state == V4L2_HAS_LOCK &&
-                               tuner_state == V4L2_HAS_LOCK) &&
-                               (tuner_id == AM_TUNER_R840))) {
-                               pll_lock = true;
-                               break;
-                       }
-
-                       if (tuner_status_cnt_local == 0) {
-                               if (auto_search_std &&
-                                       !(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;
-                               }
-
-                               break;
-                       }
-               } while (1);
-
-               std_bk = 0;
-               audio = 0;
-
-               if (pll_lock) {
-
-                       pr_dbg("[%s] freq: [%d] pll lock success\n",
-                                       __func__, p->frequency);
-#if 0 /* In get_pll_status has line_lock check.*/
-                       if (fee->tuner->drv->id == AM_TUNER_MXL661) {
-                               fe->ops.analog_ops.get_atv_status(fe,
-                                               &atv_status);
-                               if (atv_status.atv_lock)
-                                       usleep_range(30 * 1000,
-                                               30 * 1000 + 100);
-                       }
-#endif
-                       ret = v4l2_fe_afc_closer(v4l2_fe, minafcfreq,
-                                       maxafcfreq + ATV_AFC_500KHZ, 1);
-                       if (ret == 0) {
-                               v4l2_fe_try_analog_format(v4l2_fe,
-                                               auto_search_std,
-                                               &std_bk, &audio);
-
-                               pr_dbg("[%s] freq:%d, std_bk:0x%x, audmode:0x%x, search OK.\n",
-                                               __func__, p->frequency,
-                                               (unsigned int) std_bk, audio);
-
-                               if (std_bk != 0) {
-                                       p->audmode = audio;
-                                       p->std = std_bk;
-                                       /*avoid std unenable */
-                                       p->frequency -= 1;
-                                       std_bk = 0;
-                                       audio = 0;
-                               }
-#ifdef DEBUG_TIME_CUS
-                               time_end = jiffies_to_msecs(jiffies);
-                               time_delta = time_end - time_start;
-                               pr_dbg("[%s] time_delta:%d ms\n",
-                                               __func__, time_delta);
-#endif
-                               /* sync param */
-                               /* aml_fe_analog_sync_frontend(fe); */
-                               priv_cfg = AML_ATVDEMOD_UNSCAN_MODE;
-                               fe->ops.analog_ops.set_config(fe, &priv_cfg);
-                               return V4L2_SEARCH_SUCCESS;
-                       }
-               }
-
-               /*avoid sound format is not match after search over */
-               if (std_bk != 0 && audio != 0) {
-                       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);
-                       std_bk = 0;
-                       audio = 0;
-               }
-
-               pr_dbg("[%s] freq[analog.std:0x%08x] is[%d] unlock\n",
-                               __func__,
-                               (uint32_t) p->std, p->frequency);
-
-               if (p->frequency >= 44200000 &&
-                       p->frequency <= 44300000 &&
-                       double_check_cnt) {
-                       double_check_cnt--;
-                       p->frequency -= afc_step;
-                       pr_err("%s 44.25Mhz double check\n", __func__);
-               } else {
-                       ++search_count;
-                       p->frequency += afc_step * ((search_count % 2) ?
-                                       -search_count : search_count);
-               }
-
-#ifdef DEBUG_TIME_CUS
-               time_end = jiffies_to_msecs(jiffies);
-               time_delta = time_end - time_start;
-               pr_dbg("[%s] time_delta:%d ms\n", __func__, time_delta);
-#endif
-       }
-
-#ifdef DEBUG_TIME_CUS
-       time_end = jiffies_to_msecs(jiffies);
-       time_delta = time_end - time_start;
-       pr_dbg("[%s] time_delta:%d ms\n", __func__, time_delta);
-#endif
-
-       pr_dbg("[%s] [%d] over of range [min=%d, max=%d], search failed.\n",
-                       __func__, p->frequency, minafcfreq, maxafcfreq);
-       p->frequency = set_freq;
-
-       priv_cfg = AML_ATVDEMOD_UNSCAN_MODE;
-       fe->ops.analog_ops.set_config(fe, &priv_cfg);
-
-       return DVBFE_ALGO_SEARCH_FAILED;
-}
-
 
 static int v4l2_frontend_get_event(struct v4l2_frontend *v4l2_fe,
                struct v4l2_frontend_event *event, int flags)
@@ -874,8 +208,9 @@ restart:
                 */
                if ((fepriv->algo_status & V4L2_SEARCH_AGAIN)
                        && !(fepriv->state & V4L2FE_STATE_IDLE)) {
-                       if (v4l2_fe->search) {
-                               fepriv->algo_status = v4l2_fe->search(v4l2_fe);
+                       if (v4l2_fe->ops.search) {
+                               fepriv->algo_status =
+                                               v4l2_fe->ops.search(v4l2_fe);
                        /* We did do a search as was requested,
                         * the flags are now unset as well and has
                         * the flags wrt to search.
@@ -1184,7 +519,14 @@ static int v4l2_property_process_set(struct v4l2_frontend *v4l2_fe,
        switch (tvp->cmd) {
        case V4L2_TUNE:
                break;
-       case V4L2_NICAM:
+       case V4L2_SOUND_SYS:
+       case V4L2_SLOW_SEARCH_MODE:
+               /* Allow the frontend to override outgoing properties */
+               if (v4l2_fe->ops.set_property) {
+                       r = v4l2_fe->ops.set_property(v4l2_fe, tvp);
+                       if (r < 0)
+                               return r;
+               }
                break;
        default:
                return -EINVAL;
@@ -1196,9 +538,17 @@ static int v4l2_property_process_set(struct v4l2_frontend *v4l2_fe,
 static int v4l2_property_process_get(struct v4l2_frontend *v4l2_fe,
                struct v4l2_property *tvp, struct file *file)
 {
+       int r = 0;
+
        switch (tvp->cmd) {
-       case V4L2_NICAM:
-               tvp->u.data = 0;
+       case V4L2_SOUND_SYS:
+       case V4L2_SLOW_SEARCH_MODE:
+               /* Allow the frontend to override outgoing properties */
+               if (v4l2_fe->ops.get_property) {
+                       r = v4l2_fe->ops.get_property(v4l2_fe, tvp);
+                       if (r < 0)
+                               return r;
+               }
                break;
 
        default:
@@ -1222,7 +572,7 @@ static int v4l2_frontend_ioctl_properties(struct file *filp,
        struct v4l2_property *tvp = NULL;
        int i = 0;
 
-       pr_dbg("%s.\n", __func__);
+       pr_dbg("%s: cmd = 0x%x.\n", __func__, cmd);
 
        if (cmd == V4L2_SET_PROPERTY) {
                pr_dbg("%s: properties.num = %d\n", __func__, tvps->num);
@@ -1244,7 +594,7 @@ static int v4l2_frontend_ioctl_properties(struct file *filp,
                                goto out;
                        (tvp + i)->result = err;
                }
-       } else if (cmd == FE_GET_PROPERTY) {
+       } else if (cmd == V4L2_GET_PROPERTY) {
                pr_dbg("%s: properties.num = %d\n", __func__, tvps->num);
                pr_dbg("%s: properties.props = %p\n", __func__, tvps->props);
 
@@ -1333,7 +683,7 @@ static long v4l2_frontend_ioctl(struct file *filp, void *fh, bool valid_prio,
                                filp->f_flags);
                break;
 
-       case V4L2_SET_MODE: /* 0x566c */
+       case V4L2_SET_MODE: /* 0x4004566c */
                ret = v4l2_frontend_set_mode(v4l2_fe, *((int *) arg));
                break;
 
@@ -1342,12 +692,13 @@ static long v4l2_frontend_ioctl(struct file *filp, void *fh, bool valid_prio,
                                (enum v4l2_status *) arg);
                break;
 
-       case V4L2_SET_PROPERTY:
-       case V4L2_GET_PROPERTY:
+       case V4L2_SET_PROPERTY: /* 0xc010566e */
+       case V4L2_GET_PROPERTY: /* 0xc010566f */
                ret = v4l2_frontend_ioctl_properties(filp, cmd, arg);
                break;
 
        default:
+               pr_warn("%s: Unsupport cmd = 0x%x.\n", __func__, cmd);
                break;
        }
 
@@ -1522,7 +873,6 @@ int v4l2_resister_frontend(struct v4l2_frontend *v4l2_fe)
                return -ENOMEM;
        }
 
-       v4l2_fe->search = v4l2_frontend_search;
        fepriv = v4l2_fe->frontend_priv;
 
        fepriv->v4l2dev = kzalloc(sizeof(struct v4l2_atvdemod_device),
index 396bba5..0f61126 100644 (file)
 #define V4L2_GET_EVENT       _IOR('V', 107, struct v4l2_frontend_event)
 #define V4L2_SET_MODE        _IOW('V', 108, int)
 #define V4L2_READ_STATUS     _IOR('V', 109, enum v4l2_status)
-#define V4L2_SET_PROPERTY    _IOW('V', 111, struct v4l2_properties)
-#define V4L2_GET_PROPERTY    _IOR('V', 112, struct v4l2_properties)
+#define V4L2_SET_PROPERTY    _IOWR('V', 110, struct v4l2_properties)
+#define V4L2_GET_PROPERTY    _IOWR('V', 111, struct v4l2_properties)
 
-#define ANALOG_FLAG_ENABLE_AFC          0X00000001
+#define ANALOG_FLAG_ENABLE_AFC          0x00000001
 #define ANALOG_FLAG_MANUL_SCAN          0x00000011
 
-#define V4L2_UNDEFINED    0
-#define V4L2_TUNE         1
-#define V4L2_NICAM        2
+#define V4L2_UNDEFINED           0
+#define V4L2_TUNE                1
+#define V4L2_SOUND_SYS           2
+#define V4L2_SLOW_SEARCH_MODE    3
 
 
+struct v4l2_frontend;
+
 struct v4l2_analog_parameters {
        unsigned int frequency;
        unsigned int audmode;
@@ -110,23 +113,17 @@ enum v4l2_status {
                                /* DiSEqC, tone and parameters */
 
 struct v4l2_property {
-       __u32 cmd;
-       __u32 reserved[3];
-       union {
-               __u32 data;
-               struct {
-                       __u8 data[32];
-                       __u32 len;
-                       __u32 reserved1[3];
-                       void *reserved2;
-               } buffer;
-       } u;
+       unsigned int cmd;
+       unsigned int data;
        int result;
-} __attribute__ ((__packed__));
+};
 
 struct v4l2_properties {
-       __u32 num;
-       struct v4l2_property *props;
+       unsigned int num;
+       union {
+               struct v4l2_property *props;
+               __u64 reserved;
+       };
 };
 
 enum v4l2_search {
@@ -181,6 +178,15 @@ struct v4l2_adapter {
        unsigned int tuner_id;
 };
 
+struct v4l2_frontend_ops {
+       int (*set_property)(struct v4l2_frontend *fe,
+                       struct v4l2_property *tvp);
+       int (*get_property)(struct v4l2_frontend *fe,
+                       struct v4l2_property *tvp);
+
+       enum v4l2_search (*search)(struct v4l2_frontend *v4l2_fe);
+};
+
 struct v4l2_frontend {
        struct device *dev;
 
@@ -190,11 +196,11 @@ struct v4l2_frontend {
 
        void *frontend_priv;
        void *tuner_priv;
-       void *analog_priv;
+       void *analog_demod_priv;
 
        struct v4l2_analog_parameters params;
 
-       enum v4l2_search (*search)(struct v4l2_frontend *v4l2_fe);
+       struct v4l2_frontend_ops ops;
 };
 
 struct v4l2_atvdemod_device {
@@ -209,8 +215,6 @@ struct v4l2_atvdemod_device {
 
        struct i2c_client i2c;
        unsigned int tuner_id;
-
-       enum v4l2_search (*search)(struct v4l2_atvdemod_device *dev);
 };
 
 int v4l2_resister_frontend(struct v4l2_frontend *v4l2_fe);
index ab525ed..8a5d250 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 
 #include <linux/amlogic/iomap.h>
 #include <linux/amlogic/cpu_version.h>
@@ -11,6 +12,8 @@
 #include "atv_demod_debug.h"
 #include "atvauddemod_func.h"
 #include "aud_demod_settings.c"
+#include "atvdemod_func.h"
+#include "atv_demod_driver.h"
 
 /* #define AUDIO_MOD_DET_INTERNAL */
 
 unsigned int ademod_debug_en;
 /* btsc_detect_delay for btsc detect delay */
 unsigned int btsc_detect_delay = 10;
+unsigned int nicam_detect_delay = 10;
 /* signal_audmode for btsc signal audio mode */
 unsigned int signal_audmode;
 unsigned int audio_thd_threshold1 = 0x1000;
 unsigned int audio_thd_threshold2 = 0xf00;
 
+unsigned int audio_a2_auto = 1;
+unsigned int audio_a2_power_threshold = 0x1800;
+
 #undef pr_info
 #define pr_info(args...)\
        do {\
@@ -420,7 +427,7 @@ void set_a2g(void)
 
        aa = (int)((54.6875e3+117.5)/(FCLK/16/4)*1024.0*1024.0*8.0);
        adec_wr_reg(ADDR_INDICATOR_STEREO_DTO, aa);
-       aa = (int)((54.6875e3+27)/(FCLK/16/44.1)*1024.0*1024.0*8.0);
+       aa = (int)((54.6875e3+274.1)/(FCLK/16/4)*1024.0*1024.0*8.0);
        adec_wr_reg(ADDR_INDICATOR_DUAL_DTO, aa);
        aa = (int)((54.6875e3)/(FCLK/16/4)*1024.0*1024.0*8.0);
        adec_wr_reg(ADDR_INDICATOR_CENTER_DTO, aa);
@@ -454,7 +461,7 @@ void set_a2bg(void)
 
        aa = (int)((54.6875e3+117.5)/(FCLK/16/4)*1024.0*1024.0*8.0);
        adec_wr_reg(ADDR_INDICATOR_STEREO_DTO, aa);
-       aa = (int)((54.6875e3+27)/(FCLK/16/44.1)*1024.0*1024.0*8.0);
+       aa = (int)((54.6875e3+274.1)/(FCLK/16/4)*1024.0*1024.0*8.0);
        adec_wr_reg(ADDR_INDICATOR_DUAL_DTO, aa);
        aa = (int)((54.6875e3)/(FCLK/16/4)*1024.0*1024.0*8.0);
        adec_wr_reg(ADDR_INDICATOR_CENTER_DTO, aa);
@@ -488,7 +495,7 @@ void set_a2dk1(void)
 
        aa = (int)((54.6875e3+117.5)/(FCLK/16/4)*1024.0*1024.0*8.0);
        adec_wr_reg(ADDR_INDICATOR_STEREO_DTO, aa);
-       aa = (int)((54.6875e3+27)/(FCLK/16/44.1)*1024.0*1024.0*8.0);
+       aa = (int)((54.6875e3+274.1)/(FCLK/16/4)*1024.0*1024.0*8.0);
        adec_wr_reg(ADDR_INDICATOR_DUAL_DTO, aa);
        aa = (int)((54.6875e3)/(FCLK/16/4)*1024.0*1024.0*8.0);
        adec_wr_reg(ADDR_INDICATOR_CENTER_DTO, aa);
@@ -522,7 +529,7 @@ void set_a2dk2(void)
 
        aa = (int)((54.6875e3+117.5)/(FCLK/16/4)*1024.0*1024.0*8.0);
        adec_wr_reg(ADDR_INDICATOR_STEREO_DTO, aa);
-       aa = (int)((54.6875e3+27)/(FCLK/16/44.1)*1024.0*1024.0*8.0);
+       aa = (int)((54.6875e3+274.1)/(FCLK/16/4)*1024.0*1024.0*8.0);
        adec_wr_reg(ADDR_INDICATOR_DUAL_DTO, aa);
        aa = (int)((54.6875e3)/(FCLK/16/4)*1024.0*1024.0*8.0);
        adec_wr_reg(ADDR_INDICATOR_CENTER_DTO, aa);
@@ -556,7 +563,7 @@ void set_a2dk3(void)
 
        aa = (int)((54.6875e3+117.5)/(FCLK/16/4)*1024.0*1024.0*8.0);
        adec_wr_reg(ADDR_INDICATOR_STEREO_DTO, aa);
-       aa = (int)((54.6875e3+27)/(FCLK/16/44.1)*1024.0*1024.0*8.0);
+       aa = (int)((54.6875e3+274.1)/(FCLK/16/4)*1024.0*1024.0*8.0);
        adec_wr_reg(ADDR_INDICATOR_DUAL_DTO, aa);
        aa = (int)((54.6875e3)/(FCLK/16/4)*1024.0*1024.0*8.0);
        adec_wr_reg(ADDR_INDICATOR_CENTER_DTO, aa);
@@ -788,25 +795,40 @@ void update_a2_eiaj_mode(int auto_en, int *stereo_flag, int *dual_flag)
        uint32_t stereo_power, dual_power;
 
        if (auto_en) {
-               reg_value = adec_rd_reg(AUDIO_MODE_REPORT);
-               *stereo_flag = reg_value&0x1;
-               *dual_flag = (reg_value>>1)&0x1;
+               reg_value = adec_rd_reg(CARRIER_MAG_REPORT);
+               if (((reg_value >> 16) & 0xffff) < 0x400) {
+                       *stereo_flag = 0;
+                       *dual_flag = 0;
+               } else {
+                       reg_value = adec_rd_reg(AUDIO_MODE_REPORT);
+                       *stereo_flag = reg_value&0x1;
+                       *dual_flag = (reg_value>>1)&0x1;
+               }
        } else {
                reg_value = adec_rd_reg(POWER_REPORT);
                stereo_power = reg_value & 0xffff;
                dual_power = (reg_value >> 16) & 0xffff;
 
-               if (stereo_power > dual_power && stereo_power > 0x1800)
+               if (stereo_power > dual_power &&
+                       stereo_power > audio_a2_power_threshold)
                        *stereo_flag = 1;
                else
                        *stereo_flag = 0;
 
-               if (stereo_power < dual_power && dual_power > 0x1800)
+               if (stereo_power < dual_power &&
+                       dual_power > audio_a2_power_threshold)
                        *dual_flag = 1;
                else
                        *dual_flag = 0;
        }
 
+       /* 0:MONO 1:Stereo 2:Dual */
+       if (*dual_flag == 0 && *stereo_flag == 0)
+               signal_audmode = 0;
+       else if (*stereo_flag)
+               signal_audmode = 1;
+       else if (*dual_flag)
+               signal_audmode = 2;
 }
 
 void update_btsc_mode(int auto_en, int *stereo_flag, int *sap_flag)
@@ -814,7 +836,7 @@ void update_btsc_mode(int auto_en, int *stereo_flag, int *sap_flag)
        uint32_t reg_value;
        uint32_t stereo_level, sap_level;
 
-       msleep(btsc_detect_delay);
+       mdelay(btsc_detect_delay);
        if (auto_en) {
                reg_value = adec_rd_reg(AUDIO_MODE_REPORT);
                *stereo_flag = reg_value&0x1;
@@ -845,30 +867,91 @@ void update_btsc_mode(int auto_en, int *stereo_flag, int *sap_flag)
 void update_nicam_mode(int *nicam_flag, int *nicam_mono_flag,
                int *nicam_stereo_flag, int *nicam_dual_flag)
 {
-       uint32_t reg_value;
-       int nicam_lock;
-       int cic;
+       uint32_t reg_value = 0;
+       int nicam_lock = 0;
+       int cic = 0;
+
+       mdelay(nicam_detect_delay);
 
-       reg_value = adec_rd_reg(0x1a3);
+       reg_value = adec_rd_reg(NICAM_LEVEL_REPORT);
        nicam_lock = (reg_value>>28)&1;
-       reg_value = adec_rd_reg(0x1a4);
+       reg_value = adec_rd_reg(NICAM_MODE_REPORT);
        cic = (reg_value>>17)&3;
 
        *nicam_flag = nicam_lock;
        *nicam_mono_flag = (cic == 1) && nicam_lock;
        *nicam_stereo_flag = (cic == 0) && nicam_lock;
        *nicam_dual_flag = (cic == 2) && nicam_lock;
+
+       /* 0:MONO 1:Stereo 2:Dual 3:NICAM MONO */
+       if (*nicam_mono_flag)
+               signal_audmode = 3;
+       else if (*nicam_stereo_flag)
+               signal_audmode = 1;
+       else if (*nicam_dual_flag)
+               signal_audmode = 2;
+       else
+               signal_audmode = 0;
 }
 
 void set_btsc_outputmode(uint32_t outmode)
 {
-       uint32_t reg_value;
-       uint32_t tmp_value, tmp_value1;
-       int stereo_flag, sap_flag;
+       uint32_t reg_value = 0;
+       uint32_t tmp_value = 0, tmp_value1 = 0;
+       int stereo_flag = 0, sap_flag = 0;
+       static int last_stereo_flag = -1, last_sap_flag = -1, last_mode = -1;
 
        update_btsc_mode(1, &stereo_flag, &sap_flag);
+
+       /* ADEC_CTRL: 0x10
+        * bits[8]: Audio_mute, 1 = mute, 0 = not mute.
+        * bits[7:4]: Output select control.
+        * 0 = nicam mono / dual first.
+        * 1 = stereo / dual first + second.
+        * 2 = dual second.
+        * 3 = fm mono.
+        * bits[3:0]: Std_sel.
+        */
        reg_value = adec_rd_reg(ADDR_ADEC_CTRL);
 
+       if (last_stereo_flag == stereo_flag
+                       && last_sap_flag == sap_flag
+                       && last_mode == outmode)
+               return;
+
+       /* priority: Stereo > MONO > SAP */
+       /* 0:MONO 1:Stereo 2:MONO+SAP 3:Stereo+SAP */
+       switch (signal_audmode) {
+       case 0: /* MONO */
+               if (outmode != AUDIO_OUTMODE_BTSC_MONO) {
+                       outmode = AUDIO_OUTMODE_BTSC_MONO;
+                       aud_mode = AUDIO_OUTMODE_BTSC_MONO;
+               }
+               break;
+       case 1: /* Stereo */
+               if (outmode != AUDIO_OUTMODE_BTSC_MONO &&
+                       outmode != AUDIO_OUTMODE_BTSC_STEREO) {
+                       outmode = AUDIO_OUTMODE_BTSC_STEREO;
+                       aud_mode = AUDIO_OUTMODE_BTSC_STEREO;
+               }
+               break;
+       case 2: /* MONO+SAP */
+               if (outmode != AUDIO_OUTMODE_BTSC_MONO &&
+                       outmode != AUDIO_OUTMODE_BTSC_SAP) {
+                       outmode = AUDIO_OUTMODE_BTSC_MONO;
+                       aud_mode = AUDIO_OUTMODE_BTSC_MONO;
+               }
+               break;
+       case 3: /* Stereo+SAP */
+               if (outmode != AUDIO_OUTMODE_BTSC_MONO &&
+                       outmode != AUDIO_OUTMODE_BTSC_SAP &&
+                       outmode != AUDIO_OUTMODE_BTSC_STEREO) {
+                       outmode = AUDIO_OUTMODE_BTSC_STEREO;
+                       aud_mode = AUDIO_OUTMODE_BTSC_STEREO;
+               }
+               break;
+       }
+
        switch (outmode) {
        case AUDIO_OUTMODE_BTSC_MONO:
                tmp_value = (reg_value & 0xf) | (0 << 4);
@@ -913,17 +996,66 @@ void set_btsc_outputmode(uint32_t outmode)
                }
                break;
        }
+
+       last_stereo_flag = stereo_flag;
+       last_sap_flag = sap_flag;
+       last_mode = outmode;
 }
 
 void set_a2_eiaj_outputmode(uint32_t outmode)
 {
        uint32_t reg_value = 0;
        uint32_t tmp_value = 0;
-       int stereo_flag, dual_flag;
-
-       update_a2_eiaj_mode(1, &stereo_flag, &dual_flag);
+       int stereo_flag = 0, dual_flag = 0;
+       static int last_stereo_flag = -1, last_dual_flag = -1, last_mode = -1;
+
+       update_a2_eiaj_mode(audio_a2_auto, &stereo_flag, &dual_flag);
+
+       /* ADEC_CTRL: 0x10
+        * bits[8]: Audio_mute, 1 = mute, 0 = not mute.
+        * bits[7:4]: Output select control.
+        * 0 = nicam mono / dual first.
+        * 1 = stereo / dual first + second.
+        * 2 = dual second.
+        * 3 = fm mono.
+        * bits[3:0]: Std_sel.
+        */
        reg_value = adec_rd_reg(ADDR_ADEC_CTRL);
 
+       if (last_stereo_flag == stereo_flag
+                       && last_dual_flag == dual_flag
+                       && last_mode == outmode)
+               return;
+
+       set_output_left_right_exchange(1);
+
+       /* priority: Stereo > NICAM MONO > Dual > FM MONO */
+       /* 0:MONO 1:Stereo 2:Dual */
+       switch (signal_audmode) {
+       case 0: /* MONO */
+               if (outmode != AUDIO_OUTMODE_A2_MONO) {
+                       outmode = AUDIO_OUTMODE_A2_MONO;
+                       aud_mode = AUDIO_OUTMODE_A2_MONO;
+               }
+               break;
+       case 1: /* Stereo */
+               if (outmode != AUDIO_OUTMODE_A2_MONO &&
+                       outmode != AUDIO_OUTMODE_A2_STEREO) {
+                       outmode = AUDIO_OUTMODE_A2_STEREO;
+                       aud_mode = AUDIO_OUTMODE_A2_STEREO;
+               }
+               break;
+       case 2: /* Dual */
+               if (outmode != AUDIO_OUTMODE_A2_MONO &&
+                       outmode != AUDIO_OUTMODE_A2_DUAL_A &&
+                       outmode != AUDIO_OUTMODE_A2_DUAL_B &&
+                       outmode != AUDIO_OUTMODE_A2_DUAL_AB) {
+                       outmode = AUDIO_OUTMODE_A2_DUAL_A;
+                       aud_mode = AUDIO_OUTMODE_A2_DUAL_A;
+               }
+               break;
+       }
+
        switch (outmode) {
        case AUDIO_OUTMODE_A2_MONO:
                tmp_value = (reg_value&0xf)|(0<<4);
@@ -931,134 +1063,165 @@ void set_a2_eiaj_outputmode(uint32_t outmode)
                break;
 
        case AUDIO_OUTMODE_A2_STEREO:
-               if (stereo_flag) {
-                       tmp_value = (reg_value&0xf)|(1<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               } else {
-                       tmp_value = (reg_value&0xf)|(0<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               }
+               tmp_value = (reg_value&0xf)|(1<<4);
+               adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
+               set_output_left_right_exchange(0);
                break;
 
        case AUDIO_OUTMODE_A2_DUAL_A:
-               if (stereo_flag) {
-                       tmp_value = (reg_value&0xf)|(1<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               } else if (dual_flag) {
-                       tmp_value = (reg_value&0xf)|(0<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               } else {
-                       tmp_value = (reg_value&0xf)|(0<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               }
+               tmp_value = (reg_value&0xf)|(0<<4);
+               adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
                break;
 
        case AUDIO_OUTMODE_A2_DUAL_B:
-               if (stereo_flag) {
-                       tmp_value = (reg_value&0xf)|(1<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               } else if (dual_flag) {
-                       tmp_value = (reg_value&0xf)|(2<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               } else {
-                       tmp_value = (reg_value&0xf)|(0<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               }
+               tmp_value = (reg_value&0xf)|(2<<4);
+               adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
                break;
 
        case AUDIO_OUTMODE_A2_DUAL_AB:
-               if (stereo_flag) {
-                       tmp_value = (reg_value&0xf)|(1<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               } else if (dual_flag) {
-                       tmp_value = (reg_value&0xf)|(3<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               } else {
-                       tmp_value = (reg_value&0xf)|(0<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               }
+               tmp_value = (reg_value&0xf)|(3<<4);
+               adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
+               set_output_left_right_exchange(0);
                break;
        }
+
+       last_stereo_flag = stereo_flag;
+       last_dual_flag = dual_flag;
+       last_mode = outmode;
 }
 
 void set_nicam_outputmode(uint32_t outmode)
 {
        uint32_t reg_value = 0;
        uint32_t tmp_value = 0;
-       int nicam_mono_flag, nicam_stereo_flag, nicam_dual_flag;
-       int nicam_lock;
+       int nicam_mono_flag = 0, nicam_stereo_flag = 0, nicam_dual_flag = 0;
+       int nicam_lock = 0;
+       static int last_nicam_lock = -1, last_mono_flag = -1;
+       static int last_stereo_flag = -1, last_dual_flag = -1, last_mode = -1;
 
        update_nicam_mode(&nicam_lock, &nicam_mono_flag,
                        &nicam_stereo_flag, &nicam_dual_flag);
 
+       /* ADEC_CTRL: 0x10
+        * bits[8]: Audio_mute, 1 = mute, 0 = not mute.
+        * bits[7:4]: Output select control.
+        * 0 = nicam mono / dual first.
+        * 1 = stereo / dual first + second.
+        * 2 = dual second.
+        * 3 = fm mono.
+        * bits[3:0]: Std_sel.
+        */
        reg_value = adec_rd_reg(ADDR_ADEC_CTRL);
+
        pr_info("%s nicam_lock:%d, regval:0x%x\n",
                        __func__, nicam_lock, reg_value);
-       switch (outmode) {
-       case AUDIO_OUTMODE_NICAM_MONO:
-               if (nicam_lock) {
-                       tmp_value = (reg_value&0xf)|(0<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               } else {
-                       tmp_value = (reg_value&0xf)|(3<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
+
+       if (last_nicam_lock == nicam_lock
+                       && last_mono_flag == nicam_mono_flag
+                       && last_stereo_flag == nicam_stereo_flag
+                       && last_dual_flag == nicam_dual_flag
+                       && last_mode == outmode)
+               return;
+
+       set_output_left_right_exchange(1);
+
+       /* priority: Stereo > NICAM MONO > Dual > FM MONO */
+       /* 0:FM MONO 1:Stereo 2:Dual 3:NICAM MONO */
+       switch (signal_audmode) {
+       case 0: /* FM MONO */
+               if (outmode != AUDIO_OUTMODE_NICAM_MONO) {
+                       outmode = AUDIO_OUTMODE_NICAM_MONO;
+                       aud_mode = AUDIO_OUTMODE_NICAM_MONO;
                }
                break;
-
-       case AUDIO_OUTMODE_NICAM_MONO1:
-               if (nicam_lock) {
-                       tmp_value = (reg_value&0xf)|(0<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               } else {
-                       tmp_value = (reg_value&0xf)|(3<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
+       case 1: /* Stereo */
+               if (outmode != AUDIO_OUTMODE_NICAM_MONO &&
+                       outmode != AUDIO_OUTMODE_NICAM_STEREO) {
+                       outmode = AUDIO_OUTMODE_NICAM_STEREO;
+                       aud_mode = AUDIO_OUTMODE_NICAM_STEREO;
+               }
+               break;
+       case 2: /* Dual */
+               if (outmode != AUDIO_OUTMODE_NICAM_MONO &&
+                       outmode != AUDIO_OUTMODE_NICAM_DUAL_A &&
+                       outmode != AUDIO_OUTMODE_NICAM_DUAL_B &&
+                       outmode != AUDIO_OUTMODE_NICAM_DUAL_AB) {
+                       outmode = AUDIO_OUTMODE_NICAM_DUAL_A;
+                       aud_mode = AUDIO_OUTMODE_NICAM_DUAL_A;
+               }
+               break;
+       case 3: /* NICAM MONO */
+               if (outmode != AUDIO_OUTMODE_NICAM_MONO &&
+                       outmode != AUDIO_OUTMODE_NICAM_MONO1) {
+                       outmode = AUDIO_OUTMODE_NICAM_MONO1;
+                       aud_mode = AUDIO_OUTMODE_NICAM_MONO1;
                }
                break;
+       }
+
+       switch (outmode) {
+       case AUDIO_OUTMODE_NICAM_MONO:/* fm mono */
+               if (aud_std == AUDIO_STANDARD_NICAM_BG)
+                       tmp_value = (AUDIO_STANDARD_A2_BG & 0xf) | (0 << 4);
+               else if (aud_std == AUDIO_STANDARD_NICAM_DK)
+                       tmp_value = (AUDIO_STANDARD_A2_DK2 & 0xf) | (0 << 4);
+               else if (aud_std == AUDIO_STANDARD_NICAM_I)
+                       tmp_value = (AUDIO_STANDARD_CHINA & 0xf) | (0 << 4);
+               else if (aud_std == AUDIO_STANDARD_NICAM_L)
+                       tmp_value = (AUDIO_STANDARD_MONO_ONLY & 0xf) | (0 << 4);
+               adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
+               break;
+
+       case AUDIO_OUTMODE_NICAM_MONO1:/* nicam mono */
+               if ((reg_value & 0xf) != (aud_std & 0xf))
+                       reg_value = (reg_value & ~0xf) | (aud_std & 0xf);
+
+               tmp_value = (reg_value&0xf)|(0<<4);
+               adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
+               break;
 
        case AUDIO_OUTMODE_NICAM_STEREO:
-               if (nicam_lock && nicam_stereo_flag) {
-                       tmp_value = (reg_value&0xf)|(1<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               } else if (nicam_lock && !nicam_stereo_flag) {
-                       tmp_value = (reg_value&0xf)|(0<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               } else {
-                       tmp_value = (reg_value&0xf)|(3<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               }
+               if ((reg_value & 0xf) != (aud_std & 0xf))
+                       reg_value = (reg_value & ~0xf) | (aud_std & 0xf);
+
+               tmp_value = (reg_value&0xf)|(1<<4);
+               adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
+               set_output_left_right_exchange(0);
                break;
 
        case AUDIO_OUTMODE_NICAM_DUAL_A:
-               if (nicam_lock) {
-                       tmp_value = (reg_value&0xf)|(0<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               } else {
-                       tmp_value = (reg_value&0xf)|(3<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               }
+               if ((reg_value & 0xf) != (aud_std & 0xf))
+                       reg_value = (reg_value & ~0xf) | (aud_std & 0xf);
+
+               tmp_value = (reg_value&0xf)|(0<<4);
+               adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
                break;
 
        case AUDIO_OUTMODE_NICAM_DUAL_B:
-               if (nicam_lock) {
-                       tmp_value = (reg_value&0xf)|(2<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               } else {
-                       tmp_value = (reg_value&0xf)|(3<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               }
+               if ((reg_value & 0xf) != (aud_std & 0xf))
+                       reg_value = (reg_value & ~0xf) | (aud_std & 0xf);
+
+               tmp_value = (reg_value&0xf)|(2<<4);
+               adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
                break;
 
        case AUDIO_OUTMODE_NICAM_DUAL_AB:
-               if (nicam_lock) {
-                       tmp_value = (reg_value&0xf)|(1<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               } else {
-                       tmp_value = (reg_value&0xf)|(3<<4);
-                       adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
-               }
+               if ((reg_value & 0xf) != (aud_std & 0xf))
+                       reg_value = (reg_value & ~0xf) | (aud_std & 0xf);
+
+               tmp_value = (reg_value&0xf)|(1<<4);
+               adec_wr_reg(ADDR_ADEC_CTRL, tmp_value);
+               set_output_left_right_exchange(0);
                break;
        }
-       pr_info("%s tmp_value :0x%x\n", __func__, reg_value);
+
+       pr_info("[%s] tmp_value: 0x%x.\n", __func__, reg_value);
+
+       last_nicam_lock = nicam_lock;
+       last_mono_flag = nicam_mono_flag;
+       last_stereo_flag = nicam_stereo_flag;
+       last_dual_flag = nicam_dual_flag;
+       last_mode = outmode;
 }
 
 void set_outputmode(uint32_t standard, uint32_t outmode)
@@ -1259,4 +1422,18 @@ void audio_mode_det(int mode)
        }
 }
 
+void set_output_left_right_exchange(unsigned int ch)
+{
+       unsigned int read = 0;
+
+       if (amlatvdemod_devp->audio_demod_reg_base == NULL)
+               return;
+
+       read = readl(amlatvdemod_devp->audio_demod_reg_base);
+
+       if ((read & (1 << 2)) != ((ch & 0x01) << 2))
+               writel((read & ~(1 << 2)) | ((ch & 0x01) << 2),
+                               amlatvdemod_devp->audio_demod_reg_base);
+}
+
 #endif /* __ATVAUDDEMOD_FUN_H */
index 4407241..497a81b 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "aud_demod_reg.h"
 
+extern unsigned int signal_audmode;
 
 extern int atvaudiodem_reg_read(unsigned int reg, unsigned int *val);
 extern int atvaudiodem_reg_write(unsigned int reg, unsigned int val);
@@ -28,4 +29,6 @@ void update_nicam_mode(int *nicam_flag, int *nicam_mono_flag,
 void update_btsc_mode(int auto_en, int *stereo_flag, int *sap_flag);
 void update_a2_eiaj_mode(int auto_en, int *stereo_flag, int *dual_flag);
 
+void set_output_left_right_exchange(unsigned int ch);
+
 #endif /* __ATVAUDDEMOD_H_ */
index e0d2716..1ceb80b 100644 (file)
@@ -95,7 +95,7 @@ unsigned int reg_dbg_en;
 unsigned int audio_gain_val = 512;
 unsigned int audio_a2_threshold = 0x800;
 unsigned int audio_a2_delay = 10;
-
+unsigned int audio_nicam_delay = 100;
 
 enum AUDIO_SCAN_ID {
        ID_PAL_I = 0,
@@ -1369,10 +1369,10 @@ void retrieve_vpll_carrier_line_lock(int *lock)
        data = atv_dmd_rd_byte(APB_BLOCK_ADDR_VDAGC, 0x4f);
        line_lock = data & 0x10;
        line_lock_strong = data & 0x8;
-
-       pr_dbg("line_lock = 0x%x, line_lock_strong = 0x%x\n",
-                       line_lock, line_lock_strong);
-
+       /*
+        * pr_dbg("line_lock = 0x%x, line_lock_strong = 0x%x\n",
+        * line_lock, line_lock_strong);
+        */
        *lock = (line_lock | line_lock_strong);
 }
 
@@ -1395,7 +1395,7 @@ void retrieve_vpll_carrier_audio_power(int *power)
                *power = data & 0xffff;
        }
 
-       pr_dbg("retrieve_vpll_carrier_audio_power: %d.\n", *power);
+       pr_audio("retrieve_vpll_carrier_audio_power: %d.\n", *power);
 }
 
 int retrieve_vpll_carrier_afc(void)
@@ -1670,9 +1670,12 @@ void atvdemod_timer_handler(unsigned long arg)
                atvdemod_det_snr_serice();
        if (audio_thd_en)
                audio_thd_det();
+/*
        if (aml_atvdemod_get_btsc_sap_mode() == 1 &&
                        aud_std == AUDIO_STANDARD_BTSC)
                audio_mode_det(aud_mode);
+*/
+       set_outputmode(aud_std, aud_mode);
 
        if (non_std_onoff)
                atv_dmd_non_std_set(true);
@@ -1753,7 +1756,7 @@ int amlfmt_aud_standard(int broad_std)
 
        switch (broad_std) {
        case AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC:
-               std = AUDIO_STANDARD_BTSC;
+               std = AUDIO_STANDARD_A2_K;
                configure_adec(std);
                adec_soft_reset();
                msleep(audio_a2_delay);
@@ -1773,11 +1776,11 @@ int amlfmt_aud_standard(int broad_std)
                std = AUDIO_STANDARD_NICAM_BG;
                configure_adec(std);
                adec_soft_reset();
-               mdelay(2);
+               mdelay(audio_nicam_delay);
                /* need wait */
-               reg_value = adec_rd_reg(0x1a3);
+               reg_value = adec_rd_reg(NICAM_LEVEL_REPORT);
                nicam_lock = (reg_value>>28)&1;
-
+               pr_info("\n%s 0x%x\n", __func__, reg_value);
                if (nicam_lock)
                        std = AUDIO_STANDARD_NICAM_BG;
                else
@@ -1785,12 +1788,13 @@ int amlfmt_aud_standard(int broad_std)
                break;
        case AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_DK:
                std = AUDIO_STANDARD_NICAM_DK;
-               configure_adec(aud_std);
+               configure_adec(std);
                adec_soft_reset();
-               mdelay(2);
+               mdelay(audio_nicam_delay);
                /* need wait */
-               reg_value = adec_rd_reg(0x1a3);
+               reg_value = adec_rd_reg(NICAM_LEVEL_REPORT);
                nicam_lock = (reg_value>>28)&1;
+               pr_info("\n%s 0x%x\n", __func__, reg_value);
                if (nicam_lock)
                        std = AUDIO_STANDARD_NICAM_DK;
                else
@@ -1982,10 +1986,18 @@ void atv_dmd_set_std(void)
                if_inv = amlatvdemod_devp->if_inv;
        }
 
-       pr_info
-       ("[atvdemod..]%s: broad_std %d,hz_cvrt:0x%x, offset:%d,std:0x%x.\n",
-       __func__, broad_std, freq_hz_cvrt, amlatvdemod_devp->fre_offset,
-                (unsigned int) ptstd);
+       pr_info("[%s] set broad_std %d, hz_cvrt 0x%x, offset %d.\n",
+                       __func__, broad_std, freq_hz_cvrt,
+                       amlatvdemod_devp->fre_offset);
+
+       pr_info("[%s] set std color %s, audio type %s.\n",
+               __func__,
+               v4l2_std_to_str((0xff000000 & amlatvdemod_devp->std)),
+               v4l2_std_to_str((0xffffff & amlatvdemod_devp->std)));
+
+       pr_info("[%s] set if_freq %d, if_inv %d.\n",
+               __func__, amlatvdemod_devp->if_freq,
+               amlatvdemod_devp->if_inv);
 
        if (atvdemod_init())
                pr_info("[%s]: atv restart error.\n", __func__);
index 86ff0a5..b765906 100644 (file)
@@ -29,6 +29,8 @@ struct dvb_frontend;
 
 extern unsigned int reg_23cf; /* IIR filter */
 extern int broad_std_except_pal_m;
+extern unsigned int aud_std;
+extern unsigned int aud_mode;
 
 #define ATVDEMOD_INTERVAL      (HZ/100)        /*10ms, #define HZ 100*/
 
index 73a36e2..1c22732 100644 (file)
 #define CARRIER_MAG_REPORT        0x0f6
 #define BTSC_AB_REPORT            0x0f7
 #define AUDIO_MODE_REPORT         0x0f8
+#define NICAM_LEVEL_REPORT        0x1a3
+#define NICAM_MODE_REPORT         0x1a4
 
 #define CTRL_SEL            0x0ff
 
 #define        AUDIO_STANDARD_BTSC                             0x00
 #define        AUDIO_STANDARD_EIAJ                             0x01
 #define        AUDIO_STANDARD_A2_K                             0x02
-#define        AUDIO_STANDARD_A2_BG                            0x03
-#define        AUDIO_STANDARD_A2_DK1                           0x04
+#define        AUDIO_STANDARD_A2_BG                    0x03
+#define        AUDIO_STANDARD_A2_DK1                   0x04
 #define        AUDIO_STANDARD_A2_DK2                   0x05
 #define        AUDIO_STANDARD_A2_DK3                   0x06
 #define        AUDIO_STANDARD_NICAM_I                  0x07
 #define AUDIO_STANDARD_FM_USA                  0x0B
 #define        AUDIO_STANDARD_FM_EU                    0x0C
 #define AUDIO_STANDARD_CHINA                   0x0E
-#define        AUDIO_STANDARD_INDIAN           0x0F
-#define        AUDIO_STANDARD_BTSC_SA          0x10
+#define        AUDIO_STANDARD_INDIAN                   0x0F
+#define        AUDIO_STANDARD_BTSC_SA                  0x10
 #define AUDIO_STANDARD_MONO_ONLY               0x11
 
 #define AUDIO_OUTMODE_MONO 0
index 36991f9..a4439a2 100644 (file)
@@ -576,6 +576,11 @@ int adc_set_pll_cntl(bool on, unsigned int module_sel, void *pDtvPara)
                                __func__, adc_pll_chg);
                        break;
                }
+               if (adc_pll_chg & ADC_EN_ATV_DEMOD) {
+                       tvafe_pr_info("%s:ADEMOD ATV had done!:%d\n",
+                               __func__, adc_pll_chg);
+                       break;
+               }
                mutex_lock(&pll_mutex);
                do {
                        if (tvafe_cpu_type() == CPU_TYPE_TXL ||