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