blob: 9d11b47d7f4fe3cbed0f368dcdc77852a258bcc4 [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/irq.h>
#include <linux/types.h>
#include <linux/input.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/mm.h>
#include <linux/major.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/cdev.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/spinlock_types.h>
#include <linux/workqueue.h>
#include <linux/timer.h>
#include <linux/atomic.h>
#include <linux/of.h>
#include <linux/compat.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/reboot.h>
#include <linux/notifier.h>
#include <linux/random.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_wakeup.h>
#include <linux/pm_wakeirq.h>
#include <linux/pm.h>
#include <linux/poll.h>
#include <linux/amlogic/media/frame_provider/tvin/tvin.h>
#include <linux/amlogic/pm.h>
#include <linux/amlogic/cpu_version.h>
#include <linux/amlogic/iomap.h>
#include "adc.h"
#define ADC_DEV_NAME "adc"
static struct tvin_adc_dev *adc_devp;
static bool probe_finish;
static int adc_wr_afe(unsigned int reg, unsigned int val)
{
if (!probe_finish || !adc_devp)
return -1;
writel(val, (adc_devp->vir_addr[MAP_ADDR_AFE] + (reg << 2)));
return 0;
}
static unsigned int adc_rd_afe(unsigned int reg)
{
if (!probe_finish || !adc_devp)
return -1;
return readl(adc_devp->vir_addr[MAP_ADDR_AFE] + (reg << 2));
}
static int adc_wr_hiu(unsigned int reg, unsigned int val)
{
if (!probe_finish || !adc_devp)
return -1;
writel(val, (adc_devp->vir_addr[MAP_ADDR_HIU] + (reg << 2)));
return 0;
}
static unsigned int adc_rd_hiu(unsigned int reg)
{
unsigned int tmp;
if (!probe_finish || !adc_devp)
return -1;
tmp = readl(adc_devp->vir_addr[MAP_ADDR_HIU] + (reg << 2));
return tmp;
}
static unsigned int adc_rd_hiu_bits(u32 reg, const u32 start, const u32 len)
{
u32 val;
val = ((adc_rd_hiu(reg) >> (start)) & ((1L << (len)) - 1));
return val;
}
static void adc_wr_hiu_bits(u32 reg, const u32 value,
const u32 start, const u32 len)
{
adc_wr_hiu(reg, ((adc_rd_hiu(reg) &
~(((1L << (len)) - 1) << (start))) |
(((value) & ((1L << (len)) - 1)) << (start))));
}
/* add for dtv demod */
void adc_set_ddemod_default(enum fe_delivery_system delsys)
{
struct tvin_adc_dev *devp = adc_devp;
struct adc_reg_addr *adc_addr = &devp->plat_data->adc_addr;
if (!probe_finish)
return;
if (is_meson_txl_cpu() || is_meson_txlx_cpu() ||
is_meson_gxlx_cpu()) {
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
adc_wr_hiu(HHI_DADC_CNTL, 0x00102038);
adc_wr_hiu(HHI_DADC_CNTL2, 0x00000406);
adc_wr_hiu(HHI_DADC_CNTL3, 0x00082183);
/*W_HIU_REG(HHI_VDAC_CNTL0, 0x00000200);*/
/*W_HIU_BIT(HHI_VDAC_CNTL0, 1, 9, 1);*/
/* remove vdac reg write, make sure it write in vdac driver,
* because multi module use it
*/
#endif
} else if (cpu_after_eq(MESON_CPU_MAJOR_ID_TL1)) {
switch (devp->plat_data->chip_id) {
case ADC_CHIP_T5D:
case ADC_CHIP_T3:
case ADC_CHIP_T5W:
switch (delsys) {
case SYS_DVBT:
case SYS_DVBT2:
adc_wr_afe(AFE_VAFE_CTRL0, 0x00050710);
adc_wr_afe(AFE_VAFE_CTRL1, 0x3000);
adc_wr_afe(AFE_VAFE_CTRL2, 0x1fe09e31);
adc_wr_hiu(adc_addr->dadc_cntl, 0x0030303c);
if (devp->plat_data->chip_id >= ADC_CHIP_T3)
adc_wr_hiu(adc_addr->dadc_cntl_2, 0x00003448);
else
adc_wr_hiu(adc_addr->dadc_cntl_2, 0x00003440);
/* bit[1:0] adc en/dis, 00:dis, 11:en */
adc_wr_hiu(adc_addr->dadc_cntl_3, 0x08300b93);
adc_wr_hiu(adc_addr->dadc_cntl_4, 0xc00);
break;
case SYS_DVBS:
case SYS_DVBS2:
adc_wr_hiu(adc_addr->s2_dadc_cntl, 0x4100900f);
adc_wr_hiu(adc_addr->dadc_cntl_4, 0x0);
if (devp->plat_data->chip_id >= ADC_CHIP_T3) {
adc_wr_hiu(adc_addr->dadc_cntl_2, 0x00000008);
adc_wr_hiu(adc_addr->s2_dadc_cntl, 0x41209007);
}
/* only for debug to clkmsr(id:149) */
/* adc_wr_hiu(adc_addr->dadc_cntl_3, 0x08300b8f); */
break;
default:
adc_wr_afe(AFE_VAFE_CTRL0, 0x000d0710);
adc_wr_afe(AFE_VAFE_CTRL1, 0x3000);
adc_wr_afe(AFE_VAFE_CTRL2, 0x1fe09e31);
adc_wr_hiu(adc_addr->dadc_cntl, 0x00303044);
if (devp->plat_data->chip_id >= ADC_CHIP_T3)
adc_wr_hiu(adc_addr->dadc_cntl_2, 0x00003488);
else
adc_wr_hiu(adc_addr->dadc_cntl_2, 0x00003480);
adc_wr_hiu(adc_addr->dadc_cntl_3, 0x08300b83);
adc_wr_hiu(adc_addr->dadc_cntl_4, 0x0);
break;
}
adc_wr_hiu(adc_addr->s2_dadc_cntl_2, 0x00000582);
break;
case ADC_CHIP_S4:
case ADC_CHIP_S4D:
/* enable bandgap */
adc_wr_hiu_bits(0xb0, 1, 11, 1);
adc_wr_hiu(0xd1, 0x562);
adc_wr_hiu(0xd0, 0x41209007);
break;
default:
adc_wr_afe(AFE_VAFE_CTRL0, 0x000d0710);
adc_wr_afe(AFE_VAFE_CTRL1, 0x3000);
adc_wr_afe(AFE_VAFE_CTRL2, 0x1fe09e31);
adc_wr_hiu(adc_addr->dadc_cntl, 0x00303044);
adc_wr_hiu(adc_addr->dadc_cntl_2, 0x00003480);
adc_wr_hiu(adc_addr->dadc_cntl_3, 0x08300b83);
break;
}
}
}
EXPORT_SYMBOL(adc_set_ddemod_default);
int adc_set_filter_ctrl(bool on, enum filter_sel module_sel, void *data)
{
int ret = 0;
struct tvin_adc_dev *devp = adc_devp;
if (!probe_finish || !devp)
return -ENXIO;
mutex_lock(&devp->filter_mutex);
if (!on) {
devp->filter_flg &= ~module_sel;
if (devp->print_en)
pr_info("%s: on: %d, module: 0x%x, filter_flg: 0x%x\n",
__func__, on, module_sel, devp->filter_flg);
mutex_unlock(&devp->filter_mutex);
return 0;
}
if (devp->print_en)
pr_info("%s: on: %d, module: 0x%x, filter_flg: 0x%x\n",
__func__, on, module_sel, devp->filter_flg);
switch (module_sel) {
case FILTER_ATV_DEMOD:
if (devp->filter_flg & (FILTER_TVAFE | FILTER_DTV_DEMOD)) {
ret = -1;
pr_info("%s: ADEMOD fail!!!, filter_flg: %d\n",
__func__, devp->filter_flg);
break;
}
if (devp->filter_flg & FILTER_ATV_DEMOD) {
if (devp->print_en)
pr_info("%s: ADEMOD ATV had done!: %d\n",
__func__, devp->filter_flg);
break;
}
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TL1)) {
adc_wr_afe(AFE_VAFE_CTRL0, 0x000d0710);
adc_wr_afe(AFE_VAFE_CTRL1, 0x3000);
adc_wr_afe(AFE_VAFE_CTRL2, 0x1fe09e31);
} else if (get_cpu_type() == MESON_CPU_MAJOR_ID_TXL ||
get_cpu_type() == MESON_CPU_MAJOR_ID_TXLX) {
adc_wr_afe(AFE_VAFE_CTRL0, 0x00090b00);
adc_wr_afe(AFE_VAFE_CTRL1, 0x00000110);
adc_wr_afe(AFE_VAFE_CTRL2, 0x0010ef93);
}
devp->filter_flg |= FILTER_ATV_DEMOD;
break;
case FILTER_TVAFE:
if (devp->filter_flg & (FILTER_ATV_DEMOD | FILTER_DTV_DEMOD)) {
ret = -2;
pr_info("%s: AFE fail!!!, filter_flg: %d\n",
__func__, devp->filter_flg);
break;
}
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TL1)) {
adc_wr_afe(AFE_VAFE_CTRL0, 0x00490710);
adc_wr_afe(AFE_VAFE_CTRL1, 0x0000110e);
adc_wr_afe(AFE_VAFE_CTRL2, 0x1fe09f83);
} else if (get_cpu_type() == MESON_CPU_MAJOR_ID_TXL ||
get_cpu_type() == MESON_CPU_MAJOR_ID_TXLX) {
adc_wr_afe(AFE_VAFE_CTRL0, 0x00090b00);
adc_wr_afe(AFE_VAFE_CTRL1, 0x00000110);
adc_wr_afe(AFE_VAFE_CTRL2, 0x0010ef93);
}
devp->filter_flg |= FILTER_TVAFE;
break;
case FILTER_DTV_DEMOD:
if (devp->filter_flg & (FILTER_ATV_DEMOD | FILTER_TVAFE)) {
ret = -3;
pr_info("%s: DDEMOD fail!!!, filter_flg: %d\n",
__func__, devp->filter_flg);
break;
}
devp->filter_flg |= FILTER_DTV_DEMOD;
break;
case FILTER_DTV_DEMODT2:
if (devp->filter_flg & (FILTER_ATV_DEMOD | FILTER_TVAFE)) {
ret = -4;
pr_info("%s:DMODPLL fail!!!, filter_flg: %d\n",
__func__, devp->filter_flg);
break;
}
devp->filter_flg |= FILTER_DTV_DEMODT2;
break;
default:
if (devp->print_en)
pr_err("%s: module: 0x%x wrong module index!!!",
__func__, module_sel);
break;
}
mutex_unlock(&devp->filter_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(adc_set_filter_ctrl);
static void adc_set_dtvdemod_pll_by_clk(struct tvin_adc_dev *devp,
struct dfe_adcpll_para *p_dtv_para)
{
unsigned int reg_offset = 0;
enum adc_chip_ver chip = devp->plat_data->chip_id;
struct adc_reg_addr *adc_addr = &devp->plat_data->adc_addr;
struct adc_pll_reg_addr *pll_addr = &devp->plat_data->pll_addr;
if (chip == ADC_CHIP_S4 || chip == ADC_CHIP_S4D)
reg_offset = 0x10;
switch (p_dtv_para->adc_clk) {
case ADC_CLK_24M:
if (chip == ADC_CHIP_S4 || chip == ADC_CHIP_S4D) {
adc_wr_hiu(pll_addr->adc_pll_cntl_0 + reg_offset, 0x0105047d);
//adc_wr_hiu(HHI_ADC_PLL_CNTL0_TL1 + reg_offset, 0x312004e0);
adc_wr_hiu(pll_addr->adc_pll_cntl_1 + reg_offset, 0x03c00000);
/* enable bandgap */
adc_wr_hiu_bits(adc_addr->vdac_cntl_0, 1, 11, 1);
adc_wr_hiu(pll_addr->adc_pll_cntl_2 + reg_offset, 0x01800000);
adc_wr_hiu(pll_addr->adc_pll_cntl_3 + reg_offset, 0x08691d00);
adc_wr_hiu(pll_addr->adc_pll_cntl_4 + reg_offset, 0x33771291);
adc_wr_hiu(pll_addr->adc_pll_cntl_5 + reg_offset, 0x39270000);
adc_wr_hiu(pll_addr->adc_pll_cntl_6 + reg_offset, 0x50540000);
adc_wr_hiu(pll_addr->adc_pll_cntl_0 + reg_offset, 0x1105047d);
} else {
adc_wr_hiu(pll_addr->adc_pll_cntl_0 + reg_offset, 0x012004e0);
adc_wr_hiu(pll_addr->adc_pll_cntl_0 + reg_offset, 0x312004e0);
adc_wr_hiu(pll_addr->adc_pll_cntl_1 + reg_offset, 0x05400000);
/* enable bandgap */
if (chip >= ADC_CHIP_T5)
adc_wr_hiu_bits(adc_addr->vdac_cntl_0, 1, 11, 1);
if (chip >= ADC_CHIP_T5D)
adc_wr_hiu(pll_addr->adc_pll_cntl_2 + reg_offset, 0xe1800000);
else
adc_wr_hiu(pll_addr->adc_pll_cntl_2, 0xe0800000);
adc_wr_hiu(pll_addr->adc_pll_cntl_3 + reg_offset, 0x48681c00);
adc_wr_hiu(pll_addr->adc_pll_cntl_4 + reg_offset, 0x88770290);
//if (chip >= ADC_CHIP_T5D)
//adc_wr_hiu_bits(pll_addr->adc_pll_cntl_5 + reg_offset, 1, 0, 16);
//else
if (chip == ADC_CHIP_T5W)
adc_wr_hiu(pll_addr->adc_pll_cntl_5, 0x3927a00a);
else
adc_wr_hiu(pll_addr->adc_pll_cntl_5, 0x3927a000);
adc_wr_hiu(pll_addr->adc_pll_cntl_6 + reg_offset, 0x56540000);
adc_wr_hiu(pll_addr->adc_pll_cntl_0 + reg_offset, 0x111104e0);
}
break;
case ADC_CLK_25M:
adc_wr_hiu(pll_addr->adc_pll_cntl_0 + reg_offset, 0x001104c8);
adc_wr_hiu(pll_addr->adc_pll_cntl_0 + reg_offset, 0x301104c8);
adc_wr_hiu(pll_addr->adc_pll_cntl_1 + reg_offset, 0x03000000);
adc_wr_hiu(pll_addr->adc_pll_cntl_2 + reg_offset, 0xe1800000);
adc_wr_hiu(pll_addr->adc_pll_cntl_3 + reg_offset, 0x48681c00);
adc_wr_hiu(pll_addr->adc_pll_cntl_4 + reg_offset, 0x88770290);
adc_wr_hiu(pll_addr->adc_pll_cntl_6 + reg_offset, 0x56540000);
adc_wr_hiu(pll_addr->adc_pll_cntl_0 + reg_offset, 0x101104c8);
break;
default:
break;
}
}
static void adc_set_dtvdemod_pll_by_delsys(struct tvin_adc_dev *devp,
struct dfe_adcpll_para *p_dtv_para)
{
struct adc_pll_reg_addr *pll_addr = &devp->plat_data->pll_addr;
enum adc_chip_ver chip = devp->plat_data->chip_id;
unsigned int reg_offset = 0;
if (chip == ADC_CHIP_S4 || chip == ADC_CHIP_S4D)
reg_offset = 0x10;
switch (p_dtv_para->delsys) {
case SYS_DVBT:
case SYS_DVBT2:
adc_wr_hiu(pll_addr->adc_pll_cntl_0, 0x200504b4);
adc_wr_hiu(pll_addr->adc_pll_cntl_0, 0x300504b4);
adc_wr_hiu(pll_addr->adc_pll_cntl_1, 0x01400000);
adc_wr_hiu(pll_addr->adc_pll_cntl_2, 0x0);
adc_wr_hiu(pll_addr->adc_pll_cntl_3, 0x48681f00);
adc_wr_hiu(pll_addr->adc_pll_cntl_4, 0x88770290);
adc_wr_hiu(pll_addr->adc_pll_cntl_5, 0x3927a000);
adc_wr_hiu(pll_addr->adc_pll_cntl_6, 0x56540000);
adc_wr_hiu(pll_addr->adc_pll_cntl_0, 0x100504b4);
break;
case SYS_DVBS:
case SYS_DVBS2:
if (chip == ADC_CHIP_S4D) {
adc_wr_hiu(0xd0, 0x49209007);
adc_wr_hiu(pll_addr->adc_pll_cntl_0 + reg_offset, 0x20070487);
adc_wr_hiu(pll_addr->adc_pll_cntl_0 + reg_offset, 0x30070487);
adc_wr_hiu(pll_addr->adc_pll_cntl_1 + reg_offset, 0x01000000);
adc_wr_hiu(pll_addr->adc_pll_cntl_2 + reg_offset, 0x0);
adc_wr_hiu(pll_addr->adc_pll_cntl_3 + reg_offset, 0x48681f00);
adc_wr_hiu(pll_addr->adc_pll_cntl_4 + reg_offset, 0x88770290);
adc_wr_hiu(pll_addr->adc_pll_cntl_5 + reg_offset, 0x3927a000);
adc_wr_hiu(pll_addr->adc_pll_cntl_6 + reg_offset, 0x56540000);
adc_wr_hiu(pll_addr->adc_pll_cntl_0 + reg_offset, 0x10070487);
} else if (chip == ADC_CHIP_T3 || chip == ADC_CHIP_T5W) {
adc_wr_hiu(pll_addr->adc_pll_cntl_0, 0x20070487);
adc_wr_hiu(pll_addr->adc_pll_cntl_0, 0x30070487);
adc_wr_hiu(pll_addr->adc_pll_cntl_1, 0x01000000);
adc_wr_hiu(pll_addr->adc_pll_cntl_2, 0x0);
adc_wr_hiu(pll_addr->adc_pll_cntl_3, 0x48681f00);
adc_wr_hiu(pll_addr->adc_pll_cntl_4, 0x88770290);
adc_wr_hiu(pll_addr->adc_pll_cntl_5, 0x3927a000);
adc_wr_hiu(pll_addr->adc_pll_cntl_6, 0x56540000);
adc_wr_hiu(pll_addr->adc_pll_cntl_0, 0x10070487);
} else {
adc_wr_hiu(pll_addr->adc_pll_cntl_0, 0x20050487);
adc_wr_hiu(pll_addr->adc_pll_cntl_0, 0x30050487);
adc_wr_hiu(pll_addr->adc_pll_cntl_1, 0x00800000);
adc_wr_hiu(pll_addr->adc_pll_cntl_2, 0x0);
adc_wr_hiu(pll_addr->adc_pll_cntl_3, 0x48681f00);
adc_wr_hiu(pll_addr->adc_pll_cntl_4, 0x88770290);
adc_wr_hiu(pll_addr->adc_pll_cntl_5, 0x3927a000);
adc_wr_hiu(pll_addr->adc_pll_cntl_6, 0x56540000);
adc_wr_hiu(pll_addr->adc_pll_cntl_0, 0x10050487);
}
break;
default:
adc_set_dtvdemod_pll_by_clk(devp, p_dtv_para);
break;
}
}
int adc_set_pll_cntl(bool on, enum adc_sel module_sel, void *p_para)
{
unsigned int adc_pll_lock_cnt = 0, adc_pll_sts = 0;
int ret = 0;/* 0: success; -x: failed */
struct dfe_adcpll_para *p_dtv_para = p_para;/* only for dtv demod */
struct tvin_adc_dev *devp = adc_devp;
struct adc_reg_addr *adc_addr;
struct adc_pll_reg_addr *pll_addr;
unsigned int reg_offset = 0;
if (!probe_finish || !devp) {
ret = -6;
return ret;
}
adc_addr = &devp->plat_data->adc_addr;
pll_addr = &devp->plat_data->pll_addr;
if (!on) {
mutex_lock(&devp->pll_mutex);
devp->pll_flg &= ~module_sel;
mutex_unlock(&devp->pll_mutex);
if (devp->print_en)
pr_info("%s: init flag on:%d,module:0x%x,flag:0x%x\n",
__func__, on, module_sel, devp->pll_flg);
return ret;
}
switch (module_sel) {
case ADC_ATV_DEMOD:
if (devp->pll_flg & (ADC_TVAFE | ADC_DTV_DEMOD)) {
ret = -1;
if (devp->print_en)
pr_info("%s:ADEMOD fail!:%d\n",
__func__, devp->pll_flg);
break;
}
if (devp->pll_flg & ADC_ATV_DEMOD) {
if (devp->print_en)
pr_info("%s:ADEMOD ATV had done!:%d\n",
__func__, devp->pll_flg);
break;
}
mutex_lock(&devp->pll_mutex);
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TL1)) {
do {
if (get_cpu_type() >= MESON_CPU_MAJOR_ID_T5) {
adc_wr_hiu(pll_addr->adc_pll_cntl_0, 0x210504a0);
adc_wr_hiu(pll_addr->adc_pll_cntl_0, 0x310504a0);
adc_wr_hiu(pll_addr->adc_pll_cntl_1, 0x03c00000);
adc_wr_hiu(pll_addr->adc_pll_cntl_2, 0x00000000);
adc_wr_hiu(pll_addr->adc_pll_cntl_3, 0x48681f00);
adc_wr_hiu(pll_addr->adc_pll_cntl_4, 0x88770290);
adc_wr_hiu(pll_addr->adc_pll_cntl_5, 0x39272000);
adc_wr_hiu(pll_addr->adc_pll_cntl_6, 0x56540000);
adc_wr_hiu_bits(adc_addr->vdac_cntl_0, 1, 11, 1);
adc_wr_hiu(pll_addr->adc_pll_cntl_0, 0x110504a0);
if (devp->plat_data->chip_id >= ADC_CHIP_T5D) {
adc_wr_hiu(adc_addr->s2_dadc_cntl_2, 0x00000582);
adc_wr_hiu(adc_addr->dadc_cntl_4, 0x0);
}
} else {
adc_wr_hiu(pll_addr->adc_pll_cntl_0, 0x01200490);
adc_wr_hiu(pll_addr->adc_pll_cntl_0, 0x31200490);
adc_wr_hiu(pll_addr->adc_pll_cntl_1, 0x06c00000);
adc_wr_hiu(pll_addr->adc_pll_cntl_2, 0xe1800000);
adc_wr_hiu(pll_addr->adc_pll_cntl_3, 0x48681c00);
adc_wr_hiu(pll_addr->adc_pll_cntl_4, 0x88770290);
adc_wr_hiu(pll_addr->adc_pll_cntl_5, 0x39272000);
adc_wr_hiu(pll_addr->adc_pll_cntl_6, 0x56540000);
adc_wr_hiu(pll_addr->adc_pll_cntl_0, 0x11010490);
}
/** DADC CNTL for LIF signal input **/
adc_wr_hiu(adc_addr->dadc_cntl, 0x00303044);
if (devp->plat_data->chip_id >= ADC_CHIP_T3)
adc_wr_hiu(adc_addr->dadc_cntl_2, 0x00003488);
else
adc_wr_hiu(adc_addr->dadc_cntl_2, 0x00003480);
adc_wr_hiu(adc_addr->dadc_cntl_3, 0x08300b83);
usleep_range(100, 101);
adc_pll_lock_cnt++;
if (devp->plat_data->chip_id == ADC_CHIP_T3)
adc_pll_sts = adc_rd_hiu_bits(pll_addr->adc_pll_cntl_7, 31, 1);
else
adc_pll_sts = adc_rd_hiu_bits(pll_addr->adc_pll_cntl_0, 31, 1);
} while (!adc_pll_sts && (adc_pll_lock_cnt < 10));
} else {
do {
if (is_meson_txl_cpu() ||
is_meson_txlx_cpu()) {
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
adc_wr_hiu(HHI_ADC_PLL_CNTL3, 0x4a6a2110);
adc_wr_hiu(HHI_ADC_PLL_CNTL, 0x30f14250);
adc_wr_hiu(HHI_ADC_PLL_CNTL1, 0x22000442);
/* 0x5ba00380 from pll;0x5ba00384 clk */
/* from crystal */
adc_wr_hiu(HHI_ADC_PLL_CNTL2, 0x5ba00384);
adc_wr_hiu(HHI_ADC_PLL_CNTL3, 0x4a6a2110);
adc_wr_hiu(HHI_ADC_PLL_CNTL4, 0x02913004);
adc_wr_hiu(HHI_ADC_PLL_CNTL5, 0x00034a00);
adc_wr_hiu(HHI_ADC_PLL_CNTL6, 0x00005000);
adc_wr_hiu(HHI_ADC_PLL_CNTL3, 0xca6a2110);
adc_wr_hiu(HHI_ADC_PLL_CNTL3, 0x4a6a2110);
/** DADC CNTL for LIF signal input **/
adc_wr_hiu(HHI_DADC_CNTL, 0x00102038);
adc_wr_hiu(HHI_DADC_CNTL2, 0x00000406);
adc_wr_hiu(HHI_DADC_CNTL3, 0x00082183);
#endif
} else {
adc_wr_hiu(HHI_ADC_PLL_CNTL3, 0xca2a2110);
adc_wr_hiu(HHI_ADC_PLL_CNTL4, 0x2933800);
adc_wr_hiu(HHI_ADC_PLL_CNTL, 0xe0644220);
adc_wr_hiu(HHI_ADC_PLL_CNTL2, 0x34e0bf84);
adc_wr_hiu(HHI_ADC_PLL_CNTL3, 0x4a2a2110);
/** DADC CNTL for LIF signal input **/
adc_wr_hiu(HHI_DADC_CNTL, 0x1411036);
adc_wr_hiu(HHI_DADC_CNTL2, 0x0);
adc_wr_hiu(HHI_DADC_CNTL3, 0x430036);
adc_wr_hiu(HHI_DADC_CNTL4, 0x80600240);
/* TVFE reset */
adc_wr_hiu_bits(RESET1_REGISTER, 1, 7, 1);
}
usleep_range(100, 101);
adc_pll_lock_cnt++;
} while (!adc_rd_hiu_bits(HHI_ADC_PLL_CNTL, 31, 1) &&
(adc_pll_lock_cnt < 10));
}
devp->pll_flg |= ADC_ATV_DEMOD;
mutex_unlock(&devp->pll_mutex);
if (adc_pll_lock_cnt == 10)
pr_info("%s: ATV_DEMOD adc pll lock fail!!!\n",
__func__);
break;
case ADC_TVAFE:
if (devp->pll_flg & (ADC_ATV_DEMOD | ADC_DTV_DEMOD)) {
ret = -2;
if (devp->print_en)
pr_info("%s:AFE fail!!!:%d\n", __func__, devp->pll_flg);
break;
}
mutex_lock(&devp->pll_mutex);
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TL1)) {
do {
adc_wr_hiu(pll_addr->adc_pll_cntl_0, 0x01200490);
adc_wr_hiu(pll_addr->adc_pll_cntl_0, 0x31200490);
adc_wr_hiu(pll_addr->adc_pll_cntl_1, 0x06c00000);
if (devp->plat_data->chip_id >= ADC_CHIP_T5)
adc_wr_hiu(pll_addr->adc_pll_cntl_2,
0xe1800000);
else
adc_wr_hiu(pll_addr->adc_pll_cntl_2,
0xe0800000);
if (devp->plat_data->chip_id >= ADC_CHIP_T5D) {
adc_wr_hiu(adc_addr->s2_dadc_cntl_2, 0x00000582);
adc_wr_hiu(adc_addr->dadc_cntl_4, 0x0);
}
adc_wr_hiu(pll_addr->adc_pll_cntl_3, 0x48681c00);
adc_wr_hiu(pll_addr->adc_pll_cntl_4, 0x88770290);
adc_wr_hiu(pll_addr->adc_pll_cntl_5, 0x39272000);
adc_wr_hiu(pll_addr->adc_pll_cntl_6, 0x56540000);
if (get_cpu_type() >= MESON_CPU_MAJOR_ID_T5)
adc_wr_hiu_bits(adc_addr->vdac_cntl_0,
1, 11, 1);
adc_wr_hiu(pll_addr->adc_pll_cntl_0, 0x11010490);
usleep_range(100, 101);
adc_pll_lock_cnt++;
if (devp->plat_data->chip_id == ADC_CHIP_T3)
adc_pll_sts = adc_rd_hiu_bits(pll_addr->adc_pll_cntl_7, 31, 1);
else
adc_pll_sts = adc_rd_hiu_bits(pll_addr->adc_pll_cntl_0, 31, 1);
} while (!adc_pll_sts && (adc_pll_lock_cnt < 10));
adc_wr_hiu(adc_addr->dadc_cntl, 0x00303044);
if (devp->plat_data->chip_id >= ADC_CHIP_T3)
adc_wr_hiu(adc_addr->dadc_cntl_2, 0x00003408);
else
adc_wr_hiu(adc_addr->dadc_cntl_2, 0x00003400);
adc_wr_hiu(adc_addr->dadc_cntl_3, 0x08300b83);
} else {
do {
if (is_meson_txl_cpu() ||
is_meson_txlx_cpu()) {
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
adc_wr_hiu(HHI_ADC_PLL_CNTL3, 0x4a6a2110);
adc_wr_hiu(HHI_ADC_PLL_CNTL, 0x30f14250);
adc_wr_hiu(HHI_ADC_PLL_CNTL1, 0x22000442);
/* 0x5ba00380 from pll;0x5ba00384 clk */
/* from crystal */
adc_wr_hiu(HHI_ADC_PLL_CNTL2, 0x5ba00384);
adc_wr_hiu(HHI_ADC_PLL_CNTL3, 0x4a6a2110);
adc_wr_hiu(HHI_ADC_PLL_CNTL4, 0x02913004);
adc_wr_hiu(HHI_ADC_PLL_CNTL5, 0x00034a00);
adc_wr_hiu(HHI_ADC_PLL_CNTL6, 0x00005000);
adc_wr_hiu(HHI_ADC_PLL_CNTL3, 0xca6a2110);
adc_wr_hiu(HHI_ADC_PLL_CNTL3, 0x4a6a2110);
adc_wr_hiu(HHI_CADC_CNTL, 0x02000A08);
adc_wr_hiu(HHI_CADC_CNTL2, 0x04007B05);
#endif
} else {
adc_wr_hiu(HHI_ADC_PLL_CNTL3, 0xca2a2110);
adc_wr_hiu(HHI_ADC_PLL_CNTL4, 0x2933800);
adc_wr_hiu(HHI_ADC_PLL_CNTL, 0xe0644220);
adc_wr_hiu(HHI_ADC_PLL_CNTL2, 0x34e0bf84);
adc_wr_hiu(HHI_ADC_PLL_CNTL3, 0x4a2a2110);
/* TVFE reset */
adc_wr_hiu_bits(RESET1_REGISTER,
1, 7, 1);
}
usleep_range(100, 101);
adc_pll_lock_cnt++;
} while (!adc_rd_hiu_bits(HHI_ADC_PLL_CNTL, 31, 1) &&
(adc_pll_lock_cnt < 10));
}
devp->pll_flg |= ADC_TVAFE;
mutex_unlock(&devp->pll_mutex);
if (adc_pll_lock_cnt == 10)
pr_info("%s: TVAFE adc pll lock fail!!!\n",
__func__);
break;
case ADC_DTV_DEMOD:
if (devp->pll_flg & (ADC_ATV_DEMOD | ADC_TVAFE)) {
ret = -3;
if (devp->print_en)
pr_info("%s:DDEMOD fail!:%d\n",
__func__, devp->pll_flg);
break;
}
mutex_lock(&devp->pll_mutex);
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TL1)) {
do {
switch (devp->plat_data->chip_id) {
case ADC_CHIP_T5D:
case ADC_CHIP_S4:
case ADC_CHIP_T3:
case ADC_CHIP_S4D:
case ADC_CHIP_T5W:
adc_set_dtvdemod_pll_by_delsys(devp, p_dtv_para);
break;
default:
adc_set_dtvdemod_pll_by_clk(devp, p_dtv_para);
break;
}
usleep_range(100, 101);
adc_pll_lock_cnt++;
if (devp->plat_data->chip_id == ADC_CHIP_T3) {
adc_pll_sts = adc_rd_hiu_bits(pll_addr->adc_pll_cntl_7, 31, 1);
} else {
if (devp->plat_data->chip_id == ADC_CHIP_S4 ||
devp->plat_data->chip_id == ADC_CHIP_S4D)
reg_offset = 0x10;
else
reg_offset = 0;
adc_pll_sts = adc_rd_hiu_bits(pll_addr->adc_pll_cntl_0 + reg_offset, 31, 1);
}
} while (!adc_pll_sts && (adc_pll_lock_cnt < 10));
if (devp->plat_data->chip_id < ADC_CHIP_T3)
adc_wr_hiu(0xf3, 0x00800000);
} else if (is_meson_txl_cpu() || is_meson_txlx_cpu()) {
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
do {
adc_wr_hiu(HHI_ADC_PLL_CNTL3, 0x4a6a2110);
adc_wr_hiu(HHI_ADC_PLL_CNTL, 0x5d414260);
adc_wr_hiu(HHI_ADC_PLL_CNTL1, 0x22000442);
if (is_meson_txl_cpu())
adc_wr_hiu(HHI_ADC_PLL_CNTL2, 0x5ba00384);
else
adc_wr_hiu(HHI_ADC_PLL_CNTL2, 0x5ba00385);
adc_wr_hiu(HHI_ADC_PLL_CNTL3, 0x4a6a2110);
adc_wr_hiu(HHI_ADC_PLL_CNTL4, 0x02913004);
adc_wr_hiu(HHI_ADC_PLL_CNTL5, 0x00034a00);
adc_wr_hiu(HHI_ADC_PLL_CNTL6, 0x00005000);
/* reset */
adc_wr_hiu(HHI_ADC_PLL_CNTL3, 0xca6a2110);
adc_wr_hiu(HHI_ADC_PLL_CNTL3, 0x4a6a2110);
usleep_range(100, 101);
adc_pll_lock_cnt++;
} while (!adc_rd_hiu_bits(HHI_ADC_PLL_CNTL, 31, 1) &&
(adc_pll_lock_cnt < 10));
#endif
} else if (is_meson_gxlx_cpu()) {
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
adc_wr_hiu(HHI_ADC_PLL_CNTL1, 0x22000442);
adc_wr_hiu(HHI_ADC_PLL_CNTL5, 0x00034a00);
adc_wr_hiu(HHI_ADC_PLL_CNTL6, 0x00005000);
adc_pll_lock_cnt = 1;
#endif
}
devp->pll_flg |= ADC_DTV_DEMOD;
mutex_unlock(&devp->pll_mutex);
if (adc_pll_lock_cnt >= 10)
pr_info("%s: DTV_DEMOD adc pll lock fail!!!\n",
__func__);
break;
case ADC_DTV_DEMODPLL:
if (devp->pll_flg & (ADC_ATV_DEMOD | ADC_TVAFE)) {
ret = -4;
if (devp->print_en)
pr_info("%s:DMODPLL fail!!!:%d\n", __func__,
devp->pll_flg);
break;
}
if (!p_dtv_para) {
ret = -5;
if (devp->print_en)
pr_info("%s: DTV para is NULL\n", __func__);
break;
}
mutex_lock(&devp->pll_mutex);
if (is_meson_txl_cpu() || is_meson_txlx_cpu()) {
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
do {
/* reset */
adc_wr_hiu(HHI_ADC_PLL_CNTL3, 0xca6a2110);
adc_wr_hiu(HHI_ADC_PLL_CNTL, p_dtv_para->adcpllctl);
if (p_dtv_para->atsc) {
adc_wr_hiu(HHI_DEMOD_CLK_CNTL, 0x507);
} else {
/* bugzilla 139044 */
if (is_meson_txl_cpu())
adc_wr_hiu(HHI_DEMOD_CLK_CNTL,
0x301);
else
adc_wr_hiu(HHI_DEMOD_CLK_CNTL,
0x502);
}
adc_wr_hiu(HHI_ADC_PLL_CNTL3, 0x4a6a2110);
usleep_range(100, 101);
adc_pll_lock_cnt++;
} while (!adc_rd_hiu_bits(HHI_ADC_PLL_CNTL, 31, 1) &&
(adc_pll_lock_cnt < 10));
#endif
} else if (is_meson_gxlx_cpu()) {
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
adc_wr_hiu(HHI_DEMOD_CLK_CNTL, 0x1000502);
//adc_pll_lock_cnt = 1;
#endif
} else {
/*is_meson_gxtvbb_cpu()*/
adc_wr_hiu(HHI_ADC_PLL_CNTL3, 0x8a2a2110);/*reset*/
adc_wr_hiu(HHI_ADC_PLL_CNTL, p_dtv_para->adcpllctl);
adc_wr_hiu(HHI_DEMOD_CLK_CNTL, p_dtv_para->demodctl);
adc_wr_hiu(HHI_ADC_PLL_CNTL3, 0x0a2a2110);
//adc_pll_lock_cnt = 1;
}
devp->pll_flg |= ADC_DTV_DEMOD;
mutex_unlock(&devp->pll_mutex);
//if (adc_pll_lock_cnt == 10 && devp->print_en)
//pr_info("%s: adc pll lock fail!!!\n", __func__);
break;
default:
if (devp->print_en)
pr_err("%s:module: 0x%x wrong module index !! ",
__func__, module_sel);
break;
}
return ret;
}
EXPORT_SYMBOL(adc_set_pll_cntl);
void adc_pll_down(void)
{
if (!probe_finish || !adc_devp)
return;
struct adc_pll_reg_addr *pll_addr = &adc_devp->plat_data->pll_addr;
struct adc_reg_addr *adc_addr = &adc_devp->plat_data->adc_addr;
pr_info("adc: %s\n", __func__);
if (!adc_devp->pll_flg && is_meson_tl1_cpu() &&
adc_rd_hiu_bits(pll_addr->adc_pll_cntl_0, 28, 1)) {
adc_wr_hiu_bits(pll_addr->adc_pll_cntl_0, 0, 28, 1);
}
if (!adc_devp->pll_flg && get_cpu_type() >= MESON_CPU_MAJOR_ID_T5) {
adc_wr_hiu_bits(adc_addr->vdac_cntl_1, 0, 7, 1);
adc_wr_hiu_bits(adc_addr->dadc_cntl_3, 0, 0, 2);
adc_wr_hiu_bits(pll_addr->adc_pll_cntl_0, 0, 28, 1);
}
}
EXPORT_SYMBOL(adc_pll_down);
int adc_get_pll_flag(void)
{
unsigned int ret = 0;
if (!probe_finish || !adc_devp)
return -1;
if (!mutex_trylock(&adc_devp->pll_mutex))
return 0;
ret = adc_devp->pll_flg;
mutex_unlock(&adc_devp->pll_mutex);
return ret;
}
EXPORT_SYMBOL(adc_get_pll_flag);
void adc_set_pll_reset(void)
{
if (!probe_finish || !adc_devp)
return;
adc_devp->pll_flg = 0;
}
EXPORT_SYMBOL(adc_set_pll_reset);
static void adc_parse_para(char *buf_orig, char **parm)
{
char *ps, *token;
char delim1[3] = " ";
char delim2[2] = "\n";
unsigned int n = 0;
ps = buf_orig;
strcat(delim1, delim2);
while (1) {
token = strsep(&ps, delim1);
if (!token)
break;
if (*token == '\0')
continue;
parm[n++] = token;
}
}
static void adc_dump_regs(void)
{
struct adc_reg_addr *adc_addr = NULL;
struct adc_pll_reg_addr *pll_addr = NULL;
int chip_id = 0;
unsigned int reg_offset = 0;
if (IS_ERR_OR_NULL(adc_devp) || IS_ERR_OR_NULL(adc_devp->plat_data)) {
pr_info("adc_devp is NULL, it's not initialized yet\n");
return;
}
adc_addr = &adc_devp->plat_data->adc_addr;
pll_addr = &adc_devp->plat_data->pll_addr;
chip_id = adc_devp->plat_data->chip_id;
pr_info("chip_id=0x%x, pll_flag=0x%x\n",
chip_id, adc_devp->pll_flg);
if (chip_id == ADC_CHIP_S4 || chip_id == ADC_CHIP_S4D) {
reg_offset = 0x10;
} else {
reg_offset = 0;
pr_info("AFE_VAFE_CTRL0:0x%x\n", adc_rd_afe(AFE_VAFE_CTRL0));
pr_info("AFE_VAFE_CTRL1:0x%x\n", adc_rd_afe(AFE_VAFE_CTRL1));
pr_info("AFE_VAFE_CTRL2:0x%x\n", adc_rd_afe(AFE_VAFE_CTRL2));
}
pr_info("HHI_DADC_CNTL(0x%x):0x%x\n", adc_addr->dadc_cntl,
adc_rd_hiu(adc_addr->dadc_cntl));
pr_info("HHI_DADC_CNTL2(0x%x):0x%x\n", adc_addr->dadc_cntl_2,
adc_rd_hiu(adc_addr->dadc_cntl_2));
pr_info("HHI_DADC_CNTL3(0x%x):0x%x\n", adc_addr->dadc_cntl_3,
adc_rd_hiu(adc_addr->dadc_cntl_3));
pr_info("HHI_DADC_CNTL4(0x%x):0x%x\n", adc_addr->dadc_cntl_4,
adc_rd_hiu(adc_addr->dadc_cntl_4));
pr_info("HHI_S2_DADC_CNTL(0x%x):0x%x\n", adc_addr->s2_dadc_cntl,
adc_rd_hiu(adc_addr->s2_dadc_cntl));
pr_info("HHI_S2_DADC_CNTL2(0x%x):0x%x\n", adc_addr->s2_dadc_cntl_2,
adc_rd_hiu(adc_addr->s2_dadc_cntl_2));
pr_info("HHI_ADC_PLL_CNTL0(0x%x):0x%x\n",
pll_addr->adc_pll_cntl_0 + reg_offset,
adc_rd_hiu(pll_addr->adc_pll_cntl_0 + reg_offset));
pr_info("HHI_ADC_PLL_CNTL1(0x%x):0x%x\n",
pll_addr->adc_pll_cntl_1 + reg_offset,
adc_rd_hiu(pll_addr->adc_pll_cntl_1 + reg_offset));
pr_info("HHI_ADC_PLL_CNTL2(0x%x):0x%x\n",
pll_addr->adc_pll_cntl_2 + reg_offset,
adc_rd_hiu(pll_addr->adc_pll_cntl_2 + reg_offset));
pr_info("HHI_ADC_PLL_CNTL3(0x%x):0x%x\n",
pll_addr->adc_pll_cntl_3 + reg_offset,
adc_rd_hiu(pll_addr->adc_pll_cntl_3 + reg_offset));
pr_info("HHI_ADC_PLL_CNTL4(0x%x):0x%x\n",
pll_addr->adc_pll_cntl_4 + reg_offset,
adc_rd_hiu(pll_addr->adc_pll_cntl_4 + reg_offset));
pr_info("HHI_ADC_PLL_CNTL5(0x%x):0x%x\n",
pll_addr->adc_pll_cntl_5 + reg_offset,
adc_rd_hiu(pll_addr->adc_pll_cntl_5 + reg_offset));
pr_info("HHI_ADC_PLL_CNTL6(0x%x):0x%x\n",
pll_addr->adc_pll_cntl_6 + reg_offset,
adc_rd_hiu(pll_addr->adc_pll_cntl_6 + reg_offset));
pr_info("HHI_ADC_PLL_CNTL7(0x%x):0x%x\n",
pll_addr->adc_pll_cntl_7 + reg_offset,
adc_rd_hiu(pll_addr->adc_pll_cntl_7 + reg_offset));
pr_info("HHI_VDAC_CNTL0(0x%x):0x%x\n", adc_addr->vdac_cntl_0,
adc_rd_hiu(adc_addr->vdac_cntl_0));
pr_info("HHI_VDAC_CNTL1_T5(0x%x):0x%x\n", HHI_VDAC_CNTL1_T5,
adc_rd_hiu(HHI_VDAC_CNTL1_T5));
}
static ssize_t adc_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
char *buf_orig, *parm[47] = {NULL};
unsigned int val;
struct tvin_adc_dev *devp = adc_devp;
if (!probe_finish || !devp)
return -1;
buf_orig = kstrdup(buf, GFP_KERNEL);
adc_parse_para(buf_orig, (char **)&parm);
if (parm[0] && !strcmp(parm[0], "state")) {
pr_info("adc state\n");
} else if (parm[0] && !strcmp(parm[0], "down")) {
adc_pll_down();
} else if (parm[0] && !strcmp(parm[0], "dump_reg")) {
adc_dump_regs();
} else if (parm[0] && !strcmp(parm[0], "debug")) {
if (!parm[1])
goto tvin_adc_store_err;
if (kstrtouint(parm[1], 10, &val) >= 0)
devp->print_en = val;
}
tvin_adc_store_err:
kfree(buf_orig);
return count;
}
static ssize_t adc_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
if (!probe_finish || !adc_devp)
return -1;
pr_info("debug : %d\n", adc_devp->print_en);
pr_info("version : %s\n", TVDIN_ADC_VER);
return 0;
}
static char *adc_class_devnode(struct device *dev, umode_t *mode)
{
if (mode)
*mode = 0666;
return NULL;
}
static DEVICE_ATTR_RW(adc);
static struct class adc_class = {
.name = ADC_DEV_NAME,
.devnode = adc_class_devnode,
};
static int adc_open(struct inode *inode, struct file *file)
{
return 0;
}
static ssize_t adc_read(struct file *f, char __user *buf,
size_t size, loff_t *p)
{
return 0;
}
static ssize_t adc_write(struct file *f, const char __user *buf,
size_t size, loff_t *p)
{
return 0;
}
static int adc_release(struct inode *inode, struct file *file)
{
return 0;
}
static long adc_ioctl(struct file *f,
unsigned int cmd, unsigned long arg)
{
/*void __user *argp = (void __user *)arg;*/
if (!probe_finish || !adc_devp)
return -1;
mutex_lock(&adc_devp->ioctl_mutex);
switch (cmd) {
default:
break;
}
mutex_unlock(&adc_devp->ioctl_mutex);
return 0;
}
#ifdef CONFIG_COMPAT
static long adc_compat_ioctl(struct file *f,
unsigned int cmd, unsigned long arg)
{
arg = (unsigned long)compat_ptr(arg);
return adc_ioctl(f, cmd, arg);
}
#endif
static const struct file_operations adc_fops = {
.owner = THIS_MODULE,
.open = adc_open,
.read = adc_read,
.write = adc_write,
.release = adc_release,
.unlocked_ioctl = adc_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = adc_compat_ioctl,
#endif
};
static int adc_remove(struct platform_device *pdev)
{
if (probe_finish && adc_devp) {
device_destroy(&adc_class, MKDEV(adc_devp->dev_no, 0));
unregister_chrdev(adc_devp->dev_no, ADC_DEV_NAME);
class_unregister(&adc_class);
mutex_destroy(&adc_devp->pll_mutex);
mutex_destroy(&adc_devp->ioctl_mutex);
mutex_destroy(&adc_devp->filter_mutex);
kfree(adc_devp);
}
return 0;
}
static void adc_shutdown(struct platform_device *pdev)
{
adc_pll_down();
pr_info("adc: %s\n", __func__);
}
#ifdef CONFIG_PM
static int adc_suspend(struct platform_device *pdev, pm_message_t state)
{
adc_pll_down();
pr_info("adc: %s\n", __func__);
return 0;
}
static int adc_resume(struct platform_device *pdev)
{
return 0;
}
#endif
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
static const struct adc_platform_data_s adc_data_txl = {
.chip_id = ADC_CHIP_TXL,
};
static const struct adc_platform_data_s adc_data_txlx = {
.chip_id = ADC_CHIP_TXLX,
};
static const struct adc_platform_data_s adc_data_gxlx = {
.chip_id = ADC_CHIP_GXLX,
};
static const struct adc_platform_data_s adc_data_tl1 = {
ADC_ADDR_TL1_TO_S4,
ADC_PLL_ADDR_TL1,
.chip_id = ADC_CHIP_TL1,
};
#endif
static const struct adc_platform_data_s adc_data_tm2 = {
ADC_ADDR_TL1_TO_S4,
ADC_PLL_ADDR_TL1,
.chip_id = ADC_CHIP_TM2,
};
static const struct adc_platform_data_s adc_data_t5 = {
ADC_ADDR_TL1_TO_S4,
ADC_PLL_ADDR_TL1,
.chip_id = ADC_CHIP_T5,
};
static const struct adc_platform_data_s adc_data_t5d = {
ADC_ADDR_TL1_TO_S4,
ADC_PLL_ADDR_TL1,
.chip_id = ADC_CHIP_T5D,
};
static const struct adc_platform_data_s adc_data_s4 = {
ADC_ADDR_TL1_TO_S4,
ADC_PLL_ADDR_TL1,
.chip_id = ADC_CHIP_S4,
};
static const struct adc_platform_data_s adc_data_t3 = {
ADC_ADDR_T3,
ADC_PLL_ADDR_T3,
.chip_id = ADC_CHIP_T3,
};
static const struct adc_platform_data_s adc_data_s4d = {
ADC_ADDR_TL1_TO_S4,
ADC_PLL_ADDR_TL1,
.chip_id = ADC_CHIP_S4D,
};
static const struct adc_platform_data_s adc_data_t5w = {
ADC_ADDR_TL1_TO_S4,
ADC_PLL_ADDR_TL1,
.chip_id = ADC_CHIP_T5W,
};
static const struct of_device_id adc_dt_match[] = {
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
{
.compatible = "amlogic, adc-txl",
.data = &adc_data_txl,
},
{
.compatible = "amlogic, adc-txlx",
.data = &adc_data_txlx,
},
{
.compatible = "amlogic, adc-gxlx",
.data = &adc_data_gxlx,
},
{
.compatible = "amlogic, adc-tl1",
.data = &adc_data_tl1,
},
#endif
{
.compatible = "amlogic, adc-tm2",
.data = &adc_data_tm2,
},
{
.compatible = "amlogic, adc-t5",
.data = &adc_data_t5,
},
{
.compatible = "amlogic, adc-t5d",
.data = &adc_data_t5d,
},
{
.compatible = "amlogic, adc-s4",
.data = &adc_data_s4,
},
{
.compatible = "amlogic, adc-t3",
.data = &adc_data_t3,
},
{
.compatible = "amlogic, adc-s4d",
.data = &adc_data_s4d,
},
{
.compatible = "amlogic, adc-t5w",
.data = &adc_data_t5w,
},
{}
};
static int adc_probe(struct platform_device *pdev)
{
struct device *cdev;
int ret = 0;
struct tvin_adc_dev *devp;
const struct of_device_id *of_id;
int r;
int size = 0;
struct resource *res = 0;
unsigned int i;
devp = devm_kzalloc(&pdev->dev, sizeof(struct tvin_adc_dev),
GFP_KERNEL);
if (IS_ERR_OR_NULL(devp)) {
ret = -ENOMEM;
goto tag_devm_kzalloc_err;
}
adc_devp = devp;
/*devp->pdev = pdev;*/
devp->dev = &pdev->dev;
devp->node = pdev->dev.of_node;
/* cdev registe */
r = class_register(&adc_class);
if (r) {
ret = -EINVAL;
goto tag_class_reg_err;
}
pdev->dev.class = &adc_class;
r = register_chrdev(0, ADC_DEV_NAME, &adc_fops);
if (r < 0) {
ret = -ENODEV;
goto tag_chrdev_reg_err;
}
devp->dev_no = r;
cdev = device_create(&adc_class, &pdev->dev,
MKDEV(devp->dev_no, 0),
NULL, ADC_DEV_NAME);
if (IS_ERR_OR_NULL(cdev)) {
ret = -ENXIO;
goto tag_device_create_err;
}
/*create sysfs attribute files*/
ret = device_create_file(cdev, &dev_attr_adc);
if (ret < 0) {
pr_info("%s: create attribute files fail.\n", __func__);
goto tag_create_dbg_err;
}
/*devp->cdev = cdev;*/
/* get compatible matched device, to get chip related data */
of_id = of_match_device(adc_dt_match, &pdev->dev);
if (of_id) {
devp->of_id = of_id;
devp->plat_data = (struct adc_platform_data_s *)of_id->data;
}
for (i = 0; i < MAP_ADDR_NUM; i++) {
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
if (!res) {
pr_err("%s: res %d is faile\n", __func__, i);
ret = -ENOMEM;
goto fail_get_resource_mem;
}
size = resource_size(res);
devp->phy_addr[i].size = size;
devp->phy_addr[i].phy_addr = res->start;
devp->vir_addr[i] = devm_ioremap_nocache(&pdev->dev, res->start, size);
}
mutex_init(&devp->ioctl_mutex);
mutex_init(&devp->pll_mutex);
mutex_init(&devp->filter_mutex);
probe_finish = true;
pr_info("%s ver:%s\n", __func__, TVDIN_ADC_VER);
return 0;
fail_get_resource_mem:
tag_create_dbg_err:
device_destroy(&adc_class, MKDEV(devp->dev_no, 0));
tag_device_create_err:
unregister_chrdev(devp->dev_no, ADC_DEV_NAME);
tag_chrdev_reg_err:
probe_finish = false;
class_unregister(&adc_class);
tag_class_reg_err:
devm_kfree(&pdev->dev, devp);
adc_devp = NULL;
tag_devm_kzalloc_err:
return ret;
}
static struct platform_driver adc_driver = {
.driver = {
.name = "tvinadc",
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = adc_dt_match,
#endif
},
.probe = adc_probe,
.remove = adc_remove,
.shutdown = adc_shutdown,
#ifdef CONFIG_PM
.suspend = adc_suspend,
.resume = adc_resume,
#endif
};
int __init adc_init(void)
{
int ret;
ret = platform_driver_register(&adc_driver);
return ret;
}
void __exit adc_uninit(void)
{
platform_driver_unregister(&adc_driver);
}
//MODULE_VERSION(TVDIN_ADC_VER);
//MODULE_AUTHOR("yong.qin@amlogic.com");
//MODULE_DESCRIPTION("AMLOGIC tvdin adc driver");
//MODULE_LICENSE("GPL");