File Index
Files and directories
Sign in
FILE

lm95245.c

File preview with syntax highlighting.

linux-6.19.14/drivers/hwmon/lm95245.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Copyright (C) 2011 Alexander Stein <alexander.stein@systec-electronic.com>
  4 *
  5 * The LM95245 is a sensor chip made by TI / National Semiconductor.
  6 * It reports up to two temperatures (its own plus an external one).
  7 *
  8 * This driver is based on lm95241.c
  9 */
 10
 11#include <linux/err.h>
 12#include <linux/init.h>
 13#include <linux/hwmon.h>
 14#include <linux/i2c.h>
 15#include <linux/module.h>
 16#include <linux/regmap.h>
 17#include <linux/slab.h>
 18
 19static const unsigned short normal_i2c[] = {
 20	0x18, 0x19, 0x29, 0x4c, 0x4d, I2C_CLIENT_END };
 21
 22/* LM95245 registers */
 23/* general registers */
 24#define LM95245_REG_RW_CONFIG1		0x03
 25#define LM95245_REG_RW_CONVERS_RATE	0x04
 26#define LM95245_REG_W_ONE_SHOT		0x0F
 27
 28/* diode configuration */
 29#define LM95245_REG_RW_CONFIG2		0xBF
 30#define LM95245_REG_RW_REMOTE_OFFH	0x11
 31#define LM95245_REG_RW_REMOTE_OFFL	0x12
 32
 33/* status registers */
 34#define LM95245_REG_R_STATUS1		0x02
 35#define LM95245_REG_R_STATUS2		0x33
 36
 37/* limit registers */
 38#define LM95245_REG_RW_REMOTE_OS_LIMIT		0x07
 39#define LM95245_REG_RW_LOCAL_OS_TCRIT_LIMIT	0x20
 40#define LM95245_REG_RW_REMOTE_TCRIT_LIMIT	0x19
 41#define LM95245_REG_RW_COMMON_HYSTERESIS	0x21
 42
 43/* temperature signed */
 44#define LM95245_REG_R_LOCAL_TEMPH_S	0x00
 45#define LM95245_REG_R_LOCAL_TEMPL_S	0x30
 46#define LM95245_REG_R_REMOTE_TEMPH_S	0x01
 47#define LM95245_REG_R_REMOTE_TEMPL_S	0x10
 48/* temperature unsigned */
 49#define LM95245_REG_R_REMOTE_TEMPH_U	0x31
 50#define LM95245_REG_R_REMOTE_TEMPL_U	0x32
 51
 52/* id registers */
 53#define LM95245_REG_R_MAN_ID		0xFE
 54#define LM95245_REG_R_CHIP_ID		0xFF
 55
 56/* LM95245 specific bitfields */
 57#define CFG_STOP		0x40
 58#define CFG_REMOTE_TCRIT_MASK	0x10
 59#define CFG_REMOTE_OS_MASK	0x08
 60#define CFG_LOCAL_TCRIT_MASK	0x04
 61#define CFG_LOCAL_OS_MASK	0x02
 62
 63#define CFG2_OS_A0		0x40
 64#define CFG2_DIODE_FAULT_OS	0x20
 65#define CFG2_DIODE_FAULT_TCRIT	0x10
 66#define CFG2_REMOTE_TT		0x08
 67#define CFG2_REMOTE_FILTER_DIS	0x00
 68#define CFG2_REMOTE_FILTER_EN	0x06
 69
 70/* conversation rate in ms */
 71#define RATE_CR0063	0x00
 72#define RATE_CR0364	0x01
 73#define RATE_CR1000	0x02
 74#define RATE_CR2500	0x03
 75
 76#define STATUS1_ROS		0x10
 77#define STATUS1_DIODE_FAULT	0x04
 78#define STATUS1_RTCRIT		0x02
 79#define STATUS1_LOC		0x01
 80
 81#define MANUFACTURER_ID		0x01
 82#define LM95235_REVISION	0xB1
 83#define LM95245_REVISION	0xB3
 84
 85/* Client data (each client gets its own) */
 86struct lm95245_data {
 87	struct regmap *regmap;
 88	int interval;	/* in msecs */
 89};
 90
 91/* Conversions */
 92static int temp_from_reg_unsigned(u8 val_h, u8 val_l)
 93{
 94	return val_h * 1000 + val_l * 1000 / 256;
 95}
 96
 97static int temp_from_reg_signed(u8 val_h, u8 val_l)
 98{
 99	if (val_h & 0x80)
100		return (val_h - 0x100) * 1000;
101	return temp_from_reg_unsigned(val_h, val_l);
102}
103
104static int lm95245_read_conversion_rate(struct lm95245_data *data)
105{
106	unsigned int rate;
107	int ret;
108
109	ret = regmap_read(data->regmap, LM95245_REG_RW_CONVERS_RATE, &rate);
110	if (ret < 0)
111		return ret;
112
113	switch (rate) {
114	case RATE_CR0063:
115		data->interval = 63;
116		break;
117	case RATE_CR0364:
118		data->interval = 364;
119		break;
120	case RATE_CR1000:
121		data->interval = 1000;
122		break;
123	case RATE_CR2500:
124	default:
125		data->interval = 2500;
126		break;
127	}
128	return 0;
129}
130
131static int lm95245_set_conversion_rate(struct lm95245_data *data, long interval)
132{
133	int ret, rate;
134
135	if (interval <= 63) {
136		interval = 63;
137		rate = RATE_CR0063;
138	} else if (interval <= 364) {
139		interval = 364;
140		rate = RATE_CR0364;
141	} else if (interval <= 1000) {
142		interval = 1000;
143		rate = RATE_CR1000;
144	} else {
145		interval = 2500;
146		rate = RATE_CR2500;
147	}
148
149	ret = regmap_write(data->regmap, LM95245_REG_RW_CONVERS_RATE, rate);
150	if (ret < 0)
151		return ret;
152
153	data->interval = interval;
154	return 0;
155}
156
157static int lm95245_read_temp(struct device *dev, u32 attr, int channel,
158			     long *val)
159{
160	struct lm95245_data *data = dev_get_drvdata(dev);
161	struct regmap *regmap = data->regmap;
162	unsigned int regs[2];
163	unsigned int regval;
164	u8 regvals[2];
165	int ret;
166
167	switch (attr) {
168	case hwmon_temp_input:
169		regs[0] = channel ? LM95245_REG_R_REMOTE_TEMPL_S :
170				    LM95245_REG_R_LOCAL_TEMPL_S;
171		regs[1] = channel ? LM95245_REG_R_REMOTE_TEMPH_S :
172				    LM95245_REG_R_LOCAL_TEMPH_S;
173		ret = regmap_multi_reg_read(regmap, regs, regvals, 2);
174		if (ret < 0)
175			return ret;
176		/*
177		 * Local temp is always signed.
178		 * Remote temp has both signed and unsigned data.
179		 * Use signed calculation for remote if signed bit is set
180		 * or if reported temperature is below signed limit.
181		 */
182		if (!channel || (regvals[1] & 0x80) || regvals[1] < 0x7f) {
183			*val = temp_from_reg_signed(regvals[1], regvals[0]);
184			return 0;
185		}
186		ret = regmap_bulk_read(regmap, LM95245_REG_R_REMOTE_TEMPH_U, regvals, 2);
187		if (ret)
188			return ret;
189		*val = temp_from_reg_unsigned(regvals[0], regvals[1]);
190		return 0;
191	case hwmon_temp_max:
192		ret = regmap_read(regmap, LM95245_REG_RW_REMOTE_OS_LIMIT,
193				  &regval);
194		if (ret < 0)
195			return ret;
196		*val = regval * 1000;
197		return 0;
198	case hwmon_temp_crit:
199		regs[0] = channel ? LM95245_REG_RW_REMOTE_TCRIT_LIMIT :
200				    LM95245_REG_RW_LOCAL_OS_TCRIT_LIMIT;
201		ret = regmap_read(regmap, regs[0], &regval);
202		if (ret < 0)
203			return ret;
204		*val = regval * 1000;
205		return 0;
206	case hwmon_temp_max_hyst:
207		regs[0] = LM95245_REG_RW_REMOTE_OS_LIMIT;
208		regs[1] = LM95245_REG_RW_COMMON_HYSTERESIS;
209		ret = regmap_multi_reg_read(regmap, regs, regvals, 2);
210		if (ret < 0)
211			return ret;
212		*val = (regvals[0] - regvals[1]) * 1000;
213		return 0;
214	case hwmon_temp_crit_hyst:
215		regs[0] = channel ? LM95245_REG_RW_REMOTE_TCRIT_LIMIT :
216				    LM95245_REG_RW_LOCAL_OS_TCRIT_LIMIT;
217		regs[1] = LM95245_REG_RW_COMMON_HYSTERESIS;
218
219		ret = regmap_multi_reg_read(regmap, regs, regvals, 2);
220		if (ret < 0)
221			return ret;
222		*val = (regvals[0] - regvals[1]) * 1000;
223		return 0;
224	case hwmon_temp_type:
225		ret = regmap_read(regmap, LM95245_REG_RW_CONFIG2, &regval);
226		if (ret < 0)
227			return ret;
228		*val = (regval & CFG2_REMOTE_TT) ? 1 : 2;
229		return 0;
230	case hwmon_temp_offset:
231		ret = regmap_bulk_read(regmap, LM95245_REG_RW_REMOTE_OFFH, regvals, 2);
232		if (ret < 0)
233			return ret;
234		*val = temp_from_reg_signed(regvals[0], regvals[1]);
235		return 0;
236	case hwmon_temp_max_alarm:
237		ret = regmap_read(regmap, LM95245_REG_R_STATUS1, &regval);
238		if (ret < 0)
239			return ret;
240		*val = !!(regval & STATUS1_ROS);
241		return 0;
242	case hwmon_temp_crit_alarm:
243		ret = regmap_read(regmap, LM95245_REG_R_STATUS1, &regval);
244		if (ret < 0)
245			return ret;
246		*val = !!(regval & (channel ? STATUS1_RTCRIT : STATUS1_LOC));
247		return 0;
248	case hwmon_temp_fault:
249		ret = regmap_read(regmap, LM95245_REG_R_STATUS1, &regval);
250		if (ret < 0)
251			return ret;
252		*val = !!(regval & STATUS1_DIODE_FAULT);
253		return 0;
254	default:
255		return -EOPNOTSUPP;
256	}
257}
258
259static int lm95245_write_temp(struct device *dev, u32 attr, int channel,
260			      long val)
261{
262	struct lm95245_data *data = dev_get_drvdata(dev);
263	struct regmap *regmap = data->regmap;
264	unsigned int regval;
265	u8 regvals[2];
266	int ret, reg;
267
268	switch (attr) {
269	case hwmon_temp_max:
270		val = clamp_val(val / 1000, 0, 255);
271		ret = regmap_write(regmap, LM95245_REG_RW_REMOTE_OS_LIMIT, val);
272		return ret;
273	case hwmon_temp_crit:
274		reg = channel ? LM95245_REG_RW_REMOTE_TCRIT_LIMIT :
275				LM95245_REG_RW_LOCAL_OS_TCRIT_LIMIT;
276		val = clamp_val(val / 1000, 0, channel ? 255 : 127);
277		ret = regmap_write(regmap, reg, val);
278		return ret;
279	case hwmon_temp_crit_hyst:
280		ret = regmap_read(regmap, LM95245_REG_RW_LOCAL_OS_TCRIT_LIMIT,
281				  &regval);
282		if (ret < 0)
283			return ret;
284		/* Clamp to reasonable range to prevent overflow */
285		val = clamp_val(val, -1000000, 1000000);
286		val = regval - val / 1000;
287		val = clamp_val(val, 0, 31);
288		ret = regmap_write(regmap, LM95245_REG_RW_COMMON_HYSTERESIS,
289				   val);
290		return ret;
291	case hwmon_temp_offset:
292		val = clamp_val(val, -128000, 127875);
293		val = val * 256 / 1000;
294		regvals[0] = val >> 8;
295		regvals[1] = val & 0xe0;
296
297		ret = regmap_bulk_write(regmap, LM95245_REG_RW_REMOTE_OFFH, regvals, 2);
298		return ret;
299	case hwmon_temp_type:
300		if (val != 1 && val != 2)
301			return -EINVAL;
302		ret = regmap_update_bits(regmap, LM95245_REG_RW_CONFIG2,
303					 CFG2_REMOTE_TT,
304					 val == 1 ? CFG2_REMOTE_TT : 0);
305		return ret;
306	default:
307		return -EOPNOTSUPP;
308	}
309}
310
311static int lm95245_read_chip(struct device *dev, u32 attr, int channel,
312			     long *val)
313{
314	struct lm95245_data *data = dev_get_drvdata(dev);
315
316	switch (attr) {
317	case hwmon_chip_update_interval:
318		*val = data->interval;
319		return 0;
320	default:
321		return -EOPNOTSUPP;
322	}
323}
324
325static int lm95245_write_chip(struct device *dev, u32 attr, int channel,
326			      long val)
327{
328	struct lm95245_data *data = dev_get_drvdata(dev);
329
330	switch (attr) {
331	case hwmon_chip_update_interval:
332		return lm95245_set_conversion_rate(data, val);
333	default:
334		return -EOPNOTSUPP;
335	}
336}
337
338static int lm95245_read(struct device *dev, enum hwmon_sensor_types type,
339			u32 attr, int channel, long *val)
340{
341	switch (type) {
342	case hwmon_chip:
343		return lm95245_read_chip(dev, attr, channel, val);
344	case hwmon_temp:
345		return lm95245_read_temp(dev, attr, channel, val);
346	default:
347		return -EOPNOTSUPP;
348	}
349}
350
351static int lm95245_write(struct device *dev, enum hwmon_sensor_types type,
352			 u32 attr, int channel, long val)
353{
354	switch (type) {
355	case hwmon_chip:
356		return lm95245_write_chip(dev, attr, channel, val);
357	case hwmon_temp:
358		return lm95245_write_temp(dev, attr, channel, val);
359	default:
360		return -EOPNOTSUPP;
361	}
362}
363
364static umode_t lm95245_temp_is_visible(const void *data, u32 attr, int channel)
365{
366	switch (attr) {
367	case hwmon_temp_input:
368	case hwmon_temp_max_alarm:
369	case hwmon_temp_max_hyst:
370	case hwmon_temp_crit_alarm:
371	case hwmon_temp_fault:
372		return 0444;
373	case hwmon_temp_type:
374	case hwmon_temp_max:
375	case hwmon_temp_crit:
376	case hwmon_temp_offset:
377		return 0644;
378	case hwmon_temp_crit_hyst:
379		return (channel == 0) ? 0644 : 0444;
380	default:
381		return 0;
382	}
383}
384
385static umode_t lm95245_is_visible(const void *data,
386				  enum hwmon_sensor_types type,
387				  u32 attr, int channel)
388{
389	switch (type) {
390	case hwmon_chip:
391		switch (attr) {
392		case hwmon_chip_update_interval:
393			return 0644;
394		default:
395			return 0;
396		}
397	case hwmon_temp:
398		return lm95245_temp_is_visible(data, attr, channel);
399	default:
400		return 0;
401	}
402}
403
404/* Return 0 if detection is successful, -ENODEV otherwise */
405static int lm95245_detect(struct i2c_client *new_client,
406			  struct i2c_board_info *info)
407{
408	struct i2c_adapter *adapter = new_client->adapter;
409	int address = new_client->addr;
410	const char *name;
411	int rev, id;
412
413	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
414		return -ENODEV;
415
416	id = i2c_smbus_read_byte_data(new_client, LM95245_REG_R_MAN_ID);
417	if (id != MANUFACTURER_ID)
418		return -ENODEV;
419
420	rev = i2c_smbus_read_byte_data(new_client, LM95245_REG_R_CHIP_ID);
421	switch (rev) {
422	case LM95235_REVISION:
423		if (address != 0x18 && address != 0x29 && address != 0x4c)
424			return -ENODEV;
425		name = "lm95235";
426		break;
427	case LM95245_REVISION:
428		name = "lm95245";
429		break;
430	default:
431		return -ENODEV;
432	}
433
434	strscpy(info->type, name, I2C_NAME_SIZE);
435	return 0;
436}
437
438static int lm95245_init_client(struct lm95245_data *data)
439{
440	int ret;
441
442	ret = lm95245_read_conversion_rate(data);
443	if (ret < 0)
444		return ret;
445
446	return regmap_update_bits(data->regmap, LM95245_REG_RW_CONFIG1,
447				  CFG_STOP, 0);
448}
449
450static bool lm95245_is_writeable_reg(struct device *dev, unsigned int reg)
451{
452	switch (reg) {
453	case LM95245_REG_RW_CONFIG1:
454	case LM95245_REG_RW_CONVERS_RATE:
455	case LM95245_REG_W_ONE_SHOT:
456	case LM95245_REG_RW_CONFIG2:
457	case LM95245_REG_RW_REMOTE_OFFH:
458	case LM95245_REG_RW_REMOTE_OFFL:
459	case LM95245_REG_RW_REMOTE_OS_LIMIT:
460	case LM95245_REG_RW_LOCAL_OS_TCRIT_LIMIT:
461	case LM95245_REG_RW_REMOTE_TCRIT_LIMIT:
462	case LM95245_REG_RW_COMMON_HYSTERESIS:
463		return true;
464	default:
465		return false;
466	}
467}
468
469static bool lm95245_is_volatile_reg(struct device *dev, unsigned int reg)
470{
471	switch (reg) {
472	case LM95245_REG_R_STATUS1:
473	case LM95245_REG_R_STATUS2:
474	case LM95245_REG_R_LOCAL_TEMPH_S:
475	case LM95245_REG_R_LOCAL_TEMPL_S:
476	case LM95245_REG_R_REMOTE_TEMPH_S:
477	case LM95245_REG_R_REMOTE_TEMPL_S:
478	case LM95245_REG_R_REMOTE_TEMPH_U:
479	case LM95245_REG_R_REMOTE_TEMPL_U:
480		return true;
481	default:
482		return false;
483	}
484}
485
486static const struct regmap_config lm95245_regmap_config = {
487	.reg_bits = 8,
488	.val_bits = 8,
489	.writeable_reg = lm95245_is_writeable_reg,
490	.volatile_reg = lm95245_is_volatile_reg,
491	.cache_type = REGCACHE_MAPLE,
492	.use_single_read = true,
493	.use_single_write = true,
494};
495
496static const struct hwmon_channel_info * const lm95245_info[] = {
497	HWMON_CHANNEL_INFO(chip,
498			   HWMON_C_UPDATE_INTERVAL),
499	HWMON_CHANNEL_INFO(temp,
500			   HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_HYST |
501			   HWMON_T_CRIT_ALARM,
502			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
503			   HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_FAULT |
504			   HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM |
505			   HWMON_T_TYPE | HWMON_T_OFFSET),
506	NULL
507};
508
509static const struct hwmon_ops lm95245_hwmon_ops = {
510	.is_visible = lm95245_is_visible,
511	.read = lm95245_read,
512	.write = lm95245_write,
513};
514
515static const struct hwmon_chip_info lm95245_chip_info = {
516	.ops = &lm95245_hwmon_ops,
517	.info = lm95245_info,
518};
519
520static int lm95245_probe(struct i2c_client *client)
521{
522	struct device *dev = &client->dev;
523	struct lm95245_data *data;
524	struct device *hwmon_dev;
525	int ret;
526
527	data = devm_kzalloc(dev, sizeof(struct lm95245_data), GFP_KERNEL);
528	if (!data)
529		return -ENOMEM;
530
531	data->regmap = devm_regmap_init_i2c(client, &lm95245_regmap_config);
532	if (IS_ERR(data->regmap))
533		return PTR_ERR(data->regmap);
534
535	/* Initialize the LM95245 chip */
536	ret = lm95245_init_client(data);
537	if (ret < 0)
538		return ret;
539
540	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
541							 data,
542							 &lm95245_chip_info,
543							 NULL);
544	return PTR_ERR_OR_ZERO(hwmon_dev);
545}
546
547/* Driver data (common to all clients) */
548static const struct i2c_device_id lm95245_id[] = {
549	{ "lm95235" },
550	{ "lm95245" },
551	{ }
552};
553MODULE_DEVICE_TABLE(i2c, lm95245_id);
554
555static const struct of_device_id __maybe_unused lm95245_of_match[] = {
556	{ .compatible = "national,lm95235" },
557	{ .compatible = "national,lm95245" },
558	{ },
559};
560MODULE_DEVICE_TABLE(of, lm95245_of_match);
561
562static struct i2c_driver lm95245_driver = {
563	.class		= I2C_CLASS_HWMON,
564	.driver = {
565		.name	= "lm95245",
566		.of_match_table = of_match_ptr(lm95245_of_match),
567	},
568	.probe		= lm95245_probe,
569	.id_table	= lm95245_id,
570	.detect		= lm95245_detect,
571	.address_list	= normal_i2c,
572};
573
574module_i2c_driver(lm95245_driver);
575
576MODULE_AUTHOR("Alexander Stein <alexander.stein@systec-electronic.com>");
577MODULE_DESCRIPTION("LM95235/LM95245 sensor driver");
578MODULE_LICENSE("GPL");
~/ Read-only file preview.