summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Vaccaro <nvaccaro@google.com>2019-04-10 17:28:16 -0700
committerchrome-bot <chrome-bot@chromium.org>2019-05-07 17:22:34 -0700
commitc9840a44d64f8037e83acec7d970c3627bea4f8c (patch)
tree38874c55fcf325c2f7342116c90d6f4b88b84468
parent7e910fa108c6e34b2f27f1980d1cd229a743454b (diff)
downloadchrome-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.c164
-rw-r--r--driver/als_tcs3400.h31
-rw-r--r--include/accelgyro.h12
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)