summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDino Li <dino.li@ite.com.tw>2014-12-03 17:28:42 +0800
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-12-19 09:17:27 +0000
commit165cf6c8813420e1ce525e103b42f19017228ec6 (patch)
treeae6722100c5f3d6207fcf206645df2b25ed06654
parent7ec2e4158af7d5564038bc4b0336653445ba08c5 (diff)
downloadchrome-ec-165cf6c8813420e1ce525e103b42f19017228ec6.tar.gz
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 <dino.li@ite.com.tw> 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 <vpalatin@chromium.org> Commit-Queue: Dino Li <dino.li@ite.com.tw> Tested-by: Dino Li <dino.li@ite.com.tw>
-rw-r--r--board/it8380dev/board.c16
-rw-r--r--board/it8380dev/board.h14
-rw-r--r--chip/it83xx/adc.c171
-rw-r--r--chip/it83xx/adc_chip.h34
-rw-r--r--chip/it83xx/build.mk1
-rw-r--r--chip/it83xx/config_chip.h1
-rw-r--r--chip/it83xx/registers.h61
7 files changed, 296 insertions, 2 deletions
diff --git a/board/it8380dev/board.c b/board/it8380dev/board.c
index 588ab4d0d7..201a6c20c0 100644
--- a/board/it8380dev/board.c
+++ b/board/it8380dev/board.c
@@ -13,6 +13,8 @@
#include "util.h"
#include "pwm.h"
#include "pwm_chip.h"
+#include "adc.h"
+#include "adc_chip.h"
/* Test GPIO interrupt function that toggles one LED. */
void test_interrupt(enum gpio_signal signal)
@@ -47,6 +49,20 @@ static void board_init(void)
}
DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
+/* ADC channels. Must be in the exactly same order as in enum adc_channel. */
+const struct adc_t adc_channels[] = {
+ /* Convert to mV (3000mV/1024). */
+ {"adc_ch0", 3000, 1024, 0, 0},
+ {"adc_ch1", 3000, 1024, 0, 1},
+ {"adc_ch2", 3000, 1024, 0, 2},
+ {"adc_ch3", 3000, 1024, 0, 3},
+ {"adc_ch4", 3000, 1024, 0, 4},
+ {"adc_ch5", 3000, 1024, 0, 5},
+ {"adc_ch6", 3000, 1024, 0, 6},
+ {"adc_ch7", 3000, 1024, 0, 7},
+};
+BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
+
/*****************************************************************************/
/* Console commands */
diff --git a/board/it8380dev/board.h b/board/it8380dev/board.h
index 1d612d32a2..afadc3c40b 100644
--- a/board/it8380dev/board.h
+++ b/board/it8380dev/board.h
@@ -29,5 +29,19 @@ enum pwm_channel {
PWM_CH_COUNT
};
+enum adc_channel {
+ ADC_CH_0,
+ ADC_CH_1,
+ ADC_CH_2,
+ ADC_CH_3,
+ ADC_CH_4,
+ ADC_CH_5,
+ ADC_CH_6,
+ ADC_CH_7,
+
+ /* Number of ADC channels */
+ ADC_CH_COUNT
+};
+
#endif /* !__ASSEMBLER__ */
#endif /* __BOARD_H */
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