xref: /openbmc/linux/drivers/hwmon/max31827.c (revision 90fc660e)
116d60ba8SDaniel Matyas // SPDX-License-Identifier: GPL-2.0
216d60ba8SDaniel Matyas /*
316d60ba8SDaniel Matyas  * max31827.c - Support for Maxim Low-Power Switch
416d60ba8SDaniel Matyas  *
516d60ba8SDaniel Matyas  * Copyright (c) 2023 Daniel Matyas <daniel.matyas@analog.com>
616d60ba8SDaniel Matyas  */
716d60ba8SDaniel Matyas 
816d60ba8SDaniel Matyas #include <linux/bitfield.h>
916d60ba8SDaniel Matyas #include <linux/bitops.h>
1016d60ba8SDaniel Matyas #include <linux/delay.h>
1116d60ba8SDaniel Matyas #include <linux/hwmon.h>
1216d60ba8SDaniel Matyas #include <linux/i2c.h>
1316d60ba8SDaniel Matyas #include <linux/mutex.h>
1416d60ba8SDaniel Matyas #include <linux/regmap.h>
1516d60ba8SDaniel Matyas 
1616d60ba8SDaniel Matyas #define MAX31827_T_REG			0x0
1716d60ba8SDaniel Matyas #define MAX31827_CONFIGURATION_REG	0x2
1816d60ba8SDaniel Matyas #define MAX31827_TH_REG			0x4
1916d60ba8SDaniel Matyas #define MAX31827_TL_REG			0x6
2016d60ba8SDaniel Matyas #define MAX31827_TH_HYST_REG		0x8
2116d60ba8SDaniel Matyas #define MAX31827_TL_HYST_REG		0xA
2216d60ba8SDaniel Matyas 
2316d60ba8SDaniel Matyas #define MAX31827_CONFIGURATION_1SHOT_MASK	BIT(0)
2416d60ba8SDaniel Matyas #define MAX31827_CONFIGURATION_CNV_RATE_MASK	GENMASK(3, 1)
2516d60ba8SDaniel Matyas #define MAX31827_CONFIGURATION_U_TEMP_STAT_MASK	BIT(14)
2616d60ba8SDaniel Matyas #define MAX31827_CONFIGURATION_O_TEMP_STAT_MASK	BIT(15)
2716d60ba8SDaniel Matyas 
2816d60ba8SDaniel Matyas #define MAX31827_12_BIT_CNV_TIME	141
2916d60ba8SDaniel Matyas 
3016d60ba8SDaniel Matyas #define MAX31827_CNV_1_DIV_64_HZ	0x1
3116d60ba8SDaniel Matyas #define MAX31827_CNV_1_DIV_32_HZ	0x2
3216d60ba8SDaniel Matyas #define MAX31827_CNV_1_DIV_16_HZ	0x3
3316d60ba8SDaniel Matyas #define MAX31827_CNV_1_DIV_4_HZ		0x4
3416d60ba8SDaniel Matyas #define MAX31827_CNV_1_HZ		0x5
3516d60ba8SDaniel Matyas #define MAX31827_CNV_4_HZ		0x6
3616d60ba8SDaniel Matyas #define MAX31827_CNV_8_HZ		0x7
3716d60ba8SDaniel Matyas 
3816d60ba8SDaniel Matyas #define MAX31827_16_BIT_TO_M_DGR(x)	(sign_extend32(x, 15) * 1000 / 16)
3916d60ba8SDaniel Matyas #define MAX31827_M_DGR_TO_16_BIT(x)	(((x) << 4) / 1000)
4016d60ba8SDaniel Matyas #define MAX31827_DEVICE_ENABLE(x)	((x) ? 0xA : 0x0)
4116d60ba8SDaniel Matyas 
4216d60ba8SDaniel Matyas struct max31827_state {
4316d60ba8SDaniel Matyas 	/*
4416d60ba8SDaniel Matyas 	 * Prevent simultaneous access to the i2c client.
4516d60ba8SDaniel Matyas 	 */
4616d60ba8SDaniel Matyas 	struct mutex lock;
4716d60ba8SDaniel Matyas 	struct regmap *regmap;
4816d60ba8SDaniel Matyas 	bool enable;
4916d60ba8SDaniel Matyas };
5016d60ba8SDaniel Matyas 
5116d60ba8SDaniel Matyas static const struct regmap_config max31827_regmap = {
5216d60ba8SDaniel Matyas 	.reg_bits = 8,
5316d60ba8SDaniel Matyas 	.val_bits = 16,
5416d60ba8SDaniel Matyas 	.max_register = 0xA,
5516d60ba8SDaniel Matyas };
5616d60ba8SDaniel Matyas 
write_alarm_val(struct max31827_state * st,unsigned int reg,long val)5716d60ba8SDaniel Matyas static int write_alarm_val(struct max31827_state *st, unsigned int reg,
5816d60ba8SDaniel Matyas 			   long val)
5916d60ba8SDaniel Matyas {
6016d60ba8SDaniel Matyas 	unsigned int cfg;
6116d60ba8SDaniel Matyas 	unsigned int tmp;
6216d60ba8SDaniel Matyas 	int ret;
6316d60ba8SDaniel Matyas 
6416d60ba8SDaniel Matyas 	val = MAX31827_M_DGR_TO_16_BIT(val);
6516d60ba8SDaniel Matyas 
6616d60ba8SDaniel Matyas 	/*
6716d60ba8SDaniel Matyas 	 * Before the Temperature Threshold Alarm and Alarm Hysteresis Threshold
6816d60ba8SDaniel Matyas 	 * register values are changed over I2C, the part must be in shutdown
6916d60ba8SDaniel Matyas 	 * mode.
7016d60ba8SDaniel Matyas 	 *
7116d60ba8SDaniel Matyas 	 * Mutex is used to ensure, that some other process doesn't change the
7216d60ba8SDaniel Matyas 	 * configuration register.
7316d60ba8SDaniel Matyas 	 */
7416d60ba8SDaniel Matyas 	mutex_lock(&st->lock);
7516d60ba8SDaniel Matyas 
7616d60ba8SDaniel Matyas 	if (!st->enable) {
7716d60ba8SDaniel Matyas 		ret = regmap_write(st->regmap, reg, val);
7816d60ba8SDaniel Matyas 		goto unlock;
7916d60ba8SDaniel Matyas 	}
8016d60ba8SDaniel Matyas 
8116d60ba8SDaniel Matyas 	ret = regmap_read(st->regmap, MAX31827_CONFIGURATION_REG, &cfg);
8216d60ba8SDaniel Matyas 	if (ret)
8316d60ba8SDaniel Matyas 		goto unlock;
8416d60ba8SDaniel Matyas 
8516d60ba8SDaniel Matyas 	tmp = cfg & ~(MAX31827_CONFIGURATION_1SHOT_MASK |
8616d60ba8SDaniel Matyas 		      MAX31827_CONFIGURATION_CNV_RATE_MASK);
8716d60ba8SDaniel Matyas 	ret = regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, tmp);
8816d60ba8SDaniel Matyas 	if (ret)
8916d60ba8SDaniel Matyas 		goto unlock;
9016d60ba8SDaniel Matyas 
9116d60ba8SDaniel Matyas 	ret = regmap_write(st->regmap, reg, val);
9216d60ba8SDaniel Matyas 	if (ret)
9316d60ba8SDaniel Matyas 		goto unlock;
9416d60ba8SDaniel Matyas 
9516d60ba8SDaniel Matyas 	ret = regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, cfg);
9616d60ba8SDaniel Matyas 
9716d60ba8SDaniel Matyas unlock:
9816d60ba8SDaniel Matyas 	mutex_unlock(&st->lock);
9916d60ba8SDaniel Matyas 	return ret;
10016d60ba8SDaniel Matyas }
10116d60ba8SDaniel Matyas 
max31827_is_visible(const void * state,enum hwmon_sensor_types type,u32 attr,int channel)10216d60ba8SDaniel Matyas static umode_t max31827_is_visible(const void *state,
10316d60ba8SDaniel Matyas 				   enum hwmon_sensor_types type, u32 attr,
10416d60ba8SDaniel Matyas 				   int channel)
10516d60ba8SDaniel Matyas {
10616d60ba8SDaniel Matyas 	if (type == hwmon_temp) {
10716d60ba8SDaniel Matyas 		switch (attr) {
10816d60ba8SDaniel Matyas 		case hwmon_temp_enable:
10916d60ba8SDaniel Matyas 		case hwmon_temp_max:
11016d60ba8SDaniel Matyas 		case hwmon_temp_min:
11116d60ba8SDaniel Matyas 		case hwmon_temp_max_hyst:
11216d60ba8SDaniel Matyas 		case hwmon_temp_min_hyst:
11316d60ba8SDaniel Matyas 			return 0644;
11416d60ba8SDaniel Matyas 		case hwmon_temp_input:
11516d60ba8SDaniel Matyas 		case hwmon_temp_min_alarm:
11616d60ba8SDaniel Matyas 		case hwmon_temp_max_alarm:
11716d60ba8SDaniel Matyas 			return 0444;
11816d60ba8SDaniel Matyas 		default:
11916d60ba8SDaniel Matyas 			return 0;
12016d60ba8SDaniel Matyas 		}
12116d60ba8SDaniel Matyas 	} else if (type == hwmon_chip) {
12216d60ba8SDaniel Matyas 		if (attr == hwmon_chip_update_interval)
12316d60ba8SDaniel Matyas 			return 0644;
12416d60ba8SDaniel Matyas 	}
12516d60ba8SDaniel Matyas 
12616d60ba8SDaniel Matyas 	return 0;
12716d60ba8SDaniel Matyas }
12816d60ba8SDaniel Matyas 
max31827_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)12916d60ba8SDaniel Matyas static int max31827_read(struct device *dev, enum hwmon_sensor_types type,
13016d60ba8SDaniel Matyas 			 u32 attr, int channel, long *val)
13116d60ba8SDaniel Matyas {
13216d60ba8SDaniel Matyas 	struct max31827_state *st = dev_get_drvdata(dev);
13316d60ba8SDaniel Matyas 	unsigned int uval;
13416d60ba8SDaniel Matyas 	int ret = 0;
13516d60ba8SDaniel Matyas 
13616d60ba8SDaniel Matyas 	switch (type) {
13716d60ba8SDaniel Matyas 	case hwmon_temp:
13816d60ba8SDaniel Matyas 		switch (attr) {
13916d60ba8SDaniel Matyas 		case hwmon_temp_enable:
14016d60ba8SDaniel Matyas 			ret = regmap_read(st->regmap,
14116d60ba8SDaniel Matyas 					  MAX31827_CONFIGURATION_REG, &uval);
14216d60ba8SDaniel Matyas 			if (ret)
14316d60ba8SDaniel Matyas 				break;
14416d60ba8SDaniel Matyas 
14516d60ba8SDaniel Matyas 			uval = FIELD_GET(MAX31827_CONFIGURATION_1SHOT_MASK |
14616d60ba8SDaniel Matyas 					 MAX31827_CONFIGURATION_CNV_RATE_MASK,
14716d60ba8SDaniel Matyas 					 uval);
14816d60ba8SDaniel Matyas 			*val = !!uval;
14916d60ba8SDaniel Matyas 
15016d60ba8SDaniel Matyas 			break;
15116d60ba8SDaniel Matyas 		case hwmon_temp_input:
15216d60ba8SDaniel Matyas 			mutex_lock(&st->lock);
15316d60ba8SDaniel Matyas 
15416d60ba8SDaniel Matyas 			if (!st->enable) {
15516d60ba8SDaniel Matyas 				/*
15616d60ba8SDaniel Matyas 				 * This operation requires mutex protection,
15716d60ba8SDaniel Matyas 				 * because the chip configuration should not
15816d60ba8SDaniel Matyas 				 * be changed during the conversion process.
15916d60ba8SDaniel Matyas 				 */
16016d60ba8SDaniel Matyas 
16116d60ba8SDaniel Matyas 				ret = regmap_update_bits(st->regmap,
16216d60ba8SDaniel Matyas 							 MAX31827_CONFIGURATION_REG,
16316d60ba8SDaniel Matyas 							 MAX31827_CONFIGURATION_1SHOT_MASK,
16416d60ba8SDaniel Matyas 							 1);
16516d60ba8SDaniel Matyas 				if (ret) {
16616d60ba8SDaniel Matyas 					mutex_unlock(&st->lock);
16716d60ba8SDaniel Matyas 					return ret;
16816d60ba8SDaniel Matyas 				}
16916d60ba8SDaniel Matyas 
17016d60ba8SDaniel Matyas 				msleep(MAX31827_12_BIT_CNV_TIME);
17116d60ba8SDaniel Matyas 			}
17216d60ba8SDaniel Matyas 			ret = regmap_read(st->regmap, MAX31827_T_REG, &uval);
17316d60ba8SDaniel Matyas 
17416d60ba8SDaniel Matyas 			mutex_unlock(&st->lock);
17516d60ba8SDaniel Matyas 
17616d60ba8SDaniel Matyas 			if (ret)
17716d60ba8SDaniel Matyas 				break;
17816d60ba8SDaniel Matyas 
17916d60ba8SDaniel Matyas 			*val = MAX31827_16_BIT_TO_M_DGR(uval);
18016d60ba8SDaniel Matyas 
18116d60ba8SDaniel Matyas 			break;
18216d60ba8SDaniel Matyas 		case hwmon_temp_max:
18316d60ba8SDaniel Matyas 			ret = regmap_read(st->regmap, MAX31827_TH_REG, &uval);
18416d60ba8SDaniel Matyas 			if (ret)
18516d60ba8SDaniel Matyas 				break;
18616d60ba8SDaniel Matyas 
18716d60ba8SDaniel Matyas 			*val = MAX31827_16_BIT_TO_M_DGR(uval);
18816d60ba8SDaniel Matyas 			break;
18916d60ba8SDaniel Matyas 		case hwmon_temp_max_hyst:
19016d60ba8SDaniel Matyas 			ret = regmap_read(st->regmap, MAX31827_TH_HYST_REG,
19116d60ba8SDaniel Matyas 					  &uval);
19216d60ba8SDaniel Matyas 			if (ret)
19316d60ba8SDaniel Matyas 				break;
19416d60ba8SDaniel Matyas 
19516d60ba8SDaniel Matyas 			*val = MAX31827_16_BIT_TO_M_DGR(uval);
19616d60ba8SDaniel Matyas 			break;
19716d60ba8SDaniel Matyas 		case hwmon_temp_max_alarm:
19816d60ba8SDaniel Matyas 			ret = regmap_read(st->regmap,
19916d60ba8SDaniel Matyas 					  MAX31827_CONFIGURATION_REG, &uval);
20016d60ba8SDaniel Matyas 			if (ret)
20116d60ba8SDaniel Matyas 				break;
20216d60ba8SDaniel Matyas 
20316d60ba8SDaniel Matyas 			*val = FIELD_GET(MAX31827_CONFIGURATION_O_TEMP_STAT_MASK,
20416d60ba8SDaniel Matyas 					 uval);
20516d60ba8SDaniel Matyas 			break;
20616d60ba8SDaniel Matyas 		case hwmon_temp_min:
20716d60ba8SDaniel Matyas 			ret = regmap_read(st->regmap, MAX31827_TL_REG, &uval);
20816d60ba8SDaniel Matyas 			if (ret)
20916d60ba8SDaniel Matyas 				break;
21016d60ba8SDaniel Matyas 
21116d60ba8SDaniel Matyas 			*val = MAX31827_16_BIT_TO_M_DGR(uval);
21216d60ba8SDaniel Matyas 			break;
21316d60ba8SDaniel Matyas 		case hwmon_temp_min_hyst:
21416d60ba8SDaniel Matyas 			ret = regmap_read(st->regmap, MAX31827_TL_HYST_REG,
21516d60ba8SDaniel Matyas 					  &uval);
21616d60ba8SDaniel Matyas 			if (ret)
21716d60ba8SDaniel Matyas 				break;
21816d60ba8SDaniel Matyas 
21916d60ba8SDaniel Matyas 			*val = MAX31827_16_BIT_TO_M_DGR(uval);
22016d60ba8SDaniel Matyas 			break;
22116d60ba8SDaniel Matyas 		case hwmon_temp_min_alarm:
22216d60ba8SDaniel Matyas 			ret = regmap_read(st->regmap,
22316d60ba8SDaniel Matyas 					  MAX31827_CONFIGURATION_REG, &uval);
22416d60ba8SDaniel Matyas 			if (ret)
22516d60ba8SDaniel Matyas 				break;
22616d60ba8SDaniel Matyas 
22716d60ba8SDaniel Matyas 			*val = FIELD_GET(MAX31827_CONFIGURATION_U_TEMP_STAT_MASK,
22816d60ba8SDaniel Matyas 					 uval);
22916d60ba8SDaniel Matyas 			break;
23016d60ba8SDaniel Matyas 		default:
23116d60ba8SDaniel Matyas 			ret = -EOPNOTSUPP;
23216d60ba8SDaniel Matyas 			break;
23316d60ba8SDaniel Matyas 		}
23416d60ba8SDaniel Matyas 
23516d60ba8SDaniel Matyas 		break;
23616d60ba8SDaniel Matyas 
23716d60ba8SDaniel Matyas 	case hwmon_chip:
23816d60ba8SDaniel Matyas 		if (attr == hwmon_chip_update_interval) {
23916d60ba8SDaniel Matyas 			ret = regmap_read(st->regmap,
24016d60ba8SDaniel Matyas 					  MAX31827_CONFIGURATION_REG, &uval);
24116d60ba8SDaniel Matyas 			if (ret)
24216d60ba8SDaniel Matyas 				break;
24316d60ba8SDaniel Matyas 
24416d60ba8SDaniel Matyas 			uval = FIELD_GET(MAX31827_CONFIGURATION_CNV_RATE_MASK,
24516d60ba8SDaniel Matyas 					 uval);
24616d60ba8SDaniel Matyas 			switch (uval) {
24716d60ba8SDaniel Matyas 			case MAX31827_CNV_1_DIV_64_HZ:
24816d60ba8SDaniel Matyas 				*val = 64000;
24916d60ba8SDaniel Matyas 				break;
25016d60ba8SDaniel Matyas 			case MAX31827_CNV_1_DIV_32_HZ:
25116d60ba8SDaniel Matyas 				*val = 32000;
25216d60ba8SDaniel Matyas 				break;
25316d60ba8SDaniel Matyas 			case MAX31827_CNV_1_DIV_16_HZ:
25416d60ba8SDaniel Matyas 				*val = 16000;
25516d60ba8SDaniel Matyas 				break;
25616d60ba8SDaniel Matyas 			case MAX31827_CNV_1_DIV_4_HZ:
25716d60ba8SDaniel Matyas 				*val = 4000;
25816d60ba8SDaniel Matyas 				break;
25916d60ba8SDaniel Matyas 			case MAX31827_CNV_1_HZ:
26016d60ba8SDaniel Matyas 				*val = 1000;
26116d60ba8SDaniel Matyas 				break;
26216d60ba8SDaniel Matyas 			case MAX31827_CNV_4_HZ:
26316d60ba8SDaniel Matyas 				*val = 250;
26416d60ba8SDaniel Matyas 				break;
26516d60ba8SDaniel Matyas 			case MAX31827_CNV_8_HZ:
26616d60ba8SDaniel Matyas 				*val = 125;
26716d60ba8SDaniel Matyas 				break;
26816d60ba8SDaniel Matyas 			default:
26916d60ba8SDaniel Matyas 				*val = 0;
27016d60ba8SDaniel Matyas 				break;
27116d60ba8SDaniel Matyas 			}
27216d60ba8SDaniel Matyas 		}
27316d60ba8SDaniel Matyas 		break;
27416d60ba8SDaniel Matyas 
27516d60ba8SDaniel Matyas 	default:
27616d60ba8SDaniel Matyas 		ret = -EOPNOTSUPP;
27716d60ba8SDaniel Matyas 		break;
27816d60ba8SDaniel Matyas 	}
27916d60ba8SDaniel Matyas 
28016d60ba8SDaniel Matyas 	return ret;
28116d60ba8SDaniel Matyas }
28216d60ba8SDaniel Matyas 
max31827_write(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long val)28316d60ba8SDaniel Matyas static int max31827_write(struct device *dev, enum hwmon_sensor_types type,
28416d60ba8SDaniel Matyas 			  u32 attr, int channel, long val)
28516d60ba8SDaniel Matyas {
28616d60ba8SDaniel Matyas 	struct max31827_state *st = dev_get_drvdata(dev);
28716d60ba8SDaniel Matyas 	int ret;
28816d60ba8SDaniel Matyas 
28916d60ba8SDaniel Matyas 	switch (type) {
29016d60ba8SDaniel Matyas 	case hwmon_temp:
29116d60ba8SDaniel Matyas 		switch (attr) {
29216d60ba8SDaniel Matyas 		case hwmon_temp_enable:
29316d60ba8SDaniel Matyas 			if (val >> 1)
29416d60ba8SDaniel Matyas 				return -EINVAL;
29516d60ba8SDaniel Matyas 
29616d60ba8SDaniel Matyas 			mutex_lock(&st->lock);
29716d60ba8SDaniel Matyas 			/**
29816d60ba8SDaniel Matyas 			 * The chip should not be enabled while a conversion is
29916d60ba8SDaniel Matyas 			 * performed. Neither should the chip be enabled when
30016d60ba8SDaniel Matyas 			 * the alarm values are changed.
30116d60ba8SDaniel Matyas 			 */
30216d60ba8SDaniel Matyas 
30316d60ba8SDaniel Matyas 			st->enable = val;
30416d60ba8SDaniel Matyas 
30516d60ba8SDaniel Matyas 			ret = regmap_update_bits(st->regmap,
30616d60ba8SDaniel Matyas 						 MAX31827_CONFIGURATION_REG,
30716d60ba8SDaniel Matyas 						 MAX31827_CONFIGURATION_1SHOT_MASK |
30816d60ba8SDaniel Matyas 						 MAX31827_CONFIGURATION_CNV_RATE_MASK,
30916d60ba8SDaniel Matyas 						 MAX31827_DEVICE_ENABLE(val));
31016d60ba8SDaniel Matyas 
31116d60ba8SDaniel Matyas 			mutex_unlock(&st->lock);
31216d60ba8SDaniel Matyas 
31316d60ba8SDaniel Matyas 			return ret;
31416d60ba8SDaniel Matyas 
31516d60ba8SDaniel Matyas 		case hwmon_temp_max:
31616d60ba8SDaniel Matyas 			return write_alarm_val(st, MAX31827_TH_REG, val);
31716d60ba8SDaniel Matyas 
31816d60ba8SDaniel Matyas 		case hwmon_temp_max_hyst:
31916d60ba8SDaniel Matyas 			return write_alarm_val(st, MAX31827_TH_HYST_REG, val);
32016d60ba8SDaniel Matyas 
32116d60ba8SDaniel Matyas 		case hwmon_temp_min:
32216d60ba8SDaniel Matyas 			return write_alarm_val(st, MAX31827_TL_REG, val);
32316d60ba8SDaniel Matyas 
32416d60ba8SDaniel Matyas 		case hwmon_temp_min_hyst:
32516d60ba8SDaniel Matyas 			return write_alarm_val(st, MAX31827_TL_HYST_REG, val);
32616d60ba8SDaniel Matyas 
32716d60ba8SDaniel Matyas 		default:
32816d60ba8SDaniel Matyas 			return -EOPNOTSUPP;
32916d60ba8SDaniel Matyas 		}
33016d60ba8SDaniel Matyas 
33116d60ba8SDaniel Matyas 	case hwmon_chip:
33216d60ba8SDaniel Matyas 		if (attr == hwmon_chip_update_interval) {
33316d60ba8SDaniel Matyas 			if (!st->enable)
33416d60ba8SDaniel Matyas 				return -EINVAL;
33516d60ba8SDaniel Matyas 
33616d60ba8SDaniel Matyas 			switch (val) {
33716d60ba8SDaniel Matyas 			case 125:
33816d60ba8SDaniel Matyas 				val = MAX31827_CNV_8_HZ;
33916d60ba8SDaniel Matyas 				break;
34016d60ba8SDaniel Matyas 			case 250:
34116d60ba8SDaniel Matyas 				val = MAX31827_CNV_4_HZ;
34216d60ba8SDaniel Matyas 				break;
34316d60ba8SDaniel Matyas 			case 1000:
34416d60ba8SDaniel Matyas 				val = MAX31827_CNV_1_HZ;
34516d60ba8SDaniel Matyas 				break;
34616d60ba8SDaniel Matyas 			case 4000:
34716d60ba8SDaniel Matyas 				val = MAX31827_CNV_1_DIV_4_HZ;
34816d60ba8SDaniel Matyas 				break;
34916d60ba8SDaniel Matyas 			case 16000:
35016d60ba8SDaniel Matyas 				val = MAX31827_CNV_1_DIV_16_HZ;
35116d60ba8SDaniel Matyas 				break;
35216d60ba8SDaniel Matyas 			case 32000:
35316d60ba8SDaniel Matyas 				val = MAX31827_CNV_1_DIV_32_HZ;
35416d60ba8SDaniel Matyas 				break;
35516d60ba8SDaniel Matyas 			case 64000:
35616d60ba8SDaniel Matyas 				val = MAX31827_CNV_1_DIV_64_HZ;
35716d60ba8SDaniel Matyas 				break;
35816d60ba8SDaniel Matyas 			default:
35916d60ba8SDaniel Matyas 				return -EINVAL;
36016d60ba8SDaniel Matyas 			}
36116d60ba8SDaniel Matyas 
36216d60ba8SDaniel Matyas 			val = FIELD_PREP(MAX31827_CONFIGURATION_CNV_RATE_MASK,
36316d60ba8SDaniel Matyas 					 val);
36416d60ba8SDaniel Matyas 
36516d60ba8SDaniel Matyas 			return regmap_update_bits(st->regmap,
36616d60ba8SDaniel Matyas 						  MAX31827_CONFIGURATION_REG,
36716d60ba8SDaniel Matyas 						  MAX31827_CONFIGURATION_CNV_RATE_MASK,
36816d60ba8SDaniel Matyas 						  val);
36916d60ba8SDaniel Matyas 		}
37016d60ba8SDaniel Matyas 		break;
37116d60ba8SDaniel Matyas 
37216d60ba8SDaniel Matyas 	default:
37316d60ba8SDaniel Matyas 		return -EOPNOTSUPP;
37416d60ba8SDaniel Matyas 	}
37516d60ba8SDaniel Matyas 
37616d60ba8SDaniel Matyas 	return -EOPNOTSUPP;
37716d60ba8SDaniel Matyas }
37816d60ba8SDaniel Matyas 
max31827_init_client(struct max31827_state * st)37916d60ba8SDaniel Matyas static int max31827_init_client(struct max31827_state *st)
38016d60ba8SDaniel Matyas {
38116d60ba8SDaniel Matyas 	st->enable = true;
38216d60ba8SDaniel Matyas 
38316d60ba8SDaniel Matyas 	return regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG,
38416d60ba8SDaniel Matyas 				  MAX31827_CONFIGURATION_1SHOT_MASK |
38516d60ba8SDaniel Matyas 					  MAX31827_CONFIGURATION_CNV_RATE_MASK,
38616d60ba8SDaniel Matyas 				  MAX31827_DEVICE_ENABLE(1));
38716d60ba8SDaniel Matyas }
38816d60ba8SDaniel Matyas 
38916d60ba8SDaniel Matyas static const struct hwmon_channel_info *max31827_info[] = {
39016d60ba8SDaniel Matyas 	HWMON_CHANNEL_INFO(temp, HWMON_T_ENABLE | HWMON_T_INPUT | HWMON_T_MIN |
39116d60ba8SDaniel Matyas 					 HWMON_T_MIN_HYST | HWMON_T_MIN_ALARM |
39216d60ba8SDaniel Matyas 					 HWMON_T_MAX | HWMON_T_MAX_HYST |
39316d60ba8SDaniel Matyas 					 HWMON_T_MAX_ALARM),
39416d60ba8SDaniel Matyas 	HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL),
39516d60ba8SDaniel Matyas 	NULL,
39616d60ba8SDaniel Matyas };
39716d60ba8SDaniel Matyas 
39816d60ba8SDaniel Matyas static const struct hwmon_ops max31827_hwmon_ops = {
39916d60ba8SDaniel Matyas 	.is_visible = max31827_is_visible,
40016d60ba8SDaniel Matyas 	.read = max31827_read,
40116d60ba8SDaniel Matyas 	.write = max31827_write,
40216d60ba8SDaniel Matyas };
40316d60ba8SDaniel Matyas 
40416d60ba8SDaniel Matyas static const struct hwmon_chip_info max31827_chip_info = {
40516d60ba8SDaniel Matyas 	.ops = &max31827_hwmon_ops,
40616d60ba8SDaniel Matyas 	.info = max31827_info,
40716d60ba8SDaniel Matyas };
40816d60ba8SDaniel Matyas 
max31827_probe(struct i2c_client * client)40916d60ba8SDaniel Matyas static int max31827_probe(struct i2c_client *client)
41016d60ba8SDaniel Matyas {
41116d60ba8SDaniel Matyas 	struct device *dev = &client->dev;
41216d60ba8SDaniel Matyas 	struct device *hwmon_dev;
41316d60ba8SDaniel Matyas 	struct max31827_state *st;
41416d60ba8SDaniel Matyas 	int err;
41516d60ba8SDaniel Matyas 
41616d60ba8SDaniel Matyas 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
41716d60ba8SDaniel Matyas 		return -EOPNOTSUPP;
41816d60ba8SDaniel Matyas 
41916d60ba8SDaniel Matyas 	st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
42016d60ba8SDaniel Matyas 	if (!st)
42116d60ba8SDaniel Matyas 		return -ENOMEM;
42216d60ba8SDaniel Matyas 
42316d60ba8SDaniel Matyas 	mutex_init(&st->lock);
42416d60ba8SDaniel Matyas 
42516d60ba8SDaniel Matyas 	st->regmap = devm_regmap_init_i2c(client, &max31827_regmap);
42616d60ba8SDaniel Matyas 	if (IS_ERR(st->regmap))
42716d60ba8SDaniel Matyas 		return dev_err_probe(dev, PTR_ERR(st->regmap),
42816d60ba8SDaniel Matyas 				     "Failed to allocate regmap.\n");
42916d60ba8SDaniel Matyas 
43016d60ba8SDaniel Matyas 	err = max31827_init_client(st);
43116d60ba8SDaniel Matyas 	if (err)
43216d60ba8SDaniel Matyas 		return err;
43316d60ba8SDaniel Matyas 
43416d60ba8SDaniel Matyas 	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, st,
43516d60ba8SDaniel Matyas 							 &max31827_chip_info,
43616d60ba8SDaniel Matyas 							 NULL);
43716d60ba8SDaniel Matyas 
43816d60ba8SDaniel Matyas 	return PTR_ERR_OR_ZERO(hwmon_dev);
43916d60ba8SDaniel Matyas }
44016d60ba8SDaniel Matyas 
44116d60ba8SDaniel Matyas static const struct i2c_device_id max31827_i2c_ids[] = {
44216d60ba8SDaniel Matyas 	{ "max31827", 0 },
44316d60ba8SDaniel Matyas 	{ }
44416d60ba8SDaniel Matyas };
44516d60ba8SDaniel Matyas MODULE_DEVICE_TABLE(i2c, max31827_i2c_ids);
44616d60ba8SDaniel Matyas 
44716d60ba8SDaniel Matyas static const struct of_device_id max31827_of_match[] = {
44816d60ba8SDaniel Matyas 	{ .compatible = "adi,max31827" },
44916d60ba8SDaniel Matyas 	{ }
45016d60ba8SDaniel Matyas };
45116d60ba8SDaniel Matyas MODULE_DEVICE_TABLE(of, max31827_of_match);
45216d60ba8SDaniel Matyas 
45316d60ba8SDaniel Matyas static struct i2c_driver max31827_driver = {
45416d60ba8SDaniel Matyas 	.class = I2C_CLASS_HWMON,
45516d60ba8SDaniel Matyas 	.driver = {
45616d60ba8SDaniel Matyas 		.name = "max31827",
45716d60ba8SDaniel Matyas 		.of_match_table = max31827_of_match,
45816d60ba8SDaniel Matyas 	},
459*90fc660eSUwe Kleine-König 	.probe = max31827_probe,
46016d60ba8SDaniel Matyas 	.id_table = max31827_i2c_ids,
46116d60ba8SDaniel Matyas };
46216d60ba8SDaniel Matyas module_i2c_driver(max31827_driver);
46316d60ba8SDaniel Matyas 
46416d60ba8SDaniel Matyas MODULE_AUTHOR("Daniel Matyas <daniel.matyas@analog.com>");
46516d60ba8SDaniel Matyas MODULE_DESCRIPTION("Maxim MAX31827 low-power temperature switch driver");
46616d60ba8SDaniel Matyas MODULE_LICENSE("GPL");
467