1 /*
2  * Copyright (c) 2016 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT seeed_grove_temperature
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_temp, 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 struct gts_data {
31 	struct adc_channel_cfg ch_cfg;
32 	uint16_t raw;
33 };
34 
35 struct gts_config {
36 	const struct device *adc;
37 	int16_t b_const;
38 	uint8_t adc_channel;
39 };
40 
41 static struct adc_sequence_options options = {
42 	.extra_samplings = 0,
43 	.interval_us = 15,
44 };
45 
46 static struct adc_sequence adc_table = {
47 	.options = &options,
48 };
49 
gts_sample_fetch(const struct device * dev,enum sensor_channel chan)50 static int gts_sample_fetch(const struct device *dev,
51 			    enum sensor_channel chan)
52 {
53 	const struct gts_config *cfg = dev->config;
54 
55 	return adc_read(cfg->adc, &adc_table);
56 }
57 
gts_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)58 static int gts_channel_get(const struct device *dev,
59 			   enum sensor_channel chan,
60 			   struct sensor_value *val)
61 {
62 	struct gts_data *drv_data = dev->data;
63 	const struct gts_config *cfg = dev->config;
64 	double dval;
65 
66 	/*
67 	 * The formula for converting the analog value to degrees Celsius
68 	 * is taken from the sensor reference page:
69 	 *     http://www.seeedstudio.com/wiki/Grove_-_Temperature_Sensor
70 	 */
71 	dval = (1 / (log((BIT(GROVE_RESOLUTION) - 1.0)
72 			/ drv_data->raw
73 			- 1.0)
74 		     / cfg->b_const
75 		     + (1 / 298.15)))
76 		- 273.15;
77 	val->val1 = (int32_t)dval;
78 	val->val2 = ((int32_t)(dval * 1000000)) % 1000000;
79 
80 	return 0;
81 }
82 
83 static DEVICE_API(sensor, gts_api) = {
84 	.sample_fetch = &gts_sample_fetch,
85 	.channel_get = &gts_channel_get,
86 };
87 
gts_init(const struct device * dev)88 static int gts_init(const struct device *dev)
89 {
90 	struct gts_data *drv_data = dev->data;
91 	const struct gts_config *cfg = dev->config;
92 
93 	if (!device_is_ready(cfg->adc)) {
94 		LOG_ERR("ADC device is not ready.");
95 		return -EINVAL;
96 	}
97 
98 	/*Change following parameters according to board if necessary*/
99 	drv_data->ch_cfg = (struct adc_channel_cfg){
100 		.gain = GROVE_GAIN,
101 		.reference = GROVE_REF,
102 		.acquisition_time = ADC_ACQ_TIME_DEFAULT,
103 		.channel_id = cfg->adc_channel,
104 #ifdef CONFIG_ADC_NRFX_SAADC
105 		.input_positive = SAADC_CH_PSELP_PSELP_AnalogInput0 + cfg->adc_channel,
106 #endif
107 	};
108 	adc_table.buffer = &drv_data->raw;
109 	adc_table.buffer_size = sizeof(drv_data->raw);
110 	adc_table.resolution = GROVE_RESOLUTION;
111 	adc_table.channels = BIT(cfg->adc_channel);
112 
113 	adc_channel_setup(cfg->adc, &drv_data->ch_cfg);
114 
115 	return 0;
116 }
117 
118 #define GTS_DEFINE(inst)							\
119 	static struct gts_data gts_data_##inst;					\
120 										\
121 	static const struct gts_config gts_cfg_##inst = {			\
122 		.adc = DEVICE_DT_GET(DT_INST_IO_CHANNELS_CTLR(inst)),		\
123 		.b_const = (IS_ENABLED(DT_INST_PROP(inst, v1p0))		\
124 			? 3975							\
125 			: 4250),						\
126 		.adc_channel = DT_INST_IO_CHANNELS_INPUT(inst),			\
127 	};									\
128 										\
129 	SENSOR_DEVICE_DT_INST_DEFINE(inst, &gts_init, NULL,			\
130 			      &gts_data_##inst, &gts_cfg_##inst, POST_KERNEL,	\
131 			      CONFIG_SENSOR_INIT_PRIORITY, &gts_api);		\
132 
133 DT_INST_FOREACH_STATUS_OKAY(GTS_DEFINE)
134