nova: Support ALS TCS3400

Support ALS TCS3400

BUG=b:328711879
TEST=make BOARD=nova

Change-Id: I9bba39cf1217a9e43a66e23333c56828d845de12
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/5501358
Reviewed-by: Forest Mittelberg <bmbm@google.com>
Auto-Submit: Yu-An Chen <yu-an.chen@quanta.corp-partner.google.com>
Reviewed-by: Bruce Goodwin <bgoodwin@chromium.org>
Commit-Queue: Yu-An Chen <yu-an.chen@quanta.corp-partner.google.com>
Code-Coverage: Zoss <zoss-cl-coverage@prod.google.com>
Tested-by: Yu-An Chen <yu-an.chen@quanta.corp-partner.google.com>
diff --git a/board/nova/board.h b/board/nova/board.h
index fd0e46b..59ee29b 100644
--- a/board/nova/board.h
+++ b/board/nova/board.h
@@ -59,6 +59,7 @@
 #define GPIO_RECOVERY_L_2 GPIO_GSC_EC_RECOVERY_BTN_OD
 
 /* I2C Bus Configuration */
+#define I2C_PORT_SENSOR NPCX_I2C_PORT3_0
 #define I2C_PORT_EEPROM NPCX_I2C_PORT7_0
 #define I2C_PORT_MP2964 NPCX_I2C_PORT7_0
 
@@ -139,6 +140,27 @@
 /* Include math_util for bitmask_uint64 used in pd_timers */
 #define CONFIG_MATH_UTIL
 
+/* Sensor */
+#undef CONFIG_MOTION_SENSE_RESUME_DELAY_US
+#define CONFIG_MOTION_SENSE_RESUME_DELAY_US (1000 * MSEC)
+#define CONFIG_CMD_ACCEL_INFO
+/* Enable sensor fifo, must also define the _SIZE and _THRES */
+#define CONFIG_ACCEL_FIFO
+/* FIFO size is in power of 2. */
+#define CONFIG_ACCEL_FIFO_SIZE 256
+/* Depends on how fast the AP boots and typical ODRs */
+#define CONFIG_ACCEL_FIFO_THRES (CONFIG_ACCEL_FIFO_SIZE / 3)
+
+/* TCS3400 ALS */
+#define CONFIG_ALS
+#define ALS_COUNT 1
+#define CONFIG_ALS_TCS3400
+#define CONFIG_ALS_TCS3400_INT_EVENT \
+	TASK_EVENT_MOTION_SENSOR_INTERRUPT(CLEAR_ALS)
+
+/* Sensors without hardware FIFO are in forced mode */
+#define CONFIG_ACCEL_FORCE_MODE_MASK BIT(CLEAR_ALS)
+
 #ifndef __ASSEMBLER__
 
 #include "gpio_signal.h" /* needed by registers.h */
@@ -154,6 +176,12 @@
 	ADC_CH_COUNT
 };
 
+enum sensor_id {
+	CLEAR_ALS,
+	RGB_ALS,
+	SENSOR_COUNT,
+};
+
 enum temp_sensor_id {
 	TEMP_SENSOR_1_CPU,
 	TEMP_SENSOR_2_CPU_VR,
diff --git a/board/nova/ec.tasklist b/board/nova/ec.tasklist
index 91f90aa..e8e7f82 100644
--- a/board/nova/ec.tasklist
+++ b/board/nova/ec.tasklist
@@ -12,6 +12,7 @@
 
 #define CONFIG_TASK_LIST \
 	TASK_ALWAYS(HOOKS, hook_task, NULL, LARGER_TASK_STACK_SIZE) \
+	TASK_ALWAYS(MOTIONSENSE, motion_sense_task, NULL, VENTI_TASK_STACK_SIZE) \
 	TASK_NOTEST(CHIPSET, chipset_task, NULL, LARGER_TASK_STACK_SIZE) \
 	TASK_ALWAYS(HOSTCMD, host_command_task, NULL, LARGER_TASK_STACK_SIZE) \
 	TASK_ALWAYS(CONSOLE, console_task, NULL, VENTI_TASK_STACK_SIZE) \
diff --git a/board/nova/gpio.inc b/board/nova/gpio.inc
index 341ca99..1ddfba5 100644
--- a/board/nova/gpio.inc
+++ b/board/nova/gpio.inc
@@ -79,6 +79,8 @@
 /* I2C SCL/SDA */
 GPIO(EC_I2C_MISC_SCL_R,              PIN(B, 3), GPIO_INPUT)
 GPIO(EC_I2C_MISC_SDA_R,              PIN(B, 2), GPIO_INPUT)
+GPIO(EC_I2C_ALS_SCL,                 PIN(D, 1), GPIO_INPUT | GPIO_SEL_1P8V) /* EC_I2C_ALS_SCL */
+GPIO(EC_I2C_ALS_SDA,                 PIN(D, 0), GPIO_INPUT | GPIO_SEL_1P8V) /* EC_I2C_ALS_SDA */
 
 /* USBA */
 GPIO(EN_PP5000_USBA,                 PIN(D, 7), GPIO_OUT_LOW)
@@ -152,8 +154,6 @@
 UNUSED(PIN(B, 4))       /* GPIOB4/I2C0_SDA0 */
 UNUSED(PIN(9, 2))       /* GPIO92/I2C2_SCL0 */
 UNUSED(PIN(9, 1))       /* GPIO91/I2C2_SDA0 */
-UNUSED(PIN(D, 1))       /* GPIOD1/I2C3_SCL0 */
-UNUSED(PIN(D, 0))       /* GPIOD0/I2C3_SDA0 */
 UNUSED(PIN(F, 3))       /* GPIOF3/I2C4_SCL1 */
 UNUSED(PIN(F, 2))       /* GPIOF2/I2C4_SDA1 */
 UNUSED(PIN(E, 4))       /* GPIOE4/I2C6_SCL1 */
diff --git a/board/nova/i2c.c b/board/nova/i2c.c
index 18650c2..e02668b 100644
--- a/board/nova/i2c.c
+++ b/board/nova/i2c.c
@@ -10,6 +10,14 @@
 /* I2C port map configuration */
 const struct i2c_port_t i2c_ports[] = {
 	{
+		/* I2C3 */
+		.name = "sensor",
+		.port = I2C_PORT_SENSOR,
+		.kbps = 400,
+		.scl = GPIO_EC_I2C_ALS_SCL,
+		.sda = GPIO_EC_I2C_ALS_SDA,
+	},
+	{
 		/* I2C7 */
 		.name = "eeprom",
 		.port = I2C_PORT_EEPROM,
diff --git a/board/nova/sensors.c b/board/nova/sensors.c
index 811a84b..9948d4d 100644
--- a/board/nova/sensors.c
+++ b/board/nova/sensors.c
@@ -5,6 +5,7 @@
 
 #include "adc_chip.h"
 #include "common.h"
+#include "driver/als_tcs3400.h"
 #include "hooks.h"
 #include "temp_sensor.h"
 #include "temp_sensor/thermistor.h"
@@ -107,3 +108,98 @@
 	[TEMP_SENSOR_4_DIMM] = thermal_cpu,
 };
 BUILD_ASSERT(ARRAY_SIZE(thermal_params) == TEMP_SENSOR_COUNT);
+
+/* TCS3400 private data */
+static struct als_drv_data_t g_tcs3400_data = {
+	.als_cal.scale = 1,
+	.als_cal.uscale = 0,
+	.als_cal.offset = 0,
+	.als_cal.channel_scale = {
+		.k_channel_scale = ALS_CHANNEL_SCALE(1.0), /* kc */
+		.cover_scale = ALS_CHANNEL_SCALE(1.0),     /* CT */
+	},
+};
+
+static struct tcs3400_rgb_drv_data_t g_tcs3400_rgb_data = {
+	/*
+	 * b/202465034: calculate the actual coefficients and scaling factors
+	 */
+	.calibration.rgb_cal[X] = {
+		.offset = 0,
+		.scale = {
+			.k_channel_scale = ALS_CHANNEL_SCALE(1.0), /* kr */
+			.cover_scale = ALS_CHANNEL_SCALE(1.0)
+		},
+		.coeff[TCS_RED_COEFF_IDX] = FLOAT_TO_FP(0),
+		.coeff[TCS_GREEN_COEFF_IDX] = FLOAT_TO_FP(0),
+		.coeff[TCS_BLUE_COEFF_IDX] = FLOAT_TO_FP(0),
+		.coeff[TCS_CLEAR_COEFF_IDX] = FLOAT_TO_FP(0),
+	},
+	.calibration.rgb_cal[Y] = {
+		.offset = 0,
+		.scale = {
+			.k_channel_scale = ALS_CHANNEL_SCALE(1.0), /* kg */
+			.cover_scale = ALS_CHANNEL_SCALE(1.0)
+		},
+		.coeff[TCS_RED_COEFF_IDX] = FLOAT_TO_FP(0),
+		.coeff[TCS_GREEN_COEFF_IDX] = FLOAT_TO_FP(0),
+		.coeff[TCS_BLUE_COEFF_IDX] = FLOAT_TO_FP(0),
+		.coeff[TCS_CLEAR_COEFF_IDX] = FLOAT_TO_FP(0.1),
+	},
+	.calibration.rgb_cal[Z] = {
+		.offset = 0,
+		.scale = {
+			.k_channel_scale = ALS_CHANNEL_SCALE(1.0), /* kb */
+			.cover_scale = ALS_CHANNEL_SCALE(1.0)
+		},
+		.coeff[TCS_RED_COEFF_IDX] = FLOAT_TO_FP(0),
+		.coeff[TCS_GREEN_COEFF_IDX] = FLOAT_TO_FP(0),
+		.coeff[TCS_BLUE_COEFF_IDX] = FLOAT_TO_FP(0),
+		.coeff[TCS_CLEAR_COEFF_IDX] = FLOAT_TO_FP(0),
+	},
+	.calibration.irt = INT_TO_FP(1),
+	.saturation.again = TCS_DEFAULT_AGAIN,
+	.saturation.atime = TCS_DEFAULT_ATIME,
+};
+
+struct motion_sensor_t motion_sensors[] = {
+	[CLEAR_ALS] = {
+		.name = "Clear Light",
+		.active_mask = SENSOR_ACTIVE_S0,
+		.chip = MOTIONSENSE_CHIP_TCS3400,
+		.type = MOTIONSENSE_TYPE_LIGHT,
+		.location = MOTIONSENSE_LOC_BASE,
+		.drv = &tcs3400_drv,
+		.drv_data = &g_tcs3400_data,
+		.port = I2C_PORT_SENSOR,
+		.i2c_spi_addr_flags = TCS3400_I2C_ADDR_FLAGS,
+		.rot_standard_ref = NULL,
+		.default_range = 0x10000, /* scale = 1x, uscale = 0 */
+		.min_frequency = TCS3400_LIGHT_MIN_FREQ,
+		.max_frequency = TCS3400_LIGHT_MAX_FREQ,
+		.config = {
+			/* Run ALS sensor in S0 */
+			[SENSOR_CONFIG_EC_S0] = {
+				.odr = 1000,
+			},
+		},
+	},
+	[RGB_ALS] = {
+		.name = "RGB Light",
+		.active_mask = SENSOR_ACTIVE_S0,
+		.chip = MOTIONSENSE_CHIP_TCS3400,
+		.type = MOTIONSENSE_TYPE_LIGHT_RGB,
+		.location = MOTIONSENSE_LOC_BASE,
+		.drv = &tcs3400_rgb_drv,
+		.drv_data = &g_tcs3400_rgb_data,
+		.rot_standard_ref = NULL,
+		.default_range = 0x10000, /* scale = 1x, uscale = 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[CLEAR_ALS],
+};
+BUILD_ASSERT(ARRAY_SIZE(motion_als_sensors) == ALS_COUNT);