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