diff options
-rw-r--r-- | board/reef/board.c | 55 | ||||
-rw-r--r-- | board/reef/board.h | 17 | ||||
-rw-r--r-- | board/reef/ec.tasklist | 1 | ||||
-rw-r--r-- | common/motion_sense.c | 16 | ||||
-rw-r--r-- | driver/als_opt3001.c | 211 | ||||
-rw-r--r-- | driver/als_opt3001.h | 44 | ||||
-rw-r--r-- | include/ec_commands.h | 1 | ||||
-rw-r--r-- | include/motion_sense.h | 4 | ||||
-rw-r--r-- | util/ectool.c | 3 |
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, ®); + 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, ®); + 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"); } |