From bbbbde0fc044358bb511dab7ca94b974cccfdbd2 Mon Sep 17 00:00:00 2001 From: Gwendal Grignou Date: Thu, 6 Aug 2015 11:59:54 -0700 Subject: driver: si114x: Add ALS/Proxy sensor SI114x Add the Silicon Image sensors, add it to the motion_sense module to be used with the FIFO. BRANCH=smaug TEST=Check light and proxy on Smaug: Check Light value in Lux are reasonable. Check Proxy is detecting object, but value are in opposite of distance. BUG=chrome-os-partner:32829 Change-Id: I11419a0f0613f0fae9323f99deedf5a1e6c6e29c Signed-off-by: Gwendal Grignou Reviewed-on: https://chromium-review.googlesource.com/291335 Reviewed-by: Sheng-liang Song --- driver/als_si114x.c | 545 ++++++++++++++++++++++++++++++++++++++++++++++++++ driver/als_si114x.h | 245 +++++++++++++++++++++++ driver/build.mk | 1 + include/config.h | 9 + include/ec_commands.h | 9 +- 5 files changed, 807 insertions(+), 2 deletions(-) create mode 100644 driver/als_si114x.c create mode 100644 driver/als_si114x.h diff --git a/driver/als_si114x.c b/driver/als_si114x.c new file mode 100644 index 0000000000..6441873ed7 --- /dev/null +++ b/driver/als_si114x.c @@ -0,0 +1,545 @@ +/* Copyright 2015 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. + * + * Silicon Image SI1141/SI1142 light sensor driver + * + * Started from linux si114x driver. + */ +#include "accelgyro.h" +#include "common.h" +#include "console.h" +#include "driver/als_si114x.h" +#include "hooks.h" +#include "i2c.h" +#include "math_util.h" +#include "task.h" +#include "timer.h" +#include "util.h" + +#define CPUTS(outstr) cputs(CC_ACCEL, outstr) +#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args) +#define CPRINTS(format, args...) cprints(CC_ACCEL, format, ## args) + +/** + * Read 8bit register from device. + */ +static inline int raw_read8(const int addr, const int reg, int *data_ptr) +{ + return i2c_read8(I2C_PORT_ALS, addr, reg, data_ptr); +} + +/** + * Write 8bit register from device. + */ +static inline int raw_write8(const int addr, const int reg, int data) +{ + return i2c_write8(I2C_PORT_ALS, addr, reg, data); +} + +/** + * Read 16bit register from device. + */ +static inline int raw_read16(const int addr, const int reg, int *data_ptr) +{ + return i2c_read16(I2C_PORT_ALS, addr, reg, data_ptr); +} + +/* helper function to operate on parameter values: op can be query/set/or/and */ +static int si114x_param_op(const struct motion_sensor_t *s, + uint8_t op, + uint8_t param, + int *value) +{ + int ret; + + mutex_lock(s->mutex); + + if (op != SI114X_CMD_PARAM_QUERY) { + ret = raw_write8(s->addr, SI114X_REG_PARAM_WR, *value); + if (ret != EC_SUCCESS) + goto error; + } + + ret = raw_write8(s->addr, SI114X_REG_COMMAND, op | (param & 0x1F)); + if (ret != EC_SUCCESS) + goto error; + + ret = raw_read8(s->addr, SI114X_REG_PARAM_RD, value); + if (ret != EC_SUCCESS) + goto error; + + mutex_unlock(s->mutex); + + *value &= 0xff; + return EC_SUCCESS; +error: + mutex_unlock(s->mutex); + return ret; +} + +static int si114x_read_results(struct motion_sensor_t *s, int nb) +{ + int i, ret, val; + struct si114x_typed_data_t *type_data = SI114X_GET_TYPED_DATA(s); +#ifdef CONFIG_ACCEL_FIFO + struct ec_response_motion_sensor_data vector; +#endif + + /* Read ALX result */ + for (i = 0; i < nb; i++) { + ret = raw_read16(s->addr, type_data->base_data_reg + i * 2, + &val); + if (ret) + break; + /* Add offset, calibration */ + if (val + type_data->offset < 0) { + val = 0; + } else { + val += type_data->offset; + val = val * type_data->scale + + val * type_data->uscale / 10000; + } + s->raw_xyz[i] = val; + } + + if (ret != EC_SUCCESS) + return ret; + + /* Add in fifo if changed only */ + for (i = 0; i < nb; i++) { + if (s->raw_xyz[i] != s->xyz[i]) + break; + } + if (i == nb) + return EC_SUCCESS; + +#ifdef CONFIG_ACCEL_FIFO + vector.flags = 0; + for (i = 0; i < nb; i++) + vector.data[i] = s->raw_xyz[i]; + for (i = nb; i < 3; i++) + vector.data[i] = 0; + motion_sense_fifo_add_unit(&vector, s, 1); +#else + /* We need to copy raw_xyz into xyz with mutex */ +#endif + return EC_SUCCESS; +} + +void si114x_interrupt(enum gpio_signal signal) +{ + task_set_event(TASK_ID_MOTIONSENSE, + CONFIG_ALS_SI114X_INT_EVENT, 0); +} + +/** + * irq_handler - bottom half of the interrupt stack. + * Ran from the motion_sense task, finds the events that raised the interrupt. + * + * For now, we just print out. We should set a bitmask motion sense code will + * act upon. + */ +static int irq_handler(struct motion_sensor_t *s, uint32_t event) +{ + int ret = EC_SUCCESS, val; + struct si114x_drv_data_t *data = SI114X_GET_DATA(s); + struct si114x_typed_data_t *type_data = SI114X_GET_TYPED_DATA(s); + + if (!(event & CONFIG_ALS_SI114X_INT_EVENT)) + return EC_SUCCESS; + + ret = raw_read8(s->addr, SI114X_REG_IRQ_STATUS, &val); + if (ret < 0 || !(val & type_data->irq_flags)) + return EC_SUCCESS; + + /* clearing IRQ */ + ret = raw_write8(s->addr, SI114X_REG_IRQ_STATUS, + val & type_data->irq_flags); + if (ret != EC_SUCCESS) + CPRINTS("clearing irq failed"); + + switch (data->state) { + case SI114X_ALS_IN_PROGRESS: + case SI114X_ALS_IN_PROGRESS_PS_PENDING: + /* We are only reading the visible light sensor */ + ret = si114x_read_results(s, 1); + /* Fire pending requests */ + if (data->state == SI114X_ALS_IN_PROGRESS_PS_PENDING) { + ret = raw_write8(s->addr, SI114X_REG_COMMAND, + SI114X_CMD_PS_FORCE); + data->state = SI114X_PS_IN_PROGRESS; + } else { + data->state = SI114X_IDLE; + } + break; + case SI114X_PS_IN_PROGRESS: + case SI114X_PS_IN_PROGRESS_ALS_PENDING: + /* Read PS results */ + ret = si114x_read_results(s, SI114X_NUM_LEDS); + if (data->state == SI114X_PS_IN_PROGRESS_ALS_PENDING) { + ret = raw_write8(s->addr, SI114X_REG_COMMAND, + SI114X_CMD_ALS_FORCE); + data->state = SI114X_ALS_IN_PROGRESS; + } else { + data->state = SI114X_IDLE; + } + break; + case SI114X_IDLE: + default: + CPRINTS("Invalid state"); + } + return ret; +} + +/* Just trigger a measurement */ +static int read(const struct motion_sensor_t *s, vector_3_t v) +{ + int ret; + uint8_t cmd; + struct si114x_drv_data_t *data = SI114X_GET_DATA(s); + + switch (data->state) { + case SI114X_ALS_IN_PROGRESS: + if (s->type == MOTIONSENSE_TYPE_PROX) + data->state = SI114X_ALS_IN_PROGRESS_PS_PENDING; +#if 0 + else + CPRINTS("Invalid state"); +#endif + ret = EC_ERROR_BUSY; + break; + case SI114X_PS_IN_PROGRESS: + if (s->type == MOTIONSENSE_TYPE_LIGHT) + data->state = SI114X_PS_IN_PROGRESS_ALS_PENDING; +#if 0 + else + CPRINTS("Invalid state"); +#endif + ret = EC_ERROR_BUSY; + break; + case SI114X_IDLE: + switch (s->type) { + case MOTIONSENSE_TYPE_LIGHT: + cmd = SI114X_CMD_ALS_FORCE; + data->state = SI114X_ALS_IN_PROGRESS; + break; + case MOTIONSENSE_TYPE_PROX: + cmd = SI114X_CMD_PS_FORCE; + data->state = SI114X_PS_IN_PROGRESS; + break; + default: + CPRINTS("Invalid sensor type"); + } + ret = raw_write8(s->addr, SI114X_REG_COMMAND, cmd); + ret = EC_RES_IN_PROGRESS; + break; + case SI114X_ALS_IN_PROGRESS_PS_PENDING: + case SI114X_PS_IN_PROGRESS_ALS_PENDING: + default: + ret = EC_ERROR_ACCESS_DENIED; + } + return ret; +} + +static int si114x_set_chlist(const struct motion_sensor_t *s) +{ + int reg = 0; + + /* Not interested in temperature (AUX nor IR) */ + reg = SI114X_CHLIST_EN_ALSVIS; + switch (SI114X_NUM_LEDS) { + case 3: + reg |= SI114X_CHLIST_EN_PS3; + case 2: + reg |= SI114X_CHLIST_EN_PS2; + case 1: + reg |= SI114X_CHLIST_EN_PS1; + break; + } + + return si114x_param_op(s, SI114X_CMD_PARAM_SET, + SI114X_PARAM_CHLIST, ®); +} + +#ifdef CONFIG_ALS_SI114X_CHECK_REVISION +static int si114x_revisions(const struct motion_sensor_t *s) +{ + int val; + int ret = raw_read8(s->addr, SI114X_REG_PART_ID, &val); + if (ret != EC_SUCCESS) + return ret; + + if (val != CONFIG_ALS_SI114X) { + CPRINTS("invalid part"); + return EC_ERROR_ACCESS_DENIED; + } + + ret = raw_read8(s->addr, SI114X_REG_SEQ_ID, &val); + if (ret != EC_SUCCESS) + return ret; + + if (val < SI114X_SEQ_REV_A03) + CPRINTS("WARNING: old sequencer revision"); + + return 0; +} +#endif + +static int si114x_initialize(const struct motion_sensor_t *s) +{ + int ret, val; + + /* send reset command */ + ret = raw_write8(s->addr, SI114X_REG_COMMAND, SI114X_CMD_RESET); + if (ret != EC_SUCCESS) + return ret; + msleep(20); + + /* hardware key, magic value */ + ret = raw_write8(s->addr, SI114X_REG_HW_KEY, 0x17); + if (ret != EC_SUCCESS) + return ret; + msleep(20); + + /* interrupt configuration, interrupt output enable */ + ret = raw_write8(s->addr, SI114X_REG_INT_CFG, SI114X_INT_CFG_OE); + if (ret != EC_SUCCESS) + return ret; + + /* enable interrupt for certain activities */ + ret = raw_write8(s->addr, SI114X_REG_IRQ_ENABLE, + SI114X_PS3_IE | SI114X_PS2_IE | SI114X_PS1_IE | + SI114X_ALS_INT0_IE); + if (ret != EC_SUCCESS) + return ret; + + /* Only forced mode */ + ret = raw_write8(s->addr, SI114X_REG_MEAS_RATE, 0); + if (ret != EC_SUCCESS) + return ret; + + /* measure ALS every time device wakes up */ + ret = raw_write8(s->addr, SI114X_REG_ALS_RATE, 0); + if (ret != EC_SUCCESS) + return ret; + + /* measure proximity every time device wakes up */ + ret = raw_write8(s->addr, SI114X_REG_PS_RATE, 0); + if (ret != EC_SUCCESS) + return ret; + + /* set LED currents to maximum */ + switch (SI114X_NUM_LEDS) { + case 3: + ret = raw_write8(s->addr, + SI114X_REG_PS_LED3, 0x0f); + if (ret != EC_SUCCESS) + return ret; + ret = raw_write8(s->addr, + SI114X_REG_PS_LED21, 0xff); + break; + case 2: + ret = raw_write8(s->addr, + SI114X_REG_PS_LED21, 0xff); + break; + case 1: + ret = raw_write8(s->addr, + SI114X_REG_PS_LED21, 0x0f); + break; + } + if (ret != EC_SUCCESS) + return ret; + + ret = si114x_set_chlist(s); + if (ret != EC_SUCCESS) + return ret; + + /* set normal proximity measurement mode, set high signal range + * PS measurement */ + val = SI114X_PARAM_PS_ADC_MISC_NORMAL_MODE; + ret = si114x_param_op(s, SI114X_CMD_PARAM_SET, + SI114X_PARAM_PS_ADC_MISC, &val); + return ret; +} + +static int set_resolution(const struct motion_sensor_t *s, + int res, + int rnd) +{ + int ret, reg1, reg2, val; + /* override on resolution: set the gain. between 0 to 7 */ + if (s->type == MOTIONSENSE_TYPE_PROX) { + if (res < 0 || res > 5) + return EC_ERROR_PARAM2; + reg1 = SI114X_PARAM_PS_ADC_GAIN; + reg2 = SI114X_PARAM_PS_ADC_COUNTER; + } else { + if (res < 0 || res > 7) + return EC_ERROR_PARAM2; + reg1 = SI114X_PARAM_ALSVIS_ADC_GAIN; + reg2 = SI114X_PARAM_ALSVIS_ADC_COUNTER; + } + + val = res; + ret = si114x_param_op(s, SI114X_CMD_PARAM_SET, reg1, &val); + if (ret != EC_SUCCESS) + return ret; + /* set recovery period to one's complement of gain */ + val = (~res & 0x07) << 4; + ret = si114x_param_op(s, SI114X_CMD_PARAM_SET, reg2, &val); + return ret; +} + +static int get_resolution(const struct motion_sensor_t *s, + int *res) +{ + int ret, reg, val; + if (s->type == MOTIONSENSE_TYPE_PROX) + reg = SI114X_PARAM_PS_ADC_GAIN; + else + /* ignore IR led */ + reg = SI114X_PARAM_ALSVIS_ADC_GAIN; + + val = 0; + ret = si114x_param_op(s, SI114X_CMD_PARAM_QUERY, reg, &val); + if (ret != EC_SUCCESS) + return ret; + + *res = val & 0x07; + return EC_SUCCESS; +} + +static int set_range(const struct motion_sensor_t *s, + int range, + int rnd) +{ + struct si114x_typed_data_t *data = SI114X_GET_TYPED_DATA(s); + data->scale = range >> 16; + data->uscale = range & 0xffff; + return EC_SUCCESS; +} + +static int get_range(const struct motion_sensor_t *s, + int *range) +{ + struct si114x_typed_data_t *data = SI114X_GET_TYPED_DATA(s); + *range = (data->scale << 16) | (data->uscale); + return EC_SUCCESS; +} + +static int get_data_rate(const struct motion_sensor_t *s, + int *rate) +{ + /* Sensor in forced mode, rate is used by motion_sense */ + struct si114x_typed_data_t *data = SI114X_GET_TYPED_DATA(s); + *rate = data->rate; + return EC_SUCCESS; +} + +static int set_data_rate(const struct motion_sensor_t *s, + int rate, + int rnd) +{ + struct si114x_typed_data_t *data = SI114X_GET_TYPED_DATA(s); + data->rate = rate; + return EC_SUCCESS; +} + +static int set_offset(const struct motion_sensor_t *s, + const int16_t *offset, + int16_t temp) +{ + struct si114x_typed_data_t *data = SI114X_GET_TYPED_DATA(s); + data->offset = offset[X]; + return EC_SUCCESS; +} + +static int get_offset(const struct motion_sensor_t *s, + int16_t *offset, + int16_t *temp) +{ + struct si114x_typed_data_t *data = SI114X_GET_TYPED_DATA(s); + offset[X] = data->offset; + offset[Y] = 0; + offset[Z] = 0; + *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; + return EC_SUCCESS; +} + +static int set_interrupt(const struct motion_sensor_t *s, + unsigned int threshold) +{ + /* Currently unsupported. */ + return EC_ERROR_UNKNOWN; +} + +static int init(const struct motion_sensor_t *s) +{ + int ret, resol; + + /* initialize only once: light must be declared first. */ + if (s->type == MOTIONSENSE_TYPE_LIGHT) { +#ifdef CONFIG_ALS_SI114X_CHECK_REVISION + ret = si114x_revisions(s); + if (ret != EC_SUCCESS) + return ret; +#endif + ret = si114x_initialize(s); + if (ret != EC_SUCCESS) + return ret; + resol = 7; + } else { + resol = 5; + } + + set_range(s, s->runtime_config.range, 0); + /* + * Sensor is most likely behind a glass. + * Max out the gain to get correct measurement + */ + set_resolution(s, resol, 0); + + CPRINTF("[%T %s: MS Done Init type:0x%X range:%d]\n", + s->name, s->type, s->runtime_config.range); + return EC_SUCCESS; +} + +const struct accelgyro_drv si114x_drv = { + .init = init, + .read = read, + .set_range = set_range, + .get_range = get_range, + .set_resolution = set_resolution, + .get_resolution = get_resolution, + .set_data_rate = set_data_rate, + .get_data_rate = get_data_rate, + .set_offset = set_offset, + .get_offset = get_offset, + .perform_calib = NULL, +#ifdef CONFIG_ACCEL_INTERRUPTS + .set_interrupt = set_interrupt, + .irq_handler = irq_handler, +#endif + .load_fifo = NULL, +}; + +struct si114x_drv_data_t g_si114x_data = { + .state = SI114X_IDLE, + .type_data = { + /* Proximity */ + { + .base_data_reg = SI114X_REG_PS1_DATA0, + .irq_flags = SI114X_PS_INT_FLAG, + .scale = 1, + .offset = -256, + }, + /* light */ + { + .base_data_reg = SI114X_REG_ALSVIS_DATA0, + .irq_flags = SI114X_ALS_INT_FLAG, + .scale = 1, + .offset = -256, + } + } +}; diff --git a/driver/als_si114x.h b/driver/als_si114x.h new file mode 100644 index 0000000000..de3375b457 --- /dev/null +++ b/driver/als_si114x.h @@ -0,0 +1,245 @@ +/* Copyright 2015 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. + * + * Silicon Image SI1141/SI1142 light sensor driver + */ + +/* + * si114x.c - Support for Silabs si114x combined ambient light and + * proximity sensor + * + * Copyright 2012 Peter Meerwald + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + * + * IIO driver for si114x (7-bit I2C slave address 0x5a) with sequencer + * version >= A03 + */ + +#ifndef __CROS_EC_ALS_SI114X_H +#define __CROS_EC_ALS_SI114X_H + +#define SI114X_ADDR (0x5a << 1) + +#define SI114X_REG_PART_ID 0x00 +#define SI114X_SI1141_ID 0x41 +#define SI114X_SI1142_ID 0x42 +#define SI114X_SI1143_ID 0x43 + +#define SI114X_NUM_LEDS (CONFIG_ALS_SI114X - 0x40) + +#define SI114X_REG_REV_ID 0x01 +#define SI114X_REG_SEQ_ID 0x02 +#define SI114X_REG_INT_CFG 0x03 +#define SI114X_REG_IRQ_ENABLE 0x04 +#define SI114X_REG_IRQ_MODE1 0x05 +#define SI114X_REG_IRQ_MODE2 0x06 +#define SI114X_REG_HW_KEY 0x07 +/* RATE stores a 16 bit value compressed to 8 bit */ +/* Not used, the sensor is in force mode */ +#define SI114X_REG_MEAS_RATE 0x08 + + +#define SI114X_REG_ALS_RATE 0x09 +#define SI114X_REG_PS_RATE 0x0a +#define SI114X_REG_ALS_LOW_TH0 0x0b +#define SI114X_REG_ALS_LOW_TH1 0x0c +#define SI114X_REG_ALS_HI_TH0 0x0d +#define SI114X_REG_ALS_HI_TH1 0x0e +#define SI114X_REG_PS_LED21 0x0f +#define SI114X_REG_PS_LED3 0x10 +/* + * for rev A10 and below TH0 stores a 16 bit value compressed to 8 bit and + * TH1 is not used; newer revision have the LSB in TH0 and the MSB in TH1 + */ +#define SI114X_REG_PS1_TH0 0x11 +#define SI114X_REG_PS1_TH1 0x12 +#define SI114X_REG_PS2_TH0 0x13 +#define SI114X_REG_PS2_TH1 0x11 +#define SI114X_REG_PS3_TH0 0x15 +#define SI114X_REG_PS3_TH1 0x16 +#define SI114X_REG_PARAM_WR 0x17 +#define SI114X_REG_COMMAND 0x18 +#define SI114X_REG_RESPONSE 0x20 +#define SI114X_REG_IRQ_STATUS 0x21 +#define SI114X_REG_ALSVIS_DATA0 0x22 +#define SI114X_REG_ALSVIS_DATA1 0x23 +#define SI114X_REG_ALSIR_DATA0 0x24 +#define SI114X_REG_ALSIR_DATA1 0x25 +#define SI114X_REG_PS1_DATA0 0x26 +#define SI114X_REG_PS1_DATA1 0x27 +#define SI114X_REG_PS2_DATA0 0x28 +#define SI114X_REG_PS2_DATA1 0x29 +#define SI114X_REG_PS3_DATA0 0x2a +#define SI114X_REG_PS3_DATA1 0x2b +#define SI114X_REG_AUX_DATA0 0x2c +#define SI114X_REG_AUX_DATA1 0x2d +#define SI114X_REG_PARAM_RD 0x2e +#define SI114X_REG_CHIP_STAT 0x30 + +/* helper to figure out PS_LED register / shift per channel */ +#define SI114X_PS_LED_REG(ch) \ + (((ch) == 2) ? SI114X_REG_PS_LED3 : SI114X_REG_PS_LED21) +#define SI114X_PS_LED_SHIFT(ch) \ + (((ch) == 1) ? 4 : 0) + +/* Parameter offsets */ +#define SI114X_PARAM_I2C_ADDR 0x00 +#define SI114X_PARAM_CHLIST 0x01 +#define SI114X_PARAM_PSLED12_SELECT 0x02 +#define SI114X_PARAM_PSLED3_SELECT 0x03 +#define SI114X_PARAM_FILTER_EN 0x04 +#define SI114X_PARAM_PS_ENCODING 0x05 +#define SI114X_PARAM_ALS_ENCODING 0x06 +#define SI114X_PARAM_PS1_ADC_MUX 0x07 +#define SI114X_PARAM_PS2_ADC_MUX 0x08 +#define SI114X_PARAM_PS3_ADC_MUX 0x09 +#define SI114X_PARAM_PS_ADC_COUNTER 0x0a +#define SI114X_PARAM_PS_ADC_GAIN 0x0b +#define SI114X_PARAM_PS_ADC_MISC 0x0c +#define SI114X_PARAM_PS_ADC_MISC_HIGH_RANGE 0x20 +#define SI114X_PARAM_PS_ADC_MISC_NORMAL_MODE 0x04 +#define SI114X_PARAM_ALS_ADC_MUX 0x0d +#define SI114X_PARAM_ALSIR_ADC_MUX 0x0e +#define SI114X_PARAM_AUX_ADC_MUX 0x0f +#define SI114X_PARAM_ALSVIS_ADC_COUNTER 0x10 +#define SI114X_PARAM_ALSVIS_ADC_GAIN 0x11 +#define SI114X_PARAM_ALSVIS_ADC_MISC 0x12 +#define SI114X_PARAM_ALS_HYST 0x16 +#define SI114X_PARAM_PS_HYST 0x17 +#define SI114X_PARAM_PS_HISTORY 0x18 +#define SI114X_PARAM_ALS_HISTORY 0x19 +#define SI114X_PARAM_ADC_OFFSET 0x1a +#define SI114X_PARAM_SLEEP_CTRL 0x1b +#define SI114X_PARAM_LED_RECOVERY 0x1c +#define SI114X_PARAM_ALSIR_ADC_COUNTER 0x1d +#define SI114X_PARAM_ALSIR_ADC_GAIN 0x1e +#define SI114X_PARAM_ALSIR_ADC_MISC 0x1f + +/* Channel enable masks for CHLIST parameter */ +#define SI114X_CHLIST_EN_PS1 0x01 +#define SI114X_CHLIST_EN_PS2 0x02 +#define SI114X_CHLIST_EN_PS3 0x04 +#define SI114X_CHLIST_EN_ALSVIS 0x10 +#define SI114X_CHLIST_EN_ALSIR 0x20 +#define SI114X_CHLIST_EN_AUX 0x40 + +/* Signal range mask for ADC_MISC parameter */ +#define SI114X_MISC_RANGE 0x20 + +/* Commands for REG_COMMAND */ +#define SI114X_CMD_NOP 0x00 +#define SI114X_CMD_RESET 0x01 +#define SI114X_CMD_BUSADDR 0x02 +#define SI114X_CMD_PS_FORCE 0x05 +#define SI114X_CMD_ALS_FORCE 0x06 +#define SI114X_CMD_PSALS_FORCE 0x07 +#define SI114X_CMD_PS_PAUSE 0x09 +#define SI114X_CMD_ALS_PAUSE 0x0a +#define SI114X_CMD_PSALS_PAUSE 0x0b +#define SI114X_CMD_PS_AUTO 0x0d +#define SI114X_CMD_ALS_AUTO 0x0e +#define SI114X_CMD_PSALS_AUTO 0x0f +#define SI114X_CMD_PARAM_QUERY 0x80 +#define SI114X_CMD_PARAM_SET 0xa0 +#define SI114X_CMD_PARAM_AND 0xc0 +#define SI114X_CMD_PARAM_OR 0xe0 + +/* Interrupt configuration masks for INT_CFG register */ +#define SI114X_INT_CFG_OE 0x01 /* enable interrupt */ +#define SI114X_INT_CFG_MODE 0x02 /* auto reset interrupt pin */ + +/* Interrupt enable masks for IRQ_ENABLE register */ +#define SI114X_CMD_IE 0x20 +#define SI114X_PS3_IE 0x10 +#define SI114X_PS2_IE 0x08 +#define SI114X_PS1_IE 0x04 +#define SI114X_ALS_INT1_IE 0x02 +#define SI114X_ALS_INT0_IE 0x01 +#define SI114X_ALS_INT_FLAG \ + (SI114X_ALS_INT1_IE | SI114X_ALS_INT0_IE) +#define SI114X_PS_INT_FLAG \ + (SI114X_PS3_IE | SI114X_PS2_IE | SI114X_PS1_IE) + + +/* Interrupt mode masks for IRQ_MODE1 register */ +#define SI114X_PS2_IM_GREATER 0xc0 +#define SI114X_PS2_IM_CROSS 0x40 +#define SI114X_PS1_IM_GREATER 0x30 +#define SI114X_PS1_IM_CROSS 0x10 + +/* Interrupt mode masks for IRQ_MODE2 register */ +#define SI114X_CMD_IM_ERROR 0x04 +#define SI114X_PS3_IM_GREATER 0x03 +#define SI114X_PS3_IM_CROSS 0x01 + +/* Measurement rate settings */ +#define SI114X_MEAS_RATE_FORCED 0x00 +#define SI114X_MEAS_RATE_10MS 0x84 +#define SI114X_MEAS_RATE_20MS 0x94 +#define SI114X_MEAS_RATE_100MS 0xb9 +#define SI114X_MEAS_RATE_496MS 0xdf +#define SI114X_MEAS_RATE_1984MS 0xff + +/* ALS rate settings relative to measurement rate */ +#define SI114X_ALS_RATE_OFF 0x00 +#define SI114X_ALS_RATE_1X 0x08 +#define SI114X_ALS_RATE_10X 0x32 +#define SI114X_ALS_RATE_100X 0x69 + +/* PS rate settings relative to measurement rate */ +#define SI114X_PS_RATE_OFF 0x00 +#define SI114X_PS_RATE_1X 0x08 +#define SI114X_PS_RATE_10X 0x32 +#define SI114X_PS_RATE_100X 0x69 + +/* Sequencer revision from SEQ_ID */ +#define SI114X_SEQ_REV_A01 0x01 +#define SI114X_SEQ_REV_A02 0x02 +#define SI114X_SEQ_REV_A03 0x03 +#define SI114X_SEQ_REV_A10 0x08 +#define SI114X_SEQ_REV_A11 0x09 + +extern const struct accelgyro_drv si114x_drv; + +enum si114x_state { + SI114X_IDLE, + SI114X_ALS_IN_PROGRESS, + SI114X_ALS_IN_PROGRESS_PS_PENDING, + SI114X_PS_IN_PROGRESS, + SI114X_PS_IN_PROGRESS_ALS_PENDING, +}; + +/** + * struct si114x_data - si114x chip state data + * @client: I2C client + **/ +struct si114x_typed_data_t { + uint8_t base_data_reg; + uint8_t irq_flags; + /* requested frequency, in mHz */ + int rate; + /* the coef is scale.uscale */ + int16_t scale; + uint16_t uscale; + int16_t offset; +}; + +struct si114x_drv_data_t { + enum si114x_state state; + struct si114x_typed_data_t type_data[2]; +}; + +#define SI114X_GET_DATA(_s) \ + ((struct si114x_drv_data_t *)(_s)->drv_data) + +#define SI114X_GET_TYPED_DATA(_s) \ + (&SI114X_GET_DATA(_s)->type_data[(_s)->type - MOTIONSENSE_TYPE_PROX]) + +extern struct si114x_drv_data_t g_si114x_data; +void si114x_interrupt(enum gpio_signal signal); + +#endif /* __CROS_EC_ALS_SI114X_H */ diff --git a/driver/build.mk b/driver/build.mk index 8c30dd5b5a..b617033977 100644 --- a/driver/build.mk +++ b/driver/build.mk @@ -15,6 +15,7 @@ driver-$(CONFIG_MAG_BMI160_BMM150)+=mag_bmm150.o # ALS drivers driver-$(CONFIG_ALS_ISL29035)+=als_isl29035.o driver-$(CONFIG_ALS_OPT3001)+=als_opt3001.o +driver-$(CONFIG_ALS_SI114X)+=als_si114x.o # Batteries driver-$(CONFIG_BATTERY_BQ20Z453)+=battery/bq20z453.o diff --git a/include/config.h b/include/config.h index b4eb21df59..86494f1900 100644 --- a/include/config.h +++ b/include/config.h @@ -71,6 +71,15 @@ #undef CONFIG_ALS #undef CONFIG_ALS_ISL29035 #undef CONFIG_ALS_OPT3001 +/* Define the exact model ID present on the board: SI1141 = 41, SI1142 = 42, */ +#undef CONFIG_ALS_SI114X +/* Check if the device revision is supported */ +#undef CONFIG_ALS_SI114X_CHECK_REVISION +/* + * Define the event to raise when BMI160 interrupt. + * Must be within TASK_EVENT_MOTION_INTERRUPT_MASK. + */ +#undef CONFIG_ALS_SI114X_INT_EVENT /* Support AP hang detection host command and state machine */ #undef CONFIG_AP_HANG_DETECT diff --git a/include/ec_commands.h b/include/ec_commands.h index 13ce200683..6f6ee32a34 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -1709,14 +1709,16 @@ enum motionsensor_type { MOTIONSENSE_TYPE_ACCEL = 0, MOTIONSENSE_TYPE_GYRO = 1, MOTIONSENSE_TYPE_MAG = 2, - MOTIONSENSE_TYPE_MAX = 3, + MOTIONSENSE_TYPE_PROX = 3, + MOTIONSENSE_TYPE_LIGHT = 4, + MOTIONSENSE_TYPE_MAX, }; /* List of motion sensor locations. */ enum motionsensor_location { MOTIONSENSE_LOC_BASE = 0, MOTIONSENSE_LOC_LID = 1, - MOTIONSENSE_LOC_MAX = 2, + MOTIONSENSE_LOC_MAX, }; /* List of motion sensor chips. */ @@ -1724,6 +1726,9 @@ enum motionsensor_chip { MOTIONSENSE_CHIP_KXCJ9 = 0, MOTIONSENSE_CHIP_LSM6DS0 = 1, MOTIONSENSE_CHIP_BMI160 = 2, + MOTIONSENSE_CHIP_SI1141 = 3, + MOTIONSENSE_CHIP_SI1142 = 4, + MOTIONSENSE_CHIP_SI1143 = 5, }; struct ec_response_motion_sensor_data { -- cgit v1.2.1