blob: 8bbb208c607465b0f91a2aff5007de6d568ec29c [file] [log] [blame]
/*
* drivers/amlogic/media/dtv_demod/dvbc_func.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/kernel.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/dvb/aml_demod.h>
#include "demod_func.h"
#include <linux/kthread.h>
/*#include "dvbc_func.h"*/
MODULE_PARM_DESC(debug_amldvbc, "\n\t\t Enable frontend demod debug information");
static int debug_amldvbc;
module_param(debug_amldvbc, int, 0644);
/*#define dprintk(a ...) do { if (debug_amldvbc) printk(a); } while (0)*/
/*move to dvbc_old.c*/
/* static struct task_struct *cci_task; */
/*int cciflag = 0;*/
struct timer_list mytimer;
static void dvbc_cci_timer(unsigned long data)
{
#if 0
int count;
int maxCCI_p, re, im, j, i, times, maxCCI, sum, sum1, reg_0xf0, tmp1,
tmp, tmp2, reg_0xa8, reg_0xac;
int reg_0xa8_t, reg_0xac_t;
count = 100;
if ((((dvbc_read_reg(QAM_BASE + 0x18)) & 0x1) == 1)) {
PR_DVBC("[cci]lock ");
if (cciflag == 0) {
dvbc_write_reg(QAM_BASE + 0xa8, 0);
cciflag = 0;
}
PR_DVBC("\n");
mdelay(500);
mod_timer(&mytimer, jiffies + 2 * HZ);
return;
}
if (cciflag == 1) {
PR_DVBC("[cci]cciflag is 1,wait 20\n");
mdelay(20000);
}
times = 300;
tmp = 0x2be2be3;
/*0x2ae4772; IF = 6M, fs = 35M, dec2hex(round(8*IF/fs*2^25)) */
tmp2 = 0x2000;
tmp1 = 8;
reg_0xa8 = 0xc0000000; /* bypass CCI */
reg_0xac = 0xc0000000; /* bypass CCI */
maxCCI = 0;
maxCCI_p = 0;
for (i = 0; i < times; i++) {
/*reg_0xa8 = app_apb_read_reg(0xa8); */
reg_0xa8_t = reg_0xa8 + tmp + i * tmp2;
dvbc_write_reg(QAM_BASE + 0xa8, reg_0xa8_t);
reg_0xac_t = reg_0xac + tmp - i * tmp2;
dvbc_write_reg(QAM_BASE + 0xac, reg_0xac_t);
sum = 0;
sum1 = 0;
for (j = 0; j < tmp1; j++) {
/* msleep(20); */
/* mdelay(20); */
reg_0xf0 = dvbc_read_reg(QAM_BASE + 0xf0);
re = (reg_0xf0 >> 24) & 0xff;
im = (reg_0xf0 >> 16) & 0xff;
if (re > 127)
/*re = re - 256; */
re = 256 - re;
if (im > 127)
/*im = im - 256; */
im = 256 - im;
sum += re + im;
re = (reg_0xf0 >> 8) & 0xff;
im = (reg_0xf0 >> 0) & 0xff;
if (re > 127)
/*re = re - 256; */
re = 256 - re;
if (im > 127)
/*im = im - 256; */
im = 256 - im;
sum1 += re + im;
}
sum = sum / tmp1;
sum1 = sum1 / tmp1;
if (sum1 > sum) {
sum = sum1;
reg_0xa8_t = reg_0xac_t;
}
if (sum > maxCCI) {
maxCCI = sum;
if (maxCCI > 24)
maxCCI_p = reg_0xa8_t & 0x7fffffff;
}
if ((sum < 24) && (maxCCI_p > 0))
break; /* stop CCI detect. */
}
if (maxCCI_p > 0) {
dvbc_write_reg(QAM_BASE + 0xa8, maxCCI_p & 0x7fffffff);
/* enable CCI */
dvbc_write_reg(QAM_BASE + 0xac, maxCCI_p & 0x7fffffff);
/* enable CCI */
/* if(dvbc.mode == 4) // 256QAM */
dvbc_write_reg(QAM_BASE + 0x54, 0xa25705fa);
/**/ cciflag = 1;
mdelay(1000);
} else {
PR_DVBC
("[cci] ------------ find NO CCI -------------------\n");
cciflag = 0;
}
PR_DVBC("[cci][%s]--------------------------\n", __func__);
mod_timer(&mytimer, jiffies + 2 * HZ);
return;
/* }*/
#endif
}
int dvbc_timer_init(void)
{
PR_DVBC("%s\n", __func__);
setup_timer(&mytimer, dvbc_cci_timer, (unsigned long)"Hello, world!");
mytimer.expires = jiffies + 2 * HZ;
add_timer(&mytimer);
return 0;
}
void dvbc_timer_exit(void)
{
PR_DVBC("%s\n", __func__);
del_timer(&mytimer);
}
#if 0 /*ary*/
int dvbc_cci_task(void *data)
{
int count;
int maxCCI_p, re, im, j, i, times, maxCCI, sum, sum1, reg_0xf0, tmp1,
tmp, tmp2, reg_0xa8, reg_0xac;
int reg_0xa8_t, reg_0xac_t;
count = 100;
while (1) {
msleep(200);
if ((((dvbc_read_reg(QAM_BASE + 0x18)) & 0x1) == 1)) {
PR_DVBC("[cci]lock ");
if (cciflag == 0) {
dvbc_write_reg(QAM_BASE + 0xa8, 0);
dvbc_write_reg(QAM_BASE + 0xac, 0);
PR_DVBC("no cci ");
cciflag = 0;
}
PR_DVBC("\n");
msleep(500);
continue;
}
if (cciflag == 1) {
PR_DVBC("[cci]cciflag is 1,wait 20\n");
msleep(20000);
}
times = 300;
tmp = 0x2be2be3;
/*0x2ae4772; IF = 6M,fs = 35M, dec2hex(round(8*IF/fs*2^25)) */
tmp2 = 0x2000;
tmp1 = 8;
reg_0xa8 = 0xc0000000; /* bypass CCI */
reg_0xac = 0xc0000000; /* bypass CCI */
maxCCI = 0;
maxCCI_p = 0;
for (i = 0; i < times; i++) {
/*reg_0xa8 = app_apb_read_reg(0xa8); */
reg_0xa8_t = reg_0xa8 + tmp + i * tmp2;
dvbc_write_reg(QAM_BASE + 0xa8, reg_0xa8_t);
reg_0xac_t = reg_0xac + tmp - i * tmp2;
dvbc_write_reg(QAM_BASE + 0xac, reg_0xac_t);
sum = 0;
sum1 = 0;
for (j = 0; j < tmp1; j++) {
/* msleep(1); */
reg_0xf0 = dvbc_read_reg(QAM_BASE + 0xf0);
re = (reg_0xf0 >> 24) & 0xff;
im = (reg_0xf0 >> 16) & 0xff;
if (re > 127)
/*re = re - 256; */
re = 256 - re;
if (im > 127)
/*im = im - 256; */
im = 256 - im;
sum += re + im;
re = (reg_0xf0 >> 8) & 0xff;
im = (reg_0xf0 >> 0) & 0xff;
if (re > 127)
/*re = re - 256; */
re = 256 - re;
if (im > 127)
/*im = im - 256; */
im = 256 - im;
sum1 += re + im;
}
sum = sum / tmp1;
sum1 = sum1 / tmp1;
if (sum1 > sum) {
sum = sum1;
reg_0xa8_t = reg_0xac_t;
}
if (sum > maxCCI) {
maxCCI = sum;
if (maxCCI > 24)
maxCCI_p = reg_0xa8_t & 0x7fffffff;
}
if ((sum < 24) && (maxCCI_p > 0))
break; /* stop CCI detect. */
}
if (maxCCI_p > 0) {
dvbc_write_reg(QAM_BASE + 0xa8, maxCCI_p & 0x7fffffff);
/* enable CCI */
dvbc_write_reg(QAM_BASE + 0xac, maxCCI_p & 0x7fffffff);
/* enable CCI */
/* if(dvbc.mode == 4) // 256QAM */
dvbc_write_reg(QAM_BASE + 0x54, 0xa25705fa);
/**/ cciflag = 1;
msleep(1000);
} else {
cciflag = 0;
}
PR_DVBC("[cci][%s]--------------------------\n", __func__);
}
return 0;
}
int dvbc_get_cci_task(void)
{
if (cci_task)
return 0;
else
return 1;
}
void dvbc_create_cci_task(void)
{
int ret;
/*dvbc_write_reg(QAM_BASE+0xa8, 0x42b2ebe3); // enable CCI */
/* dvbc_write_reg(QAM_BASE+0xac, 0x42b2ebe3); // enable CCI */
/* if(dvbc.mode == 4) // 256QAM*/
/* dvbc_write_reg(QAM_BASE+0x54, 0xa25705fa); // */
ret = 0;
cci_task = kthread_create(dvbc_cci_task, NULL, "cci_task");
if (ret != 0) {
PR_DVBC("[%s]Create cci kthread error!\n", __func__);
cci_task = NULL;
return;
}
wake_up_process(cci_task);
PR_DVBC("[%s]Create cci kthread and wake up!\n", __func__);
}
void dvbc_kill_cci_task(void)
{
if (cci_task) {
kthread_stop(cci_task);
cci_task = NULL;
PR_DVBC("[%s]kill cci kthread !\n", __func__);
}
}
#endif
int dvbc_set_ch(struct aml_demod_sta *demod_sta,
/*struct aml_demod_i2c *demod_i2c,*/
struct aml_demod_dvbc *demod_dvbc)
{
int ret = 0;
u16 symb_rate;
u8 mode;
u32 ch_freq;
PR_DVBC("f=%d, s=%d, q=%d\n",
demod_dvbc->ch_freq, demod_dvbc->symb_rate, demod_dvbc->mode);
/*ary no use demod_i2c->tuner = 7;*/
mode = demod_dvbc->mode;
symb_rate = demod_dvbc->symb_rate;
ch_freq = demod_dvbc->ch_freq;
if (mode > 4) {
PR_DVBC("Error: Invalid QAM mode option %d\n", mode);
mode = 4;
ret = -1;
}
if (symb_rate < 1000 || symb_rate > 7000) {
PR_DVBC("Error: Invalid Symbol Rate option %d\n", symb_rate);
symb_rate = 5361;
ret = -1;
}
if (ch_freq < 1000 || ch_freq > 900000) {
PR_DVBC("Error: Invalid Channel Freq option %d\n", ch_freq);
ch_freq = 474000;
ret = -1;
}
/* if (ret != 0) return ret; */
//demod_sta->dvb_mode = 0;
demod_sta->ch_mode = mode;
/* 0:16, 1:32, 2:64, 3:128, 4:256 */
demod_sta->agc_mode = 1;
/* 0:NULL, 1:IF, 2:RF, 3:both */
demod_sta->ch_freq = ch_freq;
/*ary no use demod_sta->tuner = demod_i2c->tuner;*/
#if 0 /*ary no use*/
if (demod_i2c->tuner == 1)
demod_sta->ch_if = 36130; /* TODO DCT tuner */
else if (demod_i2c->tuner == 2)
demod_sta->ch_if = 4570; /* TODO Maxlinear tuner */
else if (demod_i2c->tuner == 7)
/* demod_sta->ch_if = 5000; // TODO Si2176 tuner */
#endif
demod_sta->ch_bw = 8000; /* TODO */
if (demod_sta->ch_if == 0)
demod_sta->ch_if = 5000;
demod_sta->symb_rate = symb_rate;
if ((!is_ic_ver(IC_VER_TL1)) && is_dvbc_ver(IC_DVBC_V3))
demod_sta->adc_freq = demod_dvbc->dat0;
#if 0
if (is_meson_txlx_cpu() || is_meson_gxlx_cpu())
dvbc_reg_initial(demod_sta);
else
dvbc_reg_initial_old(demod_sta);
#endif
if (is_dvbc_ver(IC_DVBC_V2))
dvbc_reg_initial_old(demod_sta);
else if (is_dvbc_ver(IC_DVBC_V3))
dvbc_reg_initial(demod_sta);
else
PR_ERR("%s:not support %d\n", __func__, get_dvbc_ver());
return ret;
}