365 lines
9.1 KiB
C
365 lines
9.1 KiB
C
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
|
|
/*
|
|
* drivers/adc/saradc.c
|
|
*
|
|
* Copyright (C) 2020 Amlogic, Inc. All rights reserved.
|
|
*
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <common.h>
|
|
#include <asm/arch/io.h>
|
|
#include <asm/saradc.h>
|
|
#include <asm/cpu_id.h>
|
|
#include <asm/arch/secure_apb.h>
|
|
#ifdef CONFIG_OF_LIBFDT
|
|
#include <libfdt.h>
|
|
#endif
|
|
|
|
#define FDT_DEFAULT_ADDRESS 0x01000000
|
|
|
|
#define P_SAR_ADC_REG0(base) (base + (0x0))
|
|
#define P_SAR_ADC_CHAN_LIST(base) (base + (0x1))
|
|
#define P_SAR_ADC_AVG_CNTL(base) (base + (0x2))
|
|
#define P_SAR_ADC_REG3(base) (base + (0x3))
|
|
#define P_SAR_ADC_DELAY(base) (base + (0x4))
|
|
#define P_SAR_ADC_LAST_RD(base) (base + (0x5))
|
|
#define P_SAR_ADC_FIFO_RD(base) (base + (0x6))
|
|
#define P_SAR_ADC_AUX_SW(base) (base + (0x7))
|
|
#define P_SAR_ADC_CHAN_10_SW(base) (base + (0x8))
|
|
#define P_SAR_ADC_DETECT_IDLE_SW(base) (base + (0x9))
|
|
#define P_SAR_ADC_DELTA_10(base) (base + (0xa))
|
|
#define P_SAR_ADC_REG11(base) (base + (0xb))
|
|
#define P_SAR_ADC_REG13(base) (base + (0xd))
|
|
|
|
#define FLAG_BUSY_KERNEL (1 << 14) /* for kernel:SARADC_DELAY 14bit */
|
|
#define FLAG_BUSY_KERNEL_BIT 14
|
|
#define FLAG_BUSY_BL30 (1 << 15) /* for bl30:SARADC_DELAY 15bit*/
|
|
|
|
static const char * const ch7_vol[] = {
|
|
"gnd",
|
|
"vdd/4",
|
|
"vdd/2",
|
|
"vdd*3/4",
|
|
"vdd",
|
|
};
|
|
|
|
typedef struct {
|
|
unsigned char channel;
|
|
unsigned char adc_type; /*1:12bit; 0:10bit*/
|
|
unsigned short family_id;
|
|
u32 __iomem *clk_addr;
|
|
u32 __iomem *base_addr;
|
|
}saradc_info;
|
|
|
|
static saradc_info saradc_dev;
|
|
|
|
static __inline__ void aml_set_reg32_bits(volatile unsigned int *_reg,
|
|
const uint32_t _value,
|
|
const uint32_t _start,
|
|
const uint32_t _len)
|
|
{
|
|
writel(((readl((volatile unsigned int *)_reg) & \
|
|
~(((1L << (_len) )-1) << (_start))) | \
|
|
((unsigned)((_value) & ((1L<<(_len))-1)) << (_start))),
|
|
(volatile void *)_reg);
|
|
}
|
|
static __inline__ uint32_t aml_get_reg32_bits(volatile unsigned int *_reg,
|
|
const uint32_t _start,
|
|
const uint32_t _len)
|
|
{
|
|
return ((readl((volatile unsigned int *)_reg) >> (_start)) & \
|
|
((1L << (_len) ) - 1));
|
|
}
|
|
static __inline__ void aml_write_reg32(volatile unsigned int *_reg,
|
|
const uint32_t _value)
|
|
{
|
|
writel(_value, (volatile unsigned int *)_reg );
|
|
};
|
|
static __inline__ uint32_t aml_read_reg32(volatile unsigned int *_reg)
|
|
{
|
|
return readl((volatile unsigned int *)_reg);
|
|
};
|
|
|
|
saradc_info *saradc_dev_get(void)
|
|
{
|
|
return &saradc_dev;
|
|
}
|
|
|
|
/*
|
|
* description: used to enable and disable the clock of the SARADC
|
|
* onoff: 1: enable ; 0: disable
|
|
*/
|
|
void saradc_clock_switch( int onoff)
|
|
{
|
|
saradc_info *saradc = saradc_dev_get();
|
|
|
|
if (onoff) {
|
|
if (saradc->family_id >= MESON_CPU_MAJOR_ID_GXBB)
|
|
aml_set_reg32_bits(saradc->clk_addr, 1, 8, 1);
|
|
else
|
|
aml_set_reg32_bits(P_SAR_ADC_REG3(saradc->base_addr), 1, 30, 1);
|
|
} else {
|
|
if (saradc->family_id >= MESON_CPU_MAJOR_ID_GXBB)
|
|
aml_set_reg32_bits(saradc->clk_addr, 0, 8, 1);
|
|
else
|
|
aml_set_reg32_bits(P_SAR_ADC_REG3(saradc->base_addr), 0, 30, 1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* description: used to set the DIV of the clock
|
|
*/
|
|
void saradc_clock_set(unsigned char val)
|
|
{
|
|
saradc_info *saradc = saradc_dev_get();
|
|
|
|
if (saradc->family_id >= MESON_CPU_MAJOR_ID_GXBB) {
|
|
/*bit[0-7]: set clk div; bit[9-10]: select clk source*/
|
|
aml_set_reg32_bits(saradc->clk_addr, 0, 9, 2);
|
|
aml_set_reg32_bits(saradc->clk_addr, (val & 0xff), 0, 8);
|
|
} else {
|
|
/*bit10-bit15: set clk div*/
|
|
aml_set_reg32_bits(P_SAR_ADC_REG3(saradc->base_addr),
|
|
(val & 0x3f), 10, 6);
|
|
}
|
|
}
|
|
|
|
static inline void saradc_power_control(int on)
|
|
{
|
|
saradc_info *saradc = saradc_dev_get();
|
|
|
|
if (on) {
|
|
aml_set_reg32_bits(P_SAR_ADC_REG11(saradc->base_addr), 1, 13, 1);
|
|
if (saradc->family_id >= MESON_CPU_MAJOR_ID_G12A)
|
|
aml_set_reg32_bits(P_SAR_ADC_REG11(saradc->base_addr), 0, 5, 2);
|
|
else
|
|
aml_set_reg32_bits(P_SAR_ADC_REG11(saradc->base_addr), 3, 5, 2);
|
|
aml_set_reg32_bits(P_SAR_ADC_REG3(saradc->base_addr), 1, 21, 1);
|
|
|
|
udelay(5);
|
|
saradc_clock_switch(1);
|
|
} else {
|
|
saradc_clock_switch(0);
|
|
aml_set_reg32_bits(P_SAR_ADC_REG3(saradc->base_addr), 0, 21, 1);
|
|
/*aml_set_reg32_bits(PP_SAR_ADC_REG11(saradc->base_addr),0,13,1);*/
|
|
/*aml_set_reg32_bits(P_SAR_ADC_REG11(saradc->base_addr),0,5,2);*/
|
|
}
|
|
}
|
|
|
|
void saradc_hw_init(void)
|
|
{
|
|
saradc_info *saradc = saradc_dev_get();
|
|
|
|
if (saradc->family_id <= MESON_CPU_MAJOR_ID_GXTVBB)
|
|
saradc->adc_type = 0;
|
|
else
|
|
saradc->adc_type = 1;
|
|
|
|
aml_write_reg32(P_SAR_ADC_REG0(saradc->base_addr), 0x84004040);
|
|
aml_write_reg32(P_SAR_ADC_CHAN_LIST(saradc->base_addr), 0);
|
|
/* REG2: all chanel set to 8-samples & median averaging mode */
|
|
aml_write_reg32(P_SAR_ADC_AVG_CNTL(saradc->base_addr), 0);
|
|
|
|
/*
|
|
* through lots of tests, if we first initialize the REG3 to 0x9388000a
|
|
* and then set the bit[27], the sampling data maybe wrong when change
|
|
* the clock. For example:
|
|
*
|
|
* - change the clock to 24M/(20+1)
|
|
* saradc_clock_set(20);
|
|
*
|
|
* - read the sampling data by the command below
|
|
* saradc open 1;saradc getval;saradc close
|
|
*
|
|
* However, if we set the REG3 by the following code, the issue above
|
|
* can be avoided. unfortunately we have not found the root cause.
|
|
*/
|
|
if (saradc->adc_type)
|
|
aml_write_reg32(P_SAR_ADC_REG3(saradc->base_addr), 0x9b88000a);
|
|
else
|
|
aml_write_reg32(P_SAR_ADC_REG3(saradc->base_addr), 0x9388000a);
|
|
|
|
aml_write_reg32(P_SAR_ADC_DELAY(saradc->base_addr), 0x10a000a);
|
|
aml_write_reg32(P_SAR_ADC_AUX_SW(saradc->base_addr), 0x3eb1a0c);
|
|
aml_write_reg32(P_SAR_ADC_CHAN_10_SW(saradc->base_addr), 0x8c000c);
|
|
aml_write_reg32(P_SAR_ADC_DETECT_IDLE_SW(saradc->base_addr), 0xc000c);
|
|
|
|
/* REG11 bit[1] must be set to <1> for g12a and later SoCs */
|
|
if (saradc->family_id >= MESON_CPU_MAJOR_ID_G12A)
|
|
aml_set_reg32_bits(P_SAR_ADC_REG11(saradc->base_addr), 0x1, 1, 1);
|
|
|
|
/* select the VDDA as Vref for txlx and later SoCs */
|
|
if (saradc->family_id != MESON_CPU_MAJOR_ID_GXLX &&
|
|
saradc->family_id >= MESON_CPU_MAJOR_ID_TXLX)
|
|
aml_set_reg32_bits(P_SAR_ADC_REG11(saradc->base_addr), 0x1, 0, 1);
|
|
|
|
saradc_clock_set(0xa0);
|
|
}
|
|
|
|
int saradc_probe(void)
|
|
{
|
|
saradc_info *saradc = saradc_dev_get();
|
|
|
|
saradc->family_id = get_cpu_id().family_id;
|
|
saradc->clk_addr = (u32 __iomem *)AO_SAR_CLK;
|
|
saradc->base_addr = (u32 __iomem *)AO_SAR_ADC_REG0;
|
|
|
|
saradc_hw_init();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void saradc_internal_cal_12bit(void)
|
|
{
|
|
/*reference voltage has been calibrated by BL2, there is nothing to do*/
|
|
}
|
|
|
|
int saradc_value_trim(int val)
|
|
{
|
|
int tmp;
|
|
saradc_info *saradc = saradc_dev_get();
|
|
|
|
switch (saradc->family_id) {
|
|
case MESON_CPU_MAJOR_ID_GXL:
|
|
case MESON_CPU_MAJOR_ID_GXM:
|
|
case MESON_CPU_MAJOR_ID_TXL:
|
|
tmp = val * 3072 / 2764;
|
|
return (tmp < 1024) ? tmp : 1023;
|
|
break;
|
|
|
|
default:
|
|
return val;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* description: used to get sample value
|
|
* ch: set channel
|
|
* use_10bit_num: set the bits of the sample value(1:10bit; 0:12bit)
|
|
*/
|
|
int get_adc_sample_gxbb_early(int ch, int use_10bit_num)
|
|
{
|
|
int value, count, sum;
|
|
saradc_info *saradc = saradc_dev_get();
|
|
|
|
count = 0;
|
|
|
|
while (aml_read_reg32(P_SAR_ADC_DELAY(saradc->base_addr)) & FLAG_BUSY_BL30) {
|
|
udelay(10);
|
|
if (++count > 1000) {
|
|
printf("bl30 busy error\n");
|
|
value = -1;
|
|
goto end1;
|
|
}
|
|
}
|
|
|
|
aml_set_reg32_bits(P_SAR_ADC_DELAY(saradc->base_addr), 1,
|
|
FLAG_BUSY_KERNEL_BIT, 1);
|
|
|
|
aml_write_reg32(P_SAR_ADC_CHAN_LIST(saradc->base_addr), ch);
|
|
aml_write_reg32(P_SAR_ADC_DETECT_IDLE_SW(saradc->base_addr),
|
|
(0xc000c | (ch<<23) | (ch<<7)));
|
|
aml_set_reg32_bits(P_SAR_ADC_REG0(saradc->base_addr), 1, 0, 1);
|
|
aml_set_reg32_bits(P_SAR_ADC_REG0(saradc->base_addr), 1, 2, 1);
|
|
count = 0;
|
|
do {
|
|
udelay(10);
|
|
if (!(aml_read_reg32(P_SAR_ADC_REG0(saradc->base_addr)) & 0x70000000))
|
|
break;
|
|
else if (++count > 10000) {
|
|
printf("busy error = %x\n",
|
|
aml_read_reg32(P_SAR_ADC_REG0(saradc->base_addr)));
|
|
value = -1;
|
|
goto end;
|
|
}
|
|
} while (1);
|
|
|
|
count = 0;
|
|
sum = 0;
|
|
while (aml_get_reg32_bits(P_SAR_ADC_REG0(saradc->base_addr), 21, 5) && \
|
|
(count < 32)) {
|
|
value = aml_read_reg32(P_SAR_ADC_FIFO_RD(saradc->base_addr));
|
|
if (((value >> 12) & 0x07) == ch) {
|
|
if (use_10bit_num) {
|
|
//printf("10bit val~\n");
|
|
if (saradc->adc_type) {
|
|
value &= 0xffc;
|
|
value >>= 2;
|
|
} else
|
|
value &= 0x3ff;
|
|
} else {
|
|
//printf("12bit val~\n");
|
|
value &= 0xfff;
|
|
}
|
|
sum += value;
|
|
count++;
|
|
} else
|
|
printf("channel error\n");
|
|
}
|
|
|
|
if (!count) {
|
|
value = -1;
|
|
goto end;
|
|
}
|
|
value = sum / count;
|
|
end:
|
|
aml_set_reg32_bits(P_SAR_ADC_REG0(saradc->base_addr), 1, 14, 1);
|
|
aml_set_reg32_bits(P_SAR_ADC_REG0(saradc->base_addr), 0, 0, 1);
|
|
|
|
end1:
|
|
aml_set_reg32_bits(P_SAR_ADC_DELAY(saradc->base_addr), 0,
|
|
FLAG_BUSY_KERNEL_BIT, 1);
|
|
|
|
return saradc_value_trim(value);
|
|
}
|
|
|
|
int get_adc_sample_gxbb(int ch)
|
|
{
|
|
int val;
|
|
|
|
val = get_adc_sample_gxbb_early(ch, 1);
|
|
return val;
|
|
}
|
|
|
|
int get_adc_sample_gxbb_12bit(int ch)
|
|
{
|
|
int val;
|
|
|
|
val = get_adc_sample_gxbb_early(ch, 0);
|
|
return val;
|
|
}
|
|
|
|
int saradc_enable(void)
|
|
{
|
|
saradc_probe();
|
|
saradc_power_control(1);
|
|
udelay(10);
|
|
saradc_internal_cal_12bit();
|
|
return 0;
|
|
}
|
|
|
|
int saradc_disable(void)
|
|
{
|
|
saradc_power_control(0);
|
|
return 0;
|
|
}
|
|
|
|
void saradc_sample_test(void)
|
|
{
|
|
int i;
|
|
int val;
|
|
saradc_info *saradc = saradc_dev_get();
|
|
|
|
printf("ch7 sample test:\n");
|
|
saradc_enable();
|
|
for (i = 0; i < ARRAY_SIZE(ch7_vol); i++) {
|
|
aml_set_reg32_bits(P_SAR_ADC_REG3(saradc->base_addr), i, 23, 3);
|
|
udelay(10);
|
|
val = get_adc_sample_gxbb(7);
|
|
printf("%-7s : %d\n", ch7_vol[i], val);
|
|
}
|
|
saradc_disable();
|
|
}
|