From 165cf6c8813420e1ce525e103b42f19017228ec6 Mon Sep 17 00:00:00 2001 From: Dino Li Date: Wed, 3 Dec 2014 17:28:42 +0800 Subject: it8380dev: add adc control module Add adc control module for emulation board. The ADC converts the input voltage signal ranging from 0v to 3v into a 10-bit unsigned integer. Signed-off-by: Dino Li BRANCH=none BUG=none TEST=manual test. 1 - adc channel 1, 3, 5, and 7 to ground. 2 - adc channel 0 and 2 to 1.26v. 3 - adc channel 4 and 6 to 1.72v. 4 - condition, factor_mul = 3000, factor_div = 1024, and shift = 0. 5 - console "adc", result as following. adc_ch0 = 1256 adc_ch1 = 0 adc_ch2 = 1256 adc_ch3 = 0 adc_ch4 = 1722 adc_ch5 = 0 adc_ch6 = 1725 adc_ch7 = 0 Change-Id: I72efd09c9f7dbff25c4f6fd4846c9b1c1e5637ca Reviewed-on: https://chromium-review.googlesource.com/228092 Reviewed-by: Vincent Palatin Commit-Queue: Dino Li Tested-by: Dino Li --- chip/it83xx/adc.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++ chip/it83xx/adc_chip.h | 34 +++++++++ chip/it83xx/build.mk | 1 + chip/it83xx/config_chip.h | 1 + chip/it83xx/registers.h | 61 ++++++++++++++++- 5 files changed, 266 insertions(+), 2 deletions(-) create mode 100644 chip/it83xx/adc.c create mode 100644 chip/it83xx/adc_chip.h (limited to 'chip/it83xx') diff --git a/chip/it83xx/adc.c b/chip/it83xx/adc.c new file mode 100644 index 0000000000..bb59bda0ff --- /dev/null +++ b/chip/it83xx/adc.c @@ -0,0 +1,171 @@ +/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* IT8380 ADC module for Chrome EC */ + +#include "adc.h" +#include "adc_chip.h" +#include "clock.h" +#include "console.h" +#include "common.h" +#include "gpio.h" +#include "hooks.h" +#include "registers.h" +#include "task.h" +#include "timer.h" +#include "util.h" + +/* Data structure of ADC channel control registers. */ +const struct adc_ctrl_t adc_ctrl_regs[] = { + {&IT83XX_ADC_VCH0CTL, &IT83XX_ADC_VCH0DATM, &IT83XX_ADC_VCH0DATL, + &IT83XX_GPIO_GPCRI0}, + {&IT83XX_ADC_VCH1CTL, &IT83XX_ADC_VCH1DATM, &IT83XX_ADC_VCH1DATL, + &IT83XX_GPIO_GPCRI1}, + {&IT83XX_ADC_VCH2CTL, &IT83XX_ADC_VCH2DATM, &IT83XX_ADC_VCH2DATL, + &IT83XX_GPIO_GPCRI2}, + {&IT83XX_ADC_VCH3CTL, &IT83XX_ADC_VCH3DATM, &IT83XX_ADC_VCH3DATL, + &IT83XX_GPIO_GPCRI3}, + {&IT83XX_ADC_VCH4CTL, &IT83XX_ADC_VCH4DATM, &IT83XX_ADC_VCH4DATL, + &IT83XX_GPIO_GPCRI4}, + {&IT83XX_ADC_VCH5CTL, &IT83XX_ADC_VCH5DATM, &IT83XX_ADC_VCH5DATL, + &IT83XX_GPIO_GPCRI5}, + {&IT83XX_ADC_VCH6CTL, &IT83XX_ADC_VCH6DATM, &IT83XX_ADC_VCH6DATL, + &IT83XX_GPIO_GPCRI6}, + {&IT83XX_ADC_VCH7CTL, &IT83XX_ADC_VCH7DATM, &IT83XX_ADC_VCH7DATL, + &IT83XX_GPIO_GPCRI7}, +}; + +static void adc_enable_channel(int ch) +{ + if (ch < 4) + /* + * for channel 0, 1, 2, and 3 + * bit4 ~ bit0 : indicates voltage channel[x] + * input is selected for measurement (enable) + * bit 7 : W/C data valid flag + */ + *adc_ctrl_regs[ch].adc_ctrl = 0x80 + ch; + else + /* + * for channel 4, 5, 6, and 7 + * bit4 : voltage channel enable (ch 4~7 only) + * bit7 : W/C data valid flag + */ + *adc_ctrl_regs[ch].adc_ctrl = 0x90; + + /* bit 0 : adc module enable */ + IT83XX_ADC_ADCCFG |= 0x01; +} + +static void adc_disable_channel(int ch) +{ + if (ch < 4) + /* + * for channel 0, 1, 2, and 3 + * bit4 ~ bit0 : indicates voltage channel[x] + * input is selected for measurement (disable) + * bit 7 : W/C data valid flag + */ + *adc_ctrl_regs[ch].adc_ctrl = 0x9F; + else + /* + * for channel 4, 5, 6, and 7 + * bit4 : voltage channel disable (ch 4~7 only) + * bit7 : W/C data valid flag + */ + *adc_ctrl_regs[ch].adc_ctrl = 0x80; + + /* bit 0 : adc module disable */ + IT83XX_ADC_ADCCFG &= ~0x01; +} + +int adc_read_channel(enum adc_channel ch) +{ + /* voltage 0 ~ 3v = adc data register raw data 0 ~ 3FFh (10-bit ) */ + uint16_t adc_raw_data; + int num; + int adc_ch; + + adc_ch = adc_channels[ch].channel; + + adc_enable_channel(adc_ch); + + /* Maximum time for waiting ADC conversion is ~1.525ms */ + for (num = 0x00; num < 100; num++) { + /* delay ~15.25us */ + IT83XX_GCTRL_WNCKR = 0; + + /* data valid of adc channel[x] */ + if (IT83XX_ADC_ADCDVSTS & (1 << adc_ch)) { + /* read adc raw data msb and lsb */ + adc_raw_data = (*adc_ctrl_regs[adc_ch].adc_datm << 8) + + *adc_ctrl_regs[adc_ch].adc_datl; + + /* W/C data valid flag */ + IT83XX_ADC_ADCDVSTS = (1 << adc_ch); + + adc_disable_channel(adc_ch); + return adc_raw_data * adc_channels[ch].factor_mul / + adc_channels[ch].factor_div + + adc_channels[ch].shift; + } + } + + adc_disable_channel(adc_ch); + return ADC_READ_ERROR; +} + +int adc_read_all_channels(int *data) +{ + int index; + + for (index = 0; index < ADC_CH_COUNT; index++) { + data[index] = adc_read_channel(index); + if (data[index] == ADC_READ_ERROR) + return EC_ERROR_UNKNOWN; + } + return EC_SUCCESS; +} + +/* + * ADC analog accuracy initialization (only once after VSTBY power on) + * + * Write 1 to this bit and write 0 to this bit immediately once and + * only once during the firmware initialization and do not write 1 again + * after initialization since IT8380 takes much power consumption + * if this bit is set as 1 + */ +static void adc_accuracy_initialization(void) +{ + /* bit3 : start adc accuracy initialization */ + IT83XX_ADC_ADCSTS |= 0x08; + /* short delay for adc accuracy initialization */ + IT83XX_GCTRL_WNCKR = 0; + /* bit3 : stop adc accuracy initialization */ + IT83XX_ADC_ADCSTS &= ~0x08; +} + +/* ADC module Initialization */ +static void adc_init(void) +{ + int index; + int ch; + + /* ADC analog accuracy initialization */ + adc_accuracy_initialization(); + + for (index = 0; index < ADC_CH_COUNT; index++) { + ch = adc_channels[index].channel; + + /* enable adc channel[x] function pin */ + *adc_ctrl_regs[ch].adc_pin_ctrl = 0x00; + } + + /* bit 5 : ADCCTS0 = 1 */ + IT83XX_ADC_ADCCFG = 0x20; + + IT83XX_ADC_ADCCTL = 0x04; +} +DECLARE_HOOK(HOOK_INIT, adc_init, HOOK_PRIO_DEFAULT); diff --git a/chip/it83xx/adc_chip.h b/chip/it83xx/adc_chip.h new file mode 100644 index 0000000000..ae7ee403b0 --- /dev/null +++ b/chip/it83xx/adc_chip.h @@ -0,0 +1,34 @@ +/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* IT8380 ADC module for Chrome EC */ + +#ifndef __CROS_EC_ADC_CHIP_H +#define __CROS_EC_ADC_CHIP_H + +/* Data structure to define ADC channel control registers. */ +struct adc_ctrl_t { + volatile uint8_t *adc_ctrl; + volatile uint8_t *adc_datm; + volatile uint8_t *adc_datl; + volatile uint8_t *adc_pin_ctrl; +}; + +/* Data structure to define ADC channels. */ +struct adc_t { + const char *name; + int factor_mul; + int factor_div; + int shift; + int channel; +}; + +/* + * Boards must provide this list of ADC channel definitions. This must match + * the enum adc_channel list provided by the board. + */ +extern const struct adc_t adc_channels[]; + +#endif /* __CROS_EC_ADC_CHIP_H */ diff --git a/chip/it83xx/build.mk b/chip/it83xx/build.mk index e6c9926ff1..6029ee4b30 100644 --- a/chip/it83xx/build.mk +++ b/chip/it83xx/build.mk @@ -15,3 +15,4 @@ chip-y=hwtimer.o uart.o gpio.o system.o jtag.o clock.o irq.o # Optional chip modules chip-$(CONFIG_WATCHDOG)+=watchdog.o chip-$(CONFIG_PWM)+=pwm.o +chip-$(CONFIG_ADC)+=adc.o diff --git a/chip/it83xx/config_chip.h b/chip/it83xx/config_chip.h index 0f0e86aa3c..6032ce5e83 100644 --- a/chip/it83xx/config_chip.h +++ b/chip/it83xx/config_chip.h @@ -104,5 +104,6 @@ #undef CONFIG_FLASH #undef CONFIG_WATCHDOG #define CONFIG_PWM +#define CONFIG_ADC #endif /* __CROS_EC_CONFIG_CHIP_H */ diff --git a/chip/it83xx/registers.h b/chip/it83xx/registers.h index feb16bbba9..08a3aab150 100644 --- a/chip/it83xx/registers.h +++ b/chip/it83xx/registers.h @@ -431,6 +431,15 @@ #define IT83XX_GPIO_GPCRF0 REG8(IT83XX_GPIO_BASE+0x38) +#define IT83XX_GPIO_GPCRI0 REG8(IT83XX_GPIO_BASE+0x50) +#define IT83XX_GPIO_GPCRI1 REG8(IT83XX_GPIO_BASE+0x51) +#define IT83XX_GPIO_GPCRI2 REG8(IT83XX_GPIO_BASE+0x52) +#define IT83XX_GPIO_GPCRI3 REG8(IT83XX_GPIO_BASE+0x53) +#define IT83XX_GPIO_GPCRI4 REG8(IT83XX_GPIO_BASE+0x54) +#define IT83XX_GPIO_GPCRI5 REG8(IT83XX_GPIO_BASE+0x55) +#define IT83XX_GPIO_GPCRI6 REG8(IT83XX_GPIO_BASE+0x56) +#define IT83XX_GPIO_GPCRI7 REG8(IT83XX_GPIO_BASE+0x57) + #define IT83XX_GPIO_GRC1 REG8(IT83XX_GPIO_BASE+0xF0) #define IT83XX_GPIO_GRC2 REG8(IT83XX_GPIO_BASE+0xF1) #define IT83XX_GPIO_GRC3 REG8(IT83XX_GPIO_BASE+0xF2) @@ -443,7 +452,6 @@ #define IT83XX_GPIO_DATA_BASE (IT83XX_GPIO_BASE + 0x00) #define IT83XX_GPIO_OUTPUT_TYPE_BASE (IT83XX_GPIO_BASE + 0x70) - enum { GPIO_A = 0x1, GPIO_B = 0x2, @@ -583,6 +591,56 @@ enum clock_gate_offsets { #define IT83XX_PWM_TSWCTRL REG8(IT83XX_PWM_BASE+0x48) #define IT83XX_PWM_PWMODENR REG8(IT83XX_PWM_BASE+0x49) +/* Analog to Digital Converter (ADC) */ +#define IT83XX_ADC_BASE 0x00F01900 + +#define IT83XX_ADC_ADCSTS REG8(IT83XX_ADC_BASE+0x00) +#define IT83XX_ADC_ADCCFG REG8(IT83XX_ADC_BASE+0x01) +#define IT83XX_ADC_ADCCTL REG8(IT83XX_ADC_BASE+0x02) +#define IT83XX_ADC_ADCGCR REG8(IT83XX_ADC_BASE+0x03) +#define IT83XX_ADC_VCH0CTL REG8(IT83XX_ADC_BASE+0x04) +#define IT83XX_ADC_KDCTL REG8(IT83XX_ADC_BASE+0x05) +#define IT83XX_ADC_VCH1CTL REG8(IT83XX_ADC_BASE+0x06) +#define IT83XX_ADC_VCH1DATL REG8(IT83XX_ADC_BASE+0x07) +#define IT83XX_ADC_VCH1DATM REG8(IT83XX_ADC_BASE+0x08) +#define IT83XX_ADC_VCH2CTL REG8(IT83XX_ADC_BASE+0x09) +#define IT83XX_ADC_VCH2DATL REG8(IT83XX_ADC_BASE+0x0A) +#define IT83XX_ADC_VCH2DATM REG8(IT83XX_ADC_BASE+0x0B) +#define IT83XX_ADC_VCH3CTL REG8(IT83XX_ADC_BASE+0x0C) +#define IT83XX_ADC_VCH3DATL REG8(IT83XX_ADC_BASE+0x0D) +#define IT83XX_ADC_VCH3DATM REG8(IT83XX_ADC_BASE+0x0E) +#define IT83XX_ADC_VHSCDBL REG8(IT83XX_ADC_BASE+0x14) +#define IT83XX_ADC_VHSCDBM REG8(IT83XX_ADC_BASE+0x15) +#define IT83XX_ADC_VCH0DATL REG8(IT83XX_ADC_BASE+0x18) +#define IT83XX_ADC_VCH0DATM REG8(IT83XX_ADC_BASE+0x19) +#define IT83XX_ADC_VHSGCDBL REG8(IT83XX_ADC_BASE+0x1C) +#define IT83XX_ADC_VHSGCDBM REG8(IT83XX_ADC_BASE+0x1D) +#define IT83XX_ADC_ADCSAR REG8(IT83XX_ADC_BASE+0x32) +#define IT83XX_ADC_VCMPSCP REG8(IT83XX_ADC_BASE+0x37) +#define IT83XX_ADC_VCH4CTL REG8(IT83XX_ADC_BASE+0x38) +#define IT83XX_ADC_VCH4DATM REG8(IT83XX_ADC_BASE+0x39) +#define IT83XX_ADC_VCH4DATL REG8(IT83XX_ADC_BASE+0x3A) +#define IT83XX_ADC_VCH5CTL REG8(IT83XX_ADC_BASE+0x3B) +#define IT83XX_ADC_VCH5DATM REG8(IT83XX_ADC_BASE+0x3C) +#define IT83XX_ADC_VCH5DATL REG8(IT83XX_ADC_BASE+0x3D) +#define IT83XX_ADC_VCH6CTL REG8(IT83XX_ADC_BASE+0x3E) +#define IT83XX_ADC_VCH6DATM REG8(IT83XX_ADC_BASE+0x3F) +#define IT83XX_ADC_VCH6DATL REG8(IT83XX_ADC_BASE+0x40) +#define IT83XX_ADC_VCH7CTL REG8(IT83XX_ADC_BASE+0x41) +#define IT83XX_ADC_VCH7DATM REG8(IT83XX_ADC_BASE+0x42) +#define IT83XX_ADC_VCH7DATL REG8(IT83XX_ADC_BASE+0x43) +#define IT83XX_ADC_ADCDVSTS REG8(IT83XX_ADC_BASE+0x44) +#define IT83XX_ADC_VCMPSTS REG8(IT83XX_ADC_BASE+0x45) +#define IT83XX_ADC_VCMP0CTL REG8(IT83XX_ADC_BASE+0x46) +#define IT83XX_ADC_CMP0THRDATM REG8(IT83XX_ADC_BASE+0x47) +#define IT83XX_ADC_CMP0THRDATL REG8(IT83XX_ADC_BASE+0x48) +#define IT83XX_ADC_VCMP1CTL REG8(IT83XX_ADC_BASE+0x49) +#define IT83XX_ADC_CMP1THRDATM REG8(IT83XX_ADC_BASE+0x4A) +#define IT83XX_ADC_CMP1THRDATL REG8(IT83XX_ADC_BASE+0x4B) +#define IT83XX_ADC_VCMP2CTL REG8(IT83XX_ADC_BASE+0x4C) +#define IT83XX_ADC_CMP2THRDATM REG8(IT83XX_ADC_BASE+0x4D) +#define IT83XX_ADC_CMP2THRDATL REG8(IT83XX_ADC_BASE+0x4E) + /* --- MISC (not implemented yet) --- */ #define IT83XX_SMFI_BASE 0x00F01000 @@ -591,7 +649,6 @@ enum clock_gate_offsets { #define IT83XX_SWUC_BASE 0x00F01400 #define IT83XX_PMC_BASE 0x00F01500 #define IT83XX_PS2_BASE 0x00F01700 -#define IT83XX_ADC_BASE 0x00F01900 #define IT83XX_DAC_BASE 0x00F01A00 #define IT83XX_WUC_BASE 0x00F01B00 #define IT83XX_SMB_BASE 0x00F01C00 -- cgit v1.2.1