1 /*
2  * Copyright 2023 Google LLC
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT ams_tcs3400
8 
9 #include <zephyr/drivers/gpio.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/drivers/sensor.h>
12 #include <zephyr/drivers/sensor/tcs3400.h>
13 #include <zephyr/sys/byteorder.h>
14 #include <zephyr/sys/util.h>
15 
16 #include <zephyr/logging/log.h>
17 LOG_MODULE_REGISTER(tcs3400, CONFIG_SENSOR_LOG_LEVEL);
18 
19 #define TCS3400_ENABLE_REG 0x80
20 #define TCS3400_ENABLE_AIEN BIT(4)
21 #define TCS3400_ENABLE_AEN BIT(1)
22 #define TCS3400_ENABLE_PON BIT(0)
23 
24 #define TCS3400_ATIME_REG 0x81
25 
26 #define TCS3400_PERS_REG 0x8c
27 
28 #define TCS3400_CONFIG_REG 0x8d
29 
30 #define TCS3400_CONTROL_REG 0x8f
31 
32 #define TCS3400_ID_REG 0x92
33 #define TCS3400_ID_1 0x90
34 #define TCS3400_ID_2 0x93
35 
36 #define TCS3400_STATUS_REG 0x93
37 #define TCS3400_STATUS_AVALID BIT(0)
38 
39 #define TCS3400_CDATAL_REG 0x94
40 #define TCS3400_CDATAH_REG 0x95
41 #define TCS3400_RDATAL_REG 0x96
42 #define TCS3400_RDATAH_REG 0x97
43 #define TCS3400_GDATAL_REG 0x98
44 #define TCS3400_GDATAH_REG 0x99
45 #define TCS3400_BDATAL_REG 0x9A
46 #define TCS3400_BDATAH_REG 0x9B
47 
48 #define TCS3400_AICLEAR_REG 0xe7
49 
50 /* Default values */
51 #define TCS3400_DEFAULT_ENABLE 0x00
52 #define TCS3400_DEFAULT_ATIME 0xff
53 #define TCS3400_DEFAULT_PERS 0x00
54 #define TCS3400_DEFAULT_CONFIG 0x00
55 #define TCS3400_DEFAULT_CONTROL 0x00
56 #define TCS3400_AICLEAR_RESET 0x00
57 
58 struct tcs3400_config {
59 	struct i2c_dt_spec i2c;
60 	struct gpio_dt_spec int_gpio;
61 };
62 
63 struct tcs3400_data {
64 	struct gpio_callback gpio_cb;
65 	const struct device *dev;
66 
67 	uint16_t sample_crgb[4];
68 
69 	struct k_sem data_sem;
70 };
71 
tcs3400_setup_int(const struct tcs3400_config * config,bool enable)72 static void tcs3400_setup_int(const struct tcs3400_config *config, bool enable)
73 {
74 	unsigned int flags = enable ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE;
75 
76 	gpio_pin_interrupt_configure_dt(&config->int_gpio, flags);
77 }
78 
tcs3400_gpio_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)79 static void tcs3400_gpio_callback(const struct device *dev,
80 				  struct gpio_callback *cb, uint32_t pins)
81 {
82 	struct tcs3400_data *data = CONTAINER_OF(cb, struct tcs3400_data,
83 						 gpio_cb);
84 
85 	tcs3400_setup_int(data->dev->config, false);
86 
87 	k_sem_give(&data->data_sem);
88 }
89 
tcs3400_sample_fetch(const struct device * dev,enum sensor_channel chan)90 static int tcs3400_sample_fetch(const struct device *dev,
91 				enum sensor_channel chan)
92 {
93 	const struct tcs3400_config *cfg = dev->config;
94 	struct tcs3400_data *data = dev->data;
95 	int ret;
96 	uint8_t status;
97 
98 	if (chan != SENSOR_CHAN_ALL) {
99 		LOG_ERR("Unsupported sensor channel");
100 		return -ENOTSUP;
101 	}
102 
103 	tcs3400_setup_int(cfg, true);
104 
105 	ret = i2c_reg_write_byte_dt(&cfg->i2c, TCS3400_ENABLE_REG,
106 				    TCS3400_ENABLE_AIEN | TCS3400_ENABLE_AEN |
107 				    TCS3400_ENABLE_PON);
108 	if (ret) {
109 		return ret;
110 	}
111 
112 	k_sem_take(&data->data_sem, K_FOREVER);
113 
114 	ret = i2c_reg_read_byte_dt(&cfg->i2c, TCS3400_STATUS_REG, &status);
115 	if (ret) {
116 		return ret;
117 	}
118 
119 	if (status & TCS3400_STATUS_AVALID) {
120 		ret = i2c_burst_read_dt(&cfg->i2c, TCS3400_CDATAL_REG,
121 					(uint8_t *)&data->sample_crgb,
122 					sizeof(data->sample_crgb));
123 		if (ret) {
124 			return ret;
125 		}
126 	} else {
127 		LOG_ERR("Unexpected status: %02x", status);
128 	}
129 
130 	ret = i2c_reg_write_byte_dt(&cfg->i2c, TCS3400_ENABLE_REG, 0);
131 	if (ret) {
132 		return ret;
133 	}
134 
135 	ret = i2c_reg_write_byte_dt(&cfg->i2c, TCS3400_AICLEAR_REG, 0);
136 	if (ret) {
137 		return ret;
138 	}
139 
140 	return 0;
141 }
142 
tcs3400_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)143 static int tcs3400_channel_get(const struct device *dev,
144 			       enum sensor_channel chan,
145 			       struct sensor_value *val)
146 {
147 	struct tcs3400_data *data = dev->data;
148 
149 	switch (chan) {
150 	case SENSOR_CHAN_LIGHT:
151 		val->val1 = sys_le16_to_cpu(data->sample_crgb[0]);
152 		val->val2 = 0;
153 		break;
154 	case SENSOR_CHAN_RED:
155 		val->val1 = sys_le16_to_cpu(data->sample_crgb[1]);
156 		val->val2 = 0;
157 		break;
158 	case SENSOR_CHAN_GREEN:
159 		val->val1 = sys_le16_to_cpu(data->sample_crgb[2]);
160 		val->val2 = 0;
161 		break;
162 	case SENSOR_CHAN_BLUE:
163 		val->val1 = sys_le16_to_cpu(data->sample_crgb[3]);
164 		val->val2 = 0;
165 		break;
166 	default:
167 		return -ENOTSUP;
168 	}
169 
170 	return 0;
171 }
172 
tcs3400_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)173 static int tcs3400_attr_set(const struct device *dev,
174 			    enum sensor_channel chan,
175 			    enum sensor_attribute attr,
176 			    const struct sensor_value *val)
177 {
178 	const struct tcs3400_config *cfg = dev->config;
179 	int ret;
180 	uint8_t reg_val;
181 
182 	switch (attr) {
183 	case SENSOR_ATTR_TCS3400_INTEGRATION_CYCLES:
184 		if (!IN_RANGE(val->val1, 1, 256)) {
185 			return -EINVAL;
186 		}
187 		reg_val = UINT8_MAX - val->val1 + 1;
188 		ret = i2c_reg_write_byte_dt(&cfg->i2c,
189 					    TCS3400_ATIME_REG, reg_val);
190 		if (ret) {
191 			return ret;
192 		}
193 		break;
194 	default:
195 		return -ENOTSUP;
196 	}
197 
198 	return 0;
199 }
200 
tcs3400_sensor_setup(const struct device * dev)201 static int tcs3400_sensor_setup(const struct device *dev)
202 {
203 	const struct tcs3400_config *cfg = dev->config;
204 	uint8_t chip_id;
205 	int ret;
206 	struct {
207 		uint8_t reg_addr;
208 		uint8_t value;
209 	} reset_regs[] = {
210 		{TCS3400_ENABLE_REG, TCS3400_DEFAULT_ENABLE},
211 		{TCS3400_AICLEAR_REG, TCS3400_AICLEAR_RESET},
212 		{TCS3400_ATIME_REG, TCS3400_DEFAULT_ATIME},
213 		{TCS3400_PERS_REG, TCS3400_DEFAULT_PERS},
214 		{TCS3400_CONFIG_REG, TCS3400_DEFAULT_CONFIG},
215 		{TCS3400_CONTROL_REG, TCS3400_DEFAULT_CONTROL},
216 	};
217 
218 	ret = i2c_reg_read_byte_dt(&cfg->i2c, TCS3400_ID_REG, &chip_id);
219 	if (ret) {
220 		LOG_DBG("Failed to read chip id: %d", ret);
221 		return ret;
222 	}
223 
224 	if (!((chip_id == TCS3400_ID_1) || (chip_id == TCS3400_ID_2))) {
225 		LOG_DBG("Invalid chip id: %02x", chip_id);
226 		return -EIO;
227 	}
228 
229 	LOG_INF("chip id: 0x%x", chip_id);
230 
231 	for (size_t i = 0; i < ARRAY_SIZE(reset_regs); i++) {
232 		ret = i2c_reg_write_byte_dt(&cfg->i2c, reset_regs[i].reg_addr,
233 					    reset_regs[i].value);
234 		if (ret) {
235 			LOG_ERR("Failed to set default register: %02x",
236 				reset_regs[i].reg_addr);
237 			return ret;
238 		}
239 	}
240 
241 	return 0;
242 }
243 
244 static const struct sensor_driver_api tcs3400_api = {
245 	.sample_fetch = tcs3400_sample_fetch,
246 	.channel_get = tcs3400_channel_get,
247 	.attr_set = tcs3400_attr_set,
248 };
249 
tcs3400_init(const struct device * dev)250 static int tcs3400_init(const struct device *dev)
251 {
252 	const struct tcs3400_config *cfg = dev->config;
253 	struct tcs3400_data *data = dev->data;
254 	int ret;
255 
256 	k_sem_init(&data->data_sem, 0, K_SEM_MAX_LIMIT);
257 	data->dev = dev;
258 
259 	if (!i2c_is_ready_dt(&cfg->i2c)) {
260 		LOG_ERR("I2C bus is not ready");
261 		return -ENODEV;
262 	}
263 
264 	ret = tcs3400_sensor_setup(dev);
265 	if (ret < 0) {
266 		LOG_ERR("Failed to setup device");
267 		return ret;
268 	}
269 
270 	if (!gpio_is_ready_dt(&cfg->int_gpio)) {
271 		LOG_ERR("Interrupt GPIO device not ready");
272 		return -ENODEV;
273 	}
274 
275 	ret = gpio_pin_configure_dt(&cfg->int_gpio, GPIO_INPUT);
276 	if (ret < 0) {
277 		LOG_ERR("Failed to configure interrupt pin");
278 		return ret;
279 	}
280 
281 	gpio_init_callback(&data->gpio_cb, tcs3400_gpio_callback,
282 			   BIT(cfg->int_gpio.pin));
283 
284 	ret = gpio_add_callback(cfg->int_gpio.port, &data->gpio_cb);
285 	if (ret < 0) {
286 		LOG_ERR("Failed to set GPIO callback");
287 		return ret;
288 	}
289 
290 	return 0;
291 }
292 
293 #define TCS3400_INIT(n) \
294 	static struct tcs3400_data tcs3400_data_##n; \
295 	static const struct tcs3400_config tcs3400_config_##n = { \
296 		.i2c = I2C_DT_SPEC_INST_GET(n), \
297 		.int_gpio = GPIO_DT_SPEC_INST_GET(n, int_gpios), \
298 	}; \
299 	SENSOR_DEVICE_DT_INST_DEFINE(n, &tcs3400_init, NULL, \
300 				     &tcs3400_data_##n, &tcs3400_config_##n, \
301 				     POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \
302 				     &tcs3400_api);
303 
304 DT_INST_FOREACH_STATUS_OKAY(TCS3400_INIT)
305