xref: /openbmc/linux/drivers/hwmon/ad7314.c (revision b55f3757)
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>
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 	struct device		*hwmon_dev;
404f3a6595SJonathan Cameron 	u16 rx ____cacheline_aligned;
414f3a6595SJonathan Cameron };
424f3a6595SJonathan Cameron 
43eae1415dSGuenter Roeck static int ad7314_spi_read(struct ad7314_data *chip)
444f3a6595SJonathan Cameron {
454f3a6595SJonathan Cameron 	int ret;
464f3a6595SJonathan Cameron 
474f3a6595SJonathan Cameron 	ret = spi_read(chip->spi_dev, (u8 *)&chip->rx, sizeof(chip->rx));
484f3a6595SJonathan Cameron 	if (ret < 0) {
494f3a6595SJonathan Cameron 		dev_err(&chip->spi_dev->dev, "SPI read error\n");
504f3a6595SJonathan Cameron 		return ret;
514f3a6595SJonathan Cameron 	}
524f3a6595SJonathan Cameron 
53eae1415dSGuenter Roeck 	return be16_to_cpu(chip->rx);
544f3a6595SJonathan Cameron }
554f3a6595SJonathan Cameron 
564f3a6595SJonathan Cameron static ssize_t ad7314_show_temperature(struct device *dev,
574f3a6595SJonathan Cameron 		struct device_attribute *attr,
584f3a6595SJonathan Cameron 		char *buf)
594f3a6595SJonathan Cameron {
604f3a6595SJonathan Cameron 	struct ad7314_data *chip = dev_get_drvdata(dev);
614f3a6595SJonathan Cameron 	s16 data;
624f3a6595SJonathan Cameron 	int ret;
634f3a6595SJonathan Cameron 
64eae1415dSGuenter Roeck 	ret = ad7314_spi_read(chip);
654f3a6595SJonathan Cameron 	if (ret < 0)
664f3a6595SJonathan Cameron 		return ret;
674f3a6595SJonathan Cameron 	switch (spi_get_device_id(chip->spi_dev)->driver_data) {
684f3a6595SJonathan Cameron 	case ad7314:
691137a9a6SGuenter Roeck 		data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_SHIFT;
704f3a6595SJonathan Cameron 		data = (data << 6) >> 6;
714f3a6595SJonathan Cameron 
724f3a6595SJonathan Cameron 		return sprintf(buf, "%d\n", 250 * data);
734f3a6595SJonathan Cameron 	case adt7301:
744f3a6595SJonathan Cameron 	case adt7302:
754f3a6595SJonathan Cameron 		/*
764f3a6595SJonathan Cameron 		 * Documented as a 13 bit twos complement register
774f3a6595SJonathan Cameron 		 * with a sign bit - which is a 14 bit 2's complement
784f3a6595SJonathan Cameron 		 * register.  1lsb - 31.25 milli degrees centigrade
794f3a6595SJonathan Cameron 		 */
80eae1415dSGuenter Roeck 		data = ret & ADT7301_TEMP_MASK;
814f3a6595SJonathan Cameron 		data = (data << 2) >> 2;
824f3a6595SJonathan Cameron 
834f3a6595SJonathan Cameron 		return sprintf(buf, "%d\n",
844f3a6595SJonathan Cameron 			       DIV_ROUND_CLOSEST(data * 3125, 100));
854f3a6595SJonathan Cameron 	default:
864f3a6595SJonathan Cameron 		return -EINVAL;
874f3a6595SJonathan Cameron 	}
884f3a6595SJonathan Cameron }
894f3a6595SJonathan Cameron 
903ceefe43SGuenter Roeck static ssize_t ad7314_show_name(struct device *dev,
913ceefe43SGuenter Roeck 				struct device_attribute *devattr, char *buf)
923ceefe43SGuenter Roeck {
933ceefe43SGuenter Roeck 	return sprintf(buf, "%s\n", to_spi_device(dev)->modalias);
943ceefe43SGuenter Roeck }
953ceefe43SGuenter Roeck 
963ceefe43SGuenter Roeck static DEVICE_ATTR(name, S_IRUGO, ad7314_show_name, NULL);
974f3a6595SJonathan Cameron static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
984f3a6595SJonathan Cameron 			  ad7314_show_temperature, NULL, 0);
994f3a6595SJonathan Cameron 
1004f3a6595SJonathan Cameron static struct attribute *ad7314_attributes[] = {
1013ceefe43SGuenter Roeck 	&dev_attr_name.attr,
1024f3a6595SJonathan Cameron 	&sensor_dev_attr_temp1_input.dev_attr.attr,
1034f3a6595SJonathan Cameron 	NULL,
1044f3a6595SJonathan Cameron };
1054f3a6595SJonathan Cameron 
1064f3a6595SJonathan Cameron static const struct attribute_group ad7314_group = {
1074f3a6595SJonathan Cameron 	.attrs = ad7314_attributes,
1084f3a6595SJonathan Cameron };
1094f3a6595SJonathan Cameron 
1106c931ae1SBill Pemberton static int ad7314_probe(struct spi_device *spi_dev)
1114f3a6595SJonathan Cameron {
1124f3a6595SJonathan Cameron 	int ret;
1134f3a6595SJonathan Cameron 	struct ad7314_data *chip;
1144f3a6595SJonathan Cameron 
115be923040SGuenter Roeck 	chip = devm_kzalloc(&spi_dev->dev, sizeof(*chip), GFP_KERNEL);
116be923040SGuenter Roeck 	if (chip == NULL)
117be923040SGuenter Roeck 		return -ENOMEM;
118be923040SGuenter Roeck 
1194f3a6595SJonathan Cameron 	dev_set_drvdata(&spi_dev->dev, chip);
1204f3a6595SJonathan Cameron 
1214f3a6595SJonathan Cameron 	ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group);
1224f3a6595SJonathan Cameron 	if (ret < 0)
123be923040SGuenter Roeck 		return ret;
124be923040SGuenter Roeck 
1254f3a6595SJonathan Cameron 	chip->hwmon_dev = hwmon_device_register(&spi_dev->dev);
1264f3a6595SJonathan Cameron 	if (IS_ERR(chip->hwmon_dev)) {
1274f3a6595SJonathan Cameron 		ret = PTR_ERR(chip->hwmon_dev);
1284f3a6595SJonathan Cameron 		goto error_remove_group;
1294f3a6595SJonathan Cameron 	}
130e16de913SGraeme Smecher 	chip->spi_dev = spi_dev;
1314f3a6595SJonathan Cameron 
1324f3a6595SJonathan Cameron 	return 0;
1334f3a6595SJonathan Cameron error_remove_group:
1344f3a6595SJonathan Cameron 	sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
1354f3a6595SJonathan Cameron 	return ret;
1364f3a6595SJonathan Cameron }
1374f3a6595SJonathan Cameron 
138281dfd0bSBill Pemberton static int ad7314_remove(struct spi_device *spi_dev)
1394f3a6595SJonathan Cameron {
1404f3a6595SJonathan Cameron 	struct ad7314_data *chip = dev_get_drvdata(&spi_dev->dev);
1414f3a6595SJonathan Cameron 
1424f3a6595SJonathan Cameron 	hwmon_device_unregister(chip->hwmon_dev);
1434f3a6595SJonathan Cameron 	sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
1444f3a6595SJonathan Cameron 
1454f3a6595SJonathan Cameron 	return 0;
1464f3a6595SJonathan Cameron }
1474f3a6595SJonathan Cameron 
1484f3a6595SJonathan Cameron static const struct spi_device_id ad7314_id[] = {
1494f3a6595SJonathan Cameron 	{ "adt7301", adt7301 },
1504f3a6595SJonathan Cameron 	{ "adt7302", adt7302 },
1514f3a6595SJonathan Cameron 	{ "ad7314", ad7314 },
1524f3a6595SJonathan Cameron 	{ }
1534f3a6595SJonathan Cameron };
1544f3a6595SJonathan Cameron MODULE_DEVICE_TABLE(spi, ad7314_id);
1554f3a6595SJonathan Cameron 
1564f3a6595SJonathan Cameron static struct spi_driver ad7314_driver = {
1574f3a6595SJonathan Cameron 	.driver = {
1584f3a6595SJonathan Cameron 		.name = "ad7314",
1594f3a6595SJonathan Cameron 		.owner = THIS_MODULE,
1604f3a6595SJonathan Cameron 	},
1614f3a6595SJonathan Cameron 	.probe = ad7314_probe,
1629e5e9b7aSBill Pemberton 	.remove = ad7314_remove,
1634f3a6595SJonathan Cameron 	.id_table = ad7314_id,
1644f3a6595SJonathan Cameron };
1654f3a6595SJonathan Cameron 
16691efffe2SAxel Lin module_spi_driver(ad7314_driver);
1674f3a6595SJonathan Cameron 
1684f3a6595SJonathan Cameron MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
169b55f3757SGuenter Roeck MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital temperature sensor driver");
1704f3a6595SJonathan Cameron MODULE_LICENSE("GPL v2");
171