1 /*
2  * Copyright (c) 2016 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT seeed_grove_light
8 
9 #include <zephyr/drivers/adc.h>
10 #include <zephyr/device.h>
11 #include <zephyr/devicetree.h>
12 #include <math.h>
13 #include <zephyr/drivers/sensor.h>
14 #include <zephyr/kernel.h>
15 #include <zephyr/logging/log.h>
16 
17 LOG_MODULE_REGISTER(grove_light, CONFIG_SENSOR_LOG_LEVEL);
18 
19 /* The effect of gain and reference voltage must cancel. */
20 #ifdef CONFIG_ADC_NRFX_SAADC
21 #define GROVE_GAIN ADC_GAIN_1_4
22 #define GROVE_REF ADC_REF_VDD_1_4
23 #define GROVE_RESOLUTION 12
24 #else
25 #define GROVE_GAIN ADC_GAIN_1
26 #define GROVE_REF ADC_REF_VDD_1
27 #define GROVE_RESOLUTION 12
28 #endif
29 
30 
31 struct gls_data {
32 	const struct device *adc;
33 	struct adc_channel_cfg ch_cfg;
34 	uint16_t raw;
35 };
36 
37 struct gls_config {
38 	const struct device *adc;
39 	uint8_t adc_channel;
40 };
41 
42 static struct adc_sequence_options options = {
43 	.interval_us = 12,
44 	.extra_samplings = 0,
45 };
46 
47 static struct adc_sequence adc_table = {
48 	.options = &options,
49 };
50 
gls_sample_fetch(const struct device * dev,enum sensor_channel chan)51 static int gls_sample_fetch(const struct device *dev,
52 			    enum sensor_channel chan)
53 {
54 	const struct gls_config *cfg = dev->config;
55 
56 	return adc_read(cfg->adc, &adc_table);
57 }
58 
gls_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)59 static int gls_channel_get(const struct device *dev,
60 			   enum sensor_channel chan,
61 			   struct sensor_value *val)
62 {
63 	struct gls_data *drv_data = dev->data;
64 	uint16_t analog_val = drv_data->raw;
65 	double ldr_val, dval;
66 
67 	/*
68 	 * The formula for converting the analog value to lux is taken from
69 	 * the UPM project:
70 	 * https://github.com/intel-iot-devkit/upm/blob/master/src/grove/grove.cxx#L161
71 	 */
72 	ldr_val = (BIT(GROVE_RESOLUTION) - 1.0 - analog_val) * 10.0 / analog_val;
73 	dval = 10000.0 / pow(ldr_val * 15.0, 4.0/3.0);
74 
75 	val->val1 = (int32_t)dval;
76 	val->val2 = ((int32_t)(dval * 1000000)) % 1000000;
77 
78 	return 0;
79 }
80 
81 static const struct sensor_driver_api gls_api = {
82 	.sample_fetch = &gls_sample_fetch,
83 	.channel_get = &gls_channel_get,
84 };
85 
gls_init(const struct device * dev)86 static int gls_init(const struct device *dev)
87 {
88 	struct gls_data *drv_data = dev->data;
89 	const struct gls_config *cfg = dev->config;
90 
91 	if (!device_is_ready(cfg->adc)) {
92 		LOG_ERR("ADC device is not ready.");
93 		return -EINVAL;
94 	}
95 
96 	/*Change following parameters according to board if necessary*/
97 	drv_data->ch_cfg = (struct adc_channel_cfg){
98 		.gain = GROVE_GAIN,
99 		.reference = GROVE_REF,
100 		.acquisition_time = ADC_ACQ_TIME_DEFAULT,
101 		.channel_id = cfg->adc_channel,
102 #ifdef CONFIG_ADC_NRFX_SAADC
103 		.input_positive = SAADC_CH_PSELP_PSELP_AnalogInput0 + cfg->adc_channel,
104 #endif
105 	};
106 	adc_table.buffer = &drv_data->raw;
107 	adc_table.buffer_size = sizeof(drv_data->raw);
108 	adc_table.resolution = GROVE_RESOLUTION;
109 	adc_table.channels = BIT(cfg->adc_channel);
110 
111 	adc_channel_setup(cfg->adc, &drv_data->ch_cfg);
112 
113 	return 0;
114 }
115 
116 #define GLS_DEFINE(inst)							\
117 	static struct gls_data gls_data_##inst;					\
118 										\
119 	static const struct gls_config gls_cfg_##inst = {			\
120 		.adc = DEVICE_DT_GET(DT_INST_IO_CHANNELS_CTLR(inst)),		\
121 		.adc_channel = DT_INST_IO_CHANNELS_INPUT(inst),			\
122 	};									\
123 										\
124 	SENSOR_DEVICE_DT_INST_DEFINE(inst, &gls_init, NULL,			\
125 			      &gls_data_##inst, &gls_cfg_##inst, POST_KERNEL,	\
126 			      CONFIG_SENSOR_INIT_PRIORITY, &gls_api);		\
127 
128 DT_INST_FOREACH_STATUS_OKAY(GLS_DEFINE)
129