summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVic (Chun-Ju) Yang <victoryang@chromium.org>2013-12-19 14:51:06 +0800
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2013-12-20 05:08:02 +0000
commit1b1d2e999c7349e896121abec9515270a76072f9 (patch)
treea39a10a56111ba2618da232771220bc685d4ef75
parentc455d255076f50b217f35115f2591bc5ce5f0c69 (diff)
downloadchrome-ec-1b1d2e999c7349e896121abec9515270a76072f9.tar.gz
mec1322: ADC driver
ADC driver for MEC1322 with ADC interrupt support. BUG=chrome-os-partner:24107 TEST=Read single channel TEST=Read all channels BRANCH=None Change-Id: I89d196c7fd78e736575e2c368b65cfb1ec651004 Signed-off-by: Vic (Chun-Ju) Yang <victoryang@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/180832
-rw-r--r--board/mec1322_evb/board.c11
-rw-r--r--board/mec1322_evb/board.h10
-rw-r--r--chip/mec1322/adc.c107
-rw-r--r--chip/mec1322/adc_chip.h33
-rw-r--r--chip/mec1322/build.mk1
-rw-r--r--chip/mec1322/registers.h10
6 files changed, 172 insertions, 0 deletions
diff --git a/board/mec1322_evb/board.c b/board/mec1322_evb/board.c
index 6a26913ca8..5d7dd42bb9 100644
--- a/board/mec1322_evb/board.c
+++ b/board/mec1322_evb/board.c
@@ -4,6 +4,8 @@
*/
/* MEC1322 eval board-specific configuration */
+#include "adc.h"
+#include "adc_chip.h"
#include "fan.h"
#include "gpio.h"
#include "i2c.h"
@@ -44,6 +46,15 @@ const struct gpio_alt_func gpio_alt_funcs[] = {
};
const int gpio_alt_funcs_count = ARRAY_SIZE(gpio_alt_funcs);
+/* ADC channels */
+const struct adc_t adc_channels[] = {
+ [ADC_CH_1] = {"ADC1", 1, 1, 0, MEC1322_ADC_CH(1)},
+ [ADC_CH_2] = {"ADC2", 1, 1, 0, MEC1322_ADC_CH(2)},
+ [ADC_CH_3] = {"ADC3", 1, 1, 0, MEC1322_ADC_CH(3)},
+ [ADC_CH_4] = {"ADC4", 1, 1, 0, MEC1322_ADC_CH(4)},
+};
+BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
+
/* Physical fans. These are logically separate from pwm_channels. */
const struct fan_t fans[] = {
{.flags = FAN_USE_RPM_MODE,
diff --git a/board/mec1322_evb/board.h b/board/mec1322_evb/board.h
index fa4f53609c..a4142a9fdc 100644
--- a/board/mec1322_evb/board.h
+++ b/board/mec1322_evb/board.h
@@ -12,6 +12,7 @@
#define CONFIG_SYSTEM_UNLOCKED /* Allow dangerous commands */
#define CONFIG_WATCHDOG_HELP
#define CONFIG_FANS 1
+#define CONFIG_ADC
/* Modules we want to exclude */
#undef CONFIG_EEPROM
@@ -23,6 +24,15 @@
#ifndef __ASSEMBLER__
+enum adc_channel {
+ ADC_CH_1 = 0,
+ ADC_CH_2,
+ ADC_CH_3,
+ ADC_CH_4,
+
+ ADC_CH_COUNT
+};
+
/* GPIO signal list */
enum gpio_signal {
GPIO_LED1 = 0,
diff --git a/chip/mec1322/adc.c b/chip/mec1322/adc.c
new file mode 100644
index 0000000000..e000e01cce
--- /dev/null
+++ b/chip/mec1322/adc.c
@@ -0,0 +1,107 @@
+/* Copyright (c) 2013 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.
+ */
+
+#include "adc.h"
+#include "adc_chip.h"
+#include "common.h"
+#include "console.h"
+#include "hooks.h"
+#include "registers.h"
+#include "task.h"
+#include "timer.h"
+#include "util.h"
+
+/*
+ * Conversion on a single channel takes less than 12 ms. Set timeout to
+ * 15 ms so that we have a 3-ms margin.
+ */
+#define ADC_SINGLE_READ_TIME 15000
+
+struct mutex adc_lock;
+
+static task_id_t task_waiting;
+
+static int start_single_and_wait(int timeout)
+{
+ int event;
+
+ task_waiting = task_get_current();
+
+ /* Start conversion */
+ MEC1322_ADC_CTRL |= 1 << 1;
+
+ /* Wait for interrupt */
+ event = task_wait_event(timeout);
+ task_waiting = TASK_ID_INVALID;
+ return event != TASK_EVENT_TIMER;
+}
+
+int adc_read_channel(enum adc_channel ch)
+{
+ const struct adc_t *adc = adc_channels + ch;
+ int value;
+
+ mutex_lock(&adc_lock);
+
+ MEC1322_ADC_SINGLE = 1 << adc->channel;
+
+ if (start_single_and_wait(ADC_SINGLE_READ_TIME))
+ value = MEC1322_ADC_READ(adc->channel) * adc->factor_mul /
+ adc->factor_div + adc->shift;
+ else
+ value = ADC_READ_ERROR;
+
+ mutex_unlock(&adc_lock);
+ return value;
+}
+
+int adc_read_all_channels(int *data)
+{
+ int i;
+ int ret = EC_SUCCESS;
+ const struct adc_t *adc;
+
+ mutex_lock(&adc_lock);
+
+ MEC1322_ADC_SINGLE = 0;
+ for (i = 0; i < ADC_CH_COUNT; ++i)
+ MEC1322_ADC_SINGLE |= 1 << adc_channels[i].channel;
+
+ if (!start_single_and_wait(ADC_SINGLE_READ_TIME * ADC_CH_COUNT))
+ goto exit_all_channels;
+
+ for (i = 0; i < ADC_CH_COUNT; ++i) {
+ adc = adc_channels + i;
+ data[i] = MEC1322_ADC_READ(adc->channel) * adc->factor_mul /
+ adc->factor_div + adc->shift;
+ }
+
+exit_all_channels:
+ mutex_unlock(&adc_lock);
+ return ret;
+}
+
+static void adc_init(void)
+{
+ /* Activate ADC module */
+ MEC1322_ADC_CTRL |= 1 << 0;
+
+ /* Enable interrupt */
+ task_waiting = TASK_ID_INVALID;
+ MEC1322_INT_ENABLE(17) |= 1 << 10;
+ MEC1322_INT_BLK_EN |= 1 << 17;
+ task_enable_irq(MEC1322_IRQ_ADC_SNGL);
+}
+DECLARE_HOOK(HOOK_INIT, adc_init, HOOK_PRIO_DEFAULT);
+
+static void adc_interrupt(void)
+{
+ /* Clear interrupt status bit */
+ MEC1322_ADC_CTRL |= 1 << 7;
+
+ if (task_waiting != TASK_ID_INVALID)
+ task_wake(task_waiting);
+}
+DECLARE_IRQ(MEC1322_IRQ_ADC_SNGL, adc_interrupt, 2);
diff --git a/chip/mec1322/adc_chip.h b/chip/mec1322/adc_chip.h
new file mode 100644
index 0000000000..37e7f477e6
--- /dev/null
+++ b/chip/mec1322/adc_chip.h
@@ -0,0 +1,33 @@
+/* Copyright (c) 2013 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.
+ */
+
+/* MEC1322-specific ADC module for Chrome EC */
+
+#ifndef __CROS_EC_ADC_CHIP_H
+#define __CROS_EC_ADC_CHIP_H
+
+/* 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[];
+
+/* Minimum and maximum values returned by adc_read_channel(). */
+#define ADC_READ_MIN 0
+#define ADC_READ_MAX 1023
+
+/* Just plain id mapping for code readability */
+#define MEC1322_ADC_CH(x) (x)
+
+#endif /* __CROS_EC_ADC_CHIP_H */
diff --git a/chip/mec1322/build.mk b/chip/mec1322/build.mk
index 60376d1a5f..5481581ebe 100644
--- a/chip/mec1322/build.mk
+++ b/chip/mec1322/build.mk
@@ -13,6 +13,7 @@ CFLAGS_CPU+=-march=armv7e-m -mcpu=cortex-m4
# Required chip modules
chip-y=clock.o gpio.o hwtimer.o system.o uart.o jtag.o
+chip-$(CONFIG_ADC)+=adc.o
chip-$(CONFIG_FANS)+=fan.o
chip-$(CONFIG_I2C)+=i2c.o
chip-$(CONFIG_LPC)+=lpc.o
diff --git a/chip/mec1322/registers.h b/chip/mec1322/registers.h
index 14c1aebfff..5a5aa98f2b 100644
--- a/chip/mec1322/registers.h
+++ b/chip/mec1322/registers.h
@@ -262,6 +262,16 @@ static inline uintptr_t gpio_port_base(int port_id)
#define MEC1322_KS_EXT_CTRL REG32(MEC1322_KS_BASE + 0x14)
+/* ADC */
+#define MEC1322_ADC_BASE 0x40007c00
+#define MEC1322_ADC_CTRL REG32(MEC1322_ADC_BASE + 0x0)
+#define MEC1322_ADC_DELAY REG32(MEC1322_ADC_BASE + 0x4)
+#define MEC1322_ADC_STS REG32(MEC1322_ADC_BASE + 0x8)
+#define MEC1322_ADC_SINGLE REG32(MEC1322_ADC_BASE + 0xc)
+#define MEC1322_ADC_REPEAT REG32(MEC1322_ADC_BASE + 0x10)
+#define MEC1322_ADC_READ(x) REG32(MEC1322_ADC_BASE + 0x14 + (x) * 0x4)
+
+
/* IRQ Numbers */
#define MEC1322_IRQ_I2C_0 0
#define MEC1322_IRQ_I2C_1 1