diff options
author | Alec Berg <alecaberg@chromium.org> | 2014-03-10 12:05:47 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-03-26 19:31:25 +0000 |
commit | eb1406644716d6c3c87fdeea4551eb6ea37be649 (patch) | |
tree | 8f5209485fd585aa08f384bca2dd2f9c5d3982ae | |
parent | 9b420804d88a7adf8a1ded8bd12e52e1aa8ddd84 (diff) | |
download | chrome-ec-stabilize-5696.B.tar.gz |
accel: clapper: glimmer: Add support for accelerometer interrupt.stabilize-5696.B
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: Iaab324945e34d527140399ec4f06efd812a62840
Original-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>
Reviewed-on: https://chromium-review.googlesource.com/191549
-rw-r--r-- | common/console_output.c | 1 | ||||
-rw-r--r-- | common/motion_sense.c | 18 | ||||
-rw-r--r-- | driver/accel_kxcj9.c | 141 | ||||
-rw-r--r-- | driver/accel_kxcj9.h | 12 | ||||
-rw-r--r-- | include/config.h | 5 | ||||
-rw-r--r-- | include/console.h | 1 | ||||
-rw-r--r-- | include/motion_sense.h | 15 |
7 files changed, 184 insertions, 9 deletions
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 5982a38fdc..300126a6cf 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 */ |