mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 11:50:43 +09:00
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:
@@ -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__ */
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user