blob: ab6d171ee920e3078c7c6d9127ae6cd9b83c7c53 [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <linux/types.h>
#include <uapi/linux/dvb/frontend.h>
#include "atvdemod_func.h"
#include "atvauddemod_func.h"
#include "atv_demod_monitor.h"
#include "atv_demod_ops.h"
#include "atv_demod_debug.h"
static DEFINE_MUTEX(monitor_mutex);
bool atvdemod_mixer_tune_en;
bool atvdemod_overmodulated_en;
bool atv_audio_overmodulated_en;
unsigned int atv_audio_overmodulated_cnt = 1;
bool audio_det_en;
bool atvdemod_det_snr_en = true;
bool audio_thd_en;
bool atvdemod_det_nonstd_en;
bool atvaudio_det_outputmode_en = true;
bool audio_carrier_offset_det_en;
bool atvdemod_horiz_freq_det_en = true;
unsigned int atvdemod_timer_delay = 100; /* 1s */
unsigned int atvdemod_timer_delay2 = 10; /* 100ms */
bool atvdemod_timer_en = true;
static void atv_demod_monitor_do_work(struct work_struct *work)
{
int vpll_lock = 0, line_lock = 0;
struct atv_demod_monitor *monitor =
container_of(work, struct atv_demod_monitor, work);
if (monitor->state == MONI_DISABLE)
return;
retrieve_vpll_carrier_lock(&vpll_lock);
retrieve_vpll_carrier_line_lock(&line_lock);
if ((vpll_lock != 0) || (line_lock != 0)) {
monitor->lock_cnt = 0;
return;
}
monitor->lock_cnt++;
if (atvdemod_mixer_tune_en)
atvdemod_mixer_tune();
if (atvdemod_overmodulated_en)
atvdemod_video_overmodulated();
if (atv_audio_overmodulated_en) {
if (monitor->lock_cnt > atv_audio_overmodulated_cnt)
aml_audio_overmodulation(1);
}
if (atvdemod_det_snr_en)
atvdemod_det_snr_serice();
if (audio_thd_en)
audio_thd_det();
if (atvaudio_det_outputmode_en)
atvauddemod_set_outputmode();
if (audio_carrier_offset_det_en)
audio_carrier_offset_det();
if (atvdemod_det_nonstd_en)
atv_dmd_non_std_set(true);
if (atvdemod_horiz_freq_det_en)
atvdemod_horiz_freq_detection();
}
static void atv_demod_monitor_timer_handler(struct timer_list *timer)
{
struct atv_demod_monitor *monitor = container_of(timer,
struct atv_demod_monitor, timer);
/* 100ms timer */
monitor->timer.expires = jiffies +
ATVDEMOD_INTERVAL * atvdemod_timer_delay2;
add_timer(&monitor->timer);
if (atvdemod_timer_en == 0)
return;
if (monitor->state == MONI_PAUSE)
return;
schedule_work(&monitor->work);
}
static void atv_demod_monitor_enable(struct atv_demod_monitor *monitor)
{
mutex_lock(&monitor->mtx);
if (atvdemod_timer_en && monitor->state == MONI_DISABLE) {
atv_dmd_non_std_set(false);
timer_setup(&monitor->timer, atv_demod_monitor_timer_handler, 0);
monitor->timer.function = atv_demod_monitor_timer_handler;
/* after 1s enable demod auto detect */
monitor->timer.expires = jiffies +
ATVDEMOD_INTERVAL * atvdemod_timer_delay;
add_timer(&monitor->timer);
monitor->state = MONI_ENABLE;
monitor->lock_cnt = 0;
} else if (atvdemod_timer_en && monitor->state == MONI_PAUSE) {
atv_dmd_non_std_set(false);
monitor->state = MONI_ENABLE;
monitor->lock_cnt = 0;
}
mutex_unlock(&monitor->mtx);
pr_dbg("%s: state: %d.\n", __func__, monitor->state);
}
static void atv_demod_monitor_disable(struct atv_demod_monitor *monitor)
{
mutex_lock(&monitor->mtx);
if (atvdemod_timer_en && monitor->state != MONI_DISABLE) {
monitor->state = MONI_DISABLE;
del_timer_sync(&monitor->timer);
cancel_work_sync(&monitor->work);
}
mutex_unlock(&monitor->mtx);
pr_dbg("%s: state: %d.\n", __func__, monitor->state);
}
static void atv_demod_monitor_pause(struct atv_demod_monitor *monitor)
{
mutex_lock(&monitor->mtx);
if (monitor->state == MONI_ENABLE) {
monitor->state = MONI_PAUSE;
atv_dmd_non_std_set(false);
cancel_work_sync(&monitor->work);
}
mutex_unlock(&monitor->mtx);
}
void atv_demod_monitor_init(struct atv_demod_monitor *monitor)
{
mutex_lock(&monitor_mutex);
mutex_init(&monitor->mtx);
monitor->state = MONI_DISABLE;
monitor->lock = false;
monitor->lock_cnt = 0;
monitor->disable = atv_demod_monitor_disable;
monitor->enable = atv_demod_monitor_enable;
monitor->pause = atv_demod_monitor_pause;
INIT_WORK(&monitor->work, atv_demod_monitor_do_work);
mutex_unlock(&monitor_mutex);
}