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 = >s_sample_fetch,
85 .channel_get = >s_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, >s_init, NULL, \
130 >s_data_##inst, >s_cfg_##inst, POST_KERNEL, \
131 CONFIG_SENSOR_INIT_PRIORITY, >s_api); \
132
133 DT_INST_FOREACH_STATUS_OKAY(GTS_DEFINE)
134