summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/host/board.h2
-rw-r--r--common/motion_sense.c176
-rw-r--r--driver/accel_kxcj9.c238
-rw-r--r--driver/accel_kxcj9.h30
-rw-r--r--include/accelerometer.h50
-rw-r--r--include/ec_commands.h126
-rw-r--r--test/math_util.c27
-rw-r--r--test/motion_sense.c25
-rw-r--r--util/ectool.c221
9 files changed, 789 insertions, 106 deletions
diff --git a/board/host/board.h b/board/host/board.h
index 130bdcd385..5ab078292f 100644
--- a/board/host/board.h
+++ b/board/host/board.h
@@ -54,8 +54,8 @@ enum adc_channel {
/* Identifiers for each accelerometer used. */
enum accel_id {
- ACCEL_LID,
ACCEL_BASE,
+ ACCEL_LID,
/* Number of accelerometers. */
ACCEL_COUNT
diff --git a/common/motion_sense.c b/common/motion_sense.c
index 5dad6db1cf..8629fa7588 100644
--- a/common/motion_sense.c
+++ b/common/motion_sense.c
@@ -30,9 +30,13 @@ static vector_3_t acc_lid_host, acc_base_host;
static float lid_angle_deg;
static int lid_angle_is_reliable;
+/* Bounds for setting the sensor polling interval. */
+#define MIN_POLLING_INTERVAL_MS 5
+#define MAX_POLLING_INTERVAL_MS 1000
+
/* Accelerometer polling intervals based on chipset state. */
-#define ACCEL_INTERVAL_AP_ON_MS 10
-#define ACCEL_INTERVAL_AP_SUSPEND_MS 100
+static int accel_interval_ap_on_ms = 10;
+static const int accel_interval_ap_suspend_ms = 100;
/*
* Angle threshold for how close the hinge aligns with gravity before
@@ -43,7 +47,7 @@ static int lid_angle_is_reliable;
#define HINGE_ALIGNED_WITH_GRAVITY_THRESHOLD 0.96593F
/* Sampling interval for measuring acceleration and calculating lid angle. */
-static int accel_interval_ms = ACCEL_INTERVAL_AP_SUSPEND_MS;
+static int accel_interval_ms;
#ifdef CONFIG_CMD_LID_ANGLE
static int accel_disp;
@@ -153,19 +157,17 @@ void motion_get_accel_base(vector_3_t *v)
}
#endif
-/* Lower accel polling rate on chipset suspend. */
-static void set_slow_accel_polling(void)
+static void set_ap_suspend_polling(void)
{
- accel_interval_ms = ACCEL_INTERVAL_AP_SUSPEND_MS;
+ accel_interval_ms = accel_interval_ap_suspend_ms;
}
-DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, set_slow_accel_polling, HOOK_PRIO_DEFAULT);
+DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, set_ap_suspend_polling, HOOK_PRIO_DEFAULT);
-/* Raise accel polling rate on chipset resume. */
-static void set_fast_accel_polling(void)
+static void set_ap_on_polling(void)
{
- accel_interval_ms = ACCEL_INTERVAL_AP_ON_MS;
+ accel_interval_ms = accel_interval_ap_on_ms;
}
-DECLARE_HOOK(HOOK_CHIPSET_RESUME, set_fast_accel_polling, HOOK_PRIO_DEFAULT);
+DECLARE_HOOK(HOOK_CHIPSET_RESUME, set_ap_on_polling, HOOK_PRIO_DEFAULT);
void motion_sense_task(void)
@@ -180,6 +182,14 @@ void motion_sense_task(void)
lpc_status = host_get_memmap(EC_MEMMAP_ACC_STATUS);
lpc_data = (uint16_t *)host_get_memmap(EC_MEMMAP_ACC_DATA);
+ /*
+ * TODO(crosbug.com/p/27320): The motion_sense task currently assumes
+ * one configuration of motion sensors. Namely, it assumes there is
+ * one accel in the base, one in the lid, and they both use the same
+ * driver. Eventually, all of these assumptions will have to be removed
+ * when we have other configurations of motion sensors.
+ */
+
/* Initialize accelerometers. */
ret = accel_init(ACCEL_LID);
ret |= accel_init(ACCEL_BASE);
@@ -191,6 +201,17 @@ void motion_sense_task(void)
return;
}
+ /* Initialize sampling interval. */
+ accel_interval_ms = accel_interval_ap_suspend_ms;
+
+ /* Set default accelerometer parameters. */
+ accel_set_range(ACCEL_LID, 2, 1);
+ accel_set_range(ACCEL_BASE, 2, 1);
+ accel_set_resolution(ACCEL_LID, 12, 1);
+ accel_set_resolution(ACCEL_BASE, 12, 1);
+ accel_set_datarate(ACCEL_LID, 100000, 1);
+ accel_set_datarate(ACCEL_BASE, 100000, 1);
+
/* Write to status byte to represent that accelerometers are present. */
*lpc_status |= EC_MEMMAP_ACC_STATUS_PRESENCE_BIT;
@@ -299,6 +320,139 @@ void accel_int_base(enum gpio_signal signal)
}
/*****************************************************************************/
+/* Host commands */
+
+static int host_cmd_motion_sense(struct host_cmd_handler_args *args)
+{
+ const struct ec_params_motion_sense *in = args->params;
+ struct ec_response_motion_sense *out = args->response;
+ int id, data;
+
+ switch (in->cmd) {
+ case MOTIONSENSE_CMD_DUMP:
+ /*
+ * TODO(crosbug.com/p/27320): Need to remove hard coding and
+ * use some motion_sense data structure from the board file to
+ * help fill in this response.
+ */
+ out->dump.sensor_presence[0] = 1;
+ out->dump.sensor_presence[1] = 1;
+ out->dump.sensor_presence[2] = 0;
+ out->dump.data[0] = acc_base_host[X];
+ out->dump.data[1] = acc_base_host[Y];
+ out->dump.data[2] = acc_base_host[Z];
+ out->dump.data[3] = acc_lid_host[X];
+ out->dump.data[4] = acc_lid_host[Y];
+ out->dump.data[5] = acc_lid_host[Z];
+
+ args->response_size = sizeof(out->dump);
+ break;
+
+ case MOTIONSENSE_CMD_INFO:
+ /*
+ * TODO(crosbug.com/p/27320): Need to remove hard coding and
+ * use some motion_sense data structure from the board file to
+ * help fill in this response.
+ */
+ switch (in->sensor_odr.sensor_num) {
+ case ACCEL_BASE:
+ out->info.type = MOTIONSENSE_TYPE_ACCEL;
+ out->info.location = MOTIONSENSE_LOC_BASE;
+ out->info.chip = MOTIONSENSE_CHIP_KXCJ9;
+ break;
+ case ACCEL_LID:
+ out->info.type = MOTIONSENSE_TYPE_ACCEL;
+ out->info.location = MOTIONSENSE_LOC_LID;
+ out->info.chip = MOTIONSENSE_CHIP_KXCJ9;
+ break;
+ default:
+ return EC_RES_INVALID_PARAM;
+ }
+
+ args->response_size = sizeof(out->info);
+ break;
+
+ case MOTIONSENSE_CMD_EC_RATE:
+ /*
+ * Set new sensor sampling rate when AP is on, if the data arg
+ * has a value.
+ */
+ if (in->ec_rate.data != EC_MOTION_SENSE_NO_VALUE) {
+ if (in->ec_rate.data >= MIN_POLLING_INTERVAL_MS &&
+ in->ec_rate.data <= MAX_POLLING_INTERVAL_MS) {
+ accel_interval_ap_on_ms = in->ec_rate.data;
+ accel_interval_ms = accel_interval_ap_on_ms;
+ } else {
+ CPRINTF("[%T MS bad EC sampling rate %d]\n",
+ in->ec_rate.data);
+ return EC_RES_INVALID_PARAM;
+ }
+ }
+
+ out->ec_rate.ret = accel_interval_ap_on_ms;
+
+ args->response_size = sizeof(out->ec_rate);
+ break;
+
+ case MOTIONSENSE_CMD_SENSOR_ODR:
+ /* Verify sensor number is valid. */
+ if (in->sensor_odr.sensor_num >= ACCEL_COUNT)
+ return EC_RES_INVALID_PARAM;
+
+ id = in->sensor_odr.sensor_num;
+
+ /* Set new datarate if the data arg has a value. */
+ if (in->sensor_odr.data != EC_MOTION_SENSE_NO_VALUE) {
+ if (accel_set_datarate(id, in->sensor_odr.data,
+ in->sensor_odr.roundup) != EC_SUCCESS) {
+ CPRINTF("[%T MS bad sensor rate %d]\n",
+ in->sensor_odr.data);
+ return EC_RES_INVALID_PARAM;
+ }
+ }
+
+ accel_get_datarate(id, &data);
+ out->sensor_odr.ret = data;
+
+ args->response_size = sizeof(out->sensor_odr);
+ break;
+
+ case MOTIONSENSE_CMD_SENSOR_RANGE:
+ /* Verify sensor number is valid. */
+ if (in->sensor_odr.sensor_num >= ACCEL_COUNT)
+ return EC_RES_INVALID_PARAM;
+
+ id = in->sensor_odr.sensor_num;
+
+ /* Set new datarate if the data arg has a value. */
+ if (in->sensor_range.data != EC_MOTION_SENSE_NO_VALUE) {
+ if (accel_set_range(id, in->sensor_range.data,
+ in->sensor_range.roundup) != EC_SUCCESS) {
+ CPRINTF("[%T MS bad sensor range %d]\n",
+ in->sensor_range.data);
+ return EC_RES_INVALID_PARAM;
+ }
+ }
+
+ accel_get_range(id, &data);
+ out->sensor_range.ret = data;
+
+ args->response_size = sizeof(out->sensor_range);
+ break;
+
+ default:
+ CPRINTF("[%T MS bad cmd 0x%x]\n", in->cmd);
+ return EC_RES_INVALID_PARAM;
+ }
+
+ return EC_RES_SUCCESS;
+}
+
+DECLARE_HOST_COMMAND(EC_CMD_MOTION_SENSE_CMD,
+ host_cmd_motion_sense,
+ EC_VER_MASK(0));
+
+/*****************************************************************************/
/* Console commands */
#ifdef CONFIG_CMD_LID_ANGLE
static int command_ctrl_print_lid_angle_calcs(int argc, char **argv)
diff --git a/driver/accel_kxcj9.c b/driver/accel_kxcj9.c
index 78405a039f..76aee6f1b5 100644
--- a/driver/accel_kxcj9.c
+++ b/driver/accel_kxcj9.c
@@ -21,19 +21,90 @@
/* Number of times to attempt to enable sensor before giving up. */
#define SENSOR_ENABLE_ATTEMPTS 3
-/* Range of the accelerometers: 2G, 4G, or 8G. */
-static int sensor_range[ACCEL_COUNT] = {KXCJ9_GSEL_2G, KXCJ9_GSEL_2G};
+/*
+ * Struct for pairing an engineering value with the register value for a
+ * parameter.
+ */
+struct accel_param_pair {
+ int val; /* Value in engineering units. */
+ int reg; /* Corresponding register value. */
+};
+
+/* List of range values in +/-G's and their associated register values. */
+const struct accel_param_pair ranges[] = {
+ {2, KXCJ9_GSEL_2G},
+ {4, KXCJ9_GSEL_4G},
+ {8, KXCJ9_GSEL_8G_14BIT}
+};
+
+/* List of resolution values in bits and their associated register values. */
+const struct accel_param_pair resolutions[] = {
+ {8, KXCJ9_RES_8BIT},
+ {12, KXCJ9_RES_12BIT}
+};
+
+/* List of ODR values in mHz and their associated register values. */
+const struct accel_param_pair datarates[] = {
+ {781, KXCJ9_OSA_0_781HZ},
+ {1563, KXCJ9_OSA_1_563HZ},
+ {3125, KXCJ9_OSA_3_125HZ},
+ {6250, KXCJ9_OSA_6_250HZ},
+ {12500, KXCJ9_OSA_12_50HZ},
+ {25000, KXCJ9_OSA_25_00HZ},
+ {50000, KXCJ9_OSA_50_00HZ},
+ {100000, KXCJ9_OSA_100_0HZ},
+ {200000, KXCJ9_OSA_200_0HZ},
+ {400000, KXCJ9_OSA_400_0HZ},
+ {800000, KXCJ9_OSA_800_0HZ},
+ {1600000, KXCJ9_OSA_1600_HZ}
+};
+
+/* Current range of each accelerometer. The value is an index into ranges[]. */
+static int sensor_range[ACCEL_COUNT] = {0, 0};
+
+/*
+ * Current resolution of each accelerometer. The value is an index into
+ * resolutions[].
+ */
+static int sensor_resolution[ACCEL_COUNT] = {1, 1};
-/* Resolution: KXCJ9_RES_12BIT or KXCJ9_RES_12BIT. */
-static int sensor_resolution[ACCEL_COUNT] = {KXCJ9_RES_12BIT, KXCJ9_RES_12BIT};
+/*
+ * Current output data rate of each accelerometer. The value is an index into
+ * datarates[].
+ */
+static int sensor_datarate[ACCEL_COUNT] = {6, 6};
-/* Output data rate: KXCJ9_OSA_* ranges from 0.781Hz to 1600Hz. */
-static int sensor_datarate[ACCEL_COUNT] = {KXCJ9_OSA_100_0HZ,
- KXCJ9_OSA_100_0HZ};
static struct mutex accel_mutex[ACCEL_COUNT];
/**
+ * Find index into a accel_param_pair that matches the given engineering value
+ * passed in. The round_up flag is used to specify whether to round up or down.
+ * Note, this function always returns a valid index. If the request is
+ * outside the range of values, it returns the closest valid index.
+ */
+static int find_param_index(const int eng_val, const int round_up,
+ const struct accel_param_pair *pairs, const int size)
+{
+ int i;
+
+ /* Linear search for index to match. */
+ for (i = 0; i < size - 1; i++) {
+ if (eng_val <= pairs[i].val)
+ return i;
+
+ if (eng_val < pairs[i+1].val) {
+ if (round_up)
+ return i + 1;
+ else
+ return i;
+ }
+ }
+
+ return i;
+}
+
+/**
* Read register from accelerometer.
*/
static int raw_read8(const int addr, const int reg, int *data_ptr)
@@ -125,22 +196,16 @@ static int enable_sensor(const enum accel_id id, const int ctrl1)
return ret;
}
-
-int accel_write_range(const enum accel_id id, const int range)
+int accel_set_range(const enum accel_id id, const int range, const int rnd)
{
- int ret, ctrl1, ctrl1_new;
+ int ret, ctrl1, ctrl1_new, index;
/* Check for valid id. */
if (id < 0 || id >= ACCEL_COUNT)
return EC_ERROR_INVAL;
- /*
- * Verify that the input range is valid. Note that we currently
- * don't support the 8G with 14-bit resolution mode.
- */
- if (range != KXCJ9_GSEL_2G && range != KXCJ9_GSEL_4G &&
- range != KXCJ9_GSEL_8G)
- return EC_ERROR_INVAL;
+ /* Find index for interface pair matching the specified range. */
+ index = find_param_index(range, rnd, ranges, ARRAY_SIZE(ranges));
/* Disable the sensor to allow for changing of critical parameters. */
ret = disable_sensor(id, &ctrl1);
@@ -148,12 +213,12 @@ int accel_write_range(const enum accel_id id, const int range)
return ret;
/* Determine new value of CTRL1 reg and attempt to write it. */
- ctrl1_new = (ctrl1 & ~KXCJ9_GSEL_ALL) | range;
+ ctrl1_new = (ctrl1 & ~KXCJ9_GSEL_ALL) | ranges[index].reg;
ret = raw_write8(accel_addr[id], KXCJ9_CTRL1, ctrl1_new);
/* If successfully written, then save the range. */
if (ret == EC_SUCCESS) {
- sensor_range[id] = range;
+ sensor_range[id] = index;
ctrl1 = ctrl1_new;
}
@@ -164,30 +229,40 @@ int accel_write_range(const enum accel_id id, const int range)
return ret;
}
-int accel_write_resolution(const enum accel_id id, const int res)
+int accel_get_range(const enum accel_id id, int * const range)
{
- int ret, ctrl1, ctrl1_new;
-
/* Check for valid id. */
if (id < 0 || id >= ACCEL_COUNT)
return EC_ERROR_INVAL;
- /* Check that resolution input is valid. */
- if (res != KXCJ9_RES_12BIT && res != KXCJ9_RES_8BIT)
+ *range = ranges[sensor_range[id]].val;
+ return EC_SUCCESS;
+}
+
+int accel_set_resolution(const enum accel_id id, const int res, const int rnd)
+{
+ int ret, ctrl1, ctrl1_new, index;
+
+ /* Check for valid id. */
+ if (id < 0 || id >= ACCEL_COUNT)
return EC_ERROR_INVAL;
+ /* Find index for interface pair matching the specified resolution. */
+ index = find_param_index(res, rnd, resolutions,
+ ARRAY_SIZE(resolutions));
+
/* Disable the sensor to allow for changing of critical parameters. */
ret = disable_sensor(id, &ctrl1);
if (ret != EC_SUCCESS)
return ret;
/* Determine new value of CTRL1 reg and attempt to write it. */
- ctrl1_new = (ctrl1 & ~KXCJ9_RES_12BIT) | res;
+ ctrl1_new = (ctrl1 & ~KXCJ9_RES_12BIT) | resolutions[index].reg;
ret = raw_write8(accel_addr[id], KXCJ9_CTRL1, ctrl1_new);
/* If successfully written, then save the range. */
if (ret == EC_SUCCESS) {
- sensor_resolution[id] = res;
+ sensor_resolution[id] = index;
ctrl1 = ctrl1_new;
}
@@ -198,29 +273,39 @@ int accel_write_resolution(const enum accel_id id, const int res)
return ret;
}
-int accel_write_datarate(const enum accel_id id, const int rate)
+int accel_get_resolution(const enum accel_id id, int * const res)
{
- int ret, ctrl1;
-
/* Check for valid id. */
if (id < 0 || id >= ACCEL_COUNT)
return EC_ERROR_INVAL;
- /* Check that rate input is valid. */
- if (rate < KXCJ9_OSA_12_50HZ || rate > KXCJ9_OSA_6_250HZ)
+ *res = resolutions[sensor_resolution[id]].val;
+ return EC_SUCCESS;
+}
+
+int accel_set_datarate(const enum accel_id id, const int rate, const int rnd)
+{
+ int ret, ctrl1, index;
+
+ /* Check for valid id. */
+ if (id < 0 || id >= ACCEL_COUNT)
return EC_ERROR_INVAL;
+ /* Find index for interface pair matching the specified rate. */
+ index = find_param_index(rate, rnd, datarates, ARRAY_SIZE(datarates));
+
/* Disable the sensor to allow for changing of critical parameters. */
ret = disable_sensor(id, &ctrl1);
if (ret != EC_SUCCESS)
return ret;
/* Set output data rate. */
- ret = raw_write8(accel_addr[id], KXCJ9_DATA_CTRL, rate);
+ ret = raw_write8(accel_addr[id], KXCJ9_DATA_CTRL,
+ datarates[index].reg);
/* If successfully written, then save the range. */
if (ret == EC_SUCCESS)
- sensor_datarate[id] = rate;
+ sensor_datarate[id] = index;
/* Re-enable the sensor. */
if (enable_sensor(id, ctrl1) != EC_SUCCESS)
@@ -229,6 +314,17 @@ int accel_write_datarate(const enum accel_id id, const int rate)
return ret;
}
+int accel_get_datarate(const enum accel_id id, int * const rate)
+{
+ /* Check for valid id. */
+ if (id < 0 || id >= ACCEL_COUNT)
+ return EC_ERROR_INVAL;
+
+ *rate = datarates[sensor_datarate[id]].val;
+ return EC_SUCCESS;
+}
+
+
#ifdef CONFIG_ACCEL_INTERRUPTS
int accel_set_interrupt(const enum accel_id id, unsigned int threshold)
{
@@ -284,7 +380,8 @@ error_enable_sensor:
}
#endif
-int accel_read(enum accel_id id, int *x_acc, int *y_acc, int *z_acc)
+int accel_read(const enum accel_id id, int * const x_acc, int * const y_acc,
+ int * const z_acc)
{
uint8_t acc[6];
uint8_t reg = KXCJ9_XOUT_L;
@@ -306,7 +403,7 @@ int accel_read(enum accel_id id, int *x_acc, int *y_acc, int *z_acc)
return ret;
/* Determine multiplier based on stored range. */
- switch (sensor_range[id]) {
+ switch (ranges[sensor_range[id]].reg) {
case KXCJ9_GSEL_2G:
multiplier = 1;
break;
@@ -314,6 +411,7 @@ int accel_read(enum accel_id id, int *x_acc, int *y_acc, int *z_acc)
multiplier = 2;
break;
case KXCJ9_GSEL_8G:
+ case KXCJ9_GSEL_8G_14BIT:
multiplier = 4;
break;
default:
@@ -338,7 +436,7 @@ int accel_read(enum accel_id id, int *x_acc, int *y_acc, int *z_acc)
return EC_SUCCESS;
}
-int accel_init(enum accel_id id)
+int accel_init(const enum accel_id id)
{
int ret = EC_SUCCESS;
int cnt = 0, ctrl1, ctrl2;
@@ -378,7 +476,8 @@ int accel_init(enum accel_id id)
}
/* Set resolution and range. */
- ctrl1 = sensor_resolution[id] | sensor_range[id];
+ ctrl1 = resolutions[sensor_resolution[id]].reg |
+ ranges[sensor_range[id]].reg;
#ifdef CONFIG_ACCEL_INTERRUPTS
/* Enable wake up (motion detect) functionality. */
ctrl1 |= KXCJ9_CTRL1_WUFE;
@@ -407,7 +506,8 @@ int accel_init(enum accel_id id)
#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,
+ datarates[sensor_datarate[id]].reg);
/* Enable the sensor. */
ret |= enable_sensor(id, ctrl1);
@@ -482,9 +582,9 @@ DECLARE_CONSOLE_COMMAND(accelwrite, command_write_accelerometer,
static int command_accelrange(int argc, char **argv)
{
char *e;
- int id, data;
+ int id, data, round = 1;
- if (argc < 2 || argc > 3)
+ if (argc < 2 || argc > 4)
return EC_ERROR_PARAM_COUNT;
/* First argument is sensor id. */
@@ -492,34 +592,42 @@ static int command_accelrange(int argc, char **argv)
if (*e || id < 0 || id > ACCEL_COUNT)
return EC_ERROR_PARAM1;
- if (argc == 3) {
+ if (argc >= 3) {
/* Second argument is data to write. */
data = strtoi(argv[2], &e, 0);
if (*e)
return EC_ERROR_PARAM2;
+ if (argc == 4) {
+ /* Third argument is rounding flag. */
+ round = strtoi(argv[3], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM3;
+ }
+
/*
* Write new range, if it returns invalid arg, then return
* a parameter error.
*/
- if (accel_write_range(id, data) == EC_ERROR_INVAL)
+ if (accel_set_range(id, data, round) == EC_ERROR_INVAL)
return EC_ERROR_PARAM2;
} else {
- ccprintf("Range for sensor %d: 0x%02x\n", id, sensor_range[id]);
+ accel_get_range(id, &data);
+ ccprintf("Range for sensor %d: %d\n", id, data);
}
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(accelrange, command_accelrange,
- "id [data]",
+ "id [data [roundup]]",
"Read or write accelerometer range", NULL);
static int command_accelresolution(int argc, char **argv)
{
char *e;
- int id, data;
+ int id, data, round = 1;
- if (argc < 2 || argc > 3)
+ if (argc < 2 || argc > 4)
return EC_ERROR_PARAM_COUNT;
/* First argument is sensor id. */
@@ -527,35 +635,42 @@ static int command_accelresolution(int argc, char **argv)
if (*e || id < 0 || id > ACCEL_COUNT)
return EC_ERROR_PARAM1;
- if (argc == 3) {
+ if (argc >= 3) {
/* Second argument is data to write. */
data = strtoi(argv[2], &e, 0);
if (*e)
return EC_ERROR_PARAM2;
+ if (argc == 4) {
+ /* Third argument is rounding flag. */
+ round = strtoi(argv[3], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM3;
+ }
+
/*
* Write new resolution, if it returns invalid arg, then
* return a parameter error.
*/
- if (accel_write_resolution(id, data) == EC_ERROR_INVAL)
+ if (accel_set_resolution(id, data, round) == EC_ERROR_INVAL)
return EC_ERROR_PARAM2;
} else {
- ccprintf("Resolution for sensor %d: 0x%02x\n", id,
- sensor_resolution[id]);
+ accel_get_resolution(id, &data);
+ ccprintf("Resolution for sensor %d: %d\n", id, data);
}
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(accelres, command_accelresolution,
- "id [data]",
+ "id [data [roundup]]",
"Read or write accelerometer resolution", NULL);
static int command_acceldatarate(int argc, char **argv)
{
char *e;
- int id, data;
+ int id, data, round = 1;
- if (argc < 2 || argc > 3)
+ if (argc < 2 || argc > 4)
return EC_ERROR_PARAM_COUNT;
/* First argument is sensor id. */
@@ -563,27 +678,34 @@ static int command_acceldatarate(int argc, char **argv)
if (*e || id < 0 || id > ACCEL_COUNT)
return EC_ERROR_PARAM1;
- if (argc == 3) {
+ if (argc >= 3) {
/* Second argument is data to write. */
data = strtoi(argv[2], &e, 0);
if (*e)
return EC_ERROR_PARAM2;
+ if (argc == 4) {
+ /* Third argument is rounding flag. */
+ round = strtoi(argv[3], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM3;
+ }
+
/*
* Write new data rate, if it returns invalid arg, then
* return a parameter error.
*/
- if (accel_write_datarate(id, data) == EC_ERROR_INVAL)
+ if (accel_set_datarate(id, data, round) == EC_ERROR_INVAL)
return EC_ERROR_PARAM2;
} else {
- ccprintf("Data rate for sensor %d: 0x%02x\n", id,
- sensor_datarate[id]);
+ accel_get_datarate(id, &data);
+ ccprintf("Data rate for sensor %d: %d\n", id, data);
}
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(accelrate, command_acceldatarate,
- "id [data]",
+ "id [data [roundup]]",
"Read or write accelerometer range", NULL);
#ifdef CONFIG_ACCEL_INTERRUPTS
diff --git a/driver/accel_kxcj9.h b/driver/accel_kxcj9.h
index a7137326d9..ea15b6ec17 100644
--- a/driver/accel_kxcj9.h
+++ b/driver/accel_kxcj9.h
@@ -100,36 +100,6 @@
#define KXCJ9_OSA_1600_HZ 7
-/**
- * Write the accelerometer range.
- *
- * @param id Target accelerometer
- * @param range Range (KXCJ9_GSEL_*).
- *
- * @return EC_SUCCESS if successful, non-zero if error.
- */
-int accel_write_range(const enum accel_id id, const int range);
-
-/**
- * Write the accelerometer resolution.
- *
- * @param id Target accelerometer
- * @param range Resolution (KXCJ9_RES_*).
- *
- * @return EC_SUCCESS if successful, non-zero if error.
- */
-int accel_write_resolution(const enum accel_id id, const int res);
-
-/**
- * Write the accelerometer data rate.
- *
- * @param id Target accelerometer
- * @param range Data rate (KXCJ9_OSA_*).
- *
- * @return EC_SUCCESS if successful, non-zero if error.
- */
-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
diff --git a/include/accelerometer.h b/include/accelerometer.h
index a69c227401..0c8703f3ae 100644
--- a/include/accelerometer.h
+++ b/include/accelerometer.h
@@ -29,15 +29,59 @@ enum accel_id;
*
* @return EC_SUCCESS if successful, non-zero if error.
*/
-int accel_read(enum accel_id id, int *x_acc, int *y_acc, int *z_acc);
+int accel_read(const enum accel_id id, int * const x_acc, int * const y_acc,
+ int * const z_acc);
/**
- * Initiailze accelerometers.
+ * Initialize accelerometers.
*
* @param id Target accelerometer
*
* @return EC_SUCCESS if successful, non-zero if error.
*/
-int accel_init(enum accel_id id);
+int accel_init(const enum accel_id id);
+
+/**
+ * Setter and getter methods for the sensor range. The sensor range defines
+ * the maximum value that can be returned from accel_read(). As the range
+ * increases, the resolution gets worse.
+ *
+ * @param id Target accelerometer
+ * @param range Range (Units are +/- G's for accel, +/- deg/s for gyro)
+ * @param rnd Rounding flag. If true, it rounds up to nearest valid value.
+ * Otherwise, it rounds down.
+ *
+ * @return EC_SUCCESS if successful, non-zero if error.
+ */
+int accel_set_range(const enum accel_id id, const int range, const int rnd);
+int accel_get_range(const enum accel_id id, int * const range);
+
+
+/**
+ * Setter and getter methods for the sensor resolution.
+ *
+ * @param id Target accelerometer
+ * @param range Resolution (Units are number of bits)
+ * param rnd Rounding flag. If true, it rounds up to nearest valid value.
+ * Otherwise, it rounds down.
+ *
+ * @return EC_SUCCESS if successful, non-zero if error.
+ */
+int accel_set_resolution(const enum accel_id id, const int res, const int rnd);
+int accel_get_resolution(const enum accel_id id, int * const res);
+
+/**
+ * Setter and getter methods for the sensor output data range. As the ODR
+ * increases, the LPF roll-off frequency also increases.
+ *
+ * @param id Target accelerometer
+ * @param rate Output data rate (units are mHz)
+ * @param rnd Rounding flag. If true, it rounds up to nearest valid value.
+ * Otherwise, it rounds down.
+ *
+ * @return EC_SUCCESS if successful, non-zero if error.
+ */
+int accel_set_datarate(const enum accel_id id, const int rate, const int rnd);
+int accel_get_datarate(const enum accel_id id, int * const rate);
#endif /* __CROS_EC_ACCELEROMETER_H */
diff --git a/include/ec_commands.h b/include/ec_commands.h
index 7b2f5c645a..082c4d16c0 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -1161,6 +1161,130 @@ enum ec_vboot_hash_status {
#define EC_VBOOT_HASH_OFFSET_RW 0xfffffffd
/*****************************************************************************/
+/*
+ * Motion sense commands. We'll make separate structs for sub-commands with
+ * different input args, so that we know how much to expect.
+ */
+#define EC_CMD_MOTION_SENSE_CMD 0x2B
+
+/* Motion sense commands */
+enum motionsense_command {
+ /*
+ * Dump command returns all motion sensor data including a physical
+ * presence bit for each potential sensor.
+ */
+ MOTIONSENSE_CMD_DUMP = 0,
+
+ /*
+ * Info command returns data describing the details of a given sensor,
+ * including enum motionsensor_type, enum motionsensor_location, and
+ * enum motionsensor_chip.
+ */
+ MOTIONSENSE_CMD_INFO = 1,
+
+ /*
+ * EC Rate command is a setter/getter command for the EC sampling rate
+ * of all motion sensors in milliseconds.
+ */
+ MOTIONSENSE_CMD_EC_RATE = 2,
+
+ /*
+ * Sensor ODR command is a setter/getter command for the output data
+ * rate of a specific motion sensor in millihertz.
+ */
+ MOTIONSENSE_CMD_SENSOR_ODR = 3,
+
+ /*
+ * Sensor range command is a setter/getter command for the range of
+ * a specified motion sensor in +/-G's or +/- deg/s.
+ */
+ MOTIONSENSE_CMD_SENSOR_RANGE = 4,
+
+ /* Number of motionsense sub-commands. */
+ MOTIONSENSE_NUM_CMDS
+};
+
+/* List of motion sensor types. */
+enum motionsensor_type {
+ MOTIONSENSE_TYPE_ACCEL,
+ MOTIONSENSE_TYPE_GYRO,
+};
+
+/* List of motion sensor locations. */
+enum motionsensor_location {
+ MOTIONSENSE_LOC_BASE,
+ MOTIONSENSE_LOC_LID,
+};
+
+/* List of motion sensor chips. */
+enum motionsensor_chip {
+ MOTIONSENSE_CHIP_KXCJ9,
+};
+
+/*
+ * Send this value for the data element to only perform a read. If you
+ * send any other value, the EC will interpret it as data to set.
+ */
+#define EC_MOTION_SENSE_NO_VALUE -1
+
+struct ec_params_motion_sense {
+ uint8_t cmd;
+ union {
+ /* Used for MOTIONSENSE_CMD_DUMP. */
+ struct {
+ /* no args */
+ } dump;
+
+ /* Used for MOTIONSENSE_CMD_EC_RATE. */
+ struct {
+ int16_t data;
+ } ec_rate;
+
+ /* Used for MOTIONSENSE_CMD_INFO. */
+ struct {
+ uint8_t sensor_num;
+ } info;
+
+ /*
+ * Used for MOTIONSENSE_CMD_SENSOR_ODR and
+ * MOTIONSENSE_CMD_SENSOR_RANGE.
+ */
+ struct {
+ uint8_t sensor_num;
+ uint8_t roundup;
+ uint16_t reserved;
+ int32_t data;
+ } sensor_odr, sensor_range;
+ };
+} __packed;
+
+struct ec_response_motion_sense {
+ union {
+ /* Used for MOTIONSENSE_CMD_DUMP. */
+ struct {
+ uint8_t sensor_presence[3];
+ uint8_t reserved;
+ int16_t data[9];
+ } dump;
+
+ /* Used for MOTIONSENSE_CMD_INFO. */
+ struct {
+ uint8_t type;
+ uint8_t location;
+ uint8_t chip;
+ } info;
+
+ /*
+ * Used for MOTIONSENSE_CMD_EC_RATE, MOTIONSENSE_CMD_SENSOR_ODR,
+ * and MOTIONSENSE_CMD_SENSOR_RANGE.
+ */
+ struct {
+ int32_t ret;
+ } ec_rate, sensor_odr, sensor_range;
+ };
+} __packed;
+
+/*****************************************************************************/
/* USB charging control commands */
/* Set USB port charging mode */
@@ -2143,7 +2267,7 @@ struct ec_params_reboot_ec {
* Header bytes greater than this indicate a later version. For example,
* EC_CMD_VERSION0 + 1 means we are using version 1.
*
- * The old EC interface must not use commands 0dc or higher.
+ * The old EC interface must not use commands 0xdc or higher.
*/
#define EC_CMD_VERSION0 0xdc
diff --git a/test/math_util.c b/test/math_util.c
index bfc0345655..5ace8d2a83 100644
--- a/test/math_util.c
+++ b/test/math_util.c
@@ -14,16 +14,39 @@
/*****************************************************************************/
/* Mock functions */
-/* Need to define accelerometer init and read functions just to compile. */
+/* Need to define accelerometer functions just to compile. */
int accel_init(enum accel_id id)
{
return EC_SUCCESS;
}
-
int accel_read(enum accel_id id, int *x_acc, int *y_acc, int *z_acc)
{
return EC_SUCCESS;
}
+int accel_set_range(const enum accel_id id, const int range, const int rnd)
+{
+ return EC_SUCCESS;
+}
+int accel_get_range(const enum accel_id id, int * const range)
+{
+ return EC_SUCCESS;
+}
+int accel_set_resolution(const enum accel_id id, const int res, const int rnd)
+{
+ return EC_SUCCESS;
+}
+int accel_get_resolution(const enum accel_id id, int * const res)
+{
+ return EC_SUCCESS;
+}
+int accel_set_datarate(const enum accel_id id, const int rate, const int rnd)
+{
+ return EC_SUCCESS;
+}
+int accel_get_datarate(const enum accel_id id, int * const rate)
+{
+ return EC_SUCCESS;
+}
/*****************************************************************************/
/* Test utilities */
diff --git a/test/motion_sense.c b/test/motion_sense.c
index c332f962c5..ab07a41e96 100644
--- a/test/motion_sense.c
+++ b/test/motion_sense.c
@@ -34,6 +34,31 @@ int accel_read(enum accel_id id, int *x_acc, int *y_acc, int *z_acc)
return EC_SUCCESS;
}
+int accel_set_range(const enum accel_id id, const int range, const int rnd)
+{
+ return EC_SUCCESS;
+}
+int accel_get_range(const enum accel_id id, int * const range)
+{
+ return EC_SUCCESS;
+}
+int accel_set_resolution(const enum accel_id id, const int res, const int rnd)
+{
+ return EC_SUCCESS;
+}
+int accel_get_resolution(const enum accel_id id, int * const res)
+{
+ return EC_SUCCESS;
+}
+int accel_set_datarate(const enum accel_id id, const int rate, const int rnd)
+{
+ return EC_SUCCESS;
+}
+int accel_get_datarate(const enum accel_id id, int * const rate)
+{
+ return EC_SUCCESS;
+}
+
/*****************************************************************************/
/* Test utilities */
diff --git a/util/ectool.c b/util/ectool.c
index 2e58dacef1..712f4fcf9d 100644
--- a/util/ectool.c
+++ b/util/ectool.c
@@ -106,6 +106,8 @@ const char help_str[] =
" Set the color of an LED or query brightness range\n"
" lightbar [CMDS]\n"
" Various lightbar control commands\n"
+ " motionsense [CMDS]\n"
+ " Various motion sense control commands\n"
" panicinfo\n"
" Prints saved panic info\n"
" pause_in_s5 [on|off]\n"
@@ -1686,6 +1688,224 @@ static int cmd_lightbar(int argc, char **argv)
return lb_help(argv[0]);
}
+/* Create an array to store sizes of motion sense param and response structs. */
+#define MS_SIZES(SUBCMD) { \
+ sizeof(((struct ec_params_motion_sense *)0)->SUBCMD) \
+ + sizeof(((struct ec_params_motion_sense *)0)->cmd), \
+ sizeof(((struct ec_response_motion_sense *)0)->SUBCMD) }
+static const struct {
+ uint8_t insize;
+ uint8_t outsize;
+} ms_command_sizes[] = {
+ MS_SIZES(dump),
+ MS_SIZES(info),
+ MS_SIZES(ec_rate),
+ MS_SIZES(sensor_odr),
+ MS_SIZES(sensor_range),
+};
+BUILD_ASSERT(ARRAY_SIZE(ms_command_sizes) == MOTIONSENSE_NUM_CMDS);
+#undef MS_SIZES
+
+static int ms_help(const char *cmd)
+{
+ printf("Usage:\n");
+ printf(" %s - dump all motion data\n", cmd);
+ printf(" %s info NUM - print sensor info\n", cmd);
+ printf(" %s ec_rate [RATE_MS] - set/get sample rate\n", cmd);
+ printf(" %s odr NUM [ODR [ROUNDUP]] - set/get sensor ODR\n", cmd);
+ printf(" %s range NUM [RANGE [ROUNDUP]]- set/get sensor range\n", cmd);
+
+ return 0;
+}
+
+static int cmd_motionsense(int argc, char **argv)
+{
+ int i, rv;
+ struct ec_params_motion_sense param;
+ struct ec_response_motion_sense resp;
+ char *e;
+
+ /* No motionsense command has more than 5 args. */
+ if (argc > 5)
+ return ms_help(argv[0]);
+
+ if (argc == 1) {
+ /* No args, dump motion data. */
+ param.cmd = MOTIONSENSE_CMD_DUMP;
+ rv = ec_command(EC_CMD_MOTION_SENSE_CMD, 0,
+ &param, ms_command_sizes[param.cmd].insize,
+ &resp, ms_command_sizes[param.cmd].outsize);
+
+ if (rv < 0)
+ return rv;
+
+ for (i = 0; i < ARRAY_SIZE(resp.dump.sensor_presence); i++) {
+ printf("Sensor %d: ", i);
+ if (resp.dump.sensor_presence[i])
+ printf("%d\t%d\t%d\n", resp.dump.data[3*i],
+ resp.dump.data[3*i+1],
+ resp.dump.data[3*i+2]);
+ else
+ printf("None\n");
+ }
+
+ return 0;
+ }
+
+ if (argc == 3 && !strcasecmp(argv[1], "info")) {
+ param.cmd = MOTIONSENSE_CMD_INFO;
+
+ param.sensor_odr.sensor_num = strtol(argv[2], &e, 0);
+ if (e && *e) {
+ fprintf(stderr, "Bad %s arg.\n", argv[1]);
+ return -1;
+ }
+
+ rv = ec_command(EC_CMD_MOTION_SENSE_CMD, 0,
+ &param, ms_command_sizes[param.cmd].insize,
+ &resp, ms_command_sizes[param.cmd].outsize);
+
+ if (rv < 0)
+ return rv;
+
+ printf("Type: ");
+ switch (resp.info.type) {
+ case MOTIONSENSE_TYPE_ACCEL:
+ printf("accel\n");
+ break;
+ case MOTIONSENSE_TYPE_GYRO:
+ printf("gyro\n");
+ break;
+ default:
+ printf("unknown\n");
+ }
+
+ printf("Location: ");
+ switch (resp.info.location) {
+ case MOTIONSENSE_LOC_BASE:
+ printf("base\n");
+ break;
+ case MOTIONSENSE_LOC_LID:
+ printf("lid\n");
+ break;
+ default:
+ printf("unknown\n");
+ }
+
+ printf("Chip: ");
+ switch (resp.info.chip) {
+ case MOTIONSENSE_CHIP_KXCJ9:
+ printf("kxcj9\n");
+ break;
+ default:
+ printf("unknown\n");
+ }
+
+ return 0;
+ }
+
+ if (argc < 4 && !strcasecmp(argv[1], "ec_rate")) {
+ param.cmd = MOTIONSENSE_CMD_EC_RATE;
+ param.ec_rate.data = EC_MOTION_SENSE_NO_VALUE;
+
+ if (argc == 3) {
+ param.ec_rate.data = strtol(argv[2], &e, 0);
+ if (e && *e) {
+ fprintf(stderr, "Bad %s arg.\n", argv[1]);
+ return -1;
+ }
+ }
+
+ rv = ec_command(EC_CMD_MOTION_SENSE_CMD, 0,
+ &param, ms_command_sizes[param.cmd].insize,
+ &resp, ms_command_sizes[param.cmd].outsize);
+
+ if (rv < 0)
+ return rv;
+
+ printf("%d\n", resp.ec_rate.ret);
+ return 0;
+ }
+
+ if (argc > 2 && !strcasecmp(argv[1], "odr")) {
+ param.cmd = MOTIONSENSE_CMD_SENSOR_ODR;
+ param.sensor_odr.data = EC_MOTION_SENSE_NO_VALUE;
+ param.sensor_odr.roundup = 1;
+
+ param.sensor_odr.sensor_num = strtol(argv[2], &e, 0);
+ if (e && *e) {
+ fprintf(stderr, "Bad %s arg.\n", argv[1]);
+ return -1;
+ }
+
+ if (argc >= 4) {
+ param.sensor_odr.data = strtol(argv[3], &e, 0);
+ if (e && *e) {
+ fprintf(stderr, "Bad %s arg.\n", argv[1]);
+ return -1;
+ }
+ }
+
+ if (argc == 5) {
+ param.sensor_odr.roundup = strtol(argv[4], &e, 0);
+ if (e && *e) {
+ fprintf(stderr, "Bad %s arg.\n", argv[1]);
+ return -1;
+ }
+ }
+
+ rv = ec_command(EC_CMD_MOTION_SENSE_CMD, 0,
+ &param, ms_command_sizes[param.cmd].insize,
+ &resp, ms_command_sizes[param.cmd].outsize);
+
+ if (rv < 0)
+ return rv;
+
+ printf("%d\n", resp.sensor_odr.ret);
+ return 0;
+ }
+
+ if (argc > 2 && !strcasecmp(argv[1], "range")) {
+ param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE;
+ param.sensor_range.data = EC_MOTION_SENSE_NO_VALUE;
+ param.sensor_odr.roundup = 1;
+
+ param.sensor_range.sensor_num = strtol(argv[2], &e, 0);
+ if (e && *e) {
+ fprintf(stderr, "Bad %s arg.\n", argv[1]);
+ return -1;
+ }
+
+ if (argc >= 4) {
+ param.sensor_range.data = strtol(argv[3], &e, 0);
+ if (e && *e) {
+ fprintf(stderr, "Bad %s arg.\n", argv[1]);
+ return -1;
+ }
+ }
+
+ if (argc == 5) {
+ param.sensor_odr.roundup = strtol(argv[4], &e, 0);
+ if (e && *e) {
+ fprintf(stderr, "Bad %s arg.\n", argv[1]);
+ return -1;
+ }
+ }
+
+ rv = ec_command(EC_CMD_MOTION_SENSE_CMD, 0,
+ &param, ms_command_sizes[param.cmd].insize,
+ &resp, ms_command_sizes[param.cmd].outsize);
+
+ if (rv < 0)
+ return rv;
+
+ printf("%d\n", resp.sensor_range.ret);
+ return 0;
+ }
+
+ return ms_help(argv[0]);
+}
+
static int find_led_color_by_name(const char *color)
{
int i;
@@ -3681,6 +3901,7 @@ const struct command commands[] = {
{"lightbar", cmd_lightbar},
{"keyconfig", cmd_keyconfig},
{"keyscan", cmd_keyscan},
+ {"motionsense", cmd_motionsense},
{"panicinfo", cmd_panic_info},
{"pause_in_s5", cmd_s5},
{"powerinfo", cmd_power_info},