1 /*
2 * Copyright (c) 2017 Intel Corporation
3 * Copyright (c) 2018 Phytec Messtechnik GmbH
4 *
5 *SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT avago_apds9960
9
10 /* @file
11 * @brief driver for APDS9960 ALS/RGB/gesture/proximity sensor
12 */
13
14 #include <zephyr/device.h>
15 #include <zephyr/drivers/sensor.h>
16 #include <zephyr/drivers/i2c.h>
17 #include <zephyr/pm/device.h>
18 #include <zephyr/sys/__assert.h>
19 #include <zephyr/sys/byteorder.h>
20 #include <zephyr/init.h>
21 #include <zephyr/kernel.h>
22 #include <string.h>
23 #include <zephyr/logging/log.h>
24
25 #include "apds9960.h"
26
27 LOG_MODULE_REGISTER(APDS9960, CONFIG_SENSOR_LOG_LEVEL);
28
apds9960_handle_cb(struct apds9960_data * drv_data)29 static void apds9960_handle_cb(struct apds9960_data *drv_data)
30 {
31 apds9960_setup_int(drv_data->dev->config, false);
32
33 #ifdef CONFIG_APDS9960_TRIGGER
34 k_work_submit(&drv_data->work);
35 #else
36 k_sem_give(&drv_data->data_sem);
37 #endif
38 }
39
apds9960_gpio_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)40 static void apds9960_gpio_callback(const struct device *dev,
41 struct gpio_callback *cb, uint32_t pins)
42 {
43 struct apds9960_data *drv_data =
44 CONTAINER_OF(cb, struct apds9960_data, gpio_cb);
45
46 apds9960_handle_cb(drv_data);
47 }
48
apds9960_sample_fetch(const struct device * dev,enum sensor_channel chan)49 static int apds9960_sample_fetch(const struct device *dev,
50 enum sensor_channel chan)
51 {
52 const struct apds9960_config *config = dev->config;
53 struct apds9960_data *data = dev->data;
54 uint8_t tmp;
55
56 if (chan != SENSOR_CHAN_ALL) {
57 LOG_ERR("Unsupported sensor channel");
58 return -ENOTSUP;
59 }
60
61 #ifndef CONFIG_APDS9960_TRIGGER
62 apds9960_setup_int(config, true);
63
64 #ifdef CONFIG_APDS9960_ENABLE_ALS
65 tmp = APDS9960_ENABLE_PON | APDS9960_ENABLE_AIEN;
66 #else
67 tmp = APDS9960_ENABLE_PON | APDS9960_ENABLE_PIEN;
68 #endif
69 if (i2c_reg_update_byte_dt(&config->i2c,
70 APDS9960_ENABLE_REG, tmp, tmp)) {
71 LOG_ERR("Power on bit not set.");
72 return -EIO;
73 }
74
75 k_sem_take(&data->data_sem, K_FOREVER);
76 #endif
77
78 if (i2c_reg_read_byte_dt(&config->i2c,
79 APDS9960_STATUS_REG, &tmp)) {
80 return -EIO;
81 }
82
83 LOG_DBG("status: 0x%x", tmp);
84 if (tmp & APDS9960_STATUS_PINT) {
85 if (i2c_reg_read_byte_dt(&config->i2c,
86 APDS9960_PDATA_REG, &data->pdata)) {
87 return -EIO;
88 }
89 }
90
91 if (tmp & APDS9960_STATUS_AINT) {
92 if (i2c_burst_read_dt(&config->i2c,
93 APDS9960_CDATAL_REG,
94 (uint8_t *)&data->sample_crgb,
95 sizeof(data->sample_crgb))) {
96 return -EIO;
97 }
98
99 }
100
101 #ifndef CONFIG_APDS9960_TRIGGER
102 if (i2c_reg_update_byte_dt(&config->i2c,
103 APDS9960_ENABLE_REG,
104 APDS9960_ENABLE_PON,
105 0)) {
106 return -EIO;
107 }
108 #endif
109
110 if (i2c_reg_write_byte_dt(&config->i2c,
111 APDS9960_AICLEAR_REG, 0)) {
112 return -EIO;
113 }
114
115 return 0;
116 }
117
apds9960_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)118 static int apds9960_channel_get(const struct device *dev,
119 enum sensor_channel chan,
120 struct sensor_value *val)
121 {
122 struct apds9960_data *data = dev->data;
123
124 switch (chan) {
125 #ifdef CONFIG_APDS9960_ENABLE_ALS
126 case SENSOR_CHAN_LIGHT:
127 val->val1 = sys_le16_to_cpu(data->sample_crgb[0]);
128 val->val2 = 0;
129 break;
130 case SENSOR_CHAN_RED:
131 val->val1 = sys_le16_to_cpu(data->sample_crgb[1]);
132 val->val2 = 0;
133 break;
134 case SENSOR_CHAN_GREEN:
135 val->val1 = sys_le16_to_cpu(data->sample_crgb[2]);
136 val->val2 = 0;
137 break;
138 case SENSOR_CHAN_BLUE:
139 val->val1 = sys_le16_to_cpu(data->sample_crgb[3]);
140 val->val2 = 0;
141 break;
142 #endif
143 case SENSOR_CHAN_PROX:
144 val->val1 = data->pdata;
145 val->val2 = 0;
146 break;
147 default:
148 return -ENOTSUP;
149 }
150
151 return 0;
152 }
153
apds9960_proxy_setup(const struct device * dev)154 static int apds9960_proxy_setup(const struct device *dev)
155 {
156 const struct apds9960_config *config = dev->config;
157
158 if (i2c_reg_write_byte_dt(&config->i2c,
159 APDS9960_POFFSET_UR_REG,
160 APDS9960_DEFAULT_POFFSET_UR)) {
161 LOG_ERR("Default offset UR not set ");
162 return -EIO;
163 }
164
165 if (i2c_reg_write_byte_dt(&config->i2c,
166 APDS9960_POFFSET_DL_REG,
167 APDS9960_DEFAULT_POFFSET_DL)) {
168 LOG_ERR("Default offset DL not set ");
169 return -EIO;
170 }
171
172 if (i2c_reg_write_byte_dt(&config->i2c,
173 APDS9960_PPULSE_REG,
174 config->ppcount)) {
175 LOG_ERR("Default pulse count not set ");
176 return -EIO;
177 }
178
179 if (i2c_reg_update_byte_dt(&config->i2c,
180 APDS9960_CONTROL_REG,
181 APDS9960_CONTROL_LDRIVE,
182 APDS9960_DEFAULT_LDRIVE)) {
183 LOG_ERR("LED Drive Strength not set");
184 return -EIO;
185 }
186
187 if (i2c_reg_update_byte_dt(&config->i2c,
188 APDS9960_CONFIG2_REG,
189 APDS9960_PLED_BOOST_300,
190 config->pled_boost)) {
191 LOG_ERR("LED Drive Strength not set");
192 return -EIO;
193 }
194
195 if (i2c_reg_update_byte_dt(&config->i2c,
196 APDS9960_CONTROL_REG, APDS9960_CONTROL_PGAIN,
197 (config->pgain & APDS9960_PGAIN_8X))) {
198 LOG_ERR("Gain is not set");
199 return -EIO;
200 }
201
202 if (i2c_reg_write_byte_dt(&config->i2c,
203 APDS9960_PILT_REG, APDS9960_DEFAULT_PILT)) {
204 LOG_ERR("Low threshold not set");
205 return -EIO;
206 }
207
208 if (i2c_reg_write_byte_dt(&config->i2c,
209 APDS9960_PIHT_REG, APDS9960_DEFAULT_PIHT)) {
210 LOG_ERR("High threshold not set");
211 return -EIO;
212 }
213
214 if (i2c_reg_update_byte_dt(&config->i2c,
215 APDS9960_ENABLE_REG, APDS9960_ENABLE_PEN,
216 APDS9960_ENABLE_PEN)) {
217 LOG_ERR("Proximity mode is not enabled");
218 return -EIO;
219 }
220
221 return 0;
222 }
223
224 #ifdef CONFIG_APDS9960_ENABLE_ALS
apds9960_ambient_setup(const struct device * dev)225 static int apds9960_ambient_setup(const struct device *dev)
226 {
227 const struct apds9960_config *config = dev->config;
228 uint16_t th;
229
230 /* ADC value */
231 if (i2c_reg_write_byte_dt(&config->i2c,
232 APDS9960_ATIME_REG, APDS9960_DEFAULT_ATIME)) {
233 LOG_ERR("Default integration time not set for ADC");
234 return -EIO;
235 }
236
237 /* ALS Gain */
238 if (i2c_reg_update_byte_dt(&config->i2c,
239 APDS9960_CONTROL_REG,
240 APDS9960_CONTROL_AGAIN,
241 (config->again & APDS9960_AGAIN_64X))) {
242 LOG_ERR("Ambient Gain is not set");
243 return -EIO;
244 }
245
246 th = sys_cpu_to_le16(APDS9960_DEFAULT_AILT);
247 if (i2c_burst_write_dt(&config->i2c,
248 APDS9960_INT_AILTL_REG,
249 (uint8_t *)&th, sizeof(th))) {
250 LOG_ERR("ALS low threshold not set");
251 return -EIO;
252 }
253
254 th = sys_cpu_to_le16(APDS9960_DEFAULT_AIHT);
255 if (i2c_burst_write_dt(&config->i2c,
256 APDS9960_INT_AIHTL_REG,
257 (uint8_t *)&th, sizeof(th))) {
258 LOG_ERR("ALS low threshold not set");
259 return -EIO;
260 }
261
262 /* Enable ALS */
263 if (i2c_reg_update_byte_dt(&config->i2c,
264 APDS9960_ENABLE_REG, APDS9960_ENABLE_AEN,
265 APDS9960_ENABLE_AEN)) {
266 LOG_ERR("ALS is not enabled");
267 return -EIO;
268 }
269
270 return 0;
271 }
272 #endif
273
apds9960_sensor_setup(const struct device * dev)274 static int apds9960_sensor_setup(const struct device *dev)
275 {
276 const struct apds9960_config *config = dev->config;
277 uint8_t chip_id;
278
279 if (i2c_reg_read_byte_dt(&config->i2c,
280 APDS9960_ID_REG, &chip_id)) {
281 LOG_ERR("Failed reading chip id");
282 return -EIO;
283 }
284
285 if (!((chip_id == APDS9960_ID_1) || (chip_id == APDS9960_ID_2))) {
286 LOG_ERR("Invalid chip id 0x%x", chip_id);
287 return -EIO;
288 }
289
290 /* Disable all functions and interrupts */
291 if (i2c_reg_write_byte_dt(&config->i2c,
292 APDS9960_ENABLE_REG, 0)) {
293 LOG_ERR("ENABLE register is not cleared");
294 return -EIO;
295 }
296
297 if (i2c_reg_write_byte_dt(&config->i2c,
298 APDS9960_AICLEAR_REG, 0)) {
299 return -EIO;
300 }
301
302 /* Disable gesture interrupt */
303 if (i2c_reg_write_byte_dt(&config->i2c,
304 APDS9960_GCONFIG4_REG, 0)) {
305 LOG_ERR("GCONFIG4 register is not cleared");
306 return -EIO;
307 }
308
309 if (i2c_reg_write_byte_dt(&config->i2c,
310 APDS9960_WTIME_REG, APDS9960_DEFAULT_WTIME)) {
311 LOG_ERR("Default wait time not set");
312 return -EIO;
313 }
314
315 if (i2c_reg_write_byte_dt(&config->i2c,
316 APDS9960_CONFIG1_REG,
317 APDS9960_DEFAULT_CONFIG1)) {
318 LOG_ERR("Default WLONG not set");
319 return -EIO;
320 }
321
322 if (i2c_reg_write_byte_dt(&config->i2c,
323 APDS9960_CONFIG2_REG,
324 APDS9960_DEFAULT_CONFIG2)) {
325 LOG_ERR("Configuration Register Two not set");
326 return -EIO;
327 }
328
329 if (i2c_reg_write_byte_dt(&config->i2c,
330 APDS9960_CONFIG3_REG,
331 APDS9960_DEFAULT_CONFIG3)) {
332 LOG_ERR("Configuration Register Three not set");
333 return -EIO;
334 }
335
336 if (i2c_reg_write_byte_dt(&config->i2c,
337 APDS9960_PERS_REG,
338 APDS9960_DEFAULT_PERS)) {
339 LOG_ERR("Interrupt persistence not set");
340 return -EIO;
341 }
342
343 if (apds9960_proxy_setup(dev)) {
344 LOG_ERR("Failed to setup proximity functionality");
345 return -EIO;
346 }
347
348 #ifdef CONFIG_APDS9960_ENABLE_ALS
349 if (apds9960_ambient_setup(dev)) {
350 LOG_ERR("Failed to setup ambient light functionality");
351 return -EIO;
352 }
353 #endif
354
355 return 0;
356 }
357
apds9960_init_interrupt(const struct device * dev)358 static int apds9960_init_interrupt(const struct device *dev)
359 {
360 const struct apds9960_config *config = dev->config;
361 struct apds9960_data *drv_data = dev->data;
362
363 if (!gpio_is_ready_dt(&config->int_gpio)) {
364 LOG_ERR("%s: device %s is not ready", dev->name,
365 config->int_gpio.port->name);
366 return -ENODEV;
367 }
368
369 gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT | config->int_gpio.dt_flags);
370
371 gpio_init_callback(&drv_data->gpio_cb,
372 apds9960_gpio_callback,
373 BIT(config->int_gpio.pin));
374
375 if (gpio_add_callback(config->int_gpio.port, &drv_data->gpio_cb) < 0) {
376 LOG_DBG("Failed to set gpio callback!");
377 return -EIO;
378 }
379
380 drv_data->dev = dev;
381
382 #ifdef CONFIG_APDS9960_TRIGGER
383 drv_data->work.handler = apds9960_work_cb;
384 if (i2c_reg_update_byte_dt(&config->i2c,
385 APDS9960_ENABLE_REG,
386 APDS9960_ENABLE_PON,
387 APDS9960_ENABLE_PON)) {
388 LOG_ERR("Power on bit not set.");
389 return -EIO;
390 }
391
392 #else
393 k_sem_init(&drv_data->data_sem, 0, K_SEM_MAX_LIMIT);
394 #endif
395 apds9960_setup_int(config, true);
396
397 if (gpio_pin_get_dt(&config->int_gpio) > 0) {
398 apds9960_handle_cb(drv_data);
399 }
400
401 return 0;
402 }
403
404 #ifdef CONFIG_PM_DEVICE
apds9960_pm_action(const struct device * dev,enum pm_device_action action)405 static int apds9960_pm_action(const struct device *dev,
406 enum pm_device_action action)
407 {
408 const struct apds9960_config *config = dev->config;
409 int ret = 0;
410
411 switch (action) {
412 case PM_DEVICE_ACTION_RESUME:
413 if (i2c_reg_update_byte_dt(&config->i2c,
414 APDS9960_ENABLE_REG,
415 APDS9960_ENABLE_PON,
416 APDS9960_ENABLE_PON)) {
417 ret = -EIO;
418 }
419 break;
420 case PM_DEVICE_ACTION_SUSPEND:
421 if (i2c_reg_update_byte_dt(&config->i2c,
422 APDS9960_ENABLE_REG,
423 APDS9960_ENABLE_PON, 0)) {
424 ret = -EIO;
425 }
426
427 if (i2c_reg_write_byte_dt(&config->i2c,
428 APDS9960_AICLEAR_REG, 0)) {
429 ret = -EIO;
430 }
431 break;
432 default:
433 return -ENOTSUP;
434 }
435
436 return ret;
437 }
438 #endif
439
apds9960_init(const struct device * dev)440 static int apds9960_init(const struct device *dev)
441 {
442 const struct apds9960_config *config = dev->config;
443 struct apds9960_data *data = dev->data;
444
445 /* Initialize time 5.7ms */
446 k_sleep(K_MSEC(6));
447
448 if (!device_is_ready(config->i2c.bus)) {
449 LOG_ERR("Bus device is not ready");
450 return -EINVAL;
451 }
452
453 (void)memset(data->sample_crgb, 0, sizeof(data->sample_crgb));
454 data->pdata = 0U;
455
456 if (apds9960_sensor_setup(dev) < 0) {
457 LOG_ERR("Failed to setup device!");
458 return -EIO;
459 }
460
461 if (apds9960_init_interrupt(dev) < 0) {
462 LOG_ERR("Failed to initialize interrupt!");
463 return -EIO;
464 }
465
466 return 0;
467 }
468
469 static const struct sensor_driver_api apds9960_driver_api = {
470 .sample_fetch = &apds9960_sample_fetch,
471 .channel_get = &apds9960_channel_get,
472 #ifdef CONFIG_APDS9960_TRIGGER
473 .attr_set = apds9960_attr_set,
474 .trigger_set = apds9960_trigger_set,
475 #endif
476 };
477
478 static const struct apds9960_config apds9960_config = {
479 .i2c = I2C_DT_SPEC_INST_GET(0),
480 .int_gpio = GPIO_DT_SPEC_INST_GET(0, int_gpios),
481 #if CONFIG_APDS9960_PGAIN_8X
482 .pgain = APDS9960_PGAIN_8X,
483 #elif CONFIG_APDS9960_PGAIN_4X
484 .pgain = APDS9960_PGAIN_4X,
485 #elif CONFIG_APDS9960_PGAIN_2X
486 .pgain = APDS9960_PGAIN_2X,
487 #else
488 .pgain = APDS9960_PGAIN_1X,
489 #endif
490 #if CONFIG_APDS9960_AGAIN_64X
491 .again = APDS9960_AGAIN_64X,
492 #elif CONFIG_APDS9960_AGAIN_16X
493 .again = APDS9960_AGAIN_16X,
494 #elif CONFIG_APDS9960_AGAIN_4X
495 .again = APDS9960_AGAIN_4X,
496 #else
497 .again = APDS9960_AGAIN_1X,
498 #endif
499 #if CONFIG_APDS9960_PPULSE_LENGTH_32US
500 .ppcount = APDS9960_PPULSE_LENGTH_32US |
501 (CONFIG_APDS9960_PPULSE_COUNT - 1),
502 #elif CONFIG_APDS9960_PPULSE_LENGTH_16US
503 .ppcount = APDS9960_PPULSE_LENGTH_16US |
504 (CONFIG_APDS9960_PPULSE_COUNT - 1),
505 #elif CONFIG_APDS9960_PPULSE_LENGTH_8US
506 .ppcount = APDS9960_PPULSE_LENGTH_8US |
507 (CONFIG_APDS9960_PPULSE_COUNT - 1),
508 #else
509 .ppcount = APDS9960_PPULSE_LENGTH_4US |
510 (CONFIG_APDS9960_PPULSE_COUNT - 1),
511 #endif
512 #if CONFIG_APDS9960_PLED_BOOST_300PCT
513 .pled_boost = APDS9960_PLED_BOOST_300,
514 #elif CONFIG_APDS9960_PLED_BOOST_200PCT
515 .pled_boost = APDS9960_PLED_BOOST_200,
516 #elif CONFIG_APDS9960_PLED_BOOST_150PCT
517 .pled_boost = APDS9960_PLED_BOOST_150,
518 #else
519 .pled_boost = APDS9960_PLED_BOOST_100,
520 #endif
521 };
522
523 static struct apds9960_data apds9960_data;
524
525 PM_DEVICE_DT_INST_DEFINE(0, apds9960_pm_action);
526
527 SENSOR_DEVICE_DT_INST_DEFINE(0, apds9960_init,
528 PM_DEVICE_DT_INST_GET(0), &apds9960_data, &apds9960_config,
529 POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, &apds9960_driver_api);
530