summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuibin Chang <ruibin.chang@ite.com.tw>2020-03-06 15:55:07 +0800
committerCommit Bot <commit-bot@chromium.org>2020-03-11 04:22:51 +0000
commit18500f672d0dcc76c79c8975a014293d7c7e94db (patch)
tree6a455552a6052c016102a872f7a1168bac623659
parent788b6f46ddb78c139bc960e936050882530d591d (diff)
downloadchrome-ec-18500f672d0dcc76c79c8975a014293d7c7e94db.tar.gz
it83xx/adc: add voltage comparator feature
Add voltage comparator feature. BUG=b:149094481 BRANCH=none TEST=on board it83xx_evb, 1.set VCMP1 threshold 2.8v: external input 3v, the INT would be triggered and ADC5 read the correctly voltage. 2.set VCMP0 threshold 0.2v: external input 0v, the INT would be triggered and ADC5 read the correctly voltage. Change-Id: I59510b1c6bd38004ff06e0fcbd2a671e895d59e3 Signed-off-by: Ruibin Chang <ruibin.chang@ite.com.tw> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2062110 Tested-by: Ruibin Chang <Ruibin.Chang@ite.com.tw> Reviewed-by: Diana Z <dzigterman@chromium.org> Commit-Queue: Ruibin Chang <Ruibin.Chang@ite.com.tw>
-rw-r--r--chip/it83xx/adc.c138
-rw-r--r--chip/it83xx/adc_chip.h73
-rw-r--r--chip/it83xx/intc.c5
-rw-r--r--chip/it83xx/intc.h3
-rw-r--r--chip/it83xx/registers.h22
-rw-r--r--include/config.h3
6 files changed, 244 insertions, 0 deletions
diff --git a/chip/it83xx/adc.c b/chip/it83xx/adc.c
index b6d5a7dbc1..0af56e32a3 100644
--- a/chip/it83xx/adc.c
+++ b/chip/it83xx/adc.c
@@ -62,6 +62,31 @@ const struct adc_ctrl_t adc_ctrl_regs[] = {
};
BUILD_ASSERT(ARRAY_SIZE(adc_ctrl_regs) == CHIP_ADC_COUNT);
+#ifdef CONFIG_ADC_VOLTAGE_COMPARATOR
+#define VCMP_ADC_CH_MASK_H BIT(3)
+#define VCMP_ADC_CH_MASK_L 0x7
+/* 10-bits resolution */
+#define VCMP_RESOLUTION BIT(10)
+#define VCMP_MAX_MVOLT 3000
+
+/* Data structure of voltage comparator control registers. */
+const struct vcmp_ctrl_t vcmp_ctrl_regs[] = {
+ {&IT83XX_ADC_VCMP0CTL, &IT83XX_ADC_VCMP0CSELM, &IT83XX_ADC_CMP0THRDATM,
+ &IT83XX_ADC_CMP0THRDATL},
+ {&IT83XX_ADC_VCMP1CTL, &IT83XX_ADC_VCMP1CSELM, &IT83XX_ADC_CMP1THRDATM,
+ &IT83XX_ADC_CMP1THRDATL},
+ {&IT83XX_ADC_VCMP2CTL, &IT83XX_ADC_VCMP2CSELM, &IT83XX_ADC_CMP2THRDATM,
+ &IT83XX_ADC_CMP2THRDATL},
+ {&IT83XX_ADC_VCMP3CTL, &IT83XX_ADC_VCMP3CSELM, &IT83XX_ADC_CMP3THRDATM,
+ &IT83XX_ADC_CMP3THRDATL},
+ {&IT83XX_ADC_VCMP4CTL, &IT83XX_ADC_VCMP4CSELM, &IT83XX_ADC_CMP4THRDATM,
+ &IT83XX_ADC_CMP4THRDATL},
+ {&IT83XX_ADC_VCMP5CTL, &IT83XX_ADC_VCMP5CSELM, &IT83XX_ADC_CMP5THRDATM,
+ &IT83XX_ADC_CMP5THRDATL},
+};
+BUILD_ASSERT(ARRAY_SIZE(vcmp_ctrl_regs) == CHIP_VCMP_COUNT);
+#endif
+
static void adc_enable_channel(int ch)
{
if (ch < CHIP_ADC_CH4)
@@ -190,6 +215,110 @@ void adc_interrupt(void)
task_set_event(task_waiting, TASK_EVENT_ADC_DONE, 0);
}
+#ifdef CONFIG_ADC_VOLTAGE_COMPARATOR
+/* Clear voltage comparator interrupt status */
+void clear_vcmp_status(int vcmp_x)
+{
+ if (vcmp_x <= CHIP_VCMP2)
+ IT83XX_ADC_VCMPSTS = BIT(vcmp_x);
+ else
+ IT83XX_ADC_VCMPSTS2 = BIT(vcmp_x - CHIP_VCMP3);
+}
+
+/* Enable/Disable voltage comparator interrupt */
+void vcmp_enable(int idx, int enable)
+{
+ if (enable) {
+ /* Enable comparator interrupt */
+ *vcmp_ctrl_regs[idx].vcmp_ctrl |= ADC_VCMP_CMPINTEN;
+ /* Start voltage comparator */
+ *vcmp_ctrl_regs[idx].vcmp_ctrl |= ADC_VCMP_CMPEN;
+ } else {
+ /* Stop voltage comparator */
+ *vcmp_ctrl_regs[idx].vcmp_ctrl &= ~ADC_VCMP_CMPEN;
+ /* Disable comparator interrupt */
+ *vcmp_ctrl_regs[idx].vcmp_ctrl &= ~ADC_VCMP_CMPINTEN;
+ }
+}
+
+/* Set voltage comparator conditions */
+void set_voltage_comparator_condition(int idx)
+{
+ int val;
+
+ /* CMPXTHRDAT[9:0] = threshold(mv) * 1024 / 3000(mv) */
+ val = vcmp_list[idx].threshold * VCMP_RESOLUTION / VCMP_MAX_MVOLT;
+ *vcmp_ctrl_regs[idx].vcmp_datl = (uint8_t)(val & 0xff);
+ *vcmp_ctrl_regs[idx].vcmp_datm = (uint8_t)((val >> 8) & 0xff);
+
+ /* Select greater or less equal than threshold */
+ if (vcmp_list[idx].flag & GREATER_THRESHOLD)
+ *vcmp_ctrl_regs[idx].vcmp_ctrl |= ADC_VCMP_GREATER_THRESHOLD;
+ else
+ *vcmp_ctrl_regs[idx].vcmp_ctrl &= ~ADC_VCMP_GREATER_THRESHOLD;
+}
+
+/* Voltage comparator interrupt, handle one channel at a time. */
+void voltage_comparator_interrupt(void)
+{
+ int idx, status;
+
+ /* Find out which voltage comparator triggered */
+ status = IT83XX_ADC_VCMPSTS & 0x07;
+ status |= (IT83XX_ADC_VCMPSTS2 & 0x07) << 3;
+
+ for (idx = CHIP_VCMP0; idx < VCMP_COUNT; idx++) {
+ if (status & BIT(idx)) {
+ /* Called back to board-level function */
+ if (vcmp_list[idx].vcmp_thresh_cb)
+ vcmp_list[idx].vcmp_thresh_cb();
+ /* Clear voltage comparator interrupt status */
+ clear_vcmp_status(idx);
+ }
+ }
+
+ /* Clear interrupt status */
+ task_clear_pending_irq(IT83XX_IRQ_V_COMP);
+}
+
+/* Voltage comparator initialization */
+static void voltage_comparator_init(void)
+{
+ int idx;
+
+ /* No voltage comparator is declared */
+ if (!VCMP_COUNT)
+ return;
+
+ for (idx = CHIP_VCMP0; idx < VCMP_COUNT; idx++) {
+ /*
+ * Select voltage comparator:
+ * vcmp_list[i] use voltage comparator i, i = 0 ~ 5.
+ */
+
+ /* Select which ADC channel output voltage into comparator */
+ *vcmp_ctrl_regs[idx].vcmp_ctrl |=
+ vcmp_list[idx].adc_ch & VCMP_ADC_CH_MASK_L;
+ if (vcmp_list[idx].adc_ch & VCMP_ADC_CH_MASK_H)
+ *vcmp_ctrl_regs[idx].vcmp_adc_chm |= ADC_VCMP_VCMPCSELM;
+
+ /* Set "all voltage comparator" scan period */
+ IT83XX_ADC_VCMPSCP = vcmp_list[idx].scan_period;
+ /* Set voltage comparator conditions */
+ set_voltage_comparator_condition(idx);
+ /* Clear voltage comparator interrupt status */
+ clear_vcmp_status(idx);
+ /* Enable comparator interrupt and start */
+ vcmp_enable(idx, 1);
+ }
+
+ /* Clear interrupt status */
+ task_clear_pending_irq(IT83XX_IRQ_V_COMP);
+ /* Enable voltage comparator to interrupt MCU */
+ task_enable_irq(IT83XX_IRQ_V_COMP);
+}
+#endif
+
/*
* ADC analog accuracy initialization (only once after VSTBY power on)
*
@@ -241,6 +370,15 @@ static void adc_init(void)
/* disable adc interrupt */
task_disable_irq(IT83XX_IRQ_ADC);
+#ifdef CONFIG_ADC_VOLTAGE_COMPARATOR
+ /*
+ * Init voltage comparator
+ * NOTE:ADC channel signal output to voltage comparator,
+ * so we need set the channel to ADC alternate mode first.
+ */
+ voltage_comparator_init();
+#endif
+
adc_init_done = 1;
}
DECLARE_HOOK(HOOK_INIT, adc_init, HOOK_PRIO_INIT_ADC);
diff --git a/chip/it83xx/adc_chip.h b/chip/it83xx/adc_chip.h
index c43a64c132..e894e97b64 100644
--- a/chip/it83xx/adc_chip.h
+++ b/chip/it83xx/adc_chip.h
@@ -41,6 +41,33 @@ enum chip_adc_channel {
CHIP_ADC_COUNT,
};
+/* List of voltage comparator. */
+enum chip_vcmp {
+ CHIP_VCMP0 = 0,
+ CHIP_VCMP1,
+ CHIP_VCMP2,
+ CHIP_VCMP3,
+ CHIP_VCMP4,
+ CHIP_VCMP5,
+ CHIP_VCMP_COUNT,
+};
+
+/* List of voltage comparator scan period times. */
+enum vcmp_scan_period {
+ VCMP_SCAN_PERIOD_100US = 0x10,
+ VCMP_SCAN_PERIOD_200US = 0x20,
+ VCMP_SCAN_PERIOD_400US = 0x30,
+ VCMP_SCAN_PERIOD_600US = 0x40,
+ VCMP_SCAN_PERIOD_800US = 0x50,
+ VCMP_SCAN_PERIOD_1MS = 0x60,
+ VCMP_SCAN_PERIOD_1_5MS = 0x70,
+ VCMP_SCAN_PERIOD_2MS = 0x80,
+ VCMP_SCAN_PERIOD_2_5MS = 0x90,
+ VCMP_SCAN_PERIOD_3MS = 0xA0,
+ VCMP_SCAN_PERIOD_4MS = 0xB0,
+ VCMP_SCAN_PERIOD_5MS = 0xC0,
+};
+
/* Data structure to define ADC channel control registers. */
struct adc_ctrl_t {
volatile uint8_t *adc_ctrl;
@@ -58,10 +85,56 @@ struct adc_t {
enum chip_adc_channel channel;
};
+/* Data structure to define voltage comparator control registers. */
+struct vcmp_ctrl_t {
+ volatile uint8_t *vcmp_ctrl;
+ volatile uint8_t *vcmp_adc_chm;
+ volatile uint8_t *vcmp_datm;
+ volatile uint8_t *vcmp_datl;
+};
+
+/* supported flags (member "flag" in struct vcmp_t) for voltage comparator */
+#define GREATER_THRESHOLD BIT(0)
+#define LESS_EQUAL_THRESHOLD BIT(1)
+
+/* Data structure for board to define voltage comparator list. */
+struct vcmp_t {
+ const char *name;
+ int threshold;
+ /*
+ * Select greater/less equal threshold.
+ * NOTE: once edge trigger interrupt fires, we need disable the voltage
+ * comparator, or the matching threshold level will infinitely
+ * triggers interrupt.
+ */
+ char flag;
+ /* Called when the interrupt fires */
+ void (*vcmp_thresh_cb)(void);
+ /*
+ * Select "all voltage comparator" scan period time.
+ * The power consumption is positively relative with scan frequency.
+ */
+ enum vcmp_scan_period scan_period;
+ /*
+ * Select which ADC channel output voltage into comparator and we
+ * should set the ADC channel pin in alternate mode via adc_channels[].
+ */
+ enum chip_adc_channel adc_ch;
+};
+
/*
* 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[];
+#ifdef CONFIG_ADC_VOLTAGE_COMPARATOR
+/*
+ * Boards must provide this list of voltage comparator definitions.
+ * This must match the enum board_vcmp list provided by the board.
+ */
+extern const struct vcmp_t vcmp_list[];
+void vcmp_enable(int index, int enable);
+#endif
+
#endif /* __CROS_EC_ADC_CHIP_H */
diff --git a/chip/it83xx/intc.c b/chip/it83xx/intc.c
index 1a6e6c74dc..8c1c092ed5 100644
--- a/chip/it83xx/intc.c
+++ b/chip/it83xx/intc.c
@@ -178,6 +178,11 @@ void intc_cpu_int_group_7(void)
case IT83XX_IRQ_ADC:
adc_interrupt();
break;
+#ifdef CONFIG_ADC_VOLTAGE_COMPARATOR
+ case IT83XX_IRQ_V_COMP:
+ voltage_comparator_interrupt();
+ break;
+#endif
#endif
default:
break;
diff --git a/chip/it83xx/intc.h b/chip/it83xx/intc.h
index 5a31c41b9c..45447db485 100644
--- a/chip/it83xx/intc.h
+++ b/chip/it83xx/intc.h
@@ -27,6 +27,9 @@ void pm5_ibf_interrupt(void);
void lpcrst_interrupt(enum gpio_signal signal);
void peci_interrupt(void);
void adc_interrupt(void);
+#ifdef CONFIG_ADC_VOLTAGE_COMPARATOR
+void voltage_comparator_interrupt(void);
+#endif
void i2c_interrupt(int port);
#ifdef CONFIG_I2C_SLAVE
void i2c_slv_interrupt(int port);
diff --git a/chip/it83xx/registers.h b/chip/it83xx/registers.h
index 3eceda91de..ff2467c606 100644
--- a/chip/it83xx/registers.h
+++ b/chip/it83xx/registers.h
@@ -1065,6 +1065,11 @@ enum clock_gate_offsets {
#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 ADC_VCMP_CMPEN BIT(7)
+#define ADC_VCMP_CMPINTEN BIT(6)
+#define ADC_VCMP_GREATER_THRESHOLD BIT(5)
+#define ADC_VCMP_EDGE_TRIGGER BIT(4)
+#define ADC_VCMP_GPIO_ACTIVE_LOW BIT(3)
#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)
@@ -1086,6 +1091,23 @@ enum clock_gate_offsets {
#define IT83XX_ADC_VCH16DATM REG8(IT83XX_ADC_BASE+0x6A)
#define IT83XX_ADC_VCH16DATL REG8(IT83XX_ADC_BASE+0x6B)
#define IT83XX_ADC_ADCDVSTS2 REG8(IT83XX_ADC_BASE+0x6C)
+#define IT83XX_ADC_VCMPSTS2 REG8(IT83XX_ADC_BASE+0x6D)
+#define IT83XX_ADC_VCMP3CTL REG8(IT83XX_ADC_BASE+0x6E)
+#define IT83XX_ADC_CMP3THRDATM REG8(IT83XX_ADC_BASE+0x6F)
+#define IT83XX_ADC_CMP3THRDATL REG8(IT83XX_ADC_BASE+0x70)
+#define IT83XX_ADC_VCMP4CTL REG8(IT83XX_ADC_BASE+0x71)
+#define IT83XX_ADC_CMP4THRDATM REG8(IT83XX_ADC_BASE+0x72)
+#define IT83XX_ADC_CMP4THRDATL REG8(IT83XX_ADC_BASE+0x73)
+#define IT83XX_ADC_VCMP5CTL REG8(IT83XX_ADC_BASE+0x74)
+#define IT83XX_ADC_CMP5THRDATM REG8(IT83XX_ADC_BASE+0x75)
+#define IT83XX_ADC_CMP5THRDATL REG8(IT83XX_ADC_BASE+0x76)
+#define IT83XX_ADC_VCMP0CSELM REG8(IT83XX_ADC_BASE+0x77)
+#define ADC_VCMP_VCMPCSELM BIT(0)
+#define IT83XX_ADC_VCMP1CSELM REG8(IT83XX_ADC_BASE+0x78)
+#define IT83XX_ADC_VCMP2CSELM REG8(IT83XX_ADC_BASE+0x79)
+#define IT83XX_ADC_VCMP3CSELM REG8(IT83XX_ADC_BASE+0x7A)
+#define IT83XX_ADC_VCMP4CSELM REG8(IT83XX_ADC_BASE+0x7B)
+#define IT83XX_ADC_VCMP5CSELM REG8(IT83XX_ADC_BASE+0x7C)
/* Digital to Analog Converter (DAC) */
#define IT83XX_DAC_BASE 0x00F01A00
diff --git a/include/config.h b/include/config.h
index 969e6aa674..ba48d21b71 100644
--- a/include/config.h
+++ b/include/config.h
@@ -248,6 +248,9 @@
*/
#undef CONFIG_ADC_SAMPLE_TIME
+/* Support voltage comparator */
+#undef CONFIG_ADC_VOLTAGE_COMPARATOR
+
/* Include the ADC analog watchdog feature in the ADC code */
#define CONFIG_ADC_WATCHDOG