xref: /openbmc/linux/drivers/hwmon/ad7314.c (revision 984faa1f)
14f3a6595SJonathan Cameron /*
24f3a6595SJonathan Cameron  * AD7314 digital temperature sensor driver for AD7314, ADT7301 and ADT7302
34f3a6595SJonathan Cameron  *
44f3a6595SJonathan Cameron  * Copyright 2010 Analog Devices Inc.
54f3a6595SJonathan Cameron  *
64f3a6595SJonathan Cameron  * Licensed under the GPL-2 or later.
74f3a6595SJonathan Cameron  *
84f3a6595SJonathan Cameron  * Conversion to hwmon from IIO done by Jonathan Cameron <jic23@cam.ac.uk>
94f3a6595SJonathan Cameron  */
104f3a6595SJonathan Cameron #include <linux/device.h>
114f3a6595SJonathan Cameron #include <linux/kernel.h>
124f3a6595SJonathan Cameron #include <linux/slab.h>
134f3a6595SJonathan Cameron #include <linux/sysfs.h>
144f3a6595SJonathan Cameron #include <linux/spi/spi.h>
154f3a6595SJonathan Cameron #include <linux/module.h>
164f3a6595SJonathan Cameron #include <linux/err.h>
174f3a6595SJonathan Cameron #include <linux/hwmon.h>
184f3a6595SJonathan Cameron #include <linux/hwmon-sysfs.h>
19984faa1fSRasmus Villemoes #include <linux/bitops.h>
204f3a6595SJonathan Cameron 
214f3a6595SJonathan Cameron /*
224f3a6595SJonathan Cameron  * AD7314 temperature masks
234f3a6595SJonathan Cameron  */
244f3a6595SJonathan Cameron #define AD7314_TEMP_MASK		0x7FE0
251137a9a6SGuenter Roeck #define AD7314_TEMP_SHIFT		5
264f3a6595SJonathan Cameron 
274f3a6595SJonathan Cameron /*
284f3a6595SJonathan Cameron  * ADT7301 and ADT7302 temperature masks
294f3a6595SJonathan Cameron  */
304f3a6595SJonathan Cameron #define ADT7301_TEMP_MASK		0x3FFF
314f3a6595SJonathan Cameron 
324f3a6595SJonathan Cameron enum ad7314_variant {
334f3a6595SJonathan Cameron 	adt7301,
344f3a6595SJonathan Cameron 	adt7302,
354f3a6595SJonathan Cameron 	ad7314,
364f3a6595SJonathan Cameron };
374f3a6595SJonathan Cameron 
384f3a6595SJonathan Cameron struct ad7314_data {
394f3a6595SJonathan Cameron 	struct spi_device	*spi_dev;
404f3a6595SJonathan Cameron 	struct device		*hwmon_dev;
414f3a6595SJonathan Cameron 	u16 rx ____cacheline_aligned;
424f3a6595SJonathan Cameron };
434f3a6595SJonathan Cameron 
44eae1415dSGuenter Roeck static int ad7314_spi_read(struct ad7314_data *chip)
454f3a6595SJonathan Cameron {
464f3a6595SJonathan Cameron 	int ret;
474f3a6595SJonathan Cameron 
484f3a6595SJonathan Cameron 	ret = spi_read(chip->spi_dev, (u8 *)&chip->rx, sizeof(chip->rx));
494f3a6595SJonathan Cameron 	if (ret < 0) {
504f3a6595SJonathan Cameron 		dev_err(&chip->spi_dev->dev, "SPI read error\n");
514f3a6595SJonathan Cameron 		return ret;
524f3a6595SJonathan Cameron 	}
534f3a6595SJonathan Cameron 
54eae1415dSGuenter Roeck 	return be16_to_cpu(chip->rx);
554f3a6595SJonathan Cameron }
564f3a6595SJonathan Cameron 
574f3a6595SJonathan Cameron static ssize_t ad7314_show_temperature(struct device *dev,
584f3a6595SJonathan Cameron 		struct device_attribute *attr,
594f3a6595SJonathan Cameron 		char *buf)
604f3a6595SJonathan Cameron {
614f3a6595SJonathan Cameron 	struct ad7314_data *chip = dev_get_drvdata(dev);
624f3a6595SJonathan Cameron 	s16 data;
634f3a6595SJonathan Cameron 	int ret;
644f3a6595SJonathan Cameron 
65eae1415dSGuenter Roeck 	ret = ad7314_spi_read(chip);
664f3a6595SJonathan Cameron 	if (ret < 0)
674f3a6595SJonathan Cameron 		return ret;
684f3a6595SJonathan Cameron 	switch (spi_get_device_id(chip->spi_dev)->driver_data) {
694f3a6595SJonathan Cameron 	case ad7314:
701137a9a6SGuenter Roeck 		data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_SHIFT;
71984faa1fSRasmus Villemoes 		data = sign_extend32(data, 9);
724f3a6595SJonathan Cameron 
734f3a6595SJonathan Cameron 		return sprintf(buf, "%d\n", 250 * data);
744f3a6595SJonathan Cameron 	case adt7301:
754f3a6595SJonathan Cameron 	case adt7302:
764f3a6595SJonathan Cameron 		/*
774f3a6595SJonathan Cameron 		 * Documented as a 13 bit twos complement register
784f3a6595SJonathan Cameron 		 * with a sign bit - which is a 14 bit 2's complement
794f3a6595SJonathan Cameron 		 * register.  1lsb - 31.25 milli degrees centigrade
804f3a6595SJonathan Cameron 		 */
81eae1415dSGuenter Roeck 		data = ret & ADT7301_TEMP_MASK;
82984faa1fSRasmus Villemoes 		data = sign_extend32(data, 13);
834f3a6595SJonathan Cameron 
844f3a6595SJonathan Cameron 		return sprintf(buf, "%d\n",
854f3a6595SJonathan Cameron 			       DIV_ROUND_CLOSEST(data * 3125, 100));
864f3a6595SJonathan Cameron 	default:
874f3a6595SJonathan Cameron 		return -EINVAL;
884f3a6595SJonathan Cameron 	}
894f3a6595SJonathan Cameron }
904f3a6595SJonathan Cameron 
913ceefe43SGuenter Roeck static ssize_t ad7314_show_name(struct device *dev,
923ceefe43SGuenter Roeck 				struct device_attribute *devattr, char *buf)
933ceefe43SGuenter Roeck {
943ceefe43SGuenter Roeck 	return sprintf(buf, "%s\n", to_spi_device(dev)->modalias);
953ceefe43SGuenter Roeck }
963ceefe43SGuenter Roeck 
973ceefe43SGuenter Roeck static DEVICE_ATTR(name, S_IRUGO, ad7314_show_name, NULL);
984f3a6595SJonathan Cameron static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
994f3a6595SJonathan Cameron 			  ad7314_show_temperature, NULL, 0);
1004f3a6595SJonathan Cameron 
1014f3a6595SJonathan Cameron static struct attribute *ad7314_attributes[] = {
1023ceefe43SGuenter Roeck 	&dev_attr_name.attr,
1034f3a6595SJonathan Cameron 	&sensor_dev_attr_temp1_input.dev_attr.attr,
1044f3a6595SJonathan Cameron 	NULL,
1054f3a6595SJonathan Cameron };
1064f3a6595SJonathan Cameron 
1074f3a6595SJonathan Cameron static const struct attribute_group ad7314_group = {
1084f3a6595SJonathan Cameron 	.attrs = ad7314_attributes,
1094f3a6595SJonathan Cameron };
1104f3a6595SJonathan Cameron 
1116c931ae1SBill Pemberton static int ad7314_probe(struct spi_device *spi_dev)
1124f3a6595SJonathan Cameron {
1134f3a6595SJonathan Cameron 	int ret;
1144f3a6595SJonathan Cameron 	struct ad7314_data *chip;
1154f3a6595SJonathan Cameron 
116be923040SGuenter Roeck 	chip = devm_kzalloc(&spi_dev->dev, sizeof(*chip), GFP_KERNEL);
117be923040SGuenter Roeck 	if (chip == NULL)
118be923040SGuenter Roeck 		return -ENOMEM;
119be923040SGuenter Roeck 
120debe597cSJingoo Han 	spi_set_drvdata(spi_dev, chip);
1214f3a6595SJonathan Cameron 
1224f3a6595SJonathan Cameron 	ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group);
1234f3a6595SJonathan Cameron 	if (ret < 0)
124be923040SGuenter Roeck 		return ret;
125be923040SGuenter Roeck 
1264f3a6595SJonathan Cameron 	chip->hwmon_dev = hwmon_device_register(&spi_dev->dev);
1274f3a6595SJonathan Cameron 	if (IS_ERR(chip->hwmon_dev)) {
1284f3a6595SJonathan Cameron 		ret = PTR_ERR(chip->hwmon_dev);
1294f3a6595SJonathan Cameron 		goto error_remove_group;
1304f3a6595SJonathan Cameron 	}
131e16de913SGraeme Smecher 	chip->spi_dev = spi_dev;
1324f3a6595SJonathan Cameron 
1334f3a6595SJonathan Cameron 	return 0;
1344f3a6595SJonathan Cameron error_remove_group:
1354f3a6595SJonathan Cameron 	sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
1364f3a6595SJonathan Cameron 	return ret;
1374f3a6595SJonathan Cameron }
1384f3a6595SJonathan Cameron 
139281dfd0bSBill Pemberton static int ad7314_remove(struct spi_device *spi_dev)
1404f3a6595SJonathan Cameron {
141debe597cSJingoo Han 	struct ad7314_data *chip = spi_get_drvdata(spi_dev);
1424f3a6595SJonathan Cameron 
1434f3a6595SJonathan Cameron 	hwmon_device_unregister(chip->hwmon_dev);
1444f3a6595SJonathan Cameron 	sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
1454f3a6595SJonathan Cameron 
1464f3a6595SJonathan Cameron 	return 0;
1474f3a6595SJonathan Cameron }
1484f3a6595SJonathan Cameron 
1494f3a6595SJonathan Cameron static const struct spi_device_id ad7314_id[] = {
1504f3a6595SJonathan Cameron 	{ "adt7301", adt7301 },
1514f3a6595SJonathan Cameron 	{ "adt7302", adt7302 },
1524f3a6595SJonathan Cameron 	{ "ad7314", ad7314 },
1534f3a6595SJonathan Cameron 	{ }
1544f3a6595SJonathan Cameron };
1554f3a6595SJonathan Cameron MODULE_DEVICE_TABLE(spi, ad7314_id);
1564f3a6595SJonathan Cameron 
1574f3a6595SJonathan Cameron static struct spi_driver ad7314_driver = {
1584f3a6595SJonathan Cameron 	.driver = {
1594f3a6595SJonathan Cameron 		.name = "ad7314",
1604f3a6595SJonathan Cameron 		.owner = THIS_MODULE,
1614f3a6595SJonathan Cameron 	},
1624f3a6595SJonathan Cameron 	.probe = ad7314_probe,
1639e5e9b7aSBill Pemberton 	.remove = ad7314_remove,
1644f3a6595SJonathan Cameron 	.id_table = ad7314_id,
1654f3a6595SJonathan Cameron };
1664f3a6595SJonathan Cameron 
16791efffe2SAxel Lin module_spi_driver(ad7314_driver);
1684f3a6595SJonathan Cameron 
1694f3a6595SJonathan Cameron MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
170b55f3757SGuenter Roeck MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital temperature sensor driver");
1714f3a6595SJonathan Cameron MODULE_LICENSE("GPL v2");
172