blob: 070a667283b07747aaf916e65d8e3775b37ebb47 [file] [log] [blame]
/*
* drivers/amlogic/atv_demod/atv_demod_monitor.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/types.h>
#include <uapi/linux/dvb/frontend.h>
#include <linux/amlogic/cpu_version.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;
bool audio_det_en;
bool atvdemod_det_snr_en = true;
bool audio_thd_en = true;
bool atvdemod_det_nonstd_en;
bool atvaudio_det_outputmode_en = true;
bool audio_carrier_offset_det_en;
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)
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 % 10 == 0)
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);
}
static void atv_demod_monitor_timer_handler(unsigned long arg)
{
struct atv_demod_monitor *monitor = (struct atv_demod_monitor *)arg;
/* 100ms timer */
monitor->timer.data = arg;
monitor->timer.expires = jiffies +
ATVDEMOD_INTERVAL * atvdemod_timer_delay2;
add_timer(&monitor->timer);
if (atvdemod_timer_en == 0)
return;
if (vdac_enable_check_dtv())
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) {
atv_dmd_non_std_set(false);
init_timer(&monitor->timer);
monitor->timer.data = (ulong) monitor;
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 = true;
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) {
monitor->state = false;
atv_dmd_non_std_set(false);
del_timer_sync(&monitor->timer);
cancel_work_sync(&monitor->work);
}
mutex_unlock(&monitor->mtx);
pr_dbg("%s: state: %d.\n", __func__, monitor->state);
}
void atv_demod_monitor_init(struct atv_demod_monitor *monitor)
{
mutex_lock(&monitor_mutex);
mutex_init(&monitor->mtx);
monitor->state = false;
monitor->lock = false;
monitor->lock_cnt = 0;
monitor->disable = atv_demod_monitor_disable;
monitor->enable = atv_demod_monitor_enable;
INIT_WORK(&monitor->work, atv_demod_monitor_do_work);
mutex_unlock(&monitor_mutex);
}