summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Berg <alecaberg@chromium.org>2014-03-10 12:05:47 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-03-20 21:54:57 +0000
commitaa54cb96ee147f049e5da0e77ee71dd65a733401 (patch)
tree9180c680bda4c3fa9e123b1eaf44fc9419c4378a
parent89ec00d2dac42902d694849902bde851cc67606b (diff)
downloadchrome-ec-aa54cb96ee147f049e5da0e77ee71dd65a733401.tar.gz
accel: clapper: glimmer: Add support for accelerometer interrupt.
Adding in support for accelerometer interrupt for use currently in clapper and glimmer. This is disabled by default and can be enabled with CONFIG_ACCEL_INTERRUPTS. BUG=none BRANCH=rambi TEST=Manual test on a glimmer using accelint console command. On console enter: accelint 0 32 When you tap the lid, it should fire the interrupt and print msg to console. accelint 1 32 Tap the base and it will fire another interrupt. Change-Id: I0329112fdcae3c8adc0ca07e74fef7a591d4b9a1 Signed-off-by: Alec Berg <alecaberg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/190099 Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--board/clapper/board.c6
-rw-r--r--board/clapper/board.h4
-rw-r--r--board/glimmer/board.c4
-rw-r--r--board/glimmer/board.h2
-rw-r--r--common/console_output.c1
-rw-r--r--common/motion_sense.c18
-rw-r--r--driver/accel_kxcj9.c141
-rw-r--r--driver/accel_kxcj9.h12
-rw-r--r--include/config.h5
-rw-r--r--include/console.h1
-rw-r--r--include/motion_sense.h15
11 files changed, 196 insertions, 13 deletions
diff --git a/board/clapper/board.c b/board/clapper/board.c
index 63ad85b2a1..7b73cddbe2 100644
--- a/board/clapper/board.c
+++ b/board/clapper/board.c
@@ -72,6 +72,10 @@ const struct gpio_info gpio_list[] = {
button_interrupt},
{"BUTTON_VOLUME_UP_L", LM4_GPIO_B, (1<<0), GPIO_INT_BOTH,
button_interrupt},
+ {"ACCEL_INT_LID", LM4_GPIO_F, (1<<2), GPIO_INT_RISING,
+ accel_int_lid},
+ {"ACCEL_INT_BASE", LM4_GPIO_N, (1<<5), GPIO_INT_RISING,
+ accel_int_base},
/* Other inputs */
{"BOARD_VERSION1", LM4_GPIO_Q, (1<<5), GPIO_INPUT, NULL},
@@ -88,8 +92,6 @@ const struct gpio_info gpio_list[] = {
{"PP1000_S0IX_PGOOD", LM4_GPIO_H, (1<<6), GPIO_INPUT, NULL},
{"USB1_OC_L", LM4_GPIO_E, (1<<7), GPIO_INPUT, NULL},
{"USB2_OC_L", LM4_GPIO_E, (1<<0), GPIO_INPUT, NULL},
- {"ACCEL_INT0", LM4_GPIO_F, (1<<2), GPIO_INPUT, NULL},
- {"ACCEL_INT1", LM4_GPIO_N, (1<<5), GPIO_INPUT, NULL},
/* Outputs; all unasserted by default except for reset signals */
{"CPU_PROCHOT", LM4_GPIO_B, (1<<5), GPIO_OUT_LOW, NULL},
diff --git a/board/clapper/board.h b/board/clapper/board.h
index 85de78ed2c..58ea892eb0 100644
--- a/board/clapper/board.h
+++ b/board/clapper/board.h
@@ -89,6 +89,8 @@ enum gpio_signal {
GPIO_UART0_RX, /* UART0 RX input */
GPIO_BUTTON_VOLUME_DOWN_L, /* Volume down button */
GPIO_BUTTON_VOLUME_UP_L, /* Volume up button */
+ GPIO_ACCEL_INT_LID, /* Accelerometer interrupt lid */
+ GPIO_ACCEL_INT_BASE, /* Accelerometer interrupt base */
/* Other inputs */
GPIO_BOARD_VERSION1, /* Board version stuffing resistor 1 */
@@ -102,8 +104,6 @@ enum gpio_signal {
GPIO_PP1000_S0IX_PGOOD, /* Power good on 1.00V (S0iX supplies) */
GPIO_USB1_OC_L, /* USB port overcurrent warning */
GPIO_USB2_OC_L, /* USB port overcurrent warning */
- GPIO_ACCEL_INT0, /* Accelerometer interrupt 0 */
- GPIO_ACCEL_INT1, /* Accelerometer interrupt 1 */
/* Outputs */
GPIO_CPU_PROCHOT, /* Force CPU to think it's overheated */
diff --git a/board/glimmer/board.c b/board/glimmer/board.c
index 9b7a723a8e..6aa36cb277 100644
--- a/board/glimmer/board.c
+++ b/board/glimmer/board.c
@@ -88,6 +88,10 @@ const struct gpio_info gpio_list[] = {
button_interrupt},
{"BUTTON_VOLUME_UP_L", LM4_GPIO_B, (1<<0), GPIO_INT_BOTH,
button_interrupt},
+ {"ACCEL_INT_LID", LM4_GPIO_F, (1<<2), GPIO_INT_RISING,
+ accel_int_lid},
+ {"ACCEL_INT_BASE", LM4_GPIO_N, (1<<5), GPIO_INT_RISING,
+ accel_int_base},
/* Other inputs */
{"BOARD_VERSION1", LM4_GPIO_Q, (1<<5), GPIO_INPUT, NULL},
diff --git a/board/glimmer/board.h b/board/glimmer/board.h
index 16bf39b3a0..9e10dfba5c 100644
--- a/board/glimmer/board.h
+++ b/board/glimmer/board.h
@@ -93,6 +93,8 @@ enum gpio_signal {
GPIO_UART0_RX, /* UART0 RX input */
GPIO_BUTTON_VOLUME_DOWN_L, /* Volume down button */
GPIO_BUTTON_VOLUME_UP_L, /* Volume up button */
+ GPIO_ACCEL_INT_LID, /* Accelerometer interrupt lid */
+ GPIO_ACCEL_INT_BASE, /* Accelerometer interrupt base */
/* Other inputs */
GPIO_BOARD_VERSION1, /* Board version stuffing resistor 1 */
diff --git a/common/console_output.c b/common/console_output.c
index 4c6dde279c..b9db75c7fd 100644
--- a/common/console_output.c
+++ b/common/console_output.c
@@ -32,6 +32,7 @@ static uint32_t channel_mask_saved = CC_DEFAULT;
*/
static const char * const channel_names[] = {
"command",
+ "accel",
"charger",
"chipset",
"clock",
diff --git a/common/motion_sense.c b/common/motion_sense.c
index 7c7b8a55b5..651215ef34 100644
--- a/common/motion_sense.c
+++ b/common/motion_sense.c
@@ -243,6 +243,24 @@ void motion_sense_task(void)
}
}
+void accel_int_lid(enum gpio_signal signal)
+{
+ /*
+ * Print statement is here for testing with console accelint command.
+ * Remove print statement when interrupt is used for real.
+ */
+ CPRINTF("[%T Accelerometer wake-up interrupt occurred on lid]\n");
+}
+
+void accel_int_base(enum gpio_signal signal)
+{
+ /*
+ * Print statement is here for testing with console accelint command.
+ * Remove print statement when interrupt is used for real.
+ */
+ CPRINTF("[%T Accelerometer wake-up interrupt occurred on base]\n");
+}
+
/*****************************************************************************/
/* Console commands */
#ifdef CONFIG_CMD_LID_ANGLE
diff --git a/driver/accel_kxcj9.c b/driver/accel_kxcj9.c
index e6e7864175..a95d2c46b7 100644
--- a/driver/accel_kxcj9.c
+++ b/driver/accel_kxcj9.c
@@ -14,6 +14,9 @@
#include "timer.h"
#include "util.h"
+#define CPUTS(outstr) cputs(CC_ACCEL, outstr)
+#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args)
+
/* Range of the accelerometers: 2G, 4G, or 8G. */
static int sensor_range[ACCEL_COUNT] = {KXCJ9_GSEL_2G, KXCJ9_GSEL_2G};
@@ -111,6 +114,77 @@ int accel_write_datarate(const enum accel_id id, const int rate)
return ret;
}
+#ifdef CONFIG_ACCEL_INTERRUPTS
+int accel_set_interrupt(const enum accel_id id, unsigned int threshold)
+{
+ int ctrl1, tmp, ret;
+
+ /*
+ * TODO(crosbug.com/p/26884): This driver currently assumes only one
+ * task can call this function. If this isn't true anymore, need to
+ * protect with a mutex.
+ */
+
+ /*
+ * Read the current status of the control register and disable the
+ * sensor to allow for changing of critical parameters.
+ */
+ ret = raw_read8(accel_addr[id], KXCJ9_CTRL1, &ctrl1);
+ if (ret != EC_SUCCESS)
+ return ret;
+ ret = raw_write8(accel_addr[id], KXCJ9_CTRL1, ctrl1 & ~KXCJ9_CTRL1_PC1);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ /* Set interrupt timer to 1 so it wakes up immediately. */
+ ret = raw_write8(accel_addr[id], KXCJ9_WAKEUP_TIMER, 1);
+ if (ret != EC_SUCCESS)
+ goto error_enable_sensor;
+
+ /*
+ * Set threshold, note threshold register is in units of 16 counts, so
+ * first we need to divide by 16 to get the value to send.
+ */
+ threshold >>= 4;
+ ret = raw_write8(accel_addr[id], KXCJ9_WAKEUP_THRESHOLD, threshold);
+ if (ret != EC_SUCCESS)
+ goto error_enable_sensor;
+
+ /*
+ * Set interrupt enable register on sensor. Note that once this
+ * function is called once, the interrupt stays enabled and it is
+ * only necessary to clear KXCJ9_INT_REL to allow the next interrupt.
+ */
+ ret = raw_read8(accel_addr[id], KXCJ9_INT_CTRL1, &tmp);
+ if (ret != EC_SUCCESS)
+ goto error_enable_sensor;
+ if (!(tmp & KXCJ9_INT_CTRL1_IEN)) {
+ ret = raw_write8(accel_addr[id], KXCJ9_INT_CTRL1,
+ tmp | KXCJ9_INT_CTRL1_IEN);
+ if (ret != EC_SUCCESS)
+ goto error_enable_sensor;
+ }
+
+ /*
+ * Clear any pending interrupt on sensor by reading INT_REL register.
+ * Note: this register latches motion detected above threshold. Once
+ * latched, no interrupt can occur until this register is cleared.
+ */
+ ret = raw_read8(accel_addr[id], KXCJ9_INT_REL, &tmp);
+
+error_enable_sensor:
+ /* Re-enable accelerometer. */
+ if (raw_write8(accel_addr[id], KXCJ9_CTRL1, ctrl1 | KXCJ9_CTRL1_PC1) !=
+ EC_SUCCESS) {
+ /* Cannot re-enable accel, print warning and return an error. */
+ CPRINTF("[%T Error trying to enable accelerometer %d]\n", id);
+ return EC_ERROR_UNKNOWN;
+ }
+
+ return ret;
+}
+#endif
+
int accel_read(enum accel_id id, int *x_acc, int *y_acc, int *z_acc)
{
uint8_t acc[6];
@@ -166,7 +240,7 @@ int accel_read(enum accel_id id, int *x_acc, int *y_acc, int *z_acc)
int accel_init(enum accel_id id)
{
int ret = EC_SUCCESS;
- int cnt = 0, ctrl2;
+ int cnt = 0, ctrl1, ctrl2;
/* Check for valid id. */
if (id < 0 || id >= ACCEL_COUNT)
@@ -197,14 +271,37 @@ int accel_init(enum accel_id id)
msleep(10);
}
- /* Enable accelerometer, 12-bit resolution mode, +/- 2G range.*/
- ret |= raw_write8(accel_addr[id], KXCJ9_CTRL1,
- KXCJ9_CTRL1_PC1 | sensor_resolution[id] |
- sensor_range[id]);
+#ifdef CONFIG_ACCEL_INTERRUPTS
+ /* Set interrupt polarity to rising edge and keep interrupt disabled. */
+ ret |= raw_write8(accel_addr[id], KXCJ9_INT_CTRL1, KXCJ9_INT_CTRL1_IEA);
+
+ /* Set output data rate for wake-up interrupt function. */
+ ret |= raw_write8(accel_addr[id], KXCJ9_CTRL2, KXCJ9_OWUF_100_0HZ);
+
+ /* Set interrupt to trigger on motion on any axis. */
+ ret |= raw_write8(accel_addr[id], KXCJ9_INT_CTRL2,
+ KXCJ9_INT_SRC2_XNWU | KXCJ9_INT_SRC2_XPWU |
+ KXCJ9_INT_SRC2_YNWU | KXCJ9_INT_SRC2_YPWU |
+ KXCJ9_INT_SRC2_ZNWU | KXCJ9_INT_SRC2_ZPWU);
+
+ /*
+ * Enable accel interrupts. Note: accels will not initiate an interrupt
+ * until interrupt enable bit in KXCJ9_INT_CTRL1 is set on the device.
+ */
+ gpio_enable_interrupt(GPIO_ACCEL_INT_LID);
+ gpio_enable_interrupt(GPIO_ACCEL_INT_BASE);
+#endif
/* Set output data rate. */
- ret |= raw_write8(accel_addr[id], KXCJ9_DATA_CTRL,
- sensor_datarate[id]);
+ ret |= raw_write8(accel_addr[id], KXCJ9_DATA_CTRL, sensor_datarate[id]);
+
+ /* Set resolution and range and enable sensor. */
+ ctrl1 = sensor_resolution[id] | sensor_range[id] | KXCJ9_CTRL1_PC1;
+#ifdef CONFIG_ACCEL_INTERRUPTS
+ /* Enable wake up (motion detect) functionality. */
+ ctrl1 |= KXCJ9_CTRL1_WUFE;
+#endif
+ ret = raw_write8(accel_addr[id], KXCJ9_CTRL1, ctrl1);
return ret;
}
@@ -213,7 +310,6 @@ int accel_init(enum accel_id id)
/*****************************************************************************/
/* Console commands */
-
#ifdef CONFIG_CMD_ACCELS
static int command_read_accelerometer(int argc, char **argv)
{
@@ -273,4 +369,33 @@ static int command_write_accelerometer(int argc, char **argv)
DECLARE_CONSOLE_COMMAND(accelwrite, command_write_accelerometer,
"addr reg data",
"Write to accelerometer at slave address addr", NULL);
+
+#ifdef CONFIG_ACCEL_INTERRUPTS
+static int command_accelerometer_interrupt(int argc, char **argv)
+{
+ char *e;
+ int id, thresh;
+
+ if (argc != 3)
+ return EC_ERROR_PARAM_COUNT;
+
+ /* First argument is id. */
+ id = strtoi(argv[1], &e, 0);
+ if (*e || id < 0 || id >= ACCEL_COUNT)
+ return EC_ERROR_PARAM1;
+
+ /* Second argument is interrupt threshold. */
+ thresh = strtoi(argv[2], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM2;
+
+ accel_set_interrupt(id, thresh);
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(accelint, command_accelerometer_interrupt,
+ "id threshold",
+ "Write interrupt threshold", NULL);
+#endif /* CONFIG_ACCEL_INTERRUPTS */
+
#endif /* CONFIG_CMD_ACCELS */
diff --git a/driver/accel_kxcj9.h b/driver/accel_kxcj9.h
index 9451421be5..e35386d330 100644
--- a/driver/accel_kxcj9.h
+++ b/driver/accel_kxcj9.h
@@ -129,4 +129,16 @@ int accel_write_resolution(const enum accel_id id, const int res);
*/
int accel_write_datarate(const enum accel_id id, const int rate);
+#ifdef CONFIG_ACCEL_INTERRUPTS
+/**
+ * Setup a one-time accel interrupt. If the threshold is low enough, the
+ * interrupt may trigger due simply to noise and not any real motion. If the
+ * threshold is 0, the interrupt will fire immediately.
+ *
+ * @param id Target accelerometer
+ * @param threshold Threshold for interrupt in units of counts.
+ */
+int accel_set_interrupt(const enum accel_id id, unsigned int threshold);
+#endif
+
#endif /* __CROS_EC_ACCEL_KXCJ9_H */
diff --git a/include/config.h b/include/config.h
index 224910cce2..aed9085202 100644
--- a/include/config.h
+++ b/include/config.h
@@ -36,9 +36,12 @@
* BOARD_*, CHIP_*, and CHIP_FAMILY_*.
*/
-/* Use to enable EC console functions for calibrating accelerometers. */
+/* Enable EC console functions for calibrating accelerometers. */
#undef CONFIG_ACCEL_CALIBRATE
+/* Enable accelerometer interrupts. */
+#undef CONFIG_ACCEL_INTERRUPTS
+
/* Specify type of accelerometers attached. */
#undef CONFIG_ACCEL_KXCJ9
diff --git a/include/console.h b/include/console.h
index 41bc9decbd..8106e54f56 100644
--- a/include/console.h
+++ b/include/console.h
@@ -28,6 +28,7 @@ struct console_command {
enum console_channel {
CC_COMMAND = 0, /* Console command (interactive I/O). Use this only
* inside a console command routine. */
+ CC_ACCEL,
CC_CHARGER,
CC_CHIPSET,
CC_CLOCK,
diff --git a/include/motion_sense.h b/include/motion_sense.h
index dda02f19f9..08aefbcc0b 100644
--- a/include/motion_sense.h
+++ b/include/motion_sense.h
@@ -8,6 +8,7 @@
#ifndef __CROS_EC_MOTION_SENSE_H
#define __CROS_EC_MOTION_SENSE_H
+#include "gpio.h"
#include "math_util.h"
/**
@@ -73,5 +74,19 @@ void motion_get_accel_lid(vector_3_t *v, int adjusted);
void motion_get_accel_base(vector_3_t *v);
#endif
+/**
+ * Interrupt function for lid accelerometer.
+ *
+ * @param signal GPIO signal that caused interrupt
+ */
+void accel_int_lid(enum gpio_signal signal);
+
+/**
+ * Interrupt function for base accelerometer.
+ *
+ * @param signal GPIO signal that caused interrupt
+ */
+void accel_int_base(enum gpio_signal signal);
+
#endif /* __CROS_EC_MOTION_SENSE_H */