summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Berg <alecaberg@chromium.org>2014-01-06 18:07:27 -0800
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-02-22 00:48:25 +0000
commit9305b84ab2a844393b90b897c394a557d8dfa8fb (patch)
tree1cd7fe0ebaccce6d909e736ced277a31090e2721
parent8df483bf594d6251005a88de211078e2a445a55d (diff)
downloadchrome-ec-9305b84ab2a844393b90b897c394a557d8dfa8fb.tar.gz
rambi: Accelerometer driver for kxcj9.
Added accelerometer driver for kxcj9 accelerometers. Currently the accelerometers aren't being used by anything, but there are console commands, accelwrite and accelread, to perform transactions. BUG=none BRANCH=rambi TEST=Used EC console commands to test that accelerometers respond and data looks reasonable. Original-Change-Id: I6ddcf04ec278adeacb148c19b10c3c296b467954 Signed-off-by: Alec Berg <alecaberg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/184693 Reviewed-by: Randall Spangler <rspangler@chromium.org> (cherry picked from commit 5e1d2052b034b2400b98b2126243e01397a2ce56) Conflicts: board/clapper/board.c board/clapper/board.h board/glimmer/board.c board/glimmer/board.h Change-Id: If8744ddc3273fc08e29830adfd068dc302dd120a Signed-off-by: Alec Berg <alecaberg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/187432 Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--driver/accel_kxcj9.c249
-rw-r--r--driver/accel_kxcj9.h132
-rw-r--r--driver/build.mk3
-rw-r--r--include/accelerometer.h36
-rw-r--r--include/config.h4
5 files changed, 424 insertions, 0 deletions
diff --git a/driver/accel_kxcj9.c b/driver/accel_kxcj9.c
new file mode 100644
index 0000000000..83967eb873
--- /dev/null
+++ b/driver/accel_kxcj9.c
@@ -0,0 +1,249 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* KXCJ9 gsensor module for Chrome EC */
+
+#include "accelerometer.h"
+#include "common.h"
+#include "console.h"
+#include "driver/accel_kxcj9.h"
+#include "gpio.h"
+#include "i2c.h"
+#include "util.h"
+
+/* Range of the accelerometers: 2G, 4G, or 8G. */
+static int sensor_range[ACCEL_COUNT] = {KXCJ9_GSEL_2G, KXCJ9_GSEL_2G};
+
+/* Resolution: KXCJ9_RES_12BIT or KXCJ9_RES_12BIT. */
+static int sensor_resolution[ACCEL_COUNT] = {KXCJ9_RES_12BIT, KXCJ9_RES_12BIT};
+
+/* Output data rate: KXCJ9_OSA_* ranges from 0.781Hz to 1600Hz. */
+static int sensor_datarate[ACCEL_COUNT] = {KXCJ9_OSA_12_50HZ,
+ KXCJ9_OSA_12_50HZ};
+
+#ifdef CONFIG_CMD_ACCELS
+/**
+ * Read register from accelerometer.
+ */
+static int raw_read8(const int addr, const int reg, int *data_ptr)
+{
+ return i2c_read8(I2C_PORT_ACCEL, addr, reg, data_ptr);
+}
+#endif /* CONFIG_CMD_ACCELS */
+
+/**
+ * Write register from accelerometer.
+ */
+static int raw_write8(const int addr, const int reg, int data)
+{
+ return i2c_write8(I2C_PORT_ACCEL, addr, reg, data);
+}
+
+
+int accel_write_range(const enum accel_id id, const int range)
+{
+ int ret;
+
+ /* 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;
+
+ ret = raw_write8(accel_addr[id], KXCJ9_CTRL1,
+ KXCJ9_CTRL1_PC1 | sensor_resolution[id] | range);
+
+ /* If successfully written, then save the range. */
+ if (ret == EC_SUCCESS)
+ sensor_range[id] = range;
+
+ return ret;
+}
+
+int accel_write_resolution(const enum accel_id id, const int res)
+{
+ int ret;
+
+ /* 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)
+ return EC_ERROR_INVAL;
+
+ ret = raw_write8(accel_addr[id], KXCJ9_CTRL1,
+ KXCJ9_CTRL1_PC1 | res | sensor_range[id]);
+
+ /* If successfully written, then save the range. */
+ if (ret == EC_SUCCESS)
+ sensor_resolution[id] = res;
+
+ return ret;
+}
+
+int accel_write_datarate(const enum accel_id id, const int rate)
+{
+ int ret;
+
+ /* 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)
+ return EC_ERROR_INVAL;
+
+ /* Set output data rate. */
+ ret = raw_write8(accel_addr[id], KXCJ9_DATA_CTRL, rate);
+
+ /* If successfully written, then save the range. */
+ if (ret == EC_SUCCESS)
+ sensor_datarate[id] = rate;
+
+ return ret;
+}
+
+int accel_read(enum accel_id id, int *x_acc, int *y_acc, int *z_acc)
+{
+ uint8_t acc[6];
+ uint8_t reg = KXCJ9_XOUT_L;
+ int ret, multiplier;
+
+ /* Check for valid id. */
+ if (id < 0 || id >= ACCEL_COUNT)
+ return EC_ERROR_INVAL;
+
+ /* Read 6 bytes starting at KXCJ9_XOUT_L. */
+ ret = i2c_xfer(I2C_PORT_ACCEL, accel_addr[id], &reg, 1, acc, 6,
+ I2C_XFER_SINGLE);
+
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ /* Determine multiplier based on stored range. */
+ switch (sensor_range[id]) {
+ case KXCJ9_GSEL_2G:
+ multiplier = 1;
+ break;
+ case KXCJ9_GSEL_4G:
+ multiplier = 2;
+ break;
+ case KXCJ9_GSEL_8G:
+ multiplier = 4;
+ break;
+ default:
+ return EC_ERROR_UNKNOWN;
+ }
+
+ /*
+ * Convert acceleration to a signed 12-bit number. Note, based on
+ * the order of the registers:
+ *
+ * acc[0] = KXCJ9_XOUT_L
+ * acc[1] = KXCJ9_XOUT_H
+ * acc[2] = KXCJ9_YOUT_L
+ * acc[3] = KXCJ9_YOUT_H
+ * acc[4] = KXCJ9_ZOUT_L
+ * acc[5] = KXCJ9_ZOUT_H
+ */
+ *x_acc = multiplier * (((int8_t)acc[1]) << 4) | (acc[0] >> 4);
+ *y_acc = multiplier * (((int8_t)acc[3]) << 4) | (acc[2] >> 4);
+ *z_acc = multiplier * (((int8_t)acc[5]) << 4) | (acc[4] >> 4);
+
+ return EC_SUCCESS;
+}
+
+int accel_init(enum accel_id id)
+{
+ int ret = EC_SUCCESS;
+
+ /* Check for valid id. */
+ if (id < 0 || id >= ACCEL_COUNT)
+ return EC_ERROR_INVAL;
+
+ /* 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]);
+
+ /* Set output data rate. */
+ ret |= raw_write8(accel_addr[id], KXCJ9_DATA_CTRL,
+ sensor_datarate[id]);
+
+ return ret;
+}
+
+
+
+/*****************************************************************************/
+/* Console commands */
+
+#ifdef CONFIG_CMD_ACCELS
+static int command_read_accelerometer(int argc, char **argv)
+{
+ char *e;
+ int addr, reg, data;
+
+ if (argc != 3)
+ return EC_ERROR_PARAM_COUNT;
+
+ /* First argument is address. */
+ addr = strtoi(argv[1], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM1;
+
+ /* Second argument is register offset. */
+ reg = strtoi(argv[2], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM2;
+
+ raw_read8(addr, reg, &data);
+
+ ccprintf("0x%02x\n", data);
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(accelread, command_read_accelerometer,
+ "addr reg",
+ "Read from accelerometer at slave address addr", NULL);
+
+static int command_write_accelerometer(int argc, char **argv)
+{
+ char *e;
+ int addr, reg, data;
+
+ if (argc != 4)
+ return EC_ERROR_PARAM_COUNT;
+
+ /* First argument is address. */
+ addr = strtoi(argv[1], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM1;
+
+ /* Second argument is register offset. */
+ reg = strtoi(argv[2], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM2;
+
+ /* Third argument is data. */
+ data = strtoi(argv[3], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM3;
+
+ raw_write8(addr, reg, data);
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(accelwrite, command_write_accelerometer,
+ "addr reg data",
+ "Write to accelerometer at slave address addr", NULL);
+#endif /* CONFIG_CMD_ACCELS */
diff --git a/driver/accel_kxcj9.h b/driver/accel_kxcj9.h
new file mode 100644
index 0000000000..9451421be5
--- /dev/null
+++ b/driver/accel_kxcj9.h
@@ -0,0 +1,132 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* KXCJ9 gsensor module for Chrome EC */
+
+#ifndef __CROS_EC_ACCEL_KXCJ9_H
+#define __CROS_EC_ACCEL_KXCJ9_H
+
+/*
+ * 7-bit address is 000111Xb. Where 'X' is determined
+ * by the voltage on the ADDR pin.
+ */
+#define KXCJ9_ADDR0 0x1c
+#define KXCJ9_ADDR1 0x1e
+
+/* Chip-specific registers */
+#define KXCJ9_XOUT_L 0x06
+#define KXCJ9_XOUT_H 0x07
+#define KXCJ9_YOUT_L 0x08
+#define KXCJ9_YOUT_H 0x09
+#define KXCJ9_ZOUT_L 0x0a
+#define KXCJ9_ZOUT_H 0x0b
+#define KXCJ9_DCST_RESP 0x0c
+#define KXCJ9_WHOAMI 0x0f
+#define KXCJ9_INT_SRC1 0x16
+#define KXCJ9_INT_SRC2 0x17
+#define KXCJ9_STATUS 0x18
+#define KXCJ9_INT_REL 0x1a
+#define KXCJ9_CTRL1 0x1b
+#define KXCJ9_CTRL2 0x1d
+#define KXCJ9_INT_CTRL1 0x1e
+#define KXCJ9_INT_CTRL2 0x1f
+#define KXCJ9_DATA_CTRL 0x21
+#define KXCJ9_WAKEUP_TIMER 0x29
+#define KXCJ9_SELF_TEST 0x3a
+#define KXCJ9_WAKEUP_THRESHOLD 0x6a
+
+#define KXCJ9_INT_SRC1_WUFS (1 << 1)
+#define KXCJ9_INT_SRC1_DRDY (1 << 4)
+
+#define KXCJ9_INT_SRC2_ZPWU (1 << 0)
+#define KXCJ9_INT_SRC2_ZNWU (1 << 1)
+#define KXCJ9_INT_SRC2_YPWU (1 << 2)
+#define KXCJ9_INT_SRC2_YNWU (1 << 3)
+#define KXCJ9_INT_SRC2_XPWU (1 << 4)
+#define KXCJ9_INT_SRC2_XNWU (1 << 5)
+
+#define KXCJ9_STATUS_INT (1 << 4)
+
+#define KXCJ9_CTRL1_WUFE (1 << 1)
+#define KXCJ9_CTRL1_DRDYE (1 << 5)
+#define KXCJ9_CTRL1_PC1 (1 << 7)
+
+#define KXCJ9_GSEL_2G (0 << 3)
+#define KXCJ9_GSEL_4G (1 << 3)
+#define KXCJ9_GSEL_8G (2 << 3)
+#define KXCJ9_GSEL_8G_14BIT (3 << 3)
+
+#define KXCJ9_RES_8BIT (0 << 6)
+#define KXCJ9_RES_12BIT (1 << 6)
+
+#define KXCJ9_CTRL2_OWUF (7 << 0)
+#define KXCJ9_CTRL2_DCST (1 << 4)
+#define KXCJ9_CTRL2_SRST (1 << 7)
+
+#define KXCJ9_OWUF_0_781HZ 0
+#define KXCJ9_OWUF_1_563HZ 1
+#define KXCJ9_OWUF_3_125HZ 2
+#define KXCJ9_OWUF_6_250HZ 3
+#define KXCJ9_OWUF_12_50HZ 4
+#define KXCJ9_OWUF_25_00HZ 5
+#define KXCJ9_OWUF_50_00HZ 6
+#define KXCJ9_OWUF_100_0HZ 7
+
+#define KXCJ9_INT_CTRL1_IEL (1 << 3)
+#define KXCJ9_INT_CTRL1_IEA (1 << 4)
+#define KXCJ9_INT_CTRL1_IEN (1 << 5)
+
+#define KXCJ9_INT_CTRL2_ZPWUE (1 << 0)
+#define KXCJ9_INT_CTRL2_ZNWUE (1 << 1)
+#define KXCJ9_INT_CTRL2_YPWUE (1 << 2)
+#define KXCJ9_INT_CTRL2_YNWUE (1 << 3)
+#define KXCJ9_INT_CTRL2_XPWUE (1 << 4)
+#define KXCJ9_INT_CTRL2_XNWUE (1 << 5)
+
+#define KXCJ9_OSA_0_781HZ 8
+#define KXCJ9_OSA_1_563HZ 9
+#define KXCJ9_OSA_3_125HZ 0xa
+#define KXCJ9_OSA_6_250HZ 0xb
+#define KXCJ9_OSA_12_50HZ 0
+#define KXCJ9_OSA_25_00HZ 1
+#define KXCJ9_OSA_50_00HZ 2
+#define KXCJ9_OSA_100_0HZ 3
+#define KXCJ9_OSA_200_0HZ 4
+#define KXCJ9_OSA_400_0HZ 5
+#define KXCJ9_OSA_800_0HZ 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);
+
+#endif /* __CROS_EC_ACCEL_KXCJ9_H */
diff --git a/driver/build.mk b/driver/build.mk
index f981b6942c..f9c31b143b 100644
--- a/driver/build.mk
+++ b/driver/build.mk
@@ -6,6 +6,9 @@
# Drivers for off-chip devices
#
+# Accelerometers
+driver-$(CONFIG_ACCEL_KXCJ9)+=accel_kxcj9.o
+
# ALS drivers
driver-$(CONFIG_ALS_ISL29035)+=als_isl29035.o
diff --git a/include/accelerometer.h b/include/accelerometer.h
new file mode 100644
index 0000000000..48d61ac3ab
--- /dev/null
+++ b/include/accelerometer.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* This array must be defined in board.c. */
+extern const int accel_addr[];
+
+/* This enum must be defined in board.h. */
+enum accel_id;
+
+/* Number of counts from accelerometer that represents 1G acceleration. */
+#define ACCEL_G 1024
+
+/**
+ * Read all three accelerations of an accelerometer. Note that all three
+ * accelerations come back in counts, where ACCEL_G can be used to convert
+ * counts to engineering units.
+ *
+ * @param id Target accelerometer
+ * @param x_acc Pointer to store X-axis acceleration (in counts).
+ * @param y_acc Pointer to store Y-axis acceleration (in counts).
+ * @param z_acc Pointer to store Z-axis acceleration (in counts).
+ *
+ * @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);
+
+/**
+ * Initiailze accelerometers.
+ *
+ * @param id Target accelerometer
+ *
+ * @return EC_SUCCESS if successful, non-zero if error.
+ */
+int accel_init(enum accel_id id);
diff --git a/include/config.h b/include/config.h
index 479a68e61a..114e6e982f 100644
--- a/include/config.h
+++ b/include/config.h
@@ -36,6 +36,9 @@
* BOARD_*, CHIP_*, and CHIP_FAMILY_*.
*/
+/* Specify type of accelerometers attached. */
+#undef CONFIG_ACCEL_KXCJ9
+
/* Compile chip support for analog-to-digital convertor */
#undef CONFIG_ADC
@@ -234,6 +237,7 @@
* console.
*/
+#undef CONFIG_CMD_ACCELS
#undef CONFIG_CMD_BATDEBUG
#undef CONFIG_CMD_CLOCKGATES
#undef CONFIG_CMD_COMXTEST