summaryrefslogtreecommitdiff
path: root/driver/als_tcs3400.c
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2021-11-04 12:11:58 -0600
committerCommit Bot <commit-bot@chromium.org>2021-11-05 04:22:34 +0000
commit252457d4b21f46889eebad61d4c0a65331919cec (patch)
tree01856c4d31d710b20e85a74c8d7b5836e35c3b98 /driver/als_tcs3400.c
parent08f5a1e6fc2c9467230444ac9b582dcf4d9f0068 (diff)
downloadchrome-ec-stabilize-14633.B-ish.tar.gz
In the interest of making long-term branch maintenance incur as little technical debt on us as possible, we should not maintain any files on the branch we are not actually using. This has the added effect of making it extremely clear when merging CLs from the main branch when changes have the possibility to affect us. The follow-on CL adds a convenience script to actually pull updates from the main branch and generate a CL for the update. BUG=b:204206272 BRANCH=ish TEST=make BOARD=arcada_ish && make BOARD=drallion_ish Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Change-Id: I17e4694c38219b5a0823e0a3e55a28d1348f4b18 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3262038 Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Tom Hughes <tomhughes@chromium.org>
Diffstat (limited to 'driver/als_tcs3400.c')
-rw-r--r--driver/als_tcs3400.c816
1 files changed, 0 insertions, 816 deletions
diff --git a/driver/als_tcs3400.c b/driver/als_tcs3400.c
deleted file mode 100644
index 30b24c4412..0000000000
--- a/driver/als_tcs3400.c
+++ /dev/null
@@ -1,816 +0,0 @@
-/* Copyright 2019 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.
- *
- * AMS TCS3400 light sensor driver
- */
-#include "accelgyro.h"
-#include "common.h"
-#include "console.h"
-#include "als_tcs3400.h"
-#include "hooks.h"
-#include "hwtimer.h"
-#include "i2c.h"
-#include "math_util.h"
-#include "motion_sense_fifo.h"
-#include "task.h"
-#include "util.h"
-
-#define CPRINTS(fmt, args...) cprints(CC_ACCEL, "%s "fmt, __func__, ## args)
-
-#if defined(CONFIG_ZEPHYR) && defined(CONFIG_ACCEL_INTERRUPTS)
-/*
- * Get the mostion sensor ID of the TCS3400 sensor that
- * generates the interrupt.
- * The interrupt is converted to the event and transferred to motion
- * sense task that actually handles the interrupt.
- *
- * Here, we use alias to get the motion sensor ID
- *
- * e.g) als_clear below is the label of a child node in /motionsense-sensors
- * aliases {
- * tcs3400-int = &als_clear;
- * };
- */
-#if DT_NODE_EXISTS(DT_ALIAS(tcs3400_int))
-#define CONFIG_ALS_TCS3400_INT_EVENT \
- TASK_EVENT_MOTION_SENSOR_INTERRUPT(SENSOR_ID(DT_ALIAS(tcs3400_int)))
-#endif
-#endif
-
-STATIC_IF(CONFIG_ACCEL_FIFO) volatile uint32_t last_interrupt_timestamp;
-
-#ifdef CONFIG_TCS_USE_LUX_TABLE
-/*
- * Stores the number of atime increments/decrements needed to change light value
- * by 1% of saturation for each gain setting for each predefined LUX range.
- *
- * Values in array are TCS_ATIME_GAIN_FACTOR (100x) times actual value to allow
- * for fractions using integers.
- */
-static const uint16_t
-range_atime[TCS_MAX_AGAIN - TCS_MIN_AGAIN + 1][TCS_MAX_ATIME_RANGES] = {
-{11200, 5600, 5600, 7200, 5500, 4500, 3800, 3800, 3300, 2900, 2575, 2275, 2075},
-{11200, 5100, 2700, 1840, 1400, 1133, 981, 963, 833, 728, 650, 577, 525},
-{250, 1225, 643, 441, 337, 276, 253, 235, 203, 176, 150, 0, 0},
-{790, 261, 163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
-
-static void
-decrement_atime(struct tcs_saturation_t *sat_p, uint16_t cur_lux, int percent)
-{
- int atime;
- uint16_t steps;
- int lux = MIN(cur_lux, TCS_GAIN_TABLE_MAX_LUX);
-
- steps = percent * range_atime[sat_p->again][lux / 1000] /
- TCS_ATIME_GAIN_FACTOR;
- atime = MAX(sat_p->atime - steps, TCS_MIN_ATIME);
- sat_p->atime = MIN(atime, TCS_MAX_ATIME);
-}
-
-#else
-
-static void
-decrement_atime(struct tcs_saturation_t *sat_p,
- uint16_t __attribute__((unused)) cur_lux,
- int __attribute__((unused)) percent)
-{
- sat_p->atime = MAX(sat_p->atime - TCS_ATIME_DEC_STEP, TCS_MIN_ATIME);
-}
-
-#endif /* CONFIG_TCS_USE_LUX_TABLE */
-
-static void increment_atime(struct tcs_saturation_t *sat_p)
-{
- sat_p->atime = MIN(sat_p->atime + TCS_ATIME_INC_STEP, TCS_MAX_ATIME);
-}
-
-static inline int tcs3400_i2c_read8(const struct motion_sensor_t *s,
- int reg, int *data)
-{
- return i2c_read8(s->port, s->i2c_spi_addr_flags, reg, data);
-}
-
-static inline int tcs3400_i2c_write8(const struct motion_sensor_t *s,
- int reg, int data)
-{
- return i2c_write8(s->port, s->i2c_spi_addr_flags, reg, data);
-}
-
-static void tcs3400_read_deferred(void)
-{
- task_set_event(TASK_ID_MOTIONSENSE, CONFIG_ALS_TCS3400_INT_EVENT);
-}
-DECLARE_DEFERRED(tcs3400_read_deferred);
-
-/* convert ATIME register to integration time, in microseconds */
-int tcs3400_get_integration_time(int atime)
-{
- return TCS_MAX_INTEGRATION_TIME * (TCS_ATIME_GRANULARITY - atime);
-}
-
-static int tcs3400_read(const struct motion_sensor_t *s, intv3_t v)
-{
- int atime, again;
- int ret;
-
- /* Chip may have been off, make sure to setup important registers */
- if (TCS3400_RGB_DRV_DATA(s+1)->calibration_mode) {
- atime = TCS_CALIBRATION_ATIME;
- again = TCS_CALIBRATION_AGAIN;
- } else {
- atime = TCS3400_RGB_DRV_DATA(s+1)->saturation.atime;
- again = TCS3400_RGB_DRV_DATA(s+1)->saturation.again;
- }
- ret = tcs3400_i2c_write8(s, TCS_I2C_ATIME, atime);
- if (ret)
- return ret;
- ret = tcs3400_i2c_write8(s, TCS_I2C_CONTROL, again);
- if (ret)
- return ret;
-
- /* Enable power, ADC, and interrupt to start cycle */
- ret = tcs3400_i2c_write8(s, TCS_I2C_ENABLE, TCS3400_MODE_COLLECTING);
- if (ret)
- return ret;
-
- if (IS_ENABLED(CONFIG_ALS_TCS3400_EMULATED_IRQ_EVENT)) {
- int atime;
-
- ret = tcs3400_i2c_read8(s, TCS_I2C_ATIME, &atime);
- if (ret)
- return ret;
-
- hook_call_deferred(&tcs3400_read_deferred_data,
- tcs3400_get_integration_time(atime));
- }
-
- /*
- * If write succeeded, we've started the read process, but can't
- * complete it yet until data is ready, so pass back EC_RES_IN_PROGRESS
- * to inform upper level that read data process is under way and data
- * will be delivered when available.
- */
- return EC_RES_IN_PROGRESS;
-}
-
-static int tcs3400_rgb_read(const struct motion_sensor_t *s, intv3_t v)
-{
- ccprintf("WARNING: tcs3400_rgb_read() should never be called\n");
- return EC_SUCCESS;
-}
-
-/*
- * tcs3400_adjust_sensor_for_saturation() tries to keep CRGB values as
- * close to saturation as possible without saturating by implementing
- * the following logic:
- *
- * If any of the R, G, B, or C channels have saturated, then decrease AGAIN.
- * If AGAIN is already at its minimum, increase ATIME if not at its max already.
- *
- * Else if none of the R, G, B, or C channels have saturated, and
- * all samples read are less than 90% of saturation, then increase
- * AGAIN if it is not already at its maximum, or if it is, decrease
- * ATIME if it is not at it's minimum already.
- */
-static int
-tcs3400_adjust_sensor_for_saturation(struct motion_sensor_t *s,
- uint16_t cur_lux,
- uint16_t *crgb_data,
- uint32_t status)
-{
- struct tcs_saturation_t *sat_p =
- &TCS3400_RGB_DRV_DATA(s+1)->saturation;
- const uint8_t save_again = sat_p->again;
- const uint8_t save_atime = sat_p->atime;
- uint16_t max_val = 0;
- int ret;
- int percent_left = 0;
-
- /* Adjust for saturation if needed */
- if (!(status & TCS_I2C_STATUS_RGBC_VALID))
- return EC_SUCCESS;
-
- for (int i = 0; i < CRGB_COUNT; i++)
- max_val = MAX(max_val, crgb_data[i]);
-
- /* Don't process if status isn't valid yet */
- if ((status & TCS_I2C_STATUS_ALS_SATURATED) ||
- (max_val >= TCS_SATURATION_LEVEL)) {
- /* Saturation occurred, decrease AGAIN if we can */
- if (sat_p->again > TCS_MIN_AGAIN)
- sat_p->again--;
- else if (sat_p->atime < TCS_MAX_ATIME)
- /* reduce accumulation time by incrementing ATIME reg */
- increment_atime(sat_p);
- } else if (max_val < TSC_SATURATION_LOW_BAND_LEVEL) {
- /* value < 90% saturation, try to increase sensitivity */
- if (max_val <= TCS_GAIN_SAT_LEVEL) {
- if (sat_p->again < TCS_MAX_AGAIN) {
- sat_p->again++;
- } else if (sat_p->atime > TCS_MIN_ATIME) {
- /*
- * increase accumulation time by decrementing
- * ATIME register
- */
- percent_left = TSC_SATURATION_LOW_BAND_PERCENT -
- (max_val * 100 / TCS_SATURATION_LEVEL);
- decrement_atime(sat_p, cur_lux, percent_left);
- }
- } else if (sat_p->atime > TCS_MIN_ATIME) {
- /* calculate percentage between current and desired */
- percent_left = TSC_SATURATION_LOW_BAND_PERCENT -
- (max_val * 100 / TCS_SATURATION_LEVEL);
-
- /* increase accumulation time by decrementing ATIME */
- decrement_atime(sat_p, cur_lux, percent_left);
- } else if (sat_p->again < TCS_MAX_AGAIN) {
- /*
- * Although we're not at maximum gain yet, we
- * can't just increase gain because a 4x change
- * in gain under these light conditions would
- * saturate on the next sample. What we can do
- * is to adjust atime to reduce sensitivity so
- * that we may increase gain without saturation.
- * This combination effectively acts as a half
- * gain increase (2.5x estimate) instead of a full
- * gain increase of > 4x that would result in
- * saturation.
- */
- if (max_val < TCS_GAIN_UPSHIFT_LEVEL) {
- sat_p->atime = TCS_GAIN_UPSHIFT_ATIME;
- sat_p->again++;
- }
- }
- }
-
- /* If atime or gain setting changed, update atime and gain registers */
- if (save_again != sat_p->again) {
- ret = tcs3400_i2c_write8(s, TCS_I2C_CONTROL,
- (sat_p->again & TCS_I2C_CONTROL_MASK));
- if (ret)
- return ret;
- }
-
- if (save_atime != sat_p->atime) {
- ret = tcs3400_i2c_write8(s, TCS_I2C_ATIME, sat_p->atime);
- if (ret)
- return ret;
- }
-
- return EC_SUCCESS;
-}
-
-/**
- * normalize_channel_data - normalize the light data to remove effect of
- * different atime and again settings from the sample.
- */
-static uint32_t normalize_channel_data(struct motion_sensor_t *s,
- uint32_t sample)
-{
- struct tcs_saturation_t *sat_p =
- &(TCS3400_RGB_DRV_DATA(s+1)->saturation);
- const uint16_t cur_gain = (1 << (2 * sat_p->again));
- const uint16_t cal_again = (1 << (2 * TCS_CALIBRATION_AGAIN));
-
- return DIV_ROUND_NEAREST(sample * (TCS_ATIME_GRANULARITY -
- TCS_CALIBRATION_ATIME) * cal_again,
- (TCS_ATIME_GRANULARITY - sat_p->atime) *
- cur_gain);
-}
-
-
-__overridable void tcs3400_translate_to_xyz(struct motion_sensor_t *s,
- int32_t *crgb_data, int32_t *xyz_data)
-{
- struct tcs3400_rgb_drv_data_t *rgb_drv_data = TCS3400_RGB_DRV_DATA(s+1);
- int32_t crgb_prime[CRGB_COUNT];
- int32_t ir;
- int i;
-
- /* normalize the data for atime and again changes */
- for (i = 0; i < CRGB_COUNT; i++)
- crgb_data[i] = normalize_channel_data(s, crgb_data[i]);
-
- /* IR removal */
- ir = FP_TO_INT(fp_mul(INT_TO_FP(crgb_data[1] + crgb_data[2] +
- crgb_data[3] - crgb_data[0]),
- rgb_drv_data->calibration.irt) / 2);
-
- for (i = 0; i < ARRAY_SIZE(crgb_prime); i++) {
- if (crgb_data[i] < ir)
- crgb_prime[i] = 0;
- else
- crgb_prime[i] = crgb_data[i] - ir;
- }
-
- /* if CC == 0, set BC = 0 */
- if (crgb_prime[CLEAR_CRGB_IDX] == 0)
- crgb_prime[BLUE_CRGB_IDX] = 0;
-
- /* regression fit to XYZ space */
- for (i = 0; i < 3; i++) {
- const struct rgb_channel_calibration_t *p =
- &rgb_drv_data->calibration.rgb_cal[i];
-
- xyz_data[i] = p->offset + FP_TO_INT(
- (fp_inter_t)p->coeff[RED_CRGB_IDX] *
- crgb_prime[RED_CRGB_IDX] +
- (fp_inter_t)p->coeff[GREEN_CRGB_IDX] *
- crgb_prime[GREEN_CRGB_IDX] +
- (fp_inter_t)p->coeff[BLUE_CRGB_IDX] *
- crgb_prime[BLUE_CRGB_IDX] +
- (fp_inter_t)p->coeff[CLEAR_CRGB_IDX] *
- crgb_prime[CLEAR_CRGB_IDX]);
-
- if (xyz_data[i] < 0)
- xyz_data[i] = 0;
- }
-}
-
-static void tcs3400_process_raw_data(struct motion_sensor_t *s,
- uint8_t *raw_data_buf,
- uint16_t *raw_light_data, int32_t *xyz_data)
-{
- struct als_drv_data_t *als_drv_data = TCS3400_DRV_DATA(s);
- struct tcs3400_rgb_drv_data_t *rgb_drv_data = TCS3400_RGB_DRV_DATA(s+1);
- const uint8_t calibration_mode = rgb_drv_data->calibration_mode;
- uint16_t k_channel_scale =
- als_drv_data->als_cal.channel_scale.k_channel_scale;
- uint16_t cover_scale = als_drv_data->als_cal.channel_scale.cover_scale;
- int32_t crgb_data[CRGB_COUNT];
- int i;
-
- /* adjust for calibration and scale data */
- for (i = 0; i < CRGB_COUNT; i++) {
- int index = i * 2;
-
- /* assemble the light value for this channel */
- crgb_data[i] = raw_light_data[i] =
- ((raw_data_buf[index+1] << 8) | raw_data_buf[index]);
-
- /* in calibration mode, we only assemble the raw data */
- if (calibration_mode)
- continue;
-
- /* rgb data at index 1, 2, and 3 owned by rgb driver, not ALS */
- if (i > 0) {
- struct als_channel_scale_t *csp =
- &rgb_drv_data->calibration.rgb_cal[i-1].scale;
- k_channel_scale = csp->k_channel_scale;
- cover_scale = csp->cover_scale;
- }
-
- /* Step 1: divide by individual channel scale value */
- crgb_data[i] = SENSOR_APPLY_DIV_SCALE(crgb_data[i],
- k_channel_scale);
-
- /* compensate for the light cover */
- crgb_data[i] = SENSOR_APPLY_SCALE(crgb_data[i], cover_scale);
- }
-
- if (!calibration_mode) {
- /* we're not in calibration mode & we want xyz translation */
- tcs3400_translate_to_xyz(s, crgb_data, xyz_data);
- } else {
- /* normalize the data for atime and again changes */
- for (i = 0; i < CRGB_COUNT; i++)
- crgb_data[i] = normalize_channel_data(s, crgb_data[i]);
-
- /* calibration mode returns raw data */
- for (i = 0; i < 3; i++)
- xyz_data[i] = crgb_data[i+1];
- }
-}
-
-static int32_t get_lux_from_xyz(struct motion_sensor_t *s, int32_t *xyz_data)
-{
- int32_t lux = xyz_data[Y];
- const int32_t offset =
- TCS3400_RGB_DRV_DATA(s+1)->calibration.rgb_cal[Y].offset;
-
- /*
- * Do not include the offset when determining LUX from XYZ.
- */
- lux = MAX(0, lux - offset);
-
- return lux;
-}
-
-static bool is_spoof(struct motion_sensor_t *s)
-{
- return IS_ENABLED(CONFIG_ACCEL_SPOOF_MODE) &&
- (s->flags & MOTIONSENSE_FLAG_IN_SPOOF_MODE);
-}
-
-static int tcs3400_post_events(struct motion_sensor_t *s,
- uint32_t last_ts,
- uint32_t status)
-{
- /*
- * Rule says RGB sensor is right after ALS sensor.
- * This routine will only get called from ALS sensor driver.
- */
- struct motion_sensor_t *rgb_s = s + 1;
- const uint8_t is_calibration =
- TCS3400_RGB_DRV_DATA(rgb_s)->calibration_mode;
- struct ec_response_motion_sensor_data vector = { .flags = 0, };
- uint8_t buf[TCS_RGBC_DATA_SIZE]; /* holds raw data read from chip */
- int32_t xyz_data[3] = { 0, 0, 0 };
- uint16_t raw_data[CRGB_COUNT]; /* holds raw CRGB assembled from buf[] */
- int *last_v;
- int32_t lux = 0;
- int ret;
-
- if (IS_ENABLED(CONFIG_ALS_TCS3400_EMULATED_IRQ_EVENT)) {
- int i = 5; /* 100ms max */
-
- while (i--) {
- /* Make sure data is valid */
- if (status & TCS_I2C_STATUS_RGBC_VALID)
- break;
- msleep(20);
- /*
- * When not in interrupt mode, we could have scheduled
- * the handler too early.
- */
- ret = tcs3400_i2c_read8(s, TCS_I2C_STATUS, &status);
- if (ret)
- return ret;
- }
- if (i < 0) {
- CPRINTS("RGBC invalid (0x%x)", status);
- return EC_ERROR_UNCHANGED;
- }
- }
-
- /* Read the light registers */
- ret = i2c_read_block(s->port, s->i2c_spi_addr_flags,
- TCS_DATA_START_LOCATION,
- buf, sizeof(buf));
- if (ret)
- return ret;
-
- /* Process the raw light data, adjusting for scale and calibration */
- tcs3400_process_raw_data(s, buf, raw_data, xyz_data);
-
- /* get lux value */
- lux = is_calibration ? xyz_data[Y] : get_lux_from_xyz(s, xyz_data);
-
- /* if clear channel data changed, send illuminance upstream */
- last_v = s->raw_xyz;
- if (is_calibration ||
- ((raw_data[CLEAR_CRGB_IDX] != TCS_SATURATION_LEVEL) &&
- (last_v[X] != lux))) {
- if (is_spoof(s))
- last_v[X] = s->spoof_xyz[X];
- else
- last_v[X] = is_calibration ? raw_data[CLEAR_CRGB_IDX] : lux;
-
- vector.udata[X] = ec_motion_sensor_clamp_u16(last_v[X]);
- vector.udata[Y] = 0;
- vector.udata[Z] = 0;
-
- if (IS_ENABLED(CONFIG_ACCEL_FIFO)) {
- vector.sensor_num = s - motion_sensors;
- motion_sense_fifo_stage_data(&vector, s, 3, last_ts);
- }
- }
-
- /*
- * If rgb channel data changed since last sample and didn't saturate,
- * send it upstream
- */
- last_v = rgb_s->raw_xyz;
- if (is_calibration ||
- (((last_v[X] != xyz_data[X]) || (last_v[Y] != xyz_data[Y]) ||
- (last_v[Z] != xyz_data[Z])) &&
- ((raw_data[RED_CRGB_IDX] != TCS_SATURATION_LEVEL) &&
- (raw_data[BLUE_CRGB_IDX] != TCS_SATURATION_LEVEL) &&
- (raw_data[GREEN_CRGB_IDX] != TCS_SATURATION_LEVEL)))) {
-
- if (is_spoof(rgb_s)) {
- memcpy(last_v, rgb_s->spoof_xyz, sizeof(rgb_s->spoof_xyz));
- } else if (is_calibration) {
- last_v[0] = raw_data[RED_CRGB_IDX];
- last_v[1] = raw_data[GREEN_CRGB_IDX];
- last_v[2] = raw_data[BLUE_CRGB_IDX];
- } else {
- memcpy(last_v, xyz_data, sizeof(xyz_data));
- }
-
- ec_motion_sensor_clamp_u16s(vector.udata, last_v);
-
- if (IS_ENABLED(CONFIG_ACCEL_FIFO)) {
- vector.sensor_num = rgb_s - motion_sensors;
- motion_sense_fifo_stage_data(&vector, rgb_s, 3, last_ts);
- }
- }
- if (IS_ENABLED(CONFIG_ACCEL_FIFO))
- motion_sense_fifo_commit_data();
-
- if (!is_calibration)
- ret = tcs3400_adjust_sensor_for_saturation(s, xyz_data[Y],
- raw_data, status);
-
- return ret;
-}
-
-void tcs3400_interrupt(enum gpio_signal signal)
-{
- if (IS_ENABLED(CONFIG_ACCEL_FIFO))
- last_interrupt_timestamp = __hw_clock_source_read();
-
- task_set_event(TASK_ID_MOTIONSENSE, CONFIG_ALS_TCS3400_INT_EVENT);
-}
-
-/*
- * 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_stage_data()..
- *
- * This routine will get called for the TCS3400 ALS driver, but NOT for the
- * RGB driver. We harvest data for both drivers in this routine. The RGB
- * driver is guaranteed to directly follow the ALS driver in the sensor list
- * (i.e rgb's motion_sensor_t structure can be found at (s+1) ).
- */
-static int tcs3400_irq_handler(struct motion_sensor_t *s, uint32_t *event)
-{
- uint32_t status = 0;
- int ret;
-
- if (!(*event & CONFIG_ALS_TCS3400_INT_EVENT))
- return EC_ERROR_NOT_HANDLED;
-
- ret = tcs3400_i2c_read8(s, TCS_I2C_STATUS, &status);
- if (ret)
- return ret;
-
- /* Disable future interrupts */
- ret = tcs3400_i2c_write8(s, TCS_I2C_ENABLE, TCS3400_MODE_IDLE);
- if (ret)
- return ret;
-
- if ((status & TCS_I2C_STATUS_RGBC_VALID) ||
- IS_ENABLED(CONFIG_ALS_TCS3400_EMULATED_IRQ_EVENT)) {
- ret = tcs3400_post_events(s, last_interrupt_timestamp, status);
- if (ret)
- return ret;
- }
-
- tcs3400_i2c_write8(s, TCS_I2C_AICLEAR, 0);
-
- /* Disable ADC and turn off internal oscillator */
- ret = tcs3400_i2c_write8(s, TCS_I2C_ENABLE, TCS3400_MODE_SUSPEND);
- if (ret)
- return ret;
-
- return EC_SUCCESS;
-}
-
-static int tcs3400_rgb_get_scale(const struct motion_sensor_t *s,
- uint16_t *scale,
- int16_t *temp)
-{
- struct rgb_channel_calibration_t *rgb_cal =
- TCS3400_RGB_DRV_DATA(s)->calibration.rgb_cal;
-
- scale[X] = rgb_cal[RED_RGB_IDX].scale.k_channel_scale;
- scale[Y] = rgb_cal[GREEN_RGB_IDX].scale.k_channel_scale;
- scale[Z] = rgb_cal[BLUE_RGB_IDX].scale.k_channel_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)
-{
- struct rgb_channel_calibration_t *rgb_cal =
- TCS3400_RGB_DRV_DATA(s)->calibration.rgb_cal;
-
- if (scale[X] == 0 || scale[Y] == 0 || scale[Z] == 0)
- return EC_ERROR_INVAL;
- rgb_cal[RED_RGB_IDX].scale.k_channel_scale = scale[X];
- rgb_cal[GREEN_RGB_IDX].scale.k_channel_scale = scale[Y];
- rgb_cal[BLUE_RGB_IDX].scale.k_channel_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)->calibration.rgb_cal[X].offset;
- offset[Y] = TCS3400_RGB_DRV_DATA(s)->calibration.rgb_cal[Y].offset;
- offset[Z] = TCS3400_RGB_DRV_DATA(s)->calibration.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)
-{
- /* do not allow offset to be changed, it's predetermined */
- return EC_SUCCESS;
-}
-
-static int tcs3400_rgb_set_data_rate(const struct motion_sensor_t *s,
- int rate,
- int rnd)
-{
- return EC_SUCCESS;
-}
-
-/* Enable/disable special factory calibration mode */
-static int tcs3400_perform_calib(struct motion_sensor_t *s, int enable)
-{
- TCS3400_RGB_DRV_DATA(s+1)->calibration_mode = enable;
- return EC_SUCCESS;
-}
-
-static int tcs3400_rgb_set_range(struct motion_sensor_t *s,
- int range,
- int rnd)
-{
- return EC_SUCCESS;
-}
-
-static int tcs3400_set_range(struct motion_sensor_t *s,
- int range,
- int rnd)
-{
- TCS3400_DRV_DATA(s)->als_cal.scale = range >> 16;
- TCS3400_DRV_DATA(s)->als_cal.uscale = range & 0xffff;
- s->current_range = range;
- return EC_SUCCESS;
-}
-
-static int tcs3400_get_scale(const struct motion_sensor_t *s,
- uint16_t *scale,
- int16_t *temp)
-{
- scale[X] = TCS3400_DRV_DATA(s)->als_cal.channel_scale.k_channel_scale;
- scale[Y] = 0;
- scale[Z] = 0;
- *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP;
- return EC_SUCCESS;
-}
-
-static int tcs3400_set_scale(const struct motion_sensor_t *s,
- const uint16_t *scale,
- int16_t temp)
-{
- if (scale[X] == 0)
- return EC_ERROR_INVAL;
- TCS3400_DRV_DATA(s)->als_cal.channel_scale.k_channel_scale = scale[X];
- return EC_SUCCESS;
-}
-
-static int tcs3400_get_offset(const struct motion_sensor_t *s,
- int16_t *offset,
- int16_t *temp)
-{
- offset[X] = TCS3400_DRV_DATA(s)->als_cal.offset;
- offset[Y] = 0;
- offset[Z] = 0;
- *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP;
- return EC_SUCCESS;
-}
-
-static int tcs3400_set_offset(const struct motion_sensor_t *s,
- const int16_t *offset,
- int16_t temp)
-{
- /* do not allow offset to be changed, it's predetermined */
- return EC_SUCCESS;
-}
-
-static int tcs3400_get_data_rate(const struct motion_sensor_t *s)
-{
- return TCS3400_DRV_DATA(s)->rate;
-}
-
-static int tcs3400_rgb_get_data_rate(const struct motion_sensor_t *s)
-{
- return tcs3400_get_data_rate(s - 1);
-}
-
-static int tcs3400_set_data_rate(const struct motion_sensor_t *s,
- int rate,
- int rnd)
-{
- enum tcs3400_mode mode;
- int data;
- int ret;
-
- if (rate == 0) {
- /* Suspend driver */
- mode = TCS3400_MODE_SUSPEND;
- } else {
- /*
- * We set the sensor for continuous mode,
- * integrating over 800ms.
- * Do not allow range higher than 1Hz.
- */
- if (rate > TCS3400_LIGHT_MAX_FREQ)
- rate = TCS3400_LIGHT_MAX_FREQ;
- mode = TCS3400_MODE_COLLECTING;
- }
- TCS3400_DRV_DATA(s)->rate = rate;
-
- ret = tcs3400_i2c_read8(s, TCS_I2C_ENABLE, &data);
- if (ret)
- return ret;
-
- data = (data & TCS_I2C_ENABLE_MASK) | mode;
- ret = tcs3400_i2c_write8(s, TCS_I2C_ENABLE, data);
-
- return ret;
-}
-
-/**
- * Initialise TCS3400 light sensor.
- */
-static int tcs3400_rgb_init(struct motion_sensor_t *s)
-{
- return EC_SUCCESS;
-}
-
-static int tcs3400_init(struct motion_sensor_t *s)
-{
- /*
- * These are default power-on register values with two exceptions:
- * Set ATIME = 0 (712 ms)
- * Set AGAIN = 16 (0x10) (AGAIN is in CONTROL register)
- */
- const struct reg_data {
- uint8_t reg;
- uint8_t data;
- } defaults[] = {
- { TCS_I2C_ENABLE, 0 },
- { TCS_I2C_ATIME, TCS_DEFAULT_ATIME },
- { TCS_I2C_WTIME, 0xFF },
- { TCS_I2C_AILTL, 0 },
- { TCS_I2C_AILTH, 0 },
- { TCS_I2C_AIHTL, 0 },
- { TCS_I2C_AIHTH, 0 },
- { TCS_I2C_PERS, 0 },
- { TCS_I2C_CONFIG, 0x40 },
- { TCS_I2C_CONTROL, (TCS_DEFAULT_AGAIN & TCS_I2C_CONTROL_MASK) },
- { TCS_I2C_AUX, 0 },
- { TCS_I2C_IR, 0 },
- { TCS_I2C_CICLEAR, 0 },
- { TCS_I2C_AICLEAR, 0 }
- };
- int data = 0;
- int ret;
-
- ret = tcs3400_i2c_read8(s, TCS_I2C_ID, &data);
- if (ret) {
- CPRINTS("failed reading ID reg 0x%x, ret=%d", TCS_I2C_ID, ret);
- return ret;
- }
- if ((data != TCS340015_DEVICE_ID) && (data != TCS340037_DEVICE_ID)) {
- CPRINTS("no ID match, data = 0x%x", data);
- return EC_ERROR_ACCESS_DENIED;
- }
-
- /* reset chip to default power-on settings, changes ATIME and CONTROL */
- for (int x = 0; x < ARRAY_SIZE(defaults); x++) {
- ret = tcs3400_i2c_write8(s, defaults[x].reg, defaults[x].data);
- if (ret)
- return ret;
- }
-
- return sensor_init_done(s);
-}
-
-const struct accelgyro_drv tcs3400_drv = {
- .init = tcs3400_init,
- .read = tcs3400_read,
- .set_range = tcs3400_set_range,
- .set_offset = tcs3400_set_offset,
- .get_offset = tcs3400_get_offset,
- .set_scale = tcs3400_set_scale,
- .get_scale = tcs3400_get_scale,
- .set_data_rate = tcs3400_set_data_rate,
- .get_data_rate = tcs3400_get_data_rate,
- .perform_calib = tcs3400_perform_calib,
-#ifdef CONFIG_ACCEL_INTERRUPTS
- .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,
- .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,
-};