atv_demod: Add atv afc [1/2]

PD#166320: Add atv afc.

Change-Id: I7b5d8d6290f1e394900b09a1147e7db5ec6fecf4
Signed-off-by: nengwen.chen <nengwen.chen@amlogic.com>
This commit is contained in:
nengwen.chen
2018-05-15 19:27:42 +08:00
committed by Yixun Lan
parent 700dc02512
commit 8370bd9c39
7 changed files with 598 additions and 54 deletions

View File

@@ -29,7 +29,7 @@ extern int atvdemod_debug_en;
#undef pr_dbg
#define pr_dbg(fmt, ...) \
do {\
if (atvdemod_debug_en)\
if (atvdemod_debug_en & 01)\
printk(fmt, ##__VA_ARGS__);\
} while (0)
@@ -40,4 +40,24 @@ extern int atvdemod_debug_en;
printk(fmt, ##__VA_ARGS__);\
} while (0)
#undef pr_afc
#define pr_afc(fmt, ...) \
do {\
if (atvdemod_debug_en & 0x02)\
printk(fmt, ##__VA_ARGS__);\
} while (0)
#undef pr_warn
#define pr_warn(fmt, ...) \
do {\
if (1)\
printk(fmt, ##__VA_ARGS__);\
} while (0)
#undef pr_audio
#define pr_audio(fmt, ...) \
do {\
if (atvdemod_debug_en & 0x04)\
printk(fmt, ##__VA_ARGS__);\
} while (0)
#endif /* __ATV_DEMOD_DEBUG_H__ */

View File

@@ -77,7 +77,7 @@ static ssize_t aml_atvdemod_store(struct class *class,
if (ret)
pr_info("atv init error.\n");
} else if (!strncmp(parm[0], "audout_mode", 11)) {
if (get_atvdemod_state() == ATVDEMOD_STATE_WORK) {
if (atv_demod_get_state() == ATVDEMOD_STATE_WORK) {
if (is_meson_txlx_cpu()) {
atvauddemod_set_outputmode();
pr_info("atvauddemod_set_outputmode done ....\n");
@@ -88,7 +88,7 @@ static ssize_t aml_atvdemod_store(struct class *class,
} else if (!strncmp(parm[0], "signal_audmode", 14)) {
int stereo_flag, sap_flag;
if (get_atvdemod_state() == ATVDEMOD_STATE_WORK) {
if (atv_demod_get_state() == ATVDEMOD_STATE_WORK) {
if (is_meson_txlx_cpu()) {
update_btsc_mode(1, &stereo_flag, &sap_flag);
pr_info("get signal_audmode done ....\n");
@@ -427,6 +427,18 @@ int aml_attach_demod_tuner(struct aml_atvdemod_device *dev)
return 0;
}
static int aml_detach_demod_tuner(struct aml_atvdemod_device *dev)
{
struct v4l2_frontend *v4l2_fe = &dev->v4l2_fe;
v4l2_frontend_detach(v4l2_fe);
dev->analog_attached = false;
dev->tuner_attached = false;
return 0;
}
static int aml_atvdemod_probe(struct platform_device *pdev)
{
int ret = 0;
@@ -531,6 +543,7 @@ static int aml_atvdemod_remove(struct platform_device *pdev)
return -1;
v4l2_unresister_frontend(&dev->v4l2_fe);
aml_detach_demod_tuner(dev);
amlatvdemod_devp = NULL;

View File

@@ -28,7 +28,7 @@
#include "atv_demod_ops.h"
#include "atv_demod_v4l2.h"
#define DEVICE_NAME "aml_atvdemod_fe"
#define DEVICE_NAME "aml_atvdemod"
#define ATVDEMOD_STATE_IDEL 0
#define ATVDEMOD_STATE_WORK 1
@@ -46,6 +46,295 @@ static int btsc_sap_mode = 1; /*0: off 1:monitor 2:auto */
module_param(btsc_sap_mode, int, 0644);
MODULE_DESCRIPTION("btsc sap mode\n");
static int afc_offset;
module_param(afc_offset, int, 0644);
MODULE_PARM_DESC(afc_offset, "\n afc_offset\n");
static unsigned int afc_limit = 2100;/*+-2.1Mhz*/
module_param(afc_limit, uint, 0644);
MODULE_PARM_DESC(afc_limit, "\n afc_limit\n");
static int no_sig_cnt;
struct timer_list aml_timer;
#define AML_INTERVAL (HZ/100) /* 10ms, #define HZ 100 */
static unsigned int timer_init_state;
static unsigned int aft_thread_enable;
static unsigned int aft_thread_delaycnt;
static unsigned int aml_timer_en = 1;
module_param(aml_timer_en, uint, 0644);
MODULE_PARM_DESC(aml_timer_en, "\n aml_timer_en\n");
static unsigned int timer_delay = 1;
module_param(timer_delay, uint, 0644);
MODULE_PARM_DESC(timer_delay, "\n timer_delay\n");
static unsigned int timer_delay2 = 10;
module_param(timer_delay2, uint, 0644);
MODULE_PARM_DESC(timer_delay2, "\n timer_delay2\n");
static unsigned int timer_delay3 = 10;/*100ms*/
module_param(timer_delay3, uint, 0644);
MODULE_PARM_DESC(timer_delay3, "\n timer_delay3\n");
static unsigned int afc_wave_cnt = 4;
module_param(afc_wave_cnt, uint, 0644);
MODULE_PARM_DESC(afc_wave_cnt, "\n afc_wave_cnt\n");
#define AFC_LOCK_STATUS_NULL 0
#define AFC_LOCK_STATUS_PRE_UNLOCK 1
#define AFC_LOCK_STATUS_PRE_LOCK 2
#define AFC_LOCK_STATUS_PRE_OVER_RANGE 3
#define AFC_LOCK_STATUS_POST_PROCESS 4
#define AFC_LOCK_STATUS_POST_LOCK 5
#define AFC_LOCK_STATUS_POST_UNLOCK 6
#define AFC_LOCK_STATUS_POST_OVER_RANGE 7
#define AFC_LOCK_STATUS_NUM 8
#define AFC_PRE_STEP_NUM 9
static int afc_range[11] = {0, -500, 500, -1000, 1000,
-1500, 1500, -2000, 2000, -2500, 2500};
static unsigned int afc_pre_step;
static unsigned int afc_pre_lock_cnt;
static unsigned int afc_pre_unlock_cnt;
static unsigned int afc_lock_status = AFC_LOCK_STATUS_NULL;
static void aml_fe_do_work_pre(int lock)
{
struct dvb_frontend *fe = &amlatvdemod_devp->v4l2_fe.fe;
struct atv_demod_priv *priv = fe->analog_demod_priv;
struct analog_parameters *param = &priv->atvdemod_param.param;
afc_pre_unlock_cnt++;
if (!lock) {
afc_pre_lock_cnt = 0;
if (afc_lock_status != AFC_LOCK_STATUS_PRE_UNLOCK &&
afc_offset) {
param->frequency -= afc_offset * 1000;
afc_offset = 0;
afc_pre_step = 0;
afc_lock_status = AFC_LOCK_STATUS_PRE_UNLOCK;
}
if (afc_pre_unlock_cnt <= afc_wave_cnt) {/*40ms*/
afc_lock_status = AFC_LOCK_STATUS_PRE_UNLOCK;
return;
}
if (afc_offset == afc_range[afc_pre_step]) {
param->frequency -= afc_range[afc_pre_step] * 1000;
afc_offset -= afc_range[afc_pre_step];
}
afc_pre_step++;
if (afc_pre_step < AFC_PRE_STEP_NUM) {
param->frequency += afc_range[afc_pre_step] * 1000;
afc_offset += afc_range[afc_pre_step];
afc_lock_status = AFC_LOCK_STATUS_PRE_UNLOCK;
} else {
param->frequency -= afc_offset * 1000;
afc_offset = 0;
afc_pre_step = 0;
afc_lock_status = AFC_LOCK_STATUS_PRE_OVER_RANGE;
}
if (fe->ops.tuner_ops.set_analog_params)
fe->ops.tuner_ops.set_analog_params(fe, param);
afc_pre_unlock_cnt = 0;
pr_afc("%s,unlock afc_offset:%d KHz, set freq:%d\n",
__func__, afc_offset, param->frequency);
} else {
afc_pre_lock_cnt++;
pr_afc("%s,afc_pre_lock_cnt:%d\n",
__func__, afc_pre_lock_cnt);
if (afc_pre_lock_cnt >= afc_wave_cnt * 2) {/*100ms*/
afc_pre_lock_cnt = 0;
afc_pre_unlock_cnt = 0;
afc_lock_status = AFC_LOCK_STATUS_PRE_LOCK;
}
}
}
static void aml_fe_do_work(struct work_struct *work)
{
struct dvb_frontend *fe = &amlatvdemod_devp->v4l2_fe.fe;
struct atv_demod_priv *priv = fe->analog_demod_priv;
struct analog_parameters *param = &priv->atvdemod_param.param;
int afc = 100;
int lock = 0;
int tmp = 0;
int field_lock = 0;
static int audio_overmodul;
static int wave_cnt;
if (timer_init_state == 0)
return;
retrieve_vpll_carrier_lock(&tmp);/* 0 means lock, 1 means unlock */
lock = !tmp;
/*pre afc:speed up afc*/
if ((afc_lock_status != AFC_LOCK_STATUS_POST_PROCESS) &&
(afc_lock_status != AFC_LOCK_STATUS_POST_LOCK) &&
(afc_lock_status != AFC_LOCK_STATUS_PRE_LOCK)) {
aml_fe_do_work_pre(lock);
return;
}
afc_pre_step = 0;
if (lock) {
if (0 == ((audio_overmodul++) % 10))
aml_audio_overmodulation(1);
}
retrieve_frequency_offset(&afc);
if (++wave_cnt <= afc_wave_cnt) {/*40ms*/
afc_lock_status = AFC_LOCK_STATUS_POST_PROCESS;
pr_afc("%s,wave_cnt:%d is wave,lock:%d,afc:%d ignore\n",
__func__, wave_cnt, lock, afc);
return;
}
/*retrieve_frequency_offset(&afc);*/
retrieve_field_lock(&tmp);
field_lock = tmp;
pr_afc("%s,afc:%d lock:%d field_lock:%d freq:%d\n",
__func__, afc, lock, field_lock, param->frequency);
if (lock && (abs(afc) < AFC_BEST_LOCK &&
abs(afc_offset) <= afc_limit) && field_lock) {
afc_lock_status = AFC_LOCK_STATUS_POST_LOCK;
wave_cnt = 0;
pr_afc("%s,afc lock, set wave_cnt 0\n", __func__);
return;
}
if (!lock) {
afc_lock_status = AFC_LOCK_STATUS_POST_UNLOCK;
afc_pre_lock_cnt = 0;
param->frequency -= afc_offset * 1000;
if (fe->ops.tuner_ops.set_analog_params)
fe->ops.tuner_ops.set_analog_params(fe, param);
pr_afc("%s,afc:%d , set freq:%d\n",
__func__, afc, param->frequency);
wave_cnt = 0;
afc_offset = 0;
pr_afc("%s, [post lock --> unlock]\n", __func__);
return;
}
if (abs(afc_offset) > afc_limit) {
no_sig_cnt++;
if (no_sig_cnt == 20) {
param->frequency -= afc_offset * 1000;
pr_afc("%s,afc no_sig trig, set freq:%d\n",
__func__, param->frequency);
if (fe->ops.tuner_ops.set_analog_params)
fe->ops.tuner_ops.set_analog_params(fe, param);
wave_cnt = 0;
afc_offset = 0;
afc_lock_status = AFC_LOCK_STATUS_POST_OVER_RANGE;
}
return;
}
no_sig_cnt = 0;
if (abs(afc) >= AFC_BEST_LOCK) {
param->frequency += afc * 1000;
afc_offset += afc;
if (fe->ops.tuner_ops.set_analog_params)
fe->ops.tuner_ops.set_analog_params(fe, param);
pr_afc("%s,afc:%d , set freq:%d\n",
__func__, afc, param->frequency);
}
wave_cnt = 0;
afc_lock_status = AFC_LOCK_STATUS_POST_PROCESS;
}
void aml_timer_handler(unsigned long arg)
{
struct dvb_frontend *fe = (struct dvb_frontend *)arg;
struct atv_demod_priv *priv = fe->analog_demod_priv;
unsigned int delay_ms = 0;
if ((fe == NULL) || (priv == NULL) || (timer_init_state == 0))
return;
if (afc_lock_status == AFC_LOCK_STATUS_POST_OVER_RANGE ||
afc_lock_status == AFC_LOCK_STATUS_PRE_OVER_RANGE ||
afc_lock_status == AFC_LOCK_STATUS_POST_LOCK)
delay_ms = timer_delay2;/*100ms*/
else
delay_ms = timer_delay;/*10ms*/
aml_timer.function = aml_timer_handler;
aml_timer.data = arg;
aml_timer.expires = jiffies + AML_INTERVAL * delay_ms;
add_timer(&aml_timer);
if (!aft_thread_enable) {
/*pr_info("%s, stop aft thread\n", __func__);*/
return;
}
if (aft_thread_delaycnt > 0) {
aft_thread_delaycnt--;
return;
}
if ((aml_timer_en == 0) || (fe->ops.info.type != FE_ANALOG))
return;
schedule_work(&priv->demod_wq);
}
static void afc_timer_disable(struct dvb_frontend *fe)
{
struct atv_demod_priv *priv = fe->analog_demod_priv;
if ((aml_timer_en == 1) && (timer_init_state == 1)) {
del_timer_sync(&aml_timer);
cancel_work_sync(&priv->demod_wq);
timer_init_state = 0;
}
}
static void afc_timer_enable(struct dvb_frontend *fe)
{
if (fe && (aml_timer_en == 1) && (timer_init_state == 0)) {
init_timer(&aml_timer);
aml_timer.function = aml_timer_handler;
aml_timer.data = (ulong) fe;
/* after 5s enable demod auto detect */
aml_timer.expires = jiffies + AML_INTERVAL * timer_delay3;
afc_offset = 0;
no_sig_cnt = 0;
afc_pre_step = 0;
afc_lock_status = AFC_LOCK_STATUS_NULL;
add_timer(&aml_timer);
timer_init_state = 1;
}
}
static void set_aft_thread_enable(int enable, unsigned int delay)
{
if (enable == aft_thread_enable)
return;
aft_thread_enable = enable;
aft_thread_delaycnt = delay;
if (aft_thread_enable)
afc_timer_enable(&amlatvdemod_devp->v4l2_fe.fe);
else
afc_timer_disable(&amlatvdemod_devp->v4l2_fe.fe);
}
/*
* add interface for audio driver to get atv audio state.
* state:
@@ -57,22 +346,23 @@ void aml_fe_get_atvaudio_state(int *state)
int power = 0;
int vpll_lock = 0;
int line_lock = 0;
int atv_state = atv_demod_get_state();
if (atvdemod_state == ATVDEMOD_STATE_WORK) {
if (atv_state == ATVDEMOD_STATE_WORK) {
retrieve_vpll_carrier_lock(&vpll_lock);
retrieve_vpll_carrier_line_lock(&line_lock);
if ((vpll_lock == 0) && (line_lock == 0))
retrieve_vpll_carrier_audio_power(&power);
} else
pr_err("%s, atv is not work, atvdemod_state: %d.\n",
__func__, atvdemod_state);
pr_err("%s, atv is not work, atv_state: %d.\n",
__func__, atv_state);
if (power >= 150)
*state = 1;
else
*state = 0;
pr_dbg("aml_fe_get_atvaudio_state: %d, power = %d.\n",
pr_audio("aml_fe_get_atvaudio_state: %d, power = %d.\n",
*state, power);
}
@@ -146,29 +436,28 @@ int is_atvdemod_work(void)
{
int ret = 0;
if (atvdemod_state == ATVDEMOD_STATE_WORK)
if (atv_demod_get_state() == ATVDEMOD_STATE_WORK)
ret = 1;
return ret;
}
int is_atvdemod_scan_mode(void)
static int atv_demod_get_scan_mode(void)
{
return atvdemod_scan_mode;
}
//EXPORT_SYMBOL(is_atvdemod_scan_mode);
void set_atvdemod_scan_mode(int val)
static void atv_demod_set_scan_mode(int val)
{
atvdemod_scan_mode = val;
}
int get_atvdemod_state(void)
int atv_demod_get_state(void)
{
return atvdemod_state;
}
void set_atvdemod_state(int state)
static void atv_demod_set_state(int state)
{
atvdemod_state = state;
}
@@ -178,7 +467,7 @@ int atv_demod_enter_mode(void)
int err_code = 0;
#if 0
if (atvdemod_state == ATVDEMOD_STATE_WORK)
if (atv_demod_get_state() == ATVDEMOD_STATE_WORK)
return 0;
#endif
if (amlatvdemod_devp->pin_name != NULL)
@@ -200,14 +489,15 @@ int atv_demod_enter_mode(void)
return err_code;
}
/* set_aft_thread_enable(1, 0); */
set_aft_thread_enable(1, 0);
/*
* memset(&(amlatvdemod_devp->parm), 0,
* sizeof(amlatvdemod_devp->parm));
*/
amlatvdemod_devp->std = 0;
amlatvdemod_devp->audmode = 0;
atvdemod_state = ATVDEMOD_STATE_WORK;
atv_demod_set_state(ATVDEMOD_STATE_WORK);
pr_info("%s: OK.\n", __func__);
@@ -216,10 +506,10 @@ int atv_demod_enter_mode(void)
int atv_demod_leave_mode(void)
{
if (atvdemod_state == ATVDEMOD_STATE_IDEL)
if (atv_demod_get_state() == ATVDEMOD_STATE_IDEL)
return 0;
/* set_aft_thread_enable(0, 0); */
set_aft_thread_enable(0, 0);
atvdemod_uninit();
if (amlatvdemod_devp->pin != NULL) {
devm_pinctrl_put(amlatvdemod_devp->pin);
@@ -235,7 +525,8 @@ int atv_demod_leave_mode(void)
* sizeof(amlatvdemod_devp->parm));
*/
amlatvdemod_devp->std = 0;
atvdemod_state = ATVDEMOD_STATE_IDEL;
amlatvdemod_devp->audmode = 0;
atv_demod_set_state(ATVDEMOD_STATE_IDEL);
pr_info("%s: OK.\n", __func__);
@@ -258,7 +549,7 @@ static void atv_demod_set_params(struct dvb_frontend *fe,
atvdemod_param->param.std = params->std;
/* afc tune disable,must cancel wq before set tuner freq*/
/* afc_timer_disable(); */
afc_timer_disable(fe);
if (fe->ops.tuner_ops.set_analog_params)
ret = fe->ops.tuner_ops.set_analog_params(fe, params);
@@ -303,7 +594,7 @@ static void atv_demod_set_params(struct dvb_frontend *fe,
return;
}
if (!is_atvdemod_scan_mode())
if (!atv_demod_get_scan_mode())
atvauddemod_init();
pr_info("[%s] set std color %s, audio type %s.\n",
@@ -314,6 +605,11 @@ static void atv_demod_set_params(struct dvb_frontend *fe,
__func__, amlatvdemod_devp->if_freq,
amlatvdemod_devp->if_inv);
}
/* afc tune enable */
if ((fe->ops.info.type == FE_ANALOG)
&& (atv_demod_get_scan_mode() == 0))
afc_timer_enable(fe);
}
static int atv_demod_has_signal(struct dvb_frontend *fe, u16 *signal)
@@ -339,9 +635,9 @@ static int atv_demod_has_signal(struct dvb_frontend *fe, u16 *signal)
static void atv_demod_standby(struct dvb_frontend *fe)
{
if (get_atvdemod_state() != ATVDEMOD_STATE_IDEL) {
if (atv_demod_get_state() != ATVDEMOD_STATE_IDEL) {
atv_demod_leave_mode();
set_atvdemod_state(ATVDEMOD_STATE_SLEEP);
atv_demod_set_state(ATVDEMOD_STATE_SLEEP);
}
pr_info("%s: OK.\n", __func__);
@@ -361,6 +657,7 @@ static int atv_demod_get_afc(struct dvb_frontend *fe, s32 *afc)
static void atv_demod_release(struct dvb_frontend *fe)
{
int instance = 0;
struct atv_demod_priv *priv = fe->analog_demod_priv;
atv_demod_leave_mode();
@@ -368,12 +665,13 @@ static void atv_demod_release(struct dvb_frontend *fe)
mutex_lock(&atv_demod_list_mutex);
if (priv)
hybrid_tuner_release_state(priv);
instance = hybrid_tuner_release_state(priv);
if (instance == 0)
fe->analog_demod_priv = NULL;
mutex_unlock(&atv_demod_list_mutex);
fe->analog_demod_priv = NULL;
pr_info("%s: OK.\n", __func__);
}
@@ -390,7 +688,7 @@ static int atv_demod_set_config(struct dvb_frontend *fe, void *priv_cfg)
switch (*state) {
case AML_ATVDEMOD_INIT:
if (get_atvdemod_state() != ATVDEMOD_STATE_WORK) {
if (atv_demod_get_state() != ATVDEMOD_STATE_WORK) {
atv_demod_enter_mode();
if (fe->ops.tuner_ops.set_config)
fe->ops.tuner_ops.set_config(fe, NULL);
@@ -398,7 +696,7 @@ static int atv_demod_set_config(struct dvb_frontend *fe, void *priv_cfg)
break;
case AML_ATVDEMOD_UNINIT:
if (get_atvdemod_state() != ATVDEMOD_STATE_IDEL) {
if (atv_demod_get_state() != ATVDEMOD_STATE_IDEL) {
atv_demod_leave_mode();
if (fe->ops.tuner_ops.release)
fe->ops.tuner_ops.release(fe);
@@ -406,12 +704,22 @@ static int atv_demod_set_config(struct dvb_frontend *fe, void *priv_cfg)
break;
case AML_ATVDEMOD_RESUME:
if (get_atvdemod_state() == ATVDEMOD_STATE_SLEEP) {
if (atv_demod_get_state() == ATVDEMOD_STATE_SLEEP) {
atv_demod_enter_mode();
if (fe->ops.tuner_ops.resume)
fe->ops.tuner_ops.resume(fe);
}
break;
case AML_ATVDEMOD_SCAN_MODE:
atv_demod_set_scan_mode(1);
afc_timer_disable(fe);
break;
case AML_ATVDEMOD_UNSCAN_MODE:
atv_demod_set_scan_mode(0);
afc_timer_enable(fe);
break;
}
mutex_unlock(&atv_demod_list_mutex);
@@ -421,7 +729,7 @@ static int atv_demod_set_config(struct dvb_frontend *fe, void *priv_cfg)
static struct analog_demod_ops atvdemod_ops = {
.info = {
.name = "atv_demod",
.name = DEVICE_NAME,
},
.set_params = atv_demod_set_params,
.has_signal = atv_demod_has_signal,
@@ -452,6 +760,7 @@ struct dvb_frontend *aml_atvdemod_attach(struct dvb_frontend *fe,
mutex_unlock(&atv_demod_list_mutex);
return NULL;
case 1:
INIT_WORK(&priv->demod_wq, aml_fe_do_work);
fe->analog_demod_priv = priv;
priv->standby = true;
pr_info("aml_atvdemod found\n");

View File

@@ -14,9 +14,16 @@
#ifndef __ATV_DEMOD_OPS_H__
#define __ATV_DEMOD_OPS_H__
#define AML_ATVDEMOD_RESUME 0x2
#define AML_ATVDEMOD_INIT 0x1
#define AML_ATVDEMOD_UNINIT 0x0
#define AML_ATVDEMOD_UNINIT 0x0
#define AML_ATVDEMOD_INIT 0x1
#define AML_ATVDEMOD_RESUME 0x2
#define AML_ATVDEMOD_SCAN_MODE 0x3
#define AML_ATVDEMOD_UNSCAN_MODE 0x4
#define AFC_BEST_LOCK 50
#define ATV_AFC_500KHZ 500000
#define ATV_AFC_1_0MHZ 1000000
#define ATV_AFC_2_0MHZ 2000000
#include "drivers/media/dvb-core/dvb_frontend.h"
#include "drivers/media/tuners/tuner-i2c.h"
@@ -30,6 +37,7 @@ struct atv_demod_priv {
bool standby;
struct aml_atvdemod_parameters atvdemod_param;
struct work_struct demod_wq;
};
extern int atv_demod_enter_mode(void);

View File

@@ -43,12 +43,6 @@
static DEFINE_MUTEX(v4l2_fe_mutex);
/* static int v4l2_shutdown_timeout;*/
#define AFC_BEST_LOCK 50
#define ATV_AFC_500KHZ 500000
#define ATV_AFC_1_0MHZ 1000000
#define ATV_AFC_2_0MHZ 2000000
static int tuner_status_cnt = 8; /* 4-->16 test on sky mxl661 */
module_param(tuner_status_cnt, int, 0644);
MODULE_DESCRIPTION("after write a freq, max cnt value of read tuner status\n");
@@ -444,6 +438,7 @@ static enum v4l2_search v4l2_frontend_search(struct v4l2_frontend *v4l2_fe)
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;
@@ -454,7 +449,8 @@ static enum v4l2_search v4l2_frontend_search(struct v4l2_frontend *v4l2_fe)
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_params ||
!fe->ops.analog_ops.set_config)) {
pr_err("[%s] error: NULL function or pointer.\n", __func__);
return V4L2_SEARCH_INVALID;
}
@@ -500,9 +496,8 @@ static enum v4l2_search v4l2_frontend_search(struct v4l2_frontend *v4l2_fe)
__func__, v4l2_std_to_str(p->audmode));
}
/*afc tune disable*/
//TODO: afc_timer_disable();
//analog_search_flag = 1;
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;
@@ -658,9 +653,8 @@ static enum v4l2_search v4l2_frontend_search(struct v4l2_frontend *v4l2_fe)
#endif
/*sync param */
//aml_fe_analog_sync_frontend(fe);
/*afc tune enable*/
//analog_search_flag = 0;
//afc_timer_enable(fe);
priv_cfg = AML_ATVDEMOD_UNSCAN_MODE;
fe->ops.analog_ops.set_config(fe, &priv_cfg);
return V4L2_SEARCH_SUCCESS;
}
}
@@ -711,9 +705,10 @@ static enum v4l2_search v4l2_frontend_search(struct v4l2_frontend *v4l2_fe)
pr_dbg("[%s] [%d] over of range [min=%d, max=%d], search failed.\n",
__func__, p->frequency, minafcfreq, maxafcfreq);
p->frequency = set_freq;
/*afc tune enable*/
//analog_search_flag = 0;
//afc_timer_enable(fe);
priv_cfg = AML_ATVDEMOD_UNSCAN_MODE;
fe->ops.analog_ops.set_config(fe, &priv_cfg);
return DVBFE_ALGO_SEARCH_FAILED;
}
@@ -1149,6 +1144,157 @@ static unsigned int v4l2_frontend_poll(struct file *filp,
return 0;
}
static void v4l2_property_dump(struct v4l2_frontend *v4l2_fe,
bool is_set, struct v4l2_property *tvp)
{
/*int i = 0;*/
if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {
pr_warn("%s: %s tvp.cmd = 0x%08x undefined\n",
__func__,
is_set ? "SET" : "GET",
tvp->cmd);
return;
}
#if 0
pr_dbg("%s: %s tvp.cmd = 0x%08x (%s)\n", __func__,
is_set ? "SET" : "GET",
tvp->cmd,
v4l2_cmds[tvp->cmd].name);
if (v4l2_cmds[tvp->cmd].buffer) {
pr_dbg("%s: tvp.u.buffer.len = 0x%02x\n",
__func__, tvp->u.buffer.len);
for (i = 0; i < tvp->u.buffer.len; i++)
pr_dbg("%s: tvp.u.buffer.data[0x%02x] = 0x%02x\n",
__func__, i, tvp->u.buffer.data[i]);
} else {
pr_dbg("%s: tvp.u.data = 0x%08x\n", __func__,
tvp->u.data);
}
#endif
}
static int v4l2_property_process_set(struct v4l2_frontend *v4l2_fe,
struct v4l2_property *tvp, struct file *file)
{
int r = 0;
v4l2_property_dump(v4l2_fe, true, tvp);
switch (tvp->cmd) {
case V4L2_TUNE:
break;
case V4L2_NICAM:
break;
default:
return -EINVAL;
}
return r;
}
static int v4l2_property_process_get(struct v4l2_frontend *v4l2_fe,
struct v4l2_property *tvp, struct file *file)
{
switch (tvp->cmd) {
case V4L2_NICAM:
tvp->u.data = 0;
break;
default:
pr_dbg("%s: V4L2 property %d doesn't exist\n",
__func__, tvp->cmd);
return -EINVAL;
}
v4l2_property_dump(v4l2_fe, false, tvp);
return 0;
}
static int v4l2_frontend_ioctl_properties(struct file *filp,
unsigned int cmd, void *parg)
{
struct v4l2_frontend *v4l2_fe = video_get_drvdata(video_devdata(filp));
int err = 0;
struct v4l2_properties *tvps = parg;
struct v4l2_property *tvp = NULL;
int i = 0;
pr_dbg("%s.\n", __func__);
if (cmd == V4L2_SET_PROPERTY) {
pr_dbg("%s: properties.num = %d\n", __func__, tvps->num);
pr_dbg("%s: properties.props = %p\n", __func__, tvps->props);
/* Put an arbitrary limit on the number of messages that can
* be sent at once
*/
if ((tvps->num == 0) || (tvps->num > V4L2_IOCTL_MAX_MSGS))
return -EINVAL;
tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp));
if (IS_ERR(tvp))
return PTR_ERR(tvp);
for (i = 0; i < tvps->num; i++) {
err = v4l2_property_process_set(v4l2_fe, tvp + i, filp);
if (err < 0)
goto out;
(tvp + i)->result = err;
}
} else if (cmd == FE_GET_PROPERTY) {
pr_dbg("%s: properties.num = %d\n", __func__, tvps->num);
pr_dbg("%s: properties.props = %p\n", __func__, tvps->props);
/* Put an arbitrary limit on the number of messages that can
* be sent at once
*/
if ((tvps->num == 0) || (tvps->num > V4L2_IOCTL_MAX_MSGS))
return -EINVAL;
tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp));
if (IS_ERR(tvp))
return PTR_ERR(tvp);
/*
* Let's use our own copy of property cache, in order to
* avoid mangling with DTV zigzag logic, as drivers might
* return crap, if they don't check if the data is available
* before updating the properties cache.
*/
#if 0
if (fepriv->state != V4L2FE_STATE_IDLE) {
err = v4l2_get_frontend(v4l2_fe, &getp, NULL);
if (err < 0)
goto out;
}
#endif
for (i = 0; i < tvps->num; i++) {
err = v4l2_property_process_get(v4l2_fe, tvp + i, filp);
if (err < 0)
goto out;
(tvp + i)->result = err;
}
if (copy_to_user((void __user *)tvps->props, tvp,
tvps->num * sizeof(struct v4l2_property))) {
err = -EFAULT;
goto out;
}
} else
err = -EOPNOTSUPP;
out:
kfree(tvp);
return err;
}
static long v4l2_frontend_ioctl(struct file *filp, void *fh, bool valid_prio,
unsigned int cmd, void *arg)
{
@@ -1199,6 +1345,11 @@ 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:
ret = v4l2_frontend_ioctl_properties(filp, cmd, arg);
break;
default:
break;
}
@@ -1451,6 +1602,16 @@ int v4l2_unresister_frontend(struct v4l2_frontend *v4l2_fe)
return 0;
}
void v4l2_frontend_detach(struct v4l2_frontend *v4l2_fe)
{
if (v4l2_fe->fe.ops.tuner_ops.release)
v4l2_fe->fe.ops.tuner_ops.release(&v4l2_fe->fe);
if (v4l2_fe->fe.ops.analog_ops.release)
v4l2_fe->fe.ops.analog_ops.release(&v4l2_fe->fe);
if (v4l2_fe->fe.ops.release)
v4l2_fe->fe.ops.release(&v4l2_fe->fe);
}
int v4l2_frontend_suspend(struct v4l2_frontend *v4l2_fe)
{
int ret = 0;

View File

@@ -34,13 +34,19 @@
__r; \
})
#define v4l2_detach(FUNCTION) symbol_put_addr(FUNCTION)
#else
#define v4l2_attach(FUNCTION, ARGS...) ({ \
FUNCTION(ARGS); \
})
#define v4l2_detach(FUNCTION) {}
#endif /* CONFIG_MEDIA_ATTACH */
#define V4L2_FE_NO_EXIT 0
#define V4L2_FE_NORMAL_EXIT 1
#define V4L2_FE_DEVICE_REMOVED 2
@@ -64,15 +70,22 @@
#define V4L2FE_STATE_LOSTLOCK (V4L2FE_STATE_ZIGZAG_FAST |\
V4L2FE_STATE_ZIGZAG_SLOW)
#define V4L2_IOCTL_MAX_MSGS 64
#define V4L2_SET_FRONTEND _IOW('V', 105, struct v4l2_analog_parameters)
#define V4L2_GET_FRONTEND _IOR('V', 106, struct v4l2_analog_parameters)
#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 ANALOG_FLAG_ENABLE_AFC 0X00000001
#define ANALOG_FLAG_MANUL_SCAN 0x00000011
#define ANALOG_FLAG_ENABLE_AFC 0X00000001
#define ANALOG_FLAG_MANUL_SCAN 0x00000011
#define V4L2_UNDEFINED 0
#define V4L2_TUNE 1
#define V4L2_NICAM 2
struct v4l2_analog_parameters {
@@ -96,6 +109,26 @@ enum v4l2_status {
}; /* application is recommended to reset */
/* 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;
int result;
} __attribute__ ((__packed__));
struct v4l2_properties {
__u32 num;
struct v4l2_property *props;
};
enum v4l2_search {
V4L2_SEARCH_SUCCESS = (1 << 0),
V4L2_SEARCH_ASLEEP = (1 << 1),
@@ -183,6 +216,7 @@ struct v4l2_atvdemod_device {
int v4l2_resister_frontend(struct v4l2_frontend *v4l2_fe);
int v4l2_unresister_frontend(struct v4l2_frontend *v4l2_fe);
void v4l2_frontend_detach(struct v4l2_frontend *v4l2_fe);
int v4l2_frontend_suspend(struct v4l2_frontend *v4l2_fe);
int v4l2_frontend_resume(struct v4l2_frontend *v4l2_fe);

View File

@@ -9,9 +9,8 @@ extern int atvaudiodem_reg_read(unsigned int reg, unsigned int *val);
extern int atvaudiodem_reg_write(unsigned int reg, unsigned int val);
extern uint32_t adec_rd_reg(uint32_t addr);
extern void adec_wr_reg(uint32_t reg, uint32_t val);
extern int atv_demod_get_state(void);
extern int is_atvdemod_work(void);
int get_atvdemod_state(void);
void set_atvdemod_state(int state);
extern int aml_atvdemod_get_btsc_sap_mode(void);
extern void audio_mode_det(int mode);