blob: 3fca5dbd72f5ea0beda1b7c8a32e9735383e5564 [file] [log] [blame]
#define MESON_CPU_MAJOR_ID_GXBB 0x1F
#define MESON_CPU_MAJOR_ID_GXTVBB 0x20
#define MESON_CPU_MAJOR_ID_GXL 0x21
#define MESON_CPU_MAJOR_ID_GXM 0x22
#define MESON_CPU_MAJOR_ID_TXL 0x23
static int adc_type; /*1:12bit; 0:10bit*/
unsigned int channel = 0xffff;
unsigned int keycode;
int get_adc_sample_gxbb(int ch);
static void aml_set_reg32_bits(volatile unsigned int *_reg,
const unsigned int _value,
const unsigned int _start,
const unsigned int _len)
{
writel(( (readl((volatile unsigned int *)_reg) & \
~(((1L << (_len) )-1) << (_start))) | \
((unsigned)((_value) & ((1L<<(_len))-1)) << (_start))),
(volatile void *)_reg );
}
static unsigned int aml_get_reg32_bits(volatile unsigned int *_reg,
const unsigned int _start,
const unsigned int _len)
{
return ((readl((volatile unsigned int *)_reg) >> (_start)) & \
((1L << (_len) ) - 1) );
}
static void aml_write_reg32( volatile unsigned int *_reg,
const unsigned int _value)
{
writel( _value, (volatile unsigned int *)_reg );
};
static unsigned int aml_read_reg32(volatile unsigned int *_reg)
{
return readl((volatile unsigned int *)_reg);
};
static int get_cpu_family_id(void)
{
return ((aml_read_reg32(P_AO_SEC_SD_CFG8) >> 24) & 0xff);
}
/*
* description: used to enable and disable the clock of the SARADC
* onoff: 1: enable ; 0: disable
*/
static void saradc_clock_switch(int onoff)
{
/* if the famiy id of the cpu greater than or equal to MESON_CPU_MAJOR_ID_GXBB,
* the clock switch from the clock tree register, otherwise from the adc module register.
*/
if (onoff) {
if (get_cpu_family_id() >= MESON_CPU_MAJOR_ID_GXBB)
aml_set_reg32_bits(P_AO_SAR_CLK, 1, 8, 1);
else
aml_set_reg32_bits(P_AO_SAR_ADC_REG3, 1, 30, 1);
} else {
if (get_cpu_family_id() >= MESON_CPU_MAJOR_ID_GXBB)
aml_set_reg32_bits(P_AO_SAR_CLK, 0, 8, 1);
else
aml_set_reg32_bits(P_AO_SAR_ADC_REG3, 0, 30, 1);
}
}
static inline void saradc_power_control(int on)
{
if (on) {
aml_set_reg32_bits(P_AO_SAR_ADC_REG11, 1, 13, 1);
aml_set_reg32_bits(P_AO_SAR_ADC_REG11, 3, 5, 2);
aml_set_reg32_bits(P_AO_SAR_ADC_REG3, 1, 21, 1);
_udelay(5);
saradc_clock_switch(1);
} else {
saradc_clock_switch(0);
aml_set_reg32_bits(P_AO_SAR_ADC_REG3, 0, 21, 1);
}
}
/*
* description: used to set the DIV of the clock
*/
static void saradc_clock_set(unsigned char val)
{
/* if the famiy id of the cpu greater than or equal to MESON_CPU_MAJOR_ID_GXBB,
* the clock switch from the clock tree register, otherwise from the adc module register.
*/
if (get_cpu_family_id() >= MESON_CPU_MAJOR_ID_GXBB) {
/*bit[0-7]: set clk div; bit[9-10]: select clk source*/
aml_set_reg32_bits(P_AO_SAR_CLK, 0, 9, 2);
aml_set_reg32_bits(P_AO_SAR_CLK, (val & 0xff), 0, 8);
} else {
/*bit10-bit15: set clk div*/
aml_set_reg32_bits(P_AO_SAR_ADC_REG3, (val & 0x3f), 10, 6);
}
}
void saradc_enable(void)
{
if (get_cpu_family_id() <= MESON_CPU_MAJOR_ID_GXTVBB)
adc_type = 0;
else
adc_type = 1;
aml_write_reg32(P_AO_SAR_ADC_REG0, 0x84004040);
aml_write_reg32(P_AO_SAR_ADC_CHAN_LIST, 0);
/* REG2: all chanel set to 8-samples & median averaging mode */
aml_write_reg32(P_AO_SAR_ADC_AVG_CNTL, 0);
aml_write_reg32(P_AO_SAR_ADC_REG3, 0x9388000a);
if (adc_type)
aml_set_reg32_bits(P_AO_SAR_ADC_REG3, 0x1, 27, 1);
saradc_clock_set(20);
aml_write_reg32(P_AO_SAR_ADC_DELAY, 0x10a000a);
aml_write_reg32(P_AO_SAR_ADC_AUX_SW, 0x3eb1a0c);
aml_write_reg32(P_AO_SAR_ADC_CHAN_10_SW, 0x8c000c);
aml_write_reg32(P_AO_SAR_ADC_DETECT_IDLE_SW, 0xc000c);
saradc_power_control(1);
}
int saradc_value_trim(int val)
{
int tmp;
switch (get_cpu_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;
}
}
int get_adc_sample_gxbb(int ch)
{
int value=0;
int count=0;
int sum=0;
aml_write_reg32(P_AO_SAR_ADC_CHAN_LIST, ch);
aml_write_reg32(P_AO_SAR_ADC_DETECT_IDLE_SW, (0xc000c | (ch<<23) | (ch<<7)));
aml_set_reg32_bits(P_AO_SAR_ADC_REG0, 1, 0, 1);
aml_set_reg32_bits(P_AO_SAR_ADC_REG0, 1, 2, 1);
count = 0;
do {
_udelay(10);
if (!(aml_read_reg32(P_AO_SAR_ADC_REG0) & 0x70000000))
break;
else if (++count > 10000) {
uart_puts("busy error");
uart_puts("\n");
value = -1;
goto end;
}
} while (1);
count = 0;
sum = 0;
while (aml_get_reg32_bits(P_AO_SAR_ADC_REG0, 21, 5) && (count < 32)) {
value = aml_read_reg32(P_AO_SAR_ADC_FIFO_RD);
if (((value >> 12) & 0x07) == ch) {
value &= 0xffc;
value >>= 2;
sum += value;
count++;
} else {
uart_puts("channel error");
uart_puts("\n");
}
}
if (!count) {
value = -1;
goto end;
}
value = sum / count;
end:
aml_set_reg32_bits(P_AO_SAR_ADC_REG0, 1, 14, 1);
aml_set_reg32_bits(P_AO_SAR_ADC_REG0, 0, 0, 1);
return saradc_value_trim(value);
}
int saradc_disable(void)
{
saradc_power_control(0);
return 0;
}
int check_adc_key_resume(void)
{
int value;
int min;
int max;
if (channel == 0xffff) {
channel = CONFIG_ADC_POWER_KEY_CHAN;
keycode = CONFIG_ADC_POWER_KEY_VAL;
}
/*the sampling value of adc: 0-1023*/
min = keycode - 40;
if (min < 0)
min = 0;
max = keycode + 40;
if (max > 1023)
max = 1023;
value = get_adc_sample_gxbb(channel);
if ((value >= min) && (value <= max))
return 1;
else
return 0;
}