* [PATCH v2 0/5] iio: adc: hi8435: Add Holt HI-8435 threshold detector @ 2015-07-27 23:05 Vladimir Barinov 2015-07-27 23:06 ` [PATCH v2 1/5] iio: adc: hi8435: " Vladimir Barinov ` (3 more replies) 0 siblings, 4 replies; 10+ messages in thread From: Vladimir Barinov @ 2015-07-27 23:05 UTC (permalink / raw) To: Jonathan Cameron Cc: Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-iio-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, cory.tusar-J6Z/VSE8EyIAspv4Qr0y0gC/G2K4zDHf Hello, This adds the folowing: - Holt threshold detector driver for HI-8435 chip - Add Holt vendor prefix - Document HI-8435 DT bindings - Add periodic polling functionality to SYSFS trigger - Support triggered events PDF file can be found here: http://www.holtic.com/products/3081-hi-8435.aspx Vladimir Barinov (3): [1/5] iio: adc: hi8435: Holt HI-8435 threshold detector [2/5] dt: Add vendor prefix 'holt' [3/5] dt: Document Holt HI-8435 bindings [4/5] iio: trigger: Add periodic polling to SYSFS trigger [5/5] iio: Support triggered events --- This patchset is against the 'kernel/git/torvalds/linux.git' repo. Documentation/ABI/testing/sysfs-bus-iio-adc-hi8435 | 76 ++ Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs | 11 Documentation/devicetree/bindings/iio/adc/hi8435.txt | 25 Documentation/devicetree/bindings/vendor-prefixes.txt | 1 drivers/iio/Kconfig | 6 drivers/iio/Makefile | 1 drivers/iio/adc/Kconfig | 11 drivers/iio/adc/Makefile | 1 drivers/iio/adc/hi8435.c | 659 ++++++++++++++++++ drivers/iio/industrialio-core.c | 4 drivers/iio/industrialio-trigger.c | 12 drivers/iio/industrialio-triggered-event.c | 67 + drivers/iio/trigger/iio-trig-sysfs.c | 58 + include/linux/iio/iio.h | 1 include/linux/iio/triggered_event.h | 11 15 files changed, 940 insertions(+), 4 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-adc-hi8435 create mode 100644 drivers/iio/adc/hi8435.c create mode 100644 Documentation/devicetree/bindings/iio/adc/hi8435.txt create mode 100644 drivers/iio/industrialio-triggered-event.c create mode 100644 include/linux/iio/triggered_event.h ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 1/5] iio: adc: hi8435: Holt HI-8435 threshold detector 2015-07-27 23:05 [PATCH v2 0/5] iio: adc: hi8435: Add Holt HI-8435 threshold detector Vladimir Barinov @ 2015-07-27 23:06 ` Vladimir Barinov [not found] ` <1438038300-12855-1-git-send-email-vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> ` (2 subsequent siblings) 3 siblings, 0 replies; 10+ messages in thread From: Vladimir Barinov @ 2015-07-27 23:06 UTC (permalink / raw) To: Jonathan Cameron Cc: Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, linux-kernel, linux-iio, devicetree, cory.tusar Add Holt threshold detector driver for HI-8435 chip Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> --- Changes in version 2: - Added file sysfs-bus-iio-adc-hi8435 - Changed naming from "discrete ADC" to "threshold detector" - Replaced swab16p/swab32p with be16_to_cpup/be32_to_cpup - Made *_show and *_store functions static - moved out from iio buffers to iio events - removed hi8436/hi8437 chips from the driver - moved from debounce_soft_delay/enable to debounce_interval via IIO_CHAN_INFO_DEBOUNCE_TIME - added name extention "comparator" - moved threshold/hysteresis setup via generic iio event sysfs - added software mask/unmask channel events - added programming sensor outputs while in test mode via IIO_CHAN_INFO_RAW - added channels .ext_info for programming sensing mode Documentation/ABI/testing/sysfs-bus-iio-adc-hi8435 | 76 +++ drivers/iio/adc/Kconfig | 11 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/hi8435.c | 659 +++++++++++++++++++++ 4 files changed, 747 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-adc-hi8435 create mode 100644 drivers/iio/adc/hi8435.c diff --git a/Documentation/ABI/testing/sysfs-bus-iio-adc-hi8435 b/Documentation/ABI/testing/sysfs-bus-iio-adc-hi8435 new file mode 100644 index 0000000..2ff5bb3 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-adc-hi8435 @@ -0,0 +1,76 @@ +What /sys/bus/iio/devices/iio:deviceX/in_voltageY_comparator_raw +Date: July 2015 +KernelVersion: 4.2.0 +Contact: source@cogentembedded.com +Description: + Read value is a voltage threshold measurement from channel Y. + Could be ether 0 if sensor voltage lower then low voltage + threshold or 1 if sensor votlage higher then high voltage + threshold. + Write value is a programmed sensor output while in self test + mode. Could be ether 0 or 1. The programmed value will be read + back if /sys/bus/iio/devices/iio:deviceX/test_enable is set to 1 + +What /sys/bus/iio/devices/iio:deviceX/test_enable +Date: July 2015 +KernelVersion: 4.2.0 +Contact: source@cogentembedded.com +Description: + Enable/disable the HI-8435 self test mode. + If enabled the in_voltageY_comparator_raw should be read back + accordingly to written value to in_voltageY_comparator_raw + +What /sys/bus/iio/devices/iio:deviceX/debounce_time +Date: July 2015 +KernelVersion: 4.2.0 +Contact: source@cogentembedded.com +Description: + Software debounce interval in millliseconds. If value is + set to 0 then debouncing is disabled + +What /sys/bus/iio/devices/iio:deviceX/in_voltageY_comparator_sensing_mode +Date: July 2015 +KernelVersion: 4.2.0 +Contact: source@cogentembedded.com +Description: + Program sensor type for threshold detector inputs. + Could be ether "GND-Open" or "Supply-Open" modes. Y is a + threshold detector input channel. Channels 0..7, 8..15, 16..23 + and 24..31 has common sensor types. + +What /sys/bus/iio/devices/iio:deviceX/events/in_voltageY_comparator_thresh_either_en +Date: July 2015 +KernelVersion: 4.2.0 +Contact: source@cogentembedded.com +Description: + Mask/unmask channel Y events + +What /sys/bus/iio/devices/iio:deviceX/in_voltageY_comparator_thresh_falling_value +Date: July 2015 +KernelVersion: 4.2.0 +Contact: source@cogentembedded.com +Description: + Cahnnel Y low voltage threshold. If sensor input voltage goes lower then + this value then the threshold falling event is pushed. + Depending on in_voltageY_comparator_sensing_mode the low voltage threshold + is separately set for "GND-Open" and "Supply-Open" modes. + Channels 0..31 has common low threshold values, but could have different + sensing_modes. + The low voltage threshold range is between 2..21V. + Hysteresis between low and high thresholds can not be lower then 2 and + can not be odd. + +What /sys/bus/iio/devices/iio:deviceX/in_voltageY_comparator_thresh_rising_value +Date: July 2015 +KernelVersion: 4.2.0 +Contact: source@cogentembedded.com +Description: + Cahnnel Y high voltage threshold. If sensor input voltage goes higher then + this value then the threshold rising event is pushed. + Depending on in_voltageY_comparator_sensing_mode the high voltage threshold + is separately set for "GND-Open" and "Supply-Open" modes. + Channels 0..31 has common high threshold values, but could have different + sensing_modes. + The high voltage threshold range is between 3..22V. + Hysteresis between low and high thresholds can not be lower then 2 and + can not be odd. diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index eb0cd89..553c91e 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -170,6 +170,17 @@ config EXYNOS_ADC of SoCs for drivers such as the touchscreen and hwmon to use to share this resource. +config HI8435 + tristate "Holt Integrated Circuits HI-8435 threshold detector" + select IIO_TRIGGERED_EVENT + depends on SPI + help + If you say yes here you get support for Holt Integrated Circuits + HI-8435 chip. + + This driver can also be built as a module. If so, the module will be + called hi8435. + config LP8788_ADC tristate "LP8788 ADC driver" depends on MFD_LP8788 diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index a096210..00f367aa 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_BERLIN2_ADC) += berlin2-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_HI8435) += hi8435.o obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o obj-$(CONFIG_MAX1027) += max1027.o obj-$(CONFIG_MAX1363) += max1363.o diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c new file mode 100644 index 0000000..5739a7c --- /dev/null +++ b/drivers/iio/adc/hi8435.c @@ -0,0 +1,659 @@ +/* + * Holt Integrated Circuits HI-8435 threshold detector 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/events.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_event.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 "hi8435" + +/* Register offsets for HI-8435 */ +#define HI8435_CTRL_REG 0x02 +#define HI8435_PSEN_REG 0x04 +#define HI8435_TMDATA_REG 0x1E +#define HI8435_GOCENHYS_REG 0x3A +#define HI8435_SOCENHYS_REG 0x3C +#define HI8435_SO7_0_REG 0x10 +#define HI8435_SO15_8_REG 0x12 +#define HI8435_SO23_16_REG 0x14 +#define HI8435_SO31_24_REG 0x16 +#define HI8435_SO31_0_REG 0x78 + +#define HI8435_WRITE_OPCODE 0x00 +#define HI8435_READ_OPCODE 0x80 + +/* CTRL register bits */ +#define HI8435_CTRL_TEST 0x01 +#define HI8435_CTRL_SRST 0x02 + +#define HI8435_DEBOUNCE_DELAY_MAX 1000 /* msec */ +#define HI8435_DEBOUNCE_DELAY_DEF 100 /* msec */ + +struct hi8435_priv { + struct spi_device *spi; + struct mutex lock; + struct delayed_work work; + + int reset_gpio; + int debounce_interval; /* msec */ + u32 debounce_val; /* prev value to compare during software debounce */ + + unsigned long event_scan_mask; /* soft mask/unmask channels events */ + unsigned int event_prev_val; + + unsigned threshold_lo[2]; /* GND-Open and Supply-Open thresholds */ + unsigned threshold_hi[2]; /* GND-Open and Supply-Open threshold */ + u8 reg_buffer[4] ____cacheline_aligned; +}; + +static int hi8435_readb(struct hi8435_priv *priv, u8 reg, u8 *val) +{ + reg |= HI8435_READ_OPCODE; + return spi_write_then_read(priv->spi, ®, 1, val, 1); +} + +static int hi8435_readw(struct hi8435_priv *priv, u8 reg, u16 *val) +{ + int ret; + + reg |= HI8435_READ_OPCODE; + ret = spi_write_then_read(priv->spi, ®, 1, val, 2); + *val = be16_to_cpup(val); + + return ret; +} + +static int hi8435_readl(struct hi8435_priv *priv, u8 reg, u32 *val) +{ + int ret; + + reg |= HI8435_READ_OPCODE; + ret = spi_write_then_read(priv->spi, ®, 1, val, 4); + *val = be32_to_cpup(val); + + return ret; +} + +static int hi8435_writeb(struct hi8435_priv *priv, u8 reg, u8 val) +{ + priv->reg_buffer[0] = reg | HI8435_WRITE_OPCODE; + priv->reg_buffer[1] = val; + + return spi_write(priv->spi, priv->reg_buffer, 2); +} + +static int hi8435_writew(struct hi8435_priv *priv, u8 reg, u16 val) +{ + priv->reg_buffer[0] = reg | HI8435_WRITE_OPCODE; + priv->reg_buffer[1] = (val >> 8) & 0xff; + priv->reg_buffer[2] = val & 0xff; + + return spi_write(priv->spi, priv->reg_buffer, 3); +} + +static ssize_t hi8435_test_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hi8435_priv *priv = iio_priv(dev_to_iio_dev(dev)); + int ret; + u8 reg; + + ret = hi8435_readb(priv, HI8435_CTRL_REG, ®); + if (ret < 0) + return ret; + + return sprintf(buf, "%d\n", reg & HI8435_CTRL_TEST); +} + +static ssize_t hi8435_test_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct hi8435_priv *priv = iio_priv(dev_to_iio_dev(dev)); + unsigned int val; + int ret; + + ret = kstrtouint(buf, 10, &val); + if (ret) + return ret; + + hi8435_writeb(priv, HI8435_CTRL_REG, val ? HI8435_CTRL_TEST : 0); + + return len; +} + +static IIO_DEVICE_ATTR(test_enable, S_IRUGO | S_IWUSR, + hi8435_test_enable_show, hi8435_test_enable_store, 0); + +static struct attribute *hi8435_attributes[] = { + &iio_dev_attr_test_enable.dev_attr.attr, + NULL, +}; + +static struct attribute_group hi8435_attribute_group = { + .attrs = hi8435_attributes, +}; + +static int hi8435_read_raw(struct iio_dev *idev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct hi8435_priv *priv = iio_priv(idev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = hi8435_readl(priv, HI8435_SO31_0_REG, val); + if (ret < 0) + return ret; + *val = !!(*val & BIT(chan->channel)); + return IIO_VAL_INT; + case IIO_CHAN_INFO_DEBOUNCE_TIME: + *val = priv->debounce_interval; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int hi8435_write_raw(struct iio_dev *idev, + const struct iio_chan_spec *chan, + int val, int val2, long mask) +{ + struct hi8435_priv *priv = iio_priv(idev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + /* program sensors outputs in test mode */ + hi8435_writeb(priv, HI8435_TMDATA_REG, val ? 0x1 : 0x2); + return 0; + case IIO_CHAN_INFO_DEBOUNCE_TIME: + if (val < 0) + return -EINVAL; + if (val > HI8435_DEBOUNCE_DELAY_MAX) + val = HI8435_DEBOUNCE_DELAY_MAX; + priv->debounce_interval = val; + return 0; + default: + return -EINVAL; + } +} + +static int hi8435_read_event_config(struct iio_dev *idev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct hi8435_priv *priv = iio_priv(idev); + + return !!(priv->event_scan_mask & BIT(chan->channel)); +} + +static int hi8435_write_event_config(struct iio_dev *idev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, int state) +{ + struct hi8435_priv *priv = iio_priv(idev); + + priv->event_scan_mask &= ~BIT(chan->channel); + if (state) + priv->event_scan_mask |= BIT(chan->channel); + + return 0; +} + +static int hi8435_read_event_value(struct iio_dev *idev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct hi8435_priv *priv = iio_priv(idev); + int ret; + u8 mode, psen; + u16 reg; + + ret = hi8435_readb(priv, HI8435_PSEN_REG, &psen); + if (ret < 0) + return ret; + + /* Supply-Open or GND-Open sensing mode */ + mode = !!(psen & BIT(chan->channel / 8)); + + ret = hi8435_readw(priv, mode ? HI8435_SOCENHYS_REG : + HI8435_GOCENHYS_REG, ®); + if (ret < 0) + return ret; + + if (dir == IIO_EV_DIR_FALLING) + *val = ((reg & 0xff) - (reg >> 8)) / 2; + + if (dir == IIO_EV_DIR_RISING) + *val = ((reg & 0xff) + (reg >> 8)) / 2; + + return IIO_VAL_INT; +} + +static int hi8435_write_event_value(struct iio_dev *idev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct hi8435_priv *priv = iio_priv(idev); + int ret; + u8 mode, psen; + u16 reg; + + ret = hi8435_readb(priv, HI8435_PSEN_REG, &psen); + if (ret < 0) + return ret; + + /* Supply-Open or GND-Open sensing mode */ + mode = !!(psen & BIT(chan->channel / 8)); + + ret = hi8435_readw(priv, mode ? HI8435_SOCENHYS_REG : + HI8435_GOCENHYS_REG, ®); + if (ret < 0) + return ret; + + if (dir == IIO_EV_DIR_FALLING) { + /* falling threshold range 2..21V, hysteresis minimum 2V */ + if (val < 2 || val > 21 || (val + 1) >= priv->threshold_hi[mode]) + return -EINVAL; + + if (val == priv->threshold_lo[mode]) + return 0; + + priv->threshold_lo[mode] = val; + + /* hysteresis must not be odd */ + if ((priv->threshold_hi[mode] - priv->threshold_lo[mode]) % 2) + priv->threshold_hi[mode]--; + } + + if (dir == IIO_EV_DIR_RISING) { + /* rising threshold range 3..22V, hysteresis minimum 2V */ + if (val < 3 || val > 22 || val <= (priv->threshold_lo[mode] + 1)) + return -EINVAL; + + if (val == priv->threshold_hi[mode]) + return 0; + + priv->threshold_hi[mode] = val; + + /* hysteresis must not be odd */ + if ((priv->threshold_hi[mode] - priv->threshold_lo[mode]) % 2) + priv->threshold_lo[mode]++; + } + + /* program thresholds */ + mutex_lock(&priv->lock); + + ret = hi8435_readw(priv, mode ? HI8435_SOCENHYS_REG : + HI8435_GOCENHYS_REG, ®); + if (ret < 0) { + mutex_unlock(&priv->lock); + return ret; + } + + /* hysteresis */ + reg = priv->threshold_hi[mode] - priv->threshold_lo[mode]; + reg <<= 8; + /* threshold center */ + reg |= (priv->threshold_hi[mode] + priv->threshold_lo[mode]); + + hi8435_writew(priv, mode ? HI8435_SOCENHYS_REG : + HI8435_GOCENHYS_REG, reg); + + mutex_unlock(&priv->lock); + + return 0; +} + +static const struct iio_event_spec hi8435_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_EITHER, + .mask_separate = BIT(IIO_EV_INFO_ENABLE), + }, +}; + +static int hi8435_get_sensing_mode(struct iio_dev *idev, + const struct iio_chan_spec *chan) +{ + struct hi8435_priv *priv = iio_priv(idev); + int ret; + u8 reg; + + ret = hi8435_readb(priv, HI8435_PSEN_REG, ®); + if (ret < 0) + return ret; + + return !!(reg & BIT(chan->channel / 8)); +} + +static int hi8435_set_sensing_mode(struct iio_dev *idev, + const struct iio_chan_spec *chan, + unsigned int mode) +{ + struct hi8435_priv *priv = iio_priv(idev); + int ret; + u8 reg; + + mutex_lock(&priv->lock); + + ret = hi8435_readb(priv, HI8435_PSEN_REG, ®); + if (ret < 0) { + mutex_unlock(&priv->lock); + return ret; + } + + reg &= ~BIT(chan->channel / 8); + if (mode) + reg |= BIT(chan->channel / 8); + + hi8435_writeb(priv, HI8435_PSEN_REG, reg); + + mutex_unlock(&priv->lock); + + return 0; +} + +static const char * const hi8435_sensing_modes[] = { "GND-Open", + "Supply-Open" }; + +static const struct iio_enum hi8435_sensing_mode = { + .items = hi8435_sensing_modes, + .num_items = ARRAY_SIZE(hi8435_sensing_modes), + .get = hi8435_get_sensing_mode, + .set = hi8435_set_sensing_mode, +}; + +static const struct iio_chan_spec_ext_info hi8435_ext_info[] = { + IIO_ENUM("sensing_mode", IIO_SEPARATE, &hi8435_sensing_mode), + {}, +}; + +#define HI8435_VOLTAGE_CHANNEL(num) \ +{ \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = num, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_DEBOUNCE_TIME), \ + .event_spec = hi8435_events, \ + .num_event_specs = ARRAY_SIZE(hi8435_events), \ + .ext_info = hi8435_ext_info, \ + .extend_name = "comparator" \ +} + +static const struct iio_chan_spec hi8435_channels[] = { + HI8435_VOLTAGE_CHANNEL(0), + HI8435_VOLTAGE_CHANNEL(1), + HI8435_VOLTAGE_CHANNEL(2), + HI8435_VOLTAGE_CHANNEL(3), + HI8435_VOLTAGE_CHANNEL(4), + HI8435_VOLTAGE_CHANNEL(5), + HI8435_VOLTAGE_CHANNEL(6), + HI8435_VOLTAGE_CHANNEL(7), + HI8435_VOLTAGE_CHANNEL(8), + HI8435_VOLTAGE_CHANNEL(9), + HI8435_VOLTAGE_CHANNEL(10), + HI8435_VOLTAGE_CHANNEL(11), + HI8435_VOLTAGE_CHANNEL(12), + HI8435_VOLTAGE_CHANNEL(13), + HI8435_VOLTAGE_CHANNEL(14), + HI8435_VOLTAGE_CHANNEL(15), + HI8435_VOLTAGE_CHANNEL(16), + HI8435_VOLTAGE_CHANNEL(17), + HI8435_VOLTAGE_CHANNEL(18), + HI8435_VOLTAGE_CHANNEL(19), + HI8435_VOLTAGE_CHANNEL(20), + HI8435_VOLTAGE_CHANNEL(21), + HI8435_VOLTAGE_CHANNEL(22), + HI8435_VOLTAGE_CHANNEL(23), + HI8435_VOLTAGE_CHANNEL(24), + HI8435_VOLTAGE_CHANNEL(25), + HI8435_VOLTAGE_CHANNEL(26), + HI8435_VOLTAGE_CHANNEL(27), + HI8435_VOLTAGE_CHANNEL(28), + HI8435_VOLTAGE_CHANNEL(29), + HI8435_VOLTAGE_CHANNEL(30), + HI8435_VOLTAGE_CHANNEL(31), + IIO_CHAN_SOFT_TIMESTAMP(32), +}; + +static const struct iio_info hi8435_info = { + .driver_module = THIS_MODULE, + .attrs = &hi8435_attribute_group, + .read_raw = hi8435_read_raw, + .write_raw = hi8435_write_raw, + .read_event_config = &hi8435_read_event_config, + .write_event_config = hi8435_write_event_config, + .read_event_value = &hi8435_read_event_value, + .write_event_value = &hi8435_write_event_value, +}; + +static void hi8435_iio_push_event(struct iio_dev *idev, unsigned int val) +{ + struct hi8435_priv *priv = iio_priv(idev); + enum iio_event_direction dir; + unsigned int i; + unsigned int status = priv->event_prev_val ^ val; + + if (!status) + return; + + for_each_set_bit(i, &priv->event_scan_mask, 32) { + if (!(status & BIT(i))) + continue; + + dir = val & BIT(i) ? IIO_EV_DIR_RISING : IIO_EV_DIR_FALLING; + + iio_push_event(idev, + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i, + IIO_EV_TYPE_THRESH, dir), + iio_get_time_ns()); + } + + priv->event_prev_val = val; +} + +static void hi8435_debounce_work(struct work_struct *work) +{ + struct hi8435_priv *priv = container_of(work, struct hi8435_priv, + work.work); + struct iio_dev *idev = spi_get_drvdata(priv->spi); + u32 val; + int ret; + + ret = hi8435_readl(priv, HI8435_SO31_0_REG, &val); + if (ret < 0) + return; + + if (val == priv->debounce_val) + hi8435_iio_push_event(idev, val); + else + dev_warn(&priv->spi->dev, "filtered by software debounce"); +} + +static irqreturn_t hi8435_trigger_handler(int irq, void *private) +{ + struct iio_poll_func *pf = private; + struct iio_dev *idev = pf->indio_dev; + struct hi8435_priv *priv = iio_priv(idev); + u32 val; + int ret; + + ret = hi8435_readl(priv, HI8435_SO31_0_REG, &val); + if (ret < 0) + goto err_read; + + if (priv->debounce_interval) { + priv->debounce_val = val; + schedule_delayed_work(&priv->work, + msecs_to_jiffies(priv->debounce_interval)); + } else { + hi8435_iio_push_event(idev, val); + } + +err_read: + iio_trigger_notify_done(idev->trig); + + return IRQ_HANDLED; +} + +static void hi8435_parse_dt(struct hi8435_priv *priv) +{ + struct device_node *np = priv->spi->dev.of_node; + int ret; + + ret = of_get_named_gpio(np, "holt,reset-gpios", 0); + priv->reset_gpio = ret < 0 ? 0 : ret; + + ret = of_property_read_u32(np, "holt,debounce-interval", + &priv->debounce_interval); + if (ret) + priv->debounce_interval = 0; + if (priv->debounce_interval > HI8435_DEBOUNCE_DELAY_MAX) + priv->debounce_interval = HI8435_DEBOUNCE_DELAY_MAX; +} + +static int hi8435_probe(struct spi_device *spi) +{ + struct iio_dev *idev; + struct hi8435_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) + hi8435_parse_dt(priv); + + spi_set_drvdata(spi, idev); + mutex_init(&priv->lock); + INIT_DELAYED_WORK(&priv->work, hi8435_debounce_work); + + idev->dev.parent = &spi->dev; + idev->name = spi_get_device_id(spi)->name; + idev->modes = INDIO_DIRECT_MODE; + idev->info = &hi8435_info; + idev->channels = hi8435_channels; + idev->num_channels = ARRAY_SIZE(hi8435_channels); + + if (priv->reset_gpio) { + ret = devm_gpio_request(&spi->dev, priv->reset_gpio, idev->name); + if (!ret) { + /* chip hardware reset */ + gpio_direction_output(priv->reset_gpio, 0); + udelay(5); + gpio_direction_output(priv->reset_gpio, 1); + } + } else { + /* chip software reset */ + hi8435_writeb(priv, HI8435_CTRL_REG, HI8435_CTRL_SRST); + /* get out from reset state */ + hi8435_writeb(priv, HI8435_CTRL_REG, 0); + } + + /* unmask all events */ + priv->event_scan_mask = ~(0); + /* initialize default thresholds */ + priv->threshold_lo[0] = priv->threshold_lo[1] = 2; + priv->threshold_hi[0] = priv->threshold_hi[1] = 4; + hi8435_writew(priv, HI8435_GOCENHYS_REG, 0x206); + hi8435_writew(priv, HI8435_SOCENHYS_REG, 0x206); + + ret = iio_triggered_event_setup(idev, NULL, hi8435_trigger_handler); + if (ret) + return ret; + + ret = iio_device_register(idev); + if (ret < 0) { + dev_err(&spi->dev, "unable to register device\n"); + goto unregister_triggered_event; + } + + return 0; + +unregister_triggered_event: + iio_triggered_event_cleanup(idev); + return ret; +} + +static int hi8435_remove(struct spi_device *spi) +{ + struct iio_dev *idev = spi_get_drvdata(spi); + struct hi8435_priv *priv = iio_priv(idev); + + cancel_delayed_work_sync(&priv->work); + iio_device_unregister(idev); + iio_triggered_event_cleanup(idev); + + return 0; +} + +static const struct of_device_id hi8435_dt_ids[] = { + { .compatible = "holt,hi8435" }, + {}, +}; +MODULE_DEVICE_TABLE(of, hi8435_dt_ids); + +static const struct spi_device_id hi8435_id[] = { + { "hi8435", 0}, + { } +}; +MODULE_DEVICE_TABLE(spi, hi8435_id); + +static struct spi_driver hi8435_driver = { + .driver = { + .name = DRV_NAME, + .of_match_table = of_match_ptr(hi8435_dt_ids), + }, + .probe = hi8435_probe, + .remove = hi8435_remove, + .id_table = hi8435_id, +}; +module_spi_driver(hi8435_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Vladimir Barinov"); +MODULE_DESCRIPTION("HI-8435 threshold detector"); -- 1.9.1 ^ permalink raw reply related [flat|nested] 10+ messages in thread
[parent not found: <1438038300-12855-1-git-send-email-vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>]
* [PATCH v2 2/5] dt: Add vendor prefix 'holt' [not found] ` <1438038300-12855-1-git-send-email-vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> @ 2015-07-27 23:06 ` Vladimir Barinov 2015-07-27 23:07 ` [PATCH v2 5/5] iio: Support triggered events Vladimir Barinov 1 sibling, 0 replies; 10+ messages in thread From: Vladimir Barinov @ 2015-07-27 23:06 UTC (permalink / raw) To: Jonathan Cameron Cc: Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-iio-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, cory.tusar-J6Z/VSE8EyIAspv4Qr0y0gC/G2K4zDHf Add Holt Integrated Circuits, Inc. to the list of device tree vendor prefixes Signed-off-by: Vladimir Barinov <vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> --- Changes in version 2: - none Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index d444757..bc64cc9 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -99,6 +99,7 @@ himax Himax Technologies, Inc. hisilicon Hisilicon Limited. hit Hitachi Ltd. hitex Hitex Development Tools +holt Holt Integrated Circuits, Inc. honeywell Honeywell hp Hewlett Packard i2se I2SE GmbH -- 1.9.1 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 5/5] iio: Support triggered events [not found] ` <1438038300-12855-1-git-send-email-vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> 2015-07-27 23:06 ` [PATCH v2 2/5] dt: Add vendor prefix 'holt' Vladimir Barinov @ 2015-07-27 23:07 ` Vladimir Barinov [not found] ` <1438038442-13082-1-git-send-email-vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> 1 sibling, 1 reply; 10+ messages in thread From: Vladimir Barinov @ 2015-07-27 23:07 UTC (permalink / raw) To: Jonathan Cameron Cc: Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-iio-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, cory.tusar-J6Z/VSE8EyIAspv4Qr0y0gC/G2K4zDHf Support triggered events. This is useful for chips that has no it's own interrupt sources. It allows to use generic/standalone iio triggeres for those drivers. Signed-off-by: Vladimir Barinov <vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> --- Changes in version 2: - initially added drivers/iio/Kconfig | 6 +++ drivers/iio/Makefile | 1 + drivers/iio/industrialio-core.c | 4 +- drivers/iio/industrialio-trigger.c | 12 +++++- drivers/iio/industrialio-triggered-event.c | 67 ++++++++++++++++++++++++++++++ include/linux/iio/iio.h | 1 + include/linux/iio/triggered_event.h | 11 +++++ 7 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 drivers/iio/industrialio-triggered-event.c create mode 100644 include/linux/iio/triggered_event.h diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index 4011eff..8fcc92f 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -58,6 +58,12 @@ config IIO_CONSUMERS_PER_TRIGGER This value controls the maximum number of consumers that a given trigger may handle. Default is 2. +config IIO_TRIGGERED_EVENT + tristate + select IIO_TRIGGER + help + Provides helper functions for setting up triggered events. + source "drivers/iio/accel/Kconfig" source "drivers/iio/adc/Kconfig" source "drivers/iio/amplifiers/Kconfig" diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index 698afc2..40dc13e 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -9,6 +9,7 @@ industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o industrialio-$(CONFIG_IIO_BUFFER_CB) += buffer_cb.o obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o +obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o obj-y += accel/ diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 3524b0d..54d71ea 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -948,7 +948,7 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev) static void iio_dev_release(struct device *device) { struct iio_dev *indio_dev = dev_to_iio_dev(device); - if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) + if (indio_dev->modes & (INDIO_BUFFER_TRIGGERED | INDIO_EVENT_TRIGGERED)) iio_device_unregister_trigger_consumer(indio_dev); iio_device_unregister_eventset(indio_dev); iio_device_unregister_sysfs(indio_dev); @@ -1218,7 +1218,7 @@ int iio_device_register(struct iio_dev *indio_dev) "Failed to register event set\n"); goto error_free_sysfs; } - if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) + if (indio_dev->modes & (INDIO_BUFFER_TRIGGERED | INDIO_EVENT_TRIGGERED)) iio_device_register_trigger_consumer(indio_dev); if ((indio_dev->modes & INDIO_ALL_BUFFER_MODES) && diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index d31098e..72b63e7 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -345,10 +345,18 @@ static ssize_t iio_trigger_write_current(struct device *dev, indio_dev->trig = trig; - if (oldtrig) + if (oldtrig) { + if (indio_dev->currentmode == INDIO_EVENT_TRIGGERED) + iio_trigger_detach_poll_func(oldtrig, + indio_dev->pollfunc); iio_trigger_put(oldtrig); - if (indio_dev->trig) + } + if (indio_dev->trig) { iio_trigger_get(indio_dev->trig); + if (indio_dev->currentmode == INDIO_EVENT_TRIGGERED) + iio_trigger_attach_poll_func(indio_dev->trig, + indio_dev->pollfunc); + } return len; } diff --git a/drivers/iio/industrialio-triggered-event.c b/drivers/iio/industrialio-triggered-event.c new file mode 100644 index 0000000..c434ce7 --- /dev/null +++ b/drivers/iio/industrialio-triggered-event.c @@ -0,0 +1,67 @@ + /* + * 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 version 2 as published by + * the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/export.h> +#include <linux/module.h> +#include <linux/iio/iio.h> +#include <linux/iio/triggered_event.h> +#include <linux/iio/trigger_consumer.h> + +/** + * iio_triggered_event_setup() - Setup pollfunc for triggered event + * @indio_dev: IIO device structure + * @pollfunc_bh: Function which will be used as pollfunc bottom half + * @pollfunc_th: Function which will be used as pollfunc top half + * + * This function combines some common tasks which will normally be performed + * when setting up a triggered event. It will allocate the pollfunc and + * set mode to use it for triggered event. + * + * Before calling this function the indio_dev structure should already be + * completely initialized, but not yet registered. In practice this means that + * this function should be called right before iio_device_register(). + * + * To free the resources allocated by this function call + * iio_triggered_event_cleanup(). + */ +int iio_triggered_event_setup(struct iio_dev *indio_dev, + irqreturn_t (*pollfunc_bh)(int irq, void *p), + irqreturn_t (*pollfunc_th)(int irq, void *p)) +{ + indio_dev->pollfunc = iio_alloc_pollfunc(pollfunc_bh, + pollfunc_th, + IRQF_ONESHOT, + indio_dev, + "%s_consumer%d", + indio_dev->name, + indio_dev->id); + if (indio_dev->pollfunc == NULL) + return -ENOMEM; + + /* Flag that pollfunc is used for triggered event */ + indio_dev->modes |= INDIO_EVENT_TRIGGERED; + indio_dev->currentmode = INDIO_EVENT_TRIGGERED; + + return 0; +} +EXPORT_SYMBOL(iio_triggered_event_setup); + +/** + * iio_triggered_event_cleanup() - Free resources allocated by iio_triggered_event_setup() + * @indio_dev: IIO device structure + */ +void iio_triggered_event_cleanup(struct iio_dev *indio_dev) +{ + iio_dealloc_pollfunc(indio_dev->pollfunc); +} +EXPORT_SYMBOL(iio_triggered_event_cleanup); + +MODULE_AUTHOR("Vladimir Barinov"); +MODULE_DESCRIPTION("IIO helper functions for setting up triggered events"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index f791482..b691ee0 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -294,6 +294,7 @@ static inline s64 iio_get_time_ns(void) #define INDIO_BUFFER_TRIGGERED 0x02 #define INDIO_BUFFER_SOFTWARE 0x04 #define INDIO_BUFFER_HARDWARE 0x08 +#define INDIO_EVENT_TRIGGERED 0x10 #define INDIO_ALL_BUFFER_MODES \ (INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE | INDIO_BUFFER_SOFTWARE) diff --git a/include/linux/iio/triggered_event.h b/include/linux/iio/triggered_event.h new file mode 100644 index 0000000..e9894e9 --- /dev/null +++ b/include/linux/iio/triggered_event.h @@ -0,0 +1,11 @@ +#ifndef _LINUX_IIO_TRIGGERED_EVENT_H_ +#define _LINUX_IIO_TRIGGERED_EVENT_H_ + +#include <linux/interrupt.h> + +int iio_triggered_event_setup(struct iio_dev *indio_dev, + irqreturn_t (*pollfunc_bh)(int irq, void *p), + irqreturn_t (*pollfunc_th)(int irq, void *p)); +void iio_triggered_event_cleanup(struct iio_dev *indio_dev); + +#endif -- 1.9.1 ^ permalink raw reply related [flat|nested] 10+ messages in thread
[parent not found: <1438038442-13082-1-git-send-email-vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>]
* Re: [PATCH v2 5/5] iio: Support triggered events [not found] ` <1438038442-13082-1-git-send-email-vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> @ 2015-07-28 6:37 ` Peter Meerwald 2015-07-29 7:56 ` Paul Bolle 1 sibling, 0 replies; 10+ messages in thread From: Peter Meerwald @ 2015-07-28 6:37 UTC (permalink / raw) To: Vladimir Barinov Cc: Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-iio-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, cory.tusar-J6Z/VSE8EyIAspv4Qr0y0gC/G2K4zDHf On Tue, 28 Jul 2015, Vladimir Barinov wrote: > Support triggered events. > > This is useful for chips that has no it's own interrupt sources. that don't have their own > It allows to use generic/standalone iio triggeres for those drivers. triggers > > Signed-off-by: Vladimir Barinov <vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> > --- > Changes in version 2: > - initially added > > drivers/iio/Kconfig | 6 +++ > drivers/iio/Makefile | 1 + > drivers/iio/industrialio-core.c | 4 +- > drivers/iio/industrialio-trigger.c | 12 +++++- > drivers/iio/industrialio-triggered-event.c | 67 ++++++++++++++++++++++++++++++ > include/linux/iio/iio.h | 1 + > include/linux/iio/triggered_event.h | 11 +++++ > 7 files changed, 98 insertions(+), 4 deletions(-) > create mode 100644 drivers/iio/industrialio-triggered-event.c > create mode 100644 include/linux/iio/triggered_event.h > > diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig > index 4011eff..8fcc92f 100644 > --- a/drivers/iio/Kconfig > +++ b/drivers/iio/Kconfig > @@ -58,6 +58,12 @@ config IIO_CONSUMERS_PER_TRIGGER > This value controls the maximum number of consumers that a > given trigger may handle. Default is 2. > > +config IIO_TRIGGERED_EVENT > + tristate > + select IIO_TRIGGER > + help > + Provides helper functions for setting up triggered events. > + > source "drivers/iio/accel/Kconfig" > source "drivers/iio/adc/Kconfig" > source "drivers/iio/amplifiers/Kconfig" > diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile > index 698afc2..40dc13e 100644 > --- a/drivers/iio/Makefile > +++ b/drivers/iio/Makefile > @@ -9,6 +9,7 @@ industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o > industrialio-$(CONFIG_IIO_BUFFER_CB) += buffer_cb.o > > obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o > +obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o > obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o > > obj-y += accel/ > diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c > index 3524b0d..54d71ea 100644 > --- a/drivers/iio/industrialio-core.c > +++ b/drivers/iio/industrialio-core.c > @@ -948,7 +948,7 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev) > static void iio_dev_release(struct device *device) > { > struct iio_dev *indio_dev = dev_to_iio_dev(device); > - if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) > + if (indio_dev->modes & (INDIO_BUFFER_TRIGGERED | INDIO_EVENT_TRIGGERED)) > iio_device_unregister_trigger_consumer(indio_dev); > iio_device_unregister_eventset(indio_dev); > iio_device_unregister_sysfs(indio_dev); > @@ -1218,7 +1218,7 @@ int iio_device_register(struct iio_dev *indio_dev) > "Failed to register event set\n"); > goto error_free_sysfs; > } > - if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) > + if (indio_dev->modes & (INDIO_BUFFER_TRIGGERED | INDIO_EVENT_TRIGGERED)) > iio_device_register_trigger_consumer(indio_dev); > > if ((indio_dev->modes & INDIO_ALL_BUFFER_MODES) && > diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c > index d31098e..72b63e7 100644 > --- a/drivers/iio/industrialio-trigger.c > +++ b/drivers/iio/industrialio-trigger.c > @@ -345,10 +345,18 @@ static ssize_t iio_trigger_write_current(struct device *dev, > > indio_dev->trig = trig; > > - if (oldtrig) > + if (oldtrig) { > + if (indio_dev->currentmode == INDIO_EVENT_TRIGGERED) > + iio_trigger_detach_poll_func(oldtrig, > + indio_dev->pollfunc); > iio_trigger_put(oldtrig); > - if (indio_dev->trig) > + } > + if (indio_dev->trig) { > iio_trigger_get(indio_dev->trig); > + if (indio_dev->currentmode == INDIO_EVENT_TRIGGERED) > + iio_trigger_attach_poll_func(indio_dev->trig, > + indio_dev->pollfunc); > + } > > return len; > } > diff --git a/drivers/iio/industrialio-triggered-event.c b/drivers/iio/industrialio-triggered-event.c > new file mode 100644 > index 0000000..c434ce7 > --- /dev/null > +++ b/drivers/iio/industrialio-triggered-event.c > @@ -0,0 +1,67 @@ > + /* > + * 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 version 2 as published by > + * the Free Software Foundation. > + */ > + > +#include <linux/kernel.h> > +#include <linux/export.h> > +#include <linux/module.h> > +#include <linux/iio/iio.h> > +#include <linux/iio/triggered_event.h> > +#include <linux/iio/trigger_consumer.h> > + > +/** > + * iio_triggered_event_setup() - Setup pollfunc for triggered event > + * @indio_dev: IIO device structure > + * @pollfunc_bh: Function which will be used as pollfunc bottom half > + * @pollfunc_th: Function which will be used as pollfunc top half > + * > + * This function combines some common tasks which will normally be performed > + * when setting up a triggered event. It will allocate the pollfunc and > + * set mode to use it for triggered event. > + * > + * Before calling this function the indio_dev structure should already be > + * completely initialized, but not yet registered. In practice this means that > + * this function should be called right before iio_device_register(). > + * > + * To free the resources allocated by this function call > + * iio_triggered_event_cleanup(). > + */ > +int iio_triggered_event_setup(struct iio_dev *indio_dev, > + irqreturn_t (*pollfunc_bh)(int irq, void *p), > + irqreturn_t (*pollfunc_th)(int irq, void *p)) > +{ > + indio_dev->pollfunc = iio_alloc_pollfunc(pollfunc_bh, > + pollfunc_th, > + IRQF_ONESHOT, > + indio_dev, > + "%s_consumer%d", > + indio_dev->name, > + indio_dev->id); > + if (indio_dev->pollfunc == NULL) > + return -ENOMEM; > + > + /* Flag that pollfunc is used for triggered event */ > + indio_dev->modes |= INDIO_EVENT_TRIGGERED; > + indio_dev->currentmode = INDIO_EVENT_TRIGGERED; > + > + return 0; > +} > +EXPORT_SYMBOL(iio_triggered_event_setup); > + > +/** > + * iio_triggered_event_cleanup() - Free resources allocated by iio_triggered_event_setup() > + * @indio_dev: IIO device structure > + */ > +void iio_triggered_event_cleanup(struct iio_dev *indio_dev) > +{ > + iio_dealloc_pollfunc(indio_dev->pollfunc); > +} > +EXPORT_SYMBOL(iio_triggered_event_cleanup); > + > +MODULE_AUTHOR("Vladimir Barinov"); > +MODULE_DESCRIPTION("IIO helper functions for setting up triggered events"); > +MODULE_LICENSE("GPL"); > diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h > index f791482..b691ee0 100644 > --- a/include/linux/iio/iio.h > +++ b/include/linux/iio/iio.h > @@ -294,6 +294,7 @@ static inline s64 iio_get_time_ns(void) > #define INDIO_BUFFER_TRIGGERED 0x02 > #define INDIO_BUFFER_SOFTWARE 0x04 > #define INDIO_BUFFER_HARDWARE 0x08 > +#define INDIO_EVENT_TRIGGERED 0x10 > > #define INDIO_ALL_BUFFER_MODES \ > (INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE | INDIO_BUFFER_SOFTWARE) > diff --git a/include/linux/iio/triggered_event.h b/include/linux/iio/triggered_event.h > new file mode 100644 > index 0000000..e9894e9 > --- /dev/null > +++ b/include/linux/iio/triggered_event.h > @@ -0,0 +1,11 @@ > +#ifndef _LINUX_IIO_TRIGGERED_EVENT_H_ > +#define _LINUX_IIO_TRIGGERED_EVENT_H_ > + > +#include <linux/interrupt.h> > + > +int iio_triggered_event_setup(struct iio_dev *indio_dev, > + irqreturn_t (*pollfunc_bh)(int irq, void *p), > + irqreturn_t (*pollfunc_th)(int irq, void *p)); > +void iio_triggered_event_cleanup(struct iio_dev *indio_dev); > + > +#endif > -- Peter Meerwald +43-664-2444418 (mobile) ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 5/5] iio: Support triggered events [not found] ` <1438038442-13082-1-git-send-email-vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> 2015-07-28 6:37 ` Peter Meerwald @ 2015-07-29 7:56 ` Paul Bolle 2015-07-29 7:58 ` Christoph Hellwig 1 sibling, 1 reply; 10+ messages in thread From: Paul Bolle @ 2015-07-29 7:56 UTC (permalink / raw) To: Vladimir Barinov Cc: Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-iio-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, cory.tusar-J6Z/VSE8EyIAspv4Qr0y0gC/G2K4zDHf Just a nit, I'm afraid. On di, 2015-07-28 at 02:07 +0300, Vladimir Barinov wrote: > --- /dev/null > +++ b/drivers/iio/industrialio-triggered-event.c > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published by > + * the Free Software Foundation. This states the license is GPL v2. > +MODULE_LICENSE("GPL"); And, according to include/linux/module.h, this states the license is GPL v2 or later. So either the comment or the ident used in the MODULE_LICENSE() macro needs to change. Thanks, Paul Bolle ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 5/5] iio: Support triggered events 2015-07-29 7:56 ` Paul Bolle @ 2015-07-29 7:58 ` Christoph Hellwig [not found] ` <20150729075834.GA20718-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org> 0 siblings, 1 reply; 10+ messages in thread From: Christoph Hellwig @ 2015-07-29 7:58 UTC (permalink / raw) To: Paul Bolle Cc: Vladimir Barinov, Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, linux-kernel, linux-iio, devicetree, cory.tusar On Wed, Jul 29, 2015 at 09:56:50AM +0200, Paul Bolle wrote: > > > +MODULE_LICENSE("GPL"); > > And, according to include/linux/module.h, this states the license is GPL > v2 or later. So either the comment or the ident used in the > Btw, who came up with that meaning? The default Linux license is GPLv2 only and unless othewise specified that's what we should get by default. ^ permalink raw reply [flat|nested] 10+ messages in thread
[parent not found: <20150729075834.GA20718-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>]
* Re: [PATCH v2 5/5] iio: Support triggered events [not found] ` <20150729075834.GA20718-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org> @ 2015-07-29 8:03 ` Paul Bolle 0 siblings, 0 replies; 10+ messages in thread From: Paul Bolle @ 2015-07-29 8:03 UTC (permalink / raw) To: Christoph Hellwig Cc: Vladimir Barinov, Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-iio-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, cory.tusar-J6Z/VSE8EyIAspv4Qr0y0gC/G2K4zDHf On wo, 2015-07-29 at 00:58 -0700, Christoph Hellwig wrote: > Btw, who came up with that meaning? The default Linux license is GPLv2 > only and unless othewise specified that's what we should get by default. I cobbled together a short history of these license idents in https://lkml.kernel.org/r/1426071405.4244.88.camel@x220 . Hope this helps, Paul Bolle ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 3/5] dt: Document Holt HI-8435 bindings 2015-07-27 23:05 [PATCH v2 0/5] iio: adc: hi8435: Add Holt HI-8435 threshold detector Vladimir Barinov 2015-07-27 23:06 ` [PATCH v2 1/5] iio: adc: hi8435: " Vladimir Barinov [not found] ` <1438038300-12855-1-git-send-email-vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> @ 2015-07-27 23:07 ` Vladimir Barinov 2015-07-27 23:07 ` [PATCH v2 4/5] iio: trigger: Add periodic polling to SYSFS trigger Vladimir Barinov 3 siblings, 0 replies; 10+ messages in thread From: Vladimir Barinov @ 2015-07-27 23:07 UTC (permalink / raw) To: Jonathan Cameron Cc: Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, linux-kernel, linux-iio, devicetree, cory.tusar These bindings can be used to register Holt HI-8435 threshold detector Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> --- Changes in version 2: - renamed file name hi-843x.txt to hi8435.txt - removed hi-8436,hi-8436,hi-8437 - removed holt,debounce-soft field - renamed holt,debounc-soft-delay to holt,debounce-interval - renamed mr-gpio to reset-gpios .../devicetree/bindings/iio/adc/hi8435.txt | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/hi8435.txt diff --git a/Documentation/devicetree/bindings/iio/adc/hi8435.txt b/Documentation/devicetree/bindings/iio/adc/hi8435.txt new file mode 100644 index 0000000..1d33ad0 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/hi8435.txt @@ -0,0 +1,25 @@ +Holt Integrated Circuits HI-8435 threshold detector bindings + +Required properties: + - compatible: should be "holt,hi8435" + - reg: spi chip select number for the device + +Recommended properties: + - spi-max-frequency: definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt + +Optional properties: + - holt,reset-gpios: GPIO used for controlling the reset pin + - holt,debounce-interval: software debounce interval in milliseconds + +Example: +sensor@0 { + compatible = "holt,hi8435"; + reg = <0>; + + holt,reset-gpios = <&gpio6 1 0>; + + holt,debounce-interval = <100>; + + spi-max-frequency = <1000000>; +}; -- 1.9.1 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 4/5] iio: trigger: Add periodic polling to SYSFS trigger 2015-07-27 23:05 [PATCH v2 0/5] iio: adc: hi8435: Add Holt HI-8435 threshold detector Vladimir Barinov ` (2 preceding siblings ...) 2015-07-27 23:07 ` [PATCH v2 3/5] dt: Document Holt HI-8435 bindings Vladimir Barinov @ 2015-07-27 23:07 ` Vladimir Barinov 3 siblings, 0 replies; 10+ messages in thread From: Vladimir Barinov @ 2015-07-27 23:07 UTC (permalink / raw) To: Jonathan Cameron Cc: Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, linux-kernel, linux-iio, devicetree, cory.tusar Add periodic polling functionality to SYSFS trigger Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> --- Changes in version 2: - initially added .../ABI/testing/sysfs-bus-iio-trigger-sysfs | 11 ++++ drivers/iio/trigger/iio-trig-sysfs.c | 58 ++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs b/Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs index 5235e6c..49caff2 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs +++ b/Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs @@ -9,3 +9,14 @@ Description: automated testing or in situations, where other trigger methods are not applicable. For example no RTC or spare GPIOs. X is the IIO index of the trigger. + +What: /sys/bus/iio/devices/triggerX/trigger_poll +KernelVersion: 4.2.0 +Contact: linux-iio@vger.kernel.org +Description: + This file is provided by the iio-trig-sysfs stand-alone trigger + driver. Writing this file with positive value (in milliseconds) + will start peroidic event triggereing of the driver, associated + with this trigger. Writing this file with 0 will stop perioding + triggering. + X is the IIO index of the trigger. diff --git a/drivers/iio/trigger/iio-trig-sysfs.c b/drivers/iio/trigger/iio-trig-sysfs.c index 3dfab2b..ea79311 100644 --- a/drivers/iio/trigger/iio-trig-sysfs.c +++ b/drivers/iio/trigger/iio-trig-sysfs.c @@ -18,6 +18,8 @@ struct iio_sysfs_trig { struct iio_trigger *trig; struct irq_work work; + struct delayed_work poll_work; + unsigned int poll_interval; /* msec */ int id; struct list_head l; }; @@ -110,10 +112,63 @@ static ssize_t iio_sysfs_trigger_poll(struct device *dev, return count; } +static void iio_sysfs_trigger_queue_poll_work(struct iio_sysfs_trig *trig) +{ + unsigned long delay; + + delay = msecs_to_jiffies(trig->poll_interval); + if (delay >= HZ) + delay = round_jiffies_relative(delay); + + queue_delayed_work(system_freezable_wq, &trig->poll_work, delay); +} + +static void iio_sysfs_trigger_poll_work(struct work_struct *work) +{ + struct iio_sysfs_trig *trig = container_of(work, struct iio_sysfs_trig, + poll_work.work); + + irq_work_queue(&trig->work); + iio_sysfs_trigger_queue_poll_work(trig); +} + +static ssize_t iio_sysfs_trigger_get_poll(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_trigger *trig = to_iio_trigger(dev); + struct iio_sysfs_trig *sysfs_trig = iio_trigger_get_drvdata(trig); + + return sprintf(buf, "%d\n", sysfs_trig->poll_interval); +} + +static ssize_t iio_sysfs_trigger_set_poll(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct iio_trigger *trig = to_iio_trigger(dev); + struct iio_sysfs_trig *sysfs_trig = iio_trigger_get_drvdata(trig); + unsigned int interval; + int err; + + err = kstrtouint(buf, 0, &interval); + if (err) + return err; + + sysfs_trig->poll_interval = interval; + + cancel_delayed_work_sync(&sysfs_trig->poll_work); + if (sysfs_trig->poll_interval > 0) + iio_sysfs_trigger_queue_poll_work(sysfs_trig); + + return count; +} + static DEVICE_ATTR(trigger_now, S_IWUSR, NULL, iio_sysfs_trigger_poll); +static DEVICE_ATTR(trigger_poll, S_IRUGO | S_IWUSR, iio_sysfs_trigger_get_poll, + iio_sysfs_trigger_set_poll); static struct attribute *iio_sysfs_trigger_attrs[] = { &dev_attr_trigger_now.attr, + &dev_attr_trigger_poll.attr, NULL, }; @@ -164,6 +219,7 @@ static int iio_sysfs_trigger_probe(int id) iio_trigger_set_drvdata(t->trig, t); init_irq_work(&t->work, iio_sysfs_trigger_work); + INIT_DELAYED_WORK(&t->poll_work, iio_sysfs_trigger_poll_work); ret = iio_trigger_register(t->trig); if (ret) @@ -198,6 +254,8 @@ static int iio_sysfs_trigger_remove(int id) return -EINVAL; } + cancel_delayed_work_sync(&t->poll_work); + iio_trigger_unregister(t->trig); iio_trigger_free(t->trig); -- 1.9.1 ^ permalink raw reply related [flat|nested] 10+ messages in thread
end of thread, other threads:[~2015-07-29 8:03 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2015-07-27 23:05 [PATCH v2 0/5] iio: adc: hi8435: Add Holt HI-8435 threshold detector Vladimir Barinov 2015-07-27 23:06 ` [PATCH v2 1/5] iio: adc: hi8435: " Vladimir Barinov [not found] ` <1438038300-12855-1-git-send-email-vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> 2015-07-27 23:06 ` [PATCH v2 2/5] dt: Add vendor prefix 'holt' Vladimir Barinov 2015-07-27 23:07 ` [PATCH v2 5/5] iio: Support triggered events Vladimir Barinov [not found] ` <1438038442-13082-1-git-send-email-vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> 2015-07-28 6:37 ` Peter Meerwald 2015-07-29 7:56 ` Paul Bolle 2015-07-29 7:58 ` Christoph Hellwig [not found] ` <20150729075834.GA20718-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org> 2015-07-29 8:03 ` Paul Bolle 2015-07-27 23:07 ` [PATCH v2 3/5] dt: Document Holt HI-8435 bindings Vladimir Barinov 2015-07-27 23:07 ` [PATCH v2 4/5] iio: trigger: Add periodic polling to SYSFS trigger Vladimir Barinov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).