diff options
author | Nick Vaccaro <nvaccaro@google.com> | 2019-04-10 17:28:16 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2019-05-07 17:22:34 -0700 |
commit | c9840a44d64f8037e83acec7d970c3627bea4f8c (patch) | |
tree | 38874c55fcf325c2f7342116c90d6f4b88b84468 | |
parent | 7e910fa108c6e34b2f27f1980d1cd229a743454b (diff) | |
download | chrome-ec-c9840a44d64f8037e83acec7d970c3627bea4f8c.tar.gz |
driver: add tcs3400 RGB channel sensor driver
Implements a MOTIONSENSE_TYPE_LIGHT_RGB sensor using
the tcs3400.
BUG=b:129419982
BRANCH=master
CQ-DEPEND=CL:1541955
TEST=cherry-pick CLs to enable tcs3400 for flapjack and to add
alslog, build and flash to flapjack; boot flapjack, from ec console,
execute 'sysjump rw', then execute "alslog" to enable logging of als
data. Verify als data is generated and logged to ec console.
Change-Id: Ia8000d27ff4f9683ceb4c9522bc7f0fed20c2045
Signed-off-by: Nick Vaccaro <nvaccaro@google.com>
Reviewed-on: https://chromium-review.googlesource.com/1551748
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Reviewed-by: Gwendal Grignou <gwendal@chromium.org>
-rw-r--r-- | driver/als_tcs3400.c | 164 | ||||
-rw-r--r-- | driver/als_tcs3400.h | 31 | ||||
-rw-r--r-- | include/accelgyro.h | 12 |
3 files changed, 201 insertions, 6 deletions
diff --git a/driver/als_tcs3400.c b/driver/als_tcs3400.c index f63b7156ae..e821b6bb9c 100644 --- a/driver/als_tcs3400.c +++ b/driver/als_tcs3400.c @@ -58,15 +58,28 @@ static int tcs3400_read(const struct motion_sensor_t *s, intv3_t v) return ret; } +static int tcs3400_rgb_read(const struct motion_sensor_t *s, intv3_t v) +{ + return EC_SUCCESS; +} + static int tcs3400_post_events(struct motion_sensor_t *s, uint32_t last_ts) { + /* + * Rule says RGB sensor is right after ALS sensor, and this + * routine will only get called from ALS sensor driver. + */ + struct motion_sensor_t *rgb_s = s + 1; struct tcs3400_drv_data_t *drv_data = TCS3400_DRV_DATA(s); + struct tcs3400_rgb_drv_data_t *rgb_drv_data = + TCS3400_RGB_DRV_DATA(rgb_s); struct ec_response_motion_sensor_data vector; uint8_t light_data[TCS_RGBC_DATA_SIZE]; int *v = s->raw_xyz; int retries = 20; /* 400 ms max */ + int rgb_data[3]; int data = 0; - int ret; + int i, ret; /* Make sure data is valid */ do { @@ -94,6 +107,7 @@ static int tcs3400_post_events(struct motion_sensor_t *s, uint32_t last_ts) data = data * drv_data->als_cal.scale + data * drv_data->als_cal.uscale / 10000; + /* Correct negative values to zero */ if (data < 0) { CPRINTS("Negative clear val 0x%x set to 0", data); data = 0; @@ -124,6 +138,63 @@ skip_clear_vector_load: #endif } +#ifdef CONFIG_ACCEL_SPOOF_MODE + if (s->in_spoof_mode) { + rgb_data[X] = s->spoof_xyz[X]; + rgb_data[Y] = s->spoof_xyz[Y]; + rgb_data[Z] = s->spoof_xyz[Z]; + goto skip_rgb_load; + } +#endif + + for (i = 0; i < 3; i++) { + /* rgb data at indicies 2 thru 7 inclusive in light_data */ + int index = 3 + (i * 2); + + rgb_data[i] = ((light_data[index] << 8) | light_data[index-1]); + rgb_data[i] += rgb_drv_data->rgb_cal[i].offset; + rgb_data[i] *= rgb_drv_data->rgb_cal[i].scale / BIT(15); + rgb_data[i] = rgb_data[i] * rgb_drv_data->device_scale + + rgb_data[i] * rgb_drv_data->device_uscale / 10000; + + /* Correct any negative values to zero */ + if (rgb_data[i] < 0) { + CPRINTS("Negative rgb channel #%d val 0x%x set to 0", + i, rgb_data[i]); + rgb_data[i] = 0; + } + } + +#ifdef CONFIG_ACCEL_SPOOF_MODE +skip_rgb_load: +#endif + /* If anything changed, transfer RGB data */ + if ((rgb_drv_data->last_value[X] != rgb_data[X]) || + (rgb_drv_data->last_value[Y] != rgb_data[Y]) || + (rgb_drv_data->last_value[Z] != rgb_data[Z])) { + for (i = 0; i < 3; i++) + rgb_drv_data->last_value[i] = rgb_data[i]; + v = rgb_s->raw_xyz; + vector.flags = 0; +#ifdef CONFIG_ACCEL_SPOOF_MODE + if (rgb_s->in_spoof_mode) { + for (i = 0; i < 3; i++) + vector.data[i] = v[i] = rgb_s->spoof_xyz[i]; + goto skip_vector_load; + } +#endif /* defined(CONFIG_ACCEL_SPOOF_MODE) */ + + vector.data[X] = v[X] = rgb_data[X]; + vector.data[Y] = v[Y] = rgb_data[Y]; + vector.data[Z] = v[Z] = rgb_data[Z]; + +#ifdef CONFIG_ACCEL_SPOOF_MODE +skip_vector_load: +#endif + vector.sensor_num = rgb_s - motion_sensors; + motion_sense_fifo_add_data(&vector, rgb_s, 3, last_ts); + } + return EC_SUCCESS; } @@ -136,7 +207,7 @@ void tcs3400_interrupt(enum gpio_signal signal) CONFIG_ALS_TCS3400_INT_EVENT, 0); } -/** +/* * tcs3400_irq_handler - bottom half of the interrupt stack. * Ran from the motion_sense task, finds the events that raised the interrupt, * and posts those events via motion_sense_fifo_add_data().. @@ -175,6 +246,77 @@ static int tcs3400_irq_handler(struct motion_sensor_t *s, uint32_t *event) return ret; } +static int tcs3400_rgb_get_range(const struct motion_sensor_t *s) +{ + /* Currently, calibration info is same for all channels */ + return (TCS3400_RGB_DRV_DATA(s)->device_scale << 16) | + TCS3400_RGB_DRV_DATA(s)->device_uscale; +} + +static int tcs3400_rgb_set_range(const struct motion_sensor_t *s, + int range, + int rnd) +{ + TCS3400_RGB_DRV_DATA(s)->device_scale = range >> 16; + TCS3400_RGB_DRV_DATA(s)->device_uscale = range & 0xffff; + return EC_SUCCESS; +} + +static int tcs3400_rgb_get_scale(const struct motion_sensor_t *s, + uint16_t *scale, + int16_t *temp) +{ + scale[X] = TCS3400_RGB_DRV_DATA(s)->rgb_cal[X].scale; + scale[Y] = TCS3400_RGB_DRV_DATA(s)->rgb_cal[Y].scale; + scale[Z] = TCS3400_RGB_DRV_DATA(s)->rgb_cal[Z].scale; + *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; + return EC_SUCCESS; +} + +static int tcs3400_rgb_set_scale(const struct motion_sensor_t *s, + const uint16_t *scale, + int16_t temp) +{ + TCS3400_RGB_DRV_DATA(s)->rgb_cal[X].scale = scale[X]; + TCS3400_RGB_DRV_DATA(s)->rgb_cal[Y].scale = scale[Y]; + TCS3400_RGB_DRV_DATA(s)->rgb_cal[Z].scale = scale[Z]; + return EC_SUCCESS; +} + +static int tcs3400_rgb_get_offset(const struct motion_sensor_t *s, + int16_t *offset, + int16_t *temp) +{ + offset[X] = TCS3400_RGB_DRV_DATA(s)->rgb_cal[X].offset; + offset[Y] = TCS3400_RGB_DRV_DATA(s)->rgb_cal[Y].offset; + offset[Z] = TCS3400_RGB_DRV_DATA(s)->rgb_cal[Z].offset; + *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; + return EC_SUCCESS; +} + +static int tcs3400_rgb_set_offset(const struct motion_sensor_t *s, + const int16_t *offset, + int16_t temp) +{ + TCS3400_RGB_DRV_DATA(s)->rgb_cal[X].offset = offset[X]; + TCS3400_RGB_DRV_DATA(s)->rgb_cal[Y].offset = offset[Y]; + TCS3400_RGB_DRV_DATA(s)->rgb_cal[Z].offset = offset[Z]; + return EC_SUCCESS; +} + +static int tcs3400_rgb_get_data_rate(const struct motion_sensor_t *s) +{ + return TCS3400_RGB_DRV_DATA(s)->rate; +} + +static int tcs3400_rgb_set_data_rate(const struct motion_sensor_t *s, + int rate, + int rnd) +{ + TCS3400_RGB_DRV_DATA(s)->rate = rate; + return EC_SUCCESS; +} + static int tcs3400_get_range(const struct motion_sensor_t *s) { return (TCS3400_DRV_DATA(s)->als_cal.scale << 16) | @@ -250,6 +392,11 @@ static int tcs3400_set_data_rate(const struct motion_sensor_t *s, /** * Initialise TCS3400 light sensor. */ +static int tcs3400_rgb_init(const struct motion_sensor_t *s) +{ + return sensor_init_done(s); +} + static int tcs3400_init(const struct motion_sensor_t *s) { /* @@ -310,3 +457,16 @@ const struct accelgyro_drv tcs3400_drv = { .irq_handler = tcs3400_irq_handler, #endif }; + +const struct accelgyro_drv tcs3400_rgb_drv = { + .init = tcs3400_rgb_init, + .read = tcs3400_rgb_read, + .set_range = tcs3400_rgb_set_range, + .get_range = tcs3400_rgb_get_range, + .set_offset = tcs3400_rgb_set_offset, + .get_offset = tcs3400_rgb_get_offset, + .set_scale = tcs3400_rgb_set_scale, + .get_scale = tcs3400_rgb_get_scale, + .set_data_rate = tcs3400_rgb_set_data_rate, + .get_data_rate = tcs3400_rgb_get_data_rate, +}; diff --git a/driver/als_tcs3400.h b/driver/als_tcs3400.h index dff3d5cdb7..f695fdb387 100644 --- a/driver/als_tcs3400.h +++ b/driver/als_tcs3400.h @@ -81,16 +81,39 @@ enum tcs3400_mode { #error "EC too slow for light sensor" #endif +/* Individual channel scale value between 0 and 2 to a 32-bit value */ +#define TCS3400_SCALE(x) (x << 15) + #define TCS3400_DRV_DATA(_s) ((struct tcs3400_drv_data_t *)(_s)->drv_data) +#define TCS3400_RGB_DRV_DATA(_s) \ + ((struct tcs3400_rgb_drv_data_t *)(_s)->drv_data) -/* Private tcs3400 driver data */ +/* Private tcs3400 als driver data */ struct tcs3400_drv_data_t { - int rate; /* holds current sensor rate */ - int last_value; /* holds last als clear channel value */ - struct als_calibration_t als_cal; /* calibration data */ + int rate; /* holds current sensor rate */ + int last_value; /* holds last als clear channel value */ + struct als_calibration_t als_cal; /* calibration data */ +}; + +/* Private tcs3400 rgb driver data */ +struct tcs3400_rgb_drv_data_t { + /* + * device_scale and device_uscale are used to adjust raw rgb channel + * values prior to applying any channel-specific scaling required. + * raw_value += rgb_cal.offset; + * adjusted_value = raw_value * device_scale + + * raw_value * device_uscale / 10000; + */ + uint16_t device_scale; + uint16_t device_uscale; + + int rate; /* holds current sensor rate */ + int last_value[3]; /* holds last RGB values */ + struct rgb_calibration_t rgb_cal[3]; /* calibration data */ }; extern const struct accelgyro_drv tcs3400_drv; +extern const struct accelgyro_drv tcs3400_rgb_drv; void tcs3400_interrupt(enum gpio_signal signal); #endif /* __CROS_EC_ALS_TCS3400_H */ diff --git a/include/accelgyro.h b/include/accelgyro.h index 0d00116ed6..a8724a43ee 100644 --- a/include/accelgyro.h +++ b/include/accelgyro.h @@ -165,6 +165,18 @@ struct als_calibration_t { int16_t offset; }; +/* RGB ALS Calibration Data */ +struct rgb_calibration_t { + /* + * Each channel has a scaling factor for normalization, representing + * a value between 0 and 2 (1 is translated as 1 << 15) + */ + uint16_t scale; + + /* Any offset to add to raw channel data */ + int16_t offset; +}; + #define SENSOR_APPLY_SCALE(_input, _scale) \ (((_input) * (_scale)) / MOTION_SENSE_DEFAULT_SCALE) |