summaryrefslogtreecommitdiff
path: root/chip
diff options
context:
space:
mode:
Diffstat (limited to 'chip')
-rw-r--r--chip/it83xx/adc.c100
-rw-r--r--chip/it83xx/adc_chip.h13
-rw-r--r--chip/it83xx/clock.c5
-rw-r--r--chip/it83xx/intc.c17
-rw-r--r--chip/it83xx/intc.h1
-rw-r--r--chip/it83xx/registers.h3
6 files changed, 116 insertions, 23 deletions
diff --git a/chip/it83xx/adc.c b/chip/it83xx/adc.c
index 88615b8873..f91944b1a7 100644
--- a/chip/it83xx/adc.c
+++ b/chip/it83xx/adc.c
@@ -3,7 +3,7 @@
* found in the LICENSE file.
*/
-/* IT8380 ADC module for Chrome EC */
+/* IT83xx ADC module for Chrome EC */
#include "adc.h"
#include "adc_chip.h"
@@ -17,6 +17,11 @@
#include "timer.h"
#include "util.h"
+/* Global variables */
+static struct mutex adc_lock;
+static int adc_init_done;
+static volatile task_id_t task_waiting;
+
/* Data structure of ADC channel control registers. */
const struct adc_ctrl_t adc_ctrl_regs[] = {
{&IT83XX_ADC_VCH0CTL, &IT83XX_ADC_VCH0DATM, &IT83XX_ADC_VCH0DATL,
@@ -44,16 +49,21 @@ static void adc_enable_channel(int ch)
* 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
+ * bit5 : data valid interrupt of adc.
+ * bit7 : W/C data valid flag
*/
- *adc_ctrl_regs[ch].adc_ctrl = 0x80 + ch;
+ *adc_ctrl_regs[ch].adc_ctrl = 0xa0 + ch;
else
/*
* for channel 4, 5, 6, and 7
* bit4 : voltage channel enable (ch 4~7 only)
+ * bit5 : data valid interrupt of adc.
* bit7 : W/C data valid flag
*/
- *adc_ctrl_regs[ch].adc_ctrl = 0x90;
+ *adc_ctrl_regs[ch].adc_ctrl = 0xb0;
+
+ task_clear_pending_irq(IT83XX_IRQ_ADC);
+ task_enable_irq(IT83XX_IRQ_ADC);
/* bit 0 : adc module enable */
IT83XX_ADC_ADCCFG |= 0x01;
@@ -79,24 +89,31 @@ static void adc_disable_channel(int ch)
/* bit 0 : adc module disable */
IT83XX_ADC_ADCCFG &= ~0x01;
+
+ task_disable_irq(IT83XX_IRQ_ADC);
}
int adc_read_channel(enum adc_channel ch)
{
+ uint32_t events;
/* voltage 0 ~ 3v = adc data register raw data 0 ~ 3FFh (10-bit ) */
uint16_t adc_raw_data;
- int num;
- int adc_ch;
+ int valid = 0;
+ int adc_ch, mv;
- adc_ch = adc_channels[ch].channel;
+ if (!adc_init_done)
+ return ADC_READ_ERROR;
- adc_enable_channel(adc_ch);
+ mutex_lock(&adc_lock);
- /* Maximum time for waiting ADC conversion is ~1.525ms */
- for (num = 0x00; num < 100; num++) {
- /* delay ~15.25us */
- IT83XX_GCTRL_WNCKR = 0;
+ task_waiting = task_get_current();
+ adc_ch = adc_channels[ch].channel;
+ adc_enable_channel(adc_ch);
+ /* Wait for interrupt */
+ events = task_wait_event_mask(TASK_EVENT_ADC_DONE, ADC_TIMEOUT_US);
+ task_waiting = TASK_ID_INVALID;
+ if (events & TASK_EVENT_ADC_DONE) {
/* data valid of adc channel[x] */
if (IT83XX_ADC_ADCDVSTS & (1 << adc_ch)) {
/* read adc raw data msb and lsb */
@@ -106,15 +123,40 @@ int adc_read_channel(enum adc_channel ch)
/* 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 /
+ mv = adc_raw_data * adc_channels[ch].factor_mul /
adc_channels[ch].factor_div +
adc_channels[ch].shift;
+ valid = 1;
}
}
-
adc_disable_channel(adc_ch);
- return ADC_READ_ERROR;
+
+ mutex_unlock(&adc_lock);
+
+ return valid ? mv : ADC_READ_ERROR;
+}
+
+void adc_interrupt(void)
+{
+ /*
+ * Clear the interrupt status.
+ *
+ * NOTE:
+ * The ADC interrupt pending flag won't be cleared unless
+ * we W/C data valid flag of ADC module as well.
+ * (If interrupt type setting is high-level triggered)
+ */
+ task_clear_pending_irq(IT83XX_IRQ_ADC);
+ /*
+ * We disable ADC interrupt here, because current setting of
+ * interrupt type is high-level triggered.
+ * The interrupt will be triggered again and again until
+ * we W/C data valid flag if we don't disable it.
+ */
+ task_disable_irq(IT83XX_IRQ_ADC);
+ /* Wake up the task which was waiting for the interrupt */
+ if (task_waiting != TASK_ID_INVALID)
+ task_set_event(task_waiting, TASK_EVENT_ADC_DONE, 0);
}
/*
@@ -122,7 +164,7 @@ int adc_read_channel(enum adc_channel ch)
*
* 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
+ * after initialization since IT83xx takes much power consumption
* if this bit is set as 1
*/
static void adc_accuracy_initialization(void)
@@ -150,10 +192,24 @@ static void adc_init(void)
/* 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;
+ /*
+ * bit7@ADCSTS : ADCCTS1 = 0
+ * bit5@ADCCFG : ADCCTS0 = 0
+ * bit[5-0]@ADCCTL : SCLKDIV
+ * The ADC channel conversion time is 30.8*(SCLKDIV+1) us.
+ * (Current setting is 61.6us)
+ *
+ * NOTE: A sample time delay (60us) also need to be included in
+ * conversion time, so the final result is ~= 121.6us.
+ */
+ IT83XX_ADC_ADCSTS &= ~(1 << 7);
+ IT83XX_ADC_ADCCFG &= ~(1 << 5);
+ IT83XX_ADC_ADCCTL = 1;
+
+ task_waiting = TASK_ID_INVALID;
+ /* disable adc interrupt */
+ task_disable_irq(IT83XX_IRQ_ADC);
+
+ 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 ae7ee403b0..424e00c24d 100644
--- a/chip/it83xx/adc_chip.h
+++ b/chip/it83xx/adc_chip.h
@@ -3,11 +3,22 @@
* found in the LICENSE file.
*/
-/* IT8380 ADC module for Chrome EC */
+/* IT83xx ADC module for Chrome EC */
#ifndef __CROS_EC_ADC_CHIP_H
#define __CROS_EC_ADC_CHIP_H
+#include "common.h"
+
+/*
+ * Maximum time we allow for an ADC conversion.
+ * NOTE:
+ * This setting must be less than "SLEEP_SET_HTIMER_DELAY_USEC" in clock.c
+ * or adding a sleep mask to prevent going in to deep sleep while ADC
+ * converting.
+ */
+#define ADC_TIMEOUT_US 248
+
/* Data structure to define ADC channel control registers. */
struct adc_ctrl_t {
volatile uint8_t *adc_ctrl;
diff --git a/chip/it83xx/clock.c b/chip/it83xx/clock.c
index b5638f2bbc..2dc45dbf5c 100644
--- a/chip/it83xx/clock.c
+++ b/chip/it83xx/clock.c
@@ -5,6 +5,7 @@
/* Clocks and power management settings */
+#include "adc_chip.h"
#include "clock.h"
#include "common.h"
#include "console.h"
@@ -27,6 +28,10 @@
#define SLEEP_SET_HTIMER_DELAY_USEC 250
#define SLEEP_FTIMER_SKIP_USEC (HOOK_TICK_INTERVAL * 2)
+#ifdef CONFIG_ADC
+BUILD_ASSERT(ADC_TIMEOUT_US < SLEEP_SET_HTIMER_DELAY_USEC);
+#endif
+
static timestamp_t sleep_mode_t0;
static timestamp_t sleep_mode_t1;
static int idle_doze_cnt;
diff --git a/chip/it83xx/intc.c b/chip/it83xx/intc.c
index a230fe6efb..cd4e147d01 100644
--- a/chip/it83xx/intc.c
+++ b/chip/it83xx/intc.c
@@ -121,6 +121,23 @@ void intc_cpu_int_group_12(void)
}
DECLARE_IRQ(CPU_INT_GROUP_12, intc_cpu_int_group_12, 2);
+void intc_cpu_int_group_7(void)
+{
+ /* Determine interrupt number. */
+ int intc_group_7 = intc_get_ec_int();
+
+ switch (intc_group_7) {
+#ifdef CONFIG_ADC
+ case IT83XX_IRQ_ADC:
+ adc_interrupt();
+ break;
+#endif
+ default:
+ break;
+ }
+}
+DECLARE_IRQ(CPU_INT_GROUP_7, intc_cpu_int_group_7, 2);
+
void intc_cpu_int_group_6(void)
{
/* Determine interrupt number. */
diff --git a/chip/it83xx/intc.h b/chip/it83xx/intc.h
index 129f5b63bf..642571bb26 100644
--- a/chip/it83xx/intc.h
+++ b/chip/it83xx/intc.h
@@ -18,6 +18,7 @@ void pm4_ibf_interrupt(void);
void pm5_ibf_interrupt(void);
void lpcrst_interrupt(enum gpio_signal signal);
void peci_interrupt(void);
+void adc_interrupt(void);
void i2c_interrupt(int port);
int gpio_clear_pending_interrupt(enum gpio_signal signal);
void clock_sleep_mode_wakeup_isr(void);
diff --git a/chip/it83xx/registers.h b/chip/it83xx/registers.h
index a90b5b72f2..47f06991d3 100644
--- a/chip/it83xx/registers.h
+++ b/chip/it83xx/registers.h
@@ -379,6 +379,9 @@
#define CPU_INT_GROUP_9 249
#define IT83XX_CPU_INT_IRQ_249 9
+#define CPU_INT_GROUP_7 248
+#define IT83XX_CPU_INT_IRQ_248 7
+
#define CPU_INT(irq) CONCAT2(IT83XX_CPU_INT_IRQ_, irq)
/* --- INTC --- */