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