From 7d524a96a591ed382483224dc2028e79d2151fab Mon Sep 17 00:00:00 2001 From: "nengwen.chen" Date: Thu, 7 Jun 2018 20:00:39 +0800 Subject: [PATCH] atv_demod: Add ATV NICAM. [1/5] PD#165624: Add ATV NICAM. Change-Id: I2bcc018cd5ff7a611baa2f5473cfa1dbce28118d Signed-off-by: nengwen.chen --- drivers/amlogic/atv_demod/Makefile | 2 +- drivers/amlogic/atv_demod/atv_demod_debug.c | 4 + drivers/amlogic/atv_demod/atv_demod_debug.h | 2 +- drivers/amlogic/atv_demod/atv_demod_driver.c | 104 ++- drivers/amlogic/atv_demod/atv_demod_driver.h | 1 + drivers/amlogic/atv_demod/atv_demod_ops.c | 788 +++++++++++++++++++-- drivers/amlogic/atv_demod/atv_demod_ops.h | 10 + drivers/amlogic/atv_demod/atv_demod_v4l2.c | 704 +----------------- drivers/amlogic/atv_demod/atv_demod_v4l2.h | 52 +- drivers/amlogic/atv_demod/atvauddemod_func.c | 395 ++++++++--- drivers/amlogic/atv_demod/atvauddemod_func.h | 3 + drivers/amlogic/atv_demod/atvdemod_func.c | 46 +- drivers/amlogic/atv_demod/atvdemod_func.h | 2 + drivers/amlogic/atv_demod/aud_demod_reg.h | 10 +- .../amlogic/media/vin/tvin/tvafe/tvafe_general.c | 5 + 15 files changed, 1241 insertions(+), 887 deletions(-) diff --git a/drivers/amlogic/atv_demod/Makefile b/drivers/amlogic/atv_demod/Makefile index 1f5060a..3f309c5 100644 --- a/drivers/amlogic/atv_demod/Makefile +++ b/drivers/amlogic/atv_demod/Makefile @@ -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 diff --git a/drivers/amlogic/atv_demod/atv_demod_debug.c b/drivers/amlogic/atv_demod/atv_demod_debug.c index 2692a6b..83cd9dd 100644 --- a/drivers/amlogic/atv_demod/atv_demod_debug.c +++ b/drivers/amlogic/atv_demod/atv_demod_debug.c @@ -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)\ } diff --git a/drivers/amlogic/atv_demod/atv_demod_debug.h b/drivers/amlogic/atv_demod/atv_demod_debug.h index 19fc814..3a8aa4b 100644 --- a/drivers/amlogic/atv_demod/atv_demod_debug.h +++ b/drivers/amlogic/atv_demod/atv_demod_debug.h @@ -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) diff --git a/drivers/amlogic/atv_demod/atv_demod_driver.c b/drivers/amlogic/atv_demod/atv_demod_driver.c index 8044703..e81d839 100644 --- a/drivers/amlogic/atv_demod/atv_demod_driver.c +++ b/drivers/amlogic/atv_demod/atv_demod_driver.c @@ -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, ¶ms); + 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; } diff --git a/drivers/amlogic/atv_demod/atv_demod_driver.h b/drivers/amlogic/atv_demod/atv_demod_driver.h index ad8e595..1ae9ed5 100644 --- a/drivers/amlogic/atv_demod/atv_demod_driver.h +++ b/drivers/amlogic/atv_demod/atv_demod_driver.h @@ -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 */ diff --git a/drivers/amlogic/atv_demod/atv_demod_ops.c b/drivers/amlogic/atv_demod/atv_demod_ops.c index c4b424e..32b9d28 100644 --- a/drivers/amlogic/atv_demod/atv_demod_ops.c +++ b/drivers/amlogic/atv_demod/atv_demod_ops.c @@ -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, ¶ms); + } + 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, ¶ms); + + 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, + ¶ms); + } + } + + 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, ¶ms); + + pr_dbg("[%s] [%d] is processing, [min=%d, max=%d].\n", + __func__, p->frequency, minafcfreq, maxafcfreq); + + pll_lock = false; + tuner_status_cnt_local = tuner_status_cnt; + do { + if (tuner_id == AM_TUNER_MXL661) { + usleep_range(30 * 1000, 30 * 1000 + 100); + } else if (tuner_id == AM_TUNER_R840) { + 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, + ¶ms); + + try_secam = true; + + tuner_status_cnt_local = + tuner_status_cnt / 2; + + continue; + } + + if (try_secam) { + p->std = std_bk; + p->audmode = audio; + + params.frequency = p->frequency; + params.mode = p->afc_range; + params.audmode = p->audmode; + params.std = p->std; + fe->ops.analog_ops.set_params(fe, + ¶ms); + + try_secam = false; + } + + 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, ¶ms); + 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); diff --git a/drivers/amlogic/atv_demod/atv_demod_ops.h b/drivers/amlogic/atv_demod/atv_demod_ops.h index 43272b6..216fe1a 100644 --- a/drivers/amlogic/atv_demod/atv_demod_ops.h +++ b/drivers/amlogic/atv_demod/atv_demod_ops.h @@ -30,6 +30,13 @@ #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__ */ diff --git a/drivers/amlogic/atv_demod/atv_demod_v4l2.c b/drivers/amlogic/atv_demod/atv_demod_v4l2.c index 07ca5e5..716a687 100644 --- a/drivers/amlogic/atv_demod/atv_demod_v4l2.c +++ b/drivers/amlogic/atv_demod/atv_demod_v4l2.c @@ -43,672 +43,6 @@ 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, ¶ms); - } - 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, ¶ms); - - 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, - ¶ms); - } - } - - 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, ¶ms); - - pr_dbg("[%s] [%d] is processing, [min=%d, max=%d].\n", - __func__, p->frequency, minafcfreq, maxafcfreq); - - pll_lock = false; - tuner_status_cnt_local = tuner_status_cnt; - do { - if (tuner_id == AM_TUNER_MXL661) { - usleep_range(30 * 1000, 30 * 1000 + 100); - } else if (tuner_id == AM_TUNER_R840) { - 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, - ¶ms); - - try_secam = true; - - tuner_status_cnt_local = - tuner_status_cnt / 2; - - continue; - } - - if (try_secam) { - p->std = std_bk; - p->audmode = audio; - - params.frequency = p->frequency; - params.mode = p->afc_range; - params.audmode = p->audmode; - params.std = p->std; - fe->ops.analog_ops.set_params(fe, - ¶ms); - - try_secam = false; - } - - 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, ¶ms); - 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), diff --git a/drivers/amlogic/atv_demod/atv_demod_v4l2.h b/drivers/amlogic/atv_demod/atv_demod_v4l2.h index 396bba5..0f61126 100644 --- a/drivers/amlogic/atv_demod/atv_demod_v4l2.h +++ b/drivers/amlogic/atv_demod/atv_demod_v4l2.h @@ -77,17 +77,20 @@ #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); diff --git a/drivers/amlogic/atv_demod/atvauddemod_func.c b/drivers/amlogic/atv_demod/atvauddemod_func.c index ab525ed..8a5d250 100644 --- a/drivers/amlogic/atv_demod/atvauddemod_func.c +++ b/drivers/amlogic/atv_demod/atvauddemod_func.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -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 */ @@ -18,11 +21,15 @@ 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 */ diff --git a/drivers/amlogic/atv_demod/atvauddemod_func.h b/drivers/amlogic/atv_demod/atvauddemod_func.h index 4407241c..497a81b 100644 --- a/drivers/amlogic/atv_demod/atvauddemod_func.h +++ b/drivers/amlogic/atv_demod/atvauddemod_func.h @@ -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_ */ diff --git a/drivers/amlogic/atv_demod/atvdemod_func.c b/drivers/amlogic/atv_demod/atvdemod_func.c index e0d2716..1ceb80b 100644 --- a/drivers/amlogic/atv_demod/atvdemod_func.c +++ b/drivers/amlogic/atv_demod/atvdemod_func.c @@ -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__); diff --git a/drivers/amlogic/atv_demod/atvdemod_func.h b/drivers/amlogic/atv_demod/atvdemod_func.h index 86ff0a5..b765906 100644 --- a/drivers/amlogic/atv_demod/atvdemod_func.h +++ b/drivers/amlogic/atv_demod/atvdemod_func.h @@ -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*/ diff --git a/drivers/amlogic/atv_demod/aud_demod_reg.h b/drivers/amlogic/atv_demod/aud_demod_reg.h index 73a36e2..1c22732 100644 --- a/drivers/amlogic/atv_demod/aud_demod_reg.h +++ b/drivers/amlogic/atv_demod/aud_demod_reg.h @@ -199,6 +199,8 @@ #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 @@ -286,8 +288,8 @@ #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 @@ -297,8 +299,8 @@ #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 diff --git a/drivers/amlogic/media/vin/tvin/tvafe/tvafe_general.c b/drivers/amlogic/media/vin/tvin/tvafe/tvafe_general.c index 36991f9..a4439a26 100644 --- a/drivers/amlogic/media/vin/tvin/tvafe/tvafe_general.c +++ b/drivers/amlogic/media/vin/tvin/tvafe/tvafe_general.c @@ -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 || -- 2.7.4