mirror of
https://gitee.com/Vancouver2017/luban-lite-t3e-pro.git
synced 2025-12-14 18:38:55 +00:00
393 lines
9.8 KiB
C
393 lines
9.8 KiB
C
/*
|
|
* Copyright (c) 2022-2024, ArtInChip Technology Co., Ltd
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Authors: matteo <duanmt@artinchip.com>
|
|
*/
|
|
|
|
#include "aic_core.h"
|
|
#include "aic_hal_clk.h"
|
|
|
|
#include "hal_adcim.h"
|
|
#ifdef AIC_SYSCFG_DRV
|
|
#include "hal_syscfg.h"
|
|
#endif
|
|
|
|
/* Register of ADCIM */
|
|
#define ADCIM_MCSR 0x000
|
|
#define ADCIM_CALCSR 0x004
|
|
#define ADCIM_FIFOSTS 0x008
|
|
#define ADCIM_VERSION 0xFFC
|
|
|
|
#define ADCIM_MCSR_BUSY BIT(16)
|
|
#define ADCIM_MCSR_SEMFLAG_SHIFT 8
|
|
#define ADCIM_MCSR_SEMFLAG_MASK GENMASK(15, 8)
|
|
#define ADCIM_MCSR_CHN_MASK GENMASK(3, 0)
|
|
#define ADCIM_CALCSR_CALVAL_UPD BIT(31)
|
|
#define ADCIM_CALCSR_CALVAL_SHIFT 16
|
|
#define ADCIM_CALCSR_CALVAL_MASK GENMASK(27, 16)
|
|
#define ADCIM_CALCSR_ADC_ACQ_SHIFT 8
|
|
#define ADCIM_CALCSR_ADC_ACQ_MASK GENMASK(15, 8)
|
|
#define ADCIM_CALCSR_DCAL_MASK BIT(1)
|
|
#define ADCIM_CALCSR_CAL_ENABLE BIT(0)
|
|
#define ADCIM_FIFOSTS_ADC_ARBITER_IDLE BIT(6)
|
|
#define ADCIM_FIFOSTS_FIFO_ERR BIT(5)
|
|
#define ADCIM_FIFOSTS_CTR_MASK GENMASK(4, 0)
|
|
#define ADCIM_CAL_ADC_STANDARD_VAL 0x800
|
|
#define AIC_ADC_MAX_VAL 0xFFF
|
|
#define AIC_VOLTAGE_ACCURACY 10000
|
|
#define ADCIM_CALCSR_NUM 6
|
|
|
|
#ifdef AIC_CHIP_D12X
|
|
#define ADCIM_CAL_ADC_OFFSET_MISMATCH 0x8
|
|
#elif defined(AIC_CHIP_D13X)
|
|
#define ADCIM_CAL_ADC_OFFSET_MISMATCH 0x28
|
|
#elif defined(AIC_CHIP_D21X)
|
|
#define ADCIM_CAL_ADC_OFFSET_MISMATCH 0x32
|
|
#else
|
|
#define ADCIM_CAL_ADC_OFFSET_MISMATCH 0x0
|
|
#endif
|
|
|
|
#ifdef AIC_ADCIM_DM_DRV
|
|
#define ADCDM_RTP_CFG 0x03F0
|
|
#define ADCDM_RTP_STS 0x03F4
|
|
#define ADCDM_SRAM_CTL 0x03F8
|
|
#define ADCDM_SRAM_BASE 0x0400
|
|
|
|
#define ADCDM_RTP_CAL_VAL_SHIFT 16
|
|
#define ADCDM_RTP_CAL_VAL_MASK GENMASK(27, 16)
|
|
#define ADCDM_RTP_PDET BIT(0)
|
|
|
|
#define ADCDM_RTP_DRV_SHIFT 4
|
|
#define ADCDM_RTP_DRV_MASK GENMASK(7, 4)
|
|
#define ADCDM_RTP_VPSEL_SHIFT 2
|
|
#define ADCDM_RTP_VPSEL_MASK GENMASK(3, 2)
|
|
#define ADCDM_RTP_VNSEL_MASK GENMASK(1, 0)
|
|
|
|
#define ADCDM_SRAM_CLR_SHIFT 16
|
|
#define ADCDM_SRAM_CLR(n) (1 << ((n) + ADCDM_SRAM_CLR_SHIFT))
|
|
#define ADCDM_SRAM_MODE_SHIFT 8
|
|
#define ADCDM_SRAM_MODE BIT(8)
|
|
#define ADCDM_SRAM_SEL_MASK GENMASK(3, 0)
|
|
#define ADCDM_SRAM_SEL(n) (n)
|
|
|
|
#define ADCDM_SRAM_SIZE (512 * 4)
|
|
#define ADCDM_CHAN_NUM 16
|
|
|
|
enum adcdm_sram_mode {
|
|
ADCDM_NORMAL_MODE = 0,
|
|
ADCDM_DEBUG_MODE = 1
|
|
};
|
|
#endif
|
|
|
|
struct adcim_dev {
|
|
#ifdef AIC_ADCIM_DM_DRV
|
|
u32 dm_cur_chan;
|
|
#endif
|
|
int usr_cnt;
|
|
};
|
|
|
|
#ifdef AIC_ADCIM_DM_DRV
|
|
static struct adcim_dev g_adcim_dev = {0};
|
|
#endif
|
|
|
|
static inline void adcim_writel(u32 val, int reg)
|
|
{
|
|
writel(val, ADCIM_BASE + reg);
|
|
}
|
|
|
|
static inline u32 adcim_readl(int reg)
|
|
{
|
|
return readl(ADCIM_BASE + reg);
|
|
}
|
|
|
|
int hal_adcim_calibration_set(unsigned int val)
|
|
{
|
|
int cal;
|
|
|
|
if (val > 4095) {
|
|
pr_err("The calibration value %d is too big\n", val);
|
|
return -EINVAL;
|
|
}
|
|
|
|
cal = adcim_readl(ADCIM_CALCSR);
|
|
cal = (cal & ~ADCIM_CALCSR_CALVAL_MASK)
|
|
| (val << ADCIM_CALCSR_CALVAL_SHIFT);
|
|
cal = cal | ADCIM_CALCSR_CALVAL_UPD;
|
|
adcim_writel(cal, ADCIM_CALCSR);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* The calibration value is taken six times and the average value is obtained
|
|
* after removing the maximum and minimum values, in order to ensure the
|
|
* stability of calibration
|
|
*/
|
|
u32 hal_adcim_auto_calibration(void)
|
|
{
|
|
u32 flag = 1;
|
|
u32 data = 0;
|
|
int max = 0;
|
|
int min = 0;
|
|
u32 cal_array[ADCIM_CALCSR_NUM];
|
|
|
|
for (int i = 0; i < ADCIM_CALCSR_NUM; i++) {
|
|
adcim_writel(0x08002f03, ADCIM_CALCSR);//auto cal
|
|
do {
|
|
flag = adcim_readl(ADCIM_CALCSR) & 0x00000001;
|
|
} while (flag);
|
|
|
|
cal_array[i] = (adcim_readl(ADCIM_CALCSR) >> 16) & 0xfff;
|
|
|
|
if (cal_array[i] > max)
|
|
max = cal_array[i];
|
|
|
|
if (i == 0) {
|
|
min = cal_array[0];
|
|
} else if (cal_array[i] < min) {
|
|
min = cal_array[i];
|
|
}
|
|
|
|
data += cal_array[i];
|
|
pr_debug("[%d]cal_data %d\n", i, cal_array[i]);
|
|
}
|
|
|
|
data = (data - min - max) / (ADCIM_CALCSR_NUM - 2);
|
|
|
|
pr_debug("max %d min %d, latest_data %d\n", max, min, data);
|
|
return data;
|
|
}
|
|
|
|
int hal_adcim_adc2voltage(u16 *val, u32 cal_data, int scale, float def_voltage)
|
|
{
|
|
int cal_voltage;
|
|
int st_voltage = 0;
|
|
int cal_val = 0;
|
|
|
|
#ifdef AIC_SYSCFG_DRV
|
|
st_voltage = syscfg_read_ldo_cfg();
|
|
#endif
|
|
if (!st_voltage) {
|
|
pr_err("Failed to get standard voltage\n");
|
|
st_voltage = (int)(def_voltage * AIC_VOLTAGE_ACCURACY);
|
|
}
|
|
|
|
cal_val = *val + ADCIM_CAL_ADC_STANDARD_VAL - cal_data + ADCIM_CAL_ADC_OFFSET_MISMATCH;
|
|
if (cal_val >= 0) {
|
|
*val = cal_val;
|
|
cal_voltage = *val * st_voltage / AIC_ADC_MAX_VAL;
|
|
} else {
|
|
pr_err("Out of the input voltage range - %d \n", cal_val);
|
|
*val = 0;
|
|
cal_voltage = 0;
|
|
}
|
|
|
|
return cal_voltage;
|
|
}
|
|
|
|
void adcim_status_show(void)
|
|
{
|
|
int mcsr;
|
|
int fifo;
|
|
int version;
|
|
#ifdef AIC_ADCIM_DM_DRV
|
|
int rtp_cfg, rtp_sts, sram_ctl;
|
|
#endif
|
|
|
|
mcsr = adcim_readl(ADCIM_MCSR);
|
|
fifo = adcim_readl(ADCIM_FIFOSTS);
|
|
version = adcim_readl(ADCIM_VERSION);
|
|
|
|
#ifdef AIC_ADCIM_DM_DRV
|
|
rtp_cfg = adcim_readl(ADCDM_RTP_CFG);
|
|
rtp_sts = adcim_readl(ADCDM_RTP_STS);
|
|
sram_ctl = adcim_readl(ADCDM_SRAM_CTL);
|
|
#endif
|
|
|
|
hal_log_info("In ADCIM V%d.%02d:\n"
|
|
"Busy state: %d\n"
|
|
"Semflag: %d\n"
|
|
"Current Channel: %d\n"
|
|
"ADC Arbiter Idel: %d\n"
|
|
"FIFO Error: %d\n"
|
|
"FIFO Counter: %d\n"
|
|
#ifdef AIC_ADCIM_DM_DRV
|
|
"\nIn DM:\nMode: %s, Current channel: %d/%ld\n"
|
|
"Calibration val: %ld\n"
|
|
"RTP PDET: %ld, DRV: %ld, VPSEL: %ld, VNSEL: %ld\n"
|
|
#endif
|
|
, version >> 8, version & 0xff,
|
|
(mcsr & ADCIM_MCSR_BUSY) ? 1 : 0,
|
|
(mcsr & ADCIM_MCSR_SEMFLAG_MASK)
|
|
>> ADCIM_MCSR_SEMFLAG_SHIFT,
|
|
mcsr & ADCIM_MCSR_CHN_MASK,
|
|
fifo & ADCIM_FIFOSTS_ADC_ARBITER_IDLE ? 1 : 0,
|
|
fifo & ADCIM_FIFOSTS_FIFO_ERR ? 1 : 0,
|
|
fifo & ADCIM_FIFOSTS_CTR_MASK
|
|
#ifdef AIC_ADCIM_DM_DRV
|
|
, sram_ctl & ADCDM_SRAM_MODE ? "Debug" : "Normal",
|
|
g_adcim_dev.dm_cur_chan, sram_ctl & ADCDM_SRAM_SEL_MASK,
|
|
(rtp_cfg & ADCDM_RTP_CAL_VAL_MASK)
|
|
>> ADCDM_RTP_CAL_VAL_SHIFT,
|
|
rtp_cfg & ADCDM_RTP_PDET,
|
|
(rtp_sts & ADCDM_RTP_DRV_MASK) >> ADCDM_RTP_DRV_SHIFT,
|
|
(rtp_sts & ADCDM_RTP_VPSEL_MASK)
|
|
>> ADCDM_RTP_VPSEL_SHIFT,
|
|
rtp_sts & ADCDM_RTP_VNSEL_MASK
|
|
#endif
|
|
);
|
|
}
|
|
|
|
void adcim_calibration_show(void)
|
|
{
|
|
int cal;
|
|
|
|
cal = adcim_readl(ADCIM_CALCSR);
|
|
|
|
pr_info("Calibration Enable: %d\n Current value: %d\nADC ACQ: %d\n",
|
|
(cal & ADCIM_CALCSR_CAL_ENABLE) ? 0 : 1,
|
|
(cal & ADCIM_CALCSR_CALVAL_MASK) >> ADCIM_CALCSR_CALVAL_SHIFT,
|
|
(cal & ADCIM_CALCSR_ADC_ACQ_MASK) >> ADCIM_CALCSR_ADC_ACQ_SHIFT);
|
|
}
|
|
|
|
#ifdef AIC_ADCIM_DM_DRV
|
|
void hal_dm_chan_show(void)
|
|
{
|
|
pr_info("Current chan: %d/%ld\n", g_adcim_dev.dm_cur_chan,
|
|
adcim_readl(ADCDM_SRAM_CTL) & ADCDM_SRAM_SEL_MASK);
|
|
}
|
|
|
|
s32 hal_dm_chan_store(u32 val)
|
|
{
|
|
int ret;
|
|
|
|
if (val >= ADCDM_CHAN_NUM) {
|
|
hal_log_err("Invalid channel number %u\n", val);
|
|
return 0;
|
|
}
|
|
|
|
g_adcim_dev.dm_cur_chan = val;
|
|
ret = adcim_readl(ADCDM_SRAM_CTL);
|
|
ret &= ~ADCDM_SRAM_SEL_MASK;
|
|
ret |= val;
|
|
adcim_writel(ret, ADCDM_SRAM_CTL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void hal_adcdm_rtp_down_store(u32 val)
|
|
{
|
|
int ret;
|
|
|
|
ret = adcim_readl(ADCDM_RTP_CFG);
|
|
if (val)
|
|
ret &= ~ADCDM_RTP_PDET;
|
|
else
|
|
ret |= ADCDM_RTP_PDET;
|
|
adcim_writel(ret, ADCDM_RTP_CFG);
|
|
}
|
|
|
|
static void adcdm_sram_clear(u32 chan)
|
|
{
|
|
u32 val = 0;
|
|
|
|
val = adcim_readl(ADCDM_SRAM_CTL);
|
|
val |= ADCDM_SRAM_CLR(chan);
|
|
adcim_writel(val, ADCDM_SRAM_CTL);
|
|
|
|
val &= ~ADCDM_SRAM_CLR(chan);
|
|
adcim_writel(val, ADCDM_SRAM_CTL);
|
|
}
|
|
|
|
static void adcdm_sram_mode(enum adcdm_sram_mode mode)
|
|
{
|
|
u32 val = 0;
|
|
|
|
val = adcim_readl(ADCDM_SRAM_CTL);
|
|
if (mode)
|
|
val |= mode << ADCDM_SRAM_MODE_SHIFT;
|
|
else
|
|
val &= ~ADCDM_SRAM_MODE;
|
|
adcim_writel(val, ADCDM_SRAM_CTL);
|
|
}
|
|
|
|
static void adcdm_sram_select(u32 chan)
|
|
{
|
|
u32 val = 0;
|
|
|
|
val = adcim_readl(ADCDM_SRAM_CTL);
|
|
val &= ~ADCDM_SRAM_SEL_MASK;
|
|
val |= chan;
|
|
adcim_writel(val, ADCDM_SRAM_CTL);
|
|
}
|
|
|
|
ssize_t hal_adcdm_sram_write(int *buf, u32 offset, size_t count)
|
|
{
|
|
int i;
|
|
|
|
if (count + offset > ADCDM_SRAM_SIZE)
|
|
return 0;
|
|
hal_adcim_probe();
|
|
adcdm_sram_mode(ADCDM_DEBUG_MODE);
|
|
adcdm_sram_select(g_adcim_dev.dm_cur_chan);
|
|
|
|
for (i = 0; i < count; i++) {
|
|
adcim_writel(buf[i], ADCDM_SRAM_BASE + i * 4);
|
|
}
|
|
|
|
adcdm_sram_mode(ADCDM_NORMAL_MODE);
|
|
for (i = 0; i < ADCDM_CHAN_NUM; i++)
|
|
adcdm_sram_clear(i);
|
|
|
|
return count;
|
|
}
|
|
|
|
#endif
|
|
|
|
void hal_adcim_set_dcalmask(void)
|
|
{
|
|
int val;
|
|
|
|
val = adcim_readl(ADCIM_CALCSR);
|
|
val = val | ADCIM_CALCSR_DCAL_MASK | ADCIM_CALCSR_ADC_ACQ_MASK;
|
|
adcim_writel(val, ADCIM_CALCSR);
|
|
}
|
|
|
|
s32 hal_adcim_probe(void)
|
|
{
|
|
s32 ret = 0;
|
|
static s32 inited = 0;
|
|
|
|
if (inited) {
|
|
hal_log_info("ADCIM is already inited\n");
|
|
return 0;
|
|
}
|
|
|
|
#ifdef AIC_ADCIM_DRV_V11
|
|
ret = hal_clk_set_freq(CLK_ADCIM, 48000000);
|
|
if (ret < 0) {
|
|
hal_log_err("Failed to set ADCIM clk\n");
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
ret = hal_clk_enable(CLK_ADCIM);
|
|
if (ret < 0) {
|
|
hal_log_err("ADCIM clk enable failed!\n");
|
|
return -1;
|
|
}
|
|
|
|
ret = hal_clk_enable_deassertrst(CLK_ADCIM);
|
|
if (ret < 0) {
|
|
hal_log_err("ADCIM reset deassert failed!\n");
|
|
return -1;
|
|
}
|
|
|
|
hal_adcim_set_dcalmask();
|
|
|
|
inited = 1;
|
|
return 0;
|
|
}
|