From 143324fd89eff7423c01eba79fc7044003a257e9 Mon Sep 17 00:00:00 2001 From: Rohit Sarkar Date: Wed, 18 Mar 2020 21:41:51 +0530 Subject: iio: core: Make mlock internal to the iio core "mlock" should ideally only be used by the iio core. The mlock implementation may change in the future which means that no driver should be explicitly using mlock. Signed-off-by: Rohit Sarkar Signed-off-by: Jonathan Cameron --- include/linux/iio/iio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index eed58ed2f368..e975020abaa6 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -492,7 +492,7 @@ struct iio_buffer_setup_ops { * @buffer: [DRIVER] any buffer present * @buffer_list: [INTERN] list of all buffers currently attached * @scan_bytes: [INTERN] num bytes captured to be fed to buffer demux - * @mlock: [DRIVER] lock used to prevent simultaneous device state + * @mlock: [INTERN] lock used to prevent simultaneous device state * changes * @available_scan_masks: [DRIVER] optional array of allowed bitmasks * @masklength: [INTERN] the length of the mask established from -- cgit v1.2.3 From 501d3e5dd5bd33a7119f35ee6d365a5787e32a30 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Sat, 21 Mar 2020 11:08:01 +0200 Subject: iio: ad_sigma_delta: remove unused IIO channel macros Now that all channel SigmaDelta IIO channel macros have been localized, remove the generic ones. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- include/linux/iio/adc/ad_sigma_delta.h | 58 ---------------------------------- 1 file changed, 58 deletions(-) (limited to 'include') diff --git a/include/linux/iio/adc/ad_sigma_delta.h b/include/linux/iio/adc/ad_sigma_delta.h index 5a127c0ed200..a3a838dcf8e4 100644 --- a/include/linux/iio/adc/ad_sigma_delta.h +++ b/include/linux/iio/adc/ad_sigma_delta.h @@ -133,62 +133,4 @@ void ad_sd_cleanup_buffer_and_trigger(struct iio_dev *indio_dev); int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig); -#define __AD_SD_CHANNEL(_si, _channel1, _channel2, _address, _bits, \ - _storagebits, _shift, _extend_name, _type, _mask_all) \ - { \ - .type = (_type), \ - .differential = (_channel2 == -1 ? 0 : 1), \ - .indexed = 1, \ - .channel = (_channel1), \ - .channel2 = (_channel2), \ - .address = (_address), \ - .extend_name = (_extend_name), \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_OFFSET), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ - .info_mask_shared_by_all = _mask_all, \ - .scan_index = (_si), \ - .scan_type = { \ - .sign = 'u', \ - .realbits = (_bits), \ - .storagebits = (_storagebits), \ - .shift = (_shift), \ - .endianness = IIO_BE, \ - }, \ - } - -#define AD_SD_DIFF_CHANNEL(_si, _channel1, _channel2, _address, _bits, \ - _storagebits, _shift) \ - __AD_SD_CHANNEL(_si, _channel1, _channel2, _address, _bits, \ - _storagebits, _shift, NULL, IIO_VOLTAGE, \ - BIT(IIO_CHAN_INFO_SAMP_FREQ)) - -#define AD_SD_SHORTED_CHANNEL(_si, _channel, _address, _bits, \ - _storagebits, _shift) \ - __AD_SD_CHANNEL(_si, _channel, _channel, _address, _bits, \ - _storagebits, _shift, "shorted", IIO_VOLTAGE, \ - BIT(IIO_CHAN_INFO_SAMP_FREQ)) - -#define AD_SD_CHANNEL(_si, _channel, _address, _bits, \ - _storagebits, _shift) \ - __AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \ - _storagebits, _shift, NULL, IIO_VOLTAGE, \ - BIT(IIO_CHAN_INFO_SAMP_FREQ)) - -#define AD_SD_CHANNEL_NO_SAMP_FREQ(_si, _channel, _address, _bits, \ - _storagebits, _shift) \ - __AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \ - _storagebits, _shift, NULL, IIO_VOLTAGE, 0) - -#define AD_SD_TEMP_CHANNEL(_si, _address, _bits, _storagebits, _shift) \ - __AD_SD_CHANNEL(_si, 0, -1, _address, _bits, \ - _storagebits, _shift, NULL, IIO_TEMP, \ - BIT(IIO_CHAN_INFO_SAMP_FREQ)) - -#define AD_SD_SUPPLY_CHANNEL(_si, _channel, _address, _bits, _storagebits, \ - _shift) \ - __AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \ - _storagebits, _shift, "supply", IIO_VOLTAGE, \ - BIT(IIO_CHAN_INFO_SAMP_FREQ)) - #endif -- cgit v1.2.3 From 9159c7c06cebfab4bebca0a930b924ad29437638 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Sat, 28 Mar 2020 18:34:21 +0200 Subject: iio: buffer: drop left-over 'stufftoread' field This seems like a left-over from a7348347ba8a4 ("staging:iio: Add polling of events on the ring access chrdev."). Then it was moved into the sca3000 driver around 9dd4694dafbd8 ("iio: staging: sca3000: hide stufftoread logic"), and that one seemed to be the only user of this. Then it eventually was no longer used after 152a6a884ae1 ("staging:iio:accel:sca3000 move to hybrid hard / soft buffer design.") Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- include/linux/iio/buffer_impl.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'include') diff --git a/include/linux/iio/buffer_impl.h b/include/linux/iio/buffer_impl.h index a4d2d8061ef6..1e7edf6bed96 100644 --- a/include/linux/iio/buffer_impl.h +++ b/include/linux/iio/buffer_impl.h @@ -115,9 +115,6 @@ struct iio_buffer { */ struct attribute_group scan_el_group; - /* @stufftoread: Flag to indicate new data. */ - bool stufftoread; - /* @attrs: Standard attributes of the buffer. */ const struct attribute **attrs; -- cgit v1.2.3 From 641dedd50c488739b56ef0f716988e646295dce4 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Tue, 24 Mar 2020 15:46:29 +0200 Subject: include: fpga: adi-axi-common.h: fixup whitespace tab -> space The initial version use a tab between '#define' & 'ADI_AXI_REG_VERSION'. This changes it to space. The change is purely cosmetic. Acked-by: Moritz Fischer Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- include/linux/fpga/adi-axi-common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/fpga/adi-axi-common.h b/include/linux/fpga/adi-axi-common.h index 7fc95d5c95bb..ebd4e07ae3d8 100644 --- a/include/linux/fpga/adi-axi-common.h +++ b/include/linux/fpga/adi-axi-common.h @@ -11,7 +11,7 @@ #ifndef ADI_AXI_COMMON_H_ #define ADI_AXI_COMMON_H_ -#define ADI_AXI_REG_VERSION 0x0000 +#define ADI_AXI_REG_VERSION 0x0000 #define ADI_AXI_PCORE_VER(major, minor, patch) \ (((major) << 16) | ((minor) << 8) | (patch)) -- cgit v1.2.3 From 20d5fa48d333670ffbc08d387a80710be91259a0 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Tue, 24 Mar 2020 15:46:30 +0200 Subject: include: fpga: adi-axi-common.h: add version helper macros The format for all ADI AXI IP cores is the same. i.e. 'major.minor.patch'. This patch adds the helper macros to be re-used in ADI AXI drivers. Acked-by: Moritz Fischer Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- include/linux/fpga/adi-axi-common.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include') diff --git a/include/linux/fpga/adi-axi-common.h b/include/linux/fpga/adi-axi-common.h index ebd4e07ae3d8..141ac3f251e6 100644 --- a/include/linux/fpga/adi-axi-common.h +++ b/include/linux/fpga/adi-axi-common.h @@ -16,4 +16,8 @@ #define ADI_AXI_PCORE_VER(major, minor, patch) \ (((major) << 16) | ((minor) << 8) | (patch)) +#define ADI_AXI_PCORE_VER_MAJOR(version) (((version) >> 16) & 0xff) +#define ADI_AXI_PCORE_VER_MINOR(version) (((version) >> 8) & 0xff) +#define ADI_AXI_PCORE_VER_PATCH(version) ((version) & 0xff) + #endif /* ADI_AXI_COMMON_H_ */ -- cgit v1.2.3 From e0fcca9fbd99e959855aa1d66c125d696f969e68 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Tue, 24 Mar 2020 15:46:32 +0200 Subject: iio: buffer-dmaengine: add dev-managed calls for buffer alloc Currently, when using a 'iio_dmaengine_buffer_alloc()', an matching call to 'iio_dmaengine_buffer_free()' must be made. With this change, this can be avoided by using 'devm_iio_dmaengine_buffer_alloc()'. The buffer will get free'd via the device's devres handling. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/buffer/industrialio-buffer-dmaengine.c | 39 ++++++++++++++++++++++ include/linux/iio/buffer-dmaengine.h | 3 ++ 2 files changed, 42 insertions(+) (limited to 'include') diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index 94da3b1ca3a2..6dedf12b69a4 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -229,6 +229,45 @@ void iio_dmaengine_buffer_free(struct iio_buffer *buffer) } EXPORT_SYMBOL_GPL(iio_dmaengine_buffer_free); +static void __devm_iio_dmaengine_buffer_free(struct device *dev, void *res) +{ + iio_dmaengine_buffer_free(*(struct iio_buffer **)res); +} + +/** + * devm_iio_dmaengine_buffer_alloc() - Resource-managed iio_dmaengine_buffer_alloc() + * @dev: Parent device for the buffer + * @channel: DMA channel name, typically "rx". + * + * This allocates a new IIO buffer which internally uses the DMAengine framework + * to perform its transfers. The parent device will be used to request the DMA + * channel. + * + * The buffer will be automatically de-allocated once the device gets destroyed. + */ +struct iio_buffer *devm_iio_dmaengine_buffer_alloc(struct device *dev, + const char *channel) +{ + struct iio_buffer **bufferp, *buffer; + + bufferp = devres_alloc(__devm_iio_dmaengine_buffer_free, + sizeof(*bufferp), GFP_KERNEL); + if (!bufferp) + return ERR_PTR(-ENOMEM); + + buffer = iio_dmaengine_buffer_alloc(dev, channel); + if (IS_ERR(buffer)) { + devres_free(bufferp); + return buffer; + } + + *bufferp = buffer; + devres_add(dev, bufferp); + + return buffer; +} +EXPORT_SYMBOL_GPL(devm_iio_dmaengine_buffer_alloc); + MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_DESCRIPTION("DMA buffer for the IIO framework"); MODULE_LICENSE("GPL"); diff --git a/include/linux/iio/buffer-dmaengine.h b/include/linux/iio/buffer-dmaengine.h index b3a57444a886..0e503db71289 100644 --- a/include/linux/iio/buffer-dmaengine.h +++ b/include/linux/iio/buffer-dmaengine.h @@ -14,4 +14,7 @@ struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev, const char *channel); void iio_dmaengine_buffer_free(struct iio_buffer *buffer); +struct iio_buffer *devm_iio_dmaengine_buffer_alloc(struct device *dev, + const char *channel); + #endif -- cgit v1.2.3 From ef04070692a21633ec6a60f80c19b6af44b3cf47 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 24 Mar 2020 15:46:33 +0200 Subject: iio: adc: adi-axi-adc: add support for AXI ADC IP core This change adds support for the Analog Devices Generic AXI ADC IP core. The IP core is used for interfacing with analog-to-digital (ADC) converters that require either a high-speed serial interface (JESD204B/C) or a source synchronous parallel interface (LVDS/CMOS). Usually, some other interface type (i.e SPI) is used as a control interface for the actual ADC, while the IP core (controlled via this driver), will interface to the data-lines of the ADC and handle the streaming of data into memory via DMA. Because of this, the AXI ADC driver needs the other SPI-ADC driver to register with it. The SPI-ADC needs to be register via the SPI framework, while the AXI ADC registers as a platform driver. The two cannot be ordered in a hierarchy as both drivers have their own registers, and trying to organize this [in a hierarchy becomes] problematic when trying to map memory/registers. There are some modes where the AXI ADC can operate as standalone ADC, but those will be implemented at a later point in time. DocLink: https://wiki.analog.com/resources/fpga/docs/axi_adc_ip Signed-off-by: Michael Hennerich Signed-off-by: Lars-Peter Clausen Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 20 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/adi-axi-adc.c | 482 ++++++++++++++++++++++++++++++++++++ include/linux/iio/adc/adi-axi-adc.h | 64 +++++ 4 files changed, 567 insertions(+) create mode 100644 drivers/iio/adc/adi-axi-adc.c create mode 100644 include/linux/iio/adc/adi-axi-adc.h (limited to 'include') diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index f4da821c4022..445070abf376 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -246,6 +246,26 @@ config AD799X To compile this driver as a module, choose M here: the module will be called ad799x. +config ADI_AXI_ADC + tristate "Analog Devices Generic AXI ADC IP core driver" + select IIO_BUFFER + select IIO_BUFFER_HW_CONSUMER + select IIO_BUFFER_DMAENGINE + help + Say yes here to build support for Analog Devices Generic + AXI ADC IP core. The IP core is used for interfacing with + analog-to-digital (ADC) converters that require either a high-speed + serial interface (JESD204B/C) or a source synchronous parallel + interface (LVDS/CMOS). + Typically (for such devices) SPI will be used for configuration only, + while this IP core handles the streaming of data into memory via DMA. + + Link: https://wiki.analog.com/resources/fpga/docs/axi_adc_ip + If unsure, say N (but it's safe to say "Y"). + + To compile this driver as a module, choose M here: the + module will be called adi-axi-adc. + config ASPEED_ADC tristate "Aspeed ADC" depends on ARCH_ASPEED || COMPILE_TEST diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 8462455b4228..7c6594d049f9 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_AD7793) += ad7793.o obj-$(CONFIG_AD7887) += ad7887.o obj-$(CONFIG_AD7949) += ad7949.o obj-$(CONFIG_AD799X) += ad799x.o +obj-$(CONFIG_ADI_AXI_ADC) += adi-axi-adc.o obj-$(CONFIG_ASPEED_ADC) += aspeed_adc.o obj-$(CONFIG_AT91_ADC) += at91_adc.o obj-$(CONFIG_AT91_SAMA5D2_ADC) += at91-sama5d2_adc.o diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c new file mode 100644 index 000000000000..c24c8da99eb4 --- /dev/null +++ b/drivers/iio/adc/adi-axi-adc.c @@ -0,0 +1,482 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices Generic AXI ADC IP core + * Link: https://wiki.analog.com/resources/fpga/docs/axi_adc_ip + * + * Copyright 2012-2020 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +/** + * Register definitions: + * https://wiki.analog.com/resources/fpga/docs/axi_adc_ip#register_map + */ + +/* ADC controls */ + +#define ADI_AXI_REG_RSTN 0x0040 +#define ADI_AXI_REG_RSTN_CE_N BIT(2) +#define ADI_AXI_REG_RSTN_MMCM_RSTN BIT(1) +#define ADI_AXI_REG_RSTN_RSTN BIT(0) + +/* ADC Channel controls */ + +#define ADI_AXI_REG_CHAN_CTRL(c) (0x0400 + (c) * 0x40) +#define ADI_AXI_REG_CHAN_CTRL_LB_OWR BIT(11) +#define ADI_AXI_REG_CHAN_CTRL_PN_SEL_OWR BIT(10) +#define ADI_AXI_REG_CHAN_CTRL_IQCOR_EN BIT(9) +#define ADI_AXI_REG_CHAN_CTRL_DCFILT_EN BIT(8) +#define ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT BIT(6) +#define ADI_AXI_REG_CHAN_CTRL_FMT_TYPE BIT(5) +#define ADI_AXI_REG_CHAN_CTRL_FMT_EN BIT(4) +#define ADI_AXI_REG_CHAN_CTRL_PN_TYPE_OWR BIT(1) +#define ADI_AXI_REG_CHAN_CTRL_ENABLE BIT(0) + +#define ADI_AXI_REG_CHAN_CTRL_DEFAULTS \ + (ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT | \ + ADI_AXI_REG_CHAN_CTRL_FMT_EN | \ + ADI_AXI_REG_CHAN_CTRL_ENABLE) + +struct adi_axi_adc_core_info { + unsigned int version; +}; + +struct adi_axi_adc_state { + struct mutex lock; + + struct adi_axi_adc_client *client; + void __iomem *regs; +}; + +struct adi_axi_adc_client { + struct list_head entry; + struct adi_axi_adc_conv conv; + struct adi_axi_adc_state *state; + struct device *dev; + const struct adi_axi_adc_core_info *info; +}; + +static LIST_HEAD(registered_clients); +static DEFINE_MUTEX(registered_clients_lock); + +static struct adi_axi_adc_client *conv_to_client(struct adi_axi_adc_conv *conv) +{ + return container_of(conv, struct adi_axi_adc_client, conv); +} + +void *adi_axi_adc_conv_priv(struct adi_axi_adc_conv *conv) +{ + struct adi_axi_adc_client *cl = conv_to_client(conv); + + return (char *)cl + ALIGN(sizeof(struct adi_axi_adc_client), IIO_ALIGN); +} +EXPORT_SYMBOL_GPL(adi_axi_adc_conv_priv); + +static void adi_axi_adc_write(struct adi_axi_adc_state *st, + unsigned int reg, + unsigned int val) +{ + iowrite32(val, st->regs + reg); +} + +static unsigned int adi_axi_adc_read(struct adi_axi_adc_state *st, + unsigned int reg) +{ + return ioread32(st->regs + reg); +} + +static int adi_axi_adc_config_dma_buffer(struct device *dev, + struct iio_dev *indio_dev) +{ + struct iio_buffer *buffer; + const char *dma_name; + + if (!device_property_present(dev, "dmas")) + return 0; + + if (device_property_read_string(dev, "dma-names", &dma_name)) + dma_name = "rx"; + + buffer = devm_iio_dmaengine_buffer_alloc(indio_dev->dev.parent, + dma_name); + if (IS_ERR(buffer)) + return PTR_ERR(buffer); + + indio_dev->modes |= INDIO_BUFFER_HARDWARE; + iio_device_attach_buffer(indio_dev, buffer); + + return 0; +} + +static int adi_axi_adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct adi_axi_adc_state *st = iio_priv(indio_dev); + struct adi_axi_adc_conv *conv = &st->client->conv; + + if (!conv->read_raw) + return -EOPNOTSUPP; + + return conv->read_raw(conv, chan, val, val2, mask); +} + +static int adi_axi_adc_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct adi_axi_adc_state *st = iio_priv(indio_dev); + struct adi_axi_adc_conv *conv = &st->client->conv; + + if (!conv->write_raw) + return -EOPNOTSUPP; + + return conv->write_raw(conv, chan, val, val2, mask); +} + +static int adi_axi_adc_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct adi_axi_adc_state *st = iio_priv(indio_dev); + struct adi_axi_adc_conv *conv = &st->client->conv; + unsigned int i, ctrl; + + for (i = 0; i < conv->chip_info->num_channels; i++) { + ctrl = adi_axi_adc_read(st, ADI_AXI_REG_CHAN_CTRL(i)); + + if (test_bit(i, scan_mask)) + ctrl |= ADI_AXI_REG_CHAN_CTRL_ENABLE; + else + ctrl &= ~ADI_AXI_REG_CHAN_CTRL_ENABLE; + + adi_axi_adc_write(st, ADI_AXI_REG_CHAN_CTRL(i), ctrl); + } + + return 0; +} + +static struct adi_axi_adc_conv *adi_axi_adc_conv_register(struct device *dev, + size_t sizeof_priv) +{ + struct adi_axi_adc_client *cl; + size_t alloc_size; + + alloc_size = ALIGN(sizeof(struct adi_axi_adc_client), IIO_ALIGN); + if (sizeof_priv) + alloc_size += ALIGN(sizeof_priv, IIO_ALIGN); + + cl = kzalloc(alloc_size, GFP_KERNEL); + if (!cl) + return ERR_PTR(-ENOMEM); + + mutex_lock(®istered_clients_lock); + + cl->dev = get_device(dev); + + list_add_tail(&cl->entry, ®istered_clients); + + mutex_unlock(®istered_clients_lock); + + return &cl->conv; +} + +static void adi_axi_adc_conv_unregister(struct adi_axi_adc_conv *conv) +{ + struct adi_axi_adc_client *cl = conv_to_client(conv); + + mutex_lock(®istered_clients_lock); + + list_del(&cl->entry); + put_device(cl->dev); + + mutex_unlock(®istered_clients_lock); + + kfree(cl); +} + +static void devm_adi_axi_adc_conv_release(struct device *dev, void *res) +{ + adi_axi_adc_conv_unregister(*(struct adi_axi_adc_conv **)res); +} + +struct adi_axi_adc_conv *devm_adi_axi_adc_conv_register(struct device *dev, + size_t sizeof_priv) +{ + struct adi_axi_adc_conv **ptr, *conv; + + ptr = devres_alloc(devm_adi_axi_adc_conv_release, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + conv = adi_axi_adc_conv_register(dev, sizeof_priv); + if (IS_ERR(conv)) { + devres_free(ptr); + return ERR_CAST(conv); + } + + *ptr = conv; + devres_add(dev, ptr); + + return conv; +} +EXPORT_SYMBOL_GPL(devm_adi_axi_adc_conv_register); + +static ssize_t in_voltage_scale_available_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct adi_axi_adc_state *st = iio_priv(indio_dev); + struct adi_axi_adc_conv *conv = &st->client->conv; + size_t len = 0; + int i; + + for (i = 0; i < conv->chip_info->num_scales; i++) { + const unsigned int *s = conv->chip_info->scale_table[i]; + + len += scnprintf(buf + len, PAGE_SIZE - len, + "%u.%06u ", s[0], s[1]); + } + buf[len - 1] = '\n'; + + return len; +} + +static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0); + +enum { + ADI_AXI_ATTR_SCALE_AVAIL, +}; + +#define ADI_AXI_ATTR(_en_, _file_) \ + [ADI_AXI_ATTR_##_en_] = &iio_dev_attr_##_file_.dev_attr.attr + +static struct attribute *adi_axi_adc_attributes[] = { + ADI_AXI_ATTR(SCALE_AVAIL, in_voltage_scale_available), + NULL +}; + +static umode_t axi_adc_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct adi_axi_adc_state *st = iio_priv(indio_dev); + struct adi_axi_adc_conv *conv = &st->client->conv; + + switch (n) { + case ADI_AXI_ATTR_SCALE_AVAIL: + if (!conv->chip_info->num_scales) + return 0; + return attr->mode; + default: + return attr->mode; + } +} + +static const struct attribute_group adi_axi_adc_attribute_group = { + .attrs = adi_axi_adc_attributes, + .is_visible = axi_adc_attr_is_visible, +}; + +static const struct iio_info adi_axi_adc_info = { + .read_raw = &adi_axi_adc_read_raw, + .write_raw = &adi_axi_adc_write_raw, + .attrs = &adi_axi_adc_attribute_group, + .update_scan_mode = &adi_axi_adc_update_scan_mode, +}; + +static const struct adi_axi_adc_core_info adi_axi_adc_10_0_a_info = { + .version = ADI_AXI_PCORE_VER(10, 0, 'a'), +}; + +static struct adi_axi_adc_client *adi_axi_adc_attach_client(struct device *dev) +{ + const struct adi_axi_adc_core_info *info; + struct adi_axi_adc_client *cl; + struct device_node *cln; + + info = of_device_get_match_data(dev); + if (!info) + return ERR_PTR(-ENODEV); + + cln = of_parse_phandle(dev->of_node, "adi,adc-dev", 0); + if (!cln) { + dev_err(dev, "No 'adi,adc-dev' node defined\n"); + return ERR_PTR(-ENODEV); + } + + mutex_lock(®istered_clients_lock); + + list_for_each_entry(cl, ®istered_clients, entry) { + if (!cl->dev) + continue; + + if (cl->dev->of_node != cln) + continue; + + if (!try_module_get(dev->driver->owner)) { + mutex_unlock(®istered_clients_lock); + return ERR_PTR(-ENODEV); + } + + get_device(dev); + cl->info = info; + mutex_unlock(®istered_clients_lock); + return cl; + } + + mutex_unlock(®istered_clients_lock); + + return ERR_PTR(-EPROBE_DEFER); +} + +static int adi_axi_adc_setup_channels(struct device *dev, + struct adi_axi_adc_state *st) +{ + struct adi_axi_adc_conv *conv = &st->client->conv; + int i, ret; + + if (conv->preenable_setup) { + ret = conv->preenable_setup(conv); + if (ret) + return ret; + } + + for (i = 0; i < conv->chip_info->num_channels; i++) { + adi_axi_adc_write(st, ADI_AXI_REG_CHAN_CTRL(i), + ADI_AXI_REG_CHAN_CTRL_DEFAULTS); + } + + return 0; +} + +static void axi_adc_reset(struct adi_axi_adc_state *st) +{ + adi_axi_adc_write(st, ADI_AXI_REG_RSTN, 0); + mdelay(10); + adi_axi_adc_write(st, ADI_AXI_REG_RSTN, ADI_AXI_REG_RSTN_MMCM_RSTN); + mdelay(10); + adi_axi_adc_write(st, ADI_AXI_REG_RSTN, + ADI_AXI_REG_RSTN_RSTN | ADI_AXI_REG_RSTN_MMCM_RSTN); +} + +static void adi_axi_adc_cleanup(void *data) +{ + struct adi_axi_adc_client *cl = data; + + put_device(cl->dev); + module_put(cl->dev->driver->owner); +} + +static int adi_axi_adc_probe(struct platform_device *pdev) +{ + struct adi_axi_adc_conv *conv; + struct iio_dev *indio_dev; + struct adi_axi_adc_client *cl; + struct adi_axi_adc_state *st; + unsigned int ver; + int ret; + + cl = adi_axi_adc_attach_client(&pdev->dev); + if (IS_ERR(cl)) + return PTR_ERR(cl); + + ret = devm_add_action_or_reset(&pdev->dev, adi_axi_adc_cleanup, cl); + if (ret) + return ret; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*st)); + if (indio_dev == NULL) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->client = cl; + cl->state = st; + mutex_init(&st->lock); + + st->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(st->regs)) + return PTR_ERR(st->regs); + + conv = &st->client->conv; + + axi_adc_reset(st); + + ver = adi_axi_adc_read(st, ADI_AXI_REG_VERSION); + + if (cl->info->version > ver) { + dev_err(&pdev->dev, + "IP core version is too old. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n", + ADI_AXI_PCORE_VER_MAJOR(cl->info->version), + ADI_AXI_PCORE_VER_MINOR(cl->info->version), + ADI_AXI_PCORE_VER_PATCH(cl->info->version), + ADI_AXI_PCORE_VER_MAJOR(ver), + ADI_AXI_PCORE_VER_MINOR(ver), + ADI_AXI_PCORE_VER_PATCH(ver)); + return -ENODEV; + } + + indio_dev->info = &adi_axi_adc_info; + indio_dev->dev.parent = &pdev->dev; + indio_dev->name = "adi-axi-adc"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->num_channels = conv->chip_info->num_channels; + indio_dev->channels = conv->chip_info->channels; + + ret = adi_axi_adc_config_dma_buffer(&pdev->dev, indio_dev); + if (ret) + return ret; + + ret = adi_axi_adc_setup_channels(&pdev->dev, st); + if (ret) + return ret; + + ret = devm_iio_device_register(&pdev->dev, indio_dev); + if (ret) + return ret; + + dev_info(&pdev->dev, "AXI ADC IP core (%d.%.2d.%c) probed\n", + ADI_AXI_PCORE_VER_MAJOR(ver), + ADI_AXI_PCORE_VER_MINOR(ver), + ADI_AXI_PCORE_VER_PATCH(ver)); + + return 0; +} + +/* Match table for of_platform binding */ +static const struct of_device_id adi_axi_adc_of_match[] = { + { .compatible = "adi,axi-adc-10.0.a", .data = &adi_axi_adc_10_0_a_info }, + { /* end of list */ } +}; +MODULE_DEVICE_TABLE(of, adi_axi_adc_of_match); + +static struct platform_driver adi_axi_adc_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = adi_axi_adc_of_match, + }, + .probe = adi_axi_adc_probe, +}; +module_platform_driver(adi_axi_adc_driver); + +MODULE_AUTHOR("Michael Hennerich "); +MODULE_DESCRIPTION("Analog Devices Generic AXI ADC IP core driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/iio/adc/adi-axi-adc.h b/include/linux/iio/adc/adi-axi-adc.h new file mode 100644 index 000000000000..c5d48e1c2d36 --- /dev/null +++ b/include/linux/iio/adc/adi-axi-adc.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Analog Devices Generic AXI ADC IP core driver/library + * Link: https://wiki.analog.com/resources/fpga/docs/axi_adc_ip + * + * Copyright 2012-2020 Analog Devices Inc. + */ +#ifndef __ADI_AXI_ADC_H__ +#define __ADI_AXI_ADC_H__ + +struct device; +struct iio_chan_spec; + +/** + * struct adi_axi_adc_chip_info - Chip specific information + * @name Chip name + * @id Chip ID (usually product ID) + * @channels Channel specifications of type @struct axi_adc_chan_spec + * @num_channels Number of @channels + * @scale_table Supported scales by the chip; tuples of 2 ints + * @num_scales Number of scales in the table + * @max_rate Maximum sampling rate supported by the device + */ +struct adi_axi_adc_chip_info { + const char *name; + unsigned int id; + + const struct iio_chan_spec *channels; + unsigned int num_channels; + + const unsigned int (*scale_table)[2]; + int num_scales; + + unsigned long max_rate; +}; + +/** + * struct adi_axi_adc_conv - data of the ADC attached to the AXI ADC + * @chip_info chip info details for the client ADC + * @preenable_setup op to run in the client before enabling the AXI ADC + * @reg_access IIO debugfs_reg_access hook for the client ADC + * @read_raw IIO read_raw hook for the client ADC + * @write_raw IIO write_raw hook for the client ADC + */ +struct adi_axi_adc_conv { + const struct adi_axi_adc_chip_info *chip_info; + + int (*preenable_setup)(struct adi_axi_adc_conv *conv); + int (*reg_access)(struct adi_axi_adc_conv *conv, unsigned int reg, + unsigned int writeval, unsigned int *readval); + int (*read_raw)(struct adi_axi_adc_conv *conv, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask); + int (*write_raw)(struct adi_axi_adc_conv *conv, + struct iio_chan_spec const *chan, + int val, int val2, long mask); +}; + +struct adi_axi_adc_conv *devm_adi_axi_adc_conv_register(struct device *dev, + size_t sizeof_priv); + +void *adi_axi_adc_conv_priv(struct adi_axi_adc_conv *conv); + +#endif -- cgit v1.2.3 From c0ae3591d900c0d1a54a86666c2102dd39b3d4f7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 1 Apr 2020 18:57:06 +0200 Subject: iio: dma-buffer: Cleanup buffer.h/buffer_impl.h includes The IIO DMA buffer is a DMA buffer implementation. As such it should include buffer_impl.h rather than buffer.h. The include to buffer.h in buffer-dma.h should be buffer_impl.h so it has access to the struct iio_buffer definition. The code currently only works because all places that use buffer-dma.h include buffer_impl.h before it. The include to buffer.h in industrialio-buffer-dma.c can be removed since those file does not reference any of buffer consumer functions. Signed-off-by: Lars-Peter Clausen Tested-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/buffer/industrialio-buffer-dma.c | 1 - include/linux/iio/buffer-dma.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/iio/buffer/industrialio-buffer-dma.c b/drivers/iio/buffer/industrialio-buffer-dma.c index a74bd9c0587c..d348af8b9705 100644 --- a/drivers/iio/buffer/industrialio-buffer-dma.c +++ b/drivers/iio/buffer/industrialio-buffer-dma.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/include/linux/iio/buffer-dma.h b/include/linux/iio/buffer-dma.h index 016d8a068353..ff15c61bf319 100644 --- a/include/linux/iio/buffer-dma.h +++ b/include/linux/iio/buffer-dma.h @@ -11,7 +11,7 @@ #include #include #include -#include +#include struct iio_dma_buffer_queue; struct iio_dma_buffer_ops; -- cgit v1.2.3 From 2e036804d773e00ea19c6f6b8b7a4b8232c77da1 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 10 Apr 2020 12:36:07 +0300 Subject: iio: buffer: remove 'scan_el_attrs' attribute group from buffer struct This field doesn't seem used. It seems that only 'buffer->attrs' was ever used to extend sysfs attributes for an IIO buffer. Moving forward, it may not make sense to keep it. This patch removes the field and it's initialization code. Since we want to rework IIO buffer, to be able to add more buffers per IIO device, we will merge [somehow] the 'buffer' & 'scan_elements' groups, and we will continue to add the attributes to the 'buffer' group. Removing it here, will also make the rework here a bit smaller, since this code will not be present. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 8 -------- include/linux/iio/buffer_impl.h | 6 ------ 2 files changed, 14 deletions(-) (limited to 'include') diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index e6fa1a4e135d..221157136af6 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -1283,11 +1283,6 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) indio_dev->groups[indio_dev->groupcounter++] = &buffer->buffer_group; - if (buffer->scan_el_attrs != NULL) { - attr = buffer->scan_el_attrs->attrs; - while (*attr++ != NULL) - attrcount_orig++; - } attrcount = attrcount_orig; INIT_LIST_HEAD(&buffer->scan_el_dev_attr_list); channels = indio_dev->channels; @@ -1325,9 +1320,6 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) ret = -ENOMEM; goto error_free_scan_mask; } - if (buffer->scan_el_attrs) - memcpy(buffer->scan_el_group.attrs, buffer->scan_el_attrs, - sizeof(buffer->scan_el_group.attrs[0])*attrcount_orig); attrn = attrcount_orig; list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l) diff --git a/include/linux/iio/buffer_impl.h b/include/linux/iio/buffer_impl.h index 1e7edf6bed96..a63dc07b7350 100644 --- a/include/linux/iio/buffer_impl.h +++ b/include/linux/iio/buffer_impl.h @@ -94,12 +94,6 @@ struct iio_buffer { unsigned int watermark; /* private: */ - /* - * @scan_el_attrs: Control of scan elements if that scan mode - * control method is used. - */ - struct attribute_group *scan_el_attrs; - /* @scan_timestamp: Does the scan mode include a timestamp. */ bool scan_timestamp; -- cgit v1.2.3 From 83af573e980aafa7edf56a449a6e70f6c8ac9792 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 27 Feb 2020 15:52:20 +0200 Subject: iio: core: drop devm_iio_device_unregister() API call It's unused so far, so it can be removed. Also makes sense to remove it to discourage weird uses of this call during review. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- Documentation/driver-api/driver-model/devres.rst | 1 - drivers/iio/industrialio-core.c | 17 ----------------- include/linux/iio/iio.h | 4 ---- 3 files changed, 22 deletions(-) (limited to 'include') diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index 46c13780994c..0580c64ebdfd 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -286,7 +286,6 @@ IIO devm_iio_device_alloc() devm_iio_device_free() devm_iio_device_register() - devm_iio_device_unregister() devm_iio_kfifo_allocate() devm_iio_kfifo_free() devm_iio_triggered_buffer_setup() diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 56ff24d7a174..0f278da12bcb 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1830,23 +1830,6 @@ int __devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev, } EXPORT_SYMBOL_GPL(__devm_iio_device_register); -/** - * devm_iio_device_unregister - Resource-managed iio_device_unregister() - * @dev: Device this iio_dev belongs to - * @indio_dev: the iio_dev associated with the device - * - * Unregister iio_dev registered with devm_iio_device_register(). - */ -void devm_iio_device_unregister(struct device *dev, struct iio_dev *indio_dev) -{ - int rc; - - rc = devres_release(dev, devm_iio_device_unreg, - devm_iio_device_match, indio_dev); - WARN_ON(rc); -} -EXPORT_SYMBOL_GPL(devm_iio_device_unregister); - /** * iio_device_claim_direct_mode - Keep device in direct mode * @indio_dev: the iio_dev associated with the device diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index e975020abaa6..1b2630bc327e 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -593,9 +593,6 @@ void iio_device_unregister(struct iio_dev *indio_dev); * calls iio_device_register() internally. Refer to that function for more * information. * - * If an iio_dev registered with this function needs to be unregistered - * separately, devm_iio_device_unregister() must be used. - * * RETURNS: * 0 on success, negative error number on failure. */ @@ -603,7 +600,6 @@ void iio_device_unregister(struct iio_dev *indio_dev); __devm_iio_device_register((dev), (indio_dev), THIS_MODULE); int __devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev, struct module *this_mod); -void devm_iio_device_unregister(struct device *dev, struct iio_dev *indio_dev); int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp); int iio_device_claim_direct_mode(struct iio_dev *indio_dev); void iio_device_release_direct_mode(struct iio_dev *indio_dev); -- cgit v1.2.3 From 666e4de43d942fbe0d7f1d9dbc993f5b5c81760c Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 27 Feb 2020 15:52:21 +0200 Subject: iio: core: drop devm_iio_triggered_buffer_cleanup() API call It's unused so far, so it can be removed. Also makes sense to remove it to discourage weird uses of this call during review. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- Documentation/driver-api/driver-model/devres.rst | 1 - drivers/iio/buffer/industrialio-triggered-buffer.c | 11 ----------- include/linux/iio/triggered_buffer.h | 2 -- 3 files changed, 14 deletions(-) (limited to 'include') diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index 0580c64ebdfd..1431d5e44abc 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -289,7 +289,6 @@ IIO devm_iio_kfifo_allocate() devm_iio_kfifo_free() devm_iio_triggered_buffer_setup() - devm_iio_triggered_buffer_cleanup() devm_iio_trigger_alloc() devm_iio_trigger_free() devm_iio_trigger_register() diff --git a/drivers/iio/buffer/industrialio-triggered-buffer.c b/drivers/iio/buffer/industrialio-triggered-buffer.c index cb322b2f09cd..e8046c1ecd6b 100644 --- a/drivers/iio/buffer/industrialio-triggered-buffer.c +++ b/drivers/iio/buffer/industrialio-triggered-buffer.c @@ -126,17 +126,6 @@ int devm_iio_triggered_buffer_setup(struct device *dev, } EXPORT_SYMBOL_GPL(devm_iio_triggered_buffer_setup); -void devm_iio_triggered_buffer_cleanup(struct device *dev, - struct iio_dev *indio_dev) -{ - int rc; - - rc = devres_release(dev, devm_iio_triggered_buffer_clean, - devm_iio_device_match, indio_dev); - WARN_ON(rc); -} -EXPORT_SYMBOL_GPL(devm_iio_triggered_buffer_cleanup); - MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_DESCRIPTION("IIO helper functions for setting up triggered buffers"); MODULE_LICENSE("GPL"); diff --git a/include/linux/iio/triggered_buffer.h b/include/linux/iio/triggered_buffer.h index 238ad30ce166..e99c91799359 100644 --- a/include/linux/iio/triggered_buffer.h +++ b/include/linux/iio/triggered_buffer.h @@ -18,7 +18,5 @@ int devm_iio_triggered_buffer_setup(struct device *dev, irqreturn_t (*h)(int irq, void *p), irqreturn_t (*thread)(int irq, void *p), const struct iio_buffer_setup_ops *ops); -void devm_iio_triggered_buffer_cleanup(struct device *dev, - struct iio_dev *indio_dev); #endif -- cgit v1.2.3 From 66be392a48f9d5256b4ba582ff06303fe97b5ca2 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 27 Feb 2020 15:52:22 +0200 Subject: iio: core: drop devm_iio_device_free() API call It's unused so far, so it can be removed. Also makes sense to remove it to discourage weird uses of this call during review. This is the last user of 'devm_iio_device_match()', so it can be removed as well in this patch. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- Documentation/driver-api/driver-model/devres.rst | 1 - drivers/iio/industrialio-core.c | 31 ------------------------ include/linux/iio/iio.h | 2 -- 3 files changed, 34 deletions(-) (limited to 'include') diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index 1431d5e44abc..6ae6c67dfec0 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -284,7 +284,6 @@ I2C IIO devm_iio_device_alloc() - devm_iio_device_free() devm_iio_device_register() devm_iio_kfifo_allocate() devm_iio_kfifo_free() diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 0f278da12bcb..f4daf19f2a3b 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1546,17 +1546,6 @@ static void devm_iio_device_release(struct device *dev, void *res) iio_device_free(*(struct iio_dev **)res); } -int devm_iio_device_match(struct device *dev, void *res, void *data) -{ - struct iio_dev **r = res; - if (!r || !*r) { - WARN_ON(!r || !*r); - return 0; - } - return *r == data; -} -EXPORT_SYMBOL_GPL(devm_iio_device_match); - /** * devm_iio_device_alloc - Resource-managed iio_device_alloc() * @dev: Device to allocate iio_dev for @@ -1565,9 +1554,6 @@ EXPORT_SYMBOL_GPL(devm_iio_device_match); * Managed iio_device_alloc. iio_dev allocated with this function is * automatically freed on driver detach. * - * If an iio_dev allocated with this function needs to be freed separately, - * devm_iio_device_free() must be used. - * * RETURNS: * Pointer to allocated iio_dev on success, NULL on failure. */ @@ -1592,23 +1578,6 @@ struct iio_dev *devm_iio_device_alloc(struct device *dev, int sizeof_priv) } EXPORT_SYMBOL_GPL(devm_iio_device_alloc); -/** - * devm_iio_device_free - Resource-managed iio_device_free() - * @dev: Device this iio_dev belongs to - * @iio_dev: the iio_dev associated with the device - * - * Free iio_dev allocated with devm_iio_device_alloc(). - */ -void devm_iio_device_free(struct device *dev, struct iio_dev *iio_dev) -{ - int rc; - - rc = devres_release(dev, devm_iio_device_release, - devm_iio_device_match, iio_dev); - WARN_ON(rc); -} -EXPORT_SYMBOL_GPL(devm_iio_device_free); - /** * iio_chrdev_open() - chrdev file open for buffer access and ioctls * @inode: Inode structure for identifying the device in the file system diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 1b2630bc327e..4c1e320ef7ed 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -688,9 +688,7 @@ static inline struct iio_dev *iio_priv_to_dev(void *priv) } void iio_device_free(struct iio_dev *indio_dev); -int devm_iio_device_match(struct device *dev, void *res, void *data); struct iio_dev *devm_iio_device_alloc(struct device *dev, int sizeof_priv); -void devm_iio_device_free(struct device *dev, struct iio_dev *indio_dev); struct iio_trigger *devm_iio_trigger_alloc(struct device *dev, const char *fmt, ...); void devm_iio_trigger_free(struct device *dev, struct iio_trigger *iio_trig); -- cgit v1.2.3 From 83381c9803a00d534f32ab52ed91588601eba43f Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 27 Feb 2020 15:52:23 +0200 Subject: iio: core: drop devm_iio_trigger_unregister() API call It's unused so far, so it can be removed. Also makes sense to remove it to discourage weird uses of this call during review. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- Documentation/driver-api/driver-model/devres.rst | 1 - Documentation/driver-api/iio/triggers.rst | 1 - drivers/iio/industrialio-trigger.c | 21 --------------------- include/linux/iio/trigger.h | 3 --- 4 files changed, 26 deletions(-) (limited to 'include') diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index 6ae6c67dfec0..f638a035e6d2 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -291,7 +291,6 @@ IIO devm_iio_trigger_alloc() devm_iio_trigger_free() devm_iio_trigger_register() - devm_iio_trigger_unregister() devm_iio_channel_get() devm_iio_channel_release() devm_iio_channel_get_all() diff --git a/Documentation/driver-api/iio/triggers.rst b/Documentation/driver-api/iio/triggers.rst index 5c2156de6284..160faa810d12 100644 --- a/Documentation/driver-api/iio/triggers.rst +++ b/Documentation/driver-api/iio/triggers.rst @@ -6,7 +6,6 @@ Triggers * :c:func:`devm_iio_trigger_alloc` — Resource-managed iio_trigger_alloc * :c:func:`devm_iio_trigger_free` — Resource-managed iio_trigger_free * :c:func:`devm_iio_trigger_register` — Resource-managed iio_trigger_register -* :c:func:`devm_iio_trigger_unregister` — Resource-managed iio_trigger_unregister * :c:func:`iio_trigger_validate_own_device` — Check if a trigger and IIO device belong to the same device diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 3908a9a90035..611f608a9da2 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -673,9 +673,6 @@ static void devm_iio_trigger_unreg(struct device *dev, void *res) * calls iio_trigger_register() internally. Refer to that function for more * information. * - * If an iio_trigger registered with this function needs to be unregistered - * separately, devm_iio_trigger_unregister() must be used. - * * RETURNS: * 0 on success, negative error number on failure. */ @@ -701,24 +698,6 @@ int __devm_iio_trigger_register(struct device *dev, } EXPORT_SYMBOL_GPL(__devm_iio_trigger_register); -/** - * devm_iio_trigger_unregister - Resource-managed iio_trigger_unregister() - * @dev: device this iio_trigger belongs to - * @trig_info: the trigger associated with the device - * - * Unregister trigger registered with devm_iio_trigger_register(). - */ -void devm_iio_trigger_unregister(struct device *dev, - struct iio_trigger *trig_info) -{ - int rc; - - rc = devres_release(dev, devm_iio_trigger_unreg, devm_iio_trigger_match, - trig_info); - WARN_ON(rc); -} -EXPORT_SYMBOL_GPL(devm_iio_trigger_unregister); - bool iio_trigger_using_own(struct iio_dev *indio_dev) { return indio_dev->trig->attached_own_device; diff --git a/include/linux/iio/trigger.h b/include/linux/iio/trigger.h index 84995e2967ac..cad8325903f9 100644 --- a/include/linux/iio/trigger.h +++ b/include/linux/iio/trigger.h @@ -141,9 +141,6 @@ int __devm_iio_trigger_register(struct device *dev, **/ void iio_trigger_unregister(struct iio_trigger *trig_info); -void devm_iio_trigger_unregister(struct device *dev, - struct iio_trigger *trig_info); - /** * iio_trigger_set_immutable() - set an immutable trigger on destination * -- cgit v1.2.3 From 92b7ed7fe40dd26de62ff8f5aa1605909a14e3ef Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 27 Feb 2020 15:52:24 +0200 Subject: iio: core: drop devm_iio_trigger_free() API call It's unused so far, so it can be removed. Also makes sense to remove it to discourage weird uses of this call during review. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- Documentation/driver-api/driver-model/devres.rst | 1 - Documentation/driver-api/iio/triggers.rst | 1 - drivers/iio/industrialio-trigger.c | 32 ------------------------ include/linux/iio/iio.h | 2 -- 4 files changed, 36 deletions(-) (limited to 'include') diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index f638a035e6d2..6c401c74e480 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -289,7 +289,6 @@ IIO devm_iio_kfifo_free() devm_iio_triggered_buffer_setup() devm_iio_trigger_alloc() - devm_iio_trigger_free() devm_iio_trigger_register() devm_iio_channel_get() devm_iio_channel_release() diff --git a/Documentation/driver-api/iio/triggers.rst b/Documentation/driver-api/iio/triggers.rst index 160faa810d12..dfd7ba3eabde 100644 --- a/Documentation/driver-api/iio/triggers.rst +++ b/Documentation/driver-api/iio/triggers.rst @@ -4,7 +4,6 @@ Triggers * struct :c:type:`iio_trigger` — industrial I/O trigger device * :c:func:`devm_iio_trigger_alloc` — Resource-managed iio_trigger_alloc -* :c:func:`devm_iio_trigger_free` — Resource-managed iio_trigger_free * :c:func:`devm_iio_trigger_register` — Resource-managed iio_trigger_register iio_trigger_unregister * :c:func:`iio_trigger_validate_own_device` — Check if a trigger and IIO diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 611f608a9da2..53d1931f6be8 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -585,18 +585,6 @@ static void devm_iio_trigger_release(struct device *dev, void *res) iio_trigger_free(*(struct iio_trigger **)res); } -static int devm_iio_trigger_match(struct device *dev, void *res, void *data) -{ - struct iio_trigger **r = res; - - if (!r || !*r) { - WARN_ON(!r || !*r); - return 0; - } - - return *r == data; -} - /** * devm_iio_trigger_alloc - Resource-managed iio_trigger_alloc() * @dev: Device to allocate iio_trigger for @@ -608,9 +596,6 @@ static int devm_iio_trigger_match(struct device *dev, void *res, void *data) * Managed iio_trigger_alloc. iio_trigger allocated with this function is * automatically freed on driver detach. * - * If an iio_trigger allocated with this function needs to be freed separately, - * devm_iio_trigger_free() must be used. - * * RETURNS: * Pointer to allocated iio_trigger on success, NULL on failure. */ @@ -640,23 +625,6 @@ struct iio_trigger *devm_iio_trigger_alloc(struct device *dev, } EXPORT_SYMBOL_GPL(devm_iio_trigger_alloc); -/** - * devm_iio_trigger_free - Resource-managed iio_trigger_free() - * @dev: Device this iio_dev belongs to - * @iio_trig: the iio_trigger associated with the device - * - * Free iio_trigger allocated with devm_iio_trigger_alloc(). - */ -void devm_iio_trigger_free(struct device *dev, struct iio_trigger *iio_trig) -{ - int rc; - - rc = devres_release(dev, devm_iio_trigger_release, - devm_iio_trigger_match, iio_trig); - WARN_ON(rc); -} -EXPORT_SYMBOL_GPL(devm_iio_trigger_free); - static void devm_iio_trigger_unreg(struct device *dev, void *res) { iio_trigger_unregister(*(struct iio_trigger **)res); diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 4c1e320ef7ed..d63884a54939 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -691,8 +691,6 @@ void iio_device_free(struct iio_dev *indio_dev); struct iio_dev *devm_iio_device_alloc(struct device *dev, int sizeof_priv); struct iio_trigger *devm_iio_trigger_alloc(struct device *dev, const char *fmt, ...); -void devm_iio_trigger_free(struct device *dev, struct iio_trigger *iio_trig); - /** * iio_buffer_enabled() - helper function to test if the buffer is enabled * @indio_dev: IIO device structure for device -- cgit v1.2.3 From fc1f75a0347aecc8b967c8c154564f520d6f4412 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 27 Feb 2020 15:52:25 +0200 Subject: iio: inkern: drop devm_iio_channel_release{_all} API calls It's unused so far, so it can be removed. Also makes sense to remove it to discourage weird uses of this call during review. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- Documentation/driver-api/driver-model/devres.rst | 2 -- drivers/iio/inkern.c | 27 ------------------------ include/linux/iio/consumer.h | 18 ---------------- 3 files changed, 47 deletions(-) (limited to 'include') diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index 6c401c74e480..10ccebe9f7c1 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -291,9 +291,7 @@ IIO devm_iio_trigger_alloc() devm_iio_trigger_register() devm_iio_channel_get() - devm_iio_channel_release() devm_iio_channel_get_all() - devm_iio_channel_release_all() INPUT devm_input_allocate_device() diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 5a8351c9a426..ede99e0d5371 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -360,18 +360,6 @@ static void devm_iio_channel_free(struct device *dev, void *res) iio_channel_release(channel); } -static int devm_iio_channel_match(struct device *dev, void *res, void *data) -{ - struct iio_channel **r = res; - - if (!r || !*r) { - WARN_ON(!r || !*r); - return 0; - } - - return *r == data; -} - struct iio_channel *devm_iio_channel_get(struct device *dev, const char *channel_name) { @@ -394,13 +382,6 @@ struct iio_channel *devm_iio_channel_get(struct device *dev, } EXPORT_SYMBOL_GPL(devm_iio_channel_get); -void devm_iio_channel_release(struct device *dev, struct iio_channel *channel) -{ - WARN_ON(devres_release(dev, devm_iio_channel_free, - devm_iio_channel_match, channel)); -} -EXPORT_SYMBOL_GPL(devm_iio_channel_release); - struct iio_channel *iio_channel_get_all(struct device *dev) { const char *name; @@ -514,14 +495,6 @@ struct iio_channel *devm_iio_channel_get_all(struct device *dev) } EXPORT_SYMBOL_GPL(devm_iio_channel_get_all); -void devm_iio_channel_release_all(struct device *dev, - struct iio_channel *channels) -{ - WARN_ON(devres_release(dev, devm_iio_channel_free_all, - devm_iio_channel_match, channels)); -} -EXPORT_SYMBOL_GPL(devm_iio_channel_release_all); - static int iio_channel_read(struct iio_channel *chan, int *val, int *val2, enum iio_chan_info_enum info) { diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index 2bde8c912d4d..c4118dcb8e05 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h @@ -63,15 +63,6 @@ void iio_channel_release(struct iio_channel *chan); */ struct iio_channel *devm_iio_channel_get(struct device *dev, const char *consumer_channel); -/** - * devm_iio_channel_release() - Resource managed version of - * iio_channel_release(). - * @dev: Pointer to consumer device for which resource - * is allocared. - * @chan: The channel to be released. - */ -void devm_iio_channel_release(struct device *dev, struct iio_channel *chan); - /** * iio_channel_get_all() - get all channels associated with a client * @dev: Pointer to consumer device. @@ -106,15 +97,6 @@ void iio_channel_release_all(struct iio_channel *chan); */ struct iio_channel *devm_iio_channel_get_all(struct device *dev); -/** - * devm_iio_channel_release_all() - Resource managed version of - * iio_channel_release_all(). - * @dev: Pointer to consumer device for which resource - * is allocared. - * @chan: Array channel to be released. - */ -void devm_iio_channel_release_all(struct device *dev, struct iio_channel *chan); - struct iio_cb_buffer; /** * iio_channel_get_all_cb() - register callback for triggered capture -- cgit v1.2.3 From 05c09e3cee0aa97a51c2eac1a2f453cac0ba5683 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 27 Feb 2020 15:52:26 +0200 Subject: iio: buffer: drop devm_iio_hw_consumer_free() API call It's unused so far, so it can be removed. Also makes sense to remove it to discourage weird uses of this call during review. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/buffer/industrialio-hw-consumer.c | 31 --------------------------- include/linux/iio/hw-consumer.h | 1 - 2 files changed, 32 deletions(-) (limited to 'include') diff --git a/drivers/iio/buffer/industrialio-hw-consumer.c b/drivers/iio/buffer/industrialio-hw-consumer.c index 95165697d8ae..f2d27788f666 100644 --- a/drivers/iio/buffer/industrialio-hw-consumer.c +++ b/drivers/iio/buffer/industrialio-hw-consumer.c @@ -142,17 +142,6 @@ static void devm_iio_hw_consumer_release(struct device *dev, void *res) iio_hw_consumer_free(*(struct iio_hw_consumer **)res); } -static int devm_iio_hw_consumer_match(struct device *dev, void *res, void *data) -{ - struct iio_hw_consumer **r = res; - - if (!r || !*r) { - WARN_ON(!r || !*r); - return 0; - } - return *r == data; -} - /** * devm_iio_hw_consumer_alloc - Resource-managed iio_hw_consumer_alloc() * @dev: Pointer to consumer device. @@ -160,9 +149,6 @@ static int devm_iio_hw_consumer_match(struct device *dev, void *res, void *data) * Managed iio_hw_consumer_alloc. iio_hw_consumer allocated with this function * is automatically freed on driver detach. * - * If an iio_hw_consumer allocated with this function needs to be freed - * separately, devm_iio_hw_consumer_free() must be used. - * * returns pointer to allocated iio_hw_consumer on success, NULL on failure. */ struct iio_hw_consumer *devm_iio_hw_consumer_alloc(struct device *dev) @@ -186,23 +172,6 @@ struct iio_hw_consumer *devm_iio_hw_consumer_alloc(struct device *dev) } EXPORT_SYMBOL_GPL(devm_iio_hw_consumer_alloc); -/** - * devm_iio_hw_consumer_free - Resource-managed iio_hw_consumer_free() - * @dev: Pointer to consumer device. - * @hwc: iio_hw_consumer to free. - * - * Free iio_hw_consumer allocated with devm_iio_hw_consumer_alloc(). - */ -void devm_iio_hw_consumer_free(struct device *dev, struct iio_hw_consumer *hwc) -{ - int rc; - - rc = devres_release(dev, devm_iio_hw_consumer_release, - devm_iio_hw_consumer_match, hwc); - WARN_ON(rc); -} -EXPORT_SYMBOL_GPL(devm_iio_hw_consumer_free); - /** * iio_hw_consumer_enable() - Enable IIO hardware consumer * @hwc: iio_hw_consumer to enable. diff --git a/include/linux/iio/hw-consumer.h b/include/linux/iio/hw-consumer.h index 44d48bb1d39f..e8255c2e33bc 100644 --- a/include/linux/iio/hw-consumer.h +++ b/include/linux/iio/hw-consumer.h @@ -14,7 +14,6 @@ struct iio_hw_consumer; struct iio_hw_consumer *iio_hw_consumer_alloc(struct device *dev); void iio_hw_consumer_free(struct iio_hw_consumer *hwc); struct iio_hw_consumer *devm_iio_hw_consumer_alloc(struct device *dev); -void devm_iio_hw_consumer_free(struct device *dev, struct iio_hw_consumer *hwc); int iio_hw_consumer_enable(struct iio_hw_consumer *hwc); void iio_hw_consumer_disable(struct iio_hw_consumer *hwc); -- cgit v1.2.3 From 608d98a2c4a0a72c15fa16ef1542df67afe41fee Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 27 Feb 2020 15:52:27 +0200 Subject: iio: buffer: drop devm_iio_kfifo_free() API call It's unused so far, so it can be removed. Also makes sense to remove it to discourage weird uses of this call during review. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- Documentation/driver-api/driver-model/devres.rst | 1 - drivers/iio/buffer/kfifo_buf.c | 22 ---------------------- include/linux/iio/kfifo_buf.h | 1 - 3 files changed, 24 deletions(-) (limited to 'include') diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index 10ccebe9f7c1..91b0b8e5556c 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -286,7 +286,6 @@ IIO devm_iio_device_alloc() devm_iio_device_register() devm_iio_kfifo_allocate() - devm_iio_kfifo_free() devm_iio_triggered_buffer_setup() devm_iio_trigger_alloc() devm_iio_trigger_register() diff --git a/drivers/iio/buffer/kfifo_buf.c b/drivers/iio/buffer/kfifo_buf.c index 3150f8ab984b..1359abed3b31 100644 --- a/drivers/iio/buffer/kfifo_buf.c +++ b/drivers/iio/buffer/kfifo_buf.c @@ -179,16 +179,6 @@ static void devm_iio_kfifo_release(struct device *dev, void *res) iio_kfifo_free(*(struct iio_buffer **)res); } -static int devm_iio_kfifo_match(struct device *dev, void *res, void *data) -{ - struct iio_buffer **r = res; - - if (WARN_ON(!r || !*r)) - return 0; - - return *r == data; -} - /** * devm_iio_fifo_allocate - Resource-managed iio_kfifo_allocate() * @dev: Device to allocate kfifo buffer for @@ -216,16 +206,4 @@ struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev) } EXPORT_SYMBOL(devm_iio_kfifo_allocate); -/** - * devm_iio_fifo_free - Resource-managed iio_kfifo_free() - * @dev: Device the buffer belongs to - * @r: The buffer associated with the device - */ -void devm_iio_kfifo_free(struct device *dev, struct iio_buffer *r) -{ - WARN_ON(devres_release(dev, devm_iio_kfifo_release, - devm_iio_kfifo_match, r)); -} -EXPORT_SYMBOL(devm_iio_kfifo_free); - MODULE_LICENSE("GPL"); diff --git a/include/linux/iio/kfifo_buf.h b/include/linux/iio/kfifo_buf.h index 764659e01b68..1fc1efa7799d 100644 --- a/include/linux/iio/kfifo_buf.h +++ b/include/linux/iio/kfifo_buf.h @@ -9,6 +9,5 @@ struct iio_buffer *iio_kfifo_allocate(void); void iio_kfifo_free(struct iio_buffer *r); struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev); -void devm_iio_kfifo_free(struct device *dev, struct iio_buffer *r); #endif -- cgit v1.2.3 From fec86c6b8369b5dd8e3a1ad3752578a737163b25 Mon Sep 17 00:00:00 2001 From: Nuno Sá Date: Mon, 13 Apr 2020 10:24:40 +0200 Subject: iio: imu: adis: Add Managed device functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for a managed device version of adis_setup_buffer_and_trigger. It works exactly as the original one but it calls all the devm_iio_* functions to setup an iio buffer and trigger. Hence we do not need to care about cleaning those and we do not need to support a remove() callback for every driver using the adis library. Signed-off-by: Nuno Sá Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis_buffer.c | 45 ++++++++++++++++++++++++++++++++++++++++++ drivers/iio/imu/adis_trigger.c | 41 +++++++++++++++++++++++++++++++++++--- include/linux/iio/imu/adis.h | 17 ++++++++++++++++ 3 files changed, 100 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index 04e5e2a0fd6b..8fdc4dca10c0 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -156,6 +156,14 @@ static irqreturn_t adis_trigger_handler(int irq, void *p) return IRQ_HANDLED; } +static void adis_buffer_cleanup(void *arg) +{ + struct adis *adis = arg; + + kfree(adis->buffer); + kfree(adis->xfer); +} + /** * adis_setup_buffer_and_trigger() - Sets up buffer and trigger for the adis device * @adis: The adis device. @@ -198,6 +206,43 @@ error_buffer_cleanup: } EXPORT_SYMBOL_GPL(adis_setup_buffer_and_trigger); +/** + * devm_adis_setup_buffer_and_trigger() - Sets up buffer and trigger for + * the managed adis device + * @adis: The adis device + * @indio_dev: The IIO device + * @trigger_handler: Optional trigger handler, may be NULL. + * + * Returns 0 on success, a negative error code otherwise. + * + * This function perfoms exactly the same as adis_setup_buffer_and_trigger() + */ +int +devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev, + irq_handler_t trigger_handler) +{ + int ret; + + if (!trigger_handler) + trigger_handler = adis_trigger_handler; + + ret = devm_iio_triggered_buffer_setup(&adis->spi->dev, indio_dev, + &iio_pollfunc_store_time, + trigger_handler, NULL); + if (ret) + return ret; + + if (adis->spi->irq) { + ret = devm_adis_probe_trigger(adis, indio_dev); + if (ret) + return ret; + } + + return devm_add_action_or_reset(&adis->spi->dev, adis_buffer_cleanup, + adis); +} +EXPORT_SYMBOL_GPL(devm_adis_setup_buffer_and_trigger); + /** * adis_cleanup_buffer_and_trigger() - Free buffer and trigger resources * @adis: The adis device. diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c index 8b9cd02c0f9f..a36810e0b1ab 100644 --- a/drivers/iio/imu/adis_trigger.c +++ b/drivers/iio/imu/adis_trigger.c @@ -27,6 +27,13 @@ static const struct iio_trigger_ops adis_trigger_ops = { .set_trigger_state = &adis_data_rdy_trigger_set_state, }; +static void adis_trigger_setup(struct adis *adis) +{ + adis->trig->dev.parent = &adis->spi->dev; + adis->trig->ops = &adis_trigger_ops; + iio_trigger_set_drvdata(adis->trig, adis); +} + /** * adis_probe_trigger() - Sets up trigger for a adis device * @adis: The adis device @@ -45,9 +52,7 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) if (adis->trig == NULL) return -ENOMEM; - adis->trig->dev.parent = &adis->spi->dev; - adis->trig->ops = &adis_trigger_ops; - iio_trigger_set_drvdata(adis->trig, adis); + adis_trigger_setup(adis); ret = request_irq(adis->spi->irq, &iio_trigger_generic_data_rdy_poll, @@ -73,6 +78,36 @@ error_free_trig: } EXPORT_SYMBOL_GPL(adis_probe_trigger); +/** + * devm_adis_probe_trigger() - Sets up trigger for a managed adis device + * @adis: The adis device + * @indio_dev: The IIO device + * + * Returns 0 on success or a negative error code + */ +int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) +{ + int ret; + + adis->trig = devm_iio_trigger_alloc(&adis->spi->dev, "%s-dev%d", + indio_dev->name, indio_dev->id); + if (!adis->trig) + return -ENOMEM; + + adis_trigger_setup(adis); + + ret = devm_request_irq(&adis->spi->dev, adis->spi->irq, + &iio_trigger_generic_data_rdy_poll, + IRQF_TRIGGER_RISING, + indio_dev->name, + adis->trig); + if (ret) + return ret; + + return devm_iio_trigger_register(&adis->spi->dev, adis->trig); +} +EXPORT_SYMBOL_GPL(devm_adis_probe_trigger); + /** * adis_remove_trigger() - Remove trigger for a adis devices * @adis: The adis device diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h index dd8219138c2e..e70814d96e1c 100644 --- a/include/linux/iio/imu/adis.h +++ b/include/linux/iio/imu/adis.h @@ -448,11 +448,15 @@ struct adis_burst { unsigned int extra_len; }; +int +devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev, + irq_handler_t trigger_handler); int adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev, irqreturn_t (*trigger_handler)(int, void *)); void adis_cleanup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev); +int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev); int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev); void adis_remove_trigger(struct adis *adis); @@ -461,6 +465,13 @@ int adis_update_scan_mode(struct iio_dev *indio_dev, #else /* CONFIG_IIO_BUFFER */ +static inline int +devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev, + irq_handler_t trigger_handler) +{ + return 0; +} + static inline int adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev, irqreturn_t (*trigger_handler)(int, void *)) { @@ -472,6 +483,12 @@ static inline void adis_cleanup_buffer_and_trigger(struct adis *adis, { } +static inline int devm_adis_probe_trigger(struct adis *adis, + struct iio_dev *indio_dev) +{ + return 0; +} + static inline int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) { -- cgit v1.2.3 From 698211065d4aa71ce599b38c23452664a5a8e370 Mon Sep 17 00:00:00 2001 From: Nuno Sá Date: Mon, 13 Apr 2020 10:24:41 +0200 Subject: iio: imu: adis: Add irq flag variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are some ADIS devices that can configure the data ready pin polarity. Hence, we cannot hardcode our IRQ mask as IRQF_TRIGGER_RISING since we might want to have it as IRQF_TRIGGER_FALLING. Signed-off-by: Nuno Sá Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis_trigger.c | 33 +++++++++++++++++++++++++++++++-- include/linux/iio/imu/adis.h | 2 ++ 2 files changed, 33 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c index a36810e0b1ab..8afe71947c00 100644 --- a/drivers/iio/imu/adis_trigger.c +++ b/drivers/iio/imu/adis_trigger.c @@ -34,6 +34,27 @@ static void adis_trigger_setup(struct adis *adis) iio_trigger_set_drvdata(adis->trig, adis); } +static int adis_validate_irq_flag(struct adis *adis) +{ + /* + * Typically this devices have data ready either on the rising edge or + * on the falling edge of the data ready pin. This checks enforces that + * one of those is set in the drivers... It defaults to + * IRQF_TRIGGER_RISING for backward compatibility wiht devices that + * don't support changing the pin polarity. + */ + if (!adis->irq_flag) { + adis->irq_flag = IRQF_TRIGGER_RISING; + return 0; + } else if (adis->irq_flag != IRQF_TRIGGER_RISING && + adis->irq_flag != IRQF_TRIGGER_FALLING) { + dev_err(&adis->spi->dev, "Invalid IRQ mask: %08lx\n", + adis->irq_flag); + return -EINVAL; + } + + return 0; +} /** * adis_probe_trigger() - Sets up trigger for a adis device * @adis: The adis device @@ -54,9 +75,13 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) adis_trigger_setup(adis); + ret = adis_validate_irq_flag(adis); + if (ret) + return ret; + ret = request_irq(adis->spi->irq, &iio_trigger_generic_data_rdy_poll, - IRQF_TRIGGER_RISING, + adis->irq_flag, indio_dev->name, adis->trig); if (ret) @@ -96,9 +121,13 @@ int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) adis_trigger_setup(adis); + ret = adis_validate_irq_flag(adis); + if (ret) + return ret; + ret = devm_request_irq(&adis->spi->dev, adis->spi->irq, &iio_trigger_generic_data_rdy_poll, - IRQF_TRIGGER_RISING, + adis->irq_flag, indio_dev->name, adis->trig); if (ret) diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h index e70814d96e1c..70e4d1d262f5 100644 --- a/include/linux/iio/imu/adis.h +++ b/include/linux/iio/imu/adis.h @@ -87,6 +87,7 @@ struct adis_data { * @msg: SPI message object * @xfer: SPI transfer objects to be used for a @msg * @current_page: Some ADIS devices have registers, this selects current page + * @irq_flag: IRQ handling flags as passed to request_irq() * @buffer: Data buffer for information read from the device * @tx: DMA safe TX buffer for SPI transfers * @rx: DMA safe RX buffer for SPI transfers @@ -113,6 +114,7 @@ struct adis { struct spi_message msg; struct spi_transfer *xfer; unsigned int current_page; + unsigned long irq_flag; void *buffer; uint8_t tx[10] ____cacheline_aligned; -- cgit v1.2.3 From b9c5eec725d67b548e4dfdc406d6ca2c6d30d1c2 Mon Sep 17 00:00:00 2001 From: Nuno Sá Date: Mon, 13 Apr 2020 10:24:42 +0200 Subject: iio: adis: Add adis_update_bits() APIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds a `regmap_update_bits()` like API to the ADIS library. It provides locked and unlocked variant. Signed-off-by: Nuno Sá Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis.c | 25 +++++++++++++++++++ include/linux/iio/imu/adis.h | 59 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) (limited to 'include') diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c index 2e7d0d337f8f..c539dfa3b8d3 100644 --- a/drivers/iio/imu/adis.c +++ b/drivers/iio/imu/adis.c @@ -223,6 +223,31 @@ int __adis_read_reg(struct adis *adis, unsigned int reg, return ret; } EXPORT_SYMBOL_GPL(__adis_read_reg); +/** + * __adis_update_bits_base() - ADIS Update bits function - Unlocked version + * @adis: The adis device + * @reg: The address of the lower of the two registers + * @mask: Bitmask to change + * @val: Value to be written + * @size: Size of the register to update + * + * Updates the desired bits of @reg in accordance with @mask and @val. + */ +int __adis_update_bits_base(struct adis *adis, unsigned int reg, const u32 mask, + const u32 val, u8 size) +{ + int ret; + u32 __val; + + ret = __adis_read_reg(adis, reg, &__val, size); + if (ret) + return ret; + + __val = (__val & ~mask) | (val & mask); + + return __adis_write_reg(adis, reg, __val, size); +} +EXPORT_SYMBOL_GPL(__adis_update_bits_base); #ifdef CONFIG_DEBUG_FS diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h index 70e4d1d262f5..247fc4c7185c 100644 --- a/include/linux/iio/imu/adis.h +++ b/include/linux/iio/imu/adis.h @@ -333,6 +333,65 @@ static inline int adis_read_reg_32(struct adis *adis, unsigned int reg, return ret; } +int __adis_update_bits_base(struct adis *adis, unsigned int reg, const u32 mask, + const u32 val, u8 size); +/** + * adis_update_bits_base() - ADIS Update bits function - Locked version + * @adis: The adis device + * @reg: The address of the lower of the two registers + * @mask: Bitmask to change + * @val: Value to be written + * @size: Size of the register to update + * + * Updates the desired bits of @reg in accordance with @mask and @val. + */ +static inline int adis_update_bits_base(struct adis *adis, unsigned int reg, + const u32 mask, const u32 val, u8 size) +{ + int ret; + + mutex_lock(&adis->state_lock); + ret = __adis_update_bits_base(adis, reg, mask, val, size); + mutex_unlock(&adis->state_lock); + return ret; +} + +/** + * adis_update_bits() - Wrapper macro for adis_update_bits_base - Locked version + * @adis: The adis device + * @reg: The address of the lower of the two registers + * @mask: Bitmask to change + * @val: Value to be written + * + * This macro evaluates the sizeof of @val at compile time and calls + * adis_update_bits_base() accordingly. Be aware that using MACROS/DEFINES for + * @val can lead to undesired behavior if the register to update is 16bit. + */ +#define adis_update_bits(adis, reg, mask, val) ({ \ + BUILD_BUG_ON(sizeof(val) == 1 || sizeof(val) == 8); \ + __builtin_choose_expr(sizeof(val) == 4, \ + adis_update_bits_base(adis, reg, mask, val, 4), \ + adis_update_bits_base(adis, reg, mask, val, 2)); \ +}) + +/** + * adis_update_bits() - Wrapper macro for adis_update_bits_base + * @adis: The adis device + * @reg: The address of the lower of the two registers + * @mask: Bitmask to change + * @val: Value to be written + * + * This macro evaluates the sizeof of @val at compile time and calls + * adis_update_bits_base() accordingly. Be aware that using MACROS/DEFINES for + * @val can lead to undesired behavior if the register to update is 16bit. + */ +#define __adis_update_bits(adis, reg, mask, val) ({ \ + BUILD_BUG_ON(sizeof(val) == 1 || sizeof(val) == 8); \ + __builtin_choose_expr(sizeof(val) == 4, \ + __adis_update_bits_base(adis, reg, mask, val, 4), \ + __adis_update_bits_base(adis, reg, mask, val, 2)); \ +}) + int adis_enable_irq(struct adis *adis, bool enable); int __adis_check_status(struct adis *adis); int __adis_initial_startup(struct adis *adis); -- cgit v1.2.3 From 3e04cb60e872b9433e523d62c39addf0bd1a18f1 Mon Sep 17 00:00:00 2001 From: Nuno Sá Date: Mon, 13 Apr 2020 10:24:43 +0200 Subject: iio: adis: Support different burst sizes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add burst_max_len to `adis_burst`. This is useful for devices which support different burst modes with different sizes. The buffer to be used in the spi transfer is allocated with this variable making sure that has space for all burst modes. The spi transfer length should hold the "real" burst length depending on the current burst mode configured in the device. Moreover, `extra_len` in `adis_burst` is made const and it should contain the smallest extra length necessary for a burst transfer. In `struct adis` was added a new `burst_extra_len` that should hold the extra bytes needed depending on the device instance being used. Signed-off-by: Nuno Sá Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400.c | 2 +- drivers/iio/imu/adis_buffer.c | 13 +++++++++---- include/linux/iio/imu/adis.h | 9 +++++++-- 3 files changed, 17 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c index 4445c242709c..439feb755d82 100644 --- a/drivers/iio/imu/adis16400.c +++ b/drivers/iio/imu/adis16400.c @@ -1195,7 +1195,7 @@ static int adis16400_probe(struct spi_device *spi) indio_dev->available_scan_masks = st->avail_scan_mask; st->adis.burst = &adis16400_burst; if (st->variant->flags & ADIS16400_BURST_DIAG_STAT) - st->adis.burst->extra_len = sizeof(u16); + st->adis.burst_extra_len = sizeof(u16); } adis16400_data = &st->variant->adis_data; diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index 8fdc4dca10c0..5b4225ee09b9 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -23,25 +23,30 @@ static int adis_update_scan_mode_burst(struct iio_dev *indio_dev, const unsigned long *scan_mask) { struct adis *adis = iio_device_get_drvdata(indio_dev); - unsigned int burst_length; + unsigned int burst_length, burst_max_length; u8 *tx; /* All but the timestamp channel */ burst_length = (indio_dev->num_channels - 1) * sizeof(u16); - burst_length += adis->burst->extra_len; + burst_length += adis->burst->extra_len + adis->burst_extra_len; + + if (adis->burst->burst_max_len) + burst_max_length = adis->burst->burst_max_len; + else + burst_max_length = burst_length; adis->xfer = kcalloc(2, sizeof(*adis->xfer), GFP_KERNEL); if (!adis->xfer) return -ENOMEM; - adis->buffer = kzalloc(burst_length + sizeof(u16), GFP_KERNEL); + adis->buffer = kzalloc(burst_max_length + sizeof(u16), GFP_KERNEL); if (!adis->buffer) { kfree(adis->xfer); adis->xfer = NULL; return -ENOMEM; } - tx = adis->buffer + burst_length; + tx = adis->buffer + burst_max_length; tx[0] = ADIS_READ_REG(adis->burst->reg_cmd); tx[1] = 0; diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h index 247fc4c7185c..2df67448f0d1 100644 --- a/include/linux/iio/imu/adis.h +++ b/include/linux/iio/imu/adis.h @@ -83,6 +83,8 @@ struct adis_data { * @trig: IIO trigger object data * @data: ADIS chip variant specific data * @burst: ADIS burst transfer information + * @burst_extra_len: Burst extra length. Should only be used by devices that can + * dynamically change their burst mode length. * @state_lock: Lock used by the device to protect state * @msg: SPI message object * @xfer: SPI transfer objects to be used for a @msg @@ -98,7 +100,7 @@ struct adis { const struct adis_data *data; struct adis_burst *burst; - + unsigned int burst_extra_len; /** * The state_lock is meant to be used during operations that require * a sequence of SPI R/W in order to protect the SPI transfer @@ -502,11 +504,14 @@ int adis_single_conversion(struct iio_dev *indio_dev, * @en burst mode enabled * @reg_cmd register command that triggers burst * @extra_len extra length to account in the SPI RX buffer + * @burst_max_len holds the maximum burst size when the device supports + * more than one burst mode with different sizes */ struct adis_burst { bool en; unsigned int reg_cmd; - unsigned int extra_len; + const u32 extra_len; + const u32 burst_max_len; }; int -- cgit v1.2.3