1 /*
2  * Copyright (c) 2025 Andreas Klinger
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT vishay_veml6031
8 
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/drivers/sensor.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/logging/log.h>
14 #include <zephyr/pm/device.h>
15 #include <zephyr/sys/byteorder.h>
16 
17 #include <zephyr/drivers/sensor/veml6031.h>
18 
19 LOG_MODULE_REGISTER(VEML6031, CONFIG_SENSOR_LOG_LEVEL);
20 
21 /*
22  * ID code of device
23  */
24 #define VEML6031_DEFAULT_ID 0x01
25 
26 /*
27  * Bit mask to check for data ready in single measurement.
28  */
29 #define VEML6031_ALS_AF_DATA_READY BIT(3)
30 
31 /*
32  * Maximum value of ALS data which also means that the sensor is in saturation
33  * and that the measured value might be wrong.
34  * In such a case the user program should reduce one or more of the following
35  * attributes to get a relyable value:
36  *   gain
37  *   integration time
38  *   effective photodiode size
39  *
40  */
41 #define VEML6031_ALS_DATA_OVERFLOW 0xFFFF
42 
43 /*
44  * 16-bit command register addresses
45  */
46 #define VEML6031_CMDCODE_ALS_CONF_0 0x00
47 #define VEML6031_CMDCODE_ALS_CONF_1 0x01
48 #define VEML6031_CMDCODE_ALS_WH_L   0x04
49 #define VEML6031_CMDCODE_ALS_WH_H   0x05
50 #define VEML6031_CMDCODE_ALS_WL_L   0x06
51 #define VEML6031_CMDCODE_ALS_WL_H   0x07
52 #define VEML6031_CMDCODE_ALS_DATA_L 0x10
53 #define VEML6031_CMDCODE_ALS_DATA_H 0x11
54 #define VEML6031_CMDCODE_IR_DATA_L  0x12
55 #define VEML6031_CMDCODE_IR_DATA_H  0x13
56 #define VEML6031_CMDCODE_ID_L       0x14
57 #define VEML6031_CMDCODE_ID_H       0x15
58 #define VEML6031_CMDCODE_ALS_INT    0x17
59 
60 /*
61  * ALS integration time struct.
62  */
63 struct veml6031_it_data {
64 	enum veml6031_it num;
65 	uint8_t val;
66 	int us;
67 };
68 
69 /*
70  * ALS integration time setting values.
71  *
72  * The enumerators of <tt>enum veml6031_it</tt> provide
73  * indices into this array to get the related value for the
74  * ALS_IT configuration bits.
75  */
76 static const struct veml6031_it_data veml6031_it_values[] = {
77 	{VEML6031_IT_3_125, 0x00, 3125}, /*   3.125 - 0b0000 */
78 	{VEML6031_IT_6_25, 0x01, 6250},  /*   6.25  - 0b0001 */
79 	{VEML6031_IT_12_5, 0x02, 12500}, /*  12.5   - 0b0010 */
80 	{VEML6031_IT_25, 0x03, 25000},   /*  25     - 0b0011 */
81 	{VEML6031_IT_50, 0x04, 50000},   /*  50     - 0b0100 */
82 	{VEML6031_IT_100, 0x05, 100000}, /* 100     - 0b0101 */
83 	{VEML6031_IT_200, 0x06, 200000}, /* 200     - 0b0110 */
84 	{VEML6031_IT_400, 0x07, 400000}, /* 400     - 0b0111 */
85 };
86 
87 /*
88  * Resolution matrix for values to convert between data provided
89  * by the sensor ("counts") and lux.
90  *
91  * These values depend on the current size, gain and integration time settings.
92  * The enumerators of <tt>enum veml6031_div4</tt>, <tt>enum veml6031_gain</tt>
93  * and <tt>enum veml6031_als_it</tt> are used for indices into this matrix.
94  */
95 static const float
96 	veml6031_resolution[VEML6031_DIV4_COUNT][VEML6031_GAIN_COUNT][VEML6031_IT_COUNT] = {
97 		/*3.125ms   6.25ms   12.5ms     25ms     50ms    100ms    200ms     400ms IT */
98 		/* size 4/4 */
99 		{
100 			{0.8704f, 0.4352f, 0.2176f, 0.1088f, 0.0544f, 0.0272f, 0.0136f,
101 			 0.0068f}, /* Gain 1    */
102 			{0.4352f, 0.2176f, 0.1088f, 0.0544f, 0.0272f, 0.0136f, 0.0068f,
103 			 0.0034f}, /* Gain 2    */
104 			{1.3188f, 0.6504f, 0.3297f, 0.1648f, 0.0824f, 0.0412f, 0.0206f,
105 			 0.0103f}, /* Gain 0.66 */
106 			{1.7408f, 0.8704f, 0.4352f, 0.2176f, 0.1088f, 0.0544f, 0.0272f,
107 			 0.0136f}, /* Gain 0.5  */
108 		},
109 		{
110 			/* size 1/4 */
111 			{3.4816f, 1.7408f, 0.8704f, 0.4352f, 0.2176f, 0.1088f, 0.0544f,
112 			 0.0272f}, /* Gain 1    */
113 			{1.7408f, 0.8704f, 0.4352f, 0.2176f, 0.1088f, 0.0544f, 0.0272f,
114 			 0.0136f}, /* Gain 2    */
115 			{5.2752f, 2.6376f, 1.3188f, 0.6594f, 0.3297f, 0.1648f, 0.0824f,
116 			 0.0412f}, /* Gain 0.66 */
117 			{6.9632f, 3.4816f, 1.7408f, 0.8704f, 0.4352f, 0.2176f, 0.1088f,
118 			 0.0544f}, /* Gain 0.5  */
119 		},
120 };
121 
122 struct veml6031_config {
123 	struct i2c_dt_spec bus;
124 };
125 
126 struct veml6031_data {
127 	uint8_t sd;              /* Band gap and LDO shutdown */
128 	uint8_t int_en;          /* ALS interrupt enable */
129 	uint8_t trig;            /* ALS active force trigger */
130 	uint8_t af;              /* Active force mode */
131 	uint8_t ir_sd;           /* ALS and IR channel shutdown */
132 	uint8_t cal;             /* Power on ready */
133 	enum veml6031_div4 div4; /* effective photodiode size */
134 	enum veml6031_gain gain; /* gain selection */
135 	enum veml6031_it itim;   /* ALS integration time */
136 	enum veml6031_pers pers; /* ALS persistens protect */
137 	uint16_t thresh_high;
138 	uint16_t thresh_low;
139 	uint16_t als_data;
140 	uint32_t als_lux;
141 	uint16_t ir_data;
142 	uint32_t int_flags;
143 };
144 
veml6031_sleep_by_integration_time(const struct veml6031_data * data)145 static void veml6031_sleep_by_integration_time(const struct veml6031_data *data)
146 {
147 	k_sleep(K_USEC(veml6031_it_values[data->itim].us));
148 }
149 
veml6031_check_gain(const struct sensor_value * val)150 static int veml6031_check_gain(const struct sensor_value *val)
151 {
152 	return val->val1 >= VEML6031_GAIN_1 && val->val1 <= VEML6031_GAIN_0_5;
153 }
154 
veml6031_check_it(const struct sensor_value * val)155 static int veml6031_check_it(const struct sensor_value *val)
156 {
157 	return val->val1 >= VEML6031_IT_3_125 && val->val1 <= VEML6031_IT_400;
158 }
159 
veml6031_check_div4(const struct sensor_value * val)160 static int veml6031_check_div4(const struct sensor_value *val)
161 {
162 	return val->val1 >= VEML6031_SIZE_4_4 && val->val1 <= VEML6031_SIZE_1_4;
163 }
164 
veml6031_check_pers(const struct sensor_value * val)165 static int veml6031_check_pers(const struct sensor_value *val)
166 {
167 	return val->val1 >= VEML6031_PERS_1 && val->val1 <= VEML6031_PERS_8;
168 }
169 
veml6031_read(const struct device * dev,uint8_t cmd,uint8_t * data)170 static int veml6031_read(const struct device *dev, uint8_t cmd, uint8_t *data)
171 {
172 	const struct veml6031_config *conf = dev->config;
173 
174 	uint8_t recv_buf;
175 	int ret;
176 
177 	ret = i2c_reg_read_byte_dt(&conf->bus, cmd, &recv_buf);
178 	if (ret < 0) {
179 		return ret;
180 	}
181 
182 	*data = recv_buf;
183 
184 	return 0;
185 }
186 
veml6031_read16(const struct device * dev,uint8_t cmd,uint8_t * data)187 static int veml6031_read16(const struct device *dev, uint8_t cmd, uint8_t *data)
188 {
189 	const struct veml6031_config *conf = dev->config;
190 	int ret;
191 
192 	ret = i2c_burst_read_dt(&conf->bus, cmd, data, 2);
193 	if (ret < 0) {
194 		return ret;
195 	}
196 
197 	return 0;
198 }
199 
veml6031_write16(const struct device * dev,uint8_t cmd,uint8_t * data)200 static int veml6031_write16(const struct device *dev, uint8_t cmd, uint8_t *data)
201 {
202 	const struct veml6031_config *conf = dev->config;
203 
204 	return i2c_burst_write_dt(&conf->bus, cmd, data, 2);
205 }
206 
veml6031_write_conf(const struct device * dev)207 static int veml6031_write_conf(const struct device *dev)
208 {
209 	int ret;
210 	struct veml6031_data *data = dev->data;
211 	uint8_t conf[2] = {0, 0};
212 
213 	/* Bits 7 -> ALS and IR channel shutdown */
214 	conf[1] |= data->ir_sd << 7;
215 	/* Bits 6 -> Effective photodiode size */
216 	conf[1] |= data->div4 << 6;
217 	/* Bit 5 -> reserved */
218 	/* Bits 4:3 -> Gain selection */
219 	conf[1] |= data->gain << 3;
220 	/* Bits 2:1 -> ALS persistence protect number */
221 	conf[1] |= data->pers << 1;
222 	/* Bit 0 -> Power on ready */
223 	if (data->cal) {
224 		conf[1] |= BIT(0);
225 	}
226 	/* Bit 7 -> reserved, have to be 0 */
227 	/* Bits 6:4 -> integration time (ALS_IT) */
228 	conf[0] |= data->itim << 4;
229 	/* Bit 3 -> Active force mode enable */
230 	if (data->af) {
231 		conf[0] |= BIT(3);
232 	}
233 	/* Bit 2 -> ALS active force trigger */
234 	if (data->trig) {
235 		conf[0] |= BIT(2);
236 	}
237 	/* Bit 1 -> ALS interrupt enable */
238 	if (data->int_en) {
239 		conf[0] |= BIT(1);
240 	}
241 	/* Bit 0 -> shut down setting (SD) */
242 	if (data->sd) {
243 		conf[0] |= BIT(0);
244 	}
245 
246 	ret = veml6031_write16(dev, VEML6031_CMDCODE_ALS_CONF_0, conf);
247 	if (ret) {
248 		LOG_ERR("Error while writing conf[0] ret: %d", ret);
249 		return ret;
250 	}
251 
252 	return 0;
253 }
254 
veml6031_write_thresh_high(const struct device * dev)255 static int veml6031_write_thresh_high(const struct device *dev)
256 {
257 	int ret;
258 	const struct veml6031_data *data = dev->data;
259 	uint8_t val[2];
260 
261 	val[0] = data->thresh_high & 0xFF;
262 	val[1] = data->thresh_high >> 8;
263 
264 	LOG_DBG("Writing high threshold counts: %d", data->thresh_high);
265 	ret = veml6031_write16(dev, VEML6031_CMDCODE_ALS_WH_L, val);
266 	if (ret) {
267 		return ret;
268 	}
269 
270 	return 0;
271 }
272 
veml6031_write_thresh_low(const struct device * dev)273 static int veml6031_write_thresh_low(const struct device *dev)
274 {
275 	int ret;
276 	const struct veml6031_data *data = dev->data;
277 	uint8_t val[2];
278 
279 	val[0] = data->thresh_low & 0xFF;
280 	val[1] = data->thresh_low >> 8;
281 
282 	LOG_DBG("Writing low threshold counts: %d", data->thresh_low);
283 	ret = veml6031_write16(dev, VEML6031_CMDCODE_ALS_WL_L, val);
284 	if (ret) {
285 		return ret;
286 	}
287 
288 	return 0;
289 }
290 
veml6031_fetch(const struct device * dev)291 static int veml6031_fetch(const struct device *dev)
292 {
293 	struct veml6031_data *data = dev->data;
294 	int ret;
295 
296 	ret = veml6031_read16(dev, VEML6031_CMDCODE_ALS_DATA_L, (uint8_t *)&data->als_data);
297 	if (ret < 0) {
298 		return ret;
299 	}
300 	data->als_data = sys_le16_to_cpu(data->als_data);
301 
302 	ret = veml6031_read16(dev, VEML6031_CMDCODE_IR_DATA_L, (uint8_t *)&data->ir_data);
303 	if (ret < 0) {
304 		return ret;
305 	}
306 	data->ir_data = sys_le16_to_cpu(data->ir_data);
307 
308 	data->als_lux = data->als_data * veml6031_resolution[data->div4][data->gain][data->itim];
309 
310 	LOG_DBG("Read ALS measurement: counts=%d, lux=%d ir=%d", data->als_data, data->als_lux,
311 		data->ir_data);
312 
313 	if (data->als_data == VEML6031_ALS_DATA_OVERFLOW) {
314 		return -E2BIG;
315 	}
316 
317 	return 0;
318 }
319 
veml6031_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)320 static int veml6031_attr_set(const struct device *dev, enum sensor_channel chan,
321 			     enum sensor_attribute attr, const struct sensor_value *val)
322 {
323 	struct veml6031_data *data = dev->data;
324 
325 	if (chan != SENSOR_CHAN_LIGHT) {
326 		return -ENOTSUP;
327 	}
328 
329 	/* SENSOR_ATTR_.*_THRESH are not in enum sensor_attribute_veml6031 */
330 	switch ((int)attr) {
331 	case SENSOR_ATTR_VEML6031_IT:
332 		if (veml6031_check_it(val)) {
333 			data->itim = (enum veml6031_it)val->val1;
334 		} else {
335 			return -EINVAL;
336 		}
337 		break;
338 	case SENSOR_ATTR_VEML6031_DIV4:
339 		if (veml6031_check_div4(val)) {
340 			data->div4 = (enum veml6031_div4)val->val1;
341 		} else {
342 			return -EINVAL;
343 		}
344 		break;
345 	case SENSOR_ATTR_VEML6031_GAIN:
346 		if (veml6031_check_gain(val)) {
347 			data->gain = (enum veml6031_gain)val->val1;
348 		} else {
349 			return -EINVAL;
350 		}
351 		break;
352 	case SENSOR_ATTR_VEML6031_PERS:
353 		if (veml6031_check_pers(val)) {
354 			data->pers = (enum veml6031_pers)val->val1;
355 		} else {
356 			return -EINVAL;
357 		}
358 		break;
359 	case SENSOR_ATTR_LOWER_THRESH:
360 		data->thresh_low =
361 			val->val1 / veml6031_resolution[data->div4][data->gain][data->itim];
362 		return veml6031_write_thresh_low(dev);
363 	case SENSOR_ATTR_UPPER_THRESH:
364 		data->thresh_high =
365 			val->val1 / veml6031_resolution[data->div4][data->gain][data->itim];
366 		return veml6031_write_thresh_high(dev);
367 	default:
368 		return -ENOTSUP;
369 	}
370 
371 	return 0;
372 }
373 
veml6031_attr_get(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,struct sensor_value * val)374 static int veml6031_attr_get(const struct device *dev, enum sensor_channel chan,
375 			     enum sensor_attribute attr, struct sensor_value *val)
376 {
377 	struct veml6031_data *data = dev->data;
378 
379 	if (chan != SENSOR_CHAN_LIGHT) {
380 		return -ENOTSUP;
381 	}
382 
383 	/* SENSOR_ATTR_.*_THRESH are not in enum sensor_attribute_veml6031 */
384 	switch ((int)attr) {
385 	case SENSOR_ATTR_VEML6031_IT:
386 		val->val1 = data->itim;
387 		break;
388 	case SENSOR_ATTR_VEML6031_DIV4:
389 		val->val1 = data->div4;
390 		break;
391 	case SENSOR_ATTR_VEML6031_GAIN:
392 		val->val1 = data->gain;
393 		break;
394 	case SENSOR_ATTR_VEML6031_PERS:
395 		val->val1 = data->pers;
396 		break;
397 	case SENSOR_ATTR_LOWER_THRESH:
398 		val->val1 = data->thresh_low;
399 		break;
400 	case SENSOR_ATTR_UPPER_THRESH:
401 		val->val1 = data->thresh_high;
402 		break;
403 	default:
404 		return -ENOTSUP;
405 	}
406 
407 	val->val2 = 0;
408 
409 	return 0;
410 }
411 
veml6031_perform_single_measurement(const struct device * dev)412 static int veml6031_perform_single_measurement(const struct device *dev)
413 {
414 	struct veml6031_data *data = dev->data;
415 	int ret;
416 	uint8_t val;
417 	int cnt = 0;
418 
419 	data->ir_sd = 0;
420 	data->cal = 1;
421 	data->af = 1;
422 	data->trig = 1;
423 	data->int_en = 0;
424 	data->sd = 0;
425 
426 	ret = veml6031_write_conf(dev);
427 	if (ret) {
428 		return ret;
429 	}
430 
431 	ret = veml6031_read(dev, VEML6031_CMDCODE_ALS_INT, &val);
432 
433 	veml6031_sleep_by_integration_time(data);
434 
435 	while (1) {
436 		ret = veml6031_read(dev, VEML6031_CMDCODE_ALS_INT, &val);
437 		if (ret) {
438 			return ret;
439 		}
440 
441 		if (val & VEML6031_ALS_AF_DATA_READY) {
442 			break;
443 		}
444 
445 		k_sleep(K_MSEC(1));
446 
447 		cnt++;
448 	}
449 
450 	LOG_DBG("read VEML6031_CMDCODE_ALS_INT: %02X (%d)", val, cnt);
451 
452 	return 0;
453 }
454 
veml6031_sample_fetch(const struct device * dev,enum sensor_channel chan)455 static int veml6031_sample_fetch(const struct device *dev, enum sensor_channel chan)
456 {
457 	int ret;
458 
459 	/* Start sensor for new measurement */
460 	if (chan == SENSOR_CHAN_LIGHT || chan == SENSOR_CHAN_ALL) {
461 		ret = veml6031_perform_single_measurement(dev);
462 		if (ret < 0) {
463 			return ret;
464 		}
465 
466 		return veml6031_fetch(dev);
467 	} else {
468 		return -ENOTSUP;
469 	}
470 
471 	return 0;
472 }
473 
veml6031_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)474 static int veml6031_channel_get(const struct device *dev, enum sensor_channel chan,
475 				struct sensor_value *val)
476 {
477 	struct veml6031_data *data = dev->data;
478 
479 	switch ((int)chan) {
480 	case SENSOR_CHAN_LIGHT:
481 		val->val1 = data->als_lux;
482 		break;
483 	case SENSOR_CHAN_VEML6031_ALS_RAW_COUNTS:
484 		val->val1 = data->als_data;
485 		break;
486 	case SENSOR_CHAN_VEML6031_IR_RAW_COUNTS:
487 		val->val1 = data->ir_data;
488 		break;
489 	default:
490 		return -ENOTSUP;
491 	}
492 
493 	val->val2 = 0;
494 
495 	return 0;
496 }
497 
498 #ifdef CONFIG_PM_DEVICE
499 
veml6031_set_shutdown_flag(const struct device * dev,uint8_t new_val)500 static int veml6031_set_shutdown_flag(const struct device *dev, uint8_t new_val)
501 {
502 	struct veml6031_data *data = dev->data;
503 	uint8_t prev_sd;
504 	uint8_t prev_ir_sd;
505 	int ret;
506 
507 	prev_sd = data->sd;
508 	prev_ir_sd = data->ir_sd;
509 	data->sd = new_val;
510 	data->ir_sd = new_val;
511 
512 	ret = veml6031_write_conf(dev);
513 	if (ret < 0) {
514 		data->ir_sd = prev_ir_sd;
515 		data->sd = prev_sd;
516 	}
517 	return ret;
518 }
519 
veml6031_pm_action(const struct device * dev,enum pm_device_action action)520 static int veml6031_pm_action(const struct device *dev, enum pm_device_action action)
521 {
522 	struct veml6031_data *data = dev->data;
523 
524 	if (!data->sd) {
525 		switch (action) {
526 		case PM_DEVICE_ACTION_SUSPEND:
527 			return veml6031_set_shutdown_flag(dev, 1);
528 
529 		case PM_DEVICE_ACTION_RESUME:
530 			return veml6031_set_shutdown_flag(dev, 0);
531 
532 		default:
533 			return -ENOTSUP;
534 		}
535 	}
536 
537 	return 0;
538 }
539 
540 #endif /* CONFIG_PM_DEVICE */
541 
veml6031_init(const struct device * dev)542 static int veml6031_init(const struct device *dev)
543 {
544 	const struct veml6031_config *conf = dev->config;
545 	int ret;
546 	uint8_t val8;
547 
548 	if (!i2c_is_ready_dt(&conf->bus)) {
549 		LOG_ERR("VEML device not ready");
550 		return -ENODEV;
551 	}
552 
553 	ret = veml6031_read(dev, VEML6031_CMDCODE_ID_L, &val8);
554 	if (ret < 0) {
555 		LOG_ERR("Error while reading ID low. ret: %d", ret);
556 		return ret;
557 	}
558 	if (val8 != VEML6031_DEFAULT_ID) {
559 		LOG_ERR("Device ID wrong: %d", val8);
560 		return -EIO;
561 	}
562 	ret = veml6031_read(dev, VEML6031_CMDCODE_ID_H, &val8);
563 	if (ret < 0) {
564 		LOG_ERR("Error while reading ID high. ret: %d", ret);
565 		return ret;
566 	}
567 	LOG_DBG("veml6031 found package: %02d address: %02X version: %3s", val8 >> 6,
568 		val8 >> 4 & 0x03 ? 0x10 : 0x29, val8 & 0x0F ? "XXX" : "A01");
569 
570 	/* Initialize sensor configuration */
571 	ret = veml6031_write_thresh_low(dev);
572 	if (ret < 0) {
573 		LOG_ERR("Error while writing thresh low. ret: %d", ret);
574 		return ret;
575 	}
576 
577 	ret = veml6031_write_thresh_high(dev);
578 	if (ret < 0) {
579 		LOG_ERR("Error while writing thresh high. ret: %d", ret);
580 		return ret;
581 	}
582 
583 	ret = veml6031_write_conf(dev);
584 	if (ret < 0) {
585 		LOG_ERR("Error while writing conf. ret: %d", ret);
586 		return ret;
587 	}
588 
589 	return 0;
590 }
591 
592 static DEVICE_API(sensor, veml6031_api) = {
593 	.sample_fetch = veml6031_sample_fetch,
594 	.channel_get = veml6031_channel_get,
595 	.attr_set = veml6031_attr_set,
596 	.attr_get = veml6031_attr_get,
597 };
598 
599 #define VEML6031_INIT(n)                                                                           \
600 	static struct veml6031_data veml6031_data_##n = {.trig = 1,                                \
601 							 .af = 1,                                  \
602 							 .div4 = VEML6031_SIZE_4_4,                \
603 							 .gain = VEML6031_GAIN_1,                  \
604 							 .itim = VEML6031_IT_100,                  \
605 							 .pers = VEML6031_PERS_1,                  \
606 							 .thresh_high = 0xFFFF};                   \
607                                                                                                    \
608 	static const struct veml6031_config veml6031_config_##n = {                                \
609 		.bus = I2C_DT_SPEC_INST_GET(n)};                                                   \
610                                                                                                    \
611 	PM_DEVICE_DT_INST_DEFINE(n, veml6031_pm_action);                                           \
612                                                                                                    \
613 	SENSOR_DEVICE_DT_INST_DEFINE(n, veml6031_init, PM_DEVICE_DT_INST_GET(n),                   \
614 				     &veml6031_data_##n, &veml6031_config_##n, POST_KERNEL,        \
615 				     CONFIG_SENSOR_INIT_PRIORITY, &veml6031_api);
616 
617 DT_INST_FOREACH_STATUS_OKAY(VEML6031_INIT)
618