[go: nahoru, domu]

17924425db04a6107e49312edf53c158590d52aaeSonic Zhang/*
27924425db04a6107e49312edf53c158590d52aaeSonic Zhang * AD7816 digital temperature sensor driver supporting AD7816/7/8
37924425db04a6107e49312edf53c158590d52aaeSonic Zhang *
47924425db04a6107e49312edf53c158590d52aaeSonic Zhang * Copyright 2010 Analog Devices Inc.
57924425db04a6107e49312edf53c158590d52aaeSonic Zhang *
67924425db04a6107e49312edf53c158590d52aaeSonic Zhang * Licensed under the GPL-2 or later.
77924425db04a6107e49312edf53c158590d52aaeSonic Zhang */
87924425db04a6107e49312edf53c158590d52aaeSonic Zhang
97924425db04a6107e49312edf53c158590d52aaeSonic Zhang#include <linux/interrupt.h>
107924425db04a6107e49312edf53c158590d52aaeSonic Zhang#include <linux/gpio.h>
117924425db04a6107e49312edf53c158590d52aaeSonic Zhang#include <linux/device.h>
127924425db04a6107e49312edf53c158590d52aaeSonic Zhang#include <linux/kernel.h>
137924425db04a6107e49312edf53c158590d52aaeSonic Zhang#include <linux/slab.h>
147924425db04a6107e49312edf53c158590d52aaeSonic Zhang#include <linux/sysfs.h>
157924425db04a6107e49312edf53c158590d52aaeSonic Zhang#include <linux/list.h>
167924425db04a6107e49312edf53c158590d52aaeSonic Zhang#include <linux/spi/spi.h>
1799c978529a40132a6f7a5f136b4362b56fc88d8cPaul Gortmaker#include <linux/module.h>
187924425db04a6107e49312edf53c158590d52aaeSonic Zhang
1906458e277eac2b8761b0a04d3c808d57be281a2eJonathan Cameron#include <linux/iio/iio.h>
2006458e277eac2b8761b0a04d3c808d57be281a2eJonathan Cameron#include <linux/iio/sysfs.h>
2106458e277eac2b8761b0a04d3c808d57be281a2eJonathan Cameron#include <linux/iio/events.h>
227924425db04a6107e49312edf53c158590d52aaeSonic Zhang
237924425db04a6107e49312edf53c158590d52aaeSonic Zhang/*
247924425db04a6107e49312edf53c158590d52aaeSonic Zhang * AD7816 config masks
257924425db04a6107e49312edf53c158590d52aaeSonic Zhang */
267924425db04a6107e49312edf53c158590d52aaeSonic Zhang#define AD7816_FULL			0x1
277924425db04a6107e49312edf53c158590d52aaeSonic Zhang#define AD7816_PD			0x2
287924425db04a6107e49312edf53c158590d52aaeSonic Zhang#define AD7816_CS_MASK			0x7
297924425db04a6107e49312edf53c158590d52aaeSonic Zhang#define AD7816_CS_MAX			0x4
307924425db04a6107e49312edf53c158590d52aaeSonic Zhang
317924425db04a6107e49312edf53c158590d52aaeSonic Zhang/*
327924425db04a6107e49312edf53c158590d52aaeSonic Zhang * AD7816 temperature masks
337924425db04a6107e49312edf53c158590d52aaeSonic Zhang */
347924425db04a6107e49312edf53c158590d52aaeSonic Zhang#define AD7816_VALUE_OFFSET		6
357924425db04a6107e49312edf53c158590d52aaeSonic Zhang#define AD7816_BOUND_VALUE_BASE		0x8
367924425db04a6107e49312edf53c158590d52aaeSonic Zhang#define AD7816_BOUND_VALUE_MIN		-95
377924425db04a6107e49312edf53c158590d52aaeSonic Zhang#define AD7816_BOUND_VALUE_MAX		152
387924425db04a6107e49312edf53c158590d52aaeSonic Zhang#define AD7816_TEMP_FLOAT_OFFSET	2
397924425db04a6107e49312edf53c158590d52aaeSonic Zhang#define AD7816_TEMP_FLOAT_MASK		0x3
407924425db04a6107e49312edf53c158590d52aaeSonic Zhang
417924425db04a6107e49312edf53c158590d52aaeSonic Zhang
427924425db04a6107e49312edf53c158590d52aaeSonic Zhang/*
43e3c5be2bdae553ddefacc636496f2df21aee31eeMasanari Iida * struct ad7816_chip_info - chip specific information
447924425db04a6107e49312edf53c158590d52aaeSonic Zhang */
457924425db04a6107e49312edf53c158590d52aaeSonic Zhang
467924425db04a6107e49312edf53c158590d52aaeSonic Zhangstruct ad7816_chip_info {
477924425db04a6107e49312edf53c158590d52aaeSonic Zhang	struct spi_device *spi_dev;
487924425db04a6107e49312edf53c158590d52aaeSonic Zhang	u16 rdwr_pin;
497924425db04a6107e49312edf53c158590d52aaeSonic Zhang	u16 convert_pin;
507924425db04a6107e49312edf53c158590d52aaeSonic Zhang	u16 busy_pin;
517924425db04a6107e49312edf53c158590d52aaeSonic Zhang	u8  oti_data[AD7816_CS_MAX+1];
527924425db04a6107e49312edf53c158590d52aaeSonic Zhang	u8  channel_id;	/* 0 always be temperature */
537924425db04a6107e49312edf53c158590d52aaeSonic Zhang	u8  mode;
547924425db04a6107e49312edf53c158590d52aaeSonic Zhang};
557924425db04a6107e49312edf53c158590d52aaeSonic Zhang
567924425db04a6107e49312edf53c158590d52aaeSonic Zhang/*
577924425db04a6107e49312edf53c158590d52aaeSonic Zhang * ad7816 data access by SPI
587924425db04a6107e49312edf53c158590d52aaeSonic Zhang */
597924425db04a6107e49312edf53c158590d52aaeSonic Zhangstatic int ad7816_spi_read(struct ad7816_chip_info *chip, u16 *data)
607924425db04a6107e49312edf53c158590d52aaeSonic Zhang{
617924425db04a6107e49312edf53c158590d52aaeSonic Zhang	struct spi_device *spi_dev = chip->spi_dev;
627924425db04a6107e49312edf53c158590d52aaeSonic Zhang	int ret = 0;
637924425db04a6107e49312edf53c158590d52aaeSonic Zhang
647924425db04a6107e49312edf53c158590d52aaeSonic Zhang	gpio_set_value(chip->rdwr_pin, 1);
657924425db04a6107e49312edf53c158590d52aaeSonic Zhang	gpio_set_value(chip->rdwr_pin, 0);
667924425db04a6107e49312edf53c158590d52aaeSonic Zhang	ret = spi_write(spi_dev, &chip->channel_id, sizeof(chip->channel_id));
677924425db04a6107e49312edf53c158590d52aaeSonic Zhang	if (ret < 0) {
687924425db04a6107e49312edf53c158590d52aaeSonic Zhang		dev_err(&spi_dev->dev, "SPI channel setting error\n");
697924425db04a6107e49312edf53c158590d52aaeSonic Zhang		return ret;
707924425db04a6107e49312edf53c158590d52aaeSonic Zhang	}
717924425db04a6107e49312edf53c158590d52aaeSonic Zhang	gpio_set_value(chip->rdwr_pin, 1);
727924425db04a6107e49312edf53c158590d52aaeSonic Zhang
737924425db04a6107e49312edf53c158590d52aaeSonic Zhang
747924425db04a6107e49312edf53c158590d52aaeSonic Zhang	if (chip->mode == AD7816_PD) { /* operating mode 2 */
757924425db04a6107e49312edf53c158590d52aaeSonic Zhang		gpio_set_value(chip->convert_pin, 1);
767924425db04a6107e49312edf53c158590d52aaeSonic Zhang		gpio_set_value(chip->convert_pin, 0);
777924425db04a6107e49312edf53c158590d52aaeSonic Zhang	} else { /* operating mode 1 */
787924425db04a6107e49312edf53c158590d52aaeSonic Zhang		gpio_set_value(chip->convert_pin, 0);
797924425db04a6107e49312edf53c158590d52aaeSonic Zhang		gpio_set_value(chip->convert_pin, 1);
807924425db04a6107e49312edf53c158590d52aaeSonic Zhang	}
817924425db04a6107e49312edf53c158590d52aaeSonic Zhang
827924425db04a6107e49312edf53c158590d52aaeSonic Zhang	while (gpio_get_value(chip->busy_pin))
837924425db04a6107e49312edf53c158590d52aaeSonic Zhang		cpu_relax();
847924425db04a6107e49312edf53c158590d52aaeSonic Zhang
857924425db04a6107e49312edf53c158590d52aaeSonic Zhang	gpio_set_value(chip->rdwr_pin, 0);
867924425db04a6107e49312edf53c158590d52aaeSonic Zhang	gpio_set_value(chip->rdwr_pin, 1);
877924425db04a6107e49312edf53c158590d52aaeSonic Zhang	ret = spi_read(spi_dev, (u8 *)data, sizeof(*data));
887924425db04a6107e49312edf53c158590d52aaeSonic Zhang	if (ret < 0) {
897924425db04a6107e49312edf53c158590d52aaeSonic Zhang		dev_err(&spi_dev->dev, "SPI data read error\n");
907924425db04a6107e49312edf53c158590d52aaeSonic Zhang		return ret;
917924425db04a6107e49312edf53c158590d52aaeSonic Zhang	}
927924425db04a6107e49312edf53c158590d52aaeSonic Zhang
937924425db04a6107e49312edf53c158590d52aaeSonic Zhang	*data = be16_to_cpu(*data);
947924425db04a6107e49312edf53c158590d52aaeSonic Zhang
957924425db04a6107e49312edf53c158590d52aaeSonic Zhang	return ret;
967924425db04a6107e49312edf53c158590d52aaeSonic Zhang}
977924425db04a6107e49312edf53c158590d52aaeSonic Zhang
987924425db04a6107e49312edf53c158590d52aaeSonic Zhangstatic int ad7816_spi_write(struct ad7816_chip_info *chip, u8 data)
997924425db04a6107e49312edf53c158590d52aaeSonic Zhang{
1007924425db04a6107e49312edf53c158590d52aaeSonic Zhang	struct spi_device *spi_dev = chip->spi_dev;
1017924425db04a6107e49312edf53c158590d52aaeSonic Zhang	int ret = 0;
1027924425db04a6107e49312edf53c158590d52aaeSonic Zhang
1037924425db04a6107e49312edf53c158590d52aaeSonic Zhang	gpio_set_value(chip->rdwr_pin, 1);
1047924425db04a6107e49312edf53c158590d52aaeSonic Zhang	gpio_set_value(chip->rdwr_pin, 0);
1057924425db04a6107e49312edf53c158590d52aaeSonic Zhang	ret = spi_write(spi_dev, &data, sizeof(data));
1067924425db04a6107e49312edf53c158590d52aaeSonic Zhang	if (ret < 0)
1077924425db04a6107e49312edf53c158590d52aaeSonic Zhang		dev_err(&spi_dev->dev, "SPI oti data write error\n");
1087924425db04a6107e49312edf53c158590d52aaeSonic Zhang
1097924425db04a6107e49312edf53c158590d52aaeSonic Zhang	return ret;
1107924425db04a6107e49312edf53c158590d52aaeSonic Zhang}
1117924425db04a6107e49312edf53c158590d52aaeSonic Zhang
1127924425db04a6107e49312edf53c158590d52aaeSonic Zhangstatic ssize_t ad7816_show_mode(struct device *dev,
1137924425db04a6107e49312edf53c158590d52aaeSonic Zhang		struct device_attribute *attr,
1147924425db04a6107e49312edf53c158590d52aaeSonic Zhang		char *buf)
1157924425db04a6107e49312edf53c158590d52aaeSonic Zhang{
11662c5183971428a559b687fcb15f548df28dbe8dcLars-Peter Clausen	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
11784f79ecb0c1f39393b96e1401d4e8a1d498f3613Jonathan Cameron	struct ad7816_chip_info *chip = iio_priv(indio_dev);
1187924425db04a6107e49312edf53c158590d52aaeSonic Zhang
1197924425db04a6107e49312edf53c158590d52aaeSonic Zhang	if (chip->mode)
1207924425db04a6107e49312edf53c158590d52aaeSonic Zhang		return sprintf(buf, "power-save\n");
121da96aecdc59d086926d49becd981acab8d98bb9aVaishali Thakkar	return sprintf(buf, "full\n");
1227924425db04a6107e49312edf53c158590d52aaeSonic Zhang}
1237924425db04a6107e49312edf53c158590d52aaeSonic Zhang
1247924425db04a6107e49312edf53c158590d52aaeSonic Zhangstatic ssize_t ad7816_store_mode(struct device *dev,
1257924425db04a6107e49312edf53c158590d52aaeSonic Zhang		struct device_attribute *attr,
1267924425db04a6107e49312edf53c158590d52aaeSonic Zhang		const char *buf,
1277924425db04a6107e49312edf53c158590d52aaeSonic Zhang		size_t len)
1287924425db04a6107e49312edf53c158590d52aaeSonic Zhang{
12962c5183971428a559b687fcb15f548df28dbe8dcLars-Peter Clausen	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
13084f79ecb0c1f39393b96e1401d4e8a1d498f3613Jonathan Cameron	struct ad7816_chip_info *chip = iio_priv(indio_dev);
1317924425db04a6107e49312edf53c158590d52aaeSonic Zhang
1327924425db04a6107e49312edf53c158590d52aaeSonic Zhang	if (strcmp(buf, "full")) {
1337924425db04a6107e49312edf53c158590d52aaeSonic Zhang		gpio_set_value(chip->rdwr_pin, 1);
1347924425db04a6107e49312edf53c158590d52aaeSonic Zhang		chip->mode = AD7816_FULL;
1357924425db04a6107e49312edf53c158590d52aaeSonic Zhang	} else {
1367924425db04a6107e49312edf53c158590d52aaeSonic Zhang		gpio_set_value(chip->rdwr_pin, 0);
1377924425db04a6107e49312edf53c158590d52aaeSonic Zhang		chip->mode = AD7816_PD;
1387924425db04a6107e49312edf53c158590d52aaeSonic Zhang	}
1397924425db04a6107e49312edf53c158590d52aaeSonic Zhang
1407924425db04a6107e49312edf53c158590d52aaeSonic Zhang	return len;
1417924425db04a6107e49312edf53c158590d52aaeSonic Zhang}
1427924425db04a6107e49312edf53c158590d52aaeSonic Zhang
1437924425db04a6107e49312edf53c158590d52aaeSonic Zhangstatic IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
1447924425db04a6107e49312edf53c158590d52aaeSonic Zhang		ad7816_show_mode,
1457924425db04a6107e49312edf53c158590d52aaeSonic Zhang		ad7816_store_mode,
1467924425db04a6107e49312edf53c158590d52aaeSonic Zhang		0);
1477924425db04a6107e49312edf53c158590d52aaeSonic Zhang
1487924425db04a6107e49312edf53c158590d52aaeSonic Zhangstatic ssize_t ad7816_show_available_modes(struct device *dev,
1497924425db04a6107e49312edf53c158590d52aaeSonic Zhang		struct device_attribute *attr,
1507924425db04a6107e49312edf53c158590d52aaeSonic Zhang		char *buf)
1517924425db04a6107e49312edf53c158590d52aaeSonic Zhang{
1527924425db04a6107e49312edf53c158590d52aaeSonic Zhang	return sprintf(buf, "full\npower-save\n");
1537924425db04a6107e49312edf53c158590d52aaeSonic Zhang}
1547924425db04a6107e49312edf53c158590d52aaeSonic Zhang
1557924425db04a6107e49312edf53c158590d52aaeSonic Zhangstatic IIO_DEVICE_ATTR(available_modes, S_IRUGO, ad7816_show_available_modes, NULL, 0);
1567924425db04a6107e49312edf53c158590d52aaeSonic Zhang
1577924425db04a6107e49312edf53c158590d52aaeSonic Zhangstatic ssize_t ad7816_show_channel(struct device *dev,
1587924425db04a6107e49312edf53c158590d52aaeSonic Zhang		struct device_attribute *attr,
1597924425db04a6107e49312edf53c158590d52aaeSonic Zhang		char *buf)
1607924425db04a6107e49312edf53c158590d52aaeSonic Zhang{
16162c5183971428a559b687fcb15f548df28dbe8dcLars-Peter Clausen	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
16284f79ecb0c1f39393b96e1401d4e8a1d498f3613Jonathan Cameron	struct ad7816_chip_info *chip = iio_priv(indio_dev);
1637924425db04a6107e49312edf53c158590d52aaeSonic Zhang
1647924425db04a6107e49312edf53c158590d52aaeSonic Zhang	return sprintf(buf, "%d\n", chip->channel_id);
1657924425db04a6107e49312edf53c158590d52aaeSonic Zhang}
1667924425db04a6107e49312edf53c158590d52aaeSonic Zhang
1677924425db04a6107e49312edf53c158590d52aaeSonic Zhangstatic ssize_t ad7816_store_channel(struct device *dev,
1687924425db04a6107e49312edf53c158590d52aaeSonic Zhang		struct device_attribute *attr,
1697924425db04a6107e49312edf53c158590d52aaeSonic Zhang		const char *buf,
1707924425db04a6107e49312edf53c158590d52aaeSonic Zhang		size_t len)
1717924425db04a6107e49312edf53c158590d52aaeSonic Zhang{
17262c5183971428a559b687fcb15f548df28dbe8dcLars-Peter Clausen	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
17384f79ecb0c1f39393b96e1401d4e8a1d498f3613Jonathan Cameron	struct ad7816_chip_info *chip = iio_priv(indio_dev);
1747924425db04a6107e49312edf53c158590d52aaeSonic Zhang	unsigned long data;
1757924425db04a6107e49312edf53c158590d52aaeSonic Zhang	int ret;
1767924425db04a6107e49312edf53c158590d52aaeSonic Zhang
177f86f83622fe2c45d75f83a7db8d170da55b5b476Aida Mynzhasova	ret = kstrtoul(buf, 10, &data);
1787924425db04a6107e49312edf53c158590d52aaeSonic Zhang	if (ret)
179f86f83622fe2c45d75f83a7db8d170da55b5b476Aida Mynzhasova		return ret;
1807924425db04a6107e49312edf53c158590d52aaeSonic Zhang
1817924425db04a6107e49312edf53c158590d52aaeSonic Zhang	if (data > AD7816_CS_MAX && data != AD7816_CS_MASK) {
1827924425db04a6107e49312edf53c158590d52aaeSonic Zhang		dev_err(&chip->spi_dev->dev, "Invalid channel id %lu for %s.\n",
18384f79ecb0c1f39393b96e1401d4e8a1d498f3613Jonathan Cameron			data, indio_dev->name);
1847924425db04a6107e49312edf53c158590d52aaeSonic Zhang		return -EINVAL;
18584f79ecb0c1f39393b96e1401d4e8a1d498f3613Jonathan Cameron	} else if (strcmp(indio_dev->name, "ad7818") == 0 && data > 1) {
1867924425db04a6107e49312edf53c158590d52aaeSonic Zhang		dev_err(&chip->spi_dev->dev,
1877924425db04a6107e49312edf53c158590d52aaeSonic Zhang			"Invalid channel id %lu for ad7818.\n", data);
1887924425db04a6107e49312edf53c158590d52aaeSonic Zhang		return -EINVAL;
18984f79ecb0c1f39393b96e1401d4e8a1d498f3613Jonathan Cameron	} else if (strcmp(indio_dev->name, "ad7816") == 0 && data > 0) {
1907924425db04a6107e49312edf53c158590d52aaeSonic Zhang		dev_err(&chip->spi_dev->dev,
1917924425db04a6107e49312edf53c158590d52aaeSonic Zhang			"Invalid channel id %lu for ad7816.\n", data);
1927924425db04a6107e49312edf53c158590d52aaeSonic Zhang		return -EINVAL;
1937924425db04a6107e49312edf53c158590d52aaeSonic Zhang	}
1947924425db04a6107e49312edf53c158590d52aaeSonic Zhang
1957924425db04a6107e49312edf53c158590d52aaeSonic Zhang	chip->channel_id = data;
1967924425db04a6107e49312edf53c158590d52aaeSonic Zhang
1977924425db04a6107e49312edf53c158590d52aaeSonic Zhang	return len;
1987924425db04a6107e49312edf53c158590d52aaeSonic Zhang}
1997924425db04a6107e49312edf53c158590d52aaeSonic Zhang
2007924425db04a6107e49312edf53c158590d52aaeSonic Zhangstatic IIO_DEVICE_ATTR(channel, S_IRUGO | S_IWUSR,
2017924425db04a6107e49312edf53c158590d52aaeSonic Zhang		ad7816_show_channel,
2027924425db04a6107e49312edf53c158590d52aaeSonic Zhang		ad7816_store_channel,
2037924425db04a6107e49312edf53c158590d52aaeSonic Zhang		0);
2047924425db04a6107e49312edf53c158590d52aaeSonic Zhang
2057924425db04a6107e49312edf53c158590d52aaeSonic Zhang
2067924425db04a6107e49312edf53c158590d52aaeSonic Zhangstatic ssize_t ad7816_show_value(struct device *dev,
2077924425db04a6107e49312edf53c158590d52aaeSonic Zhang		struct device_attribute *attr,
2087924425db04a6107e49312edf53c158590d52aaeSonic Zhang		char *buf)
2097924425db04a6107e49312edf53c158590d52aaeSonic Zhang{
21062c5183971428a559b687fcb15f548df28dbe8dcLars-Peter Clausen	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
21184f79ecb0c1f39393b96e1401d4e8a1d498f3613Jonathan Cameron	struct ad7816_chip_info *chip = iio_priv(indio_dev);
2127924425db04a6107e49312edf53c158590d52aaeSonic Zhang	u16 data;
2137924425db04a6107e49312edf53c158590d52aaeSonic Zhang	s8 value;
2147924425db04a6107e49312edf53c158590d52aaeSonic Zhang	int ret;
2157924425db04a6107e49312edf53c158590d52aaeSonic Zhang
2167924425db04a6107e49312edf53c158590d52aaeSonic Zhang	ret = ad7816_spi_read(chip, &data);
2177924425db04a6107e49312edf53c158590d52aaeSonic Zhang	if (ret)
2187924425db04a6107e49312edf53c158590d52aaeSonic Zhang		return -EIO;
2197924425db04a6107e49312edf53c158590d52aaeSonic Zhang
2207924425db04a6107e49312edf53c158590d52aaeSonic Zhang	data >>= AD7816_VALUE_OFFSET;
2217924425db04a6107e49312edf53c158590d52aaeSonic Zhang
2227924425db04a6107e49312edf53c158590d52aaeSonic Zhang	if (chip->channel_id == 0) {
2237924425db04a6107e49312edf53c158590d52aaeSonic Zhang		value = (s8)((data >> AD7816_TEMP_FLOAT_OFFSET) - 103);
2247924425db04a6107e49312edf53c158590d52aaeSonic Zhang		data &= AD7816_TEMP_FLOAT_MASK;
2257924425db04a6107e49312edf53c158590d52aaeSonic Zhang		if (value < 0)
2267924425db04a6107e49312edf53c158590d52aaeSonic Zhang			data = (1 << AD7816_TEMP_FLOAT_OFFSET) - data;
2277924425db04a6107e49312edf53c158590d52aaeSonic Zhang		return sprintf(buf, "%d.%.2d\n", value, data * 25);
228da96aecdc59d086926d49becd981acab8d98bb9aVaishali Thakkar	}
229da96aecdc59d086926d49becd981acab8d98bb9aVaishali Thakkar	return sprintf(buf, "%u\n", data);
2307924425db04a6107e49312edf53c158590d52aaeSonic Zhang}
2317924425db04a6107e49312edf53c158590d52aaeSonic Zhang
2327924425db04a6107e49312edf53c158590d52aaeSonic Zhangstatic IIO_DEVICE_ATTR(value, S_IRUGO, ad7816_show_value, NULL, 0);
2337924425db04a6107e49312edf53c158590d52aaeSonic Zhang
2347924425db04a6107e49312edf53c158590d52aaeSonic Zhangstatic struct attribute *ad7816_attributes[] = {
2357924425db04a6107e49312edf53c158590d52aaeSonic Zhang	&iio_dev_attr_available_modes.dev_attr.attr,
2367924425db04a6107e49312edf53c158590d52aaeSonic Zhang	&iio_dev_attr_mode.dev_attr.attr,
2377924425db04a6107e49312edf53c158590d52aaeSonic Zhang	&iio_dev_attr_channel.dev_attr.attr,
2387924425db04a6107e49312edf53c158590d52aaeSonic Zhang	&iio_dev_attr_value.dev_attr.attr,
2397924425db04a6107e49312edf53c158590d52aaeSonic Zhang	NULL,
2407924425db04a6107e49312edf53c158590d52aaeSonic Zhang};
2417924425db04a6107e49312edf53c158590d52aaeSonic Zhang
2427924425db04a6107e49312edf53c158590d52aaeSonic Zhangstatic const struct attribute_group ad7816_attribute_group = {
2437924425db04a6107e49312edf53c158590d52aaeSonic Zhang	.attrs = ad7816_attributes,
2447924425db04a6107e49312edf53c158590d52aaeSonic Zhang};
2457924425db04a6107e49312edf53c158590d52aaeSonic Zhang
2467924425db04a6107e49312edf53c158590d52aaeSonic Zhang/*
2477924425db04a6107e49312edf53c158590d52aaeSonic Zhang * temperature bound events
2487924425db04a6107e49312edf53c158590d52aaeSonic Zhang */
2497924425db04a6107e49312edf53c158590d52aaeSonic Zhang
250c4b14d99bbc93c9fa03b5934a07e95594efe7a93Jonathan Cameron#define IIO_EVENT_CODE_AD7816_OTI IIO_UNMOD_EVENT_CODE(IIO_TEMP,	\
2510bb8be643161ae1dc5c5a0255cf5ca20f7de7b5aJonathan Cameron						       0,		\
2520bb8be643161ae1dc5c5a0255cf5ca20f7de7b5aJonathan Cameron						       IIO_EV_TYPE_THRESH, \
2530bb8be643161ae1dc5c5a0255cf5ca20f7de7b5aJonathan Cameron						       IIO_EV_DIR_FALLING)
2547924425db04a6107e49312edf53c158590d52aaeSonic Zhang
255db9afe2fc0c59f84bc1950b9b78767bbcdc80f13Jonathan Cameronstatic irqreturn_t ad7816_event_handler(int irq, void *private)
2567924425db04a6107e49312edf53c158590d52aaeSonic Zhang{
2575aa9618896e0ba49b444731f9fafa7f7c18a13abJonathan Cameron	iio_push_event(private, IIO_EVENT_CODE_AD7816_OTI, iio_get_time_ns());
258db9afe2fc0c59f84bc1950b9b78767bbcdc80f13Jonathan Cameron	return IRQ_HANDLED;
2597924425db04a6107e49312edf53c158590d52aaeSonic Zhang}
2607924425db04a6107e49312edf53c158590d52aaeSonic Zhang
2617924425db04a6107e49312edf53c158590d52aaeSonic Zhangstatic ssize_t ad7816_show_oti(struct device *dev,
2627924425db04a6107e49312edf53c158590d52aaeSonic Zhang		struct device_attribute *attr,
2637924425db04a6107e49312edf53c158590d52aaeSonic Zhang		char *buf)
2647924425db04a6107e49312edf53c158590d52aaeSonic Zhang{
26562c5183971428a559b687fcb15f548df28dbe8dcLars-Peter Clausen	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
26684f79ecb0c1f39393b96e1401d4e8a1d498f3613Jonathan Cameron	struct ad7816_chip_info *chip = iio_priv(indio_dev);
2677924425db04a6107e49312edf53c158590d52aaeSonic Zhang	int value;
2687924425db04a6107e49312edf53c158590d52aaeSonic Zhang
2697924425db04a6107e49312edf53c158590d52aaeSonic Zhang	if (chip->channel_id > AD7816_CS_MAX) {
2707924425db04a6107e49312edf53c158590d52aaeSonic Zhang		dev_err(dev, "Invalid oti channel id %d.\n", chip->channel_id);
2717924425db04a6107e49312edf53c158590d52aaeSonic Zhang		return -EINVAL;
2727924425db04a6107e49312edf53c158590d52aaeSonic Zhang	} else if (chip->channel_id == 0) {
2737924425db04a6107e49312edf53c158590d52aaeSonic Zhang		value = AD7816_BOUND_VALUE_MIN +
2747924425db04a6107e49312edf53c158590d52aaeSonic Zhang			(chip->oti_data[chip->channel_id] -
2757924425db04a6107e49312edf53c158590d52aaeSonic Zhang			AD7816_BOUND_VALUE_BASE);
2767924425db04a6107e49312edf53c158590d52aaeSonic Zhang		return sprintf(buf, "%d\n", value);
277da96aecdc59d086926d49becd981acab8d98bb9aVaishali Thakkar	}
278da96aecdc59d086926d49becd981acab8d98bb9aVaishali Thakkar	return sprintf(buf, "%u\n", chip->oti_data[chip->channel_id]);
2797924425db04a6107e49312edf53c158590d52aaeSonic Zhang}
2807924425db04a6107e49312edf53c158590d52aaeSonic Zhang
2817924425db04a6107e49312edf53c158590d52aaeSonic Zhangstatic inline ssize_t ad7816_set_oti(struct device *dev,
2827924425db04a6107e49312edf53c158590d52aaeSonic Zhang		struct device_attribute *attr,
2837924425db04a6107e49312edf53c158590d52aaeSonic Zhang		const char *buf,
2847924425db04a6107e49312edf53c158590d52aaeSonic Zhang		size_t len)
2857924425db04a6107e49312edf53c158590d52aaeSonic Zhang{
28662c5183971428a559b687fcb15f548df28dbe8dcLars-Peter Clausen	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
28784f79ecb0c1f39393b96e1401d4e8a1d498f3613Jonathan Cameron	struct ad7816_chip_info *chip = iio_priv(indio_dev);
2887924425db04a6107e49312edf53c158590d52aaeSonic Zhang	long value;
2897924425db04a6107e49312edf53c158590d52aaeSonic Zhang	u8 data;
2907924425db04a6107e49312edf53c158590d52aaeSonic Zhang	int ret;
2917924425db04a6107e49312edf53c158590d52aaeSonic Zhang
292f86f83622fe2c45d75f83a7db8d170da55b5b476Aida Mynzhasova	ret = kstrtol(buf, 10, &value);
293f86f83622fe2c45d75f83a7db8d170da55b5b476Aida Mynzhasova	if (ret)
294f86f83622fe2c45d75f83a7db8d170da55b5b476Aida Mynzhasova		return ret;
2957924425db04a6107e49312edf53c158590d52aaeSonic Zhang
2967924425db04a6107e49312edf53c158590d52aaeSonic Zhang	if (chip->channel_id > AD7816_CS_MAX) {
2977924425db04a6107e49312edf53c158590d52aaeSonic Zhang		dev_err(dev, "Invalid oti channel id %d.\n", chip->channel_id);
2987924425db04a6107e49312edf53c158590d52aaeSonic Zhang		return -EINVAL;
2997924425db04a6107e49312edf53c158590d52aaeSonic Zhang	} else if (chip->channel_id == 0) {
3007924425db04a6107e49312edf53c158590d52aaeSonic Zhang		if (ret || value < AD7816_BOUND_VALUE_MIN ||
3017924425db04a6107e49312edf53c158590d52aaeSonic Zhang			value > AD7816_BOUND_VALUE_MAX)
3027924425db04a6107e49312edf53c158590d52aaeSonic Zhang			return -EINVAL;
3037924425db04a6107e49312edf53c158590d52aaeSonic Zhang
3047924425db04a6107e49312edf53c158590d52aaeSonic Zhang		data = (u8)(value - AD7816_BOUND_VALUE_MIN +
3057924425db04a6107e49312edf53c158590d52aaeSonic Zhang			AD7816_BOUND_VALUE_BASE);
3067924425db04a6107e49312edf53c158590d52aaeSonic Zhang	} else {
3077924425db04a6107e49312edf53c158590d52aaeSonic Zhang		if (ret || value < AD7816_BOUND_VALUE_BASE || value > 255)
3087924425db04a6107e49312edf53c158590d52aaeSonic Zhang			return -EINVAL;
3097924425db04a6107e49312edf53c158590d52aaeSonic Zhang
3107924425db04a6107e49312edf53c158590d52aaeSonic Zhang		data = (u8)value;
3117924425db04a6107e49312edf53c158590d52aaeSonic Zhang	}
3127924425db04a6107e49312edf53c158590d52aaeSonic Zhang
3137924425db04a6107e49312edf53c158590d52aaeSonic Zhang	ret = ad7816_spi_write(chip, data);
3147924425db04a6107e49312edf53c158590d52aaeSonic Zhang	if (ret)
3157924425db04a6107e49312edf53c158590d52aaeSonic Zhang		return -EIO;
3167924425db04a6107e49312edf53c158590d52aaeSonic Zhang
3177924425db04a6107e49312edf53c158590d52aaeSonic Zhang	chip->oti_data[chip->channel_id] = data;
3187924425db04a6107e49312edf53c158590d52aaeSonic Zhang
3197924425db04a6107e49312edf53c158590d52aaeSonic Zhang	return len;
3207924425db04a6107e49312edf53c158590d52aaeSonic Zhang}
3217924425db04a6107e49312edf53c158590d52aaeSonic Zhang
322db9afe2fc0c59f84bc1950b9b78767bbcdc80f13Jonathan Cameronstatic IIO_DEVICE_ATTR(oti, S_IRUGO | S_IWUSR,
323db9afe2fc0c59f84bc1950b9b78767bbcdc80f13Jonathan Cameron		       ad7816_show_oti, ad7816_set_oti, 0);
3247924425db04a6107e49312edf53c158590d52aaeSonic Zhang
3257924425db04a6107e49312edf53c158590d52aaeSonic Zhangstatic struct attribute *ad7816_event_attributes[] = {
326db9afe2fc0c59f84bc1950b9b78767bbcdc80f13Jonathan Cameron	&iio_dev_attr_oti.dev_attr.attr,
3277924425db04a6107e49312edf53c158590d52aaeSonic Zhang	NULL,
3287924425db04a6107e49312edf53c158590d52aaeSonic Zhang};
3297924425db04a6107e49312edf53c158590d52aaeSonic Zhang
3307924425db04a6107e49312edf53c158590d52aaeSonic Zhangstatic struct attribute_group ad7816_event_attribute_group = {
3317924425db04a6107e49312edf53c158590d52aaeSonic Zhang	.attrs = ad7816_event_attributes,
3328e7d967244a8eebcdadb048efc5e66849ec0a6b6Jonathan Cameron	.name = "events",
3337924425db04a6107e49312edf53c158590d52aaeSonic Zhang};
3347924425db04a6107e49312edf53c158590d52aaeSonic Zhang
3356fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameronstatic const struct iio_info ad7816_info = {
3366fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron	.attrs = &ad7816_attribute_group,
3376fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron	.event_attrs = &ad7816_event_attribute_group,
3386fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron	.driver_module = THIS_MODULE,
3396fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron};
3406fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron
3417924425db04a6107e49312edf53c158590d52aaeSonic Zhang/*
3427924425db04a6107e49312edf53c158590d52aaeSonic Zhang * device probe and remove
3437924425db04a6107e49312edf53c158590d52aaeSonic Zhang */
3447924425db04a6107e49312edf53c158590d52aaeSonic Zhang
3454ae1c61ff2ba4fea4e4c1a045cb1f34520608789Bill Pembertonstatic int ad7816_probe(struct spi_device *spi_dev)
3467924425db04a6107e49312edf53c158590d52aaeSonic Zhang{
3477924425db04a6107e49312edf53c158590d52aaeSonic Zhang	struct ad7816_chip_info *chip;
348b0011d6dbae18af3e4bc52670e542abc688eb5a2Jonathan Cameron	struct iio_dev *indio_dev;
3497924425db04a6107e49312edf53c158590d52aaeSonic Zhang	unsigned short *pins = spi_dev->dev.platform_data;
3507924425db04a6107e49312edf53c158590d52aaeSonic Zhang	int ret = 0;
3517924425db04a6107e49312edf53c158590d52aaeSonic Zhang	int i;
3527924425db04a6107e49312edf53c158590d52aaeSonic Zhang
3537924425db04a6107e49312edf53c158590d52aaeSonic Zhang	if (!pins) {
3547924425db04a6107e49312edf53c158590d52aaeSonic Zhang		dev_err(&spi_dev->dev, "No necessary GPIO platform data.\n");
3557924425db04a6107e49312edf53c158590d52aaeSonic Zhang		return -EINVAL;
3567924425db04a6107e49312edf53c158590d52aaeSonic Zhang	}
3577924425db04a6107e49312edf53c158590d52aaeSonic Zhang
358e5bf4f5b7d95ff7e6359df7845047dd9e6df6f3eSachin Kamat	indio_dev = devm_iio_device_alloc(&spi_dev->dev, sizeof(*chip));
359e5bf4f5b7d95ff7e6359df7845047dd9e6df6f3eSachin Kamat	if (!indio_dev)
360e5bf4f5b7d95ff7e6359df7845047dd9e6df6f3eSachin Kamat		return -ENOMEM;
361b0011d6dbae18af3e4bc52670e542abc688eb5a2Jonathan Cameron	chip = iio_priv(indio_dev);
3627924425db04a6107e49312edf53c158590d52aaeSonic Zhang	/* this is only used for device removal purposes */
363b0011d6dbae18af3e4bc52670e542abc688eb5a2Jonathan Cameron	dev_set_drvdata(&spi_dev->dev, indio_dev);
3647924425db04a6107e49312edf53c158590d52aaeSonic Zhang
3657924425db04a6107e49312edf53c158590d52aaeSonic Zhang	chip->spi_dev = spi_dev;
3667924425db04a6107e49312edf53c158590d52aaeSonic Zhang	for (i = 0; i <= AD7816_CS_MAX; i++)
3677924425db04a6107e49312edf53c158590d52aaeSonic Zhang		chip->oti_data[i] = 203;
3687924425db04a6107e49312edf53c158590d52aaeSonic Zhang	chip->rdwr_pin = pins[0];
3697924425db04a6107e49312edf53c158590d52aaeSonic Zhang	chip->convert_pin = pins[1];
3707924425db04a6107e49312edf53c158590d52aaeSonic Zhang	chip->busy_pin = pins[2];
3717924425db04a6107e49312edf53c158590d52aaeSonic Zhang
372e5bf4f5b7d95ff7e6359df7845047dd9e6df6f3eSachin Kamat	ret = devm_gpio_request(&spi_dev->dev, chip->rdwr_pin,
373e5bf4f5b7d95ff7e6359df7845047dd9e6df6f3eSachin Kamat					spi_get_device_id(spi_dev)->name);
3747924425db04a6107e49312edf53c158590d52aaeSonic Zhang	if (ret) {
3757924425db04a6107e49312edf53c158590d52aaeSonic Zhang		dev_err(&spi_dev->dev, "Fail to request rdwr gpio PIN %d.\n",
3767924425db04a6107e49312edf53c158590d52aaeSonic Zhang			chip->rdwr_pin);
377e5bf4f5b7d95ff7e6359df7845047dd9e6df6f3eSachin Kamat		return ret;
3787924425db04a6107e49312edf53c158590d52aaeSonic Zhang	}
3797924425db04a6107e49312edf53c158590d52aaeSonic Zhang	gpio_direction_input(chip->rdwr_pin);
380e5bf4f5b7d95ff7e6359df7845047dd9e6df6f3eSachin Kamat	ret = devm_gpio_request(&spi_dev->dev, chip->convert_pin,
381e5bf4f5b7d95ff7e6359df7845047dd9e6df6f3eSachin Kamat					spi_get_device_id(spi_dev)->name);
3827924425db04a6107e49312edf53c158590d52aaeSonic Zhang	if (ret) {
3837924425db04a6107e49312edf53c158590d52aaeSonic Zhang		dev_err(&spi_dev->dev, "Fail to request convert gpio PIN %d.\n",
3847924425db04a6107e49312edf53c158590d52aaeSonic Zhang			chip->convert_pin);
385e5bf4f5b7d95ff7e6359df7845047dd9e6df6f3eSachin Kamat		return ret;
3867924425db04a6107e49312edf53c158590d52aaeSonic Zhang	}
3877924425db04a6107e49312edf53c158590d52aaeSonic Zhang	gpio_direction_input(chip->convert_pin);
388e5bf4f5b7d95ff7e6359df7845047dd9e6df6f3eSachin Kamat	ret = devm_gpio_request(&spi_dev->dev, chip->busy_pin,
389e5bf4f5b7d95ff7e6359df7845047dd9e6df6f3eSachin Kamat					spi_get_device_id(spi_dev)->name);
3907924425db04a6107e49312edf53c158590d52aaeSonic Zhang	if (ret) {
3917924425db04a6107e49312edf53c158590d52aaeSonic Zhang		dev_err(&spi_dev->dev, "Fail to request busy gpio PIN %d.\n",
3927924425db04a6107e49312edf53c158590d52aaeSonic Zhang			chip->busy_pin);
393e5bf4f5b7d95ff7e6359df7845047dd9e6df6f3eSachin Kamat		return ret;
3947924425db04a6107e49312edf53c158590d52aaeSonic Zhang	}
3957924425db04a6107e49312edf53c158590d52aaeSonic Zhang	gpio_direction_input(chip->busy_pin);
3967924425db04a6107e49312edf53c158590d52aaeSonic Zhang
397b0011d6dbae18af3e4bc52670e542abc688eb5a2Jonathan Cameron	indio_dev->name = spi_get_device_id(spi_dev)->name;
398b0011d6dbae18af3e4bc52670e542abc688eb5a2Jonathan Cameron	indio_dev->dev.parent = &spi_dev->dev;
399b0011d6dbae18af3e4bc52670e542abc688eb5a2Jonathan Cameron	indio_dev->info = &ad7816_info;
400b0011d6dbae18af3e4bc52670e542abc688eb5a2Jonathan Cameron	indio_dev->modes = INDIO_DIRECT_MODE;
4017924425db04a6107e49312edf53c158590d52aaeSonic Zhang
4027924425db04a6107e49312edf53c158590d52aaeSonic Zhang	if (spi_dev->irq) {
4037924425db04a6107e49312edf53c158590d52aaeSonic Zhang		/* Only low trigger is supported in ad7816/7/8 */
404e5bf4f5b7d95ff7e6359df7845047dd9e6df6f3eSachin Kamat		ret = devm_request_threaded_irq(&spi_dev->dev, spi_dev->irq,
405e5bf4f5b7d95ff7e6359df7845047dd9e6df6f3eSachin Kamat						NULL,
406e5bf4f5b7d95ff7e6359df7845047dd9e6df6f3eSachin Kamat						&ad7816_event_handler,
407e5bf4f5b7d95ff7e6359df7845047dd9e6df6f3eSachin Kamat						IRQF_TRIGGER_LOW | IRQF_ONESHOT,
408e5bf4f5b7d95ff7e6359df7845047dd9e6df6f3eSachin Kamat						indio_dev->name,
409e5bf4f5b7d95ff7e6359df7845047dd9e6df6f3eSachin Kamat						indio_dev);
4107924425db04a6107e49312edf53c158590d52aaeSonic Zhang		if (ret)
411e5bf4f5b7d95ff7e6359df7845047dd9e6df6f3eSachin Kamat			return ret;
4127924425db04a6107e49312edf53c158590d52aaeSonic Zhang	}
4137924425db04a6107e49312edf53c158590d52aaeSonic Zhang
4145404dc77266e3159486bd89a482d11e80a3b173eSachin Kamat	ret = devm_iio_device_register(&spi_dev->dev, indio_dev);
41526d25ae3f0d8ffe350aacc75b71198d6b35bd1f4Jonathan Cameron	if (ret)
416e5bf4f5b7d95ff7e6359df7845047dd9e6df6f3eSachin Kamat		return ret;
41726d25ae3f0d8ffe350aacc75b71198d6b35bd1f4Jonathan Cameron
4187924425db04a6107e49312edf53c158590d52aaeSonic Zhang	dev_info(&spi_dev->dev, "%s temperature sensor and ADC registered.\n",
419b0011d6dbae18af3e4bc52670e542abc688eb5a2Jonathan Cameron			 indio_dev->name);
4207924425db04a6107e49312edf53c158590d52aaeSonic Zhang
4217924425db04a6107e49312edf53c158590d52aaeSonic Zhang	return 0;
4227924425db04a6107e49312edf53c158590d52aaeSonic Zhang}
4237924425db04a6107e49312edf53c158590d52aaeSonic Zhang
4247924425db04a6107e49312edf53c158590d52aaeSonic Zhangstatic const struct spi_device_id ad7816_id[] = {
4257924425db04a6107e49312edf53c158590d52aaeSonic Zhang	{ "ad7816", 0 },
4267924425db04a6107e49312edf53c158590d52aaeSonic Zhang	{ "ad7817", 0 },
4277924425db04a6107e49312edf53c158590d52aaeSonic Zhang	{ "ad7818", 0 },
4287924425db04a6107e49312edf53c158590d52aaeSonic Zhang	{}
4297924425db04a6107e49312edf53c158590d52aaeSonic Zhang};
4307924425db04a6107e49312edf53c158590d52aaeSonic Zhang
4317924425db04a6107e49312edf53c158590d52aaeSonic ZhangMODULE_DEVICE_TABLE(spi, ad7816_id);
4327924425db04a6107e49312edf53c158590d52aaeSonic Zhang
4337924425db04a6107e49312edf53c158590d52aaeSonic Zhangstatic struct spi_driver ad7816_driver = {
4347924425db04a6107e49312edf53c158590d52aaeSonic Zhang	.driver = {
4357924425db04a6107e49312edf53c158590d52aaeSonic Zhang		.name = "ad7816",
4367924425db04a6107e49312edf53c158590d52aaeSonic Zhang		.owner = THIS_MODULE,
4377924425db04a6107e49312edf53c158590d52aaeSonic Zhang	},
4387924425db04a6107e49312edf53c158590d52aaeSonic Zhang	.probe = ad7816_probe,
4397924425db04a6107e49312edf53c158590d52aaeSonic Zhang	.id_table = ad7816_id,
4407924425db04a6107e49312edf53c158590d52aaeSonic Zhang};
441ae6ae6fec3f7d6919e0146996df37b665c75f662Lars-Peter Clausenmodule_spi_driver(ad7816_driver);
4427924425db04a6107e49312edf53c158590d52aaeSonic Zhang
4437924425db04a6107e49312edf53c158590d52aaeSonic ZhangMODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
44426cfea9e0e4034c29f9a64d91af213d9974aa123Darshana PadmadasMODULE_DESCRIPTION("Analog Devices AD7816/7/8 digital temperature sensor driver");
4457924425db04a6107e49312edf53c158590d52aaeSonic ZhangMODULE_LICENSE("GPL v2");
446