summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGwendal Grignou <gwendal@chromium.org>2016-12-27 16:19:05 -0800
committerchrome-bot <chrome-bot@chromium.org>2017-02-16 18:03:59 -0800
commit484ef121193865225ddbc3a0b848db7f5384f836 (patch)
tree804173045dad81b2a2839df75c412e874e8d9154
parent69c3fc2378ee9026277c1cbaf6e8aff0b99ecf46 (diff)
downloadchrome-ec-484ef121193865225ddbc3a0b848db7f5384f836.tar.gz
motion: Add opt3001 as a motion sensor
Use the motion sensor to manage ALS as well. The current interface (via memmap) is preserved, but we can also access the sensor via cros ec sensor stack and send the ALS information to ARC++. BUG=chrome-os-partner:59423 BRANCH=reef CQ-DEPEND=CL:424217 TEST=Check the sensor is working via ACPI sensor and cros ec sensor. Check ARC++ sees the sensors. Change-Id: Iaf608370454ad582691b72b471ea87b511863a78 Signed-off-by: Gwendal Grignou <gwendal@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/424323 Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
-rw-r--r--board/reef/board.c55
-rw-r--r--board/reef/board.h17
-rw-r--r--board/reef/ec.tasklist1
-rw-r--r--common/motion_sense.c16
-rw-r--r--driver/als_opt3001.c211
-rw-r--r--driver/als_opt3001.h44
-rw-r--r--include/ec_commands.h1
-rw-r--r--include/motion_sense.h4
-rw-r--r--util/ectool.c3
9 files changed, 326 insertions, 26 deletions
diff --git a/board/reef/board.c b/board/reef/board.c
index 7074ab4952..141a1cd3e0 100644
--- a/board/reef/board.c
+++ b/board/reef/board.c
@@ -7,7 +7,6 @@
#include "adc.h"
#include "adc_chip.h"
-#include "als.h"
#include "button.h"
#include "charge_manager.h"
#include "charge_ramp.h"
@@ -216,6 +215,8 @@ struct i2c_stress_test i2c_stress_tests[] = {
#endif
#ifdef CONFIG_CMD_I2C_STRESS_TEST_ALS
{
+ .port = I2C_PORT_ALS,
+ .addr = OPT3001_I2C_ADDR1,
.i2c_test = &opt3001_i2c_stress_test_dev,
},
#endif
@@ -441,13 +442,6 @@ const struct temp_sensor_t temp_sensors[] = {
};
BUILD_ASSERT(ARRAY_SIZE(temp_sensors) == TEMP_SENSOR_COUNT);
-/* ALS instances. Must be in same order as enum als_id. */
-struct als_t als[] = {
- /* FIXME(dhendrix): verify attenuation_factor */
- {"TI", opt3001_init, opt3001_read_lux, 5},
-};
-BUILD_ASSERT(ARRAY_SIZE(als) == ALS_COUNT);
-
const struct button_config buttons[CONFIG_BUTTON_COUNT] = {
{"Volume Down", KEYBOARD_BUTTON_VOLUME_DOWN, GPIO_EC_VOLDN_BTN_ODL,
30 * MSEC, 0},
@@ -779,10 +773,13 @@ const matrix_3x3_t mag_standard_ref = {
{ 0, 0, FLOAT_TO_FP(-1)}
};
+/* sensor private data */
struct kionix_accel_data g_kx022_data;
struct bmi160_drv_data_t g_bmi160_data;
struct bmp280_drv_data_t bmp280_drv_data;
-
+struct opt3001_drv_data_t g_opt3001_data = {
+ .attenuation = 5,
+};
/* FIXME(dhendrix): Copied from Amenia, probably need to tweak for Reef */
struct motion_sensor_t motion_sensors[] = {
@@ -967,9 +964,49 @@ struct motion_sensor_t motion_sensors[] = {
},
},
},
+ [LID_ALS] = {
+ .name = "Light",
+ .active_mask = SENSOR_ACTIVE_S0_S3,
+ .chip = MOTIONSENSE_CHIP_OPT3001,
+ .type = MOTIONSENSE_TYPE_LIGHT,
+ .location = MOTIONSENSE_LOC_LID,
+ .drv = &opt3001_drv,
+ .drv_data = &g_opt3001_data,
+ .port = I2C_PORT_ALS,
+ .addr = OPT3001_I2C_ADDR1,
+ .rot_standard_ref = NULL,
+ .default_range = OPT3001_RANGE_AUTOMATIC_FULL_SCALE,
+ .config = {
+ /* AP: by default shutdown all sensors */
+ [SENSOR_CONFIG_AP] = {
+ .odr = 0,
+ .ec_rate = 0,
+ },
+ [SENSOR_CONFIG_EC_S0] = {
+ .odr = 1000,
+ .ec_rate = 0,
+ },
+ /* Sensor off in S3/S5 */
+ [SENSOR_CONFIG_EC_S3] = {
+ .odr = 0,
+ .ec_rate = 0,
+ },
+ /* Sensor off in S3/S5 */
+ [SENSOR_CONFIG_EC_S5] = {
+ .odr = 0,
+ .ec_rate = 0,
+ },
+ },
+ },
};
const unsigned int motion_sensor_count = ARRAY_SIZE(motion_sensors);
+/* ALS instances when LPC mapping is needed. Each entry directs to a sensor. */
+const struct motion_sensor_t *motion_als_sensors[] = {
+ &motion_sensors[LID_ALS],
+};
+BUILD_ASSERT(ARRAY_SIZE(motion_als_sensors) == ALS_COUNT);
+
void board_hibernate(void)
{
/*
diff --git a/board/reef/board.h b/board/reef/board.h
index 0dd246b429..0e7ef3b2e0 100644
--- a/board/reef/board.h
+++ b/board/reef/board.h
@@ -202,7 +202,6 @@
#define CONFIG_MAG_CALIBRATE
#define CONFIG_ACCEL_KX022
#define CONFIG_ALS_OPT3001
-#define OPT3001_I2C_ADDR OPT3001_I2C_ADDR1
#define CONFIG_BARO_BMP280
#define CONFIG_LID_ANGLE
#define CONFIG_LID_ANGLE_UPDATE
@@ -257,12 +256,13 @@ enum temp_sensor_id {
TEMP_SENSOR_COUNT
};
-/* Light sensors */
-enum als_id {
- ALS_OPT3001 = 0,
-
- ALS_COUNT
-};
+/*
+ * For backward compatibility, to report ALS via ACPI,
+ * Define the number of ALS sensors: motion_sensor copy the data to the ALS
+ * memmap region.
+ */
+#define CONFIG_ALS
+#define ALS_COUNT 1
/*
* Motion sensors:
@@ -276,6 +276,7 @@ enum sensor_id {
BASE_GYRO,
BASE_MAG,
BASE_BARO,
+ LID_ALS,
};
enum reef_board_version {
@@ -319,7 +320,7 @@ void board_print_tcpc_fw_version(int port);
/* Sensors without hardware FIFO are in forced mode */
#define CONFIG_ACCEL_FORCE_MODE_MASK \
- ((1 << LID_ACCEL) | (1 << BASE_BARO))
+ ((1 << LID_ACCEL) | (1 << BASE_BARO) | (1 << LID_ALS))
#endif /* !__ASSEMBLER__ */
diff --git a/board/reef/ec.tasklist b/board/reef/ec.tasklist
index 47e0048872..e153496b43 100644
--- a/board/reef/ec.tasklist
+++ b/board/reef/ec.tasklist
@@ -22,7 +22,6 @@
#define CONFIG_TASK_LIST \
TASK_ALWAYS(HOOKS, hook_task, NULL, LARGER_TASK_STACK_SIZE) \
- TASK_ALWAYS(ALS, als_task, NULL, TASK_STACK_SIZE) \
TASK_ALWAYS(CHG_RAMP, chg_ramp_task, NULL, TASK_STACK_SIZE) \
TASK_ALWAYS(USB_CHG, usb_charger_task, NULL, TASK_STACK_SIZE) \
TASK_ALWAYS(CHARGER, charger_task, NULL, LARGER_TASK_STACK_SIZE) \
diff --git a/common/motion_sense.c b/common/motion_sense.c
index 442e957540..2b9d715343 100644
--- a/common/motion_sense.c
+++ b/common/motion_sense.c
@@ -575,10 +575,13 @@ static inline void set_present(uint8_t *lpc_status)
#ifdef UPDATE_HOST_MEM_MAP
/* Update/Write LPC data */
-static inline void update_sense_data(uint8_t *lpc_status,
- uint16_t *lpc_data, int *psample_id)
+static inline void update_sense_data(uint8_t *lpc_status, int *psample_id)
{
int i;
+ uint16_t *lpc_data = (uint16_t *)host_get_memmap(EC_MEMMAP_ACC_DATA);
+#if (!defined HAS_TASK_ALS) && (defined CONFIG_ALS)
+ uint16_t *lpc_als = (uint16_t *)host_get_memmap(EC_MEMMAP_ALS);
+#endif
struct motion_sensor_t *sensor;
/*
* Set the busy bit before writing the sensor data. Increment
@@ -610,6 +613,11 @@ static inline void update_sense_data(uint8_t *lpc_status,
lpc_data[3+3*i] = sensor->xyz[Z];
}
+#if (!defined HAS_TASK_ALS) && (defined CONFIG_ALS)
+ for (i = 0; i < EC_ALS_ENTRIES && i < ALS_COUNT; i++)
+ lpc_als[i] = motion_als_sensors[i]->xyz[X];
+#endif
+
/*
* Increment sample id and clear busy bit to signal we finished
* updating data.
@@ -727,10 +735,8 @@ void motion_sense_task(void)
#ifdef UPDATE_HOST_MEM_MAP
int sample_id = 0;
uint8_t *lpc_status;
- uint16_t *lpc_data;
lpc_status = host_get_memmap(EC_MEMMAP_ACC_STATUS);
- lpc_data = (uint16_t *)host_get_memmap(EC_MEMMAP_ACC_DATA);
set_present(lpc_status);
#endif
@@ -832,7 +838,7 @@ void motion_sense_task(void)
}
#endif
#ifdef UPDATE_HOST_MEM_MAP
- update_sense_data(lpc_status, lpc_data, &sample_id);
+ update_sense_data(lpc_status, &sample_id);
#endif
ts_end_task = get_time();
diff --git a/driver/als_opt3001.c b/driver/als_opt3001.c
index bbf61a1064..7e080e8c89 100644
--- a/driver/als_opt3001.c
+++ b/driver/als_opt3001.c
@@ -8,6 +8,7 @@
#include "driver/als_opt3001.h"
#include "i2c.h"
+#ifdef HAS_TASK_ALS
/**
* Read register from OPT3001 light sensor.
*/
@@ -98,4 +99,212 @@ struct i2c_stress_test_dev opt3001_i2c_stress_test_dev = {
.i2c_read_dev = &opt3001_i2c_read,
.i2c_write_dev = &opt3001_i2c_write,
};
-#endif /* CONFIG_CMD_I2C_STRESS_TEST_ALS */
+#endif /* CONFIG_CMD_I2C_STRESS_TEST_ALS */
+#else /* HAS_TASK_ALS */
+#include "accelgyro.h"
+#include "math_util.h"
+
+/**
+ * Read register from OPT3001 light sensor.
+ */
+static int opt3001_i2c_read(const int port, const int addr, const int reg,
+ int *data_ptr)
+{
+ int ret;
+
+ ret = i2c_read16(port, addr, reg, data_ptr);
+ if (!ret)
+ *data_ptr = ((*data_ptr << 8) & 0xFF00) |
+ ((*data_ptr >> 8) & 0x00FF);
+
+ return ret;
+}
+
+/**
+ * Write register to OPT3001 light sensor.
+ */
+static int opt3001_i2c_write(const int port, const int addr, const int reg,
+ int data)
+{
+ data = ((data << 8) & 0xFF00) | ((data >> 8) & 0x00FF);
+ return i2c_write16(port, addr, reg, data);
+}
+
+/**
+ * Read OPT3001 light sensor data.
+ */
+int opt3001_read_lux(const struct motion_sensor_t *s, vector_3_t v)
+{
+ struct opt3001_drv_data_t *drv_data = OPT3001_GET_DATA(s);
+ int ret;
+ int data;
+
+ ret = opt3001_i2c_read(s->port, s->addr, OPT3001_REG_RESULT, &data);
+ if (ret)
+ return ret;
+
+ /*
+ * The default power-on values will give 12 bits of precision:
+ * 0x0000-0x0fff indicates 0 to 1310.40 lux. We multiply the sensor
+ * value by a scaling factor to account for attenuation by glass,
+ * tinting, etc.
+ */
+
+ /*
+ * lux = 2EXP[3:0] × R[11:0] / 100
+ */
+ v[0] = ((1 << ((data & 0xF000) >> 12)) * (data & 0x0FFF) *
+ drv_data->attenuation) / 100;
+ v[1] = 0;
+ v[2] = 0;
+
+ /*
+ * Return an error when nothing change to prevent filling the
+ * fifo with useless data.
+ */
+ if (v[0] == drv_data->last_value)
+ return EC_ERROR_UNCHANGED;
+ else
+ return EC_SUCCESS;
+}
+
+static int opt3001_set_range(const struct motion_sensor_t *s, int range,
+ int rnd)
+{
+ int rv;
+ int reg;
+ struct opt3001_drv_data_t *drv_data = OPT3001_GET_DATA(s);
+
+ if (range < 0 || range > OPT3001_RANGE_AUTOMATIC_FULL_SCALE)
+ return EC_ERROR_INVAL;
+
+ rv = opt3001_i2c_read(s->port, s->addr, OPT3001_REG_CONFIGURE, &reg);
+ if (rv)
+ return rv;
+
+ rv = opt3001_i2c_write(s->port, s->addr, OPT3001_REG_CONFIGURE,
+ (reg & OPT3001_RANGE_MASK) |
+ (range << OPT3001_RANGE_OFFSET));
+ if (rv)
+ return rv;
+
+ drv_data->range = range;
+
+ return EC_SUCCESS;
+}
+
+static int opt3001_get_range(const struct motion_sensor_t *s)
+{
+ struct opt3001_drv_data_t *drv_data = OPT3001_GET_DATA(s);
+
+ return drv_data->range;
+}
+
+static int opt3001_set_data_rate(const struct motion_sensor_t *s,
+ int rate, int roundup)
+{
+ struct opt3001_drv_data_t *drv_data = OPT3001_GET_DATA(s);
+ int rv;
+ int reg;
+ enum opt3001_mode mode;
+
+ if (rate == 0) {
+ /*
+ * Suspend driver:
+ */
+ mode = OPT3001_MODE_SUSPEND;
+ } else {
+ mode = OPT3001_MODE_CONTINUOUS;
+ /*
+ * We set the sensor for continuous mode,
+ * integrating over 800ms.
+ * Do not allow range higher than 1Hz.
+ */
+ if (rate > 1000)
+ rate = 1000;
+ }
+ rv = opt3001_i2c_read(s->port, s->addr, OPT3001_REG_CONFIGURE, &reg);
+ if (rv)
+ return rv;
+
+ rv = opt3001_i2c_write(s->port, s->addr, OPT3001_REG_CONFIGURE,
+ (reg & OPT3001_MODE_MASK) |
+ (mode << OPT3001_MODE_OFFSET));
+ if (rv)
+ return rv;
+
+ drv_data->rate = rate;
+ return EC_SUCCESS;
+}
+
+static int opt3001_get_data_rate(const struct motion_sensor_t *s)
+{
+ struct opt3001_drv_data_t *drv_data = OPT3001_GET_DATA(s);
+
+ return drv_data->rate;
+}
+
+static int opt3001_set_offset(const struct motion_sensor_t *s,
+ const int16_t *offset,
+ int16_t temp)
+{
+ return EC_RES_INVALID_COMMAND;
+}
+
+static int opt3001_get_offset(const struct motion_sensor_t *s,
+ int16_t *offset,
+ int16_t *temp)
+{
+ return EC_RES_INVALID_COMMAND;
+}
+/**
+ * Initialise OPT3001 light sensor.
+ */
+static int opt3001_init(const struct motion_sensor_t *s)
+{
+ int data;
+ int ret;
+
+ ret = opt3001_i2c_read(s->port, s->addr, OPT3001_REG_MAN_ID, &data);
+ if (ret)
+ return ret;
+ if (data != OPT3001_MANUFACTURER_ID)
+ return EC_ERROR_ACCESS_DENIED;
+
+ ret = opt3001_i2c_read(s->port, s->addr, OPT3001_REG_DEV_ID, &data);
+ if (ret)
+ return ret;
+ if (data != OPT3001_DEVICE_ID)
+ return EC_ERROR_ACCESS_DENIED;
+
+ /*
+ * [11] : 1b Conversion time 800ms
+ * [4] : 1b Latched window-style comparison operation
+ */
+ opt3001_i2c_write(s->port, s->addr, OPT3001_REG_CONFIGURE, 0x810);
+ return opt3001_set_range(s, s->default_range, 0);
+}
+
+const struct accelgyro_drv opt3001_drv = {
+ .init = opt3001_init,
+ .read = opt3001_read_lux,
+ .set_range = opt3001_set_range,
+ .get_range = opt3001_get_range,
+ .set_offset = opt3001_set_offset,
+ .get_offset = opt3001_get_offset,
+ .set_data_rate = opt3001_set_data_rate,
+ .get_data_rate = opt3001_get_data_rate,
+};
+
+#ifdef CONFIG_CMD_I2C_STRESS_TEST_ALS
+struct i2c_stress_test_dev opt3001_i2c_stress_test_dev = {
+ .reg_info = {
+ .read_reg = OPT3001_REG_DEV_ID,
+ .read_val = OPT3001_DEVICE_ID,
+ .write_reg = OPT3001_REG_INT_LIMIT_LSB,
+ },
+ .i2c_read = &opt3001_i2c_read,
+ .i2c_write = &opt3001_i2c_write,
+};
+#endif /* CONFIG_CMD_I2C_STRESS_TEST_ALS */
+#endif /* HAS_TASK_ALS */
diff --git a/driver/als_opt3001.h b/driver/als_opt3001.h
index 366e957995..b70909f630 100644
--- a/driver/als_opt3001.h
+++ b/driver/als_opt3001.h
@@ -17,17 +17,57 @@
/* OPT3001 registers */
#define OPT3001_REG_RESULT 0x00
#define OPT3001_REG_CONFIGURE 0x01
+#define OPT3001_RANGE_OFFSET 12
+#define OPT3001_RANGE_MASK 0x0fff
+#define OPT3001_MODE_OFFSET 9
+#define OPT3001_MODE_MASK 0xf9ff
+enum opt3001_mode {
+ OPT3001_MODE_SUSPEND,
+ OPT3001_MODE_FORCED,
+ OPT3001_MODE_CONTINUOUS,
+};
+
#define OPT3001_REG_INT_LIMIT_LSB 0x02
#define OPT3001_REG_INT_LIMIT_MSB 0x03
-#define OPT3001_REG_MAN_ID 0x7E
-#define OPT3001_REG_DEV_ID 0x7F
+#define OPT3001_REG_MAN_ID 0x7e
+#define OPT3001_REG_DEV_ID 0x7f
/* OPT3001 register values */
#define OPT3001_MANUFACTURER_ID 0x5449
#define OPT3001_DEVICE_ID 0x3001
+#ifdef HAS_TASK_ALS
int opt3001_init(void);
int opt3001_read_lux(int *lux, int af);
+#else
+/* OPT3001 Full-Scale Range */
+enum opt3001_range {
+ OPT3001_RANGE_40P95_LUX,
+ OPT3001_RANGE_81P90_LUX,
+ OPT3001_RANGE_163P80_LUX,
+ OPT3001_RANGE_327P60_LUX,
+ OPT3001_RANGE_655P20_LUX,
+ OPT3001_RANGE_1310P40_LUX,
+ OPT3001_RANGE_2620P80_LUX,
+ OPT3001_RANGE_5241P60_LUX,
+ OPT3001_RANGE_10483P20_LUX,
+ OPT3001_RANGE_20966P40_LUX,
+ OPT3001_RANGE_41932P80_LUX,
+ OPT3001_RANGE_83865P60_LUX,
+ OPT3001_RANGE_AUTOMATIC_FULL_SCALE,
+};
+
+#define OPT3001_GET_DATA(_s) ((struct opt3001_drv_data_t *)(_s)->drv_data)
+
+struct opt3001_drv_data_t {
+ enum opt3001_range range;
+ int rate;
+ int last_value;
+ int attenuation;
+};
+
+extern const struct accelgyro_drv opt3001_drv;
+#endif
#ifdef CONFIG_CMD_I2C_STRESS_TEST_ALS
extern struct i2c_stress_test_dev opt3001_i2c_stress_test_dev;
diff --git a/include/ec_commands.h b/include/ec_commands.h
index 86fac1d45c..c65d7f9d0c 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -1950,6 +1950,7 @@ enum motionsensor_chip {
MOTIONSENSE_CHIP_L3GD20H = 7,
MOTIONSENSE_CHIP_BMA255 = 8,
MOTIONSENSE_CHIP_BMP280 = 9,
+ MOTIONSENSE_CHIP_OPT3001 = 10,
};
struct __ec_todo_packed ec_response_motion_sensor_data {
diff --git a/include/motion_sense.h b/include/motion_sense.h
index 3e56e7597b..0ca7443b98 100644
--- a/include/motion_sense.h
+++ b/include/motion_sense.h
@@ -146,6 +146,10 @@ struct motion_sensor_t {
/* Defined at board level. */
extern struct motion_sensor_t motion_sensors[];
extern const unsigned motion_sensor_count;
+#if (!defined HAS_TASK_ALS) && (defined CONFIG_ALS)
+/* Needed if reading ALS via LPC is needed */
+extern const struct motion_sensor_t *motion_als_sensors[];
+#endif
/* optionally defined at board level */
extern unsigned int motion_min_interval;
diff --git a/util/ectool.c b/util/ectool.c
index 3375935d4b..cb90d1af51 100644
--- a/util/ectool.c
+++ b/util/ectool.c
@@ -3632,6 +3632,9 @@ static int cmd_motionsense(int argc, char **argv)
case MOTIONSENSE_CHIP_BMP280:
printf("bmp280\n");
break;
+ case MOTIONSENSE_CHIP_OPT3001:
+ printf("opt3001\n");
+ break;
default:
printf("unknown\n");
}