1 /*
2  * Copyright (c) 2023 Google LLC
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/drivers/adc.h>
8 #include <zephyr/drivers/sensor.h>
9 #include <zephyr/pm/device.h>
10 #include <zephyr/pm/device_runtime.h>
11 #include <zephyr/logging/log.h>
12 #include "ntc_thermistor.h"
13 
14 LOG_MODULE_REGISTER(NTC_THERMISTOR, CONFIG_SENSOR_LOG_LEVEL);
15 
16 struct ntc_thermistor_data {
17 	struct k_mutex mutex;
18 	int32_t raw;
19 	int32_t sample_val;
20 	int32_t sample_val_max;
21 };
22 
23 struct ntc_thermistor_config {
24 	const struct adc_dt_spec adc_channel;
25 	const struct ntc_config ntc_cfg;
26 };
27 
ntc_thermistor_sample_fetch(const struct device * dev,enum sensor_channel chan)28 static int ntc_thermistor_sample_fetch(const struct device *dev, enum sensor_channel chan)
29 {
30 	struct ntc_thermistor_data *data = dev->data;
31 	const struct ntc_thermistor_config *cfg = dev->config;
32 	enum pm_device_state pm_state;
33 	int res;
34 	struct adc_sequence sequence = {
35 		.options = NULL,
36 		.buffer = &data->raw,
37 		.buffer_size = sizeof(data->raw),
38 		.calibrate = false,
39 	};
40 
41 	(void)pm_device_state_get(dev, &pm_state);
42 	if (pm_state != PM_DEVICE_STATE_ACTIVE) {
43 		return -EIO;
44 	}
45 
46 	k_mutex_lock(&data->mutex, K_FOREVER);
47 
48 	adc_sequence_init_dt(&cfg->adc_channel, &sequence);
49 	res = adc_read(cfg->adc_channel.dev, &sequence);
50 	if (!res) {
51 		if (cfg->ntc_cfg.pullup_mv) {
52 			int32_t val_mv = data->raw;
53 
54 			res = adc_raw_to_millivolts_dt(&cfg->adc_channel, &val_mv);
55 			data->sample_val = val_mv;
56 			data->sample_val_max = cfg->ntc_cfg.pullup_mv;
57 		} else {
58 			data->sample_val = data->raw;
59 			data->sample_val_max = BIT(cfg->adc_channel.resolution) - 1;
60 		}
61 	}
62 
63 	k_mutex_unlock(&data->mutex);
64 
65 	return res;
66 }
67 
ntc_thermistor_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)68 static int ntc_thermistor_channel_get(const struct device *dev, enum sensor_channel chan,
69 				      struct sensor_value *val)
70 {
71 	struct ntc_thermistor_data *data = dev->data;
72 	const struct ntc_thermistor_config *cfg = dev->config;
73 	uint32_t ohm;
74 	int32_t temp;
75 
76 	switch (chan) {
77 	case SENSOR_CHAN_AMBIENT_TEMP:
78 		ohm = ntc_get_ohm_of_thermistor(&cfg->ntc_cfg, data->sample_val,
79 						data->sample_val_max);
80 		temp = ntc_get_temp_mc(&cfg->ntc_cfg.type, ohm);
81 		val->val1 = temp / 1000;
82 		val->val2 = (temp % 1000) * 1000;
83 		break;
84 	default:
85 		return -ENOTSUP;
86 	}
87 	return 0;
88 }
89 
90 static DEVICE_API(sensor, ntc_thermistor_driver_api) = {
91 	.sample_fetch = ntc_thermistor_sample_fetch,
92 	.channel_get = ntc_thermistor_channel_get,
93 };
94 
ntc_thermistor_init(const struct device * dev)95 static int ntc_thermistor_init(const struct device *dev)
96 {
97 	const struct ntc_thermistor_config *cfg = dev->config;
98 	int err;
99 
100 	if (!adc_is_ready_dt(&cfg->adc_channel)) {
101 		LOG_ERR("ADC controller device is not ready\n");
102 		return -ENODEV;
103 	}
104 
105 	err = adc_channel_setup_dt(&cfg->adc_channel);
106 	if (err < 0) {
107 		LOG_ERR("Could not setup channel err(%d)\n", err);
108 		return err;
109 	}
110 
111 #ifdef CONFIG_PM_DEVICE_RUNTIME
112 	pm_device_init_suspended(dev);
113 
114 	err = pm_device_runtime_enable(dev);
115 	if (err) {
116 		LOG_ERR("Failed to enable runtime power management");
117 		return err;
118 	}
119 #endif
120 
121 	return 0;
122 }
123 
124 #ifdef CONFIG_PM_DEVICE
ntc_thermistor_pm_action(const struct device * dev,enum pm_device_action action)125 static int ntc_thermistor_pm_action(const struct device *dev, enum pm_device_action action)
126 {
127 	switch (action) {
128 	case PM_DEVICE_ACTION_TURN_ON:
129 	case PM_DEVICE_ACTION_RESUME:
130 	case PM_DEVICE_ACTION_TURN_OFF:
131 	case PM_DEVICE_ACTION_SUSPEND:
132 		return 0;
133 	default:
134 		return -ENOTSUP;
135 	}
136 }
137 #endif
138 
139 #define NTC_THERMISTOR_DEFINE0(inst, id, _comp, _n_comp)                                           \
140 	static struct ntc_thermistor_data ntc_thermistor_driver_##id##inst;                        \
141                                                                                                    \
142 	static const struct ntc_thermistor_config ntc_thermistor_cfg_##id##inst = {                \
143 		.adc_channel = ADC_DT_SPEC_INST_GET(inst),                                         \
144 		.ntc_cfg =                                                                         \
145 			{                                                                          \
146 				.pullup_mv = DT_INST_PROP_OR(inst, pullup_uv, 0) / 1000,           \
147 				.pullup_ohm = DT_INST_PROP(inst, pullup_ohm),                      \
148 				.pulldown_ohm = DT_INST_PROP(inst, pulldown_ohm),                  \
149 				.connected_positive = DT_INST_PROP(inst, connected_positive),      \
150 				.type = {                                                          \
151 					.comp = _comp,                                             \
152 					.n_comp = _n_comp,                                         \
153 				},                                                                 \
154 			},                                                                         \
155 	};                                                                                         \
156                                                                                                    \
157 	PM_DEVICE_DT_INST_DEFINE(inst, ntc_thermistor_pm_action);                                  \
158                                                                                                    \
159 	SENSOR_DEVICE_DT_INST_DEFINE(                                                              \
160 		inst, ntc_thermistor_init, PM_DEVICE_DT_INST_GET(inst),                            \
161 		&ntc_thermistor_driver_##id##inst, &ntc_thermistor_cfg_##id##inst, POST_KERNEL,    \
162 		CONFIG_SENSOR_INIT_PRIORITY, &ntc_thermistor_driver_api);
163 
164 #define NTC_THERMISTOR_DEFINE(inst, id, comp) \
165 	NTC_THERMISTOR_DEFINE0(inst, id, comp, ARRAY_SIZE(comp))
166 
167 /* ntc-thermistor-generic */
168 #define DT_DRV_COMPAT ntc_thermistor_generic
169 
170 #define NTC_THERMISTOR_GENERIC_DEFINE(inst)                                                        \
171 	static const uint32_t comp_##inst[] = DT_INST_PROP(inst, zephyr_compensation_table);       \
172 	NTC_THERMISTOR_DEFINE0(inst, DT_DRV_COMPAT, (struct ntc_compensation *)comp_##inst,        \
173 		ARRAY_SIZE(comp_##inst) / 2)
174 
175 DT_INST_FOREACH_STATUS_OKAY(NTC_THERMISTOR_GENERIC_DEFINE)
176 
177 /* epcos,b57861s0103a039 */
178 #undef DT_DRV_COMPAT
179 #define DT_DRV_COMPAT epcos_b57861s0103a039
180 
181 static __unused const struct ntc_compensation comp_epcos_b57861s0103a039[] = {
182 	{ -25, 146676 },
183 	{ -15, 78875 },
184 	{ -5, 44424 },
185 	{ 5, 26075 },
186 	{ 15, 15881 },
187 	{ 25, 10000 },
188 	{ 35, 6488 },
189 	{ 45, 4326 },
190 	{ 55, 2956 },
191 	{ 65, 2066 },
192 	{ 75, 1474 },
193 	{ 85, 1072 },
194 	{ 95, 793 },
195 	{ 105, 596 },
196 	{ 115, 454 },
197 	{ 125, 351 },
198 };
199 
200 DT_INST_FOREACH_STATUS_OKAY_VARGS(NTC_THERMISTOR_DEFINE, DT_DRV_COMPAT,
201 				  comp_epcos_b57861s0103a039)
202 
203 /* murata,ncp15wb473 */
204 #undef DT_DRV_COMPAT
205 #define DT_DRV_COMPAT murata_ncp15wb473
206 
207 static __unused const struct ntc_compensation comp_murata_ncp15wb473[] = {
208 	{ -25, 655802 },
209 	{ -15, 360850 },
210 	{ -5,  206463 },
211 	{ 5,   122259 },
212 	{ 15,  74730 },
213 	{ 25,  47000 },
214 	{ 35,  30334 },
215 	{ 45,  20048 },
216 	{ 55,  13539 },
217 	{ 65,  9328 },
218 	{ 75,  6544 },
219 	{ 85,  4674 },
220 	{ 95,  3388 },
221 	{ 105, 2494 },
222 	{ 115, 1860 },
223 	{ 125, 1406 },
224 };
225 
226 DT_INST_FOREACH_STATUS_OKAY_VARGS(NTC_THERMISTOR_DEFINE, DT_DRV_COMPAT,
227 				  comp_murata_ncp15wb473)
228 
229 /* tdk,ntcg163jf103ft1 */
230 #undef DT_DRV_COMPAT
231 #define DT_DRV_COMPAT tdk_ntcg163jf103ft1
232 
233 static __unused const struct ntc_compensation comp_tdk_ntcg163jf103ft1[] = {
234 	{ -25, 86560 },
235 	{ -15, 53460 },
236 	{ -5, 33930 },
237 	{ 5, 22070 },
238 	{ 15, 14700 },
239 	{ 25, 10000 },
240 	{ 35, 6942 },
241 	{ 45, 4911 },
242 	{ 55, 3536 },
243 	{ 65, 2588 },
244 	{ 75, 1924 },
245 	{ 85, 1451 },
246 	{ 95, 1110 },
247 	{ 105, 860 },
248 	{ 115, 674 },
249 	{ 125, 534 },
250 };
251 
252 DT_INST_FOREACH_STATUS_OKAY_VARGS(NTC_THERMISTOR_DEFINE, DT_DRV_COMPAT,
253 				  comp_tdk_ntcg163jf103ft1)
254 
255 /* murata,ncp15xh103 */
256 #undef DT_DRV_COMPAT
257 #define DT_DRV_COMPAT murata_ncp15xh103
258 
259 static __unused const struct ntc_compensation comp_murata_ncp15xh103[] = {
260 	{ -25, 87558 },
261 	{ -15, 53649 },
262 	{  -5, 33892 },
263 	{   5, 22021 },
264 	{  15, 14673 },
265 	{  25, 10000 },
266 	{  35,  6947 },
267 	{  45,  4916 },
268 	{  55,  3535 },
269 	{  64,  2586 },
270 	{  75,  1924 },
271 	{  85,  1452 },
272 	{  95,  1109 },
273 	{ 105,   858 },
274 	{ 115,   671 },
275 	{ 125,   531 },
276 };
277 
278 DT_INST_FOREACH_STATUS_OKAY_VARGS(NTC_THERMISTOR_DEFINE, DT_DRV_COMPAT,
279 				  comp_murata_ncp15xh103)
280