From: Jonathan Cameron <jic23@cam.ac.uk>
To: "Zhang, Sonic" <Sonic.Zhang@analog.com>
Cc: Mike Frysinger <vapier@gentoo.org>,
"linux-iio@vger.kernel.org" <linux-iio@vger.kernel.org>,
"device-drivers-devel@blackfin.uclinux.org"
<device-drivers-devel@blackfin.uclinux.org>,
Guenter Roeck <guenter.roeck@ericsson.com>
Subject: Re: [PATCH 12/14] staging: iio: adc: new driver for ADT7408 temperature sensors
Date: Tue, 26 Oct 2010 10:15:30 +0100 [thread overview]
Message-ID: <4CC69C32.9030205@cam.ac.uk> (raw)
In-Reply-To: <DB904C5425BA6F4E8424B3B51A1414D16578B22370@NWD2CMBX1.ad.analog.com>
On 10/26/10 04:27, Zhang, Sonic wrote:
>
>
>> -----Original Message-----
>> From: Jonathan Cameron [mailto:jic23@cam.ac.uk]
>> Sent: Monday, October 25, 2010 6:54 AM
>> To: Mike Frysinger
>> Cc: linux-iio@vger.kernel.org;
>> device-drivers-devel@blackfin.uclinux.org; Zhang, Sonic; Guenter Roeck
>> Subject: Re: [PATCH 12/14] staging: iio: adc: new driver for
>> ADT7408 temperature sensors
>>
>> On 10/23/10 21:29, Mike Frysinger wrote:
>>> From: Sonic Zhang <sonic.zhang@analog.com>
>> Here we enter new territory. This device is already supported
>> in hwmon. Do we have a usecase that is not covered by that driver?
>>
>
> I don't find a way to get event notification other than poll in hwmon
> framework. So, I move all temperature devic with interrupt available
> to IIO framework.
Whilst it isn't often done (and is a little clunky). It is possible to select
on sysfs attributes much like any other file. I'm sure Guenter can tell us
if any current hwmon devices are doing this?
> Sonic
>
>> If this is only for hardware monitoring by Guenter (cc'd) can
>> perhaps advise on how to support everything you have here...
>>
>> I'm personally not against having drivers in IIO for devices
>> supported elsewhere, but the requirements for justification
>> are rather higher. Also care is needed to ensure no issues
>> with platform data etc.
>>
>> Guenter, for your information we have a set of temp drivers
>> coming, as a small element of a larger set, from Analog's
>> tree. Those I've reviewed so far have wanted to use IIO's
>> event infrastructure (which is much more general than hwmon's
>> handling of alarms) or have been suitably high performance
>> devices with general adc's to satisfy me that they clearly
>> have uses beyond hardware monitoring.
>>
>>
>>>
>>> Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
>>> Signed-off-by: Mike Frysinger <vapier@gentoo.org>
>>> ---
>>> drivers/staging/iio/adc/Kconfig | 7 +
>>> drivers/staging/iio/adc/Makefile | 1 +
>>> drivers/staging/iio/adc/adt7408.c | 1006
>>> +++++++++++++++++++++++++++++++++++++
>>> 3 files changed, 1014 insertions(+), 0 deletions(-) create mode
>>> 100644 drivers/staging/iio/adc/adt7408.c
>>>
>>> diff --git a/drivers/staging/iio/adc/Kconfig
>>> b/drivers/staging/iio/adc/Kconfig index 5d13918..ea75700 100644
>>> --- a/drivers/staging/iio/adc/Kconfig
>>> +++ b/drivers/staging/iio/adc/Kconfig
>>> @@ -114,3 +114,10 @@ config ADT7408
>>> help
>>> Say yes here to build support for Analog Devices ADT7408
>>> temperature sensors.
>>> +
>>> +config ADT7410
>>> + tristate "Analog Devices ADT7410 temperature sensor driver"
>>> + depends on I2C
>>> + help
>>> + Say yes here to build support for Analog Devices ADT7410
>>> + temperature sensors.
>>> diff --git a/drivers/staging/iio/adc/Makefile
>>> b/drivers/staging/iio/adc/Makefile
>>> index 6c11363..dc2bdbe 100644
>>> --- a/drivers/staging/iio/adc/Makefile
>>> +++ b/drivers/staging/iio/adc/Makefile
>>> @@ -21,3 +21,4 @@ obj-$(CONFIG_AD774X) += ad774x.o
>>> obj-$(CONFIG_AD7816) += ad7816.o
>>> obj-$(CONFIG_ADT75) += adt75.o
>>> obj-$(CONFIG_ADT7310) += adt7310.o
>>> +obj-$(CONFIG_ADT7408) += adt7408.o
>>> diff --git a/drivers/staging/iio/adc/adt7408.c
>>> b/drivers/staging/iio/adc/adt7408.c
>>> new file mode 100644
>>> index 0000000..25bd594
>>> --- /dev/null
>>> +++ b/drivers/staging/iio/adc/adt7408.c
>>> @@ -0,0 +1,1006 @@
>>> +/*
>>> + * ADT7408 digital temperature sensor driver supporting ADT7408
>>> + *
>>> + * 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>
>>> +#include <linux/rtc.h>
>>> +
>>> +#include "../iio.h"
>>> +#include "../sysfs.h"
>>> +
>>> +/*
>>> + * ADT7408 registers definition
>>> + */
>>> +
>>> +#define ADT7408_CAPABILITY 0
>>> +#define ADT7408_CONFIG 1
>>> +#define ADT7408_T_ALARM_HIGH 2
>>> +#define ADT7408_T_ALARM_LOW 3
>>> +#define ADT7408_T_CRIT 4
>>> +#define ADT7408_TEMPERATURE 5
>>> +#define ADT7408_MANUFACTURER_ID 6
>>> +#define ADT7408_DEVICE_ID 7
>>> +
>>> +/*
>>> + * ADT7408 capability
>>> + */
>>> +#define ADT7408_CAP_ALARM_CRIT_TRIPS 0x1
>>> +#define ADT7408_CAP_HIGH_PRECISION 0x2
>>> +#define ADT7408_CAP_WIDER_RANGE 0x4
>>> +#define ADT7408_CAP_T_RESOLUTION_MASK 0x18
>>> +#define ADT7408_CAP_T_RESOLUTION_HIGH 0x18
>>> +#define ADT7408_CAP_T_RESOLUTION_LOW 0x8
>>> +
>>> +/*
>>> + * ADT7408 config
>>> + */
>>> +#define ADT7408_EVENT_MODE 0x1
>>> +#define ADT7408_EVENT_POLARITY 0x2
>>> +#define ADT7408_EVENT_CRIT_ONLY 0x4
>>> +#define ADT7408_EVENT_ENABLE 0x8
>>> +#define ADT7408_EVENT_STATUS 0x10
>>> +#define ADT7408_EVENT_CLEAR 0x20
>>> +#define ADT7408_EVENT_ALARM_LOCK 0x40
>>> +#define ADT7408_EVENT_CRIT_LOCK 0x80
>>> +#define ADT7408_PD 0x100
>>> +#define ADT7408_HISTERESIS_MASK 0x600
>>> +#define ADT7408_HISTERESIS_1_5 0x200
>>> +#define ADT7408_HISTERESIS_3 0x400
>>> +#define ADT7408_HISTERESIS_6 0x600
>>> +
>>> +/*
>>> + * ADT7408 masks
>>> + */
>>> +#define ADT7408_BOUND_VALUE_SIGN 0x400
>>> +#define ADT7408_BOUND_VALUE_OFFSET 2
>>> +#define ADT7408_BOUND_VALUE_FLOAT_OFFSET 2
>>> +#define ADT7408_BOUND_VALUE_FLOAT_MASK 0x3
>>> +#define ADT7408_T_VALUE_SIGN 0x1000
>>> +#define ADT7408_T_VALUE_FLOAT_OFFSET 4
>>> +#define ADT7408_T_VALUE_FLOAT_MASK 0xF
>>> +
>>> +/*
>>> + * ADT7408 event source
>>> + */
>>> +#define ADT7408_T_BELLOW_ALARM 0x2000
>>> +#define ADT7408_T_ABOVE_ALARM 0x4000
>>> +#define ADT7408_T_ABOVE_CRIT 0x8000
>>> +
>>> +
>>> +/*
>>> + * struct adt7408_chip_info - chip specifc information */
>>> +
>>> +struct adt7408_chip_info {
>>> + const char *name;
>>> + struct i2c_client *client;
>>> + struct iio_dev *indio_dev;
>>> + struct work_struct thresh_work;
>>> + s64 last_timestamp;
>>> + u16 config;
>>> +};
>>> +
>>> +/*
>>> + * adt7408 register access by I2C
>>> + */
>>> +
>>> +static int adt7408_i2c_read(struct adt7408_chip_info *chip, u8 reg,
>>> +u16 *data) {
>>> + struct i2c_client *client = chip->client;
>>> + int ret = 0;
>>> +
>>> + ret = i2c_smbus_read_word_data(client, reg);
>>> + if (ret < 0) {
>>> + dev_err(&client->dev, "I2C read error\n");
>>> + return ret;
>>> + }
>>> +
>>> + *data = swab16((u16)ret);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int adt7408_i2c_write(struct adt7408_chip_info
>> *chip, u8 reg,
>>> +u16 data) {
>>> + struct i2c_client *client = chip->client;
>>> + int ret = 0;
>>> +
>>> + ret = i2c_smbus_write_word_data(client, reg, swab16(data));
>>> + if (ret < 0)
>>> + dev_err(&client->dev, "I2C write error\n");
>>> +
>>> + return ret;
>>> +}
>>> +
>>> +static int adt7408_is_event_locked(struct adt7408_chip_info *chip) {
>>> + return chip->config & (ADT7408_EVENT_ALARM_LOCK |
>>> +ADT7408_EVENT_ALARM_LOCK); }
>>> +
>>> +static ssize_t adt7408_show_mode(struct device *dev,
>>> + struct device_attribute *attr,
>>> + char *buf)
>>> +{
>>> + struct iio_dev *dev_info = dev_get_drvdata(dev);
>>> + struct adt7408_chip_info *chip = dev_info->dev_data;
>>> +
>>> + if (chip->config & ADT7408_PD)
>>> + return sprintf(buf, "power-save\n");
>>> + else
>>> + return sprintf(buf, "full\n");
>>> +}
>>> +
>>> +static ssize_t adt7408_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 adt7408_chip_info *chip = dev_info->dev_data;
>>> + u16 config;
>>> + int ret;
>>> +
>>> + if (adt7408_is_event_locked(chip)) {
>>> + dev_err(dev, "Warning: Events are locked.\n");
>>> + return -EIO;
>>> + }
>>> +
>>> + ret = adt7408_i2c_read(chip, ADT7408_CONFIG, &chip->config);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + config = chip->config & (~ADT7408_PD);
>>> + if (!strcmp(buf, "full"))
>>> + config |= ADT7408_PD;
>>> +
>>> + ret = adt7408_i2c_write(chip, ADT7408_CONFIG, config);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + chip->config = config;
>>> +
>>> + return ret;
>>> +}
>>> +
>>> +static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
>>> + adt7408_show_mode,
>>> + adt7408_store_mode,
>>> + 0);
>>> +
>>> +static ssize_t adt7408_show_available_modes(struct device *dev,
>>> + struct device_attribute *attr,
>>> + char *buf)
>>> +{
>>> + return sprintf(buf, "full\npower-down\n"); }
>>> +
>>> +static IIO_DEVICE_ATTR(available_modes, S_IRUGO,
>>> +adt7408_show_available_modes, NULL, 0);
>>> +
>>> +static ssize_t adt7408_show_capability(struct device *dev,
>>> + struct device_attribute *attr,
>>> + char *buf)
>>> +{
>>> + struct iio_dev *dev_info = dev_get_drvdata(dev);
>>> + struct adt7408_chip_info *chip = dev_info->dev_data;
>>> + u16 capability;
>>> + int ret;
>>> +
>>> + ret = adt7408_i2c_read(chip, ADT7408_CAPABILITY, &capability);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + return sprintf(buf, "0x%x\n", capability); }
>>> +
>>> +static IIO_DEVICE_ATTR(capability, S_IRUGO | S_IWUSR,
>>> + adt7408_show_capability,
>>> + NULL,
>>> + 0);
>>> +
>>> +static ssize_t adt7408_show_manufactory_id(struct device *dev,
>>> + struct device_attribute *attr,
>>> + char *buf)
>>> +{
>>> + struct iio_dev *dev_info = dev_get_drvdata(dev);
>>> + struct adt7408_chip_info *chip = dev_info->dev_data;
>>> + u16 id;
>>> + int ret;
>>> +
>>> + ret = adt7408_i2c_read(chip, ADT7408_MANUFACTURER_ID, &id);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + return sprintf(buf, "0x%x\n", id);
>>> +}
>>> +
>>> +static IIO_DEVICE_ATTR(manufactory_id, S_IRUGO | S_IWUSR,
>>> + adt7408_show_manufactory_id,
>>> + NULL,
>>> + 0);
>>> +
>>> +static ssize_t adt7408_show_device_id(struct device *dev,
>>> + struct device_attribute *attr,
>>> + char *buf)
>>> +{
>>> + struct iio_dev *dev_info = dev_get_drvdata(dev);
>>> + struct adt7408_chip_info *chip = dev_info->dev_data;
>>> + u16 id;
>>> + int ret;
>>> +
>>> + ret = adt7408_i2c_read(chip, ADT7408_MANUFACTURER_ID, &id);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + return sprintf(buf, "0x%x\n", id);
>>> +}
>>> +
>>> +static IIO_DEVICE_ATTR(device_id, S_IRUGO | S_IWUSR,
>>> + adt7408_show_device_id,
>>> + NULL,
>>> + 0);
>>> +
>>> +static ssize_t adt7408_show_value(struct device *dev,
>>> + struct device_attribute *attr,
>>> + char *buf)
>>> +{
>>> + struct iio_dev *dev_info = dev_get_drvdata(dev);
>>> + struct adt7408_chip_info *chip = dev_info->dev_data;
>>> + u16 data;
>>> + char sign = ' ';
>>> + int ret;
>>> +
>>> + if (chip->config & ADT7408_PD) {
>>> + dev_err(dev, "Can't read value in power-down mode.\n");
>>> + return -EIO;
>>> + }
>>> +
>>> + ret = adt7408_i2c_read(chip, ADT7408_TEMPERATURE, &data);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + if (data & ADT7408_T_VALUE_SIGN) {
>>> + /* convert supplement to positive value */
>>> + data = (ADT7408_T_VALUE_SIGN << 1) - data;
>>> + sign = '-';
>>> + }
>>> +
>>> + return sprintf(buf, "%c%d.%.4d\n", sign,
>>> + (data >> ADT7408_T_VALUE_FLOAT_OFFSET),
>>> + (data & ADT7408_T_VALUE_FLOAT_MASK) * 625); }
>>> +
>>> +static IIO_DEVICE_ATTR(value, S_IRUGO, adt7408_show_value, NULL, 0);
>>> +
>>> +static ssize_t adt7408_show_name(struct device *dev,
>>> + struct device_attribute *attr,
>>> + char *buf)
>>> +{
>>> + struct iio_dev *dev_info = dev_get_drvdata(dev);
>>> + struct adt7408_chip_info *chip = dev_info->dev_data;
>>> + return sprintf(buf, "%s\n", chip->name); }
>>> +
>>> +static IIO_DEVICE_ATTR(name, S_IRUGO, adt7408_show_name, NULL, 0);
>>> +
>>> +static struct attribute *adt7408_attributes[] = {
>>> + &iio_dev_attr_available_modes.dev_attr.attr,
>>> + &iio_dev_attr_mode.dev_attr.attr,
>>> + &iio_dev_attr_capability.dev_attr.attr,
>>> + &iio_dev_attr_device_id.dev_attr.attr,
>>> + &iio_dev_attr_manufactory_id.dev_attr.attr,
>>> + &iio_dev_attr_value.dev_attr.attr,
>>> + &iio_dev_attr_name.dev_attr.attr,
>>> + NULL,
>>> +};
>>> +
>>> +static const struct attribute_group adt7408_attribute_group = {
>>> + .attrs = adt7408_attributes,
>>> +};
>>> +
>>> +/*
>>> + * temperature bound events
>>> + */
>>> +
>>> +#define IIO_EVENT_CODE_ADT7408_ABOVE_ALARM
>> (IIO_EVENT_CODE_DEVICE_SPECIFIC + 1)
>>> +#define IIO_EVENT_CODE_ADT7408_BELLOW_ALARM
>> (IIO_EVENT_CODE_DEVICE_SPECIFIC + 2)
>>> +#define IIO_EVENT_CODE_ADT7408_ABOVE_CRIT
>> (IIO_EVENT_CODE_DEVICE_SPECIFIC + 3)
>>> +
>>> +static void adt7408_interrupt_bh(struct work_struct *work_s) {
>>> + struct adt7408_chip_info *chip =
>>> + container_of(work_s, struct adt7408_chip_info,
>> thresh_work);
>>> + u16 config;
>>> + u16 data;
>>> +
>>> + if (adt7408_i2c_read(chip, ADT7408_CONFIG, &chip->config))
>>> + return;
>>> +
>>> + if (!(chip->config & ADT7408_EVENT_STATUS))
>>> + return;
>>> +
>>> + config = chip->config & ~ADT7408_EVENT_CLEAR;
>>> + if (data)
>>> + config |= ADT7408_EVENT_CLEAR;
>>> +
>>> + adt7408_i2c_write(chip, ADT7408_CONFIG, config);
>>> +
>>> + if (adt7408_i2c_read(chip, ADT7408_TEMPERATURE, &data))
>>> + goto exit;
>>> +
>>> + if (data & ADT7408_T_ABOVE_ALARM)
>>> + iio_push_event(chip->indio_dev, 0,
>>> + IIO_EVENT_CODE_ADT7408_ABOVE_ALARM,
>>> + chip->last_timestamp);
>>> + if (data & ADT7408_T_BELLOW_ALARM)
>>> + iio_push_event(chip->indio_dev, 0,
>>> + IIO_EVENT_CODE_ADT7408_BELLOW_ALARM,
>>> + chip->last_timestamp);
>>> + if (data & ADT7408_T_ABOVE_CRIT)
>>> + iio_push_event(chip->indio_dev, 0,
>>> + IIO_EVENT_CODE_ADT7408_ABOVE_CRIT,
>>> + chip->last_timestamp);
>>> +exit:
>>> + enable_irq(chip->client->irq);
>>> +}
>>> +
>>> +static int adt7408_interrupt(struct iio_dev *dev_info,
>>> + int index,
>>> + s64 timestamp,
>>> + int no_test)
>>> +{
>>> + struct adt7408_chip_info *chip = dev_info->dev_data;
>>> +
>>> + chip->last_timestamp = timestamp;
>>> + schedule_work(&chip->thresh_work);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +IIO_EVENT_SH(adt7408, &adt7408_interrupt);
>>> +
>>> +static ssize_t adt7408_show_event_mode(struct device *dev,
>>> + struct device_attribute *attr,
>>> + char *buf)
>>> +{
>>> + struct iio_dev *dev_info = dev_get_drvdata(dev);
>>> + struct adt7408_chip_info *chip = dev_info->dev_data;
>>> + int ret;
>>> +
>>> + ret = adt7408_i2c_read(chip, ADT7408_CONFIG, &chip->config);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + if (chip->config & ADT7408_EVENT_MODE)
>>> + return sprintf(buf, "interrupt\n");
>>> + else
>>> + return sprintf(buf, "comparator\n"); }
>>> +
>>> +static ssize_t adt7408_set_event_mode(struct device *dev,
>>> + struct device_attribute *attr,
>>> + const char *buf,
>>> + size_t len)
>>> +{
>>> + struct iio_dev *dev_info = dev_get_drvdata(dev);
>>> + struct adt7408_chip_info *chip = dev_info->dev_data;
>>> + u16 config;
>>> + int ret;
>>> +
>>> + if (adt7408_is_event_locked(chip)) {
>>> + dev_err(dev, "Warning: Events are locked.\n");
>>> + return -EIO;
>>> + }
>>> +
>>> + ret = adt7408_i2c_read(chip, ADT7408_CONFIG, &chip->config);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + config = chip->config &= ~ADT7408_EVENT_MODE;
>>> + if (strcmp(buf, "comparator") != 0)
>>> + config |= ADT7408_EVENT_MODE;
>>> +
>>> + ret = adt7408_i2c_write(chip, ADT7408_CONFIG, config);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + chip->config = config;
>>> +
>>> + return ret;
>>> +}
>>> +
>>> +static ssize_t adt7408_show_available_event_modes(struct
>> device *dev,
>>> + struct device_attribute *attr,
>>> + char *buf)
>>> +{
>>> + return sprintf(buf, "comparator\ninterrupt\n"); }
>>> +
>>> +static ssize_t adt7408_show_event_crit_only(struct device *dev,
>>> + struct device_attribute *attr,
>>> + char *buf)
>>> +{
>>> + struct iio_dev *dev_info = dev_get_drvdata(dev);
>>> + struct adt7408_chip_info *chip = dev_info->dev_data;
>>> + int ret;
>>> +
>>> + ret = adt7408_i2c_read(chip, ADT7408_CONFIG, &chip->config);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + return sprintf(buf, "%d\n", !!(chip->config &
>>> +ADT7408_EVENT_CRIT_ONLY)); }
>>> +
>>> +static ssize_t adt7408_set_event_crit_only(struct device *dev,
>>> + struct device_attribute *attr,
>>> + const char *buf,
>>> + size_t len)
>>> +{
>>> + struct iio_dev *dev_info = dev_get_drvdata(dev);
>>> + struct adt7408_chip_info *chip = dev_info->dev_data;
>>> + unsigned long data = 0;
>>> + u16 config;
>>> + int ret;
>>> +
>>> + if (adt7408_is_event_locked(chip)) {
>>> + dev_err(dev, "Warning: Events are locked.\n");
>>> + return -EIO;
>>> + }
>>> +
>>> + ret = strict_strtoul(buf, 10, &data);
>>> + if (ret)
>>> + return -EINVAL;
>>> +
>>> + ret = adt7408_i2c_read(chip, ADT7408_CONFIG, &chip->config);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + config = chip->config &= ~ADT7408_EVENT_CRIT_ONLY;
>>> + if (data)
>>> + config |= ADT7408_EVENT_CRIT_ONLY;
>>> +
>>> + ret = adt7408_i2c_write(chip, ADT7408_CONFIG, config);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + chip->config = config;
>>> +
>>> + return ret;
>>> +}
>>> +
>>> +static ssize_t adt7408_show_event_enable(struct device *dev,
>>> + struct device_attribute *attr,
>>> + char *buf)
>>> +{
>>> + struct iio_dev *dev_info = dev_get_drvdata(dev);
>>> + struct adt7408_chip_info *chip = dev_info->dev_data;
>>> + int ret;
>>> +
>>> + ret = adt7408_i2c_read(chip, ADT7408_CONFIG, &chip->config);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + return sprintf(buf, "%d\n", !!(chip->config &
>>> +ADT7408_EVENT_ENABLE)); }
>>> +
>>> +static ssize_t adt7408_set_event_enable(struct device *dev,
>>> + struct device_attribute *attr,
>>> + const char *buf,
>>> + size_t len)
>>> +{
>>> + struct iio_dev *dev_info = dev_get_drvdata(dev);
>>> + struct adt7408_chip_info *chip = dev_info->dev_data;
>>> + unsigned long data;
>>> + u16 config;
>>> + int ret;
>>> +
>>> + if (adt7408_is_event_locked(chip)) {
>>> + dev_err(dev, "Warning: Events are locked.\n");
>>> + return -EIO;
>>> + }
>>> +
>>> + ret = strict_strtoul(buf, 10, &data);
>>> + if (ret)
>>> + return -EINVAL;
>>> +
>>> + ret = adt7408_i2c_read(chip, ADT7408_CONFIG, &chip->config);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + config = chip->config & ~ADT7408_EVENT_ENABLE;
>>> + if (data)
>>> + config |= ADT7408_EVENT_ENABLE;
>>> +
>>> + ret = adt7408_i2c_write(chip, ADT7408_CONFIG, config);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + chip->config = config;
>>> +
>>> + return ret;
>>> +}
>>> +
>>> +static ssize_t adt7408_show_alarm_lock(struct device *dev,
>>> + struct device_attribute *attr,
>>> + char *buf)
>>> +{
>>> + struct iio_dev *dev_info = dev_get_drvdata(dev);
>>> + struct adt7408_chip_info *chip = dev_info->dev_data;
>>> + int ret;
>>> +
>>> + ret = adt7408_i2c_read(chip, ADT7408_CONFIG, &chip->config);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + return sprintf(buf, "%d\n", !!(chip->config &
>>> +ADT7408_EVENT_ALARM_LOCK)); }
>>> +
>>> +static ssize_t adt7408_set_alarm_lock(struct device *dev,
>>> + struct device_attribute *attr,
>>> + const char *buf,
>>> + size_t len)
>>> +{
>>> + struct iio_dev *dev_info = dev_get_drvdata(dev);
>>> + struct adt7408_chip_info *chip = dev_info->dev_data;
>>> + unsigned long data;
>>> + u16 config;
>>> + int ret;
>>> +
>>> + ret = strict_strtoul(buf, 10, &data);
>>> + if (ret)
>>> + return -EINVAL;
>>> +
>>> + ret = adt7408_i2c_read(chip, ADT7408_CONFIG, &chip->config);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + config = chip->config & ~ADT7408_EVENT_ALARM_LOCK;
>>> + if (data)
>>> + config |= ADT7408_EVENT_ALARM_LOCK;
>>> +
>>> + ret = adt7408_i2c_write(chip, ADT7408_CONFIG, config);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + chip->config = config;
>>> +
>>> + return ret;
>>> +}
>>> +
>>> +static ssize_t adt7408_show_crit_lock(struct device *dev,
>>> + struct device_attribute *attr,
>>> + char *buf)
>>> +{
>>> + struct iio_dev *dev_info = dev_get_drvdata(dev);
>>> + struct adt7408_chip_info *chip = dev_info->dev_data;
>>> + int ret;
>>> +
>>> + ret = adt7408_i2c_read(chip, ADT7408_CONFIG, &chip->config);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + return sprintf(buf, "%d\n", !!(chip->config &
>>> +ADT7408_EVENT_CRIT_LOCK)); }
>>> +
>>> +static ssize_t adt7408_set_crit_lock(struct device *dev,
>>> + struct device_attribute *attr,
>>> + const char *buf,
>>> + size_t len)
>>> +{
>>> + struct iio_dev *dev_info = dev_get_drvdata(dev);
>>> + struct adt7408_chip_info *chip = dev_info->dev_data;
>>> + unsigned long data;
>>> + u16 config;
>>> + int ret;
>>> +
>>> + ret = strict_strtoul(buf, 10, &data);
>>> + if (ret)
>>> + return -EINVAL;
>>> +
>>> + ret = adt7408_i2c_read(chip, ADT7408_CONFIG, &chip->config);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + config = chip->config & ~ADT7408_EVENT_CRIT_LOCK;
>>> + if (data)
>>> + config |= ADT7408_EVENT_CRIT_LOCK;
>>> +
>>> + ret = adt7408_i2c_write(chip, ADT7408_CONFIG, config);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + chip->config = config;
>>> +
>>> + return ret;
>>> +}
>>> +
>>> +
>>> +static inline ssize_t adt7408_show_t_bound(struct device *dev,
>>> + struct device_attribute *attr,
>>> + u8 bound_reg,
>>> + char *buf)
>>> +{
>>> + struct iio_dev *dev_info = dev_get_drvdata(dev);
>>> + struct adt7408_chip_info *chip = dev_info->dev_data;
>>> + u16 data;
>>> + char sign = ' ';
>>> + int ret;
>>> +
>>> + ret = adt7408_i2c_read(chip, bound_reg, &data);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + data >>= ADT7408_BOUND_VALUE_OFFSET;
>>> + if (data & ADT7408_BOUND_VALUE_SIGN) {
>>> + /* convert supplement to positive value */
>>> + data = (ADT7408_BOUND_VALUE_SIGN << 1) - data;
>>> + sign = '-';
>>> + }
>>> +
>>> + return sprintf(buf, "%c%d.%.2d\n", sign,
>>> + data >> ADT7408_BOUND_VALUE_FLOAT_OFFSET,
>>> + (data & ADT7408_BOUND_VALUE_FLOAT_MASK) * 25); }
>>> +
>>> +static inline ssize_t adt7408_set_t_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 adt7408_chip_info *chip = dev_info->dev_data;
>>> + long tmp1, tmp2;
>>> + u16 data;
>>> + char *pos;
>>> + int ret;
>>> +
>>> + pos = strchr(buf, '.');
>>> +
>>> + ret = strict_strtol(buf, 10, &tmp1);
>>> +
>>> + if (ret || tmp1 > 127 || tmp1 < -128)
>>> + return -EINVAL;
>>> +
>>> + if (pos) {
>>> + len = strlen(pos);
>>> + if (len > ADT7408_BOUND_VALUE_FLOAT_OFFSET)
>>> + len = ADT7408_BOUND_VALUE_FLOAT_OFFSET;
>>> + pos[len] = 0;
>>> + ret = strict_strtol(pos, 10, &tmp2);
>>> +
>>> + if (!ret)
>>> + tmp2 = (tmp2 / 25) * 25;
>>> + }
>>> +
>>> + if (tmp1 < 0)
>>> + data = (u16)(-tmp1);
>>> + else
>>> + data = (u16)tmp1;
>>> + data = (data << ADT7408_BOUND_VALUE_FLOAT_OFFSET) |
>>> + (tmp2 & ADT7408_BOUND_VALUE_FLOAT_MASK);
>>> + if (tmp1 < 0)
>>> + /* convert positive value to supplyment */
>>> + data = (ADT7408_BOUND_VALUE_SIGN << 1) - data;
>>> + data <<= ADT7408_BOUND_VALUE_OFFSET;
>>> +
>>> + ret = adt7408_i2c_write(chip, bound_reg, data);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + return ret;
>>> +}
>>> +
>>> +static ssize_t adt7408_show_t_alarm_high(struct device *dev,
>>> + struct device_attribute *attr,
>>> + char *buf)
>>> +{
>>> + return adt7408_show_t_bound(dev, attr,
>>> + ADT7408_T_ALARM_HIGH, buf);
>>> +}
>>> +
>>> +static inline ssize_t adt7408_set_t_alarm_high(struct device *dev,
>>> + struct device_attribute *attr,
>>> + const char *buf,
>>> + size_t len)
>>> +{
>>> + return adt7408_set_t_bound(dev, attr,
>>> + ADT7408_T_ALARM_HIGH, buf, len);
>>> +}
>>> +
>>> +static ssize_t adt7408_show_t_alarm_low(struct device *dev,
>>> + struct device_attribute *attr,
>>> + char *buf)
>>> +{
>>> + return adt7408_show_t_bound(dev, attr,
>>> + ADT7408_T_ALARM_LOW, buf);
>>> +}
>>> +
>>> +static inline ssize_t adt7408_set_t_alarm_low(struct device *dev,
>>> + struct device_attribute *attr,
>>> + const char *buf,
>>> + size_t len)
>>> +{
>>> + return adt7408_set_t_bound(dev, attr,
>>> + ADT7408_T_ALARM_LOW, buf, len);
>>> +}
>>> +
>>> +static ssize_t adt7408_show_t_crit(struct device *dev,
>>> + struct device_attribute *attr,
>>> + char *buf)
>>> +{
>>> + return adt7408_show_t_bound(dev, attr,
>>> + ADT7408_T_CRIT, buf);
>>> +}
>>> +
>>> +static inline ssize_t adt7408_set_t_crit(struct device *dev,
>>> + struct device_attribute *attr,
>>> + const char *buf,
>>> + size_t len)
>>> +{
>>> + return adt7408_set_t_bound(dev, attr,
>>> + ADT7408_T_CRIT, buf, len);
>>> +}
>>> +
>>> +static ssize_t adt7408_show_t_hyst(struct device *dev,
>>> + struct device_attribute *attr,
>>> + char *buf)
>>> +{
>>> + struct iio_dev *dev_info = dev_get_drvdata(dev);
>>> + struct adt7408_chip_info *chip = dev_info->dev_data;
>>> + int ret;
>>> +
>>> + /* retrive ALART status */
>>> + ret = adt7408_i2c_read(chip, ADT7408_CONFIG, &chip->config);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + switch (chip->config & ADT7408_HISTERESIS_MASK) {
>>> + case ADT7408_HISTERESIS_1_5:
>>> + return sprintf(buf, "1.5\n");
>>> + case ADT7408_HISTERESIS_3:
>>> + return sprintf(buf, "3\n");
>>> + case ADT7408_HISTERESIS_6:
>>> + return sprintf(buf, "6\n");
>>> + default:
>>> + return sprintf(buf, "Disabled\n");
>>> + }
>>> +}
>>> +
>>> +static inline ssize_t adt7408_set_t_hyst(struct device *dev,
>>> + struct device_attribute *attr,
>>> + const char *buf,
>>> + size_t len)
>>> +{
>>> + struct iio_dev *dev_info = dev_get_drvdata(dev);
>>> + struct adt7408_chip_info *chip = dev_info->dev_data;
>>> + int ret;
>>> + u16 config = 0;
>>> +
>>> + if (strcmp(buf, "disble"))
>>> + config = ADT7408_HISTERESIS_MASK;
>>> + else if (strcmp(buf, "1.5"))
>>> + config = ADT7408_HISTERESIS_1_5;
>>> + else if (len > 1 && buf[0] == '3')
>>> + config = ADT7408_HISTERESIS_6;
>>> + else if (len > 1 && buf[0] == '6')
>>> + config = ADT7408_HISTERESIS_6;
>>> +
>>> + if (!config)
>>> + return -EINVAL;
>>> +
>>> + /* retrive ALART status */
>>> + ret = adt7408_i2c_read(chip, ADT7408_CONFIG, &chip->config);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + config |= chip->config & ~ADT7408_HISTERESIS_MASK;
>>> +
>>> + ret = adt7408_i2c_write(chip, ADT7408_CONFIG, config);
>>> + if (ret)
>>> + return -EIO;
>>> +
>>> + chip->config = config;
>>> + return ret;
>>> +}
>>> +
>>> +static ssize_t adt7408_show_available_t_hyst(struct device *dev,
>>> + struct device_attribute *attr,
>>> + char *buf)
>>> +{
>>> + return sprintf(buf, "1.5\n3\n6\ndisable\n"); }
>>> +
>>> +IIO_EVENT_ATTR_SH(event_mode, iio_event_adt7408,
>>> + adt7408_show_event_mode, adt7408_set_event_mode, 0);
>>> +IIO_EVENT_ATTR_SH(available_event_modes, iio_event_adt7408,
>>> + adt7408_show_available_event_modes, NULL, 0);
>>> +IIO_EVENT_ATTR_SH(event_crit_only, iio_event_adt7408,
>>> + adt7408_show_event_crit_only,
>> adt7408_set_event_crit_only, 0);
>>> +IIO_EVENT_ATTR_SH(event_enable, iio_event_adt7408,
>>> + adt7408_show_event_enable,
>> adt7408_set_event_enable, 0);
>>> +IIO_EVENT_ATTR_SH(alarm_lock, iio_event_adt7408,
>>> + adt7408_show_alarm_lock, adt7408_set_alarm_lock, 0);
>>> +IIO_EVENT_ATTR_SH(crit_lock, iio_event_adt7408,
>>> + adt7408_show_crit_lock, adt7408_set_crit_lock, 0);
>>> +IIO_EVENT_ATTR_SH(t_alarm_high, iio_event_adt7408,
>>> + adt7408_show_t_alarm_high,
>> adt7408_set_t_alarm_high, 0);
>>> +IIO_EVENT_ATTR_SH(t_alarm_low, iio_event_adt7408,
>>> + adt7408_show_t_alarm_low, adt7408_set_t_alarm_low, 0);
>>> +IIO_EVENT_ATTR_SH(t_crit, iio_event_adt7408,
>>> + adt7408_show_t_crit, adt7408_set_t_crit, 0);
>>> +IIO_EVENT_ATTR_SH(t_hyst, iio_event_adt7408,
>>> + adt7408_show_t_hyst, adt7408_set_t_hyst, 0);
>>> +IIO_EVENT_ATTR_SH(available_t_hyst, iio_event_adt7408,
>>> + adt7408_show_available_t_hyst, NULL, 0);
>>> +
>>> +static struct attribute *adt7408_event_attributes[] = {
>>> + &iio_event_attr_event_mode.dev_attr.attr,
>>> + &iio_event_attr_available_event_modes.dev_attr.attr,
>>> + &iio_event_attr_event_crit_only.dev_attr.attr,
>>> + &iio_event_attr_event_enable.dev_attr.attr,
>>> + &iio_event_attr_alarm_lock.dev_attr.attr,
>>> + &iio_event_attr_crit_lock.dev_attr.attr,
>>> + &iio_event_attr_t_alarm_high.dev_attr.attr,
>>> + &iio_event_attr_t_alarm_low.dev_attr.attr,
>>> + &iio_event_attr_t_crit.dev_attr.attr,
>>> + &iio_event_attr_t_hyst.dev_attr.attr,
>>> + &iio_event_attr_available_t_hyst.dev_attr.attr,
>>> + NULL,
>>> +};
>>> +
>>> +static struct attribute_group adt7408_event_attribute_group = {
>>> + .attrs = adt7408_event_attributes,
>>> +};
>>> +
>>> +/*
>>> + * device probe and remove
>>> + */
>>> +
>>> +static int __devinit adt7408_probe(struct i2c_client *client,
>>> + const struct i2c_device_id *id)
>>> +{
>>> + struct adt7408_chip_info *chip;
>>> + int ret = 0;
>>> +
>>> + chip = kzalloc(sizeof(struct adt7408_chip_info), GFP_KERNEL);
>>> +
>>> + if (chip == NULL)
>>> + return -ENOMEM;
>>> +
>>> + /* this is only used for device removal purposes */
>>> + i2c_set_clientdata(client, chip);
>>> +
>>> + chip->client = client;
>>> + chip->name = id->name;
>>> +
>>> + chip->indio_dev = iio_allocate_device();
>>> + if (chip->indio_dev == NULL) {
>>> + ret = -ENOMEM;
>>> + goto error_free_chip;
>>> + }
>>> +
>>> + chip->indio_dev->dev.parent = &client->dev;
>>> + chip->indio_dev->attrs = &adt7408_attribute_group;
>>> + chip->indio_dev->event_attrs = &adt7408_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 (client->irq) {
>>> + ret = iio_register_interrupt_line(client->irq,
>>> + chip->indio_dev,
>>> + 0,
>>> + client->irq_flags,
>>> + chip->name);
>>> + if (ret)
>>> + goto error_unreg_dev;
>>> +
>>> + /*
>>> + * The event handler list element refer to
>> iio_event_adt7408.
>>> + * All event attributes bind to the same event handler.
>>> + * So, only register event handler once.
>>> + */
>>> + iio_add_event_to_list(&iio_event_adt7408,
>>> +
>> &chip->indio_dev->interrupts[0]->ev_list);
>>> +
>>> + INIT_WORK(&chip->thresh_work, adt7408_interrupt_bh);
>>> +
>>> + ret = adt7408_i2c_read(chip, ADT7408_CONFIG,
>> &chip->config);
>>> + if (ret) {
>>> + ret = -EIO;
>>> + goto error_unreg_irq;
>>> + }
>>> +
>>> + if (client->irq_flags & IRQF_TRIGGER_HIGH)
>>> + chip->config |= ADT7408_EVENT_POLARITY;
>>> + else
>>> + chip->config &= ~ADT7408_EVENT_POLARITY;
>>> +
>>> + ret = adt7408_i2c_write(chip, ADT7408_CONFIG,
>> chip->config);
>>> + if (ret) {
>>> + ret = -EIO;
>>> + goto error_unreg_irq;
>>> + }
>>> + }
>>> +
>>> + dev_info(&client->dev, "%s temperature sensor registered.\n",
>>> + id->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;
>>> +}
>>> +
>>> +static int __devexit adt7408_remove(struct i2c_client *client) {
>>> + struct adt7408_chip_info *chip = i2c_get_clientdata(client);
>>> + struct iio_dev *indio_dev = chip->indio_dev;
>>> +
>>> + if (client->irq)
>>> + iio_unregister_interrupt_line(indio_dev, 0);
>>> + iio_device_unregister(indio_dev);
>>> + iio_free_device(chip->indio_dev);
>>> + kfree(chip);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static const struct i2c_device_id adt7408_id[] = {
>>> + { "adt7408", 0 },
>>> + {}
>>> +};
>>> +
>>> +MODULE_DEVICE_TABLE(i2c, adt7408_id);
>>> +
>>> +static struct i2c_driver adt7408_driver = {
>>> + .driver = {
>>> + .name = "adt7408",
>>> + },
>>> + .probe = adt7408_probe,
>>> + .remove = __devexit_p(adt7408_remove),
>>> + .id_table = adt7408_id,
>>> +};
>>> +
>>> +static __init int adt7408_init(void)
>>> +{
>>> + return i2c_add_driver(&adt7408_driver); }
>>> +
>>> +static __exit void adt7408_exit(void) {
>>> + i2c_del_driver(&adt7408_driver);
>>> +}
>>> +
>>> +MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
>>> +MODULE_DESCRIPTION("Analog Devices ADT7408 digital"
>>> + " temperature sensor driver");
>>> +MODULE_LICENSE("GPL v2");
>>> +
>>> +module_init(adt7408_init);
>>> +module_exit(adt7408_exit);
>>
>>
>
next prev parent reply other threads:[~2010-10-26 9:09 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-10-23 20:29 [PATCH 01/14] staging: iio: adc: new driver for AD7152/3 devices Mike Frysinger
2010-10-23 20:29 ` [PATCH 02/14] staging: iio: adc: new driver for AD7291 devices Mike Frysinger
2010-10-24 21:32 ` Jonathan Cameron
2010-10-23 20:29 ` [PATCH 03/14] staging: iio: adc: new driver for AD7298 devices Mike Frysinger
2010-10-24 21:49 ` Jonathan Cameron
2010-10-23 20:29 ` [PATCH 04/14] staging: iio: adc: new driver for AD7314 devices Mike Frysinger
2010-10-24 21:56 ` Jonathan Cameron
2010-10-26 3:35 ` Zhang, Sonic
2010-10-23 20:29 ` [PATCH 05/14] staging: iio: adc: new driver for AD7414/5 devices Mike Frysinger
2010-10-24 22:03 ` Jonathan Cameron
2010-10-23 20:29 ` [PATCH 06/14] staging: iio: adc: new driver for AD7416/7/8 devices Mike Frysinger
2010-10-24 22:19 ` Jonathan Cameron
2010-10-23 20:29 ` [PATCH 07/14] staging: iio: adc: new driver for AD7475/6/6A/7/7A/8/8A and AD7495 devices Mike Frysinger
2010-10-24 21:14 ` [Device-drivers-devel] " Mike Frysinger
2010-10-24 22:21 ` Jonathan Cameron
2010-10-23 20:29 ` [PATCH 08/14] staging: iio: adc: new driver for AD7745/6/7 devices Mike Frysinger
2010-10-24 22:36 ` Jonathan Cameron
2010-10-23 20:29 ` [PATCH 09/14] staging: iio: adc: new driver for AD7816 devices Mike Frysinger
2010-10-23 20:29 ` [PATCH 10/14] staging: iio: adc: new driver for ADT75 temperature sensors Mike Frysinger
2010-10-23 20:29 ` [PATCH 11/14] staging: iio: adc: new driver for ADT7310 " Mike Frysinger
2010-10-23 20:29 ` [PATCH 12/14] staging: iio: adc: new driver for ADT7408 " Mike Frysinger
2010-10-24 22:53 ` Jonathan Cameron
2010-10-24 23:47 ` Guenter Roeck
2010-10-25 10:28 ` Jonathan Cameron
2010-10-26 4:20 ` Zhang, Sonic
2010-10-26 5:08 ` Guenter Roeck
2010-10-26 5:38 ` Zhang, Sonic
2010-10-26 9:14 ` Jonathan Cameron
2010-10-25 0:46 ` Guenter Roeck
2010-10-25 10:32 ` Jonathan Cameron
2010-10-25 11:19 ` Guenter Roeck
2010-10-25 11:43 ` Jonathan Cameron
2010-10-25 14:12 ` Guenter Roeck
2010-10-25 16:18 ` Hennerich, Michael
2010-10-25 11:47 ` [Device-drivers-devel] " Hennerich, Michael
2010-10-26 3:21 ` Zhang, Sonic
2010-10-26 3:27 ` Zhang, Sonic
2010-10-26 3:52 ` Guenter Roeck
2010-10-26 9:15 ` Jonathan Cameron [this message]
2010-10-26 14:33 ` Guenter Roeck
2010-11-01 10:56 ` Jonathan Cameron
2010-11-01 14:37 ` Guenter Roeck
2010-11-01 15:19 ` Jonathan Cameron
2010-10-23 20:29 ` [PATCH 13/14] staging: iio: adc: new driver for ADT7410 " Mike Frysinger
2010-10-23 20:29 ` [PATCH 14/14] staging: iio: adc: new ad799x driver Mike Frysinger
2010-10-24 21:14 ` [Device-drivers-devel] " Mike Frysinger
2010-10-24 22:55 ` Jonathan Cameron
2010-10-24 21:09 ` [PATCH 01/14] staging: iio: adc: new driver for AD7152/3 devices Jonathan Cameron
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4CC69C32.9030205@cam.ac.uk \
--to=jic23@cam.ac.uk \
--cc=Sonic.Zhang@analog.com \
--cc=device-drivers-devel@blackfin.uclinux.org \
--cc=guenter.roeck@ericsson.com \
--cc=linux-iio@vger.kernel.org \
--cc=vapier@gentoo.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox