diff options
119 files changed, 4447 insertions, 1494 deletions
diff --git a/Documentation/devicetree/bindings/iio/adc/adc.yaml b/Documentation/devicetree/bindings/iio/adc/adc.yaml index 0a77592f7388..8e7835cf36fd 100644 --- a/Documentation/devicetree/bindings/iio/adc/adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adc.yaml @@ -46,6 +46,17 @@ properties: differential channels). If this and diff-channels are not present reg shall be used instead. + common-mode-channel: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Some ADCs have differential input pins that can be used to measure + single-ended or pseudo-differential inputs. This property can be used + in addition to single-channel to signal software that this channel is + not differential but still specify two inputs. + + The input pair is specified by setting single-channel to the positive + input pin and common-mode-channel to the negative pin. + settling-time-us: description: Time between enabling the channel and first stable readings. diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml index ea6cfcd0aff4..17c5d39cc2c1 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml @@ -19,7 +19,18 @@ description: | primarily for measurement of signals close to DC but also delivers outstanding performance with input bandwidths out to ~10kHz. + Analog Devices AD411x ADC's: + The AD411X family encompasses a series of low power, low noise, 24-bit, + sigma-delta analog-to-digital converters that offer a versatile range of + specifications. They integrate an analog front end suitable for processing + fully differential/single-ended and bipolar voltage inputs. + Datasheets for supported chips: + https://www.analog.com/media/en/technical-documentation/data-sheets/AD4111.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD4112.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD4114.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD4115.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD4116.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD7172-2.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD7172-4.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD7173-8.pdf @@ -31,6 +42,11 @@ description: | properties: compatible: enum: + - adi,ad4111 + - adi,ad4112 + - adi,ad4114 + - adi,ad4115 + - adi,ad4116 - adi,ad7172-2 - adi,ad7172-4 - adi,ad7173-8 @@ -129,10 +145,56 @@ patternProperties: maximum: 15 diff-channels: + description: | + This property is used for defining the inputs of a differential + voltage channel. The first value is the positive input and the second + value is the negative input of the channel. + + Family AD411x supports a dedicated VINCOM voltage input. + To select it set the second channel to 16. + (VIN2, VINCOM) -> diff-channels = <2 16> + + There are special values that can be selected besides the voltage + analog inputs: + 21: REF+ + 22: REF− + + Supported only by AD7172-2, AD7172-4, AD7175-2, AD7175-8, AD7177-2, + must be paired together and can be used to monitor the power supply + of the ADC: + 19: ((AVDD1 − AVSS)/5)+ + 20: ((AVDD1 − AVSS)/5)− + items: minimum: 0 maximum: 31 + single-channel: + description: | + This property is used for defining a current channel or the positive + input of a voltage channel (single-ended or pseudo-differential). + + Models AD4111 and AD4112 support current channels. + Example: (IIN2+, IIN2−) -> single-channel = <2> + To correctly configure a current channel set the "adi,current-channel" + property to true. + + To configure a single-ended/pseudo-differential channel set the + "common-mode-channel" property to the desired negative voltage input. + + When used as a voltage channel, special inputs are valid as well. + minimum: 0 + maximum: 31 + + common-mode-channel: + description: + This property is used for defining the negative input of a + single-ended or pseudo-differential voltage channel. + + Special inputs are valid as well. + minimum: 0 + maximum: 31 + adi,reference-select: description: | Select the reference source to use when converting on @@ -154,9 +216,31 @@ patternProperties: - avdd default: refout-avss + adi,current-channel: + $ref: /schemas/types.yaml#/definitions/flag + description: | + Signal that the selected inputs are current channels. + Only available on AD4111 and AD4112. + required: - reg - - diff-channels + + allOf: + - oneOf: + - required: [single-channel] + properties: + diff-channels: false + - required: [diff-channels] + properties: + single-channel: false + adi,current-channel: false + common-mode-channel: false + + - if: + required: [common-mode-channel] + then: + properties: + adi,current-channel: false required: - compatible @@ -166,7 +250,6 @@ allOf: - $ref: /schemas/spi/spi-peripheral-props.yaml# # Only ad7172-4, ad7173-8 and ad7175-8 support vref2 - # Other models have [0-3] channel registers - if: properties: compatible: @@ -187,6 +270,37 @@ allOf: - vref - refout-avss - avdd + + - if: + properties: + compatible: + contains: + enum: + - adi,ad4114 + - adi,ad4115 + - adi,ad4116 + - adi,ad7173-8 + - adi,ad7175-8 + then: + patternProperties: + "^channel@[0-9a-f]$": + properties: + reg: + maximum: 15 + + - if: + properties: + compatible: + contains: + enum: + - adi,ad7172-2 + - adi,ad7175-2 + - adi,ad7176-2 + - adi,ad7177-2 + then: + patternProperties: + "^channel@[0-9a-f]$": + properties: reg: maximum: 3 @@ -211,6 +325,34 @@ allOf: - adi,reference-select - if: + properties: + compatible: + contains: + enum: + - adi,ad4111 + - adi,ad4112 + - adi,ad4114 + - adi,ad4115 + - adi,ad4116 + then: + properties: + avdd2-supply: false + + - if: + properties: + compatible: + not: + contains: + enum: + - adi,ad4111 + - adi,ad4112 + then: + patternProperties: + "^channel@[0-9a-f]$": + properties: + adi,current-channel: false + + - if: anyOf: - required: [clock-names] - required: [clocks] @@ -221,6 +363,7 @@ allOf: unevaluatedProperties: false examples: + # Example AD7173-8 with external reference connected to REF+/REF-: - | #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> @@ -277,3 +420,50 @@ examples: }; }; }; + + # Example AD4111 with current channel and single-ended channel: + - | + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "adi,ad4111"; + reg = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + interrupts = <25 IRQ_TYPE_EDGE_FALLING>; + interrupt-names = "rdy"; + interrupt-parent = <&gpio>; + spi-max-frequency = <5000000>; + gpio-controller; + #gpio-cells = <2>; + #clock-cells = <0>; + + channel@0 { + reg = <0>; + bipolar; + diff-channels = <4 5>; + }; + + // Single ended channel VIN2/VINCOM + channel@1 { + reg = <1>; + bipolar; + single-channel = <2>; + common-mode-channel = <16>; + }; + + // Current channel IN2+/IN2- + channel@2 { + reg = <2>; + single-channel = <2>; + adi,current-channel; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml index 7fa46df1f4fb..00fdaed11cbd 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml @@ -11,6 +11,7 @@ maintainers: description: | Analog Devices AD7606 Simultaneous Sampling ADC + https://www.analog.com/media/en/technical-documentation/data-sheets/AD7605-4.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/ad7606_7606-6_7606-4.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD7606B.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD7616.pdf @@ -19,9 +20,9 @@ properties: compatible: enum: - adi,ad7605-4 - - adi,ad7606-8 - - adi,ad7606-6 - adi,ad7606-4 + - adi,ad7606-6 + - adi,ad7606-8 # Referred to as AD7606 (without -8) in the datasheet - adi,ad7606b - adi,ad7616 diff --git a/Documentation/devicetree/bindings/iio/adc/mediatek,mt6359-auxadc.yaml b/Documentation/devicetree/bindings/iio/adc/mediatek,mt6359-auxadc.yaml new file mode 100644 index 000000000000..6497c416094d --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/mediatek,mt6359-auxadc.yaml @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/mediatek,mt6359-auxadc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek MT6350 series PMIC AUXADC + +maintainers: + - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> + +description: + The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found + in some MediaTek PMICs, performing various PMIC related measurements + such as battery and PMIC internal voltage regulators temperatures, + accessory detection resistance (usually, for a 3.5mm audio jack) + other than voltages for various PMIC internal components. + +properties: + compatible: + enum: + - mediatek,mt6357-auxadc + - mediatek,mt6358-auxadc + - mediatek,mt6359-auxadc + + "#io-channel-cells": + const: 1 + +required: + - compatible + - "#io-channel-cells" + +additionalProperties: false diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml index c1b1324fa132..2722edab1d9a 100644 --- a/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml @@ -246,6 +246,10 @@ patternProperties: From common IIO binding. Used to pipe external sigma delta modulator or internal ADC output to DFSDM channel. + port: + $ref: /schemas/sound/audio-graph-port.yaml# + unevaluatedProperties: false + required: - compatible - "#sound-dai-cells" diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads1119.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads1119.yaml new file mode 100644 index 000000000000..ba6850ab1f90 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/ti,ads1119.yaml @@ -0,0 +1,155 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/ti,ads1119.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments ADS1119 ADC + +maintainers: + - João Paulo Gonçalves <jpaulo.silvagoncalves@gmail.com> + +description: + The TI ADS1119 is a precision 16-bit ADC over I2C that offers single-ended and + differential measurements using a multiplexed input. It features a programmable + gain, a programmable sample rate, an internal oscillator and voltage reference, + and a 50/60Hz rejection filter. + +properties: + compatible: + const: ti,ads1119 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + avdd-supply: true + dvdd-supply: true + + vref-supply: + description: + ADC external reference voltage (VREF). + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + "#io-channel-cells": + const: 1 + +required: + - compatible + - reg + - "#address-cells" + - "#size-cells" + - avdd-supply + - dvdd-supply + +patternProperties: + "^channel@([0-6])$": + $ref: adc.yaml + type: object + properties: + reg: + minimum: 0 + maximum: 6 + + diff-channels: + description: + Differential input channels AIN0-AIN1, AIN2-AIN3 and AIN1-AIN2. + oneOf: + - items: + - const: 0 + - const: 1 + - items: + - const: 2 + - const: 3 + - items: + - const: 1 + - const: 2 + + single-channel: + description: + Single-ended input channels AIN0, AIN1, AIN2 and AIN3. + minimum: 0 + maximum: 3 + + oneOf: + - required: + - diff-channels + - required: + - single-channel + + required: + - reg + + unevaluatedProperties: false + +additionalProperties: false + +examples: + - | + + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + adc@40 { + compatible = "ti,ads1119"; + reg = <0x40>; + interrupt-parent = <&gpio1>; + interrupts = <25 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; + avdd-supply = <®_avdd_ads1119>; + dvdd-supply = <®_dvdd_ads1119>; + vref-supply = <®_vref_ads1119>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + + channel@0 { + reg = <0>; + single-channel = <0>; + }; + + channel@1 { + reg = <1>; + diff-channels = <0 1>; + }; + + channel@2 { + reg = <2>; + single-channel = <3>; + }; + + channel@3 { + reg = <3>; + single-channel = <1>; + }; + + channel@4 { + reg = <4>; + single-channel = <2>; + }; + + channel@5 { + reg = <5>; + diff-channels = <1 2>; + }; + + channel@6 { + reg = <6>; + diff-channels = <2 3>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/frequency/adi,adf4350.yaml b/Documentation/devicetree/bindings/iio/frequency/adi,adf4350.yaml index 43cbf27114c7..d1d1311332f8 100644 --- a/Documentation/devicetree/bindings/iio/frequency/adi,adf4350.yaml +++ b/Documentation/devicetree/bindings/iio/frequency/adi,adf4350.yaml @@ -28,6 +28,12 @@ properties: clock-names: const: clkin + '#clock-cells': + const: 0 + + clock-output-names: + maxItems: 1 + gpios: maxItems: 1 description: Lock detect GPIO. diff --git a/Documentation/devicetree/bindings/iio/st,st-sensors.yaml b/Documentation/devicetree/bindings/iio/st,st-sensors.yaml index fff7e3d83a02..71c1ee33a393 100644 --- a/Documentation/devicetree/bindings/iio/st,st-sensors.yaml +++ b/Documentation/devicetree/bindings/iio/st,st-sensors.yaml @@ -26,6 +26,7 @@ properties: - st,lis2dw12 - st,lis2hh12 - st,lis2dh12-accel + - st,lis2ds12 - st,lis302dl - st,lis331dl-accel - st,lis331dlh-accel diff --git a/Documentation/driver-api/dmaengine/client.rst b/Documentation/driver-api/dmaengine/client.rst index ecf139f73da4..d491e385d61a 100644 --- a/Documentation/driver-api/dmaengine/client.rst +++ b/Documentation/driver-api/dmaengine/client.rst @@ -80,6 +80,10 @@ The details of these operations are: - slave_sg: DMA a list of scatter gather buffers from/to a peripheral + - peripheral_dma_vec: DMA an array of scatter gather buffers from/to a + peripheral. Similar to slave_sg, but uses an array of dma_vec + structures instead of a scatterlist. + - dma_cyclic: Perform a cyclic DMA operation from/to a peripheral till the operation is explicitly stopped. @@ -102,6 +106,11 @@ The details of these operations are: unsigned int sg_len, enum dma_data_direction direction, unsigned long flags); + struct dma_async_tx_descriptor *dmaengine_prep_peripheral_dma_vec( + struct dma_chan *chan, const struct dma_vec *vecs, + size_t nents, enum dma_data_direction direction, + unsigned long flags); + struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic( struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, size_t period_len, enum dma_data_direction direction); diff --git a/Documentation/driver-api/dmaengine/provider.rst b/Documentation/driver-api/dmaengine/provider.rst index ceac2a300e32..3085f8b460fa 100644 --- a/Documentation/driver-api/dmaengine/provider.rst +++ b/Documentation/driver-api/dmaengine/provider.rst @@ -433,6 +433,12 @@ supported. - residue: Provides the residue bytes of the transfer for those that support residue. +- ``device_prep_peripheral_dma_vec`` + + - Similar to ``device_prep_slave_sg``, but it takes a pointer to a + array of ``dma_vec`` structures, which (in the long run) will replace + scatterlists. + - ``device_issue_pending`` - Takes the first transaction descriptor in the pending queue, @@ -544,6 +550,10 @@ dma_cookie_t - Not really relevant any more since the introduction of ``virt-dma`` that abstracts it away. +dma_vec + +- A small structure that contains a DMA address and length. + DMA_CTRL_ACK - If clear, the descriptor cannot be reused by provider until the diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index 18caebad7376..ac9ee7441887 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -464,7 +464,10 @@ SLAVE DMA ENGINE SPI devm_spi_alloc_master() devm_spi_alloc_slave() + devm_spi_optimize_message() devm_spi_register_controller() + devm_spi_register_host() + devm_spi_register_target() WATCHDOG devm_watchdog_register_device() diff --git a/Documentation/iio/iio_dmabuf_api.rst b/Documentation/iio/iio_dmabuf_api.rst new file mode 100644 index 000000000000..2836cadbd495 --- /dev/null +++ b/Documentation/iio/iio_dmabuf_api.rst @@ -0,0 +1,54 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=================================== +High-speed DMABUF interface for IIO +=================================== + +1. Overview +=========== + +The Industrial I/O subsystem supports access to buffers through a +file-based interface, with read() and write() access calls through the +IIO device's dev node. + +It additionally supports a DMABUF based interface, where the userspace +can attach DMABUF objects (externally created) to an IIO buffer, and +subsequently use them for data transfers. + +A userspace application can then use this interface to share DMABUF +objects between several interfaces, allowing it to transfer data in a +zero-copy fashion, for instance between IIO and the USB stack. + +The userspace application can also memory-map the DMABUF objects, and +access the sample data directly. The advantage of doing this vs. the +read() interface is that it avoids an extra copy of the data between the +kernel and userspace. This is particularly useful for high-speed devices +which produce several megabytes or even gigabytes of data per second. +It does however increase the userspace-kernelspace synchronization +overhead, as the DMA_BUF_SYNC_START and DMA_BUF_SYNC_END IOCTLs have to +be used for data integrity. + +2. User API +=========== + +As part of this interface, three new IOCTLs have been added. These three +IOCTLs have to be performed on the IIO buffer's file descriptor, which +can be obtained using the IIO_BUFFER_GET_FD_IOCTL() ioctl. + + ``IIO_BUFFER_DMABUF_ATTACH_IOCTL(int fd)`` + Attach the DMABUF object, identified by its file descriptor, to the + IIO buffer. Returns zero on success, and a negative errno value on + error. + + ``IIO_BUFFER_DMABUF_DETACH_IOCTL(int fd)`` + Detach the given DMABUF object, identified by its file descriptor, + from the IIO buffer. Returns zero on success, and a negative errno + value on error. + + Note that closing the IIO buffer's file descriptor will + automatically detach all previously attached DMABUF objects. + + ``IIO_BUFFER_DMABUF_ENQUEUE_IOCTL(struct iio_dmabuf *iio_dmabuf)`` + Enqueue a previously attached DMABUF object to the buffer queue. + Enqueued DMABUFs will be read from (if output buffer) or written to + (if input buffer) as long as the buffer is enabled. diff --git a/Documentation/iio/index.rst b/Documentation/iio/index.rst index 4c13bfa2865c..9cb4c50cb20d 100644 --- a/Documentation/iio/index.rst +++ b/Documentation/iio/index.rst @@ -9,6 +9,7 @@ Industrial I/O iio_configfs iio_devbuf + iio_dmabuf_api iio_tools Industrial I/O Kernel Drivers diff --git a/MAINTAINERS b/MAINTAINERS index 9102fe0bc393..aae88b7a6c32 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1217,7 +1217,7 @@ F: Documentation/devicetree/bindings/iio/adc/adi,ad7091r* F: drivers/iio/adc/ad7091r* ANALOG DEVICES INC AD7192 DRIVER -M: Alexandru Tachici <alexandru.tachici@analog.com> +M: Alisa-Dariana Roman <alisa.roman@analog.com> L: linux-iio@vger.kernel.org S: Supported W: https://ez.analog.com/linux-software-drivers @@ -3531,6 +3531,13 @@ F: include/linux/cfag12864b.h F: include/uapi/linux/map_to_14segment.h F: include/uapi/linux/map_to_7segment.h +AVAGO APDS9306 AMBIENT LIGHT SENSOR DRIVER +M: Subhajit Ghosh <subhajit.ghosh@tweaklogic.com> +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml +F: drivers/iio/light/apds9306.c + AVIA HX711 ANALOG DIGITAL CONVERTER IIO DRIVER M: Andreas Klinger <ak@it-klinger.de> L: linux-iio@vger.kernel.org @@ -22397,6 +22404,14 @@ M: Robert Richter <rric@kernel.org> S: Odd Fixes F: drivers/gpio/gpio-thunderx.c +TI ADS1119 ADC DRIVER +M: Francesco Dolcini <francesco@dolcini.it> +M: João Paulo Gonçalves <jpaulo.silvagoncalves@gmail.com> +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/adc/ti,ads1119.yaml +F: drivers/iio/adc/ti-ads1119.c + TI ADS7924 ADC DRIVER M: Hugo Villeneuve <hvilleneuve@dimonoff.com> L: linux-iio@vger.kernel.org diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c index bdb752f11869..36943b0c6d60 100644 --- a/drivers/dma/dma-axi-dmac.c +++ b/drivers/dma/dma-axi-dmac.c @@ -620,6 +620,45 @@ static struct axi_dmac_sg *axi_dmac_fill_linear_sg(struct axi_dmac_chan *chan, return sg; } +static struct dma_async_tx_descriptor * +axi_dmac_prep_peripheral_dma_vec(struct dma_chan *c, const struct dma_vec *vecs, + size_t nb, enum dma_transfer_direction direction, + unsigned long flags) +{ + struct axi_dmac_chan *chan = to_axi_dmac_chan(c); + struct axi_dmac_desc *desc; + unsigned int num_sgs = 0; + struct axi_dmac_sg *dsg; + size_t i; + + if (direction != chan->direction) + return NULL; + + for (i = 0; i < nb; i++) + num_sgs += DIV_ROUND_UP(vecs[i].len, chan->max_length); + + desc = axi_dmac_alloc_desc(chan, num_sgs); + if (!desc) + return NULL; + + dsg = desc->sg; + + for (i = 0; i < nb; i++) { + if (!axi_dmac_check_addr(chan, vecs[i].addr) || + !axi_dmac_check_len(chan, vecs[i].len)) { + kfree(desc); + return NULL; + } + + dsg = axi_dmac_fill_linear_sg(chan, direction, vecs[i].addr, 1, + vecs[i].len, dsg); + } + + desc->cyclic = false; + + return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); +} + static struct dma_async_tx_descriptor *axi_dmac_prep_slave_sg( struct dma_chan *c, struct scatterlist *sgl, unsigned int sg_len, enum dma_transfer_direction direction, @@ -1061,6 +1100,7 @@ static int axi_dmac_probe(struct platform_device *pdev) dma_dev->device_tx_status = dma_cookie_status; dma_dev->device_issue_pending = axi_dmac_issue_pending; dma_dev->device_prep_slave_sg = axi_dmac_prep_slave_sg; + dma_dev->device_prep_peripheral_dma_vec = axi_dmac_prep_peripheral_dma_vec; dma_dev->device_prep_dma_cyclic = axi_dmac_prep_dma_cyclic; dma_dev->device_prep_interleaved_dma = axi_dmac_prep_interleaved; dma_dev->device_terminate_all = axi_dmac_terminate_all; diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c index 4c8a80847891..5722cb9d81f9 100644 --- a/drivers/hwmon/iio_hwmon.c +++ b/drivers/hwmon/iio_hwmon.c @@ -33,6 +33,17 @@ struct iio_hwmon_state { struct attribute **attrs; }; +static ssize_t iio_hwmon_read_label(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + struct iio_hwmon_state *state = dev_get_drvdata(dev); + struct iio_channel *chan = &state->channels[sattr->index]; + + return iio_read_channel_label(chan, buf); +} + /* * Assumes that IIO and hwmon operate in the same base units. * This is supposed to be true, but needs verification for @@ -68,12 +79,13 @@ static int iio_hwmon_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct iio_hwmon_state *st; struct sensor_device_attribute *a; - int ret, i; + int ret, i, attr = 0; int in_i = 1, temp_i = 1, curr_i = 1, humidity_i = 1, power_i = 1; enum iio_chan_type type; struct iio_channel *channels; struct device *hwmon_dev; char *sname; + void *buf; channels = devm_iio_channel_get_all(dev); if (IS_ERR(channels)) { @@ -85,17 +97,18 @@ static int iio_hwmon_probe(struct platform_device *pdev) } st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL); - if (st == NULL) + buf = (void *)devm_get_free_pages(dev, GFP_KERNEL, 0); + if (!st || !buf) return -ENOMEM; st->channels = channels; - /* count how many attributes we have */ + /* count how many channels we have */ while (st->channels[st->num_channels].indio_dev) st->num_channels++; st->attrs = devm_kcalloc(dev, - st->num_channels + 1, sizeof(*st->attrs), + 2 * st->num_channels + 1, sizeof(*st->attrs), GFP_KERNEL); if (st->attrs == NULL) return -ENOMEM; @@ -147,9 +160,31 @@ static int iio_hwmon_probe(struct platform_device *pdev) a->dev_attr.show = iio_hwmon_read_val; a->dev_attr.attr.mode = 0444; a->index = i; - st->attrs[i] = &a->dev_attr.attr; + st->attrs[attr++] = &a->dev_attr.attr; + + /* Let's see if we have a label... */ + if (iio_read_channel_label(&st->channels[i], buf) < 0) + continue; + + a = devm_kzalloc(dev, sizeof(*a), GFP_KERNEL); + if (a == NULL) + return -ENOMEM; + + sysfs_attr_init(&a->dev_attr.attr); + a->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, + "%s%d_label", + prefix, n); + if (!a->dev_attr.attr.name) + return -ENOMEM; + + a->dev_attr.show = iio_hwmon_read_label; + a->dev_attr.attr.mode = 0444; + a->index = i; + st->attrs[attr++] = &a->dev_attr.attr; } + devm_free_pages(dev, (unsigned long)buf); + st->attr_group.attrs = st->attrs; st->groups[0] = &st->attr_group; diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index 9c351ffc7bed..661127aed2f9 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -14,6 +14,7 @@ if IIO config IIO_BUFFER bool "Enable buffer support within IIO" + select DMA_SHARED_BUFFER help Provide core support for various buffer based data acquisition methods. diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index 4fbc01bda62e..d25e31613413 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -228,8 +228,8 @@ static int fxls8962af_power_off(struct fxls8962af_data *data) static int fxls8962af_standby(struct fxls8962af_data *data) { - return regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1, - FXLS8962AF_SENS_CONFIG1_ACTIVE, 0); + return regmap_clear_bits(data->regmap, FXLS8962AF_SENS_CONFIG1, + FXLS8962AF_SENS_CONFIG1_ACTIVE); } static int fxls8962af_active(struct fxls8962af_data *data) @@ -785,9 +785,8 @@ static int fxls8962af_reset(struct fxls8962af_data *data) unsigned int reg; int ret; - ret = regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1, - FXLS8962AF_SENS_CONFIG1_RST, - FXLS8962AF_SENS_CONFIG1_RST); + ret = regmap_set_bits(data->regmap, FXLS8962AF_SENS_CONFIG1, + FXLS8962AF_SENS_CONFIG1_RST); if (ret) return ret; @@ -830,9 +829,8 @@ static int fxls8962af_buffer_postenable(struct iio_dev *indio_dev) fxls8962af_standby(data); /* Enable buffer interrupt */ - ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_EN, - FXLS8962AF_INT_EN_BUF_EN, - FXLS8962AF_INT_EN_BUF_EN); + ret = regmap_set_bits(data->regmap, FXLS8962AF_INT_EN, + FXLS8962AF_INT_EN_BUF_EN); if (ret) return ret; @@ -851,8 +849,8 @@ static int fxls8962af_buffer_predisable(struct iio_dev *indio_dev) fxls8962af_standby(data); /* Disable buffer interrupt */ - ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_EN, - FXLS8962AF_INT_EN_BUF_EN, 0); + ret = regmap_clear_bits(data->regmap, FXLS8962AF_INT_EN, + FXLS8962AF_INT_EN_BUF_EN); if (ret) return ret; diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c index ba99649fe195..70dfd6e354db 100644 --- a/drivers/iio/accel/kxsd9.c +++ b/drivers/iio/accel/kxsd9.c @@ -370,10 +370,7 @@ static int kxsd9_power_down(struct kxsd9_state *st) * make sure we conserve power even if there are others users on the * regulators. */ - ret = regmap_update_bits(st->map, - KXSD9_REG_CTRL_B, - KXSD9_CTRL_B_ENABLE, - 0); + ret = regmap_clear_bits(st->map, KXSD9_REG_CTRL_B, KXSD9_CTRL_B_ENABLE); if (ret) return ret; diff --git a/drivers/iio/accel/msa311.c b/drivers/iio/accel/msa311.c index b8ddbfd98f11..4cdbf5424a53 100644 --- a/drivers/iio/accel/msa311.c +++ b/drivers/iio/accel/msa311.c @@ -1034,10 +1034,10 @@ static int msa311_chip_init(struct msa311_priv *msa311) "failed to unmap map0/map1 interrupts\n"); /* Disable all axes by default */ - err = regmap_update_bits(msa311->regs, MSA311_ODR_REG, - MSA311_GENMASK(F_X_AXIS_DIS) | - MSA311_GENMASK(F_Y_AXIS_DIS) | - MSA311_GENMASK(F_Z_AXIS_DIS), 0); + err = regmap_clear_bits(msa311->regs, MSA311_ODR_REG, + MSA311_GENMASK(F_X_AXIS_DIS) | + MSA311_GENMASK(F_Y_AXIS_DIS) | + MSA311_GENMASK(F_Z_AXIS_DIS)); if (err) return dev_err_probe(dev, err, "can't enable all axes\n"); diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h index e7525615712b..2659f536cef6 100644 --- a/drivers/iio/accel/st_accel.h +++ b/drivers/iio/accel/st_accel.h @@ -35,6 +35,7 @@ #define LIS3DHH_ACCEL_DEV_NAME "lis3dhh" #define LIS3DE_ACCEL_DEV_NAME "lis3de" #define LIS2DE12_ACCEL_DEV_NAME "lis2de12" +#define LIS2DS12_ACCEL_DEV_NAME "lis2ds12" #define LIS2HH12_ACCEL_DEV_NAME "lis2hh12" #define LIS302DL_ACCEL_DEV_NAME "lis302dl" #define LSM303C_ACCEL_DEV_NAME "lsm303c_accel" diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index d2104e14e255..0e371efbda70 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -926,6 +926,87 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .bootime = 2, }, { + .wai = 0x43, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, + .sensors_supported = { + [0] = LIS2DS12_ACCEL_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_accel_16bit_channels, + .odr = { + .addr = 0x20, + .mask = 0xf0, + .odr_avl = { + { .hz = 10, .value = 0x01, }, + { .hz = 50, .value = 0x02, }, + { .hz = 100, .value = 0x03, }, + { .hz = 200, .value = 0x04, }, + { .hz = 400, .value = 0x05, }, + { .hz = 800, .value = 0x06, }, + }, + }, + .pw = { + .addr = 0x20, + .mask = 0xf0, + .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, + }, + .enable_axis = { + .addr = ST_SENSORS_DEFAULT_AXIS_ADDR, + .mask = ST_SENSORS_DEFAULT_AXIS_MASK, + }, + .fs = { + .addr = 0x20, + .mask = 0x0c, + .fs_avl = { + [0] = { + .num = ST_ACCEL_FS_AVL_2G, + .value = 0x00, + .gain = IIO_G_TO_M_S_2(61), + }, + [1] = { + .num = ST_ACCEL_FS_AVL_4G, + .value = 0x02, + .gain = IIO_G_TO_M_S_2(122), + }, + [2] = { + .num = ST_ACCEL_FS_AVL_8G, + .value = 0x03, + .gain = IIO_G_TO_M_S_2(244), + }, + [3] = { + .num = ST_ACCEL_FS_AVL_16G, + .value = 0x01, + .gain = IIO_G_TO_M_S_2(488), + }, + }, + }, + .bdu = { + .addr = 0x20, + .mask = 0x01, + }, + .drdy_irq = { + .int1 = { + .addr = 0x23, + .mask = 0x01, + }, + .int2 = { + .addr = 0x24, + .mask = 0x01, + }, + .addr_ihl = 0x22, + .mask_ihl = 0x02, + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = 0x01, + }, + }, + .sim = { + .addr = 0x21, + .value = BIT(0), + }, + .multi_read_bit = true, + .bootime = 2, + }, + { .wai = 0x41, .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index fd3749871121..329a4d6fb2ec 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -103,6 +103,10 @@ static const struct of_device_id st_accel_of_match[] = { .data = LIS2DE12_ACCEL_DEV_NAME, }, { + .compatible = "st,lis2ds12", + .data = LIS2DS12_ACCEL_DEV_NAME, + }, + { .compatible = "st,lis2hh12", .data = LIS2HH12_ACCEL_DEV_NAME, }, @@ -154,6 +158,7 @@ static const struct i2c_device_id st_accel_id_table[] = { { LIS2DW12_ACCEL_DEV_NAME }, { LIS3DE_ACCEL_DEV_NAME }, { LIS2DE12_ACCEL_DEV_NAME }, + { LIS2DS12_ACCEL_DEV_NAME }, { LIS2HH12_ACCEL_DEV_NAME }, { LIS302DL_ACCEL_DEV_NAME }, { LSM303C_ACCEL_DEV_NAME }, diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index f72a24f45322..825adab37105 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -65,6 +65,10 @@ static const struct of_device_id st_accel_of_match[] = { .data = LIS2DH12_ACCEL_DEV_NAME, }, { + .compatible = "st,lis2ds12", + .data = LIS2DS12_ACCEL_DEV_NAME, + }, + { .compatible = "st,lis3l02dq", .data = LIS3L02DQ_ACCEL_DEV_NAME, }, @@ -151,6 +155,7 @@ static const struct spi_device_id st_accel_id_table[] = { { LSM330_ACCEL_DEV_NAME }, { LSM303AGR_ACCEL_DEV_NAME }, { LIS2DH12_ACCEL_DEV_NAME }, + { LIS2DS12_ACCEL_DEV_NAME }, { LIS3L02DQ_ACCEL_DEV_NAME }, { LNG2DM_ACCEL_DEV_NAME }, { H3LIS331DL_ACCEL_DEV_NAME }, diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 3d91015af6ea..f60fe85a30d5 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -892,6 +892,18 @@ config MCP3911 This driver can also be built as a module. If so, the module will be called mcp3911. +config MEDIATEK_MT6359_AUXADC + tristate "MediaTek MT6359 PMIC AUXADC driver" + depends on MFD_MT6397 + help + Say yes here to enable support for MediaTek MT6357, MT6358 and + MT6359 PMICs Auxiliary ADC. + This driver provides multiple channels for system monitoring, + such as battery voltage, PMIC temperature, and others. + + This driver can also be built as a module. If so, the module will be + called mt6359-auxadc. + config MEDIATEK_MT6360_ADC tristate "Mediatek MT6360 ADC driver" depends on MFD_MT6360 @@ -1351,6 +1363,18 @@ config TI_ADS1015 This driver can also be built as a module. If so, the module will be called ti-ads1015. +config TI_ADS1119 + tristate "Texas Instruments ADS1119 ADC" + depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + If you say yes here you get support for Texas Instruments ADS1119 + ADC chip. + + This driver can also be built as a module. If so, the module will be + called ti-ads1119. + config TI_ADS7924 tristate "Texas Instruments ADS7924 ADC" depends on I2C diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 37ac689a0209..d370e066544e 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -80,6 +80,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_MCP3564) += mcp3564.o obj-$(CONFIG_MCP3911) += mcp3911.o +obj-$(CONFIG_MEDIATEK_MT6359_AUXADC) += mt6359-auxadc.o obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o @@ -121,6 +122,7 @@ obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o obj-$(CONFIG_TI_ADS1100) += ti-ads1100.o +obj-$(CONFIG_TI_ADS1119) += ti-ads1119.o obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o obj-$(CONFIG_TI_ADS1298) += ti-ads1298.o obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c index aaf1fb0ac447..e134d6497827 100644 --- a/drivers/iio/adc/ad4130.c +++ b/drivers/iio/adc/ad4130.c @@ -1883,8 +1883,8 @@ static int ad4130_setup(struct iio_dev *indio_dev) if (ret) return ret; - ret = regmap_update_bits(st->regmap, AD4130_FIFO_CONTROL_REG, - AD4130_FIFO_CONTROL_HEADER_MASK, 0); + ret = regmap_clear_bits(st->regmap, AD4130_FIFO_CONTROL_REG, + AD4130_FIFO_CONTROL_HEADER_MASK); if (ret) return ret; diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index e7b1d517d3de..3beed78496c5 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -555,10 +555,18 @@ static int ad7124_disable_all(struct ad_sigma_delta *sd) return 0; } +static int ad7124_disable_one(struct ad_sigma_delta *sd, unsigned int chan) +{ + struct ad7124_state *st = container_of(sd, struct ad7124_state, sd); + + return ad7124_spi_write_mask(st, AD7124_CHANNEL(chan), AD7124_CHANNEL_EN_MSK, 0, 2); +} + static const struct ad_sigma_delta_info ad7124_sigma_delta_info = { .set_channel = ad7124_set_channel, .append_status = ad7124_append_status, .disable_all = ad7124_disable_all, + .disable_one = ad7124_disable_one, .set_mode = ad7124_set_mode, .has_registers = true, .addr_shift = 0, @@ -582,12 +590,6 @@ static int ad7124_read_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; - /* After the conversion is performed, disable the channel */ - ret = ad_sd_write_reg(&st->sd, AD7124_CHANNEL(chan->address), 2, - st->channels[chan->address].ain | AD7124_CHANNEL_EN(0)); - if (ret < 0) - return ret; - return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: mutex_lock(&st->cfgs_lock); diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index b26d4575e256..9544bf7142ad 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * AD717x family SPI ADC driver + * AD717x and AD411x family SPI ADC driver * * Supported devices: + * AD4111/AD4112/AD4114/AD4115/AD4116 * AD7172-2/AD7172-4/AD7173-8/AD7175-2 * AD7175-8/AD7176-2/AD7177-2 * @@ -60,11 +61,19 @@ #define AD7173_CH_SETUP_AINPOS_MASK GENMASK(9, 5) #define AD7173_CH_SETUP_AINNEG_MASK GENMASK(4, 0) +#define AD7173_NO_AINS_PER_CHANNEL 2 #define AD7173_CH_ADDRESS(pos, neg) \ (FIELD_PREP(AD7173_CH_SETUP_AINPOS_MASK, pos) | \ FIELD_PREP(AD7173_CH_SETUP_AINNEG_MASK, neg)) #define AD7173_AIN_TEMP_POS 17 #define AD7173_AIN_TEMP_NEG 18 +#define AD7173_AIN_POW_MON_POS 19 +#define AD7173_AIN_POW_MON_NEG 20 +#define AD7173_AIN_REF_POS 21 +#define AD7173_AIN_REF_NEG 22 + +#define AD7173_IS_REF_INPUT(x) ((x) == AD7173_AIN_REF_POS || \ + (x) == AD7173_AIN_REF_NEG) #define AD7172_2_ID 0x00d0 #define AD7175_ID 0x0cd0 @@ -72,6 +81,11 @@ #define AD7175_2_ID 0x0cd0 #define AD7172_4_ID 0x2050 #define AD7173_ID 0x30d0 +#define AD4111_ID AD7173_ID +#define AD4112_ID AD7173_ID +#define AD4114_ID AD7173_ID +#define AD4116_ID 0x34d0 +#define AD4115_ID 0x38d0 #define AD7175_8_ID 0x3cd0 #define AD7177_ID 0x4fd0 #define AD7173_ID_MASK GENMASK(15, 4) @@ -102,6 +116,7 @@ #define AD7173_GPO12_DATA(x) BIT((x) + 0) #define AD7173_GPO23_DATA(x) BIT((x) + 4) +#define AD4111_GPO01_DATA(x) BIT((x) + 6) #define AD7173_GPO_DATA(x) ((x) < 2 ? AD7173_GPO12_DATA(x) : AD7173_GPO23_DATA(x)) #define AD7173_INTERFACE_DATA_STAT BIT(6) @@ -120,34 +135,45 @@ #define AD7173_VOLTAGE_INT_REF_uV 2500000 #define AD7173_TEMP_SENSIIVITY_uV_per_C 477 #define AD7177_ODR_START_VALUE 0x07 +#define AD4111_SHUNT_RESISTOR_OHM 50 +#define AD4111_DIVIDER_RATIO 10 +#define AD4111_CURRENT_CHAN_CUTOFF 16 +#define AD4111_VINCOM_INPUT 0x10 + +/* pin < num_voltage_in is a normal voltage input */ +/* pin >= num_voltage_in_div is a voltage input without a divider */ +#define AD4111_IS_VINCOM_MISMATCH(pin1, pin2) ((pin1) == AD4111_VINCOM_INPUT && \ + (pin2) < st->info->num_voltage_in && \ + (pin2) >= st->info->num_voltage_in_div) #define AD7173_FILTER_ODR0_MASK GENMASK(5, 0) #define AD7173_MAX_CONFIGS 8 -enum ad7173_ids { - ID_AD7172_2, - ID_AD7172_4, - ID_AD7173_8, - ID_AD7175_2, - ID_AD7175_8, - ID_AD7176_2, - ID_AD7177_2, -}; - struct ad7173_device_info { const unsigned int *sinc5_data_rates; unsigned int num_sinc5_data_rates; unsigned int odr_start_value; + /* + * AD4116 has both inputs with a voltage divider and without. + * These inputs cannot be mixed in the channel configuration. + * Does not include the VINCOM input. + */ + unsigned int num_voltage_in_div; unsigned int num_channels; unsigned int num_configs; - unsigned int num_inputs; + unsigned int num_voltage_in; unsigned int clock; unsigned int id; char *name; + bool has_current_inputs; + bool has_vincom_input; bool has_temp; + /* ((AVDD1 − AVSS)/5) */ + bool has_pow_supply_monitoring; bool has_input_buf; bool has_int_ref; bool has_ref2; + bool higher_gpio_bits; u8 num_gpios; }; @@ -189,6 +215,24 @@ struct ad7173_state { #endif }; +static unsigned int ad4115_sinc5_data_rates[] = { + 24845000, 24845000, 20725000, 20725000, /* 0-3 */ + 15564000, 13841000, 10390000, 10390000, /* 4-7 */ + 4994000, 2499000, 1000000, 500000, /* 8-11 */ + 395500, 200000, 100000, 59890, /* 12-15 */ + 49920, 20000, 16660, 10000, /* 16-19 */ + 5000, 2500, 2500, /* 20-22 */ +}; + +static unsigned int ad4116_sinc5_data_rates[] = { + 12422360, 12422360, 12422360, 12422360, /* 0-3 */ + 10362690, 10362690, 7782100, 6290530, /* 4-7 */ + 5194800, 2496900, 1007600, 499900, /* 8-11 */ + 390600, 200300, 100000, 59750, /* 12-15 */ + 49840, 20000, 16650, 10000, /* 16-19 */ + 5000, 2500, 1250, /* 20-22 */ +}; + static const unsigned int ad7173_sinc5_data_rates[] = { 6211000, 6211000, 6211000, 6211000, 6211000, 6211000, 5181000, 4444000, /* 0-7 */ 3115000, 2597000, 1007000, 503800, 381000, 200300, 100500, 59520, /* 8-15 */ @@ -204,108 +248,214 @@ static const unsigned int ad7175_sinc5_data_rates[] = { 5000, /* 20 */ }; -static const struct ad7173_device_info ad7173_device_info[] = { - [ID_AD7172_2] = { - .name = "ad7172-2", - .id = AD7172_2_ID, - .num_inputs = 5, - .num_channels = 4, - .num_configs = 4, - .num_gpios = 2, - .has_temp = true, - .has_input_buf = true, - .has_int_ref = true, - .clock = 2 * HZ_PER_MHZ, - .sinc5_data_rates = ad7173_sinc5_data_rates, - .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), - }, - [ID_AD7172_4] = { - .name = "ad7172-4", - .id = AD7172_4_ID, - .num_inputs = 9, - .num_channels = 8, - .num_configs = 8, - .num_gpios = 4, - .has_temp = false, - .has_input_buf = true, - .has_ref2 = true, - .clock = 2 * HZ_PER_MHZ, - .sinc5_data_rates = ad7173_sinc5_data_rates, - .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), - }, - [ID_AD7173_8] = { - .name = "ad7173-8", - .id = AD7173_ID, - .num_inputs = 17, - .num_channels = 16, - .num_configs = 8, - .num_gpios = 4, - .has_temp = true, - .has_input_buf = true, - .has_int_ref = true, - .has_ref2 = true, - .clock = 2 * HZ_PER_MHZ, - .sinc5_data_rates = ad7173_sinc5_data_rates, - .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), - }, - [ID_AD7175_2] = { - .name = "ad7175-2", - .id = AD7175_2_ID, - .num_inputs = 5, - .num_channels = 4, - .num_configs = 4, - .num_gpios = 2, - .has_temp = true, - .has_input_buf = true, - .has_int_ref = true, - .clock = 16 * HZ_PER_MHZ, - .sinc5_data_rates = ad7175_sinc5_data_rates, - .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), - }, - [ID_AD7175_8] = { - .name = "ad7175-8", - .id = AD7175_8_ID, - .num_inputs = 17, - .num_channels = 16, - .num_configs = 8, - .num_gpios = 4, - .has_temp = true, - .has_input_buf = true, - .has_int_ref = true, - .has_ref2 = true, - .clock = 16 * HZ_PER_MHZ, - .sinc5_data_rates = ad7175_sinc5_data_rates, - .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), - }, - [ID_AD7176_2] = { - .name = "ad7176-2", - .id = AD7176_ID, - .num_inputs = 5, - .num_channels = 4, - .num_configs = 4, - .num_gpios = 2, - .has_temp = false, - .has_input_buf = false, - .has_int_ref = true, - .clock = 16 * HZ_PER_MHZ, - .sinc5_data_rates = ad7175_sinc5_data_rates, - .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), - }, - [ID_AD7177_2] = { - .name = "ad7177-2", - .id = AD7177_ID, - .num_inputs = 5, - .num_channels = 4, - .num_configs = 4, - .num_gpios = 2, - .has_temp = true, - .has_input_buf = true, - .has_int_ref = true, - .clock = 16 * HZ_PER_MHZ, - .odr_start_value = AD7177_ODR_START_VALUE, - .sinc5_data_rates = ad7175_sinc5_data_rates, - .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), - }, +static unsigned int ad4111_current_channel_config[] = { + /* Ain sel: pos neg */ + 0x1E8, /* 15:IIN0+ 8:IIN0− */ + 0x1C9, /* 14:IIN1+ 9:IIN1− */ + 0x1AA, /* 13:IIN2+ 10:IIN2− */ + 0x18B, /* 12:IIN3+ 11:IIN3− */ +}; + +static const struct ad7173_device_info ad4111_device_info = { + .name = "ad4111", + .id = AD4111_ID, + .num_voltage_in_div = 8, + .num_channels = 16, + .num_configs = 8, + .num_voltage_in = 8, + .num_gpios = 2, + .higher_gpio_bits = true, + .has_temp = true, + .has_vincom_input = true, + .has_input_buf = true, + .has_current_inputs = true, + .has_int_ref = true, + .clock = 2 * HZ_PER_MHZ, + .sinc5_data_rates = ad7173_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), +}; + +static const struct ad7173_device_info ad4112_device_info = { + .name = "ad4112", + .id = AD4112_ID, + .num_voltage_in_div = 8, + .num_channels = 16, + .num_configs = 8, + .num_voltage_in = 8, + .num_gpios = 2, + .higher_gpio_bits = true, + .has_vincom_input = true, + .has_temp = true, + .has_input_buf = true, + .has_current_inputs = true, + .has_int_ref = true, + .clock = 2 * HZ_PER_MHZ, + .sinc5_data_rates = ad7173_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), +}; + +static const struct ad7173_device_info ad4114_device_info = { + .name = "ad4114", + .id = AD4114_ID, + .num_voltage_in_div = 16, + .num_channels = 16, + .num_configs = 8, + .num_voltage_in = 16, + .num_gpios = 4, + .higher_gpio_bits = true, + .has_vincom_input = true, + .has_temp = true, + .has_input_buf = true, + .has_int_ref = true, + .clock = 2 * HZ_PER_MHZ, + .sinc5_data_rates = ad7173_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), +}; + +static const struct ad7173_device_info ad4115_device_info = { + .name = "ad4115", + .id = AD4115_ID, + .num_voltage_in_div = 16, + .num_channels = 16, + .num_configs = 8, + .num_voltage_in = 16, + .num_gpios = 4, + .higher_gpio_bits = true, + .has_vincom_input = true, + .has_temp = true, + .has_input_buf = true, + .has_int_ref = true, + .clock = 8 * HZ_PER_MHZ, + .sinc5_data_rates = ad4115_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad4115_sinc5_data_rates), +}; + +static const struct ad7173_device_info ad4116_device_info = { + .name = "ad4116", + .id = AD4116_ID, + .num_voltage_in_div = 11, + .num_channels = 16, + .num_configs = 8, + .num_voltage_in = 16, + .num_gpios = 4, + .higher_gpio_bits = true, + .has_vincom_input = true, + .has_temp = true, + .has_input_buf = true, + .has_int_ref = true, + .clock = 4 * HZ_PER_MHZ, + .sinc5_data_rates = ad4116_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad4116_sinc5_data_rates), +}; + +static const struct ad7173_device_info ad7172_2_device_info = { + .name = "ad7172-2", + .id = AD7172_2_ID, + .num_voltage_in = 5, + .num_channels = 4, + .num_configs = 4, + .num_gpios = 2, + .has_temp = true, + .has_input_buf = true, + .has_int_ref = true, + .has_pow_supply_monitoring = true, + .clock = 2 * HZ_PER_MHZ, + .sinc5_data_rates = ad7173_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), +}; + +static const struct ad7173_device_info ad7172_4_device_info = { + .name = "ad7172-4", + .id = AD7172_4_ID, + .num_voltage_in = 9, + .num_channels = 8, + .num_configs = 8, + .num_gpios = 4, + .has_input_buf = true, + .has_ref2 = true, + .has_pow_supply_monitoring = true, + .clock = 2 * HZ_PER_MHZ, + .sinc5_data_rates = ad7173_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), +}; + +static const struct ad7173_device_info ad7173_8_device_info = { + .name = "ad7173-8", + .id = AD7173_ID, + .num_voltage_in = 17, + .num_channels = 16, + .num_configs = 8, + .num_gpios = 4, + .has_temp = true, + .has_input_buf = true, + .has_int_ref = true, + .has_ref2 = true, + .clock = 2 * HZ_PER_MHZ, + .sinc5_data_rates = ad7173_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), +}; + +static const struct ad7173_device_info ad7175_2_device_info = { + .name = "ad7175-2", + .id = AD7175_2_ID, + .num_voltage_in = 5, + .num_channels = 4, + .num_configs = 4, + .num_gpios = 2, + .has_temp = true, + .has_input_buf = true, + .has_int_ref = true, + .has_pow_supply_monitoring = true, + .clock = 16 * HZ_PER_MHZ, + .sinc5_data_rates = ad7175_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), +}; + +static const struct ad7173_device_info ad7175_8_device_info = { + .name = "ad7175-8", + .id = AD7175_8_ID, + .num_voltage_in = 17, + .num_channels = 16, + .num_configs = 8, + .num_gpios = 4, + .has_temp = true, + .has_input_buf = true, + .has_int_ref = true, + .has_ref2 = true, + .has_pow_supply_monitoring = true, + .clock = 16 * HZ_PER_MHZ, + .sinc5_data_rates = ad7175_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), +}; + +static const struct ad7173_device_info ad7176_2_device_info = { + .name = "ad7176-2", + .id = AD7176_ID, + .num_voltage_in = 5, + .num_channels = 4, + .num_configs = 4, + .num_gpios = 2, + .has_int_ref = true, + .clock = 16 * HZ_PER_MHZ, + .sinc5_data_rates = ad7175_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), +}; + +static const struct ad7173_device_info ad7177_2_device_info = { + .name = "ad7177-2", + .id = AD7177_ID, + .num_voltage_in = 5, + .num_channels = 4, + .num_configs = 4, + .num_gpios = 2, + .has_temp = true, + .has_input_buf = true, + .has_int_ref = true, + .has_pow_supply_monitoring = true, + .clock = 16 * HZ_PER_MHZ, + .odr_start_value = AD7177_ODR_START_VALUE, + .sinc5_data_rates = ad7175_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), }; static const char *const ad7173_ref_sel_str[] = { @@ -347,6 +497,15 @@ static int ad7173_mask_xlate(struct gpio_regmap *gpio, unsigned int base, return 0; } +static int ad4111_mask_xlate(struct gpio_regmap *gpio, unsigned int base, + unsigned int offset, unsigned int *reg, + unsigned int *mask) +{ + *mask = AD4111_GPO01_DATA(offset); + *reg = base; + return 0; +} + static void ad7173_gpio_disable(void *data) { struct ad7173_state *st = data; @@ -379,7 +538,10 @@ static int ad7173_gpio_init(struct ad7173_state *st) gpio_regmap.regmap = st->reg_gpiocon_regmap; gpio_regmap.ngpio = st->info->num_gpios; gpio_regmap.reg_set_base = AD7173_REG_GPIO; - gpio_regmap.reg_mask_xlate = ad7173_mask_xlate; + if (st->info->higher_gpio_bits) + gpio_regmap.reg_mask_xlate = ad4111_mask_xlate; + else + gpio_regmap.reg_mask_xlate = ad7173_mask_xlate; st->gpio_regmap = devm_gpio_regmap_register(dev, &gpio_regmap); ret = PTR_ERR_OR_ZERO(st->gpio_regmap); @@ -569,10 +731,16 @@ static int ad7173_disable_all(struct ad_sigma_delta *sd) return 0; } +static int ad7173_disable_one(struct ad_sigma_delta *sd, unsigned int chan) +{ + return ad_sd_write_reg(sd, AD7173_REG_CH(chan), 2, 0); +} + static struct ad_sigma_delta_info ad7173_sigma_delta_info = { .set_channel = ad7173_set_channel, .append_status = ad7173_append_status, .disable_all = ad7173_disable_all, + .disable_one = ad7173_disable_one, .set_mode = ad7173_set_mode, .has_registers = true, .addr_shift = 0, @@ -668,25 +836,35 @@ static int ad7173_read_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; - /* disable channel after single conversion */ - ret = ad_sd_write_reg(&st->sd, AD7173_REG_CH(chan->address), 2, 0); - if (ret < 0) - return ret; - return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - if (chan->type == IIO_TEMP) { + + switch (chan->type) { + case IIO_TEMP: temp = AD7173_VOLTAGE_INT_REF_uV * MILLI; temp /= AD7173_TEMP_SENSIIVITY_uV_per_C; *val = temp; *val2 = chan->scan_type.realbits; - } else { + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_VOLTAGE: *val = ad7173_get_ref_voltage_milli(st, ch->cfg.ref_sel); *val2 = chan->scan_type.realbits - !!(ch->cfg.bipolar); + + if (chan->channel < st->info->num_voltage_in_div) + *val *= AD4111_DIVIDER_RATIO; + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CURRENT: + *val = ad7173_get_ref_voltage_milli(st, ch->cfg.ref_sel); + *val /= AD4111_SHUNT_RESISTOR_OHM; + *val2 = chan->scan_type.realbits - ch->cfg.bipolar; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; } - return IIO_VAL_FRACTIONAL_LOG2; case IIO_CHAN_INFO_OFFSET: - if (chan->type == IIO_TEMP) { + + switch (chan->type) { + case IIO_TEMP: /* 0 Kelvin -> raw sample */ temp = -ABSOLUTE_ZERO_MILLICELSIUS; temp *= AD7173_TEMP_SENSIIVITY_uV_per_C; @@ -695,10 +873,14 @@ static int ad7173_read_raw(struct iio_dev *indio_dev, AD7173_VOLTAGE_INT_REF_uV * MILLI); *val = -temp; - } else { + return IIO_VAL_INT; + case IIO_VOLTAGE: + case IIO_CURRENT: *val = -BIT(chan->scan_type.realbits - 1); + return IIO_VAL_INT; + default: + return -EINVAL; } - return IIO_VAL_INT; case IIO_CHAN_INFO_SAMP_FREQ: reg = st->channels[chan->address].cfg.odr; @@ -725,6 +907,21 @@ static int ad7173_write_raw(struct iio_dev *indio_dev, return ret; switch (info) { + /* + * This attribute sets the sampling frequency for each channel individually. + * There are no issues for raw or buffered reads of an individual channel. + * + * When multiple channels are enabled in buffered mode, the effective + * sampling rate of a channel is lowered in correlation to the number + * of channels enabled and the sampling rate of the other channels. + * + * Example: 3 channels enabled with rates CH1:6211sps CH2,CH3:10sps + * While the reading of CH1 takes only 0.16ms, the reading of CH2 and CH3 + * will take 100ms each. + * + * This will cause the reading of CH1 to be actually done once every + * 200.16ms, an effective rate of 4.99sps. + */ case IIO_CHAN_INFO_SAMP_FREQ: freq = val * MILLI + val2 / MILLI; for (i = st->info->odr_start_value; i < st->info->num_sinc5_data_rates - 1; i++) @@ -904,14 +1101,110 @@ static int ad7173_register_clk_provider(struct iio_dev *indio_dev) &st->int_clk_hw); } +static int ad4111_validate_current_ain(struct ad7173_state *st, + const unsigned int ain[AD7173_NO_AINS_PER_CHANNEL]) +{ + struct device *dev = &st->sd.spi->dev; + + if (!st->info->has_current_inputs) + return dev_err_probe(dev, -EINVAL, + "Model %s does not support current channels\n", + st->info->name); + + if (ain[0] >= ARRAY_SIZE(ad4111_current_channel_config)) + return dev_err_probe(dev, -EINVAL, + "For current channels single-channel must be <[0-3]>\n"); + + return 0; +} + +static int ad7173_validate_voltage_ain_inputs(struct ad7173_state *st, + unsigned int ain0, unsigned int ain1) +{ + struct device *dev = &st->sd.spi->dev; + bool special_input0, special_input1; + + /* (AVDD1-AVSS)/5 power supply monitoring */ + if (ain0 == AD7173_AIN_POW_MON_POS && ain1 == AD7173_AIN_POW_MON_NEG && + st->info->has_pow_supply_monitoring) + return 0; + + special_input0 = AD7173_IS_REF_INPUT(ain0) || + (ain0 == AD4111_VINCOM_INPUT && st->info->has_vincom_input); + special_input1 = AD7173_IS_REF_INPUT(ain1) || + (ain1 == AD4111_VINCOM_INPUT && st->info->has_vincom_input); + + if ((ain0 >= st->info->num_voltage_in && !special_input0) || + (ain1 >= st->info->num_voltage_in && !special_input1)) { + if (ain0 == AD4111_VINCOM_INPUT || ain1 == AD4111_VINCOM_INPUT) + return dev_err_probe(dev, -EINVAL, + "VINCOM not supported for %s\n", st->info->name); + + return dev_err_probe(dev, -EINVAL, + "Input pin number out of range for pair (%d %d).\n", + ain0, ain1); + } + + if (AD4111_IS_VINCOM_MISMATCH(ain0, ain1) || + AD4111_IS_VINCOM_MISMATCH(ain1, ain0)) + return dev_err_probe(dev, -EINVAL, + "VINCOM must be paired with inputs having divider.\n"); + + if (!special_input0 && !special_input1 && + ((ain0 >= st->info->num_voltage_in_div) != + (ain1 >= st->info->num_voltage_in_div))) + return dev_err_probe(dev, -EINVAL, + "Both inputs must either have a voltage divider or not have: (%d %d).\n", + ain0, ain1); + + return 0; +} + +static int ad7173_validate_reference(struct ad7173_state *st, int ref_sel) +{ + struct device *dev = &st->sd.spi->dev; + int ret; + + if (ref_sel == AD7173_SETUP_REF_SEL_INT_REF && !st->info->has_int_ref) + return dev_err_probe(dev, -EINVAL, + "Internal reference is not available on current model.\n"); + + if (ref_sel == AD7173_SETUP_REF_SEL_EXT_REF2 && !st->info->has_ref2) + return dev_err_probe(dev, -EINVAL, + "External reference 2 is not available on current model.\n"); + + ret = ad7173_get_ref_voltage_milli(st, ref_sel); + if (ret < 0) + return dev_err_probe(dev, ret, "Cannot use reference %u\n", + ref_sel); + + return 0; +} + static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) { struct ad7173_channel *chans_st_arr, *chan_st_priv; struct ad7173_state *st = iio_priv(indio_dev); struct device *dev = indio_dev->dev.parent; struct iio_chan_spec *chan_arr, *chan; - unsigned int ain[2], chan_index = 0; - int ref_sel, ret; + unsigned int ain[AD7173_NO_AINS_PER_CHANNEL], chan_index = 0; + int ref_sel, ret, num_channels; + + num_channels = device_get_child_node_count(dev); + + if (st->info->has_temp) + num_channels++; + + if (num_channels == 0) + return dev_err_probe(dev, -ENODATA, "No channels specified\n"); + + if (num_channels > st->info->num_channels) + return dev_err_probe(dev, -EINVAL, + "Too many channels specified. Maximum is %d, not including temperature channel if supported.\n", + st->info->num_channels); + + indio_dev->num_channels = num_channels; + st->num_channels = num_channels; chan_arr = devm_kcalloc(dev, sizeof(*indio_dev->channels), st->num_channels, GFP_KERNEL); @@ -941,18 +1234,41 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) } device_for_each_child_node_scoped(dev, child) { + bool is_current_chan = false; + chan = &chan_arr[chan_index]; + *chan = ad7173_channel_template; chan_st_priv = &chans_st_arr[chan_index]; ret = fwnode_property_read_u32_array(child, "diff-channels", ain, ARRAY_SIZE(ain)); - if (ret) - return ret; + if (ret) { + ret = fwnode_property_read_u32(child, "single-channel", + ain); + if (ret) + return dev_err_probe(dev, ret, + "Channel must define one of diff-channels or single-channel.\n"); - if (ain[0] >= st->info->num_inputs || - ain[1] >= st->info->num_inputs) - return dev_err_probe(dev, -EINVAL, - "Input pin number out of range for pair (%d %d).\n", - ain[0], ain[1]); + is_current_chan = fwnode_property_read_bool(child, "adi,current-channel"); + } else { + chan->differential = true; + } + + if (is_current_chan) { + ret = ad4111_validate_current_ain(st, ain); + if (ret) + return ret; + } else { + if (!chan->differential) { + ret = fwnode_property_read_u32(child, + "common-mode-channel", ain + 1); + if (ret) + return dev_err_probe(dev, ret, + "common-mode-channel must be defined for single-ended channels.\n"); + } + ret = ad7173_validate_voltage_ain_inputs(st, ain[0], ain[1]); + if (ret) + return ret; + } ret = fwnode_property_match_property_string(child, "adi,reference-select", @@ -963,32 +1279,17 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) else ref_sel = ret; - if (ref_sel == AD7173_SETUP_REF_SEL_INT_REF && - !st->info->has_int_ref) - return dev_err_probe(dev, -EINVAL, - "Internal reference is not available on current model.\n"); - - if (ref_sel == AD7173_SETUP_REF_SEL_EXT_REF2 && !st->info->has_ref2) - return dev_err_probe(dev, -EINVAL, - "External reference 2 is not available on current model.\n"); - - ret = ad7173_get_ref_voltage_milli(st, ref_sel); - if (ret < 0) - return dev_err_probe(dev, ret, - "Cannot use reference %u\n", ref_sel); + ret = ad7173_validate_reference(st, ref_sel); + if (ret) + return ret; if (ref_sel == AD7173_SETUP_REF_SEL_INT_REF) st->adc_mode |= AD7173_ADC_MODE_REF_EN; chan_st_priv->cfg.ref_sel = ref_sel; - *chan = ad7173_channel_template; chan->address = chan_index; chan->scan_index = chan_index; chan->channel = ain[0]; - chan->channel2 = ain[1]; - chan->differential = true; - - chan_st_priv->ain = AD7173_CH_ADDRESS(ain[0], ain[1]); chan_st_priv->chan_reg = chan_index; chan_st_priv->cfg.input_buf = st->info->has_input_buf; chan_st_priv->cfg.odr = 0; @@ -997,6 +1298,17 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) if (chan_st_priv->cfg.bipolar) chan->info_mask_separate |= BIT(IIO_CHAN_INFO_OFFSET); + if (is_current_chan) { + chan->type = IIO_CURRENT; + chan->differential = false; + chan->channel2 = 0; + chan_st_priv->ain = ad4111_current_channel_config[ain[0]]; + } else { + chan_st_priv->cfg.input_buf = st->info->has_input_buf; + chan->channel2 = ain[1]; + chan_st_priv->ain = AD7173_CH_ADDRESS(ain[0], ain[1]); + } + chan_index++; } return 0; @@ -1006,7 +1318,6 @@ static int ad7173_fw_parse_device_config(struct iio_dev *indio_dev) { struct ad7173_state *st = iio_priv(indio_dev); struct device *dev = indio_dev->dev.parent; - unsigned int num_channels; int ret; st->regulators[0].supply = ad7173_ref_sel_str[AD7173_SETUP_REF_SEL_EXT_REF]; @@ -1065,16 +1376,6 @@ static int ad7173_fw_parse_device_config(struct iio_dev *indio_dev) ad7173_sigma_delta_info.irq_line = ret; - num_channels = device_get_child_node_count(dev); - - if (st->info->has_temp) - num_channels++; - - if (num_channels == 0) - return dev_err_probe(dev, -ENODATA, "No channels specified\n"); - indio_dev->num_channels = num_channels; - st->num_channels = num_channels; - return ad7173_fw_parse_channel_config(indio_dev); } @@ -1134,32 +1435,35 @@ static int ad7173_probe(struct spi_device *spi) } static const struct of_device_id ad7173_of_match[] = { - { .compatible = "adi,ad7172-2", - .data = &ad7173_device_info[ID_AD7172_2]}, - { .compatible = "adi,ad7172-4", - .data = &ad7173_device_info[ID_AD7172_4]}, - { .compatible = "adi,ad7173-8", - .data = &ad7173_device_info[ID_AD7173_8]}, - { .compatible = "adi,ad7175-2", - .data = &ad7173_device_info[ID_AD7175_2]}, - { .compatible = "adi,ad7175-8", - .data = &ad7173_device_info[ID_AD7175_8]}, - { .compatible = "adi,ad7176-2", - .data = &ad7173_device_info[ID_AD7176_2]}, - { .compatible = "adi,ad7177-2", - .data = &ad7173_device_info[ID_AD7177_2]}, + { .compatible = "ad4111", .data = &ad4111_device_info }, + { .compatible = "ad4112", .data = &ad4112_device_info }, + { .compatible = "ad4114", .data = &ad4114_device_info }, + { .compatible = "ad4115", .data = &ad4115_device_info }, + { .compatible = "ad4116", .data = &ad4116_device_info }, + { .compatible = "adi,ad7172-2", .data = &ad7172_2_device_info }, + { .compatible = "adi,ad7172-4", .data = &ad7172_4_device_info }, + { .compatible = "adi,ad7173-8", .data = &ad7173_8_device_info }, + { .compatible = "adi,ad7175-2", .data = &ad7175_2_device_info }, + { .compatible = "adi,ad7175-8", .data = &ad7175_8_device_info }, + { .compatible = "adi,ad7176-2", .data = &ad7176_2_device_info }, + { .compatible = "adi,ad7177-2", .data = &ad7177_2_device_info }, { } }; MODULE_DEVICE_TABLE(of, ad7173_of_match); static const struct spi_device_id ad7173_id_table[] = { - { "ad7172-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7172_2]}, - { "ad7172-4", (kernel_ulong_t)&ad7173_device_info[ID_AD7172_4]}, - { "ad7173-8", (kernel_ulong_t)&ad7173_device_info[ID_AD7173_8]}, - { "ad7175-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7175_2]}, - { "ad7175-8", (kernel_ulong_t)&ad7173_device_info[ID_AD7175_8]}, - { "ad7176-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7176_2]}, - { "ad7177-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7177_2]}, + { "ad4111", (kernel_ulong_t)&ad4111_device_info }, + { "ad4112", (kernel_ulong_t)&ad4112_device_info }, + { "ad4114", (kernel_ulong_t)&ad4114_device_info }, + { "ad4115", (kernel_ulong_t)&ad4115_device_info }, + { "ad4116", (kernel_ulong_t)&ad4116_device_info }, + { "ad7172-2", (kernel_ulong_t)&ad7172_2_device_info }, + { "ad7172-4", (kernel_ulong_t)&ad7172_4_device_info }, + { "ad7173-8", (kernel_ulong_t)&ad7173_8_device_info }, + { "ad7175-2", (kernel_ulong_t)&ad7175_2_device_info }, + { "ad7175-8", (kernel_ulong_t)&ad7175_8_device_info }, + { "ad7176-2", (kernel_ulong_t)&ad7176_2_device_info }, + { "ad7177-2", (kernel_ulong_t)&ad7177_2_device_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7173_id_table); @@ -1177,5 +1481,5 @@ module_spi_driver(ad7173_driver); MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA); MODULE_AUTHOR("Lars-Peter Clausen <lars@metafo.de>"); MODULE_AUTHOR("Dumitru Ceclan <dumitru.ceclan@analog.com>"); -MODULE_DESCRIPTION("Analog Devices AD7172/AD7173/AD7175/AD7176 ADC driver"); +MODULE_DESCRIPTION("Analog Devices AD7173 and similar ADC driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index 0789121236d6..334ab90991d4 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -200,8 +200,6 @@ struct ad7192_chip_info { struct ad7192_state { const struct ad7192_chip_info *chip_info; - struct regulator *avdd; - struct regulator *vref; struct clk *mclk; u16 int_vref_mv; u32 aincom_mv; @@ -1189,24 +1187,17 @@ static const struct ad7192_chip_info ad7192_chip_info_tbl[] = { }, }; -static void ad7192_reg_disable(void *reg) -{ - regulator_disable(reg); -} - static int ad7192_probe(struct spi_device *spi) { + struct device *dev = &spi->dev; struct ad7192_state *st; struct iio_dev *indio_dev; - struct regulator *aincom; - int ret; + int ret, avdd_mv; - if (!spi->irq) { - dev_err(&spi->dev, "no IRQ?\n"); - return -ENODEV; - } + if (!spi->irq) + return dev_err_probe(dev, -ENODEV, "Failed to get IRQ\n"); - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; @@ -1219,74 +1210,49 @@ static int ad7192_probe(struct spi_device *spi) * Newer firmware should provide a zero volt fixed supply if wired to * ground. */ - aincom = devm_regulator_get_optional(&spi->dev, "aincom"); - if (IS_ERR(aincom)) { - if (PTR_ERR(aincom) != -ENODEV) - return dev_err_probe(&spi->dev, PTR_ERR(aincom), - "Failed to get AINCOM supply\n"); - - st->aincom_mv = 0; - } else { - ret = regulator_enable(aincom); - if (ret) - return dev_err_probe(&spi->dev, ret, - "Failed to enable specified AINCOM supply\n"); - - ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, aincom); - if (ret) - return ret; - - ret = regulator_get_voltage(aincom); - if (ret < 0) - return dev_err_probe(&spi->dev, ret, - "Device tree error, AINCOM voltage undefined\n"); - st->aincom_mv = ret / MILLI; - } - - st->avdd = devm_regulator_get(&spi->dev, "avdd"); - if (IS_ERR(st->avdd)) - return PTR_ERR(st->avdd); - - ret = regulator_enable(st->avdd); - if (ret) { - dev_err(&spi->dev, "Failed to enable specified AVdd supply\n"); - return ret; + ret = devm_regulator_get_enable_read_voltage(dev, "aincom"); + if (ret < 0 && ret != -ENODEV) + return dev_err_probe(dev, ret, "Failed to get AINCOM voltage\n"); + + st->aincom_mv = ret == -ENODEV ? 0 : ret / MILLI; + + /* AVDD can optionally be used as reference voltage */ + ret = devm_regulator_get_enable_read_voltage(dev, "avdd"); + if (ret == -ENODEV || ret == -EINVAL) { + int ret2; + + /* + * We get -EINVAL if avdd is a supply with unknown voltage. We + * still need to enable it since it is also a power supply. + */ + ret2 = devm_regulator_get_enable(dev, "avdd"); + if (ret2) + return dev_err_probe(dev, ret2, + "Failed to enable AVDD supply\n"); + } else if (ret < 0) { + return dev_err_probe(dev, ret, "Failed to get AVDD voltage\n"); } - ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, st->avdd); - if (ret) - return ret; + avdd_mv = ret == -ENODEV || ret == -EINVAL ? 0 : ret / MILLI; - ret = devm_regulator_get_enable(&spi->dev, "dvdd"); + ret = devm_regulator_get_enable(dev, "dvdd"); if (ret) - return dev_err_probe(&spi->dev, ret, "Failed to enable specified DVdd supply\n"); - - st->vref = devm_regulator_get_optional(&spi->dev, "vref"); - if (IS_ERR(st->vref)) { - if (PTR_ERR(st->vref) != -ENODEV) - return PTR_ERR(st->vref); - - ret = regulator_get_voltage(st->avdd); - if (ret < 0) - return dev_err_probe(&spi->dev, ret, - "Device tree error, AVdd voltage undefined\n"); - } else { - ret = regulator_enable(st->vref); - if (ret) { - dev_err(&spi->dev, "Failed to enable specified Vref supply\n"); - return ret; - } - - ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, st->vref); - if (ret) - return ret; + return dev_err_probe(dev, ret, "Failed to enable specified DVdd supply\n"); - ret = regulator_get_voltage(st->vref); - if (ret < 0) - return dev_err_probe(&spi->dev, ret, - "Device tree error, Vref voltage undefined\n"); + /* + * This is either REFIN1 or REFIN2 depending on adi,refin2-pins-enable. + * If this supply is not present, fall back to AVDD as reference. + */ + ret = devm_regulator_get_enable_read_voltage(dev, "vref"); + if (ret == -ENODEV) { + if (avdd_mv == 0) + return dev_err_probe(dev, -ENODEV, + "No reference voltage available\n"); + } else if (ret < 0) { + return ret; } - st->int_vref_mv = ret / 1000; + + st->int_vref_mv = ret == -ENODEV ? avdd_mv : ret / MILLI; st->chip_info = spi_get_device_match_data(spi); indio_dev->name = st->chip_info->name; @@ -1305,13 +1271,13 @@ static int ad7192_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev); + ret = devm_ad_sd_setup_buffer_and_trigger(dev, indio_dev); if (ret) return ret; st->fclk = AD7192_INT_FREQ_MHZ; - st->mclk = devm_clk_get_optional_enabled(&spi->dev, "mclk"); + st->mclk = devm_clk_get_optional_enabled(dev, "mclk"); if (IS_ERR(st->mclk)) return PTR_ERR(st->mclk); @@ -1320,18 +1286,16 @@ static int ad7192_probe(struct spi_device *spi) if (st->clock_sel == AD7192_CLK_EXT_MCLK1_2 || st->clock_sel == AD7192_CLK_EXT_MCLK2) { st->fclk = clk_get_rate(st->mclk); - if (!ad7192_valid_external_frequency(st->fclk)) { - dev_err(&spi->dev, - "External clock frequency out of bounds\n"); - return -EINVAL; - } + if (!ad7192_valid_external_frequency(st->fclk)) + return dev_err_probe(dev, -EINVAL, + "External clock frequency out of bounds\n"); } - ret = ad7192_setup(indio_dev, &spi->dev); + ret = ad7192_setup(indio_dev, dev); if (ret) return ret; - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct of_device_id ad7192_of_match[] = { diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c index 13ea8a1073d2..bdac020045b4 100644 --- a/drivers/iio/adc/ad7266.c +++ b/drivers/iio/adc/ad7266.c @@ -23,9 +23,10 @@ #include <linux/platform_data/ad7266.h> +#define AD7266_INTERNAL_REF_MV 2500 + struct ad7266_state { struct spi_device *spi; - struct regulator *reg; unsigned long vref_mv; struct spi_transfer single_xfer[3]; @@ -379,11 +380,6 @@ static const char * const ad7266_gpio_labels[] = { "ad0", "ad1", "ad2", }; -static void ad7266_reg_disable(void *reg) -{ - regulator_disable(reg); -} - static int ad7266_probe(struct spi_device *spi) { struct ad7266_platform_data *pdata = spi->dev.platform_data; @@ -398,28 +394,11 @@ static int ad7266_probe(struct spi_device *spi) st = iio_priv(indio_dev); - st->reg = devm_regulator_get_optional(&spi->dev, "vref"); - if (!IS_ERR(st->reg)) { - ret = regulator_enable(st->reg); - if (ret) - return ret; - - ret = devm_add_action_or_reset(&spi->dev, ad7266_reg_disable, st->reg); - if (ret) - return ret; - - ret = regulator_get_voltage(st->reg); - if (ret < 0) - return ret; + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); + if (ret < 0 && ret != -ENODEV) + return ret; - st->vref_mv = ret / 1000; - } else { - /* Any other error indicates that the regulator does exist */ - if (PTR_ERR(st->reg) != -ENODEV) - return PTR_ERR(st->reg); - /* Use internal reference */ - st->vref_mv = 2500; - } + st->vref_mv = ret == -ENODEV ? AD7266_INTERNAL_REF_MV : ret / 1000; if (pdata) { st->fixed_addr = pdata->fixed_addr; diff --git a/drivers/iio/adc/ad7292.c b/drivers/iio/adc/ad7292.c index 6aadd14f459d..ede80f380911 100644 --- a/drivers/iio/adc/ad7292.c +++ b/drivers/iio/adc/ad7292.c @@ -17,6 +17,8 @@ #define ADI_VENDOR_ID 0x0018 +#define AD7292_INTERNAL_REF_MV 1250 + /* AD7292 registers definition */ #define AD7292_REG_VENDOR_ID 0x00 #define AD7292_REG_CONF_BANK 0x05 @@ -79,7 +81,6 @@ static const struct iio_chan_spec ad7292_channels_diff[] = { struct ad7292_state { struct spi_device *spi; - struct regulator *reg; unsigned short vref_mv; __be16 d16 __aligned(IIO_DMA_MINALIGN); @@ -250,13 +251,6 @@ static const struct iio_info ad7292_info = { .read_raw = ad7292_read_raw, }; -static void ad7292_regulator_disable(void *data) -{ - struct ad7292_state *st = data; - - regulator_disable(st->reg); -} - static int ad7292_probe(struct spi_device *spi) { struct ad7292_state *st; @@ -277,29 +271,11 @@ static int ad7292_probe(struct spi_device *spi) return -EINVAL; } - st->reg = devm_regulator_get_optional(&spi->dev, "vref"); - if (!IS_ERR(st->reg)) { - ret = regulator_enable(st->reg); - if (ret) { - dev_err(&spi->dev, - "Failed to enable external vref supply\n"); - return ret; - } - - ret = devm_add_action_or_reset(&spi->dev, - ad7292_regulator_disable, st); - if (ret) - return ret; - - ret = regulator_get_voltage(st->reg); - if (ret < 0) - return ret; + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); + if (ret < 0 && ret != -ENODEV) + return ret; - st->vref_mv = ret / 1000; - } else { - /* Use the internal voltage reference. */ - st->vref_mv = 1250; - } + st->vref_mv = ret == -ENODEV ? AD7292_INTERNAL_REF_MV : ret / 1000; indio_dev->name = spi_get_device_id(spi)->name; indio_dev->modes = INDIO_DIRECT_MODE; diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c index 5f8cb9aaac70..d4ad7e0b515a 100644 --- a/drivers/iio/adc/ad7793.c +++ b/drivers/iio/adc/ad7793.c @@ -152,7 +152,6 @@ struct ad7793_chip_info { struct ad7793_state { const struct ad7793_chip_info *chip_info; - struct regulator *reg; u16 int_vref_mv; u16 mode; u16 conf; @@ -769,11 +768,6 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { }, }; -static void ad7793_reg_disable(void *reg) -{ - regulator_disable(reg); -} - static int ad7793_probe(struct spi_device *spi) { const struct ad7793_platform_data *pdata = spi->dev.platform_data; @@ -800,23 +794,11 @@ static int ad7793_probe(struct spi_device *spi) ad_sd_init(&st->sd, indio_dev, spi, &ad7793_sigma_delta_info); if (pdata->refsel != AD7793_REFSEL_INTERNAL) { - st->reg = devm_regulator_get(&spi->dev, "refin"); - if (IS_ERR(st->reg)) - return PTR_ERR(st->reg); - - ret = regulator_enable(st->reg); - if (ret) - return ret; - - ret = devm_add_action_or_reset(&spi->dev, ad7793_reg_disable, st->reg); - if (ret) + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "refin"); + if (ret < 0) return ret; - vref_mv = regulator_get_voltage(st->reg); - if (vref_mv < 0) - return vref_mv; - - vref_mv /= 1000; + vref_mv = ret / 1000; } else { vref_mv = 1170; /* Build-in ref */ } diff --git a/drivers/iio/adc/ad7944.c b/drivers/iio/adc/ad7944.c index e2cb64cef476..0f36138a7144 100644 --- a/drivers/iio/adc/ad7944.c +++ b/drivers/iio/adc/ad7944.c @@ -134,18 +134,12 @@ AD7944_DEFINE_CHIP_INFO(ad7985, ad7944, 16, 0); /* fully differential */ AD7944_DEFINE_CHIP_INFO(ad7986, ad7986, 18, 1); -static void ad7944_unoptimize_msg(void *msg) -{ - spi_unoptimize_message(msg); -} - static int ad7944_3wire_cs_mode_init_msg(struct device *dev, struct ad7944_adc *adc, const struct iio_chan_spec *chan) { unsigned int t_conv_ns = adc->always_turbo ? adc->timing_spec->turbo_conv_ns : adc->timing_spec->conv_ns; struct spi_transfer *xfers = adc->xfers; - int ret; /* * NB: can get better performance from some SPI controllers if we use @@ -175,11 +169,7 @@ static int ad7944_3wire_cs_mode_init_msg(struct device *dev, struct ad7944_adc * spi_message_init_with_transfers(&adc->msg, xfers, 3); - ret = spi_optimize_message(adc->spi, &adc->msg); - if (ret) - return ret; - - return devm_add_action_or_reset(dev, ad7944_unoptimize_msg, &adc->msg); + return devm_spi_optimize_message(dev, adc->spi, &adc->msg); } static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc, @@ -188,7 +178,6 @@ static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc unsigned int t_conv_ns = adc->always_turbo ? adc->timing_spec->turbo_conv_ns : adc->timing_spec->conv_ns; struct spi_transfer *xfers = adc->xfers; - int ret; /* * NB: can get better performance from some SPI controllers if we use @@ -209,11 +198,7 @@ static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc spi_message_init_with_transfers(&adc->msg, xfers, 2); - ret = spi_optimize_message(adc->spi, &adc->msg); - if (ret) - return ret; - - return devm_add_action_or_reset(dev, ad7944_unoptimize_msg, &adc->msg); + return devm_spi_optimize_message(dev, adc->spi, &adc->msg); } static int ad7944_chain_mode_init_msg(struct device *dev, struct ad7944_adc *adc, @@ -221,7 +206,6 @@ static int ad7944_chain_mode_init_msg(struct device *dev, struct ad7944_adc *adc u32 n_chain_dev) { struct spi_transfer *xfers = adc->xfers; - int ret; /* * NB: SCLK has to be low before we toggle CS to avoid triggering the @@ -249,11 +233,7 @@ static int ad7944_chain_mode_init_msg(struct device *dev, struct ad7944_adc *adc spi_message_init_with_transfers(&adc->msg, xfers, 2); - ret = spi_optimize_message(adc->spi, &adc->msg); - if (ret) - return ret; - - return devm_add_action_or_reset(dev, ad7944_unoptimize_msg, &adc->msg); + return devm_spi_optimize_message(dev, adc->spi, &adc->msg); } /** @@ -464,23 +444,17 @@ static const char * const ad7944_power_supplies[] = { "avdd", "dvdd", "bvdd", "vio" }; -static void ad7944_ref_disable(void *ref) -{ - regulator_disable(ref); -} - static int ad7944_probe(struct spi_device *spi) { const struct ad7944_chip_info *chip_info; struct device *dev = &spi->dev; struct iio_dev *indio_dev; struct ad7944_adc *adc; - bool have_refin = false; - struct regulator *ref; + bool have_refin; struct iio_chan_spec *chain_chan; unsigned long *chain_scan_masks; u32 n_chain_dev; - int ret; + int ret, ref_mv; indio_dev = devm_iio_device_alloc(dev, sizeof(*adc)); if (!indio_dev) @@ -531,47 +505,23 @@ static int ad7944_probe(struct spi_device *spi) * - external reference: REF is connected, REFIN is not connected */ - ref = devm_regulator_get_optional(dev, "ref"); - if (IS_ERR(ref)) { - if (PTR_ERR(ref) != -ENODEV) - return dev_err_probe(dev, PTR_ERR(ref), - "failed to get REF supply\n"); + ret = devm_regulator_get_enable_read_voltage(dev, "ref"); + if (ret < 0 && ret != -ENODEV) + return dev_err_probe(dev, ret, "failed to get REF voltage\n"); - ref = NULL; - } + ref_mv = ret == -ENODEV ? 0 : ret / 1000; ret = devm_regulator_get_enable_optional(dev, "refin"); - if (ret == 0) - have_refin = true; - else if (ret != -ENODEV) - return dev_err_probe(dev, ret, - "failed to get and enable REFIN supply\n"); + if (ret < 0 && ret != -ENODEV) + return dev_err_probe(dev, ret, "failed to get REFIN voltage\n"); + + have_refin = ret != -ENODEV; - if (have_refin && ref) + if (have_refin && ref_mv) return dev_err_probe(dev, -EINVAL, "cannot have both refin and ref supplies\n"); - if (ref) { - ret = regulator_enable(ref); - if (ret) - return dev_err_probe(dev, ret, - "failed to enable REF supply\n"); - - ret = devm_add_action_or_reset(dev, ad7944_ref_disable, ref); - if (ret) - return ret; - - ret = regulator_get_voltage(ref); - if (ret < 0) - return dev_err_probe(dev, ret, - "failed to get REF voltage\n"); - - /* external reference */ - adc->ref_mv = ret / 1000; - } else { - /* internal reference */ - adc->ref_mv = AD7944_INTERNAL_REF_MV; - } + adc->ref_mv = ref_mv ?: AD7944_INTERNAL_REF_MV; adc->cnv = devm_gpiod_get_optional(dev, "cnv", GPIOD_OUT_LOW); if (IS_ERR(adc->cnv)) diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index a2b87f6b7a07..8c062b0d26e3 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -321,6 +321,7 @@ out: sigma_delta->keep_cs_asserted = false; ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); + ad_sigma_delta_disable_one(sigma_delta, chan->address); sigma_delta->bus_locked = false; spi_bus_unlock(sigma_delta->spi->controller); iio_device_release_direct_mode(indio_dev); diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index 0f8bd1d75131..21ce7564e83d 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -308,7 +308,8 @@ static int adi_axi_adc_probe(struct platform_device *pdev) st->regmap = devm_regmap_init_mmio(&pdev->dev, base, &axi_adc_regmap_config); if (IS_ERR(st->regmap)) - return PTR_ERR(st->regmap); + return dev_err_probe(&pdev->dev, PTR_ERR(st->regmap), + "failed to init register map\n"); expected_ver = device_get_match_data(&pdev->dev); if (!expected_ver) @@ -316,7 +317,8 @@ static int adi_axi_adc_probe(struct platform_device *pdev) clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(clk)) - return PTR_ERR(clk); + return dev_err_probe(&pdev->dev, PTR_ERR(clk), + "failed to get clock\n"); /* * Force disable the core. Up to the frontend to enable us. And we can @@ -344,7 +346,8 @@ static int adi_axi_adc_probe(struct platform_device *pdev) ret = devm_iio_backend_register(&pdev->dev, &adi_axi_adc_generic, st); if (ret) - return ret; + return dev_err_probe(&pdev->dev, ret, + "failed to register iio backend\n"); dev_info(&pdev->dev, "AXI ADC IP core (%d.%.2d.%c) probed\n", ADI_AXI_PCORE_VER_MAJOR(ver), diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c index 998e8bcc06e1..090416c0d622 100644 --- a/drivers/iio/adc/aspeed_adc.c +++ b/drivers/iio/adc/aspeed_adc.c @@ -108,7 +108,6 @@ struct adc_gain { struct aspeed_adc_data { struct device *dev; const struct aspeed_adc_model_data *model_data; - struct regulator *regulator; void __iomem *base; spinlock_t clk_lock; struct clk_hw *fixed_div_clk; @@ -404,13 +403,6 @@ static void aspeed_adc_power_down(void *data) priv_data->base + ASPEED_REG_ENGINE_CONTROL); } -static void aspeed_adc_reg_disable(void *data) -{ - struct regulator *reg = data; - - regulator_disable(reg); -} - static int aspeed_adc_vref_config(struct iio_dev *indio_dev) { struct aspeed_adc_data *data = iio_priv(indio_dev); @@ -423,18 +415,14 @@ static int aspeed_adc_vref_config(struct iio_dev *indio_dev) } adc_engine_control_reg_val = readl(data->base + ASPEED_REG_ENGINE_CONTROL); - data->regulator = devm_regulator_get_optional(data->dev, "vref"); - if (!IS_ERR(data->regulator)) { - ret = regulator_enable(data->regulator); - if (ret) - return ret; - ret = devm_add_action_or_reset( - data->dev, aspeed_adc_reg_disable, data->regulator); - if (ret) - return ret; - data->vref_mv = regulator_get_voltage(data->regulator); - /* Conversion from uV to mV */ - data->vref_mv /= 1000; + + ret = devm_regulator_get_enable_read_voltage(data->dev, "vref"); + if (ret < 0 && ret != -ENODEV) + return ret; + + if (ret != -ENODEV) { + data->vref_mv = ret / 1000; + if ((data->vref_mv >= 1550) && (data->vref_mv <= 2700)) writel(adc_engine_control_reg_val | FIELD_PREP( @@ -453,8 +441,6 @@ static int aspeed_adc_vref_config(struct iio_dev *indio_dev) return -EOPNOTSUPP; } } else { - if (PTR_ERR(data->regulator) != -ENODEV) - return PTR_ERR(data->regulator); data->vref_mv = 2500000; of_property_read_u32(data->dev->of_node, "aspeed,int-vref-microvolt", diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c index 913ea9e5d9c5..b487e577befb 100644 --- a/drivers/iio/adc/axp20x_adc.c +++ b/drivers/iio/adc/axp20x_adc.c @@ -991,9 +991,8 @@ static int axp20x_probe(struct platform_device *pdev) regmap_write(info->regmap, AXP20X_ADC_EN1, info->data->adc_en1_mask); if (info->data->adc_en2_mask) - regmap_update_bits(info->regmap, AXP20X_ADC_EN2, - info->data->adc_en2_mask, - info->data->adc_en2_mask); + regmap_set_bits(info->regmap, AXP20X_ADC_EN2, + info->data->adc_en2_mask); /* Configure ADCs rate */ info->data->adc_rate(info, 100); diff --git a/drivers/iio/adc/axp288_adc.c b/drivers/iio/adc/axp288_adc.c index 49fff1cabd0d..f135cf2362df 100644 --- a/drivers/iio/adc/axp288_adc.c +++ b/drivers/iio/adc/axp288_adc.c @@ -247,8 +247,8 @@ static int axp288_adc_initialize(struct axp288_adc_info *info) return ret; /* Turn on the ADC for all channels except TS, leave TS as is */ - return regmap_update_bits(info->regmap, AXP20X_ADC_EN1, - AXP288_ADC_EN_MASK, AXP288_ADC_EN_MASK); + return regmap_set_bits(info->regmap, AXP20X_ADC_EN1, + AXP288_ADC_EN_MASK); } static const struct iio_info axp288_adc_iio_info = { diff --git a/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c index 5bc514bd5ebc..6bc149c51414 100644 --- a/drivers/iio/adc/bcm_iproc_adc.c +++ b/drivers/iio/adc/bcm_iproc_adc.c @@ -357,8 +357,8 @@ static int iproc_adc_enable(struct iio_dev *indio_dev) int ret; /* Set i_amux = 3b'000, select channel 0 */ - ret = regmap_update_bits(adc_priv->regmap, IPROC_ANALOG_CONTROL, - IPROC_ADC_CHANNEL_SEL_MASK, 0); + ret = regmap_clear_bits(adc_priv->regmap, IPROC_ANALOG_CONTROL, + IPROC_ADC_CHANNEL_SEL_MASK); if (ret) { dev_err(&indio_dev->dev, "failed to write IPROC_ANALOG_CONTROL %d\n", ret); @@ -543,8 +543,8 @@ static int iproc_adc_probe(struct platform_device *pdev) if (adc_priv->irqno < 0) return adc_priv->irqno; - ret = regmap_update_bits(adc_priv->regmap, IPROC_REGCTL2, - IPROC_ADC_AUXIN_SCAN_ENA, 0); + ret = regmap_clear_bits(adc_priv->regmap, IPROC_REGCTL2, + IPROC_ADC_AUXIN_SCAN_ENA); if (ret) { dev_err(&pdev->dev, "failed to write IPROC_REGCTL2 %d\n", ret); return ret; diff --git a/drivers/iio/adc/berlin2-adc.c b/drivers/iio/adc/berlin2-adc.c index a4e7c7eff5ac..4cdddc6e36e9 100644 --- a/drivers/iio/adc/berlin2-adc.c +++ b/drivers/iio/adc/berlin2-adc.c @@ -129,8 +129,8 @@ static int berlin2_adc_read(struct iio_dev *indio_dev, int channel) msecs_to_jiffies(1000)); /* Disable the interrupts */ - regmap_update_bits(priv->regmap, BERLIN2_SM_ADC_STATUS, - BERLIN2_SM_ADC_STATUS_INT_EN(channel), 0); + regmap_clear_bits(priv->regmap, BERLIN2_SM_ADC_STATUS, + BERLIN2_SM_ADC_STATUS_INT_EN(channel)); if (ret == 0) ret = -ETIMEDOUT; @@ -139,8 +139,8 @@ static int berlin2_adc_read(struct iio_dev *indio_dev, int channel) return ret; } - regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL, - BERLIN2_SM_CTRL_ADC_START, 0); + regmap_clear_bits(priv->regmap, BERLIN2_SM_CTRL, + BERLIN2_SM_CTRL_ADC_START); data = priv->data; priv->data_available = false; @@ -180,8 +180,8 @@ static int berlin2_adc_tsen_read(struct iio_dev *indio_dev) msecs_to_jiffies(1000)); /* Disable interrupts */ - regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_STATUS, - BERLIN2_SM_TSEN_STATUS_INT_EN, 0); + regmap_clear_bits(priv->regmap, BERLIN2_SM_TSEN_STATUS, + BERLIN2_SM_TSEN_STATUS_INT_EN); if (ret == 0) ret = -ETIMEDOUT; @@ -190,8 +190,8 @@ static int berlin2_adc_tsen_read(struct iio_dev *indio_dev) return ret; } - regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL, - BERLIN2_SM_TSEN_CTRL_START, 0); + regmap_clear_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL, + BERLIN2_SM_TSEN_CTRL_START); data = priv->data; priv->data_available = false; @@ -284,8 +284,7 @@ static const struct iio_info berlin2_adc_info = { static void berlin2_adc_powerdown(void *regmap) { - regmap_update_bits(regmap, BERLIN2_SM_CTRL, - BERLIN2_SM_CTRL_ADC_POWER, 0); + regmap_clear_bits(regmap, BERLIN2_SM_CTRL, BERLIN2_SM_CTRL_ADC_POWER); } @@ -339,9 +338,8 @@ static int berlin2_adc_probe(struct platform_device *pdev) indio_dev->num_channels = ARRAY_SIZE(berlin2_adc_channels); /* Power up the ADC */ - regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL, - BERLIN2_SM_CTRL_ADC_POWER, - BERLIN2_SM_CTRL_ADC_POWER); + regmap_set_bits(priv->regmap, BERLIN2_SM_CTRL, + BERLIN2_SM_CTRL_ADC_POWER); ret = devm_add_action_or_reset(&pdev->dev, berlin2_adc_powerdown, priv->regmap); diff --git a/drivers/iio/adc/cpcap-adc.c b/drivers/iio/adc/cpcap-adc.c index b6c4ef70484e..c218acf6c9c6 100644 --- a/drivers/iio/adc/cpcap-adc.c +++ b/drivers/iio/adc/cpcap-adc.c @@ -385,9 +385,8 @@ static irqreturn_t cpcap_adc_irq_thread(int irq, void *data) struct cpcap_adc *ddata = iio_priv(indio_dev); int error; - error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2, - CPCAP_BIT_ADTRIG_DIS, - CPCAP_BIT_ADTRIG_DIS); + error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2, + CPCAP_BIT_ADTRIG_DIS); if (error) return IRQ_NONE; @@ -424,23 +423,19 @@ static void cpcap_adc_setup_calibrate(struct cpcap_adc *ddata, if (error) return; - error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2, - CPCAP_BIT_ATOX_PS_FACTOR | - CPCAP_BIT_ADC_PS_FACTOR1 | - CPCAP_BIT_ADC_PS_FACTOR0, - 0); + error = regmap_clear_bits(ddata->reg, CPCAP_REG_ADCC2, + CPCAP_BIT_ATOX_PS_FACTOR | + CPCAP_BIT_ADC_PS_FACTOR1 | + CPCAP_BIT_ADC_PS_FACTOR0); if (error) return; - error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2, - CPCAP_BIT_ADTRIG_DIS, - CPCAP_BIT_ADTRIG_DIS); + error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2, + CPCAP_BIT_ADTRIG_DIS); if (error) return; - error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2, - CPCAP_BIT_ASC, - CPCAP_BIT_ASC); + error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2, CPCAP_BIT_ASC); if (error) return; @@ -455,8 +450,8 @@ static void cpcap_adc_setup_calibrate(struct cpcap_adc *ddata, dev_err(ddata->dev, "Timeout waiting for calibration to complete\n"); - error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC1, - CPCAP_BIT_CAL_MODE, 0); + error = regmap_clear_bits(ddata->reg, CPCAP_REG_ADCC1, + CPCAP_BIT_CAL_MODE); if (error) return; } @@ -602,26 +597,23 @@ static void cpcap_adc_setup_bank(struct cpcap_adc *ddata, return; if (req->timing == CPCAP_ADC_TIMING_IMM) { - error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2, - CPCAP_BIT_ADTRIG_DIS, - CPCAP_BIT_ADTRIG_DIS); + error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2, + CPCAP_BIT_ADTRIG_DIS); if (error) return; - error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2, - CPCAP_BIT_ASC, - CPCAP_BIT_ASC); + error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2, + CPCAP_BIT_ASC); if (error) return; } else { - error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2, - CPCAP_BIT_ADTRIG_ONESHOT, - CPCAP_BIT_ADTRIG_ONESHOT); + error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2, + CPCAP_BIT_ADTRIG_ONESHOT); if (error) return; - error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2, - CPCAP_BIT_ADTRIG_DIS, 0); + error = regmap_clear_bits(ddata->reg, CPCAP_REG_ADCC2, + CPCAP_BIT_ADTRIG_DIS); if (error) return; } diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c index b680690631db..b3f037510e35 100644 --- a/drivers/iio/adc/fsl-imx25-gcq.c +++ b/drivers/iio/adc/fsl-imx25-gcq.c @@ -87,13 +87,13 @@ static irqreturn_t mx25_gcq_irq(int irq, void *data) regmap_read(priv->regs, MX25_ADCQ_SR, &stats); if (stats & MX25_ADCQ_SR_EOQ) { - regmap_update_bits(priv->regs, MX25_ADCQ_MR, - MX25_ADCQ_MR_EOQ_IRQ, MX25_ADCQ_MR_EOQ_IRQ); + regmap_set_bits(priv->regs, MX25_ADCQ_MR, + MX25_ADCQ_MR_EOQ_IRQ); complete(&priv->completed); } /* Disable conversion queue run */ - regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS, 0); + regmap_clear_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS); /* Acknowledge all possible irqs */ regmap_write(priv->regs, MX25_ADCQ_SR, MX25_ADCQ_SR_FRR | @@ -115,11 +115,10 @@ static int mx25_gcq_get_raw_value(struct device *dev, regmap_write(priv->regs, MX25_ADCQ_ITEM_7_0, MX25_ADCQ_ITEM(0, chan->channel)); - regmap_update_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_EOQ_IRQ, 0); + regmap_clear_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_EOQ_IRQ); /* Trigger queue for one run */ - regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS, - MX25_ADCQ_CR_FQS); + regmap_set_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS); time_left = wait_for_completion_interruptible_timeout( &priv->completed, MX25_GCQ_TIMEOUT); @@ -272,9 +271,8 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev, MX25_ADCQ_CFG_REFN_MASK, refp | refn); } - regmap_update_bits(priv->regs, MX25_ADCQ_CR, - MX25_ADCQ_CR_FRST | MX25_ADCQ_CR_QRST, - MX25_ADCQ_CR_FRST | MX25_ADCQ_CR_QRST); + regmap_set_bits(priv->regs, MX25_ADCQ_CR, + MX25_ADCQ_CR_FRST | MX25_ADCQ_CR_QRST); regmap_write(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_PDMSK | MX25_ADCQ_CR_QSM_FQS); diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c index fef97c1d226a..b3372ccff7d5 100644 --- a/drivers/iio/adc/hx711.c +++ b/drivers/iio/adc/hx711.c @@ -80,7 +80,6 @@ struct hx711_data { struct device *dev; struct gpio_desc *gpiod_pd_sck; struct gpio_desc *gpiod_dout; - struct regulator *reg_avdd; int gain_set; /* gain set on device */ int gain_chan_a; /* gain for channel A */ struct mutex lock; @@ -465,10 +464,8 @@ static int hx711_probe(struct platform_device *pdev) int i; indio_dev = devm_iio_device_alloc(dev, sizeof(struct hx711_data)); - if (!indio_dev) { - dev_err(dev, "failed to allocate IIO device\n"); - return -ENOMEM; - } + if (!indio_dev) + return dev_err_probe(dev, -ENOMEM, "failed to allocate IIO device\n"); hx711_data = iio_priv(indio_dev); hx711_data->dev = dev; @@ -480,28 +477,20 @@ static int hx711_probe(struct platform_device *pdev) * in the driver it is an output */ hx711_data->gpiod_pd_sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW); - if (IS_ERR(hx711_data->gpiod_pd_sck)) { - dev_err(dev, "failed to get sck-gpiod: err=%ld\n", - PTR_ERR(hx711_data->gpiod_pd_sck)); - return PTR_ERR(hx711_data->gpiod_pd_sck); - } + if (IS_ERR(hx711_data->gpiod_pd_sck)) + return dev_err_probe(dev, PTR_ERR(hx711_data->gpiod_pd_sck), + "failed to get sck-gpiod\n"); /* * DOUT stands for serial data output of HX711 * for the driver it is an input */ hx711_data->gpiod_dout = devm_gpiod_get(dev, "dout", GPIOD_IN); - if (IS_ERR(hx711_data->gpiod_dout)) { - dev_err(dev, "failed to get dout-gpiod: err=%ld\n", - PTR_ERR(hx711_data->gpiod_dout)); - return PTR_ERR(hx711_data->gpiod_dout); - } + if (IS_ERR(hx711_data->gpiod_dout)) + return dev_err_probe(dev, PTR_ERR(hx711_data->gpiod_dout), + "failed to get dout-gpiod\n"); - hx711_data->reg_avdd = devm_regulator_get(dev, "avdd"); - if (IS_ERR(hx711_data->reg_avdd)) - return PTR_ERR(hx711_data->reg_avdd); - - ret = regulator_enable(hx711_data->reg_avdd); + ret = devm_regulator_get_enable_read_voltage(dev, "avdd"); if (ret < 0) return ret; @@ -517,9 +506,6 @@ static int hx711_probe(struct platform_device *pdev) * approximately to fit into a 32 bit number: * 1 LSB = (AVDD * 100) / GAIN / 1678 [10^-9 mV] */ - ret = regulator_get_voltage(hx711_data->reg_avdd); - if (ret < 0) - goto error_regulator; /* we need 10^-9 mV */ ret *= 100; @@ -547,51 +533,24 @@ static int hx711_probe(struct platform_device *pdev) hx711_data->data_ready_delay_ns = 1000000000 / hx711_data->clock_frequency; - platform_set_drvdata(pdev, indio_dev); - indio_dev->name = "hx711"; indio_dev->info = &hx711_iio_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = hx711_chan_spec; indio_dev->num_channels = ARRAY_SIZE(hx711_chan_spec); - ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time, - hx711_trigger, NULL); - if (ret < 0) { - dev_err(dev, "setup of iio triggered buffer failed\n"); - goto error_regulator; - } + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + hx711_trigger, NULL); + if (ret < 0) + return dev_err_probe(dev, ret, + "setup of iio triggered buffer failed\n"); - ret = iio_device_register(indio_dev); - if (ret < 0) { - dev_err(dev, "Couldn't register the device\n"); - goto error_buffer; - } + ret = devm_iio_device_register(dev, indio_dev); + if (ret < 0) + return dev_err_probe(dev, ret, "Couldn't register the device\n"); return 0; - -error_buffer: - iio_triggered_buffer_cleanup(indio_dev); - -error_regulator: - regulator_disable(hx711_data->reg_avdd); - - return ret; -} - -static void hx711_remove(struct platform_device *pdev) -{ - struct hx711_data *hx711_data; - struct iio_dev *indio_dev; - - indio_dev = platform_get_drvdata(pdev); - hx711_data = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - - iio_triggered_buffer_cleanup(indio_dev); - - regulator_disable(hx711_data->reg_avdd); } static const struct of_device_id of_hx711_match[] = { @@ -603,7 +562,6 @@ MODULE_DEVICE_TABLE(of, of_hx711_match); static struct platform_driver hx711_driver = { .probe = hx711_probe, - .remove_new = hx711_remove, .driver = { .name = "hx711-gpio", .of_match_table = of_hx711_match, diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 9e52207352fb..727e390bd979 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -1046,8 +1046,7 @@ static void ina2xx_remove(struct i2c_client *client) iio_device_unregister(indio_dev); /* Powerdown */ - ret = regmap_update_bits(chip->regmap, INA2XX_CONFIG, - INA2XX_MODE_MASK, 0); + ret = regmap_clear_bits(chip->regmap, INA2XX_CONFIG, INA2XX_MODE_MASK); if (ret) dev_warn(&client->dev, "Failed to power down device (%pe)\n", ERR_PTR(ret)); diff --git a/drivers/iio/adc/intel_mrfld_adc.c b/drivers/iio/adc/intel_mrfld_adc.c index c7f40ae6e608..0590a126f321 100644 --- a/drivers/iio/adc/intel_mrfld_adc.c +++ b/drivers/iio/adc/intel_mrfld_adc.c @@ -81,8 +81,8 @@ static int mrfld_adc_single_conv(struct iio_dev *indio_dev, reinit_completion(&adc->completion); - regmap_update_bits(regmap, BCOVE_MADCIRQ, BCOVE_ADCIRQ_ALL, 0); - regmap_update_bits(regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_ADC, 0); + regmap_clear_bits(regmap, BCOVE_MADCIRQ, BCOVE_ADCIRQ_ALL); + regmap_clear_bits(regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_ADC); ret = regmap_read_poll_timeout(regmap, BCOVE_GPADCREQ, req, !(req & BCOVE_GPADCREQ_BUSY), diff --git a/drivers/iio/adc/ltc2309.c b/drivers/iio/adc/ltc2309.c index 8b3a89c1b840..5f0d947d0615 100644 --- a/drivers/iio/adc/ltc2309.c +++ b/drivers/iio/adc/ltc2309.c @@ -16,6 +16,7 @@ #include <linux/regulator/consumer.h> #define LTC2309_ADC_RESOLUTION 12 +#define LTC2309_INTERNAL_REF_MV 4096 #define LTC2309_DIN_CH_MASK GENMASK(7, 4) #define LTC2309_DIN_SDN BIT(7) @@ -29,14 +30,12 @@ * struct ltc2309 - internal device data structure * @dev: Device reference * @client: I2C reference - * @vref: External reference source * @lock: Lock to serialize data access * @vref_mv: Internal voltage reference */ struct ltc2309 { struct device *dev; struct i2c_client *client; - struct regulator *vref; struct mutex lock; /* serialize data access */ int vref_mv; }; @@ -104,7 +103,7 @@ static int ltc2309_read_raw_channel(struct ltc2309 *ltc2309, unsigned long address, int *val) { int ret; - u16 buf; + __be16 buf; u8 din; din = FIELD_PREP(LTC2309_DIN_CH_MASK, address & 0x0f) | @@ -157,11 +156,6 @@ static const struct iio_info ltc2309_info = { .read_raw = ltc2309_read_raw, }; -static void ltc2309_regulator_disable(void *regulator) -{ - regulator_disable(regulator); -} - static int ltc2309_probe(struct i2c_client *client) { struct iio_dev *indio_dev; @@ -175,7 +169,6 @@ static int ltc2309_probe(struct i2c_client *client) ltc2309 = iio_priv(indio_dev); ltc2309->dev = &indio_dev->dev; ltc2309->client = client; - ltc2309->vref_mv = 4096; /* Default to the internal ref */ indio_dev->name = "ltc2309"; indio_dev->modes = INDIO_DIRECT_MODE; @@ -183,36 +176,12 @@ static int ltc2309_probe(struct i2c_client *client) indio_dev->num_channels = ARRAY_SIZE(ltc2309_channels); indio_dev->info = <c2309_info; - ltc2309->vref = devm_regulator_get_optional(&client->dev, "vref"); - if (IS_ERR(ltc2309->vref)) { - ret = PTR_ERR(ltc2309->vref); - if (ret == -ENODEV) - ltc2309->vref = NULL; - else - return ret; - } + ret = devm_regulator_get_enable_read_voltage(&client->dev, "vref"); + if (ret < 0 && ret != -ENODEV) + return dev_err_probe(ltc2309->dev, ret, + "failed to get vref voltage\n"); - if (ltc2309->vref) { - ret = regulator_enable(ltc2309->vref); - if (ret) - return dev_err_probe(ltc2309->dev, ret, - "failed to enable vref\n"); - - ret = devm_add_action_or_reset(ltc2309->dev, - ltc2309_regulator_disable, - ltc2309->vref); - if (ret) { - return dev_err_probe(ltc2309->dev, ret, - "failed to add regulator_disable action: %d\n", - ret); - } - - ret = regulator_get_voltage(ltc2309->vref); - if (ret < 0) - return ret; - - ltc2309->vref_mv = ret / 1000; - } + ltc2309->vref_mv = ret == -ENODEV ? LTC2309_INTERNAL_REF_MV : ret / 1000; mutex_init(<c2309->lock); diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 8b5bc96cb9fb..bf4b6dc53fd2 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -1561,18 +1561,12 @@ static const struct of_device_id max1363_of_match[] = { }; MODULE_DEVICE_TABLE(of, max1363_of_match); -static void max1363_reg_disable(void *reg) -{ - regulator_disable(reg); -} - static int max1363_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); int ret; struct max1363_state *st; struct iio_dev *indio_dev; - struct regulator *vref; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(struct max1363_state)); @@ -1589,26 +1583,12 @@ static int max1363_probe(struct i2c_client *client) st->chip_info = i2c_get_match_data(client); st->client = client; - st->vref_uv = st->chip_info->int_vref_mv * 1000; - vref = devm_regulator_get_optional(&client->dev, "vref"); - if (!IS_ERR(vref)) { - int vref_uv; - - ret = regulator_enable(vref); - if (ret) - return ret; - - ret = devm_add_action_or_reset(&client->dev, max1363_reg_disable, vref); - if (ret) - return ret; + ret = devm_regulator_get_enable_read_voltage(&client->dev, "vref"); + if (ret < 0 && ret != -ENODEV) + return ret; - st->vref = vref; - vref_uv = regulator_get_voltage(vref); - if (vref_uv <= 0) - return -EINVAL; - st->vref_uv = vref_uv; - } + st->vref_uv = ret == -ENODEV ? st->chip_info->int_vref_mv * 1000 : ret; if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { st->send = i2c_master_send; diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 13b473d8c6c7..e16b0e28974e 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -546,35 +546,31 @@ static void meson_sar_adc_start_sample_engine(struct iio_dev *indio_dev) reinit_completion(&priv->done); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, - MESON_SAR_ADC_REG0_FIFO_IRQ_EN, - MESON_SAR_ADC_REG0_FIFO_IRQ_EN); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_FIFO_IRQ_EN); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, - MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, - MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, - MESON_SAR_ADC_REG0_SAMPLING_START, - MESON_SAR_ADC_REG0_SAMPLING_START); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_SAMPLING_START); } static void meson_sar_adc_stop_sample_engine(struct iio_dev *indio_dev) { struct meson_sar_adc_priv *priv = iio_priv(indio_dev); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, - MESON_SAR_ADC_REG0_FIFO_IRQ_EN, 0); + regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_FIFO_IRQ_EN); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, - MESON_SAR_ADC_REG0_SAMPLING_STOP, - MESON_SAR_ADC_REG0_SAMPLING_STOP); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_SAMPLING_STOP); /* wait until all modules are stopped */ meson_sar_adc_wait_busy_clear(indio_dev); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, - MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, 0); + regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE); } static int meson_sar_adc_lock(struct iio_dev *indio_dev) @@ -586,9 +582,8 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev) if (priv->param->has_bl30_integration) { /* prevent BL30 from using the SAR ADC while we are using it */ - regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, - MESON_SAR_ADC_DELAY_KERNEL_BUSY, - MESON_SAR_ADC_DELAY_KERNEL_BUSY); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_KERNEL_BUSY); udelay(1); @@ -614,8 +609,8 @@ static void meson_sar_adc_unlock(struct iio_dev *indio_dev) if (priv->param->has_bl30_integration) /* allow BL30 to use the SAR ADC again */ - regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, - MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0); + regmap_clear_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_KERNEL_BUSY); mutex_unlock(&priv->lock); } @@ -869,17 +864,16 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) * disable this bit as seems to be only relevant for Meson6 (based * on the vendor driver), which we don't support at the moment. */ - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, - MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL, 0); + regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL); /* disable all channels by default */ regmap_write(priv->regmap, MESON_SAR_ADC_CHAN_LIST, 0x0); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, - MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE, 0); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, - MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY, - MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY); + regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY); /* delay between two samples = (10+1) * 1uS */ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, @@ -914,21 +908,17 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) MESON_SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK, regval); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, - MESON_SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW, - MESON_SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, + MESON_SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, - MESON_SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW, - MESON_SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, + MESON_SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, - MESON_SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW, - MESON_SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, + MESON_SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, - MESON_SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW, - MESON_SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, + MESON_SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW); /* * set up the input channel muxes in MESON_SAR_ADC_AUX_SW @@ -944,12 +934,10 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) regmap_write(priv->regmap, MESON_SAR_ADC_AUX_SW, regval); if (priv->temperature_sensor_calibrated) { - regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, - MESON_SAR_ADC_DELTA_10_TS_REVE1, - MESON_SAR_ADC_DELTA_10_TS_REVE1); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, - MESON_SAR_ADC_DELTA_10_TS_REVE0, - MESON_SAR_ADC_DELTA_10_TS_REVE0); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, + MESON_SAR_ADC_DELTA_10_TS_REVE1); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, + MESON_SAR_ADC_DELTA_10_TS_REVE0); /* * set bits [3:0] of the TSC (temperature sensor coefficient) @@ -976,10 +964,10 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) regval); } } else { - regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, - MESON_SAR_ADC_DELTA_10_TS_REVE1, 0); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, - MESON_SAR_ADC_DELTA_10_TS_REVE0, 0); + regmap_clear_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, + MESON_SAR_ADC_DELTA_10_TS_REVE1); + regmap_clear_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, + MESON_SAR_ADC_DELTA_10_TS_REVE0); } regval = FIELD_PREP(MESON_SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN, @@ -1062,9 +1050,8 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev) meson_sar_adc_set_bandgap(indio_dev, true); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, - MESON_SAR_ADC_REG3_ADC_EN, - MESON_SAR_ADC_REG3_ADC_EN); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_ADC_EN); udelay(5); @@ -1079,8 +1066,8 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev) return 0; err_adc_clk: - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, - MESON_SAR_ADC_REG3_ADC_EN, 0); + regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_ADC_EN); meson_sar_adc_set_bandgap(indio_dev, false); regulator_disable(priv->vref); err_vref: @@ -1104,8 +1091,8 @@ static void meson_sar_adc_hw_disable(struct iio_dev *indio_dev) clk_disable_unprepare(priv->adc_clk); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, - MESON_SAR_ADC_REG3_ADC_EN, 0); + regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_ADC_EN); meson_sar_adc_set_bandgap(indio_dev, false); diff --git a/drivers/iio/adc/mp2629_adc.c b/drivers/iio/adc/mp2629_adc.c index 7c66c2cd5be2..5f672765d4a2 100644 --- a/drivers/iio/adc/mp2629_adc.c +++ b/drivers/iio/adc/mp2629_adc.c @@ -131,9 +131,8 @@ static int mp2629_adc_probe(struct platform_device *pdev) info->dev = dev; platform_set_drvdata(pdev, indio_dev); - ret = regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL, - MP2629_ADC_START | MP2629_ADC_CONTINUOUS, - MP2629_ADC_START | MP2629_ADC_CONTINUOUS); + ret = regmap_set_bits(info->regmap, MP2629_REG_ADC_CTRL, + MP2629_ADC_START | MP2629_ADC_CONTINUOUS); if (ret) { dev_err(dev, "adc enable fail: %d\n", ret); return ret; @@ -163,10 +162,9 @@ fail_map_unregister: iio_map_array_unregister(indio_dev); fail_disable: - regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL, - MP2629_ADC_CONTINUOUS, 0); - regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL, - MP2629_ADC_START, 0); + regmap_clear_bits(info->regmap, MP2629_REG_ADC_CTRL, + MP2629_ADC_CONTINUOUS); + regmap_clear_bits(info->regmap, MP2629_REG_ADC_CTRL, MP2629_ADC_START); return ret; } @@ -180,10 +178,9 @@ static void mp2629_adc_remove(struct platform_device *pdev) iio_map_array_unregister(indio_dev); - regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL, - MP2629_ADC_CONTINUOUS, 0); - regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL, - MP2629_ADC_START, 0); + regmap_clear_bits(info->regmap, MP2629_REG_ADC_CTRL, + MP2629_ADC_CONTINUOUS); + regmap_clear_bits(info->regmap, MP2629_REG_ADC_CTRL, MP2629_ADC_START); } static const struct of_device_id mp2629_adc_of_match[] = { diff --git a/drivers/iio/adc/mt6359-auxadc.c b/drivers/iio/adc/mt6359-auxadc.c new file mode 100644 index 000000000000..a4970cfb49a5 --- /dev/null +++ b/drivers/iio/adc/mt6359-auxadc.c @@ -0,0 +1,606 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * MediaTek MT6359 PMIC AUXADC IIO driver + * + * Copyright (c) 2021 MediaTek Inc. + * Copyright (c) 2024 Collabora Ltd + * Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> + */ + +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/types.h> + +#include <linux/iio/iio.h> + +#include <linux/mfd/mt6397/core.h> + +#include <dt-bindings/iio/adc/mediatek,mt6357-auxadc.h> +#include <dt-bindings/iio/adc/mediatek,mt6358-auxadc.h> +#include <dt-bindings/iio/adc/mediatek,mt6359-auxadc.h> + +#define AUXADC_AVG_TIME_US 10 +#define AUXADC_POLL_DELAY_US 100 +#define AUXADC_TIMEOUT_US 32000 +#define AUXADC_VOLT_FULL 1800 +#define IMP_STOP_DELAY_US 150 +#define IMP_POLL_DELAY_US 1000 + +/* For PMIC_RG_RESET_VAL and MT6358_IMP0_CLEAR, the bits specific purpose is unknown. */ +#define PMIC_RG_RESET_VAL (BIT(0) | BIT(3)) +#define PMIC_AUXADC_RDY_BIT BIT(15) +#define MT6357_IMP_ADC_NUM 30 +#define MT6358_IMP_ADC_NUM 28 + +#define MT6358_DCM_CK_SW_EN GENMASK(1, 0) +#define MT6358_IMP0_CLEAR (BIT(14) | BIT(7)) +#define MT6358_IMP0_IRQ_RDY BIT(8) +#define MT6358_IMP1_AUTOREPEAT_EN BIT(15) + +#define MT6359_IMP0_CONV_EN BIT(0) +#define MT6359_IMP1_IRQ_RDY BIT(15) + +enum mtk_pmic_auxadc_regs { + PMIC_AUXADC_ADC0, + PMIC_AUXADC_DCM_CON, + PMIC_AUXADC_IMP0, + PMIC_AUXADC_IMP1, + PMIC_AUXADC_IMP3, + PMIC_AUXADC_RQST0, + PMIC_AUXADC_RQST1, + PMIC_HK_TOP_WKEY, + PMIC_HK_TOP_RST_CON0, + PMIC_FGADC_R_CON0, + PMIC_AUXADC_REGS_MAX +}; + +enum mtk_pmic_auxadc_channels { + PMIC_AUXADC_CHAN_BATADC, + PMIC_AUXADC_CHAN_ISENSE, + PMIC_AUXADC_CHAN_VCDT, + PMIC_AUXADC_CHAN_BAT_TEMP, + PMIC_AUXADC_CHAN_BATID, + PMIC_AUXADC_CHAN_CHIP_TEMP, + PMIC_AUXADC_CHAN_VCORE_TEMP, + PMIC_AUXADC_CHAN_VPROC_TEMP, + PMIC_AUXADC_CHAN_VGPU_TEMP, + PMIC_AUXADC_CHAN_ACCDET, + PMIC_AUXADC_CHAN_VDCXO, + PMIC_AUXADC_CHAN_TSX_TEMP, + PMIC_AUXADC_CHAN_HPOFS_CAL, + PMIC_AUXADC_CHAN_DCXO_TEMP, + PMIC_AUXADC_CHAN_VBIF, + PMIC_AUXADC_CHAN_IBAT, + PMIC_AUXADC_CHAN_VBAT, + PMIC_AUXADC_CHAN_MAX +}; + +/** + * struct mt6359_auxadc - Main driver structure + * @dev: Device pointer + * @regmap: Regmap from SoC PMIC Wrapper + * @chip_info: PMIC specific chip info + * @lock: Mutex to serialize AUXADC reading vs configuration + * @timed_out: Signals whether the last read timed out + */ +struct mt6359_auxadc { + struct device *dev; + struct regmap *regmap; + const struct mtk_pmic_auxadc_info *chip_info; + struct mutex lock; + bool timed_out; +}; + +/** + * struct mtk_pmic_auxadc_chan - PMIC AUXADC channel data + * @req_idx: Request register number + * @req_mask: Bitmask to activate a channel + * @num_samples: Number of AUXADC samples for averaging + * @r_ratio: Resistance ratio fractional + */ +struct mtk_pmic_auxadc_chan { + u8 req_idx; + u16 req_mask; + u16 num_samples; + struct u8_fract r_ratio; +}; + +/** + * struct mtk_pmic_auxadc_info - PMIC specific chip info + * @model_name: PMIC model name + * @channels: IIO specification of ADC channels + * @num_channels: Number of ADC channels + * @desc: PMIC AUXADC channel data + * @regs: List of PMIC specific registers + * @sec_unlock_key: Security unlock key for HK_TOP writes + * @imp_adc_num: ADC channel for battery impedance readings + * @read_imp: Callback to read impedance channels + */ +struct mtk_pmic_auxadc_info { + const char *model_name; + const struct iio_chan_spec *channels; + u8 num_channels; + const struct mtk_pmic_auxadc_chan *desc; + const u16 *regs; + u16 sec_unlock_key; + u8 imp_adc_num; + int (*read_imp)(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat); +}; + +#define MTK_PMIC_ADC_CHAN(_ch_idx, _req_idx, _req_bit, _samples, _rnum, _rdiv) \ + [PMIC_AUXADC_CHAN_##_ch_idx] = { \ + .req_idx = _req_idx, \ + .req_mask = BIT(_req_bit), \ + .num_samples = _samples, \ + .r_ratio = { _rnum, _rdiv } \ + } + +#define MTK_PMIC_IIO_CHAN(_model, _name, _ch_idx, _adc_idx, _nbits, _ch_type) \ +{ \ + .type = _ch_type, \ + .channel = _model##_AUXADC_##_ch_idx, \ + .address = _adc_idx, \ + .scan_index = PMIC_AUXADC_CHAN_##_ch_idx, \ + .datasheet_name = __stringify(_name), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = _nbits, \ + .storagebits = 16, \ + .endianness = IIO_CPU \ + }, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) \ +} + +static const struct iio_chan_spec mt6357_auxadc_channels[] = { + MTK_PMIC_IIO_CHAN(MT6357, bat_adc, BATADC, 0, 15, IIO_RESISTANCE), + MTK_PMIC_IIO_CHAN(MT6357, isense, ISENSE, 1, 12, IIO_CURRENT), + MTK_PMIC_IIO_CHAN(MT6357, cdt_v, VCDT, 2, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6357, batt_temp, BAT_TEMP, 3, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6357, chip_temp, CHIP_TEMP, 4, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6357, acc_det, ACCDET, 5, 12, IIO_RESISTANCE), + MTK_PMIC_IIO_CHAN(MT6357, dcxo_v, VDCXO, 6, 12, IIO_VOLTAGE), + MTK_PMIC_IIO_CHAN(MT6357, tsx_temp, TSX_TEMP, 7, 15, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6357, hp_ofs_cal, HPOFS_CAL, 9, 15, IIO_RESISTANCE), + MTK_PMIC_IIO_CHAN(MT6357, dcxo_temp, DCXO_TEMP, 36, 15, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6357, vcore_temp, VCORE_TEMP, 40, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6357, vproc_temp, VPROC_TEMP, 41, 12, IIO_TEMP), + + /* Battery impedance channels */ + MTK_PMIC_IIO_CHAN(MT6357, batt_v, VBAT, 0, 15, IIO_VOLTAGE), +}; + +static const struct mtk_pmic_auxadc_chan mt6357_auxadc_ch_desc[] = { + MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, 128, 3, 1), + MTK_PMIC_ADC_CHAN(ISENSE, PMIC_AUXADC_RQST0, 0, 128, 3, 1), + MTK_PMIC_ADC_CHAN(VCDT, PMIC_AUXADC_RQST0, 0, 8, 1, 1), + MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, 8, 1, 1), + MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, 8, 1, 1), + MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, 8, 1, 1), + MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, 128, 1, 1), + MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, 256, 1, 1), + MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, 16, 1, 1), + MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, 8, 1, 1), + MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 5, 8, 1, 1), + MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 6, 8, 1, 1), + + /* Battery impedance channels */ + MTK_PMIC_ADC_CHAN(VBAT, 0, 0, 128, 3, 1), +}; + +static const u16 mt6357_auxadc_regs[] = { + [PMIC_HK_TOP_RST_CON0] = 0x0f90, + [PMIC_AUXADC_DCM_CON] = 0x122e, + [PMIC_AUXADC_ADC0] = 0x1088, + [PMIC_AUXADC_IMP0] = 0x119c, + [PMIC_AUXADC_IMP1] = 0x119e, + [PMIC_AUXADC_RQST0] = 0x110e, + [PMIC_AUXADC_RQST1] = 0x1114, +}; + +static const struct iio_chan_spec mt6358_auxadc_channels[] = { + MTK_PMIC_IIO_CHAN(MT6358, bat_adc, BATADC, 0, 15, IIO_RESISTANCE), + MTK_PMIC_IIO_CHAN(MT6358, cdt_v, VCDT, 2, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6358, batt_temp, BAT_TEMP, 3, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6358, chip_temp, CHIP_TEMP, 4, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6358, acc_det, ACCDET, 5, 12, IIO_RESISTANCE), + MTK_PMIC_IIO_CHAN(MT6358, dcxo_v, VDCXO, 6, 12, IIO_VOLTAGE), + MTK_PMIC_IIO_CHAN(MT6358, tsx_temp, TSX_TEMP, 7, 15, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6358, hp_ofs_cal, HPOFS_CAL, 9, 15, IIO_RESISTANCE), + MTK_PMIC_IIO_CHAN(MT6358, dcxo_temp, DCXO_TEMP, 10, 15, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6358, bif_v, VBIF, 11, 12, IIO_VOLTAGE), + MTK_PMIC_IIO_CHAN(MT6358, vcore_temp, VCORE_TEMP, 38, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6358, vproc_temp, VPROC_TEMP, 39, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6358, vgpu_temp, VGPU_TEMP, 40, 12, IIO_TEMP), + + /* Battery impedance channels */ + MTK_PMIC_IIO_CHAN(MT6358, batt_v, VBAT, 0, 15, IIO_VOLTAGE), +}; + +static const struct mtk_pmic_auxadc_chan mt6358_auxadc_ch_desc[] = { + MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, 128, 3, 1), + MTK_PMIC_ADC_CHAN(VCDT, PMIC_AUXADC_RQST0, 0, 8, 1, 1), + MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, 8, 2, 1), + MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, 8, 1, 1), + MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, 8, 1, 1), + MTK_PMIC_ADC_CHAN(VDCXO, PMIC_AUXADC_RQST0, 6, 8, 3, 2), + MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, 128, 1, 1), + MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, 256, 1, 1), + MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, 16, 1, 1), + MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, 8, 2, 1), + MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 8, 8, 1, 1), + MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 9, 8, 1, 1), + MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST1, 10, 8, 1, 1), + + /* Battery impedance channels */ + MTK_PMIC_ADC_CHAN(VBAT, 0, 0, 128, 7, 2), +}; + +static const u16 mt6358_auxadc_regs[] = { + [PMIC_HK_TOP_RST_CON0] = 0x0f90, + [PMIC_AUXADC_DCM_CON] = 0x1260, + [PMIC_AUXADC_ADC0] = 0x1088, + [PMIC_AUXADC_IMP0] = 0x1208, + [PMIC_AUXADC_IMP1] = 0x120a, + [PMIC_AUXADC_RQST0] = 0x1108, + [PMIC_AUXADC_RQST1] = 0x110a, +}; + +static const struct iio_chan_spec mt6359_auxadc_channels[] = { + MTK_PMIC_IIO_CHAN(MT6359, bat_adc, BATADC, 0, 15, IIO_RESISTANCE), + MTK_PMIC_IIO_CHAN(MT6359, batt_temp, BAT_TEMP, 3, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6359, chip_temp, CHIP_TEMP, 4, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6359, acc_det, ACCDET, 5, 12, IIO_RESISTANCE), + MTK_PMIC_IIO_CHAN(MT6359, dcxo_v, VDCXO, 6, 12, IIO_VOLTAGE), + MTK_PMIC_IIO_CHAN(MT6359, tsx_temp, TSX_TEMP, 7, 15, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6359, hp_ofs_cal, HPOFS_CAL, 9, 15, IIO_RESISTANCE), + MTK_PMIC_IIO_CHAN(MT6359, dcxo_temp, DCXO_TEMP, 10, 15, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6359, bif_v, VBIF, 11, 12, IIO_VOLTAGE), + MTK_PMIC_IIO_CHAN(MT6359, vcore_temp, VCORE_TEMP, 30, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6359, vproc_temp, VPROC_TEMP, 31, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6359, vgpu_temp, VGPU_TEMP, 32, 12, IIO_TEMP), + + /* Battery impedance channels */ + MTK_PMIC_IIO_CHAN(MT6359, batt_v, VBAT, 0, 15, IIO_VOLTAGE), + MTK_PMIC_IIO_CHAN(MT6359, batt_i, IBAT, 0, 15, IIO_CURRENT), +}; + +static const struct mtk_pmic_auxadc_chan mt6359_auxadc_ch_desc[] = { + MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, 128, 7, 2), + MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, 8, 5, 2), + MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, 8, 1, 1), + MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, 8, 1, 1), + MTK_PMIC_ADC_CHAN(VDCXO, PMIC_AUXADC_RQST0, 6, 8, 3, 2), + MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, 128, 1, 1), + MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, 256, 1, 1), + MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, 16, 1, 1), + MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, 8, 5, 2), + MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 8, 8, 1, 1), + MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 9, 8, 1, 1), + MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST1, 10, 8, 1, 1), + + /* Battery impedance channels */ + MTK_PMIC_ADC_CHAN(VBAT, 0, 0, 128, 7, 2), + MTK_PMIC_ADC_CHAN(IBAT, 0, 0, 128, 7, 2), +}; + +static const u16 mt6359_auxadc_regs[] = { + [PMIC_FGADC_R_CON0] = 0x0d88, + [PMIC_HK_TOP_WKEY] = 0x0fb4, + [PMIC_HK_TOP_RST_CON0] = 0x0f90, + [PMIC_AUXADC_RQST0] = 0x1108, + [PMIC_AUXADC_RQST1] = 0x110a, + [PMIC_AUXADC_ADC0] = 0x1088, + [PMIC_AUXADC_IMP0] = 0x1208, + [PMIC_AUXADC_IMP1] = 0x120a, + [PMIC_AUXADC_IMP3] = 0x120e, +}; + +static void mt6358_stop_imp_conv(struct mt6359_auxadc *adc_dev) +{ + const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info; + struct regmap *regmap = adc_dev->regmap; + + regmap_set_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP0], MT6358_IMP0_CLEAR); + regmap_clear_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP0], MT6358_IMP0_CLEAR); + regmap_clear_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP1], MT6358_IMP1_AUTOREPEAT_EN); + regmap_clear_bits(regmap, cinfo->regs[PMIC_AUXADC_DCM_CON], MT6358_DCM_CK_SW_EN); +} + +static int mt6358_start_imp_conv(struct mt6359_auxadc *adc_dev) +{ + const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info; + struct regmap *regmap = adc_dev->regmap; + u32 val; + int ret; + + regmap_set_bits(regmap, cinfo->regs[PMIC_AUXADC_DCM_CON], MT6358_DCM_CK_SW_EN); + regmap_set_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP1], MT6358_IMP1_AUTOREPEAT_EN); + + ret = regmap_read_poll_timeout(adc_dev->regmap, cinfo->regs[PMIC_AUXADC_IMP0], + val, val & MT6358_IMP0_IRQ_RDY, + IMP_POLL_DELAY_US, AUXADC_TIMEOUT_US); + if (ret) { + mt6358_stop_imp_conv(adc_dev); + return ret; + } + + return 0; +} + +static int mt6358_read_imp(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat) +{ + const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info; + struct regmap *regmap = adc_dev->regmap; + u16 reg_adc0 = cinfo->regs[PMIC_AUXADC_ADC0]; + u32 val_v; + int ret; + + ret = mt6358_start_imp_conv(adc_dev); + if (ret) + return ret; + + /* Read the params before stopping */ + regmap_read(regmap, reg_adc0 + (cinfo->imp_adc_num << 1), &val_v); + + mt6358_stop_imp_conv(adc_dev); + + if (vbat) + *vbat = val_v; + if (ibat) + *ibat = 0; + + return 0; +} + +static int mt6359_read_imp(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat) +{ + const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info; + struct regmap *regmap = adc_dev->regmap; + u32 val, val_v, val_i; + int ret; + + /* Start conversion */ + regmap_write(regmap, cinfo->regs[PMIC_AUXADC_IMP0], MT6359_IMP0_CONV_EN); + ret = regmap_read_poll_timeout(regmap, cinfo->regs[PMIC_AUXADC_IMP1], + val, val & MT6359_IMP1_IRQ_RDY, + IMP_POLL_DELAY_US, AUXADC_TIMEOUT_US); + + /* Stop conversion regardless of the result */ + regmap_write(regmap, cinfo->regs[PMIC_AUXADC_IMP0], 0); + if (ret) + return ret; + + /* If it succeeded, wait for the registers to be populated */ + fsleep(IMP_STOP_DELAY_US); + + ret = regmap_read(regmap, cinfo->regs[PMIC_AUXADC_IMP3], &val_v); + if (ret) + return ret; + + ret = regmap_read(regmap, cinfo->regs[PMIC_FGADC_R_CON0], &val_i); + if (ret) + return ret; + + if (vbat) + *vbat = val_v; + if (ibat) + *ibat = val_i; + + return 0; +} + +static const struct mtk_pmic_auxadc_info mt6357_chip_info = { + .model_name = "MT6357", + .channels = mt6357_auxadc_channels, + .num_channels = ARRAY_SIZE(mt6357_auxadc_channels), + .desc = mt6357_auxadc_ch_desc, + .regs = mt6357_auxadc_regs, + .imp_adc_num = MT6357_IMP_ADC_NUM, + .read_imp = mt6358_read_imp, +}; + +static const struct mtk_pmic_auxadc_info mt6358_chip_info = { + .model_name = "MT6358", + .channels = mt6358_auxadc_channels, + .num_channels = ARRAY_SIZE(mt6358_auxadc_channels), + .desc = mt6358_auxadc_ch_desc, + .regs = mt6358_auxadc_regs, + .imp_adc_num = MT6358_IMP_ADC_NUM, + .read_imp = mt6358_read_imp, +}; + +static const struct mtk_pmic_auxadc_info mt6359_chip_info = { + .model_name = "MT6359", + .channels = mt6359_auxadc_channels, + .num_channels = ARRAY_SIZE(mt6359_auxadc_channels), + .desc = mt6359_auxadc_ch_desc, + .regs = mt6359_auxadc_regs, + .sec_unlock_key = 0x6359, + .read_imp = mt6359_read_imp, +}; + +static void mt6359_auxadc_reset(struct mt6359_auxadc *adc_dev) +{ + const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info; + struct regmap *regmap = adc_dev->regmap; + + /* Unlock HK_TOP writes */ + if (cinfo->sec_unlock_key) + regmap_write(regmap, cinfo->regs[PMIC_HK_TOP_WKEY], cinfo->sec_unlock_key); + + /* Assert ADC reset */ + regmap_set_bits(regmap, cinfo->regs[PMIC_HK_TOP_RST_CON0], PMIC_RG_RESET_VAL); + + /* De-assert ADC reset. No wait required, as pwrap takes care of that for us. */ + regmap_clear_bits(regmap, cinfo->regs[PMIC_HK_TOP_RST_CON0], PMIC_RG_RESET_VAL); + + /* Lock HK_TOP writes again */ + if (cinfo->sec_unlock_key) + regmap_write(regmap, cinfo->regs[PMIC_HK_TOP_WKEY], 0); +} + +static int mt6359_auxadc_read_adc(struct mt6359_auxadc *adc_dev, + const struct iio_chan_spec *chan, int *out) +{ + const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info; + const struct mtk_pmic_auxadc_chan *desc = &cinfo->desc[chan->scan_index]; + struct regmap *regmap = adc_dev->regmap; + u32 val; + int ret; + + /* Request to start sampling for ADC channel */ + ret = regmap_write(regmap, cinfo->regs[desc->req_idx], desc->req_mask); + if (ret) + return ret; + + /* Wait until all samples are averaged */ + fsleep(desc->num_samples * AUXADC_AVG_TIME_US); + + ret = regmap_read_poll_timeout(regmap, + cinfo->regs[PMIC_AUXADC_ADC0] + (chan->address << 1), + val, val & PMIC_AUXADC_RDY_BIT, + AUXADC_POLL_DELAY_US, AUXADC_TIMEOUT_US); + if (ret) + return ret; + + /* Stop sampling */ + regmap_write(regmap, cinfo->regs[desc->req_idx], 0); + + *out = val & GENMASK(chan->scan_type.realbits - 1, 0); + return 0; +} + +static int mt6359_auxadc_read_label(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, char *label) +{ + return sysfs_emit(label, "%s\n", chan->datasheet_name); +} + +static int mt6359_auxadc_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct mt6359_auxadc *adc_dev = iio_priv(indio_dev); + const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info; + const struct mtk_pmic_auxadc_chan *desc = &cinfo->desc[chan->scan_index]; + int ret; + + if (mask == IIO_CHAN_INFO_SCALE) { + *val = desc->r_ratio.numerator * AUXADC_VOLT_FULL; + + if (desc->r_ratio.denominator > 1) { + *val2 = desc->r_ratio.denominator; + return IIO_VAL_FRACTIONAL; + } + + return IIO_VAL_INT; + } + + scoped_guard(mutex, &adc_dev->lock) { + switch (chan->scan_index) { + case PMIC_AUXADC_CHAN_IBAT: + ret = adc_dev->chip_info->read_imp(adc_dev, NULL, val); + break; + case PMIC_AUXADC_CHAN_VBAT: + ret = adc_dev->chip_info->read_imp(adc_dev, val, NULL); + break; + default: + ret = mt6359_auxadc_read_adc(adc_dev, chan, val); + break; + } + } + + if (ret) { + /* + * If we get more than one timeout, it's possible that the + * AUXADC is stuck: perform a full reset to recover it. + */ + if (ret == -ETIMEDOUT) { + if (adc_dev->timed_out) { + dev_warn(adc_dev->dev, "Resetting stuck ADC!\r\n"); + mt6359_auxadc_reset(adc_dev); + } + adc_dev->timed_out = true; + } + return ret; + } + adc_dev->timed_out = false; + + return IIO_VAL_INT; +} + +static const struct iio_info mt6359_auxadc_iio_info = { + .read_label = mt6359_auxadc_read_label, + .read_raw = mt6359_auxadc_read_raw, +}; + +static int mt6359_auxadc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device *mt6397_mfd_dev = dev->parent; + struct mt6359_auxadc *adc_dev; + struct iio_dev *indio_dev; + struct regmap *regmap; + int ret; + + /* Regmap is from SoC PMIC Wrapper, parent of the mt6397 MFD */ + regmap = dev_get_regmap(mt6397_mfd_dev->parent, NULL); + if (!regmap) + return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n"); + + indio_dev = devm_iio_device_alloc(dev, sizeof(*adc_dev)); + if (!indio_dev) + return -ENOMEM; + + adc_dev = iio_priv(indio_dev); + adc_dev->regmap = regmap; + adc_dev->dev = dev; + + adc_dev->chip_info = device_get_match_data(dev); + if (!adc_dev->chip_info) + return -EINVAL; + + mutex_init(&adc_dev->lock); + + mt6359_auxadc_reset(adc_dev); + + indio_dev->name = adc_dev->chip_info->model_name; + indio_dev->info = &mt6359_auxadc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = adc_dev->chip_info->channels; + indio_dev->num_channels = adc_dev->chip_info->num_channels; + + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + return dev_err_probe(dev, ret, "failed to register iio device\n"); + + return 0; +} + +static const struct of_device_id mt6359_auxadc_of_match[] = { + { .compatible = "mediatek,mt6357-auxadc", .data = &mt6357_chip_info }, + { .compatible = "mediatek,mt6358-auxadc", .data = &mt6358_chip_info }, + { .compatible = "mediatek,mt6359-auxadc", .data = &mt6359_chip_info }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mt6359_auxadc_of_match); + +static struct platform_driver mt6359_auxadc_driver = { + .driver = { + .name = "mt6359-auxadc", + .of_match_table = mt6359_auxadc_of_match, + }, + .probe = mt6359_auxadc_probe, +}; +module_platform_driver(mt6359_auxadc_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>"); +MODULE_DESCRIPTION("MediaTek MT6359 PMIC AUXADC Driver"); diff --git a/drivers/iio/adc/qcom-spmi-rradc.c b/drivers/iio/adc/qcom-spmi-rradc.c index 56a713766954..1402df68dd52 100644 --- a/drivers/iio/adc/qcom-spmi-rradc.c +++ b/drivers/iio/adc/qcom-spmi-rradc.c @@ -358,15 +358,15 @@ static int rradc_enable_continuous_mode(struct rradc_chip *chip) int ret; /* Clear channel log */ - ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_LOG, - RR_ADC_LOG_CLR_CTRL, RR_ADC_LOG_CLR_CTRL); + ret = regmap_set_bits(chip->regmap, chip->base + RR_ADC_LOG, + RR_ADC_LOG_CLR_CTRL); if (ret < 0) { dev_err(chip->dev, "log ctrl update to clear failed:%d\n", ret); return ret; } - ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_LOG, - RR_ADC_LOG_CLR_CTRL, 0); + ret = regmap_clear_bits(chip->regmap, chip->base + RR_ADC_LOG, + RR_ADC_LOG_CLR_CTRL); if (ret < 0) { dev_err(chip->dev, "log ctrl update to not clear failed:%d\n", ret); @@ -374,9 +374,8 @@ static int rradc_enable_continuous_mode(struct rradc_chip *chip) } /* Switch to continuous mode */ - ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_CTL, - RR_ADC_CTL_CONTINUOUS_SEL, - RR_ADC_CTL_CONTINUOUS_SEL); + ret = regmap_set_bits(chip->regmap, chip->base + RR_ADC_CTL, + RR_ADC_CTL_CONTINUOUS_SEL); if (ret < 0) dev_err(chip->dev, "Update to continuous mode failed:%d\n", ret); @@ -389,8 +388,8 @@ static int rradc_disable_continuous_mode(struct rradc_chip *chip) int ret; /* Switch to non continuous mode */ - ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_CTL, - RR_ADC_CTL_CONTINUOUS_SEL, 0); + ret = regmap_clear_bits(chip->regmap, chip->base + RR_ADC_CTL, + RR_ADC_CTL_CONTINUOUS_SEL); if (ret < 0) dev_err(chip->dev, "Update to non-continuous mode failed:%d\n", ret); @@ -434,8 +433,8 @@ static int rradc_read_status_in_cont_mode(struct rradc_chip *chip, return -EINVAL; } - ret = regmap_update_bits(chip->regmap, chip->base + chan->trigger_addr, - chan->trigger_mask, chan->trigger_mask); + ret = regmap_set_bits(chip->regmap, chip->base + chan->trigger_addr, + chan->trigger_mask); if (ret < 0) { dev_err(chip->dev, "Failed to apply trigger for channel '%s' ret=%d\n", @@ -469,8 +468,8 @@ static int rradc_read_status_in_cont_mode(struct rradc_chip *chip, rradc_disable_continuous_mode(chip); disable_trigger: - regmap_update_bits(chip->regmap, chip->base + chan->trigger_addr, - chan->trigger_mask, 0); + regmap_clear_bits(chip->regmap, chip->base + chan->trigger_addr, + chan->trigger_mask); return ret; } @@ -481,17 +480,16 @@ static int rradc_prepare_batt_id_conversion(struct rradc_chip *chip, { int ret; - ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_CTRL, - RR_ADC_BATT_ID_CTRL_CHANNEL_CONV, - RR_ADC_BATT_ID_CTRL_CHANNEL_CONV); + ret = regmap_set_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_CTRL, + RR_ADC_BATT_ID_CTRL_CHANNEL_CONV); if (ret < 0) { dev_err(chip->dev, "Enabling BATT ID channel failed:%d\n", ret); return ret; } - ret = regmap_update_bits(chip->regmap, - chip->base + RR_ADC_BATT_ID_TRIGGER, - RR_ADC_TRIGGER_CTL, RR_ADC_TRIGGER_CTL); + ret = regmap_set_bits(chip->regmap, + chip->base + RR_ADC_BATT_ID_TRIGGER, + RR_ADC_TRIGGER_CTL); if (ret < 0) { dev_err(chip->dev, "BATT_ID trigger set failed:%d\n", ret); goto out_disable_batt_id; @@ -500,12 +498,12 @@ static int rradc_prepare_batt_id_conversion(struct rradc_chip *chip, ret = rradc_read_status_in_cont_mode(chip, chan_address); /* Reset registers back to default values */ - regmap_update_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_TRIGGER, - RR_ADC_TRIGGER_CTL, 0); + regmap_clear_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_TRIGGER, + RR_ADC_TRIGGER_CTL); out_disable_batt_id: - regmap_update_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_CTRL, - RR_ADC_BATT_ID_CTRL_CHANNEL_CONV, 0); + regmap_clear_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_CTRL, + RR_ADC_BATT_ID_CTRL_CHANNEL_CONV); return ret; } @@ -965,9 +963,9 @@ static int rradc_probe(struct platform_device *pdev) if (batt_id_delay >= 0) { batt_id_delay = FIELD_PREP(BATT_ID_SETTLE_MASK, batt_id_delay); - ret = regmap_update_bits(chip->regmap, - chip->base + RR_ADC_BATT_ID_CFG, - batt_id_delay, batt_id_delay); + ret = regmap_set_bits(chip->regmap, + chip->base + RR_ADC_BATT_ID_CFG, + batt_id_delay); if (ret < 0) { dev_err(chip->dev, "BATT_ID settling time config failed:%d\n", diff --git a/drivers/iio/adc/rn5t618-adc.c b/drivers/iio/adc/rn5t618-adc.c index 6bf32907f01d..ce5f3011fe00 100644 --- a/drivers/iio/adc/rn5t618-adc.c +++ b/drivers/iio/adc/rn5t618-adc.c @@ -137,9 +137,8 @@ static int rn5t618_adc_read(struct iio_dev *iio_dev, init_completion(&adc->conv_completion); /* single conversion */ - ret = regmap_update_bits(adc->rn5t618->regmap, RN5T618_ADCCNT3, - RN5T618_ADCCNT3_GODONE, - RN5T618_ADCCNT3_GODONE); + ret = regmap_set_bits(adc->rn5t618->regmap, RN5T618_ADCCNT3, + RN5T618_ADCCNT3_GODONE); if (ret < 0) return ret; diff --git a/drivers/iio/adc/sc27xx_adc.c b/drivers/iio/adc/sc27xx_adc.c index b4a2e057d80f..2535c2c3e60b 100644 --- a/drivers/iio/adc/sc27xx_adc.c +++ b/drivers/iio/adc/sc27xx_adc.c @@ -508,13 +508,13 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel, } } - ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL, - SC27XX_ADC_EN, SC27XX_ADC_EN); + ret = regmap_set_bits(data->regmap, data->base + SC27XX_ADC_CTL, + SC27XX_ADC_EN); if (ret) goto regulator_restore; - ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_CLR, - SC27XX_ADC_IRQ_CLR, SC27XX_ADC_IRQ_CLR); + ret = regmap_set_bits(data->regmap, data->base + SC27XX_ADC_INT_CLR, + SC27XX_ADC_IRQ_CLR); if (ret) goto disable_adc; @@ -537,8 +537,8 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel, if (ret) goto disable_adc; - ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL, - SC27XX_ADC_CHN_RUN, SC27XX_ADC_CHN_RUN); + ret = regmap_set_bits(data->regmap, data->base + SC27XX_ADC_CTL, + SC27XX_ADC_CHN_RUN); if (ret) goto disable_adc; @@ -559,8 +559,8 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel, value &= SC27XX_ADC_DATA_MASK; disable_adc: - regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL, - SC27XX_ADC_EN, 0); + regmap_clear_bits(data->regmap, data->base + SC27XX_ADC_CTL, + SC27XX_ADC_EN); regulator_restore: if ((data->var_data->set_volref) && (channel == 30 || channel == 31)) { ret_volref = regulator_set_voltage(data->volref, @@ -765,15 +765,14 @@ static int sc27xx_adc_enable(struct sc27xx_adc_data *data) { int ret; - ret = regmap_update_bits(data->regmap, data->var_data->module_en, - SC27XX_MODULE_ADC_EN, SC27XX_MODULE_ADC_EN); + ret = regmap_set_bits(data->regmap, data->var_data->module_en, + SC27XX_MODULE_ADC_EN); if (ret) return ret; /* Enable ADC work clock and controller clock */ - ret = regmap_update_bits(data->regmap, data->var_data->clk_en, - SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, - SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN); + ret = regmap_set_bits(data->regmap, data->var_data->clk_en, + SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN); if (ret) goto disable_adc; @@ -789,11 +788,11 @@ static int sc27xx_adc_enable(struct sc27xx_adc_data *data) return 0; disable_clk: - regmap_update_bits(data->regmap, data->var_data->clk_en, - SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, 0); + regmap_clear_bits(data->regmap, data->var_data->clk_en, + SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN); disable_adc: - regmap_update_bits(data->regmap, data->var_data->module_en, - SC27XX_MODULE_ADC_EN, 0); + regmap_clear_bits(data->regmap, data->var_data->module_en, + SC27XX_MODULE_ADC_EN); return ret; } @@ -803,11 +802,11 @@ static void sc27xx_adc_disable(void *_data) struct sc27xx_adc_data *data = _data; /* Disable ADC work clock and controller clock */ - regmap_update_bits(data->regmap, data->var_data->clk_en, - SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, 0); + regmap_clear_bits(data->regmap, data->var_data->clk_en, + SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN); - regmap_update_bits(data->regmap, data->var_data->module_en, - SC27XX_MODULE_ADC_EN, 0); + regmap_clear_bits(data->regmap, data->var_data->module_en, + SC27XX_MODULE_ADC_EN); } static const struct sc27xx_adc_variant_data sc2731_data = { diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index 9a47d2c87f05..fabd654245f5 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -759,8 +759,7 @@ static int stm32_dfsdm_start_conv(struct iio_dev *indio_dev, return 0; filter_unconfigure: - regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), - DFSDM_CR1_CFG_MASK, 0); + regmap_clear_bits(regmap, DFSDM_CR1(adc->fl_id), DFSDM_CR1_CFG_MASK); stop_channels: stm32_dfsdm_stop_channel(indio_dev); @@ -774,8 +773,7 @@ static void stm32_dfsdm_stop_conv(struct iio_dev *indio_dev) stm32_dfsdm_stop_filter(adc->dfsdm, adc->fl_id); - regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), - DFSDM_CR1_CFG_MASK, 0); + regmap_clear_bits(regmap, DFSDM_CR1(adc->fl_id), DFSDM_CR1_CFG_MASK); stm32_dfsdm_stop_channel(indio_dev); } @@ -951,16 +949,14 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) if (adc->nconv == 1 && !indio_dev->trig) { /* Enable regular DMA transfer*/ - ret = regmap_update_bits(adc->dfsdm->regmap, - DFSDM_CR1(adc->fl_id), - DFSDM_CR1_RDMAEN_MASK, - DFSDM_CR1_RDMAEN_MASK); + ret = regmap_set_bits(adc->dfsdm->regmap, + DFSDM_CR1(adc->fl_id), + DFSDM_CR1_RDMAEN_MASK); } else { /* Enable injected DMA transfer*/ - ret = regmap_update_bits(adc->dfsdm->regmap, - DFSDM_CR1(adc->fl_id), - DFSDM_CR1_JDMAEN_MASK, - DFSDM_CR1_JDMAEN_MASK); + ret = regmap_set_bits(adc->dfsdm->regmap, + DFSDM_CR1(adc->fl_id), + DFSDM_CR1_JDMAEN_MASK); } if (ret < 0) @@ -981,8 +977,8 @@ static void stm32_dfsdm_adc_dma_stop(struct iio_dev *indio_dev) if (!adc->dma_chan) return; - regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR1(adc->fl_id), - DFSDM_CR1_RDMAEN_MASK | DFSDM_CR1_JDMAEN_MASK, 0); + regmap_clear_bits(adc->dfsdm->regmap, DFSDM_CR1(adc->fl_id), + DFSDM_CR1_RDMAEN_MASK | DFSDM_CR1_JDMAEN_MASK); dmaengine_terminate_all(adc->dma_chan); } @@ -1305,9 +1301,8 @@ static irqreturn_t stm32_dfsdm_irq(int irq, void *arg) if (status & DFSDM_ISR_ROVRF_MASK) { if (int_en & DFSDM_CR2_ROVRIE_MASK) dev_warn(&indio_dev->dev, "Overrun detected\n"); - regmap_update_bits(regmap, DFSDM_ICR(adc->fl_id), - DFSDM_ICR_CLRROVRF_MASK, - DFSDM_ICR_CLRROVRF_MASK); + regmap_set_bits(regmap, DFSDM_ICR(adc->fl_id), + DFSDM_ICR_CLRROVRF_MASK); } return IRQ_HANDLED; diff --git a/drivers/iio/adc/ti-adc108s102.c b/drivers/iio/adc/ti-adc108s102.c index 69fcbbc7e418..9758ac801310 100644 --- a/drivers/iio/adc/ti-adc108s102.c +++ b/drivers/iio/adc/ti-adc108s102.c @@ -58,7 +58,6 @@ struct adc108s102_state { struct spi_device *spi; - struct regulator *reg; u32 va_millivolt; /* SPI transfer used by triggered buffer handler*/ struct spi_transfer ring_xfer; @@ -216,11 +215,6 @@ static const struct iio_info adc108s102_info = { .update_scan_mode = &adc108s102_update_scan_mode, }; -static void adc108s102_reg_disable(void *reg) -{ - regulator_disable(reg); -} - static int adc108s102_probe(struct spi_device *spi) { struct adc108s102_state *st; @@ -236,25 +230,9 @@ static int adc108s102_probe(struct spi_device *spi) if (ACPI_COMPANION(&spi->dev)) { st->va_millivolt = ADC108S102_VA_MV_ACPI_DEFAULT; } else { - st->reg = devm_regulator_get(&spi->dev, "vref"); - if (IS_ERR(st->reg)) - return PTR_ERR(st->reg); - - ret = regulator_enable(st->reg); - if (ret < 0) { - dev_err(&spi->dev, "Cannot enable vref regulator\n"); - return ret; - } - ret = devm_add_action_or_reset(&spi->dev, adc108s102_reg_disable, - st->reg); - if (ret) - return ret; - - ret = regulator_get_voltage(st->reg); - if (ret < 0) { - dev_err(&spi->dev, "vref get voltage failed\n"); - return ret; - } + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); + if (ret < 0) + return dev_err_probe(&spi->dev, ret, "failed get vref voltage\n"); st->va_millivolt = ret / 1000; } diff --git a/drivers/iio/adc/ti-ads1119.c b/drivers/iio/adc/ti-ads1119.c new file mode 100644 index 000000000000..630f5d5f9a60 --- /dev/null +++ b/drivers/iio/adc/ti-ads1119.c @@ -0,0 +1,825 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Texas Instruments ADS1119 ADC driver. + * + * Copyright 2024 Toradex + */ + +#include <linux/bits.h> +#include <linux/bitfield.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/interrupt.h> +#include <linux/iopoll.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/math.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include <linux/units.h> + +#include <linux/iio/iio.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/iio/trigger_consumer.h> + +#define ADS1119_CMD_RESET 0x06 +#define ADS1119_CMD_POWERDOWN 0x02 +#define ADS1119_CMD_START_SYNC 0x08 +#define ADS1119_CMD_RDATA 0x10 +#define ADS1119_CMD_RREG_CONFIG 0x20 +#define ADS1119_CMD_RREG_STATUS 0x24 +#define ADS1119_CMD_WREG 0x40 + +#define ADS1119_CMD_RREG(reg) (0x20 | (reg) << 2) + +/* Config register */ +#define ADS1119_REG_CONFIG 0x00 +#define ADS1119_CONFIG_VREF_FIELD BIT(0) +#define ADS1119_CONFIG_CM_FIELD BIT(1) +#define ADS1119_CONFIG_DR_FIELD GENMASK(3, 2) +#define ADS1119_CONFIG_GAIN_FIELD BIT(4) +#define ADS1119_CONFIG_MUX_FIELD GENMASK(7, 5) + +#define ADS1119_VREF_INTERNAL 0 +#define ADS1119_VREF_EXTERNAL 1 +#define ADS1119_VREF_INTERNAL_VAL 2048000 + +#define ADS1119_CM_SINGLE 0 +#define ADS1119_CM_CONTINUOUS 1 + +#define ADS1119_DR_20_SPS 0 +#define ADS1119_DR_90_SPS 1 +#define ADS1119_DR_330_SPS 2 +#define ADS1119_DR_1000_SPS 3 + +#define ADS1119_GAIN_1 0 +#define ADS1119_GAIN_4 1 + +#define ADS1119_MUX_AIN0_AIN1 0 +#define ADS1119_MUX_AIN2_AIN3 1 +#define ADS1119_MUX_AIN1_AIN2 2 +#define ADS1119_MUX_AIN0 3 +#define ADS1119_MUX_AIN1 4 +#define ADS1119_MUX_AIN2 5 +#define ADS1119_MUX_AIN3 6 +#define ADS1119_MUX_SHORTED 7 + +/* Status register */ +#define ADS1119_REG_STATUS 0x01 +#define ADS1119_STATUS_DRDY_FIELD BIT(7) + +#define ADS1119_DEFAULT_GAIN 1 +#define ADS1119_DEFAULT_DATARATE 20 + +#define ADS1119_SUSPEND_DELAY 2000 + +/* Timeout based on the minimum sample rate of 20 SPS (50000us) */ +#define ADS1119_MAX_DRDY_TIMEOUT 85000 + +#define ADS1119_MAX_CHANNELS 7 +#define ADS1119_MAX_SINGLE_CHANNELS 4 + +struct ads1119_channel_config { + int gain; + int datarate; + int mux; +}; + +struct ads1119_state { + struct completion completion; + struct i2c_client *client; + struct gpio_desc *reset_gpio; + struct iio_trigger *trig; + struct ads1119_channel_config *channels_cfg; + unsigned int num_channels_cfg; + unsigned int cached_config; + int vref_uV; +}; + +static const char * const ads1119_power_supplies[] = { + "avdd", "dvdd" +}; + +static const int ads1119_available_datarates[] = { + 20, 90, 330, 1000, +}; + +static const int ads1119_available_gains[] = { + 1, 1, + 1, 4, +}; + +static int ads1119_upd_cfg_reg(struct ads1119_state *st, unsigned int fields, + unsigned int val) +{ + unsigned int config = st->cached_config; + int ret; + + config &= ~fields; + config |= val; + + ret = i2c_smbus_write_byte_data(st->client, ADS1119_CMD_WREG, config); + if (ret) + return ret; + + st->cached_config = config; + + return 0; +} + +static bool ads1119_data_ready(struct ads1119_state *st) +{ + int status; + + status = i2c_smbus_read_byte_data(st->client, ADS1119_CMD_RREG_STATUS); + if (status < 0) + return false; + + return FIELD_GET(ADS1119_STATUS_DRDY_FIELD, status); +} + +static int ads1119_reset(struct ads1119_state *st) +{ + st->cached_config = 0; + + if (!st->reset_gpio) + return i2c_smbus_write_byte(st->client, ADS1119_CMD_RESET); + + gpiod_set_value_cansleep(st->reset_gpio, 1); + udelay(1); + gpiod_set_value_cansleep(st->reset_gpio, 0); + udelay(1); + + return 0; +} + +static int ads1119_set_conv_mode(struct ads1119_state *st, bool continuous) +{ + unsigned int mode; + + if (continuous) + mode = ADS1119_CM_CONTINUOUS; + else + mode = ADS1119_CM_SINGLE; + + return ads1119_upd_cfg_reg(st, ADS1119_CONFIG_CM_FIELD, + FIELD_PREP(ADS1119_CONFIG_CM_FIELD, mode)); +} + +static int ads1119_get_hw_gain(int gain) +{ + if (gain == 4) + return ADS1119_GAIN_4; + else + return ADS1119_GAIN_1; +} + +static int ads1119_get_hw_datarate(int datarate) +{ + switch (datarate) { + case 90: + return ADS1119_DR_90_SPS; + case 330: + return ADS1119_DR_330_SPS; + case 1000: + return ADS1119_DR_1000_SPS; + case 20: + default: + return ADS1119_DR_20_SPS; + } +} + +static int ads1119_configure_channel(struct ads1119_state *st, int mux, + int gain, int datarate) +{ + int ret; + + ret = ads1119_upd_cfg_reg(st, ADS1119_CONFIG_MUX_FIELD, + FIELD_PREP(ADS1119_CONFIG_MUX_FIELD, mux)); + if (ret) + return ret; + + ret = ads1119_upd_cfg_reg(st, ADS1119_CONFIG_GAIN_FIELD, + FIELD_PREP(ADS1119_CONFIG_GAIN_FIELD, + ads1119_get_hw_gain(gain))); + if (ret) + return ret; + + return ads1119_upd_cfg_reg(st, ADS1119_CONFIG_DR_FIELD, + FIELD_PREP(ADS1119_CONFIG_DR_FIELD, + ads1119_get_hw_datarate(datarate))); +} + +static int ads1119_poll_data_ready(struct ads1119_state *st, + struct iio_chan_spec const *chan) +{ + unsigned int datarate = st->channels_cfg[chan->address].datarate; + unsigned long wait_time; + bool data_ready; + + /* Poll 5 times more than the data rate */ + wait_time = DIV_ROUND_CLOSEST(MICRO, 5 * datarate); + + return read_poll_timeout(ads1119_data_ready, data_ready, + data_ready, wait_time, + ADS1119_MAX_DRDY_TIMEOUT, false, st); +} + +static int ads1119_read_data(struct ads1119_state *st, + struct iio_chan_spec const *chan, + unsigned int *val) +{ + unsigned int timeout; + int ret = 0; + + timeout = msecs_to_jiffies(ADS1119_MAX_DRDY_TIMEOUT); + + if (!st->client->irq) { + ret = ads1119_poll_data_ready(st, chan); + if (ret) + return ret; + } else if (!wait_for_completion_timeout(&st->completion, timeout)) { + return -ETIMEDOUT; + } + + ret = i2c_smbus_read_word_swapped(st->client, ADS1119_CMD_RDATA); + if (ret < 0) + return ret; + + *val = ret; + + return 0; +} + +static int ads1119_single_conversion(struct ads1119_state *st, + struct iio_chan_spec const *chan, + int *val, + bool calib_offset) +{ + struct device *dev = &st->client->dev; + int mux = st->channels_cfg[chan->address].mux; + int gain = st->channels_cfg[chan->address].gain; + int datarate = st->channels_cfg[chan->address].datarate; + unsigned int sample; + int ret; + + if (calib_offset) + mux = ADS1119_MUX_SHORTED; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + goto pdown; + + ret = ads1119_configure_channel(st, mux, gain, datarate); + if (ret) + goto pdown; + + ret = i2c_smbus_write_byte(st->client, ADS1119_CMD_START_SYNC); + if (ret) + goto pdown; + + ret = ads1119_read_data(st, chan, &sample); + if (ret) + goto pdown; + + *val = sign_extend32(sample, chan->scan_type.realbits - 1); + ret = IIO_VAL_INT; +pdown: + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + return ret; +} + +static int ads1119_validate_datarate(struct ads1119_state *st, int datarate) +{ + switch (datarate) { + case 20: + case 90: + case 330: + case 1000: + return datarate; + default: + return -EINVAL; + } +} + +static int ads1119_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + *type = IIO_VAL_FRACTIONAL; + *vals = ads1119_available_gains; + *length = ARRAY_SIZE(ads1119_available_gains); + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SAMP_FREQ: + *type = IIO_VAL_INT; + *vals = ads1119_available_datarates; + *length = ARRAY_SIZE(ads1119_available_datarates); + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int ads1119_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct ads1119_state *st = iio_priv(indio_dev); + unsigned int index = chan->address; + + if (index >= st->num_channels_cfg) + return -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) + return ads1119_single_conversion(st, chan, val, false); + unreachable(); + case IIO_CHAN_INFO_OFFSET: + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) + return ads1119_single_conversion(st, chan, val, true); + unreachable(); + case IIO_CHAN_INFO_SCALE: + *val = st->vref_uV / 1000; + *val /= st->channels_cfg[index].gain; + *val2 = chan->scan_type.realbits - 1; + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = st->channels_cfg[index].datarate; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int ads1119_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct ads1119_state *st = iio_priv(indio_dev); + unsigned int index = chan->address; + int ret; + + if (index >= st->num_channels_cfg) + return -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + ret = MICRO / ((val * MICRO) + val2); + if (ret != 1 && ret != 4) + return -EINVAL; + + st->channels_cfg[index].gain = ret; + return 0; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = ads1119_validate_datarate(st, val); + if (ret < 0) + return ret; + + st->channels_cfg[index].datarate = ret; + return 0; + default: + return -EINVAL; + } +} + +static int ads1119_debugfs_reg_access(struct iio_dev *indio_dev, + unsigned int reg, unsigned int writeval, + unsigned int *readval) +{ + struct ads1119_state *st = iio_priv(indio_dev); + int ret; + + if (reg > ADS1119_REG_STATUS) + return -EINVAL; + + if (readval) { + ret = i2c_smbus_read_byte_data(st->client, + ADS1119_CMD_RREG(reg)); + if (ret < 0) + return ret; + + *readval = ret; + return 0; + } + + if (reg > ADS1119_REG_CONFIG) + return -EINVAL; + + return i2c_smbus_write_byte_data(st->client, ADS1119_CMD_WREG, + writeval); +} + +static const struct iio_info ads1119_info = { + .read_avail = ads1119_read_avail, + .read_raw = ads1119_read_raw, + .write_raw = ads1119_write_raw, + .debugfs_reg_access = ads1119_debugfs_reg_access, +}; + +static int ads1119_triggered_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ads1119_state *st = iio_priv(indio_dev); + struct device *dev = &st->client->dev; + unsigned int index; + int ret; + + index = find_first_bit(indio_dev->active_scan_mask, + indio_dev->masklength); + + ret = ads1119_set_conv_mode(st, true); + if (ret) + return ret; + + ret = ads1119_configure_channel(st, + st->channels_cfg[index].mux, + st->channels_cfg[index].gain, + st->channels_cfg[index].datarate); + if (ret) + return ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + + return i2c_smbus_write_byte(st->client, ADS1119_CMD_START_SYNC); +} + +static int ads1119_triggered_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ads1119_state *st = iio_priv(indio_dev); + struct device *dev = &st->client->dev; + int ret; + + ret = ads1119_set_conv_mode(st, false); + if (ret) + return ret; + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + return 0; +} + +static const struct iio_buffer_setup_ops ads1119_buffer_setup_ops = { + .preenable = ads1119_triggered_buffer_preenable, + .postdisable = ads1119_triggered_buffer_postdisable, + .validate_scan_mask = &iio_validate_scan_mask_onehot, +}; + +static const struct iio_trigger_ops ads1119_trigger_ops = { + .validate_device = &iio_trigger_validate_own_device, +}; + +static irqreturn_t ads1119_irq_handler(int irq, void *dev_id) +{ + struct iio_dev *indio_dev = dev_id; + struct ads1119_state *st = iio_priv(indio_dev); + + if (iio_buffer_enabled(indio_dev) && iio_trigger_using_own(indio_dev)) + iio_trigger_poll(indio_dev->trig); + else + complete(&st->completion); + + return IRQ_HANDLED; +} + +static irqreturn_t ads1119_trigger_handler(int irq, void *private) +{ + struct iio_poll_func *pf = private; + struct iio_dev *indio_dev = pf->indio_dev; + struct ads1119_state *st = iio_priv(indio_dev); + struct { + unsigned int sample; + s64 timestamp __aligned(8); + } scan; + unsigned int index; + int ret; + + if (!iio_trigger_using_own(indio_dev)) { + index = find_first_bit(indio_dev->active_scan_mask, + indio_dev->masklength); + + ret = ads1119_poll_data_ready(st, &indio_dev->channels[index]); + if (ret) { + dev_err(&st->client->dev, + "Failed to poll data on trigger (%d)\n", ret); + goto done; + } + } + + ret = i2c_smbus_read_word_swapped(st->client, ADS1119_CMD_RDATA); + if (ret < 0) { + dev_err(&st->client->dev, + "Failed to read data on trigger (%d)\n", ret); + goto done; + } + + scan.sample = ret; + + iio_push_to_buffers_with_timestamp(indio_dev, &scan, + iio_get_time_ns(indio_dev)); +done: + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} + +static int ads1119_init(struct ads1119_state *st, bool vref_external) +{ + int ret; + + ret = ads1119_reset(st); + if (ret) + return ret; + + if (vref_external) + return ads1119_upd_cfg_reg(st, + ADS1119_CONFIG_VREF_FIELD, + FIELD_PREP(ADS1119_CONFIG_VREF_FIELD, + ADS1119_VREF_EXTERNAL)); + return 0; +} + +static int ads1119_map_analog_inputs_mux(int ain_pos, int ain_neg, + bool differential) +{ + if (ain_pos >= ADS1119_MAX_SINGLE_CHANNELS) + return -EINVAL; + + if (!differential) + return ADS1119_MUX_AIN0 + ain_pos; + + if (ain_pos == 0 && ain_neg == 1) + return ADS1119_MUX_AIN0_AIN1; + else if (ain_pos == 1 && ain_neg == 2) + return ADS1119_MUX_AIN1_AIN2; + else if (ain_pos == 2 && ain_neg == 3) + return ADS1119_MUX_AIN2_AIN3; + + return -EINVAL; +} + +static int ads1119_alloc_and_config_channels(struct iio_dev *indio_dev) +{ + const struct iio_chan_spec ads1119_channel = + (const struct iio_chan_spec) { + .type = IIO_VOLTAGE, + .indexed = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_shared_by_all_available = + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_CPU, + }, + }; + const struct iio_chan_spec ads1119_ts = IIO_CHAN_SOFT_TIMESTAMP(0); + struct ads1119_state *st = iio_priv(indio_dev); + struct iio_chan_spec *iio_channels, *chan; + struct device *dev = &st->client->dev; + unsigned int num_channels, i; + bool differential; + u32 ain[2]; + int ret; + + st->num_channels_cfg = device_get_child_node_count(dev); + if (st->num_channels_cfg > ADS1119_MAX_CHANNELS) + return dev_err_probe(dev, -EINVAL, + "Too many channels %d, max is %d\n", + st->num_channels_cfg, + ADS1119_MAX_CHANNELS); + + st->channels_cfg = devm_kcalloc(dev, st->num_channels_cfg, + sizeof(*st->channels_cfg), GFP_KERNEL); + if (!st->channels_cfg) + return -ENOMEM; + + /* Allocate one more iio channel for the timestamp */ + num_channels = st->num_channels_cfg + 1; + iio_channels = devm_kcalloc(dev, num_channels, sizeof(*iio_channels), + GFP_KERNEL); + if (!iio_channels) + return -ENOMEM; + + i = 0; + + device_for_each_child_node_scoped(dev, child) { + chan = &iio_channels[i]; + + differential = fwnode_property_present(child, "diff-channels"); + if (differential) + ret = fwnode_property_read_u32_array(child, + "diff-channels", + ain, 2); + else + ret = fwnode_property_read_u32(child, "single-channel", + &ain[0]); + + if (ret) + return dev_err_probe(dev, ret, + "Failed to get channel property\n"); + + ret = ads1119_map_analog_inputs_mux(ain[0], ain[1], + differential); + if (ret < 0) + return dev_err_probe(dev, ret, + "Invalid channel value\n"); + + st->channels_cfg[i].mux = ret; + st->channels_cfg[i].gain = ADS1119_DEFAULT_GAIN; + st->channels_cfg[i].datarate = ADS1119_DEFAULT_DATARATE; + + *chan = ads1119_channel; + chan->channel = ain[0]; + chan->address = i; + chan->scan_index = i; + + if (differential) { + chan->channel2 = ain[1]; + chan->differential = 1; + } + + dev_dbg(dev, "channel: index %d, mux %d\n", i, + st->channels_cfg[i].mux); + + i++; + } + + iio_channels[i] = ads1119_ts; + iio_channels[i].address = i; + iio_channels[i].scan_index = i; + + indio_dev->channels = iio_channels; + indio_dev->num_channels = num_channels; + + return 0; +} + +static void ads1119_powerdown(void *data) +{ + struct ads1119_state *st = data; + + i2c_smbus_write_byte(st->client, ADS1119_CMD_POWERDOWN); +} + +static int ads1119_probe(struct i2c_client *client) +{ + struct iio_dev *indio_dev; + struct ads1119_state *st; + struct device *dev = &client->dev; + bool vref_external = true; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return dev_err_probe(dev, -ENOMEM, + "Failed to allocate IIO device\n"); + + st = iio_priv(indio_dev); + st->client = client; + + indio_dev->name = "ads1119"; + indio_dev->info = &ads1119_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + i2c_set_clientdata(client, indio_dev); + + ret = devm_regulator_bulk_get_enable(dev, + ARRAY_SIZE(ads1119_power_supplies), + ads1119_power_supplies); + if (ret) + return dev_err_probe(dev, ret, + "Failed to get and enable supplies\n"); + + st->vref_uV = devm_regulator_get_enable_read_voltage(dev, "vref"); + if (st->vref_uV == -ENODEV) { + vref_external = false; + st->vref_uV = ADS1119_VREF_INTERNAL_VAL; + } else if (st->vref_uV < 0) { + return dev_err_probe(dev, st->vref_uV, "Failed to get vref\n"); + } + + st->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(st->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(st->reset_gpio), + "Failed to get reset gpio\n"); + + ret = ads1119_alloc_and_config_channels(indio_dev); + if (ret) + return ret; + + init_completion(&st->completion); + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, + ads1119_trigger_handler, + &ads1119_buffer_setup_ops); + if (ret) + return dev_err_probe(dev, ret, "Failed to setup IIO buffer\n"); + + if (client->irq > 0) { + ret = devm_request_threaded_irq(dev, client->irq, + ads1119_irq_handler, + NULL, IRQF_TRIGGER_FALLING, + "ads1119", indio_dev); + if (ret) + return dev_err_probe(dev, ret, + "Failed to allocate irq\n"); + + st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", + indio_dev->name, + iio_device_id(indio_dev)); + if (!st->trig) + return dev_err_probe(dev, -ENOMEM, + "Failed to allocate IIO trigger\n"); + + st->trig->ops = &ads1119_trigger_ops; + iio_trigger_set_drvdata(st->trig, indio_dev); + + ret = devm_iio_trigger_register(dev, st->trig); + if (ret) + return dev_err_probe(dev, ret, + "Failed to register IIO trigger\n"); + } + + ret = ads1119_init(st, vref_external); + if (ret) + return dev_err_probe(dev, ret, + "Failed to initialize device\n"); + + pm_runtime_set_autosuspend_delay(dev, ADS1119_SUSPEND_DELAY); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_set_active(dev); + + ret = devm_pm_runtime_enable(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable pm runtime\n"); + + ret = devm_add_action_or_reset(dev, ads1119_powerdown, st); + if (ret) + return dev_err_probe(dev, ret, + "Failed to add powerdown action\n"); + + return devm_iio_device_register(dev, indio_dev); +} + +static int ads1119_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct ads1119_state *st = iio_priv(indio_dev); + + return i2c_smbus_write_byte(st->client, ADS1119_CMD_POWERDOWN); +} + +/* + * The ADS1119 does not require a resume function because it automatically + * powers on after a reset. + * After a power down command, the ADS1119 can still communicate but turns off + * its analog parts. To resume from power down, the device will power up again + * upon receiving a start/sync command. + */ +static DEFINE_RUNTIME_DEV_PM_OPS(ads1119_pm_ops, ads1119_runtime_suspend, + NULL, NULL); + +static const struct of_device_id __maybe_unused ads1119_of_match[] = { + { .compatible = "ti,ads1119" }, + { } +}; +MODULE_DEVICE_TABLE(of, ads1119_of_match); + +static const struct i2c_device_id ads1119_id[] = { + { "ads1119", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ads1119_id); + +static struct i2c_driver ads1119_driver = { + .driver = { + .name = "ads1119", + .of_match_table = ads1119_of_match, + .pm = pm_ptr(&ads1119_pm_ops), + }, + .probe = ads1119_probe, + .id_table = ads1119_id, +}; +module_i2c_driver(ads1119_driver); + +MODULE_AUTHOR("João Paulo Gonçalves <joao.goncalves@toradex.com>"); +MODULE_DESCRIPTION("Texas Instruments ADS1119 ADC Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c index 9440a268a78c..7a79f0cebfbf 100644 --- a/drivers/iio/adc/ti-ads8688.c +++ b/drivers/iio/adc/ti-ads8688.c @@ -65,7 +65,6 @@ struct ads8688_state { struct mutex lock; const struct ads8688_chip_info *chip_info; struct spi_device *spi; - struct regulator *reg; unsigned int vref_mv; enum ads8688_range range[8]; union { @@ -423,28 +422,16 @@ static int ads8688_probe(struct spi_device *spi) st = iio_priv(indio_dev); - st->reg = devm_regulator_get_optional(&spi->dev, "vref"); - if (!IS_ERR(st->reg)) { - ret = regulator_enable(st->reg); - if (ret) - return ret; - - ret = regulator_get_voltage(st->reg); - if (ret < 0) - goto err_regulator_disable; + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); + if (ret < 0 && ret != -ENODEV) + return ret; - st->vref_mv = ret / 1000; - } else { - /* Use internal reference */ - st->vref_mv = ADS8688_VREF_MV; - } + st->vref_mv = ret == -ENODEV ? ADS8688_VREF_MV : ret / 1000; st->chip_info = &ads8688_chip_info_tbl[spi_get_device_id(spi)->driver_data]; spi->mode = SPI_MODE_1; - spi_set_drvdata(spi, indio_dev); - st->spi = spi; indio_dev->name = spi_get_device_id(spi)->name; @@ -457,38 +444,13 @@ static int ads8688_probe(struct spi_device *spi) mutex_init(&st->lock); - ret = iio_triggered_buffer_setup(indio_dev, NULL, ads8688_trigger_handler, NULL); - if (ret < 0) { - dev_err(&spi->dev, "iio triggered buffer setup failed\n"); - goto err_regulator_disable; - } - - ret = iio_device_register(indio_dev); - if (ret) - goto err_buffer_cleanup; - - return 0; - -err_buffer_cleanup: - iio_triggered_buffer_cleanup(indio_dev); - -err_regulator_disable: - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); - - return ret; -} - -static void ads8688_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct ads8688_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL, + ads8688_trigger_handler, NULL); + if (ret < 0) + return dev_err_probe(&spi->dev, ret, + "iio triggered buffer setup failed\n"); - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id ads8688_id[] = { @@ -511,7 +473,6 @@ static struct spi_driver ads8688_driver = { .of_match_table = ads8688_of_match, }, .probe = ads8688_probe, - .remove = ads8688_remove, .id_table = ads8688_id, }; module_spi_driver(ads8688_driver); diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c index aa05f24931f9..f051358d6b50 100644 --- a/drivers/iio/adc/xilinx-ams.c +++ b/drivers/iio/adc/xilinx-ams.c @@ -222,7 +222,7 @@ enum ams_ps_pl_seq { #define PL_SEQ(x) (AMS_PS_SEQ_MAX + (x)) #define AMS_CTRL_SEQ_BASE (AMS_PS_SEQ_MAX * 3) -#define AMS_CHAN_TEMP(_scan_index, _addr) { \ +#define AMS_CHAN_TEMP(_scan_index, _addr, _name) { \ .type = IIO_TEMP, \ .indexed = 1, \ .address = (_addr), \ @@ -232,9 +232,10 @@ enum ams_ps_pl_seq { .event_spec = ams_temp_events, \ .scan_index = _scan_index, \ .num_event_specs = ARRAY_SIZE(ams_temp_events), \ + .datasheet_name = _name, \ } -#define AMS_CHAN_VOLTAGE(_scan_index, _addr, _alarm) { \ +#define AMS_CHAN_VOLTAGE(_scan_index, _addr, _alarm, _name) { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ .address = (_addr), \ @@ -243,21 +244,24 @@ enum ams_ps_pl_seq { .event_spec = (_alarm) ? ams_voltage_events : NULL, \ .scan_index = _scan_index, \ .num_event_specs = (_alarm) ? ARRAY_SIZE(ams_voltage_events) : 0, \ + .datasheet_name = _name, \ } -#define AMS_PS_CHAN_TEMP(_scan_index, _addr) \ - AMS_CHAN_TEMP(PS_SEQ(_scan_index), _addr) -#define AMS_PS_CHAN_VOLTAGE(_scan_index, _addr) \ - AMS_CHAN_VOLTAGE(PS_SEQ(_scan_index), _addr, true) +#define AMS_PS_CHAN_TEMP(_scan_index, _addr, _name) \ + AMS_CHAN_TEMP(PS_SEQ(_scan_index), _addr, _name) +#define AMS_PS_CHAN_VOLTAGE(_scan_index, _addr, _name) \ + AMS_CHAN_VOLTAGE(PS_SEQ(_scan_index), _addr, true, _name) -#define AMS_PL_CHAN_TEMP(_scan_index, _addr) \ - AMS_CHAN_TEMP(PL_SEQ(_scan_index), _addr) -#define AMS_PL_CHAN_VOLTAGE(_scan_index, _addr, _alarm) \ - AMS_CHAN_VOLTAGE(PL_SEQ(_scan_index), _addr, _alarm) +#define AMS_PL_CHAN_TEMP(_scan_index, _addr, _name) \ + AMS_CHAN_TEMP(PL_SEQ(_scan_index), _addr, _name) +#define AMS_PL_CHAN_VOLTAGE(_scan_index, _addr, _alarm, _name) \ + AMS_CHAN_VOLTAGE(PL_SEQ(_scan_index), _addr, _alarm, _name) #define AMS_PL_AUX_CHAN_VOLTAGE(_auxno) \ - AMS_CHAN_VOLTAGE(PL_SEQ(AMS_SEQ(_auxno)), AMS_REG_VAUX(_auxno), false) -#define AMS_CTRL_CHAN_VOLTAGE(_scan_index, _addr) \ - AMS_CHAN_VOLTAGE(PL_SEQ(AMS_SEQ(AMS_SEQ(_scan_index))), _addr, false) + AMS_CHAN_VOLTAGE(PL_SEQ(AMS_SEQ(_auxno)), AMS_REG_VAUX(_auxno), false, \ + "VAUX" #_auxno) +#define AMS_CTRL_CHAN_VOLTAGE(_scan_index, _addr, _name) \ + AMS_CHAN_VOLTAGE(PL_SEQ(AMS_SEQ(AMS_SEQ(_scan_index))), _addr, false, \ + _name) /** * struct ams - This structure contains necessary state for xilinx-ams to operate @@ -505,6 +509,12 @@ static int ams_init_device(struct ams *ams) return 0; } +static int ams_read_label(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, char *label) +{ + return sysfs_emit(label, "%s\n", chan->datasheet_name); +} + static int ams_enable_single_channel(struct ams *ams, unsigned int offset) { u8 channel_num; @@ -1116,37 +1126,37 @@ static const struct iio_event_spec ams_voltage_events[] = { }; static const struct iio_chan_spec ams_ps_channels[] = { - AMS_PS_CHAN_TEMP(AMS_SEQ_TEMP, AMS_TEMP), - AMS_PS_CHAN_TEMP(AMS_SEQ_TEMP_REMOTE, AMS_TEMP_REMOTE), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY1, AMS_SUPPLY1), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY2, AMS_SUPPLY2), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY3, AMS_SUPPLY3), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY4, AMS_SUPPLY4), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY5, AMS_SUPPLY5), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY6, AMS_SUPPLY6), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY7, AMS_SUPPLY7), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY8, AMS_SUPPLY8), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY9, AMS_SUPPLY9), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY10, AMS_SUPPLY10), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_VCCAMS, AMS_VCCAMS), + AMS_PS_CHAN_TEMP(AMS_SEQ_TEMP, AMS_TEMP, "Temp_LPD"), + AMS_PS_CHAN_TEMP(AMS_SEQ_TEMP_REMOTE, AMS_TEMP_REMOTE, "Temp_FPD"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY1, AMS_SUPPLY1, "VCC_PSINTLP"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY2, AMS_SUPPLY2, "VCC_PSINTFP"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY3, AMS_SUPPLY3, "VCC_PSAUX"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY4, AMS_SUPPLY4, "VCC_PSDDR"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY5, AMS_SUPPLY5, "VCC_PSIO3"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY6, AMS_SUPPLY6, "VCC_PSIO0"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY7, AMS_SUPPLY7, "VCC_PSIO1"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY8, AMS_SUPPLY8, "VCC_PSIO2"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY9, AMS_SUPPLY9, "PS_MGTRAVCC"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY10, AMS_SUPPLY10, "PS_MGTRAVTT"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_VCCAMS, AMS_VCCAMS, "VCC_PSADC"), }; static const struct iio_chan_spec ams_pl_channels[] = { - AMS_PL_CHAN_TEMP(AMS_SEQ_TEMP, AMS_TEMP), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY1, AMS_SUPPLY1, true), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY2, AMS_SUPPLY2, true), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VREFP, AMS_VREFP, false), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VREFN, AMS_VREFN, false), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY3, AMS_SUPPLY3, true), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY4, AMS_SUPPLY4, true), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY5, AMS_SUPPLY5, true), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY6, AMS_SUPPLY6, true), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VCCAMS, AMS_VCCAMS, true), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VP_VN, AMS_VP_VN, false), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY7, AMS_SUPPLY7, true), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY8, AMS_SUPPLY8, true), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY9, AMS_SUPPLY9, true), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY10, AMS_SUPPLY10, true), + AMS_PL_CHAN_TEMP(AMS_SEQ_TEMP, AMS_TEMP, "Temp_PL"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY1, AMS_SUPPLY1, true, "VCCINT"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY2, AMS_SUPPLY2, true, "VCCAUX"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VREFP, AMS_VREFP, false, "VREFP"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VREFN, AMS_VREFN, false, "VREFN"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY3, AMS_SUPPLY3, true, "VCCBRAM"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY4, AMS_SUPPLY4, true, "VCC_PSINTLP"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY5, AMS_SUPPLY5, true, "VCC_PSINTFP"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY6, AMS_SUPPLY6, true, "VCC_PSAUX"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VCCAMS, AMS_VCCAMS, true, "VCCAMS"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VP_VN, AMS_VP_VN, false, "VP_VN"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY7, AMS_SUPPLY7, true, "VUser0"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY8, AMS_SUPPLY8, true, "VUser1"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY9, AMS_SUPPLY9, true, "VUser2"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY10, AMS_SUPPLY10, true, "VUser3"), AMS_PL_AUX_CHAN_VOLTAGE(0), AMS_PL_AUX_CHAN_VOLTAGE(1), AMS_PL_AUX_CHAN_VOLTAGE(2), @@ -1166,13 +1176,13 @@ static const struct iio_chan_spec ams_pl_channels[] = { }; static const struct iio_chan_spec ams_ctrl_channels[] = { - AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCC_PSPLL, AMS_VCC_PSPLL0), - AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCC_PSBATT, AMS_VCC_PSPLL3), - AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCINT, AMS_VCCINT), - AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCBRAM, AMS_VCCBRAM), - AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCAUX, AMS_VCCAUX), - AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_PSDDRPLL, AMS_PSDDRPLL), - AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_INTDDR, AMS_PSINTFPDDR), + AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCC_PSPLL, AMS_VCC_PSPLL0, "VCC_PSPLL"), + AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCC_PSBATT, AMS_VCC_PSPLL3, "VCC_PSBATT"), + AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCINT, AMS_VCCINT, "VCCINT"), + AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCBRAM, AMS_VCCBRAM, "VCCBRAM"), + AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCAUX, AMS_VCCAUX, "VCCAUX"), + AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_PSDDRPLL, AMS_PSDDRPLL, "VCC_PSDDR_PLL"), + AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_INTDDR, AMS_PSINTFPDDR, "VCC_PSINTFP_DDR"), }; static int ams_get_ext_chan(struct fwnode_handle *chan_node, @@ -1336,6 +1346,7 @@ static int ams_parse_firmware(struct iio_dev *indio_dev) } static const struct iio_info iio_ams_info = { + .read_label = ams_read_label, .read_raw = &ams_read_raw, .read_event_config = &ams_read_event_config, .write_event_config = &ams_write_event_config, diff --git a/drivers/iio/buffer/industrialio-buffer-dma.c b/drivers/iio/buffer/industrialio-buffer-dma.c index 13b1a858969e..647f417a045e 100644 --- a/drivers/iio/buffer/industrialio-buffer-dma.c +++ b/drivers/iio/buffer/industrialio-buffer-dma.c @@ -4,6 +4,8 @@ * Author: Lars-Peter Clausen <lars@metafoo.de> */ +#include <linux/atomic.h> +#include <linux/cleanup.h> #include <linux/slab.h> #include <linux/kernel.h> #include <linux/module.h> @@ -14,6 +16,8 @@ #include <linux/poll.h> #include <linux/iio/buffer_impl.h> #include <linux/iio/buffer-dma.h> +#include <linux/dma-buf.h> +#include <linux/dma-fence.h> #include <linux/dma-mapping.h> #include <linux/sizes.h> @@ -94,13 +98,18 @@ static void iio_buffer_block_release(struct kref *kref) { struct iio_dma_buffer_block *block = container_of(kref, struct iio_dma_buffer_block, kref); + struct iio_dma_buffer_queue *queue = block->queue; - WARN_ON(block->state != IIO_BLOCK_STATE_DEAD); + WARN_ON(block->fileio && block->state != IIO_BLOCK_STATE_DEAD); - dma_free_coherent(block->queue->dev, PAGE_ALIGN(block->size), - block->vaddr, block->phys_addr); + if (block->fileio) { + dma_free_coherent(queue->dev, PAGE_ALIGN(block->size), + block->vaddr, block->phys_addr); + } else { + atomic_dec(&queue->num_dmabufs); + } - iio_buffer_put(&block->queue->buffer); + iio_buffer_put(&queue->buffer); kfree(block); } @@ -163,7 +172,7 @@ static struct iio_dma_buffer_queue *iio_buffer_to_queue(struct iio_buffer *buf) } static struct iio_dma_buffer_block *iio_dma_buffer_alloc_block( - struct iio_dma_buffer_queue *queue, size_t size) + struct iio_dma_buffer_queue *queue, size_t size, bool fileio) { struct iio_dma_buffer_block *block; @@ -171,13 +180,16 @@ static struct iio_dma_buffer_block *iio_dma_buffer_alloc_block( if (!block) return NULL; - block->vaddr = dma_alloc_coherent(queue->dev, PAGE_ALIGN(size), - &block->phys_addr, GFP_KERNEL); - if (!block->vaddr) { - kfree(block); - return NULL; + if (fileio) { + block->vaddr = dma_alloc_coherent(queue->dev, PAGE_ALIGN(size), + &block->phys_addr, GFP_KERNEL); + if (!block->vaddr) { + kfree(block); + return NULL; + } } + block->fileio = fileio; block->size = size; block->state = IIO_BLOCK_STATE_DONE; block->queue = queue; @@ -186,6 +198,9 @@ static struct iio_dma_buffer_block *iio_dma_buffer_alloc_block( iio_buffer_get(&queue->buffer); + if (!fileio) + atomic_inc(&queue->num_dmabufs); + return block; } @@ -218,13 +233,20 @@ void iio_dma_buffer_block_done(struct iio_dma_buffer_block *block) { struct iio_dma_buffer_queue *queue = block->queue; unsigned long flags; + bool cookie; + + cookie = dma_fence_begin_signalling(); spin_lock_irqsave(&queue->list_lock, flags); _iio_dma_buffer_block_done(block); spin_unlock_irqrestore(&queue->list_lock, flags); + if (!block->fileio) + iio_buffer_signal_dmabuf_done(block->fence, 0); + iio_buffer_block_put_atomic(block); iio_dma_buffer_queue_wake(queue); + dma_fence_end_signalling(cookie); } EXPORT_SYMBOL_GPL(iio_dma_buffer_block_done); @@ -243,17 +265,27 @@ void iio_dma_buffer_block_list_abort(struct iio_dma_buffer_queue *queue, { struct iio_dma_buffer_block *block, *_block; unsigned long flags; + bool cookie; + + cookie = dma_fence_begin_signalling(); spin_lock_irqsave(&queue->list_lock, flags); list_for_each_entry_safe(block, _block, list, head) { list_del(&block->head); block->bytes_used = 0; _iio_dma_buffer_block_done(block); + + if (!block->fileio) + iio_buffer_signal_dmabuf_done(block->fence, -EINTR); iio_buffer_block_put_atomic(block); } spin_unlock_irqrestore(&queue->list_lock, flags); + if (queue->fileio.enabled) + queue->fileio.enabled = false; + iio_dma_buffer_queue_wake(queue); + dma_fence_end_signalling(cookie); } EXPORT_SYMBOL_GPL(iio_dma_buffer_block_list_abort); @@ -273,6 +305,16 @@ static bool iio_dma_block_reusable(struct iio_dma_buffer_block *block) } } +static bool iio_dma_buffer_can_use_fileio(struct iio_dma_buffer_queue *queue) +{ + /* + * Note that queue->num_dmabufs cannot increase while the queue is + * locked, it can only decrease, so it does not race against + * iio_dma_buffer_alloc_block(). + */ + return queue->fileio.enabled || !atomic_read(&queue->num_dmabufs); +} + /** * iio_dma_buffer_request_update() - DMA buffer request_update callback * @buffer: The buffer which to request an update @@ -299,6 +341,12 @@ int iio_dma_buffer_request_update(struct iio_buffer *buffer) mutex_lock(&queue->lock); + queue->fileio.enabled = iio_dma_buffer_can_use_fileio(queue); + + /* If DMABUFs were created, disable fileio interface */ + if (!queue->fileio.enabled) + goto out_unlock; + /* Allocations are page aligned */ if (PAGE_ALIGN(queue->fileio.block_size) == PAGE_ALIGN(size)) try_reuse = true; @@ -339,7 +387,7 @@ int iio_dma_buffer_request_update(struct iio_buffer *buffer) } if (!block) { - block = iio_dma_buffer_alloc_block(queue, size); + block = iio_dma_buffer_alloc_block(queue, size, true); if (!block) { ret = -ENOMEM; goto out_unlock; @@ -412,8 +460,12 @@ static void iio_dma_buffer_submit_block(struct iio_dma_buffer_queue *queue, block->state = IIO_BLOCK_STATE_ACTIVE; iio_buffer_block_get(block); + ret = queue->ops->submit(queue, block); if (ret) { + if (!block->fileio) + iio_buffer_signal_dmabuf_done(block->fence, ret); + /* * This is a bit of a problem and there is not much we can do * other then wait for the buffer to be disabled and re-enabled @@ -646,6 +698,110 @@ size_t iio_dma_buffer_usage(struct iio_buffer *buf) } EXPORT_SYMBOL_GPL(iio_dma_buffer_usage); +struct iio_dma_buffer_block * +iio_dma_buffer_attach_dmabuf(struct iio_buffer *buffer, + struct dma_buf_attachment *attach) +{ + struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer); + struct iio_dma_buffer_block *block; + + guard(mutex)(&queue->lock); + + /* + * If the buffer is enabled and in fileio mode new blocks can't be + * allocated. + */ + if (queue->fileio.enabled) + return ERR_PTR(-EBUSY); + + block = iio_dma_buffer_alloc_block(queue, attach->dmabuf->size, false); + if (!block) + return ERR_PTR(-ENOMEM); + + /* Free memory that might be in use for fileio mode */ + iio_dma_buffer_fileio_free(queue); + + return block; +} +EXPORT_SYMBOL_GPL(iio_dma_buffer_attach_dmabuf); + +void iio_dma_buffer_detach_dmabuf(struct iio_buffer *buffer, + struct iio_dma_buffer_block *block) +{ + block->state = IIO_BLOCK_STATE_DEAD; + iio_buffer_block_put_atomic(block); +} +EXPORT_SYMBOL_GPL(iio_dma_buffer_detach_dmabuf); + +static int iio_dma_can_enqueue_block(struct iio_dma_buffer_block *block) +{ + struct iio_dma_buffer_queue *queue = block->queue; + + /* If in fileio mode buffers can't be enqueued. */ + if (queue->fileio.enabled) + return -EBUSY; + + switch (block->state) { + case IIO_BLOCK_STATE_QUEUED: + return -EPERM; + case IIO_BLOCK_STATE_ACTIVE: + case IIO_BLOCK_STATE_DEAD: + return -EBUSY; + case IIO_BLOCK_STATE_DONE: + break; + } + + return 0; +} + +int iio_dma_buffer_enqueue_dmabuf(struct iio_buffer *buffer, + struct iio_dma_buffer_block *block, + struct dma_fence *fence, + struct sg_table *sgt, + size_t size, bool cyclic) +{ + struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer); + bool cookie; + int ret; + + WARN_ON(!mutex_is_locked(&queue->lock)); + + cookie = dma_fence_begin_signalling(); + + ret = iio_dma_can_enqueue_block(block); + if (ret < 0) + goto out_end_signalling; + + block->bytes_used = size; + block->cyclic = cyclic; + block->sg_table = sgt; + block->fence = fence; + + iio_dma_buffer_enqueue(queue, block); + +out_end_signalling: + dma_fence_end_signalling(cookie); + + return ret; +} +EXPORT_SYMBOL_GPL(iio_dma_buffer_enqueue_dmabuf); + +void iio_dma_buffer_lock_queue(struct iio_buffer *buffer) +{ + struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer); + + mutex_lock(&queue->lock); +} +EXPORT_SYMBOL_GPL(iio_dma_buffer_lock_queue); + +void iio_dma_buffer_unlock_queue(struct iio_buffer *buffer) +{ + struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer); + + mutex_unlock(&queue->lock); +} +EXPORT_SYMBOL_GPL(iio_dma_buffer_unlock_queue); + /** * iio_dma_buffer_set_bytes_per_datum() - DMA buffer set_bytes_per_datum callback * @buffer: Buffer to set the bytes-per-datum for diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index 918f6f8d65b6..12aa1412dfa0 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -65,25 +65,62 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, iio_buffer_to_dmaengine_buffer(&queue->buffer); struct dma_async_tx_descriptor *desc; enum dma_transfer_direction dma_dir; + struct scatterlist *sgl; + struct dma_vec *vecs; size_t max_size; dma_cookie_t cookie; + size_t len_total; + unsigned int i; + int nents; max_size = min(block->size, dmaengine_buffer->max_size); max_size = round_down(max_size, dmaengine_buffer->align); - if (queue->buffer.direction == IIO_BUFFER_DIRECTION_IN) { - block->bytes_used = max_size; + if (queue->buffer.direction == IIO_BUFFER_DIRECTION_IN) dma_dir = DMA_DEV_TO_MEM; - } else { + else dma_dir = DMA_MEM_TO_DEV; - } - if (!block->bytes_used || block->bytes_used > max_size) - return -EINVAL; + if (block->sg_table) { + sgl = block->sg_table->sgl; + nents = sg_nents_for_len(sgl, block->bytes_used); + if (nents < 0) + return nents; + + vecs = kmalloc_array(nents, sizeof(*vecs), GFP_ATOMIC); + if (!vecs) + return -ENOMEM; + + len_total = block->bytes_used; + + for (i = 0; i < nents; i++) { + vecs[i].addr = sg_dma_address(sgl); + vecs[i].len = min(sg_dma_len(sgl), len_total); + len_total -= vecs[i].len; + + sgl = sg_next(sgl); + } - desc = dmaengine_prep_slave_single(dmaengine_buffer->chan, - block->phys_addr, block->bytes_used, dma_dir, - DMA_PREP_INTERRUPT); + desc = dmaengine_prep_peripheral_dma_vec(dmaengine_buffer->chan, + vecs, nents, dma_dir, + DMA_PREP_INTERRUPT); + kfree(vecs); + } else { + max_size = min(block->size, dmaengine_buffer->max_size); + max_size = round_down(max_size, dmaengine_buffer->align); + + if (queue->buffer.direction == IIO_BUFFER_DIRECTION_IN) + block->bytes_used = max_size; + + if (!block->bytes_used || block->bytes_used > max_size) + return -EINVAL; + + desc = dmaengine_prep_slave_single(dmaengine_buffer->chan, + block->phys_addr, + block->bytes_used, + dma_dir, + DMA_PREP_INTERRUPT); + } if (!desc) return -ENOMEM; @@ -133,6 +170,13 @@ static const struct iio_buffer_access_funcs iio_dmaengine_buffer_ops = { .space_available = iio_dma_buffer_usage, .release = iio_dmaengine_buffer_release, + .enqueue_dmabuf = iio_dma_buffer_enqueue_dmabuf, + .attach_dmabuf = iio_dma_buffer_attach_dmabuf, + .detach_dmabuf = iio_dma_buffer_detach_dmabuf, + + .lock_queue = iio_dma_buffer_lock_queue, + .unlock_queue = iio_dma_buffer_unlock_queue, + .modes = INDIO_BUFFER_HARDWARE, .flags = INDIO_BUFFER_FLAG_FIXED_WATERMARK, }; diff --git a/drivers/iio/common/scmi_sensors/scmi_iio.c b/drivers/iio/common/scmi_sensors/scmi_iio.c index 0c2caf3570db..7190eaede7fb 100644 --- a/drivers/iio/common/scmi_sensors/scmi_iio.c +++ b/drivers/iio/common/scmi_sensors/scmi_iio.c @@ -626,12 +626,10 @@ scmi_alloc_iiodev(struct scmi_device *sdev, SCMI_PROTOCOL_SENSOR, SCMI_EVENT_SENSOR_UPDATE, &sensor->sensor_info->id, &sensor->sensor_update_nb); - if (ret) { - dev_err(&iiodev->dev, - "Error in registering sensor update notifier for sensor %s err %d", - sensor->sensor_info->name, ret); - return ERR_PTR(ret); - } + if (ret) + return dev_err_ptr_probe(&iiodev->dev, ret, + "Error in registering sensor update notifier for sensor %s\n", + sensor->sensor_info->name); scmi_iio_set_timestamp_channel(&iio_channels[i], i); iiodev->channels = iio_channels; @@ -653,10 +651,9 @@ static int scmi_iio_dev_probe(struct scmi_device *sdev) return -ENODEV; sensor_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_SENSOR, &ph); - if (IS_ERR(sensor_ops)) { - dev_err(dev, "SCMI device has no sensor interface\n"); - return PTR_ERR(sensor_ops); - } + if (IS_ERR(sensor_ops)) + return dev_err_probe(dev, PTR_ERR(sensor_ops), + "SCMI device has no sensor interface\n"); nr_sensors = sensor_ops->count_get(ph); if (!nr_sensors) { @@ -667,8 +664,8 @@ static int scmi_iio_dev_probe(struct scmi_device *sdev) for (i = 0; i < nr_sensors; i++) { sensor_info = sensor_ops->info_get(ph, i); if (!sensor_info) { - dev_err(dev, "SCMI sensor %d has missing info\n", i); - return -EINVAL; + return dev_err_probe(dev, -EINVAL, + "SCMI sensor %d has missing info\n", i); } /* This driver only supports 3-axis accel and gyro, skipping other sensors */ @@ -683,29 +680,25 @@ static int scmi_iio_dev_probe(struct scmi_device *sdev) scmi_iio_dev = scmi_alloc_iiodev(sdev, sensor_ops, ph, sensor_info); if (IS_ERR(scmi_iio_dev)) { - dev_err(dev, - "failed to allocate IIO device for sensor %s: %ld\n", - sensor_info->name, PTR_ERR(scmi_iio_dev)); - return PTR_ERR(scmi_iio_dev); + return dev_err_probe(dev, PTR_ERR(scmi_iio_dev), + "failed to allocate IIO device for sensor %s\n", + sensor_info->name); } err = devm_iio_kfifo_buffer_setup(&scmi_iio_dev->dev, scmi_iio_dev, &scmi_iio_buffer_ops); if (err < 0) { - dev_err(dev, - "IIO buffer setup error at sensor %s: %d\n", - sensor_info->name, err); - return err; + return dev_err_probe(dev, err, + "IIO buffer setup error at sensor %s\n", + sensor_info->name); } err = devm_iio_device_register(dev, scmi_iio_dev); - if (err) { - dev_err(dev, - "IIO device registration failed at sensor %s: %d\n", - sensor_info->name, err); - return err; - } + if (err) + return dev_err_probe(dev, err, + "IIO device registration failed at sensor %s\n", + sensor_info->name); } return err; } diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index c77d7bdcc121..c69399ac6657 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -606,10 +606,9 @@ int st_sensors_verify_id(struct iio_dev *indio_dev) } if (sdata->sensor_settings->wai != wai) { - dev_err(&indio_dev->dev, + dev_warn(&indio_dev->dev, "%s: WhoAmI mismatch (0x%x).\n", indio_dev->name, wai); - return -EINVAL; } } diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c index ddc6c262f801..bd37d304ca70 100644 --- a/drivers/iio/dac/ad3552r.c +++ b/drivers/iio/dac/ad3552r.c @@ -857,15 +857,9 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac, return 0; } -static void ad3552r_reg_disable(void *reg) -{ - regulator_disable(reg); -} - static int ad3552r_configure_device(struct ad3552r_desc *dac) { struct device *dev = &dac->spi->dev; - struct regulator *vref; int err, cnt = 0, voltage, delta = 100000; u32 vals[2], val, ch; @@ -874,30 +868,16 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) return dev_err_probe(dev, PTR_ERR(dac->gpio_ldac), "Error getting gpio ldac"); - vref = devm_regulator_get_optional(dev, "vref"); - if (IS_ERR(vref)) { - if (PTR_ERR(vref) != -ENODEV) - return dev_err_probe(dev, PTR_ERR(vref), - "Error getting vref"); + voltage = devm_regulator_get_enable_read_voltage(dev, "vref"); + if (voltage < 0 && voltage != -ENODEV) + return dev_err_probe(dev, voltage, "Error getting vref voltage\n"); + if (voltage == -ENODEV) { if (device_property_read_bool(dev, "adi,vref-out-en")) val = AD3552R_INTERNAL_VREF_PIN_2P5V; else val = AD3552R_INTERNAL_VREF_PIN_FLOATING; } else { - err = regulator_enable(vref); - if (err) { - dev_err(dev, "Failed to enable external vref supply\n"); - return err; - } - - err = devm_add_action_or_reset(dev, ad3552r_reg_disable, vref); - if (err) { - regulator_disable(vref); - return err; - } - - voltage = regulator_get_voltage(vref); if (voltage > 2500000 + delta || voltage < 2500000 - delta) { dev_warn(dev, "vref-supply must be 2.5V"); return -EINVAL; diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c index 880d83a014a1..6d56428e623d 100644 --- a/drivers/iio/dac/adi-axi-dac.c +++ b/drivers/iio/dac/adi-axi-dac.c @@ -545,7 +545,8 @@ static int axi_dac_probe(struct platform_device *pdev) clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(clk)) - return PTR_ERR(clk); + return dev_err_probe(&pdev->dev, PTR_ERR(clk), + "failed to get clock\n"); base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) @@ -555,7 +556,8 @@ static int axi_dac_probe(struct platform_device *pdev) st->regmap = devm_regmap_init_mmio(&pdev->dev, base, &axi_dac_regmap_config); if (IS_ERR(st->regmap)) - return PTR_ERR(st->regmap); + return dev_err_probe(&pdev->dev, PTR_ERR(st->regmap), + "failed to init register map\n"); /* * Force disable the core. Up to the frontend to enable us. And we can @@ -601,7 +603,8 @@ static int axi_dac_probe(struct platform_device *pdev) mutex_init(&st->lock); ret = devm_iio_backend_register(&pdev->dev, &axi_dac_generic, st); if (ret) - return ret; + return dev_err_probe(&pdev->dev, ret, + "failed to register iio backend\n"); dev_info(&pdev->dev, "AXI DAC IP core (%d.%.2d.%c) probed\n", ADI_AXI_PCORE_VER_MAJOR(ver), diff --git a/drivers/iio/dac/ltc2688.c b/drivers/iio/dac/ltc2688.c index c4b1ba30f935..af50d2a95898 100644 --- a/drivers/iio/dac/ltc2688.c +++ b/drivers/iio/dac/ltc2688.c @@ -860,9 +860,8 @@ static int ltc2688_setup(struct ltc2688_state *st, struct regulator *vref) /* bring device out of reset */ gpiod_set_value_cansleep(gpio, 0); } else { - ret = regmap_update_bits(st->regmap, LTC2688_CMD_CONFIG, - LTC2688_CONFIG_RST, - LTC2688_CONFIG_RST); + ret = regmap_set_bits(st->regmap, LTC2688_CMD_CONFIG, + LTC2688_CONFIG_RST); if (ret) return ret; } diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c index e150ac729154..2d567073996b 100644 --- a/drivers/iio/dac/stm32-dac-core.c +++ b/drivers/iio/dac/stm32-dac-core.c @@ -200,9 +200,8 @@ static int stm32_dac_core_resume(struct device *dev) if (priv->common.hfsel) { /* restore hfsel (maybe lost under low power state) */ - ret = regmap_update_bits(priv->common.regmap, STM32_DAC_CR, - STM32H7_DAC_CR_HFSEL, - STM32H7_DAC_CR_HFSEL); + ret = regmap_set_bits(priv->common.regmap, STM32_DAC_CR, + STM32H7_DAC_CR_HFSEL); if (ret) return ret; } diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c index 4abf80f75ef5..e13e64a5164c 100644 --- a/drivers/iio/frequency/adf4350.c +++ b/drivers/iio/frequency/adf4350.c @@ -19,6 +19,7 @@ #include <linux/gpio/consumer.h> #include <asm/div64.h> #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -36,6 +37,9 @@ struct adf4350_state { struct gpio_desc *lock_detect_gpiod; struct adf4350_platform_data *pdata; struct clk *clk; + struct clk *clkout; + const char *clk_out_name; + struct clk_hw hw; unsigned long clkin; unsigned long chspc; /* Channel Spacing */ unsigned long fpfd; /* Phase Frequency Detector */ @@ -61,6 +65,8 @@ struct adf4350_state { __be32 val __aligned(IIO_DMA_MINALIGN); }; +#define to_adf4350_state(_hw) container_of(_hw, struct adf4350_state, hw) + static struct adf4350_platform_data default_pdata = { .channel_spacing = 10000, .r2_user_settings = ADF4350_REG2_PD_POLARITY_POS | @@ -381,6 +387,113 @@ static const struct iio_info adf4350_info = { .debugfs_reg_access = &adf4350_reg_access, }; +static void adf4350_clk_del_provider(void *data) +{ + struct adf4350_state *st = data; + + of_clk_del_provider(st->spi->dev.of_node); +} + +static unsigned long adf4350_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct adf4350_state *st = to_adf4350_state(hw); + unsigned long long tmp; + + tmp = (u64)(st->r0_int * st->r1_mod + st->r0_fract) * st->fpfd; + do_div(tmp, st->r1_mod * (1 << st->r4_rf_div_sel)); + + return tmp; +} + +static int adf4350_clk_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct adf4350_state *st = to_adf4350_state(hw); + + if (parent_rate == 0 || parent_rate > ADF4350_MAX_FREQ_REFIN) + return -EINVAL; + + st->clkin = parent_rate; + + return adf4350_set_freq(st, rate); +} + +static int adf4350_clk_prepare(struct clk_hw *hw) +{ + struct adf4350_state *st = to_adf4350_state(hw); + + st->regs[ADF4350_REG2] &= ~ADF4350_REG2_POWER_DOWN_EN; + + return adf4350_sync_config(st); +} + +static void adf4350_clk_unprepare(struct clk_hw *hw) +{ + struct adf4350_state *st = to_adf4350_state(hw); + + st->regs[ADF4350_REG2] |= ADF4350_REG2_POWER_DOWN_EN; + + adf4350_sync_config(st); +} + +static int adf4350_clk_is_enabled(struct clk_hw *hw) +{ + struct adf4350_state *st = to_adf4350_state(hw); + + return (st->regs[ADF4350_REG2] & ADF4350_REG2_POWER_DOWN_EN); +} + +static const struct clk_ops adf4350_clk_ops = { + .recalc_rate = adf4350_clk_recalc_rate, + .set_rate = adf4350_clk_set_rate, + .prepare = adf4350_clk_prepare, + .unprepare = adf4350_clk_unprepare, + .is_enabled = adf4350_clk_is_enabled, +}; + +static int adf4350_clk_register(struct adf4350_state *st) +{ + struct spi_device *spi = st->spi; + struct clk_init_data init; + struct clk *clk; + const char *parent_name; + int ret; + + if (!device_property_present(&spi->dev, "#clock-cells")) + return 0; + + if (device_property_read_string(&spi->dev, "clock-output-names", &init.name)) { + init.name = devm_kasprintf(&spi->dev, GFP_KERNEL, "%s-clk", + fwnode_get_name(dev_fwnode(&spi->dev))); + if (!init.name) + return -ENOMEM; + } + + parent_name = of_clk_get_parent_name(spi->dev.of_node, 0); + if (!parent_name) + return -EINVAL; + + init.ops = &adf4350_clk_ops; + init.parent_names = &parent_name; + init.num_parents = 1; + init.flags = CLK_SET_RATE_PARENT; + + st->hw.init = &init; + clk = devm_clk_register(&spi->dev, &st->hw); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + ret = of_clk_add_provider(spi->dev.of_node, of_clk_src_simple_get, clk); + if (ret) + return ret; + + st->clkout = clk; + + return devm_add_action_or_reset(&spi->dev, adf4350_clk_del_provider, st); +} + static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev) { struct adf4350_platform_data *pdata; @@ -522,8 +635,6 @@ static int adf4350_probe(struct spi_device *spi) indio_dev->info = &adf4350_info; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = &adf4350_chan; - indio_dev->num_channels = 1; mutex_init(&st->lock); @@ -551,6 +662,15 @@ static int adf4350_probe(struct spi_device *spi) return ret; } + ret = adf4350_clk_register(st); + if (ret) + return ret; + + if (!st->clkout) { + indio_dev->channels = &adf4350_chan; + indio_dev->num_channels = 1; + } + ret = devm_add_action_or_reset(&spi->dev, adf4350_power_down, indio_dev); if (ret) return dev_err_probe(&spi->dev, ret, diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c index c95cf41be34b..da83adc684d0 100644 --- a/drivers/iio/gyro/adis16136.c +++ b/drivers/iio/gyro/adis16136.c @@ -221,13 +221,12 @@ static ssize_t adis16136_read_frequency(struct device *dev, unsigned int freq; int ret; - adis_dev_lock(&adis16136->adis); + adis_dev_auto_lock(&adis16136->adis); ret = __adis16136_get_freq(adis16136, &freq); - adis_dev_unlock(&adis16136->adis); if (ret) return ret; - return sprintf(buf, "%d\n", freq); + return sysfs_emit(buf, "%d\n", freq); } static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, @@ -251,21 +250,17 @@ static int adis16136_set_filter(struct iio_dev *indio_dev, int val) unsigned int freq; int i, ret; - adis_dev_lock(&adis16136->adis); + adis_dev_auto_lock(&adis16136->adis); ret = __adis16136_get_freq(adis16136, &freq); if (ret) - goto out_unlock; + return ret; for (i = ARRAY_SIZE(adis16136_3db_divisors) - 1; i >= 1; i--) { if (freq / adis16136_3db_divisors[i] >= val) break; } - ret = __adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i); -out_unlock: - adis_dev_unlock(&adis16136->adis); - - return ret; + return __adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i); } static int adis16136_get_filter(struct iio_dev *indio_dev, int *val) @@ -275,23 +270,20 @@ static int adis16136_get_filter(struct iio_dev *indio_dev, int *val) uint16_t val16; int ret; - adis_dev_lock(&adis16136->adis); + adis_dev_auto_lock(&adis16136->adis); ret = __adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, &val16); if (ret) - goto err_unlock; + return ret; ret = __adis16136_get_freq(adis16136, &freq); if (ret) - goto err_unlock; + return ret; *val = freq / adis16136_3db_divisors[val16 & 0x07]; -err_unlock: - adis_dev_unlock(&adis16136->adis); - - return ret ? ret : IIO_VAL_INT; + return IIO_VAL_INT; } static int adis16136_read_raw(struct iio_dev *indio_dev, diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c index 112d635b7dfd..495b64a27061 100644 --- a/drivers/iio/gyro/adis16260.c +++ b/drivers/iio/gyro/adis16260.c @@ -270,7 +270,6 @@ static int adis16260_write_raw(struct iio_dev *indio_dev, { struct adis16260 *adis16260 = iio_priv(indio_dev); struct adis *adis = &adis16260->adis; - int ret; u8 addr; u8 t; @@ -288,7 +287,6 @@ static int adis16260_write_raw(struct iio_dev *indio_dev, addr = adis16260_addresses[chan->scan_index][1]; return adis_write_reg_16(adis, addr, val); case IIO_CHAN_INFO_SAMP_FREQ: - adis_dev_lock(adis); if (spi_get_device_id(adis->spi)->driver_data) t = 256 / val; else @@ -298,15 +296,14 @@ static int adis16260_write_raw(struct iio_dev *indio_dev, t = ADIS16260_SMPL_PRD_DIV_MASK; else if (t > 0) t--; - - if (t >= 0x0A) - adis->spi->max_speed_hz = ADIS16260_SPI_SLOW; - else - adis->spi->max_speed_hz = ADIS16260_SPI_FAST; - ret = __adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t); - - adis_dev_unlock(adis); - return ret; + adis_dev_auto_scoped_lock(adis) { + if (t >= 0x0A) + adis->spi->max_speed_hz = ADIS16260_SPI_SLOW; + else + adis->spi->max_speed_hz = ADIS16260_SPI_FAST; + return __adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t); + } + unreachable(); } return -EINVAL; } diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c index 0e2eb0e98235..10728d5ccae3 100644 --- a/drivers/iio/gyro/bmg160_core.c +++ b/drivers/iio/gyro/bmg160_core.c @@ -285,8 +285,8 @@ static int bmg160_chip_init(struct bmg160_data *data) data->slope_thres = val; /* Set default interrupt mode */ - ret = regmap_update_bits(data->regmap, BMG160_REG_INT_EN_1, - BMG160_INT1_BIT_OD, 0); + ret = regmap_clear_bits(data->regmap, BMG160_REG_INT_EN_1, + BMG160_INT1_BIT_OD); if (ret < 0) { dev_err(dev, "Error updating bits in reg_int_en_1\n"); return ret; diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c index a791ba3a693a..35af68b41408 100644 --- a/drivers/iio/gyro/mpu3050-core.c +++ b/drivers/iio/gyro/mpu3050-core.c @@ -197,8 +197,8 @@ static int mpu3050_start_sampling(struct mpu3050 *mpu3050) int i; /* Reset */ - ret = regmap_update_bits(mpu3050->map, MPU3050_PWR_MGM, - MPU3050_PWR_MGM_RESET, MPU3050_PWR_MGM_RESET); + ret = regmap_set_bits(mpu3050->map, MPU3050_PWR_MGM, + MPU3050_PWR_MGM_RESET); if (ret) return ret; @@ -513,12 +513,9 @@ static irqreturn_t mpu3050_trigger_handler(int irq, void *p) "FIFO overflow! Emptying and resetting FIFO\n"); fifo_overflow = true; /* Reset and enable the FIFO */ - ret = regmap_update_bits(mpu3050->map, - MPU3050_USR_CTRL, - MPU3050_USR_CTRL_FIFO_EN | - MPU3050_USR_CTRL_FIFO_RST, - MPU3050_USR_CTRL_FIFO_EN | - MPU3050_USR_CTRL_FIFO_RST); + ret = regmap_set_bits(mpu3050->map, MPU3050_USR_CTRL, + MPU3050_USR_CTRL_FIFO_EN | + MPU3050_USR_CTRL_FIFO_RST); if (ret) { dev_info(mpu3050->dev, "error resetting FIFO\n"); goto out_trigger_unlock; @@ -799,10 +796,8 @@ static int mpu3050_hw_init(struct mpu3050 *mpu3050) u64 otp; /* Reset */ - ret = regmap_update_bits(mpu3050->map, - MPU3050_PWR_MGM, - MPU3050_PWR_MGM_RESET, - MPU3050_PWR_MGM_RESET); + ret = regmap_set_bits(mpu3050->map, MPU3050_PWR_MGM, + MPU3050_PWR_MGM_RESET); if (ret) return ret; @@ -872,8 +867,8 @@ static int mpu3050_power_up(struct mpu3050 *mpu3050) msleep(200); /* Take device out of sleep mode */ - ret = regmap_update_bits(mpu3050->map, MPU3050_PWR_MGM, - MPU3050_PWR_MGM_SLEEP, 0); + ret = regmap_clear_bits(mpu3050->map, MPU3050_PWR_MGM, + MPU3050_PWR_MGM_SLEEP); if (ret) { regulator_bulk_disable(ARRAY_SIZE(mpu3050->regs), mpu3050->regs); dev_err(mpu3050->dev, "error setting power mode\n"); @@ -895,8 +890,8 @@ static int mpu3050_power_down(struct mpu3050 *mpu3050) * then we would be wasting power unless we go to sleep mode * first. */ - ret = regmap_update_bits(mpu3050->map, MPU3050_PWR_MGM, - MPU3050_PWR_MGM_SLEEP, MPU3050_PWR_MGM_SLEEP); + ret = regmap_set_bits(mpu3050->map, MPU3050_PWR_MGM, + MPU3050_PWR_MGM_SLEEP); if (ret) dev_err(mpu3050->dev, "error putting to sleep\n"); @@ -997,11 +992,9 @@ static int mpu3050_drdy_trigger_set_state(struct iio_trigger *trig, return ret; /* Reset and enable the FIFO */ - ret = regmap_update_bits(mpu3050->map, MPU3050_USR_CTRL, - MPU3050_USR_CTRL_FIFO_EN | - MPU3050_USR_CTRL_FIFO_RST, - MPU3050_USR_CTRL_FIFO_EN | - MPU3050_USR_CTRL_FIFO_RST); + ret = regmap_set_bits(mpu3050->map, MPU3050_USR_CTRL, + MPU3050_USR_CTRL_FIFO_EN | + MPU3050_USR_CTRL_FIFO_RST); if (ret) return ret; diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index 1dbe48dae74e..52326dc521ac 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -422,9 +422,8 @@ static int afe4403_suspend(struct device *dev) struct afe4403_data *afe = iio_priv(indio_dev); int ret; - ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2, - AFE440X_CONTROL2_PDN_AFE, - AFE440X_CONTROL2_PDN_AFE); + ret = regmap_set_bits(afe->regmap, AFE440X_CONTROL2, + AFE440X_CONTROL2_PDN_AFE); if (ret) return ret; @@ -449,8 +448,8 @@ static int afe4403_resume(struct device *dev) return ret; } - ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2, - AFE440X_CONTROL2_PDN_AFE, 0); + ret = regmap_clear_bits(afe->regmap, AFE440X_CONTROL2, + AFE440X_CONTROL2_PDN_AFE); if (ret) return ret; diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index 390fbb6effaf..7f69baa1ed53 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -430,9 +430,8 @@ static int afe4404_suspend(struct device *dev) struct afe4404_data *afe = iio_priv(indio_dev); int ret; - ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2, - AFE440X_CONTROL2_PDN_AFE, - AFE440X_CONTROL2_PDN_AFE); + ret = regmap_set_bits(afe->regmap, AFE440X_CONTROL2, + AFE440X_CONTROL2_PDN_AFE); if (ret) return ret; @@ -457,8 +456,8 @@ static int afe4404_resume(struct device *dev) return ret; } - ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2, - AFE440X_CONTROL2_PDN_AFE, 0); + ret = regmap_clear_bits(afe->regmap, AFE440X_CONTROL2, + AFE440X_CONTROL2_PDN_AFE); if (ret) return ret; diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c index 1dc0df21450d..e08d143a707c 100644 --- a/drivers/iio/health/max30100.c +++ b/drivers/iio/health/max30100.c @@ -363,9 +363,8 @@ static int max30100_get_temp(struct max30100_data *data, int *val) int ret; /* start acquisition */ - ret = regmap_update_bits(data->regmap, MAX30100_REG_MODE_CONFIG, - MAX30100_REG_MODE_CONFIG_TEMP_EN, - MAX30100_REG_MODE_CONFIG_TEMP_EN); + ret = regmap_set_bits(data->regmap, MAX30100_REG_MODE_CONFIG, + MAX30100_REG_MODE_CONFIG_TEMP_EN); if (ret) return ret; diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c index 6616729af5b7..07a343e35a81 100644 --- a/drivers/iio/health/max30102.c +++ b/drivers/iio/health/max30102.c @@ -448,9 +448,8 @@ static int max30102_get_temp(struct max30102_data *data, int *val, bool en) } /* start acquisition */ - ret = regmap_update_bits(data->regmap, MAX30102_REG_TEMP_CONFIG, - MAX30102_REG_TEMP_CONFIG_TEMP_EN, - MAX30102_REG_TEMP_CONFIG_TEMP_EN); + ret = regmap_set_bits(data->regmap, MAX30102_REG_TEMP_CONFIG, + MAX30102_REG_TEMP_CONFIG_TEMP_EN); if (ret) goto out; diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h index 1a38b1915e7a..b7d5f4f0fada 100644 --- a/drivers/iio/iio_core.h +++ b/drivers/iio/iio_core.h @@ -34,6 +34,10 @@ void iio_device_ioctl_handler_register(struct iio_dev *indio_dev, struct iio_ioctl_handler *h); void iio_device_ioctl_handler_unregister(struct iio_ioctl_handler *h); +ssize_t do_iio_read_channel_label(struct iio_dev *indio_dev, + const struct iio_chan_spec *c, + char *buf); + int __iio_add_chan_devattr(const char *postfix, struct iio_chan_spec const *chan, ssize_t (*func)(struct device *dev, diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c index 495caf4ce87a..876848b42f69 100644 --- a/drivers/iio/imu/adis.c +++ b/drivers/iio/imu/adis.c @@ -466,17 +466,17 @@ int adis_single_conversion(struct iio_dev *indio_dev, unsigned int uval; int ret; - mutex_lock(&adis->state_lock); + guard(mutex)(&adis->state_lock); ret = __adis_read_reg(adis, chan->address, &uval, chan->scan_type.storagebits / 8); if (ret) - goto err_unlock; + return ret; if (uval & error_mask) { ret = __adis_check_status(adis); if (ret) - goto err_unlock; + return ret; } if (chan->scan_type.sign == 's') @@ -484,10 +484,7 @@ int adis_single_conversion(struct iio_dev *indio_dev, else *val = uval & ((1 << chan->scan_type.realbits) - 1); - ret = IIO_VAL_INT; -err_unlock: - mutex_unlock(&adis->state_lock); - return ret; + return IIO_VAL_INT; } EXPORT_SYMBOL_NS_GPL(adis_single_conversion, IIO_ADISLIB); diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c index 3eda32e12a53..0bfd6205f5f6 100644 --- a/drivers/iio/imu/adis16400.c +++ b/drivers/iio/imu/adis16400.c @@ -497,41 +497,38 @@ static int adis16400_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long info) { struct adis16400_state *st = iio_priv(indio_dev); - int ret, sps; + int sps; switch (info) { case IIO_CHAN_INFO_CALIBBIAS: - ret = adis_write_reg_16(&st->adis, - adis16400_addresses[chan->scan_index], val); - return ret; + return adis_write_reg_16(&st->adis, + adis16400_addresses[chan->scan_index], + val); case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: /* * Need to cache values so we can update if the frequency * changes. */ - adis_dev_lock(&st->adis); - st->filt_int = val; - /* Work out update to current value */ - sps = st->variant->get_freq(st); - if (sps < 0) { - adis_dev_unlock(&st->adis); - return sps; + adis_dev_auto_scoped_lock(&st->adis) { + st->filt_int = val; + /* Work out update to current value */ + sps = st->variant->get_freq(st); + if (sps < 0) + return sps; + + return __adis16400_set_filter(indio_dev, sps, + val * 1000 + val2 / 1000); } - - ret = __adis16400_set_filter(indio_dev, sps, - val * 1000 + val2 / 1000); - adis_dev_unlock(&st->adis); - return ret; + unreachable(); case IIO_CHAN_INFO_SAMP_FREQ: sps = val * 1000 + val2 / 1000; if (sps <= 0) return -EINVAL; - adis_dev_lock(&st->adis); - ret = st->variant->set_freq(st, sps); - adis_dev_unlock(&st->adis); - return ret; + adis_dev_auto_scoped_lock(&st->adis) + return st->variant->set_freq(st, sps); + unreachable(); default: return -EINVAL; } @@ -596,29 +593,30 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, *val = st->variant->temp_offset; return IIO_VAL_INT; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: - adis_dev_lock(&st->adis); - /* Need both the number of taps and the sampling frequency */ - ret = __adis_read_reg_16(&st->adis, - ADIS16400_SENS_AVG, - &val16); - if (ret) { - adis_dev_unlock(&st->adis); - return ret; + adis_dev_auto_scoped_lock(&st->adis) { + /* + * Need both the number of taps and the sampling + * frequency + */ + ret = __adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, + &val16); + if (ret) + return ret; + + ret = st->variant->get_freq(st); + if (ret) + return ret; } - ret = st->variant->get_freq(st); - adis_dev_unlock(&st->adis); - if (ret) - return ret; ret /= adis16400_3db_divisors[val16 & 0x07]; *val = ret / 1000; *val2 = (ret % 1000) * 1000; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SAMP_FREQ: - adis_dev_lock(&st->adis); - ret = st->variant->get_freq(st); - adis_dev_unlock(&st->adis); - if (ret) - return ret; + adis_dev_auto_scoped_lock(&st->adis) { + ret = st->variant->get_freq(st); + if (ret) + return ret; + } *val = ret / 1000; *val2 = (ret % 1000) * 1000; return IIO_VAL_INT_PLUS_MICRO; diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index cf73c6f46c79..482258ed5a3c 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -302,30 +302,25 @@ static int adis16475_get_freq(struct adis16475 *st, u32 *freq) u16 dec; u32 sample_rate = st->clk_freq; - adis_dev_lock(&st->adis); + adis_dev_auto_lock(&st->adis); if (st->sync_mode == ADIS16475_SYNC_SCALED) { u16 sync_scale; ret = __adis_read_reg_16(&st->adis, ADIS16475_REG_UP_SCALE, &sync_scale); if (ret) - goto error; + return ret; sample_rate = st->clk_freq * sync_scale; } ret = __adis_read_reg_16(&st->adis, ADIS16475_REG_DEC_RATE, &dec); if (ret) - goto error; - - adis_dev_unlock(&st->adis); + return ret; *freq = DIV_ROUND_CLOSEST(sample_rate, dec + 1); return 0; -error: - adis_dev_unlock(&st->adis); - return ret; } static int adis16475_set_freq(struct adis16475 *st, const u32 freq) @@ -340,7 +335,7 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq) if (!freq) return -EINVAL; - adis_dev_lock(&st->adis); + adis_dev_auto_lock(&st->adis); /* * When using sync scaled mode, the input clock needs to be scaled so that we have * an IMU sample rate between (optimally) int_clk - 100 and int_clk + 100. @@ -385,7 +380,7 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq) sync_scale = scaled_rate / st->clk_freq; ret = __adis_write_reg_16(&st->adis, ADIS16475_REG_UP_SCALE, sync_scale); if (ret) - goto error; + return ret; sample_rate = scaled_rate; } @@ -400,9 +395,8 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq) ret = __adis_write_reg_16(&st->adis, ADIS16475_REG_DEC_RATE, dec); if (ret) - goto error; + return ret; - adis_dev_unlock(&st->adis); /* * If decimation is used, then gyro and accel data will have meaningful * bits on the LSB registers. This info is used on the trigger handler. @@ -410,9 +404,6 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq) assign_bit(ADIS16475_LSB_DEC_MASK, &st->lsb_flag, dec); return 0; -error: - adis_dev_unlock(&st->adis); - return ret; } /* The values are approximated. */ @@ -541,19 +532,15 @@ static int adis16475_buffer_postdisable(struct iio_dev *indio_dev) struct adis *adis = &st->adis; int ret; - adis_dev_lock(&st->adis); + adis_dev_auto_lock(&st->adis); ret = __adis_update_bits(adis, ADIS16475_REG_FIFO_CTRL, ADIS16575_FIFO_EN_MASK, (u16)ADIS16575_FIFO_EN(0)); if (ret) - goto unlock; - - ret = __adis_write_reg_16(adis, ADIS16475_REG_GLOB_CMD, - ADIS16575_FIFO_FLUSH_CMD); + return ret; -unlock: - adis_dev_unlock(&st->adis); - return ret; + return __adis_write_reg_16(adis, ADIS16475_REG_GLOB_CMD, + ADIS16575_FIFO_FLUSH_CMD); } static const struct iio_buffer_setup_ops adis16475_buffer_ops = { @@ -567,20 +554,18 @@ static int adis16475_set_watermark(struct iio_dev *indio_dev, unsigned int val) int ret; u16 wm_lvl; - adis_dev_lock(&st->adis); + adis_dev_auto_lock(&st->adis); val = min_t(unsigned int, val, ADIS16575_MAX_FIFO_WM); wm_lvl = ADIS16575_WM_LVL(val - 1); ret = __adis_update_bits(&st->adis, ADIS16475_REG_FIFO_CTRL, ADIS16575_WM_LVL_MASK, wm_lvl); if (ret) - goto unlock; + return ret; st->fifo_watermark = val; -unlock: - adis_dev_unlock(&st->adis); - return ret; + return 0; } static const u32 adis16475_calib_regs[] = { @@ -1745,7 +1730,7 @@ static irqreturn_t adis16475_trigger_handler_with_fifo(int irq, void *p) int ret; u16 fifo_cnt, i; - adis_dev_lock(&st->adis); + adis_dev_auto_lock(&st->adis); ret = __adis_read_reg_16(adis, ADIS16575_REG_FIFO_CNT, &fifo_cnt); if (ret) @@ -1781,7 +1766,6 @@ unlock: * reading data from registers will impact the FIFO reading. */ adis16475_burst32_check(st); - adis_dev_unlock(&st->adis); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index 56ca5a09fbbf..c59ef6f7cfd4 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -345,7 +345,7 @@ static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2) if (t == 0) return -EINVAL; - adis_dev_lock(&st->adis); + adis_dev_auto_lock(&st->adis); /* * When using PPS mode, the input clock needs to be scaled so that we have an IMU * sample rate between (optimally) 4000 and 4250. After this, we can use the @@ -388,7 +388,7 @@ static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2) sync_scale = scaled_rate / st->clk_freq; ret = __adis_write_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, sync_scale); if (ret) - goto error; + return ret; sample_rate = scaled_rate; } @@ -400,10 +400,7 @@ static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2) if (t > st->chip_info->max_dec_rate) t = st->chip_info->max_dec_rate; - ret = __adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t); -error: - adis_dev_unlock(&st->adis); - return ret; + return __adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t); } static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) @@ -413,23 +410,21 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) int ret; unsigned int freq, sample_rate = st->clk_freq; - adis_dev_lock(&st->adis); + adis_dev_auto_lock(&st->adis); if (st->clk_mode == ADIS16480_CLK_PPS) { u16 sync_scale; ret = __adis_read_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, &sync_scale); if (ret) - goto error; + return ret; sample_rate = st->clk_freq * sync_scale; } ret = __adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t); if (ret) - goto error; - - adis_dev_unlock(&st->adis); + return ret; freq = DIV_ROUND_CLOSEST(sample_rate, (t + 1)); @@ -437,9 +432,6 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) *val2 = (freq % 1000) * 1000; return IIO_VAL_INT_PLUS_MICRO; -error: - adis_dev_unlock(&st->adis); - return ret; } enum { @@ -630,11 +622,11 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev, offset = ad16480_filter_data[chan->scan_index][1]; enable_mask = BIT(offset + 2); - adis_dev_lock(&st->adis); + adis_dev_auto_lock(&st->adis); ret = __adis_read_reg_16(&st->adis, reg, &val); if (ret) - goto out_unlock; + return ret; if (freq == 0) { val &= ~enable_mask; @@ -656,11 +648,7 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev, val |= enable_mask; } - ret = __adis_write_reg_16(&st->adis, reg, val); -out_unlock: - adis_dev_unlock(&st->adis); - - return ret; + return __adis_write_reg_16(&st->adis, reg, val); } static int adis16480_read_raw(struct iio_dev *indio_dev, @@ -1355,29 +1343,26 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p) u32 crc; bool valid; - adis_dev_lock(adis); - if (adis->current_page != 0) { - adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID); - adis->tx[1] = 0; - ret = spi_write(adis->spi, adis->tx, 2); + adis_dev_auto_scoped_lock(adis) { + if (adis->current_page != 0) { + adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID); + adis->tx[1] = 0; + ret = spi_write(adis->spi, adis->tx, 2); + if (ret) { + dev_err(dev, "Failed to change device page: %d\n", ret); + goto irq_done; + } + + adis->current_page = 0; + } + + ret = spi_sync(adis->spi, &adis->msg); if (ret) { - dev_err(dev, "Failed to change device page: %d\n", ret); - adis_dev_unlock(adis); + dev_err(dev, "Failed to read data: %d\n", ret); goto irq_done; } - - adis->current_page = 0; } - ret = spi_sync(adis->spi, &adis->msg); - if (ret) { - dev_err(dev, "Failed to read data: %d\n", ret); - adis_dev_unlock(adis); - goto irq_done; - } - - adis_dev_unlock(adis); - /* * After making the burst request, the response can have one or two * 16-bit responses containing the BURST_ID depending on the sclk. If diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index 871b78b225e2..b7c1cc04492a 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -126,6 +126,26 @@ int adis_update_scan_mode(struct iio_dev *indio_dev, } EXPORT_SYMBOL_NS_GPL(adis_update_scan_mode, IIO_ADISLIB); +static int adis_paging_trigger_handler(struct adis *adis) +{ + int ret; + + guard(mutex)(&adis->state_lock); + if (adis->current_page != 0) { + adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID); + adis->tx[1] = 0; + ret = spi_write(adis->spi, adis->tx, 2); + if (ret) { + dev_err(&adis->spi->dev, "Failed to change device page: %d\n", ret); + return ret; + } + + adis->current_page = 0; + } + + return spi_sync(adis->spi, &adis->msg); +} + static irqreturn_t adis_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; @@ -133,25 +153,10 @@ static irqreturn_t adis_trigger_handler(int irq, void *p) struct adis *adis = iio_device_get_drvdata(indio_dev); int ret; - if (adis->data->has_paging) { - mutex_lock(&adis->state_lock); - if (adis->current_page != 0) { - adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID); - adis->tx[1] = 0; - ret = spi_write(adis->spi, adis->tx, 2); - if (ret) { - dev_err(&adis->spi->dev, "Failed to change device page: %d\n", ret); - mutex_unlock(&adis->state_lock); - goto irq_done; - } - - adis->current_page = 0; - } - } - - ret = spi_sync(adis->spi, &adis->msg); if (adis->data->has_paging) - mutex_unlock(&adis->state_lock); + ret = adis_paging_trigger_handler(adis); + else + ret = spi_sync(adis->spi, &adis->msg); if (ret) { dev_err(&adis->spi->dev, "Failed to read data: %d", ret); goto irq_done; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c index a8cf74c84c3c..aae7c56481a3 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c @@ -274,9 +274,8 @@ int inv_icm42600_buffer_update_watermark(struct inv_icm42600_state *st) /* restore watermark interrupt */ if (restore) { - ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_SOURCE0, - INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN, - INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN); + ret = regmap_set_bits(st->map, INV_ICM42600_REG_INT_SOURCE0, + INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN); if (ret) return ret; } @@ -318,9 +317,8 @@ static int inv_icm42600_buffer_postenable(struct iio_dev *indio_dev) } /* set FIFO threshold interrupt */ - ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_SOURCE0, - INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN, - INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN); + ret = regmap_set_bits(st->map, INV_ICM42600_REG_INT_SOURCE0, + INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN); if (ret) goto out_unlock; @@ -375,8 +373,8 @@ static int inv_icm42600_buffer_predisable(struct iio_dev *indio_dev) goto out_unlock; /* disable FIFO threshold interrupt */ - ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_SOURCE0, - INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN, 0); + ret = regmap_clear_bits(st->map, INV_ICM42600_REG_INT_SOURCE0, + INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN); if (ret) goto out_unlock; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c index 61f1f6d4c421..c3924cc6190e 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -496,9 +496,8 @@ static int inv_icm42600_setup(struct inv_icm42600_state *st, return ret; /* sensor data in big-endian (default) */ - ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0, - INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN, - INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN); + ret = regmap_set_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0, + INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN); if (ret) return ret; @@ -603,8 +602,8 @@ static int inv_icm42600_irq_init(struct inv_icm42600_state *st, int irq, return ret; /* Deassert async reset for proper INT pin operation (cf datasheet) */ - ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_CONFIG1, - INV_ICM42600_INT_CONFIG1_ASYNC_RESET, 0); + ret = regmap_clear_bits(st->map, INV_ICM42600_REG_INT_CONFIG1, + INV_ICM42600_INT_CONFIG1_ASYNC_RESET); if (ret) return ret; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c index 8d33504d770f..ebb31b385881 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c @@ -28,8 +28,8 @@ static int inv_icm42600_i2c_bus_setup(struct inv_icm42600_state *st) INV_ICM42600_INTF_CONFIG6_MASK, INV_ICM42600_INTF_CONFIG6_I3C_EN); - ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4, - INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY, 0); + ret = regmap_clear_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4, + INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY); if (ret) return ret; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c index cc2bf1799a46..eae5ff7a3cc1 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c @@ -27,8 +27,8 @@ static int inv_icm42600_spi_bus_setup(struct inv_icm42600_state *st) if (ret) return ret; - ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4, - INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY, 0); + ret = regmap_clear_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4, + INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY); if (ret) return ret; diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c index 929aff4040ed..efe05be284b6 100644 --- a/drivers/iio/industrialio-backend.c +++ b/drivers/iio/industrialio-backend.c @@ -561,11 +561,9 @@ struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name) } fwnode = fwnode_find_reference(dev_fwnode(dev), "io-backends", index); - if (IS_ERR(fwnode)) { - dev_err_probe(dev, PTR_ERR(fwnode), - "Cannot get Firmware reference\n"); - return ERR_CAST(fwnode); - } + if (IS_ERR(fwnode)) + return dev_err_cast_probe(dev, fwnode, + "Cannot get Firmware reference\n"); guard(mutex)(&iio_back_lock); list_for_each_entry(back, &iio_back_list, entry) { diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 0138b21b244f..d6fe105d2f40 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -9,15 +9,20 @@ * - Better memory allocation techniques? * - Alternative access techniques? */ +#include <linux/atomic.h> #include <linux/anon_inodes.h> #include <linux/cleanup.h> #include <linux/kernel.h> #include <linux/export.h> #include <linux/device.h> +#include <linux/dma-buf.h> +#include <linux/dma-fence.h> +#include <linux/dma-resv.h> #include <linux/file.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/slab.h> +#include <linux/mm.h> #include <linux/poll.h> #include <linux/sched/signal.h> @@ -29,6 +34,34 @@ #include <linux/iio/buffer.h> #include <linux/iio/buffer_impl.h> +#define DMABUF_ENQUEUE_TIMEOUT_MS 5000 + +MODULE_IMPORT_NS(DMA_BUF); + +struct iio_dmabuf_priv { + struct list_head entry; + struct kref ref; + + struct iio_buffer *buffer; + struct iio_dma_buffer_block *block; + + u64 context; + + /* Spinlock used for locking the dma_fence */ + spinlock_t lock; + + struct dma_buf_attachment *attach; + struct sg_table *sgt; + enum dma_data_direction dir; + atomic_t seqno; +}; + +struct iio_dma_fence { + struct dma_fence base; + struct iio_dmabuf_priv *priv; + struct work_struct work; +}; + static const char * const iio_endian_prefix[] = { [IIO_BE] = "be", [IIO_LE] = "le", @@ -333,6 +366,8 @@ void iio_buffer_init(struct iio_buffer *buffer) { INIT_LIST_HEAD(&buffer->demux_list); INIT_LIST_HEAD(&buffer->buffer_list); + INIT_LIST_HEAD(&buffer->dmabufs); + mutex_init(&buffer->dmabufs_mutex); init_waitqueue_head(&buffer->pollq); kref_init(&buffer->ref); if (!buffer->watermark) @@ -1526,14 +1561,55 @@ static void iio_buffer_unregister_legacy_sysfs_groups(struct iio_dev *indio_dev) kfree(iio_dev_opaque->legacy_scan_el_group.attrs); } +static void iio_buffer_dmabuf_release(struct kref *ref) +{ + struct iio_dmabuf_priv *priv = container_of(ref, struct iio_dmabuf_priv, ref); + struct dma_buf_attachment *attach = priv->attach; + struct iio_buffer *buffer = priv->buffer; + struct dma_buf *dmabuf = attach->dmabuf; + + dma_resv_lock(dmabuf->resv, NULL); + dma_buf_unmap_attachment(attach, priv->sgt, priv->dir); + dma_resv_unlock(dmabuf->resv); + + buffer->access->detach_dmabuf(buffer, priv->block); + + dma_buf_detach(attach->dmabuf, attach); + dma_buf_put(dmabuf); + kfree(priv); +} + +static void iio_buffer_dmabuf_get(struct dma_buf_attachment *attach) +{ + struct iio_dmabuf_priv *priv = attach->importer_priv; + + kref_get(&priv->ref); +} + +static void iio_buffer_dmabuf_put(struct dma_buf_attachment *attach) +{ + struct iio_dmabuf_priv *priv = attach->importer_priv; + + kref_put(&priv->ref, iio_buffer_dmabuf_release); +} + static int iio_buffer_chrdev_release(struct inode *inode, struct file *filep) { struct iio_dev_buffer_pair *ib = filep->private_data; struct iio_dev *indio_dev = ib->indio_dev; struct iio_buffer *buffer = ib->buffer; + struct iio_dmabuf_priv *priv, *tmp; wake_up(&buffer->pollq); + guard(mutex)(&buffer->dmabufs_mutex); + + /* Close all attached DMABUFs */ + list_for_each_entry_safe(priv, tmp, &buffer->dmabufs, entry) { + list_del_init(&priv->entry); + iio_buffer_dmabuf_put(priv->attach); + } + kfree(ib); clear_bit(IIO_BUSY_BIT_POS, &buffer->flags); iio_device_put(indio_dev); @@ -1541,11 +1617,393 @@ static int iio_buffer_chrdev_release(struct inode *inode, struct file *filep) return 0; } +static int iio_dma_resv_lock(struct dma_buf *dmabuf, bool nonblock) +{ + if (!nonblock) + return dma_resv_lock_interruptible(dmabuf->resv, NULL); + + if (!dma_resv_trylock(dmabuf->resv)) + return -EBUSY; + + return 0; +} + +static struct dma_buf_attachment * +iio_buffer_find_attachment(struct iio_dev_buffer_pair *ib, + struct dma_buf *dmabuf, bool nonblock) +{ + struct device *dev = ib->indio_dev->dev.parent; + struct iio_buffer *buffer = ib->buffer; + struct dma_buf_attachment *attach = NULL; + struct iio_dmabuf_priv *priv; + + guard(mutex)(&buffer->dmabufs_mutex); + + list_for_each_entry(priv, &buffer->dmabufs, entry) { + if (priv->attach->dev == dev + && priv->attach->dmabuf == dmabuf) { + attach = priv->attach; + break; + } + } + + if (attach) + iio_buffer_dmabuf_get(attach); + + return attach ?: ERR_PTR(-EPERM); +} + +static int iio_buffer_attach_dmabuf(struct iio_dev_buffer_pair *ib, + int __user *user_fd, bool nonblock) +{ + struct iio_dev *indio_dev = ib->indio_dev; + struct iio_buffer *buffer = ib->buffer; + struct dma_buf_attachment *attach; + struct iio_dmabuf_priv *priv, *each; + struct dma_buf *dmabuf; + int err, fd; + + if (!buffer->access->attach_dmabuf + || !buffer->access->detach_dmabuf + || !buffer->access->enqueue_dmabuf) + return -EPERM; + + if (copy_from_user(&fd, user_fd, sizeof(fd))) + return -EFAULT; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&priv->lock); + priv->context = dma_fence_context_alloc(1); + + dmabuf = dma_buf_get(fd); + if (IS_ERR(dmabuf)) { + err = PTR_ERR(dmabuf); + goto err_free_priv; + } + + attach = dma_buf_attach(dmabuf, indio_dev->dev.parent); + if (IS_ERR(attach)) { + err = PTR_ERR(attach); + goto err_dmabuf_put; + } + + err = iio_dma_resv_lock(dmabuf, nonblock); + if (err) + goto err_dmabuf_detach; + + priv->dir = buffer->direction == IIO_BUFFER_DIRECTION_IN + ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + + priv->sgt = dma_buf_map_attachment(attach, priv->dir); + if (IS_ERR(priv->sgt)) { + err = PTR_ERR(priv->sgt); + dev_err(&indio_dev->dev, "Unable to map attachment: %d\n", err); + goto err_resv_unlock; + } + + kref_init(&priv->ref); + priv->buffer = buffer; + priv->attach = attach; + attach->importer_priv = priv; + + priv->block = buffer->access->attach_dmabuf(buffer, attach); + if (IS_ERR(priv->block)) { + err = PTR_ERR(priv->block); + goto err_dmabuf_unmap_attachment; + } + + dma_resv_unlock(dmabuf->resv); + + mutex_lock(&buffer->dmabufs_mutex); + + /* + * Check whether we already have an attachment for this driver/DMABUF + * combo. If we do, refuse to attach. + */ + list_for_each_entry(each, &buffer->dmabufs, entry) { + if (each->attach->dev == indio_dev->dev.parent + && each->attach->dmabuf == dmabuf) { + /* + * We unlocked the reservation object, so going through + * the cleanup code would mean re-locking it first. + * At this stage it is simpler to free the attachment + * using iio_buffer_dma_put(). + */ + mutex_unlock(&buffer->dmabufs_mutex); + iio_buffer_dmabuf_put(attach); + return -EBUSY; + } + } + + /* Otherwise, add the new attachment to our dmabufs list. */ + list_add(&priv->entry, &buffer->dmabufs); + mutex_unlock(&buffer->dmabufs_mutex); + + return 0; + +err_dmabuf_unmap_attachment: + dma_buf_unmap_attachment(attach, priv->sgt, priv->dir); +err_resv_unlock: + dma_resv_unlock(dmabuf->resv); +err_dmabuf_detach: + dma_buf_detach(dmabuf, attach); +err_dmabuf_put: + dma_buf_put(dmabuf); +err_free_priv: + kfree(priv); + + return err; +} + +static int iio_buffer_detach_dmabuf(struct iio_dev_buffer_pair *ib, + int __user *user_req, bool nonblock) +{ + struct iio_buffer *buffer = ib->buffer; + struct iio_dev *indio_dev = ib->indio_dev; + struct iio_dmabuf_priv *priv; + struct dma_buf *dmabuf; + int dmabuf_fd, ret = -EPERM; + + if (copy_from_user(&dmabuf_fd, user_req, sizeof(dmabuf_fd))) + return -EFAULT; + + dmabuf = dma_buf_get(dmabuf_fd); + if (IS_ERR(dmabuf)) + return PTR_ERR(dmabuf); + + guard(mutex)(&buffer->dmabufs_mutex); + + list_for_each_entry(priv, &buffer->dmabufs, entry) { + if (priv->attach->dev == indio_dev->dev.parent + && priv->attach->dmabuf == dmabuf) { + list_del(&priv->entry); + + /* Unref the reference from iio_buffer_attach_dmabuf() */ + iio_buffer_dmabuf_put(priv->attach); + ret = 0; + break; + } + } + + dma_buf_put(dmabuf); + + return ret; +} + +static const char * +iio_buffer_dma_fence_get_driver_name(struct dma_fence *fence) +{ + return "iio"; +} + +static void iio_buffer_dma_fence_release(struct dma_fence *fence) +{ + struct iio_dma_fence *iio_fence = + container_of(fence, struct iio_dma_fence, base); + + kfree(iio_fence); +} + +static const struct dma_fence_ops iio_buffer_dma_fence_ops = { + .get_driver_name = iio_buffer_dma_fence_get_driver_name, + .get_timeline_name = iio_buffer_dma_fence_get_driver_name, + .release = iio_buffer_dma_fence_release, +}; + +static int iio_buffer_enqueue_dmabuf(struct iio_dev_buffer_pair *ib, + struct iio_dmabuf __user *iio_dmabuf_req, + bool nonblock) +{ + struct iio_buffer *buffer = ib->buffer; + struct iio_dmabuf iio_dmabuf; + struct dma_buf_attachment *attach; + struct iio_dmabuf_priv *priv; + struct iio_dma_fence *fence; + struct dma_buf *dmabuf; + unsigned long timeout; + bool cookie, cyclic, dma_to_ram; + long retl; + u32 seqno; + int ret; + + if (copy_from_user(&iio_dmabuf, iio_dmabuf_req, sizeof(iio_dmabuf))) + return -EFAULT; + + if (iio_dmabuf.flags & ~IIO_BUFFER_DMABUF_SUPPORTED_FLAGS) + return -EINVAL; + + cyclic = iio_dmabuf.flags & IIO_BUFFER_DMABUF_CYCLIC; + + /* Cyclic flag is only supported on output buffers */ + if (cyclic && buffer->direction != IIO_BUFFER_DIRECTION_OUT) + return -EINVAL; + + dmabuf = dma_buf_get(iio_dmabuf.fd); + if (IS_ERR(dmabuf)) + return PTR_ERR(dmabuf); + + if (!iio_dmabuf.bytes_used || iio_dmabuf.bytes_used > dmabuf->size) { + ret = -EINVAL; + goto err_dmabuf_put; + } + + attach = iio_buffer_find_attachment(ib, dmabuf, nonblock); + if (IS_ERR(attach)) { + ret = PTR_ERR(attach); + goto err_dmabuf_put; + } + + priv = attach->importer_priv; + + fence = kmalloc(sizeof(*fence), GFP_KERNEL); + if (!fence) { + ret = -ENOMEM; + goto err_attachment_put; + } + + fence->priv = priv; + + seqno = atomic_add_return(1, &priv->seqno); + + /* + * The transfers are guaranteed to be processed in the order they are + * enqueued, so we can use a simple incrementing sequence number for + * the dma_fence. + */ + dma_fence_init(&fence->base, &iio_buffer_dma_fence_ops, + &priv->lock, priv->context, seqno); + + ret = iio_dma_resv_lock(dmabuf, nonblock); + if (ret) + goto err_fence_put; + + timeout = nonblock ? 0 : msecs_to_jiffies(DMABUF_ENQUEUE_TIMEOUT_MS); + dma_to_ram = buffer->direction == IIO_BUFFER_DIRECTION_IN; + + /* Make sure we don't have writers */ + retl = dma_resv_wait_timeout(dmabuf->resv, + dma_resv_usage_rw(dma_to_ram), + true, timeout); + if (retl == 0) + retl = -EBUSY; + if (retl < 0) { + ret = (int)retl; + goto err_resv_unlock; + } + + if (buffer->access->lock_queue) + buffer->access->lock_queue(buffer); + + ret = dma_resv_reserve_fences(dmabuf->resv, 1); + if (ret) + goto err_queue_unlock; + + dma_resv_add_fence(dmabuf->resv, &fence->base, + dma_to_ram ? DMA_RESV_USAGE_WRITE : DMA_RESV_USAGE_READ); + dma_resv_unlock(dmabuf->resv); + + cookie = dma_fence_begin_signalling(); + + ret = buffer->access->enqueue_dmabuf(buffer, priv->block, &fence->base, + priv->sgt, iio_dmabuf.bytes_used, + cyclic); + if (ret) { + /* + * DMABUF enqueue failed, but we already added the fence. + * Signal the error through the fence completion mechanism. + */ + iio_buffer_signal_dmabuf_done(&fence->base, ret); + } + + if (buffer->access->unlock_queue) + buffer->access->unlock_queue(buffer); + + dma_fence_end_signalling(cookie); + dma_buf_put(dmabuf); + + return ret; + +err_queue_unlock: + if (buffer->access->unlock_queue) + buffer->access->unlock_queue(buffer); +err_resv_unlock: + dma_resv_unlock(dmabuf->resv); +err_fence_put: + dma_fence_put(&fence->base); +err_attachment_put: + iio_buffer_dmabuf_put(attach); +err_dmabuf_put: + dma_buf_put(dmabuf); + + return ret; +} + +static void iio_buffer_cleanup(struct work_struct *work) +{ + struct iio_dma_fence *fence = + container_of(work, struct iio_dma_fence, work); + struct iio_dmabuf_priv *priv = fence->priv; + struct dma_buf_attachment *attach = priv->attach; + + dma_fence_put(&fence->base); + iio_buffer_dmabuf_put(attach); +} + +void iio_buffer_signal_dmabuf_done(struct dma_fence *fence, int ret) +{ + struct iio_dma_fence *iio_fence = + container_of(fence, struct iio_dma_fence, base); + bool cookie = dma_fence_begin_signalling(); + + /* + * Get a reference to the fence, so that it's not freed as soon as + * it's signaled. + */ + dma_fence_get(fence); + + fence->error = ret; + dma_fence_signal(fence); + dma_fence_end_signalling(cookie); + + /* + * The fence will be unref'd in iio_buffer_cleanup. + * It can't be done here, as the unref functions might try to lock the + * resv object, which can deadlock. + */ + INIT_WORK(&iio_fence->work, iio_buffer_cleanup); + schedule_work(&iio_fence->work); +} +EXPORT_SYMBOL_GPL(iio_buffer_signal_dmabuf_done); + +static long iio_buffer_chrdev_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct iio_dev_buffer_pair *ib = filp->private_data; + void __user *_arg = (void __user *)arg; + bool nonblock = filp->f_flags & O_NONBLOCK; + + switch (cmd) { + case IIO_BUFFER_DMABUF_ATTACH_IOCTL: + return iio_buffer_attach_dmabuf(ib, _arg, nonblock); + case IIO_BUFFER_DMABUF_DETACH_IOCTL: + return iio_buffer_detach_dmabuf(ib, _arg, nonblock); + case IIO_BUFFER_DMABUF_ENQUEUE_IOCTL: + return iio_buffer_enqueue_dmabuf(ib, _arg, nonblock); + default: + return -EINVAL; + } +} + static const struct file_operations iio_buffer_chrdev_fileops = { .owner = THIS_MODULE, .llseek = noop_llseek, .read = iio_buffer_read, .write = iio_buffer_write, + .unlocked_ioctl = iio_buffer_chrdev_ioctl, + .compat_ioctl = compat_ptr_ioctl, .poll = iio_buffer_poll, .release = iio_buffer_chrdev_release, }; @@ -1994,6 +2452,7 @@ static void iio_buffer_release(struct kref *ref) { struct iio_buffer *buffer = container_of(ref, struct iio_buffer, ref); + mutex_destroy(&buffer->dmabufs_mutex); buffer->access->release(buffer); } diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 2f185b386949..0f6cda7ffe45 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -727,22 +727,27 @@ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals) } EXPORT_SYMBOL_GPL(iio_format_value); -static ssize_t iio_read_channel_label(struct device *dev, - struct device_attribute *attr, - char *buf) +ssize_t do_iio_read_channel_label(struct iio_dev *indio_dev, + const struct iio_chan_spec *c, + char *buf) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - if (indio_dev->info->read_label) - return indio_dev->info->read_label(indio_dev, this_attr->c, buf); + return indio_dev->info->read_label(indio_dev, c, buf); - if (this_attr->c->extend_name) - return sysfs_emit(buf, "%s\n", this_attr->c->extend_name); + if (c->extend_name) + return sysfs_emit(buf, "%s\n", c->extend_name); return -EINVAL; } +static ssize_t iio_read_channel_label(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return do_iio_read_channel_label(dev_to_iio_dev(dev), + to_iio_dev_attr(attr)->c, buf); +} + static ssize_t iio_read_channel_info(struct device *dev, struct device_attribute *attr, char *buf) diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 39cf26d69d17..9f484c94bc6e 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -1010,3 +1010,9 @@ ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr, chan->channel, buf, len); } EXPORT_SYMBOL_GPL(iio_write_channel_ext_info); + +ssize_t iio_read_channel_label(struct iio_channel *chan, char *buf) +{ + return do_iio_read_channel_label(chan->indio_dev, chan->channel, buf); +} +EXPORT_SYMBOL_GPL(iio_read_channel_label); diff --git a/drivers/iio/light/adux1020.c b/drivers/iio/light/adux1020.c index d4eb938c3bf5..2e0170be077a 100644 --- a/drivers/iio/light/adux1020.c +++ b/drivers/iio/light/adux1020.c @@ -539,9 +539,8 @@ static int adux1020_write_event_config(struct iio_dev *indio_dev, * Trigger proximity interrupt when the intensity is above * or below threshold */ - ret = regmap_update_bits(data->regmap, ADUX1020_REG_PROX_TYPE, - ADUX1020_PROX_TYPE, - ADUX1020_PROX_TYPE); + ret = regmap_set_bits(data->regmap, ADUX1020_REG_PROX_TYPE, + ADUX1020_PROX_TYPE); if (ret < 0) goto fail; @@ -748,8 +747,8 @@ static int adux1020_chip_init(struct adux1020_data *data) dev_dbg(&client->dev, "Detected ADUX1020 with chip id: 0x%04x\n", val); - ret = regmap_update_bits(data->regmap, ADUX1020_REG_SW_RESET, - ADUX1020_SW_RESET, ADUX1020_SW_RESET); + ret = regmap_set_bits(data->regmap, ADUX1020_REG_SW_RESET, + ADUX1020_SW_RESET); if (ret < 0) return ret; @@ -764,8 +763,8 @@ static int adux1020_chip_init(struct adux1020_data *data) return ret; /* Use LED_IREF for proximity mode */ - ret = regmap_update_bits(data->regmap, ADUX1020_REG_LED_CURRENT, - ADUX1020_LED_PIREF_EN, 0); + ret = regmap_clear_bits(data->regmap, ADUX1020_REG_LED_CURRENT, + ADUX1020_LED_PIREF_EN); if (ret < 0) return ret; diff --git a/drivers/iio/light/iqs621-als.c b/drivers/iio/light/iqs621-als.c index 004ea890a4b2..6de33feada3a 100644 --- a/drivers/iio/light/iqs621-als.c +++ b/drivers/iio/light/iqs621-als.c @@ -86,8 +86,8 @@ static int iqs621_als_init(struct iqs621_als_private *iqs621_als) if (iqs621_als->prox_en) event_mask |= iqs62x->dev_desc->ir_mask; - return regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK, - event_mask, 0); + return regmap_clear_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK, + event_mask); } static int iqs621_als_notifier(struct notifier_block *notifier, diff --git a/drivers/iio/light/isl29018.c b/drivers/iio/light/isl29018.c index 43484c18b101..8dfc750e68c0 100644 --- a/drivers/iio/light/isl29018.c +++ b/drivers/iio/light/isl29018.c @@ -550,9 +550,9 @@ static int isl29018_chip_init(struct isl29018_chip *chip) return -ENODEV; /* Clear brownout bit */ - status = regmap_update_bits(chip->regmap, - ISL29035_REG_DEVICE_ID, - ISL29035_BOUT_MASK, 0); + status = regmap_clear_bits(chip->regmap, + ISL29035_REG_DEVICE_ID, + ISL29035_BOUT_MASK); if (status < 0) return status; } diff --git a/drivers/iio/light/st_uvis25_core.c b/drivers/iio/light/st_uvis25_core.c index d4e17079b2f4..fba3997574bb 100644 --- a/drivers/iio/light/st_uvis25_core.c +++ b/drivers/iio/light/st_uvis25_core.c @@ -330,8 +330,8 @@ static int st_uvis25_suspend(struct device *dev) struct iio_dev *iio_dev = dev_get_drvdata(dev); struct st_uvis25_hw *hw = iio_priv(iio_dev); - return regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR, - ST_UVIS25_REG_ODR_MASK, 0); + return regmap_clear_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR, + ST_UVIS25_REG_ODR_MASK); } static int st_uvis25_resume(struct device *dev) diff --git a/drivers/iio/light/veml6030.c b/drivers/iio/light/veml6030.c index 4be151308574..2e86d310952e 100644 --- a/drivers/iio/light/veml6030.c +++ b/drivers/iio/light/veml6030.c @@ -144,8 +144,8 @@ static const struct attribute_group veml6030_event_attr_group = { static int veml6030_als_pwr_on(struct veml6030_data *data) { - return regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF, - VEML6030_ALS_SD, 0); + return regmap_clear_bits(data->regmap, VEML6030_REG_ALS_CONF, + VEML6030_ALS_SD); } static int veml6030_als_shut_down(struct veml6030_data *data) diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c index d802034c5402..961b1e0bfb13 100644 --- a/drivers/iio/magnetometer/ak8974.c +++ b/drivers/iio/magnetometer/ak8974.c @@ -327,10 +327,7 @@ static int ak8974_trigmeas(struct ak8974 *ak8974) } /* Force a measurement */ - return regmap_update_bits(ak8974->map, - AK8974_CTRL3, - AK8974_CTRL3_FORCE, - AK8974_CTRL3_FORCE); + return regmap_set_bits(ak8974->map, AK8974_CTRL3, AK8974_CTRL3_FORCE); } static int ak8974_await_drdy(struct ak8974 *ak8974) @@ -438,10 +435,7 @@ static int ak8974_selftest(struct ak8974 *ak8974) } /* Trigger self-test */ - ret = regmap_update_bits(ak8974->map, - AK8974_CTRL3, - AK8974_CTRL3_SELFTEST, - AK8974_CTRL3_SELFTEST); + ret = regmap_set_bits(ak8974->map, AK8974_CTRL3, AK8974_CTRL3_SELFTEST); if (ret) { dev_err(dev, "could not write CTRL3\n"); return ret; diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c index c57932db455f..dd480a4a5f98 100644 --- a/drivers/iio/magnetometer/mmc35240.c +++ b/drivers/iio/magnetometer/mmc35240.c @@ -186,9 +186,8 @@ static int mmc35240_hw_set(struct mmc35240_data *data, bool set) * Recharge the capacitor at VCAP pin, requested to be issued * before a SET/RESET command. */ - ret = regmap_update_bits(data->regmap, MMC35240_REG_CTRL0, - MMC35240_CTRL0_REFILL_BIT, - MMC35240_CTRL0_REFILL_BIT); + ret = regmap_set_bits(data->regmap, MMC35240_REG_CTRL0, + MMC35240_CTRL0_REFILL_BIT); if (ret < 0) return ret; usleep_range(MMC35240_WAIT_CHARGE_PUMP, MMC35240_WAIT_CHARGE_PUMP + 1); @@ -198,8 +197,7 @@ static int mmc35240_hw_set(struct mmc35240_data *data, bool set) else coil_bit = MMC35240_CTRL0_RESET_BIT; - return regmap_update_bits(data->regmap, MMC35240_REG_CTRL0, - coil_bit, coil_bit); + return regmap_set_bits(data->regmap, MMC35240_REG_CTRL0, coil_bit); } diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 50d71ad83f37..49081b729618 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -1645,8 +1645,8 @@ static int bmp580_nvmem_write_impl(void *priv, unsigned int offset, void *val, goto exit; /* Disable programming mode bit */ - ret = regmap_update_bits(data->regmap, BMP580_REG_NVM_ADDR, - BMP580_NVM_PROG_EN, 0); + ret = regmap_clear_bits(data->regmap, BMP580_REG_NVM_ADDR, + BMP580_NVM_PROG_EN); if (ret) { dev_err(data->dev, "error resetting nvm write\n"); goto exit; diff --git a/drivers/iio/proximity/sx9324.c b/drivers/iio/proximity/sx9324.c index aa0d14a49d5e..629f83c37d59 100644 --- a/drivers/iio/proximity/sx9324.c +++ b/drivers/iio/proximity/sx9324.c @@ -835,9 +835,8 @@ static int sx9324_init_compensation(struct iio_dev *indio_dev) int ret; /* run the compensation phase on all channels */ - ret = regmap_update_bits(data->regmap, SX9324_REG_STAT2, - SX9324_REG_STAT2_COMPSTAT_MASK, - SX9324_REG_STAT2_COMPSTAT_MASK); + ret = regmap_set_bits(data->regmap, SX9324_REG_STAT2, + SX9324_REG_STAT2_COMPSTAT_MASK); if (ret) return ret; diff --git a/drivers/iio/proximity/sx9360.c b/drivers/iio/proximity/sx9360.c index 75a1c29f14eb..2b90bf45a201 100644 --- a/drivers/iio/proximity/sx9360.c +++ b/drivers/iio/proximity/sx9360.c @@ -672,9 +672,8 @@ static int sx9360_init_compensation(struct iio_dev *indio_dev) int ret; /* run the compensation phase on all channels */ - ret = regmap_update_bits(data->regmap, SX9360_REG_STAT, - SX9360_REG_STAT_COMPSTAT_MASK, - SX9360_REG_STAT_COMPSTAT_MASK); + ret = regmap_set_bits(data->regmap, SX9360_REG_STAT, + SX9360_REG_STAT_COMPSTAT_MASK); if (ret) return ret; diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index b89d49defd7a..92630812ece2 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -209,7 +209,7 @@ static int sx9500_inc_users(struct sx9500_data *data, int *counter, /* Bit is already active, nothing to do. */ return 0; - return regmap_update_bits(data->regmap, reg, bitmask, bitmask); + return regmap_set_bits(data->regmap, reg, bitmask); } static int sx9500_dec_users(struct sx9500_data *data, int *counter, @@ -220,7 +220,7 @@ static int sx9500_dec_users(struct sx9500_data *data, int *counter, /* There are more users, do not deactivate. */ return 0; - return regmap_update_bits(data->regmap, reg, bitmask, 0); + return regmap_clear_bits(data->regmap, reg, bitmask); } static int sx9500_inc_chan_users(struct sx9500_data *data, int chan) @@ -795,8 +795,8 @@ static int sx9500_init_compensation(struct iio_dev *indio_dev) int i, ret; unsigned int val; - ret = regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0, - SX9500_CHAN_MASK, SX9500_CHAN_MASK); + ret = regmap_set_bits(data->regmap, SX9500_REG_PROX_CTRL0, + SX9500_CHAN_MASK); if (ret < 0) return ret; @@ -815,8 +815,8 @@ static int sx9500_init_compensation(struct iio_dev *indio_dev) } out: - regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0, - SX9500_CHAN_MASK, 0); + regmap_clear_bits(data->regmap, SX9500_REG_PROX_CTRL0, + SX9500_CHAN_MASK); return ret; } diff --git a/drivers/iio/proximity/sx_common.c b/drivers/iio/proximity/sx_common.c index fe07d1444ac3..a95e9814aaf2 100644 --- a/drivers/iio/proximity/sx_common.c +++ b/drivers/iio/proximity/sx_common.c @@ -111,17 +111,16 @@ static int sx_common_enable_irq(struct sx_common_data *data, unsigned int irq) { if (!data->client->irq) return 0; - return regmap_update_bits(data->regmap, data->chip_info->reg_irq_msk, - irq << data->chip_info->irq_msk_offset, - irq << data->chip_info->irq_msk_offset); + return regmap_set_bits(data->regmap, data->chip_info->reg_irq_msk, + irq << data->chip_info->irq_msk_offset); } static int sx_common_disable_irq(struct sx_common_data *data, unsigned int irq) { if (!data->client->irq) return 0; - return regmap_update_bits(data->regmap, data->chip_info->reg_irq_msk, - irq << data->chip_info->irq_msk_offset, 0); + return regmap_clear_bits(data->regmap, data->chip_info->reg_irq_msk, + irq << data->chip_info->irq_msk_offset); } static int sx_common_update_chan_en(struct sx_common_data *data, diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c index 24d19f3c7292..21f2cfc55bf8 100644 --- a/drivers/iio/temperature/ltc2983.c +++ b/drivers/iio/temperature/ltc2983.c @@ -8,6 +8,8 @@ #include <linux/bitfield.h> #include <linux/completion.h> #include <linux/device.h> +#include <linux/err.h> +#include <linux/errno.h> #include <linux/kernel.h> #include <linux/iio/iio.h> #include <linux/interrupt.h> @@ -432,10 +434,9 @@ __ltc2983_custom_sensor_new(struct ltc2983_data *st, const struct fwnode_handle else n_entries = fwnode_property_count_u64(fn, propname); /* n_entries must be an even number */ - if (!n_entries || (n_entries % 2) != 0) { - dev_err(dev, "Number of entries either 0 or not even\n"); - return ERR_PTR(-EINVAL); - } + if (!n_entries || (n_entries % 2) != 0) + return dev_err_ptr_probe(dev, -EINVAL, + "Number of entries either 0 or not even\n"); new_custom = devm_kzalloc(dev, sizeof(*new_custom), GFP_KERNEL); if (!new_custom) @@ -443,19 +444,17 @@ __ltc2983_custom_sensor_new(struct ltc2983_data *st, const struct fwnode_handle new_custom->size = n_entries * n_size; /* check Steinhart size */ - if (is_steinhart && new_custom->size != LTC2983_CUSTOM_STEINHART_SIZE) { - dev_err(dev, "Steinhart sensors size(%zu) must be %u\n", new_custom->size, - LTC2983_CUSTOM_STEINHART_SIZE); - return ERR_PTR(-EINVAL); - } + if (is_steinhart && new_custom->size != LTC2983_CUSTOM_STEINHART_SIZE) + return dev_err_ptr_probe(dev, -EINVAL, + "Steinhart sensors size(%zu) must be %u\n", + new_custom->size, LTC2983_CUSTOM_STEINHART_SIZE); + /* Check space on the table. */ if (st->custom_table_size + new_custom->size > - (LTC2983_CUST_SENS_TBL_END_REG - - LTC2983_CUST_SENS_TBL_START_REG) + 1) { - dev_err(dev, "No space left(%d) for new custom sensor(%zu)", - st->custom_table_size, new_custom->size); - return ERR_PTR(-EINVAL); - } + (LTC2983_CUST_SENS_TBL_END_REG - LTC2983_CUST_SENS_TBL_START_REG) + 1) + return dev_err_ptr_probe(dev, -EINVAL, + "No space left(%d) for new custom sensor(%zu)\n", + st->custom_table_size, new_custom->size); /* allocate the table */ if (is_steinhart) @@ -688,21 +687,19 @@ ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data LTC2983_THERMOCOUPLE_OC_CURR(3); break; default: - dev_err(&st->spi->dev, - "Invalid open circuit current:%u", oc_current); - return ERR_PTR(-EINVAL); + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid open circuit current:%u\n", + oc_current); } thermo->sensor_config |= LTC2983_THERMOCOUPLE_OC_CHECK(1); } /* validate channel index */ if (!(thermo->sensor_config & LTC2983_THERMOCOUPLE_DIFF_MASK) && - sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) { - dev_err(&st->spi->dev, - "Invalid chann:%d for differential thermocouple", - sensor->chan); - return ERR_PTR(-EINVAL); - } + sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid chann:%d for differential thermocouple\n", + sensor->chan); struct fwnode_handle *ref __free(fwnode_handle) = fwnode_find_reference(child, "adi,cold-junction-handle", 0); @@ -710,14 +707,13 @@ ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data ref = NULL; } else { ret = fwnode_property_read_u32(ref, "reg", &thermo->cold_junction_chan); - if (ret) { + if (ret) /* * This would be catched later but we can just return * the error right away. */ - dev_err(&st->spi->dev, "Property reg must be given\n"); - return ERR_PTR(ret); - } + return dev_err_ptr_probe(&st->spi->dev, ret, + "Property reg must be given\n"); } /* check custom sensor */ @@ -753,16 +749,14 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, struct fwnode_handle *ref __free(fwnode_handle) = fwnode_find_reference(child, "adi,rsense-handle", 0); - if (IS_ERR(ref)) { - dev_err(dev, "Property adi,rsense-handle missing or invalid"); - return ERR_CAST(ref); - } + if (IS_ERR(ref)) + return dev_err_cast_probe(dev, ref, + "Property adi,rsense-handle missing or invalid\n"); ret = fwnode_property_read_u32(ref, "reg", &rtd->r_sense_chan); - if (ret) { - dev_err(dev, "Property reg must be given\n"); - return ERR_PTR(ret); - } + if (ret) + return dev_err_ptr_probe(dev, ret, + "Property reg must be given\n"); ret = fwnode_property_read_u32(child, "adi,number-of-wires", &n_wires); if (!ret) { @@ -781,19 +775,19 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, rtd->sensor_config = LTC2983_RTD_N_WIRES(3); break; default: - dev_err(dev, "Invalid number of wires:%u\n", n_wires); - return ERR_PTR(-EINVAL); + return dev_err_ptr_probe(dev, -EINVAL, + "Invalid number of wires:%u\n", + n_wires); } } if (fwnode_property_read_bool(child, "adi,rsense-share")) { /* Current rotation is only available with rsense sharing */ if (fwnode_property_read_bool(child, "adi,current-rotate")) { - if (n_wires == 2 || n_wires == 3) { - dev_err(dev, - "Rotation not allowed for 2/3 Wire RTDs"); - return ERR_PTR(-EINVAL); - } + if (n_wires == 2 || n_wires == 3) + return dev_err_ptr_probe(dev, -EINVAL, + "Rotation not allowed for 2/3 Wire RTDs\n"); + rtd->sensor_config |= LTC2983_RTD_C_ROTATE(1); } else { rtd->sensor_config |= LTC2983_RTD_R_SHARE(1); @@ -816,29 +810,22 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, if (((rtd->sensor_config & LTC2983_RTD_KELVIN_R_SENSE_MASK) == LTC2983_RTD_KELVIN_R_SENSE_MASK) && - (rtd->r_sense_chan <= min)) { + (rtd->r_sense_chan <= min)) /* kelvin rsense*/ - dev_err(dev, - "Invalid rsense chann:%d to use in kelvin rsense", - rtd->r_sense_chan); - - return ERR_PTR(-EINVAL); - } - - if (sensor->chan < min || sensor->chan > max) { - dev_err(dev, "Invalid chann:%d for the rtd config", - sensor->chan); - - return ERR_PTR(-EINVAL); - } + return dev_err_ptr_probe(dev, -EINVAL, + "Invalid rsense chann:%d to use in kelvin rsense\n", + rtd->r_sense_chan); + + if (sensor->chan < min || sensor->chan > max) + return dev_err_ptr_probe(dev, -EINVAL, + "Invalid chann:%d for the rtd config\n", + sensor->chan); } else { /* same as differential case */ - if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) { - dev_err(&st->spi->dev, - "Invalid chann:%d for RTD", sensor->chan); - - return ERR_PTR(-EINVAL); - } + if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid chann:%d for RTD\n", + sensor->chan); } /* check custom sensor */ @@ -886,10 +873,9 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, rtd->excitation_current = 0x08; break; default: - dev_err(&st->spi->dev, - "Invalid value for excitation current(%u)", - excitation_current); - return ERR_PTR(-EINVAL); + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid value for excitation current(%u)\n", + excitation_current); } } @@ -913,16 +899,14 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s struct fwnode_handle *ref __free(fwnode_handle) = fwnode_find_reference(child, "adi,rsense-handle", 0); - if (IS_ERR(ref)) { - dev_err(dev, "Property adi,rsense-handle missing or invalid"); - return ERR_CAST(ref); - } + if (IS_ERR(ref)) + return dev_err_cast_probe(dev, ref, + "Property adi,rsense-handle missing or invalid\n"); ret = fwnode_property_read_u32(ref, "reg", &thermistor->r_sense_chan); - if (ret) { - dev_err(dev, "rsense channel must be configured...\n"); - return ERR_PTR(ret); - } + if (ret) + return dev_err_ptr_probe(dev, ret, + "rsense channel must be configured...\n"); if (fwnode_property_read_bool(child, "adi,single-ended")) { thermistor->sensor_config = LTC2983_THERMISTOR_SGL(1); @@ -937,12 +921,10 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s } /* validate channel index */ if (!(thermistor->sensor_config & LTC2983_THERMISTOR_DIFF_MASK) && - sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) { - dev_err(&st->spi->dev, - "Invalid chann:%d for differential thermistor", - sensor->chan); - return ERR_PTR(-EINVAL); - } + sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid chann:%d for differential thermistor\n", + sensor->chan); /* check custom sensor */ if (sensor->type >= LTC2983_SENSOR_THERMISTOR_STEINHART) { @@ -981,12 +963,10 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s switch (excitation_current) { case 0: /* auto range */ - if (sensor->type >= - LTC2983_SENSOR_THERMISTOR_STEINHART) { - dev_err(&st->spi->dev, - "Auto Range not allowed for custom sensors\n"); - return ERR_PTR(-EINVAL); - } + if (sensor->type >= LTC2983_SENSOR_THERMISTOR_STEINHART) + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Auto Range not allowed for custom sensors\n"); + thermistor->excitation_current = 0x0c; break; case 250: @@ -1023,10 +1003,9 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s thermistor->excitation_current = 0x0b; break; default: - dev_err(&st->spi->dev, - "Invalid value for excitation current(%u)", - excitation_current); - return ERR_PTR(-EINVAL); + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid value for excitation current(%u)\n", + excitation_current); } } @@ -1056,12 +1035,11 @@ ltc2983_diode_new(const struct fwnode_handle *child, const struct ltc2983_data * /* validate channel index */ if (!(diode->sensor_config & LTC2983_DIODE_DIFF_MASK) && - sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) { - dev_err(&st->spi->dev, - "Invalid chann:%d for differential thermistor", - sensor->chan); - return ERR_PTR(-EINVAL); - } + sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid chann:%d for differential thermistor\n", + sensor->chan); + /* set common parameters */ diode->sensor.fault_handler = ltc2983_common_fault_handler; diode->sensor.assign_chan = ltc2983_diode_assign_chan; @@ -1083,10 +1061,9 @@ ltc2983_diode_new(const struct fwnode_handle *child, const struct ltc2983_data * diode->excitation_current = 0x03; break; default: - dev_err(&st->spi->dev, - "Invalid value for excitation current(%u)", - excitation_current); - return ERR_PTR(-EINVAL); + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid value for excitation current(%u)\n", + excitation_current); } } @@ -1111,17 +1088,15 @@ static struct ltc2983_sensor *ltc2983_r_sense_new(struct fwnode_handle *child, return ERR_PTR(-ENOMEM); /* validate channel index */ - if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) { - dev_err(&st->spi->dev, "Invalid chann:%d for r_sense", - sensor->chan); - return ERR_PTR(-EINVAL); - } + if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid chann:%d for r_sense\n", + sensor->chan); ret = fwnode_property_read_u32(child, "adi,rsense-val-milli-ohms", &temp); - if (ret) { - dev_err(&st->spi->dev, "Property adi,rsense-val-milli-ohms missing\n"); - return ERR_PTR(-EINVAL); - } + if (ret) + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Property adi,rsense-val-milli-ohms missing\n"); /* * Times 1000 because we have milli-ohms and __convert_to_raw * expects scales of 1000000 which are used for all other @@ -1149,12 +1124,11 @@ static struct ltc2983_sensor *ltc2983_adc_new(struct fwnode_handle *child, if (fwnode_property_read_bool(child, "adi,single-ended")) adc->single_ended = true; - if (!adc->single_ended && - sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) { - dev_err(&st->spi->dev, "Invalid chan:%d for differential adc\n", - sensor->chan); - return ERR_PTR(-EINVAL); - } + if (!adc->single_ended && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid chan:%d for differential adc\n", + sensor->chan); + /* set common parameters */ adc->sensor.assign_chan = ltc2983_adc_assign_chan; adc->sensor.fault_handler = ltc2983_common_fault_handler; @@ -1175,12 +1149,10 @@ static struct ltc2983_sensor *ltc2983_temp_new(struct fwnode_handle *child, if (fwnode_property_read_bool(child, "adi,single-ended")) temp->single_ended = true; - if (!temp->single_ended && - sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) { - dev_err(&st->spi->dev, "Invalid chan:%d for differential temp\n", - sensor->chan); - return ERR_PTR(-EINVAL); - } + if (!temp->single_ended && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid chan:%d for differential temp\n", + sensor->chan); temp->custom = __ltc2983_custom_sensor_new(st, child, "adi,custom-temp", false, 4096, true); @@ -1296,8 +1268,8 @@ static int ltc2983_reg_access(struct iio_dev *indio_dev, if (readval) return regmap_read(st->regmap, reg, readval); - else - return regmap_write(st->regmap, reg, writeval); + + return regmap_write(st->regmap, reg, writeval); } static irqreturn_t ltc2983_irq_handler(int irq, void *data) @@ -1330,10 +1302,9 @@ static int ltc2983_parse_fw(struct ltc2983_data *st) device_property_read_u32(dev, "adi,filter-notch-freq", &st->filter_notch_freq); st->num_channels = device_get_child_node_count(dev); - if (!st->num_channels) { - dev_err(&st->spi->dev, "At least one channel must be given!"); - return -EINVAL; - } + if (!st->num_channels) + return dev_err_probe(&st->spi->dev, -EINVAL, + "At least one channel must be given!\n"); st->sensors = devm_kcalloc(dev, st->num_channels, sizeof(*st->sensors), GFP_KERNEL); @@ -1438,19 +1409,17 @@ static int ltc2983_eeprom_cmd(struct ltc2983_data *st, unsigned int cmd, time = wait_for_completion_timeout(&st->completion, msecs_to_jiffies(wait_time)); - if (!time) { - dev_err(&st->spi->dev, "EEPROM command timed out\n"); - return -ETIMEDOUT; - } + if (!time) + return dev_err_probe(&st->spi->dev, -ETIMEDOUT, + "EEPROM command timed out\n"); ret = regmap_read(st->regmap, status_reg, &val); if (ret) return ret; - if (val & status_fail_mask) { - dev_err(&st->spi->dev, "EEPROM command failed: 0x%02X\n", val); - return -EINVAL; - } + if (val & status_fail_mask) + return dev_err_probe(&st->spi->dev, -EINVAL, + "EEPROM command failed: 0x%02X\n", val); return 0; } @@ -1464,10 +1433,9 @@ static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio) ret = regmap_read_poll_timeout(st->regmap, LTC2983_STATUS_REG, status, LTC2983_STATUS_UP(status) == 1, 25000, 25000 * 10); - if (ret) { - dev_err(&st->spi->dev, "Device startup timed out\n"); - return ret; - } + if (ret) + return dev_err_probe(&st->spi->dev, ret, + "Device startup timed out\n"); ret = regmap_update_bits(st->regmap, LTC2983_GLOBAL_CONFIG_REG, LTC2983_NOTCH_FREQ_MASK, @@ -1583,10 +1551,9 @@ static int ltc2983_probe(struct spi_device *spi) return -ENODEV; st->regmap = devm_regmap_init_spi(spi, <c2983_regmap_config); - if (IS_ERR(st->regmap)) { - dev_err(&spi->dev, "Failed to initialize regmap\n"); - return PTR_ERR(st->regmap); - } + if (IS_ERR(st->regmap)) + return dev_err_probe(&spi->dev, PTR_ERR(st->regmap), + "Failed to initialize regmap\n"); mutex_init(&st->lock); init_completion(&st->completion); @@ -1624,10 +1591,9 @@ static int ltc2983_probe(struct spi_device *spi) ret = devm_request_irq(&spi->dev, spi->irq, ltc2983_irq_handler, IRQF_TRIGGER_RISING, st->info->name, st); - if (ret) { - dev_err(&spi->dev, "failed to request an irq, %d", ret); - return ret; - } + if (ret) + return dev_err_probe(&spi->dev, ret, + "failed to request an irq\n"); if (st->info->has_eeprom) { ret = ltc2983_eeprom_cmd(st, LTC2983_EEPROM_WRITE_CMD, diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c index 4676e0edde4a..ae4ea587e7f9 100644 --- a/drivers/iio/temperature/mlx90632.c +++ b/drivers/iio/temperature/mlx90632.c @@ -334,8 +334,8 @@ static int mlx90632_perform_measurement(struct mlx90632_data *data) unsigned int reg_status; int ret; - ret = regmap_update_bits(data->regmap, MLX90632_REG_STATUS, - MLX90632_STAT_DATA_RDY, 0); + ret = regmap_clear_bits(data->regmap, MLX90632_REG_STATUS, + MLX90632_STAT_DATA_RDY); if (ret < 0) return ret; diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c index d76444030a28..0684329956d9 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -158,7 +158,7 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv, regmap_write(priv->regmap, TIM_PSC, prescaler); regmap_write(priv->regmap, TIM_ARR, prd - 1); - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE); + regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE); /* Force master mode to update mode */ if (stm32_timer_is_trgo2_name(trig->name)) @@ -169,10 +169,10 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv, 0x2 << TIM_CR2_MMS_SHIFT); /* Make sure that registers are updated */ - regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); + regmap_set_bits(priv->regmap, TIM_EGR, TIM_EGR_UG); /* Enable controller */ - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN); + regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); mutex_unlock(&priv->lock); return 0; @@ -189,19 +189,19 @@ static void stm32_timer_stop(struct stm32_timer_trigger *priv, mutex_lock(&priv->lock); /* Stop timer */ - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0); - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); + regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE); + regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); regmap_write(priv->regmap, TIM_PSC, 0); regmap_write(priv->regmap, TIM_ARR, 0); /* Force disable master mode */ if (stm32_timer_is_trgo2_name(trig->name)) - regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, 0); + regmap_clear_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2); else - regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS, 0); + regmap_clear_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS); /* Make sure that registers are updated */ - regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); + regmap_set_bits(priv->regmap, TIM_EGR, TIM_EGR_UG); if (priv->enabled) { priv->enabled = false; @@ -498,11 +498,9 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev, priv->enabled = true; clk_enable(priv->clk); } - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, - TIM_CR1_CEN); + regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); } else { - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, - 0); + regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); if (priv->enabled) { priv->enabled = false; clk_disable(priv->clk); @@ -555,7 +553,7 @@ static int stm32_set_trigger_mode(struct iio_dev *indio_dev, { struct stm32_timer_trigger *priv = iio_priv(indio_dev); - regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, TIM_SMCR_SMS); + regmap_set_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS); return 0; } @@ -683,7 +681,7 @@ static ssize_t stm32_count_set_preset(struct iio_dev *indio_dev, return ret; /* TIMx_ARR register shouldn't be buffered (ARPE=0) */ - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0); + regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE); regmap_write(priv->regmap, TIM_ARR, preset); return len; @@ -757,9 +755,9 @@ static void stm32_timer_detect_trgo2(struct stm32_timer_trigger *priv) * Master mode selection 2 bits can only be written and read back when * timer supports it. */ - regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, TIM_CR2_MMS2); + regmap_set_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2); regmap_read(priv->regmap, TIM_CR2, &val); - regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, 0); + regmap_clear_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2); priv->has_trgo2 = !!val; } @@ -820,7 +818,7 @@ static void stm32_timer_trigger_remove(struct platform_device *pdev) /* Check if nobody else use the timer, then disable it */ regmap_read(priv->regmap, TIM_CCER, &val); if (!(val & TIM_CCER_CCXE)) - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); + regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); if (priv->enabled) clk_disable(priv->clk); @@ -841,7 +839,7 @@ static int stm32_timer_trigger_suspend(struct device *dev) regmap_read(priv->regmap, TIM_SMCR, &priv->bak.smcr); /* Disable the timer */ - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); + regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); clk_disable(priv->clk); } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index fc13fa192189..c957a7710777 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -4382,6 +4382,34 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) return ctlr->transfer(spi, message); } +static void devm_spi_unoptimize_message(void *msg) +{ + spi_unoptimize_message(msg); +} + +/** + * devm_spi_optimize_message - managed version of spi_optimize_message() + * @dev: the device that manages @msg (usually @spi->dev) + * @spi: the device that will be used for the message + * @msg: the message to optimize + * Return: zero on success, else a negative error code + * + * spi_unoptimize_message() will automatically be called when the device is + * removed. + */ +int devm_spi_optimize_message(struct device *dev, struct spi_device *spi, + struct spi_message *msg) +{ + int ret; + + ret = spi_optimize_message(spi, msg); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, devm_spi_unoptimize_message, msg); +} +EXPORT_SYMBOL_GPL(devm_spi_optimize_message); + /** * spi_async - asynchronous SPI transfer * @spi: device with which data will be exchanged diff --git a/include/dt-bindings/iio/adc/mediatek,mt6357-auxadc.h b/include/dt-bindings/iio/adc/mediatek,mt6357-auxadc.h new file mode 100644 index 000000000000..03ebb1d23953 --- /dev/null +++ b/include/dt-bindings/iio/adc/mediatek,mt6357-auxadc.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ + +#ifndef _DT_BINDINGS_MEDIATEK_MT6357_AUXADC_H +#define _DT_BINDINGS_MEDIATEK_MT6357_AUXADC_H + +/* ADC Channel Index */ +#define MT6357_AUXADC_BATADC 0 +#define MT6357_AUXADC_ISENSE 1 +#define MT6357_AUXADC_VCDT 2 +#define MT6357_AUXADC_BAT_TEMP 3 +#define MT6357_AUXADC_CHIP_TEMP 4 +#define MT6357_AUXADC_ACCDET 5 +#define MT6357_AUXADC_VDCXO 6 +#define MT6357_AUXADC_TSX_TEMP 7 +#define MT6357_AUXADC_HPOFS_CAL 8 +#define MT6357_AUXADC_DCXO_TEMP 9 +#define MT6357_AUXADC_VCORE_TEMP 10 +#define MT6357_AUXADC_VPROC_TEMP 11 +#define MT6357_AUXADC_VBAT 12 + +#endif diff --git a/include/dt-bindings/iio/adc/mediatek,mt6358-auxadc.h b/include/dt-bindings/iio/adc/mediatek,mt6358-auxadc.h new file mode 100644 index 000000000000..efa08398fafd --- /dev/null +++ b/include/dt-bindings/iio/adc/mediatek,mt6358-auxadc.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ + +#ifndef _DT_BINDINGS_MEDIATEK_MT6358_AUXADC_H +#define _DT_BINDINGS_MEDIATEK_MT6358_AUXADC_H + +/* ADC Channel Index */ +#define MT6358_AUXADC_BATADC 0 +#define MT6358_AUXADC_VCDT 1 +#define MT6358_AUXADC_BAT_TEMP 2 +#define MT6358_AUXADC_CHIP_TEMP 3 +#define MT6358_AUXADC_ACCDET 4 +#define MT6358_AUXADC_VDCXO 5 +#define MT6358_AUXADC_TSX_TEMP 6 +#define MT6358_AUXADC_HPOFS_CAL 7 +#define MT6358_AUXADC_DCXO_TEMP 8 +#define MT6358_AUXADC_VBIF 9 +#define MT6358_AUXADC_VCORE_TEMP 10 +#define MT6358_AUXADC_VPROC_TEMP 11 +#define MT6358_AUXADC_VGPU_TEMP 12 +#define MT6358_AUXADC_VBAT 13 + +#endif diff --git a/include/dt-bindings/iio/adc/mediatek,mt6359-auxadc.h b/include/dt-bindings/iio/adc/mediatek,mt6359-auxadc.h new file mode 100644 index 000000000000..59826393ee7e --- /dev/null +++ b/include/dt-bindings/iio/adc/mediatek,mt6359-auxadc.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ + +#ifndef _DT_BINDINGS_MEDIATEK_MT6359_AUXADC_H +#define _DT_BINDINGS_MEDIATEK_MT6359_AUXADC_H + +/* ADC Channel Index */ +#define MT6359_AUXADC_BATADC 0 +#define MT6359_AUXADC_BAT_TEMP 1 +#define MT6359_AUXADC_CHIP_TEMP 2 +#define MT6359_AUXADC_ACCDET 3 +#define MT6359_AUXADC_VDCXO 4 +#define MT6359_AUXADC_TSX_TEMP 5 +#define MT6359_AUXADC_HPOFS_CAL 6 +#define MT6359_AUXADC_DCXO_TEMP 7 +#define MT6359_AUXADC_VBIF 8 +#define MT6359_AUXADC_VCORE_TEMP 9 +#define MT6359_AUXADC_VPROC_TEMP 10 +#define MT6359_AUXADC_VGPU_TEMP 11 +#define MT6359_AUXADC_VBAT 12 +#define MT6359_AUXADC_IBAT 13 + +#endif diff --git a/include/linux/dev_printk.h b/include/linux/dev_printk.h index ae80a303c216..ca32b5bb28eb 100644 --- a/include/linux/dev_printk.h +++ b/include/linux/dev_printk.h @@ -277,4 +277,12 @@ do { \ __printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...); +/* Simple helper for dev_err_probe() when ERR_PTR() is to be returned. */ +#define dev_err_ptr_probe(dev, ___err, fmt, ...) \ + ERR_PTR(dev_err_probe(dev, ___err, fmt, ##__VA_ARGS__)) + +/* Simple helper for dev_err_probe() when ERR_CAST() is to be returned. */ +#define dev_err_cast_probe(dev, ___err_ptr, fmt, ...) \ + ERR_PTR(dev_err_probe(dev, PTR_ERR(___err_ptr), fmt, ##__VA_ARGS__)) + #endif /* _DEVICE_PRINTK_H_ */ diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 752dbde4cec1..9fc03068cabc 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -161,6 +161,16 @@ struct dma_interleaved_template { }; /** + * struct dma_vec - DMA vector + * @addr: Bus address of the start of the vector + * @len: Length in bytes of the DMA vector + */ +struct dma_vec { + dma_addr_t addr; + size_t len; +}; + +/** * enum dma_ctrl_flags - DMA flags to augment operation preparation, * control completion, and communicate status. * @DMA_PREP_INTERRUPT - trigger an interrupt (callback) upon completion of @@ -910,6 +920,10 @@ struct dma_device { struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)( struct dma_chan *chan, unsigned long flags); + struct dma_async_tx_descriptor *(*device_prep_peripheral_dma_vec)( + struct dma_chan *chan, const struct dma_vec *vecs, + size_t nents, enum dma_transfer_direction direction, + unsigned long flags); struct dma_async_tx_descriptor *(*device_prep_slave_sg)( struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, enum dma_transfer_direction direction, @@ -973,6 +987,25 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_single( dir, flags, NULL); } +/** + * dmaengine_prep_peripheral_dma_vec() - Prepare a DMA scatter-gather descriptor + * @chan: The channel to be used for this descriptor + * @vecs: The array of DMA vectors that should be transferred + * @nents: The number of DMA vectors in the array + * @dir: Specifies the direction of the data transfer + * @flags: DMA engine flags + */ +static inline struct dma_async_tx_descriptor *dmaengine_prep_peripheral_dma_vec( + struct dma_chan *chan, const struct dma_vec *vecs, size_t nents, + enum dma_transfer_direction dir, unsigned long flags) +{ + if (!chan || !chan->device || !chan->device->device_prep_peripheral_dma_vec) + return NULL; + + return chan->device->device_prep_peripheral_dma_vec(chan, vecs, nents, + dir, flags); +} + static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_sg( struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, enum dma_transfer_direction dir, unsigned long flags) diff --git a/include/linux/iio/adc/ad_sigma_delta.h b/include/linux/iio/adc/ad_sigma_delta.h index 383614ebd760..f8c1d2505940 100644 --- a/include/linux/iio/adc/ad_sigma_delta.h +++ b/include/linux/iio/adc/ad_sigma_delta.h @@ -37,6 +37,10 @@ struct iio_dev; * @append_status: Will be called to enable status append at the end of the sample, may be NULL. * @set_mode: Will be called to select the current mode, may be NULL. * @disable_all: Will be called to disable all channels, may be NULL. + * @disable_one: Will be called to disable a single channel after + * ad_sigma_delta_single_conversion(), may be NULL. + * Usage of this callback expects iio_chan_spec.address to contain + * the value required for the driver to identify the channel. * @postprocess_sample: Is called for each sampled data word, can be used to * modify or drop the sample data, it, may be NULL. * @has_registers: true if the device has writable and readable registers, false @@ -55,6 +59,7 @@ struct ad_sigma_delta_info { int (*append_status)(struct ad_sigma_delta *, bool append); int (*set_mode)(struct ad_sigma_delta *, enum ad_sigma_delta_mode mode); int (*disable_all)(struct ad_sigma_delta *); + int (*disable_one)(struct ad_sigma_delta *, unsigned int chan); int (*postprocess_sample)(struct ad_sigma_delta *, unsigned int raw_sample); bool has_registers; unsigned int addr_shift; @@ -140,6 +145,15 @@ static inline int ad_sigma_delta_disable_all(struct ad_sigma_delta *sd) return 0; } +static inline int ad_sigma_delta_disable_one(struct ad_sigma_delta *sd, + unsigned int chan) +{ + if (sd->info->disable_one) + return sd->info->disable_one(sd, chan); + + return 0; +} + static inline int ad_sigma_delta_set_mode(struct ad_sigma_delta *sd, unsigned int mode) { diff --git a/include/linux/iio/buffer-dma.h b/include/linux/iio/buffer-dma.h index 6e27e47077d5..5eb66a399002 100644 --- a/include/linux/iio/buffer-dma.h +++ b/include/linux/iio/buffer-dma.h @@ -7,6 +7,7 @@ #ifndef __INDUSTRIALIO_DMA_BUFFER_H__ #define __INDUSTRIALIO_DMA_BUFFER_H__ +#include <linux/atomic.h> #include <linux/list.h> #include <linux/kref.h> #include <linux/spinlock.h> @@ -16,6 +17,9 @@ struct iio_dma_buffer_queue; struct iio_dma_buffer_ops; struct device; +struct dma_buf_attachment; +struct dma_fence; +struct sg_table; /** * enum iio_block_state - State of a struct iio_dma_buffer_block @@ -41,6 +45,10 @@ enum iio_block_state { * @queue: Parent DMA buffer queue * @kref: kref used to manage the lifetime of block * @state: Current state of the block + * @cyclic: True if this is a cyclic buffer + * @fileio: True if this buffer is used for fileio mode + * @sg_table: DMA table for the transfer when transferring a DMABUF + * @fence: DMA fence to be signaled when a DMABUF transfer is complete */ struct iio_dma_buffer_block { /* May only be accessed by the owner of the block */ @@ -63,6 +71,12 @@ struct iio_dma_buffer_block { * queue->list_lock if the block is not owned by the core. */ enum iio_block_state state; + + bool cyclic; + bool fileio; + + struct sg_table *sg_table; + struct dma_fence *fence; }; /** @@ -72,6 +86,7 @@ struct iio_dma_buffer_block { * @pos: Read offset in the active block * @block_size: Size of each block * @next_dequeue: index of next block that will be dequeued + * @enabled: Whether the buffer is operating in fileio mode */ struct iio_dma_buffer_queue_fileio { struct iio_dma_buffer_block *blocks[2]; @@ -80,6 +95,7 @@ struct iio_dma_buffer_queue_fileio { size_t block_size; unsigned int next_dequeue; + bool enabled; }; /** @@ -95,6 +111,7 @@ struct iio_dma_buffer_queue_fileio { * the DMA controller * @incoming: List of buffers on the incoming queue * @active: Whether the buffer is currently active + * @num_dmabufs: Total number of DMABUFs attached to this queue * @fileio: FileIO state */ struct iio_dma_buffer_queue { @@ -107,6 +124,7 @@ struct iio_dma_buffer_queue { struct list_head incoming; bool active; + atomic_t num_dmabufs; struct iio_dma_buffer_queue_fileio fileio; }; @@ -144,4 +162,17 @@ int iio_dma_buffer_init(struct iio_dma_buffer_queue *queue, void iio_dma_buffer_exit(struct iio_dma_buffer_queue *queue); void iio_dma_buffer_release(struct iio_dma_buffer_queue *queue); +struct iio_dma_buffer_block * +iio_dma_buffer_attach_dmabuf(struct iio_buffer *buffer, + struct dma_buf_attachment *attach); +void iio_dma_buffer_detach_dmabuf(struct iio_buffer *buffer, + struct iio_dma_buffer_block *block); +int iio_dma_buffer_enqueue_dmabuf(struct iio_buffer *buffer, + struct iio_dma_buffer_block *block, + struct dma_fence *fence, + struct sg_table *sgt, + size_t size, bool cyclic); +void iio_dma_buffer_lock_queue(struct iio_buffer *buffer); +void iio_dma_buffer_unlock_queue(struct iio_buffer *buffer); + #endif diff --git a/include/linux/iio/buffer_impl.h b/include/linux/iio/buffer_impl.h index 89c3fd7c29ca..e72552e026f3 100644 --- a/include/linux/iio/buffer_impl.h +++ b/include/linux/iio/buffer_impl.h @@ -9,8 +9,12 @@ #include <uapi/linux/iio/buffer.h> #include <linux/iio/buffer.h> +struct dma_buf_attachment; +struct dma_fence; struct iio_dev; +struct iio_dma_buffer_block; struct iio_buffer; +struct sg_table; /** * INDIO_BUFFER_FLAG_FIXED_WATERMARK - Watermark level of the buffer can not be @@ -39,6 +43,16 @@ struct iio_buffer; * device stops sampling. Calles are balanced with @enable. * @release: called when the last reference to the buffer is dropped, * should free all resources allocated by the buffer. + * @attach_dmabuf: called from userspace via ioctl to attach one external + * DMABUF. + * @detach_dmabuf: called from userspace via ioctl to detach one previously + * attached DMABUF. + * @enqueue_dmabuf: called from userspace via ioctl to queue this DMABUF + * object to this buffer. Requires a valid DMABUF fd, that + * was previouly attached to this buffer. + * @lock_queue: called when the core needs to lock the buffer queue; + * it is used when enqueueing DMABUF objects. + * @unlock_queue: used to unlock a previously locked buffer queue * @modes: Supported operating modes by this buffer type * @flags: A bitmask combination of INDIO_BUFFER_FLAG_* * @@ -68,6 +82,17 @@ struct iio_buffer_access_funcs { void (*release)(struct iio_buffer *buffer); + struct iio_dma_buffer_block * (*attach_dmabuf)(struct iio_buffer *buffer, + struct dma_buf_attachment *attach); + void (*detach_dmabuf)(struct iio_buffer *buffer, + struct iio_dma_buffer_block *block); + int (*enqueue_dmabuf)(struct iio_buffer *buffer, + struct iio_dma_buffer_block *block, + struct dma_fence *fence, struct sg_table *sgt, + size_t size, bool cyclic); + void (*lock_queue)(struct iio_buffer *buffer); + void (*unlock_queue)(struct iio_buffer *buffer); + unsigned int modes; unsigned int flags; }; @@ -136,6 +161,12 @@ struct iio_buffer { /* @ref: Reference count of the buffer. */ struct kref ref; + + /* @dmabufs: List of DMABUF attachments */ + struct list_head dmabufs; /* P: dmabufs_mutex */ + + /* @dmabufs_mutex: Protects dmabufs */ + struct mutex dmabufs_mutex; }; /** @@ -159,6 +190,8 @@ void iio_buffer_init(struct iio_buffer *buffer); struct iio_buffer *iio_buffer_get(struct iio_buffer *buffer); void iio_buffer_put(struct iio_buffer *buffer); +void iio_buffer_signal_dmabuf_done(struct dma_fence *fence, int ret); + #else /* CONFIG_IIO_BUFFER */ static inline void iio_buffer_get(struct iio_buffer *buffer) {} diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index e9910b41d48e..333d1d8ccb37 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h @@ -441,4 +441,14 @@ ssize_t iio_read_channel_ext_info(struct iio_channel *chan, ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr, const char *buf, size_t len); +/** + * iio_read_channel_label() - read label for a given channel + * @chan: The channel being queried. + * @buf: Where to store the attribute value. Assumed to hold + * at least PAGE_SIZE bytes. + * + * Returns the number of bytes written to buf, or an error code. + */ +ssize_t iio_read_channel_label(struct iio_channel *chan, char *buf); + #endif diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h index 4bb0a53cf7ea..e6a75356567a 100644 --- a/include/linux/iio/imu/adis.h +++ b/include/linux/iio/imu/adis.h @@ -9,6 +9,7 @@ #ifndef __IIO_ADIS_H__ #define __IIO_ADIS_H__ +#include <linux/cleanup.h> #include <linux/spi/spi.h> #include <linux/interrupt.h> #include <linux/iio/iio.h> @@ -150,13 +151,8 @@ int __adis_reset(struct adis *adis); */ static inline int adis_reset(struct adis *adis) { - int ret; - - mutex_lock(&adis->state_lock); - ret = __adis_reset(adis); - mutex_unlock(&adis->state_lock); - - return ret; + guard(mutex)(&adis->state_lock); + return __adis_reset(adis); } int __adis_write_reg(struct adis *adis, unsigned int reg, @@ -248,13 +244,8 @@ static inline int __adis_read_reg_32(struct adis *adis, unsigned int reg, static inline int adis_write_reg(struct adis *adis, unsigned int reg, unsigned int val, unsigned int size) { - int ret; - - mutex_lock(&adis->state_lock); - ret = __adis_write_reg(adis, reg, val, size); - mutex_unlock(&adis->state_lock); - - return ret; + guard(mutex)(&adis->state_lock); + return __adis_write_reg(adis, reg, val, size); } /** @@ -267,13 +258,8 @@ static inline int adis_write_reg(struct adis *adis, unsigned int reg, static int adis_read_reg(struct adis *adis, unsigned int reg, unsigned int *val, unsigned int size) { - int ret; - - mutex_lock(&adis->state_lock); - ret = __adis_read_reg(adis, reg, val, size); - mutex_unlock(&adis->state_lock); - - return ret; + guard(mutex)(&adis->state_lock); + return __adis_read_reg(adis, reg, val, size); } /** @@ -365,12 +351,8 @@ int __adis_update_bits_base(struct adis *adis, unsigned int reg, const u32 mask, 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; + guard(mutex)(&adis->state_lock); + return __adis_update_bits_base(adis, reg, mask, val, size); } /** @@ -411,35 +393,19 @@ int __adis_enable_irq(struct adis *adis, bool enable); static inline int adis_enable_irq(struct adis *adis, bool enable) { - int ret; - - mutex_lock(&adis->state_lock); - ret = __adis_enable_irq(adis, enable); - mutex_unlock(&adis->state_lock); - - return ret; + guard(mutex)(&adis->state_lock); + return __adis_enable_irq(adis, enable); } static inline int adis_check_status(struct adis *adis) { - int ret; - - mutex_lock(&adis->state_lock); - ret = __adis_check_status(adis); - mutex_unlock(&adis->state_lock); - - return ret; -} - -static inline void adis_dev_lock(struct adis *adis) -{ - mutex_lock(&adis->state_lock); + guard(mutex)(&adis->state_lock); + return __adis_check_status(adis); } -static inline void adis_dev_unlock(struct adis *adis) -{ - mutex_unlock(&adis->state_lock); -} +#define adis_dev_auto_lock(adis) guard(mutex)(&(adis)->state_lock) +#define adis_dev_auto_scoped_lock(adis) \ + scoped_guard(mutex, &(adis)->state_lock) int adis_single_conversion(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, diff --git a/include/linux/math.h b/include/linux/math.h index dd4152711de7..f5f18dc3616b 100644 --- a/include/linux/math.h +++ b/include/linux/math.h @@ -112,6 +112,8 @@ struct type##_fract { \ __##type numerator; \ __##type denominator; \ }; +__STRUCT_FRACT(s8) +__STRUCT_FRACT(u8) __STRUCT_FRACT(s16) __STRUCT_FRACT(u16) __STRUCT_FRACT(s32) diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 98fdef6e28f2..8f119f355632 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -1269,6 +1269,8 @@ static inline void spi_message_free(struct spi_message *m) extern int spi_optimize_message(struct spi_device *spi, struct spi_message *msg); extern void spi_unoptimize_message(struct spi_message *msg); +extern int devm_spi_optimize_message(struct device *dev, struct spi_device *spi, + struct spi_message *msg); extern int spi_setup(struct spi_device *spi); extern int spi_async(struct spi_device *spi, struct spi_message *message); diff --git a/include/uapi/linux/iio/buffer.h b/include/uapi/linux/iio/buffer.h index 13939032b3f6..c666aa95e532 100644 --- a/include/uapi/linux/iio/buffer.h +++ b/include/uapi/linux/iio/buffer.h @@ -5,6 +5,28 @@ #ifndef _UAPI_IIO_BUFFER_H_ #define _UAPI_IIO_BUFFER_H_ +#include <linux/types.h> + +/* Flags for iio_dmabuf.flags */ +#define IIO_BUFFER_DMABUF_CYCLIC (1 << 0) +#define IIO_BUFFER_DMABUF_SUPPORTED_FLAGS 0x00000001 + +/** + * struct iio_dmabuf - Descriptor for a single IIO DMABUF object + * @fd: file descriptor of the DMABUF object + * @flags: one or more IIO_BUFFER_DMABUF_* flags + * @bytes_used: number of bytes used in this DMABUF for the data transfer. + * Should generally be set to the DMABUF's size. + */ +struct iio_dmabuf { + __u32 fd; + __u32 flags; + __u64 bytes_used; +}; + #define IIO_BUFFER_GET_FD_IOCTL _IOWR('i', 0x91, int) +#define IIO_BUFFER_DMABUF_ATTACH_IOCTL _IOW('i', 0x92, int) +#define IIO_BUFFER_DMABUF_DETACH_IOCTL _IOW('i', 0x93, int) +#define IIO_BUFFER_DMABUF_ENQUEUE_IOCTL _IOW('i', 0x94, struct iio_dmabuf) #endif /* _UAPI_IIO_BUFFER_H_ */ |