1 /*
2  * Copyright (c) 2024 Calian Advanced Technologies
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT national_lm95234
8 
9 #include <zephyr/device.h>
10 #include <zephyr/devicetree.h>
11 #include <zephyr/drivers/i2c.h>
12 #include <zephyr/drivers/sensor.h>
13 #include <zephyr/drivers/sensor/lm95234.h>
14 #include <zephyr/pm/device.h>
15 #include <zephyr/pm/device_runtime.h>
16 #include <zephyr/logging/log.h>
17 
18 LOG_MODULE_REGISTER(LM95234, CONFIG_SENSOR_LOG_LEVEL);
19 
20 #define LM95234_REG_LOCAL_TEMP_SIGNED_MSB				0x10
21 #define LM95234_REG_LOCAL_TEMP_SIGNED_LSB				0x20
22 #define LM95234_REG_REMOTE_TEMP_1_SIGNED_MSB				0x11
23 #define LM95234_REG_REMOTE_TEMP_1_SIGNED_LSB				0x21
24 #define LM95234_REG_REMOTE_TEMP_2_SIGNED_MSB				0x12
25 #define LM95234_REG_REMOTE_TEMP_2_SIGNED_LSB				0x22
26 #define LM95234_REG_REMOTE_TEMP_3_SIGNED_MSB				0x13
27 #define LM95234_REG_REMOTE_TEMP_3_SIGNED_LSB				0x23
28 #define LM95234_REG_REMOTE_TEMP_4_SIGNED_MSB				0x14
29 #define LM95234_REG_REMOTE_TEMP_4_SIGNED_LSB				0x24
30 #define LM95234_REG_REMOTE_TEMP_1_UNSIGNED_MSB				0x19
31 #define LM95234_REG_REMOTE_TEMP_1_UNSIGNED_LSB				0x29
32 #define LM95234_REG_REMOTE_TEMP_2_UNSIGNED_MSB				0x1a
33 #define LM95234_REG_REMOTE_TEMP_2_UNSIGNED_LSB				0x2a
34 #define LM95234_REG_REMOTE_TEMP_3_UNSIGNED_MSB				0x1b
35 #define LM95234_REG_REMOTE_TEMP_3_UNSIGNED_LSB				0x2b
36 #define LM95234_REG_REMOTE_TEMP_4_UNSIGNED_MSB				0x1c
37 #define LM95234_REG_REMOTE_TEMP_4_UNSIGNED_LSB				0x2c
38 #define LM95234_REG_DIODE_MODEL_SELECT					0x30
39 #define LM95234_REG_REMOTE_1_OFFSET					0x31
40 #define LM95234_REG_REMOTE_2_OFFSET					0x32
41 #define LM95234_REG_REMOTE_3_OFFSET					0x33
42 #define LM95234_REG_REMOTE_4_OFFSET					0x34
43 #define LM95234_REG_CONFIG						0x03
44 #define LM95234_REG_CONV_RATE						0x04
45 #define LM95234_REG_CHANNEL_CONV_ENABLE					0x05
46 #define LM95234_REG_FILTER_SETTING					0x06
47 #define LM95234_REG_ONESHOT						0x0f
48 #define LM95234_REG_COMMON_STATUS					0x02
49 #define LM95234_REG_STATUS_1						0x07
50 #define LM95234_REG_STATUS_2						0x08
51 #define LM95234_REG_STATUS_3						0x09
52 #define LM95234_REG_STATUS_4						0x0a
53 #define LM95234_REG_DIODE_MODEL_STATUS					0x38
54 #define LM95234_REG_TCRIT1_MASK						0x0c
55 #define LM95234_REG_TCRIT2_MASK						0x0d
56 #define LM95234_REG_TCRIT3_MASK						0x0e
57 #define LM95234_REG_LOCAL_TCRIT_LIMIT					0x40
58 #define LM95234_REG_REMOTE1_TCRIT1_LIMIT				0x41
59 #define LM95234_REG_REMOTE2_TCRIT1_LIMIT				0x42
60 #define LM95234_REG_REMOTE3_TCRIT_LIMIT					0x43
61 #define LM95234_REG_REMOTE4_TCRIT_LIMIT					0x44
62 #define LM95234_REG_REMOTE1_TCRIT23_LIMIT				0x49
63 #define LM95234_REG_REMOTE2_TCRIT23_LIMIT				0x4a
64 #define LM95234_REG_COMMON_TCRIT_HYSTERESIS				0x5a
65 #define LM95234_REG_MANUF_ID						0xfe
66 #define LM95234_REG_REV_ID						0xff
67 
68 #define LM95234_MAN_ID							0x01
69 #define LM95234_CHIP_ID							0x79
70 
71 #define LM95234_CONFIG_STANDBY						BIT(6)
72 
73 struct lm95234_data {
74 	/** Temperatures in raw format read from sensor */
75 	int32_t local;
76 	int32_t remote[4];
77 };
78 
79 struct lm95234_config {
80 	struct i2c_dt_spec i2c;
81 };
82 
lm95234_fetch_temp(const struct lm95234_config * cfg,struct lm95234_data * data,enum sensor_channel chan,int32_t * output)83 static inline int lm95234_fetch_temp(const struct lm95234_config *cfg, struct lm95234_data *data,
84 				     enum sensor_channel chan, int32_t *output)
85 {
86 	int ret;
87 	uint8_t val;
88 	int32_t result = 0;
89 
90 	if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
91 		uint16_t temp;
92 		int offset = (chan - SENSOR_CHAN_LM95234_REMOTE_TEMP_1);
93 
94 		ret = i2c_reg_read_byte_dt(&cfg->i2c,
95 					   LM95234_REG_REMOTE_TEMP_1_UNSIGNED_MSB + offset, &val);
96 		if (ret) {
97 			return ret;
98 		}
99 		temp = val << 8;
100 		ret = i2c_reg_read_byte_dt(&cfg->i2c,
101 					  LM95234_REG_REMOTE_TEMP_1_UNSIGNED_LSB + offset, &val);
102 		if (ret) {
103 			return ret;
104 		}
105 		temp |= val;
106 		result = temp;
107 	}
108 
109 	/* Read signed temperature if unsigned temperature is 0, or for local sensor */
110 	if (chan == SENSOR_CHAN_AMBIENT_TEMP || result == 0) {
111 		int offset = chan == SENSOR_CHAN_AMBIENT_TEMP ? 0 :
112 			(chan - SENSOR_CHAN_LM95234_REMOTE_TEMP_1 + 1);
113 		int16_t temp;
114 
115 		ret = i2c_reg_read_byte_dt(&cfg->i2c,
116 					  LM95234_REG_LOCAL_TEMP_SIGNED_MSB + offset, &val);
117 		if (ret) {
118 			return ret;
119 		}
120 		temp = val << 8;
121 		ret = i2c_reg_read_byte_dt(&cfg->i2c,
122 					   LM95234_REG_LOCAL_TEMP_SIGNED_LSB + offset, &val);
123 		if (ret) {
124 			return ret;
125 		}
126 		temp |= val;
127 		result = temp;
128 	}
129 	*output = result;
130 	return 0;
131 }
132 
lm95234_sample_fetch(const struct device * dev,enum sensor_channel chan)133 static int lm95234_sample_fetch(const struct device *dev,
134 			     enum sensor_channel chan)
135 {
136 	struct lm95234_data *data = dev->data;
137 	const struct lm95234_config *cfg = dev->config;
138 	enum pm_device_state pm_state;
139 	int ret;
140 
141 	(void)pm_device_state_get(dev, &pm_state);
142 	if (pm_state != PM_DEVICE_STATE_ACTIVE) {
143 		ret = -EIO;
144 		return ret;
145 	}
146 
147 	switch ((uint32_t)chan) {
148 	case SENSOR_CHAN_ALL:
149 		ret = lm95234_fetch_temp(cfg, data, SENSOR_CHAN_AMBIENT_TEMP, &data->local);
150 		if (ret) {
151 			return ret;
152 		}
153 		for (int i = 0; i < ARRAY_SIZE(data->remote); i++) {
154 			ret = lm95234_fetch_temp(cfg, data,
155 						 SENSOR_CHAN_LM95234_REMOTE_TEMP_1 + i,
156 						 &data->remote[i]);
157 			if (ret) {
158 				return ret;
159 			}
160 		}
161 		break;
162 	case SENSOR_CHAN_AMBIENT_TEMP:
163 		ret = lm95234_fetch_temp(cfg, data, chan, &data->local);
164 		break;
165 	case SENSOR_CHAN_LM95234_REMOTE_TEMP_1:
166 	case SENSOR_CHAN_LM95234_REMOTE_TEMP_2:
167 	case SENSOR_CHAN_LM95234_REMOTE_TEMP_3:
168 	case SENSOR_CHAN_LM95234_REMOTE_TEMP_4:
169 		ret = lm95234_fetch_temp(cfg, data, chan,
170 					 &data->remote[chan - SENSOR_CHAN_LM95234_REMOTE_TEMP_1]);
171 		break;
172 	default:
173 		ret = -ENOTSUP;
174 		break;
175 	}
176 
177 	return ret;
178 }
179 
lm95234_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)180 static int lm95234_channel_get(const struct device *dev,
181 			    enum sensor_channel chan,
182 			    struct sensor_value *val)
183 {
184 	struct lm95234_data *data = dev->data;
185 	int32_t raw_temp;
186 
187 	switch ((uint32_t)chan) {
188 	case SENSOR_CHAN_AMBIENT_TEMP:
189 		raw_temp = data->local;
190 		break;
191 	case SENSOR_CHAN_LM95234_REMOTE_TEMP_1:
192 	case SENSOR_CHAN_LM95234_REMOTE_TEMP_2:
193 	case SENSOR_CHAN_LM95234_REMOTE_TEMP_3:
194 	case SENSOR_CHAN_LM95234_REMOTE_TEMP_4:
195 		raw_temp = data->remote[chan - SENSOR_CHAN_LM95234_REMOTE_TEMP_1];
196 		break;
197 	default:
198 		return -ENOTSUP;
199 	}
200 
201 	/* Raw data format is 8 bits integer, 5 bits fractional, 3 bits zero */
202 	val->val1 = raw_temp / 256;
203 	val->val2 = (raw_temp % 256) * 1000000 / 256;
204 	return 0;
205 }
206 
207 static DEVICE_API(sensor, lm95234_driver_api) = {
208 	.sample_fetch = lm95234_sample_fetch,
209 	.channel_get = lm95234_channel_get,
210 };
211 
lm95234_init(const struct device * dev)212 static int lm95234_init(const struct device *dev)
213 {
214 	const struct lm95234_config *cfg = dev->config;
215 	int ret = 0;
216 	uint8_t value, model_select, model_status;
217 
218 	if (!i2c_is_ready_dt(&cfg->i2c)) {
219 		LOG_ERR("I2C dev not ready");
220 		return -ENODEV;
221 	}
222 
223 	ret = i2c_reg_read_byte_dt(&cfg->i2c, LM95234_REG_MANUF_ID, &value);
224 	if (ret) {
225 		LOG_ERR("Could not read manufacturer ID: %d", ret);
226 		return ret;
227 	}
228 	if (value != LM95234_MAN_ID) {
229 		LOG_ERR("Invalid manufacturer ID: %02x", value);
230 		return -ENODEV;
231 	}
232 	ret = i2c_reg_read_byte_dt(&cfg->i2c, LM95234_REG_REV_ID, &value);
233 	if (ret) {
234 		LOG_ERR("Could not read revision ID: %d", ret);
235 		return ret;
236 	}
237 	if (value != LM95234_CHIP_ID) {
238 		LOG_ERR("Invalid chip ID: %02x", value);
239 		return -ENODEV;
240 	}
241 	ret = i2c_reg_read_byte_dt(&cfg->i2c, LM95234_REG_CONFIG, &value);
242 	if (ret) {
243 		LOG_ERR("Could not read config: %d", ret);
244 		return ret;
245 	}
246 	if (value & LM95234_CONFIG_STANDBY) {
247 		value &= ~LM95234_CONFIG_STANDBY;
248 		ret = i2c_reg_write_byte_dt(&cfg->i2c, LM95234_REG_CONFIG, value);
249 		if (ret) {
250 			LOG_ERR("Could not write config: %d", ret);
251 			return ret;
252 		}
253 	}
254 	ret = i2c_reg_read_byte_dt(&cfg->i2c, LM95234_REG_DIODE_MODEL_SELECT, &model_select);
255 	if (ret) {
256 		LOG_ERR("Could not read diode model select: %d", ret);
257 		return ret;
258 	}
259 	ret = i2c_reg_read_byte_dt(&cfg->i2c, LM95234_REG_DIODE_MODEL_STATUS, &model_status);
260 	if (ret) {
261 		LOG_ERR("Could not read diode model status: %d", ret);
262 		return ret;
263 	}
264 	/**
265 	 * Check if any remote inputs have a 3904 transistor detected but are not configured
266 	 * as such. If so, configure them as 3904 transistors.
267 	 */
268 	if (model_select & model_status) {
269 		model_select &= ~model_status;
270 		ret = i2c_reg_write_byte_dt(&cfg->i2c, LM95234_REG_DIODE_MODEL_SELECT,
271 					    model_select);
272 		if (ret) {
273 			LOG_ERR("Could not write diode model select: %d", ret);
274 			return ret;
275 		}
276 	}
277 
278 #ifdef CONFIG_PM_DEVICE_RUNTIME
279 	pm_device_init_suspended(dev);
280 
281 	ret = pm_device_runtime_enable(dev);
282 	if (ret < 0 && ret != -ENOTSUP) {
283 		LOG_ERR("Failed to enable runtime power management");
284 		return ret;
285 	}
286 #endif
287 
288 	return 0;
289 }
290 
291 #ifdef CONFIG_PM_DEVICE
292 
lm95234_pm_action(const struct device * dev,enum pm_device_action action)293 static int lm95234_pm_action(const struct device *dev, enum pm_device_action action)
294 {
295 	switch (action) {
296 	case PM_DEVICE_ACTION_TURN_ON:
297 	case PM_DEVICE_ACTION_RESUME:
298 	case PM_DEVICE_ACTION_TURN_OFF:
299 	case PM_DEVICE_ACTION_SUSPEND:
300 		break;
301 	default:
302 		return -ENOTSUP;
303 	}
304 
305 	return 0;
306 }
307 
308 #endif
309 
310 #define LM95234_INST(inst)                                     \
311 static struct lm95234_data lm95234_data_##inst;                \
312 static const struct lm95234_config lm95234_config_##inst = {   \
313 	.i2c = I2C_DT_SPEC_INST_GET(inst),                     \
314 };                                                             \
315 PM_DEVICE_DT_INST_DEFINE(inst, lm95234_pm_action);	       \
316 SENSOR_DEVICE_DT_INST_DEFINE(inst, lm95234_init,               \
317 			     PM_DEVICE_DT_INST_GET(inst),      \
318 			     &lm95234_data_##inst,	       \
319 			     &lm95234_config_##inst,           \
320 			     POST_KERNEL,                      \
321 			     CONFIG_SENSOR_INIT_PRIORITY,      \
322 			     &lm95234_driver_api);
323 
324 DT_INST_FOREACH_STATUS_OKAY(LM95234_INST)
325