root/drivers/staging/iio/addac/adt7316.c
// SPDX-License-Identifier: GPL-2.0+
/*
 * ADT7316 digital temperature sensor driver supporting ADT7316/7/8 ADT7516/7/9
 *
 * Copyright 2010 Analog Devices Inc.
 */

#include <linux/interrupt.h>
#include <linux/gpio/consumer.h>
#include <linux/irq.h>
#include <linux/workqueue.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
#include <linux/i2c.h>
#include <linux/rtc.h>
#include <linux/module.h>

#include <linux/iio/iio.h>
#include <linux/iio/events.h>
#include <linux/iio/sysfs.h>
#include "adt7316.h"

/*
 * ADT7316 registers definition
 */
#define ADT7316_INT_STAT1               0x0
#define ADT7316_INT_STAT2               0x1
#define ADT7316_LSB_IN_TEMP_VDD         0x3
#define ADT7316_LSB_IN_TEMP_MASK        0x3
#define ADT7316_LSB_VDD_MASK            0xC
#define ADT7316_LSB_VDD_OFFSET          2
#define ADT7316_LSB_EX_TEMP_AIN         0x4
#define ADT7316_LSB_EX_TEMP_MASK        0x3
#define ADT7516_LSB_AIN_SHIFT           2
#define ADT7316_AD_MSB_DATA_BASE        0x6
#define ADT7316_AD_MSB_DATA_REGS        3
#define ADT7516_AD_MSB_DATA_REGS        6
#define ADT7316_MSB_VDD                 0x6
#define ADT7316_MSB_IN_TEMP             0x7
#define ADT7316_MSB_EX_TEMP             0x8
#define ADT7516_MSB_AIN1                0x8
#define ADT7516_MSB_AIN2                0x9
#define ADT7516_MSB_AIN3                0xA
#define ADT7516_MSB_AIN4                0xB
#define ADT7316_DA_DATA_BASE            0x10
#define ADT7316_DA_10_BIT_LSB_SHIFT     6
#define ADT7316_DA_12_BIT_LSB_SHIFT     4
#define ADT7316_DA_MSB_DATA_REGS        4
#define ADT7316_LSB_DAC_A               0x10
#define ADT7316_MSB_DAC_A               0x11
#define ADT7316_LSB_DAC_B               0x12
#define ADT7316_MSB_DAC_B               0x13
#define ADT7316_LSB_DAC_C               0x14
#define ADT7316_MSB_DAC_C               0x15
#define ADT7316_LSB_DAC_D               0x16
#define ADT7316_MSB_DAC_D               0x17
#define ADT7316_CONFIG1                 0x18
#define ADT7316_CONFIG2                 0x19
#define ADT7316_CONFIG3                 0x1A
#define ADT7316_DAC_CONFIG              0x1B
#define ADT7316_LDAC_CONFIG             0x1C
#define ADT7316_INT_MASK1               0x1D
#define ADT7316_INT_MASK2               0x1E
#define ADT7316_IN_TEMP_OFFSET          0x1F
#define ADT7316_EX_TEMP_OFFSET          0x20
#define ADT7316_IN_ANALOG_TEMP_OFFSET   0x21
#define ADT7316_EX_ANALOG_TEMP_OFFSET   0x22
#define ADT7316_VDD_HIGH                0x23
#define ADT7316_VDD_LOW                 0x24
#define ADT7316_IN_TEMP_HIGH            0x25
#define ADT7316_IN_TEMP_LOW             0x26
#define ADT7316_EX_TEMP_HIGH            0x27
#define ADT7316_EX_TEMP_LOW             0x28
#define ADT7516_AIN2_HIGH               0x2B
#define ADT7516_AIN2_LOW                0x2C
#define ADT7516_AIN3_HIGH               0x2D
#define ADT7516_AIN3_LOW                0x2E
#define ADT7516_AIN4_HIGH               0x2F
#define ADT7516_AIN4_LOW                0x30
#define ADT7316_DEVICE_ID               0x4D
#define ADT7316_MANUFACTURE_ID          0x4E
#define ADT7316_DEVICE_REV              0x4F
#define ADT7316_SPI_LOCK_STAT           0x7F

/*
 * ADT7316 config1
 */
#define ADT7316_EN                      0x1
#define ADT7516_SEL_EX_TEMP             0x4
#define ADT7516_SEL_AIN1_2_EX_TEMP_MASK 0x6
#define ADT7516_SEL_AIN3                0x8
#define ADT7316_INT_EN                  0x20
#define ADT7316_INT_POLARITY            0x40
#define ADT7316_PD                      0x80

/*
 * ADT7316 config2
 */
#define ADT7316_AD_SINGLE_CH_MASK       0x3
#define ADT7516_AD_SINGLE_CH_MASK       0x7
#define ADT7316_AD_SINGLE_CH_VDD        0
#define ADT7316_AD_SINGLE_CH_IN         1
#define ADT7316_AD_SINGLE_CH_EX         2
#define ADT7516_AD_SINGLE_CH_AIN1       2
#define ADT7516_AD_SINGLE_CH_AIN2       3
#define ADT7516_AD_SINGLE_CH_AIN3       4
#define ADT7516_AD_SINGLE_CH_AIN4       5
#define ADT7316_AD_SINGLE_CH_MODE       0x10
#define ADT7316_DISABLE_AVERAGING       0x20
#define ADT7316_EN_SMBUS_TIMEOUT        0x40
#define ADT7316_RESET                   0x80

/*
 * ADT7316 config3
 */
#define ADT7316_ADCLK_22_5              0x1
#define ADT7316_DA_HIGH_RESOLUTION      0x2
#define ADT7316_DA_EN_VIA_DAC_LDAC      0x8
#define ADT7516_AIN_IN_VREF             0x10
#define ADT7316_EN_IN_TEMP_PROP_DACA    0x20
#define ADT7316_EN_EX_TEMP_PROP_DACB    0x40

/*
 * ADT7316 DAC config
 */
#define ADT7316_DA_2VREF_CH_MASK        0xF
#define ADT7316_DA_EN_MODE_MASK         0x30
#define ADT7316_DA_EN_MODE_SHIFT        4
#define ADT7316_DA_EN_MODE_SINGLE       0x00
#define ADT7316_DA_EN_MODE_AB_CD        0x10
#define ADT7316_DA_EN_MODE_ABCD         0x20
#define ADT7316_DA_EN_MODE_LDAC         0x30
#define ADT7316_VREF_BYPASS_DAC_AB      0x40
#define ADT7316_VREF_BYPASS_DAC_CD      0x80

/*
 * ADT7316 LDAC config
 */
#define ADT7316_LDAC_EN_DA_MASK         0xF
#define ADT7316_DAC_IN_VREF             0x10
#define ADT7516_DAC_AB_IN_VREF          0x10
#define ADT7516_DAC_CD_IN_VREF          0x20
#define ADT7516_DAC_IN_VREF_OFFSET      4
#define ADT7516_DAC_IN_VREF_MASK        0x30

/*
 * ADT7316 INT_MASK2
 */
#define ADT7316_INT_MASK2_VDD           0x10

/*
 * ADT7316 value masks
 */
#define ADT7316_VALUE_MASK              0xfff
#define ADT7316_T_VALUE_SIGN            0x400
#define ADT7316_T_VALUE_FLOAT_OFFSET    2
#define ADT7316_T_VALUE_FLOAT_MASK      0x2

/*
 * Chip ID
 */
#define ID_ADT7316              0x1
#define ID_ADT7317              0x2
#define ID_ADT7318              0x3
#define ID_ADT7516              0x11
#define ID_ADT7517              0x12
#define ID_ADT7519              0x14

#define ID_FAMILY_MASK          0xF0
#define ID_ADT73XX              0x0
#define ID_ADT75XX              0x10

/*
 * struct adt7316_chip_info - chip specific information
 */

struct adt7316_chip_info {
        struct adt7316_bus      bus;
        struct gpio_desc        *ldac_pin;
        u16                     int_mask;       /* 0x2f */
        u8                      config1;
        u8                      config2;
        u8                      config3;
        u8                      dac_config;     /* DAC config */
        u8                      ldac_config;    /* LDAC config */
        u8                      dac_bits;       /* 8, 10, 12 */
        u8                      id;             /* chip id */
};

/*
 * Logic interrupt mask for user application to enable
 * interrupts.
 */
#define ADT7316_IN_TEMP_HIGH_INT_MASK   0x1
#define ADT7316_IN_TEMP_LOW_INT_MASK    0x2
#define ADT7316_EX_TEMP_HIGH_INT_MASK   0x4
#define ADT7316_EX_TEMP_LOW_INT_MASK    0x8
#define ADT7316_EX_TEMP_FAULT_INT_MASK  0x10
#define ADT7516_AIN1_INT_MASK           0x4
#define ADT7516_AIN2_INT_MASK           0x20
#define ADT7516_AIN3_INT_MASK           0x40
#define ADT7516_AIN4_INT_MASK           0x80
#define ADT7316_VDD_INT_MASK            0x100
#define ADT7316_TEMP_INT_MASK           0x1F
#define ADT7516_AIN_INT_MASK            0xE0
#define ADT7316_TEMP_AIN_INT_MASK       \
        (ADT7316_TEMP_INT_MASK)

static ssize_t adt7316_show_enabled(struct device *dev,
                                    struct device_attribute *attr,
                                    char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return sysfs_emit(buf, "%d\n", !!(chip->config1 & ADT7316_EN));
}

static ssize_t _adt7316_store_enabled(struct adt7316_chip_info *chip,
                                      int enable)
{
        u8 config1;
        int ret;

        if (enable)
                config1 = chip->config1 | ADT7316_EN;
        else
                config1 = chip->config1 & ~ADT7316_EN;

        ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1);
        if (ret)
                return -EIO;

        chip->config1 = config1;

        return ret;
}

static ssize_t adt7316_store_enabled(struct device *dev,
                                     struct device_attribute *attr,
                                     const char *buf,
                                     size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        int enable;

        if (buf[0] == '1')
                enable = 1;
        else
                enable = 0;

        if (_adt7316_store_enabled(chip, enable) < 0)
                return -EIO;

        return len;
}

static IIO_DEVICE_ATTR(enabled, 0644,
                adt7316_show_enabled,
                adt7316_store_enabled,
                0);

static ssize_t adt7316_show_select_ex_temp(struct device *dev,
                                           struct device_attribute *attr,
                                           char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
                return -EPERM;

        return sysfs_emit(buf, "%d\n", !!(chip->config1 & ADT7516_SEL_EX_TEMP));
}

static ssize_t adt7316_store_select_ex_temp(struct device *dev,
                                            struct device_attribute *attr,
                                            const char *buf,
                                            size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 config1;
        int ret;

        if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
                return -EPERM;

        config1 = chip->config1 & (~ADT7516_SEL_EX_TEMP);
        if (buf[0] == '1')
                config1 |= ADT7516_SEL_EX_TEMP;

        ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1);
        if (ret)
                return -EIO;

        chip->config1 = config1;

        return len;
}

static IIO_DEVICE_ATTR(select_ex_temp, 0644,
                adt7316_show_select_ex_temp,
                adt7316_store_select_ex_temp,
                0);

static ssize_t adt7316_show_mode(struct device *dev,
                                 struct device_attribute *attr,
                                 char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        if (chip->config2 & ADT7316_AD_SINGLE_CH_MODE)
                return sysfs_emit(buf, "single_channel\n");

        return sysfs_emit(buf, "round_robin\n");
}

static ssize_t adt7316_store_mode(struct device *dev,
                                  struct device_attribute *attr,
                                  const char *buf,
                                  size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 config2;
        int ret;

        config2 = chip->config2 & (~ADT7316_AD_SINGLE_CH_MODE);
        if (!memcmp(buf, "single_channel", 14))
                config2 |= ADT7316_AD_SINGLE_CH_MODE;

        ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
        if (ret)
                return -EIO;

        chip->config2 = config2;

        return len;
}

static IIO_DEVICE_ATTR(mode, 0644,
                adt7316_show_mode,
                adt7316_store_mode,
                0);

static ssize_t adt7316_show_all_modes(struct device *dev,
                                      struct device_attribute *attr,
                                      char *buf)
{
        return sysfs_emit(buf, "single_channel\nround_robin\n");
}

static IIO_DEVICE_ATTR(all_modes, 0444, adt7316_show_all_modes, NULL, 0);

static ssize_t adt7316_show_ad_channel(struct device *dev,
                                       struct device_attribute *attr,
                                       char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE))
                return -EPERM;

        switch (chip->config2 & ADT7516_AD_SINGLE_CH_MASK) {
        case ADT7316_AD_SINGLE_CH_VDD:
                return sysfs_emit(buf, "0 - VDD\n");
        case ADT7316_AD_SINGLE_CH_IN:
                return sysfs_emit(buf, "1 - Internal Temperature\n");
        case ADT7316_AD_SINGLE_CH_EX:
                if (((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) &&
                    (chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0)
                        return sysfs_emit(buf, "2 - AIN1\n");

                return sysfs_emit(buf, "2 - External Temperature\n");
        case ADT7516_AD_SINGLE_CH_AIN2:
                if ((chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0)
                        return sysfs_emit(buf, "3 - AIN2\n");

                return sysfs_emit(buf, "N/A\n");
        case ADT7516_AD_SINGLE_CH_AIN3:
                if (chip->config1 & ADT7516_SEL_AIN3)
                        return sysfs_emit(buf, "4 - AIN3\n");

                return sysfs_emit(buf, "N/A\n");
        case ADT7516_AD_SINGLE_CH_AIN4:
                return sysfs_emit(buf, "5 - AIN4\n");
        default:
                return sysfs_emit(buf, "N/A\n");
        }
}

static ssize_t adt7316_store_ad_channel(struct device *dev,
                                        struct device_attribute *attr,
                                        const char *buf,
                                        size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 config2;
        u8 data;
        int ret;

        if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE))
                return -EPERM;

        ret = kstrtou8(buf, 10, &data);
        if (ret)
                return -EINVAL;

        if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) {
                if (data > 5)
                        return -EINVAL;

                config2 = chip->config2 & (~ADT7516_AD_SINGLE_CH_MASK);
        } else {
                if (data > 2)
                        return -EINVAL;

                config2 = chip->config2 & (~ADT7316_AD_SINGLE_CH_MASK);
        }

        config2 |= data;

        ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
        if (ret)
                return -EIO;

        chip->config2 = config2;

        return len;
}

static IIO_DEVICE_ATTR(ad_channel, 0644,
                adt7316_show_ad_channel,
                adt7316_store_ad_channel,
                0);

static ssize_t adt7316_show_all_ad_channels(struct device *dev,
                                            struct device_attribute *attr,
                                            char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE))
                return -EPERM;

        if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
                return sysfs_emit(buf, "0 - VDD\n1 - Internal Temperature\n"
                                "2 - External Temperature or AIN1\n"
                                "3 - AIN2\n4 - AIN3\n5 - AIN4\n");
        return sysfs_emit(buf, "0 - VDD\n1 - Internal Temperature\n"
                        "2 - External Temperature\n");
}

static IIO_DEVICE_ATTR(all_ad_channels, 0444,
                adt7316_show_all_ad_channels, NULL, 0);

static ssize_t adt7316_show_disable_averaging(struct device *dev,
                                              struct device_attribute *attr,
                                              char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return sysfs_emit(buf, "%d\n",
                !!(chip->config2 & ADT7316_DISABLE_AVERAGING));
}

static ssize_t adt7316_store_disable_averaging(struct device *dev,
                                               struct device_attribute *attr,
                                               const char *buf,
                                               size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 config2;
        int ret;

        config2 = chip->config2 & (~ADT7316_DISABLE_AVERAGING);
        if (buf[0] == '1')
                config2 |= ADT7316_DISABLE_AVERAGING;

        ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
        if (ret)
                return -EIO;

        chip->config2 = config2;

        return len;
}

static IIO_DEVICE_ATTR(disable_averaging, 0644,
                adt7316_show_disable_averaging,
                adt7316_store_disable_averaging,
                0);

static ssize_t adt7316_show_enable_smbus_timeout(struct device *dev,
                                                 struct device_attribute *attr,
                                                 char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return sysfs_emit(buf, "%d\n",
                !!(chip->config2 & ADT7316_EN_SMBUS_TIMEOUT));
}

static ssize_t adt7316_store_enable_smbus_timeout(struct device *dev,
                                                  struct device_attribute *attr,
                                                  const char *buf,
                                                  size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 config2;
        int ret;

        config2 = chip->config2 & (~ADT7316_EN_SMBUS_TIMEOUT);
        if (buf[0] == '1')
                config2 |= ADT7316_EN_SMBUS_TIMEOUT;

        ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
        if (ret)
                return -EIO;

        chip->config2 = config2;

        return len;
}

static IIO_DEVICE_ATTR(enable_smbus_timeout, 0644,
                adt7316_show_enable_smbus_timeout,
                adt7316_store_enable_smbus_timeout,
                0);

static ssize_t adt7316_show_powerdown(struct device *dev,
                                      struct device_attribute *attr,
                                      char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return sysfs_emit(buf, "%d\n", !!(chip->config1 & ADT7316_PD));
}

static ssize_t adt7316_store_powerdown(struct device *dev,
                                       struct device_attribute *attr,
                                       const char *buf,
                                       size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 config1;
        int ret;

        config1 = chip->config1 & (~ADT7316_PD);
        if (buf[0] == '1')
                config1 |= ADT7316_PD;

        ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1);
        if (ret)
                return -EIO;

        chip->config1 = config1;

        return len;
}

static IIO_DEVICE_ATTR(powerdown, 0644,
                adt7316_show_powerdown,
                adt7316_store_powerdown,
                0);

static ssize_t adt7316_show_fast_ad_clock(struct device *dev,
                                          struct device_attribute *attr,
                                          char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return sysfs_emit(buf, "%d\n", !!(chip->config3 & ADT7316_ADCLK_22_5));
}

static ssize_t adt7316_store_fast_ad_clock(struct device *dev,
                                           struct device_attribute *attr,
                                           const char *buf,
                                           size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 config3;
        int ret;

        config3 = chip->config3 & (~ADT7316_ADCLK_22_5);
        if (buf[0] == '1')
                config3 |= ADT7316_ADCLK_22_5;

        ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3);
        if (ret)
                return -EIO;

        chip->config3 = config3;

        return len;
}

static IIO_DEVICE_ATTR(fast_ad_clock, 0644,
                adt7316_show_fast_ad_clock,
                adt7316_store_fast_ad_clock,
                0);

static ssize_t adt7316_show_da_high_resolution(struct device *dev,
                                               struct device_attribute *attr,
                                               char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        if (chip->config3 & ADT7316_DA_HIGH_RESOLUTION) {
                if (chip->id != ID_ADT7318 && chip->id != ID_ADT7519)
                        return sysfs_emit(buf, "1 (10 bits)\n");
        }

        return sysfs_emit(buf, "0 (8 bits)\n");
}

static ssize_t adt7316_store_da_high_resolution(struct device *dev,
                                                struct device_attribute *attr,
                                                const char *buf,
                                                size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 config3;
        int ret;

        if (chip->id == ID_ADT7318 || chip->id == ID_ADT7519)
                return -EPERM;

        config3 = chip->config3 & (~ADT7316_DA_HIGH_RESOLUTION);
        if (buf[0] == '1')
                config3 |= ADT7316_DA_HIGH_RESOLUTION;

        ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3);
        if (ret)
                return -EIO;

        chip->config3 = config3;

        return len;
}

static IIO_DEVICE_ATTR(da_high_resolution, 0644,
                adt7316_show_da_high_resolution,
                adt7316_store_da_high_resolution,
                0);

static ssize_t adt7316_show_AIN_internal_Vref(struct device *dev,
                                              struct device_attribute *attr,
                                              char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
                return -EPERM;

        return sysfs_emit(buf, "%d\n",
                !!(chip->config3 & ADT7516_AIN_IN_VREF));
}

static ssize_t adt7316_store_AIN_internal_Vref(struct device *dev,
                                               struct device_attribute *attr,
                                               const char *buf,
                                               size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 config3;
        int ret;

        if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
                return -EPERM;

        if (buf[0] != '1')
                config3 = chip->config3 & (~ADT7516_AIN_IN_VREF);
        else
                config3 = chip->config3 | ADT7516_AIN_IN_VREF;

        ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3);
        if (ret)
                return -EIO;

        chip->config3 = config3;

        return len;
}

static IIO_DEVICE_ATTR(AIN_internal_Vref, 0644,
                adt7316_show_AIN_internal_Vref,
                adt7316_store_AIN_internal_Vref,
                0);

static ssize_t adt7316_show_enable_prop_DACA(struct device *dev,
                                             struct device_attribute *attr,
                                             char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return sysfs_emit(buf, "%d\n",
                !!(chip->config3 & ADT7316_EN_IN_TEMP_PROP_DACA));
}

static ssize_t adt7316_store_enable_prop_DACA(struct device *dev,
                                              struct device_attribute *attr,
                                              const char *buf,
                                              size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 config3;
        int ret;

        config3 = chip->config3 & (~ADT7316_EN_IN_TEMP_PROP_DACA);
        if (buf[0] == '1')
                config3 |= ADT7316_EN_IN_TEMP_PROP_DACA;

        ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3);
        if (ret)
                return -EIO;

        chip->config3 = config3;

        return len;
}

static IIO_DEVICE_ATTR(enable_proportion_DACA, 0644,
                       adt7316_show_enable_prop_DACA,
                       adt7316_store_enable_prop_DACA,
                       0);

static ssize_t adt7316_show_enable_prop_DACB(struct device *dev,
                                             struct device_attribute *attr,
                                             char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return sysfs_emit(buf, "%d\n",
                !!(chip->config3 & ADT7316_EN_EX_TEMP_PROP_DACB));
}

static ssize_t adt7316_store_enable_prop_DACB(struct device *dev,
                                              struct device_attribute *attr,
                                              const char *buf,
                                              size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 config3;
        int ret;

        config3 = chip->config3 & (~ADT7316_EN_EX_TEMP_PROP_DACB);
        if (buf[0] == '1')
                config3 |= ADT7316_EN_EX_TEMP_PROP_DACB;

        ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3);
        if (ret)
                return -EIO;

        chip->config3 = config3;

        return len;
}

static IIO_DEVICE_ATTR(enable_proportion_DACB, 0644,
                       adt7316_show_enable_prop_DACB,
                       adt7316_store_enable_prop_DACB,
                       0);

static ssize_t adt7316_show_DAC_2Vref_ch_mask(struct device *dev,
                                              struct device_attribute *attr,
                                              char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return sysfs_emit(buf, "0x%x\n",
                chip->dac_config & ADT7316_DA_2VREF_CH_MASK);
}

static ssize_t adt7316_store_DAC_2Vref_ch_mask(struct device *dev,
                                               struct device_attribute *attr,
                                               const char *buf,
                                               size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 dac_config;
        u8 data;
        int ret;

        ret = kstrtou8(buf, 16, &data);
        if (ret || data > ADT7316_DA_2VREF_CH_MASK)
                return -EINVAL;

        dac_config = chip->dac_config & (~ADT7316_DA_2VREF_CH_MASK);
        dac_config |= data;

        ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config);
        if (ret)
                return -EIO;

        chip->dac_config = dac_config;

        return len;
}

static IIO_DEVICE_ATTR(DAC_2Vref_channels_mask, 0644,
                       adt7316_show_DAC_2Vref_ch_mask,
                       adt7316_store_DAC_2Vref_ch_mask,
                       0);

static ssize_t adt7316_show_DAC_update_mode(struct device *dev,
                                            struct device_attribute *attr,
                                            char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDAC))
                return sysfs_emit(buf, "manual\n");

        switch (chip->dac_config & ADT7316_DA_EN_MODE_MASK) {
        case ADT7316_DA_EN_MODE_SINGLE:
                return sysfs_emit(buf,
                        "0 - auto at any MSB DAC writing\n");
        case ADT7316_DA_EN_MODE_AB_CD:
                return sysfs_emit(buf,
                        "1 - auto at MSB DAC AB and CD writing\n");
        case ADT7316_DA_EN_MODE_ABCD:
                return sysfs_emit(buf,
                        "2 - auto at MSB DAC ABCD writing\n");
        default: /* ADT7316_DA_EN_MODE_LDAC */
                return sysfs_emit(buf, "3 - manual\n");
        }
}

static ssize_t adt7316_store_DAC_update_mode(struct device *dev,
                                             struct device_attribute *attr,
                                             const char *buf,
                                             size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 dac_config;
        u8 data;
        int ret;

        if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDAC))
                return -EPERM;

        ret = kstrtou8(buf, 10, &data);
        if (ret || data > (ADT7316_DA_EN_MODE_MASK >> ADT7316_DA_EN_MODE_SHIFT))
                return -EINVAL;

        dac_config = chip->dac_config & (~ADT7316_DA_EN_MODE_MASK);
        dac_config |= data << ADT7316_DA_EN_MODE_SHIFT;

        ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config);
        if (ret)
                return -EIO;

        chip->dac_config = dac_config;

        return len;
}

static IIO_DEVICE_ATTR(DAC_update_mode, 0644,
                       adt7316_show_DAC_update_mode,
                       adt7316_store_DAC_update_mode,
                       0);

static ssize_t adt7316_show_all_DAC_update_modes(struct device *dev,
                                                 struct device_attribute *attr,
                                                 char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDAC)
                return sysfs_emit(buf, "0 - auto at any MSB DAC writing\n"
                                "1 - auto at MSB DAC AB and CD writing\n"
                                "2 - auto at MSB DAC ABCD writing\n"
                                "3 - manual\n");
        return sysfs_emit(buf, "manual\n");
}

static IIO_DEVICE_ATTR(all_DAC_update_modes, 0444,
                       adt7316_show_all_DAC_update_modes, NULL, 0);

static ssize_t adt7316_store_update_DAC(struct device *dev,
                                        struct device_attribute *attr,
                                        const char *buf,
                                        size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 ldac_config;
        u8 data;
        int ret;

        if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDAC) {
                if ((chip->dac_config & ADT7316_DA_EN_MODE_MASK) !=
                        ADT7316_DA_EN_MODE_LDAC)
                        return -EPERM;

                ret = kstrtou8(buf, 16, &data);
                if (ret || data > ADT7316_LDAC_EN_DA_MASK)
                        return -EINVAL;

                ldac_config = chip->ldac_config & (~ADT7316_LDAC_EN_DA_MASK);
                ldac_config |= data;

                ret = chip->bus.write(chip->bus.client, ADT7316_LDAC_CONFIG,
                        ldac_config);
                if (ret)
                        return -EIO;
        } else {
                gpiod_set_value(chip->ldac_pin, 0);
                gpiod_set_value(chip->ldac_pin, 1);
        }

        return len;
}

static IIO_DEVICE_ATTR(update_DAC, 0644,
                       NULL,
                       adt7316_store_update_DAC,
                       0);

static ssize_t adt7316_show_DA_AB_Vref_bypass(struct device *dev,
                                              struct device_attribute *attr,
                                              char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return sysfs_emit(buf, "%d\n",
                !!(chip->dac_config & ADT7316_VREF_BYPASS_DAC_AB));
}

static ssize_t adt7316_store_DA_AB_Vref_bypass(struct device *dev,
                                               struct device_attribute *attr,
                                               const char *buf,
                                               size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 dac_config;
        int ret;

        dac_config = chip->dac_config & (~ADT7316_VREF_BYPASS_DAC_AB);
        if (buf[0] == '1')
                dac_config |= ADT7316_VREF_BYPASS_DAC_AB;

        ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config);
        if (ret)
                return -EIO;

        chip->dac_config = dac_config;

        return len;
}

static IIO_DEVICE_ATTR(DA_AB_Vref_bypass, 0644,
                       adt7316_show_DA_AB_Vref_bypass,
                       adt7316_store_DA_AB_Vref_bypass,
                       0);

static ssize_t adt7316_show_DA_CD_Vref_bypass(struct device *dev,
                                              struct device_attribute *attr,
                                              char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return sysfs_emit(buf, "%d\n",
                !!(chip->dac_config & ADT7316_VREF_BYPASS_DAC_CD));
}

static ssize_t adt7316_store_DA_CD_Vref_bypass(struct device *dev,
                                               struct device_attribute *attr,
                                               const char *buf,
                                               size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 dac_config;
        int ret;

        dac_config = chip->dac_config & (~ADT7316_VREF_BYPASS_DAC_CD);
        if (buf[0] == '1')
                dac_config |= ADT7316_VREF_BYPASS_DAC_CD;

        ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config);
        if (ret)
                return -EIO;

        chip->dac_config = dac_config;

        return len;
}

static IIO_DEVICE_ATTR(DA_CD_Vref_bypass, 0644,
                       adt7316_show_DA_CD_Vref_bypass,
                       adt7316_store_DA_CD_Vref_bypass,
                       0);

static ssize_t adt7316_show_DAC_internal_Vref(struct device *dev,
                                              struct device_attribute *attr,
                                              char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
                return sysfs_emit(buf, "0x%x\n",
                        (chip->ldac_config & ADT7516_DAC_IN_VREF_MASK) >>
                        ADT7516_DAC_IN_VREF_OFFSET);
        return sysfs_emit(buf, "%d\n",
                       !!(chip->ldac_config & ADT7316_DAC_IN_VREF));
}

static ssize_t adt7316_store_DAC_internal_Vref(struct device *dev,
                                               struct device_attribute *attr,
                                               const char *buf,
                                               size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 ldac_config;
        u8 data;
        int ret;

        if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) {
                ret = kstrtou8(buf, 16, &data);
                if (ret || data > 3)
                        return -EINVAL;

                ldac_config = chip->ldac_config & (~ADT7516_DAC_IN_VREF_MASK);
                if (data & 0x1)
                        ldac_config |= ADT7516_DAC_AB_IN_VREF;
                if (data & 0x2)
                        ldac_config |= ADT7516_DAC_CD_IN_VREF;
        } else {
                ret = kstrtou8(buf, 16, &data);
                if (ret)
                        return -EINVAL;

                ldac_config = chip->ldac_config & (~ADT7316_DAC_IN_VREF);
                if (data)
                        ldac_config = chip->ldac_config | ADT7316_DAC_IN_VREF;
        }

        ret = chip->bus.write(chip->bus.client, ADT7316_LDAC_CONFIG,
                        ldac_config);
        if (ret)
                return -EIO;

        chip->ldac_config = ldac_config;

        return len;
}

static IIO_DEVICE_ATTR(DAC_internal_Vref, 0644,
                       adt7316_show_DAC_internal_Vref,
                       adt7316_store_DAC_internal_Vref,
                       0);

static ssize_t adt7316_show_ad(struct adt7316_chip_info *chip,
                               int channel, char *buf)
{
        u16 data;
        u8 msb, lsb;
        char sign = ' ';
        int ret;

        if ((chip->config2 & ADT7316_AD_SINGLE_CH_MODE) &&
            channel != (chip->config2 & ADT7516_AD_SINGLE_CH_MASK))
                return -EPERM;

        switch (channel) {
        case ADT7316_AD_SINGLE_CH_IN:
                ret = chip->bus.read(chip->bus.client,
                        ADT7316_LSB_IN_TEMP_VDD, &lsb);
                if (ret)
                        return -EIO;

                ret = chip->bus.read(chip->bus.client,
                        ADT7316_AD_MSB_DATA_BASE + channel, &msb);
                if (ret)
                        return -EIO;

                data = msb << ADT7316_T_VALUE_FLOAT_OFFSET;
                data |= lsb & ADT7316_LSB_IN_TEMP_MASK;
                break;
        case ADT7316_AD_SINGLE_CH_VDD:
                ret = chip->bus.read(chip->bus.client,
                        ADT7316_LSB_IN_TEMP_VDD, &lsb);
                if (ret)
                        return -EIO;

                ret = chip->bus.read(chip->bus.client,

                        ADT7316_AD_MSB_DATA_BASE + channel, &msb);
                if (ret)
                        return -EIO;

                data = msb << ADT7316_T_VALUE_FLOAT_OFFSET;
                data |= (lsb & ADT7316_LSB_VDD_MASK) >> ADT7316_LSB_VDD_OFFSET;
                return sysfs_emit(buf, "%d\n", data);
        default: /* ex_temp and ain */
                ret = chip->bus.read(chip->bus.client,
                        ADT7316_LSB_EX_TEMP_AIN, &lsb);
                if (ret)
                        return -EIO;

                ret = chip->bus.read(chip->bus.client,
                        ADT7316_AD_MSB_DATA_BASE + channel, &msb);
                if (ret)
                        return -EIO;

                data = msb << ADT7316_T_VALUE_FLOAT_OFFSET;
                data |= lsb & (ADT7316_LSB_EX_TEMP_MASK <<
                        (ADT7516_LSB_AIN_SHIFT * (channel -
                        (ADT7316_MSB_EX_TEMP - ADT7316_AD_MSB_DATA_BASE))));

                if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
                        return sysfs_emit(buf, "%d\n", data);

                break;
        }

        if (data & ADT7316_T_VALUE_SIGN) {
                /* convert supplement to positive value */
                data = (ADT7316_T_VALUE_SIGN << 1) - data;
                sign = '-';
        }

        return sysfs_emit(buf, "%c%d.%.2d\n", sign,
                (data >> ADT7316_T_VALUE_FLOAT_OFFSET),
                (data & ADT7316_T_VALUE_FLOAT_MASK) * 25);
}

static ssize_t adt7316_show_VDD(struct device *dev,
                                struct device_attribute *attr,
                                char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_VDD, buf);
}
static IIO_DEVICE_ATTR(VDD, 0444, adt7316_show_VDD, NULL, 0);

static ssize_t adt7316_show_in_temp(struct device *dev,
                                    struct device_attribute *attr,
                                    char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_IN, buf);
}

static IIO_DEVICE_ATTR(in_temp, 0444, adt7316_show_in_temp, NULL, 0);

static ssize_t adt7316_show_ex_temp_AIN1(struct device *dev,
                                         struct device_attribute *attr,
                                         char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_EX, buf);
}

static IIO_DEVICE_ATTR(ex_temp_AIN1, 0444, adt7316_show_ex_temp_AIN1,
                       NULL, 0);
static IIO_DEVICE_ATTR(ex_temp, 0444, adt7316_show_ex_temp_AIN1, NULL, 0);

static ssize_t adt7316_show_AIN2(struct device *dev,
                                 struct device_attribute *attr,
                                 char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN2, buf);
}
static IIO_DEVICE_ATTR(AIN2, 0444, adt7316_show_AIN2, NULL, 0);

static ssize_t adt7316_show_AIN3(struct device *dev,
                                 struct device_attribute *attr,
                                 char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN3, buf);
}
static IIO_DEVICE_ATTR(AIN3, 0444, adt7316_show_AIN3, NULL, 0);

static ssize_t adt7316_show_AIN4(struct device *dev,
                                 struct device_attribute *attr,
                                 char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN4, buf);
}
static IIO_DEVICE_ATTR(AIN4, 0444, adt7316_show_AIN4, NULL, 0);

static ssize_t adt7316_show_temp_offset(struct adt7316_chip_info *chip,
                                        int offset_addr, char *buf)
{
        int data;
        u8 val;
        int ret;

        ret = chip->bus.read(chip->bus.client, offset_addr, &val);
        if (ret)
                return -EIO;

        data = (int)val;
        if (val & 0x80)
                data -= 256;

        return sysfs_emit(buf, "%d\n", data);
}

static ssize_t adt7316_store_temp_offset(struct adt7316_chip_info *chip,
                                         int offset_addr,
                                         const char *buf,
                                         size_t len)
{
        int data;
        u8 val;
        int ret;

        ret = kstrtoint(buf, 10, &data);
        if (ret || data > 127 || data < -128)
                return -EINVAL;

        if (data < 0)
                data += 256;

        val = (u8)data;

        ret = chip->bus.write(chip->bus.client, offset_addr, val);
        if (ret)
                return -EIO;

        return len;
}

static ssize_t adt7316_show_in_temp_offset(struct device *dev,
                                           struct device_attribute *attr,
                                           char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_show_temp_offset(chip, ADT7316_IN_TEMP_OFFSET, buf);
}

static ssize_t adt7316_store_in_temp_offset(struct device *dev,
                                            struct device_attribute *attr,
                                            const char *buf,
                                            size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_store_temp_offset(chip, ADT7316_IN_TEMP_OFFSET, buf,
                        len);
}

static IIO_DEVICE_ATTR(in_temp_offset, 0644,
                       adt7316_show_in_temp_offset,
                       adt7316_store_in_temp_offset, 0);

static ssize_t adt7316_show_ex_temp_offset(struct device *dev,
                                           struct device_attribute *attr,
                                           char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_show_temp_offset(chip, ADT7316_EX_TEMP_OFFSET, buf);
}

static ssize_t adt7316_store_ex_temp_offset(struct device *dev,
                                            struct device_attribute *attr,
                                            const char *buf,
                                            size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_store_temp_offset(chip, ADT7316_EX_TEMP_OFFSET, buf,
                        len);
}

static IIO_DEVICE_ATTR(ex_temp_offset, 0644,
                       adt7316_show_ex_temp_offset,
                       adt7316_store_ex_temp_offset, 0);

static ssize_t adt7316_show_in_analog_temp_offset(struct device *dev,
                                                  struct device_attribute *attr,
                                                  char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_show_temp_offset(chip,
                        ADT7316_IN_ANALOG_TEMP_OFFSET, buf);
}

static ssize_t adt7316_store_in_analog_temp_offset(struct device *dev,
                                                   struct device_attribute *attr,
                                                   const char *buf,
                                                   size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_store_temp_offset(chip,
                        ADT7316_IN_ANALOG_TEMP_OFFSET, buf, len);
}

static IIO_DEVICE_ATTR(in_analog_temp_offset, 0644,
                       adt7316_show_in_analog_temp_offset,
                       adt7316_store_in_analog_temp_offset, 0);

static ssize_t adt7316_show_ex_analog_temp_offset(struct device *dev,
                                                  struct device_attribute *attr,
                                                  char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_show_temp_offset(chip,
                        ADT7316_EX_ANALOG_TEMP_OFFSET, buf);
}

static ssize_t adt7316_store_ex_analog_temp_offset(struct device *dev,
                                                   struct device_attribute *attr,
                                                   const char *buf,
                                                   size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_store_temp_offset(chip,
                        ADT7316_EX_ANALOG_TEMP_OFFSET, buf, len);
}

static IIO_DEVICE_ATTR(ex_analog_temp_offset, 0644,
                       adt7316_show_ex_analog_temp_offset,
                       adt7316_store_ex_analog_temp_offset, 0);

static ssize_t adt7316_show_DAC(struct adt7316_chip_info *chip,
                                int channel, char *buf)
{
        u16 data = 0;
        u8 msb, lsb, offset;
        int ret;

        if (channel >= ADT7316_DA_MSB_DATA_REGS ||
            (channel == 0 &&
            (chip->config3 & ADT7316_EN_IN_TEMP_PROP_DACA)) ||
            (channel == 1 &&
            (chip->config3 & ADT7316_EN_EX_TEMP_PROP_DACB)))
                return -EPERM;

        offset = chip->dac_bits - 8;

        if (chip->dac_bits > 8) {
                ret = chip->bus.read(chip->bus.client,
                        ADT7316_DA_DATA_BASE + channel * 2, &lsb);
                if (ret)
                        return -EIO;
        }

        ret = chip->bus.read(chip->bus.client,
                ADT7316_DA_DATA_BASE + 1 + channel * 2, &msb);
        if (ret)
                return -EIO;

        if (chip->dac_bits == 12)
                data = lsb >> ADT7316_DA_12_BIT_LSB_SHIFT;
        else if (chip->dac_bits == 10)
                data = lsb >> ADT7316_DA_10_BIT_LSB_SHIFT;
        data |= msb << offset;

        return sysfs_emit(buf, "%d\n", data);
}

static ssize_t adt7316_store_DAC(struct adt7316_chip_info *chip,
                                 int channel, const char *buf, size_t len)
{
        u8 msb, lsb, lsb_reg, offset;
        u16 data;
        int ret;

        if (channel >= ADT7316_DA_MSB_DATA_REGS ||
            (channel == 0 &&
            (chip->config3 & ADT7316_EN_IN_TEMP_PROP_DACA)) ||
            (channel == 1 &&
            (chip->config3 & ADT7316_EN_EX_TEMP_PROP_DACB)))
                return -EPERM;

        offset = chip->dac_bits - 8;

        ret = kstrtou16(buf, 10, &data);
        if (ret || data >= (1 << chip->dac_bits))
                return -EINVAL;

        if (chip->dac_bits > 8) {
                lsb = data & ((1 << offset) - 1);
                if (chip->dac_bits == 12)
                        lsb_reg = lsb << ADT7316_DA_12_BIT_LSB_SHIFT;
                else
                        lsb_reg = lsb << ADT7316_DA_10_BIT_LSB_SHIFT;
                ret = chip->bus.write(chip->bus.client,
                        ADT7316_DA_DATA_BASE + channel * 2, lsb_reg);
                if (ret)
                        return -EIO;
        }

        msb = data >> offset;
        ret = chip->bus.write(chip->bus.client,
                ADT7316_DA_DATA_BASE + 1 + channel * 2, msb);
        if (ret)
                return -EIO;

        return len;
}

static ssize_t adt7316_show_DAC_A(struct device *dev,
                                  struct device_attribute *attr,
                                  char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_show_DAC(chip, 0, buf);
}

static ssize_t adt7316_store_DAC_A(struct device *dev,
                                   struct device_attribute *attr,
                                   const char *buf,
                                   size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_store_DAC(chip, 0, buf, len);
}

static IIO_DEVICE_ATTR(DAC_A, 0644, adt7316_show_DAC_A,
                       adt7316_store_DAC_A, 0);

static ssize_t adt7316_show_DAC_B(struct device *dev,
                                  struct device_attribute *attr,
                                  char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_show_DAC(chip, 1, buf);
}

static ssize_t adt7316_store_DAC_B(struct device *dev,
                                   struct device_attribute *attr,
                                   const char *buf,
                                   size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_store_DAC(chip, 1, buf, len);
}

static IIO_DEVICE_ATTR(DAC_B, 0644, adt7316_show_DAC_B,
                       adt7316_store_DAC_B, 0);

static ssize_t adt7316_show_DAC_C(struct device *dev,
                                  struct device_attribute *attr,
                                  char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_show_DAC(chip, 2, buf);
}

static ssize_t adt7316_store_DAC_C(struct device *dev,
                                   struct device_attribute *attr,
                                   const char *buf,
                                   size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_store_DAC(chip, 2, buf, len);
}

static IIO_DEVICE_ATTR(DAC_C, 0644, adt7316_show_DAC_C,
                       adt7316_store_DAC_C, 0);

static ssize_t adt7316_show_DAC_D(struct device *dev,
                                  struct device_attribute *attr,
                                  char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_show_DAC(chip, 3, buf);
}

static ssize_t adt7316_store_DAC_D(struct device *dev,
                                   struct device_attribute *attr,
                                   const char *buf,
                                   size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return adt7316_store_DAC(chip, 3, buf, len);
}

static IIO_DEVICE_ATTR(DAC_D, 0644, adt7316_show_DAC_D,
                       adt7316_store_DAC_D, 0);

static ssize_t adt7316_show_device_id(struct device *dev,
                                      struct device_attribute *attr,
                                      char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 id;
        int ret;

        ret = chip->bus.read(chip->bus.client, ADT7316_DEVICE_ID, &id);
        if (ret)
                return -EIO;

        return sysfs_emit(buf, "%d\n", id);
}

static IIO_DEVICE_ATTR(device_id, 0444, adt7316_show_device_id, NULL, 0);

static ssize_t adt7316_show_manufactorer_id(struct device *dev,
                                            struct device_attribute *attr,
                                            char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 id;
        int ret;

        ret = chip->bus.read(chip->bus.client, ADT7316_MANUFACTURE_ID, &id);
        if (ret)
                return -EIO;

        return sysfs_emit(buf, "%d\n", id);
}

static IIO_DEVICE_ATTR(manufactorer_id, 0444,
                       adt7316_show_manufactorer_id, NULL, 0);

static ssize_t adt7316_show_device_rev(struct device *dev,
                                       struct device_attribute *attr,
                                       char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 rev;
        int ret;

        ret = chip->bus.read(chip->bus.client, ADT7316_DEVICE_REV, &rev);
        if (ret)
                return -EIO;

        return sysfs_emit(buf, "%d\n", rev);
}

static IIO_DEVICE_ATTR(device_rev, 0444, adt7316_show_device_rev, NULL, 0);

static ssize_t adt7316_show_bus_type(struct device *dev,
                                     struct device_attribute *attr,
                                     char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 stat;
        int ret;

        ret = chip->bus.read(chip->bus.client, ADT7316_SPI_LOCK_STAT, &stat);
        if (ret)
                return -EIO;

        if (stat)
                return sysfs_emit(buf, "spi\n");

        return sysfs_emit(buf, "i2c\n");
}

static IIO_DEVICE_ATTR(bus_type, 0444, adt7316_show_bus_type, NULL, 0);

static struct attribute *adt7316_attributes[] = {
        &iio_dev_attr_all_modes.dev_attr.attr,
        &iio_dev_attr_mode.dev_attr.attr,
        &iio_dev_attr_enabled.dev_attr.attr,
        &iio_dev_attr_ad_channel.dev_attr.attr,
        &iio_dev_attr_all_ad_channels.dev_attr.attr,
        &iio_dev_attr_disable_averaging.dev_attr.attr,
        &iio_dev_attr_enable_smbus_timeout.dev_attr.attr,
        &iio_dev_attr_powerdown.dev_attr.attr,
        &iio_dev_attr_fast_ad_clock.dev_attr.attr,
        &iio_dev_attr_da_high_resolution.dev_attr.attr,
        &iio_dev_attr_enable_proportion_DACA.dev_attr.attr,
        &iio_dev_attr_enable_proportion_DACB.dev_attr.attr,
        &iio_dev_attr_DAC_2Vref_channels_mask.dev_attr.attr,
        &iio_dev_attr_DAC_update_mode.dev_attr.attr,
        &iio_dev_attr_all_DAC_update_modes.dev_attr.attr,
        &iio_dev_attr_update_DAC.dev_attr.attr,
        &iio_dev_attr_DA_AB_Vref_bypass.dev_attr.attr,
        &iio_dev_attr_DA_CD_Vref_bypass.dev_attr.attr,
        &iio_dev_attr_DAC_internal_Vref.dev_attr.attr,
        &iio_dev_attr_VDD.dev_attr.attr,
        &iio_dev_attr_in_temp.dev_attr.attr,
        &iio_dev_attr_ex_temp.dev_attr.attr,
        &iio_dev_attr_in_temp_offset.dev_attr.attr,
        &iio_dev_attr_ex_temp_offset.dev_attr.attr,
        &iio_dev_attr_in_analog_temp_offset.dev_attr.attr,
        &iio_dev_attr_ex_analog_temp_offset.dev_attr.attr,
        &iio_dev_attr_DAC_A.dev_attr.attr,
        &iio_dev_attr_DAC_B.dev_attr.attr,
        &iio_dev_attr_DAC_C.dev_attr.attr,
        &iio_dev_attr_DAC_D.dev_attr.attr,
        &iio_dev_attr_device_id.dev_attr.attr,
        &iio_dev_attr_manufactorer_id.dev_attr.attr,
        &iio_dev_attr_device_rev.dev_attr.attr,
        &iio_dev_attr_bus_type.dev_attr.attr,
        NULL,
};

static const struct attribute_group adt7316_attribute_group = {
        .attrs = adt7316_attributes,
};

static struct attribute *adt7516_attributes[] = {
        &iio_dev_attr_all_modes.dev_attr.attr,
        &iio_dev_attr_mode.dev_attr.attr,
        &iio_dev_attr_select_ex_temp.dev_attr.attr,
        &iio_dev_attr_enabled.dev_attr.attr,
        &iio_dev_attr_ad_channel.dev_attr.attr,
        &iio_dev_attr_all_ad_channels.dev_attr.attr,
        &iio_dev_attr_disable_averaging.dev_attr.attr,
        &iio_dev_attr_enable_smbus_timeout.dev_attr.attr,
        &iio_dev_attr_powerdown.dev_attr.attr,
        &iio_dev_attr_fast_ad_clock.dev_attr.attr,
        &iio_dev_attr_AIN_internal_Vref.dev_attr.attr,
        &iio_dev_attr_da_high_resolution.dev_attr.attr,
        &iio_dev_attr_enable_proportion_DACA.dev_attr.attr,
        &iio_dev_attr_enable_proportion_DACB.dev_attr.attr,
        &iio_dev_attr_DAC_2Vref_channels_mask.dev_attr.attr,
        &iio_dev_attr_DAC_update_mode.dev_attr.attr,
        &iio_dev_attr_all_DAC_update_modes.dev_attr.attr,
        &iio_dev_attr_update_DAC.dev_attr.attr,
        &iio_dev_attr_DAC_internal_Vref.dev_attr.attr,
        &iio_dev_attr_VDD.dev_attr.attr,
        &iio_dev_attr_in_temp.dev_attr.attr,
        &iio_dev_attr_ex_temp_AIN1.dev_attr.attr,
        &iio_dev_attr_AIN2.dev_attr.attr,
        &iio_dev_attr_AIN3.dev_attr.attr,
        &iio_dev_attr_AIN4.dev_attr.attr,
        &iio_dev_attr_in_temp_offset.dev_attr.attr,
        &iio_dev_attr_ex_temp_offset.dev_attr.attr,
        &iio_dev_attr_in_analog_temp_offset.dev_attr.attr,
        &iio_dev_attr_ex_analog_temp_offset.dev_attr.attr,
        &iio_dev_attr_DAC_A.dev_attr.attr,
        &iio_dev_attr_DAC_B.dev_attr.attr,
        &iio_dev_attr_DAC_C.dev_attr.attr,
        &iio_dev_attr_DAC_D.dev_attr.attr,
        &iio_dev_attr_device_id.dev_attr.attr,
        &iio_dev_attr_manufactorer_id.dev_attr.attr,
        &iio_dev_attr_device_rev.dev_attr.attr,
        &iio_dev_attr_bus_type.dev_attr.attr,
        NULL,
};

static const struct attribute_group adt7516_attribute_group = {
        .attrs = adt7516_attributes,
};

static irqreturn_t adt7316_event_handler(int irq, void *private)
{
        struct iio_dev *indio_dev = private;
        struct adt7316_chip_info *chip = iio_priv(indio_dev);
        u8 stat1, stat2;
        int ret;
        s64 time;

        ret = chip->bus.read(chip->bus.client, ADT7316_INT_STAT1, &stat1);
        if (!ret) {
                if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
                        stat1 &= 0x1F;

                time = iio_get_time_ns(indio_dev);
                if (stat1 & BIT(0))
                        iio_push_event(indio_dev,
                                       IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0,
                                                            IIO_EV_TYPE_THRESH,
                                                            IIO_EV_DIR_RISING),
                                       time);
                if (stat1 & BIT(1))
                        iio_push_event(indio_dev,
                                       IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0,
                                                            IIO_EV_TYPE_THRESH,
                                                            IIO_EV_DIR_FALLING),
                                       time);
                if (stat1 & BIT(2))
                        iio_push_event(indio_dev,
                                       IIO_UNMOD_EVENT_CODE(IIO_TEMP, 1,
                                                            IIO_EV_TYPE_THRESH,
                                                            IIO_EV_DIR_RISING),
                                       time);
                if (stat1 & BIT(3))
                        iio_push_event(indio_dev,
                                       IIO_UNMOD_EVENT_CODE(IIO_TEMP, 1,
                                                            IIO_EV_TYPE_THRESH,
                                                            IIO_EV_DIR_FALLING),
                                       time);
                if (stat1 & BIT(5))
                        iio_push_event(indio_dev,
                                       IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 1,
                                                            IIO_EV_TYPE_THRESH,
                                                            IIO_EV_DIR_EITHER),
                                       time);
                if (stat1 & BIT(6))
                        iio_push_event(indio_dev,
                                       IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 2,
                                                            IIO_EV_TYPE_THRESH,
                                                            IIO_EV_DIR_EITHER),
                                       time);
                if (stat1 & BIT(7))
                        iio_push_event(indio_dev,
                                       IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 3,
                                                            IIO_EV_TYPE_THRESH,
                                                            IIO_EV_DIR_EITHER),
                                       time);
                }
        ret = chip->bus.read(chip->bus.client, ADT7316_INT_STAT2, &stat2);
        if (!ret) {
                if (stat2 & ADT7316_INT_MASK2_VDD)
                        iio_push_event(indio_dev,
                                       IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE,
                                                            0,
                                                            IIO_EV_TYPE_THRESH,
                                                            IIO_EV_DIR_RISING),
                                       iio_get_time_ns(indio_dev));
        }

        return IRQ_HANDLED;
}

static int adt7316_setup_irq(struct iio_dev *indio_dev)
{
        struct adt7316_chip_info *chip = iio_priv(indio_dev);
        int irq_type, ret;

        irq_type = irq_get_trigger_type(chip->bus.irq);

        switch (irq_type) {
        case IRQF_TRIGGER_HIGH:
        case IRQF_TRIGGER_RISING:
                break;
        case IRQF_TRIGGER_LOW:
        case IRQF_TRIGGER_FALLING:
                break;
        default:
                dev_info(&indio_dev->dev, "mode %d unsupported, using IRQF_TRIGGER_LOW\n",
                         irq_type);
                irq_type = IRQF_TRIGGER_LOW;
                break;
        }

        ret = devm_request_threaded_irq(&indio_dev->dev, chip->bus.irq,
                                        NULL, adt7316_event_handler,
                                        irq_type | IRQF_ONESHOT,
                                        indio_dev->name, indio_dev);
        if (ret) {
                dev_err(&indio_dev->dev, "failed to request irq %d\n",
                        chip->bus.irq);
                return ret;
        }

        if (irq_type & IRQF_TRIGGER_HIGH)
                chip->config1 |= ADT7316_INT_POLARITY;

        return 0;
}

/*
 * Show mask of enabled interrupts in Hex.
 */
static ssize_t adt7316_show_int_mask(struct device *dev,
                                     struct device_attribute *attr,
                                     char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return sysfs_emit(buf, "0x%x\n", chip->int_mask);
}

/*
 * Set 1 to the mask in Hex to enabled interrupts.
 */
static ssize_t adt7316_set_int_mask(struct device *dev,
                                    struct device_attribute *attr,
                                    const char *buf,
                                    size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u16 data;
        int ret;
        u8 mask;

        ret = kstrtou16(buf, 16, &data);
        if (ret || data >= ADT7316_VDD_INT_MASK + 1)
                return -EINVAL;

        if (data & ADT7316_VDD_INT_MASK)
                mask = 0;                       /* enable vdd int */
        else
                mask = ADT7316_INT_MASK2_VDD;   /* disable vdd int */

        ret = chip->bus.write(chip->bus.client, ADT7316_INT_MASK2, mask);
        if (!ret) {
                chip->int_mask &= ~ADT7316_VDD_INT_MASK;
                chip->int_mask |= data & ADT7316_VDD_INT_MASK;
        }

        if (data & ADT7316_TEMP_AIN_INT_MASK) {
                if ((chip->id & ID_FAMILY_MASK) == ID_ADT73XX)
                        /* mask in reg is opposite, set 1 to disable */
                        mask = (~data) & ADT7316_TEMP_INT_MASK;
                else
                        /* mask in reg is opposite, set 1 to disable */
                        mask = (~data) & ADT7316_TEMP_AIN_INT_MASK;
        }
        ret = chip->bus.write(chip->bus.client, ADT7316_INT_MASK1, mask);

        chip->int_mask = mask;

        return len;
}

static inline ssize_t adt7316_show_ad_bound(struct device *dev,
                                            struct device_attribute *attr,
                                            char *buf)
{
        struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 val;
        int data;
        int ret;

        if ((chip->id & ID_FAMILY_MASK) == ID_ADT73XX &&
            this_attr->address > ADT7316_EX_TEMP_LOW)
                return -EPERM;

        ret = chip->bus.read(chip->bus.client, this_attr->address, &val);
        if (ret)
                return -EIO;

        data = (int)val;

        if (!((chip->id & ID_FAMILY_MASK) == ID_ADT75XX &&
              (chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0)) {
                if (data & 0x80)
                        data -= 256;
        }

        return sysfs_emit(buf, "%d\n", data);
}

static inline ssize_t adt7316_set_ad_bound(struct device *dev,
                                           struct device_attribute *attr,
                                           const char *buf,
                                           size_t len)
{
        struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        int data;
        u8 val;
        int ret;

        if ((chip->id & ID_FAMILY_MASK) == ID_ADT73XX &&
            this_attr->address > ADT7316_EX_TEMP_LOW)
                return -EPERM;

        ret = kstrtoint(buf, 10, &data);
        if (ret)
                return -EINVAL;

        if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX &&
            (chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0) {
                if (data > 255 || data < 0)
                        return -EINVAL;
        } else {
                if (data > 127 || data < -128)
                        return -EINVAL;

                if (data < 0)
                        data += 256;
        }

        val = (u8)data;

        ret = chip->bus.write(chip->bus.client, this_attr->address, val);
        if (ret)
                return -EIO;

        return len;
}

static ssize_t adt7316_show_int_enabled(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return sysfs_emit(buf, "%d\n", !!(chip->config1 & ADT7316_INT_EN));
}

static ssize_t adt7316_set_int_enabled(struct device *dev,
                                       struct device_attribute *attr,
                                       const char *buf,
                                       size_t len)
{
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
        u8 config1;
        int ret;

        config1 = chip->config1 & (~ADT7316_INT_EN);
        if (buf[0] == '1')
                config1 |= ADT7316_INT_EN;

        ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1);
        if (ret)
                return -EIO;

        chip->config1 = config1;

        return len;
}

static IIO_DEVICE_ATTR(int_mask,
                       0644,
                       adt7316_show_int_mask, adt7316_set_int_mask,
                       0);
static IIO_DEVICE_ATTR(in_temp_high_value,
                       0644,
                       adt7316_show_ad_bound, adt7316_set_ad_bound,
                       ADT7316_IN_TEMP_HIGH);
static IIO_DEVICE_ATTR(in_temp_low_value,
                       0644,
                       adt7316_show_ad_bound, adt7316_set_ad_bound,
                       ADT7316_IN_TEMP_LOW);
static IIO_DEVICE_ATTR(ex_temp_high_value,
                       0644,
                       adt7316_show_ad_bound, adt7316_set_ad_bound,
                       ADT7316_EX_TEMP_HIGH);
static IIO_DEVICE_ATTR(ex_temp_low_value,
                       0644,
                       adt7316_show_ad_bound, adt7316_set_ad_bound,
                       ADT7316_EX_TEMP_LOW);

/* NASTY duplication to be fixed */
static IIO_DEVICE_ATTR(ex_temp_ain1_high_value,
                       0644,
                       adt7316_show_ad_bound, adt7316_set_ad_bound,
                       ADT7316_EX_TEMP_HIGH);
static IIO_DEVICE_ATTR(ex_temp_ain1_low_value,
                       0644,
                       adt7316_show_ad_bound, adt7316_set_ad_bound,
                       ADT7316_EX_TEMP_LOW);
static IIO_DEVICE_ATTR(ain2_high_value,
                       0644,
                       adt7316_show_ad_bound, adt7316_set_ad_bound,
                       ADT7516_AIN2_HIGH);
static IIO_DEVICE_ATTR(ain2_low_value,
                       0644,
                       adt7316_show_ad_bound, adt7316_set_ad_bound,
                       ADT7516_AIN2_LOW);
static IIO_DEVICE_ATTR(ain3_high_value,
                       0644,
                       adt7316_show_ad_bound, adt7316_set_ad_bound,
                       ADT7516_AIN3_HIGH);
static IIO_DEVICE_ATTR(ain3_low_value,
                       0644,
                       adt7316_show_ad_bound, adt7316_set_ad_bound,
                       ADT7516_AIN3_LOW);
static IIO_DEVICE_ATTR(ain4_high_value,
                       0644,
                       adt7316_show_ad_bound, adt7316_set_ad_bound,
                       ADT7516_AIN4_HIGH);
static IIO_DEVICE_ATTR(ain4_low_value,
                       0644,
                       adt7316_show_ad_bound, adt7316_set_ad_bound,
                       ADT7516_AIN4_LOW);
static IIO_DEVICE_ATTR(int_enabled,
                       0644,
                       adt7316_show_int_enabled,
                       adt7316_set_int_enabled, 0);

static struct attribute *adt7316_event_attributes[] = {
        &iio_dev_attr_int_mask.dev_attr.attr,
        &iio_dev_attr_in_temp_high_value.dev_attr.attr,
        &iio_dev_attr_in_temp_low_value.dev_attr.attr,
        &iio_dev_attr_ex_temp_high_value.dev_attr.attr,
        &iio_dev_attr_ex_temp_low_value.dev_attr.attr,
        &iio_dev_attr_int_enabled.dev_attr.attr,
        NULL,
};

static const struct attribute_group adt7316_event_attribute_group = {
        .attrs = adt7316_event_attributes,
        .name = "events",
};

static struct attribute *adt7516_event_attributes[] = {
        &iio_dev_attr_int_mask.dev_attr.attr,
        &iio_dev_attr_in_temp_high_value.dev_attr.attr,
        &iio_dev_attr_in_temp_low_value.dev_attr.attr,
        &iio_dev_attr_ex_temp_ain1_high_value.dev_attr.attr,
        &iio_dev_attr_ex_temp_ain1_low_value.dev_attr.attr,
        &iio_dev_attr_ain2_high_value.dev_attr.attr,
        &iio_dev_attr_ain2_low_value.dev_attr.attr,
        &iio_dev_attr_ain3_high_value.dev_attr.attr,
        &iio_dev_attr_ain3_low_value.dev_attr.attr,
        &iio_dev_attr_ain4_high_value.dev_attr.attr,
        &iio_dev_attr_ain4_low_value.dev_attr.attr,
        &iio_dev_attr_int_enabled.dev_attr.attr,
        NULL,
};

static const struct attribute_group adt7516_event_attribute_group = {
        .attrs = adt7516_event_attributes,
        .name = "events",
};

static int adt7316_disable(struct device *dev)
{
        struct iio_dev *dev_info = dev_get_drvdata(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return _adt7316_store_enabled(chip, 0);
}

static int adt7316_enable(struct device *dev)
{
        struct iio_dev *dev_info = dev_get_drvdata(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);

        return _adt7316_store_enabled(chip, 1);
}

EXPORT_GPL_SIMPLE_DEV_PM_OPS(adt7316_pm_ops, adt7316_disable, adt7316_enable);

static const struct iio_info adt7316_info = {
        .attrs = &adt7316_attribute_group,
        .event_attrs = &adt7316_event_attribute_group,
};

static const struct iio_info adt7516_info = {
        .attrs = &adt7516_attribute_group,
        .event_attrs = &adt7516_event_attribute_group,
};

/*
 * device probe and remove
 */
int adt7316_probe(struct device *dev, struct adt7316_bus *bus,
                  const char *name)
{
        struct adt7316_chip_info *chip;
        struct iio_dev *indio_dev;
        int ret;

        indio_dev = devm_iio_device_alloc(dev, sizeof(*chip));
        if (!indio_dev)
                return -ENOMEM;
        chip = iio_priv(indio_dev);
        /* this is only used for device removal purposes */
        dev_set_drvdata(dev, indio_dev);

        chip->bus = *bus;

        if (name[4] == '3')
                chip->id = ID_ADT7316 + (name[6] - '6');
        else if (name[4] == '5')
                chip->id = ID_ADT7516 + (name[6] - '6');
        else
                return -ENODEV;

        if (chip->id == ID_ADT7316 || chip->id == ID_ADT7516)
                chip->dac_bits = 12;
        else if (chip->id == ID_ADT7317 || chip->id == ID_ADT7517)
                chip->dac_bits = 10;
        else
                chip->dac_bits = 8;

        chip->ldac_pin = devm_gpiod_get_optional(dev, "adi,ldac",
                                                 GPIOD_OUT_LOW);
        if (IS_ERR(chip->ldac_pin)) {
                ret = PTR_ERR(chip->ldac_pin);
                dev_err(dev, "Failed to request ldac GPIO: %d\n", ret);
                return ret;
        }

        if (!chip->ldac_pin) {
                chip->config3 |= ADT7316_DA_EN_VIA_DAC_LDAC;
                if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
                        chip->config1 |= ADT7516_SEL_AIN3;
        }
        chip->int_mask = ADT7316_TEMP_INT_MASK | ADT7316_VDD_INT_MASK;
        if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
                chip->int_mask |= ADT7516_AIN_INT_MASK;

        if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
                indio_dev->info = &adt7516_info;
        else
                indio_dev->info = &adt7316_info;
        indio_dev->name = name;
        indio_dev->modes = INDIO_DIRECT_MODE;

        if (chip->bus.irq > 0) {
                ret = adt7316_setup_irq(indio_dev);
                if (ret)
                        return ret;
        }

        ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, chip->config1);
        if (ret)
                return -EIO;

        ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, chip->config3);
        if (ret)
                return -EIO;

        ret = devm_iio_device_register(dev, indio_dev);
        if (ret)
                return ret;

        dev_info(dev, "%s temperature sensor, ADC and DAC registered.\n",
                 indio_dev->name);

        return 0;
}
EXPORT_SYMBOL(adt7316_probe);

MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
MODULE_DESCRIPTION("Analog Devices ADT7316/7/8 and ADT7516/7/9 digital temperature sensor, ADC and DAC driver");
MODULE_LICENSE("GPL v2");