1 /* ST Microelectronics STTS22H temperature sensor
2  *
3  * Copyright (c) 2024 STMicroelectronics
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  *
7  * Datasheet:
8  * https://www.st.com/resource/en/datasheet/stts22h.pdf
9  */
10 
11 #define DT_DRV_COMPAT st_stts22h
12 
13 #include <zephyr/drivers/sensor.h>
14 #include <zephyr/kernel.h>
15 #include <zephyr/device.h>
16 #include <zephyr/init.h>
17 #include <zephyr/sys/byteorder.h>
18 #include <zephyr/sys/__assert.h>
19 #include <zephyr/logging/log.h>
20 
21 #include "stts22h.h"
22 
23 LOG_MODULE_REGISTER(STTS22H, CONFIG_SENSOR_LOG_LEVEL);
24 
stts22h_set_odr_raw(const struct device * dev,stts22h_odr_temp_t odr)25 static inline int stts22h_set_odr_raw(const struct device *dev, stts22h_odr_temp_t odr)
26 {
27 	const struct stts22h_config *cfg = dev->config;
28 	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
29 
30 	return stts22h_temp_data_rate_set(ctx, odr);
31 }
32 
stts22h_sample_fetch(const struct device * dev,enum sensor_channel chan)33 static int stts22h_sample_fetch(const struct device *dev, enum sensor_channel chan)
34 {
35 	struct stts22h_data *data = dev->data;
36 	const struct stts22h_config *cfg = dev->config;
37 	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
38 	int16_t raw_temp;
39 
40 	if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP) {
41 		LOG_ERR("Invalid channel: %d", chan);
42 		return -ENOTSUP;
43 	}
44 
45 	if (stts22h_temperature_raw_get(ctx, &raw_temp) < 0) {
46 		LOG_ERR("Failed to read sample");
47 		return -EIO;
48 	}
49 
50 	data->sample_temp = raw_temp;
51 
52 	return 0;
53 }
54 
stts22h_temp_convert(struct sensor_value * val,int16_t raw_val)55 static inline void stts22h_temp_convert(struct sensor_value *val, int16_t raw_val)
56 {
57 	val->val1 = raw_val / 100;
58 	val->val2 = ((int32_t)raw_val % 100) * 10000;
59 }
60 
stts22h_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)61 static int stts22h_channel_get(const struct device *dev,
62 			       enum sensor_channel chan,
63 			       struct sensor_value *val)
64 {
65 	struct stts22h_data *data = dev->data;
66 
67 	if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
68 		LOG_ERR("Invalid channel: %d", chan);
69 		return -ENOTSUP;
70 	}
71 
72 	stts22h_temp_convert(val, data->sample_temp);
73 
74 	return 0;
75 }
76 
77 static const uint8_t stts22h_map[6] = {0, 1, 25, 50, 100, 200};
78 
stts22h_odr_set(const struct device * dev,const struct sensor_value * val)79 static int stts22h_odr_set(const struct device *dev,
80 			   const struct sensor_value *val)
81 {
82 	int odr;
83 
84 	for (odr = 0; odr < ARRAY_SIZE(stts22h_map); odr++) {
85 		if (val->val1 <= stts22h_map[odr]) {
86 			break;
87 		}
88 	}
89 
90 	switch (odr) {
91 	case 0:
92 		return stts22h_set_odr_raw(dev, STTS22H_POWER_DOWN);
93 	case 1:
94 		return stts22h_set_odr_raw(dev, STTS22H_1Hz);
95 	case 2:
96 		return stts22h_set_odr_raw(dev, STTS22H_25Hz);
97 	case 3:
98 		return stts22h_set_odr_raw(dev, STTS22H_50Hz);
99 	case 4:
100 		return stts22h_set_odr_raw(dev, STTS22H_100Hz);
101 	case 5:
102 		return stts22h_set_odr_raw(dev, STTS22H_200Hz);
103 	default:
104 		LOG_ERR("bad frequency: %d (odr = %d)", val->val1, odr);
105 		return -EINVAL;
106 	}
107 }
108 
stts22h_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)109 static int stts22h_attr_set(const struct device *dev,
110 			    enum sensor_channel chan,
111 			    enum sensor_attribute attr,
112 			    const struct sensor_value *val)
113 {
114 	if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP) {
115 		LOG_ERR("Invalid channel: %d", chan);
116 		return -ENOTSUP;
117 	}
118 
119 	switch (attr) {
120 	case SENSOR_ATTR_SAMPLING_FREQUENCY:
121 		return stts22h_odr_set(dev, val);
122 	default:
123 		LOG_ERR("Attribute %d not supported.", attr);
124 		return -ENOTSUP;
125 	}
126 
127 	return 0;
128 }
129 
130 static DEVICE_API(sensor, stts22h_api_funcs) = {
131 	.attr_set = stts22h_attr_set,
132 	.sample_fetch = stts22h_sample_fetch,
133 	.channel_get = stts22h_channel_get,
134 #if CONFIG_STTS22H_TRIGGER
135 	.trigger_set = stts22h_trigger_set,
136 #endif
137 };
138 
stts22h_init_chip(const struct device * dev)139 static int stts22h_init_chip(const struct device *dev)
140 {
141 	const struct stts22h_config *cfg = dev->config;
142 	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
143 	uint8_t chip_id, odr;
144 
145 	if (stts22h_dev_id_get(ctx, &chip_id) < 0) {
146 		LOG_ERR("Failed reading chip id");
147 		return -EIO;
148 	}
149 
150 	LOG_INF("chip id 0x%02x", chip_id);
151 
152 	if (stts22h_auto_increment_set(ctx, 1) < 0) {
153 		LOG_ERR("Failed to set autoincr");
154 		return -EIO;
155 	}
156 
157 	/* set odr from DT */
158 	odr = cfg->odr;
159 	LOG_INF("sensor odr is %d", odr);
160 	if (stts22h_set_odr_raw(dev, odr) < 0) {
161 		LOG_ERR("Failed to set sampling rate");
162 		return -EIO;
163 	}
164 
165 	return 0;
166 }
167 
stts22h_init(const struct device * dev)168 static int stts22h_init(const struct device *dev)
169 {
170 	struct stts22h_data *data = dev->data;
171 #ifdef CONFIG_STTS22H_TRIGGER
172 	const struct stts22h_config *cfg = dev->config;
173 #endif
174 
175 	LOG_INF("Initialize device %s", dev->name);
176 	data->dev = dev;
177 
178 	if (stts22h_init_chip(dev) < 0) {
179 		LOG_ERR("Failed to initialize chip");
180 		return -EIO;
181 	}
182 
183 #ifdef CONFIG_STTS22H_TRIGGER
184 	if (cfg->int_gpio.port) {
185 		if (stts22h_init_interrupt(dev) < 0) {
186 			LOG_ERR("Failed to initialize interrupt.");
187 			return -EIO;
188 		}
189 	}
190 #endif
191 
192 	return 0;
193 }
194 
195 #define STTS22H_DEFINE(inst)									\
196 	static struct stts22h_data stts22h_data_##inst;						\
197 												\
198 	static const struct stts22h_config stts22h_config_##inst = {				\
199 		STMEMSC_CTX_I2C(&stts22h_config_##inst.i2c),					\
200 		.i2c = I2C_DT_SPEC_INST_GET(inst),						\
201 		.temp_hi = DT_INST_PROP(inst, temperature_hi_threshold),			\
202 		.temp_lo = DT_INST_PROP(inst, temperature_lo_threshold),			\
203 		.odr = DT_INST_PROP(inst, sampling_rate),					\
204 		IF_ENABLED(CONFIG_STTS22H_TRIGGER,						\
205 			   (.int_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, { 0 }),))	\
206 	};											\
207 												\
208 	SENSOR_DEVICE_DT_INST_DEFINE(inst, stts22h_init, NULL,					\
209 			      &stts22h_data_##inst, &stts22h_config_##inst, POST_KERNEL,	\
210 			      CONFIG_SENSOR_INIT_PRIORITY, &stts22h_api_funcs);			\
211 
212 DT_INST_FOREACH_STATUS_OKAY(STTS22H_DEFINE)
213