summaryrefslogtreecommitdiff
path: root/driver
diff options
context:
space:
mode:
authorAlec Berg <alecaberg@chromium.org>2014-03-24 10:03:56 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-04-05 03:25:47 +0000
commit529548208cad436232cfba2c0b802523ddaf5383 (patch)
tree74e7b6febda2d30599ab72204befc8d61e0c3d7c /driver
parentf06ad7e2ab4fa1a03c2e48a8bca3fdf2abbdffa9 (diff)
downloadchrome-ec-529548208cad436232cfba2c0b802523ddaf5383.tar.gz
accel: add host command to modify accel params and add ectool command
Created a host command to set/get various motion sensor parameters and added an ectool command to use that host command. The host command is created such that the first argument is a sub-command. Sub-commands created include: dump: dumps all current motion sensor data info: returns general information about each motion sensor ec_rate: set/get the EC sampling rate of sensors sensor_range: set/get the sensor range (ie +/- 2G,4G,8G) sensor_odr: set/get the sensor output data rate (ie 50Hz, 100Hz, ...) For sensor_range and sensor_odr parameters, since the host doesn't know what are valid values for the parameter, the host can specify to round up or down to the nearest valid value. For example, the host can specify to set the output data rate to at least 100Hz, and the EC will return the closest valid output data rate that is at least 100Hz. BUG=chrome-os-partner:27321 BRANCH=rambi TEST=Test on a glimmer using ectool from vt-2 prompt: > ectool motionsense help Usage: motionsense - dump all motion data motionsense info NUM - print sensor info motionsense ec_rate [RATE_MS] - set/get sample rate motionsense odr NUM [ODR [ROUNDUP]] - set/get sensor ODR motionsense range NUM [RANGE [ROUNDUP]]- set/get sensor range > > ectool motionsense Sensor 0: 0, 0, 1024 Sensor 1: 1024, 0, 0 Sensor 2: None > ectool motionsense info 0 Type: accel Location: base Chip: kxcj9 > ectool motionsense ec_rate 10 > ectool motionsense ec_rate 1000 1000 > ectool motionsense odr 0 100000 > ectool motionsense odr 0 40000 1 50000 > ectool motionsense range 0 8 8 After running this I verified on the EC console that all the parameters were set appropriately. I tested the EC sampling rate was 1000ms by running lidangle on and making sure samples were displayed roughly every second. I verified the sensor odr and range by defining CONFIG_CMD_ACCELS and typing: > accelrange 0 8 > accelrate 0 50000 Change-Id: I444e2f0eafabd607f1c7aa78b5c4e91f6cb06387 Signed-off-by: Alec Berg <alecaberg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/192064 Reviewed-on: https://chromium-review.googlesource.com/193307 Reviewed-by: Randall Spangler <rspangler@chromium.org>
Diffstat (limited to 'driver')
-rw-r--r--driver/accel_kxcj9.c238
-rw-r--r--driver/accel_kxcj9.h30
2 files changed, 180 insertions, 88 deletions
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