> Add Holt descrete ADC driver for HI-8435/8436/8437 chips discrete link to datasheet would be nice, comments below what is the purpose of the driver? the driver-specific ABI needs to be documented under Documentation/ABI/testing/sys-bus-iio-* > > Signed-off-by: Vladimir Barinov <vladimir.barinov@xxxxxxxxxxxxxxxxxx> > --- > drivers/iio/adc/Kconfig | 12 + > drivers/iio/adc/Makefile | 1 + > drivers/iio/adc/hi-843x.c | 777 ++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 790 insertions(+) > create mode 100644 drivers/iio/adc/hi-843x.c > > diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig > index e36a73e..71b0efc 100644 > --- a/drivers/iio/adc/Kconfig > +++ b/drivers/iio/adc/Kconfig > @@ -164,6 +164,18 @@ config EXYNOS_ADC > of SoCs for drivers such as the touchscreen and hwmon to use to share > this resource. > > +config HI_843X we recommend against using a placeholder in a drivers name; we suggest to name the driver after the first/primary chip it supports (that you test with most) > + tristate "Holt Integrated Circuits HI-8435/8436/8437" > + select IIO_BUFFER > + select IIO_TRIGGERED_BUFFER > + depends on SPI > + help > + If you say yes here you get support for Holt Integrated Circuits > + HI-8435/8436/8437 chip. > + > + This driver can also be built as a module. If so, the module will be > + called hi-843x. > + > config LP8788_ADC > tristate "LP8788 ADC driver" > depends on MFD_LP8788 > diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile > index 3930e63..65f54c2 100644 > --- a/drivers/iio/adc/Makefile > +++ b/drivers/iio/adc/Makefile > @@ -18,6 +18,7 @@ obj-$(CONFIG_AXP288_ADC) += axp288_adc.o > obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o > obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o > obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o > +obj-$(CONFIG_HI_843X) += hi-843x.o > obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o > obj-$(CONFIG_MAX1027) += max1027.o > obj-$(CONFIG_MAX1363) += max1363.o > diff --git a/drivers/iio/adc/hi-843x.c b/drivers/iio/adc/hi-843x.c > new file mode 100644 > index 0000000..ccc46e7 > --- /dev/null > +++ b/drivers/iio/adc/hi-843x.c > @@ -0,0 +1,777 @@ > +/* > + * Holt Integrated Circuits HI-8435/8436/8437 discrete ADC driver > + * > + * Copyright (C) 2015 Zodiac Inflight Innovations > + * Copyright (C) 2015 Cogent Embedded, Inc. > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License as published by the > + * Free Software Foundation; either version 2 of the License, or (at your > + * option) any later version. > + */ > + > +#include <linux/delay.h> > +#include <linux/iio/buffer.h> > +#include <linux/iio/iio.h> > +#include <linux/iio/sysfs.h> > +#include <linux/iio/trigger.h> > +#include <linux/iio/trigger_consumer.h> > +#include <linux/iio/triggered_buffer.h> > +#include <linux/module.h> > +#include <linux/of.h> > +#include <linux/of_device.h> > +#include <linux/of_gpio.h> > +#include <linux/spi/spi.h> > +#include <linux/workqueue.h> > + > +#include <linux/interrupt.h> > + > +#define DRV_NAME "hi-843x" HI84.. prefix > + > +/* Register offsets for HI-843X */ > +#define HI843X_CTRL_REG 0x02 > +#define HI843X_PSEN_REG 0x04 > +#define HI843X_TMDATA_REG 0x1E > +#define HI843X_GOCENHYS_REG 0x3A > +#define HI843X_SOCENHYS_REG 0x3C > +#define HI843X_SO7_0_REG 0x10 > +#define HI843X_SO15_8_REG 0x12 > +#define HI843X_SO23_16_REG 0x14 > +#define HI843X_SO31_24_REG 0x16 > +#define HI843X_SO31_0_REG 0x78 > + > +#define HI843X_WRITE_OPCODE 0x00 > +#define HI843X_READ_OPCODE 0x80 > + > +/* THRESHOLD mask */ > +#define HI843X_THRESHOLD_MAX 0x3f > +#define HI843X_THRESHOLD_MASK 0xff > + > +/* CTRL register bits */ > +#define HI843X_CTRL_TEST 0x01 > +#define HI843X_CTRL_SRST 0x02 > + > +#define HI843X_DEBOUNCE_SOFT_DELAY_MAX 1000 /* ms */ > +#define HI843X_DEBOUNCE_SOFT_DELAY_DEF 100 /* ms */ > + > +struct hi843x_priv { > + struct spi_device *spi; > + struct mutex lock; > + struct delayed_work work; > + > + int mr_gpio; > + bool debounce_soft; > + int debounce_soft_delay; > + int debounce_soft_val; > + > + void *iio_buffer; > + u8 reg_buffer[4] ____cacheline_aligned; > +}; > + > +static int hi843x_readb(struct hi843x_priv *priv, u8 reg, u8 *val) > +{ > + reg |= HI843X_READ_OPCODE; > + return spi_write_then_read(priv->spi, ®, 1, val, 1); > +} > + > +static int hi843x_readw(struct hi843x_priv *priv, u8 reg, u16 *val) > +{ > + int ret; > + > + reg |= HI843X_READ_OPCODE; > + ret = spi_write_then_read(priv->spi, ®, 1, val, 2); > + *val = swab16p(val); will this work on big- and little-endian CPUs? > + > + return ret; > +} > + > +static int hi843x_readl(struct hi843x_priv *priv, u8 reg, u32 *val) > +{ > + int ret; > + > + reg |= HI843X_READ_OPCODE; > + ret = spi_write_then_read(priv->spi, ®, 1, val, 4); > + *val = swab32p(val); > + > + return ret; > +} > + > +static int hi843x_writeb(struct hi843x_priv *priv, u8 reg, u8 val) > +{ > + priv->reg_buffer[0] = reg | HI843X_WRITE_OPCODE; > + priv->reg_buffer[1] = val; > + > + return spi_write(priv->spi, priv->reg_buffer, 2); > +} > + > +static int hi843x_writew(struct hi843x_priv *priv, u8 reg, u16 val) > +{ > + priv->reg_buffer[0] = reg | HI843X_WRITE_OPCODE; > + priv->reg_buffer[1] = (val >> 8) & 0xff; > + priv->reg_buffer[2] = val & 0xff; > + > + return spi_write(priv->spi, priv->reg_buffer, 3); > +} > + > +ssize_t hi843x_debounce_soft_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct hi843x_priv *priv = iio_priv(dev_to_iio_dev(dev)); > + > + return sprintf(buf, "%d\n", priv->debounce_soft); > +} > + > +ssize_t hi843x_debounce_soft_delay_show(struct device *dev, > + struct device_attribute *attr, > + char *buf) > +{ > + struct hi843x_priv *priv = iio_priv(dev_to_iio_dev(dev)); > + > + return sprintf(buf, "%d\n", priv->debounce_soft_delay); > +} > + > +ssize_t hi843x_sensing_mode_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct hi843x_priv *priv = iio_priv(dev_to_iio_dev(dev)); > + int ret; > + u8 reg; > + > + ret = hi843x_readb(priv, HI843X_PSEN_REG, ®); > + if (ret < 0) > + return ret; > + > + return sprintf(buf, "%d\n", reg); > +} > + > +ssize_t hi843x_test_enable_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct hi843x_priv *priv = iio_priv(dev_to_iio_dev(dev)); > + int ret; > + u8 reg; > + > + ret = hi843x_readb(priv, HI843X_CTRL_REG, ®); > + if (ret < 0) > + return ret; > + > + return sprintf(buf, "%d\n", reg & HI843X_CTRL_TEST); > +} > + > +ssize_t hi843x_test_mode_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct hi843x_priv *priv = iio_priv(dev_to_iio_dev(dev)); > + int ret; > + u8 reg; > + > + ret = hi843x_readb(priv, HI843X_TMDATA_REG, ®); > + if (ret < 0) > + return ret; > + > + return sprintf(buf, "%d\n", reg); > +} > + > +ssize_t hi843x_debounce_soft_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t len) > +{ > + struct hi843x_priv *priv = iio_priv(dev_to_iio_dev(dev)); > + unsigned int val; > + int ret; > + > + ret = kstrtouint(buf, 10, &val); > + if (ret) > + return ret; > + > + priv->debounce_soft = !!val; > + > + return len; > +} > + > +ssize_t hi843x_debounce_soft_delay_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t len) > +{ > + struct hi843x_priv *priv = iio_priv(dev_to_iio_dev(dev)); > + unsigned int val; > + int ret; > + > + ret = kstrtouint(buf, 10, &val); > + if (ret) > + return ret; > + > + if (val > HI843X_DEBOUNCE_SOFT_DELAY_MAX) > + val = HI843X_DEBOUNCE_SOFT_DELAY_MAX; > + > + priv->debounce_soft_delay = val; > + > + return len; > +} > + > +ssize_t hi843x_sensing_mode_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t len) > +{ > + struct hi843x_priv *priv = iio_priv(dev_to_iio_dev(dev)); > + unsigned int val; > + int ret; > + > + ret = kstrtouint(buf, 10, &val); > + if (ret) > + return ret; > + > + hi843x_writeb(priv, HI843X_PSEN_REG, val & 0xf); > + > + return len; > +} > + > +ssize_t hi843x_test_enable_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t len) > +{ > + struct hi843x_priv *priv = iio_priv(dev_to_iio_dev(dev)); > + unsigned int val; > + int ret; > + > + ret = kstrtouint(buf, 10, &val); > + if (ret) > + return ret; > + > + hi843x_writeb(priv, HI843X_CTRL_REG, val ? HI843X_CTRL_TEST : 0); > + > + return len; > +} > + > +ssize_t hi843x_test_mode_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t len) > +{ > + struct hi843x_priv *priv = iio_priv(dev_to_iio_dev(dev)); > + unsigned int val; > + int ret; > + > + ret = kstrtouint(buf, 10, &val); > + if (ret) > + return ret; > + > + hi843x_writeb(priv, HI843X_TMDATA_REG, val & 0xf); > + > + return len; > +} > + > +ssize_t hi843x_threshold_gohys_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct hi843x_priv *priv = iio_priv(dev_to_iio_dev(dev)); > + int ret; > + u16 reg; > + > + ret = hi843x_readw(priv, HI843X_GOCENHYS_REG, ®); > + if (ret < 0) > + return ret; > + > + return sprintf(buf, "%d\n", (reg >> 8) & HI843X_THRESHOLD_MASK); > +} > + > +ssize_t hi843x_threshold_gocval_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct hi843x_priv *priv = iio_priv(dev_to_iio_dev(dev)); > + int ret; > + u16 reg; > + > + ret = hi843x_readw(priv, HI843X_GOCENHYS_REG, ®); > + if (ret < 0) > + return ret; > + > + return sprintf(buf, "%d\n", reg & HI843X_THRESHOLD_MASK); > +} > + > +ssize_t hi843x_threshold_sohys_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct hi843x_priv *priv = iio_priv(dev_to_iio_dev(dev)); > + int ret; > + u16 reg; > + > + ret = hi843x_readw(priv, HI843X_SOCENHYS_REG, ®); > + if (ret < 0) > + return ret; > + > + return sprintf(buf, "%d\n", (reg >> 8) & HI843X_THRESHOLD_MASK); > +} > + > +ssize_t hi843x_threshold_socval_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct hi843x_priv *priv = iio_priv(dev_to_iio_dev(dev)); > + int ret; > + u16 reg; > + > + ret = hi843x_readw(priv, HI843X_SOCENHYS_REG, ®); > + if (ret < 0) > + return ret; > + > + return sprintf(buf, "%d\n", reg & HI843X_THRESHOLD_MASK); > +} > + > +ssize_t hi843x_threshold_gohys_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t len) > +{ > + struct hi843x_priv *priv = iio_priv(dev_to_iio_dev(dev)); > + unsigned int val, ret; > + u16 reg; > + > + ret = kstrtouint(buf, 10, &val); > + if (ret) > + return ret; > + > + if (val > HI843X_THRESHOLD_MAX) > + return -EINVAL; > + > + mutex_lock(&priv->lock); > + > + ret = hi843x_readw(priv, HI843X_GOCENHYS_REG, ®); > + if (ret < 0) { > + mutex_unlock(&priv->lock); > + return ret; > + } > + reg &= ~(HI843X_THRESHOLD_MASK << 8); > + reg |= (val << 8); > + hi843x_writew(priv, HI843X_GOCENHYS_REG, reg); > + > + mutex_unlock(&priv->lock); > + > + return len; > +} > + > +ssize_t hi843x_threshold_gocval_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t len) > +{ > + struct hi843x_priv *priv = iio_priv(dev_to_iio_dev(dev)); > + unsigned int val, ret; > + u16 reg; > + > + ret = kstrtouint(buf, 10, &val); > + if (ret) > + return ret; > + > + if (val > HI843X_THRESHOLD_MAX) > + return -EINVAL; > + > + mutex_lock(&priv->lock); > + > + ret = hi843x_readw(priv, HI843X_GOCENHYS_REG, ®); > + if (ret < 0) { > + mutex_unlock(&priv->lock); > + return ret; > + } > + reg &= ~HI843X_THRESHOLD_MASK; > + reg |= val; > + hi843x_writew(priv, HI843X_GOCENHYS_REG, reg); > + > + mutex_unlock(&priv->lock); > + > + return len; > +} > + > +ssize_t hi843x_threshold_sohys_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t len) > +{ > + struct hi843x_priv *priv = iio_priv(dev_to_iio_dev(dev)); > + unsigned int val, ret; > + u16 reg; > + > + ret = kstrtouint(buf, 10, &val); > + if (ret) > + return ret; > + > + if (val > HI843X_THRESHOLD_MAX) > + return -EINVAL; > + > + mutex_lock(&priv->lock); > + > + ret = hi843x_readw(priv, HI843X_SOCENHYS_REG, ®); > + if (ret < 0) { > + mutex_unlock(&priv->lock); > + return ret; > + } > + reg &= ~(HI843X_THRESHOLD_MASK << 8); > + reg |= (val << 8); > + hi843x_writew(priv, HI843X_SOCENHYS_REG, reg); > + > + mutex_unlock(&priv->lock); > + > + return len; > +} > + > +ssize_t hi843x_threshold_socval_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t len) > +{ > + struct hi843x_priv *priv = iio_priv(dev_to_iio_dev(dev)); > + unsigned int val, ret; > + u16 reg; > + > + ret = kstrtouint(buf, 10, &val); > + if (ret) > + return ret; > + > + if (val > HI843X_THRESHOLD_MAX) > + return -EINVAL; > + > + mutex_lock(&priv->lock); > + > + ret = hi843x_readw(priv, HI843X_SOCENHYS_REG, ®); > + if (ret < 0) { > + mutex_unlock(&priv->lock); > + return ret; > + } > + reg &= ~HI843X_THRESHOLD_MASK; > + reg |= val; > + hi843x_writew(priv, HI843X_SOCENHYS_REG, reg); > + > + mutex_unlock(&priv->lock); > + > + return len; > +} > + > +static IIO_DEVICE_ATTR(debounce_soft, S_IRUGO | S_IWUSR, > + hi843x_debounce_soft_show, hi843x_debounce_soft_store, 0); > +static IIO_DEVICE_ATTR(debounce_soft_delay, S_IRUGO | S_IWUSR, > + hi843x_debounce_soft_delay_show, hi843x_debounce_soft_delay_store, 0); > +static IIO_DEVICE_ATTR(sensing_mode, S_IRUGO | S_IWUSR, > + hi843x_sensing_mode_show, hi843x_sensing_mode_store, 0); > +static IIO_DEVICE_ATTR(test_enable, S_IRUGO | S_IWUSR, > + hi843x_test_enable_show, hi843x_test_enable_store, 0); > +static IIO_DEVICE_ATTR(test_mode, S_IRUGO | S_IWUSR, > + hi843x_test_mode_show, hi843x_test_mode_store, 0); > +static IIO_DEVICE_ATTR(threshold_gohys, S_IRUGO | S_IWUSR, > + hi843x_threshold_gohys_show, hi843x_threshold_gohys_store, 0); > +static IIO_DEVICE_ATTR(threshold_gocval, S_IRUGO | S_IWUSR, > + hi843x_threshold_gocval_show, hi843x_threshold_gocval_store, 0); > +static IIO_DEVICE_ATTR(threshold_sohys, S_IRUGO | S_IWUSR, > + hi843x_threshold_sohys_show, hi843x_threshold_sohys_store, 0); > +static IIO_DEVICE_ATTR(threshold_socval, S_IRUGO | S_IWUSR, > + hi843x_threshold_socval_show, hi843x_threshold_socval_store, 0); > + > +static struct attribute *hi843x_attributes[] = { > + &iio_dev_attr_debounce_soft.dev_attr.attr, > + &iio_dev_attr_debounce_soft_delay.dev_attr.attr, > + &iio_dev_attr_sensing_mode.dev_attr.attr, > + &iio_dev_attr_test_enable.dev_attr.attr, > + &iio_dev_attr_test_mode.dev_attr.attr, > + &iio_dev_attr_threshold_gohys.dev_attr.attr, > + &iio_dev_attr_threshold_gocval.dev_attr.attr, > + &iio_dev_attr_threshold_sohys.dev_attr.attr, > + &iio_dev_attr_threshold_socval.dev_attr.attr, > + NULL, > +}; > + > +static struct attribute_group hi843x_attribute_group = { > + .attrs = hi843x_attributes, > +}; > + > +static int hi843x_read_raw(struct iio_dev *idev, > + struct iio_chan_spec const *channel, int *val, > + int *val2, long mask) > +{ > + struct hi843x_priv *priv = iio_priv(idev); > + int ret; > + > + switch (mask) { > + case IIO_CHAN_INFO_PROCESSED: > + case IIO_CHAN_INFO_RAW: > + ret = hi843x_readl(priv, HI843X_SO31_0_REG, val); > + if (ret < 0) > + return ret; > + > + if (mask == IIO_CHAN_INFO_RAW) > + *val = !!(*val & BIT(channel->channel)); > + return IIO_VAL_INT; > + default: > + return -EINVAL; > + } > +} > + > +#define HI843X_VOLTAGE_CHANNEL(num) \ > + { \ > + .type = IIO_VOLTAGE, \ > + .indexed = 1, \ > + .channel = num, \ > + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ > + .scan_index = num, \ > + .scan_type = { \ > + .sign = 'u', \ > + .realbits = 1, \ huh? this is unusual for an ADC > + .storagebits = 8, \ > + }, \ > + } > + > +static const struct iio_chan_spec hi843x_channels[] = { > + HI843X_VOLTAGE_CHANNEL(0), > + HI843X_VOLTAGE_CHANNEL(1), > + HI843X_VOLTAGE_CHANNEL(2), > + HI843X_VOLTAGE_CHANNEL(3), > + HI843X_VOLTAGE_CHANNEL(4), > + HI843X_VOLTAGE_CHANNEL(5), > + HI843X_VOLTAGE_CHANNEL(6), > + HI843X_VOLTAGE_CHANNEL(7), > + HI843X_VOLTAGE_CHANNEL(8), > + HI843X_VOLTAGE_CHANNEL(9), > + HI843X_VOLTAGE_CHANNEL(10), > + HI843X_VOLTAGE_CHANNEL(11), > + HI843X_VOLTAGE_CHANNEL(12), > + HI843X_VOLTAGE_CHANNEL(13), > + HI843X_VOLTAGE_CHANNEL(14), > + HI843X_VOLTAGE_CHANNEL(15), > + HI843X_VOLTAGE_CHANNEL(16), > + HI843X_VOLTAGE_CHANNEL(17), > + HI843X_VOLTAGE_CHANNEL(18), > + HI843X_VOLTAGE_CHANNEL(19), > + HI843X_VOLTAGE_CHANNEL(20), > + HI843X_VOLTAGE_CHANNEL(21), > + HI843X_VOLTAGE_CHANNEL(22), > + HI843X_VOLTAGE_CHANNEL(23), > + HI843X_VOLTAGE_CHANNEL(24), > + HI843X_VOLTAGE_CHANNEL(25), > + HI843X_VOLTAGE_CHANNEL(26), > + HI843X_VOLTAGE_CHANNEL(27), > + HI843X_VOLTAGE_CHANNEL(28), > + HI843X_VOLTAGE_CHANNEL(29), > + HI843X_VOLTAGE_CHANNEL(30), > + HI843X_VOLTAGE_CHANNEL(31), > + { > + .type = IIO_ALTVOLTAGE, > + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), > + .scan_index = 32, > + .scan_type = { > + .sign = 'u', > + .realbits = 32, > + .storagebits = 32, > + }, > + }, > + IIO_CHAN_SOFT_TIMESTAMP(33), > +}; > + > +static const struct iio_info hi843x_info = { > + .driver_module = THIS_MODULE, > + .attrs = &hi843x_attribute_group, > + .read_raw = hi843x_read_raw, > +}; > + > +static void h843x_iio_push_to_buffers(struct iio_dev *idev, int val) > +{ > + struct hi843x_priv *priv = iio_priv(idev); > + u8 *pbuffer = priv->iio_buffer; > + int i; > + > + for_each_set_bit(i, idev->active_scan_mask, idev->masklength) { > + if (idev->channels[i].type == IIO_ALTVOLTAGE) { > + *(u32 *)pbuffer = val; > + pbuffer += 4; > + } else { > + *pbuffer = !!(val & BIT(i)); > + pbuffer++; > + } > + } > + iio_push_to_buffers_with_timestamp(idev, priv->iio_buffer, > + iio_get_time_ns()); > +} > + > +static void hi843x_debounce_soft_work(struct work_struct *work) > +{ > + struct hi843x_priv *priv = container_of(work, struct hi843x_priv, > + work.work); > + struct iio_dev *idev = spi_get_drvdata(priv->spi); > + int val, ret; > + > + ret = hi843x_readl(priv, HI843X_SO31_0_REG, &val); > + if (ret < 0) > + return; > + > + if (val == priv->debounce_soft_val) > + h843x_iio_push_to_buffers(idev, val); > + else > + dev_warn(&priv->spi->dev, "filtered by soft debounce"); > +} > + > +static irqreturn_t hi843x_trigger_handler(int irq, void *private) > +{ > + struct iio_poll_func *pf = private; > + struct iio_dev *idev = pf->indio_dev; > + struct hi843x_priv *priv = iio_priv(idev); > + int val, ret; > + > + ret = hi843x_readl(priv, HI843X_SO31_0_REG, &val); > + if (ret < 0) > + goto err_read; > + > + if (priv->debounce_soft) { > + priv->debounce_soft_val = val; > + schedule_delayed_work(&priv->work, > + msecs_to_jiffies(priv->debounce_soft_delay)); > + } else > + h843x_iio_push_to_buffers(idev, val); > + > +err_read: > + iio_trigger_notify_done(idev->trig); > + > + return IRQ_HANDLED; > +} > + > +static int hi843x_buffer_postenable(struct iio_dev *idev) > +{ > + struct hi843x_priv *priv = iio_priv(idev); > + > + priv->iio_buffer = kmalloc(idev->scan_bytes, GFP_KERNEL); > + if (!priv->iio_buffer) > + return -ENOMEM; > + > + return iio_triggered_buffer_postenable(idev); > +} > + > +static int hi843x_buffer_predisable(struct iio_dev *idev) > +{ > + struct hi843x_priv *priv = iio_priv(idev); > + int ret; > + > + ret = iio_triggered_buffer_predisable(idev); > + if (!ret) > + kfree(priv->iio_buffer); > + > + return ret; > +} > + > +static const struct iio_buffer_setup_ops hi843x_buffer_setup_ops = { > + .postenable = &hi843x_buffer_postenable, > + .predisable = &hi843x_buffer_predisable, > +}; > + > +static const struct iio_trigger_ops hi843x_trigger_ops = { > + .owner = THIS_MODULE, > +}; > + > +static void hi843x_parse_dt(struct hi843x_priv *priv) > +{ > + struct device_node *np = priv->spi->dev.of_node; > + int ret; > + > + ret = of_get_named_gpio(np, "holt,mr-gpio", 0); > + priv->mr_gpio = ret < 0 ? 0 : ret; > + > + if (of_find_property(np, "holt,debounce-soft", NULL)) > + priv->debounce_soft = 1; > + > + ret = of_property_read_u32(np, "holt,debounce-soft-delay", > + &priv->debounce_soft_delay); > + if (ret) > + priv->debounce_soft_delay = HI843X_DEBOUNCE_SOFT_DELAY_DEF; > +} > + > +static int hi843x_probe(struct spi_device *spi) > +{ > + struct iio_dev *idev; > + struct hi843x_priv *priv; > + int ret; > + > + idev = devm_iio_device_alloc(&spi->dev, sizeof(*priv)); > + if (!idev) > + return -ENOMEM; > + > + priv = iio_priv(idev); > + priv->spi = spi; > + > + if (spi->dev.of_node) > + hi843x_parse_dt(priv); > + > + spi_set_drvdata(spi, idev); > + mutex_init(&priv->lock); > + INIT_DELAYED_WORK(&priv->work, hi843x_debounce_soft_work); > + > + idev->dev.parent = &spi->dev; > + idev->name = spi_get_device_id(spi)->name; > + idev->modes = INDIO_DIRECT_MODE; > + idev->info = &hi843x_info; > + idev->channels = hi843x_channels; > + idev->num_channels = ARRAY_SIZE(hi843x_channels); > + > + if (priv->mr_gpio) { > + ret = devm_gpio_request(&spi->dev, priv->mr_gpio, idev->name); > + if (!ret) { > + /* chip hardware reset */ > + gpio_direction_output(priv->mr_gpio, 0); > + udelay(5); > + gpio_direction_output(priv->mr_gpio, 1); > + } > + } else { > + /* chip software reset */ > + hi843x_writeb(priv, HI843X_CTRL_REG, HI843X_CTRL_SRST); > + /* get out from reset state */ > + hi843x_writeb(priv, HI843X_CTRL_REG, 0); > + } > + > + ret = iio_triggered_buffer_setup(idev, NULL, hi843x_trigger_handler, > + &hi843x_buffer_setup_ops); > + if (ret) > + return ret; > + > + ret = iio_device_register(idev); > + if (ret < 0) { > + dev_err(&spi->dev, "unable to register device\n"); > + goto unregister_buffer; > + } > + > + return 0; > + > +unregister_buffer: > + iio_triggered_buffer_cleanup(idev); > + return ret; > +} > + > +static int hi843x_remove(struct spi_device *spi) > +{ > + struct iio_dev *idev = spi_get_drvdata(spi); > + struct hi843x_priv *priv = iio_priv(idev); > + > + cancel_delayed_work_sync(&priv->work); > + iio_device_unregister(idev); > + iio_triggered_buffer_cleanup(idev); > + > + return 0; > +} > + > +static const struct of_device_id hi843x_dt_ids[] = { > + { .compatible = "holt,hi-8435" }, > + { .compatible = "holt,hi-8436" }, > + { .compatible = "holt,hi-8437" }, > + {}, > +}; > +MODULE_DEVICE_TABLE(of, hi843x_dt_ids); > + > +static const struct spi_device_id hi843x_id[] = { > + { "hi-8435", 0}, > + { "hi-8436", 0}, > + { "hi-8437", 0}, > + { } > +}; > +MODULE_DEVICE_TABLE(spi, hi843x_id); > + > +static struct spi_driver hi843x_driver = { > + .driver = { > + .name = DRV_NAME, > + .of_match_table = of_match_ptr(hi843x_dt_ids), > + }, > + .probe = hi843x_probe, > + .remove = hi843x_remove, > + .id_table = hi843x_id, > +}; > +module_spi_driver(hi843x_driver); > + > +MODULE_LICENSE("GPL"); > +MODULE_AUTHOR("Vladimir Barinov"); > +MODULE_DESCRIPTION("HI-8435/8436/8437 discrete ADC"); > -- Peter Meerwald +43-664-2444418 (mobile) -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html