xref: /openbmc/linux/drivers/hwmon/max31722.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
136edc939SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
204e1e70aSTiberiu Breana /*
304e1e70aSTiberiu Breana  * max31722 - hwmon driver for Maxim Integrated MAX31722/MAX31723 SPI
404e1e70aSTiberiu Breana  * digital thermometer and thermostats.
504e1e70aSTiberiu Breana  *
604e1e70aSTiberiu Breana  * Copyright (c) 2016, Intel Corporation.
704e1e70aSTiberiu Breana  */
804e1e70aSTiberiu Breana 
904e1e70aSTiberiu Breana #include <linux/hwmon.h>
1004e1e70aSTiberiu Breana #include <linux/hwmon-sysfs.h>
1104e1e70aSTiberiu Breana #include <linux/kernel.h>
1204e1e70aSTiberiu Breana #include <linux/module.h>
1304e1e70aSTiberiu Breana #include <linux/spi/spi.h>
1404e1e70aSTiberiu Breana 
1504e1e70aSTiberiu Breana #define MAX31722_REG_CFG				0x00
1604e1e70aSTiberiu Breana #define MAX31722_REG_TEMP_LSB				0x01
1704e1e70aSTiberiu Breana 
1804e1e70aSTiberiu Breana #define MAX31722_MODE_CONTINUOUS			0x00
1904e1e70aSTiberiu Breana #define MAX31722_MODE_STANDBY				0x01
2004e1e70aSTiberiu Breana #define MAX31722_MODE_MASK				0xFE
2104e1e70aSTiberiu Breana #define MAX31722_RESOLUTION_12BIT			0x06
2204e1e70aSTiberiu Breana #define MAX31722_WRITE_MASK				0x80
2304e1e70aSTiberiu Breana 
2404e1e70aSTiberiu Breana struct max31722_data {
2504e1e70aSTiberiu Breana 	struct device *hwmon_dev;
2604e1e70aSTiberiu Breana 	struct spi_device *spi_device;
2704e1e70aSTiberiu Breana 	u8 mode;
2804e1e70aSTiberiu Breana };
2904e1e70aSTiberiu Breana 
max31722_set_mode(struct max31722_data * data,u8 mode)3004e1e70aSTiberiu Breana static int max31722_set_mode(struct max31722_data *data, u8 mode)
3104e1e70aSTiberiu Breana {
3204e1e70aSTiberiu Breana 	int ret;
3304e1e70aSTiberiu Breana 	struct spi_device *spi = data->spi_device;
3404e1e70aSTiberiu Breana 	u8 buf[2] = {
3504e1e70aSTiberiu Breana 		MAX31722_REG_CFG | MAX31722_WRITE_MASK,
3604e1e70aSTiberiu Breana 		(data->mode & MAX31722_MODE_MASK) | mode
3704e1e70aSTiberiu Breana 	};
3804e1e70aSTiberiu Breana 
3904e1e70aSTiberiu Breana 	ret = spi_write(spi, &buf, sizeof(buf));
4004e1e70aSTiberiu Breana 	if (ret < 0) {
4104e1e70aSTiberiu Breana 		dev_err(&spi->dev, "failed to set sensor mode.\n");
4204e1e70aSTiberiu Breana 		return ret;
4304e1e70aSTiberiu Breana 	}
4404e1e70aSTiberiu Breana 	data->mode = (data->mode & MAX31722_MODE_MASK) | mode;
4504e1e70aSTiberiu Breana 
4604e1e70aSTiberiu Breana 	return 0;
4704e1e70aSTiberiu Breana }
4804e1e70aSTiberiu Breana 
max31722_temp_show(struct device * dev,struct device_attribute * attr,char * buf)49845ee709SGuenter Roeck static ssize_t max31722_temp_show(struct device *dev,
50845ee709SGuenter Roeck 				  struct device_attribute *attr, char *buf)
5104e1e70aSTiberiu Breana {
5204e1e70aSTiberiu Breana 	ssize_t ret;
5304e1e70aSTiberiu Breana 	struct max31722_data *data = dev_get_drvdata(dev);
5404e1e70aSTiberiu Breana 
5504e1e70aSTiberiu Breana 	ret = spi_w8r16(data->spi_device, MAX31722_REG_TEMP_LSB);
5604e1e70aSTiberiu Breana 	if (ret < 0)
5704e1e70aSTiberiu Breana 		return ret;
5804e1e70aSTiberiu Breana 	/* Keep 12 bits and multiply by the scale of 62.5 millidegrees/bit. */
5904e1e70aSTiberiu Breana 	return sprintf(buf, "%d\n", (s16)le16_to_cpu(ret) * 125 / 32);
6004e1e70aSTiberiu Breana }
6104e1e70aSTiberiu Breana 
62845ee709SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_input, max31722_temp, 0);
6304e1e70aSTiberiu Breana 
6404e1e70aSTiberiu Breana static struct attribute *max31722_attrs[] = {
6504e1e70aSTiberiu Breana 	&sensor_dev_attr_temp1_input.dev_attr.attr,
6604e1e70aSTiberiu Breana 	NULL,
6704e1e70aSTiberiu Breana };
6804e1e70aSTiberiu Breana 
6904e1e70aSTiberiu Breana ATTRIBUTE_GROUPS(max31722);
7004e1e70aSTiberiu Breana 
max31722_probe(struct spi_device * spi)7104e1e70aSTiberiu Breana static int max31722_probe(struct spi_device *spi)
7204e1e70aSTiberiu Breana {
7304e1e70aSTiberiu Breana 	int ret;
7404e1e70aSTiberiu Breana 	struct max31722_data *data;
7504e1e70aSTiberiu Breana 
7604e1e70aSTiberiu Breana 	data = devm_kzalloc(&spi->dev, sizeof(*data), GFP_KERNEL);
7704e1e70aSTiberiu Breana 	if (!data)
7804e1e70aSTiberiu Breana 		return -ENOMEM;
7904e1e70aSTiberiu Breana 
8004e1e70aSTiberiu Breana 	spi_set_drvdata(spi, data);
8104e1e70aSTiberiu Breana 	data->spi_device = spi;
8204e1e70aSTiberiu Breana 	/*
8304e1e70aSTiberiu Breana 	 * Set SD bit to 0 so we can have continuous measurements.
8404e1e70aSTiberiu Breana 	 * Set resolution to 12 bits for maximum precision.
8504e1e70aSTiberiu Breana 	 */
8604e1e70aSTiberiu Breana 	data->mode = MAX31722_MODE_CONTINUOUS | MAX31722_RESOLUTION_12BIT;
8704e1e70aSTiberiu Breana 	ret = max31722_set_mode(data, MAX31722_MODE_CONTINUOUS);
8804e1e70aSTiberiu Breana 	if (ret < 0)
8904e1e70aSTiberiu Breana 		return ret;
9004e1e70aSTiberiu Breana 
9104e1e70aSTiberiu Breana 	data->hwmon_dev = hwmon_device_register_with_groups(&spi->dev,
9204e1e70aSTiberiu Breana 							    spi->modalias,
9304e1e70aSTiberiu Breana 							    data,
9404e1e70aSTiberiu Breana 							    max31722_groups);
9504e1e70aSTiberiu Breana 	if (IS_ERR(data->hwmon_dev)) {
9604e1e70aSTiberiu Breana 		max31722_set_mode(data, MAX31722_MODE_STANDBY);
9704e1e70aSTiberiu Breana 		return PTR_ERR(data->hwmon_dev);
9804e1e70aSTiberiu Breana 	}
9904e1e70aSTiberiu Breana 
10004e1e70aSTiberiu Breana 	return 0;
10104e1e70aSTiberiu Breana }
10204e1e70aSTiberiu Breana 
max31722_remove(struct spi_device * spi)103a0386bbaSUwe Kleine-König static void max31722_remove(struct spi_device *spi)
10404e1e70aSTiberiu Breana {
10504e1e70aSTiberiu Breana 	struct max31722_data *data = spi_get_drvdata(spi);
106efb389b8SUwe Kleine-König 	int ret;
10704e1e70aSTiberiu Breana 
10804e1e70aSTiberiu Breana 	hwmon_device_unregister(data->hwmon_dev);
10904e1e70aSTiberiu Breana 
110efb389b8SUwe Kleine-König 	ret = max31722_set_mode(data, MAX31722_MODE_STANDBY);
111efb389b8SUwe Kleine-König 	if (ret)
112efb389b8SUwe Kleine-König 		/* There is nothing we can do about this ... */
113efb389b8SUwe Kleine-König 		dev_warn(&spi->dev, "Failed to put device in stand-by mode\n");
11404e1e70aSTiberiu Breana }
11504e1e70aSTiberiu Breana 
max31722_suspend(struct device * dev)116*80294537SJonathan Cameron static int max31722_suspend(struct device *dev)
11704e1e70aSTiberiu Breana {
11804e1e70aSTiberiu Breana 	struct spi_device *spi_device = to_spi_device(dev);
11904e1e70aSTiberiu Breana 	struct max31722_data *data = spi_get_drvdata(spi_device);
12004e1e70aSTiberiu Breana 
12104e1e70aSTiberiu Breana 	return max31722_set_mode(data, MAX31722_MODE_STANDBY);
12204e1e70aSTiberiu Breana }
12304e1e70aSTiberiu Breana 
max31722_resume(struct device * dev)124*80294537SJonathan Cameron static int max31722_resume(struct device *dev)
12504e1e70aSTiberiu Breana {
12604e1e70aSTiberiu Breana 	struct spi_device *spi_device = to_spi_device(dev);
12704e1e70aSTiberiu Breana 	struct max31722_data *data = spi_get_drvdata(spi_device);
12804e1e70aSTiberiu Breana 
12904e1e70aSTiberiu Breana 	return max31722_set_mode(data, MAX31722_MODE_CONTINUOUS);
13004e1e70aSTiberiu Breana }
13104e1e70aSTiberiu Breana 
132*80294537SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(max31722_pm_ops, max31722_suspend, max31722_resume);
13304e1e70aSTiberiu Breana 
13404e1e70aSTiberiu Breana static const struct spi_device_id max31722_spi_id[] = {
13504e1e70aSTiberiu Breana 	{"max31722", 0},
13604e1e70aSTiberiu Breana 	{"max31723", 0},
13704e1e70aSTiberiu Breana 	{}
13804e1e70aSTiberiu Breana };
13904e1e70aSTiberiu Breana MODULE_DEVICE_TABLE(spi, max31722_spi_id);
14004e1e70aSTiberiu Breana 
14104e1e70aSTiberiu Breana static struct spi_driver max31722_driver = {
14204e1e70aSTiberiu Breana 	.driver = {
14304e1e70aSTiberiu Breana 		.name = "max31722",
144*80294537SJonathan Cameron 		.pm = pm_sleep_ptr(&max31722_pm_ops),
14504e1e70aSTiberiu Breana 	},
14604e1e70aSTiberiu Breana 	.probe =            max31722_probe,
14704e1e70aSTiberiu Breana 	.remove =           max31722_remove,
14804e1e70aSTiberiu Breana 	.id_table =         max31722_spi_id,
14904e1e70aSTiberiu Breana };
15004e1e70aSTiberiu Breana 
15104e1e70aSTiberiu Breana module_spi_driver(max31722_driver);
15204e1e70aSTiberiu Breana 
15304e1e70aSTiberiu Breana MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>");
15404e1e70aSTiberiu Breana MODULE_DESCRIPTION("max31722 sensor driver");
15504e1e70aSTiberiu Breana MODULE_LICENSE("GPL v2");
156