Re: [PATCH] staging: iio: new ADT7316/7/8 and ADT7516/7/9 driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 10/23/10 21:23, Mike Frysinger wrote:
> From: Sonic Zhang <sonic.zhang@xxxxxxxxxx>
> 
> IIO driver for temperature sensor, ADC and DAC devices over SPI and I2C.

Given I'm low on time I've done this review without diving into the
datasheets, so I may have missed some stuff.

DAC interfaces need thorough discussion. That doesn't prevent merging
but note they will almost certainly change somewhat. I'm not all that
familiar with these devices so I'm happy to have others propose the
interface, but it needs to be proposed widely and discussed before we
commit to it.  Hence we won't have a stable userspace abi for now.

Few quirks that could do with cleaning up.
For starters I can't find any users of the multi_read and multi_write
functions, other than where they are used for the spi single read and
write equivalent.

Some of the sanity checks related to the exact chip can be removed
as I don't think it's possible for the functions to run such that
the checks can fail.

Some errors from the bus functions are eaten rather than passed on.

Not keen on the single channel / round robin control. It is utterly
non standard. If I understand what this is doing, it's just the same
as the scan modes handled in a consistent manner by a number of
other drivers (max1363 and other adc drivers).
I don't mind this merging as is, but it needs a TODO file to indicate
that this needs cleaning up.  The whole selecting channel stuff is
completely wrong under our abi. Sorry guys, but it just doesn't
generalize. You should have separate attributes such as:
in0_supply_raw
in1_raw
in2_raw
in3_raw
temp0_external_raw
temp1_raw

There are elements here that the abi covers that are incorrect here
as well. in_temp for example doesn't exist.

as appropriate. The temp0_external will need documenting as we haven't
had that one before. 

Locking needed to ensure consistency.  Always remember multiple reads
of sysfs attributes can occur at the same time.

Whilst clearer than many cases, there are magic numbers in the resolution
parameters.  Please just use the actual values.

Sorry, event codes have all changed and you'll need to update that stuff before
it will build against current staging-next.  Disadvantage of working on
big drivers out of mainline I'm afraid.  What we had for this was a mess
and only got cleaned up in this kernel cycle.  Lots of your events don't
look device specific anyway so should never have been using those codes.

The hex based interrupt mask definitely needs changing to be abi compliant.


This one is way off on the abi, but I guess if it builds we can merge it and
fix in tree as long as someone has the relevant part and is willing todo
testing.  Should definitely have an accompanying TODO covering the various
points in here if they haven't been fixed prior to merge.

It would be good to merge it as we still have relatively few drivers implementing
the event interfaces. What worries me is it may lead other driver writers
astray. 

Jonathan

> 
> Signed-off-by: Sonic Zhang <sonic.zhang@xxxxxxxxxx>
> Signed-off-by: Mike Frysinger <vapier@xxxxxxxxxx>
> ---
>  drivers/staging/iio/Kconfig             |    1 +
>  drivers/staging/iio/Makefile            |    1 +
(nothing to do with this driver - just idle musing ;)
I'm beginning to wonder whether it was such a good idea to break the
devices out into directories.  As this one shows the divisions aren't
always all that clear.  We can decide that at a later date though.  
>  drivers/staging/iio/addac/Kconfig       |   25 +
>  drivers/staging/iio/addac/Makefile      |    7 +
>  drivers/staging/iio/addac/adt7316-i2c.c |  169 +++
>  drivers/staging/iio/addac/adt7316-spi.c |  179 +++
>  drivers/staging/iio/addac/adt7316.c     | 2402 +++++++++++++++++++++++++++++++
>  drivers/staging/iio/addac/adt7316.h     |   33 +
>  8 files changed, 2817 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/staging/iio/addac/Kconfig
>  create mode 100644 drivers/staging/iio/addac/Makefile
>  create mode 100644 drivers/staging/iio/addac/adt7316-i2c.c
>  create mode 100644 drivers/staging/iio/addac/adt7316-spi.c
>  create mode 100644 drivers/staging/iio/addac/adt7316.c
>  create mode 100644 drivers/staging/iio/addac/adt7316.h
> 
> diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
> index ed48815..b8bb5f1 100644
> --- a/drivers/staging/iio/Kconfig
> +++ b/drivers/staging/iio/Kconfig
> @@ -42,6 +42,7 @@ config IIO_TRIGGER
>  
>  source "drivers/staging/iio/accel/Kconfig"
>  source "drivers/staging/iio/adc/Kconfig"
> +source "drivers/staging/iio/addac/Kconfig"
>  source "drivers/staging/iio/gyro/Kconfig"
>  source "drivers/staging/iio/imu/Kconfig"
>  source "drivers/staging/iio/light/Kconfig"
> diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile
> index e909674..0111647 100644
> --- a/drivers/staging/iio/Makefile
> +++ b/drivers/staging/iio/Makefile
> @@ -11,6 +11,7 @@ obj-$(CONFIG_IIO_SW_RING) += ring_sw.o
>  
>  obj-y += accel/
>  obj-y += adc/
> +obj-y += addac/
>  obj-y += gyro/
>  obj-y += imu/
>  obj-y += light/
> diff --git a/drivers/staging/iio/addac/Kconfig b/drivers/staging/iio/addac/Kconfig
> new file mode 100644
> index 0000000..9b4ee42
> --- /dev/null
> +++ b/drivers/staging/iio/addac/Kconfig
> @@ -0,0 +1,25 @@
> +#
> +# ADDAC drivers
> +#
> +comment "Analog digital bi-direction convertors"
> +
> +config ADT7316
> +	tristate "Analog Devices ADT7316/7/8 ADT7516/7/9 temperature sensor, ADC and DAC driver"
> +	help
(non critical) Please can we have the names in full in the help text.  It makes
for easier grepping.
> +	  Say yes here to build support for Analog Devices ADT7316/7/8
> +	  and ADT7516/7/9 temperature sensors, ADC and DAC.
> +
> +config ADT7316_SPI
> +	tristate "support SPI bus connection"
> +	depends on SPI && ADT7316
why default y ?  
> +	default y
> +	help
> +	  Say yes here to build SPI bus support for Analog Devices ADT7316/7/8
> +	  and ADT7516/7/9.
> +
> +config ADT7316_I2C
> +	tristate "support I2C bus connection"
> +	depends on I2C && ADT7316
> +	help
> +	  Say yes here to build I2C bus support for Analog Devices ADT7316/7/8
> +	  and ADT7516/7/9.
> diff --git a/drivers/staging/iio/addac/Makefile b/drivers/staging/iio/addac/Makefile
> new file mode 100644
> index 0000000..4c76861
> --- /dev/null
> +++ b/drivers/staging/iio/addac/Makefile
> @@ -0,0 +1,7 @@
> +#
> +# Makefile for industrial I/O ADDAC drivers
> +#
> +
> +obj-$(CONFIG_ADT7316) += adt7316.o
> +obj-$(CONFIG_ADT7316_SPI) += adt7316-spi.o
> +obj-$(CONFIG_ADT7316_I2C) += adt7316-i2c.o
> diff --git a/drivers/staging/iio/addac/adt7316-i2c.c b/drivers/staging/iio/addac/adt7316-i2c.c
> new file mode 100644
> index 0000000..744c82d
> --- /dev/null
> +++ b/drivers/staging/iio/addac/adt7316-i2c.c
> @@ -0,0 +1,169 @@
> +/*
> + * I2C bus driver for ADT7316/7/8 ADT7516/7/9 digital temperature
> + * sensor, ADC and DAC
> + *
> + * Copyright 2010 Analog Devices Inc.
> + *
> + * Licensed under the GPL-2 or later.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/kernel.h>
> +#include <linux/i2c.h>
> +
> +#include "adt7316.h"
> +
> +/*
> + * adt7316 register access by I2C
> + */
> +static int adt7316_i2c_read(void *client, u8 reg, u8 *data)
> +{
> +	struct i2c_client *cl = client;
> +	int ret = 0;
Don't bother initializing the value.
> +
> +	ret = i2c_smbus_write_byte(cl, reg);
> +	if (ret < 0) {
> +		dev_err(&cl->dev, "I2C fail to select reg\n");
> +		return ret;
> +	}
> +
> +	ret = i2c_smbus_read_byte(client);
> +	if (ret < 0) {
> +		dev_err(&cl->dev, "I2C read error\n");
> +		return ret;
> +	}
I think these two calls correspond to a single
i2c_smbus_read_byte_data call.
If there is a quirk that makes this inappropriate then there
should probably be a comment about it.

> +
> +	return 0;
> +}
> +
> +static int adt7316_i2c_write(void *client, u8 reg, u8 data)
> +{
> +	struct i2c_client *cl = client;
> +	int ret = 0;
No point in initializing the value.
> +
> +	ret = i2c_smbus_write_byte_data(cl, reg, data);
> +	if (ret < 0)
> +		dev_err(&cl->dev, "I2C write error\n");
> +
> +	return ret;
> +}
> +
> +static int adt7316_i2c_multi_read(void *client, u8 reg, u8 count, u8 *data)
> +{
> +	struct i2c_client *cl = client;
> +	int i, ret = 0;
> +
This is rather odd. Surely basic care will prevent this condition
occuring and if it does it probably implies a bug in the driver...
> +	if (count > ADT7316_REG_MAX_ADDR)
> +		count = ADT7316_REG_MAX_ADDR;
> +
> +	for (i = 0; i < count; i++) {
> +		ret = adt7316_i2c_read(cl, reg, &data[i]);
> +		if (ret < 0) {
> +			dev_err(&cl->dev, "I2C multi read error\n");
> +			return ret;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int adt7316_i2c_multi_write(void *client, u8 reg, u8 count, u8 *data)
> +{
> +	struct i2c_client *cl = client;
> +	int i, ret = 0;
> +
> +	if (count > ADT7316_REG_MAX_ADDR)
> +		count = ADT7316_REG_MAX_ADDR;
> +
> +	for (i = 0; i < count; i++) {
> +		ret = adt7316_i2c_write(cl, reg, data[i]);
> +		if (ret < 0) {
> +			dev_err(&cl->dev, "I2C multi write error\n");
> +			return ret;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * device probe and remove
> + */
> +
> +static int __devinit adt7316_i2c_probe(struct i2c_client *client,
> +		const struct i2c_device_id *id)
> +{

Isn't there an issue with this structure going out of scope.
Probably needs to be coppied in the adt7316_probe funciton.
> +	struct adt7316_bus bus = {
> +		.client = client,
> +		.irq = client->irq,
> +		.irq_flags = client->irq_flags,
> +		.read = adt7316_i2c_read,
> +		.write = adt7316_i2c_write,
> +		.multi_read = adt7316_i2c_multi_read,
> +		.multi_write = adt7316_i2c_multi_write,
> +	};
> +
> +	return adt7316_probe(&client->dev, &bus, id->name);
> +}
> +
> +static int __devexit adt7316_i2c_remove(struct i2c_client *client)
> +{
> +	return adt7316_remove(&client->dev);;
> +}
> +
> +static const struct i2c_device_id adt7316_i2c_id[] = {
> +	{ "adt7316", 0 },
> +	{ "adt7317", 0 },
> +	{ "adt7318", 0 },
> +	{ "adt7516", 0 },
> +	{ "adt7517", 0 },
> +	{ "adt7519", 0 },
> +	{ }
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, adt7316_i2c_id);
> +
> +#ifdef CONFIG_PM
> +static int adt7316_i2c_suspend(struct i2c_client *client, pm_message_t message)
> +{
> +	return adt7316_disable(&client->dev);
> +}
> +
> +static int adt7316_i2c_resume(struct i2c_client *client)
> +{
> +	return adt7316_enable(&client->dev);
> +}
> +#else
> +# define adt7316_i2c_suspend NULL
> +# define adt7316_i2c_resume  NULL
> +#endif
> +
> +static struct i2c_driver adt7316_driver = {
> +	.driver = {
> +		.name = "adt7316",
> +		.owner  = THIS_MODULE,
> +	},
> +	.probe = adt7316_i2c_probe,
> +	.remove = __devexit_p(adt7316_i2c_remove),
> +	.suspend = adt7316_i2c_suspend,
> +	.resume = adt7316_i2c_resume,
> +	.id_table = adt7316_i2c_id,
> +};
> +
> +static __init int adt7316_i2c_init(void)
> +{
> +	return i2c_add_driver(&adt7316_driver);
> +}
> +
> +static __exit void adt7316_i2c_exit(void)
> +{
> +	i2c_del_driver(&adt7316_driver);
> +}
> +
> +MODULE_AUTHOR("Sonic Zhang <sonic.zhang@xxxxxxxxxx>");
> +MODULE_DESCRIPTION("I2C bus driver for Analog Devices ADT7316/7/9 and"
> +			"ADT7516/7/8 digital temperature sensor, ADC and DAC");
> +MODULE_LICENSE("GPL v2");
> +
> +module_init(adt7316_i2c_init);
> +module_exit(adt7316_i2c_exit);
> diff --git a/drivers/staging/iio/addac/adt7316-spi.c b/drivers/staging/iio/addac/adt7316-spi.c
> new file mode 100644
> index 0000000..13c6cde
> --- /dev/null
> +++ b/drivers/staging/iio/addac/adt7316-spi.c
> @@ -0,0 +1,179 @@
> +/*
> + * API bus driver for ADT7316/7/8 ADT7516/7/9 digital temperature
> + * sensor, ADC and DAC
> + *
> + * Copyright 2010 Analog Devices Inc.
> + *
> + * Licensed under the GPL-2 or later.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/spi/spi.h>
> +
> +#include "adt7316.h"
> +
> +#define ADT7316_SPI_MAX_FREQ_HZ		5000000
> +#define ADT7316_SPI_CMD_READ		0x91
> +#define ADT7316_SPI_CMD_WRITE		0x90
> +
> +/*
> + * adt7316 register access by SPI
> + */
> +
> +static int adt7316_spi_multi_read(void *client, u8 reg, u8 count, u8 *data)
> +{
> +	struct spi_device *spi_dev = client;
> +	u8 cmd[2];
> +	int ret = 0;
Again, no need to initialize this.  Conversly
could initialize cmd
> +
> +	if (count > ADT7316_REG_MAX_ADDR)
> +		count = ADT7316_REG_MAX_ADDR;
> +
> +	cmd[0] = ADT7316_SPI_CMD_WRITE;
> +	cmd[1] = reg;
> +
> +	ret = spi_write(spi_dev, cmd, 2);
> +	if (ret < 0) {
> +		dev_err(&spi_dev->dev, "SPI fail to select reg\n");
> +		return ret;
> +	}
> +
> +	cmd[0] = ADT7316_SPI_CMD_READ;
> +
> +	ret = spi_write_then_read(spi_dev, cmd, 1, data, count);
> +	if (ret < 0) {
> +		dev_err(&spi_dev->dev, "SPI read data error\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int adt7316_spi_multi_write(void *client, u8 reg, u8 count, u8 *data)
> +{
> +	struct spi_device *spi_dev = client;
> +	u8 buf[ADT7316_REG_MAX_ADDR + 2];
> +	int i, ret = 0;
> +
> +	if (count > ADT7316_REG_MAX_ADDR)
> +		count = ADT7316_REG_MAX_ADDR;
> +
> +	buf[0] = ADT7316_SPI_CMD_WRITE;
> +	buf[1] = reg;
> +	for (i = 0; i < count; i++)
> +		buf[i + 2] = data[i];
> +
> +	ret = spi_write(spi_dev, buf, count + 2);
> +	if (ret < 0) {
> +		dev_err(&spi_dev->dev, "SPI write error\n");
> +		return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +static int adt7316_spi_read(void *client, u8 reg, u8 *data)
> +{
> +	return adt7316_spi_multi_read(client, reg, 1, data);
> +}
> +
> +static int adt7316_spi_write(void *client, u8 reg, u8 val)
> +{
> +	return adt7316_spi_multi_write(client, reg, 1, &val);
> +}
> +
> +/*
> + * device probe and remove
> + */
> +
> +static int __devinit adt7316_spi_probe(struct spi_device *spi_dev)
> +{
> +	struct adt7316_bus bus = {
> +		.client = spi_dev,
> +		.irq = spi_dev->irq,
> +		.irq_flags = spi_dev->irq_flags,
> +		.read = adt7316_spi_read,
> +		.write = adt7316_spi_write,
> +		.multi_read = adt7316_spi_multi_read,
> +		.multi_write = adt7316_spi_multi_write,
> +	};
> +
> +	/* don't exceed max specified SPI CLK frequency */
> +	if (spi_dev->max_speed_hz > ADT7316_SPI_MAX_FREQ_HZ) {
> +		dev_err(&spi_dev->dev, "SPI CLK %d Hz?\n",
> +			spi_dev->max_speed_hz);
> +		return -EINVAL;
> +	}
> +
> +	/* switch from default I2C protocol to SPI protocol */
> +	adt7316_spi_write(spi_dev, 0, 0);
> +	adt7316_spi_write(spi_dev, 0, 0);
> +	adt7316_spi_write(spi_dev, 0, 0);
> +
> +	return adt7316_probe(&spi_dev->dev, &bus, spi_dev->modalias);
> +}
> +
> +static int __devexit adt7316_spi_remove(struct spi_device *spi_dev)
> +{
> +	return adt7316_remove(&spi_dev->dev);
> +}
> +
> +static const struct spi_device_id adt7316_spi_id[] = {
> +	{ "adt7316", 0 },
> +	{ "adt7317", 0 },
> +	{ "adt7318", 0 },
> +	{ "adt7516", 0 },
> +	{ "adt7517", 0 },
> +	{ "adt7519", 0 },
> +	{ }
> +};
> +
> +MODULE_DEVICE_TABLE(spi, adt7316_spi_id);
> +
> +#ifdef CONFIG_PM
> +static int adt7316_spi_suspend(struct spi_device *spi_dev, pm_message_t message)
> +{
> +	return adt7316_disable(&spi_dev->dev);
> +}
> +
> +static int adt7316_spi_resume(struct spi_device *spi_dev)
> +{
> +	return adt7316_enable(&spi_dev->dev);
> +}
> +#else
> +# define adt7316_spi_suspend NULL
> +# define adt7316_spi_resume  NULL
> +#endif
> +
> +static struct spi_driver adt7316_driver = {
> +	.driver = {
> +		.name = "adt7316",
> +		.bus = &spi_bus_type,
> +		.owner = THIS_MODULE,
> +	},
> +	.probe = adt7316_spi_probe,
> +	.remove = __devexit_p(adt7316_spi_remove),
> +	.suspend = adt7316_spi_suspend,
> +	.resume = adt7316_spi_resume,
> +	.id_table = adt7316_spi_id,
> +};
> +
> +static __init int adt7316_spi_init(void)
> +{
> +	return spi_register_driver(&adt7316_driver);
> +}
> +
> +static __exit void adt7316_spi_exit(void)
> +{
> +	spi_unregister_driver(&adt7316_driver);
> +}
> +
> +MODULE_AUTHOR("Sonic Zhang <sonic.zhang@xxxxxxxxxx>");
> +MODULE_DESCRIPTION("SPI bus driver for Analog Devices ADT7316/7/8 and"
> +			"ADT7516/7/9 digital temperature sensor, ADC and DAC");
> +MODULE_LICENSE("GPL v2");
> +
> +module_init(adt7316_spi_init);
> +module_exit(adt7316_spi_exit);
> diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c
> new file mode 100644
> index 0000000..dfc153b
> --- /dev/null
> +++ b/drivers/staging/iio/addac/adt7316.c
> @@ -0,0 +1,2402 @@
> +/*
> + * ADT7316 digital temperature sensor driver supporting ADT7316/7/8 ADT7516/7/9
> + *
> + *
> + * Copyright 2010 Analog Devices Inc.
> + *
> + * Licensed under the GPL-2 or later.
> + */
> +
> +#include <linux/interrupt.h>
> +#include <linux/gpio.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>

rtc.h?  Why?
> +#include <linux/rtc.h>
> +
> +#include "../iio.h"
> +#include "../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_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_LDAC_CONFIG		0x1B
> +#define ADT7316_DAC_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_LDCA	0x4
> +#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_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 specifc information
> + */

I'd like to see this structure more fully documented
(would make review simpler).
> +
> +struct adt7316_chip_info {
> +	const char		*name;
> +	struct iio_dev		*indio_dev;
> +	struct work_struct	thresh_work;
> +	s64			last_timestamp;
> +	struct adt7316_bus	bus;
> +	u16			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 | ADT7316_TEMP_INT_MASK)
> +
> +/*
> + * struct adt7316_chip_info - chip specifc information
> + */
Comment doesn't correspond to this structure.
> +
> +struct adt7316_limit_regs {
> +	u16	data_high;
> +	u16	data_low;
> +};
> +
> +static ssize_t adt7316_show_enabled(struct device *dev,
> +		struct device_attribute *attr,
> +		char *buf)
> +{
> +	struct iio_dev *dev_info = dev_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_EN));
> +}
> +
> +static ssize_t _adt7316_store_enabled(struct adt7316_chip_info *chip,
> +		int enable)
> +{
> +	u8 config1;
> +	int ret;
> +
Don't think it matters that much, but probably want some locking
in here to ensure the cache matches the state.
> +	if (enable)
> +		config1 = chip->config1 | ADT7316_EN;
> +	else
> +		config1 = chip->config1 & ~ADT7316_EN;
> +
> +	ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1);
Can this eat more informative errors coming up from the underlying bus
drivers?
> +	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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	int enable;
> +
> +	if (!memcmp(buf, "1", 1))
> +		enable = 1;
> +	else
> +		enable = 0;
enable = !!memcmp(buf, "1", 1);
> +
> +	if (_adt7316_store_enabled(chip, enable) < 0)
Pass on the error that came from the function.
> +		return -EIO;
> +	else
> +		return len;
> +}
> +
> +static IIO_DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR,
> +		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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
How can this happen?
> +		return -EPERM;
> +
> +	return sprintf(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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 config1;
> +	int ret;
> +
> +	if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
Same as above. I can't see how this can happen.
> +		return -EPERM;
> +
Ideally some locking here would prevent odd inconsistent results.
> +	config1 = chip->config1 & (~ADT7516_SEL_EX_TEMP);
> +	if (!memcmp(buf, "1", 1))
> +		config1 |= ADT7516_SEL_EX_TEMP;
> +
> +	ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1);
> +	if (ret)
More error eating. Don't do it.
> +		return -EIO;
> +
> +	chip->config1 = config1;
> +
> +	return len;
> +}
> +
> +static IIO_DEVICE_ATTR(select_ex_temp, S_IRUGO | S_IWUSR,
> +		adt7316_show_select_ex_temp,
> +		adt7316_store_select_ex_temp,
> +		0);
> +

This probably needs proper support as per the various ADC
drivers in mainline.  Userspace basically doesn't need to
know this.  The driver should setup which ever mode meets
the requirements of what userspace requests.

I guess we can let this go for now, but I will add a todo
file to the directory to point out this needs to change.
> +static ssize_t adt7316_show_mode(struct device *dev,
> +		struct device_attribute *attr,
> +		char *buf)
> +{
> +	struct iio_dev *dev_info = dev_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	if (chip->config2 & ADT7316_AD_SINGLE_CH_MODE)
> +		return sprintf(buf, "single_channel\n");
> +	else
> +		return sprintf(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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 config2;
> +	int ret;
> +
> +	config2 = chip->config2 & (~ADT7316_AD_SINGLE_CH_MODE);
> +	if (!memcmp(buf, "single_channel", 14))
sysfs_strcmp is probably more appropriate.
> +		config2 |= ADT7316_AD_SINGLE_CH_MODE;
> +
> +	ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
> +	if (ret)
Error eating.
> +		return -EIO;
> +
> +	chip->config2 = config2;
locking please.
> +
> +	return len;
> +}
> +
> +static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
> +		adt7316_show_mode,
> +		adt7316_store_mode,
> +		0);
> +
> +static ssize_t adt7316_show_all_modes(struct device *dev,
> +		struct device_attribute *attr,
> +		char *buf)
> +{
> +	return sprintf(buf, "single_channel\nround_robin\n");
Space separated please.  Could use IIO_CONST_ATTR macro
to cover this.
> +}
> +
> +static IIO_DEVICE_ATTR(all_modes, S_IRUGO, 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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE))
Again, if this can happen you have a driver bug.
> +		return -EPERM;
> +
> +	switch (chip->config2 & ADT7516_AD_SINGLE_CH_MASK) {
> +	case ADT7316_AD_SINGLE_CH_VDD:
> +		return sprintf(buf, "0 - VDD\n");
> +	case ADT7316_AD_SINGLE_CH_IN:
> +		return sprintf(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 sprintf(buf, "2 - AIN1\n");
> +		else
> +			return sprintf(buf, "2 - External Temperature\n");
> +	case ADT7516_AD_SINGLE_CH_AIN2:
> +		if ((chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0)
> +			return sprintf(buf, "3 - AIN2\n");
> +		else
> +			return sprintf(buf, "N/A\n");
> +	case ADT7516_AD_SINGLE_CH_AIN3:
> +		if (chip->config1 & ADT7516_SEL_AIN3)
> +			return sprintf(buf, "4 - AIN3\n");
> +		else
> +			return sprintf(buf, "N/A\n");
> +	case ADT7516_AD_SINGLE_CH_AIN4:
> +		return sprintf(buf, "5 - AIN4\n");
> +	default:
> +		return sprintf(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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 config2;
> +	unsigned long data = 0;
> +	int ret;
> +
> +	if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE))
> +		return -EPERM;
> +
> +	ret = strict_strtoul(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, S_IRUGO | S_IWUSR,
> +		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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE))
> +		return -EPERM;
> +
> +	if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
Space separated, also work on the strings, not numbers. It simplifies
this.  Though it will go anyway if abi compliant.
> +		return sprintf(buf, "0 - VDD\n1 - Internal Temperature\n"
> +				"2 - External Temperature or AIN2\n"
> +				"3 - AIN2\n4 - AIN3\n5 - AIN4\n");
> +	else
> +		return sprintf(buf, "0 - VDD\n1 - Internal Temperature\n"
> +				"2 - External Temperature\n");
> +}
> +
> +static IIO_DEVICE_ATTR(all_ad_channels, S_IRUGO,
> +		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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return sprintf(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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 config2;
> +	int ret;
> +
> +	config2 = chip->config2 & (~ADT7316_DISABLE_AVERAGING);
> +	if (!memcmp(buf, "1", 1))
> +		config2 |= ADT7316_DISABLE_AVERAGING;
> +
> +	ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
> +	if (ret)
> +		return -EIO;
> +
> +	chip->config2 = config2;
> +
> +	return len;
> +}
> +
This one is new to us.  So we need to work out naming. For events
we have mean_period so something similar to that probably makes
sense.  If it applies to all channels we will need to figure out
how to indicate this.
> +static IIO_DEVICE_ATTR(disable_averaging, S_IRUGO | S_IWUSR,
> +		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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return sprintf(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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 config2;
> +	int ret;
> +
> +	config2 = chip->config2 & (~ADT7316_EN_SMBUS_TIMEOUT);
> +	if (!memcmp(buf, "1", 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;
> +}
> +
That's very device specific (not seen it before). Please add some
documentation for this one.
> +static IIO_DEVICE_ATTR(enable_smbus_timeout, S_IRUGO | S_IWUSR,
> +		adt7316_show_enable_smbus_timeout,
> +		adt7316_store_enable_smbus_timeout,
> +		0);
> +
> +
> +static ssize_t adt7316_store_reset(struct device *dev,
> +		struct device_attribute *attr,
> +		const char *buf,
> +		size_t len)
> +{
> +	struct iio_dev *dev_info = dev_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 config2;
> +	int ret;
> +
> +	config2 = chip->config2 | ADT7316_RESET;
> +
> +	ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
> +	if (ret)
> +		return -EIO;
> +
> +	return len;
> +}
> +
> +static IIO_DEVICE_ATTR(reset, S_IWUSR,
> +		NULL,
> +		adt7316_store_reset,
> +		0);
> +

Idealy this functionality would be handled via runtime pm,
but that can occur in the future. For now it's fine with me.
> +static ssize_t adt7316_show_powerdown(struct device *dev,
> +		struct device_attribute *attr,
> +		char *buf)
> +{
> +	struct iio_dev *dev_info = dev_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return sprintf(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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 config1;
> +	int ret;
> +
> +	config1 = chip->config1 & (~ADT7316_PD);
> +	if (!memcmp(buf, "1", 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, S_IRUGO | S_IWUSR,
> +		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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return sprintf(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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 config3;
> +	int ret;
> +
> +	config3 = chip->config3 & (~ADT7316_ADCLK_22_5);
> +	if (!memcmp(buf, "1", 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;
> +}
> +
Guessing this corresponds indirectly to sampling_frequency?
> +static IIO_DEVICE_ATTR(fast_ad_clock, S_IRUGO | S_IWUSR,
> +		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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	if (chip->config3 & ADT7316_DA_HIGH_RESOLUTION) {
> +		if (chip->id == ID_ADT7316 || chip->id == ID_ADT7516)
> +			return sprintf(buf, "1 (12 bits)\n");
> +		else if (chip->id == ID_ADT7317 || chip->id == ID_ADT7517)
> +			return sprintf(buf, "1 (10 bits)\n");
> +	}
> +
> +	return sprintf(buf, "0 (8 bits)\n");
No. We have type attributes for this and never allow magic numbers.

> +}
> +
> +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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 config3;
> +	int ret;
> +
> +	chip->dac_bits = 8;
> +
> +	if (!memcmp(buf, "1", 1)) {
> +		config3 = chip->config3 | ADT7316_DA_HIGH_RESOLUTION;
> +		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
> +		config3 = chip->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, S_IRUGO | S_IWUSR,
> +		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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
Again, can it happen?
> +		return -EPERM;
> +
> +	return sprintf(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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 config3;
> +	int ret;
> +
> +	if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
> +		return -EPERM;
> +
> +	if (memcmp(buf, "1", 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)
error eating.
> +		return -EIO;
> +
> +	chip->config3 = config3;
> +
> +	return len;
> +}
> +
> +static IIO_DEVICE_ATTR(AIN_internal_Vref, S_IRUGO | S_IWUSR,
> +		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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return sprintf(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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 config3;
> +	int ret;
> +
> +	config3 = chip->config3 & (~ADT7316_EN_IN_TEMP_PROP_DACA);
> +	if (!memcmp(buf, "1", 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;
> +}
> +
I don't know what this is, so at very least it nees docs.  
> +static IIO_DEVICE_ATTR(enable_proportion_DACA, S_IRUGO | S_IWUSR,
> +		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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return sprintf(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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 config3;
> +	int ret;
> +
> +	config3 = chip->config3 & (~ADT7316_EN_EX_TEMP_PROP_DACB);
> +	if (!memcmp(buf, "1", 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;
> +}
> +
Also needs docs and I'm very anti acronyms unless they are very very
well known.
> +static IIO_DEVICE_ATTR(enable_proportion_DACB, S_IRUGO | S_IWUSR,
> +		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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return sprintf(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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 dac_config;
> +	unsigned long data = 0;
> +	int ret;
> +
> +	ret = strict_strtoul(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;
> +}
> +
This interface needs clean documentation so we can discuss it.

> +static IIO_DEVICE_ATTR(DAC_2Vref_channels_mask, S_IRUGO | S_IWUSR,
> +		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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA))
> +		return sprintf(buf, "manual\n");
> +	else {
> +		switch (chip->dac_config & ADT7316_DA_EN_MODE_MASK) {
> +		case ADT7316_DA_EN_MODE_SINGLE:
> +			return sprintf(buf, "0 - auto at any MSB DAC writing\n");
> +		case ADT7316_DA_EN_MODE_AB_CD:
> +			return sprintf(buf, "1 - auto at MSB DAC AB and CD writing\n");
> +		case ADT7316_DA_EN_MODE_ABCD:
> +			return sprintf(buf, "2 - auto at MSB DAC ABCD writing\n");
> +		default: /* ADT7316_DA_EN_MODE_LDAC */
> +			return sprintf(buf, "3 - manual\n");
The word 'ouch' comes to mind.  This interface needs detailed description and
general discussion.
> +		};
> +	}
> +}
> +
> +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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 dac_config;
> +	unsigned long data;
> +	int ret;
> +
> +	if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA))
> +		return -EPERM;
> +
> +	ret = strict_strtoul(buf, 10, &data);
> +	if (ret || data > ADT7316_DA_EN_MODE_MASK)
> +		return -EINVAL;
> +
> +	dac_config = chip->dac_config & (~ADT7316_DA_EN_MODE_MASK);
> +	dac_config |= data;
> +
> +	ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config);
> +	if (ret)
error eating and locking again.
> +		return -EIO;
> +
> +	chip->dac_config = dac_config;
> +
> +	return len;
> +}
> +
> +static IIO_DEVICE_ATTR(DAC_update_mode, S_IRUGO | S_IWUSR,
> +		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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA)
> +		return sprintf(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");
> +	else
> +		return sprintf(buf, "manual\n");
> +}
> +
> +static IIO_DEVICE_ATTR(all_DAC_update_modes, S_IRUGO,
> +		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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 ldac_config;
> +	unsigned long data;
> +	int ret;
> +
> +	if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA) {
> +		if ((chip->dac_config & ADT7316_DA_EN_MODE_MASK) !=
> +			ADT7316_DA_EN_MODE_LDAC)
> +			return -EPERM;
> +
> +		ret = strict_strtoul(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 {
> +		gpio_set_value(chip->ldac_pin, 0);
> +		gpio_set_value(chip->ldac_pin, 1);
> +	}
> +
> +	return len;
> +}
> +
> +static IIO_DEVICE_ATTR(update_DAC, S_IRUGO | S_IWUSR,
> +		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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
> +		return -EPERM;
> +
> +	return sprintf(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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 dac_config;
> +	int ret;
> +
> +	if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
> +		return -EPERM;
> +
> +	dac_config = chip->dac_config & (~ADT7316_VREF_BYPASS_DAC_AB);
> +	if (!memcmp(buf, "1", 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, S_IRUGO | S_IWUSR,
> +		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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
> +		return -EPERM;
> +
> +	return sprintf(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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 dac_config;
> +	int ret;
> +
> +	if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
> +		return -EPERM;
> +
> +	dac_config = chip->dac_config & (~ADT7316_VREF_BYPASS_DAC_CD);
> +	if (!memcmp(buf, "1", 1))
> +		dac_config |= ADT7316_VREF_BYPASS_DAC_CD;
> +
> +	ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config);
> +	if (ret)
locking + error eating.
> +		return -EIO;
> +
> +	chip->dac_config = dac_config;
> +
> +	return len;
> +}
> +
> +static IIO_DEVICE_ATTR(DA_CD_Vref_bypass, S_IRUGO | S_IWUSR,
> +		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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
> +		return sprintf(buf, "0x%x\n",
> +			(chip->dac_config & ADT7516_DAC_IN_VREF_MASK) >>
> +			ADT7516_DAC_IN_VREF_OFFSET);
Why in hex?
> +	else
> +		return sprintf(buf, "%d\n",
> +			!!(chip->dac_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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 ldac_config;
> +	unsigned long data;
> +	int ret;
> +
> +	if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) {
> +		ret = strict_strtoul(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;
> +		else if (data & 0x2)
> +			ldac_config |= ADT7516_DAC_CD_IN_VREF;
> +	} else {
> +		ret = strict_strtoul(buf, 16, &data);
> +		if (ret)
error eating.. (at least I think in theory that function can be more specific).
> +			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, S_IRUGO | S_IWUSR,
> +		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)
error eating
> +			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 sprintf(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 sprintf(buf, "%d\n", data);
> +		else
> +			break;
> +	};
> +
> +	if (data & ADT7316_T_VALUE_SIGN) {
> +		/* convert supplement to positive value */
> +		data = (ADT7316_T_VALUE_SIGN << 1) - data;
> +		sign = '-';
> +	}
> +
> +	return sprintf(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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_VDD, buf);
> +}
> +static IIO_DEVICE_ATTR(VDD, S_IRUGO, 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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_IN, buf);
> +}
> +
> +static IIO_DEVICE_ATTR(in_temp, S_IRUGO, adt7316_show_in_temp, NULL, 0);
temp_raw please - unless it really is just a general purpose adc then there
is probably no point in calling it temp at all.

> +
> +static ssize_t adt7316_show_ex_temp_AIN1(struct device *dev,
> +		struct device_attribute *attr,
> +		char *buf)
> +{
> +	struct iio_dev *dev_info = dev_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_EX, buf);
> +}
> +
> +static IIO_DEVICE_ATTR(ex_temp_AIN1, S_IRUGO, adt7316_show_ex_temp_AIN1, NULL, 0);
No way too that naming.  Please either switch to standard naming or explain why
that doesn't work.

> +static IIO_DEVICE_ATTR(ex_temp, S_IRUGO, 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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN2, buf);
> +}
> +static IIO_DEVICE_ATTR(AIN2, S_IRUGO, adt7316_show_AIN2, NULL, 0);
Again we have standard names. Please use them.  in2_raw I would imagine
there are wrapper macros for these.
> +
> +static ssize_t adt7316_show_AIN3(struct device *dev,
> +		struct device_attribute *attr,
> +		char *buf)
> +{
> +	struct iio_dev *dev_info = dev_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN3, buf);
> +}
> +static IIO_DEVICE_ATTR(AIN3, S_IRUGO, 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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN4, buf);
> +}
> +static IIO_DEVICE_ATTR(AIN4, S_IRUGO, 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)
error eating.
> +		return -EIO;
> +
> +	data = (int)val;
> +	if (val & 0x80)
> +		data -= 256;
> +
> +	return sprintf(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)
> +{
> +	long data;
> +	u8 val;
> +	int ret;
> +
> +	ret = strict_strtol(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)
error eating.
> +		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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return adt7316_store_temp_offset(chip, ADT7316_IN_TEMP_OFFSET, buf, len);
> +}
> +
> +static IIO_DEVICE_ATTR(in_temp_offset, S_IRUGO | S_IWUSR,
> +		adt7316_show_in_temp_offset,
> +		adt7316_store_in_temp_offset, 0);
temp_offset if it covers both types of temperature input, temp0_offset
if not.
> +
> +static ssize_t adt7316_show_ex_temp_offset(struct device *dev,
> +		struct device_attribute *attr,
> +		char *buf)
> +{
> +	struct iio_dev *dev_info = dev_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return adt7316_store_temp_offset(chip, ADT7316_EX_TEMP_OFFSET, buf, len);
> +}
> +
> +static IIO_DEVICE_ATTR(ex_temp_offset, S_IRUGO | S_IWUSR,
> +		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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return adt7316_store_temp_offset(chip,
> +			ADT7316_IN_ANALOG_TEMP_OFFSET, buf, len);
> +}
> +
> +static IIO_DEVICE_ATTR(in_analog_temp_offset, S_IRUGO | S_IWUSR,
> +		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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return adt7316_store_temp_offset(chip,
> +			ADT7316_EX_ANALOG_TEMP_OFFSET, buf, len);
> +}
> +
> +static IIO_DEVICE_ATTR(ex_analog_temp_offset, S_IRUGO | S_IWUSR,
> +		adt7316_show_ex_analog_temp_offset,
> +		adt7316_store_ex_analog_temp_offset, 0);
No way to that naming.

temp1_ex_raw maybe.
> +
> +static ssize_t adt7316_show_DAC(struct adt7316_chip_info *chip,
> +		int channel, char *buf)
> +{
> +	u16 data;
> +	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)
error eating.
> +		return -EIO;
> +
> +	data = (msb << offset) + (lsb & ((1 << offset) - 1));
> +
> +	return sprintf(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, offset;
> +	unsigned long 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 = strict_strtoul(buf, 10, &data);
> +	if (ret || data >= (1 << chip->dac_bits))
> +		return -EINVAL;
> +
> +	if (chip->dac_bits > 8) {
> +		lsb = data & (1 << offset);
> +		ret = chip->bus.write(chip->bus.client,
> +			ADT7316_DA_DATA_BASE + channel * 2, lsb);
> +		if (ret)
> +			return -EIO;
> +	}
> +
> +	msb = data >> offset;
> +	ret = chip->bus.write(chip->bus.client,
> +		ADT7316_DA_DATA_BASE + 1 + channel * 2, msb);
> +	if (ret)
error eating.
> +		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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return adt7316_store_DAC(chip, 0, buf, len);
> +}
> +
Don't know what this is, but that name is nowhere near any of out abis
> +static IIO_DEVICE_ATTR(DAC_A, S_IRUGO | S_IWUSR, 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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return adt7316_store_DAC(chip, 1, buf, len);
> +}
> +
> +static IIO_DEVICE_ATTR(DAC_B, S_IRUGO | S_IWUSR, 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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return adt7316_store_DAC(chip, 2, buf, len);
> +}
> +
> +static IIO_DEVICE_ATTR(DAC_C, S_IRUGO | S_IWUSR, 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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return adt7316_store_DAC(chip, 3, buf, len);
> +}
> +
If nothing else these need to be number based + I think we should keep
to lower case (though I may be convinced otherwise), so dac4_raw

> +static IIO_DEVICE_ATTR(DAC_D, S_IRUGO | S_IWUSR, 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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 id;
> +	int ret;
> +
> +	ret = chip->bus.read(chip->bus.client, ADT7316_DEVICE_ID, &id);
> +	if (ret)
> +		return -EIO;
> +
> +	return sprintf(buf, "%d\n", id);
> +}
> +
> +static IIO_DEVICE_ATTR(device_id, S_IRUGO, 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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 id;
> +	int ret;
> +
> +	ret = chip->bus.read(chip->bus.client, ADT7316_MANUFACTURE_ID, &id);
> +	if (ret)
> +		return -EIO;
> +
> +	return sprintf(buf, "%d\n", id);
> +}
> +
> +static IIO_DEVICE_ATTR(manufactorer_id, S_IRUGO,
> +		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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 rev;
> +	int ret;
> +
> +	ret = chip->bus.read(chip->bus.client, ADT7316_DEVICE_REV, &rev);
> +	if (ret)
> +		return -EIO;
> +
> +	return sprintf(buf, "%d\n", rev);
> +}
> +
> +static IIO_DEVICE_ATTR(device_rev, S_IRUGO, adt7316_show_device_rev, NULL, 0);
Is this of interest beyond for matching against the device that was registered?
Not sure why userspce would care...
> +
> +static ssize_t adt7316_show_bus_type(struct device *dev,
> +		struct device_attribute *attr,
> +		char *buf)
> +{
> +	struct iio_dev *dev_info = dev_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 stat;
> +	int ret;
> +
> +	ret = chip->bus.read(chip->bus.client, ADT7316_SPI_LOCK_STAT, &stat);
> +	if (ret)
> +		return -EIO;
> +
> +	if (stat)
> +		return sprintf(buf, "spi\n");
> +	else
> +		return sprintf(buf, "i2c\n");
> +}
Don't see any point in this at all.
By all means try and convince me otherwise.

> +
> +static IIO_DEVICE_ATTR(bus_type, S_IRUGO, adt7316_show_bus_type, NULL, 0);
> +
> +static ssize_t adt7316_show_name(struct device *dev,
> +		struct device_attribute *attr,
> +		char *buf)
> +{
> +	struct iio_dev *dev_info = dev_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return sprintf(buf, "%s\n", chip->name);
> +}
> +
> +static IIO_DEVICE_ATTR(name, S_IRUGO, adt7316_show_name, NULL, 0);
> +

Lets sumarize those I'm not happy with in here.
> +static struct attribute *adt7316_attributes[] = {
> +	&iio_dev_attr_all_modes.dev_attr.attr,
modes_available or fix to be abi compliant.
> +	&iio_dev_attr_mode.dev_attr.attr,
> +	&iio_dev_attr_reset.dev_attr.attr,
> +	&iio_dev_attr_enabled.dev_attr.attr,
difference between this and powerdown?
> +	&iio_dev_attr_ad_channel.dev_attr.attr,
Each channel should have separate access and driver should handle
switching to the required one.  If really not possible in_channel
> +	&iio_dev_attr_all_ad_channels.dev_attr.attr,
If it were here in_channel_available (though not abi compatible).
> +	&iio_dev_attr_disable_averaging.dev_attr.attr,
in_mean_period 0 for disable, whatever the period is (in seconds)
otherwise.
> +	&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,
sampling_frequency
> +	&iio_dev_attr_da_high_resolution.dev_attr.attr,
in_type (or possibly type if it covers temp as well.
> +	&iio_dev_attr_enable_proportion_DACA.dev_attr.attr,
Don't know what this is.
> +	&iio_dev_attr_enable_proportion_DACB.dev_attr.attr,
> +	&iio_dev_attr_DAC_2Vref_channels_mask.dev_attr.attr,
not a clue.
> +	&iio_dev_attr_DAC_update_mode.dev_attr.attr,
> +	&iio_dev_attr_all_DAC_update_modes.dev_attr.attr,
DAC_update_mode_available is convention. (though not
happy with the base name either).

> +	&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,
in0_supply_raw
> +	&iio_dev_attr_in_temp.dev_attr.attr,
temp0_raw
> +	&iio_dev_attr_ex_temp.dev_attr.attr,
temp1_external_raw
> +	&iio_dev_attr_in_temp_offset.dev_attr.attr,
temp0_offset
> +	&iio_dev_attr_ex_temp_offset.dev_attr.attr,
temp1_external_offset
> +	&iio_dev_attr_in_analog_temp_offset.dev_attr.attr,
> +	&iio_dev_attr_ex_analog_temp_offset.dev_attr.attr,
What are the differences between these and the non analog versions?
> +	&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,
dac0_raw to dac3_raw (not in abi yet sho should be discussed.
> +	&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,
pointless.  Can always find this out from sysfs anyway (look at parent
of the device).
> +	&iio_dev_attr_name.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_reset.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_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_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,
> +	&iio_dev_attr_name.dev_attr.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group adt7516_attribute_group = {
> +	.attrs = adt7516_attributes,
> +};
> +
> +
> +/*
> + * temperature bound events
> + */
> +
> +#define IIO_EVENT_CODE_ADT7316_IN_TEMP_HIGH   (IIO_EVENT_CODE_DEVICE_SPECIFIC + 1)
> +#define IIO_EVENT_CODE_ADT7316_IN_TEMP_LOW    (IIO_EVENT_CODE_DEVICE_SPECIFIC + 2)
These aren't device specific.  We have perfectly good codes for them.  Also note
the event codes have all changed so you'll need to update.
> +#define IIO_EVENT_CODE_ADT7316_EX_TEMP_HIGH   (IIO_EVENT_CODE_DEVICE_SPECIFIC + 3)
> +#define IIO_EVENT_CODE_ADT7316_EX_TEMP_LOW    (IIO_EVENT_CODE_DEVICE_SPECIFIC + 4)
> +#define IIO_EVENT_CODE_ADT7316_EX_TEMP_FAULT  (IIO_EVENT_CODE_DEVICE_SPECIFIC + 5)
This is the only one not currently there.  Happy to add a type for that one. Please
propose something suitable under the new event code structure.

All perfectly well handled by standard events.
> +#define IIO_EVENT_CODE_ADT7516_AIN1           (IIO_EVENT_CODE_DEVICE_SPECIFIC + 3)
> +#define IIO_EVENT_CODE_ADT7516_AIN2           (IIO_EVENT_CODE_DEVICE_SPECIFIC + 6)
> +#define IIO_EVENT_CODE_ADT7516_AIN3           (IIO_EVENT_CODE_DEVICE_SPECIFIC + 7)
> +#define IIO_EVENT_CODE_ADT7516_AIN4           (IIO_EVENT_CODE_DEVICE_SPECIFIC + 8)
> +#define IIO_EVENT_CODE_ADT7316_VDD	      (IIO_EVENT_CODE_DEVICE_SPECIFIC + 9)
This will be an in0 based code.  Not sure what it does?  Is it out of range?
> +
> +static void adt7316_interrupt_bh(struct work_struct *work_s)
> +{
> +	struct adt7316_chip_info *chip =
> +		container_of(work_s, struct adt7316_chip_info, thresh_work);
> +	u8 stat1, stat2;
> +	int i, ret, count;
> +
> +	ret = chip->bus.read(chip->bus.client, ADT7316_INT_STAT1, &stat1);
> +	if (!ret) {
> +		if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
> +			count = 8;
> +		else
> +			count = 5;
> +
> +		for (i = 0; i < count; i++) {
> +			if (stat1 & (1 << i))
> +				iio_push_event(chip->indio_dev, 0,
> +					IIO_EVENT_CODE_ADT7316_IN_TEMP_HIGH + i,
> +					chip->last_timestamp);
> +		}
> +	}
> +
> +	ret = chip->bus.read(chip->bus.client, ADT7316_INT_STAT2, &stat2);
> +	if (!ret) {
> +		if (stat2 & ADT7316_INT_MASK2_VDD)
> +			iio_push_event(chip->indio_dev, 0,
> +				IIO_EVENT_CODE_ADT7316_VDD,
> +				chip->last_timestamp);
> +	}
> +
> +	enable_irq(chip->bus.irq);
> +}
> +
> +static int adt7316_interrupt(struct iio_dev *dev_info,
> +		int index,
> +		s64 timestamp,
> +		int no_test)
> +{
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	chip->last_timestamp = timestamp;
> +	schedule_work(&chip->thresh_work);
> +
> +	return 0;
> +}
> +
> +IIO_EVENT_SH(adt7316, &adt7316_interrupt);
> +
> +/*
> + * 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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return sprintf(buf, "0x%x\n", chip->int_mask);
> +}
No.  This is not abi compliant.  I'll let it as is as long
as someone promises to either work on it or offer testing
to someone else who does.
> +
> +/*
> + * 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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	unsigned long data;
> +	int ret;
> +	u8 mask;
> +
> +	ret = strict_strtoul(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,
> +		u8 bound_reg,
> +		char *buf)
> +{
> +	struct iio_dev *dev_info = dev_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 val;
> +	int data;
> +	int ret;
> +
> +	if ((chip->id & ID_FAMILY_MASK) == ID_ADT73XX &&
> +		bound_reg > ADT7316_EX_TEMP_LOW)
> +		return -EPERM;
> +
> +	ret = chip->bus.read(chip->bus.client, bound_reg, &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 sprintf(buf, "%d\n", data);
> +}
> +
> +static inline ssize_t adt7316_set_ad_bound(struct device *dev,
> +		struct device_attribute *attr,
> +		u8 bound_reg,
> +		const char *buf,
> +		size_t len)
> +{
> +	struct iio_dev *dev_info = dev_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	long data;
> +	u8 val;
> +	int ret;
> +
> +	if ((chip->id & ID_FAMILY_MASK) == ID_ADT73XX &&
> +		bound_reg > ADT7316_EX_TEMP_LOW)
> +		return -EPERM;
> +
> +	ret = strict_strtol(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, bound_reg, val);
> +	if (ret)
> +		return -EIO;
> +
> +	return len;
> +}
> +
> +static ssize_t adt7316_show_in_temp_high(struct device *dev,
> +		struct device_attribute *attr,
> +		char *buf)
> +{
> +	return adt7316_show_ad_bound(dev, attr,
> +			ADT7316_IN_TEMP_HIGH, buf);
> +}
> +
> +static inline ssize_t adt7316_set_in_temp_high(struct device *dev,
> +		struct device_attribute *attr,
> +		const char *buf,
> +		size_t len)
> +{
> +	return adt7316_set_ad_bound(dev, attr,
> +			ADT7316_IN_TEMP_HIGH, buf, len);
> +}
> +
> +static ssize_t adt7316_show_in_temp_low(struct device *dev,
> +		struct device_attribute *attr,
> +		char *buf)
> +{
> +	return adt7316_show_ad_bound(dev, attr,
> +			ADT7316_IN_TEMP_LOW, buf);
> +}
> +
> +static inline ssize_t adt7316_set_in_temp_low(struct device *dev,
> +		struct device_attribute *attr,
> +		const char *buf,
> +		size_t len)
> +{
> +	return adt7316_set_ad_bound(dev, attr,
> +			ADT7316_IN_TEMP_LOW, buf, len);
> +}
> +
> +static ssize_t adt7316_show_ex_temp_ain1_high(struct device *dev,
> +		struct device_attribute *attr,
> +		char *buf)
> +{
> +	return adt7316_show_ad_bound(dev, attr,
> +			ADT7316_EX_TEMP_HIGH, buf);
> +}
> +
> +static inline ssize_t adt7316_set_ex_temp_ain1_high(struct device *dev,
> +		struct device_attribute *attr,
> +		const char *buf,
> +		size_t len)
> +{
> +	return adt7316_set_ad_bound(dev, attr,
> +			ADT7316_EX_TEMP_HIGH, buf, len);
> +}
> +
> +static ssize_t adt7316_show_ex_temp_ain1_low(struct device *dev,
> +		struct device_attribute *attr,
> +		char *buf)
> +{
> +	return adt7316_show_ad_bound(dev, attr,
> +			ADT7316_EX_TEMP_LOW, buf);
> +}
> +
> +static inline ssize_t adt7316_set_ex_temp_ain1_low(struct device *dev,
> +		struct device_attribute *attr,
> +		const char *buf,
> +		size_t len)
> +{
> +	return adt7316_set_ad_bound(dev, attr,
> +			ADT7316_EX_TEMP_LOW, buf, len);
> +}
> +
> +static ssize_t adt7316_show_ain2_high(struct device *dev,
> +		struct device_attribute *attr,
> +		char *buf)
> +{
> +	return adt7316_show_ad_bound(dev, attr,
> +			ADT7516_AIN2_HIGH, buf);
> +}
> +
> +static inline ssize_t adt7316_set_ain2_high(struct device *dev,
> +		struct device_attribute *attr,
> +		const char *buf,
> +		size_t len)
> +{
> +	return adt7316_set_ad_bound(dev, attr,
> +			ADT7516_AIN2_HIGH, buf, len);
> +}
> +
> +static ssize_t adt7316_show_ain2_low(struct device *dev,
> +		struct device_attribute *attr,
> +		char *buf)
> +{
> +	return adt7316_show_ad_bound(dev, attr,
> +			ADT7516_AIN2_LOW, buf);
> +}
> +
> +static inline ssize_t adt7316_set_ain2_low(struct device *dev,
> +		struct device_attribute *attr,
> +		const char *buf,
> +		size_t len)
> +{
> +	return adt7316_set_ad_bound(dev, attr,
> +			ADT7516_AIN2_LOW, buf, len);
> +}
> +
> +static ssize_t adt7316_show_ain3_high(struct device *dev,
> +		struct device_attribute *attr,
> +		char *buf)
> +{
> +	return adt7316_show_ad_bound(dev, attr,
> +			ADT7516_AIN3_HIGH, buf);
> +}
> +
> +static inline ssize_t adt7316_set_ain3_high(struct device *dev,
> +		struct device_attribute *attr,
> +		const char *buf,
> +		size_t len)
> +{
> +	return adt7316_set_ad_bound(dev, attr,
> +			ADT7516_AIN3_HIGH, buf, len);
> +}
> +
> +static ssize_t adt7316_show_ain3_low(struct device *dev,
> +		struct device_attribute *attr,
> +		char *buf)
> +{
> +	return adt7316_show_ad_bound(dev, attr,
> +			ADT7516_AIN3_LOW, buf);
> +}
> +
> +static inline ssize_t adt7316_set_ain3_low(struct device *dev,
> +		struct device_attribute *attr,
> +		const char *buf,
> +		size_t len)
> +{
> +	return adt7316_set_ad_bound(dev, attr,
> +			ADT7516_AIN3_LOW, buf, len);
> +}
> +
> +static ssize_t adt7316_show_ain4_high(struct device *dev,
> +		struct device_attribute *attr,
> +		char *buf)
> +{
> +	return adt7316_show_ad_bound(dev, attr,
> +			ADT7516_AIN4_HIGH, buf);
> +}
> +
> +static inline ssize_t adt7316_set_ain4_high(struct device *dev,
> +		struct device_attribute *attr,
> +		const char *buf,
> +		size_t len)
> +{
> +	return adt7316_set_ad_bound(dev, attr,
> +			ADT7516_AIN4_HIGH, buf, len);
> +}
> +
> +static ssize_t adt7316_show_ain4_low(struct device *dev,
> +		struct device_attribute *attr,
> +		char *buf)
> +{
> +	return adt7316_show_ad_bound(dev, attr,
> +			ADT7516_AIN4_LOW, buf);
> +}
> +
> +static inline ssize_t adt7316_set_ain4_low(struct device *dev,
> +		struct device_attribute *attr,
> +		const char *buf,
> +		size_t len)
> +{
> +	return adt7316_set_ad_bound(dev, attr,
> +			ADT7516_AIN4_LOW, buf, len);
> +}
> +
> +static ssize_t adt7316_show_int_enabled(struct device *dev,
> +		struct device_attribute *attr,
> +		char *buf)
> +{
> +	struct iio_dev *dev_info = dev_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return sprintf(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_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	u8 config1;
> +	int ret;
> +
> +	config1 = chip->config1 & (~ADT7316_INT_EN);
> +	if (!memcmp(buf, "1", 1))
> +		config1 |= ADT7316_INT_EN;
> +
> +	ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1);
> +	if (ret)
> +		return -EIO;
> +
> +	chip->config1 = config1;
> +
> +	return len;
> +}
> +
> +
> +IIO_EVENT_ATTR_SH(int_mask, iio_event_adt7316,
> +		adt7316_show_int_mask, adt7316_set_int_mask, 0);
> +IIO_EVENT_ATTR_SH(in_temp_high, iio_event_adt7316,
> +		adt7316_show_in_temp_high, adt7316_set_in_temp_high, 0);
> +IIO_EVENT_ATTR_SH(in_temp_low, iio_event_adt7316,
> +		adt7316_show_in_temp_low, adt7316_set_in_temp_low, 0);
> +IIO_EVENT_ATTR_SH(ex_temp_high, iio_event_adt7316,
> +		adt7316_show_ex_temp_ain1_high,
> +		adt7316_set_ex_temp_ain1_high, 0);
> +IIO_EVENT_ATTR_SH(ex_temp_low, iio_event_adt7316,
> +		adt7316_show_ex_temp_ain1_low,
> +		adt7316_set_ex_temp_ain1_low, 0);
> +IIO_EVENT_ATTR_SH(ex_temp_ain1_high, iio_event_adt7316,
> +		adt7316_show_ex_temp_ain1_high,
> +		adt7316_set_ex_temp_ain1_high, 0);
> +IIO_EVENT_ATTR_SH(ex_temp_ain1_low, iio_event_adt7316,
> +		adt7316_show_ex_temp_ain1_low,
> +		adt7316_set_ex_temp_ain1_low, 0);
> +IIO_EVENT_ATTR_SH(ain2_high, iio_event_adt7316,
> +		adt7316_show_ain2_high, adt7316_set_ain2_high, 0);
> +IIO_EVENT_ATTR_SH(ain2_low, iio_event_adt7316,
> +		adt7316_show_ain2_low, adt7316_set_ain2_low, 0);
> +IIO_EVENT_ATTR_SH(ain3_high, iio_event_adt7316,
> +		adt7316_show_ain3_high, adt7316_set_ain3_high, 0);
> +IIO_EVENT_ATTR_SH(ain3_low, iio_event_adt7316,
> +		adt7316_show_ain3_low, adt7316_set_ain3_low, 0);
> +IIO_EVENT_ATTR_SH(ain4_high, iio_event_adt7316,
> +		adt7316_show_ain4_high, adt7316_set_ain4_high, 0);
> +IIO_EVENT_ATTR_SH(ain4_low, iio_event_adt7316,
> +		adt7316_show_ain4_low, adt7316_set_ain4_low, 0);
> +IIO_EVENT_ATTR_SH(int_enabled, iio_event_adt7316,
> +		adt7316_show_int_enabled, adt7316_set_int_enabled, 0);
These macros are meant to be for enabling disabling not the values.

See max1363 for example of use.
> +

> +static struct attribute *adt7316_event_attributes[] = {
> +	&iio_event_attr_int_mask.dev_attr.attr,
> +	&iio_event_attr_in_temp_high.dev_attr.attr,
> +	&iio_event_attr_in_temp_low.dev_attr.attr,
> +	&iio_event_attr_ex_temp_high.dev_attr.attr,
> +	&iio_event_attr_ex_temp_low.dev_attr.attr,
> +	&iio_event_attr_int_enabled.dev_attr.attr,
> +	NULL,
> +};
> +
> +static struct attribute_group adt7316_event_attribute_group = {
> +	.attrs = adt7316_event_attributes,
> +};

Lets list what should be here (I think, I'm doing this from memory of the
abi as defined and extending where necessary)  Guessing these are edge
type interrupts, level equivalents exist though haven't been used much as
yet.

iio_event_attr_temp0_thresh_rising_en
iio_event_attr_temp0_thresh_falling_en
iio_event_attr_temp1_external_thresh_rising_en
iio_event_attr_temp1_external_thresh_falling_en
iio_event_attr_in0_thresh_rising_en
iio_event_attr_in0_thresh_falling_en
etc for all enabling /disabling attributes.
iio_device_attr_temp0_thresh_rising_value
iio_device_attr_temp0_thresh_falling_value
iio_device_attr_temp1_external_thresh_rising_value
iio_device_attr_temp1_external_thresh_falling_value
etc for all values.


> +
> +static struct attribute *adt7516_event_attributes[] = {
> +	&iio_event_attr_int_mask.dev_attr.attr,
> +	&iio_event_attr_in_temp_high.dev_attr.attr,
> +	&iio_event_attr_in_temp_low.dev_attr.attr,
> +	&iio_event_attr_ex_temp_ain1_high.dev_attr.attr,
> +	&iio_event_attr_ex_temp_ain1_low.dev_attr.attr,
> +	&iio_event_attr_ain2_high.dev_attr.attr,
> +	&iio_event_attr_ain2_low.dev_attr.attr,
> +	&iio_event_attr_ain3_high.dev_attr.attr,
> +	&iio_event_attr_ain3_low.dev_attr.attr,
> +	&iio_event_attr_ain4_high.dev_attr.attr,
> +	&iio_event_attr_ain4_low.dev_attr.attr,
> +	&iio_event_attr_int_enabled.dev_attr.attr,
> +	NULL,
> +};
> +
> +static struct attribute_group adt7516_event_attribute_group = {
> +	.attrs = adt7516_event_attributes,
> +};
> +
> +#ifdef CONFIG_PM
> +int adt7316_disable(struct device *dev)
> +{
> +	struct iio_dev *dev_info = dev_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return _adt7316_store_enabled(chip, 0);
> +}
> +EXPORT_SYMBOL(adt7316_disable);
> +
> +int adt7316_enable(struct device *dev)
> +{
> +	struct iio_dev *dev_info = dev_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +
> +	return _adt7316_store_enabled(chip, 1);
> +}
> +EXPORT_SYMBOL(adt7316_enable);
> +#endif
> +
> +/*
> + * device probe and remove
> + */
> +int __devinit adt7316_probe(struct device *dev, struct adt7316_bus *bus,
> +		const char *name)
> +{
> +	struct adt7316_chip_info *chip;
> +	unsigned short *adt7316_platform_data = dev->platform_data;
> +	int ret = 0;
> +
> +	chip = kzalloc(sizeof(struct adt7316_chip_info), GFP_KERNEL);
> +
> +	if (chip == NULL)
> +		return -ENOMEM;
> +
> +	/* this is only used for device removal purposes */
> +	dev_set_drvdata(dev, chip);
> +
> +	chip->bus = *bus;
> +	chip->name = name;
> +
This is rather clunky. A simple table of names, or having the relevant id
tables pass on an enum value would be cleaner.
> +	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;
> +
> +	chip->ldac_pin = adt7316_platform_data[1];
> +	if (chip->ldac_pin) {
> +		chip->config3 |= ADT7316_DA_EN_VIA_DAC_LDCA;
> +		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;
> +
> +	chip->indio_dev = iio_allocate_device();
> +	if (chip->indio_dev == NULL) {
> +		ret = -ENOMEM;
> +		goto error_free_chip;
> +	}
> +
> +	chip->indio_dev->dev.parent = dev;
I think I'd rather see this stuff done with a chip_info struct covering each
set of parameters.  Tends to make for easier to read code and easy addition
of new parts.

> +	if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) {
> +		chip->indio_dev->attrs = &adt7516_attribute_group;
> +		chip->indio_dev->event_attrs = &adt7516_event_attribute_group;
> +	} else {
> +		chip->indio_dev->attrs = &adt7316_attribute_group;
> +		chip->indio_dev->event_attrs = &adt7316_event_attribute_group;
> +	}
> +	chip->indio_dev->dev_data = (void *)chip;
> +	chip->indio_dev->driver_module = THIS_MODULE;
> +	chip->indio_dev->num_interrupt_lines = 1;
> +	chip->indio_dev->modes = INDIO_DIRECT_MODE;
> +
> +	ret = iio_device_register(chip->indio_dev);
> +	if (ret)
> +		goto error_free_dev;
> +
> +	if (chip->bus.irq > 0) {
> +		if (adt7316_platform_data[0])
> +			chip->bus.irq_flags = adt7316_platform_data[0];
> +
> +		ret = iio_register_interrupt_line(chip->bus.irq,
> +				chip->indio_dev,
> +				0,
> +				chip->bus.irq_flags,
> +				chip->name);
> +		if (ret)
> +			goto error_unreg_dev;
> +
> +		/*
> +		 * The event handler list element refer to iio_event_adt7316.
> +		 * All event attributes bind to the same event handler.
> +		 * So, only register event handler once.
> +		 */
> +		iio_add_event_to_list(&iio_event_adt7316,
> +				&chip->indio_dev->interrupts[0]->ev_list);
> +
> +		INIT_WORK(&chip->thresh_work, adt7316_interrupt_bh);
> +
> +		if (chip->bus.irq_flags & IRQF_TRIGGER_HIGH)
> +			chip->config1 |= ADT7316_INT_POLARITY;
> +	}
> +
> +	ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, chip->config1);
> +	if (ret) {
> +		ret = -EIO;
> +		goto error_unreg_irq;
> +	}
> +
> +	ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, chip->config3);
> +	if (ret) {
> +		ret = -EIO;
> +		goto error_unreg_irq;
> +	}
> +
> +	dev_info(dev, "%s temperature sensor, ADC and DAC registered.\n",
> +			chip->name);
> +
> +	return 0;
> +
> +error_unreg_irq:
> +	iio_unregister_interrupt_line(chip->indio_dev, 0);
> +error_unreg_dev:
> +	iio_device_unregister(chip->indio_dev);
> +error_free_dev:
> +	iio_free_device(chip->indio_dev);
> +error_free_chip:
> +	kfree(chip);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(adt7316_probe);
> +
> +int __devexit adt7316_remove(struct device *dev)
> +{
> +
> +	struct iio_dev *dev_info = dev_get_drvdata(dev);
> +	struct adt7316_chip_info *chip = dev_info->dev_data;
> +	struct iio_dev *indio_dev = chip->indio_dev;
> +
> +	dev_set_drvdata(dev, NULL);
> +	if (chip->bus.irq)
> +		iio_unregister_interrupt_line(indio_dev, 0);
> +	iio_device_unregister(indio_dev);
> +	iio_free_device(chip->indio_dev);
> +	kfree(chip);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(adt7316_remove);
> +
> +MODULE_AUTHOR("Sonic Zhang <sonic.zhang@xxxxxxxxxx>");
> +MODULE_DESCRIPTION("Analog Devices ADT7316/7/8 and ADT7516/7/9 digital"
> +			" temperature sensor, ADC and DAC driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/staging/iio/addac/adt7316.h b/drivers/staging/iio/addac/adt7316.h
> new file mode 100644
> index 0000000..d34bd67
> --- /dev/null
> +++ b/drivers/staging/iio/addac/adt7316.h
> @@ -0,0 +1,33 @@
> +/*
> + * ADT7316 digital temperature sensor driver supporting ADT7316/7/8 ADT7516/7/9
> + *
> + * Copyright 2010 Analog Devices Inc.
> + *
> + * Licensed under the GPL-2 or later.
> + */
> +
> +#ifndef _ADT7316_H_
> +#define _ADT7316_H_
> +
> +#include <linux/types.h>
> +
> +#define ADT7316_REG_MAX_ADDR		0x3F
> +
> +struct adt7316_bus {
> +	void *client;
> +	int irq;
> +	int irq_flags;
> +	int (*read) (void *client, u8 reg, u8 *data);
> +	int (*write) (void *client, u8 reg, u8 val);

Why do these two exist?  Don't think they are directly used.
> +	int (*multi_read) (void *client, u8 first_reg, u8 count, u8 *data);
> +	int (*multi_write) (void *client, u8 first_reg, u8 count, u8 *data);
> +};
> +
> +#ifdef CONFIG_PM
> +int adt7316_disable(struct device *dev);
> +int adt7316_enable(struct device *dev);
> +#endif
> +int adt7316_probe(struct device *dev, struct adt7316_bus *bus, const char *name);
> +int adt7316_remove(struct device *dev);
> +
> +#endif

--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux