diff options
-rw-r--r-- | chip/it83xx/adc.c | 100 | ||||
-rw-r--r-- | chip/it83xx/adc_chip.h | 13 | ||||
-rw-r--r-- | chip/it83xx/clock.c | 5 | ||||
-rw-r--r-- | chip/it83xx/intc.c | 17 | ||||
-rw-r--r-- | chip/it83xx/intc.h | 1 | ||||
-rw-r--r-- | chip/it83xx/registers.h | 3 |
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 --- */ |