xref: /openbmc/linux/drivers/hwmon/ad7314.c (revision 80503b23)
180503b23SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
24f3a6595SJonathan Cameron /*
34f3a6595SJonathan Cameron  * AD7314 digital temperature sensor driver for AD7314, ADT7301 and ADT7302
44f3a6595SJonathan Cameron  *
54f3a6595SJonathan Cameron  * Copyright 2010 Analog Devices Inc.
64f3a6595SJonathan Cameron  *
74f3a6595SJonathan Cameron  * Conversion to hwmon from IIO done by Jonathan Cameron <jic23@cam.ac.uk>
84f3a6595SJonathan Cameron  */
94f3a6595SJonathan Cameron #include <linux/device.h>
104f3a6595SJonathan Cameron #include <linux/kernel.h>
114f3a6595SJonathan Cameron #include <linux/slab.h>
124f3a6595SJonathan Cameron #include <linux/sysfs.h>
134f3a6595SJonathan Cameron #include <linux/spi/spi.h>
144f3a6595SJonathan Cameron #include <linux/module.h>
154f3a6595SJonathan Cameron #include <linux/err.h>
164f3a6595SJonathan Cameron #include <linux/hwmon.h>
174f3a6595SJonathan Cameron #include <linux/hwmon-sysfs.h>
18984faa1fSRasmus Villemoes #include <linux/bitops.h>
194f3a6595SJonathan Cameron 
204f3a6595SJonathan Cameron /*
214f3a6595SJonathan Cameron  * AD7314 temperature masks
224f3a6595SJonathan Cameron  */
234f3a6595SJonathan Cameron #define AD7314_TEMP_MASK		0x7FE0
241137a9a6SGuenter Roeck #define AD7314_TEMP_SHIFT		5
254f3a6595SJonathan Cameron 
264f3a6595SJonathan Cameron /*
274f3a6595SJonathan Cameron  * ADT7301 and ADT7302 temperature masks
284f3a6595SJonathan Cameron  */
294f3a6595SJonathan Cameron #define ADT7301_TEMP_MASK		0x3FFF
304f3a6595SJonathan Cameron 
314f3a6595SJonathan Cameron enum ad7314_variant {
324f3a6595SJonathan Cameron 	adt7301,
334f3a6595SJonathan Cameron 	adt7302,
344f3a6595SJonathan Cameron 	ad7314,
354f3a6595SJonathan Cameron };
364f3a6595SJonathan Cameron 
374f3a6595SJonathan Cameron struct ad7314_data {
384f3a6595SJonathan Cameron 	struct spi_device	*spi_dev;
394f3a6595SJonathan Cameron 	u16 rx ____cacheline_aligned;
404f3a6595SJonathan Cameron };
414f3a6595SJonathan Cameron 
ad7314_spi_read(struct ad7314_data * chip)42eae1415dSGuenter Roeck static int ad7314_spi_read(struct ad7314_data *chip)
434f3a6595SJonathan Cameron {
444f3a6595SJonathan Cameron 	int ret;
454f3a6595SJonathan Cameron 
464f3a6595SJonathan Cameron 	ret = spi_read(chip->spi_dev, (u8 *)&chip->rx, sizeof(chip->rx));
474f3a6595SJonathan Cameron 	if (ret < 0) {
484f3a6595SJonathan Cameron 		dev_err(&chip->spi_dev->dev, "SPI read error\n");
494f3a6595SJonathan Cameron 		return ret;
504f3a6595SJonathan Cameron 	}
514f3a6595SJonathan Cameron 
52eae1415dSGuenter Roeck 	return be16_to_cpu(chip->rx);
534f3a6595SJonathan Cameron }
544f3a6595SJonathan Cameron 
ad7314_temperature_show(struct device * dev,struct device_attribute * attr,char * buf)551ba3e023SGuenter Roeck static ssize_t ad7314_temperature_show(struct device *dev,
564f3a6595SJonathan Cameron 				       struct device_attribute *attr,
574f3a6595SJonathan Cameron 				       char *buf)
584f3a6595SJonathan Cameron {
594f3a6595SJonathan Cameron 	struct ad7314_data *chip = dev_get_drvdata(dev);
604f3a6595SJonathan Cameron 	s16 data;
614f3a6595SJonathan Cameron 	int ret;
624f3a6595SJonathan Cameron 
63eae1415dSGuenter Roeck 	ret = ad7314_spi_read(chip);
644f3a6595SJonathan Cameron 	if (ret < 0)
654f3a6595SJonathan Cameron 		return ret;
664f3a6595SJonathan Cameron 	switch (spi_get_device_id(chip->spi_dev)->driver_data) {
674f3a6595SJonathan Cameron 	case ad7314:
681137a9a6SGuenter Roeck 		data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_SHIFT;
69984faa1fSRasmus Villemoes 		data = sign_extend32(data, 9);
704f3a6595SJonathan Cameron 
714f3a6595SJonathan Cameron 		return sprintf(buf, "%d\n", 250 * data);
724f3a6595SJonathan Cameron 	case adt7301:
734f3a6595SJonathan Cameron 	case adt7302:
744f3a6595SJonathan Cameron 		/*
754f3a6595SJonathan Cameron 		 * Documented as a 13 bit twos complement register
764f3a6595SJonathan Cameron 		 * with a sign bit - which is a 14 bit 2's complement
774f3a6595SJonathan Cameron 		 * register.  1lsb - 31.25 milli degrees centigrade
784f3a6595SJonathan Cameron 		 */
79eae1415dSGuenter Roeck 		data = ret & ADT7301_TEMP_MASK;
80984faa1fSRasmus Villemoes 		data = sign_extend32(data, 13);
814f3a6595SJonathan Cameron 
824f3a6595SJonathan Cameron 		return sprintf(buf, "%d\n",
834f3a6595SJonathan Cameron 			       DIV_ROUND_CLOSEST(data * 3125, 100));
844f3a6595SJonathan Cameron 	default:
854f3a6595SJonathan Cameron 		return -EINVAL;
864f3a6595SJonathan Cameron 	}
874f3a6595SJonathan Cameron }
884f3a6595SJonathan Cameron 
891ba3e023SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_input, ad7314_temperature, 0);
904f3a6595SJonathan Cameron 
91157926c0SAxel Lin static struct attribute *ad7314_attrs[] = {
924f3a6595SJonathan Cameron 	&sensor_dev_attr_temp1_input.dev_attr.attr,
934f3a6595SJonathan Cameron 	NULL,
944f3a6595SJonathan Cameron };
954f3a6595SJonathan Cameron 
96157926c0SAxel Lin ATTRIBUTE_GROUPS(ad7314);
974f3a6595SJonathan Cameron 
ad7314_probe(struct spi_device * spi_dev)986c931ae1SBill Pemberton static int ad7314_probe(struct spi_device *spi_dev)
994f3a6595SJonathan Cameron {
1004f3a6595SJonathan Cameron 	struct ad7314_data *chip;
101157926c0SAxel Lin 	struct device *hwmon_dev;
1024f3a6595SJonathan Cameron 
103be923040SGuenter Roeck 	chip = devm_kzalloc(&spi_dev->dev, sizeof(*chip), GFP_KERNEL);
104be923040SGuenter Roeck 	if (chip == NULL)
105be923040SGuenter Roeck 		return -ENOMEM;
106be923040SGuenter Roeck 
107e16de913SGraeme Smecher 	chip->spi_dev = spi_dev;
108157926c0SAxel Lin 	hwmon_dev = devm_hwmon_device_register_with_groups(&spi_dev->dev,
109157926c0SAxel Lin 							   spi_dev->modalias,
110157926c0SAxel Lin 							   chip, ad7314_groups);
111157926c0SAxel Lin 	return PTR_ERR_OR_ZERO(hwmon_dev);
1124f3a6595SJonathan Cameron }
1134f3a6595SJonathan Cameron 
1144f3a6595SJonathan Cameron static const struct spi_device_id ad7314_id[] = {
1154f3a6595SJonathan Cameron 	{ "adt7301", adt7301 },
1164f3a6595SJonathan Cameron 	{ "adt7302", adt7302 },
1174f3a6595SJonathan Cameron 	{ "ad7314", ad7314 },
1184f3a6595SJonathan Cameron 	{ }
1194f3a6595SJonathan Cameron };
1204f3a6595SJonathan Cameron MODULE_DEVICE_TABLE(spi, ad7314_id);
1214f3a6595SJonathan Cameron 
1224f3a6595SJonathan Cameron static struct spi_driver ad7314_driver = {
1234f3a6595SJonathan Cameron 	.driver = {
1244f3a6595SJonathan Cameron 		.name = "ad7314",
1254f3a6595SJonathan Cameron 	},
1264f3a6595SJonathan Cameron 	.probe = ad7314_probe,
1274f3a6595SJonathan Cameron 	.id_table = ad7314_id,
1284f3a6595SJonathan Cameron };
1294f3a6595SJonathan Cameron 
13091efffe2SAxel Lin module_spi_driver(ad7314_driver);
1314f3a6595SJonathan Cameron 
1324f3a6595SJonathan Cameron MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
133b55f3757SGuenter Roeck MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital temperature sensor driver");
1344f3a6595SJonathan Cameron MODULE_LICENSE("GPL v2");
135