1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Driver for MAX31730 3-Channel Remote Temperature Sensor |
4 | * |
5 | * Copyright (c) 2019 Guenter Roeck <linux@roeck-us.net> |
6 | */ |
7 | |
8 | #include <linux/bits.h> |
9 | #include <linux/err.h> |
10 | #include <linux/i2c.h> |
11 | #include <linux/init.h> |
12 | #include <linux/hwmon.h> |
13 | #include <linux/module.h> |
14 | #include <linux/of.h> |
15 | #include <linux/slab.h> |
16 | |
17 | /* Addresses scanned */ |
18 | static const unsigned short normal_i2c[] = { 0x1c, 0x1d, 0x1e, 0x1f, 0x4c, |
19 | 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; |
20 | |
21 | /* The MAX31730 registers */ |
22 | #define MAX31730_REG_TEMP 0x00 |
23 | #define MAX31730_REG_CONF 0x13 |
24 | #define MAX31730_STOP BIT(7) |
25 | #define BIT(1) |
26 | #define MAX31730_REG_TEMP_OFFSET 0x16 |
27 | #define MAX31730_TEMP_OFFSET_BASELINE 0x77 |
28 | #define MAX31730_REG_OFFSET_ENABLE 0x17 |
29 | #define MAX31730_REG_TEMP_MAX 0x20 |
30 | #define MAX31730_REG_TEMP_MIN 0x30 |
31 | #define MAX31730_REG_STATUS_HIGH 0x32 |
32 | #define MAX31730_REG_STATUS_LOW 0x33 |
33 | #define MAX31730_REG_CHANNEL_ENABLE 0x35 |
34 | #define MAX31730_REG_TEMP_FAULT 0x36 |
35 | |
36 | #define MAX31730_REG_MFG_ID 0x50 |
37 | #define MAX31730_MFG_ID 0x4d |
38 | #define MAX31730_REG_MFG_REV 0x51 |
39 | #define MAX31730_MFG_REV 0x01 |
40 | |
41 | #define MAX31730_TEMP_MIN (-128000) |
42 | #define MAX31730_TEMP_MAX 127937 |
43 | |
44 | /* Each client has this additional data */ |
45 | struct max31730_data { |
46 | struct i2c_client *client; |
47 | u8 orig_conf; |
48 | u8 current_conf; |
49 | u8 offset_enable; |
50 | u8 channel_enable; |
51 | }; |
52 | |
53 | /*-----------------------------------------------------------------------*/ |
54 | |
55 | static inline long max31730_reg_to_mc(s16 temp) |
56 | { |
57 | return DIV_ROUND_CLOSEST((temp >> 4) * 1000, 16); |
58 | } |
59 | |
60 | static int max31730_write_config(struct max31730_data *data, u8 set_mask, |
61 | u8 clr_mask) |
62 | { |
63 | u8 value; |
64 | |
65 | clr_mask |= MAX31730_EXTRANGE; |
66 | value = data->current_conf & ~clr_mask; |
67 | value |= set_mask; |
68 | |
69 | if (data->current_conf != value) { |
70 | s32 err; |
71 | |
72 | err = i2c_smbus_write_byte_data(client: data->client, MAX31730_REG_CONF, |
73 | value); |
74 | if (err) |
75 | return err; |
76 | data->current_conf = value; |
77 | } |
78 | return 0; |
79 | } |
80 | |
81 | static int max31730_set_enable(struct i2c_client *client, int reg, |
82 | u8 *confdata, int channel, bool enable) |
83 | { |
84 | u8 regval = *confdata; |
85 | int err; |
86 | |
87 | if (enable) |
88 | regval |= BIT(channel); |
89 | else |
90 | regval &= ~BIT(channel); |
91 | |
92 | if (regval != *confdata) { |
93 | err = i2c_smbus_write_byte_data(client, command: reg, value: regval); |
94 | if (err) |
95 | return err; |
96 | *confdata = regval; |
97 | } |
98 | return 0; |
99 | } |
100 | |
101 | static int max31730_set_offset_enable(struct max31730_data *data, int channel, |
102 | bool enable) |
103 | { |
104 | return max31730_set_enable(client: data->client, MAX31730_REG_OFFSET_ENABLE, |
105 | confdata: &data->offset_enable, channel, enable); |
106 | } |
107 | |
108 | static int max31730_set_channel_enable(struct max31730_data *data, int channel, |
109 | bool enable) |
110 | { |
111 | return max31730_set_enable(client: data->client, MAX31730_REG_CHANNEL_ENABLE, |
112 | confdata: &data->channel_enable, channel, enable); |
113 | } |
114 | |
115 | static int max31730_read(struct device *dev, enum hwmon_sensor_types type, |
116 | u32 attr, int channel, long *val) |
117 | { |
118 | struct max31730_data *data = dev_get_drvdata(dev); |
119 | int regval, reg, offset; |
120 | |
121 | if (type != hwmon_temp) |
122 | return -EINVAL; |
123 | |
124 | switch (attr) { |
125 | case hwmon_temp_input: |
126 | if (!(data->channel_enable & BIT(channel))) |
127 | return -ENODATA; |
128 | reg = MAX31730_REG_TEMP + (channel * 2); |
129 | break; |
130 | case hwmon_temp_max: |
131 | reg = MAX31730_REG_TEMP_MAX + (channel * 2); |
132 | break; |
133 | case hwmon_temp_min: |
134 | reg = MAX31730_REG_TEMP_MIN; |
135 | break; |
136 | case hwmon_temp_enable: |
137 | *val = !!(data->channel_enable & BIT(channel)); |
138 | return 0; |
139 | case hwmon_temp_offset: |
140 | if (!channel) |
141 | return -EINVAL; |
142 | if (!(data->offset_enable & BIT(channel))) { |
143 | *val = 0; |
144 | return 0; |
145 | } |
146 | offset = i2c_smbus_read_byte_data(client: data->client, |
147 | MAX31730_REG_TEMP_OFFSET); |
148 | if (offset < 0) |
149 | return offset; |
150 | *val = (offset - MAX31730_TEMP_OFFSET_BASELINE) * 125; |
151 | return 0; |
152 | case hwmon_temp_fault: |
153 | regval = i2c_smbus_read_byte_data(client: data->client, |
154 | MAX31730_REG_TEMP_FAULT); |
155 | if (regval < 0) |
156 | return regval; |
157 | *val = !!(regval & BIT(channel)); |
158 | return 0; |
159 | case hwmon_temp_min_alarm: |
160 | regval = i2c_smbus_read_byte_data(client: data->client, |
161 | MAX31730_REG_STATUS_LOW); |
162 | if (regval < 0) |
163 | return regval; |
164 | *val = !!(regval & BIT(channel)); |
165 | return 0; |
166 | case hwmon_temp_max_alarm: |
167 | regval = i2c_smbus_read_byte_data(client: data->client, |
168 | MAX31730_REG_STATUS_HIGH); |
169 | if (regval < 0) |
170 | return regval; |
171 | *val = !!(regval & BIT(channel)); |
172 | return 0; |
173 | default: |
174 | return -EINVAL; |
175 | } |
176 | regval = i2c_smbus_read_word_swapped(client: data->client, command: reg); |
177 | if (regval < 0) |
178 | return regval; |
179 | |
180 | *val = max31730_reg_to_mc(temp: regval); |
181 | |
182 | return 0; |
183 | } |
184 | |
185 | static int max31730_write(struct device *dev, enum hwmon_sensor_types type, |
186 | u32 attr, int channel, long val) |
187 | { |
188 | struct max31730_data *data = dev_get_drvdata(dev); |
189 | int reg, err; |
190 | |
191 | if (type != hwmon_temp) |
192 | return -EINVAL; |
193 | |
194 | switch (attr) { |
195 | case hwmon_temp_max: |
196 | reg = MAX31730_REG_TEMP_MAX + channel * 2; |
197 | break; |
198 | case hwmon_temp_min: |
199 | reg = MAX31730_REG_TEMP_MIN; |
200 | break; |
201 | case hwmon_temp_enable: |
202 | if (val != 0 && val != 1) |
203 | return -EINVAL; |
204 | return max31730_set_channel_enable(data, channel, enable: val); |
205 | case hwmon_temp_offset: |
206 | val = clamp_val(val, -14875, 17000) + 14875; |
207 | val = DIV_ROUND_CLOSEST(val, 125); |
208 | err = max31730_set_offset_enable(data, channel, |
209 | enable: val != MAX31730_TEMP_OFFSET_BASELINE); |
210 | if (err) |
211 | return err; |
212 | return i2c_smbus_write_byte_data(client: data->client, |
213 | MAX31730_REG_TEMP_OFFSET, value: val); |
214 | default: |
215 | return -EINVAL; |
216 | } |
217 | |
218 | val = clamp_val(val, MAX31730_TEMP_MIN, MAX31730_TEMP_MAX); |
219 | val = DIV_ROUND_CLOSEST(val << 4, 1000) << 4; |
220 | |
221 | return i2c_smbus_write_word_swapped(client: data->client, command: reg, value: (u16)val); |
222 | } |
223 | |
224 | static umode_t max31730_is_visible(const void *data, |
225 | enum hwmon_sensor_types type, |
226 | u32 attr, int channel) |
227 | { |
228 | switch (type) { |
229 | case hwmon_temp: |
230 | switch (attr) { |
231 | case hwmon_temp_input: |
232 | case hwmon_temp_min_alarm: |
233 | case hwmon_temp_max_alarm: |
234 | case hwmon_temp_fault: |
235 | return 0444; |
236 | case hwmon_temp_min: |
237 | return channel ? 0444 : 0644; |
238 | case hwmon_temp_offset: |
239 | case hwmon_temp_enable: |
240 | case hwmon_temp_max: |
241 | return 0644; |
242 | } |
243 | break; |
244 | default: |
245 | break; |
246 | } |
247 | return 0; |
248 | } |
249 | |
250 | static const struct hwmon_channel_info * const max31730_info[] = { |
251 | HWMON_CHANNEL_INFO(chip, |
252 | HWMON_C_REGISTER_TZ), |
253 | HWMON_CHANNEL_INFO(temp, |
254 | HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | |
255 | HWMON_T_ENABLE | |
256 | HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM, |
257 | HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | |
258 | HWMON_T_OFFSET | HWMON_T_ENABLE | |
259 | HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM | |
260 | HWMON_T_FAULT, |
261 | HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | |
262 | HWMON_T_OFFSET | HWMON_T_ENABLE | |
263 | HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM | |
264 | HWMON_T_FAULT, |
265 | HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | |
266 | HWMON_T_OFFSET | HWMON_T_ENABLE | |
267 | HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM | |
268 | HWMON_T_FAULT |
269 | ), |
270 | NULL |
271 | }; |
272 | |
273 | static const struct hwmon_ops max31730_hwmon_ops = { |
274 | .is_visible = max31730_is_visible, |
275 | .read = max31730_read, |
276 | .write = max31730_write, |
277 | }; |
278 | |
279 | static const struct hwmon_chip_info max31730_chip_info = { |
280 | .ops = &max31730_hwmon_ops, |
281 | .info = max31730_info, |
282 | }; |
283 | |
284 | static void max31730_remove(void *data) |
285 | { |
286 | struct max31730_data *max31730 = data; |
287 | struct i2c_client *client = max31730->client; |
288 | |
289 | i2c_smbus_write_byte_data(client, MAX31730_REG_CONF, |
290 | value: max31730->orig_conf); |
291 | } |
292 | |
293 | static int |
294 | max31730_probe(struct i2c_client *client) |
295 | { |
296 | struct device *dev = &client->dev; |
297 | struct device *hwmon_dev; |
298 | struct max31730_data *data; |
299 | int status, err; |
300 | |
301 | if (!i2c_check_functionality(adap: client->adapter, |
302 | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) |
303 | return -EIO; |
304 | |
305 | data = devm_kzalloc(dev, size: sizeof(struct max31730_data), GFP_KERNEL); |
306 | if (!data) |
307 | return -ENOMEM; |
308 | |
309 | data->client = client; |
310 | |
311 | /* Cache original configuration and enable status */ |
312 | status = i2c_smbus_read_byte_data(client, MAX31730_REG_CHANNEL_ENABLE); |
313 | if (status < 0) |
314 | return status; |
315 | data->channel_enable = status; |
316 | |
317 | status = i2c_smbus_read_byte_data(client, MAX31730_REG_OFFSET_ENABLE); |
318 | if (status < 0) |
319 | return status; |
320 | data->offset_enable = status; |
321 | |
322 | status = i2c_smbus_read_byte_data(client, MAX31730_REG_CONF); |
323 | if (status < 0) |
324 | return status; |
325 | data->orig_conf = status; |
326 | data->current_conf = status; |
327 | |
328 | err = max31730_write_config(data, |
329 | set_mask: data->channel_enable ? 0 : MAX31730_STOP, |
330 | clr_mask: data->channel_enable ? MAX31730_STOP : 0); |
331 | if (err) |
332 | return err; |
333 | |
334 | dev_set_drvdata(dev, data); |
335 | |
336 | err = devm_add_action_or_reset(dev, max31730_remove, data); |
337 | if (err) |
338 | return err; |
339 | |
340 | hwmon_dev = devm_hwmon_device_register_with_info(dev, name: client->name, |
341 | drvdata: data, |
342 | info: &max31730_chip_info, |
343 | NULL); |
344 | return PTR_ERR_OR_ZERO(ptr: hwmon_dev); |
345 | } |
346 | |
347 | static const struct i2c_device_id max31730_ids[] = { |
348 | { "max31730" , 0, }, |
349 | { } |
350 | }; |
351 | MODULE_DEVICE_TABLE(i2c, max31730_ids); |
352 | |
353 | static const struct of_device_id __maybe_unused max31730_of_match[] = { |
354 | { |
355 | .compatible = "maxim,max31730" , |
356 | }, |
357 | { }, |
358 | }; |
359 | MODULE_DEVICE_TABLE(of, max31730_of_match); |
360 | |
361 | static bool max31730_check_reg_temp(struct i2c_client *client, |
362 | int reg) |
363 | { |
364 | int regval; |
365 | |
366 | regval = i2c_smbus_read_byte_data(client, command: reg + 1); |
367 | return regval < 0 || (regval & 0x0f); |
368 | } |
369 | |
370 | /* Return 0 if detection is successful, -ENODEV otherwise */ |
371 | static int max31730_detect(struct i2c_client *client, |
372 | struct i2c_board_info *info) |
373 | { |
374 | struct i2c_adapter *adapter = client->adapter; |
375 | int regval; |
376 | int i; |
377 | |
378 | if (!i2c_check_functionality(adap: adapter, I2C_FUNC_SMBUS_BYTE_DATA | |
379 | I2C_FUNC_SMBUS_WORD_DATA)) |
380 | return -ENODEV; |
381 | |
382 | regval = i2c_smbus_read_byte_data(client, MAX31730_REG_MFG_ID); |
383 | if (regval != MAX31730_MFG_ID) |
384 | return -ENODEV; |
385 | regval = i2c_smbus_read_byte_data(client, MAX31730_REG_MFG_REV); |
386 | if (regval != MAX31730_MFG_REV) |
387 | return -ENODEV; |
388 | |
389 | /* lower 4 bit of temperature and limit registers must be 0 */ |
390 | if (max31730_check_reg_temp(client, MAX31730_REG_TEMP_MIN)) |
391 | return -ENODEV; |
392 | |
393 | for (i = 0; i < 4; i++) { |
394 | if (max31730_check_reg_temp(client, MAX31730_REG_TEMP + i * 2)) |
395 | return -ENODEV; |
396 | if (max31730_check_reg_temp(client, |
397 | MAX31730_REG_TEMP_MAX + i * 2)) |
398 | return -ENODEV; |
399 | } |
400 | |
401 | strscpy(info->type, "max31730" , I2C_NAME_SIZE); |
402 | |
403 | return 0; |
404 | } |
405 | |
406 | static int max31730_suspend(struct device *dev) |
407 | { |
408 | struct max31730_data *data = dev_get_drvdata(dev); |
409 | |
410 | return max31730_write_config(data, MAX31730_STOP, clr_mask: 0); |
411 | } |
412 | |
413 | static int max31730_resume(struct device *dev) |
414 | { |
415 | struct max31730_data *data = dev_get_drvdata(dev); |
416 | |
417 | return max31730_write_config(data, set_mask: 0, MAX31730_STOP); |
418 | } |
419 | |
420 | static DEFINE_SIMPLE_DEV_PM_OPS(max31730_pm_ops, max31730_suspend, max31730_resume); |
421 | |
422 | static struct i2c_driver max31730_driver = { |
423 | .class = I2C_CLASS_HWMON, |
424 | .driver = { |
425 | .name = "max31730" , |
426 | .of_match_table = of_match_ptr(max31730_of_match), |
427 | .pm = pm_sleep_ptr(&max31730_pm_ops), |
428 | }, |
429 | .probe = max31730_probe, |
430 | .id_table = max31730_ids, |
431 | .detect = max31730_detect, |
432 | .address_list = normal_i2c, |
433 | }; |
434 | |
435 | module_i2c_driver(max31730_driver); |
436 | |
437 | MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>" ); |
438 | MODULE_DESCRIPTION("MAX31730 driver" ); |
439 | MODULE_LICENSE("GPL" ); |
440 | |