diff options
author | Tomasz Michalec <tm@semihalf.com> | 2021-07-23 15:02:28 +0200 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-07-27 18:32:40 +0000 |
commit | 414b3d2b9de35f8bf53293b6244d8d58b3488239 (patch) | |
tree | b753c54a6f942479b5917854e9b0c734a3b8d832 /zephyr | |
parent | f4047a0646f11dee2f9c33a78c6dd2009affd81f (diff) | |
download | chrome-ec-414b3d2b9de35f8bf53293b6244d8d58b3488239.tar.gz |
zephyr: drivers: add als_tcs3400 test suite
Functions exposed in public API by TCS3400 driver are tested using TCS
emulator. Driver's irq handler is tested in calibration and normal mode.
BUG=b:184856080
BRANCH=none
TEST=run zmake drivers test
Signed-off-by: Tomasz Michalec <tm@semihalf.com>
Change-Id: I80fa87accc43c9fd41ab057a2b1026577847275a
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3048095
Reviewed-by: Jeremy Bettis <jbettis@chromium.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'zephyr')
-rw-r--r-- | zephyr/test/drivers/overlay.dts | 105 | ||||
-rw-r--r-- | zephyr/test/drivers/prj.conf | 2 | ||||
-rw-r--r-- | zephyr/test/drivers/src/main.c | 2 | ||||
-rw-r--r-- | zephyr/test/drivers/src/tcs3400.c | 622 |
4 files changed, 731 insertions, 0 deletions
diff --git a/zephyr/test/drivers/overlay.dts b/zephyr/test/drivers/overlay.dts index 47662890aa..f0413746d3 100644 --- a/zephyr/test/drivers/overlay.dts +++ b/zephyr/test/drivers/overlay.dts @@ -9,6 +9,7 @@ aliases { bmi260-int = &ms_bmi260_accel; bmi160-int = &ms_bmi160_accel; + tcs3400-int = &tcs3400_clear; }; named-gpios { compatible = "named-gpios"; @@ -200,6 +201,70 @@ compatible = "cros-ec,drvdata-bmi160"; status = "okay"; }; + + tcs_clear_data: tcs3400-clear-drv-data { + compatible = "cros-ec,drvdata-tcs3400-clear"; + status = "okay"; + + als-drv-data { + compatible = "cros-ec,accelgyro-als-drv-data"; + als-cal { + scale = <1>; + uscale = <0>; + offset = <0>; + als-channel-scale { + compatible = + "cros-ec,accelgyro-als-channel-scale"; + k-channel-scale = <1>; + cover-scale = <1>; + }; + }; + }; + }; + + tcs_rgb_data: tcs3400-rgb-drv-data { + compatible = "cros-ec,drvdata-tcs3400-rgb"; + status = "okay"; + + /* node for rgb_calibration_t defined in accelgyro.h */ + rgb_calibration { + compatible = + "cros-ec,accelgyro-rgb-calibration"; + + irt = <1>; + + rgb-cal-x { + offset = <0>; + coeff = <0 1 0 0>; + als-channel-scale { + compatible = + "cros-ec,accelgyro-als-channel-scale"; + k-channel-scale = <1>; + cover-scale = <1>; + }; + }; + rgb-cal-y { + offset = <0>; + coeff = <0 0 1 0>; + als-channel-scale { + compatible = + "cros-ec,accelgyro-als-channel-scale"; + k-channel-scale = <1>; + cover-scale = <1>; + }; + }; + rgb-cal-z { + offset = <0>; + coeff = <0 0 0 1>; + als-channel-scale { + compatible = + "cros-ec,accelgyro-als-channel-scale"; + k-channel-scale = <1>; + cover-scale = <1>; + }; + }; + }; + }; }; /* @@ -259,6 +324,37 @@ default-range = <1000>; /* dps */ i2c-spi-addr-flags = "BMI160_ADDR0_FLAGS"; }; + + tcs3400_clear: tcs3400-clear { + compatible = "cros-ec,tcs3400-clear"; + status = "okay"; + + label = "Clear Light"; + location = "MOTIONSENSE_LOC_BASE"; + port = <&i2c_sensor>; + default-range = <0x10000>; + drv-data = <&tcs_clear_data>; + i2c-spi-addr-flags = "TCS3400_I2C_ADDR_FLAGS"; + configs { + compatible = + "cros-ec,motionsense-sensor-config"; + ec-s0 { + /* Run ALS sensor in S0 */ + label = "SENSOR_CONFIG_EC_S0"; + odr = <1000>; + }; + }; + }; + + tcs3400_rgb: tcs3400-rgb { + compatible = "cros-ec,tcs3400-rgb"; + status = "okay"; + + label = "RGB Light"; + location = "MOTIONSENSE_LOC_BASE"; + default-range = <0x10000>; /* scale = 1x, uscale = 0 */ + drv-data = <&tcs_rgb_data>; + }; }; /* @@ -284,6 +380,15 @@ error-on-reserved-bit-write; simulate-command-exec-time; }; + + tcs_emul: tcs@39 { + compatible = "zephyr,tcs3400"; + reg = <0x39>; + label = "TCS_EMUL"; + error-on-ro-write; + error-on-reserved-bit-write; + error-on-msb-first-access; + }; }; }; diff --git a/zephyr/test/drivers/prj.conf b/zephyr/test/drivers/prj.conf index 87700ec8c6..3fd3636946 100644 --- a/zephyr/test/drivers/prj.conf +++ b/zephyr/test/drivers/prj.conf @@ -20,6 +20,7 @@ CONFIG_ADC_EMUL=y CONFIG_HEAP_MEM_POOL_SIZE=1024 CONFIG_EMUL_BMA255=y CONFIG_EMUL_BMI=y +CONFIG_EMUL_TCS3400=y CONFIG_PLATFORM_EC_BATTERY_PRESENT_GPIO=y CONFIG_PLATFORM_EC_EXTPOWER_GPIO=y @@ -58,6 +59,7 @@ CONFIG_PLATFORM_EC_ACCELGYRO_BMI_COMM_I2C=y CONFIG_PLATFORM_EC_ACCEL_INTERRUPTS=y CONFIG_PLATFORM_EC_ACCEL_FIFO=y CONFIG_PLATFORM_EC_SENSOR_TIGHT_TIMESTAMPS=y +CONFIG_PLATFORM_EC_ALS_TCS3400=y # Things that default to on, but aren't working yet CONFIG_PLATFORM_EC_BACKLIGHT_LID=n diff --git a/zephyr/test/drivers/src/main.c b/zephyr/test/drivers/src/main.c index 3c2c6856d7..ca573b98fd 100644 --- a/zephyr/test/drivers/src/main.c +++ b/zephyr/test/drivers/src/main.c @@ -17,6 +17,7 @@ extern void test_suite_bc12(void); extern void test_suite_ppc(void); extern void test_suite_bmi260(void); extern void test_suite_bmi160(void); +extern void test_suite_tcs3400(void); void test_main(void) { @@ -35,4 +36,5 @@ void test_main(void) test_suite_ppc(); test_suite_bmi260(); test_suite_bmi160(); + test_suite_tcs3400(); } diff --git a/zephyr/test/drivers/src/tcs3400.c b/zephyr/test/drivers/src/tcs3400.c new file mode 100644 index 0000000000..7f9ce38351 --- /dev/null +++ b/zephyr/test/drivers/src/tcs3400.c @@ -0,0 +1,622 @@ +/* Copyright 2021 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. + */ + +#include <zephyr.h> +#include <ztest.h> + +#include "common.h" +#include "i2c.h" +#include "emul/emul_tcs3400.h" + +#include "motion_sense.h" +#include "motion_sense_fifo.h" +#include "driver/als_tcs3400.h" + +#define TCS_ORD DT_DEP_ORD(DT_NODELABEL(tcs_emul)) +#define TCS_CLR_SENSOR_ID SENSOR_ID(DT_NODELABEL(tcs3400_clear)) +#define TCS_RGB_SENSOR_ID SENSOR_ID(DT_NODELABEL(tcs3400_rgb)) +#define TCS_INT_EVENT \ + TASK_EVENT_MOTION_SENSOR_INTERRUPT(SENSOR_ID(DT_ALIAS(tcs3400_int))) + +/** How accurate comparision of rgb sensors should be */ +#define V_EPS 8 + +/** Test initialization of light sensor driver and device */ +static void test_tcs_init(void) +{ + struct motion_sensor_t *ms, *ms_rgb; + struct i2c_emul *emul; + + emul = tcs_emul_get(TCS_ORD); + ms = &motion_sensors[TCS_CLR_SENSOR_ID]; + ms_rgb = &motion_sensors[TCS_RGB_SENSOR_ID]; + + /* RGB sensor initialization is always successful */ + zassert_equal(EC_SUCCESS, ms_rgb->drv->init(ms_rgb), NULL); + + /* Fail init on communication errors */ + tcs_emul_set_read_fail_reg(emul, TCS_EMUL_FAIL_ALL_REG); + zassert_equal(-EIO, ms->drv->init(ms), NULL); + tcs_emul_set_read_fail_reg(emul, TCS_EMUL_NO_FAIL_REG); + + /* Fail on bad ID */ + tcs_emul_set_reg(emul, TCS_I2C_ID, 0); + zassert_equal(EC_ERROR_ACCESS_DENIED, ms->drv->init(ms), NULL); + /* Restore ID */ + tcs_emul_set_reg(emul, TCS_I2C_ID, DT_ENUM_TOKEN(DT_NODELABEL(tcs_emul), + device_id)); + + /* Test successful init. ATIME and AGAIN should be changed on init */ + zassert_equal(EC_SUCCESS, ms->drv->init(ms), NULL); + zassert_equal(TCS_DEFAULT_ATIME, + tcs_emul_get_reg(emul, TCS_I2C_ATIME), NULL); + zassert_equal(TCS_DEFAULT_AGAIN, + tcs_emul_get_reg(emul, TCS_I2C_CONTROL), NULL); +} + +/** Test if read function leaves device in correct mode to accuire data */ +static void test_tcs_read(void) +{ + struct motion_sensor_t *ms; + struct i2c_emul *emul; + uint8_t enable; + intv3_t v; + + emul = tcs_emul_get(TCS_ORD); + ms = &motion_sensors[TCS_CLR_SENSOR_ID]; + + /* Test error on writing registers */ + tcs_emul_set_write_fail_reg(emul, TCS_I2C_ATIME); + zassert_equal(-EIO, ms->drv->read(ms, v), NULL); + tcs_emul_set_write_fail_reg(emul, TCS_I2C_CONTROL); + zassert_equal(-EIO, ms->drv->read(ms, v), NULL); + tcs_emul_set_write_fail_reg(emul, TCS_I2C_ENABLE); + zassert_equal(-EIO, ms->drv->read(ms, v), NULL); + tcs_emul_set_write_fail_reg(emul, TCS_EMUL_NO_FAIL_REG); + + /* Test starting read with calibration */ + tcs_emul_set_reg(emul, TCS_I2C_ATIME, 0); + tcs_emul_set_reg(emul, TCS_I2C_CONTROL, 0); + tcs_emul_set_reg(emul, TCS_I2C_ENABLE, 0); + zassert_equal(EC_SUCCESS, ms->drv->perform_calib(ms, 1), NULL); + zassert_equal(EC_RES_IN_PROGRESS, ms->drv->read(ms, v), NULL); + zassert_equal(TCS_CALIBRATION_ATIME, + tcs_emul_get_reg(emul, TCS_I2C_ATIME), NULL); + zassert_equal(TCS_CALIBRATION_AGAIN, + tcs_emul_get_reg(emul, TCS_I2C_CONTROL), NULL); + enable = tcs_emul_get_reg(emul, TCS_I2C_ENABLE); + zassert_true(enable & TCS_I2C_ENABLE_POWER_ON, NULL); + zassert_true(enable & TCS_I2C_ENABLE_ADC_ENABLE, NULL); + zassert_true(enable & TCS_I2C_ENABLE_INT_ENABLE, NULL); + + /* Test starting read without calibration */ + tcs_emul_set_reg(emul, TCS_I2C_ATIME, 0); + tcs_emul_set_reg(emul, TCS_I2C_CONTROL, 0); + tcs_emul_set_reg(emul, TCS_I2C_ENABLE, 0); + zassert_equal(EC_SUCCESS, ms->drv->perform_calib(ms, 0), NULL); + zassert_equal(EC_RES_IN_PROGRESS, ms->drv->read(ms, v), NULL); + enable = tcs_emul_get_reg(emul, TCS_I2C_ENABLE); + zassert_true(enable & TCS_I2C_ENABLE_POWER_ON, NULL); + zassert_true(enable & TCS_I2C_ENABLE_ADC_ENABLE, NULL); + zassert_true(enable & TCS_I2C_ENABLE_INT_ENABLE, NULL); +} + +/** Check if FIFO for RGB and clear sensor is empty */ +static void check_fifo_empty_f(struct motion_sensor_t *ms, + struct motion_sensor_t *ms_rgb, int line) +{ + struct ec_response_motion_sensor_data vector; + uint16_t size; + + /* Read all data committed to FIFO */ + while (motion_sense_fifo_read(sizeof(vector), 1, &vector, &size)) { + /* Ignore timestamp frames */ + if (vector.flags == MOTIONSENSE_SENSOR_FLAG_TIMESTAMP) { + continue; + } + + if (ms - motion_sensors == vector.sensor_num) { + zassert_unreachable( + "Unexpected frame for clear sensor"); + } + + if (ms_rgb - motion_sensors == vector.sensor_num) { + zassert_unreachable("Unexpected frame for rgb sensor"); + } + } +} +#define check_fifo_empty(ms, ms_rgb) \ + check_fifo_empty_f(ms, ms_rgb, __LINE__) + +/** + * Test different conditions where irq handler fail or commit no data + * to fifo + */ +static void test_tcs_irq_handler_fail(void) +{ + struct motion_sensor_t *ms, *ms_rgb; + struct i2c_emul *emul; + uint32_t event; + + emul = tcs_emul_get(TCS_ORD); + ms = &motion_sensors[TCS_CLR_SENSOR_ID]; + ms_rgb = &motion_sensors[TCS_RGB_SENSOR_ID]; + + /* Fail on wrong event */ + event = 0x1234 & ~TCS_INT_EVENT; + zassert_equal(EC_ERROR_NOT_HANDLED, ms->drv->irq_handler(ms, &event), + NULL); + check_fifo_empty(ms, ms_rgb); + + event = TCS_INT_EVENT; + /* Test error on reading status */ + tcs_emul_set_read_fail_reg(emul, TCS_I2C_STATUS); + zassert_equal(-EIO, ms->drv->irq_handler(ms, &event), NULL); + tcs_emul_set_read_fail_reg(emul, TCS_EMUL_NO_FAIL_REG); + check_fifo_empty(ms, ms_rgb); + + /* Test fail on changing device power state */ + tcs_emul_set_write_fail_reg(emul, TCS_I2C_ENABLE); + zassert_equal(-EIO, ms->drv->irq_handler(ms, &event), NULL); + tcs_emul_set_write_fail_reg(emul, TCS_EMUL_NO_FAIL_REG); + check_fifo_empty(ms, ms_rgb); + + /* Test that no data is committed when status is 0 */ + tcs_emul_set_reg(emul, TCS_I2C_STATUS, 0); + zassert_equal(EC_SUCCESS, ms->drv->irq_handler(ms, &event), NULL); + check_fifo_empty(ms, ms_rgb); +} + +/** + * Check if last data committed to FIFO for RGB and clear sensor equals to + * expected value. + */ +static void check_fifo_f(struct motion_sensor_t *ms, + struct motion_sensor_t *ms_rgb, + int *exp_v, int eps, int line) +{ + struct ec_response_motion_sensor_data vector; + uint16_t size; + int ret_v[4] = {-1, -1, -1, -1}; + int i; + + /* Read all data committed to FIFO */ + while (motion_sense_fifo_read(sizeof(vector), 1, &vector, &size)) { + /* Ignore timestamp frames */ + if (vector.flags == MOTIONSENSE_SENSOR_FLAG_TIMESTAMP) { + continue; + } + + /* Get clear frame */ + if (ms - motion_sensors == vector.sensor_num) { + ret_v[0] = vector.udata[0]; + } + + /* Get rgb frame */ + if (ms_rgb - motion_sensors == vector.sensor_num) { + ret_v[1] = vector.udata[0]; + ret_v[2] = vector.udata[1]; + ret_v[3] = vector.udata[2]; + } + } + + if (ret_v[0] == -1) { + zassert_unreachable("No frame for clear sensor, line %d", line); + } + + if (ret_v[1] == -1) { + zassert_unreachable("No frame for rgb sensor, line %d", line); + } + + /* Compare with last committed data */ + for (i = 0; i < 4; i++) { + zassert_within(exp_v[i], ret_v[i], eps, + "Expected [%d; %d; %d; %d], got [%d; %d; %d; %d]; line: %d", + exp_v[0], exp_v[1], exp_v[2], exp_v[3], + ret_v[0], ret_v[1], ret_v[2], ret_v[3], line); + } +} +#define check_fifo(ms, ms_rgb, exp_v, eps) \ + check_fifo_f(ms, ms_rgb, exp_v, eps, __LINE__) + +/** Test calibration mode reading of light sensor values */ +static void test_tcs_read_calibration(void) +{ + struct motion_sensor_t *ms, *ms_rgb; + struct i2c_emul *emul; + uint32_t event = TCS_INT_EVENT; + int emul_v[4]; + int exp_v[4]; + int ret; + intv3_t v; + + emul = tcs_emul_get(TCS_ORD); + ms = &motion_sensors[TCS_CLR_SENSOR_ID]; + ms_rgb = &motion_sensors[TCS_RGB_SENSOR_ID]; + + /* Need to be set to collect all data in FIFO */ + ms->oversampling_ratio = 1; + ms_rgb->oversampling_ratio = 1; + /* Enable calibration mode */ + zassert_equal(EC_SUCCESS, ms->drv->perform_calib(ms, 1), NULL); + /* Setup AGAIN and ATIME for calibration */ + zassert_equal(EC_RES_IN_PROGRESS, ms->drv->read(ms, v), NULL); + + /* Test data that are in calibration range */ + exp_v[0] = 12; + exp_v[1] = 123; + exp_v[2] = 1234; + exp_v[3] = 12345; + /* + * Emulator value is with gain 64, while expected value is + * with gain 16 + */ + emul_v[0] = exp_v[0] * 64 / 16; + emul_v[1] = exp_v[1] * 64 / 16; + emul_v[2] = exp_v[2] * 64 / 16; + emul_v[3] = exp_v[3] * 64 / 16; + tcs_emul_set_val(emul, TCS_EMUL_C, emul_v[0]); + tcs_emul_set_val(emul, TCS_EMUL_R, emul_v[1]); + tcs_emul_set_val(emul, TCS_EMUL_G, emul_v[2]); + tcs_emul_set_val(emul, TCS_EMUL_B, emul_v[3]); + /* Set status to show valid data */ + tcs_emul_set_reg(emul, TCS_I2C_STATUS, TCS_I2C_STATUS_RGBC_VALID); + + zassert_equal(EC_SUCCESS, ms->drv->irq_handler(ms, &event), NULL); + /* In calibration mode check for exact match */ + check_fifo(ms, ms_rgb, exp_v, 1); + + /* Test data that are outside of calibration range */ + exp_v[0] = 0; + exp_v[1] = UINT16_MAX; + exp_v[2] = UINT16_MAX; + exp_v[3] = 213; + /* + * Emulator value is with gain 64, while expected value is + * with gain 16 + */ + emul_v[0] = 0; + emul_v[1] = exp_v[1] * 64 / 16; + emul_v[2] = (UINT16_MAX + 23) * 64 / 16; + emul_v[3] = exp_v[3] * 64 / 16; + tcs_emul_set_val(emul, TCS_EMUL_C, emul_v[0]); + tcs_emul_set_val(emul, TCS_EMUL_R, emul_v[1]); + tcs_emul_set_val(emul, TCS_EMUL_G, emul_v[2]); + tcs_emul_set_val(emul, TCS_EMUL_B, emul_v[3]); + /* Set status to show valid data */ + tcs_emul_set_reg(emul, TCS_I2C_STATUS, TCS_I2C_STATUS_RGBC_VALID); + + zassert_equal(EC_SUCCESS, ms->drv->irq_handler(ms, &event), NULL); + /* In calibration mode check for exact match */ + check_fifo(ms, ms_rgb, exp_v, 1); +} + +/** + * Set emulator internal value using expected output value returned by + * the driver. First element of expected vector is IR value used in + * calculations. Based on that clear light value is calculated. + * First element of expected vector is updated by this function. + */ +static void set_emul_val_from_exp(int *exp_v, uint16_t *scale, + struct i2c_emul *emul) +{ + int emul_v[4]; + int ir; + + /* We use exp_v[0] as IR value */ + ir = exp_v[0]; + /* Driver will return lux value as calculated blue light value */ + exp_v[0] = exp_v[2]; + + /* + * Driver takes care of different ATIME and AGAIN value, so expected + * value is always normalized to ATIME 256 and AGAIN 16. Convert it + * to internal emulator value (ATIME 256, AGAIN 64) and add expected IR + * value. Clear light is the sum of rgb light and IR component. + */ + emul_v[1] = (exp_v[1] + ir) * 64 / 16; + emul_v[2] = (exp_v[2] + ir) * 64 / 16; + emul_v[3] = (exp_v[3] + ir) * 64 / 16; + emul_v[0] = (exp_v[1] + exp_v[2] + exp_v[3] + ir) * 64 / 16; + + /* Apply scale, driver should divide by this value */ + emul_v[0] = SENSOR_APPLY_SCALE(emul_v[0], scale[0]); + emul_v[1] = SENSOR_APPLY_SCALE(emul_v[1], scale[1]); + emul_v[2] = SENSOR_APPLY_SCALE(emul_v[2], scale[2]); + emul_v[3] = SENSOR_APPLY_SCALE(emul_v[3], scale[3]); + + /* Set emulator values */ + tcs_emul_set_val(emul, TCS_EMUL_C, emul_v[0]); + tcs_emul_set_val(emul, TCS_EMUL_R, emul_v[1]); + tcs_emul_set_val(emul, TCS_EMUL_G, emul_v[2]); + tcs_emul_set_val(emul, TCS_EMUL_B, emul_v[3]); +} + +/** Test normal mode reading of light sensor values */ +static void test_tcs_read_xyz(void) +{ + struct motion_sensor_t *ms, *ms_rgb; + struct i2c_emul *emul; + uint32_t event = TCS_INT_EVENT; + /* Expected data to test: IR, R, G, B */ + int exp_v[][4] = { + {200, 1110, 870, 850}, + {300, 1110, 10000, 8500}, + {600, 50000, 40000, 30000}, + {1000, 3000, 40000, 2000}, + {1000, 65000, 65000, 65000}, + {100, 214, 541, 516}, + {143, 2141, 5414, 5163}, + {100, 50000, 40000, 30000}, + {1430, 2141, 5414, 5163}, + {10000, 50000, 40000, 30000}, + {10000, 214, 541, 516}, + {15000, 50000, 40000, 30000}, + }; + uint16_t scale[4] = { + MOTION_SENSE_DEFAULT_SCALE, MOTION_SENSE_DEFAULT_SCALE, + MOTION_SENSE_DEFAULT_SCALE, MOTION_SENSE_DEFAULT_SCALE + }; + int ret, i, test; + intv3_t v; + + emul = tcs_emul_get(TCS_ORD); + ms = &motion_sensors[TCS_CLR_SENSOR_ID]; + ms_rgb = &motion_sensors[TCS_RGB_SENSOR_ID]; + + /* Need to be set to collect all data in FIFO */ + ms->oversampling_ratio = 1; + ms_rgb->oversampling_ratio = 1; + /* Disable calibration mode */ + zassert_equal(EC_SUCCESS, ms->drv->perform_calib(ms, 0), NULL); + /* Setup AGAIN and ATIME for normal mode */ + zassert_equal(EC_RES_IN_PROGRESS, ms->drv->read(ms, v), NULL); + + /* Test different data in supported range */ + for (test = 0; test < ARRAY_SIZE(exp_v); test++) { + set_emul_val_from_exp(exp_v[test], scale, emul); + + /* Run few times to allow driver change gain */ + for (i = 0; i < 5; i++) { + tcs_emul_set_reg(emul, TCS_I2C_STATUS, + TCS_I2C_STATUS_RGBC_VALID); + zassert_equal(EC_SUCCESS, + ms->drv->irq_handler(ms, &event), NULL); + } + check_fifo(ms, ms_rgb, exp_v[test], V_EPS); + } + + /* Test data that are outside of supported range */ + exp_v[0][0] = 3000; + exp_v[0][1] = UINT16_MAX; + exp_v[0][2] = UINT16_MAX * 32; + exp_v[0][3] = 200; + set_emul_val_from_exp(exp_v[0], scale, emul); + + /* Run few times to allow driver change gain */ + for (i = 0; i < 10; i++) { + tcs_emul_set_reg(emul, TCS_I2C_STATUS, + TCS_I2C_STATUS_RGBC_VALID); + zassert_equal(EC_SUCCESS, ms->drv->irq_handler(ms, &event), + NULL); + } + /* + * If saturation value is exceeded on any rgb sensor, than data + * shouldn't be committed to FIFO. + */ + check_fifo_empty(ms, ms_rgb); +} + +/** + * Test getting and setting scale of light sensor. Checks if collected values + * are scaled properly. + */ +static void test_tcs_scale(void) +{ + struct motion_sensor_t *ms, *ms_rgb; + struct i2c_emul *emul; + uint32_t event = TCS_INT_EVENT; + /* Expected data to test: IR, R, G, B */ + int exp_v[][4] = { + {200, 1110, 870, 850}, + {300, 1110, 10000, 8500}, + {600, 5000, 4000, 3000}, + {100, 3000, 4000, 2000}, + {100, 1000, 1000, 1000}, + }; + /* Scale for each test */ + uint16_t exp_scale[][4] = { + {MOTION_SENSE_DEFAULT_SCALE, MOTION_SENSE_DEFAULT_SCALE, + MOTION_SENSE_DEFAULT_SCALE, MOTION_SENSE_DEFAULT_SCALE}, + {MOTION_SENSE_DEFAULT_SCALE + 300, + MOTION_SENSE_DEFAULT_SCALE + 300, + MOTION_SENSE_DEFAULT_SCALE + 300, + MOTION_SENSE_DEFAULT_SCALE + 300}, + {MOTION_SENSE_DEFAULT_SCALE - 300, + MOTION_SENSE_DEFAULT_SCALE - 300, + MOTION_SENSE_DEFAULT_SCALE - 300, + MOTION_SENSE_DEFAULT_SCALE - 300}, + {MOTION_SENSE_DEFAULT_SCALE + 345, + MOTION_SENSE_DEFAULT_SCALE - 5423, + MOTION_SENSE_DEFAULT_SCALE - 30, + MOTION_SENSE_DEFAULT_SCALE + 400}, + {MOTION_SENSE_DEFAULT_SCALE - 345, + MOTION_SENSE_DEFAULT_SCALE + 5423, + MOTION_SENSE_DEFAULT_SCALE + 30, + MOTION_SENSE_DEFAULT_SCALE - 400}, + {MOTION_SENSE_DEFAULT_SCALE, MOTION_SENSE_DEFAULT_SCALE, + MOTION_SENSE_DEFAULT_SCALE, MOTION_SENSE_DEFAULT_SCALE} + }; + uint16_t scale[3]; + int16_t temp; + int ret, i, test; + intv3_t v; + + emul = tcs_emul_get(TCS_ORD); + ms = &motion_sensors[TCS_CLR_SENSOR_ID]; + ms_rgb = &motion_sensors[TCS_RGB_SENSOR_ID]; + + /* Need to be set to collect all data in FIFO */ + ms->oversampling_ratio = 1; + ms_rgb->oversampling_ratio = 1; + /* Disable calibration mode */ + zassert_equal(EC_SUCCESS, ms->drv->perform_calib(ms, 0), NULL); + /* Setup AGAIN and ATIME for normal mode */ + zassert_equal(EC_RES_IN_PROGRESS, ms->drv->read(ms, v), NULL); + + /* Test different data in supported range */ + for (test = 0; test < ARRAY_SIZE(exp_v); test++) { + /* Set and test clear sensor scale */ + zassert_equal(EC_SUCCESS, + ms->drv->set_scale(ms, exp_scale[test], 0), + "test %d", test); + zassert_equal(EC_SUCCESS, + ms->drv->get_scale(ms, scale, &temp), + "test %d", test); + zassert_equal((int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP, temp, + "test %d, %d", test, temp); + zassert_equal(exp_scale[test][0], scale[0], "test %d", test); + + /* Set and test RGB sensor scale */ + zassert_equal(EC_SUCCESS, ms_rgb->drv->set_scale(ms_rgb, + &(exp_scale[test][1]), 0), + "test %d", test); + zassert_equal(EC_SUCCESS, + ms_rgb->drv->get_scale(ms_rgb, scale, &temp), + "test %d", test); + zassert_equal((int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP, temp, + "test %d", test); + zassert_equal(exp_scale[test][1], scale[0], "test %d", test); + zassert_equal(exp_scale[test][2], scale[1], "test %d", test); + zassert_equal(exp_scale[test][3], scale[2], "test %d", test); + + set_emul_val_from_exp(exp_v[test], exp_scale[test], emul); + + /* Run few times to allow driver change gain */ + for (i = 0; i < 5; i++) { + tcs_emul_set_reg(emul, TCS_I2C_STATUS, + TCS_I2C_STATUS_RGBC_VALID); + zassert_equal(EC_SUCCESS, + ms->drv->irq_handler(ms, &event), NULL); + } + check_fifo(ms, ms_rgb, exp_v[test], V_EPS); + } + + /* Test fail if scale equals 0 */ + scale[0] = 0; + scale[1] = MOTION_SENSE_DEFAULT_SCALE; + scale[2] = MOTION_SENSE_DEFAULT_SCALE; + zassert_equal(EC_ERROR_INVAL, ms->drv->set_scale(ms, scale, 0), NULL); + + zassert_equal(EC_ERROR_INVAL, ms_rgb->drv->set_scale(ms_rgb, scale, 0), + NULL); + scale[0] = MOTION_SENSE_DEFAULT_SCALE; + scale[1] = 0; + scale[2] = MOTION_SENSE_DEFAULT_SCALE; + zassert_equal(EC_ERROR_INVAL, ms_rgb->drv->set_scale(ms_rgb, scale, 0), + NULL); + scale[0] = MOTION_SENSE_DEFAULT_SCALE; + scale[1] = MOTION_SENSE_DEFAULT_SCALE; + scale[2] = 0; + zassert_equal(EC_ERROR_INVAL, ms_rgb->drv->set_scale(ms_rgb, scale, 0), + NULL); +} + +/** Test setting and getting data rate of light sensor */ +static void test_tcs_data_rate(void) +{ + struct motion_sensor_t *ms, *ms_rgb; + struct i2c_emul *emul; + uint8_t enable; + + emul = tcs_emul_get(TCS_ORD); + ms = &motion_sensors[TCS_CLR_SENSOR_ID]; + /* RGB sensor doesn't set rate, but return rate of clear sesnor */ + ms_rgb = &motion_sensors[TCS_RGB_SENSOR_ID]; + + /* Test fail on reading device power state */ + tcs_emul_set_read_fail_reg(emul, TCS_I2C_ENABLE); + zassert_equal(-EIO, ms->drv->set_data_rate(ms, 0, 0), NULL); + zassert_equal(-EIO, ms->drv->set_data_rate(ms, 0, 1), NULL); + zassert_equal(-EIO, ms->drv->set_data_rate(ms, 100, 0), NULL); + zassert_equal(-EIO, ms->drv->set_data_rate(ms, 100, 1), NULL); + tcs_emul_set_read_fail_reg(emul, TCS_EMUL_NO_FAIL_REG); + + /* Test setting 0 rate disables device */ + zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, 0, 0), NULL); + zassert_equal(0, tcs_emul_get_reg(emul, TCS_I2C_ENABLE), NULL); + zassert_equal(0, ms->drv->get_data_rate(ms), NULL); + zassert_equal(0, ms_rgb->drv->get_data_rate(ms_rgb), NULL); + + zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, 0, 1), NULL); + zassert_equal(0, tcs_emul_get_reg(emul, TCS_I2C_ENABLE), NULL); + zassert_equal(0, tcs_emul_get_reg(emul, TCS_I2C_ENABLE), NULL); + zassert_equal(0, ms->drv->get_data_rate(ms), NULL); + zassert_equal(0, ms_rgb->drv->get_data_rate(ms_rgb), NULL); + + + /* Test setting non-zero rate enables device */ + zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, 100, 0), NULL); + enable = tcs_emul_get_reg(emul, TCS_I2C_ENABLE); + zassert_true(enable & TCS_I2C_ENABLE_POWER_ON, NULL); + zassert_true(enable & TCS_I2C_ENABLE_ADC_ENABLE, NULL); + zassert_true(enable & TCS_I2C_ENABLE_INT_ENABLE, NULL); + zassert_equal(100, ms->drv->get_data_rate(ms), NULL); + zassert_equal(100, ms_rgb->drv->get_data_rate(ms_rgb), NULL); + + zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, 100, 1), NULL); + enable = tcs_emul_get_reg(emul, TCS_I2C_ENABLE); + zassert_true(enable & TCS_I2C_ENABLE_POWER_ON, NULL); + zassert_true(enable & TCS_I2C_ENABLE_ADC_ENABLE, NULL); + zassert_true(enable & TCS_I2C_ENABLE_INT_ENABLE, NULL); + zassert_equal(100, ms->drv->get_data_rate(ms), NULL); + zassert_equal(100, ms_rgb->drv->get_data_rate(ms_rgb), NULL); + + /* Test RGB sensor doesn't change data rate */ + zassert_equal(EC_SUCCESS, ms_rgb->drv->set_data_rate(ms_rgb, 300, 0), + NULL); + zassert_equal(100, ms->drv->get_data_rate(ms), NULL); + zassert_equal(100, ms_rgb->drv->get_data_rate(ms_rgb), NULL); + + zassert_equal(EC_SUCCESS, ms_rgb->drv->set_data_rate(ms_rgb, 300, 1), + NULL); + zassert_equal(100, ms->drv->get_data_rate(ms), NULL); + zassert_equal(100, ms_rgb->drv->get_data_rate(ms_rgb), NULL); +} + +/** Test set range function of clear and RGB sensors */ +static void test_tcs_set_range(void) +{ + struct motion_sensor_t *ms, *ms_rgb; + struct i2c_emul *emul; + + emul = tcs_emul_get(TCS_ORD); + ms = &motion_sensors[TCS_CLR_SENSOR_ID]; + ms_rgb = &motion_sensors[TCS_RGB_SENSOR_ID]; + + /* RGB sensor doesn't set anything */ + zassert_equal(EC_SUCCESS, ms_rgb->drv->set_range(ms_rgb, 1, 0), NULL); + + /* Clear sensor doesn't change anything on device to set range */ + zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, 0x12300, 1), NULL); + zassert_equal(0x12300, ms->current_range, NULL); + + zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, 0x10000, 0), NULL); + zassert_equal(0x10000, ms->current_range, NULL); +} + +void test_suite_tcs3400(void) +{ + ztest_test_suite(tcs3400, + ztest_user_unit_test(test_tcs_init), + ztest_user_unit_test(test_tcs_read), + ztest_user_unit_test(test_tcs_irq_handler_fail), + ztest_user_unit_test(test_tcs_read_calibration), + ztest_user_unit_test(test_tcs_read_xyz), + ztest_user_unit_test(test_tcs_scale), + ztest_user_unit_test(test_tcs_data_rate), + ztest_user_unit_test(test_tcs_set_range)); + ztest_run_test_suite(tcs3400); +} |