diff options
| author | Mark Brown <broonie@kernel.org> | 2026-07-26 23:41:46 +0100 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-07-26 23:41:46 +0100 |
| commit | 28e1889f3f4ae563843a7660400f8cc2cc2ac6fd (patch) | |
| tree | 381af8d1366579551e9e52bda644af061aefb6db | |
| parent | e383a013dff77eb3faee677e99b2d83b2a4865c7 (diff) | |
| parent | 0506462caaecb179708657142575823177c83783 (diff) | |
| download | linux-next-28e1889f3f4ae563843a7660400f8cc2cc2ac6fd.tar.gz linux-next-28e1889f3f4ae563843a7660400f8cc2cc2ac6fd.zip | |
Merge branch 'togreg' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git
351 files changed, 10490 insertions, 2262 deletions
@@ -885,6 +885,7 @@ Tobias Klauser <tklauser@distanz.ch> <klto@zhaw.ch> Tobias Klauser <tklauser@distanz.ch> <tklauser@nuerscht.ch> Tobias Klauser <tklauser@distanz.ch> <tklauser@xenon.tklauser.home> Todor Tomov <todor.too@gmail.com> <todor.tomov@linaro.org> +Tomasz Duszynski <tduszyns@gmail.com> <tomasz.duszynski@octakon.com> Tomasz Jeznach <tomasz.jeznach@linux.dev> <tjeznach@rivosinc.com> Tony Luck <tony.luck@intel.com> Trilok Soni <quic_tsoni@quicinc.com> <tsoni@codeaurora.org> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index d8d6d85235b0..5cc2e82c4997 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -770,6 +770,7 @@ Description: 3.85kohm_to_gnd: connected to ground via a 3.85kOhm resistor, 6kohm_to_gnd: connected to ground via a 6kOhm resistor, 7.7kohm_to_gnd: connected to ground via a 7.7kOhm resistor, + 10kohm_to_gnd: connected to ground via a 10kOhm resistor, 16kohm_to_gnd: connected to ground via a 16kOhm resistor, 20kohm_to_gnd: connected to ground via a 20kOhm resistor, 32kohm_to_gnd: connected to ground via a 32kOhm resistor, @@ -917,7 +918,7 @@ Description: Note the driver will assume the last p events requested are to be enabled where p is how many it supports (which may vary - depending on the exact set requested. So if you want to be + depending on the exact set requested). So if you want to be sure you have set what you think you have, check the contents of these attributes after everything is configured. Drivers may have to buffer any parameters so that they are consistent when @@ -973,7 +974,7 @@ Description: Note the driver will assume the last p events requested are to be enabled where p is however many it supports (which may - vary depending on the exact set requested. So if you want to be + vary depending on the exact set requested). So if you want to be sure you have set what you think you have, check the contents of these attributes after everything is configured. Drivers may have to buffer any parameters so that they are consistent when @@ -1528,9 +1529,9 @@ Description: the unused bits, so to get a clean value the bits value must be used to mask the buffer output value appropriately. The storagebits value also specifies the data alignment. So s48/64>>2 will be a - signed 48 bit integer stored in a 64 bit location aligned to a 64 - bit boundary. To obtain the clean value, shift right 2 and apply a - mask to zero the top 16 bits of the result. + signed 48-bit integer stored in a 64-bit location aligned to a + 64-bit boundary. To obtain the clean value, shift right 2 and apply + a mask to zero the top 16 bits of the result. For other storage combinations this attribute will be extended appropriately. diff --git a/Documentation/ABI/testing/sysfs-bus-iio-adc-ad7192 b/Documentation/ABI/testing/sysfs-bus-iio-adc-ad7192 index 28be1cabf112..d44eb5f8728b 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-adc-ad7192 +++ b/Documentation/ABI/testing/sysfs-bus-iio-adc-ad7192 @@ -16,7 +16,7 @@ Description: In bridge applications, such as strain gauges and load cells, the bridge itself consumes the majority of the current in the system. To minimize the current consumption of the system, - the bridge can be disconnected (when it is not being used + the bridge can be disconnected (when it is not being used) using the bridge_switch_en attribute. What: /sys/bus/iio/devices/iio:deviceX/in_voltage2-voltage2_shorted_raw diff --git a/Documentation/ABI/testing/sysfs-bus-iio-frequency b/Documentation/ABI/testing/sysfs-bus-iio-frequency new file mode 100644 index 000000000000..46075aee7804 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-frequency @@ -0,0 +1,11 @@ +What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_frequency_resolution +KernelVersion: 3.4.0 +Contact: linux-iio@vger.kernel.org +Description: + Stores channel Y frequency resolution/channel spacing in Hz for PLL + devices. The given value directly influences the operating mode when + fractional-N synthesis is required, as it derives values for + configurable modulus parameters used in the calculation of the output + frequency. It is assumed that the algorithm used to compute the various + dividers is able to generate proper values for multiples of the channel + spacing. diff --git a/Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350 b/Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350 index 1254457a726e..76987a119feb 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350 +++ b/Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350 @@ -1,13 +1,3 @@ -What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_frequency_resolution -KernelVersion: 3.4.0 -Contact: linux-iio@vger.kernel.org -Description: - Stores channel Y frequency resolution/channel spacing in Hz. - The value given directly influences the MODULUS used by - the fractional-N PLL. It is assumed that the algorithm - that is used to compute the various dividers, is able to - generate proper values for multiples of channel spacing. - What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_refin_frequency KernelVersion: 3.4.0 Contact: linux-iio@vger.kernel.org diff --git a/Documentation/devicetree/bindings/iio/adc/adc.yaml b/Documentation/devicetree/bindings/iio/adc/adc.yaml index b9bc02b5b07a..b673eaa5d072 100644 --- a/Documentation/devicetree/bindings/iio/adc/adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adc.yaml @@ -73,6 +73,47 @@ properties: device design and can interact with other characteristics such as settling time. + reference-sources: + $ref: /schemas/types.yaml#/definitions/string-array + description: + Indicates the voltage reference source or sources for this channel. Some + ADCs usually allow choosing between internal reference sources or a pair + of external pins. + + input-chopping: + type: boolean + description: + If set, the positive and negative input channels are swapped on every + other conversion to reduce offset error. This generally comes at the + expense of added settling time between conversions, so should be omitted + on systems with high-frequency signals or high data rate requirements. + + excitation-channels: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: + Excitation current sources provide current to resistive temperature + devices (RTDs), thermistors, diodes and other resistive sensors that + require constant current biasing. + + This array describes the mux configuration of the excitation current + sources. The values correspond to pins similar to the diff-channels and + single-channel properties. + + excitation-current-nanoamp: + description: + Excitation current sources provide current to resistive temperature + devices (RTDs), thermistors, diodes and other resistive sensors that + require constant current biasing. + + This array describes the current configuration of the excitation current + sources. The index in the array corresponds to the same index in the + excitation-channels array. + + burn-out-current-nanoamp: + description: + Burn-out current sources provide current to the channel's input pins for + open-circuit or short-circuit detection. + anyOf: - oneOf: - required: diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml index 4a3f7d3e05c3..db8467b98e67 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml @@ -39,6 +39,7 @@ properties: - adi,ad4087 - adi,ad4088 - adi,ad4880 + - adi,ad4883 - adi,ad4884 reg: @@ -102,6 +103,7 @@ allOf: contains: enum: - adi,ad4880 + - adi,ad4883 - adi,ad4884 then: properties: diff --git a/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml b/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml index 1ea60dff98d5..099235b5fd54 100644 --- a/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml +++ b/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml @@ -33,6 +33,26 @@ properties: description: Analog supply voltage (AVDD). + vsup-supply: + description: + Supply voltage for the on-chip regulator (VSUP). + + dvdd-supply: + description: + Digital supply voltage (DVDD). On the HX711, DVDD is a + board-supplied digital rail; it was missing from the original + binding. On the HX710B, DVDD must be greater than or equal to + AVDD; when DVDD is a battery rail and AVDD is a regulated supply, + one channel monitors the DVDD-AVDD difference for battery level + detection. + + rate-gpios: + description: + GPIO connected to the RATE pin. When driven low the output data + rate is 10 SPS; when driven high it is 80 SPS. If omitted the + RATE pin state is determined by the board wiring. + maxItems: 1 + clock-frequency: description: Controls the SCK bit-bang timing. The value is used to derive the @@ -57,6 +77,7 @@ examples: compatible = "avia,hx711"; sck-gpios = <&gpio3 10 GPIO_ACTIVE_HIGH>; dout-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>; + rate-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>; avdd-supply = <&avdd>; clock-frequency = <100000>; }; diff --git a/Documentation/devicetree/bindings/iio/adc/mediatek,mt6359-auxadc.yaml b/Documentation/devicetree/bindings/iio/adc/mediatek,mt6359-auxadc.yaml index 9936aa605c7b..c2f7387e4bfc 100644 --- a/Documentation/devicetree/bindings/iio/adc/mediatek,mt6359-auxadc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/mediatek,mt6359-auxadc.yaml @@ -4,7 +4,7 @@ $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 +title: MediaTek MT6350 series and similar PMIC AUXADC maintainers: - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> @@ -20,6 +20,7 @@ properties: compatible: oneOf: - enum: + - mediatek,mt6323-auxadc - mediatek,mt6357-auxadc - mediatek,mt6358-auxadc - mediatek,mt6359-auxadc diff --git a/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.yaml b/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.yaml index 6769d679c907..f0551d665916 100644 --- a/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.yaml @@ -22,7 +22,9 @@ properties: - const: rockchip,rk3562-saradc - const: rockchip,rk3588-saradc - items: - - const: rockchip,rk3576-saradc + - enum: + - rockchip,rk3576-saradc + - rockchip,rv1106-saradc - const: rockchip,rk3588-saradc - items: - enum: diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads112c14.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads112c14.yaml new file mode 100644 index 000000000000..facfeee61330 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/ti,ads112c14.yaml @@ -0,0 +1,219 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/ti,ads112c14.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments' ADS112C14 and similar ADC chips + +description: | + Supports the following Texas Instruments' ADC chips: + - ADS112C14 (16-bit) + - ADS122C14 (24-bit) + + https://www.ti.com/lit/ds/symlink/ads122c14.pdf + + These chips are primarily designed for use with resistive sensors such as + RTDs, thermocouples, Wheatstone bridges, etc. The channel bindings reflect + this in that each channel represents the conditions required to make a + measurement rather than strictly just the physical input channels. + +maintainers: + - David Lechner <dlechner@baylibre.com> + +properties: + compatible: + enum: + - ti,ads112c14 + - ti,ads122c14 + + reg: + items: + - minimum: 0x40 + maximum: 0x47 + + clocks: + maxItems: 1 + description: Optional external clock connected to GPIO3 pin. + + avdd-supply: true + dvdd-supply: true + + refp-supply: true + refn-supply: true + + ti,refp-refn-resistor-ohms: + description: + The resistance of the external resistor between REFP and REFN when using + resistor bridge driven by current outputs for RTD measurements. + + interrupts: + minItems: 1 + items: + - description: /FAULT interrupt (GPIO2 pin) + - description: /DRDY interrupt (GPIO3 pin) + + interrupt-names: + minItems: 1 + maxItems: 2 + items: + enum: [fault, drdy] + + gpio-controller: true + '#gpio-cells': + const: 2 + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +patternProperties: + ^channel@[0-9a-f]$: + $ref: adc.yaml + + unevaluatedProperties: false + + properties: + reg: + items: + - maximum: 15 # arbitrary limit, channel@ can be any combination of AIN0-AIN7 + + single-channel: + maximum: 7 + + diff-channels: + items: + maximum: 7 + + bipolar: true + + input-chopping: true + + excitation-channels: + maxItems: 2 + items: + maximum: 7 + + excitation-current-nanoamp: + maxItems: 2 + items: + enum: [1000, 10000, 20000, 30000, 40000, 50000, 60000, 70000, 80000, + 90000, 100000, 200000, 300000, 400000, 500000, 600000, 700000, + 800000, 900000, 1000000] + + burn-out-current-nanoamp: + items: + - enum: [200, 1000, 10000] + + reference-sources: + items: + - enum: [internal-2.5v, internal-1.25v, external, avdd] + default: internal-2.5v + + dependencies: + excitation-channels: [ excitation-current-nanoamp ] + excitation-current-nanoamp: [ excitation-channels ] + + oneOf: + - required: [ single-channel ] + - required: [ diff-channels ] + +unevaluatedProperties: false + +required: + - compatible + - reg + - avdd-supply + - dvdd-supply + +dependencies: + refn-supply: [ refp-supply ] + +oneOf: + - required: [ refp-supply ] + - required: [ "ti,refp-refn-resistor-ohms" ] + - properties: + refp-supply: false + refn-supply: false + ti,refp-refn-resistor-ohms: false + +# /DRDY out and CLK in use the same AIN7/GPIO3 pin. +if: + required: + - interrupt-names + properties: + interrupt-names: + contains: + const: drdy +then: + properties: + clocks: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + adc@40 { + compatible = "ti,ads112c14"; + reg = <0x40>; + + avdd-supply = <&avdd>; + dvdd-supply = <&dvdd>; + + /* 3-Wire RTD: Two IDACs, One Measurement (AIN1-AIN2) */ + + ti,refp-refn-resistor-ohms = <500>; + + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + diff-channels = <1>, <2>; + input-chopping; + excitation-channels = <0>, <3>; + excitation-current-nanoamp = <500000>, <500000>; + reference-sources = "external"; + label = "rtd"; + }; + }; + }; + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + adc@40 { + compatible = "ti,ads112c14"; + reg = <0x40>; + + avdd-supply = <&avdd>; + dvdd-supply = <&dvdd>; + + /* Resistive Bridge Measurement With a Thermistor for Temperature Compensation */ + + refp-supply = <&avdd>; + + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + diff-channels = <6>, <7>; + bipolar; + reference-sources = "external"; + label = "bridge"; + }; + + channel@1 { + reg = <1>; + diff-channels = <1>, <2>; + reference-sources = "internal-2.5v"; + label = "thermistor"; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/adc/xlnx,versal-sysmon.yaml b/Documentation/devicetree/bindings/iio/adc/xlnx,versal-sysmon.yaml new file mode 100644 index 000000000000..1ad58e3d6163 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/xlnx,versal-sysmon.yaml @@ -0,0 +1,154 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/xlnx,versal-sysmon.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: AMD/Xilinx Versal System Monitor + +maintainers: + - Salih Erim <salih.erim@amd.com> + +description: + The AMD/Xilinx Versal System Monitor (SysMon) is the successor to the + Zynq UltraScale+ AMS block. It provides on-chip voltage and temperature + monitoring with up to 160 voltage measurement points and up to + 64 temperature satellites distributed across the SoC. The hardware + supports configurable threshold alarms and oversampling. The device + can be accessed via memory-mapped I/O or via an I2C interface. + +properties: + compatible: + const: xlnx,versal-sysmon + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + '#io-channel-cells': + const: 1 + + voltage-channels: + type: object + description: + Container for voltage measurement channels. + + properties: + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + patternProperties: + '^channel@([0-9a-f]|[1-9][0-9a-f])$': + $ref: adc.yaml + + description: + Measures a voltage rail. The register index and rail + name are assigned by the hardware design tool (Vivado). + + properties: + reg: + minimum: 0 + maximum: 159 + description: + Voltage measurement register index assigned by the hardware + design tool. + + required: + - reg + - label + + unevaluatedProperties: false + + required: + - '#address-cells' + - '#size-cells' + + additionalProperties: false + + temperature-channels: + type: object + description: + Container for temperature satellite measurement channels. + + properties: + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + patternProperties: + '^channel@([1-9a-f]|[1-3][0-9a-f]|40)$': + $ref: adc.yaml + + description: + Reads a temperature satellite sensor. Each satellite monitors + a specific region of the SoC die. + + properties: + reg: + minimum: 1 + maximum: 64 + description: + Temperature satellite number (1-based hardware index). + + required: + - reg + - label + + unevaluatedProperties: false + + required: + - '#address-cells' + - '#size-cells' + + additionalProperties: false + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + + sysmon@f1270000 { + compatible = "xlnx,versal-sysmon"; + reg = <0xf1270000 0x4000>; + interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>; + #io-channel-cells = <1>; + + voltage-channels { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + label = "vccaux"; + }; + + channel@3 { + reg = <3>; + label = "vcc_ram"; + bipolar; + }; + }; + + temperature-channels { + #address-cells = <1>; + #size-cells = <0>; + + channel@a { + reg = <10>; + label = "aie-temp-ch1"; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/chemical/sensirion,scd30.yaml b/Documentation/devicetree/bindings/iio/chemical/sensirion,scd30.yaml index a5b0debe85b1..25291bda1a8b 100644 --- a/Documentation/devicetree/bindings/iio/chemical/sensirion,scd30.yaml +++ b/Documentation/devicetree/bindings/iio/chemical/sensirion,scd30.yaml @@ -8,6 +8,7 @@ title: Sensirion SCD30 carbon dioxide sensor maintainers: - Maxwell Doose <m32285159@gmail.com> + - Tomasz Duszynski <tduszyns@gmail.com> description: | Air quality sensor capable of measuring co2 concentration, temperature diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml index a355d52a9d64..2fe098619772 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml @@ -10,15 +10,17 @@ maintainers: - Kim Seer Paller <kimseer.paller@analog.com> description: | - The AD3530/AD3530R (8-channel) and AD3531/AD3531R (4-channel) are low-power, - 16-bit, buffered voltage output digital-to-analog converters (DACs) with - software-programmable gain controls, providing full-scale output spans of 2.5V - or 5V for reference voltages of 2.5V. These devices operate from a single 2.7V - to 5.5V supply and are guaranteed monotonic by design. The "R" variants - include a 2.5V, 5ppm/°C internal reference, which is disabled by default. + The AD3530/AD3530R (8-channel), AD3531/AD3531R (4-channel), and AD3532/AD3532R + (16-channel) are low-power, 16-bit, buffered voltage output digital-to-analog + converters (DACs) with software-programmable gain controls, providing + full-scale output spans of 2.5V or 5V for reference voltages of 2.5V. These + devices operate from a single 2.7V to 5.5V supply and are guaranteed monotonic + by design. The "R" variants include a 2.5V, 5ppm/°C internal reference, which + is disabled by default. Datasheet can be found here: https://www.analog.com/media/en/technical-documentation/data-sheets/ad3530_ad530r.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/ad3531-ad3531r.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/ad3532r.pdf properties: compatible: @@ -27,6 +29,8 @@ properties: - adi,ad3530r - adi,ad3531 - adi,ad3531r + - adi,ad3532 + - adi,ad3532r reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5686.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5686.yaml index 713f535bb33a..02e8c78e36d3 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ad5686.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5686.yaml @@ -32,27 +32,95 @@ properties: reg: maxItems: 1 + vdd-supply: + description: Input power supply. + + vlogic-supply: + description: + Digital power supply. On some tiny package variants for single-channel + devices, this supply is internally connected to vdd; in that case, specify + this property with the same regulator as vdd. + + vref-supply: + description: + Reference voltage supply. If not supplied the internal reference is used. + vcc-supply: - description: If not supplied the internal reference is used. + deprecated: true + description: Use vref-supply instead. + + reset-gpios: + description: Active-low RESET pin to reset the device. + maxItems: 1 + + ldac-gpios: + description: + Active-low LDAC pin used to asynchronously update the DAC channels. + maxItems: 1 + + gain-gpios: + description: + GAIN pin that sets a multiplier for the DAC output voltage. When high, + the DAC output voltage is multiplied by 2, otherwise it is unchanged. + maxItems: 1 + + adi,range-double: + description: + Sets the initial voltage output range from 0 to 2xVREF. On devices that + have a GAIN pin and no gain-gpios property is set, this indicates the pin + is hardwired high. + type: boolean required: - compatible - reg + - vdd-supply + - vlogic-supply allOf: - $ref: /schemas/spi/spi-peripheral-props.yaml# + - if: + properties: + compatible: + contains: + enum: + - adi,ad5676 + - adi,ad5683 + - adi,ad5684 + - adi,ad5686 + then: + required: + - vref-supply + - if: + properties: + compatible: + contains: + enum: + - adi,ad5310r + - adi,ad5681r + - adi,ad5682r + - adi,ad5683 + - adi,ad5683r + then: + properties: + gain-gpios: false unevaluatedProperties: false examples: - | + #include <dt-bindings/gpio/gpio.h> spi { #address-cells = <1>; #size-cells = <0>; dac@0 { reg = <0>; compatible = "adi,ad5310r"; - vcc-supply = <&dac_vref0>; + vdd-supply = <&dac_vdd>; + vlogic-supply = <&dac_vlogic>; + vref-supply = <&dac_vref>; + reset-gpios = <&gpio0 0 GPIO_ACTIVE_LOW>; + ldac-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; }; }; ... diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5696.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5696.yaml index b5a88b03dc2f..e10f8596f9d3 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ad5696.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5696.yaml @@ -33,18 +33,82 @@ properties: reg: maxItems: 1 + vdd-supply: + description: Input power supply. + + vlogic-supply: + description: + Digital power supply. On some tiny package variants for single-channel + devices, this supply is internally connected to vdd; in that case, specify + this property with the same regulator as vdd. + + vref-supply: + description: + Reference voltage supply. If not supplied the internal reference is used. + vcc-supply: - description: | - The regulator supply for DAC reference voltage. + deprecated: true + description: Use vref-supply instead. + + reset-gpios: + description: Active-low RESET pin to reset the device. + maxItems: 1 + + ldac-gpios: + description: + Active-low LDAC pin used to asynchronously update the DAC channels. + maxItems: 1 + + gain-gpios: + description: + GAIN pin that sets a multiplier for the DAC output voltage. When high, + the DAC output voltage is multiplied by 2, otherwise it is unchanged. + maxItems: 1 + + adi,range-double: + description: + Sets the initial voltage output range from 0 to 2xVREF. On devices that + have a GAIN pin and no gain-gpios property is set, this indicates the pin + is hardwired high. + type: boolean required: - compatible - reg + - vdd-supply + - vlogic-supply + +allOf: + - if: + properties: + compatible: + contains: + enum: + - adi,ad5693 + - adi,ad5694 + - adi,ad5696 + then: + required: + - vref-supply + - if: + properties: + compatible: + contains: + enum: + - adi,ad5311r + - adi,ad5691r + - adi,ad5692r + - adi,ad5693 + - adi,ad5693r + then: + properties: + gain-gpios: false additionalProperties: false examples: - | + #include <dt-bindings/gpio/gpio.h> i2c { #address-cells = <1>; #size-cells = <0>; @@ -52,7 +116,10 @@ examples: ad5696: dac@0 { compatible = "adi,ad5696"; reg = <0>; - vcc-supply = <&dac_vref>; + vdd-supply = <&dac_vdd>; + vlogic-supply = <&dac_vlogic>; + vref-supply = <&dac_vref>; + ldac-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; }; }; ... diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml index 2bd89e0aa46b..80fb98035c6f 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml @@ -36,11 +36,11 @@ properties: vrefp-supply: description: - Positive referance input voltage range. From 5v to (vdd - 2.5) + Positive reference input voltage range. From 5v to (vdd - 2.5) vrefn-supply: description: - Negative referance input voltage range. From (vss + 2.5) to 0. + Negative reference input voltage range. From (vss + 2.5) to 0. adi,rbuf-gain2-en: description: Specify to allow an external amplifier to be connected in a diff --git a/Documentation/devicetree/bindings/iio/frequency/adi,adf41513.yaml b/Documentation/devicetree/bindings/iio/frequency/adi,adf41513.yaml new file mode 100644 index 000000000000..f4fae9210382 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/frequency/adi,adf41513.yaml @@ -0,0 +1,227 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/frequency/adi,adf41513.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices ADF41513 PLL Frequency Synthesizer + +maintainers: + - Rodrigo Alencar <rodrigo.alencar@analog.com> + +description: + The ADF41513 is an ultralow noise frequency synthesizer that can be used to + implement local oscillators (LOs) as high as 26.5 GHz in the upconversion and + downconversion sections of wireless receivers and transmitters. The ADF41510 + supports frequencies up to 10 GHz. + + https://www.analog.com/en/products/adf41510.html + https://www.analog.com/en/products/adf41513.html + +properties: + compatible: + enum: + - adi,adf41510 + - adi,adf41513 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 25000000 + + clocks: + maxItems: 1 + description: Clock that provides the reference input frequency. + + avdd1-supply: + description: PFD and Up and Down Digital Driver Power Supply (3.3 V) + + avdd2-supply: + description: RF Buffer and Prescaler Power Supply (3.3 V) + + avdd3-supply: + description: N Divider Power Supply (3.3 V) + + avdd4-supply: + description: R Divider and Lock Detector Power Supply (3.3 V) + + avdd5-supply: + description: Sigma-Delta Modulator and SPI Power Supply (3.3 V) + + vp-supply: + description: Charge Pump Power Supply (3.3 V) + + enable-gpios: + description: + GPIO that controls the chip enable pin. A logic low on this pin + powers down the device and puts the charge pump output into + three-state mode. + maxItems: 1 + + lock-detect-gpios: + description: + GPIO for lock detect functionality. When configured for digital lock + detect, this pin will output a logic high when the PLL is locked. + maxItems: 1 + + adi,power-up-frequency-mhz: + minimum: 1000 + maximum: 26500 + default: 10000 + description: + The PLL tunes to this frequency during the initialization sequence. + This property should be set to a frequency supported by the loop filter + and VCO used in the design. Range is 1 GHz to 26.5 GHz for ADF41513, + and 1 GHz to 10 GHz for ADF41510. + + adi,reference-div-factor: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + maximum: 32 + default: 1 + description: + Value for the reference division factor (R Counter). The driver will + increment R Counter as needed to achieve a PFD frequency within the + allowed range. High R counter values will reduce the PFD frequency, which + lowers the frequency resolution, and affects phase noise performance. + As it affects the PFD frequency, this value depends on the loop filter + design. + + adi,reference-doubler-enable: + description: + Enables the reference doubler when deriving the PFD frequency. + The maximum reference frequency when the doubler is enabled is 225 MHz. + As it affects the PFD frequency, this value depends on the loop filter + design. + type: boolean + + adi,reference-div2-enable: + description: + Enables the reference divide-by-2 function when deriving the PFD + frequency. As it affects the PFD frequency, this value depends on the + loop filter design. + type: boolean + + adi,charge-pump-resistor-ohms: + minimum: 1800 + maximum: 10000 + default: 2700 + description: + External charge pump resistor (R_SET) value in ohms. This sets the maximum + charge pump current along with the charge pump current setting. + + adi,charge-pump-current-microamp: + minimum: 81 + maximum: 7200 + description: + Charge pump current (I_CP) in microamps. The value will be rounded to the + nearest supported value. Range of acceptable values depends on the + charge pump resistor value, such that 810 mV <= I_CP * R_SET <= 12960 mV. + This value depends on the loop filter and the VCO design. + + adi,logic-level-1v8-enable: + description: + Set MUXOUT and DLD logic levels to 1.8V. Default is 3.3V. + type: boolean + + adi,phase-detector-polarity-positive-enable: + description: + Set phase detector polarity to positive. Default is negative. + Use positive polarity with non-inverting loop filter and VCO with + positive tuning slope, or with inverting loop filter and VCO with + negative tuning slope. + type: boolean + + adi,lock-detector-count: + $ref: /schemas/types.yaml#/definitions/uint32 + default: 64 + description: + Sets the value for Lock Detector count of the PLL, which determines the + number of consecutive phase detector cycles that must be within the lock + detector window before lock is declared. Lower values increase the lock + detection sensitivity, while higher values provides a more stable lock + detection. Applications that consume the lock detect signal may require + different settings based on system requirements. + enum: [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192] + + adi,phase-resync-period-ns: + default: 0 + description: + When this value is non-zero, enable phase resync functionality, which + produces a consistent output phase offset with respect to the input + reference. The value specifies the resync period in nanoseconds, used + to configure clock dividers with respect to the PFD frequency. This value + should be set to a value that is at least as long as the worst case lock + time, i.e., it depends mostly on the loop filter design. + + adi,le-sync-enable: + description: + Synchronizes Load Enable (LE) transitions with the reference signal to + avoid asynchronous glitches in the output. This is recommended when using + the PLL as a frequency synthesizer, where the reference signal will always + be present while the device is being configured. When using the PLL as a + frequency tracker, where the reference signal may be absent, LE sync + should be left disabled. + type: boolean + +dependencies: + adi,charge-pump-resistor-ohms: [ 'adi,charge-pump-current-microamp' ] + +required: + - compatible + - reg + - clocks + - avdd1-supply + - avdd2-supply + - avdd3-supply + - avdd4-supply + - avdd5-supply + - vp-supply + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + - if: + properties: + compatible: + contains: + const: adi,adf41510 + then: + properties: + adi,power-up-frequency-mhz: + maximum: 10000 + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + spi { + #address-cells = <1>; + #size-cells = <0>; + + pll@0 { + compatible = "adi,adf41513"; + reg = <0>; + spi-max-frequency = <25000000>; + clocks = <&ref_clk>; + avdd1-supply = <&avdd1_3v3>; + avdd2-supply = <&avdd2_3v3>; + avdd3-supply = <&avdd3_3v3>; + avdd4-supply = <&avdd4_3v3>; + avdd5-supply = <&avdd5_3v3>; + vp-supply = <&vp_3v3>; + enable-gpios = <&gpio0 10 GPIO_ACTIVE_HIGH>; + lock-detect-gpios = <&gpio0 11 GPIO_ACTIVE_HIGH>; + + adi,power-up-frequency-mhz = <15500>; + adi,charge-pump-current-microamp = <3600>; + adi,charge-pump-resistor-ohms = <2700>; + adi,reference-doubler-enable; + adi,lock-detector-count = <64>; + adi,phase-resync-period-ns = <0>; + adi,phase-detector-polarity-positive-enable; + adi,le-sync-enable; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/magnetometer/qstcorp,qmc5883l.yaml b/Documentation/devicetree/bindings/iio/magnetometer/qstcorp,qmc5883l.yaml new file mode 100644 index 000000000000..38abd083a4fb --- /dev/null +++ b/Documentation/devicetree/bindings/iio/magnetometer/qstcorp,qmc5883l.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/magnetometer/qstcorp,qmc5883l.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: QST QMC5883L 3-Axis Magnetic Sensor + +maintainers: + - Siratul Islam <siratul.islam@linux.dev> + +description: | + QST QMC5883L 3-Axis Magnetic Sensor on I2C bus. + https://www.qstcorp.com/upload/pdf/202512/13-52-04%20QMC5883L%20Datasheet%20Rev.%20B.pdf + +properties: + compatible: + enum: + - qstcorp,qmc5883l + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + vdd-supply: true + + vddio-supply: true + +additionalProperties: false + +required: + - compatible + - reg + - vdd-supply + - vddio-supply + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + magnetometer@d { + compatible = "qstcorp,qmc5883l"; + reg = <0x0d>; + vdd-supply = <&vdd_3v3_reg>; + vddio-supply = <&vdd_3v3_reg>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/magnetometer/qstcorp,qmc6308.yaml b/Documentation/devicetree/bindings/iio/magnetometer/qstcorp,qmc6308.yaml new file mode 100644 index 000000000000..6201a44cfe38 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/magnetometer/qstcorp,qmc6308.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/magnetometer/qstcorp,qmc6308.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: QST QMC6308 3-Axis Magnetic Sensor + +maintainers: + - Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net> + +description: | + QST QMC6308 3-axis anisotropic magnetoresistive (AMR) magnetic sensor + on I2C bus, with a single supply and no interrupt pin. + https://qstcorp.com/upload/pdf/202202/13-52-15%20QMC6308%20Datasheet%20Rev.%20F(1).pdf + +properties: + compatible: + const: qstcorp,qmc6308 + + reg: + maxItems: 1 + + vdd-supply: true + + mount-matrix: true + +additionalProperties: false + +required: + - compatible + - reg + - vdd-supply + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + magnetometer@2c { + compatible = "qstcorp,qmc6308"; + reg = <0x2c>; + vdd-supply = <&vdd_1v8_reg>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/proximity/st,vl53l0x.yaml b/Documentation/devicetree/bindings/iio/proximity/st,vl53l0x.yaml index f7f8be1e379d..d23dc59505cc 100644 --- a/Documentation/devicetree/bindings/iio/proximity/st,vl53l0x.yaml +++ b/Documentation/devicetree/bindings/iio/proximity/st,vl53l0x.yaml @@ -8,7 +8,7 @@ title: ST VL53L0X/VL53L1X ToF ranging sensor maintainers: - Song Qiang <songqiang1304521@gmail.com> - - Siratul Islam <email@sirat.me> + - Siratul Islam <siratul.islam@linux.dev> properties: compatible: diff --git a/Documentation/devicetree/bindings/iio/temperature/ti,tmp117.yaml b/Documentation/devicetree/bindings/iio/temperature/ti,tmp117.yaml index fbba5e934861..7fb3e6820791 100644 --- a/Documentation/devicetree/bindings/iio/temperature/ti,tmp117.yaml +++ b/Documentation/devicetree/bindings/iio/temperature/ti,tmp117.yaml @@ -7,19 +7,25 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: TI TMP117 - Digital temperature sensor with integrated NV memory description: | - TI TMP116/117 - Digital temperature sensor with integrated NV memory that - supports I2C interface. + TI TMP116/117/119 - Digital temperature sensor with integrated NV memory + that supports I2C interface. https://www.ti.com/lit/gpn/tmp116 https://www.ti.com/lit/gpn/tmp117 + https://www.ti.com/lit/gpn/tmp119 maintainers: - Puranjay Mohan <puranjay12@gmail.com> properties: compatible: - enum: - - ti,tmp116 - - ti,tmp117 + oneOf: + - enum: + - ti,tmp116 + - ti,tmp117 + - items: + - enum: + - ti,tmp119 + - const: ti,tmp117 reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 358b6f2d50be..9e79dece7faf 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1379,6 +1379,8 @@ patternProperties: description: Shenzhen QiShenglong Industrialist Co., Ltd. "^qnap,.*": description: QNAP Systems, Inc. + "^qstcorp,.*": + description: QST Corporation Limited "^quanta,.*": description: Quanta Computer Inc. "^radxa,.*": diff --git a/Documentation/iio/adf41513.rst b/Documentation/iio/adf41513.rst new file mode 100644 index 000000000000..244453cce6f6 --- /dev/null +++ b/Documentation/iio/adf41513.rst @@ -0,0 +1,199 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=============== +ADF41513 driver +=============== + +This driver supports Analog Devices' ADF41513 and similar SPI PLL frequency +synthesizers. + +1. Supported devices +==================== + +* `ADF41510 <https://www.analog.com/ADF41510>`_ +* `ADF41513 <https://www.analog.com/ADF41513>`_ + +The ADF41513 is an ultralow noise frequency synthesizer that can be used to +implement local oscillators (LOs) as high as 26.5 GHz in the upconversion and +downconversion sections of wireless receivers and transmitters. The ADF41510 +is a similar device that supports frequencies up to 10 GHz. + +Both devices support integer-N and fractional-N operation modes, providing +excellent phase noise performance and flexible frequency generation +capabilities. + +Key Features: + +- **ADF41510**: 1 GHz to 10 GHz frequency range +- **ADF41513**: 1 GHz to 26.5 GHz frequency range +- Integer-N and fractional-N operation modes +- Ultra-low phase noise (-235 dBc/Hz integer-N, -231 dBc/Hz fractional-N) +- High maximum PFD frequency (250 MHz integer-N, 125 MHz fractional-N) +- 25-bit fixed modulus or 49-bit variable modulus fractional modes +- Programmable charge pump currents with 16x range +- Digital lock detect functionality +- Phase resync capability for consistent output phase + +2. Device attributes +==================== + +The ADF41513 driver provides the following IIO extended attributes for +frequency control and monitoring: + +Each IIO device has a device folder under ``/sys/bus/iio/devices/iio:deviceX``, +where X is the IIO index of the device. Under these folders reside a set of +device files that provide access to the synthesizer's functionality. + +The following table shows the ADF41513 related device files: + ++--------------------------------------+-------------------------------------------------------+ +| Device file | Description | ++======================================+=======================================================+ +| out_altvoltage0_frequency | RF output frequency control and readback (Hz) | ++--------------------------------------+-------------------------------------------------------+ +| out_altvoltage0_frequency_resolution | Target frequency resolution control (Hz) | ++--------------------------------------+-------------------------------------------------------+ +| out_altvoltage0_powerdown | Power management control (0=active, 1=power down) | ++--------------------------------------+-------------------------------------------------------+ +| out_altvoltage0_phase | RF output phase adjustment and readback (radians) | ++--------------------------------------+-------------------------------------------------------+ + +2.1 Frequency Control +---------------------- + +The ``out_altvoltage0_frequency`` attribute controls the RF output frequency +with sub-Hz precision. The driver automatically selects between integer-N and +fractional-N modes to achieve the requested frequency with the best possible +phase noise performance. + +**Supported ranges:** + +- **ADF41510**: 1,000,000,000 Hz to 10,000,000,000 Hz (1 GHz to 10 GHz) +- **ADF41513**: 1,000,000,000 Hz to 26,500,000,000 Hz (1 GHz to 26.5 GHz) + +The frequency is specified in Hz, for sub-Hz precision use decimal notation. +For example, 12.102 GHz would be written as "12102000000.000000". + +2.2 Frequency Resolution Control +-------------------------------- + +The ``out_altvoltage0_frequency_resolution`` attribute controls the target +frequency resolution that the driver attempts to achieve. This affects the +choice between integer-N and fractional-N modes, including fixed modulus +(25-bit) and variable modulus (49-bit) fractional-N modes: + +- **Integer-N**: Resolution = :math:`f_{PFD}` (same as PFD frequency) +- **Fixed modulus**: Resolution = :math:`f_{PFD} / 2^{25}` (~3 Hz with 100 MHz PFD) +- **Variable modulus**: Resolution = :math:`f_{PFD} / 2^{49}` (µHz resolution possible) + +Default resolution is 1 Hz (1,000,000 µHz). + +2.3 Phase adjustment +-------------------- + +The ``out_altvoltage0_phase`` attribute allows adjustment of the output phase +in radians. Setting this attribute enables phase adjustment. It can be set +from 0 to :math:`2\pi` radians. Reading this attribute returns the current +phase offset of the output signal. To create a consistent phase relationship +with the reference signal, the phase resync feature needs to be enabled by +setting a non-zero value to the ``adi,phase-resync-period-ns`` device property, +which triggers a phase resynchronization after locking is achieved. + +3. Operating modes +================== + +3.1 Integer-N Mode +------------------ + +When the requested frequency can be achieved as an integer multiple of the PFD +frequency (within the specified resolution tolerance), the driver automatically +selects integer-N mode for optimal phase noise performance. + +In integer-N mode: + +- Phase noise: -235 dBc/Hz normalized floor +- Frequency resolution: :math:`f_{PFD}` (same as PFD frequency) +- Maximum PFD frequency: 250 MHz +- Bleed current: Disabled + +3.2 Fractional-N Mode +--------------------- + +When sub-integer frequency steps are required, the driver automatically selects +fractional-N mode using either fixed or variable modulus. + +**Fixed Modulus (25-bit)**: + +- Used when variable modulus is not required +- Resolution: :math:`f_{PFD} / 2^{25}` +- Simpler implementation, faster settling + +**Variable Modulus (49-bit)**: + +- Used for maximum resolution requirements +- Resolution: :math:`f_{PFD} / 2^{49}` (theoretical) +- Exact frequency synthesis capability + +In fractional-N mode: + +- Phase noise: -231 dBc/Hz normalized floor +- Maximum PFD frequency: 125 MHz +- Bleed current: Automatically enabled and optimized +- Dithering: Enabled to reduce fractional spurs + +3.3 Automatic Mode Selection +---------------------------- + +The driver automatically selects the optimal operating mode based on: + +1. **Frequency accuracy requirements**: Determined by ``frequency_resolution`` setting +2. **Phase noise optimization**: Integer-N preferred when possible +3. **PFD frequency constraints**: Different limits for integer vs fractional modes +4. **Prescaler selection**: Automatic 4/5 vs 8/9 prescaler selection based on frequency + +4. Usage examples +================= + +4.1 Basic Frequency Setting +---------------------------- + +Set output frequency to 12.102 GHz: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> echo 12102000000 > out_altvoltage0_frequency + +Read current frequency: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat out_altvoltage0_frequency + 12101999999.582767 + +4.2 High Resolution Frequency Control +------------------------------------- + +Configure for sub-Hz resolution and set a precise frequency: + +.. code-block:: bash + + # Set resolution to 0.1 Hz (100,000 µHz) + root:/sys/bus/iio/devices/iio:device0> echo 0.1 > out_altvoltage0_frequency_resolution + + # Set frequency to 12.102 GHz (1 µHz precision) + root:/sys/bus/iio/devices/iio:device0> echo 12102000000 > out_altvoltage0_frequency + root:/sys/bus/iio/devices/iio:device0> cat out_altvoltage0_frequency + 12101999999.980131 + +4.3 Monitor Lock Status +----------------------- + +When lock detect GPIO is configured, check if PLL is locked: + +.. code-block:: bash + + # Read frequency - will return error if not locked + root:/sys/bus/iio/devices/iio:device0> cat out_altvoltage0_frequency + +If the PLL is not locked, the frequency read will return ``-EBUSY`` (Device or +resource busy). diff --git a/Documentation/iio/index.rst b/Documentation/iio/index.rst index 007e0a1fcc5a..b02b879b053a 100644 --- a/Documentation/iio/index.rst +++ b/Documentation/iio/index.rst @@ -31,6 +31,7 @@ Industrial I/O Kernel Drivers ad7625 ad7944 ade9000 + adf41513 adis16475 adis16480 adis16550 diff --git a/MAINTAINERS b/MAINTAINERS index 357c17546078..5edebe387142 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1718,6 +1718,15 @@ W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ade9000.yaml F: drivers/iio/adc/ade9000.c +ANALOG DEVICES INC ADF41513 DRIVER +M: Rodrigo Alencar <rodrigo.alencar@analog.com> +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/frequency/adi,adf41513.yaml +F: Documentation/iio/adf41513.rst +F: drivers/iio/frequency/adf41513.c + ANALOG DEVICES INC ADF4377 DRIVER M: Antoniu Miclaus <antoniu.miclaus@analog.com> L: linux-iio@vger.kernel.org @@ -16623,6 +16632,13 @@ S: Maintained F: Documentation/devicetree/bindings/mmc/mtk-sd.yaml F: drivers/mmc/host/mtk-sd.c +MEDIATEK MT6323 PMIC AUXADC DRIVER +M: Roman Vivchar <rva333@protonmail.com> +L: linux-iio@vger.kernel.org +S: Maintained +F: drivers/iio/adc/mt6323-auxadc.c +F: include/dt-bindings/iio/adc/mediatek,mt6323-auxadc.h + MEDIATEK MT6735 CLOCK & RESET DRIVERS M: Yassine Oudjana <y.oudjana@protonmail.com> L: linux-clk@vger.kernel.org @@ -22136,6 +22152,20 @@ F: Documentation/networking/device_drivers/ethernet/freescale/dpaa2/overview.rst F: drivers/bus/fsl-mc/ F: include/uapi/linux/fsl_mc.h +QST QMC5883L 3-Axis Magnetic Sensor +M: Siratul Islam <siratul.islam@linux.dev> +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/magnetometer/qstcorp,qmc5883l.yaml +F: drivers/iio/magnetometer/qmc5883l.c + +QST QMC6308 3-AXIS MAGNETIC SENSOR +M: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net> +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/magnetometer/qstcorp,qmc6308.yaml +F: drivers/iio/magnetometer/qmc6308.c + QT1010 MEDIA DRIVER L: linux-media@vger.kernel.org S: Orphan @@ -24645,6 +24675,7 @@ F: drivers/iio/chemical/sunrise_co2.c SENSIRION SCD30 CARBON DIOXIDE SENSOR DRIVER M: Maxwell Doose <m32285159@gmail.com> +M: Tomasz Duszynski <tduszyns@gmail.com> S: Maintained F: Documentation/devicetree/bindings/iio/chemical/sensirion,scd30.yaml F: drivers/iio/chemical/scd30.h @@ -25813,7 +25844,7 @@ F: Documentation/devicetree/bindings/iio/proximity/st,vl53l0x.yaml F: drivers/iio/proximity/vl53l0x-i2c.c ST VL53L1X ToF RANGER(I2C) IIO DRIVER -M: Siratul Islam <email@sirat.me> +M: Siratul Islam <siratul.islam@linux.dev> L: linux-iio@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/iio/proximity/st,vl53l0x.yaml @@ -27069,6 +27100,13 @@ S: Maintained F: Documentation/devicetree/bindings/iio/adc/ti,ads1119.yaml F: drivers/iio/adc/ti-ads1119.c +TI ADS112C14 ADC DRIVER +M: David Lechner <dlechner@baylibre.com> +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/adc/ti,ads112c14.yaml +F: drivers/iio/adc/ti-ads112c14.c + TI ADS1018 ADC DRIVER M: Kurt Borja <kuurtb@gmail.com> L: linux-iio@vger.kernel.org @@ -28896,6 +28934,7 @@ F: drivers/iio/light/veml3235.c VISHAY VEML3328 RGB IR LIGHT SENSOR DRIVER M: Joshua Crofts <joshua.crofts1@gmail.com> +L: linux-iio@vger.kernel.org S: Maintained F: drivers/iio/light/veml3328.c @@ -29650,7 +29689,7 @@ F: include/uapi/linux/dqblk_xfs.h F: include/uapi/linux/fsmap.h XILINX AMS DRIVER -M: Salih Erim <salih.erim@amd.com> +M: Sai Krishna Potthuri <sai.krishna.potthuri@amd.com> M: Conall O'Griofa <conall.ogriofa@amd.com> L: linux-iio@vger.kernel.org S: Maintained @@ -29751,6 +29790,14 @@ F: Documentation/devicetree/bindings/memory-controllers/xlnx,versal-net-ddrmc5.y F: drivers/edac/versalnet_edac.c F: include/linux/cdx/edac_cdx_pcol.h +XILINX VERSAL SYSMON DRIVER +M: Salih Erim <salih.erim@amd.com> +M: Sai Krishna Potthuri <sai.krishna.potthuri@amd.com> +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/adc/xlnx,versal-sysmon.yaml +F: drivers/iio/adc/versal-sysmon* + XILINX WATCHDOG DRIVER M: Srinivas Neeli <srinivas.neeli@amd.com> R: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com> diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index 7e3c9f38297b..e735f43dcdeb 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c @@ -210,3 +210,4 @@ module_platform_driver(adc_jack_driver); MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); MODULE_DESCRIPTION("ADC Jack extcon driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c index fc17ad93a376..6502e20517a8 100644 --- a/drivers/hwmon/iio_hwmon.c +++ b/drivers/hwmon/iio_hwmon.c @@ -221,3 +221,4 @@ module_platform_driver(iio_hwmon_driver); MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); MODULE_DESCRIPTION("IIO to hwmon driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c index 1ac0288fbbd8..4fa7f522f245 100644 --- a/drivers/hwmon/ntc_thermistor.c +++ b/drivers/hwmon/ntc_thermistor.c @@ -748,3 +748,4 @@ MODULE_DESCRIPTION("NTC Thermistor Driver"); MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:ntc-thermistor"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/iio/TODO b/drivers/iio/TODO index 2ace27d1ac62..7b05308248d7 100644 --- a/drivers/iio/TODO +++ b/drivers/iio/TODO @@ -5,12 +5,17 @@ Documentation tree - Yaml conversions for abandoned drivers - ABI Documentation - - Audit driviers/iio/staging/Documentation + - Audit drivers/staging/iio/Documentation -- Converting drivers from device tree centric to more generic -property handlers. +- Converting drivers from device tree centric to generic property handlers. - Refactor old platform_data constructs from drivers and convert it -to state struct and using property handlers and readers. + to state struct and using property handlers and readers. + +- Convert selected IIO drivers to use fully device managed resource APIs. + +- Evaluate and possibly adopt cleanup.h helpers (guard()(), __free(), et cetera) + in drivers where manual resource management is still used and there is a + significant improvement to the code flow and complexity to be had. Mailing list: linux-iio@vger.kernel.org diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c index 0315f4bfd69a..4fa1b04f75b6 100644 --- a/drivers/iio/accel/adxl345_spi.c +++ b/drivers/iio/accel/adxl345_spi.c @@ -60,8 +60,8 @@ static const struct adxl345_chip_info adxl375_spi_info = { }; static const struct spi_device_id adxl345_spi_id[] = { - { "adxl345", (kernel_ulong_t)&adxl345_spi_info }, - { "adxl375", (kernel_ulong_t)&adxl375_spi_info }, + { .name = "adxl345", .driver_data = (kernel_ulong_t)&adxl345_spi_info }, + { .name = "adxl375", .driver_data = (kernel_ulong_t)&adxl375_spi_info }, { } }; MODULE_DEVICE_TABLE(spi, adxl345_spi_id); diff --git a/drivers/iio/accel/adxl355_spi.c b/drivers/iio/accel/adxl355_spi.c index 437be2f1d53c..d2209ca8ca6e 100644 --- a/drivers/iio/accel/adxl355_spi.c +++ b/drivers/iio/accel/adxl355_spi.c @@ -40,8 +40,8 @@ static int adxl355_spi_probe(struct spi_device *spi) } static const struct spi_device_id adxl355_spi_id[] = { - { "adxl355", (kernel_ulong_t)&adxl35x_chip_info[ADXL355] }, - { "adxl359", (kernel_ulong_t)&adxl35x_chip_info[ADXL359] }, + { .name = "adxl355", .driver_data = (kernel_ulong_t)&adxl35x_chip_info[ADXL355] }, + { .name = "adxl359", .driver_data = (kernel_ulong_t)&adxl35x_chip_info[ADXL359] }, { } }; MODULE_DEVICE_TABLE(spi, adxl355_spi_id); diff --git a/drivers/iio/accel/adxl367_spi.c b/drivers/iio/accel/adxl367_spi.c index 785652c7fc92..1d1418452bdc 100644 --- a/drivers/iio/accel/adxl367_spi.c +++ b/drivers/iio/accel/adxl367_spi.c @@ -137,7 +137,7 @@ static int adxl367_spi_probe(struct spi_device *spi) } static const struct spi_device_id adxl367_spi_id[] = { - { "adxl367", 0 }, + { .name = "adxl367" }, { } }; MODULE_DEVICE_TABLE(spi, adxl367_spi_id); diff --git a/drivers/iio/accel/adxl372_spi.c b/drivers/iio/accel/adxl372_spi.c index 25fdb4254372..128e148c4e96 100644 --- a/drivers/iio/accel/adxl372_spi.c +++ b/drivers/iio/accel/adxl372_spi.c @@ -34,8 +34,8 @@ static int adxl372_spi_probe(struct spi_device *spi) } static const struct spi_device_id adxl372_spi_id[] = { - { "adxl371", (kernel_ulong_t)&adxl371_chip_info }, - { "adxl372", (kernel_ulong_t)&adxl372_chip_info }, + { .name = "adxl371", .driver_data = (kernel_ulong_t)&adxl371_chip_info }, + { .name = "adxl372", .driver_data = (kernel_ulong_t)&adxl372_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, adxl372_spi_id); diff --git a/drivers/iio/accel/adxl380_spi.c b/drivers/iio/accel/adxl380_spi.c index ee3e6338b53d..ae8467f4e6c0 100644 --- a/drivers/iio/accel/adxl380_spi.c +++ b/drivers/iio/accel/adxl380_spi.c @@ -34,10 +34,10 @@ static int adxl380_spi_probe(struct spi_device *spi) } static const struct spi_device_id adxl380_spi_id[] = { - { "adxl318", (kernel_ulong_t)&adxl318_chip_info }, - { "adxl319", (kernel_ulong_t)&adxl319_chip_info }, - { "adxl380", (kernel_ulong_t)&adxl380_chip_info }, - { "adxl382", (kernel_ulong_t)&adxl382_chip_info }, + { .name = "adxl318", .driver_data = (kernel_ulong_t)&adxl318_chip_info }, + { .name = "adxl319", .driver_data = (kernel_ulong_t)&adxl319_chip_info }, + { .name = "adxl380", .driver_data = (kernel_ulong_t)&adxl380_chip_info }, + { .name = "adxl382", .driver_data = (kernel_ulong_t)&adxl382_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, adxl380_spi_id); diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c index d897aec1c9f2..d6c1087cc3c0 100644 --- a/drivers/iio/accel/bma220_spi.c +++ b/drivers/iio/accel/bma220_spi.c @@ -25,7 +25,7 @@ static int bma220_spi_probe(struct spi_device *spi) } static const struct spi_device_id bma220_spi_id[] = { - { "bma220", 0 }, + { .name = "bma220" }, { } }; diff --git a/drivers/iio/accel/bma400_spi.c b/drivers/iio/accel/bma400_spi.c index 4b89e313704f..7ac0a7881b59 100644 --- a/drivers/iio/accel/bma400_spi.c +++ b/drivers/iio/accel/bma400_spi.c @@ -87,7 +87,7 @@ static int bma400_spi_probe(struct spi_device *spi) } static const struct spi_device_id bma400_spi_ids[] = { - { "bma400", 0 }, + { .name = "bma400" }, { } }; MODULE_DEVICE_TABLE(spi, bma400_spi_ids); diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index dc8a6285cf3d..46bb36d9366e 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -988,8 +988,10 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev, do_div(sample_period, count); tstamp = data->timestamp - (count - 1) * sample_period; - if (samples && count > samples) - count = samples; + if (samples) + count = min3(count, samples, BMC150_ACCEL_FIFO_LENGTH); + else + count = min(count, BMC150_ACCEL_FIFO_LENGTH); count = min_t(u8, count, BMC150_ACCEL_FIFO_LENGTH); diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c index 7d2be6f63538..405bd7b2d199 100644 --- a/drivers/iio/accel/bmc150-accel-spi.c +++ b/drivers/iio/accel/bmc150-accel-spi.c @@ -52,15 +52,15 @@ static const struct acpi_device_id bmc150_accel_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match); static const struct spi_device_id bmc150_accel_id[] = { - {"bma222"}, - {"bma222e"}, - {"bma250e"}, - {"bma253"}, - {"bma255"}, - {"bma280"}, - {"bmc150_accel"}, - {"bmc156_accel", BOSCH_BMC156}, - {"bmi055_accel"}, + { .name = "bma222", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma222e", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma250e", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma253", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma255", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma280", .driver_data = BOSCH_UNKNOWN }, + { .name = "bmc150_accel", .driver_data = BOSCH_UNKNOWN }, + { .name = "bmc156_accel", .driver_data = BOSCH_BMC156 }, + { .name = "bmi055_accel", .driver_data = BOSCH_UNKNOWN }, { } }; MODULE_DEVICE_TABLE(spi, bmc150_accel_id); diff --git a/drivers/iio/accel/bmi088-accel-spi.c b/drivers/iio/accel/bmi088-accel-spi.c index 44cb50c76cb1..ae89e162e097 100644 --- a/drivers/iio/accel/bmi088-accel-spi.c +++ b/drivers/iio/accel/bmi088-accel-spi.c @@ -72,9 +72,9 @@ static const struct of_device_id bmi088_of_match[] = { MODULE_DEVICE_TABLE(of, bmi088_of_match); static const struct spi_device_id bmi088_accel_id[] = { - {"bmi085-accel", BOSCH_BMI085}, - {"bmi088-accel", BOSCH_BMI088}, - {"bmi090l-accel", BOSCH_BMI090L}, + { .name = "bmi085-accel", .driver_data = BOSCH_BMI085 }, + { .name = "bmi088-accel", .driver_data = BOSCH_BMI088 }, + { .name = "bmi090l-accel", .driver_data = BOSCH_BMI090L }, { } }; MODULE_DEVICE_TABLE(spi, bmi088_accel_id); diff --git a/drivers/iio/accel/dmard09.c b/drivers/iio/accel/dmard09.c index fe35a1270786..6f0497ab6133 100644 --- a/drivers/iio/accel/dmard09.c +++ b/drivers/iio/accel/dmard09.c @@ -8,6 +8,7 @@ #include <linux/unaligned.h> #include <linux/module.h> #include <linux/i2c.h> +#include <linux/units.h> #include <linux/iio/iio.h> #define DMARD09_DRV_NAME "dmard09" @@ -79,6 +80,12 @@ static int dmard09_read_raw(struct iio_dev *indio_dev, *val = accel; return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + /* 1 g / 32 LSB, in m/s^2 */ + *val2 = IIO_G_TO_M_S_2(NANO / 32); + + return IIO_VAL_INT_PLUS_NANO; default: return -EINVAL; } diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index d0c2a8daef0d..18d7b09bddd2 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -969,6 +969,8 @@ static int fxls8962af_fifo_flush(struct iio_dev *indio_dev) if (!count) return 0; + count = min(count, FXLS8962AF_FIFO_LENGTH); + data->old_timestamp = data->timestamp; data->timestamp = iio_get_time_ns(indio_dev); diff --git a/drivers/iio/accel/fxls8962af-spi.c b/drivers/iio/accel/fxls8962af-spi.c index 8936032526a0..baf3c4352f14 100644 --- a/drivers/iio/accel/fxls8962af-spi.c +++ b/drivers/iio/accel/fxls8962af-spi.c @@ -34,8 +34,8 @@ static const struct of_device_id fxls8962af_spi_of_match[] = { MODULE_DEVICE_TABLE(of, fxls8962af_spi_of_match); static const struct spi_device_id fxls8962af_spi_id_table[] = { - { "fxls8962af", fxls8962af }, - { "fxls8964af", fxls8964af }, + { .name = "fxls8962af", .driver_data = fxls8962af }, + { .name = "fxls8964af", .driver_data = fxls8964af }, { } }; MODULE_DEVICE_TABLE(spi, fxls8962af_spi_id_table); diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index 737572bb44d9..eb521125f4eb 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -121,9 +121,8 @@ static const struct iio_chan_spec gravity_channels[] = { /* Channel read_raw handler */ static int accel_3d_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, - long mask) + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct accel_3d_state *accel_state = iio_priv(indio_dev); int report_id = -1; @@ -150,7 +149,7 @@ static int accel_3d_read_raw(struct iio_dev *indio_dev, else { *val = 0; hid_sensor_power_state(&accel_state->common_attributes, - false); + false); return -EINVAL; } hid_sensor_power_state(&accel_state->common_attributes, false); @@ -183,10 +182,8 @@ static int accel_3d_read_raw(struct iio_dev *indio_dev, /* Channel write_raw handler */ static int accel_3d_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct accel_3d_state *accel_state = iio_priv(indio_dev); int ret = 0; @@ -222,8 +219,7 @@ static void hid_sensor_push_data(struct iio_dev *indio_dev, void *data, /* Callback handler to send event after all samples are received and captured */ static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - void *priv) + u32 usage_id, void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct accel_3d_state *accel_state = iio_priv(indio_dev); @@ -246,9 +242,9 @@ static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int accel_3d_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - size_t raw_len, char *raw_data, - void *priv) + u32 usage_id, + size_t raw_len, char *raw_data, + void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct accel_3d_state *accel_state = iio_priv(indio_dev); @@ -280,10 +276,10 @@ static int accel_3d_capture_sample(struct hid_sensor_hub_device *hsdev, /* Parse report which is specific to an usage id*/ static int accel_3d_parse_report(struct platform_device *pdev, - struct hid_sensor_hub_device *hsdev, - struct iio_chan_spec *channels, - unsigned usage_id, - struct accel_3d_state *st) + struct hid_sensor_hub_device *hsdev, + struct iio_chan_spec *channels, + u32 usage_id, + struct accel_3d_state *st) { int ret; @@ -302,10 +298,10 @@ static int accel_3d_parse_report(struct platform_device *pdev, }; } dev_dbg(&pdev->dev, "accel_3d %x:%x, %x:%x, %x:%x\n", - st->accel[0].index, - st->accel[0].report_id, - st->accel[1].index, st->accel[1].report_id, - st->accel[2].index, st->accel[2].report_id); + st->accel[0].index, + st->accel[0].report_id, + st->accel[1].index, st->accel[1].report_id, + st->accel[2].index, st->accel[2].report_id); st->scale_precision = hid_sensor_format_scale( hsdev->usage, @@ -328,7 +324,7 @@ static int hid_accel_3d_probe(struct platform_device *pdev) indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct accel_3d_state)); - if (indio_dev == NULL) + if (!indio_dev) return -ENOMEM; platform_set_drvdata(pdev, indio_dev); @@ -365,8 +361,8 @@ static int hid_accel_3d_probe(struct platform_device *pdev) return -ENOMEM; } ret = accel_3d_parse_report(pdev, hsdev, - (struct iio_chan_spec *)indio_dev->channels, - hsdev->usage, accel_state); + (struct iio_chan_spec *)indio_dev->channels, + hsdev->usage, accel_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); return ret; @@ -379,32 +375,32 @@ static int hid_accel_3d_probe(struct platform_device *pdev) atomic_set(&accel_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, - &accel_state->common_attributes); + &accel_state->common_attributes); if (ret < 0) { dev_err(&pdev->dev, "trigger setup failed\n"); return ret; } - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(&pdev->dev, "device register failed\n"); - goto error_remove_trigger; - } - accel_state->callbacks.send_event = accel_3d_proc_event; accel_state->callbacks.capture_sample = accel_3d_capture_sample; accel_state->callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, hsdev->usage, - &accel_state->callbacks); + &accel_state->callbacks); if (ret < 0) { dev_err(&pdev->dev, "callback reg failed\n"); - goto error_iio_unreg; + goto error_remove_trigger; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "device register failed\n"); + goto error_remove_callback; } return ret; -error_iio_unreg: - iio_device_unregister(indio_dev); +error_remove_callback: + sensor_hub_remove_callback(hsdev, hsdev->usage); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes); return ret; @@ -417,8 +413,8 @@ static void hid_accel_3d_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct accel_3d_state *accel_state = iio_priv(indio_dev); - sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); + sensor_hub_remove_callback(hsdev, hsdev->usage); hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes); } diff --git a/drivers/iio/accel/kxsd9-spi.c b/drivers/iio/accel/kxsd9-spi.c index 31a26baba9f7..71da958d4051 100644 --- a/drivers/iio/accel/kxsd9-spi.c +++ b/drivers/iio/accel/kxsd9-spi.c @@ -36,7 +36,7 @@ static void kxsd9_spi_remove(struct spi_device *spi) } static const struct spi_device_id kxsd9_spi_id[] = { - {"kxsd9", 0}, + { .name = "kxsd9" }, { } }; MODULE_DEVICE_TABLE(spi, kxsd9_spi_id); diff --git a/drivers/iio/accel/mma7455_spi.c b/drivers/iio/accel/mma7455_spi.c index aca02e83f789..872c47acf882 100644 --- a/drivers/iio/accel/mma7455_spi.c +++ b/drivers/iio/accel/mma7455_spi.c @@ -28,8 +28,8 @@ static void mma7455_spi_remove(struct spi_device *spi) } static const struct spi_device_id mma7455_spi_ids[] = { - { "mma7455", 0 }, - { "mma7456", 0 }, + { .name = "mma7455" }, + { .name = "mma7456" }, { } }; MODULE_DEVICE_TABLE(spi, mma7455_spi_ids); diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c index 573831199bba..a92a563f6a4b 100644 --- a/drivers/iio/accel/sca3000.c +++ b/drivers/iio/accel/sca3000.c @@ -1504,10 +1504,10 @@ static int sca3000_probe(struct spi_device *spi) } static const struct spi_device_id sca3000_id[] = { - { "sca3000_d01", (kernel_ulong_t)&sca3000_chip_info_d01 }, - { "sca3000_e02", (kernel_ulong_t)&sca3000_chip_info_e02 }, - { "sca3000_e04", (kernel_ulong_t)&sca3000_chip_info_e04 }, - { "sca3000_e05", (kernel_ulong_t)&sca3000_chip_info_e05 }, + { .name = "sca3000_d01", .driver_data = (kernel_ulong_t)&sca3000_chip_info_d01 }, + { .name = "sca3000_e02", .driver_data = (kernel_ulong_t)&sca3000_chip_info_e02 }, + { .name = "sca3000_e04", .driver_data = (kernel_ulong_t)&sca3000_chip_info_e04 }, + { .name = "sca3000_e05", .driver_data = (kernel_ulong_t)&sca3000_chip_info_e05 }, { } }; MODULE_DEVICE_TABLE(spi, sca3000_id); diff --git a/drivers/iio/accel/sca3300.c b/drivers/iio/accel/sca3300.c index 8380b237831c..67582cc34149 100644 --- a/drivers/iio/accel/sca3300.c +++ b/drivers/iio/accel/sca3300.c @@ -664,8 +664,8 @@ static const struct of_device_id sca3300_dt_ids[] = { MODULE_DEVICE_TABLE(of, sca3300_dt_ids); static const struct spi_device_id sca3300_ids[] = { - { "sca3300" }, - { "scl3300" }, + { .name = "sca3300" }, + { .name = "scl3300" }, { } }; MODULE_DEVICE_TABLE(spi, sca3300_ids); diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index e6bf8d0d4ff5..171f241c0a30 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -146,26 +146,26 @@ static int st_accel_spi_probe(struct spi_device *spi) } static const struct spi_device_id st_accel_id_table[] = { - { LIS3DH_ACCEL_DEV_NAME }, - { LSM330D_ACCEL_DEV_NAME }, - { LSM330DL_ACCEL_DEV_NAME }, - { LSM330DLC_ACCEL_DEV_NAME }, - { LIS331DLH_ACCEL_DEV_NAME }, - { 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 }, - { LIS331DL_ACCEL_DEV_NAME }, - { LIS3LV02DL_ACCEL_DEV_NAME }, - { LIS2DW12_ACCEL_DEV_NAME }, - { LIS3DHH_ACCEL_DEV_NAME }, - { LIS3DE_ACCEL_DEV_NAME }, - { LIS302DL_ACCEL_DEV_NAME }, - { LSM303C_ACCEL_DEV_NAME }, - { IIS328DQ_ACCEL_DEV_NAME }, + { .name = LIS3DH_ACCEL_DEV_NAME }, + { .name = LSM330D_ACCEL_DEV_NAME }, + { .name = LSM330DL_ACCEL_DEV_NAME }, + { .name = LSM330DLC_ACCEL_DEV_NAME }, + { .name = LIS331DLH_ACCEL_DEV_NAME }, + { .name = LSM330_ACCEL_DEV_NAME }, + { .name = LSM303AGR_ACCEL_DEV_NAME }, + { .name = LIS2DH12_ACCEL_DEV_NAME }, + { .name = LIS2DS12_ACCEL_DEV_NAME }, + { .name = LIS3L02DQ_ACCEL_DEV_NAME }, + { .name = LNG2DM_ACCEL_DEV_NAME }, + { .name = H3LIS331DL_ACCEL_DEV_NAME }, + { .name = LIS331DL_ACCEL_DEV_NAME }, + { .name = LIS3LV02DL_ACCEL_DEV_NAME }, + { .name = LIS2DW12_ACCEL_DEV_NAME }, + { .name = LIS3DHH_ACCEL_DEV_NAME }, + { .name = LIS3DE_ACCEL_DEV_NAME }, + { .name = LIS302DL_ACCEL_DEV_NAME }, + { .name = LSM303C_ACCEL_DEV_NAME }, + { .name = IIS328DQ_ACCEL_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(spi, st_accel_id_table); diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index 8b5a3e0489e9..ad4d11337f4b 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -7,12 +7,20 @@ * IIO driver for STK8312; 7-bit I2C address: 0x3D. */ +#include <linux/array_size.h> +#include <linux/bits.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> +#include <linux/errno.h> #include <linux/i2c.h> #include <linux/interrupt.h> -#include <linux/kernel.h> #include <linux/module.h> -#include <linux/delay.h> +#include <linux/mod_devicetable.h> +#include <linux/mutex.h> +#include <linux/pm.h> +#include <linux/sysfs.h> #include <linux/types.h> + #include <linux/iio/buffer.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index d0c53b8ac850..54638cd75ea7 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -7,11 +7,18 @@ * STK8BA50 7-bit I2C address: 0x18. */ +#include <linux/array_size.h> +#include <linux/bitops.h> +#include <linux/dev_printk.h> +#include <linux/errno.h> #include <linux/i2c.h> #include <linux/interrupt.h> -#include <linux/kernel.h> #include <linux/module.h> +#include <linux/mutex.h> +#include <linux/pm.h> +#include <linux/sysfs.h> #include <linux/types.h> + #include <linux/iio/buffer.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> diff --git a/drivers/iio/adc/88pm886-gpadc.c b/drivers/iio/adc/88pm886-gpadc.c index ff9bc5f06c18..938ba43c2c35 100644 --- a/drivers/iio/adc/88pm886-gpadc.c +++ b/drivers/iio/adc/88pm886-gpadc.c @@ -279,7 +279,7 @@ static int pm886_gpadc_read_raw(struct iio_dev *iio, struct iio_chan_spec const static int pm886_gpadc_hw_enable(struct regmap *map) { - const u8 config[] = { + static const u8 config[] = { PM886_GPADC_CONFIG1_EN_ALL, PM886_GPADC_CONFIG2_EN_ALL, PM886_GPADC_GND_DET2_EN, diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index c6d3cf68b1f7..c204d83b90d0 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -33,7 +33,8 @@ config AB8500_GPADC and USB voltages integral to the U8500 platform. config AD_SIGMA_DELTA - tristate + tristate "Analog Devices Sigma-Delta Modulator support" if COMPILE_TEST + depends on SPI select IIO_BUFFER select IIO_BUFFER_DMAENGINE select IIO_TRIGGERED_BUFFER @@ -1167,6 +1168,17 @@ config MCP3911 This driver can also be built as a module. If so, the module will be called mcp3911. +config MEDIATEK_MT6323_AUXADC + tristate "MediaTek MT6323 PMIC AUXADC driver" + depends on MFD_MT6397 + help + Say yes here to enable support for MediaTek MT6323 PMIC 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 mt6323-auxadc. + config MEDIATEK_MT6359_AUXADC tristate "MediaTek MT6359 PMIC AUXADC driver" depends on MFD_MT6397 @@ -1791,6 +1803,18 @@ config TI_ADS1119 This driver can also be built as a module. If so, the module will be called ti-ads1119. +config TI_ADS112C14 + tristate "Texas Instruments ADS112C14/ADS122C14" + depends on I2C + select REGMAP + select REGMAP_I2C + help + If you say yes here you get support for Texas Instruments ADS112C14, + ADS122C14 ADC chips. + + This driver can also be built as a module. If so, the module will be + called ti-ads112c14. + config TI_ADS124S08 tristate "Texas Instruments ADS124S08" depends on SPI @@ -1966,6 +1990,39 @@ config TWL6030_GPADC This driver can also be built as a module. If so, the module will be called twl6030-gpadc. +config VERSAL_SYSMON_CORE + tristate + select REGMAP + +config VERSAL_SYSMON + tristate "AMD Versal SysMon driver" + depends on ARCH_ZYNQMP || COMPILE_TEST + depends on HAS_IOMEM + select VERSAL_SYSMON_CORE + help + Say yes here to have support for the AMD/Xilinx Versal System + Monitor (SysMon). This driver provides voltage and temperature + monitoring through the IIO subsystem. + + The SysMon measures up to 160 supply voltages and reads up to + 64 temperature satellites distributed across the SoC. + + To compile this driver as a module, choose M here: the module + will be called versal-sysmon. + +config VERSAL_SYSMON_I2C + tristate "AMD Versal SysMon I2C driver" + depends on I2C + select VERSAL_SYSMON_CORE + help + Say yes here to have support for the AMD/Xilinx Versal System + Monitor (SysMon) via I2C interface. This driver enables voltage + and temperature monitoring when the Versal chip has SysMon + configured with I2C access. + + To compile this driver as a module, choose M here: the module + will be called versal-sysmon-i2c. + config VF610_ADC tristate "Freescale vf610 ADC driver" depends on HAS_IOMEM diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 707dd708912f..3778c7b0b8b5 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -100,6 +100,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_MCP3564) += mcp3564.o obj-$(CONFIG_MCP3911) += mcp3911.o +obj-$(CONFIG_MEDIATEK_MT6323_AUXADC) += mt6323-auxadc.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 @@ -153,6 +154,7 @@ obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o obj-$(CONFIG_TI_ADS1018) += ti-ads1018.o obj-$(CONFIG_TI_ADS1100) += ti-ads1100.o obj-$(CONFIG_TI_ADS1119) += ti-ads1119.o +obj-$(CONFIG_TI_ADS112C14) += ti-ads112c14.o obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o obj-$(CONFIG_TI_ADS1298) += ti-ads1298.o obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o @@ -168,6 +170,9 @@ obj-$(CONFIG_TI_TLC4541) += ti-tlc4541.o obj-$(CONFIG_TI_TSC2046) += ti-tsc2046.o obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o +obj-$(CONFIG_VERSAL_SYSMON_CORE) += versal-sysmon-core.o +obj-$(CONFIG_VERSAL_SYSMON) += versal-sysmon.o +obj-$(CONFIG_VERSAL_SYSMON_I2C) += versal-sysmon-i2c.o obj-$(CONFIG_VF610_ADC) += vf610_adc.o obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o obj-$(CONFIG_XILINX_AMS) += xilinx-ams.o diff --git a/drivers/iio/adc/ad4000.c b/drivers/iio/adc/ad4000.c index c2f6f5f9812c..a33896b2cf97 100644 --- a/drivers/iio/adc/ad4000.c +++ b/drivers/iio/adc/ad4000.c @@ -1176,37 +1176,37 @@ static int ad4000_probe(struct spi_device *spi) } static const struct spi_device_id ad4000_id[] = { - { "ad4000", (kernel_ulong_t)&ad4000_chip_info }, - { "ad4001", (kernel_ulong_t)&ad4001_chip_info }, - { "ad4002", (kernel_ulong_t)&ad4002_chip_info }, - { "ad4003", (kernel_ulong_t)&ad4003_chip_info }, - { "ad4004", (kernel_ulong_t)&ad4004_chip_info }, - { "ad4005", (kernel_ulong_t)&ad4005_chip_info }, - { "ad4006", (kernel_ulong_t)&ad4006_chip_info }, - { "ad4007", (kernel_ulong_t)&ad4007_chip_info }, - { "ad4008", (kernel_ulong_t)&ad4008_chip_info }, - { "ad4010", (kernel_ulong_t)&ad4010_chip_info }, - { "ad4011", (kernel_ulong_t)&ad4011_chip_info }, - { "ad4020", (kernel_ulong_t)&ad4020_chip_info }, - { "ad4021", (kernel_ulong_t)&ad4021_chip_info }, - { "ad4022", (kernel_ulong_t)&ad4022_chip_info }, - { "adaq4001", (kernel_ulong_t)&adaq4001_chip_info }, - { "adaq4003", (kernel_ulong_t)&adaq4003_chip_info }, - { "ad7685", (kernel_ulong_t)&ad7685_chip_info }, - { "ad7686", (kernel_ulong_t)&ad7686_chip_info }, - { "ad7687", (kernel_ulong_t)&ad7687_chip_info }, - { "ad7688", (kernel_ulong_t)&ad7688_chip_info }, - { "ad7690", (kernel_ulong_t)&ad7690_chip_info }, - { "ad7691", (kernel_ulong_t)&ad7691_chip_info }, - { "ad7693", (kernel_ulong_t)&ad7693_chip_info }, - { "ad7942", (kernel_ulong_t)&ad7942_chip_info }, - { "ad7946", (kernel_ulong_t)&ad7946_chip_info }, - { "ad7980", (kernel_ulong_t)&ad7980_chip_info }, - { "ad7982", (kernel_ulong_t)&ad7982_chip_info }, - { "ad7983", (kernel_ulong_t)&ad7983_chip_info }, - { "ad7984", (kernel_ulong_t)&ad7984_chip_info }, - { "ad7988-1", (kernel_ulong_t)&ad7988_1_chip_info }, - { "ad7988-5", (kernel_ulong_t)&ad7988_5_chip_info }, + { .name = "ad4000", .driver_data = (kernel_ulong_t)&ad4000_chip_info }, + { .name = "ad4001", .driver_data = (kernel_ulong_t)&ad4001_chip_info }, + { .name = "ad4002", .driver_data = (kernel_ulong_t)&ad4002_chip_info }, + { .name = "ad4003", .driver_data = (kernel_ulong_t)&ad4003_chip_info }, + { .name = "ad4004", .driver_data = (kernel_ulong_t)&ad4004_chip_info }, + { .name = "ad4005", .driver_data = (kernel_ulong_t)&ad4005_chip_info }, + { .name = "ad4006", .driver_data = (kernel_ulong_t)&ad4006_chip_info }, + { .name = "ad4007", .driver_data = (kernel_ulong_t)&ad4007_chip_info }, + { .name = "ad4008", .driver_data = (kernel_ulong_t)&ad4008_chip_info }, + { .name = "ad4010", .driver_data = (kernel_ulong_t)&ad4010_chip_info }, + { .name = "ad4011", .driver_data = (kernel_ulong_t)&ad4011_chip_info }, + { .name = "ad4020", .driver_data = (kernel_ulong_t)&ad4020_chip_info }, + { .name = "ad4021", .driver_data = (kernel_ulong_t)&ad4021_chip_info }, + { .name = "ad4022", .driver_data = (kernel_ulong_t)&ad4022_chip_info }, + { .name = "adaq4001", .driver_data = (kernel_ulong_t)&adaq4001_chip_info }, + { .name = "adaq4003", .driver_data = (kernel_ulong_t)&adaq4003_chip_info }, + { .name = "ad7685", .driver_data = (kernel_ulong_t)&ad7685_chip_info }, + { .name = "ad7686", .driver_data = (kernel_ulong_t)&ad7686_chip_info }, + { .name = "ad7687", .driver_data = (kernel_ulong_t)&ad7687_chip_info }, + { .name = "ad7688", .driver_data = (kernel_ulong_t)&ad7688_chip_info }, + { .name = "ad7690", .driver_data = (kernel_ulong_t)&ad7690_chip_info }, + { .name = "ad7691", .driver_data = (kernel_ulong_t)&ad7691_chip_info }, + { .name = "ad7693", .driver_data = (kernel_ulong_t)&ad7693_chip_info }, + { .name = "ad7942", .driver_data = (kernel_ulong_t)&ad7942_chip_info }, + { .name = "ad7946", .driver_data = (kernel_ulong_t)&ad7946_chip_info }, + { .name = "ad7980", .driver_data = (kernel_ulong_t)&ad7980_chip_info }, + { .name = "ad7982", .driver_data = (kernel_ulong_t)&ad7982_chip_info }, + { .name = "ad7983", .driver_data = (kernel_ulong_t)&ad7983_chip_info }, + { .name = "ad7984", .driver_data = (kernel_ulong_t)&ad7984_chip_info }, + { .name = "ad7988-1", .driver_data = (kernel_ulong_t)&ad7988_1_chip_info }, + { .name = "ad7988-5", .driver_data = (kernel_ulong_t)&ad7988_5_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad4000_id); diff --git a/drivers/iio/adc/ad4030.c b/drivers/iio/adc/ad4030.c index 9c5f19321e3b..e97400a1aa48 100644 --- a/drivers/iio/adc/ad4030.c +++ b/drivers/iio/adc/ad4030.c @@ -1763,13 +1763,13 @@ static const struct ad4030_chip_info adaq4224_chip_info = { }; static const struct spi_device_id ad4030_id_table[] = { - { "ad4030-24", (kernel_ulong_t)&ad4030_24_chip_info }, - { "ad4630-16", (kernel_ulong_t)&ad4630_16_chip_info }, - { "ad4630-24", (kernel_ulong_t)&ad4630_24_chip_info }, - { "ad4632-16", (kernel_ulong_t)&ad4632_16_chip_info }, - { "ad4632-24", (kernel_ulong_t)&ad4632_24_chip_info }, - { "adaq4216", (kernel_ulong_t)&adaq4216_chip_info }, - { "adaq4224", (kernel_ulong_t)&adaq4224_chip_info }, + { .name = "ad4030-24", .driver_data = (kernel_ulong_t)&ad4030_24_chip_info }, + { .name = "ad4630-16", .driver_data = (kernel_ulong_t)&ad4630_16_chip_info }, + { .name = "ad4630-24", .driver_data = (kernel_ulong_t)&ad4630_24_chip_info }, + { .name = "ad4632-16", .driver_data = (kernel_ulong_t)&ad4632_16_chip_info }, + { .name = "ad4632-24", .driver_data = (kernel_ulong_t)&ad4632_24_chip_info }, + { .name = "adaq4216", .driver_data = (kernel_ulong_t)&adaq4216_chip_info }, + { .name = "adaq4224", .driver_data = (kernel_ulong_t)&adaq4224_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad4030_id_table); diff --git a/drivers/iio/adc/ad4080.c b/drivers/iio/adc/ad4080.c index 967144eee3eb..04cd6628ebff 100644 --- a/drivers/iio/adc/ad4080.c +++ b/drivers/iio/adc/ad4080.c @@ -135,6 +135,7 @@ #define AD4087_CHIP_ID 0x0057 #define AD4088_CHIP_ID 0x0058 #define AD4880_CHIP_ID 0x0059 +#define AD4883_CHIP_ID 0x005B #define AD4884_CHIP_ID 0x005C #define AD4080_MAX_CHANNELS 2 @@ -541,6 +542,11 @@ static const struct iio_chan_spec ad4880_channels[] = { AD4880_CHANNEL_DEFINE(20, 32, 1), }; +static const struct iio_chan_spec ad4883_channels[] = { + AD4880_CHANNEL_DEFINE(16, 16, 0), + AD4880_CHANNEL_DEFINE(16, 16, 1), +}; + static const struct iio_chan_spec ad4884_channels[] = { AD4880_CHANNEL_DEFINE(16, 16, 0), AD4880_CHANNEL_DEFINE(16, 16, 1), @@ -646,6 +652,16 @@ static const struct ad4080_chip_info ad4880_chip_info = { .lvds_cnv_clk_cnt_max = AD4080_LVDS_CNV_CLK_CNT_MAX, }; +static const struct ad4080_chip_info ad4883_chip_info = { + .name = "ad4883", + .product_id = AD4883_CHIP_ID, + .scale_table = ad4080_scale_table, + .num_scales = ARRAY_SIZE(ad4080_scale_table), + .num_channels = 2, + .channels = ad4883_channels, + .lvds_cnv_clk_cnt_max = 5, +}; + static const struct ad4080_chip_info ad4884_chip_info = { .name = "ad4884", .product_id = AD4884_CHIP_ID, @@ -853,17 +869,18 @@ static int ad4080_probe(struct spi_device *spi) } static const struct spi_device_id ad4080_id[] = { - { "ad4080", (kernel_ulong_t)&ad4080_chip_info }, - { "ad4081", (kernel_ulong_t)&ad4081_chip_info }, - { "ad4082", (kernel_ulong_t)&ad4082_chip_info }, - { "ad4083", (kernel_ulong_t)&ad4083_chip_info }, - { "ad4084", (kernel_ulong_t)&ad4084_chip_info }, - { "ad4085", (kernel_ulong_t)&ad4085_chip_info }, - { "ad4086", (kernel_ulong_t)&ad4086_chip_info }, - { "ad4087", (kernel_ulong_t)&ad4087_chip_info }, - { "ad4088", (kernel_ulong_t)&ad4088_chip_info }, - { "ad4880", (kernel_ulong_t)&ad4880_chip_info }, - { "ad4884", (kernel_ulong_t)&ad4884_chip_info }, + { .name = "ad4080", .driver_data = (kernel_ulong_t)&ad4080_chip_info }, + { .name = "ad4081", .driver_data = (kernel_ulong_t)&ad4081_chip_info }, + { .name = "ad4082", .driver_data = (kernel_ulong_t)&ad4082_chip_info }, + { .name = "ad4083", .driver_data = (kernel_ulong_t)&ad4083_chip_info }, + { .name = "ad4084", .driver_data = (kernel_ulong_t)&ad4084_chip_info }, + { .name = "ad4085", .driver_data = (kernel_ulong_t)&ad4085_chip_info }, + { .name = "ad4086", .driver_data = (kernel_ulong_t)&ad4086_chip_info }, + { .name = "ad4087", .driver_data = (kernel_ulong_t)&ad4087_chip_info }, + { .name = "ad4088", .driver_data = (kernel_ulong_t)&ad4088_chip_info }, + { .name = "ad4880", .driver_data = (kernel_ulong_t)&ad4880_chip_info }, + { .name = "ad4883", .driver_data = (kernel_ulong_t)&ad4883_chip_info }, + { .name = "ad4884", .driver_data = (kernel_ulong_t)&ad4884_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad4080_id); @@ -879,6 +896,7 @@ static const struct of_device_id ad4080_of_match[] = { { .compatible = "adi,ad4087", &ad4087_chip_info }, { .compatible = "adi,ad4088", &ad4088_chip_info }, { .compatible = "adi,ad4880", &ad4880_chip_info }, + { .compatible = "adi,ad4883", &ad4883_chip_info }, { .compatible = "adi,ad4884", &ad4884_chip_info }, { } }; diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c index 7f39f3484062..3ffc4b765e0e 100644 --- a/drivers/iio/adc/ad4130.c +++ b/drivers/iio/adc/ad4130.c @@ -2425,12 +2425,12 @@ static const struct of_device_id ad4130_of_match[] = { MODULE_DEVICE_TABLE(of, ad4130_of_match); static const struct spi_device_id ad4130_id_table[] = { - { "ad4129-4", (kernel_ulong_t)&ad4129_4_chip_info }, - { "ad4129-8", (kernel_ulong_t)&ad4129_8_chip_info }, - { "ad4130-4", (kernel_ulong_t)&ad4130_4_chip_info }, - { "ad4130", (kernel_ulong_t)&ad4130_8_chip_info }, - { "ad4131-4", (kernel_ulong_t)&ad4131_4_chip_info }, - { "ad4131-8", (kernel_ulong_t)&ad4131_8_chip_info }, + { .name = "ad4129-4", .driver_data = (kernel_ulong_t)&ad4129_4_chip_info }, + { .name = "ad4129-8", .driver_data = (kernel_ulong_t)&ad4129_8_chip_info }, + { .name = "ad4130-4", .driver_data = (kernel_ulong_t)&ad4130_4_chip_info }, + { .name = "ad4130", .driver_data = (kernel_ulong_t)&ad4130_8_chip_info }, + { .name = "ad4131-4", .driver_data = (kernel_ulong_t)&ad4131_4_chip_info }, + { .name = "ad4131-8", .driver_data = (kernel_ulong_t)&ad4131_8_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad4130_id_table); diff --git a/drivers/iio/adc/ad4134.c b/drivers/iio/adc/ad4134.c index cb9d74316f6a..0490218bb0e9 100644 --- a/drivers/iio/adc/ad4134.c +++ b/drivers/iio/adc/ad4134.c @@ -472,7 +472,7 @@ static int ad4134_probe(struct spi_device *spi) } static const struct spi_device_id ad4134_id[] = { - { "ad4134" }, + { .name = "ad4134" }, { } }; MODULE_DEVICE_TABLE(spi, ad4134_id); diff --git a/drivers/iio/adc/ad4170-4.c b/drivers/iio/adc/ad4170-4.c index 627cbf5a37b0..f7757b3a931c 100644 --- a/drivers/iio/adc/ad4170-4.c +++ b/drivers/iio/adc/ad4170-4.c @@ -2979,9 +2979,9 @@ static int ad4170_probe(struct spi_device *spi) } static const struct spi_device_id ad4170_id_table[] = { - { "ad4170-4", (kernel_ulong_t)&ad4170_chip_info }, - { "ad4190-4", (kernel_ulong_t)&ad4190_chip_info }, - { "ad4195-4", (kernel_ulong_t)&ad4195_chip_info }, + { .name = "ad4170-4", .driver_data = (kernel_ulong_t)&ad4170_chip_info }, + { .name = "ad4190-4", .driver_data = (kernel_ulong_t)&ad4190_chip_info }, + { .name = "ad4195-4", .driver_data = (kernel_ulong_t)&ad4195_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad4170_id_table); diff --git a/drivers/iio/adc/ad4851.c b/drivers/iio/adc/ad4851.c index 940b042d743a..480d1798f17b 100644 --- a/drivers/iio/adc/ad4851.c +++ b/drivers/iio/adc/ad4851.c @@ -1285,15 +1285,15 @@ static const struct of_device_id ad4851_of_match[] = { }; static const struct spi_device_id ad4851_spi_id[] = { - { "ad4851", (kernel_ulong_t)&ad4851_info }, - { "ad4852", (kernel_ulong_t)&ad4852_info }, - { "ad4853", (kernel_ulong_t)&ad4853_info }, - { "ad4854", (kernel_ulong_t)&ad4854_info }, - { "ad4855", (kernel_ulong_t)&ad4855_info }, - { "ad4856", (kernel_ulong_t)&ad4856_info }, - { "ad4857", (kernel_ulong_t)&ad4857_info }, - { "ad4858", (kernel_ulong_t)&ad4858_info }, - { "ad4858i", (kernel_ulong_t)&ad4858i_info }, + { .name = "ad4851", .driver_data = (kernel_ulong_t)&ad4851_info }, + { .name = "ad4852", .driver_data = (kernel_ulong_t)&ad4852_info }, + { .name = "ad4853", .driver_data = (kernel_ulong_t)&ad4853_info }, + { .name = "ad4854", .driver_data = (kernel_ulong_t)&ad4854_info }, + { .name = "ad4855", .driver_data = (kernel_ulong_t)&ad4855_info }, + { .name = "ad4856", .driver_data = (kernel_ulong_t)&ad4856_info }, + { .name = "ad4857", .driver_data = (kernel_ulong_t)&ad4857_info }, + { .name = "ad4858", .driver_data = (kernel_ulong_t)&ad4858_info }, + { .name = "ad4858i", .driver_data = (kernel_ulong_t)&ad4858i_info }, { } }; MODULE_DEVICE_TABLE(spi, ad4851_spi_id); diff --git a/drivers/iio/adc/ad7091r8.c b/drivers/iio/adc/ad7091r8.c index e93b8bb60e8e..465a8ba01a22 100644 --- a/drivers/iio/adc/ad7091r8.c +++ b/drivers/iio/adc/ad7091r8.c @@ -249,9 +249,9 @@ static const struct of_device_id ad7091r8_of_match[] = { MODULE_DEVICE_TABLE(of, ad7091r8_of_match); static const struct spi_device_id ad7091r8_spi_id[] = { - { "ad7091r2", (kernel_ulong_t)&ad7091r2_init_info }, - { "ad7091r4", (kernel_ulong_t)&ad7091r4_init_info }, - { "ad7091r8", (kernel_ulong_t)&ad7091r8_init_info }, + { .name = "ad7091r2", .driver_data = (kernel_ulong_t)&ad7091r2_init_info }, + { .name = "ad7091r4", .driver_data = (kernel_ulong_t)&ad7091r4_init_info }, + { .name = "ad7091r8", .driver_data = (kernel_ulong_t)&ad7091r8_init_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7091r8_spi_id); diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index 19058d081418..fc5dbc624856 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -1683,8 +1683,8 @@ static const struct of_device_id ad7124_of_match[] = { MODULE_DEVICE_TABLE(of, ad7124_of_match); static const struct spi_device_id ad71124_ids[] = { - { "ad7124-4", (kernel_ulong_t)&ad7124_4_chip_info }, - { "ad7124-8", (kernel_ulong_t)&ad7124_8_chip_info }, + { .name = "ad7124-4", .driver_data = (kernel_ulong_t)&ad7124_4_chip_info }, + { .name = "ad7124-8", .driver_data = (kernel_ulong_t)&ad7124_8_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad71124_ids); diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index 9ee65d63c525..c940f51ad744 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -2065,19 +2065,19 @@ static const struct of_device_id ad7173_of_match[] = { MODULE_DEVICE_TABLE(of, ad7173_of_match); static const struct spi_device_id ad7173_id_table[] = { - { "ad4111", (kernel_ulong_t)&ad4111_device_info }, - { "ad4112", (kernel_ulong_t)&ad4112_device_info }, - { "ad4113", (kernel_ulong_t)&ad4113_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 }, + { .name = "ad4111", .driver_data = (kernel_ulong_t)&ad4111_device_info }, + { .name = "ad4112", .driver_data = (kernel_ulong_t)&ad4112_device_info }, + { .name = "ad4113", .driver_data = (kernel_ulong_t)&ad4113_device_info }, + { .name = "ad4114", .driver_data = (kernel_ulong_t)&ad4114_device_info }, + { .name = "ad4115", .driver_data = (kernel_ulong_t)&ad4115_device_info }, + { .name = "ad4116", .driver_data = (kernel_ulong_t)&ad4116_device_info }, + { .name = "ad7172-2", .driver_data = (kernel_ulong_t)&ad7172_2_device_info }, + { .name = "ad7172-4", .driver_data = (kernel_ulong_t)&ad7172_4_device_info }, + { .name = "ad7173-8", .driver_data = (kernel_ulong_t)&ad7173_8_device_info }, + { .name = "ad7175-2", .driver_data = (kernel_ulong_t)&ad7175_2_device_info }, + { .name = "ad7175-8", .driver_data = (kernel_ulong_t)&ad7175_8_device_info }, + { .name = "ad7176-2", .driver_data = (kernel_ulong_t)&ad7176_2_device_info }, + { .name = "ad7177-2", .driver_data = (kernel_ulong_t)&ad7177_2_device_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7173_id_table); diff --git a/drivers/iio/adc/ad7191.c b/drivers/iio/adc/ad7191.c index 94b172dce866..071d26191b3c 100644 --- a/drivers/iio/adc/ad7191.c +++ b/drivers/iio/adc/ad7191.c @@ -535,7 +535,7 @@ static const struct of_device_id ad7191_of_match[] = { MODULE_DEVICE_TABLE(of, ad7191_of_match); static const struct spi_device_id ad7191_id_table[] = { - { "ad7191" }, + { .name = "ad7191" }, { } }; MODULE_DEVICE_TABLE(spi, ad7191_id_table); diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index 2cfad0bda752..d8f5886fcf69 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -1448,11 +1448,11 @@ static const struct of_device_id ad7192_of_match[] = { MODULE_DEVICE_TABLE(of, ad7192_of_match); static const struct spi_device_id ad7192_ids[] = { - { "ad7190", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7190] }, - { "ad7192", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7192] }, - { "ad7193", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7193] }, - { "ad7194", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7194] }, - { "ad7195", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7195] }, + { .name = "ad7190", .driver_data = (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7190] }, + { .name = "ad7192", .driver_data = (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7192] }, + { .name = "ad7193", .driver_data = (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7193] }, + { .name = "ad7194", .driver_data = (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7194] }, + { .name = "ad7195", .driver_data = (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7195] }, { } }; MODULE_DEVICE_TABLE(spi, ad7192_ids); diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c index 0ef36c249ab8..594a070c3745 100644 --- a/drivers/iio/adc/ad7266.c +++ b/drivers/iio/adc/ad7266.c @@ -453,8 +453,8 @@ static int ad7266_probe(struct spi_device *spi) } static const struct spi_device_id ad7266_id[] = { - { "ad7265", 0 }, - { "ad7266", 0 }, + { .name = "ad7265" }, + { .name = "ad7266" }, { } }; MODULE_DEVICE_TABLE(spi, ad7266_id); diff --git a/drivers/iio/adc/ad7280a.c b/drivers/iio/adc/ad7280a.c index 2972e706de92..505fa68ee539 100644 --- a/drivers/iio/adc/ad7280a.c +++ b/drivers/iio/adc/ad7280a.c @@ -1082,7 +1082,7 @@ static int ad7280_probe(struct spi_device *spi) } static const struct spi_device_id ad7280_id[] = { - { "ad7280a", 0 }, + { .name = "ad7280a" }, { } }; MODULE_DEVICE_TABLE(spi, ad7280_id); diff --git a/drivers/iio/adc/ad7292.c b/drivers/iio/adc/ad7292.c index 0ba0fbad4f70..1d7bf46b80e2 100644 --- a/drivers/iio/adc/ad7292.c +++ b/drivers/iio/adc/ad7292.c @@ -299,7 +299,7 @@ static int ad7292_probe(struct spi_device *spi) } static const struct spi_device_id ad7292_id_table[] = { - { "ad7292", 0 }, + { .name = "ad7292" }, { } }; MODULE_DEVICE_TABLE(spi, ad7292_id_table); diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c index 5fa76aec360e..c669022b5dec 100644 --- a/drivers/iio/adc/ad7298.c +++ b/drivers/iio/adc/ad7298.c @@ -353,7 +353,7 @@ static const struct acpi_device_id ad7298_acpi_ids[] = { MODULE_DEVICE_TABLE(acpi, ad7298_acpi_ids); static const struct spi_device_id ad7298_id[] = { - { "ad7298", 0 }, + { .name = "ad7298" }, { } }; MODULE_DEVICE_TABLE(spi, ad7298_id); diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c index 9f77990a03f9..2e90f125a797 100644 --- a/drivers/iio/adc/ad7380.c +++ b/drivers/iio/adc/ad7380.c @@ -2116,24 +2116,24 @@ static const struct of_device_id ad7380_of_match_table[] = { }; static const struct spi_device_id ad7380_id_table[] = { - { "ad7380", (kernel_ulong_t)&ad7380_chip_info }, - { "ad7381", (kernel_ulong_t)&ad7381_chip_info }, - { "ad7383", (kernel_ulong_t)&ad7383_chip_info }, - { "ad7384", (kernel_ulong_t)&ad7384_chip_info }, - { "ad7386", (kernel_ulong_t)&ad7386_chip_info }, - { "ad7387", (kernel_ulong_t)&ad7387_chip_info }, - { "ad7388", (kernel_ulong_t)&ad7388_chip_info }, - { "ad7380-4", (kernel_ulong_t)&ad7380_4_chip_info }, - { "ad7381-4", (kernel_ulong_t)&ad7381_4_chip_info }, - { "ad7383-4", (kernel_ulong_t)&ad7383_4_chip_info }, - { "ad7384-4", (kernel_ulong_t)&ad7384_4_chip_info }, - { "ad7386-4", (kernel_ulong_t)&ad7386_4_chip_info }, - { "ad7387-4", (kernel_ulong_t)&ad7387_4_chip_info }, - { "ad7388-4", (kernel_ulong_t)&ad7388_4_chip_info }, - { "ad7389-4", (kernel_ulong_t)&ad7389_4_chip_info }, - { "adaq4370-4", (kernel_ulong_t)&adaq4370_4_chip_info }, - { "adaq4380-4", (kernel_ulong_t)&adaq4380_4_chip_info }, - { "adaq4381-4", (kernel_ulong_t)&adaq4381_4_chip_info }, + { .name = "ad7380", .driver_data = (kernel_ulong_t)&ad7380_chip_info }, + { .name = "ad7381", .driver_data = (kernel_ulong_t)&ad7381_chip_info }, + { .name = "ad7383", .driver_data = (kernel_ulong_t)&ad7383_chip_info }, + { .name = "ad7384", .driver_data = (kernel_ulong_t)&ad7384_chip_info }, + { .name = "ad7386", .driver_data = (kernel_ulong_t)&ad7386_chip_info }, + { .name = "ad7387", .driver_data = (kernel_ulong_t)&ad7387_chip_info }, + { .name = "ad7388", .driver_data = (kernel_ulong_t)&ad7388_chip_info }, + { .name = "ad7380-4", .driver_data = (kernel_ulong_t)&ad7380_4_chip_info }, + { .name = "ad7381-4", .driver_data = (kernel_ulong_t)&ad7381_4_chip_info }, + { .name = "ad7383-4", .driver_data = (kernel_ulong_t)&ad7383_4_chip_info }, + { .name = "ad7384-4", .driver_data = (kernel_ulong_t)&ad7384_4_chip_info }, + { .name = "ad7386-4", .driver_data = (kernel_ulong_t)&ad7386_4_chip_info }, + { .name = "ad7387-4", .driver_data = (kernel_ulong_t)&ad7387_4_chip_info }, + { .name = "ad7388-4", .driver_data = (kernel_ulong_t)&ad7388_4_chip_info }, + { .name = "ad7389-4", .driver_data = (kernel_ulong_t)&ad7389_4_chip_info }, + { .name = "adaq4370-4", .driver_data = (kernel_ulong_t)&adaq4370_4_chip_info }, + { .name = "adaq4380-4", .driver_data = (kernel_ulong_t)&adaq4380_4_chip_info }, + { .name = "adaq4381-4", .driver_data = (kernel_ulong_t)&adaq4381_4_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7380_id_table); diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index 21d3f6aae972..c007f453ae18 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -411,42 +411,42 @@ static int ad7476_probe(struct spi_device *spi) } static const struct spi_device_id ad7476_id[] = { - { "ad7091", (kernel_ulong_t)&ad7091_chip_info }, - { "ad7091r", (kernel_ulong_t)&ad7091r_chip_info }, - { "ad7273", (kernel_ulong_t)&ad7273_chip_info }, - { "ad7274", (kernel_ulong_t)&ad7274_chip_info }, - { "ad7276", (kernel_ulong_t)&ad7276_chip_info }, - { "ad7277", (kernel_ulong_t)&ad7277_chip_info }, - { "ad7278", (kernel_ulong_t)&ad7278_chip_info }, - { "ad7466", (kernel_ulong_t)&ad7466_chip_info }, - { "ad7467", (kernel_ulong_t)&ad7467_chip_info }, - { "ad7468", (kernel_ulong_t)&ad7468_chip_info }, - { "ad7475", (kernel_ulong_t)&ad7475_chip_info }, - { "ad7476", (kernel_ulong_t)&ad7466_chip_info }, - { "ad7476a", (kernel_ulong_t)&ad7466_chip_info }, - { "ad7477", (kernel_ulong_t)&ad7467_chip_info }, - { "ad7477a", (kernel_ulong_t)&ad7467_chip_info }, - { "ad7478", (kernel_ulong_t)&ad7468_chip_info }, - { "ad7478a", (kernel_ulong_t)&ad7468_chip_info }, - { "ad7495", (kernel_ulong_t)&ad7495_chip_info }, - { "ad7910", (kernel_ulong_t)&ad7467_chip_info }, - { "ad7920", (kernel_ulong_t)&ad7466_chip_info }, - { "ad7940", (kernel_ulong_t)&ad7940_chip_info }, - { "adc081s", (kernel_ulong_t)&adc081s_chip_info }, - { "adc101s", (kernel_ulong_t)&adc101s_chip_info }, - { "adc121s", (kernel_ulong_t)&adc121s_chip_info }, - { "ads7866", (kernel_ulong_t)&ads7866_chip_info }, - { "ads7867", (kernel_ulong_t)&ads7867_chip_info }, - { "ads7868", (kernel_ulong_t)&ads7868_chip_info }, - { "bd79105", (kernel_ulong_t)&bd79105_chip_info }, + { .name = "ad7091", .driver_data = (kernel_ulong_t)&ad7091_chip_info }, + { .name = "ad7091r", .driver_data = (kernel_ulong_t)&ad7091r_chip_info }, + { .name = "ad7273", .driver_data = (kernel_ulong_t)&ad7273_chip_info }, + { .name = "ad7274", .driver_data = (kernel_ulong_t)&ad7274_chip_info }, + { .name = "ad7276", .driver_data = (kernel_ulong_t)&ad7276_chip_info }, + { .name = "ad7277", .driver_data = (kernel_ulong_t)&ad7277_chip_info }, + { .name = "ad7278", .driver_data = (kernel_ulong_t)&ad7278_chip_info }, + { .name = "ad7466", .driver_data = (kernel_ulong_t)&ad7466_chip_info }, + { .name = "ad7467", .driver_data = (kernel_ulong_t)&ad7467_chip_info }, + { .name = "ad7468", .driver_data = (kernel_ulong_t)&ad7468_chip_info }, + { .name = "ad7475", .driver_data = (kernel_ulong_t)&ad7475_chip_info }, + { .name = "ad7476", .driver_data = (kernel_ulong_t)&ad7466_chip_info }, + { .name = "ad7476a", .driver_data = (kernel_ulong_t)&ad7466_chip_info }, + { .name = "ad7477", .driver_data = (kernel_ulong_t)&ad7467_chip_info }, + { .name = "ad7477a", .driver_data = (kernel_ulong_t)&ad7467_chip_info }, + { .name = "ad7478", .driver_data = (kernel_ulong_t)&ad7468_chip_info }, + { .name = "ad7478a", .driver_data = (kernel_ulong_t)&ad7468_chip_info }, + { .name = "ad7495", .driver_data = (kernel_ulong_t)&ad7495_chip_info }, + { .name = "ad7910", .driver_data = (kernel_ulong_t)&ad7467_chip_info }, + { .name = "ad7920", .driver_data = (kernel_ulong_t)&ad7466_chip_info }, + { .name = "ad7940", .driver_data = (kernel_ulong_t)&ad7940_chip_info }, + { .name = "adc081s", .driver_data = (kernel_ulong_t)&adc081s_chip_info }, + { .name = "adc101s", .driver_data = (kernel_ulong_t)&adc101s_chip_info }, + { .name = "adc121s", .driver_data = (kernel_ulong_t)&adc121s_chip_info }, + { .name = "ads7866", .driver_data = (kernel_ulong_t)&ads7866_chip_info }, + { .name = "ads7867", .driver_data = (kernel_ulong_t)&ads7867_chip_info }, + { .name = "ads7868", .driver_data = (kernel_ulong_t)&ads7868_chip_info }, + { .name = "bd79105", .driver_data = (kernel_ulong_t)&bd79105_chip_info }, /* * The ROHM BU79100G is identical to the TI's ADS7866 from the software * point of view. The binding document mandates the ADS7866 to be * marked as a fallback for the BU79100G, but we still need the SPI ID * here to make the module loading work. */ - { "bu79100g", (kernel_ulong_t)&ads7866_chip_info }, - { "ltc2314-14", (kernel_ulong_t)<c2314_14_chip_info }, + { .name = "bu79100g", .driver_data = (kernel_ulong_t)&ads7866_chip_info }, + { .name = "ltc2314-14", .driver_data = (kernel_ulong_t)<c2314_14_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7476_id); diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c index 7e17ccbcedd0..1ebdfb8580ab 100644 --- a/drivers/iio/adc/ad7606_spi.c +++ b/drivers/iio/adc/ad7606_spi.c @@ -463,17 +463,17 @@ static int ad7606_spi_probe(struct spi_device *spi) } static const struct spi_device_id ad7606_id_table[] = { - { "ad7605-4", (kernel_ulong_t)&ad7605_4_bus_info }, - { "ad7606-4", (kernel_ulong_t)&ad7606_4_bus_info }, - { "ad7606-6", (kernel_ulong_t)&ad7606_6_bus_info }, - { "ad7606-8", (kernel_ulong_t)&ad7606_8_bus_info }, - { "ad7606b", (kernel_ulong_t)&ad7606b_bus_info }, - { "ad7606c-16", (kernel_ulong_t)&ad7606c_16_bus_info }, - { "ad7606c-18", (kernel_ulong_t)&ad7606c_18_bus_info }, - { "ad7607", (kernel_ulong_t)&ad7607_bus_info }, - { "ad7608", (kernel_ulong_t)&ad7608_bus_info }, - { "ad7609", (kernel_ulong_t)&ad7609_bus_info }, - { "ad7616", (kernel_ulong_t)&ad7616_bus_info }, + { .name = "ad7605-4", .driver_data = (kernel_ulong_t)&ad7605_4_bus_info }, + { .name = "ad7606-4", .driver_data = (kernel_ulong_t)&ad7606_4_bus_info }, + { .name = "ad7606-6", .driver_data = (kernel_ulong_t)&ad7606_6_bus_info }, + { .name = "ad7606-8", .driver_data = (kernel_ulong_t)&ad7606_8_bus_info }, + { .name = "ad7606b", .driver_data = (kernel_ulong_t)&ad7606b_bus_info }, + { .name = "ad7606c-16", .driver_data = (kernel_ulong_t)&ad7606c_16_bus_info }, + { .name = "ad7606c-18", .driver_data = (kernel_ulong_t)&ad7606c_18_bus_info }, + { .name = "ad7607", .driver_data = (kernel_ulong_t)&ad7607_bus_info }, + { .name = "ad7608", .driver_data = (kernel_ulong_t)&ad7608_bus_info }, + { .name = "ad7609", .driver_data = (kernel_ulong_t)&ad7609_bus_info }, + { .name = "ad7616", .driver_data = (kernel_ulong_t)&ad7616_bus_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7606_id_table); diff --git a/drivers/iio/adc/ad7766.c b/drivers/iio/adc/ad7766.c index 9e4a66477d2d..92957196de59 100644 --- a/drivers/iio/adc/ad7766.c +++ b/drivers/iio/adc/ad7766.c @@ -285,12 +285,12 @@ static int ad7766_probe(struct spi_device *spi) } static const struct spi_device_id ad7766_id[] = { - { "ad7766", ID_AD7766 }, - { "ad7766-1", ID_AD7766_1 }, - { "ad7766-2", ID_AD7766_2 }, - { "ad7767", ID_AD7766 }, - { "ad7767-1", ID_AD7766_1 }, - { "ad7767-2", ID_AD7766_2 }, + { .name = "ad7766", .driver_data = ID_AD7766 }, + { .name = "ad7766-1", .driver_data = ID_AD7766_1 }, + { .name = "ad7766-2", .driver_data = ID_AD7766_2 }, + { .name = "ad7767", .driver_data = ID_AD7766 }, + { .name = "ad7767-1", .driver_data = ID_AD7766_1 }, + { .name = "ad7767-2", .driver_data = ID_AD7766_2 }, { } }; MODULE_DEVICE_TABLE(spi, ad7766_id); diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 598936e47fd2..e9060c1bbe6f 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -1918,10 +1918,10 @@ static int ad7768_probe(struct spi_device *spi) } static const struct spi_device_id ad7768_id_table[] = { - { "ad7768-1", (kernel_ulong_t)&ad7768_chip_info }, - { "adaq7767-1", (kernel_ulong_t)&adaq7767_chip_info }, - { "adaq7768-1", (kernel_ulong_t)&adaq7768_chip_info }, - { "adaq7769-1", (kernel_ulong_t)&adaq7769_chip_info }, + { .name = "ad7768-1", .driver_data = (kernel_ulong_t)&ad7768_chip_info }, + { .name = "adaq7767-1", .driver_data = (kernel_ulong_t)&adaq7767_chip_info }, + { .name = "adaq7768-1", .driver_data = (kernel_ulong_t)&adaq7768_chip_info }, + { .name = "adaq7769-1", .driver_data = (kernel_ulong_t)&adaq7769_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7768_id_table); diff --git a/drivers/iio/adc/ad7779.c b/drivers/iio/adc/ad7779.c index 003e23d6e242..79fb38d0f400 100644 --- a/drivers/iio/adc/ad7779.c +++ b/drivers/iio/adc/ad7779.c @@ -142,7 +142,6 @@ struct ad7779_state { const struct ad7779_chip_info *chip_info; struct clk *mclk; struct iio_trigger *trig; - struct completion completion; unsigned int sampling_freq; enum ad7779_filter filter_enabled; struct iio_backend *back; @@ -842,8 +841,7 @@ static int ad7779_setup_without_backend(struct ad7779_state *st, struct iio_dev IRQF_NO_THREAD | IRQF_NO_AUTOEN, indio_dev->name, st->trig); if (ret) - return dev_err_probe(dev, ret, "request IRQ %d failed\n", - st->spi->irq); + return ret; ret = devm_iio_trigger_register(dev, st->trig); if (ret) @@ -851,8 +849,6 @@ static int ad7779_setup_without_backend(struct ad7779_state *st, struct iio_dev indio_dev->trig = iio_trigger_get(st->trig); - init_completion(&st->completion); - ret = devm_iio_triggered_buffer_setup(dev, indio_dev, &iio_pollfunc_store_time, &ad7779_trigger_handler, diff --git a/drivers/iio/adc/ad7780.c b/drivers/iio/adc/ad7780.c index 26382b1f8c9e..1cfad70320fe 100644 --- a/drivers/iio/adc/ad7780.c +++ b/drivers/iio/adc/ad7780.c @@ -347,10 +347,10 @@ static int ad7780_probe(struct spi_device *spi) } static const struct spi_device_id ad7780_id[] = { - { "ad7170", ID_AD7170 }, - { "ad7171", ID_AD7171 }, - { "ad7780", ID_AD7780 }, - { "ad7781", ID_AD7781 }, + { .name = "ad7170", .driver_data = ID_AD7170 }, + { .name = "ad7171", .driver_data = ID_AD7171 }, + { .name = "ad7780", .driver_data = ID_AD7780 }, + { .name = "ad7781", .driver_data = ID_AD7781 }, { } }; MODULE_DEVICE_TABLE(spi, ad7780_id); diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c index bcdc19e799aa..c2688307bbba 100644 --- a/drivers/iio/adc/ad7791.c +++ b/drivers/iio/adc/ad7791.c @@ -458,11 +458,11 @@ static int ad7791_probe(struct spi_device *spi) } static const struct spi_device_id ad7791_spi_ids[] = { - { "ad7787", AD7787 }, - { "ad7788", AD7788 }, - { "ad7789", AD7789 }, - { "ad7790", AD7790 }, - { "ad7791", AD7791 }, + { .name = "ad7787", .driver_data = AD7787 }, + { .name = "ad7788", .driver_data = AD7788 }, + { .name = "ad7789", .driver_data = AD7789 }, + { .name = "ad7790", .driver_data = AD7790 }, + { .name = "ad7791", .driver_data = AD7791 }, { } }; MODULE_DEVICE_TABLE(spi, ad7791_spi_ids); diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c index ea1c192e2142..b0f44c144f20 100644 --- a/drivers/iio/adc/ad7793.c +++ b/drivers/iio/adc/ad7793.c @@ -829,15 +829,15 @@ static int ad7793_probe(struct spi_device *spi) } static const struct spi_device_id ad7793_id[] = { - { "ad7785", ID_AD7785 }, - { "ad7792", ID_AD7792 }, - { "ad7793", ID_AD7793 }, - { "ad7794", ID_AD7794 }, - { "ad7795", ID_AD7795 }, - { "ad7796", ID_AD7796 }, - { "ad7797", ID_AD7797 }, - { "ad7798", ID_AD7798 }, - { "ad7799", ID_AD7799 }, + { .name = "ad7785", .driver_data = ID_AD7785 }, + { .name = "ad7792", .driver_data = ID_AD7792 }, + { .name = "ad7793", .driver_data = ID_AD7793 }, + { .name = "ad7794", .driver_data = ID_AD7794 }, + { .name = "ad7795", .driver_data = ID_AD7795 }, + { .name = "ad7796", .driver_data = ID_AD7796 }, + { .name = "ad7797", .driver_data = ID_AD7797 }, + { .name = "ad7798", .driver_data = ID_AD7798 }, + { .name = "ad7799", .driver_data = ID_AD7799 }, { } }; MODULE_DEVICE_TABLE(spi, ad7793_id); diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c index 068171d54596..62aaedbce748 100644 --- a/drivers/iio/adc/ad7887.c +++ b/drivers/iio/adc/ad7887.c @@ -328,7 +328,7 @@ static int ad7887_probe(struct spi_device *spi) } static const struct spi_device_id ad7887_id[] = { - { "ad7887", ID_AD7887 }, + { .name = "ad7887", .driver_data = ID_AD7887 }, { } }; MODULE_DEVICE_TABLE(spi, ad7887_id); diff --git a/drivers/iio/adc/ad7923.c b/drivers/iio/adc/ad7923.c index acc87d486aa4..44e014da9722 100644 --- a/drivers/iio/adc/ad7923.c +++ b/drivers/iio/adc/ad7923.c @@ -360,13 +360,13 @@ static int ad7923_probe(struct spi_device *spi) } static const struct spi_device_id ad7923_id[] = { - { "ad7904", AD7904 }, - { "ad7914", AD7914 }, - { "ad7923", AD7924 }, - { "ad7924", AD7924 }, - { "ad7908", AD7908 }, - { "ad7918", AD7918 }, - { "ad7928", AD7928 }, + { .name = "ad7904", .driver_data = AD7904 }, + { .name = "ad7914", .driver_data = AD7914 }, + { .name = "ad7923", .driver_data = AD7924 }, + { .name = "ad7924", .driver_data = AD7924 }, + { .name = "ad7908", .driver_data = AD7908 }, + { .name = "ad7918", .driver_data = AD7918 }, + { .name = "ad7928", .driver_data = AD7928 }, { } }; MODULE_DEVICE_TABLE(spi, ad7923_id); diff --git a/drivers/iio/adc/ad7944.c b/drivers/iio/adc/ad7944.c index 7722cf9e8214..12656d3cdcec 100644 --- a/drivers/iio/adc/ad7944.c +++ b/drivers/iio/adc/ad7944.c @@ -865,9 +865,9 @@ static const struct of_device_id ad7944_of_match[] = { MODULE_DEVICE_TABLE(of, ad7944_of_match); static const struct spi_device_id ad7944_spi_id[] = { - { "ad7944", (kernel_ulong_t)&ad7944_chip_info }, - { "ad7985", (kernel_ulong_t)&ad7985_chip_info }, - { "ad7986", (kernel_ulong_t)&ad7986_chip_info }, + { .name = "ad7944", .driver_data = (kernel_ulong_t)&ad7944_chip_info }, + { .name = "ad7985", .driver_data = (kernel_ulong_t)&ad7985_chip_info }, + { .name = "ad7986", .driver_data = (kernel_ulong_t)&ad7986_chip_info }, { } }; diff --git a/drivers/iio/adc/ad7949.c b/drivers/iio/adc/ad7949.c index ebc629bcfd4d..93a57a3d59b8 100644 --- a/drivers/iio/adc/ad7949.c +++ b/drivers/iio/adc/ad7949.c @@ -410,9 +410,9 @@ static const struct of_device_id ad7949_spi_of_id[] = { MODULE_DEVICE_TABLE(of, ad7949_spi_of_id); static const struct spi_device_id ad7949_spi_id[] = { - { "ad7949", ID_AD7949 }, - { "ad7682", ID_AD7682 }, - { "ad7689", ID_AD7689 }, + { .name = "ad7949", .driver_data = ID_AD7949 }, + { .name = "ad7682", .driver_data = ID_AD7682 }, + { .name = "ad7689", .driver_data = ID_AD7689 }, { } }; MODULE_DEVICE_TABLE(spi, ad7949_spi_id); diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c index 0c377f9a7f25..34b7b1256f0d 100644 --- a/drivers/iio/adc/ad9467.c +++ b/drivers/iio/adc/ad9467.c @@ -1406,13 +1406,13 @@ static const struct of_device_id ad9467_of_match[] = { MODULE_DEVICE_TABLE(of, ad9467_of_match); static const struct spi_device_id ad9467_ids[] = { - { "ad9211", (kernel_ulong_t)&ad9211_chip_tbl }, - { "ad9265", (kernel_ulong_t)&ad9265_chip_tbl }, - { "ad9434", (kernel_ulong_t)&ad9434_chip_tbl }, - { "ad9467", (kernel_ulong_t)&ad9467_chip_tbl }, - { "ad9643", (kernel_ulong_t)&ad9643_chip_tbl }, - { "ad9649", (kernel_ulong_t)&ad9649_chip_tbl, }, - { "ad9652", (kernel_ulong_t)&ad9652_chip_tbl, }, + { .name = "ad9211", .driver_data = (kernel_ulong_t)&ad9211_chip_tbl }, + { .name = "ad9265", .driver_data = (kernel_ulong_t)&ad9265_chip_tbl }, + { .name = "ad9434", .driver_data = (kernel_ulong_t)&ad9434_chip_tbl }, + { .name = "ad9467", .driver_data = (kernel_ulong_t)&ad9467_chip_tbl }, + { .name = "ad9643", .driver_data = (kernel_ulong_t)&ad9643_chip_tbl }, + { .name = "ad9649", .driver_data = (kernel_ulong_t)&ad9649_chip_tbl }, + { .name = "ad9652", .driver_data = (kernel_ulong_t)&ad9652_chip_tbl }, { } }; MODULE_DEVICE_TABLE(spi, ad9467_ids); diff --git a/drivers/iio/adc/ade9000.c b/drivers/iio/adc/ade9000.c index c0a9babfa519..c6c3ea953fea 100644 --- a/drivers/iio/adc/ade9000.c +++ b/drivers/iio/adc/ade9000.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * ADE9000 driver * * Copyright 2025 Analog Devices Inc. @@ -1768,7 +1768,7 @@ static int ade9000_probe(struct spi_device *spi) }; static const struct spi_device_id ade9000_id[] = { - { "ade9000", 0 }, + { .name = "ade9000" }, { } }; MODULE_DEVICE_TABLE(spi, ade9000_id); diff --git a/drivers/iio/adc/envelope-detector.c b/drivers/iio/adc/envelope-detector.c index 30672e584c10..aace7e103770 100644 --- a/drivers/iio/adc/envelope-detector.c +++ b/drivers/iio/adc/envelope-detector.c @@ -405,3 +405,4 @@ module_platform_driver(envelope_detector_driver); MODULE_DESCRIPTION("Envelope detector using a DAC and a comparator"); MODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c index b01ba86c2945..9fa63de4b9ca 100644 --- a/drivers/iio/adc/hi8435.c +++ b/drivers/iio/adc/hi8435.c @@ -526,7 +526,7 @@ static const struct of_device_id hi8435_dt_ids[] = { MODULE_DEVICE_TABLE(of, hi8435_dt_ids); static const struct spi_device_id hi8435_id[] = { - { "hi8435", 0 }, + { .name = "hi8435" }, { } }; MODULE_DEVICE_TABLE(spi, hi8435_id); diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c index 17e9badf1d1c..00adafa7cbd7 100644 --- a/drivers/iio/adc/hx711.c +++ b/drivers/iio/adc/hx711.c @@ -4,6 +4,8 @@ * * Copyright (c) 2016 Andreas Klinger <ak@it-klinger.de> */ +#include <linux/array_size.h> +#include <linux/dev_printk.h> #include <linux/err.h> #include <linux/kernel.h> #include <linux/module.h> @@ -20,6 +22,8 @@ #include <linux/gpio/consumer.h> #include <linux/regulator/consumer.h> +#define HX711_DATA_BITS 24 + /* gain to pulse and scale conversion */ #define HX711_GAIN_MAX 3 #define HX711_RESET_GAIN 128 @@ -73,6 +77,20 @@ static int hx711_get_scale_to_gain(const int *gain_scale, int scale) return -EINVAL; } +/** + * struct hx711_chip_info - per-variant static configuration + * @name: IIO device name + * @channels: channel specification array + * @num_channels: number of entries in @channels + * @iio_info: IIO info ops for this variant + */ +struct hx711_chip_info { + const char *name; + const struct iio_chan_spec *channels __counted_by_ptr(num_channels); + unsigned int num_channels; + const struct iio_info *iio_info; +}; + struct hx711_data { struct device *dev; struct gpio_desc *gpiod_pd_sck; @@ -80,6 +98,7 @@ struct hx711_data { int gain_set; /* gain set on device */ int gain_chan_a; /* gain for channel A */ int gain_scale[HX711_GAIN_MAX]; + const struct hx711_chip_info *chip_info; struct mutex lock; /* * triggered buffer @@ -137,17 +156,18 @@ static int hx711_cycle(struct hx711_data *hx711_data) return gpiod_get_value(hx711_data->gpiod_dout); } -static int hx711_read(struct hx711_data *hx711_data) +static int hx711_read(struct hx711_data *hx711_data, int trailing_pulses) { - int i, ret; int value = 0; - int val = gpiod_get_value(hx711_data->gpiod_dout); + int val; + int ret; /* we double check if it's really down */ + val = gpiod_get_value(hx711_data->gpiod_dout); if (val) return -EIO; - for (i = 0; i < 24; i++) { + for (int i = 0; i < HX711_DATA_BITS; i++) { value <<= 1; ret = hx711_cycle(hx711_data); if (ret) @@ -156,7 +176,7 @@ static int hx711_read(struct hx711_data *hx711_data) value ^= 0x800000; - for (i = 0; i < hx711_get_gain_to_pulse(hx711_data->gain_set); i++) + for (int i = 0; i < trailing_pulses; i++) hx711_cycle(hx711_data); return value; @@ -186,8 +206,9 @@ static int hx711_wait_for_ready(struct hx711_data *hx711_data) static int hx711_reset(struct hx711_data *hx711_data) { - int val = hx711_wait_for_ready(hx711_data); + int val; + val = hx711_wait_for_ready(hx711_data); if (val) { /* * an examination with the oszilloscope indicated @@ -219,7 +240,8 @@ static int hx711_set_gain_for_channel(struct hx711_data *hx711_data, int chan) if (hx711_data->gain_set == 32) { hx711_data->gain_set = hx711_data->gain_chan_a; - ret = hx711_read(hx711_data); + ret = hx711_read(hx711_data, + hx711_get_gain_to_pulse(hx711_data->gain_set)); if (ret < 0) return ret; @@ -231,7 +253,8 @@ static int hx711_set_gain_for_channel(struct hx711_data *hx711_data, int chan) if (hx711_data->gain_set != 32) { hx711_data->gain_set = 32; - ret = hx711_read(hx711_data); + ret = hx711_read(hx711_data, + hx711_get_gain_to_pulse(hx711_data->gain_set)); if (ret < 0) return ret; @@ -244,10 +267,26 @@ static int hx711_set_gain_for_channel(struct hx711_data *hx711_data, int chan) return 0; } -static int hx711_reset_read(struct hx711_data *hx711_data, int chan) +static int hx711_set_hx711_channel(struct hx711_data *hx711_data, + const struct iio_chan_spec *chan, + int *trailing_pulses) { int ret; - int val; + + ret = hx711_set_gain_for_channel(hx711_data, chan->channel); + if (ret < 0) + return ret; + + *trailing_pulses = hx711_get_gain_to_pulse(hx711_data->gain_set); + + return 0; +} + +static int hx711_reset_read(struct hx711_data *hx711_data, + const struct iio_chan_spec *chan) +{ + int trailing_pulses; + int ret; /* * hx711_reset() must be called from here @@ -258,13 +297,11 @@ static int hx711_reset_read(struct hx711_data *hx711_data, int chan) return -EIO; } - ret = hx711_set_gain_for_channel(hx711_data, chan); + ret = hx711_set_hx711_channel(hx711_data, chan, &trailing_pulses); if (ret < 0) return ret; - val = hx711_read(hx711_data); - - return val; + return hx711_read(hx711_data, trailing_pulses); } static int hx711_read_raw(struct iio_dev *indio_dev, @@ -277,7 +314,7 @@ static int hx711_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_RAW: mutex_lock(&hx711_data->lock); - *val = hx711_reset_read(hx711_data, chan->channel); + *val = hx711_reset_read(hx711_data, chan); mutex_unlock(&hx711_data->lock); @@ -331,7 +368,8 @@ static int hx711_write_raw(struct iio_dev *indio_dev, if (gain != 32) hx711_data->gain_chan_a = gain; - ret = hx711_read(hx711_data); + ret = hx711_read(hx711_data, + hx711_get_gain_to_pulse(hx711_data->gain_set)); if (ret < 0) { mutex_unlock(&hx711_data->lock); return ret; @@ -366,8 +404,8 @@ static irqreturn_t hx711_trigger(int irq, void *p) memset(&hx711_data->buffer, 0, sizeof(hx711_data->buffer)); iio_for_each_active_channel(indio_dev, i) { - hx711_data->buffer.channel[j] = hx711_reset_read(hx711_data, - indio_dev->channels[i].channel); + hx711_data->buffer.channel[j] = + hx711_reset_read(hx711_data, &indio_dev->channels[i]); j++; } @@ -455,8 +493,16 @@ static const struct iio_chan_spec hx711_chan_spec[] = { IIO_CHAN_SOFT_TIMESTAMP(2), }; +static const struct hx711_chip_info hx711_chip = { + .name = "hx711", + .channels = hx711_chan_spec, + .iio_info = &hx711_iio_info, + .num_channels = ARRAY_SIZE(hx711_chan_spec), +}; + static int hx711_probe(struct platform_device *pdev) { + const struct hx711_chip_info *chip_info; struct device *dev = &pdev->dev; struct hx711_data *hx711_data; struct iio_dev *indio_dev; @@ -472,6 +518,12 @@ static int hx711_probe(struct platform_device *pdev) mutex_init(&hx711_data->lock); + chip_info = device_get_match_data(dev); + if (!chip_info) + return dev_err_probe(dev, -ENODEV, "missing driver data\n"); + + hx711_data->chip_info = chip_info; + /* * PD_SCK stands for power down and serial clock input of HX711 * in the driver it is an output @@ -533,11 +585,11 @@ static int hx711_probe(struct platform_device *pdev) hx711_data->data_ready_delay_ns = 1000000000 / hx711_data->clock_frequency; - indio_dev->name = "hx711"; - indio_dev->info = &hx711_iio_info; + indio_dev->name = chip_info->name; + indio_dev->info = chip_info->iio_info; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = hx711_chan_spec; - indio_dev->num_channels = ARRAY_SIZE(hx711_chan_spec); + indio_dev->channels = chip_info->channels; + indio_dev->num_channels = chip_info->num_channels; ret = devm_iio_triggered_buffer_setup(dev, indio_dev, iio_pollfunc_store_time, @@ -554,7 +606,7 @@ static int hx711_probe(struct platform_device *pdev) } static const struct of_device_id of_hx711_match[] = { - { .compatible = "avia,hx711", }, + { .compatible = "avia,hx711", .data = &hx711_chip }, { } }; diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c index 8b2c7b2a9c8f..fb6f12316724 100644 --- a/drivers/iio/adc/max1027.c +++ b/drivers/iio/adc/max1027.c @@ -72,12 +72,12 @@ enum max1027_id { }; static const struct spi_device_id max1027_id[] = { - { "max1027", max1027 }, - { "max1029", max1029 }, - { "max1031", max1031 }, - { "max1227", max1227 }, - { "max1229", max1229 }, - { "max1231", max1231 }, + { .name = "max1027", .driver_data = max1027 }, + { .name = "max1029", .driver_data = max1029 }, + { .name = "max1031", .driver_data = max1031 }, + { .name = "max1227", .driver_data = max1227 }, + { .name = "max1229", .driver_data = max1229 }, + { .name = "max1231", .driver_data = max1231 }, { } }; MODULE_DEVICE_TABLE(spi, max1027_id); diff --git a/drivers/iio/adc/max1118.c b/drivers/iio/adc/max1118.c index d394e03cc4e8..75e51ce3077e 100644 --- a/drivers/iio/adc/max1118.c +++ b/drivers/iio/adc/max1118.c @@ -256,9 +256,9 @@ static int max1118_probe(struct spi_device *spi) } static const struct spi_device_id max1118_id[] = { - { "max1117", max1117 }, - { "max1118", max1118 }, - { "max1119", max1119 }, + { .name = "max1117", .driver_data = max1117 }, + { .name = "max1118", .driver_data = max1118 }, + { .name = "max1119", .driver_data = max1119 }, { } }; MODULE_DEVICE_TABLE(spi, max1118_id); diff --git a/drivers/iio/adc/max11205.c b/drivers/iio/adc/max11205.c index 6c803df220b6..63b6561dcf47 100644 --- a/drivers/iio/adc/max11205.c +++ b/drivers/iio/adc/max11205.c @@ -145,8 +145,8 @@ static int max11205_probe(struct spi_device *spi) } static const struct spi_device_id max11205_spi_ids[] = { - { "max11205a", (kernel_ulong_t)&max11205_chip_info[TYPE_MAX11205A] }, - { "max11205b", (kernel_ulong_t)&max11205_chip_info[TYPE_MAX11205B] }, + { .name = "max11205a", .driver_data = (kernel_ulong_t)&max11205_chip_info[TYPE_MAX11205A] }, + { .name = "max11205b", .driver_data = (kernel_ulong_t)&max11205_chip_info[TYPE_MAX11205B] }, { } }; MODULE_DEVICE_TABLE(spi, max11205_spi_ids); diff --git a/drivers/iio/adc/max11410.c b/drivers/iio/adc/max11410.c index dc1b96356592..23ae684cf08b 100644 --- a/drivers/iio/adc/max11410.c +++ b/drivers/iio/adc/max11410.c @@ -1025,7 +1025,7 @@ static const struct of_device_id max11410_spi_of_id[] = { MODULE_DEVICE_TABLE(of, max11410_spi_of_id); static const struct spi_device_id max11410_id[] = { - { "max11410" }, + { .name = "max11410" }, { } }; MODULE_DEVICE_TABLE(spi, max11410_id); diff --git a/drivers/iio/adc/max1241.c b/drivers/iio/adc/max1241.c index d62c1a011659..b3cecbf9a89e 100644 --- a/drivers/iio/adc/max1241.c +++ b/drivers/iio/adc/max1241.c @@ -15,10 +15,6 @@ #define MAX1241_VAL_MASK GENMASK(11, 0) #define MAX1241_SHUTDOWN_DELAY_USEC 4 -enum max1241_id { - max1241, -}; - struct max1241 { struct spi_device *spi; struct mutex lock; @@ -166,7 +162,7 @@ static int max1241_probe(struct spi_device *spi) else dev_dbg(dev, "no shutdown pin passed, low-power mode disabled"); - indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->name = "max1241"; indio_dev->info = &max1241_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = max1241_channels; @@ -176,9 +172,10 @@ static int max1241_probe(struct spi_device *spi) } static const struct spi_device_id max1241_id[] = { - { "max1241", max1241 }, + { .name = "max1241" }, { } }; +MODULE_DEVICE_TABLE(spi, max1241_id); static const struct of_device_id max1241_dt_ids[] = { { .compatible = "maxim,max1241" }, diff --git a/drivers/iio/adc/max14001.c b/drivers/iio/adc/max14001.c index 09017163b191..58adeac62dde 100644 --- a/drivers/iio/adc/max14001.c +++ b/drivers/iio/adc/max14001.c @@ -362,8 +362,8 @@ static struct max14001_chip_info max14002_chip_info = { }; static const struct spi_device_id max14001_id_table[] = { - { "max14001", (kernel_ulong_t)&max14001_chip_info }, - { "max14002", (kernel_ulong_t)&max14002_chip_info }, + { .name = "max14001", .driver_data = (kernel_ulong_t)&max14001_chip_info }, + { .name = "max14002", .driver_data = (kernel_ulong_t)&max14002_chip_info }, { } }; diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c index 686c519aa3d2..18cb957e7095 100644 --- a/drivers/iio/adc/mcp320x.c +++ b/drivers/iio/adc/mcp320x.c @@ -476,19 +476,19 @@ static const struct of_device_id mcp320x_dt_ids[] = { MODULE_DEVICE_TABLE(of, mcp320x_dt_ids); static const struct spi_device_id mcp320x_id[] = { - { "mcp3001", mcp3001 }, - { "mcp3002", mcp3002 }, - { "mcp3004", mcp3004 }, - { "mcp3008", mcp3008 }, - { "mcp3201", mcp3201 }, - { "mcp3202", mcp3202 }, - { "mcp3204", mcp3204 }, - { "mcp3208", mcp3208 }, - { "mcp3301", mcp3301 }, - { "mcp3550-50", mcp3550_50 }, - { "mcp3550-60", mcp3550_60 }, - { "mcp3551", mcp3551 }, - { "mcp3553", mcp3553 }, + { .name = "mcp3001", .driver_data = mcp3001 }, + { .name = "mcp3002", .driver_data = mcp3002 }, + { .name = "mcp3004", .driver_data = mcp3004 }, + { .name = "mcp3008", .driver_data = mcp3008 }, + { .name = "mcp3201", .driver_data = mcp3201 }, + { .name = "mcp3202", .driver_data = mcp3202 }, + { .name = "mcp3204", .driver_data = mcp3204 }, + { .name = "mcp3208", .driver_data = mcp3208 }, + { .name = "mcp3301", .driver_data = mcp3301 }, + { .name = "mcp3550-50", .driver_data = mcp3550_50 }, + { .name = "mcp3550-60", .driver_data = mcp3550_60 }, + { .name = "mcp3551", .driver_data = mcp3551 }, + { .name = "mcp3553", .driver_data = mcp3553 }, { } }; MODULE_DEVICE_TABLE(spi, mcp320x_id); diff --git a/drivers/iio/adc/mcp3564.c b/drivers/iio/adc/mcp3564.c index 36675563829e..259ac4ebdedf 100644 --- a/drivers/iio/adc/mcp3564.c +++ b/drivers/iio/adc/mcp3564.c @@ -1451,18 +1451,18 @@ static const struct of_device_id mcp3564_dt_ids[] = { MODULE_DEVICE_TABLE(of, mcp3564_dt_ids); static const struct spi_device_id mcp3564_id[] = { - { "mcp3461", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3461] }, - { "mcp3462", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3462] }, - { "mcp3464", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3464] }, - { "mcp3561", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3561] }, - { "mcp3562", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3562] }, - { "mcp3564", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3564] }, - { "mcp3461r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3461r] }, - { "mcp3462r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3462r] }, - { "mcp3464r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3464r] }, - { "mcp3561r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3561r] }, - { "mcp3562r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3562r] }, - { "mcp3564r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3564r] }, + { .name = "mcp3461", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3461] }, + { .name = "mcp3462", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3462] }, + { .name = "mcp3464", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3464] }, + { .name = "mcp3561", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3561] }, + { .name = "mcp3562", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3562] }, + { .name = "mcp3564", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3564] }, + { .name = "mcp3461r", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3461r] }, + { .name = "mcp3462r", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3462r] }, + { .name = "mcp3464r", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3464r] }, + { .name = "mcp3561r", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3561r] }, + { .name = "mcp3562r", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3562r] }, + { .name = "mcp3564r", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3564r] }, { } }; MODULE_DEVICE_TABLE(spi, mcp3564_id); diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c index 5bf74b49bdb5..797424f59f74 100644 --- a/drivers/iio/adc/mcp3911.c +++ b/drivers/iio/adc/mcp3911.c @@ -927,13 +927,13 @@ static const struct of_device_id mcp3911_dt_ids[] = { MODULE_DEVICE_TABLE(of, mcp3911_dt_ids); static const struct spi_device_id mcp3911_id[] = { - { "mcp3910", (kernel_ulong_t)&mcp3911_chip_info[MCP3910] }, - { "mcp3911", (kernel_ulong_t)&mcp3911_chip_info[MCP3911] }, - { "mcp3912", (kernel_ulong_t)&mcp3911_chip_info[MCP3912] }, - { "mcp3913", (kernel_ulong_t)&mcp3911_chip_info[MCP3913] }, - { "mcp3914", (kernel_ulong_t)&mcp3911_chip_info[MCP3914] }, - { "mcp3918", (kernel_ulong_t)&mcp3911_chip_info[MCP3918] }, - { "mcp3919", (kernel_ulong_t)&mcp3911_chip_info[MCP3919] }, + { .name = "mcp3910", .driver_data = (kernel_ulong_t)&mcp3911_chip_info[MCP3910] }, + { .name = "mcp3911", .driver_data = (kernel_ulong_t)&mcp3911_chip_info[MCP3911] }, + { .name = "mcp3912", .driver_data = (kernel_ulong_t)&mcp3911_chip_info[MCP3912] }, + { .name = "mcp3913", .driver_data = (kernel_ulong_t)&mcp3911_chip_info[MCP3913] }, + { .name = "mcp3914", .driver_data = (kernel_ulong_t)&mcp3911_chip_info[MCP3914] }, + { .name = "mcp3918", .driver_data = (kernel_ulong_t)&mcp3911_chip_info[MCP3918] }, + { .name = "mcp3919", .driver_data = (kernel_ulong_t)&mcp3911_chip_info[MCP3919] }, { } }; MODULE_DEVICE_TABLE(spi, mcp3911_id); diff --git a/drivers/iio/adc/mt6323-auxadc.c b/drivers/iio/adc/mt6323-auxadc.c new file mode 100644 index 000000000000..4f73ac42abb7 --- /dev/null +++ b/drivers/iio/adc/mt6323-auxadc.c @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2026 Roman Vivchar <rva333@protonmail.com> + * + * Based on drivers/iio/adc/mt6359-auxadc.c + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/delay.h> +#include <linux/iio/iio.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/stringify.h> +#include <linux/time.h> +#include <linux/types.h> + +#include <linux/mfd/mt6323/registers.h> + +#include <dt-bindings/iio/adc/mediatek,mt6323-auxadc.h> + +#define AUXADC_STRUP_CON10_RSTB_SEL BIT(7) +#define AUXADC_STRUP_CON10_RSTB_SW BIT(5) + +#define AUXADC_TOP_CKPDN2_CTL_CK BIT(5) + +#define AUXADC_TRIM_CH2_MASK GENMASK(11, 10) +#define AUXADC_TRIM_CH4_MASK GENMASK(9, 8) +#define AUXADC_TRIM_CH5_MASK GENMASK(5, 4) +#define AUXADC_TRIM_CH6_MASK GENMASK(3, 2) + +#define AUXADC_CON27_VREF18_ENB_MD BIT(15) +#define AUXADC_CON27_MD_STATUS BIT(0) + +#define AUXADC_CON19_GPS_STATUS BIT(1) + +#define AUXADC_CON26_VREF18_SELB BIT(1) +#define AUXADC_CON26_DECI_GDLY_SEL BIT(0) + +#define AUXADC_CON11_VBUF_EN BIT(4) + +#define AUXADC_CON19_DECI_GDLY_MASK GENMASK(15, 14) +#define AUXADC_ADC19_BUSY_MASK GENMASK(15, 1) +#define AUXADC_READY_MASK BIT(15) +#define AUXADC_DATA_MASK GENMASK(14, 0) + +#define AUXADC_CON9_OSR_MASK GENMASK(12, 10) +#define AUXADC_DEFAULT_OSR 3 + +#define MTK_PMIC_IIO_CHAN(_name, _chan, _addr) \ +{ \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = _chan, \ + .address = _addr, \ + .datasheet_name = __stringify(_name), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ +} + +/* + * AUXADC reports everything in mV, including temperature and + * current channels. Channel macros are mapped such that their + * ID matches their respective hardware bit position in CON22. + */ +static const struct iio_chan_spec mt6323_auxadc_channels[] = { + MTK_PMIC_IIO_CHAN(baton2, MT6323_AUXADC_BATON2, MT6323_AUXADC_ADC6), + MTK_PMIC_IIO_CHAN(ch6, MT6323_AUXADC_CH6, MT6323_AUXADC_ADC11), + MTK_PMIC_IIO_CHAN(bat_temp, MT6323_AUXADC_BAT_TEMP, MT6323_AUXADC_ADC5), + MTK_PMIC_IIO_CHAN(chip_temp, MT6323_AUXADC_CHIP_TEMP, MT6323_AUXADC_ADC4), + MTK_PMIC_IIO_CHAN(vcdt, MT6323_AUXADC_VCDT, MT6323_AUXADC_ADC2), + MTK_PMIC_IIO_CHAN(baton1, MT6323_AUXADC_BATON1, MT6323_AUXADC_ADC3), + MTK_PMIC_IIO_CHAN(isense, MT6323_AUXADC_ISENSE, MT6323_AUXADC_ADC1), + MTK_PMIC_IIO_CHAN(batsns, MT6323_AUXADC_BATSNS, MT6323_AUXADC_ADC0), + MTK_PMIC_IIO_CHAN(accdet, MT6323_AUXADC_ACCDET, MT6323_AUXADC_ADC7), +}; + +/* + * The MediaTek MT6323 (as well as a lot of other PMICs) has the following hierarchy: + * PMIC AUXADC <- PMIC MFD <- SoC PWRAP (wrapper for PWRAP FSM) + * + * Therefore, PWRAP regmap should be obtained using dev->parent->parent. + */ +struct mt6323_auxadc { + struct regmap *regmap; + /* AUXADC doesn't support reading multiple channels simultaneously. */ + struct mutex lock; +}; + +static int mt6323_auxadc_prepare_channel(struct mt6323_auxadc *auxadc) +{ + struct regmap *map = auxadc->regmap; + u32 val; + int ret; + + ret = regmap_read(map, MT6323_AUXADC_CON19, &val); + if (ret) + return ret; + + /* The ADC is idle. */ + if (!(val & AUXADC_CON19_DECI_GDLY_MASK)) + return 0; + + ret = regmap_read_poll_timeout(map, MT6323_AUXADC_ADC19, + val, !(val & AUXADC_ADC19_BUSY_MASK), + 10, 500); + if (ret) + return ret; + + return regmap_clear_bits(map, MT6323_AUXADC_CON19, + AUXADC_CON19_DECI_GDLY_MASK); +} + +static int mt6323_auxadc_request(struct mt6323_auxadc *auxadc, + unsigned long channel) +{ + struct regmap *map = auxadc->regmap; + int ret; + + ret = regmap_set_bits(map, MT6323_AUXADC_CON11, AUXADC_CON11_VBUF_EN); + if (ret) + return ret; + + return regmap_set_bits(map, MT6323_AUXADC_CON22, BIT(channel)); +} + +static int mt6323_auxadc_release(struct mt6323_auxadc *auxadc, + unsigned long channel) +{ + struct regmap *map = auxadc->regmap; + int ret; + + ret = regmap_clear_bits(map, MT6323_AUXADC_CON22, BIT(channel)); + if (ret) + return ret; + + return regmap_clear_bits(map, MT6323_AUXADC_CON11, AUXADC_CON11_VBUF_EN); +} + +static int mt6323_auxadc_read(struct mt6323_auxadc *auxadc, + const struct iio_chan_spec *chan, int *out) +{ + struct regmap *map = auxadc->regmap; + u32 val; + int ret; + + ret = regmap_read_poll_timeout(map, chan->address, + val, (val & AUXADC_READY_MASK), + 1 * USEC_PER_MSEC, 100 * USEC_PER_MSEC); + if (ret) + return ret; + + *out = FIELD_GET(AUXADC_DATA_MASK, val); + + return 0; +} + +static int mt6323_auxadc_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct mt6323_auxadc *auxadc = iio_priv(indio_dev); + int ret, mult; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + if (chan->channel == MT6323_AUXADC_ISENSE || + chan->channel == MT6323_AUXADC_BATSNS) + mult = 4; + else + mult = 1; + + /* 1800mV full range with 15-bit resolution. */ + *val = mult * 1800; + *val2 = 15; + + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_RAW: { + guard(mutex)(&auxadc->lock); + + ret = mt6323_auxadc_prepare_channel(auxadc); + if (ret) + return ret; + + ret = mt6323_auxadc_request(auxadc, chan->channel); + if (ret) + return ret; + + /* Hardware limitation: the AUXADC needs a delay to become ready. */ + fsleep(300); + + ret = mt6323_auxadc_read(auxadc, chan, val); + + if (mt6323_auxadc_release(auxadc, chan->channel)) + dev_err(&indio_dev->dev, + "failed to release channel %d\n", chan->channel); + + if (ret) + return ret; + + return IIO_VAL_INT; + } + default: + return -EINVAL; + } +} + +static int mt6323_auxadc_init(struct mt6323_auxadc *auxadc) +{ + struct regmap *map = auxadc->regmap; + int ret; + + ret = regmap_set_bits(map, MT6323_STRUP_CON10, + AUXADC_STRUP_CON10_RSTB_SW | + AUXADC_STRUP_CON10_RSTB_SEL); + if (ret) + return ret; + + ret = regmap_set_bits(map, MT6323_TOP_CKPDN2, AUXADC_TOP_CKPDN2_CTL_CK); + if (ret) + return ret; + + ret = regmap_update_bits(map, MT6323_AUXADC_CON10, + AUXADC_TRIM_CH2_MASK | AUXADC_TRIM_CH4_MASK | + AUXADC_TRIM_CH5_MASK | AUXADC_TRIM_CH6_MASK, + FIELD_PREP(AUXADC_TRIM_CH2_MASK, 1) | + FIELD_PREP(AUXADC_TRIM_CH4_MASK, 1) | + FIELD_PREP(AUXADC_TRIM_CH5_MASK, 1) | + FIELD_PREP(AUXADC_TRIM_CH6_MASK, 1)); + if (ret) + return ret; + + ret = regmap_set_bits(map, MT6323_AUXADC_CON27, + AUXADC_CON27_VREF18_ENB_MD | + AUXADC_CON27_MD_STATUS); + if (ret) + return ret; + + ret = regmap_set_bits(map, MT6323_AUXADC_CON19, AUXADC_CON19_GPS_STATUS); + if (ret) + return ret; + + ret = regmap_set_bits(map, MT6323_AUXADC_CON26, + AUXADC_CON26_VREF18_SELB | + AUXADC_CON26_DECI_GDLY_SEL); + if (ret) + return ret; + + return regmap_update_bits(map, MT6323_AUXADC_CON9, AUXADC_CON9_OSR_MASK, + FIELD_PREP(AUXADC_CON9_OSR_MASK, AUXADC_DEFAULT_OSR)); +} + +static const struct iio_info mt6323_auxadc_iio_info = { + .read_raw = mt6323_auxadc_read_raw, +}; + +static int mt6323_auxadc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mt6323_auxadc *auxadc; + struct regmap *regmap; + struct iio_dev *iio; + int ret; + + regmap = dev_get_regmap(dev->parent->parent, NULL); + if (!regmap) + return dev_err_probe(dev, -ENODEV, "failed to get regmap\n"); + + iio = devm_iio_device_alloc(dev, sizeof(*auxadc)); + if (!iio) + return -ENOMEM; + + auxadc = iio_priv(iio); + auxadc->regmap = regmap; + + ret = devm_mutex_init(dev, &auxadc->lock); + if (ret) + return ret; + + ret = mt6323_auxadc_init(auxadc); + if (ret) + return dev_err_probe(dev, ret, "failed to initialize auxadc\n"); + + iio->name = "mt6323-auxadc"; + iio->info = &mt6323_auxadc_iio_info; + iio->modes = INDIO_DIRECT_MODE; + iio->channels = mt6323_auxadc_channels; + iio->num_channels = ARRAY_SIZE(mt6323_auxadc_channels); + + return devm_iio_device_register(dev, iio); +} + +static const struct of_device_id mt6323_auxadc_of_match[] = { + { .compatible = "mediatek,mt6323-auxadc" }, + { } +}; +MODULE_DEVICE_TABLE(of, mt6323_auxadc_of_match); + +static struct platform_driver mt6323_auxadc_driver = { + .driver = { + .name = "mt6323-auxadc", + .of_match_table = mt6323_auxadc_of_match, + }, + .probe = mt6323_auxadc_probe, +}; +module_platform_driver(mt6323_auxadc_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MediaTek MT6323 PMIC AUXADC Driver"); diff --git a/drivers/iio/adc/rohm-bd79112.c b/drivers/iio/adc/rohm-bd79112.c index c4b0bec80794..2506fec7be84 100644 --- a/drivers/iio/adc/rohm-bd79112.c +++ b/drivers/iio/adc/rohm-bd79112.c @@ -529,7 +529,7 @@ static const struct of_device_id bd79112_of_match[] = { MODULE_DEVICE_TABLE(of, bd79112_of_match); static const struct spi_device_id bd79112_id[] = { - { "bd79112" }, + { .name = "bd79112" }, { } }; MODULE_DEVICE_TABLE(spi, bd79112_id); diff --git a/drivers/iio/adc/rtq6056.c b/drivers/iio/adc/rtq6056.c index ba525a3c5cc2..2083c4351e43 100644 --- a/drivers/iio/adc/rtq6056.c +++ b/drivers/iio/adc/rtq6056.c @@ -871,8 +871,8 @@ static const struct richtek_dev_data rtq6059_devdata = { }; static const struct i2c_device_id rtq6056_id[] = { - { "rtq6056", (kernel_ulong_t)&rtq6056_devdata }, - { "rtq6059", (kernel_ulong_t)&rtq6059_devdata }, + { .name = "rtq6056", .driver_data = (kernel_ulong_t)&rtq6056_devdata }, + { .name = "rtq6059", .driver_data = (kernel_ulong_t)&rtq6059_devdata }, { } }; MODULE_DEVICE_TABLE(i2c, rtq6056_id); diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index 9664b9bd75d4..00f05e167afc 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -660,11 +660,8 @@ static int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm, } df_ch->src = val; - ret = of_property_read_u32_index(indio_dev->dev.of_node, - "st,adc-alt-channel", chan_idx, - &df_ch->alt_si); - if (ret < 0) - df_ch->alt_si = 0; + df_ch->alt_si = of_property_present(indio_dev->dev.of_node, + "st,adc-alt-channel"); return 0; } @@ -1815,9 +1812,8 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) adc->dfsdm->fl_list[adc->fl_id].ford = val; - ret = of_property_read_u32(dev->of_node, "st,filter0-sync", &val); - if (!ret) - adc->dfsdm->fl_list[adc->fl_id].sync_mode = val; + adc->dfsdm->fl_list[adc->fl_id].sync_mode = + of_property_read_bool(dev->of_node, "st,filter0-sync"); adc->dev_data = dev_data; ret = dev_data->init(dev, iio); diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c index e33a2f4bf66c..2df8f1c21c2a 100644 --- a/drivers/iio/adc/ti-adc081c.c +++ b/drivers/iio/adc/ti-adc081c.c @@ -189,10 +189,8 @@ static int adc081c_probe(struct i2c_client *client) err = devm_iio_triggered_buffer_setup(&client->dev, iio, NULL, adc081c_trigger_handler, NULL); - if (err < 0) { - dev_err(&client->dev, "iio triggered buffer setup failed\n"); - return err; - } + if (err < 0) + return dev_err_probe(&client->dev, err, "iio triggered buffer setup failed\n"); return devm_iio_device_register(&client->dev, iio); } diff --git a/drivers/iio/adc/ti-adc0832.c b/drivers/iio/adc/ti-adc0832.c index 63d712d5d111..a522d8676034 100644 --- a/drivers/iio/adc/ti-adc0832.c +++ b/drivers/iio/adc/ti-adc0832.c @@ -313,10 +313,10 @@ static const struct of_device_id adc0832_dt_ids[] = { MODULE_DEVICE_TABLE(of, adc0832_dt_ids); static const struct spi_device_id adc0832_id[] = { - { "adc0831", adc0831 }, - { "adc0832", adc0832 }, - { "adc0834", adc0834 }, - { "adc0838", adc0838 }, + { .name = "adc0831", .driver_data = adc0831 }, + { .name = "adc0832", .driver_data = adc0832 }, + { .name = "adc0834", .driver_data = adc0834 }, + { .name = "adc0838", .driver_data = adc0838 }, { } }; MODULE_DEVICE_TABLE(spi, adc0832_id); diff --git a/drivers/iio/adc/ti-adc084s021.c b/drivers/iio/adc/ti-adc084s021.c index 51596b500a90..cf2f6ee59411 100644 --- a/drivers/iio/adc/ti-adc084s021.c +++ b/drivers/iio/adc/ti-adc084s021.c @@ -228,10 +228,8 @@ static int adc084s021_probe(struct spi_device *spi) ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL, adc084s021_buffer_trigger_handler, &adc084s021_buffer_setup_ops); - if (ret) { - dev_err(&spi->dev, "Failed to setup triggered buffer\n"); - return ret; - } + if (ret) + return dev_err_probe(&spi->dev, ret, "Failed to setup triggered buffer\n"); return devm_iio_device_register(&spi->dev, indio_dev); } @@ -243,7 +241,7 @@ static const struct of_device_id adc084s021_of_match[] = { MODULE_DEVICE_TABLE(of, adc084s021_of_match); static const struct spi_device_id adc084s021_id[] = { - { ADC084S021_DRIVER_NAME, 0 }, + { .name = ADC084S021_DRIVER_NAME }, { } }; MODULE_DEVICE_TABLE(spi, adc084s021_id); diff --git a/drivers/iio/adc/ti-adc108s102.c b/drivers/iio/adc/ti-adc108s102.c index d1f61b440959..10959e835cb8 100644 --- a/drivers/iio/adc/ti-adc108s102.c +++ b/drivers/iio/adc/ti-adc108s102.c @@ -276,7 +276,7 @@ static const struct acpi_device_id adc108s102_acpi_ids[] = { MODULE_DEVICE_TABLE(acpi, adc108s102_acpi_ids); static const struct spi_device_id adc108s102_id[] = { - { "adc108s102", 0 }, + { .name = "adc108s102" }, { } }; MODULE_DEVICE_TABLE(spi, adc108s102_id); diff --git a/drivers/iio/adc/ti-adc12138.c b/drivers/iio/adc/ti-adc12138.c index e5ec4b073daa..279e4999eb49 100644 --- a/drivers/iio/adc/ti-adc12138.c +++ b/drivers/iio/adc/ti-adc12138.c @@ -516,9 +516,9 @@ static const struct of_device_id adc12138_dt_ids[] = { MODULE_DEVICE_TABLE(of, adc12138_dt_ids); static const struct spi_device_id adc12138_id[] = { - { "adc12130", adc12130 }, - { "adc12132", adc12132 }, - { "adc12138", adc12138 }, + { .name = "adc12130", .driver_data = adc12130 }, + { .name = "adc12132", .driver_data = adc12132 }, + { .name = "adc12138", .driver_data = adc12138 }, { } }; MODULE_DEVICE_TABLE(spi, adc12138_id); diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c index 2cb68582ee6a..1899813c1aee 100644 --- a/drivers/iio/adc/ti-adc128s052.c +++ b/drivers/iio/adc/ti-adc128s052.c @@ -247,18 +247,18 @@ static const struct of_device_id adc128_of_match[] = { MODULE_DEVICE_TABLE(of, adc128_of_match); static const struct spi_device_id adc128_id[] = { - { "adc128s052", (kernel_ulong_t)&adc128s_config }, - { "adc122s021", (kernel_ulong_t)&adc122s_config }, - { "adc122s051", (kernel_ulong_t)&adc122s_config }, - { "adc122s101", (kernel_ulong_t)&adc122s_config }, - { "adc124s021", (kernel_ulong_t)&adc124s_config }, - { "adc124s051", (kernel_ulong_t)&adc124s_config }, - { "adc124s101", (kernel_ulong_t)&adc124s_config }, - { "bd79100", (kernel_ulong_t)&bd79100_config }, - { "bd79101", (kernel_ulong_t)&bd79101_config }, - { "bd79102", (kernel_ulong_t)&bd79102_config }, - { "bd79103", (kernel_ulong_t)&bd79104_config }, - { "bd79104", (kernel_ulong_t)&bd79104_config }, + { .name = "adc128s052", .driver_data = (kernel_ulong_t)&adc128s_config }, + { .name = "adc122s021", .driver_data = (kernel_ulong_t)&adc122s_config }, + { .name = "adc122s051", .driver_data = (kernel_ulong_t)&adc122s_config }, + { .name = "adc122s101", .driver_data = (kernel_ulong_t)&adc122s_config }, + { .name = "adc124s021", .driver_data = (kernel_ulong_t)&adc124s_config }, + { .name = "adc124s051", .driver_data = (kernel_ulong_t)&adc124s_config }, + { .name = "adc124s101", .driver_data = (kernel_ulong_t)&adc124s_config }, + { .name = "bd79100", .driver_data = (kernel_ulong_t)&bd79100_config }, + { .name = "bd79101", .driver_data = (kernel_ulong_t)&bd79101_config }, + { .name = "bd79102", .driver_data = (kernel_ulong_t)&bd79102_config }, + { .name = "bd79103", .driver_data = (kernel_ulong_t)&bd79104_config }, + { .name = "bd79104", .driver_data = (kernel_ulong_t)&bd79104_config }, { } }; MODULE_DEVICE_TABLE(spi, adc128_id); diff --git a/drivers/iio/adc/ti-adc161s626.c b/drivers/iio/adc/ti-adc161s626.c index 08aa32bd5e4b..422df0685580 100644 --- a/drivers/iio/adc/ti-adc161s626.c +++ b/drivers/iio/adc/ti-adc161s626.c @@ -229,8 +229,8 @@ static const struct of_device_id ti_adc_dt_ids[] = { MODULE_DEVICE_TABLE(of, ti_adc_dt_ids); static const struct spi_device_id ti_adc_id[] = { - { "adc141s626", TI_ADC141S626 }, - { "adc161s626", TI_ADC161S626 }, + { .name = "adc141s626", .driver_data = TI_ADC141S626 }, + { .name = "adc161s626", .driver_data = TI_ADC161S626 }, { } }; MODULE_DEVICE_TABLE(spi, ti_adc_id); diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index 8a272af69f7d..0fbfa4e499aa 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -930,6 +930,17 @@ static int ads1015_set_conv_mode(struct ads1015_data *data, int mode) mode << ADS1015_CFG_MOD_SHIFT); } +static void ads1015_power_down(void *p) +{ + struct ads1015_data *data = p; + int ret; + + ret = ads1015_set_conv_mode(data, ADS1015_SINGLESHOT); + if (ret) + dev_warn(regmap_get_device(data->regmap), + "Failed to power down (%pe)\n", ERR_PTR(ret)); +} + static int ads1015_probe(struct i2c_client *client) { const struct ads1015_chip_data *chip; @@ -1030,6 +1041,10 @@ static int ads1015_probe(struct i2c_client *client) if (ret) return ret; + ret = devm_add_action_or_reset(&client->dev, ads1015_power_down, data); + if (ret) + return ret; + data->conv_invalid = true; ret = pm_runtime_set_active(&client->dev); @@ -1037,33 +1052,11 @@ static int ads1015_probe(struct i2c_client *client) return ret; pm_runtime_set_autosuspend_delay(&client->dev, ADS1015_SLEEP_DELAY_MS); pm_runtime_use_autosuspend(&client->dev); - pm_runtime_enable(&client->dev); - - ret = iio_device_register(indio_dev); - if (ret < 0) { - dev_err(&client->dev, "Failed to register IIO device\n"); + ret = devm_pm_runtime_enable(&client->dev); + if (ret) return ret; - } - - return 0; -} -static void ads1015_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct ads1015_data *data = iio_priv(indio_dev); - int ret; - - iio_device_unregister(indio_dev); - - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); - - /* power down single shot mode */ - ret = ads1015_set_conv_mode(data, ADS1015_SINGLESHOT); - if (ret) - dev_warn(&client->dev, "Failed to power down (%pe)\n", - ERR_PTR(ret)); + return devm_iio_device_register(&client->dev, indio_dev); } #ifdef CONFIG_PM @@ -1150,7 +1143,6 @@ static struct i2c_driver ads1015_driver = { .pm = &ads1015_pm_ops, }, .probe = ads1015_probe, - .remove = ads1015_remove, .id_table = ads1015_id, }; diff --git a/drivers/iio/adc/ti-ads1018.c b/drivers/iio/adc/ti-ads1018.c index d6624c71a374..d9ec4a8d7ce5 100644 --- a/drivers/iio/adc/ti-ads1018.c +++ b/drivers/iio/adc/ti-ads1018.c @@ -717,8 +717,8 @@ static const struct of_device_id ads1018_of_match[] = { MODULE_DEVICE_TABLE(of, ads1018_of_match); static const struct spi_device_id ads1018_spi_match[] = { - { "ads1018", (kernel_ulong_t)&ads1018_chip_info }, - { "ads1118", (kernel_ulong_t)&ads1118_chip_info }, + { .name = "ads1018", .driver_data = (kernel_ulong_t)&ads1018_chip_info }, + { .name = "ads1118", .driver_data = (kernel_ulong_t)&ads1118_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ads1018_spi_match); diff --git a/drivers/iio/adc/ti-ads112c14.c b/drivers/iio/adc/ti-ads112c14.c new file mode 100644 index 000000000000..3035d45b64b0 --- /dev/null +++ b/drivers/iio/adc/ti-ads112c14.c @@ -0,0 +1,1224 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * IIO driver for Texas Instruments ADS112C14 and similar ADCs. + * + * Copyright (C) 2026 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2026 Baylibre Inc. + * + * Datasheet: https://www.ti.com/lit/ds/symlink/ads122c14.pdf + */ + +#include <linux/bitfield.h> +#include <linux/cleanup.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> +#include <linux/device/devres.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/math64.h> +#include <linux/minmax.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/sysfs.h> +#include <linux/time64.h> +#include <linux/types.h> +#include <linux/unaligned.h> +#include <linux/units.h> + +/* Datasheet t_d(RST) - time to wait after reset before next I2C use. */ +#define ADS112C14_DELAY_RESET_US 500 + +#define ADS112C14_CMD_RDATA 0x00 +#define ADS112C14_CMD_RREG 0x40 +#define ADS112C14_CMD_WREG 0x80 + +#define ADS112C14_REG_DEVICE_ID 0x00 +#define ADS112C14_DEVICE_ID_BITS GENMASK(3, 0) + +#define ADS112C14_REG_REVISION_ID 0x01 + +#define ADS112C14_REG_STATUS_MSB 0x02 +#define ADS112C14_STATUS_MSB_RESETN BIT(7) +#define ADS112C14_STATUS_MSB_AVDD_UVN BIT(6) +#define ADS112C14_STATUS_MSB_REF_UVN BIT(5) +#define ADS112C14_STATUS_MSB_REG_MAP_CRC_FAULTN BIT(3) +#define ADS112C14_STATUS_MSB_MEM_FAULTN BIT(2) +#define ADS112C14_STATUS_MSB_REG_WRITE_FAULTN BIT(1) +#define ADS112C14_STATUS_MSB_DRDY BIT(0) + +#define ADS112C14_REG_STATUS_LSB 0x03 +#define ADS112C14_STATUS_LSB_CONV_COUNT GENMASK(7, 4) +#define ADS112C14_STATUS_LSB_GPIO3_DAT_IN BIT(3) +#define ADS112C14_STATUS_LSB_GPIO2_DAT_IN BIT(2) +#define ADS112C14_STATUS_LSB_GPIO1_DAT_IN BIT(1) +#define ADS112C14_STATUS_LSB_GPIO0_DAT_IN BIT(0) + +#define ADS112C14_REG_CONVERSION_CTRL 0x04 +#define ADS112C14_CONVERSION_CTRL_RESET GENMASK(7, 2) +#define ADS112C14_CONVERSION_CTRL_START BIT(1) +#define ADS112C14_CONVERSION_CTRL_STOP BIT(0) + +#define ADS112C14_REG_DEVICE_CFG 0x05 +#define ADS112C14_DEVICE_CFG_PWDN BIT(7) +#define ADS112C14_DEVICE_CFG_STBY_MODE BIT(6) +#define ADS112C14_DEVICE_CFG_BOCS GENMASK(5, 4) +#define ADS112C14_DEVICE_CFG_CLK_SEL BIT(3) +#define ADS112C14_DEVICE_CFG_CONV_MODE BIT(2) +#define ADS112C14_DEVICE_CFG_CONV_MODE_CONTINUOUS 0 +#define ADS112C14_DEVICE_CFG_CONV_MODE_SINGLE_SHOT 1 +#define ADS112C14_DEVICE_CFG_SPEED_MODE GENMASK(1, 0) + +#define ADS112C14_REG_DATA_RATE_CFG 0x06 +#define ADS112C14_DATA_RATE_CFG_DELAY GENMASK(7, 4) +#define ADS112C14_DATA_RATE_CFG_GC_EN BIT(3) +#define ADS112C14_DATA_RATE_CFG_FLTR_OSR GENMASK(2, 0) + +#define ADS112C14_REG_MUX_CFG 0x07 +#define ADS112C14_MUX_CFG_AINP GENMASK(7, 4) +#define ADS112C14_MUX_CFG_AINN GENMASK(3, 0) +#define ADS112C14_MUX_CFG_AIN_GND 8 + +#define ADS112C14_REG_GAIN_CFG 0x08 +#define ADS112C14_GAIN_CFG_SPARE BIT(7) +#define ADS112C14_GAIN_CFG_SYS_MON GENMASK(6, 4) +#define ADS112C14_GAIN_CFG_GAIN GENMASK(3, 0) + +#define ADS112C14_REG_REFERENCE_CFG 0x09 +#define ADS112C14_REFERENCE_CFG_REF_UV_EN BIT(7) +#define ADS112C14_REFERENCE_CFG_REFP_BUF_EN BIT(5) +#define ADS112C14_REFERENCE_CFG_REFN_BUF_EN BIT(4) +#define ADS112C14_REFERENCE_CFG_REF_VAL BIT(2) +#define ADS112C14_REFERENCE_CFG_REF_VAL_1_25V 0 +#define ADS112C14_REFERENCE_CFG_REF_VAL_2_5V 1 +#define ADS112C14_REFERENCE_CFG_REF_SEL GENMASK(1, 0) +#define ADS112C14_REFERENCE_CFG_REF_SEL_INTERNAL 0 +#define ADS112C14_REFERENCE_CFG_REF_SEL_EXTERNAL 1 +#define ADS112C14_REFERENCE_CFG_REF_SEL_AVDD 2 + +#define ADS112C14_REG_DIGITAL_CFG 0x0A +#define ADS112C14_DIGITAL_CFG_REG_MAP_CRC_EN BIT(6) +#define ADS112C14_DIGITAL_CFG_I2C_CRC_EN BIT(5) +#define ADS112C14_DIGITAL_CFG_STATUS_EN BIT(4) +#define ADS112C14_DIGITAL_CFG_FAULT_PIN_BEHAVIOR BIT(3) +#define ADS112C14_DIGITAL_CFG_CODING BIT(1) + +#define ADS112C14_REG_GPIO_CFG 0x0B +#define ADS112C14_GPIO_CFG_GPIO3_CFG GENMASK(7, 6) +#define ADS112C14_GPIO_CFG_GPIO2_CFG GENMASK(5, 4) +#define ADS112C14_GPIO_CFG_GPIO1_CFG GENMASK(3, 2) +#define ADS112C14_GPIO_CFG_GPIO0_CFG GENMASK(1, 0) + +#define ADS112C14_REG_GPIO_DATA_OUTPUT 0x0C +#define ADS112C14_GPIO_DATA_OUTPUT_GPIO3_SRC BIT(7) +#define ADS112C14_GPIO_DATA_OUTPUT_GPIO2_SRC BIT(6) +#define ADS112C14_GPIO_DATA_OUTPUT_GPIO3_DAT_OUT BIT(3) +#define ADS112C14_GPIO_DATA_OUTPUT_GPIO2_DAT_OUT BIT(2) +#define ADS112C14_GPIO_DATA_OUTPUT_GPIO1_DAT_OUT BIT(1) +#define ADS112C14_GPIO_DATA_OUTPUT_GPIO0_DAT_OUT BIT(0) + +#define ADS112C14_REG_IDAC_MAG_CFG 0x0D +#define ADS112C14_IDAC_MAG_CFG_I2MAG GENMASK(7, 4) +#define ADS112C14_IDAC_MAG_CFG_I1MAG GENMASK(3, 0) + +#define ADS112C14_REG_IDAC_MUX_CFG 0x0E +#define ADS112C14_IDAC_MUX_CFG_IUNIT BIT(7) +#define ADS112C14_IDAC_MUX_CFG_I2MUX GENMASK(6, 4) +#define ADS112C14_IDAC_MUX_CFG_I1MUX GENMASK(2, 0) + +#define ADS112C14_REG_REG_MAP_CRC 0x0F + +#define ADS112C14_INT_REF0_mV 1250 +#define ADS112C14_INT_REF1_mV 2500 + +enum { + ADS112C14_VREF_SOURCE_INTERNAL_2_5V, + ADS112C14_VREF_SOURCE_INTERNAL_1_25V, + ADS112C14_VREF_SOURCE_EXTERNAL, + ADS112C14_VREF_SOURCE_AVDD, +}; + +static const char * const ads112c14_vref_source_names[] = { + [ADS112C14_VREF_SOURCE_INTERNAL_2_5V] = "internal-2.5v", + [ADS112C14_VREF_SOURCE_INTERNAL_1_25V] = "internal-1.25v", + [ADS112C14_VREF_SOURCE_EXTERNAL] = "external", + [ADS112C14_VREF_SOURCE_AVDD] = "avdd", +}; + +/* + * Available gains as tenths (e.g. value 5 == 0.5 gain). Indexes correspond to + * ADS112C14_GAIN_CFG_GAIN values. + */ +static const u32 ads112c14_pga_gains_x10[] = { + 5, 10, 20, 40, 50, 80, 100, 160, /* 0 - 7 */ + 200, 320, 500, 640, 1000, 1280, 2000, 2560, /* 8 - 15 */ +}; + +struct ads112c14_chip_info { + const char *name; + u8 device_id; + u32 resolution_bits; +}; + +/* Fixed channels for system monitor measurements. */ + +#define ADS112C14_SYS_MON_CHANNEL_BASE 100 + +enum { + ADS112C14_SYS_MON_CHANNEL_TEMP = ADS112C14_SYS_MON_CHANNEL_BASE, + ADS112C14_SYS_MON_CHANNEL_EXT_REF, + ADS112C14_SYS_MON_CHANNEL_AVDD, + ADS112C14_SYS_MON_CHANNEL_DVDD, + ADS112C14_SYS_MON_CHANNEL_SHORT, +}; + +static const struct iio_chan_spec ads112c14_sys_mon_channels[] = { + { + .type = IIO_TEMP, + .indexed = 1, + .channel = ADS112C14_SYS_MON_CHANNEL_TEMP, + .address = 2, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) + | BIT(IIO_CHAN_INFO_SCALE) + | BIT(IIO_CHAN_INFO_OFFSET), + }, + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = ADS112C14_SYS_MON_CHANNEL_EXT_REF, + .address = 3, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) + | BIT(IIO_CHAN_INFO_SCALE), + }, + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = ADS112C14_SYS_MON_CHANNEL_AVDD, + .address = 4, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) + | BIT(IIO_CHAN_INFO_SCALE), + }, + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = ADS112C14_SYS_MON_CHANNEL_DVDD, + .address = 5, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) + | BIT(IIO_CHAN_INFO_SCALE), + }, + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = ADS112C14_SYS_MON_CHANNEL_SHORT, + .channel2 = ADS112C14_SYS_MON_CHANNEL_SHORT, + .differential = 1, + .address = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) + | BIT(IIO_CHAN_INFO_SCALE), + .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE), + }, +}; + +struct ads112c14_measurement { + const char *label; + u32 vref_source; + u8 iunit; + u8 idac1_mag; + u8 idac2_mag; + u8 idac1_mux; + u8 idac2_mux; + u8 iadc_count; + u8 gain_val; + bool global_chop; + bool bipolar; + int scale_available[ARRAY_SIZE(ads112c14_pga_gains_x10)][2]; +}; + +struct ads112c14_data { + const struct ads112c14_chip_info *chip_info; + struct regmap *regmap; + /* Synchronizes access to register value fields. */ + struct mutex lock; + u32 avdd_uV; + u32 ext_ref_uV; + bool refp_is_avdd; + bool refn_is_gnd; + u32 ext_ref_ohms; + struct ads112c14_measurement *measurements; + u32 num_measurements; + u8 sys_mon_chan_short_gain_val; + int sys_mon_chan_short_scale_available[ARRAY_SIZE(ads112c14_pga_gains_x10)][2]; +}; + +static bool ads112c14_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ADS112C14_REG_DEVICE_ID: + case ADS112C14_REG_REVISION_ID: + case ADS112C14_REG_STATUS_LSB: + return false; + default: + return true; + } +} + +static bool ads112c14_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ADS112C14_REG_STATUS_MSB: + case ADS112C14_REG_STATUS_LSB: + case ADS112C14_REG_CONVERSION_CTRL: + return true; + default: + return false; + } +} + +static const struct reg_default ads112c14_reg_defaults[] = { + { ADS112C14_REG_DEVICE_CFG, 0 }, + { ADS112C14_REG_DATA_RATE_CFG, 0 }, + { ADS112C14_REG_MUX_CFG, 0 }, + { ADS112C14_REG_GAIN_CFG, FIELD_PREP_CONST(ADS112C14_GAIN_CFG_GAIN, 1) }, + { ADS112C14_REG_REFERENCE_CFG, 0 }, + { ADS112C14_REG_DIGITAL_CFG, 0 }, + { ADS112C14_REG_GPIO_CFG, 0 }, + { ADS112C14_REG_GPIO_DATA_OUTPUT, 0 }, + { ADS112C14_REG_IDAC_MAG_CFG, 0 }, + { ADS112C14_REG_IDAC_MUX_CFG, FIELD_PREP_CONST(ADS112C14_IDAC_MUX_CFG_I2MUX, 1) }, +}; + +static const struct regmap_config ads112c14_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .read_flag_mask = ADS112C14_CMD_RREG, + .write_flag_mask = ADS112C14_CMD_WREG, + .max_register = ADS112C14_REG_REG_MAP_CRC, + .writeable_reg = ads112c14_writeable_reg, + .volatile_reg = ads112c14_volatile_reg, + .reg_defaults = ads112c14_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(ads112c14_reg_defaults), + .cache_type = REGCACHE_MAPLE, +}; + +static int ads112c14_prepare_measurement_channel(struct ads112c14_data *data, + const struct iio_chan_spec *chan) +{ + struct ads112c14_measurement *measurement = &data->measurements[chan->scan_index]; + u32 refp_buf_en, refn_buf_en, ref_val, ref_sel; + int ret; + + ret = regmap_update_bits(data->regmap, ADS112C14_REG_MUX_CFG, + ADS112C14_MUX_CFG_AINP | ADS112C14_MUX_CFG_AINN, + FIELD_PREP(ADS112C14_MUX_CFG_AINP, chan->channel) | + FIELD_PREP(ADS112C14_MUX_CFG_AINN, chan->channel2)); + if (ret) + return ret; + + ret = regmap_assign_bits(data->regmap, ADS112C14_REG_DIGITAL_CFG, + ADS112C14_DIGITAL_CFG_CODING, + !measurement->bipolar); + if (ret) + return ret; + + ret = regmap_update_bits(data->regmap, ADS112C14_REG_GAIN_CFG, + ADS112C14_GAIN_CFG_SYS_MON | + ADS112C14_GAIN_CFG_GAIN, + FIELD_PREP(ADS112C14_GAIN_CFG_SYS_MON, 0) | + FIELD_PREP(ADS112C14_GAIN_CFG_GAIN, + measurement->gain_val)); + if (ret) + return ret; + + ret = regmap_update_bits(data->regmap, ADS112C14_REG_IDAC_MAG_CFG, + ADS112C14_IDAC_MAG_CFG_I2MAG | + ADS112C14_IDAC_MAG_CFG_I1MAG, + FIELD_PREP(ADS112C14_IDAC_MAG_CFG_I2MAG, + measurement->idac2_mag) | + FIELD_PREP(ADS112C14_IDAC_MAG_CFG_I1MAG, + measurement->idac1_mag)); + if (ret) + return ret; + + ret = regmap_update_bits(data->regmap, ADS112C14_REG_IDAC_MUX_CFG, + ADS112C14_IDAC_MUX_CFG_IUNIT | + ADS112C14_IDAC_MUX_CFG_I2MUX | + ADS112C14_IDAC_MUX_CFG_I1MUX, + FIELD_PREP(ADS112C14_IDAC_MUX_CFG_IUNIT, + measurement->iunit) | + FIELD_PREP(ADS112C14_IDAC_MUX_CFG_I2MUX, + measurement->idac2_mux) | + FIELD_PREP(ADS112C14_IDAC_MUX_CFG_I1MUX, + measurement->idac1_mux)); + if (ret) + return ret; + + ret = regmap_update_bits(data->regmap, ADS112C14_REG_DATA_RATE_CFG, + ADS112C14_DATA_RATE_CFG_GC_EN, + FIELD_PREP(ADS112C14_DATA_RATE_CFG_GC_EN, + measurement->global_chop)); + if (ret) + return ret; + + refp_buf_en = !data->refp_is_avdd && + measurement->vref_source == ADS112C14_VREF_SOURCE_EXTERNAL; + refn_buf_en = !data->refn_is_gnd && + measurement->vref_source == ADS112C14_VREF_SOURCE_EXTERNAL; + + ref_val = measurement->vref_source == ADS112C14_VREF_SOURCE_INTERNAL_2_5V ? + ADS112C14_REFERENCE_CFG_REF_VAL_2_5V : + ADS112C14_REFERENCE_CFG_REF_VAL_1_25V; + + switch (measurement->vref_source) { + case ADS112C14_VREF_SOURCE_AVDD: + ref_sel = ADS112C14_REFERENCE_CFG_REF_SEL_AVDD; + break; + case ADS112C14_VREF_SOURCE_EXTERNAL: + ref_sel = ADS112C14_REFERENCE_CFG_REF_SEL_EXTERNAL; + break; + default: + ref_sel = ADS112C14_REFERENCE_CFG_REF_SEL_INTERNAL; + break; + } + + return regmap_update_bits(data->regmap, ADS112C14_REG_REFERENCE_CFG, + ADS112C14_REFERENCE_CFG_REFP_BUF_EN | + ADS112C14_REFERENCE_CFG_REFN_BUF_EN | + ADS112C14_REFERENCE_CFG_REF_VAL | + ADS112C14_REFERENCE_CFG_REF_SEL, + FIELD_PREP(ADS112C14_REFERENCE_CFG_REFP_BUF_EN, + refp_buf_en) | + FIELD_PREP(ADS112C14_REFERENCE_CFG_REFN_BUF_EN, + refn_buf_en) | + FIELD_PREP(ADS112C14_REFERENCE_CFG_REF_VAL, + ref_val) | + FIELD_PREP(ADS112C14_REFERENCE_CFG_REF_SEL, + ref_sel)); +} + +static int ads112c14_prepare_sys_mon_channel(struct ads112c14_data *data, + const struct iio_chan_spec *chan) +{ + u32 gain_val; + int ret; + + /* + * NB: IDAC registers are left as-is in case they are generating current + * needed for the external reference measurement. + */ + + /* + * All SYS_MON channels use GAIN of 1 to keep it simple. Other than + * the internal short channel, where it is useful in practice. + */ + gain_val = chan->channel == ADS112C14_SYS_MON_CHANNEL_SHORT ? + data->sys_mon_chan_short_gain_val : 1; + + ret = regmap_update_bits(data->regmap, ADS112C14_REG_GAIN_CFG, + ADS112C14_GAIN_CFG_SYS_MON | + ADS112C14_GAIN_CFG_GAIN, + FIELD_PREP(ADS112C14_GAIN_CFG_SYS_MON, chan->address) | + FIELD_PREP(ADS112C14_GAIN_CFG_GAIN, gain_val)); + if (ret) + return ret; + + /* All SYS_MON channels use signed data to keep it simple. */ + ret = regmap_clear_bits(data->regmap, ADS112C14_REG_DIGITAL_CFG, + ADS112C14_DIGITAL_CFG_CODING); + if (ret) + return ret; + + /* + * REVISIT: if we implement regulator support for the REFOUT pin, we + * might need to make this voltage match what is required by that. In + * that case, we could also adjust GAIN so that we still get the same + * range. + */ + /* + * NB: SYS_MON channels ignore REF_SEL except for the shorted input + * channel, so we set it here to internal reference to be consistent. + * If we ever need to make a measurement of shorted input with other + * reference source, we could add additional channels for that. + */ + ret = regmap_update_bits(data->regmap, ADS112C14_REG_REFERENCE_CFG, + ADS112C14_REFERENCE_CFG_REF_VAL | + ADS112C14_REFERENCE_CFG_REF_SEL, + FIELD_PREP(ADS112C14_REFERENCE_CFG_REF_VAL, + ADS112C14_REFERENCE_CFG_REF_VAL_2_5V) | + FIELD_PREP(ADS112C14_REFERENCE_CFG_REF_SEL, + ADS112C14_REFERENCE_CFG_REF_SEL_INTERNAL)); + if (ret) + return ret; + + return 0; +} + +static int ads112c14_single_conversion(struct ads112c14_data *data, + const struct iio_chan_spec *chan, + u8 *buf) +{ + struct i2c_client *client = to_i2c_client(regmap_get_device(data->regmap)); + u32 reg_val; + int ret; + + guard(mutex)(&data->lock); + + if (chan->channel < ADS112C14_SYS_MON_CHANNEL_BASE) { + ret = ads112c14_prepare_measurement_channel(data, chan); + if (ret) + return ret; + } else { + ret = ads112c14_prepare_sys_mon_channel(data, chan); + if (ret) + return ret; + } + + ret = regmap_write(data->regmap, ADS112C14_REG_CONVERSION_CTRL, + ADS112C14_CONVERSION_CTRL_START); + if (ret) + return ret; + + ret = regmap_read_poll_timeout(data->regmap, + ADS112C14_REG_STATUS_MSB, reg_val, + FIELD_GET(ADS112C14_STATUS_MSB_DRDY, reg_val), + 1 * USEC_PER_MSEC, 100 * USEC_PER_MSEC); + if (ret) + return ret; + + ret = i2c_smbus_read_i2c_block_data(client, ADS112C14_CMD_RDATA, + BITS_TO_BYTES(data->chip_info->resolution_bits), + buf); + if (ret < 0) + return ret; + + return 0; +} + +static int ads112c14_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct ads112c14_data *data = iio_priv(indio_dev); + struct ads112c14_measurement *measurement = NULL; + const int *scale_avail; + u32 vref_uV, fsr_bits; + + /* Selecting V_REF source is not implemented yet. */ + vref_uV = ADS112C14_INT_REF1_mV * (MICRO / MILLI); + + if (chan->channel < ADS112C14_SYS_MON_CHANNEL_BASE) { + measurement = &data->measurements[chan->scan_index]; + fsr_bits = data->chip_info->resolution_bits - measurement->bipolar; + } else { + /* All SYS_MON channels are using signed coding. */ + fsr_bits = data->chip_info->resolution_bits - 1; + } + + switch (mask) { + case IIO_CHAN_INFO_RAW: { + u8 buf[3]; + int ret; + + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + ret = ads112c14_single_conversion(data, chan, buf); + if (ret) + return ret; + + switch (data->chip_info->resolution_bits) { + case 16: + *val = get_unaligned_be16(buf); + break; + case 24: + *val = get_unaligned_be24(buf); + break; + default: + return -EINVAL; + } + + if (!measurement || measurement->bipolar) + *val = sign_extend32(*val, fsr_bits); + + return IIO_VAL_INT; + } + case IIO_CHAN_INFO_SCALE: + if (chan->type == IIO_TEMP) { + /* TS_TC (typical) = 405 uV/°C */ + *val = MILLI * vref_uV / 405; + *val2 = fsr_bits; + return IIO_VAL_FRACTIONAL_LOG2; + } + + if (chan->channel < ADS112C14_SYS_MON_CHANNEL_BASE) { + guard(mutex)(&data->lock); + + scale_avail = measurement->scale_available[measurement->gain_val]; + *val = scale_avail[0]; + *val2 = scale_avail[1]; + + return IIO_VAL_DECIMAL64_PICO; + } + + if (chan->channel == ADS112C14_SYS_MON_CHANNEL_SHORT) { + u8 idx; + + guard(mutex)(&data->lock); + + idx = data->sys_mon_chan_short_gain_val; + scale_avail = data->sys_mon_chan_short_scale_available[idx]; + *val = scale_avail[0]; + *val2 = scale_avail[1]; + + return IIO_VAL_DECIMAL64_PICO; + } + + *val = vref_uV / (MICRO / MILLI); + + /* + * Some SYS_MON channels (ext ref, AVDD, DVDD) need to be + * multiplied by 8 to account for internal attenuation of / 8. + */ + switch (chan->address) { + case 3 ... 5: + *val2 = fsr_bits - 3; + break; + default: + *val2 = fsr_bits; + break; + } + + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_OFFSET: + /* Only the temperature channel has an offset. */ + if (chan->type != IIO_TEMP) + return -EINVAL; + /* + * Die temperature [°C] = 25°C + (Measured voltage – TS_Offset) / TS_TC + * TS_TC (typical) = 405 uV/°C + * TS_Offset (typical) = 119.5 mV + */ + *val = div_s64((s64)(25 * 405 - 119500) * BIT(fsr_bits), vref_uV); + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int ads112c14_read_avail(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, const int **vals, + int *type, int *length, long mask) +{ + struct ads112c14_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + if (chan->channel < ADS112C14_SYS_MON_CHANNEL_BASE) { + struct ads112c14_measurement *measurement; + + guard(mutex)(&data->lock); + + measurement = &data->measurements[chan->scan_index]; + *vals = (const int *)measurement->scale_available; + *length = 2 * ARRAY_SIZE(measurement->scale_available); + *type = IIO_VAL_DECIMAL64_PICO; + return IIO_AVAIL_LIST; + } + + if (chan->channel == ADS112C14_SYS_MON_CHANNEL_SHORT) { + guard(mutex)(&data->lock); + + *vals = (const int *)data->sys_mon_chan_short_scale_available; + *length = 2 * ARRAY_SIZE(data->sys_mon_chan_short_scale_available); + *type = IIO_VAL_DECIMAL64_PICO; + return IIO_AVAIL_LIST; + } + + return -EINVAL; + default: + return -EINVAL; + } +} + +static int ads112c14_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct ads112c14_data *data = iio_priv(indio_dev); + const int (*scale_avail)[2]; + u8 *gain_val; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: { + guard(mutex)(&data->lock); + + if (chan->channel < ADS112C14_SYS_MON_CHANNEL_BASE) { + struct ads112c14_measurement *measurement; + + measurement = &data->measurements[chan->scan_index]; + scale_avail = measurement->scale_available; + gain_val = &measurement->gain_val; + } else if (chan->channel == ADS112C14_SYS_MON_CHANNEL_SHORT) { + scale_avail = data->sys_mon_chan_short_scale_available; + gain_val = &data->sys_mon_chan_short_gain_val; + } else { + return -EINVAL; + } + + for (u32 i = 0; i < ARRAY_SIZE(ads112c14_pga_gains_x10); i++) { + if (iio_val_s64_compose(val, val2) == + iio_val_s64_compose(scale_avail[i][0], scale_avail[i][1])) { + *gain_val = i; + return 0; + } + } + + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int ads112c14_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_DECIMAL64_PICO; + default: + return IIO_VAL_INT_PLUS_MICRO; + } +} + +static int ads112c14_debugfs_reg_access(struct iio_dev *indio_dev, + unsigned int reg, + unsigned int writeval, + unsigned int *readval) +{ + struct ads112c14_data *data = iio_priv(indio_dev); + + if (readval) + return regmap_read(data->regmap, reg, readval); + + return regmap_write(data->regmap, reg, writeval); +} + +static int ads112c14_read_label(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, char *label) +{ + struct ads112c14_data *data = iio_priv(indio_dev); + const char *label_source; + + /* measurement channels */ + if (chan->channel < ADS112C14_SYS_MON_CHANNEL_BASE) { + struct ads112c14_measurement *measurement; + + measurement = &data->measurements[chan->scan_index]; + if (!measurement->label) + return -EINVAL; + + return sysfs_emit(label, "%s\n", measurement->label); + } + + /* System monitor channels. */ + switch (chan->channel) { + case ADS112C14_SYS_MON_CHANNEL_TEMP: + label_source = "Internal temperature sensor"; + break; + case ADS112C14_SYS_MON_CHANNEL_EXT_REF: + label_source = "External reference"; + break; + case ADS112C14_SYS_MON_CHANNEL_AVDD: + label_source = "AVDD"; + break; + case ADS112C14_SYS_MON_CHANNEL_DVDD: + label_source = "DVDD"; + break; + case ADS112C14_SYS_MON_CHANNEL_SHORT: + label_source = "Internal short (internal reference source)"; + break; + default: + return -EINVAL; + } + + return sysfs_emit(label, "%s\n", label_source); +} + +static const struct iio_info ads112c14_info = { + .read_raw = ads112c14_read_raw, + .read_avail = ads112c14_read_avail, + .write_raw = ads112c14_write_raw, + .write_raw_get_fmt = ads112c14_write_raw_get_fmt, + .debugfs_reg_access = ads112c14_debugfs_reg_access, + .read_label = ads112c14_read_label, +}; + +static int ads112c14_populate_idac_mag(u32 current_nA, u8 *idac_mag) +{ + u32 current_uA = current_nA / (NANO / MICRO); + + /* Convert microamps to IMAG bits */ + if (current_uA == 1) + *idac_mag = 1; + else if (in_range(current_uA, 10, 100) && current_uA % 10 == 0) + *idac_mag = current_uA / 10 + 1; + else + return dev_err_probe(NULL, -EINVAL, + "invalid excitation-current-nanoamp value\n"); + + return 0; +} + +static int ads112c14_parse_channels(struct iio_dev *indio_dev, + bool *need_avdd_ref, bool *need_ext_ref) +{ + struct ads112c14_data *data = iio_priv(indio_dev); + struct device *dev = indio_dev->dev.parent; + struct iio_chan_spec *channels; + u32 num_child_nodes, i, pair[2]; + int ret; + + *need_avdd_ref = false; + *need_ext_ref = false; + + num_child_nodes = device_get_named_child_node_count(dev, "channel"); + + data->measurements = devm_kcalloc(dev, num_child_nodes, + sizeof(*data->measurements), GFP_KERNEL); + if (!data->measurements) + return -ENOMEM; + + channels = devm_kcalloc(dev, num_child_nodes + + ARRAY_SIZE(ads112c14_sys_mon_channels), + sizeof(*channels), GFP_KERNEL); + if (!channels) + return -ENOMEM; + + i = 0; + device_for_each_named_child_node_scoped(dev, child, "channel") { + struct ads112c14_measurement *measurement = &data->measurements[i]; + struct iio_chan_spec *spec = &channels[i]; + + spec->indexed = 1; + spec->scan_index = i; + measurement->gain_val = 1; + + if (fwnode_property_present(child, "label")) { + ret = fwnode_property_read_string(child, "label", &measurement->label); + if (ret) + return dev_err_probe(dev, ret, + "failed to read label property\n"); + } + + if (fwnode_property_present(child, "single-channel")) { + ret = fwnode_property_read_u32(child, "single-channel", + &pair[0]); + if (ret) + return dev_err_probe(dev, ret, + "failed to read single-channel property\n"); + + if (pair[0] >= 8) + return dev_err_probe(dev, -EINVAL, + "single-channel value must be between 0 and 7\n"); + + spec->channel = pair[0]; + /* + * NB: channel2 is unused by iio core code in this case. + * Let's us avoid special case for negative input mux + * for single-ended channels when taking measurements. + */ + spec->channel2 = ADS112C14_MUX_CFG_AIN_GND; + } else if (fwnode_property_present(child, "diff-channels")) { + ret = fwnode_property_read_u32_array(child, "diff-channels", + pair, ARRAY_SIZE(pair)); + if (ret) + return dev_err_probe(dev, ret, + "failed to read diff-channels property\n"); + + if (pair[0] >= 8 || pair[1] >= 8) + return dev_err_probe(dev, -EINVAL, + "diff-channels values must be between 0 and 7\n"); + + spec->differential = 1; + spec->channel = pair[0]; + spec->channel2 = pair[1]; + } else { + return dev_err_probe(dev, -EINVAL, + "channel node missing channel type property\n"); + } + + if (fwnode_property_present(child, "excitation-channels")) { + ret = fwnode_property_count_u32(child, "excitation-channels"); + if (ret < 0) + return dev_err_probe(dev, ret, + "failed to read excitation-channels property\n"); + + if (ret < 1 || ret > 2) + return dev_err_probe(dev, -EINVAL, + "excitation-channels property must have 1 or 2 values\n"); + + measurement->iadc_count = ret; + pair[1] = 0; + + ret = fwnode_property_read_u32_array(child, "excitation-channels", + pair, measurement->iadc_count); + if (ret) + return dev_err_probe(dev, ret, + "failed to read excitation-channels property\n"); + + if (pair[0] >= 8 || pair[1] >= 8) + return dev_err_probe(dev, -EINVAL, + "excitation-channels values must be between 0 and 7\n"); + + measurement->idac1_mux = pair[0]; + measurement->idac2_mux = measurement->iadc_count > 1 ? pair[1] : 0; + + ret = fwnode_property_read_u32_array(child, "excitation-current-nanoamp", + pair, measurement->iadc_count); + if (ret) + return dev_err_probe(dev, ret, + "failed to read excitation-current-nanoamp property\n"); + + if (pair[0] <= 100 * (NANO / MICRO) && + (measurement->iadc_count == 1 || pair[1] <= 100 * (NANO / MICRO))) { + /* + * If both values are 100µA or less, then we can + * use IUNIT = 1µA for better precision. + */ + ret = ads112c14_populate_idac_mag(pair[0], + &measurement->idac1_mag); + if (ret) + return ret; + + if (measurement->iadc_count > 1) { + ret = ads112c14_populate_idac_mag(pair[1], + &measurement->idac2_mag); + if (ret) + return ret; + } + } else { + /* + * Otherwise, IUINT is 10µA (flag set) and so + * IxMAG is 1/10 of the actual current. + */ + measurement->iunit = 1; + + ret = ads112c14_populate_idac_mag(pair[0] / 10, + &measurement->idac1_mag); + if (ret) + return ret; + + if (measurement->iadc_count > 1) { + ret = ads112c14_populate_idac_mag(pair[1] / 10, + &measurement->idac2_mag); + if (ret) + return ret; + } + } + } + + measurement->bipolar = fwnode_property_read_bool(child, "bipolar"); + measurement->global_chop = fwnode_property_read_bool(child, + "input-chopping"); + + if (fwnode_property_present(child, "reference-sources")) { + ret = fwnode_property_match_property_string(child, + "reference-sources", ads112c14_vref_source_names, + ARRAY_SIZE(ads112c14_vref_source_names)); + if (ret < 0) + return dev_err_probe(dev, ret, + "invalid reference-sources value\n"); + + measurement->vref_source = ret; + } + + if (measurement->vref_source == ADS112C14_VREF_SOURCE_AVDD) + *need_avdd_ref = true; + if (measurement->vref_source == ADS112C14_VREF_SOURCE_EXTERNAL) + *need_ext_ref = true; + + spec->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE); + spec->info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE); + + /* + * If reference source is resistor rather than voltage supply, + * then the measurement is effectively a resistance measurement. + */ + spec->type = (measurement->vref_source == ADS112C14_VREF_SOURCE_EXTERNAL && + data->ext_ref_ohms) ? IIO_RESISTANCE : IIO_VOLTAGE; + + if (spec->type == IIO_RESISTANCE) + spec->differential = 0; + + i++; + } + + data->num_measurements = i; + memcpy(channels + i, ads112c14_sys_mon_channels, sizeof(ads112c14_sys_mon_channels)); + + indio_dev->channels = channels; + indio_dev->num_channels = i + ARRAY_SIZE(ads112c14_sys_mon_channels); + + return 0; +} + +static void ads112c14_populate_scale_available(int (*scale_avail)[2], + u32 full_scale, u32 fsr_bits) +{ + for (u32 i = 0; i < ARRAY_SIZE(ads112c14_pga_gains_x10); i++) { + u64 gain_x10 = ads112c14_pga_gains_x10[i]; + s64 scale; + + scale = div64_u64((u64)PICO * 10U * full_scale, + gain_x10 * BIT(fsr_bits)); + + iio_val_s64_decompose(scale, &scale_avail[i][0], + &scale_avail[i][1]); + } +} + +static void ads112c14_populate_tables(struct ads112c14_data *data) +{ + u32 full_scale, fsr_bits; + + for (u32 i = 0; i < data->num_measurements; i++) { + struct ads112c14_measurement *measurement = &data->measurements[i]; + + switch (measurement->vref_source) { + case ADS112C14_VREF_SOURCE_EXTERNAL: + if (data->ext_ref_ohms) + full_scale = data->ext_ref_ohms; + else + full_scale = data->ext_ref_uV / (MICRO / MILLI); + break; + case ADS112C14_VREF_SOURCE_AVDD: + full_scale = data->avdd_uV / (MICRO / MILLI); + break; + case ADS112C14_VREF_SOURCE_INTERNAL_1_25V: + full_scale = ADS112C14_INT_REF0_mV; + break; + default: + full_scale = ADS112C14_INT_REF1_mV; + break; + } + + fsr_bits = data->chip_info->resolution_bits - measurement->bipolar; + + ads112c14_populate_scale_available(measurement->scale_available, + full_scale, fsr_bits); + } + + /* For now, assuming all sys_mon channels are using 2.5V reference. */ + full_scale = ADS112C14_INT_REF1_mV; + fsr_bits = data->chip_info->resolution_bits - 1; + + ads112c14_populate_scale_available(data->sys_mon_chan_short_scale_available, + full_scale, fsr_bits); +} + +static int ads112c14_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + const struct ads112c14_chip_info *info; + struct iio_dev *indio_dev; + struct ads112c14_data *data; + bool need_avdd_ref, need_ext_ref; + u32 refp_uV = 0; + u32 refn_uV = 0; + u32 reg_val; + int ret; + + info = i2c_get_match_data(client); + if (!info) + return dev_err_probe(dev, -ENODEV, "missing match data\n"); + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->chip_info = info; + + ret = devm_mutex_init(dev, &data->lock); + if (ret) + return ret; + + if (device_property_present(dev, "ti,refp-refn-resistor-ohms")) { + ret = device_property_read_u32(dev, "ti,refp-refn-resistor-ohms", + &data->ext_ref_ohms); + if (ret) + return dev_err_probe(dev, ret, + "failed to read ti,refp-refn-resistor-ohms property\n"); + } + + ret = ads112c14_parse_channels(indio_dev, &need_avdd_ref, &need_ext_ref); + if (ret) + return ret; + + ret = devm_regulator_get_enable(dev, "dvdd"); + if (ret) + return dev_err_probe(dev, ret, "failed to get dvdd regulator\n"); + + if (need_avdd_ref) { + ret = devm_regulator_get_enable_read_voltage(dev, "avdd"); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to get avdd voltage\n"); + + data->avdd_uV = ret; + } else { + ret = devm_regulator_get_enable(dev, "avdd"); + if (ret) + return dev_err_probe(dev, ret, "failed to get avdd regulator\n"); + } + + if (device_property_present(dev, "refp-supply")) { + ret = devm_regulator_get_enable_read_voltage(dev, "refp"); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to get refp voltage\n"); + + refp_uV = ret; + + struct fwnode_handle *refp_fwnode __free(fwnode_handle) = + fwnode_find_reference(dev->fwnode, "refp-supply", 0); + if (IS_ERR(refp_fwnode)) + return dev_err_probe(dev, PTR_ERR(refp_fwnode), + "failed to get refp fwnode\n"); + + struct fwnode_handle *avdd_fwnode __free(fwnode_handle) = + fwnode_find_reference(dev->fwnode, "avdd-supply", 0); + if (IS_ERR(avdd_fwnode)) + return dev_err_probe(dev, PTR_ERR(avdd_fwnode), + "failed to get avdd fwnode\n"); + + /* REFP buffer should not be enabled when connected to AVDD */ + data->refp_is_avdd = refp_fwnode == avdd_fwnode; + } + + if (device_property_present(dev, "refn-supply")) { + ret = devm_regulator_get_enable_read_voltage(dev, "refn"); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to get refn voltage\n"); + + refn_uV = ret; + } else { + data->refn_is_gnd = true; + } + + data->ext_ref_uV = refp_uV - refn_uV; + + if (data->ext_ref_uV && data->ext_ref_ohms) + return dev_err_probe(dev, -EINVAL, + "ti,refp-refn-resistor-ohms property should not be present when refp-supply or refn-supply is present\n"); + + if (need_ext_ref && !data->ext_ref_uV && !data->ext_ref_ohms) + return dev_err_probe(dev, -EINVAL, + "external reference measurements require either refp-supply or ti,refp-refn-resistor-ohms property\n"); + + /* It takes some time for the internal reference to stabilize. */ + fsleep(10 * USEC_PER_MSEC); + + data->regmap = devm_regmap_init_i2c(client, &ads112c14_regmap_config); + if (IS_ERR(data->regmap)) + return dev_err_probe(dev, PTR_ERR(data->regmap), + "failed to init regmap\n"); + + /* + * Write magic reset value (0x16) to ensure known state. The reset may + * cause an error because of failing to get the I2C ACK at the end of + * the message. The device still gets reset so it is safe to ignore the + * return value here. If something else is wrong, later read/write will + * likely have the same error. + */ + regmap_write(data->regmap, ADS112C14_REG_CONVERSION_CTRL, + FIELD_PREP(ADS112C14_CONVERSION_CTRL_RESET, 0x16)); + + fsleep(ADS112C14_DELAY_RESET_US); + + ret = regmap_read(data->regmap, ADS112C14_REG_STATUS_MSB, ®_val); + if (ret) + return ret; + + if (FIELD_GET(ADS112C14_STATUS_MSB_RESETN, reg_val)) + return dev_err_probe(dev, -EIO, "reset failed\n"); + + /* Default gain after reset is 1. */ + data->sys_mon_chan_short_gain_val = 1; + + /* + * Clear reset bit to prepare for next probe. And clear AVDD fault since + * that happens on every reset. + */ + ret = regmap_write(data->regmap, ADS112C14_REG_STATUS_MSB, + ADS112C14_STATUS_MSB_RESETN | + ADS112C14_STATUS_MSB_AVDD_UVN); + if (ret) + return ret; + + ret = regmap_read(data->regmap, ADS112C14_REG_DEVICE_ID, ®_val); + if (ret) + return ret; + + if (FIELD_GET(ADS112C14_DEVICE_ID_BITS, reg_val) != info->device_id) + dev_info(dev, "device ID mismatch, expected 0x%X, got 0x%lX\n", + info->device_id, + FIELD_GET(ADS112C14_DEVICE_ID_BITS, reg_val)); + + ret = regmap_update_bits(data->regmap, ADS112C14_REG_DEVICE_CFG, + ADS112C14_DEVICE_CFG_CONV_MODE, + FIELD_PREP(ADS112C14_DEVICE_CFG_CONV_MODE, + ADS112C14_DEVICE_CFG_CONV_MODE_SINGLE_SHOT)); + if (ret) + return ret; + + ads112c14_populate_tables(data); + + indio_dev->name = info->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &ads112c14_info; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct ads112c14_chip_info ads112c14_chip_info = { + .name = "ads112c14", + .device_id = 0xE, + .resolution_bits = 16, +}; + +static const struct ads112c14_chip_info ads122c14_chip_info = { + .name = "ads122c14", + .device_id = 0xF, + .resolution_bits = 24, +}; + +static const struct of_device_id ads112c14_of_match[] = { + { .compatible = "ti,ads112c14", .data = &ads112c14_chip_info }, + { .compatible = "ti,ads122c14", .data = &ads122c14_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, ads112c14_of_match); + +static const struct i2c_device_id ads112c14_id[] = { + { .name = "ads112c14", .driver_data = (kernel_ulong_t)&ads112c14_chip_info }, + { .name = "ads122c14", .driver_data = (kernel_ulong_t)&ads122c14_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ads112c14_id); + +static struct i2c_driver ads112c14_driver = { + .driver = { + .name = "ads112c14", + .of_match_table = ads112c14_of_match, + }, + .probe = ads112c14_probe, + .id_table = ads112c14_id, +}; +module_i2c_driver(ads112c14_driver); + +MODULE_AUTHOR("David Lechner (TI) <dlechner@baylibre.com>"); +MODULE_DESCRIPTION("TI ADS112C14 I2C ADC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/adc/ti-ads124s08.c b/drivers/iio/adc/ti-ads124s08.c index 45de47778809..49fbc63508ac 100644 --- a/drivers/iio/adc/ti-ads124s08.c +++ b/drivers/iio/adc/ti-ads124s08.c @@ -348,8 +348,8 @@ static int ads124s_probe(struct spi_device *spi) } static const struct spi_device_id ads124s_id[] = { - { "ads124s06", ADS124S06_ID }, - { "ads124s08", ADS124S08_ID }, + { .name = "ads124s06", .driver_data = ADS124S06_ID }, + { .name = "ads124s08", .driver_data = ADS124S08_ID }, { } }; MODULE_DEVICE_TABLE(spi, ads124s_id); diff --git a/drivers/iio/adc/ti-ads1298.c b/drivers/iio/adc/ti-ads1298.c index 9e47ace16acd..06c6353aa1b2 100644 --- a/drivers/iio/adc/ti-ads1298.c +++ b/drivers/iio/adc/ti-ads1298.c @@ -743,7 +743,7 @@ static int ads1298_probe(struct spi_device *spi) } static const struct spi_device_id ads1298_id[] = { - { "ads1298" }, + { .name = "ads1298" }, { } }; MODULE_DEVICE_TABLE(spi, ads1298_id); diff --git a/drivers/iio/adc/ti-ads131e08.c b/drivers/iio/adc/ti-ads131e08.c index a585621b0bc3..1d25f887cadb 100644 --- a/drivers/iio/adc/ti-ads131e08.c +++ b/drivers/iio/adc/ti-ads131e08.c @@ -917,9 +917,9 @@ static const struct of_device_id ads131e08_of_match[] = { MODULE_DEVICE_TABLE(of, ads131e08_of_match); static const struct spi_device_id ads131e08_ids[] = { - { "ads131e04", (kernel_ulong_t)&ads131e08_info_tbl[ads131e04] }, - { "ads131e06", (kernel_ulong_t)&ads131e08_info_tbl[ads131e06] }, - { "ads131e08", (kernel_ulong_t)&ads131e08_info_tbl[ads131e08] }, + { .name = "ads131e04", .driver_data = (kernel_ulong_t)&ads131e08_info_tbl[ads131e04] }, + { .name = "ads131e06", .driver_data = (kernel_ulong_t)&ads131e08_info_tbl[ads131e06] }, + { .name = "ads131e08", .driver_data = (kernel_ulong_t)&ads131e08_info_tbl[ads131e08] }, { } }; MODULE_DEVICE_TABLE(spi, ads131e08_ids); diff --git a/drivers/iio/adc/ti-ads131m02.c b/drivers/iio/adc/ti-ads131m02.c index 36203ce37c89..2f8f75c8216b 100644 --- a/drivers/iio/adc/ti-ads131m02.c +++ b/drivers/iio/adc/ti-ads131m02.c @@ -943,11 +943,11 @@ static const struct of_device_id ads131m_of_match[] = { MODULE_DEVICE_TABLE(of, ads131m_of_match); static const struct spi_device_id ads131m_id[] = { - { "ads131m02", (kernel_ulong_t)&ads131m02_config }, - { "ads131m03", (kernel_ulong_t)&ads131m03_config }, - { "ads131m04", (kernel_ulong_t)&ads131m04_config }, - { "ads131m06", (kernel_ulong_t)&ads131m06_config }, - { "ads131m08", (kernel_ulong_t)&ads131m08_config }, + { .name = "ads131m02", .driver_data = (kernel_ulong_t)&ads131m02_config }, + { .name = "ads131m03", .driver_data = (kernel_ulong_t)&ads131m03_config }, + { .name = "ads131m04", .driver_data = (kernel_ulong_t)&ads131m04_config }, + { .name = "ads131m06", .driver_data = (kernel_ulong_t)&ads131m06_config }, + { .name = "ads131m08", .driver_data = (kernel_ulong_t)&ads131m08_config }, { } }; MODULE_DEVICE_TABLE(spi, ads131m_id); diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c index 39a074bce6d5..d27c1f2885fd 100644 --- a/drivers/iio/adc/ti-ads7950.c +++ b/drivers/iio/adc/ti-ads7950.c @@ -619,18 +619,18 @@ static int ti_ads7950_probe(struct spi_device *spi) } static const struct spi_device_id ti_ads7950_id[] = { - { "ads7950", (kernel_ulong_t)&ti_ads7950_chip_info }, - { "ads7951", (kernel_ulong_t)&ti_ads7951_chip_info }, - { "ads7952", (kernel_ulong_t)&ti_ads7952_chip_info }, - { "ads7953", (kernel_ulong_t)&ti_ads7953_chip_info }, - { "ads7954", (kernel_ulong_t)&ti_ads7954_chip_info }, - { "ads7955", (kernel_ulong_t)&ti_ads7955_chip_info }, - { "ads7956", (kernel_ulong_t)&ti_ads7956_chip_info }, - { "ads7957", (kernel_ulong_t)&ti_ads7957_chip_info }, - { "ads7958", (kernel_ulong_t)&ti_ads7958_chip_info }, - { "ads7959", (kernel_ulong_t)&ti_ads7959_chip_info }, - { "ads7960", (kernel_ulong_t)&ti_ads7960_chip_info }, - { "ads7961", (kernel_ulong_t)&ti_ads7961_chip_info }, + { .name = "ads7950", .driver_data = (kernel_ulong_t)&ti_ads7950_chip_info }, + { .name = "ads7951", .driver_data = (kernel_ulong_t)&ti_ads7951_chip_info }, + { .name = "ads7952", .driver_data = (kernel_ulong_t)&ti_ads7952_chip_info }, + { .name = "ads7953", .driver_data = (kernel_ulong_t)&ti_ads7953_chip_info }, + { .name = "ads7954", .driver_data = (kernel_ulong_t)&ti_ads7954_chip_info }, + { .name = "ads7955", .driver_data = (kernel_ulong_t)&ti_ads7955_chip_info }, + { .name = "ads7956", .driver_data = (kernel_ulong_t)&ti_ads7956_chip_info }, + { .name = "ads7957", .driver_data = (kernel_ulong_t)&ti_ads7957_chip_info }, + { .name = "ads7958", .driver_data = (kernel_ulong_t)&ti_ads7958_chip_info }, + { .name = "ads7959", .driver_data = (kernel_ulong_t)&ti_ads7959_chip_info }, + { .name = "ads7960", .driver_data = (kernel_ulong_t)&ti_ads7960_chip_info }, + { .name = "ads7961", .driver_data = (kernel_ulong_t)&ti_ads7961_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ti_ads7950_id); diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c index ba5e240aa41a..8ad070b5ec4c 100644 --- a/drivers/iio/adc/ti-ads8688.c +++ b/drivers/iio/adc/ti-ads8688.c @@ -453,8 +453,8 @@ static int ads8688_probe(struct spi_device *spi) } static const struct spi_device_id ads8688_id[] = { - { "ads8684", ID_ADS8684 }, - { "ads8688", ID_ADS8688 }, + { .name = "ads8684", .driver_data = ID_ADS8684 }, + { .name = "ads8688", .driver_data = ID_ADS8688 }, { } }; MODULE_DEVICE_TABLE(spi, ads8688_id); diff --git a/drivers/iio/adc/ti-lmp92064.c b/drivers/iio/adc/ti-lmp92064.c index 7e57006a8a12..d248bbea0d31 100644 --- a/drivers/iio/adc/ti-lmp92064.c +++ b/drivers/iio/adc/ti-lmp92064.c @@ -357,7 +357,7 @@ static int lmp92064_adc_probe(struct spi_device *spi) } static const struct spi_device_id lmp92064_id_table[] = { - { "lmp92064" }, + { .name = "lmp92064" }, { } }; MODULE_DEVICE_TABLE(spi, lmp92064_id_table); diff --git a/drivers/iio/adc/ti-tlc4541.c b/drivers/iio/adc/ti-tlc4541.c index 94bbf5afe30e..ea776f80de72 100644 --- a/drivers/iio/adc/ti-tlc4541.c +++ b/drivers/iio/adc/ti-tlc4541.c @@ -240,8 +240,8 @@ static const struct of_device_id tlc4541_dt_ids[] = { MODULE_DEVICE_TABLE(of, tlc4541_dt_ids); static const struct spi_device_id tlc4541_id[] = { - { "tlc3541", TLC3541 }, - { "tlc4541", TLC4541 }, + { .name = "tlc3541", .driver_data = TLC3541 }, + { .name = "tlc4541", .driver_data = TLC4541 }, { } }; MODULE_DEVICE_TABLE(spi, tlc4541_id); diff --git a/drivers/iio/adc/ti-tsc2046.c b/drivers/iio/adc/ti-tsc2046.c index aba4b10a17ac..125f6d7e2d84 100644 --- a/drivers/iio/adc/ti-tsc2046.c +++ b/drivers/iio/adc/ti-tsc2046.c @@ -121,11 +121,6 @@ struct tsc2046_adc_group_layout { unsigned int skip; }; -struct tsc2046_adc_dcfg { - const struct iio_chan_spec *channels; - unsigned int num_channels; -}; - struct tsc2046_adc_ch_cfg { unsigned int settling_time_us; unsigned int oversampling_ratio; @@ -141,7 +136,6 @@ enum tsc2046_state { struct tsc2046_adc_priv { struct spi_device *spi; - const struct tsc2046_adc_dcfg *dcfg; bool internal_vref; struct iio_trigger *trig; @@ -214,11 +208,6 @@ const struct iio_chan_spec name ## _channels[] = { \ static DECLARE_TI_TSC2046_8_CHANNELS(tsc2046_adc, 12); -static const struct tsc2046_adc_dcfg tsc2046_adc_dcfg_tsc2046e = { - .channels = tsc2046_adc_channels, - .num_channels = ARRAY_SIZE(tsc2046_adc_channels), -}; - /* * Convert time to a number of samples which can be transferred within this * time. @@ -739,7 +728,6 @@ static void tsc2046_adc_parse_fwnode(struct tsc2046_adc_priv *priv) static int tsc2046_adc_probe(struct spi_device *spi) { - const struct tsc2046_adc_dcfg *dcfg; struct device *dev = &spi->dev; struct tsc2046_adc_priv *priv; struct iio_dev *indio_dev; @@ -752,10 +740,6 @@ static int tsc2046_adc_probe(struct spi_device *spi) return -EINVAL; } - dcfg = spi_get_device_match_data(spi); - if (!dcfg) - return -EINVAL; - spi->mode &= ~SPI_MODE_X_MASK; spi->mode |= SPI_MODE_0; ret = spi_setup(spi); @@ -767,14 +751,13 @@ static int tsc2046_adc_probe(struct spi_device *spi) return -ENOMEM; priv = iio_priv(indio_dev); - priv->dcfg = dcfg; priv->spi = spi; indio_dev->name = TI_TSC2046_NAME; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = dcfg->channels; - indio_dev->num_channels = dcfg->num_channels; + indio_dev->channels = tsc2046_adc_channels; + indio_dev->num_channels = ARRAY_SIZE(tsc2046_adc_channels); indio_dev->info = &tsc2046_adc_info; ret = devm_regulator_get_enable_read_voltage(dev, "vref"); @@ -829,13 +812,13 @@ static int tsc2046_adc_probe(struct spi_device *spi) } static const struct of_device_id ads7950_of_table[] = { - { .compatible = "ti,tsc2046e-adc", .data = &tsc2046_adc_dcfg_tsc2046e }, + { .compatible = "ti,tsc2046e-adc" }, { } }; MODULE_DEVICE_TABLE(of, ads7950_of_table); static const struct spi_device_id tsc2046_adc_spi_ids[] = { - { "tsc2046e-adc", (unsigned long)&tsc2046_adc_dcfg_tsc2046e }, + { .name = "tsc2046e-adc" }, { } }; MODULE_DEVICE_TABLE(spi, tsc2046_adc_spi_ids); diff --git a/drivers/iio/adc/versal-sysmon-core.c b/drivers/iio/adc/versal-sysmon-core.c new file mode 100644 index 000000000000..1b55d343982e --- /dev/null +++ b/drivers/iio/adc/versal-sysmon-core.c @@ -0,0 +1,1052 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AMD Versal SysMon core driver + * + * Copyright (C) 2019 - 2022, Xilinx, Inc. + * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc. + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/cleanup.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/limits.h> +#include <linux/minmax.h> +#include <linux/module.h> +#include <linux/overflow.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/string.h> +#include <linux/sysfs.h> +#include <linux/units.h> + +#include <linux/iio/events.h> +#include <linux/iio/iio.h> + +#include "versal-sysmon.h" + +/* + * Oversampling ratio values exposed to userspace via IIO. + * Actual number of samples averaged: 1=none, 2=2x, 4=4x, 8=8x, 16=16x. + */ +static const int sysmon_oversampling_avail[] = { 1, 2, 4, 8, 16 }; + +/* TEMP hysteresis mode bit in SYSMON_TEMP_EV_CFG */ +#define SYSMON_TEMP_HYST_MASK BIT(1) + +/* Compute alarm register offset from a channel address */ +#define SYSMON_ALARM_OFFSET(addr) \ + (SYSMON_ALARM_REG + ((addr) / SYSMON_ALARM_BITS_PER_REG) * SYSMON_REG_STRIDE) + +#define SYSMON_CHAN_TEMP(_chan, _address, _name) \ +{ \ + .type = IIO_TEMP, \ + .indexed = 1, \ + .address = _address, \ + .channel = _chan, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .datasheet_name = _name, \ +} + +enum sysmon_alarm_bit { + SYSMON_BIT_ALARM0 = 0, + SYSMON_BIT_ALARM1 = 1, + SYSMON_BIT_ALARM2 = 2, + SYSMON_BIT_ALARM3 = 3, + SYSMON_BIT_ALARM4 = 4, + SYSMON_BIT_TEMP = 9, +}; + +/* Temperature event specification: rising threshold + hysteresis only */ +static const struct iio_event_spec sysmon_temp_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_HYSTERESIS), + }, +}; + +/* Supply event specifications */ +static const struct iio_event_spec sysmon_supply_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_EITHER, + .mask_separate = BIT(IIO_EV_INFO_ENABLE), + }, +}; + +/* + * Static temperature channels (always present). + * + * These are hardware-computed aggregate registers across all active + * temperature satellites: + * temp: current max temperature across all active satellites + * min: current min temperature across all active satellites + * max_max: highest peak recorded since last hardware reset + * min_min: lowest trough recorded since last hardware reset + */ +static const struct iio_chan_spec temp_channels[] = { + SYSMON_CHAN_TEMP(0, SYSMON_TEMP_MAX, "temp"), + SYSMON_CHAN_TEMP(1, SYSMON_TEMP_MIN, "min"), + SYSMON_CHAN_TEMP(2, SYSMON_TEMP_MAX_MAX, "max_max"), + SYSMON_CHAN_TEMP(3, SYSMON_TEMP_MIN_MIN, "min_min"), +}; + +static void sysmon_q8p7_to_millicelsius(s16 raw_data, int *val) +{ + *val = (raw_data * MILLIDEGREE_PER_DEGREE) >> SYSMON_FRACTIONAL_SHIFT; +} + +static void sysmon_millicelsius_to_q8p7(u32 *raw_data, int val) +{ + *raw_data = (val << SYSMON_FRACTIONAL_SHIFT) / MILLIDEGREE_PER_DEGREE; +} + +static void sysmon_supply_rawtoprocessed(int raw_data, int *val) +{ + int mantissa, format, exponent; + + mantissa = FIELD_GET(SYSMON_MANTISSA_MASK, raw_data); + exponent = SYSMON_SUPPLY_MANTISSA_BITS - FIELD_GET(SYSMON_MODE_MASK, raw_data); + format = FIELD_GET(SYSMON_FMT_MASK, raw_data); + /* + * When format bit is set the mantissa is two's complement + * (per hardware spec); sign-extend to int for correct arithmetic. + */ + if (format) + mantissa = sign_extend32(mantissa, 15); + + *val = (mantissa * (int)MILLI) >> exponent; +} + +static void sysmon_supply_processedtoraw(int val, u32 reg_val, u32 *raw_data) +{ + int exponent = FIELD_GET(SYSMON_MODE_MASK, reg_val); + int format = FIELD_GET(SYSMON_FMT_MASK, reg_val); + int scale, tmp; + + scale = BIT(SYSMON_SUPPLY_MANTISSA_BITS - exponent); + tmp = (val * scale) / (int)MILLI; + + if (format) + tmp = clamp(tmp, S16_MIN, S16_MAX); + else + tmp = clamp(tmp, 0, U16_MAX); + + *raw_data = (u16)tmp; +} + +static int sysmon_supply_thresh_offset(unsigned long address, enum iio_event_direction dir) +{ + if (dir == IIO_EV_DIR_RISING) + return (address * SYSMON_REG_STRIDE) + SYSMON_SUPPLY_TH_UP; + if (dir == IIO_EV_DIR_FALLING) + return (address * SYSMON_REG_STRIDE) + SYSMON_SUPPLY_TH_LOW; + + return -EINVAL; +} + +static int sysmon_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct sysmon *sysmon = iio_priv(indio_dev); + unsigned int regval; + int ret; + + guard(mutex)(&sysmon->lock); + + if (mask == IIO_CHAN_INFO_OVERSAMPLING_RATIO) { + *val = (chan->type == IIO_TEMP) ? sysmon->temp_oversampling : + sysmon->supply_oversampling; + return IIO_VAL_INT; + } + + switch (chan->type) { + case IIO_TEMP: + if (mask == IIO_CHAN_INFO_SCALE) { + /* Q8.7 to millicelsius: raw * 1000 / 128 */ + *val = MILLIDEGREE_PER_DEGREE; + *val2 = BIT(SYSMON_FRACTIONAL_SHIFT); + return IIO_VAL_FRACTIONAL; + } + if (mask != IIO_CHAN_INFO_RAW) + return -EINVAL; + + ret = regmap_read(sysmon->regmap, chan->address, ®val); + if (ret) + return ret; + + *val = sign_extend32(regval, 15); + return IIO_VAL_INT; + + case IIO_VOLTAGE: + if (mask != IIO_CHAN_INFO_PROCESSED) + return -EINVAL; + + ret = regmap_read(sysmon->regmap, + chan->address * SYSMON_REG_STRIDE + + SYSMON_SUPPLY_BASE, ®val); + if (ret) + return ret; + + sysmon_supply_rawtoprocessed(regval, val); + return IIO_VAL_INT; + + default: + return -EINVAL; + } +} + +static u32 sysmon_get_event_mask(const struct iio_chan_spec *chan) +{ + if (chan->type == IIO_TEMP) + return BIT(SYSMON_BIT_TEMP); + + return BIT(chan->address / SYSMON_ALARM_BITS_PER_REG); +} + +static int sysmon_read_alarm_config(struct sysmon *sysmon, + unsigned long address) +{ + u32 shift = address % SYSMON_ALARM_BITS_PER_REG; + u32 offset = SYSMON_ALARM_OFFSET(address); + + return regmap_test_bits(sysmon->regmap, offset, BIT(shift)); +} + +static int sysmon_write_alarm_config(struct sysmon *sysmon, + unsigned long address, bool enable) +{ + u32 shift = address % SYSMON_ALARM_BITS_PER_REG; + u32 offset = SYSMON_ALARM_OFFSET(address); + + return regmap_assign_bits(sysmon->regmap, offset, BIT(shift), enable); +} + +static int sysmon_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct sysmon *sysmon = iio_priv(indio_dev); + u32 mask = sysmon_get_event_mask(chan); + unsigned int imr; + int config_value; + int ret; + + ret = regmap_read(sysmon->regmap, SYSMON_IMR, &imr); + if (ret) + return ret; + + /* IMR bits are 1=masked, invert to get 1=enabled */ + imr = ~imr; + + switch (chan->type) { + case IIO_VOLTAGE: + config_value = sysmon_read_alarm_config(sysmon, chan->address); + if (config_value < 0) + return config_value; + return config_value && (imr & mask); + + case IIO_TEMP: + /* + * Return the administrative state, not the hardware IMR. + * The IRQ handler temporarily masks the interrupt during + * the polling window; reading IMR would show it as disabled. + * temp_mask bit is set when administratively disabled. + */ + return !(sysmon->temp_mask & mask); + + default: + return -EINVAL; + } +} + +static int sysmon_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + bool state) +{ + u32 offset = SYSMON_ALARM_OFFSET(chan->address); + struct sysmon *sysmon = iio_priv(indio_dev); + u32 mask = sysmon_get_event_mask(chan); + unsigned int alarm_config; + int ret; + + guard(mutex)(&sysmon->lock); + + switch (chan->type) { + case IIO_VOLTAGE: + ret = sysmon_write_alarm_config(sysmon, chan->address, state); + if (ret) + return ret; + + ret = regmap_read(sysmon->regmap, offset, &alarm_config); + if (ret) + return ret; + + if (alarm_config) + return regmap_write(sysmon->regmap, SYSMON_IER, mask); + + return regmap_write(sysmon->regmap, SYSMON_IDR, mask); + + case IIO_TEMP: + if (state) { + ret = regmap_write(sysmon->regmap, SYSMON_IER, mask); + if (ret) + return ret; + + scoped_guard(spinlock_irq, &sysmon->irq_lock) + sysmon->temp_mask &= ~mask; + } else { + ret = regmap_write(sysmon->regmap, SYSMON_IDR, mask); + if (ret) + return ret; + + scoped_guard(spinlock_irq, &sysmon->irq_lock) + sysmon->temp_mask |= mask; + } + return 0; + + default: + return -EINVAL; + } +} + +/* + * Recompute the lower threshold register from upper threshold and + * cached hysteresis. Called when either upper threshold or hysteresis + * is written. + */ +static int sysmon_update_temp_lower(struct sysmon *sysmon) +{ + unsigned int upper_reg; + int upper_mc, lower_mc; + u32 raw_val; + int ret; + + ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_UP, &upper_reg); + if (ret) + return ret; + + sysmon_q8p7_to_millicelsius(upper_reg, &upper_mc); + lower_mc = clamp(upper_mc - sysmon->temp_hysteresis, -256000, 255992); + sysmon_millicelsius_to_q8p7(&raw_val, lower_mc); + + return regmap_write(sysmon->regmap, SYSMON_TEMP_TH_LOW, raw_val); +} + +static int sysmon_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct sysmon *sysmon = iio_priv(indio_dev); + unsigned int reg_val; + int offset; + int ret; + + guard(mutex)(&sysmon->lock); + + switch (chan->type) { + case IIO_TEMP: + switch (info) { + case IIO_EV_INFO_VALUE: + ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_UP, ®_val); + if (ret) + return ret; + + sysmon_q8p7_to_millicelsius(reg_val, val); + + return IIO_VAL_INT; + + case IIO_EV_INFO_HYSTERESIS: + *val = sysmon->temp_hysteresis; + return IIO_VAL_INT; + + default: + return -EINVAL; + } + + case IIO_VOLTAGE: + offset = sysmon_supply_thresh_offset(chan->address, dir); + if (offset < 0) + return offset; + + ret = regmap_read(sysmon->regmap, offset, ®_val); + if (ret) + return ret; + + sysmon_supply_rawtoprocessed(reg_val, val); + + return IIO_VAL_INT; + + default: + return -EINVAL; + } +} + +static int sysmon_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct sysmon *sysmon = iio_priv(indio_dev); + unsigned int reg_val; + u32 raw_val; + int offset; + int ret; + + guard(mutex)(&sysmon->lock); + + switch (chan->type) { + case IIO_TEMP: + switch (info) { + case IIO_EV_INFO_VALUE: + /* Q8.7 signed range: -256000 to +255992 mC */ + if (val < -256000 || val > 255992) + return -EINVAL; + + sysmon_millicelsius_to_q8p7(&raw_val, val); + + ret = regmap_write(sysmon->regmap, SYSMON_TEMP_TH_UP, raw_val); + if (ret) + return ret; + + /* Recompute lower = upper - hysteresis */ + return sysmon_update_temp_lower(sysmon); + + case IIO_EV_INFO_HYSTERESIS: + if (val < 0) + return -EINVAL; + + sysmon->temp_hysteresis = val; + + return sysmon_update_temp_lower(sysmon); + + default: + return -EINVAL; + } + + case IIO_VOLTAGE: + offset = sysmon_supply_thresh_offset(chan->address, dir); + if (offset < 0) + return offset; + + ret = regmap_read(sysmon->regmap, offset, ®_val); + if (ret) + return ret; + + /* Clamp to prevent overflow in processedtoraw conversion */ + if (val < -32768 || val > 32767) + return -EINVAL; + + sysmon_supply_processedtoraw(val, reg_val, &raw_val); + + /* + * The hardware threshold register returns FMT and MODE + * bits in the upper 16 bits on read, but only the lower + * 16-bit mantissa is used on write. + */ + return regmap_write(sysmon->regmap, offset, raw_val); + + default: + return -EINVAL; + } +} + +static int sysmon_set_avg_enable(struct sysmon *sysmon, + u32 base, u32 count, u32 val) +{ + struct regmap *map = sysmon->regmap; + int ret; + + for (unsigned int i = 0; i < count; i++) { + ret = regmap_write(map, base + i * SYSMON_REG_STRIDE, val); + if (ret) + return ret; + } + + return 0; +} + +static int sysmon_osr_write_temp(struct sysmon *sysmon, unsigned int val) +{ + /* + * HW register encoding is sample_count / 2: + * 0=none, 1=2x, 2=4x, 4=8x, 8=16x (not log2-based). + */ + unsigned int hw_val = val >> 1; + unsigned int readback; + int ret; + + ret = regmap_update_bits(sysmon->regmap, SYSMON_CONFIG, + SYSMON_CONFIG_TEMP_SAT_OSR, + FIELD_PREP(SYSMON_CONFIG_TEMP_SAT_OSR, hw_val)); + if (ret) + return ret; + + /* + * Readback fence: the SysMon CONFIG register resides in the + * PMC domain behind the NoC. A posted write may not reach the + * hardware before the next MMIO access. Reading the register + * back forces the interconnect to complete the write, preventing + * a bus hang on the subsequent access. + */ + regmap_read(sysmon->regmap, SYSMON_CONFIG, &readback); + + return sysmon_set_avg_enable(sysmon, SYSMON_TEMP_EN_AVG_BASE, + SYSMON_TEMP_EN_AVG_COUNT, + hw_val ? ~0 : 0); +} + +static int sysmon_osr_write_supply(struct sysmon *sysmon, unsigned int val) +{ + /* HW encoding: sample_count / 2 (see sysmon_osr_write_temp) */ + unsigned int hw_val = val >> 1; + unsigned int readback; + int ret; + + ret = regmap_update_bits(sysmon->regmap, SYSMON_CONFIG, + SYSMON_CONFIG_SUPPLY_OSR, + FIELD_PREP(SYSMON_CONFIG_SUPPLY_OSR, hw_val)); + if (ret) + return ret; + + /* Readback fence -- see sysmon_osr_write_temp for details */ + regmap_read(sysmon->regmap, SYSMON_CONFIG, &readback); + + return sysmon_set_avg_enable(sysmon, SYSMON_SUPPLY_EN_AVG_BASE, + SYSMON_SUPPLY_EN_AVG_COUNT, + hw_val ? ~0 : 0); +} + +static int sysmon_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct sysmon *sysmon = iio_priv(indio_dev); + unsigned int i; + int ret; + + if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(sysmon_oversampling_avail); i++) { + if (val == sysmon_oversampling_avail[i]) + break; + } + if (i == ARRAY_SIZE(sysmon_oversampling_avail)) + return -EINVAL; + + guard(mutex)(&sysmon->lock); + + if (chan->type == IIO_TEMP) { + ret = sysmon_osr_write_temp(sysmon, val); + if (ret) + return ret; + sysmon->temp_oversampling = val; + } else { + ret = sysmon_osr_write_supply(sysmon, val); + if (ret) + return ret; + sysmon->supply_oversampling = val; + } + + return 0; +} + +static int sysmon_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + if (mask == IIO_CHAN_INFO_OVERSAMPLING_RATIO) + return IIO_VAL_INT; + + return -EINVAL; +} + +static int sysmon_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, + int *length, long mask) +{ + if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO) + return -EINVAL; + + *vals = sysmon_oversampling_avail; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(sysmon_oversampling_avail); + + return IIO_AVAIL_LIST; +} + +static int sysmon_read_label(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + char *label) +{ + if (chan->datasheet_name) + return sysfs_emit(label, "%s\n", chan->datasheet_name); + + return -EINVAL; +} + +static const struct iio_info sysmon_iio_info = { + .read_raw = sysmon_read_raw, + .write_raw = sysmon_write_raw, + .write_raw_get_fmt = sysmon_write_raw_get_fmt, + .read_avail = sysmon_read_avail, + .read_label = sysmon_read_label, + .read_event_config = sysmon_read_event_config, + .write_event_config = sysmon_write_event_config, + .read_event_value = sysmon_read_event_value, + .write_event_value = sysmon_write_event_value, +}; + +static void sysmon_push_event(struct iio_dev *indio_dev, u32 address) +{ + const struct iio_chan_spec *chan; + enum iio_event_direction dir; + + for (unsigned int i = 0; i < indio_dev->num_channels; i++) { + if (indio_dev->channels[i].address != address) + continue; + + chan = &indio_dev->channels[i]; + /* Temp uses hysteresis mode (rising only), voltage uses window */ + dir = (chan->type == IIO_TEMP) ? IIO_EV_DIR_RISING : + IIO_EV_DIR_EITHER; + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(chan->type, + chan->channel, + IIO_EV_TYPE_THRESH, + dir), + iio_get_time_ns(indio_dev)); + } +} + +static int sysmon_handle_event(struct iio_dev *indio_dev, u32 event) +{ + u32 alarm_flag_offset = SYSMON_ALARM_FLAG + event * SYSMON_REG_STRIDE; + u32 alarm_reg_offset = SYSMON_ALARM_REG + event * SYSMON_REG_STRIDE; + struct sysmon *sysmon = iio_priv(indio_dev); + unsigned long alarm_flag_reg; + unsigned int reg_val; + u32 address, bit; + int ret; + + switch (event) { + case SYSMON_BIT_TEMP: + sysmon_push_event(indio_dev, SYSMON_TEMP_MAX); + + ret = regmap_write(sysmon->regmap, SYSMON_IDR, BIT(SYSMON_BIT_TEMP)); + if (ret) + return ret; + + sysmon->masked_temp |= BIT(SYSMON_BIT_TEMP); + return 0; + + case SYSMON_BIT_ALARM0: + case SYSMON_BIT_ALARM1: + case SYSMON_BIT_ALARM2: + case SYSMON_BIT_ALARM3: + case SYSMON_BIT_ALARM4: + ret = regmap_read(sysmon->regmap, alarm_flag_offset, ®_val); + if (ret) + return ret; + + alarm_flag_reg = reg_val; + + for_each_set_bit(bit, &alarm_flag_reg, SYSMON_ALARM_BITS_PER_REG) { + address = bit + SYSMON_ALARM_BITS_PER_REG * event; + sysmon_push_event(indio_dev, address); + ret = regmap_clear_bits(sysmon->regmap, alarm_reg_offset, BIT(bit)); + if (ret) + return ret; + } + + return regmap_write(sysmon->regmap, alarm_flag_offset, alarm_flag_reg); + + default: + return -EINVAL; + } +} + +static void sysmon_handle_events(struct iio_dev *indio_dev, + unsigned long events) +{ + unsigned int bit; + + for_each_set_bit(bit, &events, SYSMON_NO_OF_EVENTS) + sysmon_handle_event(indio_dev, bit); +} + +static void sysmon_unmask_temp(struct sysmon *sysmon, unsigned int isr) +{ + unsigned int status; + u32 ier; + + status = isr & SYSMON_TEMP_INTR_MASK; + + ier = ~status & sysmon->masked_temp; + sysmon->masked_temp &= status; + + /* Only unmask if not administratively disabled by userspace */ + ier &= ~sysmon->temp_mask; + + regmap_write(sysmon->regmap, SYSMON_IER, ier); +} + +/* + * Versal threshold interrupts are level-sensitive. Active threshold + * interrupts are masked in the handler and polled via delayed work + * until the condition clears, then unmasked. + */ +static void sysmon_unmask_worker(struct work_struct *work) +{ + struct sysmon *sysmon = + container_of(work, struct sysmon, sysmon_unmask_work.work); + unsigned int isr; + + /* + * If the ISR read fails, skip processing to avoid acting + * on undefined data. + */ + scoped_guard(spinlock_irq, &sysmon->irq_lock) { + if (regmap_read(sysmon->regmap, SYSMON_ISR, &isr)) + break; + regmap_write(sysmon->regmap, SYSMON_ISR, isr); + sysmon_unmask_temp(sysmon, isr); + } + + if (sysmon->masked_temp) + schedule_delayed_work(&sysmon->sysmon_unmask_work, + msecs_to_jiffies(SYSMON_UNMASK_WORK_DELAY_MS)); + else + regmap_write(sysmon->regmap, SYSMON_STATUS_RESET, 1); +} + +static irqreturn_t sysmon_iio_irq(int irq, void *data) +{ + struct iio_dev *indio_dev = data; + struct sysmon *sysmon = iio_priv(indio_dev); + unsigned int isr, imr; + + guard(spinlock)(&sysmon->irq_lock); + + if (regmap_read(sysmon->regmap, SYSMON_ISR, &isr) || + regmap_read(sysmon->regmap, SYSMON_IMR, &imr)) + return IRQ_NONE; + + isr &= ~imr; + if (!isr) + return IRQ_NONE; + + regmap_write(sysmon->regmap, SYSMON_ISR, isr); + + sysmon_handle_events(indio_dev, isr); + schedule_delayed_work(&sysmon->sysmon_unmask_work, + msecs_to_jiffies(SYSMON_UNMASK_WORK_DELAY_MS)); + + return IRQ_HANDLED; +} + +static void sysmon_disable_interrupts(void *data) +{ + struct sysmon *sysmon = data; + + regmap_write(sysmon->regmap, SYSMON_IDR, SYSMON_INTR_ALL_MASK); + + scoped_guard(spinlock_irq, &sysmon->irq_lock) + sysmon->masked_temp = 0; + + cancel_delayed_work_sync(&sysmon->sysmon_unmask_work); +} + +static int sysmon_init_interrupt(struct sysmon *sysmon, + struct device *dev, + struct iio_dev *indio_dev, + int irq) +{ + unsigned int imr; + int ret; + + /* Events not supported without IRQ (e.g. I2C path) */ + if (!irq) + return 0; + + INIT_DELAYED_WORK(&sysmon->sysmon_unmask_work, sysmon_unmask_worker); + + ret = regmap_read(sysmon->regmap, SYSMON_IMR, &imr); + if (ret) + return ret; + sysmon->temp_mask = imr & SYSMON_TEMP_INTR_MASK; + + ret = devm_request_irq(dev, irq, sysmon_iio_irq, 0, "sysmon-irq", indio_dev); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, sysmon_disable_interrupts, sysmon); +} + +/* + * Initialize the cached hysteresis for a temperature channel from the + * current hardware threshold registers: hysteresis = upper - lower. + */ +static int sysmon_init_hysteresis(struct sysmon *sysmon, int *hysteresis) +{ + unsigned int upper_reg, lower_reg; + int upper_mc, lower_mc; + int ret; + + ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_UP, &upper_reg); + if (ret) + return ret; + + ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_LOW, &lower_reg); + if (ret) + return ret; + + sysmon_q8p7_to_millicelsius(upper_reg, &upper_mc); + sysmon_q8p7_to_millicelsius(lower_reg, &lower_mc); + *hysteresis = upper_mc - lower_mc; + + return 0; +} + +/** + * sysmon_parse_fw() - Parse firmware nodes and configure IIO channels. + * @indio_dev: IIO device instance + * @dev: Parent device + * @irq: IRQ number (positive enables event channels, 0 disables) + * + * Reads voltage-channels and temperature-channels container nodes from + * firmware and builds the IIO channel array. Static temperature channels + * and event channels are prepended, followed by supply and satellite + * channels from DT. + * + * Event channels and per-channel event specs are only added when the + * device has an IRQ. I2C devices have no interrupt line, and the I2C + * regmap cannot be called from atomic context, so events are not + * supported on that path. + * + * Return: 0 on success, negative errno on failure. + */ +static int sysmon_parse_fw(struct iio_dev *indio_dev, struct device *dev, int irq) +{ + unsigned int num_chan, num_static, num_supply, num_temp; + unsigned int idx, temp_chan_idx, volt_chan_idx; + struct iio_chan_spec *sysmon_channels; + const char *label; + u32 reg; + int ret; + + struct fwnode_handle *supply_node __free(fwnode_handle) = + device_get_named_child_node(dev, "voltage-channels"); + num_supply = fwnode_get_child_node_count(supply_node); + + struct fwnode_handle *temp_node __free(fwnode_handle) = + device_get_named_child_node(dev, "temperature-channels"); + num_temp = fwnode_get_child_node_count(temp_node); + + num_static = ARRAY_SIZE(temp_channels); + num_chan = size_add(num_temp, size_add(num_static, num_supply)); + sysmon_channels = devm_kcalloc(dev, num_chan, sizeof(*sysmon_channels), GFP_KERNEL); + if (!sysmon_channels) + return -ENOMEM; + + memcpy(sysmon_channels, temp_channels, sizeof(temp_channels)); + + /* Attach event spec to channel 0 when IRQ is available */ + if (irq > 0) { + sysmon_channels[0].event_spec = sysmon_temp_events; + sysmon_channels[0].num_event_specs = ARRAY_SIZE(sysmon_temp_events); + } + + idx = num_static; + + /* Supply channels from DT */ + fwnode_for_each_child_node_scoped(supply_node, child) { + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret) + return dev_err_probe(dev, ret, + "missing reg for supply channel\n"); + + if (reg > SYSMON_SUPPLY_IDX_MAX) + return dev_err_probe(dev, -EINVAL, + "supply reg %u exceeds max %u\n", + reg, SYSMON_SUPPLY_IDX_MAX); + + ret = fwnode_property_read_string(child, "label", &label); + if (ret) + return dev_err_probe(dev, ret, + "missing label for supply channel\n"); + + sysmon_channels[idx++] = (struct iio_chan_spec) { + .type = IIO_VOLTAGE, + .indexed = 1, + .address = reg, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .info_mask_shared_by_type = + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_type_available = + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .event_spec = irq > 0 ? + sysmon_supply_events : NULL, + .num_event_specs = irq > 0 ? + ARRAY_SIZE(sysmon_supply_events) : 0, + .datasheet_name = label, + }; + } + + /* Temperature satellite channels from DT */ + fwnode_for_each_child_node_scoped(temp_node, child) { + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret) + return dev_err_probe(dev, ret, + "missing reg for temp channel\n"); + + if (reg < 1 || reg > SYSMON_TEMP_SAT_MAX) + return dev_err_probe(dev, -EINVAL, + "temp reg %u out of range [1..%u]\n", + reg, SYSMON_TEMP_SAT_MAX); + + ret = fwnode_property_read_string(child, "label", &label); + if (ret) + return dev_err_probe(dev, ret, + "missing label for temp channel\n"); + + sysmon_channels[idx++] = (struct iio_chan_spec) { + .type = IIO_TEMP, + .indexed = 1, + .address = SYSMON_TEMP_SAT_BASE + + (reg - 1) * SYSMON_REG_STRIDE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_type_available = + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .datasheet_name = label, + }; + } + + indio_dev->num_channels = idx; + indio_dev->info = &sysmon_iio_info; + + /* + * Assign per-type sequential channel numbers. + * IIO sysfs uses type prefix (in_tempN, in_voltageN) + * so numbers only need to be unique within each type. + */ + temp_chan_idx = 0; + volt_chan_idx = 0; + for (unsigned int idx = 0; idx < indio_dev->num_channels; idx++) { + if (sysmon_channels[idx].type == IIO_TEMP) + sysmon_channels[idx].channel = temp_chan_idx++; + else + sysmon_channels[idx].channel = volt_chan_idx++; + } + + indio_dev->channels = sysmon_channels; + + return 0; +} + +/** + * devm_versal_sysmon_core_probe() - Initialize Versal SysMon core + * @dev: Parent device + * @regmap: Register map for hardware access + * + * Return: 0 on success, negative errno on failure. + */ +int devm_versal_sysmon_core_probe(struct device *dev, struct regmap *regmap) +{ + struct iio_dev *indio_dev; + struct sysmon *sysmon; + int irq; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*sysmon)); + if (!indio_dev) + return -ENOMEM; + + sysmon = iio_priv(indio_dev); + sysmon->regmap = regmap; + sysmon->temp_oversampling = 1; + sysmon->supply_oversampling = 1; + + ret = devm_mutex_init(dev, &sysmon->lock); + if (ret) + return ret; + spin_lock_init(&sysmon->irq_lock); + + /* Disable all interrupts and clear pending status */ + ret = regmap_write(sysmon->regmap, SYSMON_IDR, SYSMON_INTR_ALL_MASK); + if (ret) + return ret; + ret = regmap_write(sysmon->regmap, SYSMON_ISR, SYSMON_INTR_ALL_MASK); + if (ret) + return ret; + + irq = fwnode_irq_get(dev_fwnode(dev), 0); + if (irq == -EPROBE_DEFER) + return dev_err_probe(dev, irq, "failed to get IRQ\n"); + + indio_dev->name = "versal-sysmon"; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = sysmon_parse_fw(indio_dev, dev, irq); + if (ret) + return ret; + + if (irq > 0) { + /* Set hysteresis mode for temperature threshold */ + ret = regmap_set_bits(sysmon->regmap, SYSMON_TEMP_EV_CFG, + SYSMON_TEMP_HYST_MASK); + if (ret) + return ret; + + /* Initialize cached hysteresis from hardware registers */ + ret = sysmon_init_hysteresis(sysmon, &sysmon->temp_hysteresis); + if (ret) + return ret; + + ret = sysmon_init_interrupt(sysmon, dev, indio_dev, irq); + if (ret) + return ret; + } + + return devm_iio_device_register(dev, indio_dev); +} +EXPORT_SYMBOL_NS_GPL(devm_versal_sysmon_core_probe, "VERSAL_SYSMON"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AMD Versal SysMon Core Driver"); +MODULE_AUTHOR("Salih Erim <salih.erim@amd.com>"); diff --git a/drivers/iio/adc/versal-sysmon-i2c.c b/drivers/iio/adc/versal-sysmon-i2c.c new file mode 100644 index 000000000000..e9a7629159ab --- /dev/null +++ b/drivers/iio/adc/versal-sysmon-i2c.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AMD Versal SysMon I2C driver + * + * Copyright (C) 2023 - 2026, Advanced Micro Devices, Inc. + */ + +#include <linux/bits.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/types.h> +#include <linux/unaligned.h> + +#include "versal-sysmon.h" + +#define SYSMON_I2C_INSTR_READ BIT(2) +#define SYSMON_I2C_INSTR_WRITE BIT(3) + +/* + * I2C command frame layout (8 bytes): + * [0..3] data payload (little-endian u32) + * [4..5] register offset >> 2 (little-endian u16) + * [6] instruction (read/write) + * [7] reserved + */ +#define SYSMON_I2C_DATA_OFS 0 +#define SYSMON_I2C_REG_OFS 4 +#define SYSMON_I2C_INSTR_OFS 6 + +static int sysmon_i2c_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct i2c_client *client = context; + u8 write_buf[8] = { }; + u8 read_buf[4]; + int ret; + + put_unaligned_le16(reg >> 2, &write_buf[SYSMON_I2C_REG_OFS]); + write_buf[SYSMON_I2C_INSTR_OFS] = SYSMON_I2C_INSTR_READ; + + ret = i2c_master_send(client, write_buf, sizeof(write_buf)); + if (ret < 0) + return ret; + if (ret != sizeof(write_buf)) + return -EIO; + + ret = i2c_master_recv(client, read_buf, sizeof(read_buf)); + if (ret < 0) + return ret; + if (ret != sizeof(read_buf)) + return -EIO; + + *val = get_unaligned_le32(read_buf); + + return 0; +} + +static int sysmon_i2c_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + struct i2c_client *client = context; + u8 write_buf[8] = { }; + int ret; + + put_unaligned_le32(val, &write_buf[SYSMON_I2C_DATA_OFS]); + put_unaligned_le16(reg >> 2, &write_buf[SYSMON_I2C_REG_OFS]); + write_buf[SYSMON_I2C_INSTR_OFS] = SYSMON_I2C_INSTR_WRITE; + + ret = i2c_master_send(client, write_buf, sizeof(write_buf)); + if (ret < 0) + return ret; + if (ret != sizeof(write_buf)) + return -EIO; + + return 0; +} + +/* + * Almost all registers are volatile (live ADC readings, interrupt + * status). The rest are not accessed often enough to benefit from + * caching. + */ +static const struct regmap_config sysmon_i2c_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = SYSMON_REG_STRIDE, + .max_register = SYSMON_MAX_REG, + .reg_read = sysmon_i2c_reg_read, + .reg_write = sysmon_i2c_reg_write, +}; + +static int sysmon_i2c_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct regmap *regmap; + + regmap = devm_regmap_init(dev, NULL, client, &sysmon_i2c_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + /* I2C has no IRQ connection; events are not supported */ + return devm_versal_sysmon_core_probe(dev, regmap); +} + +static const struct of_device_id sysmon_i2c_of_match_table[] = { + { .compatible = "xlnx,versal-sysmon" }, + { } +}; +MODULE_DEVICE_TABLE(of, sysmon_i2c_of_match_table); + +static const struct i2c_device_id sysmon_i2c_id_table[] = { + { .name = "versal-sysmon" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sysmon_i2c_id_table); + +static struct i2c_driver sysmon_i2c_driver = { + .probe = sysmon_i2c_probe, + .driver = { + .name = "versal-sysmon-i2c", + .of_match_table = sysmon_i2c_of_match_table, + }, + .id_table = sysmon_i2c_id_table, +}; +module_i2c_driver(sysmon_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AMD Versal SysMon I2C Driver"); +MODULE_IMPORT_NS("VERSAL_SYSMON"); +MODULE_AUTHOR("Conall O'Griofa <conall.ogriofa@amd.com>"); +MODULE_AUTHOR("Salih Erim <salih.erim@amd.com>"); diff --git a/drivers/iio/adc/versal-sysmon.c b/drivers/iio/adc/versal-sysmon.c new file mode 100644 index 000000000000..529d0486c9f9 --- /dev/null +++ b/drivers/iio/adc/versal-sysmon.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AMD Versal SysMon MMIO platform driver + * + * Copyright (C) 2019 - 2022, Xilinx, Inc. + * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc. + */ + +#include <linux/err.h> +#include <linux/io.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/types.h> + +#include "versal-sysmon.h" + +struct sysmon_mmio { + void __iomem *base; +}; + +static int sysmon_mmio_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + struct sysmon_mmio *mmio = context; + + *val = readl(mmio->base + reg); + return 0; +} + +static int sysmon_mmio_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct sysmon_mmio *mmio = context; + + /* NPI must be unlocked before any register write except to NPI_LOCK */ + if (reg != SYSMON_NPI_LOCK) + writel(SYSMON_NPI_UNLOCK_CODE, mmio->base + SYSMON_NPI_LOCK); + writel(val, mmio->base + reg); + + return 0; +} + +static const struct regmap_config sysmon_mmio_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = SYSMON_REG_STRIDE, + .max_register = SYSMON_MAX_REG, + .reg_read = sysmon_mmio_reg_read, + .reg_write = sysmon_mmio_reg_write, + .fast_io = true, +}; + +static int sysmon_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sysmon_mmio *mmio; + struct regmap *regmap; + + mmio = devm_kzalloc(dev, sizeof(*mmio), GFP_KERNEL); + if (!mmio) + return -ENOMEM; + + mmio->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(mmio->base)) + return PTR_ERR(mmio->base); + + regmap = devm_regmap_init(dev, NULL, mmio, &sysmon_mmio_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return devm_versal_sysmon_core_probe(dev, regmap); +} + +static const struct of_device_id sysmon_of_match_table[] = { + { .compatible = "xlnx,versal-sysmon" }, + { } +}; +MODULE_DEVICE_TABLE(of, sysmon_of_match_table); + +static struct platform_driver sysmon_platform_driver = { + .probe = sysmon_platform_probe, + .driver = { + .name = "versal-sysmon", + .of_match_table = sysmon_of_match_table, + }, +}; +module_platform_driver(sysmon_platform_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AMD Versal SysMon Platform Driver"); +MODULE_IMPORT_NS("VERSAL_SYSMON"); +MODULE_AUTHOR("Salih Erim <salih.erim@amd.com>"); diff --git a/drivers/iio/adc/versal-sysmon.h b/drivers/iio/adc/versal-sysmon.h new file mode 100644 index 000000000000..bb9a75bf71c0 --- /dev/null +++ b/drivers/iio/adc/versal-sysmon.h @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * AMD Versal SysMon driver + * + * Copyright (C) 2019 - 2022, Xilinx, Inc. + * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc. + */ + +#ifndef _VERSAL_SYSMON_H_ +#define _VERSAL_SYSMON_H_ + +#include <linux/bits.h> +#include <linux/mutex.h> +#include <linux/spinlock_types.h> +#include <linux/workqueue.h> + +struct device; +struct regmap; + +/* Register offsets (sorted by address) */ +#define SYSMON_NPI_LOCK 0x000C +#define SYSMON_ISR 0x0044 +#define SYSMON_IMR 0x0048 +#define SYSMON_IER 0x004C +#define SYSMON_IDR 0x0050 +#define SYSMON_CONFIG 0x0100 +#define SYSMON_TEMP_MAX 0x1030 +#define SYSMON_TEMP_MIN 0x1034 +#define SYSMON_SUPPLY_BASE 0x1040 +#define SYSMON_ALARM_FLAG 0x1018 +#define SYSMON_ALARM_REG 0x1940 +#define SYSMON_SUPPLY_EN_AVG_BASE 0x1958 +#define SYSMON_TEMP_TH_LOW 0x1970 +#define SYSMON_TEMP_TH_UP 0x1974 +#define SYSMON_SUPPLY_TH_LOW 0x1980 +#define SYSMON_SUPPLY_TH_UP 0x1C80 +#define SYSMON_TEMP_EV_CFG 0x1F84 +#define SYSMON_TEMP_MIN_MIN 0x1F8C +#define SYSMON_TEMP_MAX_MAX 0x1F90 +#define SYSMON_STATUS_RESET 0x1F94 +#define SYSMON_TEMP_SAT_BASE 0x1FAC +#define SYSMON_TEMP_EN_AVG_BASE 0x24B4 +#define SYSMON_MAX_REG 0x24C0 + +/* NPI unlock value written to SYSMON_NPI_LOCK */ +#define SYSMON_NPI_UNLOCK_CODE 0xF9E8D7C6 + +/* Register stride: 4 bytes per 32-bit register */ +#define SYSMON_REG_STRIDE 4 + +#define SYSMON_SUPPLY_IDX_MAX 159 +#define SYSMON_TEMP_SAT_MAX 64 +#define SYSMON_NO_OF_EVENTS 32 +#define SYSMON_INTR_ALL_MASK GENMASK(31, 0) + +/* ISR/IMR temperature alarm mask (bit 9) */ +#define SYSMON_TEMP_INTR_MASK BIT(9) + +/* SYSMON_CONFIG: supply oversampling ratio */ +#define SYSMON_CONFIG_SUPPLY_OSR GENMASK(17, 14) + +/* SYSMON_CONFIG: temperature satellite oversampling ratio */ +#define SYSMON_CONFIG_TEMP_SAT_OSR GENMASK(27, 24) + +/* Per-channel averaging enable register counts */ +#define SYSMON_SUPPLY_EN_AVG_COUNT 5 +#define SYSMON_TEMP_EN_AVG_COUNT 2 + +/* Supply voltage conversion register fields */ +#define SYSMON_MANTISSA_MASK GENMASK(15, 0) +#define SYSMON_FMT_MASK BIT(16) +#define SYSMON_MODE_MASK GENMASK(18, 17) + +/* Q8.7 fractional shift */ +#define SYSMON_FRACTIONAL_SHIFT 7U +#define SYSMON_SUPPLY_MANTISSA_BITS 16 + +/* Bits per alarm register */ +#define SYSMON_ALARM_BITS_PER_REG 32 + +#define SYSMON_UNMASK_WORK_DELAY_MS 500 + +/** + * struct sysmon - Driver data for Versal SysMon + * @regmap: register map for hardware access + * @lock: protects read-modify-write sequences on threshold registers + * and cached state that spans multiple regmap calls + * @irq_lock: protects interrupt mask register updates (MMIO path only) + * @masked_temp: currently masked temperature alarm bits + * @temp_mask: temperature interrupt configuration mask + * @temp_hysteresis: cached DEVICE_TEMP hysteresis in millicelsius + * @sysmon_unmask_work: re-enables events after alarm condition clears + * @temp_oversampling: current temp oversampling ratio + * @supply_oversampling: current supply oversampling ratio + */ +struct sysmon { + struct regmap *regmap; + /* + * Protects read-modify-write sequences on threshold registers + * and cached state (oversampling ratios, hysteresis values) + * that spans multiple regmap calls. + */ + struct mutex lock; + /* + * Protects interrupt mask register updates. Only used on the + * MMIO path (fast_io regmap); I2C has no IRQ and never reaches + * the event code that takes this lock. + */ + spinlock_t irq_lock; + unsigned int masked_temp; + unsigned int temp_mask; + int temp_hysteresis; + struct delayed_work sysmon_unmask_work; + unsigned int temp_oversampling; + unsigned int supply_oversampling; +}; + +int devm_versal_sysmon_core_probe(struct device *dev, struct regmap *regmap); + +#endif /* _VERSAL_SYSMON_H_ */ diff --git a/drivers/iio/addac/ad74115.c b/drivers/iio/addac/ad74115.c index 41e0b1d334cc..9b9d7a12ce87 100644 --- a/drivers/iio/addac/ad74115.c +++ b/drivers/iio/addac/ad74115.c @@ -1904,7 +1904,7 @@ static int __init ad74115_register_driver(struct spi_driver *spi) } static const struct spi_device_id ad74115_spi_id[] = { - { "ad74115h" }, + { .name = "ad74115h" }, { } }; diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c index 654a3a50eb4f..3a6a09ffa526 100644 --- a/drivers/iio/afe/iio-rescale.c +++ b/drivers/iio/afe/iio-rescale.c @@ -608,3 +608,4 @@ module_platform_driver(rescale_driver); MODULE_DESCRIPTION("IIO rescale driver"); MODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/iio/amplifiers/ad8366.c b/drivers/iio/amplifiers/ad8366.c index affc9c9d8488..e12f8604f59f 100644 --- a/drivers/iio/amplifiers/ad8366.c +++ b/drivers/iio/amplifiers/ad8366.c @@ -351,19 +351,19 @@ static int ad8366_probe(struct spi_device *spi) } static const struct spi_device_id ad8366_id[] = { - { "ad8366", (kernel_ulong_t)&ad8366_chip_info }, - { "ada4961", (kernel_ulong_t)&ada4961_chip_info }, - { "adl5240", (kernel_ulong_t)&adl5240_chip_info }, - { "adrf5702", (kernel_ulong_t)&adrf5702_chip_info }, - { "adrf5703", (kernel_ulong_t)&adrf5703_chip_info }, - { "adrf5720", (kernel_ulong_t)&adrf5720_chip_info }, - { "adrf5730", (kernel_ulong_t)&adrf5730_chip_info }, - { "adrf5731", (kernel_ulong_t)&adrf5731_chip_info }, - { "hmc271a", (kernel_ulong_t)&hmc271_chip_info }, - { "hmc792a", (kernel_ulong_t)&hmc792_chip_info }, - { "hmc1018a", (kernel_ulong_t)&hmc1018_chip_info }, - { "hmc1019a", (kernel_ulong_t)&hmc1019_chip_info }, - { "hmc1119", (kernel_ulong_t)&hmc1119_chip_info }, + { .name = "ad8366", .driver_data = (kernel_ulong_t)&ad8366_chip_info }, + { .name = "ada4961", .driver_data = (kernel_ulong_t)&ada4961_chip_info }, + { .name = "adl5240", .driver_data = (kernel_ulong_t)&adl5240_chip_info }, + { .name = "adrf5702", .driver_data = (kernel_ulong_t)&adrf5702_chip_info }, + { .name = "adrf5703", .driver_data = (kernel_ulong_t)&adrf5703_chip_info }, + { .name = "adrf5720", .driver_data = (kernel_ulong_t)&adrf5720_chip_info }, + { .name = "adrf5730", .driver_data = (kernel_ulong_t)&adrf5730_chip_info }, + { .name = "adrf5731", .driver_data = (kernel_ulong_t)&adrf5731_chip_info }, + { .name = "hmc271a", .driver_data = (kernel_ulong_t)&hmc271_chip_info }, + { .name = "hmc792a", .driver_data = (kernel_ulong_t)&hmc792_chip_info }, + { .name = "hmc1018a", .driver_data = (kernel_ulong_t)&hmc1018_chip_info }, + { .name = "hmc1019a", .driver_data = (kernel_ulong_t)&hmc1019_chip_info }, + { .name = "hmc1119", .driver_data = (kernel_ulong_t)&hmc1119_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad8366_id); diff --git a/drivers/iio/amplifiers/ada4250.c b/drivers/iio/amplifiers/ada4250.c index 71e361af2074..9702de3a5074 100644 --- a/drivers/iio/amplifiers/ada4250.c +++ b/drivers/iio/amplifiers/ada4250.c @@ -358,7 +358,7 @@ static int ada4250_probe(struct spi_device *spi) } static const struct spi_device_id ada4250_id[] = { - { "ada4250", 0 }, + { .name = "ada4250" }, { } }; MODULE_DEVICE_TABLE(spi, ada4250_id); diff --git a/drivers/iio/buffer/industrialio-buffer-cb.c b/drivers/iio/buffer/industrialio-buffer-cb.c index 0c266c216525..b58263bcf3cb 100644 --- a/drivers/iio/buffer/industrialio-buffer-cb.c +++ b/drivers/iio/buffer/industrialio-buffer-cb.c @@ -154,3 +154,4 @@ EXPORT_SYMBOL_GPL(iio_channel_cb_get_iio_dev); MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); MODULE_DESCRIPTION("Industrial I/O callback buffer"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index 98acce909854..ecc02a427b92 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -56,6 +56,23 @@ static void iio_dmaengine_buffer_block_done(void *data, iio_dma_buffer_block_done(block); } +/* + * Cyclic transfers run until abort. Cap active cyclic blocks to one until there + * is a use case for more. + */ +static bool iio_dmaengine_buffer_has_active_cyclic(struct dmaengine_buffer *dmaengine_buffer) +{ + struct iio_dma_buffer_block *block; + + guard(spinlock_irqsave)(&dmaengine_buffer->queue.list_lock); + list_for_each_entry(block, &dmaengine_buffer->active, head) { + if (block->cyclic) + return true; + } + + return false; +} + static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, struct iio_dma_buffer_block *block) { @@ -79,7 +96,14 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, else dma_dir = DMA_MEM_TO_DEV; + if (block->cyclic && iio_dmaengine_buffer_has_active_cyclic(dmaengine_buffer)) { + dev_err(queue->dev, "cyclic DMA transfer already active\n"); + return -EBUSY; + } + if (block->sg_table) { + unsigned long flags; + sgl = block->sg_table->sgl; nents = sg_nents_for_len(sgl, block->bytes_used); if (nents < 0) @@ -99,9 +123,19 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, sgl = sg_next(sgl); } + if (block->cyclic) + flags = DMA_PREP_REPEAT; + else + flags = DMA_PREP_INTERRUPT; + + /* + * A new transfer may need to end an already active cyclic transfer + * before it can run, so always set the EOT flag. + */ + flags |= DMA_PREP_LOAD_EOT; desc = dmaengine_prep_peripheral_dma_vec(dmaengine_buffer->chan, vecs, nents, dma_dir, - DMA_PREP_INTERRUPT); + flags); kfree(vecs); } else { max_size = min(block->size, dmaengine_buffer->max_size); @@ -122,8 +156,10 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, if (!desc) return -ENOMEM; - desc->callback_result = iio_dmaengine_buffer_block_done; - desc->callback_param = block; + if (!block->cyclic) { + desc->callback_result = iio_dmaengine_buffer_block_done; + desc->callback_param = block; + } cookie = dmaengine_submit(desc); if (dma_submit_error(cookie)) diff --git a/drivers/iio/buffer/industrialio-hw-consumer.c b/drivers/iio/buffer/industrialio-hw-consumer.c index 10e912bbf0c5..d035aa33b357 100644 --- a/drivers/iio/buffer/industrialio-hw-consumer.c +++ b/drivers/iio/buffer/industrialio-hw-consumer.c @@ -216,3 +216,4 @@ EXPORT_SYMBOL_GPL(iio_hw_consumer_disable); MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); MODULE_DESCRIPTION("Hardware consumer buffer the IIO framework"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/iio/chemical/bme680_spi.c b/drivers/iio/chemical/bme680_spi.c index 785200a6fd65..c55c6c514594 100644 --- a/drivers/iio/chemical/bme680_spi.c +++ b/drivers/iio/chemical/bme680_spi.c @@ -130,7 +130,7 @@ static int bme680_spi_probe(struct spi_device *spi) } static const struct spi_device_id bme680_spi_id[] = { - {"bme680", 0}, + { .name = "bme680" }, { } }; MODULE_DEVICE_TABLE(spi, bme680_spi_id); diff --git a/drivers/iio/chemical/ens160_spi.c b/drivers/iio/chemical/ens160_spi.c index a674c0e1bf4b..7c11d19291c9 100644 --- a/drivers/iio/chemical/ens160_spi.c +++ b/drivers/iio/chemical/ens160_spi.c @@ -39,7 +39,7 @@ static const struct of_device_id ens160_spi_of_match[] = { MODULE_DEVICE_TABLE(of, ens160_spi_of_match); static const struct spi_device_id ens160_spi_id[] = { - { "ens160" }, + { .name = "ens160" }, { } }; MODULE_DEVICE_TABLE(spi, ens160_spi_id); diff --git a/drivers/iio/chemical/scd30_core.c b/drivers/iio/chemical/scd30_core.c index c5425136814b..f85cdd8bd84f 100644 --- a/drivers/iio/chemical/scd30_core.c +++ b/drivers/iio/chemical/scd30_core.c @@ -2,7 +2,7 @@ /* * Sensirion SCD30 carbon dioxide sensor core driver * - * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com> + * Copyright (c) 2020 Tomasz Duszynski <tduszyns@gmail.com> */ #include <linux/bitfield.h> @@ -711,7 +711,11 @@ int scd30_probe(struct device *dev, int irq, const char *name, void *priv, state->pressure_comp = SCD30_PRESSURE_COMP_DEFAULT; state->meas_interval = SCD30_MEAS_INTERVAL_DEFAULT; state->command = command; - mutex_init(&state->lock); + + ret = devm_mutex_init(dev, &state->lock); + if (ret) + return ret; + init_completion(&state->meas_ready); dev_set_drvdata(dev, indio_dev); @@ -770,6 +774,6 @@ int scd30_probe(struct device *dev, int irq, const char *name, void *priv, } EXPORT_SYMBOL_NS(scd30_probe, "IIO_SCD30"); -MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>"); +MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>"); MODULE_DESCRIPTION("Sensirion SCD30 carbon dioxide sensor core driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/chemical/scd30_i2c.c b/drivers/iio/chemical/scd30_i2c.c index abceccdddc71..bcef1e473e34 100644 --- a/drivers/iio/chemical/scd30_i2c.c +++ b/drivers/iio/chemical/scd30_i2c.c @@ -2,7 +2,7 @@ /* * Sensirion SCD30 carbon dioxide sensor i2c driver * - * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com> + * Copyright (c) 2020 Tomasz Duszynski <tduszyns@gmail.com> * * I2C slave address: 0x61 */ @@ -136,7 +136,7 @@ static struct i2c_driver scd30_i2c_driver = { }; module_i2c_driver(scd30_i2c_driver); -MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>"); +MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>"); MODULE_DESCRIPTION("Sensirion SCD30 carbon dioxide sensor i2c driver"); MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS("IIO_SCD30"); diff --git a/drivers/iio/chemical/scd30_serial.c b/drivers/iio/chemical/scd30_serial.c index 7fefdadbfa0a..31b0fc957b08 100644 --- a/drivers/iio/chemical/scd30_serial.c +++ b/drivers/iio/chemical/scd30_serial.c @@ -2,7 +2,7 @@ /* * Sensirion SCD30 carbon dioxide sensor serial driver * - * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com> + * Copyright (c) 2020 Tomasz Duszynski <tduszyns@gmail.com> */ #include <linux/crc16.h> #include <linux/device.h> @@ -257,7 +257,7 @@ static struct serdev_device_driver scd30_serdev_driver = { }; module_serdev_device_driver(scd30_serdev_driver); -MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>"); +MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>"); MODULE_DESCRIPTION("Sensirion SCD30 carbon dioxide sensor serial driver"); MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS("IIO_SCD30"); diff --git a/drivers/iio/chemical/sps30_i2c.c b/drivers/iio/chemical/sps30_i2c.c index 90f1adb8c89f..2d3a876cc06e 100644 --- a/drivers/iio/chemical/sps30_i2c.c +++ b/drivers/iio/chemical/sps30_i2c.c @@ -2,7 +2,7 @@ /* * Sensirion SPS30 particulate matter sensor i2c driver * - * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com> + * Copyright (c) 2020 Tomasz Duszynski <tduszyns@gmail.com> * * I2C slave address: 0x69 */ @@ -252,7 +252,7 @@ static struct i2c_driver sps30_i2c_driver = { }; module_i2c_driver(sps30_i2c_driver); -MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>"); +MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>"); MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor i2c driver"); MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS("IIO_SPS30"); diff --git a/drivers/iio/chemical/sps30_serial.c b/drivers/iio/chemical/sps30_serial.c index 80eab9b2e4bf..0cdba8703e93 100644 --- a/drivers/iio/chemical/sps30_serial.c +++ b/drivers/iio/chemical/sps30_serial.c @@ -2,7 +2,7 @@ /* * Sensirion SPS30 particulate matter sensor serial driver * - * Copyright (c) 2021 Tomasz Duszynski <tomasz.duszynski@octakon.com> + * Copyright (c) 2021 Tomasz Duszynski <tduszyns@gmail.com> */ #include <linux/completion.h> #include <linux/device.h> @@ -425,7 +425,7 @@ static struct serdev_device_driver sps30_serial_driver = { }; module_serdev_device_driver(sps30_serial_driver); -MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>"); +MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>"); MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor serial driver"); MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS("IIO_SPS30"); diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c index c115a72832b2..9e7c26e37880 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -72,8 +72,7 @@ static const struct { {HID_USAGE_SENSOR_HUMAN_ATTENTION, 0, 1, 0}, }; -static void simple_div(int dividend, int divisor, int *whole, - int *micro_frac) +static void simple_div(int dividend, int divisor, int *whole, int *micro_frac) { int rem; int exp = 0; @@ -111,7 +110,7 @@ for 10^-2. Negative numbers are 2's complement */ static void convert_from_vtf_format(u32 value, int size, int exp, - int *val1, int *val2) + int *val1, int *val2) { int sign = 1; @@ -176,7 +175,7 @@ s32 hid_sensor_read_poll_value(struct hid_sensor_common *st) EXPORT_SYMBOL_NS(hid_sensor_read_poll_value, "IIO_HID_ATTRIBUTES"); int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st, - int *val1, int *val2) + int *val1, int *val2) { s32 value; int ret; @@ -203,7 +202,7 @@ int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st, EXPORT_SYMBOL_NS(hid_sensor_read_samp_freq_value, "IIO_HID"); int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st, - int val1, int val2) + int val1, int val2) { s32 value; int ret; @@ -238,15 +237,15 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st, EXPORT_SYMBOL_NS(hid_sensor_write_samp_freq_value, "IIO_HID"); int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st, - int *val1, int *val2) + int *val1, int *val2) { s32 value; int ret; ret = sensor_hub_get_feature(st->hsdev, st->sensitivity.report_id, - st->sensitivity.index, sizeof(value), - &value); + st->sensitivity.index, + sizeof(value), &value); if (ret < 0 || value < 0) { *val1 = *val2 = 0; return -EINVAL; @@ -268,8 +267,8 @@ int hid_sensor_read_raw_hyst_rel_value(struct hid_sensor_common *st, int *val1, ret = sensor_hub_get_feature(st->hsdev, st->sensitivity_rel.report_id, - st->sensitivity_rel.index, sizeof(value), - &value); + st->sensitivity_rel.index, + sizeof(value), &value); if (ret < 0 || value < 0) { *val1 = *val2 = 0; return -EINVAL; @@ -282,9 +281,8 @@ int hid_sensor_read_raw_hyst_rel_value(struct hid_sensor_common *st, int *val1, } EXPORT_SYMBOL_NS(hid_sensor_read_raw_hyst_rel_value, "IIO_HID"); - int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, - int val1, int val2) + int val1, int val2) { s32 value; int ret; @@ -293,8 +291,8 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, return -EINVAL; value = convert_to_vtf_format(st->sensitivity.size, - st->sensitivity.unit_expo, - val1, val2); + st->sensitivity.unit_expo, + val1, val2); ret = sensor_hub_set_feature(st->hsdev, st->sensitivity.report_id, st->sensitivity.index, sizeof(value), &value); @@ -303,8 +301,8 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, ret = sensor_hub_get_feature(st->hsdev, st->sensitivity.report_id, - st->sensitivity.index, sizeof(value), - &value); + st->sensitivity.index, + sizeof(value), &value); if (ret < 0 || value < 0) return -EINVAL; @@ -324,8 +322,8 @@ int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st, return -EINVAL; value = convert_to_vtf_format(st->sensitivity_rel.size, - st->sensitivity_rel.unit_expo, - val1, val2); + st->sensitivity_rel.unit_expo, + val1, val2); ret = sensor_hub_set_feature(st->hsdev, st->sensitivity_rel.report_id, st->sensitivity_rel.index, sizeof(value), &value); @@ -334,8 +332,8 @@ int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st, ret = sensor_hub_get_feature(st->hsdev, st->sensitivity_rel.report_id, - st->sensitivity_rel.index, sizeof(value), - &value); + st->sensitivity_rel.index, + sizeof(value), &value); if (ret < 0 || value < 0) return -EINVAL; @@ -356,8 +354,8 @@ EXPORT_SYMBOL_NS(hid_sensor_write_raw_hyst_rel_value, "IIO_HID"); * 1.001745329 ->exp:4-> val0[10017]val1[453290000] * 9.806650000 ->exp:-2-> val0[0]val1[98066500] */ -static void adjust_exponent_nano(int *val0, int *val1, int scale0, - int scale1, int exp) +static void adjust_exponent_nano(int *val0, int *val1, + int scale0, int scale1, int exp) { int divisor; int i; @@ -404,8 +402,8 @@ static void adjust_exponent_nano(int *val0, int *val1, int scale0, } int hid_sensor_format_scale(u32 usage_id, - struct hid_sensor_hub_attribute_info *attr_info, - int *val0, int *val1) + struct hid_sensor_hub_attribute_info *attr_info, + int *val0, int *val1) { int i; int exp; @@ -415,12 +413,11 @@ int hid_sensor_format_scale(u32 usage_id, for (i = 0; i < ARRAY_SIZE(unit_conversion); ++i) { if (unit_conversion[i].usage_id == usage_id && - unit_conversion[i].unit == attr_info->units) { - exp = hid_sensor_convert_exponent( - attr_info->unit_expo); + unit_conversion[i].unit == attr_info->units) { + exp = hid_sensor_convert_exponent(attr_info->unit_expo); adjust_exponent_nano(val0, val1, - unit_conversion[i].scale_val0, - unit_conversion[i].scale_val1, exp); + unit_conversion[i].scale_val0, + unit_conversion[i].scale_val1, exp); break; } } @@ -438,8 +435,8 @@ EXPORT_SYMBOL_NS(hid_sensor_convert_timestamp, "IIO_HID"); static int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev, - u32 usage_id, - struct hid_sensor_common *st) + u32 usage_id, + struct hid_sensor_common *st) { sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, usage_id, @@ -473,9 +470,10 @@ int hid_sensor_get_report_latency(struct hid_sensor_common *st) int ret; int value; - ret = sensor_hub_get_feature(st->hsdev, st->report_latency.report_id, - st->report_latency.index, sizeof(value), - &value); + ret = sensor_hub_get_feature(st->hsdev, + st->report_latency.report_id, + st->report_latency.index, + sizeof(value), &value); if (ret < 0) return ret; @@ -498,10 +496,10 @@ bool hid_sensor_batch_mode_supported(struct hid_sensor_common *st) EXPORT_SYMBOL_NS(hid_sensor_batch_mode_supported, "IIO_HID_ATTRIBUTES"); int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, - u32 usage_id, - struct hid_sensor_common *st, - const u32 *sensitivity_addresses, - u32 sensitivity_addresses_len) + u32 usage_id, + struct hid_sensor_common *st, + const u32 *sensitivity_addresses, + u32 sensitivity_addresses_len) { struct hid_sensor_hub_attribute_info timestamp; @@ -527,7 +525,7 @@ int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, usage_id, HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS, - &st->sensitivity); + &st->sensitivity); sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, usage_id, @@ -578,8 +576,9 @@ int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, timestamp.index, timestamp.report_id); ret = sensor_hub_get_feature(hsdev, - st->power_state.report_id, - st->power_state.index, sizeof(value), &value); + st->power_state.report_id, + st->power_state.index, + sizeof(value), &value); if (ret < 0) return ret; if (value < 0) diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index 417c4ab8c1b2..60808e2430ca 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -233,7 +233,7 @@ void hid_sensor_remove_trigger(struct iio_dev *indio_dev, EXPORT_SYMBOL_NS(hid_sensor_remove_trigger, "IIO_HID"); int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, - struct hid_sensor_common *attrb) + struct hid_sensor_common *attrb) { const struct iio_dev_attr **fifo_attrs; int ret; @@ -266,7 +266,7 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, trig = iio_trigger_alloc(indio_dev->dev.parent, "%s-dev%d", name, iio_device_id(indio_dev)); - if (trig == NULL) { + if (!trig) { dev_err(&indio_dev->dev, "Trigger Allocate Failed\n"); return -ENOMEM; } @@ -314,7 +314,9 @@ static int __maybe_unused hid_sensor_resume(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev); + schedule_work(&attrb->work); + return 0; } @@ -322,6 +324,7 @@ static int __maybe_unused hid_sensor_runtime_resume(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev); + return _hid_sensor_power_state(attrb, true); } diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h index f94fca4f1edf..589de858e369 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h @@ -15,7 +15,7 @@ struct iio_dev; extern const struct dev_pm_ops hid_sensor_pm_ops; int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, - struct hid_sensor_common *attrb); + struct hid_sensor_common *attrb); void hid_sensor_remove_trigger(struct iio_dev *indio_dev, struct hid_sensor_common *attrb); int hid_sensor_power_state(struct hid_sensor_common *st, bool state); diff --git a/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c b/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c index e0b10366ed2b..88a82d1370c5 100644 --- a/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c +++ b/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c @@ -10,18 +10,19 @@ #include <linux/iio/common/inv_sensors_timestamp.h> -/* compute jitter, min and max following jitter in per mille */ -#define INV_SENSORS_TIMESTAMP_JITTER(_val, _jitter) \ - (div_s64((_val) * (_jitter), 1000)) +/* compute min and max following jitter in per mille */ #define INV_SENSORS_TIMESTAMP_MIN(_val, _jitter) \ (((_val) * (1000 - (_jitter))) / 1000) #define INV_SENSORS_TIMESTAMP_MAX(_val, _jitter) \ (((_val) * (1000 + (_jitter))) / 1000) +/* minimum timestamp delta between 2 interrupts for measuring period (20ms) */ +#define INV_SENSORS_MIN_IT_DELTA (20 * NSEC_PER_MSEC) + /* Add a new value inside an accumulator and update the estimate value */ -static void inv_update_acc(struct inv_sensors_timestamp_acc *acc, uint32_t val) +static void inv_update_acc(struct inv_sensors_timestamp_acc *acc, u32 val) { - uint64_t sum = 0; + u64 sum = 0; size_t i; acc->values[acc->idx++] = val; @@ -58,9 +59,9 @@ void inv_sensors_timestamp_init(struct inv_sensors_timestamp *ts, EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_init, "IIO_INV_SENSORS_TIMESTAMP"); int inv_sensors_timestamp_update_odr(struct inv_sensors_timestamp *ts, - uint32_t period, bool fifo) + u32 period, bool fifo) { - uint32_t mult; + u32 mult; /* when FIFO is on, prevent odr change if one is already pending */ if (fifo && ts->new_mult != 0) @@ -78,9 +79,9 @@ int inv_sensors_timestamp_update_odr(struct inv_sensors_timestamp *ts, } EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_update_odr, "IIO_INV_SENSORS_TIMESTAMP"); -static bool inv_validate_period(struct inv_sensors_timestamp *ts, uint32_t period) +static bool inv_validate_period(struct inv_sensors_timestamp *ts, u32 period) { - uint32_t period_min, period_max; + u32 period_min, period_max; /* check that period is acceptable */ period_min = ts->min_period * ts->mult; @@ -92,9 +93,9 @@ static bool inv_validate_period(struct inv_sensors_timestamp *ts, uint32_t perio } static bool inv_update_chip_period(struct inv_sensors_timestamp *ts, - uint32_t period) + u32 period) { - uint32_t new_chip_period; + u32 new_chip_period; if (!inv_validate_period(ts, period)) return false; @@ -102,78 +103,84 @@ static bool inv_update_chip_period(struct inv_sensors_timestamp *ts, /* update chip internal period estimation */ new_chip_period = period / ts->mult; inv_update_acc(&ts->chip_period, new_chip_period); - ts->period = ts->mult * ts->chip_period.val; return true; } -static void inv_align_timestamp_it(struct inv_sensors_timestamp *ts) +static u32 inv_align_timestamp_it(struct inv_sensors_timestamp *ts, + unsigned int sample_nb) { - const int64_t period_min = (int64_t)ts->min_period * ts->mult; - const int64_t period_max = (int64_t)ts->max_period * ts->mult; - int64_t add_max, sub_max; - int64_t delta, jitter; - int64_t adjust; - - /* delta time between last sample and last interrupt */ - delta = ts->it.lo - ts->timestamp; - - /* adjust timestamp while respecting jitter */ - add_max = period_max - (int64_t)ts->period; - sub_max = period_min - (int64_t)ts->period; - jitter = INV_SENSORS_TIMESTAMP_JITTER((int64_t)ts->period, ts->chip.jitter); - if (delta > jitter) - adjust = add_max; - else if (delta < -jitter) - adjust = sub_max; - else - adjust = 0; + const s64 period_min = (s64)ts->min_period * ts->mult; + const s64 period_max = (s64)ts->max_period * ts->mult; + s64 new_period; - ts->timestamp += adjust; + /* compute new period aligning last timestamp with interrupt timestamp */ + new_period = div_s64(ts->it.up - ts->timestamp, sample_nb); + + /* ensure that period never overflows the jitter */ + return clamp(new_period, period_min, period_max); } void inv_sensors_timestamp_interrupt(struct inv_sensors_timestamp *ts, - size_t sample_nb, int64_t timestamp) + size_t sample_nb, s64 timestamp) { struct inv_sensors_timestamp_interval *it; - int64_t delta, interval; - uint32_t period; + s64 delta, delta_threshold, interval; + u32 period; bool valid = false; if (sample_nb == 0) return; + /* no previous data, compute theoretical value from interrupt */ + if (ts->timestamp == 0) { + /* elapsed time: sensor period * sensor samples number */ + interval = (s64)ts->period * (s64)sample_nb; + ts->timestamp = timestamp - interval; + } + + /* update delta timestamps and estimated period */ + it = &ts->delta; + ts->delta_counter += sample_nb; + delta = timestamp - it->up; + delta_threshold = INV_SENSORS_TIMESTAMP_MIN(INV_SENSORS_MIN_IT_DELTA, ts->chip.jitter); + if (delta >= delta_threshold) { + it->lo = it->up; + it->up = timestamp; + if (it->lo != 0) { + /* compute period: delta time divided by number of samples */ + delta = it->up - it->lo; + period = div_s64(delta, ts->delta_counter); + inv_update_chip_period(ts, period); + } + ts->delta_counter = 0; + } + /* update interrupt timestamp and compute chip and sensor periods */ it = &ts->it; it->lo = it->up; it->up = timestamp; delta = it->up - it->lo; if (it->lo != 0) { - /* compute period: delta time divided by number of samples */ + /* compute period and check validity */ period = div_s64(delta, sample_nb); - valid = inv_update_chip_period(ts, period); - } - - /* no previous data, compute theoretical value from interrupt */ - if (ts->timestamp == 0) { - /* elapsed time: sensor period * sensor samples number */ - interval = (int64_t)ts->period * (int64_t)sample_nb; - ts->timestamp = it->up - interval; - return; + valid = inv_validate_period(ts, period); } /* if interrupt interval is valid, sync with interrupt timestamp */ if (valid) - inv_align_timestamp_it(ts); + ts->period = inv_align_timestamp_it(ts, sample_nb); + else + ts->period = ts->mult * ts->chip_period.val; } EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_interrupt, "IIO_INV_SENSORS_TIMESTAMP"); void inv_sensors_timestamp_apply_odr(struct inv_sensors_timestamp *ts, - uint32_t fifo_period, size_t fifo_nb, + u32 fifo_period, size_t fifo_nb, unsigned int fifo_no) { - int64_t interval; - uint32_t fifo_mult; + s64 interval; + u32 fifo_mult; if (ts->new_mult == 0) return; @@ -194,7 +201,7 @@ void inv_sensors_timestamp_apply_odr(struct inv_sensors_timestamp *ts, fifo_mult = fifo_period / ts->chip.clock_period; fifo_period = fifo_mult * ts->chip_period.val; /* computes time interval between interrupt and this sample */ - interval = (int64_t)(fifo_nb - fifo_no) * (int64_t)fifo_period; + interval = (s64)(fifo_nb - fifo_no) * (s64)fifo_period; ts->timestamp = ts->it.up - interval; } } diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 14a246729d2b..03a7a0aa6b61 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -11,8 +11,11 @@ config AD3530R depends on SPI select REGMAP_SPI help - Say yes here to build support for Analog Devices AD3530R, AD3531R - Digital to Analog Converter. + Say yes here to build support for the following Analog Devices + Digital to Analog Converters: + - AD3530/AD3530R (8-channel) + - AD3531/AD3531R (4-channel) + - AD3532/AD3532R (16-channel) To compile this driver as a module, choose M here: the module will be called ad3530r. @@ -240,6 +243,8 @@ config LTC2688 config AD5686 tristate + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER config AD5686_SPI tristate "Analog Devices AD5686 and similar multi-channel DACs (SPI)" @@ -527,6 +532,17 @@ config MAX5821 Say yes here to build support for Maxim MAX5821 10 bits DAC. +config MCF54415_DAC + tristate "NXP MCF54415 DAC driver" + depends on M5441x || COMPILE_TEST + select REGMAP_MMIO + help + Say yes here if you want to build support for NXP ColdFire + MCF54415/6/7/8 12-bit DAC module. + + To compile this driver as a module, choose M here: the module + will be called mcf54415_dac. + config MCP4725 tristate "MCP4725/6 DAC driver" depends on I2C diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 003431798498..5d20d37e44ce 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_MAX517) += max517.o obj-$(CONFIG_MAX22007) += max22007.o obj-$(CONFIG_MAX5522) += max5522.o obj-$(CONFIG_MAX5821) += max5821.o +obj-$(CONFIG_MCF54415_DAC) += mcf54415_dac.o obj-$(CONFIG_MCP4725) += mcp4725.o obj-$(CONFIG_MCP4728) += mcp4728.o obj-$(CONFIG_MCP47FEB02) += mcp47feb02.o diff --git a/drivers/iio/dac/ad3530r.c b/drivers/iio/dac/ad3530r.c index 4e911bfb6fc5..06b7f280f61b 100644 --- a/drivers/iio/dac/ad3530r.c +++ b/drivers/iio/dac/ad3530r.c @@ -2,6 +2,7 @@ /* * AD3530R/AD3530 8-channel, 16-bit Voltage Output DAC Driver * AD3531R/AD3531 4-channel, 16-bit Voltage Output DAC Driver + * AD3532R/AD3532 16-channel, 16-bit Voltage Output DAC Driver * * Copyright 2025 Analog Devices Inc. */ @@ -38,6 +39,25 @@ #define AD3531R_SW_LDAC_TRIG_A 0xDD #define AD3531R_INPUT_CH 0xE3 +/* AD3532R/AD3532 bank 0 registers (channels 0-7) */ +#define AD3532R_INTERFACE_CONFIG_A_0 0x1000 +#define AD3532R_OUTPUT_OPERATING_MODE_0 0x1020 +#define AD3532R_OUTPUT_OPERATING_MODE_1 0x1021 +#define AD3532R_OUTPUT_CONTROL_0 0x102A +#define AD3532R_REFERENCE_CONTROL_0 0x103C +#define AD3532R_SW_LDAC_TRIG_0 0x10E5 +#define AD3532R_INPUT_CH_0 0x10EB + +/* AD3532R/AD3532 bank 1 registers (channels 8-15) */ +#define AD3532R_INTERFACE_CONFIG_A_1 0x3000 +#define AD3532R_OUTPUT_OPERATING_MODE_2 0x3020 +#define AD3532R_OUTPUT_OPERATING_MODE_3 0x3021 +#define AD3532R_OUTPUT_CONTROL_1 0x302A +#define AD3532R_REFERENCE_CONTROL_1 0x303C +#define AD3532R_SW_LDAC_TRIG_1 0x30E5 +#define AD3532R_INPUT_CH_1 0x30EB +#define AD3532R_MAX_REG_ADDR 0x30F9 + #define AD3530R_SLD_TRIG_A BIT(7) #define AD3530R_OUTPUT_CONTROL_RANGE BIT(2) #define AD3530R_REFERENCE_CONTROL_SEL BIT(0) @@ -49,8 +69,10 @@ #define AD3530R_LDAC_PULSE_US 100 #define AD3530R_DAC_MAX_VAL GENMASK(15, 0) -#define AD3530R_MAX_CHANNELS 8 +#define AD3530R_CH_PER_REG 4 +#define AD3530R_CH_PER_BANK 8 #define AD3531R_MAX_CHANNELS 4 +#define AD3532R_MAX_CHANNELS 16 enum ad3530r_mode { AD3530R_NORMAL_OP, @@ -67,9 +89,16 @@ struct ad3530r_chan { struct ad3530r_chip_info { const char *name; const struct iio_chan_spec *channels; + const struct regmap_config *regmap_config; int (*input_ch_reg)(unsigned int channel); + int (*sw_ldac_trig_reg)(unsigned int channel); + const unsigned int *interface_config_a; + const unsigned int *output_control; + const unsigned int *reference_control; + const unsigned int *op_mode; unsigned int num_channels; - unsigned int sw_ldac_trig_reg; + unsigned int num_banks; + unsigned int num_op_mode_regs; bool internal_ref_support; }; @@ -77,7 +106,7 @@ struct ad3530r_state { struct regmap *regmap; /* lock to protect against multiple access to the device and shared data */ struct mutex lock; - struct ad3530r_chan chan[AD3530R_MAX_CHANNELS]; + struct ad3530r_chan chan[AD3532R_MAX_CHANNELS]; const struct ad3530r_chip_info *chip_info; struct gpio_desc *ldac_gpio; int vref_mV; @@ -98,6 +127,14 @@ static int ad3531r_input_ch_reg(unsigned int channel) return 2 * channel + AD3531R_INPUT_CH; } +static int ad3532r_input_ch_reg(unsigned int channel) +{ + unsigned int bank = channel / AD3530R_CH_PER_BANK; + unsigned int local_ch = channel % AD3530R_CH_PER_BANK; + + return 2 * local_ch + (bank ? AD3532R_INPUT_CH_1 : AD3532R_INPUT_CH_0); +} + static const char * const ad3530r_powerdown_modes[] = { "1kohm_to_gnd", "7.7kohm_to_gnd", @@ -110,6 +147,12 @@ static const char * const ad3531r_powerdown_modes[] = { "16kohm_to_gnd", }; +static const char * const ad3532r_powerdown_modes[] = { + "1kohm_to_gnd", + "10kohm_to_gnd", + "three_state", +}; + static int ad3530r_get_powerdown_mode(struct iio_dev *indio_dev, const struct iio_chan_spec *chan) { @@ -145,6 +188,13 @@ static const struct iio_enum ad3531r_powerdown_mode_enum = { .set = ad3530r_set_powerdown_mode, }; +static const struct iio_enum ad3532r_powerdown_mode_enum = { + .items = ad3532r_powerdown_modes, + .num_items = ARRAY_SIZE(ad3532r_powerdown_modes), + .get = ad3530r_get_powerdown_mode, + .set = ad3530r_set_powerdown_mode, +}; + static ssize_t ad3530r_get_dac_powerdown(struct iio_dev *indio_dev, uintptr_t private, const struct iio_chan_spec *chan, @@ -189,6 +239,62 @@ static ssize_t ad3530r_set_dac_powerdown(struct iio_dev *indio_dev, return len; } +static ssize_t ad3532r_set_dac_powerdown(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct ad3530r_state *st = iio_priv(indio_dev); + unsigned int bank, local_ch, reg_in_bank, ch_in_reg; + unsigned int reg, mask, val; + bool powerdown; + int ret; + + ret = kstrtobool(buf, &powerdown); + if (ret) + return ret; + + bank = chan->channel / AD3530R_CH_PER_BANK; + local_ch = chan->channel % AD3530R_CH_PER_BANK; + reg_in_bank = local_ch / AD3530R_CH_PER_REG; + ch_in_reg = local_ch % AD3530R_CH_PER_REG; + + reg = reg_in_bank + (bank ? AD3532R_OUTPUT_OPERATING_MODE_2 : + AD3532R_OUTPUT_OPERATING_MODE_0); + mask = AD3530R_OP_MODE_CHAN_MSK(ch_in_reg); + + guard(mutex)(&st->lock); + if (powerdown) { + val = field_prep(mask, st->chan[chan->channel].powerdown_mode); + ret = regmap_update_bits(st->regmap, reg, mask, val); + } else { + ret = regmap_clear_bits(st->regmap, reg, mask); + } + if (ret) + return ret; + + st->chan[chan->channel].powerdown = powerdown; + + return len; +} + +static int ad3530r_trigger_sw_ldac_reg(unsigned int channel) +{ + return AD3530R_SW_LDAC_TRIG_A; +} + +static int ad3531r_trigger_sw_ldac_reg(unsigned int channel) +{ + return AD3531R_SW_LDAC_TRIG_A; +} + +static int ad3532r_trigger_sw_ldac_reg(unsigned int channel) +{ + unsigned int bank = channel / AD3530R_CH_PER_BANK; + + return bank ? AD3532R_SW_LDAC_TRIG_1 : AD3532R_SW_LDAC_TRIG_0; +} + static int ad3530r_trigger_hw_ldac(struct gpio_desc *ldac_gpio) { gpiod_set_value_cansleep(ldac_gpio, 1); @@ -214,7 +320,7 @@ static int ad3530r_dac_write(struct ad3530r_state *st, unsigned int chan, if (st->ldac_gpio) return ad3530r_trigger_hw_ldac(st->ldac_gpio); - return regmap_set_bits(st->regmap, st->chip_info->sw_ldac_trig_reg, + return regmap_set_bits(st->regmap, st->chip_info->sw_ldac_trig_reg(chan), AD3530R_SLD_TRIG_A); } @@ -301,6 +407,19 @@ static const struct iio_chan_spec_ext_info ad3531r_ext_info[] = { { } }; +static const struct iio_chan_spec_ext_info ad3532r_ext_info[] = { + { + .name = "powerdown", + .shared = IIO_SEPARATE, + .read = ad3530r_get_dac_powerdown, + .write = ad3532r_set_dac_powerdown, + }, + IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad3532r_powerdown_mode_enum), + IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, + &ad3532r_powerdown_mode_enum), + { } +}; + #define AD3530R_CHAN(_chan, _ext_info) \ { \ .type = IIO_VOLTAGE, \ @@ -330,48 +449,215 @@ static const struct iio_chan_spec ad3531r_channels[] = { AD3530R_CHAN(3, ad3531r_ext_info), }; +static const struct iio_chan_spec ad3532r_channels[] = { + AD3530R_CHAN(0, ad3532r_ext_info), + AD3530R_CHAN(1, ad3532r_ext_info), + AD3530R_CHAN(2, ad3532r_ext_info), + AD3530R_CHAN(3, ad3532r_ext_info), + AD3530R_CHAN(4, ad3532r_ext_info), + AD3530R_CHAN(5, ad3532r_ext_info), + AD3530R_CHAN(6, ad3532r_ext_info), + AD3530R_CHAN(7, ad3532r_ext_info), + AD3530R_CHAN(8, ad3532r_ext_info), + AD3530R_CHAN(9, ad3532r_ext_info), + AD3530R_CHAN(10, ad3532r_ext_info), + AD3530R_CHAN(11, ad3532r_ext_info), + AD3530R_CHAN(12, ad3532r_ext_info), + AD3530R_CHAN(13, ad3532r_ext_info), + AD3530R_CHAN(14, ad3532r_ext_info), + AD3530R_CHAN(15, ad3532r_ext_info), +}; + +static const unsigned int ad3530r_if_config[] = { + AD3530R_INTERFACE_CONFIG_A, +}; + +static const unsigned int ad3530r_out_ctrl[] = { + AD3530R_OUTPUT_CONTROL_0, +}; + +static const unsigned int ad3530r_ref_ctrl[] = { + AD3530R_REFERENCE_CONTROL_0, +}; + +static const unsigned int ad3530r_op_mode[] = { + AD3530R_OUTPUT_OPERATING_MODE_0, + AD3530R_OUTPUT_OPERATING_MODE_1, +}; + +static const unsigned int ad3531r_op_mode[] = { + AD3530R_OUTPUT_OPERATING_MODE_0, +}; + +static const unsigned int ad3532r_if_config[] = { + AD3532R_INTERFACE_CONFIG_A_0, + AD3532R_INTERFACE_CONFIG_A_1, +}; + +static const unsigned int ad3532r_out_ctrl[] = { + AD3532R_OUTPUT_CONTROL_0, + AD3532R_OUTPUT_CONTROL_1, +}; + +static const unsigned int ad3532r_ref_ctrl[] = { + AD3532R_REFERENCE_CONTROL_0, + AD3532R_REFERENCE_CONTROL_1, +}; + +static const unsigned int ad3532r_op_mode[] = { + AD3532R_OUTPUT_OPERATING_MODE_0, + AD3532R_OUTPUT_OPERATING_MODE_1, + AD3532R_OUTPUT_OPERATING_MODE_2, + AD3532R_OUTPUT_OPERATING_MODE_3, +}; + +static const struct regmap_config ad3530r_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .max_register = AD3530R_MAX_REG_ADDR, +}; + +static const struct regmap_config ad3532r_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .max_register = AD3532R_MAX_REG_ADDR, +}; + static const struct ad3530r_chip_info ad3530_chip = { .name = "ad3530", .channels = ad3530r_channels, + .regmap_config = &ad3530r_regmap_config, .num_channels = ARRAY_SIZE(ad3530r_channels), - .sw_ldac_trig_reg = AD3530R_SW_LDAC_TRIG_A, + .sw_ldac_trig_reg = ad3530r_trigger_sw_ldac_reg, .input_ch_reg = ad3530r_input_ch_reg, + .interface_config_a = ad3530r_if_config, + .output_control = ad3530r_out_ctrl, + .reference_control = ad3530r_ref_ctrl, + .op_mode = ad3530r_op_mode, + .num_banks = ARRAY_SIZE(ad3530r_if_config), + .num_op_mode_regs = ARRAY_SIZE(ad3530r_op_mode), .internal_ref_support = false, }; static const struct ad3530r_chip_info ad3530r_chip = { .name = "ad3530r", .channels = ad3530r_channels, + .regmap_config = &ad3530r_regmap_config, .num_channels = ARRAY_SIZE(ad3530r_channels), - .sw_ldac_trig_reg = AD3530R_SW_LDAC_TRIG_A, + .sw_ldac_trig_reg = ad3530r_trigger_sw_ldac_reg, .input_ch_reg = ad3530r_input_ch_reg, + .interface_config_a = ad3530r_if_config, + .output_control = ad3530r_out_ctrl, + .reference_control = ad3530r_ref_ctrl, + .op_mode = ad3530r_op_mode, + .num_banks = ARRAY_SIZE(ad3530r_if_config), + .num_op_mode_regs = ARRAY_SIZE(ad3530r_op_mode), .internal_ref_support = true, }; static const struct ad3530r_chip_info ad3531_chip = { .name = "ad3531", .channels = ad3531r_channels, + .regmap_config = &ad3530r_regmap_config, .num_channels = ARRAY_SIZE(ad3531r_channels), - .sw_ldac_trig_reg = AD3531R_SW_LDAC_TRIG_A, + .sw_ldac_trig_reg = ad3531r_trigger_sw_ldac_reg, .input_ch_reg = ad3531r_input_ch_reg, + .interface_config_a = ad3530r_if_config, + .output_control = ad3530r_out_ctrl, + .reference_control = ad3530r_ref_ctrl, + .op_mode = ad3531r_op_mode, + .num_banks = ARRAY_SIZE(ad3530r_if_config), + .num_op_mode_regs = ARRAY_SIZE(ad3531r_op_mode), .internal_ref_support = false, }; static const struct ad3530r_chip_info ad3531r_chip = { .name = "ad3531r", .channels = ad3531r_channels, + .regmap_config = &ad3530r_regmap_config, .num_channels = ARRAY_SIZE(ad3531r_channels), - .sw_ldac_trig_reg = AD3531R_SW_LDAC_TRIG_A, + .sw_ldac_trig_reg = ad3531r_trigger_sw_ldac_reg, .input_ch_reg = ad3531r_input_ch_reg, + .interface_config_a = ad3530r_if_config, + .output_control = ad3530r_out_ctrl, + .reference_control = ad3530r_ref_ctrl, + .op_mode = ad3531r_op_mode, + .num_banks = ARRAY_SIZE(ad3530r_if_config), + .num_op_mode_regs = ARRAY_SIZE(ad3531r_op_mode), + .internal_ref_support = true, +}; + +static const struct ad3530r_chip_info ad3532_chip = { + .name = "ad3532", + .channels = ad3532r_channels, + .regmap_config = &ad3532r_regmap_config, + .num_channels = ARRAY_SIZE(ad3532r_channels), + .sw_ldac_trig_reg = ad3532r_trigger_sw_ldac_reg, + .input_ch_reg = ad3532r_input_ch_reg, + .interface_config_a = ad3532r_if_config, + .output_control = ad3532r_out_ctrl, + .reference_control = ad3532r_ref_ctrl, + .op_mode = ad3532r_op_mode, + .num_banks = ARRAY_SIZE(ad3532r_if_config), + .num_op_mode_regs = ARRAY_SIZE(ad3532r_op_mode), + .internal_ref_support = false, +}; + +static const struct ad3530r_chip_info ad3532r_chip = { + .name = "ad3532r", + .channels = ad3532r_channels, + .regmap_config = &ad3532r_regmap_config, + .num_channels = ARRAY_SIZE(ad3532r_channels), + .sw_ldac_trig_reg = ad3532r_trigger_sw_ldac_reg, + .input_ch_reg = ad3532r_input_ch_reg, + .interface_config_a = ad3532r_if_config, + .output_control = ad3532r_out_ctrl, + .reference_control = ad3532r_ref_ctrl, + .op_mode = ad3532r_op_mode, + .num_banks = ARRAY_SIZE(ad3532r_if_config), + .num_op_mode_regs = ARRAY_SIZE(ad3532r_op_mode), .internal_ref_support = true, }; +static int ad3530r_set_reg_bank_bits(const struct ad3530r_state *st, + const unsigned int *regs, + unsigned int num_regs, + unsigned int mask) +{ + int ret; + + for (unsigned int i = 0; i < num_regs; i++) { + ret = regmap_set_bits(st->regmap, regs[i], mask); + if (ret) + return ret; + } + + return 0; +} + +static int ad3530r_write_reg_banks(const struct ad3530r_state *st, + const unsigned int *regs, + unsigned int num_regs, + unsigned int val) +{ + int ret; + + for (unsigned int i = 0; i < num_regs; i++) { + ret = regmap_write(st->regmap, regs[i], val); + if (ret) + return ret; + } + + return 0; +} + static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV) { + const struct ad3530r_chip_info *chip_info = st->chip_info; struct device *dev = regmap_get_device(st->regmap); struct gpio_desc *reset_gpio; - int i, ret; u8 range_multiplier, val; + int ret; reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(reset_gpio)) @@ -384,8 +670,9 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV) gpiod_set_value_cansleep(reset_gpio, 0); } else { /* Perform software reset */ - ret = regmap_update_bits(st->regmap, AD3530R_INTERFACE_CONFIG_A, - AD3530R_SW_RESET, AD3530R_SW_RESET); + ret = ad3530r_set_reg_bank_bits(st, chip_info->interface_config_a, + chip_info->num_banks, + AD3530R_SW_RESET); if (ret) return ret; } @@ -394,8 +681,9 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV) range_multiplier = 1; if (device_property_read_bool(dev, "adi,range-double")) { - ret = regmap_set_bits(st->regmap, AD3530R_OUTPUT_CONTROL_0, - AD3530R_OUTPUT_CONTROL_RANGE); + ret = ad3530r_set_reg_bank_bits(st, chip_info->output_control, + chip_info->num_banks, + AD3530R_OUTPUT_CONTROL_RANGE); if (ret) return ret; @@ -405,8 +693,9 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV) if (external_vref_uV) { st->vref_mV = range_multiplier * external_vref_uV / MILLI; } else { - ret = regmap_set_bits(st->regmap, AD3530R_REFERENCE_CONTROL_0, - AD3530R_REFERENCE_CONTROL_SEL); + ret = ad3530r_set_reg_bank_bits(st, chip_info->reference_control, + chip_info->num_banks, + AD3530R_REFERENCE_CONTROL_SEL); if (ret) return ret; @@ -419,18 +708,12 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV) FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(2), AD3530R_NORMAL_OP) | FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(3), AD3530R_NORMAL_OP); - ret = regmap_write(st->regmap, AD3530R_OUTPUT_OPERATING_MODE_0, val); + ret = ad3530r_write_reg_banks(st, st->chip_info->op_mode, + st->chip_info->num_op_mode_regs, val); if (ret) return ret; - if (st->chip_info->num_channels > 4) { - ret = regmap_write(st->regmap, AD3530R_OUTPUT_OPERATING_MODE_1, - val); - if (ret) - return ret; - } - - for (i = 0; i < st->chip_info->num_channels; i++) + for (unsigned int i = 0; i < st->chip_info->num_channels; i++) st->chan[i].powerdown_mode = AD3530R_POWERDOWN_32K; st->ldac_gpio = devm_gpiod_get_optional(dev, "ldac", GPIOD_OUT_LOW); @@ -441,12 +724,6 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV) return 0; } -static const struct regmap_config ad3530r_regmap_config = { - .reg_bits = 16, - .val_bits = 8, - .max_register = AD3530R_MAX_REG_ADDR, -}; - static const struct iio_info ad3530r_info = { .read_raw = ad3530r_read_raw, .write_raw = ad3530r_write_raw, @@ -467,7 +744,11 @@ static int ad3530r_probe(struct spi_device *spi) st = iio_priv(indio_dev); - st->regmap = devm_regmap_init_spi(spi, &ad3530r_regmap_config); + st->chip_info = spi_get_device_match_data(spi); + if (!st->chip_info) + return -ENODEV; + + st->regmap = devm_regmap_init_spi(spi, st->chip_info->regmap_config); if (IS_ERR(st->regmap)) return dev_err_probe(dev, PTR_ERR(st->regmap), "Failed to init regmap"); @@ -476,10 +757,6 @@ static int ad3530r_probe(struct spi_device *spi) if (ret) return ret; - st->chip_info = spi_get_device_match_data(spi); - if (!st->chip_info) - return -ENODEV; - ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulators), regulators); if (ret) @@ -509,10 +786,12 @@ static int ad3530r_probe(struct spi_device *spi) } static const struct spi_device_id ad3530r_id[] = { - { "ad3530", (kernel_ulong_t)&ad3530_chip }, - { "ad3530r", (kernel_ulong_t)&ad3530r_chip }, - { "ad3531", (kernel_ulong_t)&ad3531_chip }, - { "ad3531r", (kernel_ulong_t)&ad3531r_chip }, + { .name = "ad3530", .driver_data = (kernel_ulong_t)&ad3530_chip }, + { .name = "ad3530r", .driver_data = (kernel_ulong_t)&ad3530r_chip }, + { .name = "ad3531", .driver_data = (kernel_ulong_t)&ad3531_chip }, + { .name = "ad3531r", .driver_data = (kernel_ulong_t)&ad3531r_chip }, + { .name = "ad3532", .driver_data = (kernel_ulong_t)&ad3532_chip }, + { .name = "ad3532r", .driver_data = (kernel_ulong_t)&ad3532r_chip }, { } }; MODULE_DEVICE_TABLE(spi, ad3530r_id); @@ -522,6 +801,8 @@ static const struct of_device_id ad3530r_of_match[] = { { .compatible = "adi,ad3530r", .data = &ad3530r_chip }, { .compatible = "adi,ad3531", .data = &ad3531_chip }, { .compatible = "adi,ad3531r", .data = &ad3531r_chip }, + { .compatible = "adi,ad3532", .data = &ad3532_chip }, + { .compatible = "adi,ad3532r", .data = &ad3532r_chip }, { } }; MODULE_DEVICE_TABLE(of, ad3530r_of_match); diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c index b5ec33f5c317..298f3a703571 100644 --- a/drivers/iio/dac/ad5064.c +++ b/drivers/iio/dac/ad5064.c @@ -920,22 +920,22 @@ static int ad5064_spi_probe(struct spi_device *spi) } static const struct spi_device_id ad5064_spi_ids[] = { - {"ad5024", ID_AD5024}, - {"ad5025", ID_AD5025}, - {"ad5044", ID_AD5044}, - {"ad5045", ID_AD5045}, - {"ad5064", ID_AD5064}, - {"ad5064-1", ID_AD5064_1}, - {"ad5065", ID_AD5065}, - {"ad5628-1", ID_AD5628_1}, - {"ad5628-2", ID_AD5628_2}, - {"ad5648-1", ID_AD5648_1}, - {"ad5648-2", ID_AD5648_2}, - {"ad5666-1", ID_AD5666_1}, - {"ad5666-2", ID_AD5666_2}, - {"ad5668-1", ID_AD5668_1}, - {"ad5668-2", ID_AD5668_2}, - {"ad5668-3", ID_AD5668_2}, /* similar enough to ad5668-2 */ + { .name = "ad5024", .driver_data = ID_AD5024 }, + { .name = "ad5025", .driver_data = ID_AD5025 }, + { .name = "ad5044", .driver_data = ID_AD5044 }, + { .name = "ad5045", .driver_data = ID_AD5045 }, + { .name = "ad5064", .driver_data = ID_AD5064 }, + { .name = "ad5064-1", .driver_data = ID_AD5064_1 }, + { .name = "ad5065", .driver_data = ID_AD5065 }, + { .name = "ad5628-1", .driver_data = ID_AD5628_1 }, + { .name = "ad5628-2", .driver_data = ID_AD5628_2 }, + { .name = "ad5648-1", .driver_data = ID_AD5648_1 }, + { .name = "ad5648-2", .driver_data = ID_AD5648_2 }, + { .name = "ad5666-1", .driver_data = ID_AD5666_1 }, + { .name = "ad5666-2", .driver_data = ID_AD5666_2 }, + { .name = "ad5668-1", .driver_data = ID_AD5668_1 }, + { .name = "ad5668-2", .driver_data = ID_AD5668_2 }, + { .name = "ad5668-3", .driver_data = ID_AD5668_2 }, /* similar enough to ad5668-2 */ { } }; MODULE_DEVICE_TABLE(spi, ad5064_spi_ids); diff --git a/drivers/iio/dac/ad5360.c b/drivers/iio/dac/ad5360.c index 20316fd568e6..c1553f18a26a 100644 --- a/drivers/iio/dac/ad5360.c +++ b/drivers/iio/dac/ad5360.c @@ -523,14 +523,14 @@ static void ad5360_remove(struct spi_device *spi) } static const struct spi_device_id ad5360_ids[] = { - { "ad5360", ID_AD5360 }, - { "ad5361", ID_AD5361 }, - { "ad5362", ID_AD5362 }, - { "ad5363", ID_AD5363 }, - { "ad5370", ID_AD5370 }, - { "ad5371", ID_AD5371 }, - { "ad5372", ID_AD5372 }, - { "ad5373", ID_AD5373 }, + { .name = "ad5360", .driver_data = ID_AD5360 }, + { .name = "ad5361", .driver_data = ID_AD5361 }, + { .name = "ad5362", .driver_data = ID_AD5362 }, + { .name = "ad5363", .driver_data = ID_AD5363 }, + { .name = "ad5370", .driver_data = ID_AD5370 }, + { .name = "ad5371", .driver_data = ID_AD5371 }, + { .name = "ad5372", .driver_data = ID_AD5372 }, + { .name = "ad5373", .driver_data = ID_AD5373 }, { } }; MODULE_DEVICE_TABLE(spi, ad5360_ids); diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index 2e587bdd3214..4a5ad419f4ea 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c @@ -446,22 +446,22 @@ static int ad5380_spi_probe(struct spi_device *spi) } static const struct spi_device_id ad5380_spi_ids[] = { - { "ad5380-3", ID_AD5380_3 }, - { "ad5380-5", ID_AD5380_5 }, - { "ad5381-3", ID_AD5381_3 }, - { "ad5381-5", ID_AD5381_5 }, - { "ad5382-3", ID_AD5382_3 }, - { "ad5382-5", ID_AD5382_5 }, - { "ad5383-3", ID_AD5383_3 }, - { "ad5383-5", ID_AD5383_5 }, - { "ad5384-3", ID_AD5380_3 }, - { "ad5384-5", ID_AD5380_5 }, - { "ad5390-3", ID_AD5390_3 }, - { "ad5390-5", ID_AD5390_5 }, - { "ad5391-3", ID_AD5391_3 }, - { "ad5391-5", ID_AD5391_5 }, - { "ad5392-3", ID_AD5392_3 }, - { "ad5392-5", ID_AD5392_5 }, + { .name = "ad5380-3", .driver_data = ID_AD5380_3 }, + { .name = "ad5380-5", .driver_data = ID_AD5380_5 }, + { .name = "ad5381-3", .driver_data = ID_AD5381_3 }, + { .name = "ad5381-5", .driver_data = ID_AD5381_5 }, + { .name = "ad5382-3", .driver_data = ID_AD5382_3 }, + { .name = "ad5382-5", .driver_data = ID_AD5382_5 }, + { .name = "ad5383-3", .driver_data = ID_AD5383_3 }, + { .name = "ad5383-5", .driver_data = ID_AD5383_5 }, + { .name = "ad5384-3", .driver_data = ID_AD5380_3 }, + { .name = "ad5384-5", .driver_data = ID_AD5380_5 }, + { .name = "ad5390-3", .driver_data = ID_AD5390_3 }, + { .name = "ad5390-5", .driver_data = ID_AD5390_5 }, + { .name = "ad5391-3", .driver_data = ID_AD5391_3 }, + { .name = "ad5391-5", .driver_data = ID_AD5391_5 }, + { .name = "ad5392-3", .driver_data = ID_AD5392_3 }, + { .name = "ad5392-5", .driver_data = ID_AD5392_5 }, { } }; MODULE_DEVICE_TABLE(spi, ad5380_spi_ids); diff --git a/drivers/iio/dac/ad5446-spi.c b/drivers/iio/dac/ad5446-spi.c index 54bd0e113f40..85bb8829046a 100644 --- a/drivers/iio/dac/ad5446-spi.c +++ b/drivers/iio/dac/ad5446-spi.c @@ -163,38 +163,38 @@ static const struct ad5446_chip_info ad5662_chip_info = { }; static const struct spi_device_id ad5446_spi_ids[] = { - {"ad5300", (kernel_ulong_t)&ad5300_chip_info}, - {"ad5310", (kernel_ulong_t)&ad5310_chip_info}, - {"ad5320", (kernel_ulong_t)&ad5320_chip_info}, - {"ad5444", (kernel_ulong_t)&ad5444_chip_info}, - {"ad5446", (kernel_ulong_t)&ad5446_chip_info}, - {"ad5450", (kernel_ulong_t)&ad5450_chip_info}, - {"ad5451", (kernel_ulong_t)&ad5451_chip_info}, - {"ad5452", (kernel_ulong_t)&ad5444_chip_info}, /* ad5452 is compatible to the ad5444 */ - {"ad5453", (kernel_ulong_t)&ad5446_chip_info}, /* ad5453 is compatible to the ad5446 */ - {"ad5512a", (kernel_ulong_t)&ad5512a_chip_info}, - {"ad5541a", (kernel_ulong_t)&ad5541a_chip_info}, - {"ad5542", (kernel_ulong_t)&ad5541a_chip_info}, /* ad5541a and ad5542 are compatible */ - {"ad5542a", (kernel_ulong_t)&ad5541a_chip_info}, /* ad5541a and ad5542a are compatible */ - {"ad5543", (kernel_ulong_t)&ad5541a_chip_info}, /* ad5541a and ad5543 are compatible */ - {"ad5553", (kernel_ulong_t)&ad5553_chip_info}, - {"ad5600", (kernel_ulong_t)&ad5541a_chip_info}, /* ad5541a and ad5600 are compatible */ - {"ad5601", (kernel_ulong_t)&ad5601_chip_info}, - {"ad5611", (kernel_ulong_t)&ad5611_chip_info}, - {"ad5621", (kernel_ulong_t)&ad5621_chip_info}, - {"ad5641", (kernel_ulong_t)&ad5641_chip_info}, - {"ad5620-2500", (kernel_ulong_t)&ad5620_2500_chip_info}, /* AD5620/40/60: */ + { .name = "ad5300", .driver_data = (kernel_ulong_t)&ad5300_chip_info }, + { .name = "ad5310", .driver_data = (kernel_ulong_t)&ad5310_chip_info }, + { .name = "ad5320", .driver_data = (kernel_ulong_t)&ad5320_chip_info }, + { .name = "ad5444", .driver_data = (kernel_ulong_t)&ad5444_chip_info }, + { .name = "ad5446", .driver_data = (kernel_ulong_t)&ad5446_chip_info }, + { .name = "ad5450", .driver_data = (kernel_ulong_t)&ad5450_chip_info }, + { .name = "ad5451", .driver_data = (kernel_ulong_t)&ad5451_chip_info }, + { .name = "ad5452", .driver_data = (kernel_ulong_t)&ad5444_chip_info }, /* ad5452 is compatible to the ad5444 */ + { .name = "ad5453", .driver_data = (kernel_ulong_t)&ad5446_chip_info }, /* ad5453 is compatible to the ad5446 */ + { .name = "ad5512a", .driver_data = (kernel_ulong_t)&ad5512a_chip_info }, + { .name = "ad5541a", .driver_data = (kernel_ulong_t)&ad5541a_chip_info }, + { .name = "ad5542", .driver_data = (kernel_ulong_t)&ad5541a_chip_info }, /* ad5541a and ad5542 are compatible */ + { .name = "ad5542a", .driver_data = (kernel_ulong_t)&ad5541a_chip_info }, /* ad5541a and ad5542a are compatible */ + { .name = "ad5543", .driver_data = (kernel_ulong_t)&ad5541a_chip_info }, /* ad5541a and ad5543 are compatible */ + { .name = "ad5553", .driver_data = (kernel_ulong_t)&ad5553_chip_info }, + { .name = "ad5600", .driver_data = (kernel_ulong_t)&ad5541a_chip_info }, /* ad5541a and ad5600 are compatible */ + { .name = "ad5601", .driver_data = (kernel_ulong_t)&ad5601_chip_info }, + { .name = "ad5611", .driver_data = (kernel_ulong_t)&ad5611_chip_info }, + { .name = "ad5621", .driver_data = (kernel_ulong_t)&ad5621_chip_info }, + { .name = "ad5641", .driver_data = (kernel_ulong_t)&ad5641_chip_info }, + { .name = "ad5620-2500", .driver_data = (kernel_ulong_t)&ad5620_2500_chip_info }, /* AD5620/40/60: */ /* part numbers may look differently */ - {"ad5620-1250", (kernel_ulong_t)&ad5620_1250_chip_info}, - {"ad5640-2500", (kernel_ulong_t)&ad5640_2500_chip_info}, - {"ad5640-1250", (kernel_ulong_t)&ad5640_1250_chip_info}, - {"ad5660-2500", (kernel_ulong_t)&ad5660_2500_chip_info}, - {"ad5660-1250", (kernel_ulong_t)&ad5660_1250_chip_info}, - {"ad5662", (kernel_ulong_t)&ad5662_chip_info}, - {"dac081s101", (kernel_ulong_t)&ad5300_chip_info}, /* compatible Texas Instruments chips */ - {"dac101s101", (kernel_ulong_t)&ad5310_chip_info}, - {"dac121s101", (kernel_ulong_t)&ad5320_chip_info}, - {"dac7512", (kernel_ulong_t)&ad5320_chip_info}, + { .name = "ad5620-1250", .driver_data = (kernel_ulong_t)&ad5620_1250_chip_info }, + { .name = "ad5640-2500", .driver_data = (kernel_ulong_t)&ad5640_2500_chip_info }, + { .name = "ad5640-1250", .driver_data = (kernel_ulong_t)&ad5640_1250_chip_info }, + { .name = "ad5660-2500", .driver_data = (kernel_ulong_t)&ad5660_2500_chip_info }, + { .name = "ad5660-1250", .driver_data = (kernel_ulong_t)&ad5660_1250_chip_info }, + { .name = "ad5662", .driver_data = (kernel_ulong_t)&ad5662_chip_info }, + { .name = "dac081s101", .driver_data = (kernel_ulong_t)&ad5300_chip_info }, /* compatible Texas Instruments chips */ + { .name = "dac101s101", .driver_data = (kernel_ulong_t)&ad5310_chip_info }, + { .name = "dac121s101", .driver_data = (kernel_ulong_t)&ad5320_chip_info }, + { .name = "dac7512", .driver_data = (kernel_ulong_t)&ad5320_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad5446_spi_ids); diff --git a/drivers/iio/dac/ad5449.c b/drivers/iio/dac/ad5449.c index d8c325260259..19e66bc69676 100644 --- a/drivers/iio/dac/ad5449.c +++ b/drivers/iio/dac/ad5449.c @@ -330,13 +330,13 @@ static void ad5449_spi_remove(struct spi_device *spi) } static const struct spi_device_id ad5449_spi_ids[] = { - { "ad5415", ID_AD5449 }, - { "ad5426", ID_AD5426 }, - { "ad5429", ID_AD5429 }, - { "ad5432", ID_AD5432 }, - { "ad5439", ID_AD5439 }, - { "ad5443", ID_AD5443 }, - { "ad5449", ID_AD5449 }, + { .name = "ad5415", .driver_data = ID_AD5449 }, + { .name = "ad5426", .driver_data = ID_AD5426 }, + { .name = "ad5429", .driver_data = ID_AD5429 }, + { .name = "ad5432", .driver_data = ID_AD5432 }, + { .name = "ad5439", .driver_data = ID_AD5439 }, + { .name = "ad5443", .driver_data = ID_AD5443 }, + { .name = "ad5449", .driver_data = ID_AD5449 }, { } }; MODULE_DEVICE_TABLE(spi, ad5449_spi_ids); diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index 5e586185d857..ad1a74678cf2 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c @@ -319,8 +319,8 @@ static int ad5504_probe(struct spi_device *spi) } static const struct spi_device_id ad5504_id[] = { - {"ad5504", ID_AD5504}, - {"ad5501", ID_AD5501}, + { .name = "ad5504", .driver_data = ID_AD5504 }, + { .name = "ad5501", .driver_data = ID_AD5501 }, { } }; MODULE_DEVICE_TABLE(spi, ad5504_id); diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c index 13aefe769bad..56aea4b1c167 100644 --- a/drivers/iio/dac/ad5624r_spi.c +++ b/drivers/iio/dac/ad5624r_spi.c @@ -260,12 +260,12 @@ static int ad5624r_probe(struct spi_device *spi) } static const struct spi_device_id ad5624r_id[] = { - {"ad5624r3", ID_AD5624R3}, - {"ad5644r3", ID_AD5644R3}, - {"ad5664r3", ID_AD5664R3}, - {"ad5624r5", ID_AD5624R5}, - {"ad5644r5", ID_AD5644R5}, - {"ad5664r5", ID_AD5664R5}, + { .name = "ad5624r3", .driver_data = ID_AD5624R3 }, + { .name = "ad5644r3", .driver_data = ID_AD5644R3 }, + { .name = "ad5664r3", .driver_data = ID_AD5664R3 }, + { .name = "ad5624r5", .driver_data = ID_AD5624R5 }, + { .name = "ad5644r5", .driver_data = ID_AD5644R5 }, + { .name = "ad5664r5", .driver_data = ID_AD5664R5 }, { } }; MODULE_DEVICE_TABLE(spi, ad5624r_id); diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c index 8abfaf8f0c46..1877d7cd2155 100644 --- a/drivers/iio/dac/ad5686-spi.c +++ b/drivers/iio/dac/ad5686-spi.c @@ -9,61 +9,104 @@ */ #include <linux/array_size.h> +#include <linux/bitfield.h> #include <linux/errno.h> #include <linux/module.h> +#include <linux/overflow.h> #include <linux/spi/spi.h> #include <asm/byteorder.h> #include "ad5686.h" +/** + * struct ad5686_spi_data - SPI bus specific data + * @msg: SPI message used for transfers + * @size: number of transfers currently in the message + * @capacity: maximum number of transfers that can be added to the message + * @xfers: array of SPI transfers, allocated with the provided capacity + */ +struct ad5686_spi_data { + struct spi_message msg; + unsigned int size; + unsigned int capacity; + struct spi_transfer xfers[] __counted_by(capacity); +}; + static int ad5686_spi_write(struct ad5686_state *st, u8 cmd, u8 addr, u16 val) { - struct spi_device *spi = to_spi_device(st->dev); - u8 tx_len, *buf; - + struct ad5686_spi_data *bus_data = st->bus_data; + struct spi_transfer *xfer; + + if (bus_data->size >= bus_data->capacity) + return -E2BIG; + + /* + * This function stores spi transfers to a spi message to be sent over + * the bus when sync() op is called. If there are already transfers in + * the spi message, set the cs_change flag on the last transfer to + * ensure that the chip select is deasserted between transfers. If this + * is the first transfer, initialize the spi message. Later on, the + * current transfer is added to the message with spi_message_add_tail(). + */ + if (bus_data->size) + bus_data->xfers[bus_data->size - 1].cs_change = 1; + else + spi_message_init(&bus_data->msg); + + xfer = &bus_data->xfers[bus_data->size]; + auto buf = &st->data[bus_data->size]; switch (st->chip_info->regmap_type) { case AD5310_REGMAP: - st->data[0].d16 = cpu_to_be16(AD5310_CMD(cmd) | - val); - buf = &st->data[0].d8[0]; - tx_len = 2; + buf->d16 = cpu_to_be16(FIELD_PREP(AD5310_CMD_MSK, cmd) | + FIELD_PREP(AD5310_DATA_MSK, val)); + *xfer = (struct spi_transfer) { + .tx_buf = &buf->d16, + .len = sizeof(buf->d16), + }; break; case AD5683_REGMAP: - st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) | - AD5683_DATA(val)); - buf = &st->data[0].d8[1]; - tx_len = 3; + buf->d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, cmd) | + FIELD_PREP(AD5683_DATA_MSK, val)); + *xfer = (struct spi_transfer) { + .tx_buf = &buf->d8[1], + .len = sizeof(buf->d8) - 1, + }; break; case AD5686_REGMAP: - st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) | - AD5686_ADDR(addr) | - val); - buf = &st->data[0].d8[1]; - tx_len = 3; + buf->d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, cmd) | + FIELD_PREP(AD5686_ADDR_MSK, addr) | + FIELD_PREP(AD5686_DATA_MSK, val)); + *xfer = (struct spi_transfer) { + .tx_buf = &buf->d8[1], + .len = sizeof(buf->d8) - 1, + }; break; default: return -EINVAL; } - return spi_write(spi, buf, tx_len); + spi_message_add_tail(xfer, &bus_data->msg); + bus_data->size++; + + return 0; +} + +static int ad5686_spi_sync(struct ad5686_state *st) +{ + struct spi_device *spi = to_spi_device(st->dev); + struct ad5686_spi_data *bus_data = st->bus_data; + + bus_data->size = 0; /* always reset, even on sync failure */ + return spi_sync(spi, &bus_data->msg); } static int ad5686_spi_read(struct ad5686_state *st, u8 addr) { - struct spi_transfer t[] = { - { - .tx_buf = &st->data[0].d8[1], - .len = 3, - .cs_change = 1, - }, { - .tx_buf = &st->data[1].d8[1], - .rx_buf = &st->data[2].d8[1], - .len = 3, - }, - }; struct spi_device *spi = to_spi_device(st->dev); + struct ad5686_spi_data *bus_data = st->bus_data; + struct spi_transfer *xfer = &bus_data->xfers[0]; u8 cmd = 0; int ret; @@ -80,12 +123,25 @@ static int ad5686_spi_read(struct ad5686_state *st, u8 addr) return -EINVAL; } - st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) | - AD5686_ADDR(addr)); - st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP)); + st->data[0].d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, cmd) | + FIELD_PREP(AD5686_ADDR_MSK, addr)); + st->data[1].d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, AD5686_CMD_NOOP)); + + xfer[0] = (struct spi_transfer) { + .tx_buf = &st->data[0].d8[1], + .len = sizeof(st->data[0].d8) - 1, + .cs_change = 1, + }; + xfer[1] = (struct spi_transfer) { + .tx_buf = &st->data[1].d8[1], + .rx_buf = &st->data[2].d8[1], + .len = sizeof(st->data[1].d8) - 1, + }; + + spi_message_init_with_transfers(&bus_data->msg, xfer, 2); - ret = spi_sync_transfer(spi, t, ARRAY_SIZE(t)); - if (ret < 0) + ret = spi_sync(spi, &bus_data->msg); + if (ret) return ret; return be32_to_cpu(st->data[2].d32); @@ -94,12 +150,30 @@ static int ad5686_spi_read(struct ad5686_state *st, u8 addr) static const struct ad5686_bus_ops ad5686_spi_ops = { .write = ad5686_spi_write, .read = ad5686_spi_read, + .sync = ad5686_spi_sync, }; static int ad5686_spi_probe(struct spi_device *spi) { - return ad5686_probe(&spi->dev, spi_get_device_match_data(spi), - spi->modalias, &ad5686_spi_ops); + const struct ad5686_chip_info *info; + struct ad5686_spi_data *bus_data; + struct device *dev = &spi->dev; + unsigned int capacity; + + info = spi_get_device_match_data(spi); + if (!info) + return -ENODATA; + + /* read operation requires at least 2 transfers */ + capacity = max(info->num_channels, 2); + bus_data = devm_kzalloc(dev, struct_size(bus_data, xfers, capacity), + GFP_KERNEL); + if (!bus_data) + return -ENOMEM; + + bus_data->capacity = capacity; + + return ad5686_probe(dev, info, spi->modalias, &ad5686_spi_ops, bus_data); } static const struct spi_device_id ad5686_spi_id[] = { diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 5840fda4b011..873dfb5b9107 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -8,15 +8,27 @@ #include <linux/array_size.h> #include <linux/bitfield.h> #include <linux/bitops.h> +#include <linux/cleanup.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> #include <linux/errno.h> #include <linux/export.h> +#include <linux/gpio/consumer.h> #include <linux/kstrtox.h> +#include <linux/math64.h> #include <linux/module.h> +#include <linux/property.h> #include <linux/regulator/consumer.h> +#include <linux/reset.h> #include <linux/sysfs.h> +#include <linux/units.h> #include <linux/wordpart.h> +#include <linux/iio/buffer.h> #include <linux/iio/iio.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> #include "ad5686.h" @@ -31,8 +43,9 @@ static int ad5310_control_sync(struct ad5686_state *st) unsigned int pd_val = st->pwr_down_mask & st->pwr_down_mode; return ad5686_write(st, AD5686_CMD_CONTROL_REG, 0, - FIELD_PREP(AD5310_PD_MSK, pd_val & AD5686_PD_MSK) | - FIELD_PREP(AD5310_REF_BIT_MSK, st->use_internal_vref ? 0 : 1)); + FIELD_PREP(AD5310_DATA_PD_MSK, pd_val & AD5686_PD_MSK) | + FIELD_PREP(AD5310_DATA_REF_MSK, st->use_internal_vref ? 0 : 1) | + FIELD_PREP(AD5310_DATA_GAIN_MSK, st->double_scale ? 1 : 0)); } static int ad5683_control_sync(struct ad5686_state *st) @@ -40,8 +53,9 @@ static int ad5683_control_sync(struct ad5686_state *st) unsigned int pd_val = st->pwr_down_mask & st->pwr_down_mode; return ad5686_write(st, AD5686_CMD_CONTROL_REG, 0, - FIELD_PREP(AD5683_PD_MSK, pd_val & AD5686_PD_MSK) | - FIELD_PREP(AD5683_REF_BIT_MSK, st->use_internal_vref ? 0 : 1)); + FIELD_PREP(AD5683_DATA_PD_MSK, pd_val & AD5686_PD_MSK) | + FIELD_PREP(AD5683_DATA_REF_MSK, st->use_internal_vref ? 0 : 1) | + FIELD_PREP(AD5683_DATA_GAIN_MSK, st->double_scale ? 1 : 0)); } static inline unsigned int ad5686_pd_mask_shift(const struct iio_chan_spec *chan) @@ -173,20 +187,25 @@ static int ad5686_read_raw(struct iio_dev *indio_dev, struct ad5686_state *st = iio_priv(indio_dev); int ret; + guard(mutex)(&st->lock); + switch (m) { case IIO_CHAN_INFO_RAW: - mutex_lock(&st->lock); ret = ad5686_read(st, chan->address); - mutex_unlock(&st->lock); if (ret < 0) return ret; *val = (ret >> chan->scan_type.shift) & GENMASK(chan->scan_type.realbits - 1, 0); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - *val = st->vref_mv; - *val2 = chan->scan_type.realbits; - return IIO_VAL_FRACTIONAL_LOG2; + if (st->double_scale) { + *val = st->scale_avail[2]; + *val2 = st->scale_avail[3]; + } else { + *val = st->scale_avail[0]; + *val2 = st->scale_avail[1]; + } + return IIO_VAL_INT_PLUS_NANO; } return -EINVAL; } @@ -198,28 +217,104 @@ static int ad5686_write_raw(struct iio_dev *indio_dev, long mask) { struct ad5686_state *st = iio_priv(indio_dev); + bool double_scale; int ret; + guard(mutex)(&st->lock); + switch (mask) { case IIO_CHAN_INFO_RAW: if (val >= (1 << chan->scan_type.realbits) || val < 0) return -EINVAL; - mutex_lock(&st->lock); - ret = ad5686_write(st, AD5686_CMD_WRITE_INPUT_N_UPDATE_N, - chan->address, val << chan->scan_type.shift); - mutex_unlock(&st->lock); - break; + return ad5686_write(st, AD5686_CMD_WRITE_INPUT_N_UPDATE_N, + chan->address, val << chan->scan_type.shift); + case IIO_CHAN_INFO_SCALE: + if (val == st->scale_avail[0] && val2 == st->scale_avail[1]) + double_scale = false; + else if (val == st->scale_avail[2] && val2 == st->scale_avail[3]) + double_scale = true; + else + return -EINVAL; + + if (st->double_scale == double_scale) + return 0; /* no change */ + + if (st->chip_info->regmap_type == AD5686_REGMAP && !st->gain_gpio) + return -EINVAL; /* GAIN pin is board-strapped */ + + st->double_scale = double_scale; + switch (st->chip_info->regmap_type) { + case AD5310_REGMAP: + ret = ad5310_control_sync(st); + break; + case AD5683_REGMAP: + ret = ad5683_control_sync(st); + break; + case AD5686_REGMAP: + ret = gpiod_set_value_cansleep(st->gain_gpio, + st->double_scale ? 1 : 0); + break; + default: + ret = -EINVAL; + } + if (ret) + st->double_scale = !double_scale; /* revert on failure */ + return ret; default: - ret = -EINVAL; + return -EINVAL; } +} - return ret; +static int ad5686_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_RAW: + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + default: + return -EINVAL; + } +} + +static int ad5686_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct ad5686_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + *type = IIO_VAL_INT_PLUS_NANO; + + if (st->chip_info->regmap_type == AD5686_REGMAP && !st->gain_gpio) { + /* + * GAIN pin is board-strapped, so only the current + * scale is available. + */ + *vals = st->double_scale ? &st->scale_avail[2] : + &st->scale_avail[0]; + *length = 2; + return IIO_AVAIL_LIST; + } + + *vals = st->scale_avail; + *length = ARRAY_SIZE(st->scale_avail); + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } } static const struct iio_info ad5686_info = { .read_raw = ad5686_read_raw, .write_raw = ad5686_write_raw, + .write_raw_get_fmt = ad5686_write_raw_get_fmt, + .read_avail = ad5686_read_avail, }; static const struct iio_chan_spec_ext_info ad5686_ext_info[] = { @@ -241,7 +336,9 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = { .channel = chan, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\ + .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE),\ .address = addr, \ + .scan_index = chan, \ .scan_type = { \ .sign = 'u', \ .realbits = (bits), \ @@ -466,10 +563,74 @@ const struct ad5686_chip_info ad5679r_chip_info = { }; EXPORT_SYMBOL_NS_GPL(ad5679r_chip_info, "IIO_AD5686"); +static void ad5686_init_scale_avail(struct ad5686_state *st) +{ + int realbits = st->chip_info->channels[0].scan_type.realbits; + s64 tmp = 2ULL * st->vref_mv * NANO >> realbits; + + st->scale_avail[2] = div_s64_rem(tmp, NANO, &st->scale_avail[3]); + st->scale_avail[0] = div_s64_rem(tmp >> 1, NANO, &st->scale_avail[1]); +} + +static void do_ad5686_trigger_handler(struct iio_dev *indio_dev) +{ + struct ad5686_state *st = iio_priv(indio_dev); + u16 val[AD5686_MAX_CHANNELS] = { }; + unsigned int scan_count, ch, i; + bool async_update; + u8 cmd; + + if (iio_pop_from_buffer(indio_dev->buffer, val)) + return; + + guard(mutex)(&st->lock); + + scan_count = bitmap_weight(indio_dev->active_scan_mask, + iio_get_masklength(indio_dev)); + async_update = st->ldac_gpio && scan_count > 1; + if (async_update) { + /* use LDAC to update all channels simultaneously */ + cmd = AD5686_CMD_WRITE_INPUT_N; + gpiod_set_value_cansleep(st->ldac_gpio, 0); + } else { + cmd = AD5686_CMD_WRITE_INPUT_N_UPDATE_N; + } + + i = 0; + iio_for_each_active_channel(indio_dev, ch) { + if (st->ops->write(st, cmd, indio_dev->channels[ch].address, val[i++])) + break; + } + + /* + * If sync() is available, it is called here regardless of write + * failure to allow bus implementation to reset. In that case, partial + * writes are unlikely as the write operations would just queue up + * the transfers. + */ + if (st->ops->sync) + st->ops->sync(st); + + if (async_update) + gpiod_set_value_cansleep(st->ldac_gpio, 1); +} + +static irqreturn_t ad5686_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + + do_ad5686_trigger_handler(indio_dev); + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} + int ad5686_probe(struct device *dev, const struct ad5686_chip_info *chip_info, - const char *name, const struct ad5686_bus_ops *ops) + const char *name, const struct ad5686_bus_ops *ops, + void *bus_data) { + struct reset_control *rstc; struct ad5686_state *st; struct iio_dev *indio_dev; int ret, i; @@ -482,14 +643,56 @@ int ad5686_probe(struct device *dev, st->dev = dev; st->ops = ops; + st->bus_data = bus_data; st->chip_info = chip_info; - ret = devm_regulator_get_enable_read_voltage(dev, "vcc"); + rstc = devm_reset_control_get_optional_exclusive(dev, NULL); + if (IS_ERR(rstc)) + return dev_err_probe(dev, PTR_ERR(rstc), + "Failed to get reset control\n"); + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, "failed to enable vdd supply\n"); + + ret = devm_regulator_get_enable(dev, "vlogic"); + if (ret) + return dev_err_probe(dev, ret, "failed to enable vlogic supply\n"); + + ret = devm_regulator_get_enable_read_voltage(dev, "vref"); + if (ret == -ENODEV) /* vcc-supply is deprecated, but supported still */ + ret = devm_regulator_get_enable_read_voltage(dev, "vcc"); if (ret < 0 && ret != -ENODEV) - return ret; + return dev_err_probe(dev, ret, "failed to read vref voltage\n"); st->use_internal_vref = ret == -ENODEV; st->vref_mv = st->use_internal_vref ? st->chip_info->int_vref_mv : ret / 1000; + if (!st->vref_mv) + return dev_err_probe(dev, -EINVAL, + "invalid or not provided vref voltage\n"); + + /* 4.5us power-up time: Datasheet Table 4: Timing Characteristics */ + fsleep(5); + + /* 1us >> 30ns reset pulse activation time: Datasheet Table 4 */ + reset_control_assert(rstc); + fsleep(1); + reset_control_deassert(rstc); + + st->ldac_gpio = devm_gpiod_get_optional(dev, "ldac", GPIOD_OUT_HIGH); + if (IS_ERR(st->ldac_gpio)) + return dev_err_probe(dev, PTR_ERR(st->ldac_gpio), + "Failed to get LDAC GPIO\n"); + + st->double_scale = device_property_read_bool(dev, "adi,range-double"); + st->gain_gpio = devm_gpiod_get_optional(dev, "gain", + st->double_scale ? GPIOD_OUT_HIGH : + GPIOD_OUT_LOW); + if (IS_ERR(st->gain_gpio)) + return dev_err_probe(dev, PTR_ERR(st->gain_gpio), + "Failed to get GAIN GPIO\n"); + + ad5686_init_scale_avail(st); /* Initialize masks to all ones */ st->pwr_down_mask = ~0; @@ -526,7 +729,7 @@ int ad5686_probe(struct device *dev, break; case AD5686_REGMAP: ret = ad5686_write(st, AD5686_CMD_INTERNAL_REFER_SETUP, 0, - st->use_internal_vref ? 0 : AD5686_REF_BIT_MSK); + st->use_internal_vref ? 0 : AD5686_DATA_REF_MSK); if (ret) return ret; break; @@ -534,6 +737,13 @@ int ad5686_probe(struct device *dev, return -EINVAL; } + ret = devm_iio_triggered_buffer_setup_ext(dev, indio_dev, NULL, + &ad5686_trigger_handler, + IIO_BUFFER_DIRECTION_OUT, + NULL, NULL); + if (ret) + return ret; + return devm_iio_device_register(dev, indio_dev); } EXPORT_SYMBOL_NS_GPL(ad5686_probe, "IIO_AD5686"); diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h index a06fe7d89305..c1222ef83a4f 100644 --- a/drivers/iio/dac/ad5686.h +++ b/drivers/iio/dac/ad5686.h @@ -14,15 +14,18 @@ #include <linux/iio/iio.h> -#define AD5310_CMD(x) ((x) << 12) +#define AD5310_CMD_MSK GENMASK(15, 12) +#define AD5310_DATA_MSK GENMASK(11, 0) -#define AD5683_DATA(x) ((x) << 4) +#define AD5683_DATA_MSK GENMASK(19, 4) -#define AD5686_ADDR(x) ((x) << 16) -#define AD5686_CMD(x) ((x) << 20) +#define AD5686_CMD_MSK GENMASK(23, 20) +#define AD5686_ADDR_MSK GENMASK(19, 16) +#define AD5686_DATA_MSK GENMASK(15, 0) #define AD5686_ADDR_DAC(chan) (0x1 << (chan)) #define AD5686_ADDR_ALL_DAC 0xF +#define AD5686_MAX_CHANNELS 16 #define AD5686_CMD_NOOP 0x0 #define AD5686_CMD_WRITE_INPUT_N 0x1 @@ -38,15 +41,17 @@ #define AD5686_CMD_CONTROL_REG 0x4 #define AD5686_CMD_READBACK_ENABLE_V2 0x5 -#define AD5310_REF_BIT_MSK BIT(8) -#define AD5310_PD_MSK GENMASK(10, 9) +#define AD5310_DATA_GAIN_MSK BIT(7) +#define AD5310_DATA_REF_MSK BIT(8) +#define AD5310_DATA_PD_MSK GENMASK(10, 9) -#define AD5683_REF_BIT_MSK BIT(12) -#define AD5683_PD_MSK GENMASK(14, 13) +#define AD5683_DATA_GAIN_MSK BIT(11) /* DB15 */ +#define AD5683_DATA_REF_MSK BIT(12) /* DB16 */ +#define AD5683_DATA_PD_MSK GENMASK(14, 13) /* DB18:DB17 */ -#define AD5686_REF_BIT_MSK BIT(0) -#define AD5686_PD_MSK GENMASK(1, 0) +#define AD5686_DATA_REF_MSK BIT(0) +#define AD5686_PD_MSK GENMASK(1, 0) #define AD5686_PD_MODE_1K_TO_GND 0x1 #define AD5686_PD_MODE_100K_TO_GND 0x2 #define AD5686_PD_MODE_THREE_STATE 0x3 @@ -60,16 +65,20 @@ enum ad5686_regmap_type { AD5686_REGMAP, }; +struct gpio_desc; + struct ad5686_state; /** * struct ad5686_bus_ops - bus specific read/write operations * @read: read a register value at the given address * @write: write a command, address and value to the device + * @sync: ensure the completion of the write operation (optional) */ struct ad5686_bus_ops { int (*read)(struct ad5686_state *st, u8 addr); int (*write)(struct ad5686_state *st, u8 cmd, u8 addr, u16 val); + int (*sync)(struct ad5686_state *st); }; /** @@ -119,23 +128,33 @@ extern const struct ad5686_chip_info ad5679r_chip_info; * @dev: device instance * @chip_info: chip model specific constants, available modes etc * @ops: bus specific operations - * @vref_mv: actual reference voltage used + * @ldac_gpio: LDAC pin GPIO descriptor + * @gain_gpio: GAIN pin GPIO descriptor * @pwr_down_mask: power down mask * @pwr_down_mode: current power down mode + * @scale_avail: pre-calculated available scale values + * @vref_mv: actual reference voltage used + * @double_scale: flag to indicate the gain multiplier is applied * @use_internal_vref: set to true if the internal reference voltage is used * @lock: lock to protect access to state fields, which includes * the data buffer during regmap ops + * @bus_data: bus specific data * @data: transfer buffers */ struct ad5686_state { struct device *dev; const struct ad5686_chip_info *chip_info; const struct ad5686_bus_ops *ops; - unsigned short vref_mv; + struct gpio_desc *ldac_gpio; + struct gpio_desc *gain_gpio; unsigned int pwr_down_mask; unsigned int pwr_down_mode; + int scale_avail[4]; + unsigned short vref_mv; + bool double_scale; bool use_internal_vref; struct mutex lock; + void *bus_data; /* * DMA (thus cache coherency maintenance) may require the @@ -146,17 +165,24 @@ struct ad5686_state { __be32 d32; __be16 d16; u8 d8[4]; - } data[3] __aligned(IIO_DMA_MINALIGN); + } data[AD5686_MAX_CHANNELS] __aligned(IIO_DMA_MINALIGN); }; int ad5686_probe(struct device *dev, const struct ad5686_chip_info *chip_info, - const char *name, const struct ad5686_bus_ops *ops); + const char *name, const struct ad5686_bus_ops *ops, + void *bus_data); static inline int ad5686_write(struct ad5686_state *st, u8 cmd, u8 addr, u16 val) { - return st->ops->write(st, cmd, addr, val); + int ret; + + ret = st->ops->write(st, cmd, addr, val); + if (ret) + return ret; + + return st->ops->sync ? st->ops->sync(st) : 0; } static inline int ad5686_read(struct ad5686_state *st, u8 addr) diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c index d49946adbde3..046f904f7c88 100644 --- a/drivers/iio/dac/ad5696-i2c.c +++ b/drivers/iio/dac/ad5696-i2c.c @@ -7,6 +7,7 @@ * Copyright 2018 Analog Devices Inc. */ +#include <linux/bitfield.h> #include <linux/errno.h> #include <linux/i2c.h> #include <linux/module.h> @@ -34,9 +35,8 @@ static int ad5686_i2c_read(struct ad5686_state *st, u8 addr) }; int ret; - st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP) | - AD5686_ADDR(addr) | - 0x00); + st->data[0].d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, AD5686_CMD_NOOP) | + FIELD_PREP(AD5686_ADDR_MSK, addr)); ret = i2c_transfer(i2c->adapter, msg, 2); if (ret < 0) @@ -51,8 +51,9 @@ static int ad5686_i2c_write(struct ad5686_state *st, struct i2c_client *i2c = to_i2c_client(st->dev); int ret; - st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) | AD5686_ADDR(addr) - | val); + st->data[0].d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, cmd) | + FIELD_PREP(AD5686_ADDR_MSK, addr) | + FIELD_PREP(AD5686_DATA_MSK, val)); ret = i2c_master_send(i2c, &st->data[0].d8[1], 3); if (ret < 0) @@ -68,8 +69,13 @@ static const struct ad5686_bus_ops ad5686_i2c_ops = { static int ad5686_i2c_probe(struct i2c_client *i2c) { - return ad5686_probe(&i2c->dev, i2c_get_match_data(i2c), - i2c->name, &ad5686_i2c_ops); + const struct ad5686_chip_info *info; + + info = i2c_get_match_data(i2c); + if (!info) + return -ENODATA; + + return ad5686_probe(&i2c->dev, info, i2c->name, &ad5686_i2c_ops, NULL); } static const struct i2c_device_id ad5686_i2c_id[] = { diff --git a/drivers/iio/dac/ad5706r.c b/drivers/iio/dac/ad5706r.c index e4e48ca7ad34..06c4860a7eba 100644 --- a/drivers/iio/dac/ad5706r.c +++ b/drivers/iio/dac/ad5706r.c @@ -232,7 +232,7 @@ static const struct of_device_id ad5706r_of_match[] = { MODULE_DEVICE_TABLE(of, ad5706r_of_match); static const struct spi_device_id ad5706r_id[] = { - { "ad5706r" }, + { .name = "ad5706r" }, { } }; MODULE_DEVICE_TABLE(spi, ad5706r_id); diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c index cc6d56140d66..0828b9909099 100644 --- a/drivers/iio/dac/ad5755.c +++ b/drivers/iio/dac/ad5755.c @@ -849,11 +849,11 @@ static int ad5755_probe(struct spi_device *spi) } static const struct spi_device_id ad5755_id[] = { - { "ad5755", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5755] }, - { "ad5755-1", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5755] }, - { "ad5757", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5757] }, - { "ad5735", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5735] }, - { "ad5737", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5737] }, + { .name = "ad5755", .driver_data = (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5755] }, + { .name = "ad5755-1", .driver_data = (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5755] }, + { .name = "ad5757", .driver_data = (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5757] }, + { .name = "ad5735", .driver_data = (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5735] }, + { .name = "ad5737", .driver_data = (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5737] }, { } }; MODULE_DEVICE_TABLE(spi, ad5755_id); diff --git a/drivers/iio/dac/ad5758.c b/drivers/iio/dac/ad5758.c index bb30842e7080..44efa373cd80 100644 --- a/drivers/iio/dac/ad5758.c +++ b/drivers/iio/dac/ad5758.c @@ -878,7 +878,7 @@ static int ad5758_probe(struct spi_device *spi) } static const struct spi_device_id ad5758_id[] = { - { "ad5758", 0 }, + { .name = "ad5758" }, { } }; MODULE_DEVICE_TABLE(spi, ad5758_id); diff --git a/drivers/iio/dac/ad5761.c b/drivers/iio/dac/ad5761.c index b5d20f04f070..c49568b943d6 100644 --- a/drivers/iio/dac/ad5761.c +++ b/drivers/iio/dac/ad5761.c @@ -342,10 +342,10 @@ static int ad5761_probe(struct spi_device *spi) } static const struct spi_device_id ad5761_id[] = { - {"ad5721", ID_AD5721}, - {"ad5721r", ID_AD5721R}, - {"ad5761", ID_AD5761}, - {"ad5761r", ID_AD5761R}, + { .name = "ad5721", .driver_data = ID_AD5721 }, + { .name = "ad5721r", .driver_data = ID_AD5721R }, + { .name = "ad5761", .driver_data = ID_AD5761 }, + { .name = "ad5761r", .driver_data = ID_AD5761R }, { } }; MODULE_DEVICE_TABLE(spi, ad5761_id); diff --git a/drivers/iio/dac/ad5764.c b/drivers/iio/dac/ad5764.c index fbbd7105a80c..2be4bee7eb01 100644 --- a/drivers/iio/dac/ad5764.c +++ b/drivers/iio/dac/ad5764.c @@ -342,10 +342,10 @@ static void ad5764_remove(struct spi_device *spi) } static const struct spi_device_id ad5764_ids[] = { - { "ad5744", ID_AD5744 }, - { "ad5744r", ID_AD5744R }, - { "ad5764", ID_AD5764 }, - { "ad5764r", ID_AD5764R }, + { .name = "ad5744", .driver_data = ID_AD5744 }, + { .name = "ad5744r", .driver_data = ID_AD5744R }, + { .name = "ad5764", .driver_data = ID_AD5764 }, + { .name = "ad5764r", .driver_data = ID_AD5764R }, { } }; MODULE_DEVICE_TABLE(spi, ad5764_ids); diff --git a/drivers/iio/dac/ad5766.c b/drivers/iio/dac/ad5766.c index f6a0a0d84fef..061b43fc0345 100644 --- a/drivers/iio/dac/ad5766.c +++ b/drivers/iio/dac/ad5766.c @@ -651,8 +651,8 @@ static const struct of_device_id ad5766_dt_match[] = { MODULE_DEVICE_TABLE(of, ad5766_dt_match); static const struct spi_device_id ad5766_spi_ids[] = { - { "ad5766", ID_AD5766 }, - { "ad5767", ID_AD5767 }, + { .name = "ad5766", .driver_data = ID_AD5766 }, + { .name = "ad5767", .driver_data = ID_AD5767 }, { } }; MODULE_DEVICE_TABLE(spi, ad5766_spi_ids); diff --git a/drivers/iio/dac/ad5770r.c b/drivers/iio/dac/ad5770r.c index 6027e8d88b27..bdc48e57013f 100644 --- a/drivers/iio/dac/ad5770r.c +++ b/drivers/iio/dac/ad5770r.c @@ -642,7 +642,7 @@ static const struct of_device_id ad5770r_of_id[] = { MODULE_DEVICE_TABLE(of, ad5770r_of_id); static const struct spi_device_id ad5770r_id[] = { - { "ad5770r", 0 }, + { .name = "ad5770r" }, { } }; MODULE_DEVICE_TABLE(spi, ad5770r_id); diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c index ae7297f08398..a5eda135c9bd 100644 --- a/drivers/iio/dac/ad5791.c +++ b/drivers/iio/dac/ad5791.c @@ -586,11 +586,11 @@ static const struct of_device_id ad5791_of_match[] = { MODULE_DEVICE_TABLE(of, ad5791_of_match); static const struct spi_device_id ad5791_id[] = { - { "ad5760", (kernel_ulong_t)&ad5760_chip_info }, - { "ad5780", (kernel_ulong_t)&ad5780_chip_info }, - { "ad5781", (kernel_ulong_t)&ad5781_chip_info }, - { "ad5790", (kernel_ulong_t)&ad5790_chip_info }, - { "ad5791", (kernel_ulong_t)&ad5791_chip_info }, + { .name = "ad5760", .driver_data = (kernel_ulong_t)&ad5760_chip_info }, + { .name = "ad5780", .driver_data = (kernel_ulong_t)&ad5780_chip_info }, + { .name = "ad5781", .driver_data = (kernel_ulong_t)&ad5781_chip_info }, + { .name = "ad5790", .driver_data = (kernel_ulong_t)&ad5790_chip_info }, + { .name = "ad5791", .driver_data = (kernel_ulong_t)&ad5791_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad5791_id); diff --git a/drivers/iio/dac/ad7293.c b/drivers/iio/dac/ad7293.c index 03acf7c114b0..33a49813ece0 100644 --- a/drivers/iio/dac/ad7293.c +++ b/drivers/iio/dac/ad7293.c @@ -869,7 +869,7 @@ static int ad7293_probe(struct spi_device *spi) } static const struct spi_device_id ad7293_id[] = { - { "ad7293", 0 }, + { .name = "ad7293" }, { } }; MODULE_DEVICE_TABLE(spi, ad7293_id); diff --git a/drivers/iio/dac/ad7303.c b/drivers/iio/dac/ad7303.c index 6451fc586a67..83153e7d7fc8 100644 --- a/drivers/iio/dac/ad7303.c +++ b/drivers/iio/dac/ad7303.c @@ -270,7 +270,7 @@ static const struct of_device_id ad7303_spi_of_match[] = { MODULE_DEVICE_TABLE(of, ad7303_spi_of_match); static const struct spi_device_id ad7303_spi_ids[] = { - { "ad7303", 0 }, + { .name = "ad7303" }, { } }; MODULE_DEVICE_TABLE(spi, ad7303_spi_ids); diff --git a/drivers/iio/dac/ad8460.c b/drivers/iio/dac/ad8460.c index ddec62b6e57b..a2292810e4cf 100644 --- a/drivers/iio/dac/ad8460.c +++ b/drivers/iio/dac/ad8460.c @@ -954,3 +954,4 @@ MODULE_AUTHOR("Mariel Tinaco <mariel.tinaco@analog.com"); MODULE_DESCRIPTION("AD8460 DAC driver"); MODULE_LICENSE("GPL"); MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/iio/dac/ad8801.c b/drivers/iio/dac/ad8801.c index 60e663af1cc1..08d7d74e999e 100644 --- a/drivers/iio/dac/ad8801.c +++ b/drivers/iio/dac/ad8801.c @@ -151,8 +151,8 @@ static int ad8801_probe(struct spi_device *spi) } static const struct spi_device_id ad8801_ids[] = { - {"ad8801", ID_AD8801}, - {"ad8803", ID_AD8803}, + { .name = "ad8801", .driver_data = ID_AD8801 }, + { .name = "ad8803", .driver_data = ID_AD8803 }, { } }; MODULE_DEVICE_TABLE(spi, ad8801_ids); diff --git a/drivers/iio/dac/ad9739a.c b/drivers/iio/dac/ad9739a.c index ccd6a3b1e891..5263a0c968f5 100644 --- a/drivers/iio/dac/ad9739a.c +++ b/drivers/iio/dac/ad9739a.c @@ -446,7 +446,7 @@ static const struct of_device_id ad9739a_of_match[] = { MODULE_DEVICE_TABLE(of, ad9739a_of_match); static const struct spi_device_id ad9739a_id[] = { - {"ad9739a"}, + { .name = "ad9739a" }, { } }; MODULE_DEVICE_TABLE(spi, ad9739a_id); diff --git a/drivers/iio/dac/dpot-dac.c b/drivers/iio/dac/dpot-dac.c index cf6d94e7af84..de36e2e27330 100644 --- a/drivers/iio/dac/dpot-dac.c +++ b/drivers/iio/dac/dpot-dac.c @@ -253,3 +253,4 @@ module_platform_driver(dpot_dac_driver); MODULE_DESCRIPTION("DAC emulation driver using a digital potentiometer"); MODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/iio/dac/ltc1660.c b/drivers/iio/dac/ltc1660.c index 6e80b49f4665..90ffb58e7927 100644 --- a/drivers/iio/dac/ltc1660.c +++ b/drivers/iio/dac/ltc1660.c @@ -224,8 +224,8 @@ static const struct of_device_id ltc1660_dt_ids[] = { MODULE_DEVICE_TABLE(of, ltc1660_dt_ids); static const struct spi_device_id ltc1660_id[] = { - {"ltc1660", ID_LTC1660}, - {"ltc1665", ID_LTC1665}, + { .name = "ltc1660", .driver_data = ID_LTC1660 }, + { .name = "ltc1665", .driver_data = ID_LTC1665 }, { } }; MODULE_DEVICE_TABLE(spi, ltc1660_id); diff --git a/drivers/iio/dac/ltc2632.c b/drivers/iio/dac/ltc2632.c index d6a3d290e7a8..3800aee8dd6e 100644 --- a/drivers/iio/dac/ltc2632.c +++ b/drivers/iio/dac/ltc2632.c @@ -362,28 +362,28 @@ static int ltc2632_probe(struct spi_device *spi) } static const struct spi_device_id ltc2632_id[] = { - { "ltc2632-l12", (kernel_ulong_t)<c2632l12_chip_info }, - { "ltc2632-l10", (kernel_ulong_t)<c2632l10_chip_info }, - { "ltc2632-l8", (kernel_ulong_t)<c2632l8_chip_info }, - { "ltc2632-h12", (kernel_ulong_t)<c2632h12_chip_info }, - { "ltc2632-h10", (kernel_ulong_t)<c2632h10_chip_info }, - { "ltc2632-h8", (kernel_ulong_t)<c2632h8_chip_info }, - { "ltc2634-l12", (kernel_ulong_t)<c2634l12_chip_info }, - { "ltc2634-l10", (kernel_ulong_t)<c2634l10_chip_info }, - { "ltc2634-l8", (kernel_ulong_t)<c2634l8_chip_info }, - { "ltc2634-h12", (kernel_ulong_t)<c2634h12_chip_info }, - { "ltc2634-h10", (kernel_ulong_t)<c2634h10_chip_info }, - { "ltc2634-h8", (kernel_ulong_t)<c2634h8_chip_info }, - { "ltc2636-l12", (kernel_ulong_t)<c2636l12_chip_info }, - { "ltc2636-l10", (kernel_ulong_t)<c2636l10_chip_info }, - { "ltc2636-l8", (kernel_ulong_t)<c2636l8_chip_info }, - { "ltc2636-h12", (kernel_ulong_t)<c2636h12_chip_info }, - { "ltc2636-h10", (kernel_ulong_t)<c2636h10_chip_info }, - { "ltc2636-h8", (kernel_ulong_t)<c2636h8_chip_info }, - { "ltc2654-l16", (kernel_ulong_t)<c2654l16_chip_info }, - { "ltc2654-l12", (kernel_ulong_t)<c2634l12_chip_info }, - { "ltc2654-h16", (kernel_ulong_t)<c2654h16_chip_info }, - { "ltc2654-h12", (kernel_ulong_t)<c2634h12_chip_info }, + { .name = "ltc2632-l12", .driver_data = (kernel_ulong_t)<c2632l12_chip_info }, + { .name = "ltc2632-l10", .driver_data = (kernel_ulong_t)<c2632l10_chip_info }, + { .name = "ltc2632-l8", .driver_data = (kernel_ulong_t)<c2632l8_chip_info }, + { .name = "ltc2632-h12", .driver_data = (kernel_ulong_t)<c2632h12_chip_info }, + { .name = "ltc2632-h10", .driver_data = (kernel_ulong_t)<c2632h10_chip_info }, + { .name = "ltc2632-h8", .driver_data = (kernel_ulong_t)<c2632h8_chip_info }, + { .name = "ltc2634-l12", .driver_data = (kernel_ulong_t)<c2634l12_chip_info }, + { .name = "ltc2634-l10", .driver_data = (kernel_ulong_t)<c2634l10_chip_info }, + { .name = "ltc2634-l8", .driver_data = (kernel_ulong_t)<c2634l8_chip_info }, + { .name = "ltc2634-h12", .driver_data = (kernel_ulong_t)<c2634h12_chip_info }, + { .name = "ltc2634-h10", .driver_data = (kernel_ulong_t)<c2634h10_chip_info }, + { .name = "ltc2634-h8", .driver_data = (kernel_ulong_t)<c2634h8_chip_info }, + { .name = "ltc2636-l12", .driver_data = (kernel_ulong_t)<c2636l12_chip_info }, + { .name = "ltc2636-l10", .driver_data = (kernel_ulong_t)<c2636l10_chip_info }, + { .name = "ltc2636-l8", .driver_data = (kernel_ulong_t)<c2636l8_chip_info }, + { .name = "ltc2636-h12", .driver_data = (kernel_ulong_t)<c2636h12_chip_info }, + { .name = "ltc2636-h10", .driver_data = (kernel_ulong_t)<c2636h10_chip_info }, + { .name = "ltc2636-h8", .driver_data = (kernel_ulong_t)<c2636h8_chip_info }, + { .name = "ltc2654-l16", .driver_data = (kernel_ulong_t)<c2654l16_chip_info }, + { .name = "ltc2654-l12", .driver_data = (kernel_ulong_t)<c2634l12_chip_info }, + { .name = "ltc2654-h16", .driver_data = (kernel_ulong_t)<c2654h16_chip_info }, + { .name = "ltc2654-h12", .driver_data = (kernel_ulong_t)<c2634h12_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ltc2632_id); diff --git a/drivers/iio/dac/ltc2664.c b/drivers/iio/dac/ltc2664.c index c48b9efc8280..35bec55ebde1 100644 --- a/drivers/iio/dac/ltc2664.c +++ b/drivers/iio/dac/ltc2664.c @@ -708,8 +708,8 @@ static int ltc2664_probe(struct spi_device *spi) } static const struct spi_device_id ltc2664_id[] = { - { "ltc2664", (kernel_ulong_t)<c2664_chip }, - { "ltc2672", (kernel_ulong_t)<c2672_chip }, + { .name = "ltc2664", .driver_data = (kernel_ulong_t)<c2664_chip }, + { .name = "ltc2672", .driver_data = (kernel_ulong_t)<c2672_chip }, { } }; MODULE_DEVICE_TABLE(spi, ltc2664_id); diff --git a/drivers/iio/dac/ltc2688.c b/drivers/iio/dac/ltc2688.c index a575ef8371dc..0301bb7dce31 100644 --- a/drivers/iio/dac/ltc2688.c +++ b/drivers/iio/dac/ltc2688.c @@ -991,7 +991,7 @@ static const struct of_device_id ltc2688_of_id[] = { MODULE_DEVICE_TABLE(of, ltc2688_of_id); static const struct spi_device_id ltc2688_id[] = { - { "ltc2688" }, + { .name = "ltc2688" }, { } }; MODULE_DEVICE_TABLE(spi, ltc2688_id); diff --git a/drivers/iio/dac/max22007.c b/drivers/iio/dac/max22007.c index d747901df5a3..e2c7e2ad37ba 100644 --- a/drivers/iio/dac/max22007.c +++ b/drivers/iio/dac/max22007.c @@ -464,7 +464,7 @@ static int max22007_probe(struct spi_device *spi) } static const struct spi_device_id max22007_id[] = { - { "max22007" }, + { .name = "max22007" }, { } }; MODULE_DEVICE_TABLE(spi, max22007_id); diff --git a/drivers/iio/dac/max5522.c b/drivers/iio/dac/max5522.c index 1459ba132df6..f3415748c765 100644 --- a/drivers/iio/dac/max5522.c +++ b/drivers/iio/dac/max5522.c @@ -24,15 +24,8 @@ #define MAX5522_REG_DATA(x) ((x) + MAX5522_CTRL_LOAD_IN_A) -struct max5522_chip_info { - const char *name; - const struct iio_chan_spec *channels; - unsigned int num_channels; -}; - struct max5522_state { struct regmap *regmap; - const struct max5522_chip_info *chip_info; unsigned short dac_cache[2]; int vref_mV; }; @@ -57,18 +50,6 @@ static const struct iio_chan_spec max5522_channels[] = { MAX5522_CHANNEL(1), }; -enum max5522_type { - ID_MAX5522, -}; - -static const struct max5522_chip_info max5522_chip_info_tbl[] = { - [ID_MAX5522] = { - .name = "max5522", - .channels = max5522_channels, - .num_channels = 2, - }, -}; - static inline int max5522_info_to_reg(struct iio_chan_spec const *chan) { return MAX5522_REG_DATA(chan->channel); @@ -139,9 +120,6 @@ static int max5522_spi_probe(struct spi_device *spi) } state = iio_priv(indio_dev); - state->chip_info = spi_get_device_match_data(spi); - if (!state->chip_info) - return -EINVAL; ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vrefin"); if (ret < 0) @@ -158,22 +136,19 @@ static int max5522_spi_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = max5522_channels; indio_dev->num_channels = ARRAY_SIZE(max5522_channels); - indio_dev->name = max5522_chip_info_tbl[ID_MAX5522].name; + indio_dev->name = "max5522"; return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id max5522_ids[] = { - { "max5522", (kernel_ulong_t)&max5522_chip_info_tbl[ID_MAX5522] }, + { .name = "max5522" }, { } }; MODULE_DEVICE_TABLE(spi, max5522_ids); static const struct of_device_id max5522_of_match[] = { - { - .compatible = "maxim,max5522", - .data = &max5522_chip_info_tbl[ID_MAX5522], - }, + { .compatible = "maxim,max5522" }, { } }; MODULE_DEVICE_TABLE(of, max5522_of_match); diff --git a/drivers/iio/dac/mcf54415_dac.c b/drivers/iio/dac/mcf54415_dac.c new file mode 100644 index 000000000000..e2c12241a534 --- /dev/null +++ b/drivers/iio/dac/mcf54415_dac.c @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * NXP mcf54415 DAC driver + * + * Copyright 2026 BayLibre - adureghello@baylibre.com + */ + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/types.h> + +#include <linux/iio/iio.h> + +#define MCF54415_DAC_CR 0x00 +#define MCF54415_DAC_CR_PDN BIT(0) +#define MCF54415_DAC_CR_HSLS BIT(6) +#define MCF54415_DAC_CR_WMLVL GENMASK(9, 8) +#define MCF54415_DAC_CR_FILT BIT(12) + +#define MCF54415_DAC_DATA 0x02 + +struct mcf54415_dac { + struct regmap *map; + struct clk *clk; +}; + +static const struct regmap_config mcf54415_dac_regmap_config = { + .reg_bits = 16, + .reg_stride = 2, + .val_bits = 16, + .max_register = 0x0c, /* DACX_FILTCNT, R.M. Table 30-2 */ + .val_format_endian = REGMAP_ENDIAN_BIG, + .reg_format_endian = REGMAP_ENDIAN_BIG, +}; + +static int mcf54415_dac_init(struct mcf54415_dac *info) +{ + u16 val = MCF54415_DAC_CR_FILT | FIELD_PREP(MCF54415_DAC_CR_WMLVL, 1); + int ret; + + /* Fixed defaults and enable DAC (bit 0 set to 0) */ + ret = regmap_write(info->map, MCF54415_DAC_CR, val); + if (ret) + return ret; + + /* DAC is ready after 12us, from RM table 40-3 */ + fsleep(12); + + return 0; +} + +static void mcf54415_dac_exit(void *data) +{ + struct mcf54415_dac *info = data; + + regmap_set_bits(info->map, MCF54415_DAC_CR, MCF54415_DAC_CR_PDN); +} + +static const struct iio_chan_spec mcf54415_dac_iio_channel = { + .type = IIO_VOLTAGE, + .output = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), +}; + +static int mcf54415_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct mcf54415_dac *info = iio_priv(indio_dev); + unsigned int reg; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = regmap_read(info->map, MCF54415_DAC_DATA, ®); + if (ret) + return ret; + *val = reg & GENMASK(11, 0); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + /* Reference voltage as per ColdFire datasheet is 3.3V */ + *val = 3300 /* mV */; + *val2 = 12; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } +} + +static int mcf54415_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct mcf54415_dac *info = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + /* Check based on RM 30.3.2 (DACn_DATA) reg. resolution */ + if (val < 0 || val > 4095) + return -EINVAL; + return regmap_write(info->map, MCF54415_DAC_DATA, val); + default: + return -EINVAL; + } +} + +static const struct iio_info mcf54415_dac_iio_info = { + .read_raw = &mcf54415_read_raw, + .write_raw = &mcf54415_write_raw, +}; + +static int mcf54415_dac_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct iio_dev *indio_dev; + struct mcf54415_dac *info; + void __iomem *regs; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*info)); + if (!indio_dev) + return -ENOMEM; + + info = iio_priv(indio_dev); + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) + return dev_err_probe(dev, PTR_ERR(regs), "failed to get io regs\n"); + + info->map = devm_regmap_init_mmio(dev, regs, &mcf54415_dac_regmap_config); + if (IS_ERR(info->map)) + return PTR_ERR(info->map); + + info->clk = devm_clk_get_enabled(dev, "dac"); + if (IS_ERR(info->clk)) + return dev_err_probe(dev, PTR_ERR(info->clk), "failed getting clock\n"); + + indio_dev->name = "mcf54415"; + indio_dev->info = &mcf54415_dac_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = &mcf54415_dac_iio_channel; + indio_dev->num_channels = 1; + + ret = mcf54415_dac_init(info); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, mcf54415_dac_exit, info); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct platform_device_id mcf54415_dac_ids[] = { + { .name = "mcfdac" }, + { } +}; +MODULE_DEVICE_TABLE(platform, mcf54415_dac_ids); + +static struct platform_driver mcf54415_dac_driver = { + .driver = { + .name = "mcf54415_dac", + }, + .probe = mcf54415_dac_probe, + .id_table = mcf54415_dac_ids, +}; +module_platform_driver(mcf54415_dac_driver); + +MODULE_AUTHOR("Angelo Dureghello <angelo@kernel-space.org>"); +MODULE_DESCRIPTION("NXP MCF54415 DAC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/dac/mcp4821.c b/drivers/iio/dac/mcp4821.c index d2e7c930c848..8d8c00cd60e9 100644 --- a/drivers/iio/dac/mcp4821.c +++ b/drivers/iio/dac/mcp4821.c @@ -297,12 +297,12 @@ static const struct of_device_id mcp4821_of_table[] = { MODULE_DEVICE_TABLE(of, mcp4821_of_table); static const struct spi_device_id mcp4821_id_table[] = { - { "mcp4801", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4801]}, - { "mcp4802", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4802]}, - { "mcp4811", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4811]}, - { "mcp4812", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4812]}, - { "mcp4821", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4821]}, - { "mcp4822", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4822]}, + { .name = "mcp4801", .driver_data = (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4801] }, + { .name = "mcp4802", .driver_data = (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4802] }, + { .name = "mcp4811", .driver_data = (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4811] }, + { .name = "mcp4812", .driver_data = (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4812] }, + { .name = "mcp4821", .driver_data = (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4821] }, + { .name = "mcp4822", .driver_data = (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4822] }, { } }; MODULE_DEVICE_TABLE(spi, mcp4821_id_table); diff --git a/drivers/iio/dac/mcp4922.c b/drivers/iio/dac/mcp4922.c index 74f338afcab9..15072a9081ff 100644 --- a/drivers/iio/dac/mcp4922.c +++ b/drivers/iio/dac/mcp4922.c @@ -157,10 +157,10 @@ static int mcp4922_probe(struct spi_device *spi) static const struct spi_device_id mcp4922_id[] = { - {"mcp4902", ID_MCP4902}, - {"mcp4912", ID_MCP4912}, - {"mcp4921", ID_MCP4921}, - {"mcp4922", ID_MCP4922}, + { .name = "mcp4902", .driver_data = ID_MCP4902 }, + { .name = "mcp4912", .driver_data = ID_MCP4912 }, + { .name = "mcp4921", .driver_data = ID_MCP4921 }, + { .name = "mcp4922", .driver_data = ID_MCP4922 }, { } }; MODULE_DEVICE_TABLE(spi, mcp4922_id); diff --git a/drivers/iio/dac/rohm-bd79703.c b/drivers/iio/dac/rohm-bd79703.c index e91090e4a66d..6e2e7787f8a4 100644 --- a/drivers/iio/dac/rohm-bd79703.c +++ b/drivers/iio/dac/rohm-bd79703.c @@ -214,10 +214,10 @@ static int bd79703_probe(struct spi_device *spi) } static const struct spi_device_id bd79703_id[] = { - { "bd79700", (kernel_ulong_t)&bd79700_chip_data }, - { "bd79701", (kernel_ulong_t)&bd79701_chip_data }, - { "bd79702", (kernel_ulong_t)&bd79702_chip_data }, - { "bd79703", (kernel_ulong_t)&bd79703_chip_data }, + { .name = "bd79700", .driver_data = (kernel_ulong_t)&bd79700_chip_data }, + { .name = "bd79701", .driver_data = (kernel_ulong_t)&bd79701_chip_data }, + { .name = "bd79702", .driver_data = (kernel_ulong_t)&bd79702_chip_data }, + { .name = "bd79703", .driver_data = (kernel_ulong_t)&bd79703_chip_data }, { } }; MODULE_DEVICE_TABLE(spi, bd79703_id); diff --git a/drivers/iio/dac/ti-dac082s085.c b/drivers/iio/dac/ti-dac082s085.c index 6e62c1f302c8..afa7d9bad5de 100644 --- a/drivers/iio/dac/ti-dac082s085.c +++ b/drivers/iio/dac/ti-dac082s085.c @@ -334,12 +334,12 @@ static const struct of_device_id ti_dac_of_id[] = { MODULE_DEVICE_TABLE(of, ti_dac_of_id); static const struct spi_device_id ti_dac_spi_id[] = { - { "dac082s085", dual_8bit }, - { "dac102s085", dual_10bit }, - { "dac122s085", dual_12bit }, - { "dac084s085", quad_8bit }, - { "dac104s085", quad_10bit }, - { "dac124s085", quad_12bit }, + { .name = "dac082s085", .driver_data = dual_8bit }, + { .name = "dac102s085", .driver_data = dual_10bit }, + { .name = "dac122s085", .driver_data = dual_12bit }, + { .name = "dac084s085", .driver_data = quad_8bit }, + { .name = "dac104s085", .driver_data = quad_10bit }, + { .name = "dac124s085", .driver_data = quad_12bit }, { } }; MODULE_DEVICE_TABLE(spi, ti_dac_spi_id); diff --git a/drivers/iio/dac/ti-dac7311.c b/drivers/iio/dac/ti-dac7311.c index 5c1c5213962f..e5843bd35259 100644 --- a/drivers/iio/dac/ti-dac7311.c +++ b/drivers/iio/dac/ti-dac7311.c @@ -311,9 +311,9 @@ static const struct of_device_id ti_dac_of_id[] = { MODULE_DEVICE_TABLE(of, ti_dac_of_id); static const struct spi_device_id ti_dac_spi_id[] = { - { "dac5311", ID_DAC5311 }, - { "dac6311", ID_DAC6311 }, - { "dac7311", ID_DAC7311 }, + { .name = "dac5311", .driver_data = ID_DAC5311 }, + { .name = "dac6311", .driver_data = ID_DAC6311 }, + { .name = "dac7311", .driver_data = ID_DAC7311 }, { } }; MODULE_DEVICE_TABLE(spi, ti_dac_spi_id); diff --git a/drivers/iio/dac/ti-dac7612.c b/drivers/iio/dac/ti-dac7612.c index c308eca02b88..9065663cd609 100644 --- a/drivers/iio/dac/ti-dac7612.c +++ b/drivers/iio/dac/ti-dac7612.c @@ -165,7 +165,7 @@ static int dac7612_probe(struct spi_device *spi) } static const struct spi_device_id dac7612_id[] = { - {"ti-dac7612"}, + { .name = "ti-dac7612" }, { } }; MODULE_DEVICE_TABLE(spi, dac7612_id); diff --git a/drivers/iio/filter/admv8818.c b/drivers/iio/filter/admv8818.c index 8bcd298e1f3d..b88689e60cc8 100644 --- a/drivers/iio/filter/admv8818.c +++ b/drivers/iio/filter/admv8818.c @@ -789,7 +789,7 @@ static int admv8818_probe(struct spi_device *spi) } static const struct spi_device_id admv8818_id[] = { - { "admv8818", 0 }, + { .name = "admv8818" }, { } }; MODULE_DEVICE_TABLE(spi, admv8818_id); diff --git a/drivers/iio/frequency/Kconfig b/drivers/iio/frequency/Kconfig index 583cbdf4e8cd..90c6304c4bcd 100644 --- a/drivers/iio/frequency/Kconfig +++ b/drivers/iio/frequency/Kconfig @@ -29,6 +29,16 @@ endmenu menu "Phase-Locked Loop (PLL) frequency synthesizers" +config ADF41513 + tristate "Analog Devices ADF41513 PLL Frequency Synthesizer" + depends on SPI + help + Say yes here to build support for Analog Devices ADF41513 + 26.5 GHz Integer-N/Fractional-N PLL Frequency Synthesizer. + + To compile this driver as a module, choose M here: the + module will be called adf41513. + config ADF4350 tristate "Analog Devices ADF4350/ADF4351 Wideband Synthesizers" depends on SPI diff --git a/drivers/iio/frequency/Makefile b/drivers/iio/frequency/Makefile index 70d0e0b70e80..53b4d01414d8 100644 --- a/drivers/iio/frequency/Makefile +++ b/drivers/iio/frequency/Makefile @@ -5,6 +5,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_AD9523) += ad9523.o +obj-$(CONFIG_ADF41513) += adf41513.o obj-$(CONFIG_ADF4350) += adf4350.o obj-$(CONFIG_ADF4371) += adf4371.o obj-$(CONFIG_ADF4377) += adf4377.o diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c index ea4d2763564a..1e393f40a8c8 100644 --- a/drivers/iio/frequency/ad9523.c +++ b/drivers/iio/frequency/ad9523.c @@ -990,7 +990,6 @@ static int ad9523_probe(struct spi_device *spi) if (IS_ERR(st->sync_gpio)) return PTR_ERR(st->sync_gpio); - spi_set_drvdata(spi, indio_dev); st->spi = spi; st->pdata = pdata; @@ -1009,7 +1008,7 @@ static int ad9523_probe(struct spi_device *spi) } static const struct spi_device_id ad9523_id[] = { - {"ad9523-1", 9523}, + { .name = "ad9523-1" }, { } }; MODULE_DEVICE_TABLE(spi, ad9523_id); diff --git a/drivers/iio/frequency/adf41513.c b/drivers/iio/frequency/adf41513.c new file mode 100644 index 000000000000..c497027012ba --- /dev/null +++ b/drivers/iio/frequency/adf41513.c @@ -0,0 +1,1246 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ADF41513 SPI PLL Frequency Synthesizer driver + * + * Copyright 2026 Analog Devices Inc. + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/clk.h> +#include <linux/dev_printk.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/kstrtox.h> +#include <linux/log2.h> +#include <linux/math64.h> +#include <linux/minmax.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/pm.h> +#include <linux/property.h> +#include <linux/regulator/consumer.h> +#include <linux/spi/spi.h> +#include <linux/sysfs.h> +#include <linux/time64.h> +#include <linux/types.h> +#include <linux/units.h> + +#include <linux/iio/iio.h> + +/* Registers */ +#define ADF41513_REG0 0 +#define ADF41513_REG1 1 +#define ADF41513_REG2 2 +#define ADF41513_REG3 3 +#define ADF41513_REG4 4 +#define ADF41513_REG5 5 +#define ADF41513_REG6 6 +#define ADF41513_REG7 7 +#define ADF41513_REG8 8 +#define ADF41513_REG9 9 +#define ADF41513_REG10 10 +#define ADF41513_REG11 11 +#define ADF41513_REG12 12 +#define ADF41513_REG13 13 +#define ADF41513_REG_NUM 14 + +#define ADF41513_SYNC_REG0 BIT(ADF41513_REG0) +#define ADF41513_SYNC_REG1 BIT(ADF41513_REG1) +#define ADF41513_SYNC_REG2 BIT(ADF41513_REG2) +#define ADF41513_SYNC_REG3 BIT(ADF41513_REG3) +#define ADF41513_SYNC_REG4 BIT(ADF41513_REG4) +#define ADF41513_SYNC_REG5 BIT(ADF41513_REG5) +#define ADF41513_SYNC_REG6 BIT(ADF41513_REG6) +#define ADF41513_SYNC_REG7 BIT(ADF41513_REG7) +#define ADF41513_SYNC_REG9 BIT(ADF41513_REG9) +#define ADF41513_SYNC_REG11 BIT(ADF41513_REG11) +#define ADF41513_SYNC_REG12 BIT(ADF41513_REG12) +#define ADF41513_SYNC_REG13 BIT(ADF41513_REG13) +#define ADF41513_SYNC_DIFF 0 +#define ADF41513_SYNC_ALL GENMASK(ADF41513_REG13, ADF41513_REG0) + +/* REG0 Bit Definitions */ +#define ADF41513_REG0_CTRL_BITS_MSK GENMASK(3, 0) +#define ADF41513_REG0_INT_MSK GENMASK(19, 4) +#define ADF41513_REG0_VAR_MOD_MSK BIT(28) + +/* REG1 Bit Definitions */ +#define ADF41513_REG1_FRAC1_MSK GENMASK(28, 4) +#define ADF41513_REG1_DITHER2_MSK BIT(31) + +/* REG2 Bit Definitions */ +#define ADF41513_REG2_PHASE_VAL_MSK GENMASK(15, 4) +#define ADF41513_REG2_PHASE_ADJ_MSK BIT(31) + +/* REG3 Bit Definitions */ +#define ADF41513_REG3_FRAC2_MSK GENMASK(27, 4) + +/* REG4 Bit Definitions */ +#define ADF41513_REG4_MOD2_MSK GENMASK(27, 4) + +/* REG5 Bit Definitions */ +#define ADF41513_REG5_CLK1_DIV_MSK GENMASK(15, 4) +#define ADF41513_REG5_R_CNT_MSK GENMASK(20, 16) +#define ADF41513_REG5_REF_DOUBLER_MSK BIT(21) +#define ADF41513_REG5_RDIV2_MSK BIT(22) +#define ADF41513_REG5_PRESCALER_MSK BIT(23) +#define ADF41513_REG5_LSB_P1_MSK BIT(24) +#define ADF41513_REG5_CP_CURRENT_MSK GENMASK(28, 25) +#define ADF41513_REG5_DLD_MODES_MSK GENMASK(31, 30) + +/* REG6 Bit Definitions */ +#define ADF41513_REG6_COUNTER_RESET_MSK BIT(4) +#define ADF41513_REG6_CP_TRISTATE_MSK BIT(5) +#define ADF41513_REG6_POWER_DOWN_MSK BIT(6) +#define ADF41513_REG6_PD_POLARITY_MSK BIT(7) +#define ADF41513_REG6_LDP_MSK GENMASK(9, 8) +#define ADF41513_REG6_CP_TRISTATE_PD_ON_MSK BIT(16) +#define ADF41513_REG6_SD_RESET_MSK BIT(17) +#define ADF41513_REG6_LOL_ENABLE_MSK BIT(18) +#define ADF41513_REG6_ABP_MSK BIT(19) +#define ADF41513_REG6_INT_MODE_MSK BIT(20) +#define ADF41513_REG6_BLEED_ENABLE_MSK BIT(22) +#define ADF41513_REG6_BLEED_POLARITY_MSK BIT(23) +#define ADF41513_REG6_BLEED_CURRENT_MSK GENMASK(31, 24) + +/* REG7 Bit Definitions */ +#define ADF41513_REG7_CLK2_DIV_MSK GENMASK(17, 6) +#define ADF41513_REG7_CLK_DIV_MODE_MSK GENMASK(19, 18) +#define ADF41513_REG7_PS_BIAS_MSK GENMASK(21, 20) +#define ADF41513_REG7_N_DELAY_MSK GENMASK(23, 22) +#define ADF41513_REG7_LD_CLK_SEL_MSK BIT(26) +#define ADF41513_REG7_LD_COUNT_MSK GENMASK(29, 27) + +/* REG9 Bit Definitions */ +#define ADF41513_REG9_LD_BIAS_MSK GENMASK(31, 30) + +/* REG11 Bit Definitions */ +#define ADF41513_REG11_POWER_DOWN_SEL_MSK BIT(31) + +/* REG12 Bit Definitions */ +#define ADF41513_REG12_READBACK_SEL_MSK GENMASK(19, 14) +#define ADF41513_REG12_LE_SELECT_MSK BIT(20) +#define ADF41513_REG12_MASTER_RESET_MSK BIT(22) +#define ADF41513_REG12_LOGIC_LEVEL_MSK BIT(27) +#define ADF41513_REG12_MUXOUT_MSK GENMASK(31, 28) + +/* MUXOUT Selection */ +#define ADF41513_MUXOUT_TRISTATE 0x0 +#define ADF41513_MUXOUT_DVDD 0x1 +#define ADF41513_MUXOUT_DGND 0x2 +#define ADF41513_MUXOUT_R_DIV 0x3 +#define ADF41513_MUXOUT_N_DIV 0x4 +#define ADF41513_MUXOUT_DIG_LD 0x6 +#define ADF41513_MUXOUT_SDO 0x7 +#define ADF41513_MUXOUT_READBACK 0x8 +#define ADF41513_MUXOUT_CLK1_DIV 0xA +#define ADF41513_MUXOUT_R_DIV2 0xD +#define ADF41513_MUXOUT_N_DIV2 0xE + +/* DLD Mode Selection */ +#define ADF41513_DLD_TRISTATE 0x0 +#define ADF41513_DLD_DIG_LD 0x1 +#define ADF41513_DLD_LOW 0x2 +#define ADF41513_DLD_HIGH 0x3 + +/* Prescaler Selection */ +#define ADF41513_PRESCALER_4_5 0 +#define ADF41513_PRESCALER_8_9 1 +#define ADF41513_PRESCALER_AUTO 2 + +/* CLK Divider mode */ +#define ADF41513_CLK_DIV_MODE_OFF 0 +#define ADF41513_CLK_DIV_MODE_PHASE_RESYNC 2 + +/* Specifications */ +#define ADF41510_MAX_RF_FREQ_HZ (10ULL * HZ_PER_GHZ) +#define ADF41513_MIN_RF_FREQ_HZ (1ULL * HZ_PER_GHZ) +#define ADF41513_MAX_RF_FREQ_HZ (26500ULL * HZ_PER_MHZ) + +#define ADF41513_MIN_REF_FREQ_HZ (10 * HZ_PER_MHZ) +#define ADF41513_MAX_REF_FREQ_HZ (800 * HZ_PER_MHZ) +#define ADF41513_MAX_REF_FREQ_DOUBLER_HZ (225 * HZ_PER_MHZ) + +#define ADF41513_MAX_PFD_FREQ_INT_N_UHZ (250ULL * MEGA * MICROHZ_PER_HZ) +#define ADF41513_MAX_PFD_FREQ_FRAC_N_UHZ (125ULL * MEGA * MICROHZ_PER_HZ) +#define ADF41513_MAX_FREQ_RESOLUTION_UHZ (100ULL * KILO * MICROHZ_PER_HZ) + +#define ADF41513_MIN_INT_4_5 20 +#define ADF41513_MAX_INT_4_5 511 +#define ADF41513_MIN_INT_8_9 64 +#define ADF41513_MAX_INT_8_9 1023 + +#define ADF41513_MIN_INT_FRAC_4_5 23 +#define ADF41513_MIN_INT_FRAC_8_9 75 + +#define ADF41513_MIN_R_CNT 1 +#define ADF41513_MAX_R_CNT 32 + +#define ADF41513_MIN_R_SET 1800 +#define ADF41513_DEFAULT_R_SET 2700 +#define ADF41513_MAX_R_SET 10000 + +#define ADF41513_MIN_CP_VOLTAGE_mV 810 +#define ADF41513_DEFAULT_CP_VOLTAGE_mV 6480 +#define ADF41513_MAX_CP_VOLTAGE_mV 12960 + +#define ADF41513_MIN_CP_CURRENT_uA 81 +#define ADF41513_MAX_CP_CURRENT_uA 7200 + +#define ADF41513_LD_COUNT_FAST_MIN 2 +#define ADF41513_LD_COUNT_FAST_LIMIT 64 +#define ADF41513_LD_COUNT_MIN 64 +#define ADF41513_LD_COUNT_MAX 8192 + +#define ADF41513_FIXED_MODULUS BIT(25) +#define ADF41513_MAX_MOD2 (BIT(24) - 1) +#define ADF41513_MAX_PHASE_VAL (BIT(12) - 1) +#define ADF41513_MAX_CLK_DIVIDER (BIT(12) - 1) + +#define ADF41513_HZ_DECIMAL_SCALE 6 +#define ADF41513_PS_BIAS_INIT 0x2 +#define ADF41513_MAX_PHASE_MICRORAD ((2 * 314159265UL) / 100) + +enum adf41513_pll_mode { + ADF41513_MODE_INVALID, + ADF41513_MODE_INTEGER_N, + ADF41513_MODE_FIXED_MODULUS, + ADF41513_MODE_VARIABLE_MODULUS, +}; + +struct adf41513_chip_info { + const char *name; + u64 max_rf_freq_hz; + bool has_prescaler_8_9; +}; + +struct adf41513_data { + u64 power_up_frequency_hz; + u64 freq_resolution_uhz; + u32 phase_resync_period_ns; + u32 charge_pump_voltage_mv; + u32 lock_detect_count; + + u8 ref_div_factor; + bool ref_doubler_en; + bool ref_div2_en; + bool phase_detector_polarity; + + bool logic_lvl_1v8_en; + bool le_sync_en; +}; + +struct adf41513_pll_settings { + enum adf41513_pll_mode mode; + + /* reference path parameters */ + u8 r_counter; + u8 ref_doubler; + u8 ref_div2; + u8 prescaler; + + /* frequency parameters */ + u64 target_frequency_uhz; + u64 actual_frequency_uhz; + u64 pfd_frequency_uhz; + + /* pll parameters */ + u32 frac1; + u32 frac2; + u32 mod2; + u16 int_val; +}; + +struct adf41513_state { + const struct adf41513_chip_info *chip_info; + struct spi_device *spi; + struct gpio_desc *lock_detect; + struct clk *ref_clk; + u32 ref_freq_hz; + + /* + * Lock for accessing device registers. Some operations require + * multiple consecutive R/W operations, during which the device + * shouldn't be interrupted. The buffers are also shared across + * all operations so need to be protected on stand alone reads and + * writes. + */ + struct mutex lock; + + /* Cached register values */ + u32 regs[ADF41513_REG_NUM]; + u32 regs_hw[ADF41513_REG_NUM]; + + struct adf41513_data data; + struct adf41513_pll_settings settings; + + bool powerdown; +}; + +static const u16 adf41513_ld_window_x10_ns[] = { + 9, 12, 16, 17, 21, 28, 29, 35, /* 0 - 7 */ + 43, 47, 49, 52, 70, 79, 115, /* 8 - 14 */ +}; + +static const u8 adf41513_ldp_bias[] = { + 0xC, 0xD, 0xE, 0x8, 0x9, 0x4, 0xA, 0x5, /* 0 - 7 */ + 0x0, 0x6, 0xB, 0x1, 0x2, 0x7, 0x3, /* 8 - 14 */ +}; + +static const char * const adf41513_power_supplies[] = { + "avdd1", "avdd2", "avdd3", "avdd4", "avdd5", "vp", +}; + +static int adf41513_sync_config(struct adf41513_state *st, u16 sync_mask) +{ + __be32 d32; + int ret; + + /* write registers in reverse order (R13 to R0)*/ + for (int i = ADF41513_REG13; i >= ADF41513_REG0; i--) { + if (st->regs_hw[i] == st->regs[i] && !(sync_mask & BIT(i))) + continue; + + d32 = cpu_to_be32(st->regs[i] | i); + ret = spi_write_then_read(st->spi, &d32, sizeof(d32), NULL, 0); + if (ret < 0) + return ret; + st->regs_hw[i] = st->regs[i]; + dev_dbg(&st->spi->dev, "REG%d <= 0x%08X\n", i, st->regs[i] | i); + } + + return 0; +} + +static u64 adf41513_pll_get_rate(struct adf41513_state *st) +{ + struct adf41513_pll_settings *cfg = &st->settings; + + if (cfg->mode != ADF41513_MODE_INVALID) + return cfg->actual_frequency_uhz; + + /* get pll settings from regs_hw */ + cfg->int_val = FIELD_GET(ADF41513_REG0_INT_MSK, st->regs_hw[ADF41513_REG0]); + cfg->frac1 = FIELD_GET(ADF41513_REG1_FRAC1_MSK, st->regs_hw[ADF41513_REG1]); + cfg->frac2 = FIELD_GET(ADF41513_REG3_FRAC2_MSK, st->regs_hw[ADF41513_REG3]); + cfg->mod2 = FIELD_GET(ADF41513_REG4_MOD2_MSK, st->regs_hw[ADF41513_REG4]); + cfg->r_counter = FIELD_GET(ADF41513_REG5_R_CNT_MSK, st->regs_hw[ADF41513_REG5]); + cfg->ref_doubler = FIELD_GET(ADF41513_REG5_REF_DOUBLER_MSK, st->regs_hw[ADF41513_REG5]); + cfg->ref_div2 = FIELD_GET(ADF41513_REG5_RDIV2_MSK, st->regs_hw[ADF41513_REG5]); + cfg->prescaler = FIELD_GET(ADF41513_REG5_PRESCALER_MSK, st->regs_hw[ADF41513_REG5]); + + if (!cfg->mod2) + cfg->mod2 = 1; + if (!cfg->r_counter) + cfg->r_counter = ADF41513_MAX_R_CNT; + + /* calculate pfd frequency */ + cfg->pfd_frequency_uhz = (u64)st->ref_freq_hz * MICRO; + if (cfg->ref_doubler) + cfg->pfd_frequency_uhz <<= 1; + if (cfg->ref_div2) + cfg->pfd_frequency_uhz >>= 1; + cfg->pfd_frequency_uhz = div_u64(cfg->pfd_frequency_uhz, cfg->r_counter); + cfg->actual_frequency_uhz = (u64)cfg->int_val * cfg->pfd_frequency_uhz; + + /* check if int mode is selected */ + if (FIELD_GET(ADF41513_REG6_INT_MODE_MSK, st->regs_hw[ADF41513_REG6])) { + cfg->mode = ADF41513_MODE_INTEGER_N; + } else { + cfg->actual_frequency_uhz += mul_u64_u32_div(cfg->pfd_frequency_uhz, + cfg->frac1, + ADF41513_FIXED_MODULUS); + + /* check if variable modulus is selected */ + if (FIELD_GET(ADF41513_REG0_VAR_MOD_MSK, st->regs_hw[ADF41513_REG0])) { + cfg->actual_frequency_uhz += + mul_u64_u64_div_u64(cfg->frac2, + cfg->pfd_frequency_uhz, + (u64)cfg->mod2 * ADF41513_FIXED_MODULUS); + + cfg->mode = ADF41513_MODE_VARIABLE_MODULUS; + } else { + /* LSB_P1 offset */ + if (!FIELD_GET(ADF41513_REG5_LSB_P1_MSK, st->regs_hw[ADF41513_REG5])) + cfg->actual_frequency_uhz += + div_u64(cfg->pfd_frequency_uhz, + 2 * ADF41513_FIXED_MODULUS); + cfg->mode = ADF41513_MODE_FIXED_MODULUS; + } + } + + cfg->target_frequency_uhz = cfg->actual_frequency_uhz; + + return cfg->actual_frequency_uhz; +} + +static int adf41513_calc_pfd_frequency(struct adf41513_state *st, + struct adf41513_pll_settings *result, + u64 fpfd_limit_uhz) +{ + result->ref_div2 = st->data.ref_div2_en; + result->ref_doubler = st->data.ref_doubler_en; + result->r_counter = st->data.ref_div_factor - 1; + + do { + result->r_counter++; + /* f_PFD = REF_IN × ((1 + D)/(R × (1 + T))) */ + result->pfd_frequency_uhz = (u64)st->ref_freq_hz * MICRO; + if (result->ref_doubler) + result->pfd_frequency_uhz <<= 1; + if (result->ref_div2) + result->pfd_frequency_uhz >>= 1; + result->pfd_frequency_uhz = div_u64(result->pfd_frequency_uhz, + result->r_counter); + } while (result->pfd_frequency_uhz > fpfd_limit_uhz); + + if (result->r_counter > ADF41513_MAX_R_CNT) { + dev_err(&st->spi->dev, "Cannot optimize PFD frequency\n"); + return -ERANGE; + } + + return 0; +} + +static int adf41513_calc_integer_n(struct adf41513_state *st, + struct adf41513_pll_settings *result) +{ + u32 max_int = st->chip_info->has_prescaler_8_9 ? + ADF41513_MAX_INT_8_9 : ADF41513_MAX_INT_4_5; + u64 freq_error_uhz; + u32 int_val = div64_u64_rem(result->target_frequency_uhz, result->pfd_frequency_uhz, + &freq_error_uhz); + + /* check if freq error is within a tolerance of 1/2 resolution */ + if (freq_error_uhz > (result->pfd_frequency_uhz >> 1) && int_val < max_int) { + int_val++; + freq_error_uhz = result->pfd_frequency_uhz - freq_error_uhz; + } + + if (freq_error_uhz > st->data.freq_resolution_uhz) + return -ERANGE; + + /* set prescaler */ + if (st->chip_info->has_prescaler_8_9 && int_val >= ADF41513_MIN_INT_8_9 && + int_val <= ADF41513_MAX_INT_8_9) + result->prescaler = 1; + else if (int_val >= ADF41513_MIN_INT_4_5 && int_val <= ADF41513_MAX_INT_4_5) + result->prescaler = 0; + else + return -ERANGE; + + result->actual_frequency_uhz = (u64)int_val * result->pfd_frequency_uhz; + result->mode = ADF41513_MODE_INTEGER_N; + result->int_val = int_val; + result->frac1 = 0; + result->frac2 = 0; + result->mod2 = 0; + + return 0; +} + +static int adf41513_calc_fixed_mod(struct adf41513_state *st, + struct adf41513_pll_settings *result) +{ + u64 resolution_uhz = div_u64(result->pfd_frequency_uhz, ADF41513_FIXED_MODULUS); + u64 target_frequency_uhz = result->target_frequency_uhz; + u64 freq_error_uhz; + u32 int_val, frac1; + bool lsb_p1_offset = !FIELD_GET(ADF41513_REG5_LSB_P1_MSK, st->regs[ADF41513_REG5]); + + /* LSB_P1 adds a frequency offset of f_pfd/2^26 */ + if (lsb_p1_offset) + target_frequency_uhz -= resolution_uhz >> 1; + + int_val = div64_u64_rem(target_frequency_uhz, result->pfd_frequency_uhz, + &freq_error_uhz); + + if (st->chip_info->has_prescaler_8_9 && int_val >= ADF41513_MIN_INT_FRAC_8_9 && + int_val <= ADF41513_MAX_INT_8_9) + result->prescaler = 1; + else if (int_val >= ADF41513_MIN_INT_FRAC_4_5 && int_val <= ADF41513_MAX_INT_4_5) + result->prescaler = 0; + else + return -ERANGE; + + /* compute frac1 and fixed modulus error */ + frac1 = mul_u64_u64_div_u64(freq_error_uhz, ADF41513_FIXED_MODULUS, + result->pfd_frequency_uhz); + freq_error_uhz -= mul_u64_u32_div(result->pfd_frequency_uhz, frac1, + ADF41513_FIXED_MODULUS); + + /* check if freq error is within a tolerance of 1/2 resolution */ + if (freq_error_uhz > (resolution_uhz >> 1) && frac1 < (ADF41513_FIXED_MODULUS - 1)) { + frac1++; + freq_error_uhz = freq_error_uhz < resolution_uhz ? + resolution_uhz - freq_error_uhz : 0; + } + + if (freq_error_uhz > st->data.freq_resolution_uhz) + return -ERANGE; + + /* integer part */ + result->actual_frequency_uhz = (u64)int_val * result->pfd_frequency_uhz; + /* fractional part */ + if (lsb_p1_offset) + result->actual_frequency_uhz += (resolution_uhz >> 1); + result->actual_frequency_uhz += mul_u64_u32_div(result->pfd_frequency_uhz, frac1, + ADF41513_FIXED_MODULUS); + result->mode = ADF41513_MODE_FIXED_MODULUS; + result->int_val = int_val; + result->frac1 = frac1; + result->frac2 = 0; + result->mod2 = 0; + + return 0; +} + +static int adf41513_calc_variable_mod(struct adf41513_state *st, + struct adf41513_pll_settings *result) +{ + u64 freq_error_uhz, mod2; + u32 frac1, frac2; + u32 int_val = div64_u64_rem(result->target_frequency_uhz, + result->pfd_frequency_uhz, &freq_error_uhz); + + if (st->chip_info->has_prescaler_8_9 && int_val >= ADF41513_MIN_INT_FRAC_8_9 && + int_val <= ADF41513_MAX_INT_8_9) + result->prescaler = 1; + else if (int_val >= ADF41513_MIN_INT_FRAC_4_5 && int_val <= ADF41513_MAX_INT_4_5) + result->prescaler = 0; + else + return -ERANGE; + + /* calculate required mod2 based on target resolution / 2 */ + mod2 = DIV64_U64_ROUND_CLOSEST(result->pfd_frequency_uhz << 1, + st->data.freq_resolution_uhz * ADF41513_FIXED_MODULUS); + /* ensure mod2 is at least 2 for meaningful operation */ + mod2 = clamp(mod2, 2, ADF41513_MAX_MOD2); + + /* calculate frac1 and frac2 */ + frac1 = mul_u64_u64_div_u64(freq_error_uhz, ADF41513_FIXED_MODULUS, + result->pfd_frequency_uhz); + frac2 = mul_u64_u64_div_u64(freq_error_uhz, mod2 * ADF41513_FIXED_MODULUS, + result->pfd_frequency_uhz) - mod2 * frac1; + + /* integer part */ + result->actual_frequency_uhz = (u64)int_val * result->pfd_frequency_uhz; + /* fractional part */ + result->actual_frequency_uhz += mul_u64_u64_div_u64(mod2 * frac1 + frac2, + result->pfd_frequency_uhz, + mod2 * ADF41513_FIXED_MODULUS); + result->mode = ADF41513_MODE_VARIABLE_MODULUS; + result->int_val = int_val; + result->frac1 = frac1; + result->frac2 = frac2; + result->mod2 = mod2; + + return 0; +} + +static int adf41513_calc_pll_settings(struct adf41513_state *st, + struct adf41513_pll_settings *result, + u64 rf_out_uhz) +{ + u64 max_rf_freq_uhz = st->chip_info->max_rf_freq_hz * MICRO; + u64 min_rf_freq_uhz = ADF41513_MIN_RF_FREQ_HZ * MICRO; + u64 pfd_freq_limit_uhz; + int ret; + + if (rf_out_uhz < min_rf_freq_uhz || rf_out_uhz > max_rf_freq_uhz) { + dev_err(&st->spi->dev, "RF frequency %llu uHz out of range [%llu, %llu] uHz\n", + rf_out_uhz, min_rf_freq_uhz, max_rf_freq_uhz); + return -EINVAL; + } + + result->target_frequency_uhz = rf_out_uhz; + + /* try integer-N first (best phase noise performance) */ + pfd_freq_limit_uhz = min(div_u64(rf_out_uhz, ADF41513_MIN_INT_4_5), + ADF41513_MAX_PFD_FREQ_INT_N_UHZ); + ret = adf41513_calc_pfd_frequency(st, result, pfd_freq_limit_uhz); + if (ret) + return ret; + + if (adf41513_calc_integer_n(st, result) == 0) + return 0; + + /* try fractional-N: recompute pfd frequency if necessary */ + pfd_freq_limit_uhz = min(div_u64(rf_out_uhz, ADF41513_MIN_INT_FRAC_4_5), + ADF41513_MAX_PFD_FREQ_FRAC_N_UHZ); + if (pfd_freq_limit_uhz < result->pfd_frequency_uhz) { + ret = adf41513_calc_pfd_frequency(st, result, pfd_freq_limit_uhz); + if (ret) + return ret; + } + + /* fixed-modulus attempt */ + if (adf41513_calc_fixed_mod(st, result) == 0) + return 0; + + /* variable-modulus attempt */ + ret = adf41513_calc_variable_mod(st, result); + if (ret) { + dev_err(&st->spi->dev, + "no valid PLL configuration found for %llu uHz\n", + rf_out_uhz); + return ret; + } + + return 0; +} + +static void adf41513_set_bleed_val(struct adf41513_state *st) +{ + u32 bleed_value, cp_index; + + if (!(st->regs[ADF41513_REG6] & ADF41513_REG6_BLEED_ENABLE_MSK)) + return; + + if (st->data.phase_detector_polarity) + bleed_value = 90; + else + bleed_value = 144; + + cp_index = 1 + FIELD_GET(ADF41513_REG5_CP_CURRENT_MSK, + st->regs[ADF41513_REG5]); + bleed_value = div64_u64(st->settings.pfd_frequency_uhz * cp_index * bleed_value, + 1600ULL * MEGA * MICROHZ_PER_HZ); + + FIELD_MODIFY(ADF41513_REG6_BLEED_CURRENT_MSK, &st->regs[ADF41513_REG6], + bleed_value); +} + +static void adf41513_set_ld_window(struct adf41513_state *st) +{ + /* + * The ideal lock detector window size is halfway between the max + * window, set by the phase comparison period t_PFD = (1 / f_PFD), + * and the minimum is set by (I_BLEED/I_CP) × t_PFD + */ + u16 ld_window_10x_ns = div64_u64(10ULL * NSEC_PER_SEC * MICROHZ_PER_HZ, + st->settings.pfd_frequency_uhz << 1); + u8 ld_idx, ldp, ld_bias; + + if (st->settings.mode != ADF41513_MODE_INTEGER_N) { + /* account for bleed current (deduced from eq.6 and eq.7) */ + if (st->data.phase_detector_polarity) + ld_window_10x_ns += 4; + else + ld_window_10x_ns += 6; + } + + ld_idx = find_closest(ld_window_10x_ns, adf41513_ld_window_x10_ns, + ARRAY_SIZE(adf41513_ld_window_x10_ns)); + ldp = (adf41513_ldp_bias[ld_idx] >> 2) & 0x3; + ld_bias = adf41513_ldp_bias[ld_idx] & 0x3; + + FIELD_MODIFY(ADF41513_REG6_LDP_MSK, &st->regs[ADF41513_REG6], ldp); + FIELD_MODIFY(ADF41513_REG9_LD_BIAS_MSK, &st->regs[ADF41513_REG9], ld_bias); +} + +static void adf41513_set_phase_resync(struct adf41513_state *st) +{ + u32 total_div, clk1_div, clk2_div; + + if (!st->data.phase_resync_period_ns) + return; + + /* assuming both clock dividers hold similar values */ + total_div = mul_u64_u64_div_u64(st->settings.pfd_frequency_uhz, + st->data.phase_resync_period_ns, + 1ULL * MICROHZ_PER_HZ * NSEC_PER_SEC); + clk1_div = clamp(int_sqrt(total_div), 1, + ADF41513_MAX_CLK_DIVIDER); + clk2_div = clamp(DIV_ROUND_CLOSEST(total_div, clk1_div), 1, + ADF41513_MAX_CLK_DIVIDER); + + FIELD_MODIFY(ADF41513_REG5_CLK1_DIV_MSK, &st->regs[ADF41513_REG5], + clk1_div); + FIELD_MODIFY(ADF41513_REG7_CLK2_DIV_MSK, &st->regs[ADF41513_REG7], + clk2_div); + + /* enable phase resync */ + FIELD_MODIFY(ADF41513_REG7_CLK_DIV_MODE_MSK, &st->regs[ADF41513_REG7], + ADF41513_CLK_DIV_MODE_PHASE_RESYNC); +} + +static int adf41513_set_frequency(struct adf41513_state *st, u64 freq_uhz, u16 sync_mask) +{ + struct adf41513_pll_settings result; + bool pfd_change = false; + bool mode_change = false; + int ret; + + ret = adf41513_calc_pll_settings(st, &result, freq_uhz); + if (ret < 0) + return ret; + + /* apply computed results to pll settings */ + pfd_change = st->settings.pfd_frequency_uhz != result.pfd_frequency_uhz; + mode_change = st->settings.mode != result.mode; + st->settings = result; + + dev_dbg(&st->spi->dev, + "%s mode: int=%u, frac1=%u, frac2=%u, mod2=%u, fpdf=%llu Hz, prescaler=%s\n", + (result.mode == ADF41513_MODE_INTEGER_N) ? "integer-n" : + (result.mode == ADF41513_MODE_FIXED_MODULUS) ? "fixed-modulus" : "variable-modulus", + result.int_val, result.frac1, result.frac2, result.mod2, + div64_u64(result.pfd_frequency_uhz, MICRO), + result.prescaler ? "8/9" : "4/5"); + + st->regs[ADF41513_REG0] = FIELD_PREP(ADF41513_REG0_INT_MSK, + st->settings.int_val); + if (st->settings.mode == ADF41513_MODE_VARIABLE_MODULUS) + st->regs[ADF41513_REG0] |= ADF41513_REG0_VAR_MOD_MSK; + + st->regs[ADF41513_REG1] = FIELD_PREP(ADF41513_REG1_FRAC1_MSK, + st->settings.frac1); + if (st->settings.mode != ADF41513_MODE_INTEGER_N) + st->regs[ADF41513_REG1] |= ADF41513_REG1_DITHER2_MSK; + + st->regs[ADF41513_REG3] = FIELD_PREP(ADF41513_REG3_FRAC2_MSK, + st->settings.frac2); + FIELD_MODIFY(ADF41513_REG4_MOD2_MSK, &st->regs[ADF41513_REG4], + st->settings.mod2); + FIELD_MODIFY(ADF41513_REG5_R_CNT_MSK, &st->regs[ADF41513_REG5], + st->settings.r_counter % ADF41513_MAX_R_CNT); + FIELD_MODIFY(ADF41513_REG5_REF_DOUBLER_MSK, &st->regs[ADF41513_REG5], + st->settings.ref_doubler); + FIELD_MODIFY(ADF41513_REG5_RDIV2_MSK, &st->regs[ADF41513_REG5], + st->settings.ref_div2); + FIELD_MODIFY(ADF41513_REG5_PRESCALER_MSK, &st->regs[ADF41513_REG5], + st->settings.prescaler); + + if (st->settings.mode == ADF41513_MODE_INTEGER_N) { + st->regs[ADF41513_REG6] |= ADF41513_REG6_INT_MODE_MSK; + st->regs[ADF41513_REG6] &= ~ADF41513_REG6_BLEED_ENABLE_MSK; + } else { + st->regs[ADF41513_REG6] &= ~ADF41513_REG6_INT_MODE_MSK; + st->regs[ADF41513_REG6] |= ADF41513_REG6_BLEED_ENABLE_MSK; + } + + if (pfd_change) + adf41513_set_phase_resync(st); + + if (pfd_change || mode_change) { + adf41513_set_bleed_val(st); + adf41513_set_ld_window(st); + } + + return adf41513_sync_config(st, sync_mask | ADF41513_SYNC_REG0); +} + +static int adf41513_suspend(struct adf41513_state *st) +{ + st->regs[ADF41513_REG6] |= FIELD_PREP(ADF41513_REG6_POWER_DOWN_MSK, 1); + st->regs[ADF41513_REG12] &= ~ADF41513_REG12_LE_SELECT_MSK; + return adf41513_sync_config(st, ADF41513_SYNC_DIFF); +} + +static int adf41513_resume(struct adf41513_state *st) +{ + int ret; + + st->regs[ADF41513_REG6] &= ~ADF41513_REG6_POWER_DOWN_MSK; + st->regs[ADF41513_REG12] &= ~ADF41513_REG12_LE_SELECT_MSK; + ret = adf41513_sync_config(st, ADF41513_SYNC_ALL); + if (ret) + return ret; + + if (st->data.le_sync_en) { + st->regs[ADF41513_REG12] |= ADF41513_REG12_LE_SELECT_MSK; + ret = adf41513_sync_config(st, ADF41513_SYNC_DIFF); + if (ret) + return ret; + } + + return 0; +} + +static ssize_t adf41513_read_resolution(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + struct adf41513_state *st = iio_priv(indio_dev); + int vals[2]; + + guard(mutex)(&st->lock); + + iio_val_s64_decompose(st->data.freq_resolution_uhz, &vals[0], &vals[1]); + return iio_format_value(buf, IIO_VAL_DECIMAL64_MICRO, ARRAY_SIZE(vals), vals); +} + +static ssize_t adf41513_read_powerdown(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + struct adf41513_state *st = iio_priv(indio_dev); + u32 val; + + guard(mutex)(&st->lock); + + val = FIELD_GET(ADF41513_REG6_POWER_DOWN_MSK, st->regs_hw[ADF41513_REG6]); + return sysfs_emit(buf, "%u\n", val); +} + +static ssize_t adf41513_write_resolution(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct adf41513_state *st = iio_priv(indio_dev); + u64 freq_uhz; + int ret; + + ret = kstrtoudec64(buf, ADF41513_HZ_DECIMAL_SCALE, &freq_uhz); + if (ret) + return ret; + + if (freq_uhz == 0 || freq_uhz > ADF41513_MAX_FREQ_RESOLUTION_UHZ) + return -EINVAL; + + guard(mutex)(&st->lock); + + st->data.freq_resolution_uhz = freq_uhz; + return len; +} + +static ssize_t adf41513_write_powerdown(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct adf41513_state *st = iio_priv(indio_dev); + bool val; + int ret; + + ret = kstrtobool(buf, &val); + if (ret) + return ret; + + guard(mutex)(&st->lock); + + if (val) + ret = adf41513_suspend(st); + else + ret = adf41513_resume(st); + if (ret) + return ret; + + st->powerdown = val; + return len; +} + +static const struct iio_chan_spec_ext_info adf41513_ext_info[] = { + { + .name = "frequency_resolution", + .read = adf41513_read_resolution, + .write = adf41513_write_resolution, + .shared = IIO_SEPARATE, + }, + { + .name = "powerdown", + .read = adf41513_read_powerdown, + .write = adf41513_write_powerdown, + .shared = IIO_SEPARATE, + }, + { } +}; + +static const struct iio_chan_spec adf41513_chan = { + .type = IIO_ALTVOLTAGE, + .indexed = 1, + .output = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_FREQUENCY) | + BIT(IIO_CHAN_INFO_PHASE), + .ext_info = adf41513_ext_info, +}; + +static int adf41513_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long info) +{ + struct adf41513_state *st = iio_priv(indio_dev); + u64 tmp64; + + guard(mutex)(&st->lock); + + switch (info) { + case IIO_CHAN_INFO_FREQUENCY: + if (st->lock_detect && + !gpiod_get_value_cansleep(st->lock_detect)) { + dev_dbg(&st->spi->dev, "PLL un-locked\n"); + return -EBUSY; + } + tmp64 = adf41513_pll_get_rate(st); + iio_val_s64_decompose(tmp64, val, val2); + return IIO_VAL_DECIMAL64_MICRO; + case IIO_CHAN_INFO_PHASE: + tmp64 = FIELD_GET(ADF41513_REG2_PHASE_VAL_MSK, + st->regs_hw[ADF41513_REG2]); + tmp64 = (tmp64 * ADF41513_MAX_PHASE_MICRORAD) >> 12; + iio_val_s64_decompose(tmp64, val, val2); + return IIO_VAL_DECIMAL64_MICRO; + default: + return -EINVAL; + } +} + +static int adf41513_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long info) +{ + struct adf41513_state *st = iio_priv(indio_dev); + u64 tmp64 = iio_val_s64_compose(val, val2); + u16 phase_val; + int ret; + + guard(mutex)(&st->lock); + + switch (info) { + case IIO_CHAN_INFO_FREQUENCY: + return adf41513_set_frequency(st, tmp64, ADF41513_SYNC_DIFF); + case IIO_CHAN_INFO_PHASE: + if (tmp64 >= ADF41513_MAX_PHASE_MICRORAD) + return -EINVAL; + + phase_val = DIV_U64_ROUND_CLOSEST(tmp64 << 12, + ADF41513_MAX_PHASE_MICRORAD); + phase_val = min(phase_val, ADF41513_MAX_PHASE_VAL); + st->regs[ADF41513_REG2] |= ADF41513_REG2_PHASE_ADJ_MSK; + FIELD_MODIFY(ADF41513_REG2_PHASE_VAL_MSK, + &st->regs[ADF41513_REG2], phase_val); + ret = adf41513_sync_config(st, ADF41513_SYNC_REG0); + /* clear phase adjust for the next sync */ + st->regs[ADF41513_REG2] &= ~ADF41513_REG2_PHASE_ADJ_MSK; + return ret; + default: + return -EINVAL; + } +} + +static int adf41513_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_FREQUENCY: + case IIO_CHAN_INFO_PHASE: + return IIO_VAL_DECIMAL64_MICRO; + default: + return -EINVAL; + } +} + +static int adf41513_reg_access(struct iio_dev *indio_dev, unsigned int reg, + unsigned int writeval, unsigned int *readval) +{ + struct adf41513_state *st = iio_priv(indio_dev); + + if (reg > ADF41513_REG13) + return -EINVAL; + + guard(mutex)(&st->lock); + + if (!readval) { + if (reg <= ADF41513_REG6) + st->settings.mode = ADF41513_MODE_INVALID; + st->regs[reg] = writeval & ~0xF; /* Clear control bits */ + return adf41513_sync_config(st, BIT(reg)); + } + + *readval = st->regs_hw[reg]; + return 0; +} + +static const struct iio_info adf41513_info = { + .read_raw = adf41513_read_raw, + .write_raw = adf41513_write_raw, + .write_raw_get_fmt = adf41513_write_raw_get_fmt, + .debugfs_reg_access = &adf41513_reg_access, +}; + +static int adf41513_parse_fw(struct adf41513_state *st) +{ + struct device *dev = &st->spi->dev; + u32 tmp, cp_resistance, cp_current; + int ret; + + tmp = ADF41510_MAX_RF_FREQ_HZ / MEGA; + device_property_read_u32(dev, "adi,power-up-frequency-mhz", &tmp); + st->data.power_up_frequency_hz = (u64)tmp * MEGA; + if (st->data.power_up_frequency_hz < ADF41513_MIN_RF_FREQ_HZ || + st->data.power_up_frequency_hz > st->chip_info->max_rf_freq_hz) + return dev_err_probe(dev, -ERANGE, + "power-up frequency %llu Hz out of range\n", + st->data.power_up_frequency_hz); + + tmp = ADF41513_MIN_R_CNT; + device_property_read_u32(dev, "adi,reference-div-factor", &tmp); + if (tmp < ADF41513_MIN_R_CNT || tmp > ADF41513_MAX_R_CNT) + return dev_err_probe(dev, -ERANGE, + "invalid reference div factor %u\n", tmp); + st->data.ref_div_factor = tmp; + + st->data.ref_div2_en = device_property_read_bool(dev, "adi,reference-div2-enable"); + st->data.ref_doubler_en = device_property_read_bool(dev, "adi,reference-doubler-enable"); + + if (st->data.ref_doubler_en && + st->ref_freq_hz > ADF41513_MAX_REF_FREQ_DOUBLER_HZ) { + return dev_err_probe(dev, -ERANGE, + "Ref frequency not supported with doubler enabled\n"); + } + + cp_resistance = ADF41513_DEFAULT_R_SET; + device_property_read_u32(dev, "adi,charge-pump-resistor-ohms", &cp_resistance); + if (cp_resistance < ADF41513_MIN_R_SET || cp_resistance > ADF41513_MAX_R_SET) + return dev_err_probe(dev, -ERANGE, "R_SET %u Ohms out of range\n", cp_resistance); + + st->data.charge_pump_voltage_mv = ADF41513_DEFAULT_CP_VOLTAGE_mV; + ret = device_property_read_u32(dev, "adi,charge-pump-current-microamp", &cp_current); + if (!ret) { + if (cp_current < ADF41513_MIN_CP_CURRENT_uA || + cp_current > ADF41513_MAX_CP_CURRENT_uA) + return dev_err_probe(dev, -ERANGE, + "I_CP %u uA out of range\n", cp_current); + + tmp = DIV_ROUND_CLOSEST(cp_current * cp_resistance, MILLI); + if (tmp < ADF41513_MIN_CP_VOLTAGE_mV || tmp > ADF41513_MAX_CP_VOLTAGE_mV) + return dev_err_probe(dev, -ERANGE, "I_CP %u uA (%u Ohms) out of range\n", + cp_current, cp_resistance); + st->data.charge_pump_voltage_mv = tmp; + } + + st->data.phase_detector_polarity = + device_property_read_bool(dev, "adi,phase-detector-polarity-positive-enable"); + + st->data.phase_resync_period_ns = 0; + ret = device_property_read_u32(dev, "adi,phase-resync-period-ns", &tmp); + if (!ret) + st->data.phase_resync_period_ns = tmp; + + st->data.logic_lvl_1v8_en = device_property_read_bool(dev, "adi,logic-level-1v8-enable"); + + tmp = ADF41513_LD_COUNT_MIN; + device_property_read_u32(dev, "adi,lock-detector-count", &tmp); + if (tmp < ADF41513_LD_COUNT_FAST_MIN || tmp > ADF41513_LD_COUNT_MAX || + !is_power_of_2(tmp)) + return dev_err_probe(dev, -ERANGE, + "invalid lock detect count: %u\n", tmp); + st->data.lock_detect_count = tmp; + + /* load enable sync */ + st->data.le_sync_en = device_property_read_bool(dev, "adi,le-sync-enable"); + st->data.freq_resolution_uhz = MICROHZ_PER_HZ; + + return 0; +} + +static void adf41513_chip_disable(void *data) +{ + gpiod_set_value_cansleep(data, 0); +} + +static void adf41513_close(void *data) +{ + adf41513_suspend(data); +} + +static int adf41513_setup(struct device *dev, struct adf41513_state *st) +{ + u32 tmp; + int ret; + + memset(st->regs_hw, 0xFF, sizeof(st->regs_hw)); + + /* assuming DLD pin is used for lock detection */ + st->regs[ADF41513_REG5] = FIELD_PREP(ADF41513_REG5_DLD_MODES_MSK, + ADF41513_DLD_DIG_LD); + + tmp = DIV_ROUND_CLOSEST(st->data.charge_pump_voltage_mv, ADF41513_MIN_CP_VOLTAGE_mV); + st->regs[ADF41513_REG5] |= FIELD_PREP(ADF41513_REG5_CP_CURRENT_MSK, tmp - 1); + + st->regs[ADF41513_REG6] = ADF41513_REG6_ABP_MSK | + ADF41513_REG6_LOL_ENABLE_MSK | + ADF41513_REG6_SD_RESET_MSK; + if (st->data.phase_detector_polarity) + st->regs[ADF41513_REG6] |= ADF41513_REG6_PD_POLARITY_MSK; + + st->regs[ADF41513_REG7] = FIELD_PREP(ADF41513_REG7_PS_BIAS_MSK, + ADF41513_PS_BIAS_INIT); + tmp = ilog2(st->data.lock_detect_count); + if (st->data.lock_detect_count < ADF41513_LD_COUNT_FAST_LIMIT) { + tmp -= const_ilog2(ADF41513_LD_COUNT_FAST_MIN); + st->regs[ADF41513_REG7] |= ADF41513_REG7_LD_CLK_SEL_MSK; + } else { + tmp -= const_ilog2(ADF41513_LD_COUNT_MIN); + } + st->regs[ADF41513_REG7] |= FIELD_PREP(ADF41513_REG7_LD_COUNT_MSK, tmp); + + st->regs[ADF41513_REG11] = ADF41513_REG11_POWER_DOWN_SEL_MSK; + st->regs[ADF41513_REG12] = FIELD_PREP(ADF41513_REG12_LOGIC_LEVEL_MSK, + st->data.logic_lvl_1v8_en ? 0 : 1); + + /* perform initialization sequence with power-up frequency */ + ret = adf41513_set_frequency(st, st->data.power_up_frequency_hz * MICRO, + ADF41513_SYNC_ALL); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, adf41513_close, st); + if (ret) + return ret; + + if (st->data.le_sync_en) { + st->regs[ADF41513_REG12] |= ADF41513_REG12_LE_SELECT_MSK; + ret = adf41513_sync_config(st, ADF41513_SYNC_DIFF); + if (ret) + return ret; + } + + return 0; +} + +static int adf41513_pm_suspend(struct device *dev) +{ + struct adf41513_state *st = dev_get_drvdata(dev); + + guard(mutex)(&st->lock); + return adf41513_suspend(st); +} + +static int adf41513_pm_resume(struct device *dev) +{ + struct adf41513_state *st = dev_get_drvdata(dev); + + guard(mutex)(&st->lock); + if (st->powerdown) + return 0; /* nothing to do */ + + return adf41513_resume(st); +} + +static const struct adf41513_chip_info adf41510_chip_info = { + .name = "adf41510", + .max_rf_freq_hz = ADF41510_MAX_RF_FREQ_HZ, + .has_prescaler_8_9 = false, +}; + +static const struct adf41513_chip_info adf41513_chip_info = { + .name = "adf41513", + .max_rf_freq_hz = ADF41513_MAX_RF_FREQ_HZ, + .has_prescaler_8_9 = true, +}; + +static int adf41513_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct gpio_desc *chip_enable; + struct iio_dev *indio_dev; + struct adf41513_state *st; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->spi = spi; + st->chip_info = spi_get_device_match_data(spi); + if (!st->chip_info) + return -EINVAL; + + spi_set_drvdata(spi, st); + + st->ref_clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(st->ref_clk)) + return PTR_ERR(st->ref_clk); + + st->ref_freq_hz = clk_get_rate(st->ref_clk); + if (st->ref_freq_hz < ADF41513_MIN_REF_FREQ_HZ || + st->ref_freq_hz > ADF41513_MAX_REF_FREQ_HZ) + return dev_err_probe(dev, -ERANGE, + "reference frequency %u Hz out of range\n", + st->ref_freq_hz); + + ret = adf41513_parse_fw(st); + if (ret) + return ret; + + ret = devm_regulator_bulk_get_enable(dev, + ARRAY_SIZE(adf41513_power_supplies), + adf41513_power_supplies); + if (ret) + return dev_err_probe(dev, ret, + "failed to get and enable regulators\n"); + + st->lock_detect = devm_gpiod_get_optional(dev, "lock-detect", GPIOD_IN); + if (IS_ERR(st->lock_detect)) + return dev_err_probe(dev, PTR_ERR(st->lock_detect), + "fail to request lock detect GPIO\n"); + + chip_enable = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); + if (IS_ERR(chip_enable)) + return dev_err_probe(dev, PTR_ERR(chip_enable), + "fail to request chip enable GPIO\n"); + + ret = devm_add_action_or_reset(dev, adf41513_chip_disable, chip_enable); + if (ret) + return dev_err_probe(dev, ret, "Failed to add disable action\n"); + + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; + + indio_dev->name = st->chip_info->name; + indio_dev->info = &adf41513_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = &adf41513_chan; + indio_dev->num_channels = 1; + + ret = adf41513_setup(dev, st); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to setup device\n"); + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct spi_device_id adf41513_id[] = { + { .name = "adf41510", .driver_data = (kernel_ulong_t)&adf41510_chip_info }, + { .name = "adf41513", .driver_data = (kernel_ulong_t)&adf41513_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(spi, adf41513_id); + +static const struct of_device_id adf41513_of_match[] = { + { .compatible = "adi,adf41510", .data = &adf41510_chip_info }, + { .compatible = "adi,adf41513", .data = &adf41513_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, adf41513_of_match); + +static DEFINE_SIMPLE_DEV_PM_OPS(adf41513_pm_ops, adf41513_pm_suspend, adf41513_pm_resume); + +static struct spi_driver adf41513_driver = { + .driver = { + .name = "adf41513", + .pm = pm_ptr(&adf41513_pm_ops), + .of_match_table = adf41513_of_match, + }, + .probe = adf41513_probe, + .id_table = adf41513_id, +}; +module_spi_driver(adf41513_driver); + +MODULE_AUTHOR("Rodrigo Alencar <rodrigo.alencar@analog.com>"); +MODULE_DESCRIPTION("Analog Devices ADF41513 PLL Frequency Synthesizer"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c index 639cac522b44..315317d6eec4 100644 --- a/drivers/iio/frequency/adf4350.c +++ b/drivers/iio/frequency/adf4350.c @@ -691,8 +691,8 @@ static const struct of_device_id adf4350_of_match[] = { MODULE_DEVICE_TABLE(of, adf4350_of_match); static const struct spi_device_id adf4350_id[] = { - {"adf4350", 4350}, - {"adf4351", 4351}, + { .name = "adf4350", .driver_data = 4350 }, + { .name = "adf4351", .driver_data = 4351 }, { } }; MODULE_DEVICE_TABLE(spi, adf4350_id); diff --git a/drivers/iio/frequency/adf4371.c b/drivers/iio/frequency/adf4371.c index d6dc7827fb41..e20ed718d01d 100644 --- a/drivers/iio/frequency/adf4371.c +++ b/drivers/iio/frequency/adf4371.c @@ -624,8 +624,8 @@ static int adf4371_probe(struct spi_device *spi) } static const struct spi_device_id adf4371_id_table[] = { - { "adf4371", (kernel_ulong_t)&adf4371_chip_info }, - { "adf4372", (kernel_ulong_t)&adf4372_chip_info }, + { .name = "adf4371", .driver_data = (kernel_ulong_t)&adf4371_chip_info }, + { .name = "adf4372", .driver_data = (kernel_ulong_t)&adf4372_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, adf4371_id_table); diff --git a/drivers/iio/frequency/adf4377.c b/drivers/iio/frequency/adf4377.c index ff6077e29c73..4dd19a9aa994 100644 --- a/drivers/iio/frequency/adf4377.c +++ b/drivers/iio/frequency/adf4377.c @@ -7,6 +7,7 @@ #include <linux/bitfield.h> #include <linux/bits.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/clkdev.h> @@ -518,14 +519,15 @@ static int adf4377_get_freq(struct adf4377_state *st, u64 *freq) u64 clkin_freq; int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); + ret = regmap_read(st->regmap, 0x12, &ref_div_factor); if (ret) - goto exit; + return ret; ret = regmap_bulk_read(st->regmap, 0x10, st->buf, sizeof(st->buf)); if (ret) - goto exit; + return ret; clkin_freq = clk_get_rate(st->clkin); ref_div_factor = FIELD_GET(ADF4377_0012_R_DIV_MSK, ref_div_factor); @@ -533,10 +535,8 @@ static int adf4377_get_freq(struct adf4377_state *st, u64 *freq) get_unaligned_le16(&st->buf)); *freq = div_u64(clkin_freq, ref_div_factor) * n_int; -exit: - mutex_unlock(&st->lock); - return ret; + return 0; } static int adf4377_set_freq(struct adf4377_state *st, u64 freq) @@ -545,26 +545,24 @@ static int adf4377_set_freq(struct adf4377_state *st, u64 freq) u64 f_vco; int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); - if (freq > ADF4377_MAX_CLKPN_FREQ || freq < ADF4377_MIN_CLKPN_FREQ) { - ret = -EINVAL; - goto exit; - } + if (freq > ADF4377_MAX_CLKPN_FREQ || freq < ADF4377_MIN_CLKPN_FREQ) + return -EINVAL; ret = regmap_update_bits(st->regmap, 0x1C, ADF4377_001C_EN_DNCLK_MSK | ADF4377_001C_EN_DRCLK_MSK, FIELD_PREP(ADF4377_001C_EN_DNCLK_MSK, 1) | FIELD_PREP(ADF4377_001C_EN_DRCLK_MSK, 1)); if (ret) - goto exit; + return ret; ret = regmap_update_bits(st->regmap, 0x11, ADF4377_0011_EN_AUTOCAL_MSK | ADF4377_0011_DCLK_DIV2_MSK, FIELD_PREP(ADF4377_0011_EN_AUTOCAL_MSK, 1) | FIELD_PREP(ADF4377_0011_DCLK_DIV2_MSK, st->dclk_div2)); if (ret) - goto exit; + return ret; ret = regmap_update_bits(st->regmap, 0x2E, ADF4377_002E_EN_ADC_CNV_MSK | ADF4377_002E_EN_ADC_MSK | @@ -574,56 +572,56 @@ static int adf4377_set_freq(struct adf4377_state *st, u64 freq) FIELD_PREP(ADF4377_002E_ADC_A_CONV_MSK, ADF4377_002E_ADC_A_CONV_VCO_CALIB)); if (ret) - goto exit; + return ret; ret = regmap_update_bits(st->regmap, 0x20, ADF4377_0020_EN_ADC_CLK_MSK, FIELD_PREP(ADF4377_0020_EN_ADC_CLK_MSK, 1)); if (ret) - goto exit; + return ret; ret = regmap_update_bits(st->regmap, 0x2F, ADF4377_002F_DCLK_DIV1_MSK, FIELD_PREP(ADF4377_002F_DCLK_DIV1_MSK, st->dclk_div1)); if (ret) - goto exit; + return ret; ret = regmap_update_bits(st->regmap, 0x24, ADF4377_0024_DCLK_MODE_MSK, FIELD_PREP(ADF4377_0024_DCLK_MODE_MSK, st->dclk_mode)); if (ret) - goto exit; + return ret; ret = regmap_write(st->regmap, 0x27, FIELD_PREP(ADF4377_0027_SYNTH_LOCK_TO_LSB_MSK, st->synth_lock_timeout)); if (ret) - goto exit; + return ret; ret = regmap_update_bits(st->regmap, 0x28, ADF4377_0028_SYNTH_LOCK_TO_MSB_MSK, FIELD_PREP(ADF4377_0028_SYNTH_LOCK_TO_MSB_MSK, st->synth_lock_timeout >> 8)); if (ret) - goto exit; + return ret; ret = regmap_write(st->regmap, 0x29, FIELD_PREP(ADF4377_0029_VCO_ALC_TO_LSB_MSK, st->vco_alc_timeout)); if (ret) - goto exit; + return ret; ret = regmap_update_bits(st->regmap, 0x2A, ADF4377_002A_VCO_ALC_TO_MSB_MSK, FIELD_PREP(ADF4377_002A_VCO_ALC_TO_MSB_MSK, st->vco_alc_timeout >> 8)); if (ret) - goto exit; + return ret; ret = regmap_write(st->regmap, 0x26, FIELD_PREP(ADF4377_0026_VCO_BAND_DIV_MSK, st->vco_band_div)); if (ret) - goto exit; + return ret; ret = regmap_write(st->regmap, 0x2D, FIELD_PREP(ADF4377_002D_ADC_CLK_DIV_MSK, st->adc_clk_div)); if (ret) - goto exit; + return ret; st->clkout_div_sel = 0; @@ -641,24 +639,24 @@ static int adf4377_set_freq(struct adf4377_state *st, u64 freq) FIELD_PREP(ADF4377_0011_EN_RDBLR_MSK, 0) | FIELD_PREP(ADF4377_0011_N_INT_MSB_MSK, st->n_int >> 8)); if (ret) - goto exit; + return ret; ret = regmap_update_bits(st->regmap, 0x12, ADF4377_0012_R_DIV_MSK | ADF4377_0012_CLKOUT_DIV_MSK, FIELD_PREP(ADF4377_0012_CLKOUT_DIV_MSK, st->clkout_div_sel) | FIELD_PREP(ADF4377_0012_R_DIV_MSK, st->ref_div_factor)); if (ret) - goto exit; + return ret; ret = regmap_write(st->regmap, 0x10, FIELD_PREP(ADF4377_0010_N_INT_LSB_MSK, st->n_int)); if (ret) - goto exit; + return ret; ret = regmap_read_poll_timeout(st->regmap, 0x49, read_val, !(read_val & (ADF4377_0049_FSM_BUSY_MSK)), 200, 200 * 100); if (ret) - goto exit; + return ret; /* Disable EN_DNCLK, EN_DRCLK */ ret = regmap_update_bits(st->regmap, 0x1C, ADF4377_001C_EN_DNCLK_MSK | @@ -666,26 +664,21 @@ static int adf4377_set_freq(struct adf4377_state *st, u64 freq) FIELD_PREP(ADF4377_001C_EN_DNCLK_MSK, 0) | FIELD_PREP(ADF4377_001C_EN_DRCLK_MSK, 0)); if (ret) - goto exit; + return ret; /* Disable EN_ADC_CLK */ ret = regmap_update_bits(st->regmap, 0x20, ADF4377_0020_EN_ADC_CLK_MSK, FIELD_PREP(ADF4377_0020_EN_ADC_CLK_MSK, 0)); if (ret) - goto exit; + return ret; /* Set output Amplitude */ - ret = regmap_update_bits(st->regmap, 0x19, ADF4377_0019_CLKOUT2_OP_MSK | - ADF4377_0019_CLKOUT1_OP_MSK, - FIELD_PREP(ADF4377_0019_CLKOUT1_OP_MSK, - ADF4377_0019_CLKOUT_420MV) | - FIELD_PREP(ADF4377_0019_CLKOUT2_OP_MSK, - ADF4377_0019_CLKOUT_420MV)); - -exit: - mutex_unlock(&st->lock); - - return ret; + return regmap_update_bits(st->regmap, 0x19, ADF4377_0019_CLKOUT2_OP_MSK | + ADF4377_0019_CLKOUT1_OP_MSK, + FIELD_PREP(ADF4377_0019_CLKOUT1_OP_MSK, + ADF4377_0019_CLKOUT_420MV) | + FIELD_PREP(ADF4377_0019_CLKOUT2_OP_MSK, + ADF4377_0019_CLKOUT_420MV)); } static void adf4377_gpio_init(struct adf4377_state *st) @@ -919,13 +912,11 @@ static int adf4377_properties_parse(struct adf4377_state *st) static int adf4377_freq_change(struct notifier_block *nb, unsigned long action, void *data) { struct adf4377_state *st = container_of(nb, struct adf4377_state, nb); - int ret; if (action == POST_RATE_CHANGE) { - mutex_lock(&st->lock); - ret = notifier_from_errno(adf4377_init(st)); - mutex_unlock(&st->lock); - return ret; + guard(mutex)(&st->lock); + + return notifier_from_errno(adf4377_init(st)); } return NOTIFY_OK; @@ -1097,8 +1088,8 @@ static int adf4377_probe(struct spi_device *spi) } static const struct spi_device_id adf4377_id[] = { - { "adf4377", (kernel_ulong_t)&adf4377_chip_info }, - { "adf4378", (kernel_ulong_t)&adf4378_chip_info }, + { .name = "adf4377", .driver_data = (kernel_ulong_t)&adf4377_chip_info }, + { .name = "adf4378", .driver_data = (kernel_ulong_t)&adf4378_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, adf4377_id); diff --git a/drivers/iio/frequency/admv1013.c b/drivers/iio/frequency/admv1013.c index b823adfb0f70..c9baaab574e3 100644 --- a/drivers/iio/frequency/admv1013.c +++ b/drivers/iio/frequency/admv1013.c @@ -619,7 +619,7 @@ static int admv1013_probe(struct spi_device *spi) } static const struct spi_device_id admv1013_id[] = { - { "admv1013", 0 }, + { .name = "admv1013" }, { } }; MODULE_DEVICE_TABLE(spi, admv1013_id); diff --git a/drivers/iio/frequency/admv1014.c b/drivers/iio/frequency/admv1014.c index 5d36ac4bb666..d1d528975229 100644 --- a/drivers/iio/frequency/admv1014.c +++ b/drivers/iio/frequency/admv1014.c @@ -781,7 +781,7 @@ static int admv1014_probe(struct spi_device *spi) } static const struct spi_device_id admv1014_id[] = { - { "admv1014", 0 }, + { .name = "admv1014" }, { } }; MODULE_DEVICE_TABLE(spi, admv1014_id); diff --git a/drivers/iio/frequency/adrf6780.c b/drivers/iio/frequency/adrf6780.c index c2dc06f05c21..79a615062172 100644 --- a/drivers/iio/frequency/adrf6780.c +++ b/drivers/iio/frequency/adrf6780.c @@ -486,7 +486,7 @@ static int adrf6780_probe(struct spi_device *spi) } static const struct spi_device_id adrf6780_id[] = { - { "adrf6780", 0 }, + { .name = "adrf6780" }, { } }; MODULE_DEVICE_TABLE(spi, adrf6780_id); diff --git a/drivers/iio/gyro/adis16080.c b/drivers/iio/gyro/adis16080.c index 178bba95a709..0c8bc1e569fe 100644 --- a/drivers/iio/gyro/adis16080.c +++ b/drivers/iio/gyro/adis16080.c @@ -212,8 +212,8 @@ static int adis16080_probe(struct spi_device *spi) } static const struct spi_device_id adis16080_ids[] = { - { "adis16080", ID_ADIS16080 }, - { "adis16100", ID_ADIS16100 }, + { .name = "adis16080", .driver_data = ID_ADIS16080 }, + { .name = "adis16100", .driver_data = ID_ADIS16100 }, { } }; MODULE_DEVICE_TABLE(spi, adis16080_ids); diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c index 369c7428e1ef..ff335f81e9ae 100644 --- a/drivers/iio/gyro/adis16136.c +++ b/drivers/iio/gyro/adis16136.c @@ -563,10 +563,10 @@ static int adis16136_probe(struct spi_device *spi) } static const struct spi_device_id adis16136_ids[] = { - { "adis16133", ID_ADIS16133 }, - { "adis16135", ID_ADIS16135 }, - { "adis16136", ID_ADIS16136 }, - { "adis16137", ID_ADIS16137 }, + { .name = "adis16133", .driver_data = ID_ADIS16133 }, + { .name = "adis16135", .driver_data = ID_ADIS16135 }, + { .name = "adis16136", .driver_data = ID_ADIS16136 }, + { .name = "adis16137", .driver_data = ID_ADIS16137 }, { } }; MODULE_DEVICE_TABLE(spi, adis16136_ids); diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c index 91b9c5f18ec4..a79a8edf4c98 100644 --- a/drivers/iio/gyro/adis16260.c +++ b/drivers/iio/gyro/adis16260.c @@ -411,12 +411,12 @@ static int adis16260_probe(struct spi_device *spi) * support for the on chip filtering. */ static const struct spi_device_id adis16260_id[] = { - {"adis16260", ADIS16260}, - {"adis16265", ADIS16260}, - {"adis16266", ADIS16266}, - {"adis16250", ADIS16260}, - {"adis16255", ADIS16260}, - {"adis16251", ADIS16251}, + { .name = "adis16260", .driver_data = ADIS16260 }, + { .name = "adis16265", .driver_data = ADIS16260 }, + { .name = "adis16266", .driver_data = ADIS16266 }, + { .name = "adis16250", .driver_data = ADIS16260 }, + { .name = "adis16255", .driver_data = ADIS16260 }, + { .name = "adis16251", .driver_data = ADIS16251 }, { } }; MODULE_DEVICE_TABLE(spi, adis16260_id); diff --git a/drivers/iio/gyro/adxrs450.c b/drivers/iio/gyro/adxrs450.c index a1d8d3cb301b..030d042cab8b 100644 --- a/drivers/iio/gyro/adxrs450.c +++ b/drivers/iio/gyro/adxrs450.c @@ -439,8 +439,8 @@ static int adxrs450_probe(struct spi_device *spi) } static const struct spi_device_id adxrs450_id[] = { - {"adxrs450", ID_ADXRS450}, - {"adxrs453", ID_ADXRS453}, + { .name = "adxrs450", .driver_data = ID_ADXRS450 }, + { .name = "adxrs453", .driver_data = ID_ADXRS453 }, { } }; MODULE_DEVICE_TABLE(spi, adxrs450_id); diff --git a/drivers/iio/gyro/bmg160_spi.c b/drivers/iio/gyro/bmg160_spi.c index 6aecc5eb8347..14ae1d03be3d 100644 --- a/drivers/iio/gyro/bmg160_spi.c +++ b/drivers/iio/gyro/bmg160_spi.c @@ -33,12 +33,11 @@ static void bmg160_spi_remove(struct spi_device *spi) } static const struct spi_device_id bmg160_spi_id[] = { - {"bmg160", 0}, - {"bmi055_gyro", 0}, - {"bmi088_gyro", 0}, + { .name = "bmg160" }, + { .name = "bmi055_gyro" }, + { .name = "bmi088_gyro" }, { } }; - MODULE_DEVICE_TABLE(spi, bmg160_spi_id); static const struct of_device_id bmg160_of_match[] = { diff --git a/drivers/iio/gyro/fxas21002c_spi.c b/drivers/iio/gyro/fxas21002c_spi.c index bd5b8678da13..40b1e02b2a5c 100644 --- a/drivers/iio/gyro/fxas21002c_spi.c +++ b/drivers/iio/gyro/fxas21002c_spi.c @@ -39,7 +39,7 @@ static void fxas21002c_spi_remove(struct spi_device *spi) } static const struct spi_device_id fxas21002c_spi_id[] = { - { "fxas21002c", 0 }, + { .name = "fxas21002c" }, { } }; MODULE_DEVICE_TABLE(spi, fxas21002c_spi_id); diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index adc52a5267f7..58250a972567 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -84,9 +84,8 @@ static const struct iio_chan_spec gyro_3d_channels[] = { /* Channel read_raw handler */ static int gyro_3d_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, - long mask) + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct gyro_3d_state *gyro_state = iio_priv(indio_dev); int report_id = -1; @@ -111,8 +110,7 @@ static int gyro_3d_read_raw(struct iio_dev *indio_dev, min < 0); else { *val = 0; - hid_sensor_power_state(&gyro_state->common_attributes, - false); + hid_sensor_power_state(&gyro_state->common_attributes, false); return -EINVAL; } hid_sensor_power_state(&gyro_state->common_attributes, false); @@ -145,10 +143,8 @@ static int gyro_3d_read_raw(struct iio_dev *indio_dev, /* Channel write_raw handler */ static int gyro_3d_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct gyro_3d_state *gyro_state = iio_priv(indio_dev); int ret = 0; @@ -176,8 +172,7 @@ static const struct iio_info gyro_3d_info = { /* Callback handler to send event after all samples are received and captured */ static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - void *priv) + u32 usage_id, void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct gyro_3d_state *gyro_state = iio_priv(indio_dev); @@ -198,9 +193,9 @@ static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - size_t raw_len, char *raw_data, - void *priv) + u32 usage_id, + size_t raw_len, char *raw_data, + void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct gyro_3d_state *gyro_state = iio_priv(indio_dev); @@ -233,7 +228,7 @@ static int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev, static int gyro_3d_parse_report(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, struct iio_chan_spec *channels, - unsigned usage_id, + u32 usage_id, struct gyro_3d_state *st) { int ret; @@ -253,10 +248,10 @@ static int gyro_3d_parse_report(struct platform_device *pdev, }; } dev_dbg(&pdev->dev, "gyro_3d %x:%x, %x:%x, %x:%x\n", - st->gyro[0].index, - st->gyro[0].report_id, - st->gyro[1].index, st->gyro[1].report_id, - st->gyro[2].index, st->gyro[2].report_id); + st->gyro[0].index, + st->gyro[0].report_id, + st->gyro[1].index, st->gyro[1].report_id, + st->gyro[2].index, st->gyro[2].report_id); st->scale_precision = hid_sensor_format_scale( HID_USAGE_SENSOR_GYRO_3D, @@ -317,32 +312,32 @@ static int hid_gyro_3d_probe(struct platform_device *pdev) atomic_set(&gyro_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, - &gyro_state->common_attributes); + &gyro_state->common_attributes); if (ret < 0) { dev_err(&pdev->dev, "trigger setup failed\n"); return ret; } - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(&pdev->dev, "device register failed\n"); - goto error_remove_trigger; - } - gyro_state->callbacks.send_event = gyro_3d_proc_event; gyro_state->callbacks.capture_sample = gyro_3d_capture_sample; gyro_state->callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D, - &gyro_state->callbacks); + &gyro_state->callbacks); if (ret < 0) { dev_err(&pdev->dev, "callback reg failed\n"); - goto error_iio_unreg; + goto error_remove_trigger; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "device register failed\n"); + goto error_remove_callback; } return ret; -error_iio_unreg: - iio_device_unregister(indio_dev); +error_remove_callback: + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes); return ret; @@ -355,8 +350,8 @@ static void hid_gyro_3d_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct gyro_3d_state *gyro_state = iio_priv(indio_dev); - sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D); iio_device_unregister(indio_dev); + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D); hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes); } diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c index adfbbc0d37dc..c56331755b5c 100644 --- a/drivers/iio/gyro/st_gyro_spi.c +++ b/drivers/iio/gyro/st_gyro_spi.c @@ -97,15 +97,15 @@ static int st_gyro_spi_probe(struct spi_device *spi) } static const struct spi_device_id st_gyro_id_table[] = { - { L3G4200D_GYRO_DEV_NAME }, - { LSM330D_GYRO_DEV_NAME }, - { LSM330DL_GYRO_DEV_NAME }, - { LSM330DLC_GYRO_DEV_NAME }, - { L3GD20_GYRO_DEV_NAME }, - { L3GD20H_GYRO_DEV_NAME }, - { L3G4IS_GYRO_DEV_NAME }, - { LSM330_GYRO_DEV_NAME }, - { LSM9DS0_GYRO_DEV_NAME }, + { .name = L3G4200D_GYRO_DEV_NAME }, + { .name = LSM330D_GYRO_DEV_NAME }, + { .name = LSM330DL_GYRO_DEV_NAME }, + { .name = LSM330DLC_GYRO_DEV_NAME }, + { .name = L3GD20_GYRO_DEV_NAME }, + { .name = L3GD20H_GYRO_DEV_NAME }, + { .name = L3G4IS_GYRO_DEV_NAME }, + { .name = LSM330_GYRO_DEV_NAME }, + { .name = LSM9DS0_GYRO_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(spi, st_gyro_id_table); diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index d358f4d5e5da..27e32707f089 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -568,7 +568,7 @@ static int afe4403_probe(struct spi_device *spi) } static const struct spi_device_id afe4403_ids[] = { - { "afe4403", 0 }, + { .name = "afe4403" }, { } }; MODULE_DEVICE_TABLE(spi, afe4403_ids); diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c index 5267a14d73ec..7cec81ff5685 100644 --- a/drivers/iio/humidity/hid-sensor-humidity.c +++ b/drivers/iio/humidity/hid-sensor-humidity.c @@ -44,7 +44,7 @@ static const struct iio_chan_spec humidity_channels[] = { /* Adjust channel real bits based on report descriptor */ static void humidity_adjust_channel_bit_mask(struct iio_chan_spec *channels, - int channel, int size) + int channel, int size) { channels[channel].scan_type.sign = 's'; /* Real storage bits will change based on the report desc. */ @@ -54,8 +54,8 @@ static void humidity_adjust_channel_bit_mask(struct iio_chan_spec *channels, } static int humidity_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, long mask) + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct hid_humidity_state *humid_st = iio_priv(indio_dev); @@ -100,8 +100,8 @@ static int humidity_read_raw(struct iio_dev *indio_dev, } static int humidity_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct hid_humidity_state *humid_st = iio_priv(indio_dev); @@ -126,7 +126,7 @@ static const struct iio_info humidity_info = { /* Callback handler to send event after all samples are received and captured */ static int humidity_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned int usage_id, void *pdev) + u32 usage_id, void *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct hid_humidity_state *humid_st = iio_priv(indio_dev); @@ -140,8 +140,9 @@ static int humidity_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int humidity_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned int usage_id, size_t raw_len, - char *raw_data, void *pdev) + u32 usage_id, + size_t raw_len, char *raw_data, + void *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct hid_humidity_state *humid_st = iio_priv(indio_dev); @@ -158,10 +159,10 @@ static int humidity_capture_sample(struct hid_sensor_hub_device *hsdev, /* Parse report which is specific to an usage id */ static int humidity_parse_report(struct platform_device *pdev, - struct hid_sensor_hub_device *hsdev, - struct iio_chan_spec *channels, - unsigned int usage_id, - struct hid_humidity_state *st) + struct hid_sensor_hub_device *hsdev, + struct iio_chan_spec *channels, + u32 usage_id, + struct hid_humidity_state *st) { int ret; @@ -214,13 +215,13 @@ static int hid_humidity_probe(struct platform_device *pdev) if (ret) return ret; - humid_chans = devm_kmemdup(&indio_dev->dev, humidity_channels, - sizeof(humidity_channels), GFP_KERNEL); + humid_chans = devm_kmemdup(&pdev->dev, humidity_channels, + sizeof(humidity_channels), GFP_KERNEL); if (!humid_chans) return -ENOMEM; ret = humidity_parse_report(pdev, hsdev, humid_chans, - HID_USAGE_SENSOR_HUMIDITY, humid_st); + HID_USAGE_SENSOR_HUMIDITY, humid_st); if (ret) return ret; @@ -233,7 +234,7 @@ static int hid_humidity_probe(struct platform_device *pdev) atomic_set(&humid_st->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, - &humid_st->common_attributes); + &humid_st->common_attributes); if (ret) return ret; @@ -241,7 +242,7 @@ static int hid_humidity_probe(struct platform_device *pdev) humidity_callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY, - &humidity_callbacks); + &humidity_callbacks); if (ret) goto error_remove_trigger; diff --git a/drivers/iio/humidity/hts221_spi.c b/drivers/iio/humidity/hts221_spi.c index e6fef2acd523..f962842cc71d 100644 --- a/drivers/iio/humidity/hts221_spi.c +++ b/drivers/iio/humidity/hts221_spi.c @@ -47,7 +47,7 @@ static const struct of_device_id hts221_spi_of_match[] = { MODULE_DEVICE_TABLE(of, hts221_spi_of_match); static const struct spi_device_id hts221_spi_id_table[] = { - { HTS221_DEV_NAME }, + { .name = HTS221_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(spi, hts221_spi_id_table); diff --git a/drivers/iio/iio_core_trigger.h b/drivers/iio/iio_core_trigger.h index e1a56824e07f..4698a857739f 100644 --- a/drivers/iio/iio_core_trigger.h +++ b/drivers/iio/iio_core_trigger.h @@ -56,4 +56,4 @@ static inline int iio_trigger_detach_poll_func(struct iio_trigger *trig, return 0; } -#endif /* CONFIG_TRIGGER_CONSUMER */ +#endif /* CONFIG_IIO_TRIGGER */ diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c index 36323ad149e0..4842346f9f0c 100644 --- a/drivers/iio/imu/adis16400.c +++ b/drivers/iio/imu/adis16400.c @@ -1189,21 +1189,21 @@ static int adis16400_probe(struct spi_device *spi) } static const struct spi_device_id adis16400_id[] = { - { "adis16300", (kernel_ulong_t)&adis16300_chip_info }, - { "adis16305", (kernel_ulong_t)&adis16300_chip_info }, - { "adis16334", (kernel_ulong_t)&adis16334_chip_info }, - { "adis16350", (kernel_ulong_t)&adis16350_chip_info }, - { "adis16354", (kernel_ulong_t)&adis16350_chip_info }, - { "adis16355", (kernel_ulong_t)&adis16350_chip_info }, - { "adis16360", (kernel_ulong_t)&adis16360_chip_info }, - { "adis16362", (kernel_ulong_t)&adis16362_chip_info }, - { "adis16364", (kernel_ulong_t)&adis16364_chip_info }, - { "adis16365", (kernel_ulong_t)&adis16360_chip_info }, - { "adis16367", (kernel_ulong_t)&adis16367_chip_info }, - { "adis16400", (kernel_ulong_t)&adis16400_chip_info }, - { "adis16405", (kernel_ulong_t)&adis16400_chip_info }, - { "adis16445", (kernel_ulong_t)&adis16445_chip_info }, - { "adis16448", (kernel_ulong_t)&adis16448_chip_info }, + { .name = "adis16300", .driver_data = (kernel_ulong_t)&adis16300_chip_info }, + { .name = "adis16305", .driver_data = (kernel_ulong_t)&adis16300_chip_info }, + { .name = "adis16334", .driver_data = (kernel_ulong_t)&adis16334_chip_info }, + { .name = "adis16350", .driver_data = (kernel_ulong_t)&adis16350_chip_info }, + { .name = "adis16354", .driver_data = (kernel_ulong_t)&adis16350_chip_info }, + { .name = "adis16355", .driver_data = (kernel_ulong_t)&adis16350_chip_info }, + { .name = "adis16360", .driver_data = (kernel_ulong_t)&adis16360_chip_info }, + { .name = "adis16362", .driver_data = (kernel_ulong_t)&adis16362_chip_info }, + { .name = "adis16364", .driver_data = (kernel_ulong_t)&adis16364_chip_info }, + { .name = "adis16365", .driver_data = (kernel_ulong_t)&adis16360_chip_info }, + { .name = "adis16367", .driver_data = (kernel_ulong_t)&adis16367_chip_info }, + { .name = "adis16400", .driver_data = (kernel_ulong_t)&adis16400_chip_info }, + { .name = "adis16405", .driver_data = (kernel_ulong_t)&adis16400_chip_info }, + { .name = "adis16445", .driver_data = (kernel_ulong_t)&adis16445_chip_info }, + { .name = "adis16448", .driver_data = (kernel_ulong_t)&adis16448_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, adis16400_id); diff --git a/drivers/iio/imu/adis16460.c b/drivers/iio/imu/adis16460.c index ba1887d36577..cadf21c05bbf 100644 --- a/drivers/iio/imu/adis16460.c +++ b/drivers/iio/imu/adis16460.c @@ -394,7 +394,7 @@ static int adis16460_probe(struct spi_device *spi) } static const struct spi_device_id adis16460_ids[] = { - { "adis16460", 0 }, + { .name = "adis16460" }, { } }; MODULE_DEVICE_TABLE(spi, adis16460_ids); diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index 17335386d8e3..5f21dceda8f7 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -2061,33 +2061,33 @@ static const struct of_device_id adis16475_of_match[] = { MODULE_DEVICE_TABLE(of, adis16475_of_match); static const struct spi_device_id adis16475_ids[] = { - { "adis16470", (kernel_ulong_t)&adis16475_chip_info[ADIS16470] }, - { "adis16475-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16475_1] }, - { "adis16475-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16475_2] }, - { "adis16475-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16475_3] }, - { "adis16477-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16477_1] }, - { "adis16477-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16477_2] }, - { "adis16477-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16477_3] }, - { "adis16465-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16465_1] }, - { "adis16465-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16465_2] }, - { "adis16465-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16465_3] }, - { "adis16467-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16467_1] }, - { "adis16467-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16467_2] }, - { "adis16467-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16467_3] }, - { "adis16500", (kernel_ulong_t)&adis16475_chip_info[ADIS16500] }, - { "adis16501", (kernel_ulong_t)&adis16475_chip_info[ADIS16501] }, - { "adis16505-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16505_1] }, - { "adis16505-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16505_2] }, - { "adis16505-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16505_3] }, - { "adis16507-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16507_1] }, - { "adis16507-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16507_2] }, - { "adis16507-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16507_3] }, - { "adis16575-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16575_2] }, - { "adis16575-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16575_3] }, - { "adis16576-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16576_2] }, - { "adis16576-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16576_3] }, - { "adis16577-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16577_2] }, - { "adis16577-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16577_3] }, + { .name = "adis16470", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16470] }, + { .name = "adis16475-1", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16475_1] }, + { .name = "adis16475-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16475_2] }, + { .name = "adis16475-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16475_3] }, + { .name = "adis16477-1", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16477_1] }, + { .name = "adis16477-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16477_2] }, + { .name = "adis16477-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16477_3] }, + { .name = "adis16465-1", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16465_1] }, + { .name = "adis16465-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16465_2] }, + { .name = "adis16465-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16465_3] }, + { .name = "adis16467-1", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16467_1] }, + { .name = "adis16467-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16467_2] }, + { .name = "adis16467-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16467_3] }, + { .name = "adis16500", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16500] }, + { .name = "adis16501", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16501] }, + { .name = "adis16505-1", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16505_1] }, + { .name = "adis16505-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16505_2] }, + { .name = "adis16505-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16505_3] }, + { .name = "adis16507-1", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16507_1] }, + { .name = "adis16507-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16507_2] }, + { .name = "adis16507-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16507_3] }, + { .name = "adis16575-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16575_2] }, + { .name = "adis16575-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16575_3] }, + { .name = "adis16576-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16576_2] }, + { .name = "adis16576-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16576_3] }, + { .name = "adis16577-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16577_2] }, + { .name = "adis16577-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16577_3] }, { } }; MODULE_DEVICE_TABLE(spi, adis16475_ids); diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index e009f3824768..5187566c1876 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -110,7 +110,7 @@ #define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20) -/* Each filter coefficent bank spans two pages */ +/* Each filter coefficient bank spans two pages */ #define ADIS16480_FIR_COEF(page) (x < 60 ? ADIS16480_REG(page, (x) + 8) : \ ADIS16480_REG((page) + 1, (x) - 60 + 8)) #define ADIS16480_FIR_COEF_A(x) ADIS16480_FIR_COEF(0x05, (x)) @@ -1467,7 +1467,7 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p) * We need to perform the padding to have the buffer * elements naturally aligned in case there are any * 32-bit storage size channels enabled which are added - * in the buffer after the temprature data. In case + * in the buffer after the temperature data. In case * there is no data being added after the temperature * data, the padding is harmless. */ @@ -1806,26 +1806,26 @@ static int adis16480_probe(struct spi_device *spi) } static const struct spi_device_id adis16480_ids[] = { - { "adis16375", ADIS16375 }, - { "adis16480", ADIS16480 }, - { "adis16485", ADIS16485 }, - { "adis16486", ADIS16486 }, - { "adis16487", ADIS16487 }, - { "adis16488", ADIS16488 }, - { "adis16489", ADIS16489 }, - { "adis16490", ADIS16490 }, - { "adis16495-1", ADIS16495_1 }, - { "adis16495-2", ADIS16495_2 }, - { "adis16495-3", ADIS16495_3 }, - { "adis16497-1", ADIS16497_1 }, - { "adis16497-2", ADIS16497_2 }, - { "adis16497-3", ADIS16497_3 }, - { "adis16545-1", ADIS16545_1 }, - { "adis16545-2", ADIS16545_2 }, - { "adis16545-3", ADIS16545_3 }, - { "adis16547-1", ADIS16547_1 }, - { "adis16547-2", ADIS16547_2 }, - { "adis16547-3", ADIS16547_3 }, + { .name = "adis16375", .driver_data = ADIS16375 }, + { .name = "adis16480", .driver_data = ADIS16480 }, + { .name = "adis16485", .driver_data = ADIS16485 }, + { .name = "adis16486", .driver_data = ADIS16486 }, + { .name = "adis16487", .driver_data = ADIS16487 }, + { .name = "adis16488", .driver_data = ADIS16488 }, + { .name = "adis16489", .driver_data = ADIS16489 }, + { .name = "adis16490", .driver_data = ADIS16490 }, + { .name = "adis16495-1", .driver_data = ADIS16495_1 }, + { .name = "adis16495-2", .driver_data = ADIS16495_2 }, + { .name = "adis16495-3", .driver_data = ADIS16495_3 }, + { .name = "adis16497-1", .driver_data = ADIS16497_1 }, + { .name = "adis16497-2", .driver_data = ADIS16497_2 }, + { .name = "adis16497-3", .driver_data = ADIS16497_3 }, + { .name = "adis16545-1", .driver_data = ADIS16545_1 }, + { .name = "adis16545-2", .driver_data = ADIS16545_2 }, + { .name = "adis16545-3", .driver_data = ADIS16545_3 }, + { .name = "adis16547-1", .driver_data = ADIS16547_1 }, + { .name = "adis16547-2", .driver_data = ADIS16547_2 }, + { .name = "adis16547-3", .driver_data = ADIS16547_3 }, { } }; MODULE_DEVICE_TABLE(spi, adis16480_ids); diff --git a/drivers/iio/imu/adis16550.c b/drivers/iio/imu/adis16550.c index 1e435d60cd6d..096a612865c4 100644 --- a/drivers/iio/imu/adis16550.c +++ b/drivers/iio/imu/adis16550.c @@ -88,25 +88,7 @@ struct adis16550_sync { u16 max_rate; }; -struct adis16550_chip_info { - const struct iio_chan_spec *channels; - const struct adis16550_sync *sync_mode; - char *name; - u32 num_channels; - u32 gyro_max_val; - u32 gyro_max_scale; - u32 accel_max_val; - u32 accel_max_scale; - u32 temp_scale; - u32 deltang_max_val; - u32 deltvel_max_val; - u32 int_clk; - u16 max_dec; - u16 num_sync; -}; - struct adis16550 { - const struct adis16550_chip_info *info; struct adis adis; unsigned long clk_freq_hz; u32 sync_mode; @@ -449,8 +431,8 @@ static int adis16550_set_freq_hz(struct adis16550 *st, u32 freq_hz) * The optimal sample rate for the supported IMUs is between * int_clk - 1000 and int_clk + 500. */ - u32 max_sample_rate = st->info->int_clk * 1000 + 500000; - u32 min_sample_rate = st->info->int_clk * 1000 - 1000000; + u32 max_sample_rate = 4000 * 1000 + 500000; + u32 min_sample_rate = 4000 * 1000 - 1000000; if (!freq_hz) return -EINVAL; @@ -483,7 +465,7 @@ static int adis16550_set_freq_hz(struct adis16550 *st, u32 freq_hz) if (dec) dec--; - dec = min(dec, st->info->max_dec); + dec = min(dec, 4095); return __adis_write_reg_16(&st->adis, ADIS16550_REG_DEC_RATE, dec); } @@ -591,30 +573,30 @@ static int adis16550_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_ANGL_VEL: - *val = st->info->gyro_max_val; - *val2 = st->info->gyro_max_scale; + *val = 1; + *val2 = IIO_RAD_TO_DEGREE(80 << 16); return IIO_VAL_FRACTIONAL; case IIO_ACCEL: - *val = st->info->accel_max_val; - *val2 = st->info->accel_max_scale; + *val = 1; + *val2 = IIO_M_S_2_TO_G(102400000); return IIO_VAL_FRACTIONAL; case IIO_TEMP: - *val = st->info->temp_scale; + *val = 4; return IIO_VAL_INT; case IIO_DELTA_ANGL: - *val = st->info->deltang_max_val; + *val = IIO_DEGREE_TO_RAD(720); *val2 = 31; return IIO_VAL_FRACTIONAL_LOG2; case IIO_DELTA_VELOCITY: - *val = st->info->deltvel_max_val; + *val = 125; *val2 = 31; return IIO_VAL_FRACTIONAL_LOG2; default: return -EINVAL; } case IIO_CHAN_INFO_OFFSET: - /* temperature centered at 25°C */ - *val = DIV_ROUND_CLOSEST(25000, st->info->temp_scale); + /* temperature centered at 25°C divided by temp scale */ + *val = 25000 / 4; return IIO_VAL_INT; case IIO_CHAN_INFO_CALIBBIAS: ret = adis_read_reg_32(&st->adis, @@ -792,23 +774,6 @@ static const struct adis16550_sync adis16550_sync_modes[] = { { ADIS16550_SYNC_MODE_SCALED, 1, 128 }, }; -static const struct adis16550_chip_info adis16550_chip_info = { - .num_channels = ARRAY_SIZE(adis16550_channels), - .channels = adis16550_channels, - .name = "adis16550", - .gyro_max_val = 1, - .gyro_max_scale = IIO_RAD_TO_DEGREE(80 << 16), - .accel_max_val = 1, - .accel_max_scale = IIO_M_S_2_TO_G(102400000), - .temp_scale = 4, - .deltang_max_val = IIO_DEGREE_TO_RAD(720), - .deltvel_max_val = 125, - .int_clk = 4000, - .max_dec = 4095, - .sync_mode = adis16550_sync_modes, - .num_sync = ARRAY_SIZE(adis16550_sync_modes), -}; - static u32 adis16550_validate_crc(__be32 *buffer, const u8 n_elem) { int i; @@ -917,21 +882,21 @@ static int adis16550_config_sync(struct adis16550 *st) if (IS_ERR(clk)) return PTR_ERR(clk); if (!clk) { - st->clk_freq_hz = st->info->int_clk * 1000; + st->clk_freq_hz = 4000000; return 0; } st->clk_freq_hz = clk_get_rate(clk); - for (i = 0; i < st->info->num_sync; i++) { - if (st->clk_freq_hz >= st->info->sync_mode[i].min_rate && - st->clk_freq_hz <= st->info->sync_mode[i].max_rate) { - sync_mode_data = &st->info->sync_mode[i]; + for (i = 0; i < ARRAY_SIZE(adis16550_sync_modes); i++) { + if (st->clk_freq_hz >= adis16550_sync_modes[i].min_rate && + st->clk_freq_hz <= adis16550_sync_modes[i].max_rate) { + sync_mode_data = &adis16550_sync_modes[i]; break; } } - if (i == st->info->num_sync) + if (i == ARRAY_SIZE(adis16550_sync_modes)) return dev_err_probe(dev, -EINVAL, "Clk rate: %lu not in a valid range", st->clk_freq_hz); @@ -942,7 +907,7 @@ static int adis16550_config_sync(struct adis16550 *st) * of [3000 4500]. */ - sync_scale = DIV_ROUND_CLOSEST(st->info->int_clk, st->clk_freq_hz); + sync_scale = DIV_ROUND_CLOSEST(4000, st->clk_freq_hz); if (3000 > sync_scale || 4500 < sync_scale) return dev_err_probe(dev, -EINVAL, @@ -954,7 +919,7 @@ static int adis16550_config_sync(struct adis16550 *st) if (ret) return ret; - st->clk_freq_hz = st->info->int_clk; + st->clk_freq_hz = 4000; } st->clk_freq_hz *= 1000; @@ -1063,13 +1028,11 @@ static int adis16550_probe(struct spi_device *spi) return -ENOMEM; st = iio_priv(indio_dev); - st->info = spi_get_device_match_data(spi); - if (!st->info) - return -EINVAL; + adis = &st->adis; - indio_dev->name = st->info->name; - indio_dev->channels = st->info->channels; - indio_dev->num_channels = st->info->num_channels; + indio_dev->name = "adis16550"; + indio_dev->channels = adis16550_channels; + indio_dev->num_channels = ARRAY_SIZE(adis16550_channels); indio_dev->available_scan_masks = adis16550_channel_masks; indio_dev->info = &adis16550_info; indio_dev->modes = INDIO_DIRECT_MODE; @@ -1116,13 +1079,13 @@ static int adis16550_probe(struct spi_device *spi) } static const struct spi_device_id adis16550_id[] = { - { "adis16550", (kernel_ulong_t)&adis16550_chip_info}, + { .name = "adis16550" }, { } }; MODULE_DEVICE_TABLE(spi, adis16550_id); static const struct of_device_id adis16550_of_match[] = { - { .compatible = "adi,adis16550", .data = &adis16550_chip_info }, + { .compatible = "adi,adis16550" }, { } }; MODULE_DEVICE_TABLE(of, adis16550_of_match); diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index 86f6ecfd64aa..1e73a7f1f017 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -5,7 +5,7 @@ * Copyright (c) 2016, Intel Corporation. * Copyright (c) 2019, Martin Kelly. * - * IIO core driver for BMI160, with support for I2C/SPI busses + * IIO core driver for BMI160, with support for I2C/SPI buses * * TODO: magnetometer, hardware FIFO */ diff --git a/drivers/iio/imu/bmi160/bmi160_spi.c b/drivers/iio/imu/bmi160/bmi160_spi.c index 2f0a578ee40f..107eb3374922 100644 --- a/drivers/iio/imu/bmi160/bmi160_spi.c +++ b/drivers/iio/imu/bmi160/bmi160_spi.c @@ -34,8 +34,8 @@ static int bmi160_spi_probe(struct spi_device *spi) } static const struct spi_device_id bmi160_spi_id[] = { - {"bmi120", 0}, - {"bmi160", 0}, + { .name = "bmi120" }, + { .name = "bmi160" }, { } }; MODULE_DEVICE_TABLE(spi, bmi160_spi_id); diff --git a/drivers/iio/imu/bmi270/bmi270_spi.c b/drivers/iio/imu/bmi270/bmi270_spi.c index dc7fa01421bc..759b56b59e54 100644 --- a/drivers/iio/imu/bmi270/bmi270_spi.c +++ b/drivers/iio/imu/bmi270/bmi270_spi.c @@ -65,8 +65,8 @@ static int bmi270_spi_probe(struct spi_device *spi) } static const struct spi_device_id bmi270_spi_id[] = { - { "bmi260", (kernel_ulong_t)&bmi260_chip_info }, - { "bmi270", (kernel_ulong_t)&bmi270_chip_info }, + { .name = "bmi260", .driver_data = (kernel_ulong_t)&bmi260_chip_info }, + { .name = "bmi270", .driver_data = (kernel_ulong_t)&bmi270_chip_info }, { } }; @@ -75,6 +75,7 @@ static const struct of_device_id bmi270_of_match[] = { { .compatible = "bosch,bmi270", .data = &bmi270_chip_info }, { } }; +MODULE_DEVICE_TABLE(of, bmi270_of_match); static struct spi_driver bmi270_spi_driver = { .driver = { diff --git a/drivers/iio/imu/bmi323/bmi323_core.c b/drivers/iio/imu/bmi323/bmi323_core.c index f3d499423399..72955a697a93 100644 --- a/drivers/iio/imu/bmi323/bmi323_core.c +++ b/drivers/iio/imu/bmi323/bmi323_core.c @@ -1128,7 +1128,7 @@ static int bmi323_set_watermark(struct iio_dev *indio_dev, unsigned int val) { struct bmi323_data *data = iio_priv(indio_dev); - val = min(val, (u32)BMI323_FIFO_FULL_IN_FRAMES); + val = min(val, BMI323_FIFO_FULL_IN_FRAMES); guard(mutex)(&data->mutex); data->watermark = val; diff --git a/drivers/iio/imu/bmi323/bmi323_spi.c b/drivers/iio/imu/bmi323/bmi323_spi.c index 92f1c4bcc192..ed0235cc40da 100644 --- a/drivers/iio/imu/bmi323/bmi323_spi.c +++ b/drivers/iio/imu/bmi323/bmi323_spi.c @@ -64,7 +64,7 @@ static int bmi323_spi_probe(struct spi_device *spi) } static const struct spi_device_id bmi323_spi_ids[] = { - { "bmi323" }, + { .name = "bmi323" }, { } }; MODULE_DEVICE_TABLE(spi, bmi323_spi_ids); diff --git a/drivers/iio/imu/fxos8700_core.c b/drivers/iio/imu/fxos8700_core.c index 281ebfd9c15a..9d2eb6fbab4a 100644 --- a/drivers/iio/imu/fxos8700_core.c +++ b/drivers/iio/imu/fxos8700_core.c @@ -2,7 +2,7 @@ /* * FXOS8700 - NXP IMU (accelerometer plus magnetometer) * - * IIO core driver for FXOS8700, with support for I2C/SPI busses + * IIO core driver for FXOS8700, with support for I2C/SPI buses * * TODO: Buffer, trigger, and IRQ support */ diff --git a/drivers/iio/imu/fxos8700_spi.c b/drivers/iio/imu/fxos8700_spi.c index 3edf90220bfa..56ad0c5914d9 100644 --- a/drivers/iio/imu/fxos8700_spi.c +++ b/drivers/iio/imu/fxos8700_spi.c @@ -23,7 +23,7 @@ static int fxos8700_spi_probe(struct spi_device *spi) } static const struct spi_device_id fxos8700_spi_id[] = { - {"fxos8700", 0}, + { .name = "fxos8700" }, { } }; MODULE_DEVICE_TABLE(spi, fxos8700_spi_id); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index c8b48a5c5ed0..b55d993f0264 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -6,13 +6,15 @@ #ifndef INV_ICM42600_H_ #define INV_ICM42600_H_ -#include <linux/bits.h> #include <linux/bitfield.h> -#include <linux/regmap.h> +#include <linux/bits.h> #include <linux/mutex.h> -#include <linux/regulator/consumer.h> #include <linux/pm.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + #include <linux/iio/iio.h> + #include <linux/iio/common/inv_sensors_timestamp.h> #include "inv_icm42600_buffer.h" @@ -354,6 +356,8 @@ struct inv_icm42600_sensor_state { cpu_to_le16((_wm) & GENMASK(11, 0)) /* FIFO is 2048 bytes, let 12 samples for reading latency */ #define INV_ICM42600_FIFO_WATERMARK_MAX (2048 - 12 * 16) +/* INV_ICM42600_FIFO_WATERMARK_MAX / 8 = 232 */ +#define INV_ICM42600_FIFO_WATERMARK_MAX_SAMPLES 232 #define INV_ICM42600_REG_INT_CONFIG1 0x0064 #define INV_ICM42600_INT_CONFIG1_TPULSE_DURATION BIT(6) diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index 7df920ef3cf0..4b0e3cd8a506 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -3,25 +3,26 @@ * Copyright (C) 2020 Invensense, Inc. */ -#include <linux/kernel.h> +#include <linux/delay.h> #include <linux/device.h> +#include <linux/kernel.h> +#include <linux/math64.h> +#include <linux/minmax.h> #include <linux/mutex.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> -#include <linux/delay.h> -#include <linux/math64.h> -#include <linux/minmax.h> #include <linux/units.h> #include <linux/iio/buffer.h> -#include <linux/iio/common/inv_sensors_timestamp.h> #include <linux/iio/events.h> #include <linux/iio/iio.h> #include <linux/iio/kfifo_buf.h> +#include <linux/iio/common/inv_sensors_timestamp.h> + #include "inv_icm42600.h" -#include "inv_icm42600_temp.h" #include "inv_icm42600_buffer.h" +#include "inv_icm42600_temp.h" #define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \ { \ @@ -1186,8 +1187,9 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st) indio_dev->num_channels = ARRAY_SIZE(inv_icm42600_accel_channels); indio_dev->available_scan_masks = inv_icm42600_accel_scan_masks; - ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, - &inv_icm42600_buffer_ops); + ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev, + &inv_icm42600_buffer_ops, + inv_icm42600_buffer_attrs); if (ret) return ERR_PTR(ret); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c index 5c3840acf085..998d312f7bde 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c @@ -3,17 +3,20 @@ * Copyright (C) 2020 Invensense, Inc. */ -#include <linux/kernel.h> +#include <linux/delay.h> #include <linux/device.h> +#include <linux/kernel.h> #include <linux/minmax.h> #include <linux/mutex.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> -#include <linux/delay.h> +#include <linux/stringify.h> #include <linux/iio/buffer.h> -#include <linux/iio/common/inv_sensors_timestamp.h> #include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> + +#include <linux/iio/common/inv_sensors_timestamp.h> #include "inv_icm42600.h" #include "inv_icm42600_buffer.h" @@ -186,7 +189,7 @@ static unsigned int inv_icm42600_wm_truncate(unsigned int watermark, * smallest latency but this is not as simple as choosing the smallest watermark * value. Latency depends on watermark and ODR. It requires several steps: * 1) compute gyro and accel latencies and choose the smallest value. - * 2) adapt the choosen latency so that it is a multiple of both gyro and accel + * 2) adapt the chosen latency so that it is a multiple of both gyro and accel * ones. Otherwise it is possible that you don't meet a requirement. (for * example with gyro @100Hz wm 4 and accel @100Hz with wm 6, choosing the * value of 4 will not meet accel latency requirement because 6 is not a @@ -438,6 +441,40 @@ const struct iio_buffer_setup_ops inv_icm42600_buffer_ops = { .postdisable = inv_icm42600_buffer_postdisable, }; +static ssize_t hwfifo_watermark_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + unsigned int wm; + + guard(mutex)(&st->lock); + + if (indio_dev == st->indio_accel) + wm = st->fifo.watermark.eff_accel; + else if (indio_dev == st->indio_gyro) + wm = st->fifo.watermark.eff_gyro; + else + return -EINVAL; + + return sysfs_emit(buf, "%u\n", wm); +} + +IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_min, "1"); +IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_max, + __stringify(INV_ICM42600_FIFO_WATERMARK_MAX_SAMPLES)); +static IIO_DEVICE_ATTR_RO(hwfifo_watermark, 0); +IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_enabled, "1"); + +const struct iio_dev_attr *inv_icm42600_buffer_attrs[] = { + &iio_dev_attr_hwfifo_watermark_min, + &iio_dev_attr_hwfifo_watermark_max, + &iio_dev_attr_hwfifo_watermark, + &iio_dev_attr_hwfifo_enabled, + NULL +}; + int inv_icm42600_buffer_fifo_read(struct inv_icm42600_state *st, unsigned int max) { diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h index 88b8b9f780af..e37ee3416337 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h @@ -6,8 +6,8 @@ #ifndef INV_ICM42600_BUFFER_H_ #define INV_ICM42600_BUFFER_H_ -#include <linux/kernel.h> #include <linux/bits.h> +#include <linux/kernel.h> struct inv_icm42600_state; @@ -80,6 +80,7 @@ ssize_t inv_icm42600_fifo_decode_packet(const void *packet, const void **accel, const void **timestamp, unsigned int *odr); extern const struct iio_buffer_setup_ops inv_icm42600_buffer_ops; +extern const struct iio_dev_attr *inv_icm42600_buffer_attrs[]; int inv_icm42600_buffer_init(struct inv_icm42600_state *st); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c index 76eb22488e5f..dc97d8a274e3 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -3,18 +3,18 @@ * Copyright (C) 2020 Invensense, Inc. */ -#include <linux/kernel.h> -#include <linux/device.h> -#include <linux/module.h> -#include <linux/slab.h> #include <linux/delay.h> -#include <linux/mutex.h> +#include <linux/device.h> #include <linux/interrupt.h> #include <linux/irq.h> -#include <linux/regulator/consumer.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> #include <linux/pm_runtime.h> #include <linux/property.h> #include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> #include <linux/iio/iio.h> diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c index a18dcac93929..253bf571439d 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c @@ -3,22 +3,23 @@ * Copyright (C) 2020 Invensense, Inc. */ -#include <linux/kernel.h> +#include <linux/delay.h> #include <linux/device.h> +#include <linux/kernel.h> +#include <linux/math64.h> #include <linux/mutex.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> -#include <linux/delay.h> -#include <linux/math64.h> #include <linux/iio/buffer.h> -#include <linux/iio/common/inv_sensors_timestamp.h> #include <linux/iio/iio.h> #include <linux/iio/kfifo_buf.h> +#include <linux/iio/common/inv_sensors_timestamp.h> + #include "inv_icm42600.h" -#include "inv_icm42600_temp.h" #include "inv_icm42600_buffer.h" +#include "inv_icm42600_temp.h" #define INV_ICM42600_GYRO_CHAN(_modifier, _index, _ext_info) \ { \ @@ -772,8 +773,9 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st) indio_dev->available_scan_masks = inv_icm42600_gyro_scan_masks; indio_dev->setup_ops = &inv_icm42600_buffer_ops; - ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, - &inv_icm42600_buffer_ops); + ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev, + &inv_icm42600_buffer_ops, + inv_icm42600_buffer_attrs); if (ret) return ERR_PTR(ret); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c index 1013aff4f0ab..28552d2db91d 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c @@ -3,12 +3,12 @@ * Copyright (C) 2020 InvenSense, Inc. */ -#include <linux/kernel.h> #include <linux/device.h> -#include <linux/module.h> #include <linux/i2c.h> -#include <linux/regmap.h> +#include <linux/kernel.h> +#include <linux/module.h> #include <linux/property.h> +#include <linux/regmap.h> #include "inv_icm42600.h" diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c index 57e3c448dca1..faf743bc6444 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c @@ -3,12 +3,12 @@ * Copyright (C) 2020 InvenSense, Inc. */ -#include <linux/kernel.h> #include <linux/device.h> +#include <linux/kernel.h> #include <linux/module.h> -#include <linux/spi/spi.h> -#include <linux/regmap.h> #include <linux/property.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> #include "inv_icm42600.h" @@ -71,13 +71,13 @@ static int inv_icm42600_probe(struct spi_device *spi) * supported by this driver */ static const struct spi_device_id inv_icm42600_id[] = { - { "icm42600", INV_CHIP_ICM42600 }, - { "icm42602", INV_CHIP_ICM42602 }, - { "icm42605", INV_CHIP_ICM42605 }, - { "icm42686", INV_CHIP_ICM42686 }, - { "icm42622", INV_CHIP_ICM42622 }, - { "icm42688", INV_CHIP_ICM42688 }, - { "icm42631", INV_CHIP_ICM42631 }, + { .name = "icm42600", .driver_data = INV_CHIP_ICM42600 }, + { .name = "icm42602", .driver_data = INV_CHIP_ICM42602 }, + { .name = "icm42605", .driver_data = INV_CHIP_ICM42605 }, + { .name = "icm42686", .driver_data = INV_CHIP_ICM42686 }, + { .name = "icm42622", .driver_data = INV_CHIP_ICM42622 }, + { .name = "icm42688", .driver_data = INV_CHIP_ICM42688 }, + { .name = "icm42631", .driver_data = INV_CHIP_ICM42631 }, { } }; MODULE_DEVICE_TABLE(spi, inv_icm42600_id); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c index 727b03d541a5..7f80bda471c3 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c @@ -3,11 +3,12 @@ * Copyright (C) 2020 Invensense, Inc. */ -#include <linux/kernel.h> #include <linux/device.h> +#include <linux/kernel.h> #include <linux/mutex.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> + #include <linux/iio/iio.h> #include "inv_icm42600.h" diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600.h b/drivers/iio/imu/inv_icm45600/inv_icm45600.h index 1c796d4b2a40..95fa934a42b4 100644 --- a/drivers/iio/imu/inv_icm45600/inv_icm45600.h +++ b/drivers/iio/imu/inv_icm45600/inv_icm45600.h @@ -190,7 +190,7 @@ struct inv_icm45600_sensor_state { #define INV_ICM45600_REG_IREG_ADDR 0x7C #define INV_ICM45600_REG_IREG_DATA 0x7E -/* Direct acces registers */ +/* Direct access registers */ #define INV_ICM45600_REG_MISC2 0x007F #define INV_ICM45600_MISC2_SOFT_RESET BIT(1) diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_buffer.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_buffer.c index 2b9ea317385c..42111c543d3c 100644 --- a/drivers/iio/imu/inv_icm45600/inv_icm45600_buffer.c +++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_buffer.c @@ -422,8 +422,11 @@ int inv_icm45600_buffer_fifo_read(struct inv_icm45600_state *st, if (max > 0 && fifo_nb > max) fifo_nb = max; - /* Try to read all FIFO data in internal buffer. */ - st->fifo.count = fifo_nb * packet_size; + /* + * Read all FIFO data into the internal buffer, clamping the + * device-reported count to the buffer capacity. + */ + st->fifo.count = min(fifo_nb * packet_size, INV_ICM45600_FIFO_SIZE_MAX); ret = regmap_noinc_read(st->map, INV_ICM45600_REG_FIFO_DATA, st->fifo.data, st->fifo.count); if (ret == -ENOTSUPP || ret == -EFBIG) { diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_core.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_core.c index d49053161a65..c1d7aa7e950d 100644 --- a/drivers/iio/imu/inv_icm45600/inv_icm45600_core.c +++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_core.c @@ -716,7 +716,7 @@ int inv_icm45600_core_probe(struct regmap *regmap, const struct inv_icm45600_chi dev_set_drvdata(dev, st); - st->fifo.data = devm_kzalloc(dev, 8192, GFP_KERNEL); + st->fifo.data = devm_kzalloc(dev, INV_ICM45600_FIFO_SIZE_MAX, GFP_KERNEL); if (!st->fifo.data) return -ENOMEM; diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c index 81ba1b60f04b..69acf9bac2db 100644 --- a/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c +++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c @@ -22,7 +22,7 @@ static int inv_icm45600_probe(struct i2c_client *client) if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) return -ENODEV; - chip_info = device_get_match_data(&client->dev); + chip_info = i2c_get_match_data(client); if (!chip_info) return -ENODEV; diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_spi.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_spi.c index 450a0f2abaaa..087e590e04c2 100644 --- a/drivers/iio/imu/inv_icm45600/inv_icm45600_spi.c +++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_spi.c @@ -48,14 +48,14 @@ static int inv_icm45600_probe(struct spi_device *spi) * supported by this driver. */ static const struct spi_device_id inv_icm45600_id[] = { - { "icm45605", (kernel_ulong_t)&inv_icm45605_chip_info }, - { "icm45606", (kernel_ulong_t)&inv_icm45606_chip_info }, - { "icm45608", (kernel_ulong_t)&inv_icm45608_chip_info }, - { "icm45634", (kernel_ulong_t)&inv_icm45634_chip_info }, - { "icm45686", (kernel_ulong_t)&inv_icm45686_chip_info }, - { "icm45687", (kernel_ulong_t)&inv_icm45687_chip_info }, - { "icm45688p", (kernel_ulong_t)&inv_icm45688p_chip_info }, - { "icm45689", (kernel_ulong_t)&inv_icm45689_chip_info }, + { .name = "icm45605", .driver_data = (kernel_ulong_t)&inv_icm45605_chip_info }, + { .name = "icm45606", .driver_data = (kernel_ulong_t)&inv_icm45606_chip_info }, + { .name = "icm45608", .driver_data = (kernel_ulong_t)&inv_icm45608_chip_info }, + { .name = "icm45634", .driver_data = (kernel_ulong_t)&inv_icm45634_chip_info }, + { .name = "icm45686", .driver_data = (kernel_ulong_t)&inv_icm45686_chip_info }, + { .name = "icm45687", .driver_data = (kernel_ulong_t)&inv_icm45687_chip_info }, + { .name = "icm45688p", .driver_data = (kernel_ulong_t)&inv_icm45688p_chip_info }, + { .name = "icm45689", .driver_data = (kernel_ulong_t)&inv_icm45689_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, inv_icm45600_id); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c index 47394594d17a..6b858fdfd1c6 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c @@ -106,9 +106,9 @@ static int inv_magn_init(struct inv_mpu6050_state *st) return ret; /* - * Sensor sentivity + * Sensor sensitivity * 1 uT = 0.01 G and value is in micron (1e6) - * sensitvity = x uT * 0.01 * 1e6 + * sensitivity = x uT * 0.01 * 1e6 */ switch (st->chip_type) { case INV_MPU9150: diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c index b8204eb0b4c6..71e90ddc19dd 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c @@ -65,23 +65,23 @@ static int inv_mpu_probe(struct spi_device *spi) * supported by this driver */ static const struct spi_device_id inv_mpu_id[] = { - {"mpu6000", INV_MPU6000}, - {"mpu6500", INV_MPU6500}, - {"mpu6515", INV_MPU6515}, - {"mpu6880", INV_MPU6880}, - {"mpu9250", INV_MPU9250}, - {"mpu9255", INV_MPU9255}, - {"icm20608", INV_ICM20608}, - {"icm20608d", INV_ICM20608D}, - {"icm20609", INV_ICM20609}, - {"icm20689", INV_ICM20689}, - {"icm20600", INV_ICM20600}, - {"icm20602", INV_ICM20602}, - {"icm20690", INV_ICM20690}, - {"iam20380", INV_IAM20380}, - {"iam20680", INV_IAM20680}, - {"iam20680hp", INV_IAM20680HP}, - {"iam20680ht", INV_IAM20680HT}, + { .name = "mpu6000", .driver_data = INV_MPU6000 }, + { .name = "mpu6500", .driver_data = INV_MPU6500 }, + { .name = "mpu6515", .driver_data = INV_MPU6515 }, + { .name = "mpu6880", .driver_data = INV_MPU6880 }, + { .name = "mpu9250", .driver_data = INV_MPU9250 }, + { .name = "mpu9255", .driver_data = INV_MPU9255 }, + { .name = "icm20608", .driver_data = INV_ICM20608 }, + { .name = "icm20608d", .driver_data = INV_ICM20608D }, + { .name = "icm20609", .driver_data = INV_ICM20609 }, + { .name = "icm20689", .driver_data = INV_ICM20689 }, + { .name = "icm20600", .driver_data = INV_ICM20600 }, + { .name = "icm20602", .driver_data = INV_ICM20602 }, + { .name = "icm20690", .driver_data = INV_ICM20690 }, + { .name = "iam20380", .driver_data = INV_IAM20380 }, + { .name = "iam20680", .driver_data = INV_IAM20680 }, + { .name = "iam20680hp", .driver_data = INV_IAM20680HP }, + { .name = "iam20680ht", .driver_data = INV_IAM20680HT }, { } }; diff --git a/drivers/iio/imu/smi240.c b/drivers/iio/imu/smi240.c index d159ee59acdd..f419296bba88 100644 --- a/drivers/iio/imu/smi240.c +++ b/drivers/iio/imu/smi240.c @@ -593,7 +593,7 @@ static int smi240_probe(struct spi_device *spi) } static const struct spi_device_id smi240_spi_id[] = { - { "smi240" }, + { .name = "smi240" }, { } }; MODULE_DEVICE_TABLE(spi, smi240_spi_id); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c index 3389b15df0bc..ed47d5a6f11c 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c @@ -138,30 +138,30 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = { MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match); static const struct spi_device_id st_lsm6dsx_spi_id_table[] = { - { ST_LSM6DS3_DEV_NAME, ST_LSM6DS3_ID }, - { ST_LSM6DS3H_DEV_NAME, ST_LSM6DS3H_ID }, - { ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID }, - { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID }, - { ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID }, - { ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID }, - { ST_ASM330LHH_DEV_NAME, ST_ASM330LHH_ID }, - { ST_LSM6DSOX_DEV_NAME, ST_LSM6DSOX_ID }, - { ST_LSM6DSR_DEV_NAME, ST_LSM6DSR_ID }, - { ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID }, - { ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID }, - { ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID }, - { ST_LSM6DS0_DEV_NAME, ST_LSM6DS0_ID }, - { ST_LSM6DSRX_DEV_NAME, ST_LSM6DSRX_ID }, - { ST_LSM6DST_DEV_NAME, ST_LSM6DST_ID }, - { ST_LSM6DSOP_DEV_NAME, ST_LSM6DSOP_ID }, - { ST_ASM330LHHX_DEV_NAME, ST_ASM330LHHX_ID }, - { ST_LSM6DSTX_DEV_NAME, ST_LSM6DSTX_ID }, - { ST_LSM6DSV_DEV_NAME, ST_LSM6DSV_ID }, - { ST_LSM6DSV16X_DEV_NAME, ST_LSM6DSV16X_ID }, - { ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID }, - { ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID }, - { ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID }, - { ST_ASM330LHHXG1_DEV_NAME, ST_ASM330LHHXG1_ID }, + { .name = ST_LSM6DS3_DEV_NAME, .driver_data = ST_LSM6DS3_ID }, + { .name = ST_LSM6DS3H_DEV_NAME, .driver_data = ST_LSM6DS3H_ID }, + { .name = ST_LSM6DSL_DEV_NAME, .driver_data = ST_LSM6DSL_ID }, + { .name = ST_LSM6DSM_DEV_NAME, .driver_data = ST_LSM6DSM_ID }, + { .name = ST_ISM330DLC_DEV_NAME, .driver_data = ST_ISM330DLC_ID }, + { .name = ST_LSM6DSO_DEV_NAME, .driver_data = ST_LSM6DSO_ID }, + { .name = ST_ASM330LHH_DEV_NAME, .driver_data = ST_ASM330LHH_ID }, + { .name = ST_LSM6DSOX_DEV_NAME, .driver_data = ST_LSM6DSOX_ID }, + { .name = ST_LSM6DSR_DEV_NAME, .driver_data = ST_LSM6DSR_ID }, + { .name = ST_LSM6DS3TRC_DEV_NAME, .driver_data = ST_LSM6DS3TRC_ID }, + { .name = ST_ISM330DHCX_DEV_NAME, .driver_data = ST_ISM330DHCX_ID }, + { .name = ST_LSM9DS1_DEV_NAME, .driver_data = ST_LSM9DS1_ID }, + { .name = ST_LSM6DS0_DEV_NAME, .driver_data = ST_LSM6DS0_ID }, + { .name = ST_LSM6DSRX_DEV_NAME, .driver_data = ST_LSM6DSRX_ID }, + { .name = ST_LSM6DST_DEV_NAME, .driver_data = ST_LSM6DST_ID }, + { .name = ST_LSM6DSOP_DEV_NAME, .driver_data = ST_LSM6DSOP_ID }, + { .name = ST_ASM330LHHX_DEV_NAME, .driver_data = ST_ASM330LHHX_ID }, + { .name = ST_LSM6DSTX_DEV_NAME, .driver_data = ST_LSM6DSTX_ID }, + { .name = ST_LSM6DSV_DEV_NAME, .driver_data = ST_LSM6DSV_ID }, + { .name = ST_LSM6DSV16X_DEV_NAME, .driver_data = ST_LSM6DSV16X_ID }, + { .name = ST_LSM6DSO16IS_DEV_NAME, .driver_data = ST_LSM6DSO16IS_ID }, + { .name = ST_ISM330IS_DEV_NAME, .driver_data = ST_ISM330IS_ID }, + { .name = ST_ASM330LHB_DEV_NAME, .driver_data = ST_ASM330LHB_ID }, + { .name = ST_ASM330LHHXG1_DEV_NAME, .driver_data = ST_ASM330LHHXG1_ID }, { } }; MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table); diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c index 8c5d8535e54c..e67f09e1f093 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c @@ -32,8 +32,8 @@ static const struct of_device_id st_lsm9ds0_of_match[] = { MODULE_DEVICE_TABLE(of, st_lsm9ds0_of_match); static const struct spi_device_id st_lsm9ds0_id_table[] = { - { LSM303D_IMU_DEV_NAME }, - { LSM9DS0_IMU_DEV_NAME }, + { .name = LSM303D_IMU_DEV_NAME }, + { .name = LSM9DS0_IMU_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(spi, st_lsm9ds0_id_table); diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c index 4763e224ebc6..f7a4be8ec320 100644 --- a/drivers/iio/industrialio-backend.c +++ b/drivers/iio/industrialio-backend.c @@ -649,7 +649,7 @@ EXPORT_SYMBOL_NS_GPL(iio_backend_ext_info_get, "IIO_BACKEND"); * @len: Buffer length * * This helper is intended to be used by backends that extend an IIO channel - * (trough iio_backend_extend_chan_spec()) with extended info. In that case, + * (through iio_backend_extend_chan_spec()) with extended info. In that case, * backends are not supposed to give their own callbacks (as they would not have * a way to get the backend from indio_dev). This is the setter. * @@ -851,7 +851,7 @@ EXPORT_SYMBOL_NS_GPL(iio_backend_filter_type_set, "IIO_BACKEND"); * @back: Backend device * @timeout_us: Timeout value in us. * - * When activated, it initates a proccess that aligns the sample's most + * When activated, it initiates a process that aligns the sample's most * significant bit (MSB) based solely on the captured data, without * considering any other external signals. * @@ -1017,7 +1017,7 @@ static struct iio_backend *__devm_iio_backend_fwnode_get(struct device *dev, con * @dev: Consumer device for the backend * @name: Backend name * - * Get's the backend associated with @dev. + * Gets the backend associated with @dev. * * RETURNS: * A backend pointer, negative error pointer otherwise. @@ -1050,7 +1050,7 @@ EXPORT_SYMBOL_NS_GPL(devm_iio_backend_get_by_index, "IIO_BACKEND"); * @name: Backend name * @fwnode: Firmware node of the backend consumer * - * Get's the backend associated with a firmware node. + * Gets the backend associated with a firmware node. * * RETURNS: * A backend pointer, negative error pointer otherwise. diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 7e3d3872e2e6..bdf3d4c06331 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -19,6 +19,7 @@ #include <linux/idr.h> #include <linux/kdev_t.h> #include <linux/kernel.h> +#include <linux/math64.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/poll.h> @@ -26,7 +27,6 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/wait.h> -#include <linux/wordpart.h> #include <linux/iio/buffer.h> #include <linux/iio/buffer_impl.h> @@ -656,6 +656,7 @@ static ssize_t __iio_format_value(char *buf, size_t offset, unsigned int type, int size, const int *vals) { int tmp0, tmp1; + int l = 0; s64 tmp2; bool scale_db = false; @@ -699,7 +700,6 @@ static ssize_t __iio_format_value(char *buf, size_t offset, unsigned int type, case IIO_VAL_INT_MULTIPLE: { int i; - int l = 0; for (i = 0; i < size; ++i) l += sysfs_emit_at(buf, offset + l, "%d ", vals[i]); @@ -708,8 +708,25 @@ static ssize_t __iio_format_value(char *buf, size_t offset, unsigned int type, case IIO_VAL_CHAR: return sysfs_emit_at(buf, offset, "%c", (char)vals[0]); case IIO_VAL_INT_64: - tmp2 = (s64)((((u64)vals[1]) << 32) | (u32)vals[0]); - return sysfs_emit_at(buf, offset, "%lld", tmp2); + return sysfs_emit_at(buf, offset, "%lld", + iio_val_s64_compose(vals[0], vals[1])); + case IIO_VAL_DECIMAL64_MILLI: + case IIO_VAL_DECIMAL64_MICRO: + case IIO_VAL_DECIMAL64_NANO: + case IIO_VAL_DECIMAL64_PICO: + { + int scale = type - IIO_VAL_DECIMAL64_BASE; + s64 frac; + + tmp2 = div64_s64_rem(iio_val_s64_compose(vals[0], vals[1]), + int_pow(10, scale), &frac); + if (tmp2 == 0 && frac < 0) + l += sysfs_emit_at(buf, offset, "-"); + + l += sysfs_emit_at(buf, offset + l, "%lld.%0*lld", tmp2, scale, + abs(frac)); + return l; + } default: return 0; } @@ -979,6 +996,7 @@ static ssize_t iio_write_channel_info(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret, fract_mult = 100000; + int type, dec_scale = 0; int integer, fract = 0; long long integer64; bool is_char = false; @@ -989,9 +1007,11 @@ static ssize_t iio_write_channel_info(struct device *dev, if (!indio_dev->info->write_raw) return -EINVAL; - if (indio_dev->info->write_raw_get_fmt) - switch (indio_dev->info->write_raw_get_fmt(indio_dev, - this_attr->c, this_attr->address)) { + if (indio_dev->info->write_raw_get_fmt) { + type = indio_dev->info->write_raw_get_fmt(indio_dev, + this_attr->c, + this_attr->address); + switch (type) { case IIO_VAL_INT: fract_mult = 0; break; @@ -1007,12 +1027,19 @@ static ssize_t iio_write_channel_info(struct device *dev, case IIO_VAL_CHAR: is_char = true; break; + case IIO_VAL_DECIMAL64_MILLI: + case IIO_VAL_DECIMAL64_MICRO: + case IIO_VAL_DECIMAL64_NANO: + case IIO_VAL_DECIMAL64_PICO: + dec_scale = type - IIO_VAL_DECIMAL64_BASE; + fallthrough; case IIO_VAL_INT_64: is_64bit = true; break; default: return -EINVAL; } + } if (is_char) { char ch; @@ -1021,12 +1048,14 @@ static ssize_t iio_write_channel_info(struct device *dev, return -EINVAL; integer = ch; } else if (is_64bit) { - ret = kstrtoll(buf, 0, &integer64); + if (dec_scale) + ret = kstrtodec64(buf, dec_scale, &integer64); + else + ret = kstrtoll(buf, 0, &integer64); if (ret) return ret; - fract = upper_32_bits(integer64); - integer = lower_32_bits(integer64); + iio_val_s64_decompose(integer64, &integer, &fract); } else { ret = __iio_str_to_fixpoint(buf, fract_mult, &integer, &fract, scale_db); diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 9ce20cb05a9b..fb08e4f02520 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -281,7 +281,7 @@ struct iio_channel *fwnode_iio_channel_get_by_name(struct fwnode_handle *fwnode, return ERR_PTR(-ENODEV); } -EXPORT_SYMBOL_GPL(fwnode_iio_channel_get_by_name); +EXPORT_SYMBOL_NS_GPL(fwnode_iio_channel_get_by_name, "IIO_CONSUMER"); static struct iio_channel *fwnode_iio_channel_get_all(struct device *dev) { @@ -386,7 +386,7 @@ struct iio_channel *iio_channel_get(struct device *dev, return iio_channel_get_sys(name, channel_name); } -EXPORT_SYMBOL_GPL(iio_channel_get); +EXPORT_SYMBOL_NS_GPL(iio_channel_get, "IIO_CONSUMER"); void iio_channel_release(struct iio_channel *channel) { @@ -395,7 +395,7 @@ void iio_channel_release(struct iio_channel *channel) iio_device_put(channel->indio_dev); kfree(channel); } -EXPORT_SYMBOL_GPL(iio_channel_release); +EXPORT_SYMBOL_NS_GPL(iio_channel_release, "IIO_CONSUMER"); static void devm_iio_channel_free(void *iio_channel) { @@ -418,7 +418,7 @@ struct iio_channel *devm_iio_channel_get(struct device *dev, return channel; } -EXPORT_SYMBOL_GPL(devm_iio_channel_get); +EXPORT_SYMBOL_NS_GPL(devm_iio_channel_get, "IIO_CONSUMER"); struct iio_channel *devm_fwnode_iio_channel_get_by_name(struct device *dev, struct fwnode_handle *fwnode, @@ -437,7 +437,7 @@ struct iio_channel *devm_fwnode_iio_channel_get_by_name(struct device *dev, return channel; } -EXPORT_SYMBOL_GPL(devm_fwnode_iio_channel_get_by_name); +EXPORT_SYMBOL_NS_GPL(devm_fwnode_iio_channel_get_by_name, "IIO_CONSUMER"); struct iio_channel *iio_channel_get_all(struct device *dev) { @@ -506,7 +506,7 @@ error_free_chans: iio_device_put(chans[i].indio_dev); return ERR_PTR(ret); } -EXPORT_SYMBOL_GPL(iio_channel_get_all); +EXPORT_SYMBOL_NS_GPL(iio_channel_get_all, "IIO_CONSUMER"); void iio_channel_release_all(struct iio_channel *channels) { @@ -518,7 +518,7 @@ void iio_channel_release_all(struct iio_channel *channels) } kfree(channels); } -EXPORT_SYMBOL_GPL(iio_channel_release_all); +EXPORT_SYMBOL_NS_GPL(iio_channel_release_all, "IIO_CONSUMER"); static void devm_iio_channel_free_all(void *iio_channels) { @@ -541,7 +541,7 @@ struct iio_channel *devm_iio_channel_get_all(struct device *dev) return channels; } -EXPORT_SYMBOL_GPL(devm_iio_channel_get_all); +EXPORT_SYMBOL_NS_GPL(devm_iio_channel_get_all, "IIO_CONSUMER"); static int iio_channel_read(struct iio_channel *chan, int *val, int *val2, enum iio_chan_info_enum info) @@ -585,7 +585,7 @@ int iio_read_channel_raw(struct iio_channel *chan, int *val) return iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW); } -EXPORT_SYMBOL_GPL(iio_read_channel_raw); +EXPORT_SYMBOL_NS_GPL(iio_read_channel_raw, "IIO_CONSUMER"); int iio_read_channel_average_raw(struct iio_channel *chan, int *val) { @@ -597,7 +597,7 @@ int iio_read_channel_average_raw(struct iio_channel *chan, int *val) return iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_AVERAGE_RAW); } -EXPORT_SYMBOL_GPL(iio_read_channel_average_raw); +EXPORT_SYMBOL_NS_GPL(iio_read_channel_average_raw, "IIO_CONSUMER"); int iio_multiply_value(int *result, s64 multiplier, unsigned int type, int val, int val2) @@ -701,7 +701,7 @@ int iio_convert_raw_to_processed(struct iio_channel *chan, int raw, return iio_convert_raw_to_processed_unlocked(chan, raw, processed, scale); } -EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed); +EXPORT_SYMBOL_NS_GPL(iio_convert_raw_to_processed, "IIO_CONSUMER"); int iio_read_channel_attribute(struct iio_channel *chan, int *val, int *val2, enum iio_chan_info_enum attribute) @@ -714,13 +714,13 @@ int iio_read_channel_attribute(struct iio_channel *chan, int *val, int *val2, return iio_channel_read(chan, val, val2, attribute); } -EXPORT_SYMBOL_GPL(iio_read_channel_attribute); +EXPORT_SYMBOL_NS_GPL(iio_read_channel_attribute, "IIO_CONSUMER"); int iio_read_channel_offset(struct iio_channel *chan, int *val, int *val2) { return iio_read_channel_attribute(chan, val, val2, IIO_CHAN_INFO_OFFSET); } -EXPORT_SYMBOL_GPL(iio_read_channel_offset); +EXPORT_SYMBOL_NS_GPL(iio_read_channel_offset, "IIO_CONSUMER"); int iio_read_channel_processed_scale(struct iio_channel *chan, int *val, unsigned int scale) @@ -752,20 +752,20 @@ int iio_read_channel_processed_scale(struct iio_channel *chan, int *val, scale); } } -EXPORT_SYMBOL_GPL(iio_read_channel_processed_scale); +EXPORT_SYMBOL_NS_GPL(iio_read_channel_processed_scale, "IIO_CONSUMER"); int iio_read_channel_processed(struct iio_channel *chan, int *val) { /* This is just a special case with scale factor 1 */ return iio_read_channel_processed_scale(chan, val, 1); } -EXPORT_SYMBOL_GPL(iio_read_channel_processed); +EXPORT_SYMBOL_NS_GPL(iio_read_channel_processed, "IIO_CONSUMER"); int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2) { return iio_read_channel_attribute(chan, val, val2, IIO_CHAN_INFO_SCALE); } -EXPORT_SYMBOL_GPL(iio_read_channel_scale); +EXPORT_SYMBOL_NS_GPL(iio_read_channel_scale, "IIO_CONSUMER"); static int iio_channel_read_avail(struct iio_channel *chan, const int **vals, int *type, int *length, @@ -794,7 +794,7 @@ int iio_read_avail_channel_attribute(struct iio_channel *chan, return iio_channel_read_avail(chan, vals, type, length, attribute); } -EXPORT_SYMBOL_GPL(iio_read_avail_channel_attribute); +EXPORT_SYMBOL_NS_GPL(iio_read_avail_channel_attribute, "IIO_CONSUMER"); int iio_read_avail_channel_raw(struct iio_channel *chan, const int **vals, int *length) @@ -811,7 +811,7 @@ int iio_read_avail_channel_raw(struct iio_channel *chan, return ret; } -EXPORT_SYMBOL_GPL(iio_read_avail_channel_raw); +EXPORT_SYMBOL_NS_GPL(iio_read_avail_channel_raw, "IIO_CONSUMER"); static int iio_channel_read_max(struct iio_channel *chan, int *val, int *val2, int *type, @@ -867,7 +867,7 @@ int iio_read_max_channel_raw(struct iio_channel *chan, int *val) return iio_channel_read_max(chan, val, NULL, &type, IIO_CHAN_INFO_RAW); } -EXPORT_SYMBOL_GPL(iio_read_max_channel_raw); +EXPORT_SYMBOL_NS_GPL(iio_read_max_channel_raw, "IIO_CONSUMER"); static int iio_channel_read_min(struct iio_channel *chan, int *val, int *val2, int *type, @@ -923,7 +923,7 @@ int iio_read_min_channel_raw(struct iio_channel *chan, int *val) return iio_channel_read_min(chan, val, NULL, &type, IIO_CHAN_INFO_RAW); } -EXPORT_SYMBOL_GPL(iio_read_min_channel_raw); +EXPORT_SYMBOL_NS_GPL(iio_read_min_channel_raw, "IIO_CONSUMER"); int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type) { @@ -937,7 +937,7 @@ int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type) return 0; } -EXPORT_SYMBOL_GPL(iio_get_channel_type); +EXPORT_SYMBOL_NS_GPL(iio_get_channel_type, "IIO_CONSUMER"); static int iio_channel_write(struct iio_channel *chan, int val, int val2, enum iio_chan_info_enum info) @@ -961,13 +961,13 @@ int iio_write_channel_attribute(struct iio_channel *chan, int val, int val2, return iio_channel_write(chan, val, val2, attribute); } -EXPORT_SYMBOL_GPL(iio_write_channel_attribute); +EXPORT_SYMBOL_NS_GPL(iio_write_channel_attribute, "IIO_CONSUMER"); int iio_write_channel_raw(struct iio_channel *chan, int val) { return iio_write_channel_attribute(chan, val, 0, IIO_CHAN_INFO_RAW); } -EXPORT_SYMBOL_GPL(iio_write_channel_raw); +EXPORT_SYMBOL_NS_GPL(iio_write_channel_raw, "IIO_CONSUMER"); unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan) { @@ -982,7 +982,7 @@ unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan) return i; } -EXPORT_SYMBOL_GPL(iio_get_channel_ext_info_count); +EXPORT_SYMBOL_NS_GPL(iio_get_channel_ext_info_count, "IIO_CONSUMER"); static const struct iio_chan_spec_ext_info * iio_lookup_ext_info(const struct iio_channel *chan, const char *attr) @@ -1017,7 +1017,7 @@ ssize_t iio_read_channel_ext_info(struct iio_channel *chan, return ext_info->read(chan->indio_dev, ext_info->private, chan->channel, buf); } -EXPORT_SYMBOL_GPL(iio_read_channel_ext_info); +EXPORT_SYMBOL_NS_GPL(iio_read_channel_ext_info, "IIO_CONSUMER"); ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr, const char *buf, size_t len) @@ -1031,7 +1031,7 @@ ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr, return ext_info->write(chan->indio_dev, ext_info->private, chan->channel, buf, len); } -EXPORT_SYMBOL_GPL(iio_write_channel_ext_info); +EXPORT_SYMBOL_NS_GPL(iio_write_channel_ext_info, "IIO_CONSUMER"); ssize_t iio_read_channel_label(struct iio_channel *chan, char *buf) { @@ -1042,4 +1042,4 @@ 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); +EXPORT_SYMBOL_NS_GPL(iio_read_channel_label, "IIO_CONSUMER"); diff --git a/drivers/iio/light/cm3605.c b/drivers/iio/light/cm3605.c index 98c84f33db60..9f799041edf9 100644 --- a/drivers/iio/light/cm3605.c +++ b/drivers/iio/light/cm3605.c @@ -324,3 +324,4 @@ module_platform_driver(cm3605_driver); MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); MODULE_DESCRIPTION("CM3605 ambient light and proximity sensor driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c index 05773e24931b..02818e2aed68 100644 --- a/drivers/iio/light/gp2ap002.c +++ b/drivers/iio/light/gp2ap002.c @@ -723,3 +723,4 @@ module_i2c_driver(gp2ap002_driver); MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); MODULE_DESCRIPTION("GP2AP002 ambient light and proximity sensor driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index 6bf1bc9a38fe..6fb6ace26834 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -119,9 +119,8 @@ static const struct iio_chan_spec als_channels[] = { /* Channel read_raw handler */ static int als_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, - long mask) + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct als_state *als_state = iio_priv(indio_dev); struct hid_sensor_hub_device *hsdev = als_state->common_attributes.hsdev; @@ -162,12 +161,12 @@ static int als_read_raw(struct iio_dev *indio_dev, } if (report_id >= 0) { hid_sensor_power_state(&als_state->common_attributes, - true); + true); *val = sensor_hub_input_attr_get_raw_value( hsdev, hsdev->usage, address, report_id, SENSOR_HUB_SYNC, min < 0); hid_sensor_power_state(&als_state->common_attributes, - false); + false); } else { *val = 0; return -EINVAL; @@ -205,10 +204,8 @@ static int als_read_raw(struct iio_dev *indio_dev, /* Channel write_raw handler */ static int als_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct als_state *als_state = iio_priv(indio_dev); int ret = 0; @@ -240,8 +237,7 @@ static const struct iio_info als_info = { /* Callback handler to send event after all samples are received and captured */ static int als_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - void *priv) + u32 usage_id, void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct als_state *als_state = iio_priv(indio_dev); @@ -262,9 +258,9 @@ static int als_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int als_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - size_t raw_len, char *raw_data, - void *priv) + u32 usage_id, + size_t raw_len, char *raw_data, + void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct als_state *als_state = iio_priv(indio_dev); @@ -303,9 +299,9 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev, /* Parse report which is specific to an usage id*/ static int als_parse_report(struct platform_device *pdev, - struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - struct als_state *st) + struct hid_sensor_hub_device *hsdev, + u32 usage_id, + struct als_state *st) { struct iio_chan_spec *channels; int ret, index = 0; @@ -399,31 +395,31 @@ static int hid_als_probe(struct platform_device *pdev) atomic_set(&als_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, - &als_state->common_attributes); + &als_state->common_attributes); if (ret < 0) { dev_err(&pdev->dev, "trigger setup failed\n"); return ret; } - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(&pdev->dev, "device register failed\n"); - goto error_remove_trigger; - } - als_state->callbacks.send_event = als_proc_event; als_state->callbacks.capture_sample = als_capture_sample; als_state->callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, hsdev->usage, &als_state->callbacks); if (ret < 0) { dev_err(&pdev->dev, "callback reg failed\n"); - goto error_iio_unreg; + goto error_remove_trigger; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "device register failed\n"); + goto error_remove_callback; } return ret; -error_iio_unreg: - iio_device_unregister(indio_dev); +error_remove_callback: + sensor_hub_remove_callback(hsdev, hsdev->usage); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes); return ret; @@ -436,8 +432,8 @@ static void hid_als_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct als_state *als_state = iio_priv(indio_dev); - sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); + sensor_hub_remove_callback(hsdev, hsdev->usage); hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes); } diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c index 95bf2bfd86ee..63fd3eff171c 100644 --- a/drivers/iio/light/hid-sensor-prox.c +++ b/drivers/iio/light/hid-sensor-prox.c @@ -69,9 +69,8 @@ static const struct iio_chan_spec prox_channels[] = { /* Channel read_raw handler */ static int prox_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, - long mask) + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct prox_state *prox_state = iio_priv(indio_dev); struct hid_sensor_hub_device *hsdev; @@ -134,10 +133,8 @@ static int prox_read_raw(struct iio_dev *indio_dev, /* Channel write_raw handler */ static int prox_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct prox_state *prox_state = iio_priv(indio_dev); int ret = 0; @@ -165,8 +162,7 @@ static const struct iio_info prox_info = { /* Callback handler to send event after all samples are received and captured */ static int prox_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - void *priv) + u32 usage_id, void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct prox_state *prox_state = iio_priv(indio_dev); @@ -182,9 +178,9 @@ static int prox_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int prox_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - size_t raw_len, char *raw_data, - void *priv) + u32 usage_id, + size_t raw_len, char *raw_data, + void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct prox_state *prox_state = iio_priv(indio_dev); @@ -217,8 +213,8 @@ static int prox_capture_sample(struct hid_sensor_hub_device *hsdev, /* Parse report which is specific to an usage id*/ static int prox_parse_report(struct platform_device *pdev, - struct hid_sensor_hub_device *hsdev, - struct prox_state *st) + struct hid_sensor_hub_device *hsdev, + struct prox_state *st) { struct iio_chan_spec *channels = st->channels; int index = 0; @@ -270,8 +266,7 @@ static int hid_prox_probe(struct platform_device *pdev) struct iio_dev *indio_dev; struct prox_state *prox_state; - indio_dev = devm_iio_device_alloc(&pdev->dev, - sizeof(struct prox_state)); + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct prox_state)); if (!indio_dev) return -ENOMEM; platform_set_drvdata(pdev, indio_dev); @@ -305,18 +300,12 @@ static int hid_prox_probe(struct platform_device *pdev) atomic_set(&prox_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, - &prox_state->common_attributes); + &prox_state->common_attributes); if (ret) { dev_err(&pdev->dev, "trigger setup failed\n"); return ret; } - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(&pdev->dev, "device register failed\n"); - goto error_remove_trigger; - } - prox_state->callbacks.send_event = prox_proc_event; prox_state->callbacks.capture_sample = prox_capture_sample; prox_state->callbacks.pdev = pdev; @@ -324,13 +313,19 @@ static int hid_prox_probe(struct platform_device *pdev) &prox_state->callbacks); if (ret < 0) { dev_err(&pdev->dev, "callback reg failed\n"); - goto error_iio_unreg; + goto error_remove_trigger; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "device register failed\n"); + goto error_remove_callback; } return ret; -error_iio_unreg: - iio_device_unregister(indio_dev); +error_remove_callback: + sensor_hub_remove_callback(hsdev, hsdev->usage); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes); return ret; @@ -343,8 +338,8 @@ static void hid_prox_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct prox_state *prox_state = iio_priv(indio_dev); - sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); + sensor_hub_remove_callback(hsdev, hsdev->usage); hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes); } diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c index c5bd7fa23fb7..a948353014ac 100644 --- a/drivers/iio/light/opt3001.c +++ b/drivers/iio/light/opt3001.c @@ -10,6 +10,7 @@ #include <linux/array_size.h> #include <linux/bits.h> +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/dev_printk.h> #include <linux/errno.h> @@ -100,9 +101,14 @@ struct opt3001_chip_info { struct opt3001 { struct i2c_client *client; - struct device *dev; + /* + * Ensure data capture and read-modify-write sequences are + * not interrupted. + */ struct mutex lock; + + /* Allows for IRQs to bypass locking mechanism */ bool ok_to_ignore_lock; bool result_ready; wait_queue_head_t result_ready_queue; @@ -223,11 +229,10 @@ static const struct opt3001_scale opt3002_scales[] = { }, }; -static int opt3001_find_scale(const struct opt3001 *opt, int val, - int val2, u8 *exponent) +static int opt3001_find_scale(const struct opt3001 *opt, int val, int val2, + u8 *exponent) { - int i; - for (i = 0; i < ARRAY_SIZE(*opt->chip_info->scales); i++) { + for (unsigned int i = 0; i < ARRAY_SIZE(*opt->chip_info->scales); i++) { const struct opt3001_scale *scale = &(*opt->chip_info->scales)[i]; /* * Compare the integer and micro parts to determine value scale. @@ -242,8 +247,8 @@ static int opt3001_find_scale(const struct opt3001 *opt, int val, return -EINVAL; } -static void opt3001_to_iio_ret(struct opt3001 *opt, u8 exponent, - u16 mantissa, int *val, int *val2) +static void opt3001_to_iio_ret(struct opt3001 *opt, u8 exponent, u16 mantissa, + int *val, int *val2) { int ret; int whole = opt->chip_info->factor_whole; @@ -310,123 +315,143 @@ static const struct iio_chan_spec opt3002_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(1), }; -static int opt3001_get_processed(struct opt3001 *opt, int *val, int *val2) +static int opt3001_start_conversion(struct opt3001 *opt) { - int ret; - u16 mantissa; + struct i2c_client *client = opt->client; + struct device *dev = &client->dev; u16 reg; - u8 exponent; - u16 value; - long timeout; - - if (opt->use_irq) { - /* - * Enable the end-of-conversion interrupt mechanism. Note that - * doing so will overwrite the low-level limit value however we - * will restore this value later on. - */ - ret = i2c_smbus_write_word_swapped(opt->client, - OPT3001_LOW_LIMIT, - OPT3001_LOW_LIMIT_EOC_ENABLE); - if (ret < 0) { - dev_err(opt->dev, "failed to write register %02x\n", - OPT3001_LOW_LIMIT); - return ret; - } - - /* Allow IRQ to access the device despite lock being set */ - opt->ok_to_ignore_lock = true; - } + int ret; /* Reset data-ready indicator flag */ opt->result_ready = false; /* Configure for single-conversion mode and start a new conversion */ - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION); if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_CONFIGURATION); - goto err; + dev_err(dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + return ret; } reg = ret; opt3001_set_mode(opt, ®, OPT3001_CONFIGURATION_M_SINGLE); - ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, - reg); + ret = i2c_smbus_write_word_swapped(client, OPT3001_CONFIGURATION, reg); + if (ret) + dev_err(dev, "failed to write register %02x\n", + OPT3001_CONFIGURATION); + + return ret; +} + +static int opt3001_get_processed_irq(struct opt3001 *opt) +{ + struct i2c_client *client = opt->client; + struct device *dev = &client->dev; + u16 value; + int ret; + + /* + * Enable the end-of-conversion interrupt mechanism. Note that doing so + * will overwrite the low-level limit value however we will restore this + * value later on. + */ + ret = i2c_smbus_write_word_swapped(client, + OPT3001_LOW_LIMIT, + OPT3001_LOW_LIMIT_EOC_ENABLE); if (ret < 0) { - dev_err(opt->dev, "failed to write register %02x\n", - OPT3001_CONFIGURATION); - goto err; + dev_err(dev, "failed to write register %02x\n", + OPT3001_LOW_LIMIT); + return ret; } - if (opt->use_irq) { - /* Wait for the IRQ to indicate the conversion is complete */ - ret = wait_event_timeout(opt->result_ready_queue, - opt->result_ready, - msecs_to_jiffies(OPT3001_RESULT_READY_LONG)); - if (ret == 0) { - ret = -ETIMEDOUT; - goto err; - } - } else { - /* Sleep for result ready time */ - timeout = (opt->int_time == OPT3001_INT_TIME_SHORT) ? - OPT3001_RESULT_READY_SHORT : OPT3001_RESULT_READY_LONG; - msleep(timeout); - - /* Check result ready flag */ - ret = i2c_smbus_read_word_swapped(opt->client, - OPT3001_CONFIGURATION); - if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_CONFIGURATION); - goto err; - } + /* Allow IRQ to access the device despite lock being set */ + opt->ok_to_ignore_lock = true; - if (!(ret & OPT3001_CONFIGURATION_CRF)) { - ret = -ETIMEDOUT; - goto err; - } + ret = opt3001_start_conversion(opt); + if (ret) + goto err; - /* Obtain value */ - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_RESULT); - if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_RESULT); - goto err; - } - opt->result = ret; - opt->result_ready = true; - } + if (wait_event_timeout(opt->result_ready_queue, opt->result_ready, + msecs_to_jiffies(OPT3001_RESULT_READY_LONG))) + ret = 0; + else + ret = -ETIMEDOUT; err: - if (opt->use_irq) - /* Disallow IRQ to access the device while lock is active */ - opt->ok_to_ignore_lock = false; + opt->ok_to_ignore_lock = false; if (ret < 0) return ret; - if (opt->use_irq) { - /* - * Disable the end-of-conversion interrupt mechanism by - * restoring the low-level limit value (clearing - * OPT3001_LOW_LIMIT_EOC_ENABLE). Note that selectively clearing - * those enable bits would affect the actual limit value due to - * bit-overlap and therefore can't be done. - */ - value = (opt->low_thresh_exp << 12) | opt->low_thresh_mantissa; - ret = i2c_smbus_write_word_swapped(opt->client, - OPT3001_LOW_LIMIT, - value); - if (ret < 0) { - dev_err(opt->dev, "failed to write register %02x\n", - OPT3001_LOW_LIMIT); - return ret; - } + /* + * Disable the end-of-conversion interrupt mechanism by restoring the + * low-level limit value (clearing OPT3001_LOW_LIMIT_EOC_ENABLE). Note + * that selectively clearing those enable bits would affect the actual + * limit value due to bit-overlap and therefore can't be done. + */ + value = (opt->low_thresh_exp << 12) | opt->low_thresh_mantissa; + ret = i2c_smbus_write_word_swapped(client, OPT3001_LOW_LIMIT, value); + if (ret) + dev_err(dev, "failed to write register %02x\n", + OPT3001_LOW_LIMIT); + + return ret; +} + +static int opt3001_get_processed_noirq(struct opt3001 *opt) +{ + struct i2c_client *client = opt->client; + struct device *dev = &client->dev; + int ret; + + ret = opt3001_start_conversion(opt); + if (ret) + return ret; + + if (opt->int_time == OPT3001_INT_TIME_SHORT) + msleep(OPT3001_RESULT_READY_SHORT); + else + msleep(OPT3001_RESULT_READY_LONG); + + /* Check result ready flag */ + ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION); + if (ret < 0) { + dev_err(dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + return ret; } + if (!(ret & OPT3001_CONFIGURATION_CRF)) + return -ETIMEDOUT; + + /* Obtain value */ + ret = i2c_smbus_read_word_swapped(client, OPT3001_RESULT); + if (ret < 0) { + dev_err(dev, "failed to read register %02x\n", + OPT3001_RESULT); + return ret; + } + + opt->result = ret; + opt->result_ready = true; + + return 0; +} + +static int opt3001_get_processed(struct opt3001 *opt, int *val, int *val2) +{ + u16 mantissa; + u8 exponent; + int ret; + + if (opt->use_irq) + ret = opt3001_get_processed_irq(opt); + else + ret = opt3001_get_processed_noirq(opt); + if (ret) + return ret; + exponent = OPT3001_REG_EXPONENT(opt->result); mantissa = OPT3001_REG_MANTISSA(opt->result); @@ -445,13 +470,15 @@ static int opt3001_get_int_time(struct opt3001 *opt, int *val, int *val2) static int opt3001_set_int_time(struct opt3001 *opt, int time) { + struct i2c_client *client = opt->client; + struct device *dev = &client->dev; int ret; u16 reg; - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION); if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_CONFIGURATION); + dev_err(dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); return ret; } @@ -470,16 +497,14 @@ static int opt3001_set_int_time(struct opt3001 *opt, int time) return -EINVAL; } - return i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, - reg); + return i2c_smbus_write_word_swapped(client, OPT3001_CONFIGURATION, reg); } static int opt3001_read_raw(struct iio_dev *iio, - struct iio_chan_spec const *chan, int *val, int *val2, - long mask) + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct opt3001 *opt = iio_priv(iio); - int ret; if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS) return -EBUSY; @@ -487,31 +512,24 @@ static int opt3001_read_raw(struct iio_dev *iio, if (chan->type != opt->chip_info->chan_type) return -EINVAL; - mutex_lock(&opt->lock); + guard(mutex)(&opt->lock); switch (mask) { case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_PROCESSED: - ret = opt3001_get_processed(opt, val, val2); - break; + return opt3001_get_processed(opt, val, val2); case IIO_CHAN_INFO_INT_TIME: - ret = opt3001_get_int_time(opt, val, val2); - break; + return opt3001_get_int_time(opt, val, val2); default: - ret = -EINVAL; + return -EINVAL; } - - mutex_unlock(&opt->lock); - - return ret; } static int opt3001_write_raw(struct iio_dev *iio, - struct iio_chan_spec const *chan, int val, int val2, - long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct opt3001 *opt = iio_priv(iio); - int ret; if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS) return -EBUSY; @@ -525,47 +543,46 @@ static int opt3001_write_raw(struct iio_dev *iio, if (val != 0) return -EINVAL; - mutex_lock(&opt->lock); - ret = opt3001_set_int_time(opt, val2); - mutex_unlock(&opt->lock); + guard(mutex)(&opt->lock); - return ret; + return opt3001_set_int_time(opt, val2); } static int opt3001_read_event_value(struct iio_dev *iio, - const struct iio_chan_spec *chan, enum iio_event_type type, - enum iio_event_direction dir, enum iio_event_info info, - int *val, int *val2) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) { struct opt3001 *opt = iio_priv(iio); - int ret = IIO_VAL_INT_PLUS_MICRO; - mutex_lock(&opt->lock); + guard(mutex)(&opt->lock); switch (dir) { case IIO_EV_DIR_RISING: opt3001_to_iio_ret(opt, opt->high_thresh_exp, - opt->high_thresh_mantissa, val, val2); - break; + opt->high_thresh_mantissa, val, val2); + return IIO_VAL_INT_PLUS_MICRO; case IIO_EV_DIR_FALLING: opt3001_to_iio_ret(opt, opt->low_thresh_exp, - opt->low_thresh_mantissa, val, val2); - break; + opt->low_thresh_mantissa, val, val2); + return IIO_VAL_INT_PLUS_MICRO; default: - ret = -EINVAL; + return -EINVAL; } - - mutex_unlock(&opt->lock); - - return ret; } static int opt3001_write_event_value(struct iio_dev *iio, - const struct iio_chan_spec *chan, enum iio_event_type type, - enum iio_event_direction dir, enum iio_event_info info, - int val, int val2) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) { struct opt3001 *opt = iio_priv(iio); + struct i2c_client *client = opt->client; + struct device *dev = &client->dev; int ret; int whole; int integer; @@ -580,12 +597,12 @@ static int opt3001_write_event_value(struct iio_dev *iio, if (val < 0) return -EINVAL; - mutex_lock(&opt->lock); + guard(mutex)(&opt->lock); ret = opt3001_find_scale(opt, val, val2, &exponent); if (ret < 0) { - dev_err(opt->dev, "can't find scale for %d.%06u\n", val, val2); - goto err; + dev_err(dev, "can't find scale for %d.%06u\n", val, val2); + return ret; } whole = opt->chip_info->factor_whole; @@ -608,25 +625,22 @@ static int opt3001_write_event_value(struct iio_dev *iio, opt->low_thresh_exp = exponent; break; default: - ret = -EINVAL; - goto err; + return -EINVAL; } - ret = i2c_smbus_write_word_swapped(opt->client, reg, value); + ret = i2c_smbus_write_word_swapped(client, reg, value); if (ret < 0) { - dev_err(opt->dev, "failed to write register %02x\n", reg); - goto err; + dev_err(dev, "failed to write register %02x\n", reg); + return ret; } -err: - mutex_unlock(&opt->lock); - - return ret; + return 0; } static int opt3001_read_event_config(struct iio_dev *iio, - const struct iio_chan_spec *chan, enum iio_event_type type, - enum iio_event_direction dir) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) { struct opt3001 *opt = iio_priv(iio); @@ -634,10 +648,14 @@ static int opt3001_read_event_config(struct iio_dev *iio, } static int opt3001_write_event_config(struct iio_dev *iio, - const struct iio_chan_spec *chan, enum iio_event_type type, - enum iio_event_direction dir, bool state) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + bool state) { struct opt3001 *opt = iio_priv(iio); + struct i2c_client *client = opt->client; + struct device *dev = &client->dev; int ret; u16 mode; u16 reg; @@ -648,33 +666,29 @@ static int opt3001_write_event_config(struct iio_dev *iio, if (!state && opt->mode == OPT3001_CONFIGURATION_M_SHUTDOWN) return 0; - mutex_lock(&opt->lock); + guard(mutex)(&opt->lock); mode = state ? OPT3001_CONFIGURATION_M_CONTINUOUS : OPT3001_CONFIGURATION_M_SHUTDOWN; - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION); if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_CONFIGURATION); - goto err; + dev_err(dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + return ret; } reg = ret; opt3001_set_mode(opt, ®, mode); - ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, - reg); + ret = i2c_smbus_write_word_swapped(client, OPT3001_CONFIGURATION, reg); if (ret < 0) { - dev_err(opt->dev, "failed to write register %02x\n", - OPT3001_CONFIGURATION); - goto err; + dev_err(dev, "failed to write register %02x\n", + OPT3001_CONFIGURATION); + return ret; } -err: - mutex_unlock(&opt->lock); - - return ret; + return 0; } static const struct iio_info opt3001_info = { @@ -689,47 +703,69 @@ static const struct iio_info opt3001_info = { static int opt3001_read_id(struct opt3001 *opt) { + struct i2c_client *client = opt->client; + struct device *dev = &client->dev; char manufacturer[2]; u16 device_id; int ret; - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_MANUFACTURER_ID); - if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_MANUFACTURER_ID); - return ret; - } + ret = i2c_smbus_read_word_swapped(client, OPT3001_MANUFACTURER_ID); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to read register %02x\n", + OPT3001_MANUFACTURER_ID); manufacturer[0] = ret >> 8; manufacturer[1] = ret & 0xff; - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_DEVICE_ID); - if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_DEVICE_ID); - return ret; - } + ret = i2c_smbus_read_word_swapped(client, OPT3001_DEVICE_ID); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to read register %02x\n", + OPT3001_DEVICE_ID); device_id = ret; - dev_info(opt->dev, "Found %c%c OPT%04x\n", manufacturer[0], - manufacturer[1], device_id); + dev_info(dev, "Found %c%c OPT%04x\n", manufacturer[0], manufacturer[1], + device_id); return 0; } -static int opt3001_configure(struct opt3001 *opt) +static void opt3001_power_off(void *data) { + struct opt3001 *opt = data; + struct i2c_client *client = opt->client; + struct device *dev = &client->dev; + u16 reg_val; int ret; - u16 reg; - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION); if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_CONFIGURATION); - return ret; + dev_err(dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + return; } + reg_val = ret; + opt3001_set_mode(opt, ®_val, OPT3001_CONFIGURATION_M_SHUTDOWN); + + ret = i2c_smbus_write_word_swapped(client, OPT3001_CONFIGURATION, reg_val); + if (ret < 0) + dev_err(dev, "failed to write to register %02x\n", + OPT3001_CONFIGURATION); +} + +static int opt3001_configure(struct opt3001 *opt) +{ + struct i2c_client *client = opt->client; + struct device *dev = &client->dev; + int ret; + u16 reg; + + ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + reg = ret; /* Enable automatic full-scale setting mode */ @@ -751,30 +787,28 @@ static int opt3001_configure(struct opt3001 *opt) reg &= ~OPT3001_CONFIGURATION_ME; reg &= ~OPT3001_CONFIGURATION_FC_MASK; - ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, - reg); - if (ret < 0) { - dev_err(opt->dev, "failed to write register %02x\n", - OPT3001_CONFIGURATION); - return ret; - } + ret = i2c_smbus_write_word_swapped(client, OPT3001_CONFIGURATION, reg); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to write register %02x\n", + OPT3001_CONFIGURATION); - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_LOW_LIMIT); - if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_LOW_LIMIT); - return ret; - } + ret = devm_add_action_or_reset(dev, opt3001_power_off, opt); + if (ret) + return dev_err_probe(dev, ret, + "failed to register power off function\n"); + + ret = i2c_smbus_read_word_swapped(client, OPT3001_LOW_LIMIT); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to read register %02x\n", + OPT3001_LOW_LIMIT); opt->low_thresh_mantissa = OPT3001_REG_MANTISSA(ret); opt->low_thresh_exp = OPT3001_REG_EXPONENT(ret); - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_HIGH_LIMIT); - if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_HIGH_LIMIT); - return ret; - } + ret = i2c_smbus_read_word_swapped(client, OPT3001_HIGH_LIMIT); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to read register %02x\n", + OPT3001_HIGH_LIMIT); opt->high_thresh_mantissa = OPT3001_REG_MANTISSA(ret); opt->high_thresh_exp = OPT3001_REG_EXPONENT(ret); @@ -786,6 +820,8 @@ static irqreturn_t opt3001_irq(int irq, void *_iio) { struct iio_dev *iio = _iio; struct opt3001 *opt = iio_priv(iio); + struct i2c_client *client = opt->client; + struct device *dev = &client->dev; int ret; bool wake_result_ready_queue = false; enum iio_chan_type chan_type = opt->chip_info->chan_type; @@ -794,10 +830,10 @@ static irqreturn_t opt3001_irq(int irq, void *_iio) if (!ok_to_ignore_lock) mutex_lock(&opt->lock); - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION); if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_CONFIGURATION); + dev_err(dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); goto out; } @@ -805,21 +841,21 @@ static irqreturn_t opt3001_irq(int irq, void *_iio) OPT3001_CONFIGURATION_M_CONTINUOUS) { if (ret & OPT3001_CONFIGURATION_FH) iio_push_event(iio, - IIO_UNMOD_EVENT_CODE(chan_type, 0, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_RISING), - iio_get_time_ns(iio)); + IIO_UNMOD_EVENT_CODE(chan_type, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + iio_get_time_ns(iio)); if (ret & OPT3001_CONFIGURATION_FL) iio_push_event(iio, - IIO_UNMOD_EVENT_CODE(chan_type, 0, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_FALLING), - iio_get_time_ns(iio)); + IIO_UNMOD_EVENT_CODE(chan_type, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + iio_get_time_ns(iio)); } else if (ret & OPT3001_CONFIGURATION_CRF) { - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_RESULT); + ret = i2c_smbus_read_word_swapped(client, OPT3001_RESULT); if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_RESULT); + dev_err(dev, "failed to read register %02x\n", + OPT3001_RESULT); goto out; } opt->result = ret; @@ -852,12 +888,13 @@ static int opt3001_probe(struct i2c_client *client) opt = iio_priv(iio); opt->client = client; - opt->dev = dev; opt->chip_info = i2c_get_match_data(client); - mutex_init(&opt->lock); + ret = devm_mutex_init(dev, &opt->lock); + if (ret) + return ret; + init_waitqueue_head(&opt->result_ready_queue); - i2c_set_clientdata(client, iio); if (opt->chip_info->has_id) { ret = opt3001_read_id(opt); @@ -875,55 +912,20 @@ static int opt3001_probe(struct i2c_client *client) iio->modes = INDIO_DIRECT_MODE; iio->info = &opt3001_info; - ret = devm_iio_device_register(dev, iio); - if (ret) { - dev_err(dev, "failed to register IIO device\n"); - return ret; - } - /* Make use of INT pin only if valid IRQ no. is given */ if (irq > 0) { - ret = request_threaded_irq(irq, NULL, opt3001_irq, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - "opt3001", iio); - if (ret) { - dev_err(dev, "failed to request IRQ #%d\n", irq); + ret = devm_request_threaded_irq(dev, irq, NULL, opt3001_irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "opt3001", iio); + if (ret) return ret; - } + opt->use_irq = true; } else { - dev_dbg(opt->dev, "enabling interrupt-less operation\n"); - } - - return 0; -} - -static void opt3001_remove(struct i2c_client *client) -{ - struct iio_dev *iio = i2c_get_clientdata(client); - struct opt3001 *opt = iio_priv(iio); - int ret; - u16 reg; - - if (opt->use_irq) - free_irq(client->irq, iio); - - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); - if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_CONFIGURATION); - return; + dev_dbg(dev, "enabling interrupt-less operation\n"); } - reg = ret; - opt3001_set_mode(opt, ®, OPT3001_CONFIGURATION_M_SHUTDOWN); - - ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, - reg); - if (ret < 0) { - dev_err(opt->dev, "failed to write register %02x\n", - OPT3001_CONFIGURATION); - } + return devm_iio_device_register(dev, iio); } static const struct opt3001_chip_info opt3001_chip_information = { @@ -964,7 +966,6 @@ MODULE_DEVICE_TABLE(of, opt3001_of_match); static struct i2c_driver opt3001_driver = { .probe = opt3001_probe, - .remove = opt3001_remove, .id_table = opt3001_id, .driver = { diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index f961973892f2..e0914f699dfd 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -1071,7 +1071,10 @@ static int rpr0521_runtime_resume(struct device *dev) struct rpr0521_data *data = iio_priv(indio_dev); int ret; - regcache_sync(data->regmap); + ret = regcache_sync(data->regmap); + if (ret < 0) + return ret; + if (data->als_ps_need_en) { ret = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE); if (ret < 0) diff --git a/drivers/iio/light/st_uvis25_spi.c b/drivers/iio/light/st_uvis25_spi.c index c4c15093e9e5..0f78a0abfafb 100644 --- a/drivers/iio/light/st_uvis25_spi.c +++ b/drivers/iio/light/st_uvis25_spi.c @@ -46,7 +46,7 @@ static const struct of_device_id st_uvis25_spi_of_match[] = { MODULE_DEVICE_TABLE(of, st_uvis25_spi_of_match); static const struct spi_device_id st_uvis25_spi_id_table[] = { - { ST_UVIS25_DEV_NAME }, + { .name = ST_UVIS25_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(spi, st_uvis25_spi_id_table); diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index b61442c5c1be..b392943e51c8 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -9,8 +9,6 @@ * TCS34727) * * Datasheet: http://ams.com/eng/content/download/319364/1117183/file/TCS3472_Datasheet_EN_v2.pdf - * - * TODO: wait time */ #include <linux/cleanup.h> @@ -19,6 +17,7 @@ #include <linux/module.h> #include <linux/mutex.h> #include <linux/pm.h> +#include <linux/units.h> #include <linux/iio/buffer.h> #include <linux/iio/events.h> @@ -53,19 +52,30 @@ #define TCS3472_STATUS_AINT BIT(4) #define TCS3472_STATUS_AVALID BIT(0) #define TCS3472_ENABLE_AIEN BIT(4) +#define TCS3472_ENABLE_WEN BIT(3) #define TCS3472_ENABLE_AEN BIT(1) #define TCS3472_ENABLE_PON BIT(0) +#define TCS3472_ENABLE_RUN \ + (TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON | TCS3472_ENABLE_WEN) #define TCS3472_CONTROL_AGAIN_MASK (BIT(0) | BIT(1)) +#define TCS3472_CONFIG_WLONG BIT(1) + +#define TCS3472_ATIME_TO_US(atime) (((256) - (atime)) * 2400) struct tcs3472_data { struct i2c_client *client; struct mutex lock; + int target_freq_hz; + int target_freq_uhz; u16 low_thresh; u16 high_thresh; u8 enable; + u8 enable_pre_suspend; u8 control; u8 atime; u8 apers; + u8 wtime; + bool wlong; }; static const struct iio_event_spec tcs3472_events[] = { @@ -91,6 +101,7 @@ static const struct iio_event_spec tcs3472_events[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBSCALE) | \ BIT(IIO_CHAN_INFO_INT_TIME), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .channel2 = IIO_MOD_LIGHT_##_color, \ .address = _addr, \ .scan_index = _si, \ @@ -114,9 +125,65 @@ static const struct iio_chan_spec tcs3472_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(4), }; +/* + * The chip's cycle time is the sum of three components: + * - ATIME: the programmable RGBC integration time. + * - The fixed RGBC initialization time (2400 us). + * - WTIME: the wait time, used only if WEN is set. If WLONG is active, + * the wait step is multiplied by 12 (2400 us -> 28800 us). + */ +static unsigned int tcs3472_cycle_time_us(struct tcs3472_data *data) +{ + unsigned int atime_us = TCS3472_ATIME_TO_US(data->atime); + unsigned int init_us = 2400; + unsigned int wtime_us; + + if (!(data->enable & TCS3472_ENABLE_WEN)) + wtime_us = 0; + else if (data->wlong) + wtime_us = (256 - data->wtime) * 28800; + else + wtime_us = (256 - data->wtime) * 2400; + + return atime_us + init_us + wtime_us; +} + +/* + * Convert a cycle time in microseconds to a frequency in Hz and microhertz. + * + * Given cycle_us = T (the cycle period in microseconds), the corresponding + * frequency is: + * f = 1e6 / T [Hz] + * + * The result is split into the IIO_VAL_INT_PLUS_MICRO format: + * val = floor(1e6 / T) [Hz] + * val2 = (1e6 mod T) * 1e6 / T [microhertz] + */ +static void tcs3472_cycle_to_freq(unsigned int cycle_us, int *val, int *val2) +{ + *val = USEC_PER_SEC / cycle_us; + *val2 = div_u64((u64)(USEC_PER_SEC % cycle_us) * USEC_PER_SEC, + cycle_us); +} + static int tcs3472_req_data(struct tcs3472_data *data) { - int tries = 50; + /* + * The worst-case cycle time is reached with ATIME=0x00, WTIME=0x00 + * and WLONG=1. So: + * 614 ms (Max Integration Time) + * + 2.4 ms (RGBC Init) + * + 7.37 s (Max Wait Time) + * = ~ 8 s (Total Max cycle time). + * Use that as a polling upper bound; in normal operation the loop + * exits as soon as AVALID is set. So the total number of tries in 8 + * seconds considering a polling period of 20 ms is 400. + * Considering a 20% margin due to oscillator tolerance, the total + * duration becomes approximately 9.8 seconds, which corresponds to + * about 480 steps. Therefore, setting it to 500 appears to be a + * reasonable and safe trade-off. + */ + int tries = 500; int ret; while (tries--) { @@ -164,18 +231,165 @@ static int tcs3472_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_INT_TIME: *val = 0; - *val2 = (256 - data->atime) * 2400; + *val2 = TCS3472_ATIME_TO_US(data->atime); return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: { + unsigned int cycle_us; + + guard(mutex)(&data->lock); + cycle_us = tcs3472_cycle_time_us(data); + tcs3472_cycle_to_freq(cycle_us, val, val2); + return IIO_VAL_INT_PLUS_MICRO; + } default: return -EINVAL; } } +/* + * __tcs3472_set_sampling_freq() - implementation of sampling frequency + * configuration. The caller must hold data->lock. + */ +static int __tcs3472_set_sampling_freq(struct tcs3472_data *data, + int val, int val2) +{ + unsigned int atime_us; + unsigned int init_us = 2400; + u64 cycle_us; + s64 wait_us; + int wtime; + bool wlong = false; + u8 config; + int ret; + + if (val < 0 || val2 < 0 || (val == 0 && val2 == 0)) + return -EINVAL; + + atime_us = TCS3472_ATIME_TO_US(data->atime); + + /* + * cycle_us = 1 / freq, expressed in microseconds. + * Numerator: 1 [s] = PSEC_PER_SEC [ps] + * Denominator: freq [Hz] * MICROHZ_PER_HZ + val2 [uHz] = freq in [uHz] + * Result: ps / uHz = us + */ + cycle_us = div64_u64(PSEC_PER_SEC, (u64)val * MICROHZ_PER_HZ + val2); + + /* + * wait_us can be negative when the requested frequency is too high + * to be reached, or very large when the requested frequency is + * close to zero. Use s64 to cover the full range: + * + * cycle_us = PSEC_PER_SEC / (val * MICROHZ_PER_HZ + val2) + * + * The divisor of the formula above reaches its maximum when + * val = val2 = INT_MAX: + * INT_MAX * MICROHZ_PER_HZ + INT_MAX = ~2.15e18 + * so cycle_us_min = floor(1e12 / 2.15e18) = 0. + * + * The divisor reaches its minimum (1) when val = 0 and val2 = 1, + * so cycle_us_max = 1e12 / 1 = 1e12. + * + * Therefore: + * wait_us_min = 0 - 2400 - 612000 = -616800 + * wait_us_max = 1e12 - 2400 - 2400 = 999999995200 + * + * Both fit comfortably in s64. + */ + wait_us = (s64)cycle_us - init_us - atime_us; + if (wait_us < 2400) { + if (data->enable & TCS3472_ENABLE_WEN) { + u8 enable = data->enable & ~TCS3472_ENABLE_WEN; + + ret = i2c_smbus_write_byte_data(data->client, + TCS3472_ENABLE, enable); + if (ret) + return ret; + + data->enable = enable; + } + + data->target_freq_hz = val; + data->target_freq_uhz = val2; + return 0; + } + + /* + * Wait state is needed: make sure WEN is active before programming + * WTIME (and possibly WLONG). + */ + if (!(data->enable & TCS3472_ENABLE_WEN)) { + u8 enable = data->enable | TCS3472_ENABLE_WEN; + + ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, + enable); + if (ret) + return ret; + + data->enable = enable; + } + + wtime = 256 - DIV_ROUND_CLOSEST_ULL(wait_us, 2400); + if (wtime < 0) { + /* + * If wait_us is too high (so the requested frequency is too + * low), the resulting wait exceeds what WTIME can represent + * (max 614 ms without WLONG). Enable WLONG, whose step is 12x + * longer (28.8 ms instead of 2.4 ms), and recompute. + */ + wlong = true; + wtime = 256 - DIV_ROUND_CLOSEST_ULL(wait_us, 28800); + } + + if (wlong != data->wlong) { + ret = i2c_smbus_read_byte_data(data->client, TCS3472_CONFIG); + if (ret < 0) + return ret; + + config = ret; + if (wlong) + config |= TCS3472_CONFIG_WLONG; + else + config &= ~TCS3472_CONFIG_WLONG; + + ret = i2c_smbus_write_byte_data(data->client, TCS3472_CONFIG, + config); + if (ret) + return ret; + + data->wlong = wlong; + } + + /* + * If the requested wait is so long that even WLONG cannot + * cover it, wtime may still be negative. Saturate to 0, + * which is the largest possible wait (256 * 28.8 ms = 7.37 s). + */ + wtime = clamp(wtime, 0, 255); + ret = i2c_smbus_write_byte_data(data->client, TCS3472_WTIME, wtime); + if (ret) + return ret; + + data->wtime = wtime; + data->target_freq_hz = val; + data->target_freq_uhz = val2; + + return 0; +} + +static int tcs3472_set_sampling_freq(struct tcs3472_data *data, + int val, int val2) +{ + guard(mutex)(&data->lock); + return __tcs3472_set_sampling_freq(data, val, val2); +} + static int tcs3472_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { struct tcs3472_data *data = iio_priv(indio_dev); + int ret; int i; switch (mask) { @@ -196,15 +410,31 @@ static int tcs3472_write_raw(struct iio_dev *indio_dev, if (val != 0) return -EINVAL; for (i = 0; i < 256; i++) { - if (val2 == (256 - i) * 2400) { - data->atime = i; - return i2c_smbus_write_byte_data( - data->client, TCS3472_ATIME, - data->atime); - } - + if (val2 != (256 - i) * 2400) + continue; + + guard(mutex)(&data->lock); + + ret = i2c_smbus_write_byte_data(data->client, + TCS3472_ATIME, i); + if (ret) + return ret; + + data->atime = i; + + /* + * ATIME just changed, so the cycle time changed too. + * Re-run the sampling frequency logic to recompute + * WTIME and preserve the user's last requested + * frequency. Lock is already held. + */ + return __tcs3472_set_sampling_freq(data, + data->target_freq_hz, + data->target_freq_uhz); } return -EINVAL; + case IIO_CHAN_INFO_SAMP_FREQ: + return tcs3472_set_sampling_freq(data, val, val2); default: return -EINVAL; } @@ -234,7 +464,7 @@ static int tcs3472_read_event(struct iio_dev *indio_dev, data->high_thresh : data->low_thresh; return IIO_VAL_INT; case IIO_EV_INFO_PERIOD: - period = (256 - data->atime) * 2400 * + period = tcs3472_cycle_time_us(data) * tcs3472_intr_pers[data->apers]; *val = period / USEC_PER_SEC; *val2 = period % USEC_PER_SEC; @@ -279,11 +509,13 @@ static int tcs3472_write_event(struct iio_dev *indio_dev, data->low_thresh = val; return 0; - case IIO_EV_INFO_PERIOD: + case IIO_EV_INFO_PERIOD:{ + unsigned int cycle_us; + period = val * USEC_PER_SEC + val2; + cycle_us = tcs3472_cycle_time_us(data); for (i = 1; i < ARRAY_SIZE(tcs3472_intr_pers) - 1; i++) { - if (period <= (256 - data->atime) * 2400 * - tcs3472_intr_pers[i]) + if (period <= cycle_us * tcs3472_intr_pers[i]) break; } ret = i2c_smbus_write_byte_data(data->client, TCS3472_PERS, i); @@ -293,6 +525,7 @@ static int tcs3472_write_event(struct iio_dev *indio_dev, data->apers = i; return 0; + } default: return -EINVAL; } @@ -434,17 +667,16 @@ static const struct iio_info tcs3472_info = { static int tcs3472_powerdown(struct tcs3472_data *data) { int ret; - u8 enable_mask = TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON; guard(mutex)(&data->lock); + data->enable_pre_suspend = data->enable; + ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, - data->enable & ~enable_mask); + data->enable & ~TCS3472_ENABLE_RUN); if (ret) return ret; - data->enable &= ~enable_mask; - return 0; } @@ -458,7 +690,9 @@ static int tcs3472_probe(struct i2c_client *client) struct device *dev = &client->dev; struct tcs3472_data *data; struct iio_dev *indio_dev; + unsigned int cycle_us; int ret; + u8 enable; indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) @@ -498,6 +732,16 @@ static int tcs3472_probe(struct i2c_client *client) return ret; data->atime = ret; + ret = i2c_smbus_read_byte_data(data->client, TCS3472_WTIME); + if (ret < 0) + return ret; + data->wtime = ret; + + ret = i2c_smbus_read_byte_data(data->client, TCS3472_CONFIG); + if (ret < 0) + return ret; + data->wlong = (ret & TCS3472_CONFIG_WLONG) ? 1 : 0; + ret = i2c_smbus_read_word_data(data->client, TCS3472_AILT); if (ret < 0) return ret; @@ -518,14 +762,30 @@ static int tcs3472_probe(struct i2c_client *client) if (ret < 0) return ret; - /* enable device */ - data->enable = ret | TCS3472_ENABLE_PON | TCS3472_ENABLE_AEN; - data->enable &= ~TCS3472_ENABLE_AIEN; - ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, - data->enable); + /* + * Enable the chip in its full running state, including WEN. The + * actual wait time is controlled by the WTIME and WLONG registers, + * which retain their power-on defaults until userspace writes to + * sampling_frequency. + */ + enable = (ret | TCS3472_ENABLE_RUN) & ~TCS3472_ENABLE_AIEN; + + ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, enable); if (ret < 0) return ret; + data->enable = enable; + + /* + * Initialize target frequency from the chip's current state so that + * subsequent integration_time changes via IIO_CHAN_INFO_INT_TIME can + * preserve a meaningful sampling rate, even before userspace writes + * sampling_frequency for the first time. + */ + cycle_us = tcs3472_cycle_time_us(data); + tcs3472_cycle_to_freq(cycle_us, &data->target_freq_hz, + &data->target_freq_uhz); + ret = devm_add_action_or_reset(dev, tcs3472_powerdown_action, data); if (ret) return ret; @@ -561,16 +821,21 @@ static int tcs3472_resume(struct device *dev) struct tcs3472_data *data = iio_priv(i2c_get_clientdata( to_i2c_client(dev))); int ret; - u8 enable_mask = TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON; guard(mutex)(&data->lock); + /* + * Restore the full ENABLE register from the snapshot taken in + * tcs3472_powerdown(). This preserves the user's last + * sampling_frequency configuration (in particular the WEN bit) + * across suspend/resume. + */ ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, - data->enable | enable_mask); + data->enable_pre_suspend); if (ret) return ret; - data->enable |= enable_mask; + data->enable = data->enable_pre_suspend; return 0; } diff --git a/drivers/iio/light/tsl2583.c b/drivers/iio/light/tsl2583.c index a0dd122af2cf..a210d87a1519 100644 --- a/drivers/iio/light/tsl2583.c +++ b/drivers/iio/light/tsl2583.c @@ -475,7 +475,7 @@ static ssize_t in_illuminance_input_target_show(struct device *dev, int ret; mutex_lock(&chip->als_mutex); - ret = sprintf(buf, "%d\n", chip->als_settings.als_cal_target); + ret = sysfs_emit(buf, "%d\n", chip->als_settings.als_cal_target); mutex_unlock(&chip->als_mutex); return ret; @@ -533,10 +533,10 @@ static ssize_t in_illuminance_lux_table_show(struct device *dev, int offset = 0; for (i = 0; i < ARRAY_SIZE(chip->als_settings.als_device_lux); i++) { - offset += sprintf(buf + offset, "%u,%u,%u,", - chip->als_settings.als_device_lux[i].ratio, - chip->als_settings.als_device_lux[i].ch0, - chip->als_settings.als_device_lux[i].ch1); + offset += sysfs_emit_at(buf, offset, "%u,%u,%u,", + chip->als_settings.als_device_lux[i].ratio, + chip->als_settings.als_device_lux[i].ch0, + chip->als_settings.als_device_lux[i].ch1); if (chip->als_settings.als_device_lux[i].ratio == 0) { /* * We just printed the first "0" entry. @@ -547,7 +547,7 @@ static ssize_t in_illuminance_lux_table_show(struct device *dev, } } - offset += sprintf(buf + offset, "\n"); + offset += sysfs_emit_at(buf, offset, "\n"); return offset; } diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index 128ae3f94074..b8ac156ad5c9 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -1922,7 +1922,7 @@ static void vcnl4000_cleanup(void *data) static int vcnl4000_probe(struct i2c_client *client) { - const char * const regulator_names[] = { "vdd", "vio", "vled" }; + static const char * const regulator_names[] = { "vdd", "vio", "vled" }; struct device *dev = &client->dev; struct vcnl4000_data *data; struct iio_dev *indio_dev; diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c index bf3a49b4351d..d13c5ff33e07 100644 --- a/drivers/iio/light/vcnl4035.c +++ b/drivers/iio/light/vcnl4035.c @@ -647,7 +647,10 @@ static int vcnl4035_runtime_resume(struct device *dev) struct vcnl4035_data *data = iio_priv(indio_dev); int ret; - regcache_sync(data->regmap); + ret = regcache_sync(data->regmap); + if (ret < 0) + return ret; + ret = vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_ENABLE); if (ret < 0) return ret; diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index ea2697fb5ab6..d359003b248e 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig @@ -209,6 +209,28 @@ config INFINEON_TLV493D To compile this driver as a module, choose M here: the module will be called tlv493d. +config QMC5883L + tristate "QST QMC5883L 3-Axis Magnetic Sensor" + depends on I2C + select REGMAP_I2C + help + Say Y here to add support driver for QST QMC5883L 3-Axis + Magnetic Sensor. + + To compile this driver as a module, choose M here: the + module will be called qmc5883l. + +config QMC6308 + tristate "QST QMC6308 3-Axis Magnetic Sensor" + depends on I2C + select REGMAP_I2C + help + Say Y here to add support for the QST QMC6308 3-Axis + Magnetic Sensor. + + To compile this driver as a module, choose M here: the + module will be called qmc6308. + config SENSORS_HMC5843 tristate select IIO_BUFFER diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile index 7fd9b3fd914e..8f2205975c1b 100644 --- a/drivers/iio/magnetometer/Makefile +++ b/drivers/iio/magnetometer/Makefile @@ -27,6 +27,9 @@ obj-$(CONFIG_IIO_ST_MAGN_SPI_3AXIS) += st_magn_spi.o obj-$(CONFIG_INFINEON_TLV493D) += tlv493d.o +obj-$(CONFIG_QMC5883L) += qmc5883l.o +obj-$(CONFIG_QMC6308) += qmc6308.o + obj-$(CONFIG_SENSORS_HMC5843) += hmc5843_core.o obj-$(CONFIG_SENSORS_HMC5843_I2C) += hmc5843_i2c.o obj-$(CONFIG_SENSORS_HMC5843_SPI) += hmc5843_spi.o diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index bf2551988008..32dff9cdd0f7 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -9,23 +9,25 @@ * (C) Copyright 2011~2014 Bosch Sensortec GmbH All Rights Reserved */ -#include <linux/module.h> -#include <linux/i2c.h> -#include <linux/interrupt.h> +#include <linux/bitfield.h> #include <linux/cleanup.h> #include <linux/delay.h> -#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/module.h> #include <linux/pm.h> #include <linux/pm_runtime.h> -#include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> + #include <linux/iio/buffer.h> #include <linux/iio/events.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> #include <linux/iio/trigger.h> #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> -#include <linux/regmap.h> -#include <linux/regulator/consumer.h> #include "bmc150_magn.h" @@ -245,14 +247,14 @@ static int bmc150_magn_set_power_mode(struct bmc150_magn_data *data, return regmap_update_bits(data->regmap, BMC150_MAGN_REG_OPMODE_ODR, BMC150_MAGN_MASK_OPMODE, - BMC150_MAGN_MODE_SLEEP << - BMC150_MAGN_SHIFT_OPMODE); + FIELD_PREP(BMC150_MAGN_MASK_OPMODE, + BMC150_MAGN_MODE_SLEEP)); case BMC150_MAGN_POWER_MODE_NORMAL: return regmap_update_bits(data->regmap, BMC150_MAGN_REG_OPMODE_ODR, BMC150_MAGN_MASK_OPMODE, - BMC150_MAGN_MODE_NORMAL << - BMC150_MAGN_SHIFT_OPMODE); + FIELD_PREP(BMC150_MAGN_MASK_OPMODE, + BMC150_MAGN_MODE_NORMAL)); } return -EINVAL; @@ -290,7 +292,7 @@ static int bmc150_magn_get_odr(struct bmc150_magn_data *data, int *val) ret = regmap_read(data->regmap, BMC150_MAGN_REG_OPMODE_ODR, ®_val); if (ret < 0) return ret; - odr_val = (reg_val & BMC150_MAGN_MASK_ODR) >> BMC150_MAGN_SHIFT_ODR; + odr_val = FIELD_GET(BMC150_MAGN_MASK_ODR, reg_val); for (i = 0; i < ARRAY_SIZE(bmc150_magn_samp_freq_table); i++) if (bmc150_magn_samp_freq_table[i].reg_val == odr_val) { @@ -303,21 +305,17 @@ static int bmc150_magn_get_odr(struct bmc150_magn_data *data, int *val) static int bmc150_magn_set_odr(struct bmc150_magn_data *data, int val) { - int ret; u8 i; for (i = 0; i < ARRAY_SIZE(bmc150_magn_samp_freq_table); i++) { - if (bmc150_magn_samp_freq_table[i].freq == val) { - ret = regmap_update_bits(data->regmap, - BMC150_MAGN_REG_OPMODE_ODR, - BMC150_MAGN_MASK_ODR, - bmc150_magn_samp_freq_table[i]. - reg_val << - BMC150_MAGN_SHIFT_ODR); - if (ret < 0) - return ret; - return 0; - } + if (bmc150_magn_samp_freq_table[i].freq != val) + continue; + + return regmap_update_bits(data->regmap, + BMC150_MAGN_REG_OPMODE_ODR, + BMC150_MAGN_MASK_ODR, + FIELD_PREP(BMC150_MAGN_MASK_ODR, + bmc150_magn_samp_freq_table[i].reg_val)); } return -EINVAL; @@ -800,7 +798,7 @@ static int bmc150_magn_data_rdy_trigger_set_state(struct iio_trigger *trig, ret = regmap_update_bits(data->regmap, BMC150_MAGN_REG_INT_DRDY, BMC150_MAGN_MASK_DRDY_EN, - state << BMC150_MAGN_SHIFT_DRDY_EN); + FIELD_PREP(BMC150_MAGN_MASK_DRDY_EN, state)); if (ret < 0) return ret; diff --git a/drivers/iio/magnetometer/bmc150_magn_spi.c b/drivers/iio/magnetometer/bmc150_magn_spi.c index 8af8d3528c43..27ab845fb257 100644 --- a/drivers/iio/magnetometer/bmc150_magn_spi.c +++ b/drivers/iio/magnetometer/bmc150_magn_spi.c @@ -33,9 +33,9 @@ static void bmc150_magn_spi_remove(struct spi_device *spi) } static const struct spi_device_id bmc150_magn_spi_id[] = { - {"bmc150_magn", 0}, - {"bmc156_magn", 0}, - {"bmm150_magn", 0}, + { .name = "bmc150_magn" }, + { .name = "bmc156_magn" }, + { .name = "bmm150_magn" }, { } }; MODULE_DEVICE_TABLE(spi, bmc150_magn_spi_id); diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index d8b8bcc865c3..ad18f233ee16 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -134,9 +134,8 @@ static const struct iio_chan_spec magn_3d_channels[] = { /* Channel read_raw handler */ static int magn_3d_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, - long mask) + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct magn_3d_state *magn_state = iio_priv(indio_dev); int report_id = -1; @@ -166,8 +165,7 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev, false); return -EINVAL; } - hid_sensor_power_state(&magn_state->magn_flux_attributes, - false); + hid_sensor_power_state(&magn_state->magn_flux_attributes, false); ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SCALE: @@ -228,10 +226,8 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev, /* Channel write_raw handler */ static int magn_3d_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct magn_3d_state *magn_state = iio_priv(indio_dev); int ret = 0; @@ -269,8 +265,7 @@ static const struct iio_info magn_3d_info = { /* Callback handler to send event after all samples are received and captured */ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev, - u32 usage_id, - void *priv) + u32 usage_id, void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct magn_3d_state *magn_state = iio_priv(indio_dev); @@ -291,9 +286,9 @@ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev, - u32 usage_id, - size_t raw_len, char *raw_data, - void *priv) + u32 usage_id, + size_t raw_len, char *raw_data, + void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct magn_3d_state *magn_state = iio_priv(indio_dev); @@ -326,7 +321,7 @@ static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev, iio_val = magn_state->magn_val_addr[offset]; - if (iio_val != NULL) + if (iio_val) *iio_val = *((u32 *)raw_data); else ret = -EINVAL; @@ -367,18 +362,17 @@ static int magn_3d_parse_report(struct platform_device *pdev, return -EINVAL; } - dev_dbg(&pdev->dev, "magn_3d Found %d usage attributes\n", - attr_count); + dev_dbg(&pdev->dev, "magn_3d Found %d usage attributes\n", attr_count); dev_dbg(&pdev->dev, "magn_3d X: %x:%x Y: %x:%x Z: %x:%x\n", - st->magn[0].index, - st->magn[0].report_id, - st->magn[1].index, st->magn[1].report_id, - st->magn[2].index, st->magn[2].report_id); + st->magn[0].index, + st->magn[0].report_id, + st->magn[1].index, st->magn[1].report_id, + st->magn[2].index, st->magn[2].report_id); /* Setup IIO channel array */ _channels = devm_kcalloc(&pdev->dev, attr_count, - sizeof(struct iio_chan_spec), - GFP_KERNEL); + sizeof(struct iio_chan_spec), + GFP_KERNEL); if (!_channels) { dev_err(&pdev->dev, "failed to allocate space for iio channels\n"); @@ -425,8 +419,7 @@ static int magn_3d_parse_report(struct platform_device *pdev, *channels = _channels; - dev_dbg(&pdev->dev, "magn_3d Setup %d IIO channels\n", - *chan_count); + dev_dbg(&pdev->dev, "magn_3d Setup %d IIO channels\n", *chan_count); st->magn_flux_attr.scale_precision = hid_sensor_format_scale( HID_USAGE_SENSOR_COMPASS_3D, @@ -467,7 +460,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev) indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct magn_3d_state)); - if (indio_dev == NULL) + if (!indio_dev) return -ENOMEM; platform_set_drvdata(pdev, indio_dev); @@ -490,8 +483,8 @@ static int hid_magn_3d_probe(struct platform_device *pdev) magn_state->rot_attributes.sensitivity.index = -1; ret = magn_3d_parse_report(pdev, hsdev, - &channels, &chan_count, - HID_USAGE_SENSOR_COMPASS_3D, magn_state); + &channels, &chan_count, + HID_USAGE_SENSOR_COMPASS_3D, magn_state); if (ret) { dev_err(&pdev->dev, "failed to parse report\n"); return ret; @@ -506,32 +499,32 @@ static int hid_magn_3d_probe(struct platform_device *pdev) atomic_set(&magn_state->magn_flux_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, - &magn_state->magn_flux_attributes); + &magn_state->magn_flux_attributes); if (ret < 0) { dev_err(&pdev->dev, "trigger setup failed\n"); return ret; } - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(&pdev->dev, "device register failed\n"); - goto error_remove_trigger; - } - magn_state->callbacks.send_event = magn_3d_proc_event; magn_state->callbacks.capture_sample = magn_3d_capture_sample; magn_state->callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D, - &magn_state->callbacks); + &magn_state->callbacks); if (ret < 0) { dev_err(&pdev->dev, "callback reg failed\n"); - goto error_iio_unreg; + goto error_remove_trigger; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "device register failed\n"); + goto error_remove_callback; } return ret; -error_iio_unreg: - iio_device_unregister(indio_dev); +error_remove_callback: + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &magn_state->magn_flux_attributes); return ret; @@ -544,8 +537,8 @@ static void hid_magn_3d_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct magn_3d_state *magn_state = iio_priv(indio_dev); - sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D); iio_device_unregister(indio_dev); + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D); hid_sensor_remove_trigger(indio_dev, &magn_state->magn_flux_attributes); } diff --git a/drivers/iio/magnetometer/hmc5843_spi.c b/drivers/iio/magnetometer/hmc5843_spi.c index 6a55c1559b0d..29dee5dce2ae 100644 --- a/drivers/iio/magnetometer/hmc5843_spi.c +++ b/drivers/iio/magnetometer/hmc5843_spi.c @@ -56,7 +56,6 @@ static int hmc5843_spi_probe(struct spi_device *spi) { int ret; struct regmap *regmap; - const struct spi_device_id *id = spi_get_device_id(spi); spi->mode = SPI_MODE_3; spi->max_speed_hz = 8000000; @@ -69,8 +68,7 @@ static int hmc5843_spi_probe(struct spi_device *spi) return PTR_ERR(regmap); return hmc5843_common_probe(&spi->dev, - regmap, - id->driver_data, id->name); + regmap, HMC5983_ID, "hmc5983"); } static void hmc5843_spi_remove(struct spi_device *spi) @@ -79,7 +77,7 @@ static void hmc5843_spi_remove(struct spi_device *spi) } static const struct spi_device_id hmc5843_id[] = { - { "hmc5983", HMC5983_ID }, + { .name = "hmc5983" }, { } }; MODULE_DEVICE_TABLE(spi, hmc5843_id); diff --git a/drivers/iio/magnetometer/mmc5983.c b/drivers/iio/magnetometer/mmc5983.c index 03f46e8c1611..d10a6288e147 100644 --- a/drivers/iio/magnetometer/mmc5983.c +++ b/drivers/iio/magnetometer/mmc5983.c @@ -327,7 +327,7 @@ static const struct of_device_id mmc5983_of_match[] = { MODULE_DEVICE_TABLE(of, mmc5983_of_match); static const struct i2c_device_id mmc5983_id[] = { - { "mmc5983" }, + { .name = "mmc5983" }, { } }; MODULE_DEVICE_TABLE(i2c, mmc5983_id); diff --git a/drivers/iio/magnetometer/qmc5883l.c b/drivers/iio/magnetometer/qmc5883l.c new file mode 100644 index 000000000000..c3469715dc63 --- /dev/null +++ b/drivers/iio/magnetometer/qmc5883l.c @@ -0,0 +1,516 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * Support for QST QMC5883L 3-Axis Magnetic Sensor on I2C bus. + * + * Copyright (C) 2026 Siratul Islam <siratul.islam@linux.dev> + * + * Datasheet available at + * <https://www.qstcorp.com/upload/pdf/202512/13-52-04%20QMC5883L%20Datasheet%20Rev.%20B.pdf> + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/time.h> +#include <linux/types.h> + +#include <asm/byteorder.h> + +#include <linux/iio/iio.h> + +#define QMC5883L_REG_X_LSB 0x00 +#define QMC5883L_REG_STATUS1 0x06 +#define QMC5883L_REG_CTRL1 0x09 +#define QMC5883L_REG_CTRL2 0x0A +#define QMC5883L_REG_SET_RESET 0x0B +#define QMC5883L_REG_ID 0x0D + +#define QMC5883L_CHIP_ID 0xFF + +#define QMC5883L_MODE_MASK GENMASK(1, 0) +#define QMC5883L_ODR_MASK GENMASK(3, 2) +#define QMC5883L_RNG_MASK GENMASK(5, 4) +#define QMC5883L_OSR_MASK GENMASK(7, 6) + +#define QMC5883L_MODE_STANDBY 0x00 +#define QMC5883L_MODE_CONT 0x01 + +#define QMC5883L_ODR_10HZ 0x00 +#define QMC5883L_ODR_50HZ 0x01 +#define QMC5883L_ODR_100HZ 0x02 +#define QMC5883L_ODR_200HZ 0x03 + +#define QMC5883L_RNG_2G 0x00 +#define QMC5883L_RNG_8G 0x01 + +#define QMC5883L_OSR_512 0x00 +#define QMC5883L_OSR_256 0x01 +#define QMC5883L_OSR_128 0x02 +#define QMC5883L_OSR_64 0x03 + +#define QMC5883L_STATUS_DRDY BIT(0) +#define QMC5883L_STATUS_OVL BIT(1) + +#define QMC5883L_SET_RESET_VAL BIT(0) +#define QMC5883L_INT_DISABLE BIT(0) +#define QMC5883L_SOFT_RESET BIT(7) + +#define QMC5883L_PORT_US 350 + +struct qmc5883l_data { + struct regmap *regmap; + /* + * Protect data->range/odr/osr. + * Protect poll and read during measurement. + */ + struct mutex mutex; + u8 range; + u8 odr; + u8 osr; +}; + +enum qmc5883l_chan { + QMC5883L_AXIS_X, + QMC5883L_AXIS_Y, + QMC5883L_AXIS_Z, +}; + +static const int qmc5883l_odr_avail[] = { 10, 50, 100, 200 }; + +static const int qmc5883l_osr_avail[] = { 512, 256, 128, 64 }; + +static const int qmc5883l_scales[][2] = { + [QMC5883L_RNG_2G] = { 0, 83333 }, + [QMC5883L_RNG_8G] = { 0, 333333 }, +}; + +static int qmc5883l_take_measurement(struct iio_dev *indio_dev, int index, + int *val) +{ + struct qmc5883l_data *data = iio_priv(indio_dev); + struct regmap *map = data->regmap; + unsigned int status; + __le16 buf[3]; + int ret; + + guard(mutex) (&data->mutex); + + /* 50ms headroom over the slowest ODR (10Hz) */ + ret = regmap_read_poll_timeout(map, QMC5883L_REG_STATUS1, + status, (status & QMC5883L_STATUS_DRDY), + 2 * USEC_PER_MSEC, 150 * USEC_PER_MSEC); + if (ret) + return ret; + + ret = regmap_bulk_read(map, QMC5883L_REG_X_LSB, buf, sizeof(buf)); + if (ret) + return ret; + + if (status & QMC5883L_STATUS_OVL) + return -ERANGE; + + *val = (s16)le16_to_cpu(buf[index]); + + return 0; +} + +static int qmc5883l_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct qmc5883l_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = qmc5883l_take_measurement(indio_dev, chan->address, val); + if (ret) + return ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: { + guard(mutex)(&data->mutex); + + *val = qmc5883l_scales[data->range][0]; + *val2 = qmc5883l_scales[data->range][1]; + + return IIO_VAL_INT_PLUS_NANO; + } + case IIO_CHAN_INFO_SAMP_FREQ: { + guard(mutex)(&data->mutex); + + switch (data->odr) { + case QMC5883L_ODR_200HZ: + *val = 200; + break; + case QMC5883L_ODR_100HZ: + *val = 100; + break; + case QMC5883L_ODR_50HZ: + *val = 50; + break; + case QMC5883L_ODR_10HZ: + *val = 10; + break; + default: + return -EINVAL; + } + + return IIO_VAL_INT; + } + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { + guard(mutex)(&data->mutex); + + switch (data->osr) { + case QMC5883L_OSR_64: + *val = 64; + break; + case QMC5883L_OSR_128: + *val = 128; + break; + case QMC5883L_OSR_256: + *val = 256; + break; + case QMC5883L_OSR_512: + *val = 512; + break; + default: + return -EINVAL; + } + + return IIO_VAL_INT; + } + default: + return -EINVAL; + } +} + +static int qmc5883l_write_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int val, int val2, long mask) +{ + struct qmc5883l_data *data = iio_priv(indio_dev); + u8 rng, osr, odr; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: { + if (val != 0) + return -EINVAL; + + if (val2 == qmc5883l_scales[QMC5883L_RNG_2G][1]) + rng = QMC5883L_RNG_2G; + else if (val2 == qmc5883l_scales[QMC5883L_RNG_8G][1]) + rng = QMC5883L_RNG_8G; + else + return -EINVAL; + + guard(mutex)(&data->mutex); + + ret = regmap_update_bits(data->regmap, QMC5883L_REG_CTRL1, + QMC5883L_RNG_MASK, + FIELD_PREP(QMC5883L_RNG_MASK, rng)); + if (ret) + return ret; + + data->range = rng; + + return 0; + } + case IIO_CHAN_INFO_SAMP_FREQ: { + switch (val) { + case 200: + odr = QMC5883L_ODR_200HZ; + break; + case 100: + odr = QMC5883L_ODR_100HZ; + break; + case 50: + odr = QMC5883L_ODR_50HZ; + break; + case 10: + odr = QMC5883L_ODR_10HZ; + break; + default: + return -EINVAL; + } + + guard(mutex)(&data->mutex); + + ret = regmap_update_bits(data->regmap, QMC5883L_REG_CTRL1, + QMC5883L_ODR_MASK, + FIELD_PREP(QMC5883L_ODR_MASK, odr)); + if (ret) + return ret; + + data->odr = odr; + + return 0; + } + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { + switch (val) { + case 64: + osr = QMC5883L_OSR_64; + break; + case 128: + osr = QMC5883L_OSR_128; + break; + case 256: + osr = QMC5883L_OSR_256; + break; + case 512: + osr = QMC5883L_OSR_512; + break; + default: + return -EINVAL; + } + + guard(mutex)(&data->mutex); + + ret = regmap_update_bits(data->regmap, QMC5883L_REG_CTRL1, + QMC5883L_OSR_MASK, + FIELD_PREP(QMC5883L_OSR_MASK, osr)); + if (ret) + return ret; + + data->osr = osr; + + return 0; + } + default: + return -EINVAL; + } +} + +static int qmc5883l_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_SAMP_FREQ: + *vals = qmc5883l_odr_avail; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(qmc5883l_odr_avail); + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *vals = qmc5883l_osr_avail; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(qmc5883l_osr_avail); + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SCALE: + *vals = (const int *)qmc5883l_scales; + *type = IIO_VAL_INT_PLUS_NANO; + *length = ARRAY_SIZE(qmc5883l_scales) * 2; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int qmc5883l_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + default: + return IIO_VAL_INT; + } +} + +static const struct iio_info qmc5883l_info = { + .read_raw = qmc5883l_read_raw, + .write_raw = qmc5883l_write_raw, + .read_avail = qmc5883l_read_avail, + .write_raw_get_fmt = qmc5883l_write_raw_get_fmt, +}; + +static int qmc5883l_init(struct qmc5883l_data *data) +{ + struct regmap *map = data->regmap; + unsigned int reg; + int ret; + + ret = regmap_read(map, QMC5883L_REG_ID, ®); + if (ret) + return ret; + + /* Not failing because rev 1.0 had this register reserved */ + if (reg != QMC5883L_CHIP_ID) + dev_warn(regmap_get_device(map), + "Unknown chip id: 0x%02x, continuing\n", reg); + + ret = regmap_write(map, QMC5883L_REG_CTRL2, QMC5883L_SOFT_RESET); + if (ret) + return ret; + + /* Use POR completion time as a conservative bound */ + fsleep(QMC5883L_PORT_US); + + /* DRDY pin not used in this version of the driver */ + ret = regmap_write(map, QMC5883L_REG_CTRL2, QMC5883L_INT_DISABLE); + if (ret) + return ret; + + ret = regmap_write(map, QMC5883L_REG_SET_RESET, QMC5883L_SET_RESET_VAL); + if (ret) + return ret; + + data->odr = QMC5883L_ODR_50HZ; + data->range = QMC5883L_RNG_2G; + data->osr = QMC5883L_OSR_64; + + return regmap_write(map, QMC5883L_REG_CTRL1, + FIELD_PREP(QMC5883L_MODE_MASK, QMC5883L_MODE_CONT) | + FIELD_PREP(QMC5883L_ODR_MASK, data->odr) | + FIELD_PREP(QMC5883L_RNG_MASK, data->range) | + FIELD_PREP(QMC5883L_OSR_MASK, data->osr)); +} + +static void qmc5883l_power_down_action(void *priv) +{ + struct qmc5883l_data *data = priv; + + regmap_update_bits(data->regmap, QMC5883L_REG_CTRL1, + QMC5883L_MODE_MASK, + FIELD_PREP(QMC5883L_MODE_MASK, QMC5883L_MODE_STANDBY)); +} + +static bool qmc5883l_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg <= QMC5883L_REG_STATUS1; +} + +static bool qmc5883l_writable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case QMC5883L_REG_CTRL1: + case QMC5883L_REG_CTRL2: + case QMC5883L_REG_SET_RESET: + return true; + default: + return false; + } +} + +static const struct regmap_config qmc5883l_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = QMC5883L_REG_ID, + .cache_type = REGCACHE_MAPLE, + .volatile_reg = qmc5883l_volatile_reg, + .writeable_reg = qmc5883l_writable_reg, +}; + +#define QMC5883L_CHANNEL(_axis) \ + { \ + .type = IIO_MAGN, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .address = QMC5883L_AXIS_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + } + +static const struct iio_chan_spec qmc5883l_channels[] = { + QMC5883L_CHANNEL(X), + QMC5883L_CHANNEL(Y), + QMC5883L_CHANNEL(Z), +}; + +static int qmc5883l_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct qmc5883l_data *data; + struct iio_dev *indio_dev; + struct regmap *map; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + map = devm_regmap_init_i2c(client, &qmc5883l_regmap_config); + if (IS_ERR(map)) + return dev_err_probe(dev, PTR_ERR(map), + "regmap initialization failed\n"); + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable VDD regulator\n"); + + ret = devm_regulator_get_enable(dev, "vddio"); + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable VDDIO regulator\n"); + + /* POR completion time max per datasheet Table 7 */ + fsleep(QMC5883L_PORT_US); + + data = iio_priv(indio_dev); + data->regmap = map; + + ret = devm_mutex_init(dev, &data->mutex); + if (ret) + return ret; + + indio_dev->name = "qmc5883l"; + indio_dev->info = &qmc5883l_info; + indio_dev->channels = qmc5883l_channels; + indio_dev->num_channels = ARRAY_SIZE(qmc5883l_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = qmc5883l_init(data); + if (ret) + return dev_err_probe(dev, ret, "qmc5883l init failed\n"); + + ret = devm_add_action_or_reset(dev, qmc5883l_power_down_action, data); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id qmc5883l_match[] = { + { .compatible = "qstcorp,qmc5883l" }, + { } +}; +MODULE_DEVICE_TABLE(of, qmc5883l_match); + +static const struct i2c_device_id qmc5883l_id[] = { + { .name = "qmc5883l" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, qmc5883l_id); + +static struct i2c_driver qmc5883l_driver = { + .driver = { + .name = "qmc5883l", + .of_match_table = qmc5883l_match, + }, + .id_table = qmc5883l_id, + .probe = qmc5883l_probe, +}; +module_i2c_driver(qmc5883l_driver); + +MODULE_DESCRIPTION("QST QMC5883L 3-Axis Magnetic Sensor driver"); +MODULE_AUTHOR("Siratul Islam <siratul.islam@linux.dev>"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/iio/magnetometer/qmc6308.c b/drivers/iio/magnetometer/qmc6308.c new file mode 100644 index 000000000000..7d4df846bbc5 --- /dev/null +++ b/drivers/iio/magnetometer/qmc6308.c @@ -0,0 +1,602 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Support for QST QMC6308 3-Axis Magnetic Sensor on I2C bus. + * + * Copyright (C) 2026 Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net> + * + * Datasheet available at + * <https://qstcorp.com/upload/pdf/202202/13-52-15%20QMC6308%20Datasheet%20Rev.%20F(1).pdf> + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/time.h> +#include <linux/types.h> + +#include <asm/byteorder.h> + +#include <linux/iio/iio.h> + +#define QMC6308_REG_ID 0x00 +#define QMC6308_REG_X_LSB 0x01 +#define QMC6308_REG_STATUS 0x09 +#define QMC6308_REG_CTRL1 0x0A +#define QMC6308_REG_CTRL2 0x0B +#define QMC6308_REG_CTRL3 0x0D +#define QMC6308_REG_CTRL4 0x29 + +#define QMC6308_CHIP_ID 0x80 + +/* Control register 1 */ +#define QMC6308_MODE_MASK GENMASK(1, 0) +#define QMC6308_ODR_MASK GENMASK(3, 2) +#define QMC6308_OSR1_MASK GENMASK(5, 4) +#define QMC6308_OSR2_MASK GENMASK(7, 6) + +#define QMC6308_MODE_SUSPEND 0x00 +#define QMC6308_MODE_NORMAL 0x01 + +#define QMC6308_ODR_10HZ 0x00 +#define QMC6308_ODR_50HZ 0x01 +#define QMC6308_ODR_100HZ 0x02 +#define QMC6308_ODR_200HZ 0x03 + +#define QMC6308_OSR1_8 0x00 +#define QMC6308_OSR1_4 0x01 +#define QMC6308_OSR1_2 0x02 +#define QMC6308_OSR1_1 0x03 + +/* Control register 2 */ +#define QMC6308_SET_RESET_MASK GENMASK(1, 0) +#define QMC6308_RNG_MASK GENMASK(3, 2) +#define QMC6308_SELF_TEST BIT(6) +#define QMC6308_SOFT_RST BIT(7) + +#define QMC6308_SET_RESET_ON 0x00 + +#define QMC6308_RNG_30G 0x00 +#define QMC6308_RNG_12G 0x01 +#define QMC6308_RNG_8G 0x02 +#define QMC6308_RNG_2G 0x03 + +/* Status register */ +#define QMC6308_STATUS_DRDY BIT(0) +#define QMC6308_STATUS_OVFL BIT(1) + +/* Power-on completion time (datasheet Table 7) */ +#define QMC6308_POR_US 250 + +#define QMC6308_AUTOSUSPEND_DELAY_MS 500 + +struct qmc6308_data { + struct regmap *regmap; + /* Protect data->range/odr/osr and serialize measurements */ + struct mutex mutex; + struct iio_mount_matrix orientation; + u8 range; + u8 odr; + u8 osr; +}; + +enum qmc6308_axis { + QMC6308_AXIS_X, + QMC6308_AXIS_Y, + QMC6308_AXIS_Z, +}; + +static const int qmc6308_odr_avail[] = { + [QMC6308_ODR_10HZ] = 10, + [QMC6308_ODR_50HZ] = 50, + [QMC6308_ODR_100HZ] = 100, + [QMC6308_ODR_200HZ] = 200, +}; + +static const int qmc6308_osr1_avail[] = { + [QMC6308_OSR1_8] = 8, + [QMC6308_OSR1_4] = 4, + [QMC6308_OSR1_2] = 2, + [QMC6308_OSR1_1] = 1, +}; + +/* + * Sensitivity is 1000/2500/3750/15000 LSB/Gauss for the + * +-30/12/8/2 Gauss ranges respectively. + */ +static const int qmc6308_scales[][2] = { + [QMC6308_RNG_30G] = { 0, 1000000 }, + [QMC6308_RNG_12G] = { 0, 400000 }, + [QMC6308_RNG_8G] = { 0, 266667 }, + [QMC6308_RNG_2G] = { 0, 66667 }, +}; + +static int qmc6308_set_mode(struct qmc6308_data *data, unsigned int mode) +{ + return regmap_update_bits(data->regmap, QMC6308_REG_CTRL1, + QMC6308_MODE_MASK, + FIELD_PREP(QMC6308_MODE_MASK, mode)); +} + +static int qmc6308_take_measurement(struct iio_dev *indio_dev, int index, + int *val) +{ + struct qmc6308_data *data = iio_priv(indio_dev); + struct device *dev = regmap_get_device(data->regmap); + unsigned int status; + __le16 buf[3]; + int ret; + + PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) { + dev_err(dev, "Failed to power on (%d)\n", ret); + return ret; + } + + guard(mutex)(&data->mutex); + + /* + * Reading the status register clears DRDY, which is why the poll + * and the data read stay under one mutex hold. A runtime resume + * clears DRDY too, so a sample converted before the last suspend + * is never returned here. + * + * The timeout is 50ms of headroom over the slowest ODR (10Hz). + */ + ret = regmap_read_poll_timeout(data->regmap, QMC6308_REG_STATUS, + status, + (status & QMC6308_STATUS_DRDY), + 2 * USEC_PER_MSEC, + 150 * USEC_PER_MSEC); + if (ret) + return ret; + + ret = regmap_bulk_read(data->regmap, QMC6308_REG_X_LSB, buf, + sizeof(buf)); + if (ret) + return ret; + + if (status & QMC6308_STATUS_OVFL) + return -ERANGE; + + *val = (s16)le16_to_cpu(buf[index]); + + return 0; +} + +static int qmc6308_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct qmc6308_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = qmc6308_take_measurement(indio_dev, chan->address, val); + if (ret) + return ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: { + guard(mutex)(&data->mutex); + + *val = qmc6308_scales[data->range][0]; + *val2 = qmc6308_scales[data->range][1]; + + return IIO_VAL_INT_PLUS_NANO; + } + case IIO_CHAN_INFO_SAMP_FREQ: { + guard(mutex)(&data->mutex); + + *val = qmc6308_odr_avail[data->odr]; + + return IIO_VAL_INT; + } + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { + guard(mutex)(&data->mutex); + + *val = qmc6308_osr1_avail[data->osr]; + + return IIO_VAL_INT; + } + default: + return -EINVAL; + } +} + +static int qmc6308_write_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int val, int val2, long mask) +{ + struct qmc6308_data *data = iio_priv(indio_dev); + unsigned int status; + unsigned int i; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: { + if (val != 0) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(qmc6308_scales); i++) { + if (val2 == qmc6308_scales[i][1]) + break; + } + if (i == ARRAY_SIZE(qmc6308_scales)) + return -EINVAL; + + guard(mutex)(&data->mutex); + + ret = regmap_update_bits(data->regmap, QMC6308_REG_CTRL2, + QMC6308_RNG_MASK, + FIELD_PREP(QMC6308_RNG_MASK, i)); + if (ret) + return ret; + + data->range = i; + + /* + * The data registers still hold (and DRDY still + * advertises) a sample converted at the previous range; + * discard it so that a read does not pair old-range data + * with the new scale. A conversion already in flight may + * still complete at the old range, so this narrows the + * window rather than closing it. The range change itself + * took effect, so only log a failure here: an error + * would mislead userspace about an effective write. + */ + ret = regmap_read(data->regmap, QMC6308_REG_STATUS, + &status); + if (ret) + dev_warn(regmap_get_device(data->regmap), + "Failed to discard stale sample (%d)\n", + ret); + + return 0; + } + case IIO_CHAN_INFO_SAMP_FREQ: { + for (i = 0; i < ARRAY_SIZE(qmc6308_odr_avail); i++) { + if (val == qmc6308_odr_avail[i]) + break; + } + if (i == ARRAY_SIZE(qmc6308_odr_avail)) + return -EINVAL; + + guard(mutex)(&data->mutex); + + ret = regmap_update_bits(data->regmap, QMC6308_REG_CTRL1, + QMC6308_ODR_MASK, + FIELD_PREP(QMC6308_ODR_MASK, i)); + if (ret) + return ret; + + data->odr = i; + + return 0; + } + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { + for (i = 0; i < ARRAY_SIZE(qmc6308_osr1_avail); i++) { + if (val == qmc6308_osr1_avail[i]) + break; + } + if (i == ARRAY_SIZE(qmc6308_osr1_avail)) + return -EINVAL; + + guard(mutex)(&data->mutex); + + ret = regmap_update_bits(data->regmap, QMC6308_REG_CTRL1, + QMC6308_OSR1_MASK, + FIELD_PREP(QMC6308_OSR1_MASK, i)); + if (ret) + return ret; + + data->osr = i; + + return 0; + } + default: + return -EINVAL; + } +} + +static int qmc6308_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_SAMP_FREQ: + *vals = qmc6308_odr_avail; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(qmc6308_odr_avail); + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *vals = qmc6308_osr1_avail; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(qmc6308_osr1_avail); + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SCALE: + *vals = (const int *)qmc6308_scales; + *type = IIO_VAL_INT_PLUS_NANO; + *length = ARRAY_SIZE(qmc6308_scales) * 2; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int qmc6308_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + default: + return IIO_VAL_INT; + } +} + +static const struct iio_mount_matrix * +qmc6308_get_mount_matrix(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct qmc6308_data *data = iio_priv(indio_dev); + + return &data->orientation; +} + +static const struct iio_chan_spec_ext_info qmc6308_ext_info[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, qmc6308_get_mount_matrix), + { } +}; + +static const struct iio_info qmc6308_info = { + .read_raw = qmc6308_read_raw, + .write_raw = qmc6308_write_raw, + .read_avail = qmc6308_read_avail, + .write_raw_get_fmt = qmc6308_write_raw_get_fmt, +}; + +static int qmc6308_init(struct qmc6308_data *data) +{ + struct regmap *map = data->regmap; + unsigned int reg; + int ret; + + ret = regmap_read(map, QMC6308_REG_ID, ®); + if (ret) + return ret; + + /* Allow unknown IDs so that fallback compatibles work */ + if (reg != QMC6308_CHIP_ID) + dev_warn(regmap_get_device(map), + "Unknown chip id: 0x%02x, continuing\n", reg); + + /* The SOFT_RST bit is not auto-cleared and must be written back 0 */ + ret = regmap_write(map, QMC6308_REG_CTRL2, QMC6308_SOFT_RST); + if (ret) + return ret; + + /* + * The datasheet gives no soft-reset completion figure; reuse the + * power-on time as a conservative bound. + */ + fsleep(QMC6308_POR_US); + + data->range = QMC6308_RNG_30G; + data->odr = QMC6308_ODR_50HZ; + data->osr = QMC6308_OSR1_8; + + ret = regmap_write(map, QMC6308_REG_CTRL2, + FIELD_PREP(QMC6308_SET_RESET_MASK, + QMC6308_SET_RESET_ON) | + FIELD_PREP(QMC6308_RNG_MASK, data->range)); + if (ret) + return ret; + + /* OSR2 (second-stage filter) set to its power-on default of 0 */ + return regmap_write(map, QMC6308_REG_CTRL1, + FIELD_PREP(QMC6308_MODE_MASK, + QMC6308_MODE_NORMAL) | + FIELD_PREP(QMC6308_ODR_MASK, data->odr) | + FIELD_PREP(QMC6308_OSR1_MASK, data->osr) | + FIELD_PREP(QMC6308_OSR2_MASK, 0)); +} + +static void qmc6308_power_down_action(void *priv) +{ + struct qmc6308_data *data = priv; + + if (!pm_runtime_status_suspended(regmap_get_device(data->regmap))) + qmc6308_set_mode(data, QMC6308_MODE_SUSPEND); +} + +static bool qmc6308_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg >= QMC6308_REG_X_LSB && reg <= QMC6308_REG_STATUS; +} + +static bool qmc6308_writable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case QMC6308_REG_CTRL1: + case QMC6308_REG_CTRL2: + case QMC6308_REG_CTRL3: + case QMC6308_REG_CTRL4: + return true; + default: + return false; + } +} + +static const struct regmap_config qmc6308_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = QMC6308_REG_CTRL4, + .cache_type = REGCACHE_MAPLE, + .volatile_reg = qmc6308_volatile_reg, + .writeable_reg = qmc6308_writable_reg, +}; + +#define QMC6308_CHANNEL(_axis) \ + { \ + .type = IIO_MAGN, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .address = QMC6308_AXIS_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .ext_info = qmc6308_ext_info, \ + } + +static const struct iio_chan_spec qmc6308_channels[] = { + QMC6308_CHANNEL(X), + QMC6308_CHANNEL(Y), + QMC6308_CHANNEL(Z), +}; + +static int qmc6308_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct qmc6308_data *data; + struct iio_dev *indio_dev; + struct regmap *map; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + i2c_set_clientdata(client, indio_dev); + + map = devm_regmap_init_i2c(client, &qmc6308_regmap_config); + if (IS_ERR(map)) + return dev_err_probe(dev, PTR_ERR(map), + "regmap initialization failed\n"); + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable VDD regulator\n"); + + fsleep(QMC6308_POR_US); + + data = iio_priv(indio_dev); + data->regmap = map; + + ret = devm_mutex_init(dev, &data->mutex); + if (ret) + return ret; + + ret = iio_read_mount_matrix(dev, &data->orientation); + if (ret) + return dev_err_probe(dev, ret, + "Failed to read mount matrix\n"); + + indio_dev->name = "qmc6308"; + indio_dev->info = &qmc6308_info; + indio_dev->channels = qmc6308_channels; + indio_dev->num_channels = ARRAY_SIZE(qmc6308_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = qmc6308_init(data); + if (ret) + return dev_err_probe(dev, ret, "qmc6308 init failed\n"); + + ret = pm_runtime_set_active(dev); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, qmc6308_power_down_action, data); + if (ret) + return ret; + + pm_runtime_use_autosuspend(dev); + pm_runtime_set_autosuspend_delay(dev, QMC6308_AUTOSUSPEND_DELAY_MS); + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static int qmc6308_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct qmc6308_data *data = iio_priv(indio_dev); + + return qmc6308_set_mode(data, QMC6308_MODE_SUSPEND); +} + +static int qmc6308_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct qmc6308_data *data = iio_priv(indio_dev); + unsigned int status; + int ret; + + ret = qmc6308_set_mode(data, QMC6308_MODE_NORMAL); + if (ret) + return ret; + + /* + * DRDY may still be set for a sample converted before the last + * suspend; reading the status register clears it so the next + * measurement waits for fresh data. + */ + ret = regmap_read(data->regmap, QMC6308_REG_STATUS, &status); + if (ret) { + /* Best effort to leave the chip in a consistent state */ + qmc6308_set_mode(data, QMC6308_MODE_SUSPEND); + } + + return ret; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(qmc6308_pm_ops, qmc6308_runtime_suspend, + qmc6308_runtime_resume, NULL); + +static const struct of_device_id qmc6308_match[] = { + { .compatible = "qstcorp,qmc6308" }, + { } +}; +MODULE_DEVICE_TABLE(of, qmc6308_match); + +static const struct i2c_device_id qmc6308_id[] = { + { .name = "qmc6308" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, qmc6308_id); + +static struct i2c_driver qmc6308_driver = { + .driver = { + .name = "qmc6308", + .of_match_table = qmc6308_match, + .pm = pm_ptr(&qmc6308_pm_ops), + }, + .id_table = qmc6308_id, + .probe = qmc6308_probe, +}; +module_i2c_driver(qmc6308_driver); + +MODULE_DESCRIPTION("QST QMC6308 3-Axis Magnetic Sensor driver"); +MODULE_AUTHOR("Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c index 69693e836ad7..af4642b6c3c0 100644 --- a/drivers/iio/magnetometer/st_magn_spi.c +++ b/drivers/iio/magnetometer/st_magn_spi.c @@ -87,12 +87,12 @@ static int st_magn_spi_probe(struct spi_device *spi) } static const struct spi_device_id st_magn_id_table[] = { - { LIS3MDL_MAGN_DEV_NAME }, - { LSM303AGR_MAGN_DEV_NAME }, - { LIS2MDL_MAGN_DEV_NAME }, - { LSM9DS1_MAGN_DEV_NAME }, - { IIS2MDC_MAGN_DEV_NAME }, - { LSM303C_MAGN_DEV_NAME }, + { .name = LIS3MDL_MAGN_DEV_NAME }, + { .name = LSM303AGR_MAGN_DEV_NAME }, + { .name = LIS2MDL_MAGN_DEV_NAME }, + { .name = LSM9DS1_MAGN_DEV_NAME }, + { .name = IIS2MDC_MAGN_DEV_NAME }, + { .name = LSM303C_MAGN_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(spi, st_magn_id_table); diff --git a/drivers/iio/multiplexer/iio-mux.c b/drivers/iio/multiplexer/iio-mux.c index 4421dafcf94e..562457a67382 100644 --- a/drivers/iio/multiplexer/iio-mux.c +++ b/drivers/iio/multiplexer/iio-mux.c @@ -463,3 +463,4 @@ module_platform_driver(mux_driver); MODULE_DESCRIPTION("IIO multiplexer driver"); MODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c index ea60611192f3..aea28321db95 100644 --- a/drivers/iio/orientation/hid-sensor-incl-3d.c +++ b/drivers/iio/orientation/hid-sensor-incl-3d.c @@ -85,8 +85,7 @@ static const struct iio_chan_spec incl_3d_channels[] = { }; /* Adjust channel real bits based on report descriptor */ -static void incl_3d_adjust_channel_bit_mask(struct iio_chan_spec *chan, - int size) +static void incl_3d_adjust_channel_bit_mask(struct iio_chan_spec *chan, int size) { chan->scan_type.sign = 's'; /* Real storage bits will change based on the report desc. */ @@ -97,9 +96,8 @@ static void incl_3d_adjust_channel_bit_mask(struct iio_chan_spec *chan, /* Channel read_raw handler */ static int incl_3d_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, - long mask) + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct incl_3d_state *incl_state = iio_priv(indio_dev); int report_id = -1; @@ -124,7 +122,7 @@ static int incl_3d_read_raw(struct iio_dev *indio_dev, min < 0); else { hid_sensor_power_state(&incl_state->common_attributes, - false); + false); return -EINVAL; } hid_sensor_power_state(&incl_state->common_attributes, false); @@ -157,10 +155,8 @@ static int incl_3d_read_raw(struct iio_dev *indio_dev, /* Channel write_raw handler */ static int incl_3d_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct incl_3d_state *incl_state = iio_priv(indio_dev); int ret; @@ -188,8 +184,7 @@ static const struct iio_info incl_3d_info = { /* Callback handler to send event after all samples are received and captured */ static int incl_3d_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - void *priv) + u32 usage_id, void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct incl_3d_state *incl_state = iio_priv(indio_dev); @@ -211,9 +206,9 @@ static int incl_3d_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int incl_3d_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - size_t raw_len, char *raw_data, - void *priv) + u32 usage_id, + size_t raw_len, char *raw_data, + void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct incl_3d_state *incl_state = iio_priv(indio_dev); @@ -246,7 +241,7 @@ static int incl_3d_capture_sample(struct hid_sensor_hub_device *hsdev, static int incl_3d_parse_report(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, struct iio_chan_spec *channels, - unsigned usage_id, + u32 usage_id, struct incl_3d_state *st) { int ret; @@ -306,7 +301,7 @@ static int hid_incl_3d_probe(struct platform_device *pdev) indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct incl_3d_state)); - if (indio_dev == NULL) + if (!indio_dev) return -ENOMEM; platform_set_drvdata(pdev, indio_dev); @@ -349,33 +344,33 @@ static int hid_incl_3d_probe(struct platform_device *pdev) atomic_set(&incl_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, - &incl_state->common_attributes); + &incl_state->common_attributes); if (ret) { dev_err(&pdev->dev, "trigger setup failed\n"); return ret; } - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(&pdev->dev, "device register failed\n"); - goto error_remove_trigger; - } - incl_state->callbacks.send_event = incl_3d_proc_event; incl_state->callbacks.capture_sample = incl_3d_capture_sample; incl_state->callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, - HID_USAGE_SENSOR_INCLINOMETER_3D, - &incl_state->callbacks); + HID_USAGE_SENSOR_INCLINOMETER_3D, + &incl_state->callbacks); if (ret) { dev_err(&pdev->dev, "callback reg failed\n"); - goto error_iio_unreg; + goto error_remove_trigger; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "device register failed\n"); + goto error_remove_callback; } return 0; -error_iio_unreg: - iio_device_unregister(indio_dev); +error_remove_callback: + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes); return ret; @@ -388,8 +383,8 @@ static void hid_incl_3d_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct incl_3d_state *incl_state = iio_priv(indio_dev); - sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D); iio_device_unregister(indio_dev); + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D); hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes); } diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c index cc3e66dbb90f..f8c98f866cb0 100644 --- a/drivers/iio/orientation/hid-sensor-rotation.c +++ b/drivers/iio/orientation/hid-sensor-rotation.c @@ -80,9 +80,8 @@ static const struct iio_chan_spec dev_rot_channels[] = { /* Channel read_raw handler */ static int dev_rot_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int size, int *vals, int *val_len, - long mask) + struct iio_chan_spec const *chan, + int size, int *vals, int *val_len, long mask) { struct dev_rot_state *rot_state = iio_priv(indio_dev); struct hid_sensor_hub_device *hsdev = rot_state->common_attributes.hsdev; @@ -164,10 +163,8 @@ static int dev_rot_read_raw(struct iio_dev *indio_dev, /* Channel write_raw handler */ static int dev_rot_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct dev_rot_state *rot_state = iio_priv(indio_dev); int ret; @@ -211,8 +208,7 @@ static const struct iio_info dev_rot_info = { /* Callback handler to send event after all samples are received and captured */ static int dev_rot_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - void *priv) + u32 usage_id, void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct dev_rot_state *rot_state = iio_priv(indio_dev); @@ -244,9 +240,9 @@ static int dev_rot_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int dev_rot_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - size_t raw_len, char *raw_data, - void *priv) + u32 usage_id, + size_t raw_len, char *raw_data, + void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct dev_rot_state *rot_state = iio_priv(indio_dev); @@ -275,7 +271,7 @@ static int dev_rot_capture_sample(struct hid_sensor_hub_device *hsdev, /* Parse report which is specific to an usage id*/ static int dev_rot_parse_report(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, - unsigned usage_id, + u32 usage_id, struct dev_rot_state *st) { int ret; @@ -313,7 +309,7 @@ static int hid_dev_rot_probe(struct platform_device *pdev) indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct dev_rot_state)); - if (indio_dev == NULL) + if (!indio_dev) return -ENOMEM; platform_set_drvdata(pdev, indio_dev); @@ -361,32 +357,32 @@ static int hid_dev_rot_probe(struct platform_device *pdev) atomic_set(&rot_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, - &rot_state->common_attributes); + &rot_state->common_attributes); if (ret) { dev_err(&pdev->dev, "trigger setup failed\n"); return ret; } - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(&pdev->dev, "device register failed\n"); - goto error_remove_trigger; - } - rot_state->callbacks.send_event = dev_rot_proc_event; rot_state->callbacks.capture_sample = dev_rot_capture_sample; rot_state->callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, hsdev->usage, - &rot_state->callbacks); + &rot_state->callbacks); if (ret) { dev_err(&pdev->dev, "callback reg failed\n"); - goto error_iio_unreg; + goto error_remove_trigger; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "device register failed\n"); + goto error_remove_callback; } return 0; -error_iio_unreg: - iio_device_unregister(indio_dev); +error_remove_callback: + sensor_hub_remove_callback(hsdev, hsdev->usage); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &rot_state->common_attributes); return ret; @@ -399,8 +395,8 @@ static void hid_dev_rot_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct dev_rot_state *rot_state = iio_priv(indio_dev); - sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); + sensor_hub_remove_callback(hsdev, hsdev->usage); hid_sensor_remove_trigger(indio_dev, &rot_state->common_attributes); } diff --git a/drivers/iio/position/hid-sensor-custom-intel-hinge.c b/drivers/iio/position/hid-sensor-custom-intel-hinge.c index bffa8fe4fe44..d275bc1413fe 100644 --- a/drivers/iio/position/hid-sensor-custom-intel-hinge.c +++ b/drivers/iio/position/hid-sensor-custom-intel-hinge.c @@ -106,8 +106,8 @@ static void hinge_adjust_channel_realbits(struct iio_chan_spec *channels, /* Channel read_raw handler */ static int hinge_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, int *val, int *val2, - long mask) + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct hinge_state *st = iio_priv(indio_dev); struct hid_sensor_hub_device *hsdev; @@ -153,8 +153,8 @@ static int hinge_read_raw(struct iio_dev *indio_dev, /* Channel write_raw handler */ static int hinge_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, int val, int val2, - long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct hinge_state *st = iio_priv(indio_dev); @@ -189,7 +189,7 @@ static const struct iio_info hinge_info = { * and captured. */ static int hinge_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned int usage_id, void *priv) + u32 usage_id, void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct hinge_state *st = iio_priv(indio_dev); @@ -208,8 +208,9 @@ static int hinge_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int hinge_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned int usage_id, size_t raw_len, - char *raw_data, void *priv) + u32 usage_id, + size_t raw_len, char *raw_data, + void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct hinge_state *st = iio_priv(indio_dev); @@ -235,7 +236,7 @@ static int hinge_capture_sample(struct hid_sensor_hub_device *hsdev, static int hinge_parse_report(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, struct iio_chan_spec *channels, - unsigned int usage_id, struct hinge_state *st) + u32 usage_id, struct hinge_state *st) { int ret; int i; @@ -291,7 +292,7 @@ static int hid_hinge_probe(struct platform_device *pdev) } indio_dev->num_channels = ARRAY_SIZE(hinge_channels); - indio_dev->channels = devm_kmemdup(&indio_dev->dev, hinge_channels, + indio_dev->channels = devm_kmemdup(&pdev->dev, hinge_channels, sizeof(hinge_channels), GFP_KERNEL); if (!indio_dev->channels) return -ENOMEM; diff --git a/drivers/iio/potentiometer/max5481.c b/drivers/iio/potentiometer/max5481.c index ddf54a1df976..ec1b7bdc706b 100644 --- a/drivers/iio/potentiometer/max5481.c +++ b/drivers/iio/potentiometer/max5481.c @@ -169,10 +169,10 @@ static int max5481_probe(struct spi_device *spi) } static const struct spi_device_id max5481_id_table[] = { - { "max5481", max5481 }, - { "max5482", max5482 }, - { "max5483", max5483 }, - { "max5484", max5484 }, + { .name = "max5481", .driver_data = max5481 }, + { .name = "max5482", .driver_data = max5482 }, + { .name = "max5483", .driver_data = max5483 }, + { .name = "max5484", .driver_data = max5484 }, { } }; MODULE_DEVICE_TABLE(spi, max5481_id_table); diff --git a/drivers/iio/potentiometer/max5487.c b/drivers/iio/potentiometer/max5487.c index 9541695af474..1f0d0056f412 100644 --- a/drivers/iio/potentiometer/max5487.c +++ b/drivers/iio/potentiometer/max5487.c @@ -125,9 +125,9 @@ static void max5487_spi_remove(struct spi_device *spi) } static const struct spi_device_id max5487_id[] = { - { "MAX5487", 10 }, - { "MAX5488", 50 }, - { "MAX5489", 100 }, + { .name = "MAX5487", .driver_data = 10 }, + { .name = "MAX5488", .driver_data = 50 }, + { .name = "MAX5489", .driver_data = 100 }, { } }; MODULE_DEVICE_TABLE(spi, max5487_id); diff --git a/drivers/iio/potentiometer/mcp41010.c b/drivers/iio/potentiometer/mcp41010.c index ed0764231224..cfd5d0f6d368 100644 --- a/drivers/iio/potentiometer/mcp41010.c +++ b/drivers/iio/potentiometer/mcp41010.c @@ -175,12 +175,12 @@ static const struct of_device_id mcp41010_match[] = { MODULE_DEVICE_TABLE(of, mcp41010_match); static const struct spi_device_id mcp41010_id[] = { - { "mcp41010", MCP41010 }, - { "mcp41050", MCP41050 }, - { "mcp41100", MCP41100 }, - { "mcp42010", MCP42010 }, - { "mcp42050", MCP42050 }, - { "mcp42100", MCP42100 }, + { .name = "mcp41010", .driver_data = MCP41010 }, + { .name = "mcp41050", .driver_data = MCP41050 }, + { .name = "mcp41100", .driver_data = MCP41100 }, + { .name = "mcp42010", .driver_data = MCP42010 }, + { .name = "mcp42050", .driver_data = MCP42050 }, + { .name = "mcp42100", .driver_data = MCP42100 }, { } }; MODULE_DEVICE_TABLE(spi, mcp41010_id); diff --git a/drivers/iio/potentiometer/mcp4131.c b/drivers/iio/potentiometer/mcp4131.c index dad09ce6a75d..fadf9fcc1817 100644 --- a/drivers/iio/potentiometer/mcp4131.c +++ b/drivers/iio/potentiometer/mcp4131.c @@ -406,70 +406,70 @@ static const struct of_device_id mcp4131_dt_ids[] = { MODULE_DEVICE_TABLE(of, mcp4131_dt_ids); static const struct spi_device_id mcp4131_id[] = { - { "mcp4131-502", MCP413x_502 }, - { "mcp4131-103", MCP413x_103 }, - { "mcp4131-503", MCP413x_503 }, - { "mcp4131-104", MCP413x_104 }, - { "mcp4132-502", MCP413x_502 }, - { "mcp4132-103", MCP413x_103 }, - { "mcp4132-503", MCP413x_503 }, - { "mcp4132-104", MCP413x_104 }, - { "mcp4141-502", MCP414x_502 }, - { "mcp4141-103", MCP414x_103 }, - { "mcp4141-503", MCP414x_503 }, - { "mcp4141-104", MCP414x_104 }, - { "mcp4142-502", MCP414x_502 }, - { "mcp4142-103", MCP414x_103 }, - { "mcp4142-503", MCP414x_503 }, - { "mcp4142-104", MCP414x_104 }, - { "mcp4151-502", MCP415x_502 }, - { "mcp4151-103", MCP415x_103 }, - { "mcp4151-503", MCP415x_503 }, - { "mcp4151-104", MCP415x_104 }, - { "mcp4152-502", MCP415x_502 }, - { "mcp4152-103", MCP415x_103 }, - { "mcp4152-503", MCP415x_503 }, - { "mcp4152-104", MCP415x_104 }, - { "mcp4161-502", MCP416x_502 }, - { "mcp4161-103", MCP416x_103 }, - { "mcp4161-503", MCP416x_503 }, - { "mcp4161-104", MCP416x_104 }, - { "mcp4162-502", MCP416x_502 }, - { "mcp4162-103", MCP416x_103 }, - { "mcp4162-503", MCP416x_503 }, - { "mcp4162-104", MCP416x_104 }, - { "mcp4231-502", MCP423x_502 }, - { "mcp4231-103", MCP423x_103 }, - { "mcp4231-503", MCP423x_503 }, - { "mcp4231-104", MCP423x_104 }, - { "mcp4232-502", MCP423x_502 }, - { "mcp4232-103", MCP423x_103 }, - { "mcp4232-503", MCP423x_503 }, - { "mcp4232-104", MCP423x_104 }, - { "mcp4241-502", MCP424x_502 }, - { "mcp4241-103", MCP424x_103 }, - { "mcp4241-503", MCP424x_503 }, - { "mcp4241-104", MCP424x_104 }, - { "mcp4242-502", MCP424x_502 }, - { "mcp4242-103", MCP424x_103 }, - { "mcp4242-503", MCP424x_503 }, - { "mcp4242-104", MCP424x_104 }, - { "mcp4251-502", MCP425x_502 }, - { "mcp4251-103", MCP425x_103 }, - { "mcp4251-503", MCP425x_503 }, - { "mcp4251-104", MCP425x_104 }, - { "mcp4252-502", MCP425x_502 }, - { "mcp4252-103", MCP425x_103 }, - { "mcp4252-503", MCP425x_503 }, - { "mcp4252-104", MCP425x_104 }, - { "mcp4261-502", MCP426x_502 }, - { "mcp4261-103", MCP426x_103 }, - { "mcp4261-503", MCP426x_503 }, - { "mcp4261-104", MCP426x_104 }, - { "mcp4262-502", MCP426x_502 }, - { "mcp4262-103", MCP426x_103 }, - { "mcp4262-503", MCP426x_503 }, - { "mcp4262-104", MCP426x_104 }, + { .name = "mcp4131-502", .driver_data = MCP413x_502 }, + { .name = "mcp4131-103", .driver_data = MCP413x_103 }, + { .name = "mcp4131-503", .driver_data = MCP413x_503 }, + { .name = "mcp4131-104", .driver_data = MCP413x_104 }, + { .name = "mcp4132-502", .driver_data = MCP413x_502 }, + { .name = "mcp4132-103", .driver_data = MCP413x_103 }, + { .name = "mcp4132-503", .driver_data = MCP413x_503 }, + { .name = "mcp4132-104", .driver_data = MCP413x_104 }, + { .name = "mcp4141-502", .driver_data = MCP414x_502 }, + { .name = "mcp4141-103", .driver_data = MCP414x_103 }, + { .name = "mcp4141-503", .driver_data = MCP414x_503 }, + { .name = "mcp4141-104", .driver_data = MCP414x_104 }, + { .name = "mcp4142-502", .driver_data = MCP414x_502 }, + { .name = "mcp4142-103", .driver_data = MCP414x_103 }, + { .name = "mcp4142-503", .driver_data = MCP414x_503 }, + { .name = "mcp4142-104", .driver_data = MCP414x_104 }, + { .name = "mcp4151-502", .driver_data = MCP415x_502 }, + { .name = "mcp4151-103", .driver_data = MCP415x_103 }, + { .name = "mcp4151-503", .driver_data = MCP415x_503 }, + { .name = "mcp4151-104", .driver_data = MCP415x_104 }, + { .name = "mcp4152-502", .driver_data = MCP415x_502 }, + { .name = "mcp4152-103", .driver_data = MCP415x_103 }, + { .name = "mcp4152-503", .driver_data = MCP415x_503 }, + { .name = "mcp4152-104", .driver_data = MCP415x_104 }, + { .name = "mcp4161-502", .driver_data = MCP416x_502 }, + { .name = "mcp4161-103", .driver_data = MCP416x_103 }, + { .name = "mcp4161-503", .driver_data = MCP416x_503 }, + { .name = "mcp4161-104", .driver_data = MCP416x_104 }, + { .name = "mcp4162-502", .driver_data = MCP416x_502 }, + { .name = "mcp4162-103", .driver_data = MCP416x_103 }, + { .name = "mcp4162-503", .driver_data = MCP416x_503 }, + { .name = "mcp4162-104", .driver_data = MCP416x_104 }, + { .name = "mcp4231-502", .driver_data = MCP423x_502 }, + { .name = "mcp4231-103", .driver_data = MCP423x_103 }, + { .name = "mcp4231-503", .driver_data = MCP423x_503 }, + { .name = "mcp4231-104", .driver_data = MCP423x_104 }, + { .name = "mcp4232-502", .driver_data = MCP423x_502 }, + { .name = "mcp4232-103", .driver_data = MCP423x_103 }, + { .name = "mcp4232-503", .driver_data = MCP423x_503 }, + { .name = "mcp4232-104", .driver_data = MCP423x_104 }, + { .name = "mcp4241-502", .driver_data = MCP424x_502 }, + { .name = "mcp4241-103", .driver_data = MCP424x_103 }, + { .name = "mcp4241-503", .driver_data = MCP424x_503 }, + { .name = "mcp4241-104", .driver_data = MCP424x_104 }, + { .name = "mcp4242-502", .driver_data = MCP424x_502 }, + { .name = "mcp4242-103", .driver_data = MCP424x_103 }, + { .name = "mcp4242-503", .driver_data = MCP424x_503 }, + { .name = "mcp4242-104", .driver_data = MCP424x_104 }, + { .name = "mcp4251-502", .driver_data = MCP425x_502 }, + { .name = "mcp4251-103", .driver_data = MCP425x_103 }, + { .name = "mcp4251-503", .driver_data = MCP425x_503 }, + { .name = "mcp4251-104", .driver_data = MCP425x_104 }, + { .name = "mcp4252-502", .driver_data = MCP425x_502 }, + { .name = "mcp4252-103", .driver_data = MCP425x_103 }, + { .name = "mcp4252-503", .driver_data = MCP425x_503 }, + { .name = "mcp4252-104", .driver_data = MCP425x_104 }, + { .name = "mcp4261-502", .driver_data = MCP426x_502 }, + { .name = "mcp4261-103", .driver_data = MCP426x_103 }, + { .name = "mcp4261-503", .driver_data = MCP426x_503 }, + { .name = "mcp4261-104", .driver_data = MCP426x_104 }, + { .name = "mcp4262-502", .driver_data = MCP426x_502 }, + { .name = "mcp4262-103", .driver_data = MCP426x_103 }, + { .name = "mcp4262-503", .driver_data = MCP426x_503 }, + { .name = "mcp4262-104", .driver_data = MCP426x_104 }, { } }; MODULE_DEVICE_TABLE(spi, mcp4131_id); diff --git a/drivers/iio/potentiometer/x9250.c b/drivers/iio/potentiometer/x9250.c index 735348492699..974e4447fc2c 100644 --- a/drivers/iio/potentiometer/x9250.c +++ b/drivers/iio/potentiometer/x9250.c @@ -198,8 +198,8 @@ static const struct of_device_id x9250_of_match[] = { MODULE_DEVICE_TABLE(of, x9250_of_match); static const struct spi_device_id x9250_id_table[] = { - { "x9250t", (kernel_ulong_t)&x9250_cfg[X9250T] }, - { "x9250u", (kernel_ulong_t)&x9250_cfg[X9250U] }, + { .name = "x9250t", .driver_data = (kernel_ulong_t)&x9250_cfg[X9250T] }, + { .name = "x9250u", .driver_data = (kernel_ulong_t)&x9250_cfg[X9250U] }, { } }; MODULE_DEVICE_TABLE(spi, x9250_id_table); diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c index 1984d990438c..00cb3fea97ca 100644 --- a/drivers/iio/potentiostat/lmp91000.c +++ b/drivers/iio/potentiostat/lmp91000.c @@ -422,3 +422,4 @@ module_i2c_driver(lmp91000_driver); MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>"); MODULE_DESCRIPTION("LMP91000 digital potentiostat"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/iio/pressure/abp2030pa_spi.c b/drivers/iio/pressure/abp2030pa_spi.c index 8bc59eb499aa..60d078574827 100644 --- a/drivers/iio/pressure/abp2030pa_spi.c +++ b/drivers/iio/pressure/abp2030pa_spi.c @@ -45,7 +45,7 @@ static const struct of_device_id abp2_spi_match[] = { MODULE_DEVICE_TABLE(of, abp2_spi_match); static const struct spi_device_id abp2_spi_id[] = { - { "abp2030pa" }, + { .name = "abp2030pa" }, { } }; MODULE_DEVICE_TABLE(spi, abp2_spi_id); diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 990340a9b10c..c89153dcc323 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -750,7 +750,10 @@ static int bmp280_read_raw(struct iio_dev *indio_dev, struct bmp280_data *data = iio_priv(indio_dev); int ret; - pm_runtime_get_sync(data->dev); + ret = pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; + ret = bmp280_read_raw_impl(indio_dev, chan, val, val2, mask); pm_runtime_put_autosuspend(data->dev); @@ -924,7 +927,10 @@ static int bmp280_write_raw(struct iio_dev *indio_dev, struct bmp280_data *data = iio_priv(indio_dev); int ret; - pm_runtime_get_sync(data->dev); + ret = pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; + ret = bmp280_write_raw_impl(indio_dev, chan, val, val2, mask); pm_runtime_put_autosuspend(data->dev); @@ -2254,7 +2260,10 @@ static int bmp580_nvmem_read(void *priv, unsigned int offset, void *val, struct bmp280_data *data = priv; int ret; - pm_runtime_get_sync(data->dev); + ret = pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; + ret = bmp580_nvmem_read_impl(priv, offset, val, bytes); pm_runtime_put_autosuspend(data->dev); @@ -2328,7 +2337,10 @@ static int bmp580_nvmem_write(void *priv, unsigned int offset, void *val, struct bmp280_data *data = priv; int ret; - pm_runtime_get_sync(data->dev); + ret = pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; + ret = bmp580_nvmem_write_impl(priv, offset, val, bytes); pm_runtime_put_autosuspend(data->dev); @@ -3108,11 +3120,17 @@ EXPORT_SYMBOL_NS(bmp085_chip_info, "IIO_BMP280"); static int bmp280_buffer_preenable(struct iio_dev *indio_dev) { struct bmp280_data *data = iio_priv(indio_dev); + int ret; - pm_runtime_get_sync(data->dev); - data->chip_info->set_mode(data, BMP280_NORMAL); + ret = pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; - return 0; + ret = data->chip_info->set_mode(data, BMP280_NORMAL); + if (ret) + pm_runtime_put_autosuspend(data->dev); + + return ret; } static int bmp280_buffer_postdisable(struct iio_dev *indio_dev) diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c index 04bf2f5be5b1..a02a621b8015 100644 --- a/drivers/iio/pressure/bmp280-spi.c +++ b/drivers/iio/pressure/bmp280-spi.c @@ -118,13 +118,13 @@ static const struct of_device_id bmp280_of_spi_match[] = { MODULE_DEVICE_TABLE(of, bmp280_of_spi_match); static const struct spi_device_id bmp280_spi_id[] = { - { "bmp085", (kernel_ulong_t)&bmp085_chip_info }, - { "bmp180", (kernel_ulong_t)&bmp180_chip_info }, - { "bmp181", (kernel_ulong_t)&bmp180_chip_info }, - { "bmp280", (kernel_ulong_t)&bmp280_chip_info }, - { "bme280", (kernel_ulong_t)&bme280_chip_info }, - { "bmp380", (kernel_ulong_t)&bmp380_chip_info }, - { "bmp580", (kernel_ulong_t)&bmp580_chip_info }, + { .name = "bmp085", .driver_data = (kernel_ulong_t)&bmp085_chip_info }, + { .name = "bmp180", .driver_data = (kernel_ulong_t)&bmp180_chip_info }, + { .name = "bmp181", .driver_data = (kernel_ulong_t)&bmp180_chip_info }, + { .name = "bmp280", .driver_data = (kernel_ulong_t)&bmp280_chip_info }, + { .name = "bme280", .driver_data = (kernel_ulong_t)&bme280_chip_info }, + { .name = "bmp380", .driver_data = (kernel_ulong_t)&bmp380_chip_info }, + { .name = "bmp580", .driver_data = (kernel_ulong_t)&bmp580_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, bmp280_spi_id); diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c index ae499d197555..e688b0776547 100644 --- a/drivers/iio/pressure/hid-sensor-press.c +++ b/drivers/iio/pressure/hid-sensor-press.c @@ -55,9 +55,8 @@ static const struct iio_chan_spec press_channels[] = { /* Channel read_raw handler */ static int press_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, - long mask) + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct press_state *press_state = iio_priv(indio_dev); int report_id = -1; @@ -81,7 +80,7 @@ static int press_read_raw(struct iio_dev *indio_dev, } if (report_id >= 0) { hid_sensor_power_state(&press_state->common_attributes, - true); + true); *val = sensor_hub_input_attr_get_raw_value( press_state->common_attributes.hsdev, HID_USAGE_SENSOR_PRESSURE, address, @@ -89,7 +88,7 @@ static int press_read_raw(struct iio_dev *indio_dev, SENSOR_HUB_SYNC, min < 0); hid_sensor_power_state(&press_state->common_attributes, - false); + false); } else { *val = 0; return -EINVAL; @@ -123,10 +122,8 @@ static int press_read_raw(struct iio_dev *indio_dev, /* Channel write_raw handler */ static int press_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct press_state *press_state = iio_priv(indio_dev); int ret = 0; @@ -154,8 +151,7 @@ static const struct iio_info press_info = { /* Callback handler to send event after all samples are received and captured */ static int press_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - void *priv) + u32 usage_id, void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct press_state *press_state = iio_priv(indio_dev); @@ -175,7 +171,7 @@ static int press_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int press_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, + u32 usage_id, size_t raw_len, char *raw_data, void *priv) { @@ -201,10 +197,10 @@ static int press_capture_sample(struct hid_sensor_hub_device *hsdev, /* Parse report which is specific to an usage id*/ static int press_parse_report(struct platform_device *pdev, - struct hid_sensor_hub_device *hsdev, - struct iio_chan_spec *channels, - unsigned usage_id, - struct press_state *st) + struct hid_sensor_hub_device *hsdev, + struct iio_chan_spec *channels, + u32 usage_id, + struct press_state *st) { int ret; @@ -221,7 +217,7 @@ static int press_parse_report(struct platform_device *pdev, }; dev_dbg(&pdev->dev, "press %x:%x\n", st->press_attr.index, - st->press_attr.report_id); + st->press_attr.report_id); st->scale_precision = hid_sensor_format_scale( HID_USAGE_SENSOR_PRESSURE, @@ -240,8 +236,7 @@ static int hid_press_probe(struct platform_device *pdev) struct iio_dev *indio_dev; struct press_state *press_state; - indio_dev = devm_iio_device_alloc(&pdev->dev, - sizeof(struct press_state)); + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct press_state)); if (!indio_dev) return -ENOMEM; platform_set_drvdata(pdev, indio_dev); @@ -284,32 +279,32 @@ static int hid_press_probe(struct platform_device *pdev) atomic_set(&press_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, - &press_state->common_attributes); + &press_state->common_attributes); if (ret) { dev_err(&pdev->dev, "trigger setup failed\n"); return ret; } - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(&pdev->dev, "device register failed\n"); - goto error_remove_trigger; - } - press_state->callbacks.send_event = press_proc_event; press_state->callbacks.capture_sample = press_capture_sample; press_state->callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_PRESSURE, - &press_state->callbacks); + &press_state->callbacks); if (ret < 0) { dev_err(&pdev->dev, "callback reg failed\n"); - goto error_iio_unreg; + goto error_remove_trigger; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "device register failed\n"); + goto error_remove_callback; } return ret; -error_iio_unreg: - iio_device_unregister(indio_dev); +error_remove_callback: + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes); return ret; @@ -322,8 +317,8 @@ static void hid_press_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct press_state *press_state = iio_priv(indio_dev); - sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE); iio_device_unregister(indio_dev); + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE); hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes); } diff --git a/drivers/iio/pressure/hsc030pa_spi.c b/drivers/iio/pressure/hsc030pa_spi.c index be58e550cc12..02021b6f799a 100644 --- a/drivers/iio/pressure/hsc030pa_spi.c +++ b/drivers/iio/pressure/hsc030pa_spi.c @@ -39,7 +39,7 @@ static const struct of_device_id hsc_spi_match[] = { MODULE_DEVICE_TABLE(of, hsc_spi_match); static const struct spi_device_id hsc_spi_id[] = { - { "hsc030pa" }, + { .name = "hsc030pa" }, { } }; MODULE_DEVICE_TABLE(spi, hsc_spi_id); diff --git a/drivers/iio/pressure/mpl115.c b/drivers/iio/pressure/mpl115.c index 16e112b796ba..2929ea8e4e01 100644 --- a/drivers/iio/pressure/mpl115.c +++ b/drivers/iio/pressure/mpl115.c @@ -203,9 +203,9 @@ int mpl115_probe(struct device *dev, const char *name, if (data->shutdown) { /* Enable runtime PM */ - pm_runtime_get_noresume(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); + ret = pm_runtime_set_active(dev); + if (ret) + return ret; /* * As the device takes 3 ms to come up with a fresh @@ -215,7 +215,10 @@ int mpl115_probe(struct device *dev, const char *name, */ pm_runtime_set_autosuspend_delay(dev, 2000); pm_runtime_use_autosuspend(dev); - pm_runtime_put(dev); + + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; dev_dbg(dev, "low-power mode enabled"); } else diff --git a/drivers/iio/pressure/mpl115_spi.c b/drivers/iio/pressure/mpl115_spi.c index 4e1d24beff94..3cff616e8d2f 100644 --- a/drivers/iio/pressure/mpl115_spi.c +++ b/drivers/iio/pressure/mpl115_spi.c @@ -84,7 +84,7 @@ static int mpl115_spi_probe(struct spi_device *spi) } static const struct spi_device_id mpl115_spi_ids[] = { - { "mpl115", 0 }, + { .name = "mpl115" }, { } }; MODULE_DEVICE_TABLE(spi, mpl115_spi_ids); diff --git a/drivers/iio/pressure/mprls0025pa_spi.c b/drivers/iio/pressure/mprls0025pa_spi.c index 23f47c04ed45..6270370383c3 100644 --- a/drivers/iio/pressure/mprls0025pa_spi.c +++ b/drivers/iio/pressure/mprls0025pa_spi.c @@ -59,7 +59,7 @@ static const struct of_device_id mpr_spi_match[] = { MODULE_DEVICE_TABLE(of, mpr_spi_match); static const struct spi_device_id mpr_spi_id[] = { - { "mprls0025pa" }, + { .name = "mprls0025pa" }, { } }; MODULE_DEVICE_TABLE(spi, mpr_spi_id); diff --git a/drivers/iio/pressure/ms5611_spi.c b/drivers/iio/pressure/ms5611_spi.c index c41aaa6244cd..7133e6744e3f 100644 --- a/drivers/iio/pressure/ms5611_spi.c +++ b/drivers/iio/pressure/ms5611_spi.c @@ -113,8 +113,8 @@ static const struct of_device_id ms5611_spi_matches[] = { MODULE_DEVICE_TABLE(of, ms5611_spi_matches); static const struct spi_device_id ms5611_id[] = { - { "ms5611", MS5611 }, - { "ms5607", MS5607 }, + { .name = "ms5611", .driver_data = MS5611 }, + { .name = "ms5607", .driver_data = MS5607 }, { } }; MODULE_DEVICE_TABLE(spi, ms5611_id); diff --git a/drivers/iio/pressure/rohm-bm1390.c b/drivers/iio/pressure/rohm-bm1390.c index b3be9de03678..9d72ae64126c 100644 --- a/drivers/iio/pressure/rohm-bm1390.c +++ b/drivers/iio/pressure/rohm-bm1390.c @@ -621,17 +621,15 @@ static const struct iio_buffer_setup_ops bm1390_buffer_ops = { .predisable = bm1390_buffer_predisable, }; -static irqreturn_t bm1390_trigger_handler(int irq, void *p) +static bool bm1390_handle_trigger(struct iio_dev *idev) { - struct iio_poll_func *pf = p; - struct iio_dev *idev = pf->indio_dev; struct bm1390_data *data = iio_priv(idev); int ret, status; /* DRDY is acked by reading status reg */ ret = regmap_read(data->regmap, BM1390_REG_STATUS, &status); if (ret || !status) - return IRQ_NONE; + return false; dev_dbg(data->dev, "DRDY trig status 0x%x\n", status); @@ -639,7 +637,7 @@ static irqreturn_t bm1390_trigger_handler(int irq, void *p) ret = bm1390_pressure_read(data, &data->buf.pressure); if (ret) { dev_warn(data->dev, "sample read failed %d\n", ret); - return IRQ_NONE; + return false; } } @@ -648,15 +646,26 @@ static irqreturn_t bm1390_trigger_handler(int irq, void *p) &data->buf.temp, sizeof(data->buf.temp)); if (ret) { dev_warn(data->dev, "temp read failed %d\n", ret); - return IRQ_HANDLED; + return true; } } iio_push_to_buffers_with_ts(idev, &data->buf, sizeof(data->buf), data->timestamp); + + return true; +} + +static irqreturn_t bm1390_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *idev = pf->indio_dev; + bool result; + + result = bm1390_handle_trigger(idev); iio_trigger_notify_done(idev->trig); - return IRQ_HANDLED; + return IRQ_RETVAL(result); } /* Get timestamps and wake the thread if we need to read data */ diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c index d843186b44af..8add0c392c6a 100644 --- a/drivers/iio/pressure/st_pressure_spi.c +++ b/drivers/iio/pressure/st_pressure_spi.c @@ -93,18 +93,18 @@ static int st_press_spi_probe(struct spi_device *spi) } static const struct spi_device_id st_press_id_table[] = { - { LPS001WP_PRESS_DEV_NAME }, - { LPS25H_PRESS_DEV_NAME }, - { LPS331AP_PRESS_DEV_NAME }, - { LPS22HB_PRESS_DEV_NAME }, - { LPS33HW_PRESS_DEV_NAME }, - { LPS35HW_PRESS_DEV_NAME }, - { LPS22HH_PRESS_DEV_NAME }, - { LPS22DF_PRESS_DEV_NAME }, - { "lps001wp-press" }, - { "lps25h-press", }, - { "lps331ap-press" }, - { "lps22hb-press" }, + { .name = LPS001WP_PRESS_DEV_NAME }, + { .name = LPS25H_PRESS_DEV_NAME }, + { .name = LPS331AP_PRESS_DEV_NAME }, + { .name = LPS22HB_PRESS_DEV_NAME }, + { .name = LPS33HW_PRESS_DEV_NAME }, + { .name = LPS35HW_PRESS_DEV_NAME }, + { .name = LPS22HH_PRESS_DEV_NAME }, + { .name = LPS22DF_PRESS_DEV_NAME }, + { .name = "lps001wp-press" }, + { .name = "lps25h-press" }, + { .name = "lps331ap-press" }, + { .name = "lps22hb-press" }, { } }; MODULE_DEVICE_TABLE(spi, st_press_id_table); diff --git a/drivers/iio/pressure/zpa2326_spi.c b/drivers/iio/pressure/zpa2326_spi.c index 73e37a77c933..dfbb74a58dc0 100644 --- a/drivers/iio/pressure/zpa2326_spi.c +++ b/drivers/iio/pressure/zpa2326_spi.c @@ -60,7 +60,7 @@ static void zpa2326_remove_spi(struct spi_device *spi) } static const struct spi_device_id zpa2326_spi_ids[] = { - { "zpa2326", 0 }, + { .name = "zpa2326" }, { } }; MODULE_DEVICE_TABLE(spi, zpa2326_spi_ids); diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index 3406232822cb..93833037bc94 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -448,7 +448,7 @@ static const struct of_device_id as3935_of_match[] = { MODULE_DEVICE_TABLE(of, as3935_of_match); static const struct spi_device_id as3935_id[] = { - {"as3935", 0}, + { .name = "as3935" }, { } }; MODULE_DEVICE_TABLE(spi, as3935_id); diff --git a/drivers/iio/proximity/vl53l1x-i2c.c b/drivers/iio/proximity/vl53l1x-i2c.c index dc4ffbc95d1f..bce238d1b6de 100644 --- a/drivers/iio/proximity/vl53l1x-i2c.c +++ b/drivers/iio/proximity/vl53l1x-i2c.c @@ -2,7 +2,7 @@ /* * Support for ST VL53L1X FlightSense ToF Ranging Sensor on a i2c bus. * - * Copyright (C) 2026 Siratul Islam <email@sirat.me> + * Copyright (C) 2026 Siratul Islam <siratul.islam@linux.dev> * * Datasheet available at * <https://www.st.com/resource/en/datasheet/vl53l1x.pdf> @@ -42,6 +42,7 @@ #define VL53L1X_REG_SOFT_RESET 0x0000 #define VL53L1X_REG_VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND 0x0008 #define VL53L1X_REG_VHV_CONFIG__INIT 0x000B +#define VL53L1X_REG_DEFAULT_CONFIG 0x002D #define VL53L1X_REG_GPIO_HV_MUX__CTRL 0x0030 #define VL53L1X_REG_GPIO__TIO_HV_STATUS 0x0031 #define VL53L1X_REG_SYSTEM__INTERRUPT_CONFIG_GPIO 0x0046 @@ -63,7 +64,6 @@ #define VL53L1X_REG_RESULT__OSC_CALIBRATE_VAL 0x00DE #define VL53L1X_REG_FIRMWARE__SYSTEM_STATUS 0x00E5 #define VL53L1X_REG_IDENTIFICATION__MODEL_ID 0x010F -#define VL53L1X_REG_DEFAULT_CONFIG 0x002D #define VL53L1X_MODEL_ID_VAL 0xEACC @@ -81,6 +81,9 @@ #define VL53L1X_OSC_CALIBRATE_MASK GENMASK(9, 0) +#define VL53L1X_FIRMWARE__SYSTEM_STATUS_BOOTED BIT(0) +#define VL53L1X_GPIO__TIO_HV_STATUS_DATA_READY BIT(0) + /* Inter-measurement period uses PLL divider with 1.075 oscillator correction */ static const struct u32_fract vl53l1x_osc_correction = { .numerator = 1075, @@ -190,6 +193,17 @@ static int vl53l1x_stop_ranging(struct vl53l1x_data *data) VL53L1X_MODE_START_STOP); } +static int vl53l1x_wait_data_ready(struct vl53l1x_data *data) +{ + unsigned int val; + + /* 1ms poll, 1s timeout covers max timing budgets (per ST Ultra Lite Driver) */ + return regmap_read_poll_timeout(data->regmap, + VL53L1X_REG_GPIO__TIO_HV_STATUS, val, + (val & VL53L1X_GPIO__TIO_HV_STATUS_DATA_READY) != data->gpio_polarity, + 1 * USEC_PER_MSEC, 1 * USEC_PER_SEC); +} + /* * Default configuration blob from ST's VL53L1X Ultra Lite Driver * (STSW-IMG009). @@ -229,10 +243,9 @@ static int vl53l1x_chip_init(struct vl53l1x_data *data) } ret = regmap_read_poll_timeout(data->regmap, - VL53L1X_REG_FIRMWARE__SYSTEM_STATUS, val, - val & BIT(0), - 1 * USEC_PER_MSEC, - 100 * USEC_PER_MSEC); + VL53L1X_REG_FIRMWARE__SYSTEM_STATUS, + val, val & VL53L1X_FIRMWARE__SYSTEM_STATUS_BOOTED, + 1 * USEC_PER_MSEC, 100 * USEC_PER_MSEC); if (ret) return dev_err_probe(dev, ret, "firmware boot timeout\n"); @@ -260,12 +273,7 @@ static int vl53l1x_chip_init(struct vl53l1x_data *data) if (ret) return ret; - /* 1ms poll, 1s timeout covers max timing budgets (per ST Ultra Lite Driver) */ - ret = regmap_read_poll_timeout(data->regmap, - VL53L1X_REG_GPIO__TIO_HV_STATUS, val, - (val & 1) != data->gpio_polarity, - 1 * USEC_PER_MSEC, - 1000 * USEC_PER_MSEC); + ret = vl53l1x_wait_data_ready(data); if (ret) return ret; @@ -460,14 +468,7 @@ static int vl53l1x_read_proximity(struct vl53l1x_data *data, int *val) if (!wait_for_completion_timeout(&data->completion, HZ)) return -ETIMEDOUT; } else { - unsigned int rdy; - - /* 1ms poll, 1s timeout covers max timing budgets (per ST Ultra Lite Driver) */ - ret = regmap_read_poll_timeout(data->regmap, - VL53L1X_REG_GPIO__TIO_HV_STATUS, rdy, - (rdy & 1) != data->gpio_polarity, - 1 * USEC_PER_MSEC, - 1000 * USEC_PER_MSEC); + ret = vl53l1x_wait_data_ready(data); if (ret) return ret; } @@ -750,6 +751,6 @@ static struct i2c_driver vl53l1x_driver = { }; module_i2c_driver(vl53l1x_driver); -MODULE_AUTHOR("Siratul Islam <email@sirat.me>"); +MODULE_AUTHOR("Siratul Islam <siratul.islam@linux.dev>"); MODULE_DESCRIPTION("ST VL53L1X ToF ranging sensor driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/iio/resolver/ad2s1200.c b/drivers/iio/resolver/ad2s1200.c index 55bcbbd4021a..27ecc434eee9 100644 --- a/drivers/iio/resolver/ad2s1200.c +++ b/drivers/iio/resolver/ad2s1200.c @@ -143,18 +143,14 @@ static int ad2s1200_probe(struct spi_device *spi) st->sdev = spi; st->sample = devm_gpiod_get(&spi->dev, "adi,sample", GPIOD_OUT_LOW); - if (IS_ERR(st->sample)) { - dev_err(&spi->dev, "Failed to claim SAMPLE gpio: err=%ld\n", - PTR_ERR(st->sample)); - return PTR_ERR(st->sample); - } + if (IS_ERR(st->sample)) + return dev_err_probe(&spi->dev, PTR_ERR(st->sample), + "Failed to claim SAMPLE gpio\n"); st->rdvel = devm_gpiod_get(&spi->dev, "adi,rdvel", GPIOD_OUT_LOW); - if (IS_ERR(st->rdvel)) { - dev_err(&spi->dev, "Failed to claim RDVEL gpio: err=%ld\n", - PTR_ERR(st->rdvel)); - return PTR_ERR(st->rdvel); - } + if (IS_ERR(st->rdvel)) + return dev_err_probe(&spi->dev, PTR_ERR(st->rdvel), + "Failed to claim RDVEL gpio\n"); indio_dev->info = &ad2s1200_info; indio_dev->modes = INDIO_DIRECT_MODE; @@ -182,8 +178,8 @@ static const struct of_device_id ad2s1200_of_match[] = { MODULE_DEVICE_TABLE(of, ad2s1200_of_match); static const struct spi_device_id ad2s1200_id[] = { - { "ad2s1200" }, - { "ad2s1205" }, + { .name = "ad2s1200" }, + { .name = "ad2s1205" }, { } }; MODULE_DEVICE_TABLE(spi, ad2s1200_id); diff --git a/drivers/iio/resolver/ad2s1210.c b/drivers/iio/resolver/ad2s1210.c index 1be19fe8aa3f..3b5ec21e3446 100644 --- a/drivers/iio/resolver/ad2s1210.c +++ b/drivers/iio/resolver/ad2s1210.c @@ -1276,10 +1276,8 @@ static int ad2s1210_debugfs_reg_access(struct iio_dev *indio_dev, return regmap_write(st->regmap, reg, writeval); } -static irqreturn_t ad2s1210_trigger_handler(int irq, void *p) +static void ad2s1210_scan_to_buffers(struct iio_dev *indio_dev, s64 timestamp) { - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; struct ad2s1210_state *st = iio_priv(indio_dev); size_t chan = 0; int ret; @@ -1295,15 +1293,15 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p) AD2S1210_REG_POSITION_MSB, &st->sample.raw, 2); if (ret < 0) - goto error_ret; + return; } else { ret = ad2s1210_set_mode(st, MOD_POS); if (ret < 0) - goto error_ret; + return; ret = spi_read(st->sdev, &st->sample, 3); if (ret < 0) - goto error_ret; + return; } memcpy(&st->scan.chan[chan++], &st->sample.raw, 2); @@ -1315,15 +1313,15 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p) AD2S1210_REG_VELOCITY_MSB, &st->sample.raw, 2); if (ret < 0) - goto error_ret; + return; } else { ret = ad2s1210_set_mode(st, MOD_VEL); if (ret < 0) - goto error_ret; + return; ret = spi_read(st->sdev, &st->sample, 3); if (ret < 0) - goto error_ret; + return; } memcpy(&st->scan.chan[chan++], &st->sample.raw, 2); @@ -1334,16 +1332,22 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p) ret = regmap_read(st->regmap, AD2S1210_REG_FAULT, ®_val); if (ret < 0) - goto error_ret; + return; st->sample.fault = reg_val; } - ad2s1210_push_events(indio_dev, st->sample.fault, pf->timestamp); + ad2s1210_push_events(indio_dev, st->sample.fault, timestamp); iio_push_to_buffers_with_ts(indio_dev, &st->scan, sizeof(st->scan), - pf->timestamp); + timestamp); +} + +static irqreturn_t ad2s1210_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; -error_ret: + ad2s1210_scan_to_buffers(indio_dev, pf->timestamp); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; @@ -1597,7 +1601,7 @@ static const struct of_device_id ad2s1210_of_match[] = { MODULE_DEVICE_TABLE(of, ad2s1210_of_match); static const struct spi_device_id ad2s1210_id[] = { - { "ad2s1210" }, + { .name = "ad2s1210" }, { } }; MODULE_DEVICE_TABLE(spi, ad2s1210_id); diff --git a/drivers/iio/resolver/ad2s90.c b/drivers/iio/resolver/ad2s90.c index 18f1c905eeac..b7a2dcc42871 100644 --- a/drivers/iio/resolver/ad2s90.c +++ b/drivers/iio/resolver/ad2s90.c @@ -110,7 +110,7 @@ static const struct of_device_id ad2s90_of_match[] = { MODULE_DEVICE_TABLE(of, ad2s90_of_match); static const struct spi_device_id ad2s90_id[] = { - { "ad2s90" }, + { .name = "ad2s90" }, { } }; MODULE_DEVICE_TABLE(spi, ad2s90_id); diff --git a/drivers/iio/temperature/hid-sensor-temperature.c b/drivers/iio/temperature/hid-sensor-temperature.c index 58d4c0273932..5e3262e461f4 100644 --- a/drivers/iio/temperature/hid-sensor-temperature.c +++ b/drivers/iio/temperature/hid-sensor-temperature.c @@ -44,7 +44,7 @@ static const struct iio_chan_spec temperature_channels[] = { /* Adjust channel real bits based on report descriptor */ static void temperature_adjust_channel_bit_mask(struct iio_chan_spec *channels, - int channel, int size) + int channel, int size) { channels[channel].scan_type.sign = 's'; /* Real storage bits will change based on the report desc. */ @@ -100,8 +100,8 @@ static int temperature_read_raw(struct iio_dev *indio_dev, } static int temperature_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct temperature_state *temp_st = iio_priv(indio_dev); @@ -124,7 +124,7 @@ static const struct iio_info temperature_info = { /* Callback handler to send event after all samples are received and captured */ static int temperature_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned int usage_id, void *pdev) + u32 usage_id, void *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct temperature_state *temp_st = iio_priv(indio_dev); @@ -139,8 +139,9 @@ static int temperature_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int temperature_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned int usage_id, size_t raw_len, - char *raw_data, void *pdev) + u32 usage_id, + size_t raw_len, char *raw_data, + void *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct temperature_state *temp_st = iio_priv(indio_dev); @@ -156,10 +157,10 @@ static int temperature_capture_sample(struct hid_sensor_hub_device *hsdev, /* Parse report which is specific to an usage id*/ static int temperature_parse_report(struct platform_device *pdev, - struct hid_sensor_hub_device *hsdev, - struct iio_chan_spec *channels, - unsigned int usage_id, - struct temperature_state *st) + struct hid_sensor_hub_device *hsdev, + struct iio_chan_spec *channels, + u32 usage_id, + struct temperature_state *st) { int ret; @@ -170,8 +171,7 @@ static int temperature_parse_report(struct platform_device *pdev, if (ret < 0) return ret; - temperature_adjust_channel_bit_mask(channels, 0, - st->temperature_attr.size); + temperature_adjust_channel_bit_mask(channels, 0, st->temperature_attr.size); st->scale_precision = hid_sensor_format_scale( HID_USAGE_SENSOR_TEMPERATURE, @@ -212,13 +212,13 @@ static int hid_temperature_probe(struct platform_device *pdev) if (ret) return ret; - temp_chans = devm_kmemdup(&indio_dev->dev, temperature_channels, - sizeof(temperature_channels), GFP_KERNEL); + temp_chans = devm_kmemdup(&pdev->dev, temperature_channels, + sizeof(temperature_channels), GFP_KERNEL); if (!temp_chans) return -ENOMEM; ret = temperature_parse_report(pdev, hsdev, temp_chans, - HID_USAGE_SENSOR_TEMPERATURE, temp_st); + HID_USAGE_SENSOR_TEMPERATURE, temp_st); if (ret) return ret; @@ -231,7 +231,7 @@ static int hid_temperature_probe(struct platform_device *pdev) atomic_set(&temp_st->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, - &temp_st->common_attributes); + &temp_st->common_attributes); if (ret) return ret; @@ -239,7 +239,7 @@ static int hid_temperature_probe(struct platform_device *pdev) temperature_callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_TEMPERATURE, - &temperature_callbacks); + &temperature_callbacks); if (ret) goto error_remove_trigger; diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c index f8c4917bb118..a9d38ed45da6 100644 --- a/drivers/iio/temperature/ltc2983.c +++ b/drivers/iio/temperature/ltc2983.c @@ -2070,11 +2070,11 @@ static const struct ltc2983_chip_info ltm2985_chip_info_data = { }; static const struct spi_device_id ltc2983_id_table[] = { - { "adt7604", (kernel_ulong_t)&adt7604_chip_info_data }, - { "ltc2983", (kernel_ulong_t)<c2983_chip_info_data }, - { "ltc2984", (kernel_ulong_t)<c2984_chip_info_data }, - { "ltc2986", (kernel_ulong_t)<c2986_chip_info_data }, - { "ltm2985", (kernel_ulong_t)<m2985_chip_info_data }, + { .name = "adt7604", .driver_data = (kernel_ulong_t)&adt7604_chip_info_data }, + { .name = "ltc2983", .driver_data = (kernel_ulong_t)<c2983_chip_info_data }, + { .name = "ltc2984", .driver_data = (kernel_ulong_t)<c2984_chip_info_data }, + { .name = "ltc2986", .driver_data = (kernel_ulong_t)<c2986_chip_info_data }, + { .name = "ltm2985", .driver_data = (kernel_ulong_t)<m2985_chip_info_data }, { } }; MODULE_DEVICE_TABLE(spi, ltc2983_id_table); diff --git a/drivers/iio/temperature/max31856.c b/drivers/iio/temperature/max31856.c index 13405f3ba829..061f6fe6de5e 100644 --- a/drivers/iio/temperature/max31856.c +++ b/drivers/iio/temperature/max31856.c @@ -461,7 +461,7 @@ static int max31856_probe(struct spi_device *spi) } static const struct spi_device_id max31856_id[] = { - { "max31856", 0 }, + { .name = "max31856" }, { } }; MODULE_DEVICE_TABLE(spi, max31856_id); diff --git a/drivers/iio/temperature/max31865.c b/drivers/iio/temperature/max31865.c index 82cf06c4d272..f9c93f95d80b 100644 --- a/drivers/iio/temperature/max31865.c +++ b/drivers/iio/temperature/max31865.c @@ -324,7 +324,7 @@ static int max31865_probe(struct spi_device *spi) } static const struct spi_device_id max31865_id[] = { - { "max31865", 0 }, + { .name = "max31865" }, { } }; MODULE_DEVICE_TABLE(spi, max31865_id); diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c index 015afeab1914..5f216e238d55 100644 --- a/drivers/iio/temperature/maxim_thermocouple.c +++ b/drivers/iio/temperature/maxim_thermocouple.c @@ -262,15 +262,15 @@ static int maxim_thermocouple_probe(struct spi_device *spi) } static const struct spi_device_id maxim_thermocouple_id[] = { - {"max6675", MAX6675}, - {"max31855", MAX31855}, - {"max31855k", MAX31855K}, - {"max31855j", MAX31855J}, - {"max31855n", MAX31855N}, - {"max31855s", MAX31855S}, - {"max31855t", MAX31855T}, - {"max31855e", MAX31855E}, - {"max31855r", MAX31855R}, + { .name = "max6675", .driver_data = MAX6675 }, + { .name = "max31855", .driver_data = MAX31855 }, + { .name = "max31855k", .driver_data = MAX31855K }, + { .name = "max31855j", .driver_data = MAX31855J }, + { .name = "max31855n", .driver_data = MAX31855N }, + { .name = "max31855s", .driver_data = MAX31855S }, + { .name = "max31855t", .driver_data = MAX31855T }, + { .name = "max31855e", .driver_data = MAX31855E }, + { .name = "max31855r", .driver_data = MAX31855R }, { } }; MODULE_DEVICE_TABLE(spi, maxim_thermocouple_id); diff --git a/drivers/iio/temperature/tmp117.c b/drivers/iio/temperature/tmp117.c index 6bc18616ad15..74cb8d62bef3 100644 --- a/drivers/iio/temperature/tmp117.c +++ b/drivers/iio/temperature/tmp117.c @@ -9,6 +9,7 @@ * Note: This driver assumes that the sensor has been calibrated beforehand. */ +#include <linux/array_size.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/i2c.h> @@ -38,6 +39,7 @@ #define TMP116_DEVICE_ID 0x1116 #define TMP117_DEVICE_ID 0x0117 +#define TMP119_DEVICE_ID 0x2117 struct tmp117_data { struct i2c_client *client; @@ -139,6 +141,12 @@ static const struct tmp11x_info tmp117_channels_info = { .num_channels = ARRAY_SIZE(tmp117_channels) }; +static const struct tmp11x_info tmp119_channels_info = { + .name = "tmp119", + .channels = tmp117_channels, + .num_channels = ARRAY_SIZE(tmp117_channels) +}; + static const struct iio_info tmp117_info = { .read_raw = tmp117_read_raw, .write_raw = tmp117_write_raw, @@ -172,6 +180,9 @@ static int tmp117_probe(struct i2c_client *client) case TMP117_DEVICE_ID: match_data = &tmp117_channels_info; break; + case TMP119_DEVICE_ID: + match_data = &tmp119_channels_info; + break; default: dev_info(&client->dev, "Unknown device id (0x%x), use fallback compatible\n", @@ -204,6 +215,7 @@ static int tmp117_probe(struct i2c_client *client) static const struct of_device_id tmp117_of_match[] = { { .compatible = "ti,tmp116", .data = &tmp116_channels_info }, { .compatible = "ti,tmp117", .data = &tmp117_channels_info }, + { .compatible = "ti,tmp119", .data = &tmp119_channels_info }, { } }; MODULE_DEVICE_TABLE(of, tmp117_of_match); @@ -211,6 +223,7 @@ MODULE_DEVICE_TABLE(of, tmp117_of_match); static const struct i2c_device_id tmp117_id[] = { { .name = "tmp116", .driver_data = (kernel_ulong_t)&tmp116_channels_info }, { .name = "tmp117", .driver_data = (kernel_ulong_t)&tmp117_channels_info }, + { .name = "tmp119", .driver_data = (kernel_ulong_t)&tmp119_channels_info }, { } }; MODULE_DEVICE_TABLE(i2c, tmp117_id); diff --git a/drivers/iio/test/iio-test-format.c b/drivers/iio/test/iio-test-format.c index 872dd8582003..e5d0a2ac4670 100644 --- a/drivers/iio/test/iio-test-format.c +++ b/drivers/iio/test/iio-test-format.c @@ -200,56 +200,108 @@ static void iio_test_iio_format_value_multiple(struct kunit *test) static void iio_test_iio_format_value_integer_64(struct kunit *test) { int values[2]; - s64 value; char *buf; int ret; buf = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); - value = 24; - values[0] = lower_32_bits(value); - values[1] = upper_32_bits(value); + iio_val_s64_decompose(24, &values[0], &values[1]); ret = iio_format_value(buf, IIO_VAL_INT_64, ARRAY_SIZE(values), values); IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "24\n"); - value = -24; - values[0] = lower_32_bits(value); - values[1] = upper_32_bits(value); + iio_val_s64_decompose(-24, &values[0], &values[1]); ret = iio_format_value(buf, IIO_VAL_INT_64, ARRAY_SIZE(values), values); IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-24\n"); - value = 0; - values[0] = lower_32_bits(value); - values[1] = upper_32_bits(value); + iio_val_s64_decompose(0, &values[0], &values[1]); ret = iio_format_value(buf, IIO_VAL_INT_64, ARRAY_SIZE(values), values); IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0\n"); - value = UINT_MAX; - values[0] = lower_32_bits(value); - values[1] = upper_32_bits(value); + iio_val_s64_decompose(UINT_MAX, &values[0], &values[1]); ret = iio_format_value(buf, IIO_VAL_INT_64, ARRAY_SIZE(values), values); IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "4294967295\n"); - value = -((s64)UINT_MAX); - values[0] = lower_32_bits(value); - values[1] = upper_32_bits(value); + iio_val_s64_decompose(-((s64)UINT_MAX), &values[0], &values[1]); ret = iio_format_value(buf, IIO_VAL_INT_64, ARRAY_SIZE(values), values); IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-4294967295\n"); - value = LLONG_MAX; - values[0] = lower_32_bits(value); - values[1] = upper_32_bits(value); + iio_val_s64_decompose(LLONG_MAX, &values[0], &values[1]); ret = iio_format_value(buf, IIO_VAL_INT_64, ARRAY_SIZE(values), values); IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "9223372036854775807\n"); - value = LLONG_MIN; - values[0] = lower_32_bits(value); - values[1] = upper_32_bits(value); + iio_val_s64_decompose(LLONG_MIN, &values[0], &values[1]); ret = iio_format_value(buf, IIO_VAL_INT_64, ARRAY_SIZE(values), values); IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-9223372036854775808\n"); } +static void iio_test_iio_format_value_decimal_64(struct kunit *test) +{ + int values[2]; + char *buf; + int ret; + + buf = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); + + /* DECIMAL64_MILLI: positive >= 1, value 1.234 */ + iio_val_s64_decompose(1234, &values[0], &values[1]); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MILLI, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "1.234\n"); + + /* DECIMAL64_MICRO: positive >= 1, value 3.141592 */ + iio_val_s64_decompose(3141592, &values[0], &values[1]); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MICRO, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "3.141592\n"); + + /* DECIMAL64_MILLI: positive < 1, value 0.042 */ + iio_val_s64_decompose(42, &values[0], &values[1]); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MILLI, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0.042\n"); + + /* DECIMAL64_MILLI: negative <= -1, value -1.234 */ + iio_val_s64_decompose(-1234, &values[0], &values[1]); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MILLI, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-1.234\n"); + + /* DECIMAL64_MILLI: negative > -1, value -0.123 */ + iio_val_s64_decompose(-123, &values[0], &values[1]); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MILLI, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-0.123\n"); + + /* DECIMAL64_MILLI: zero */ + iio_val_s64_decompose(0, &values[0], &values[1]); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MILLI, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0.000\n"); + + /* DECIMAL64_NANO: value 1.000000001 */ + iio_val_s64_decompose(1000000001, &values[0], &values[1]); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_NANO, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "1.000000001\n"); + + /* DECIMAL64_MICRO: large value using upper 32 bits */ + iio_val_s64_decompose(5000000000000042LL, &values[0], &values[1]); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MICRO, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "5000000000.000042\n"); + + /* limits */ + iio_val_s64_decompose(LLONG_MAX, &values[0], &values[1]); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_PICO, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "9223372.036854775807\n"); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_NANO, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "9223372036.854775807\n"); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MICRO, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "9223372036854.775807\n"); + + iio_val_s64_decompose(LLONG_MIN, &values[0], &values[1]); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_PICO, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-9223372.036854775808\n"); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_NANO, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-9223372036.854775808\n"); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MICRO, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-9223372036854.775808\n"); +} + static struct kunit_case iio_format_test_cases[] = { KUNIT_CASE(iio_test_iio_format_value_integer), KUNIT_CASE(iio_test_iio_format_value_fixedpoint), @@ -257,6 +309,7 @@ static struct kunit_case iio_format_test_cases[] = { KUNIT_CASE(iio_test_iio_format_value_fractional_log2), KUNIT_CASE(iio_test_iio_format_value_multiple), KUNIT_CASE(iio_test_iio_format_value_integer_64), + KUNIT_CASE(iio_test_iio_format_value_decimal_64), { } }; diff --git a/drivers/iio/test/iio-test-rescale.c b/drivers/iio/test/iio-test-rescale.c index ac6942cf1e44..bcd4a607be19 100644 --- a/drivers/iio/test/iio-test-rescale.c +++ b/drivers/iio/test/iio-test-rescale.c @@ -575,7 +575,7 @@ static const struct rescale_tc_data offset_cases[] = { static void case_to_desc(const struct rescale_tc_data *t, char *desc) { - strcpy(desc, t->name); + strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); } KUNIT_ARRAY_PARAM(iio_rescale_scale, scale_cases, case_to_desc); diff --git a/drivers/input/joystick/adc-joystick.c b/drivers/input/joystick/adc-joystick.c index ff44f9978b71..4fa42f88bcfa 100644 --- a/drivers/input/joystick/adc-joystick.c +++ b/drivers/input/joystick/adc-joystick.c @@ -329,3 +329,4 @@ module_platform_driver(adc_joystick_driver); MODULE_DESCRIPTION("Input driver for joysticks connected over ADC"); MODULE_AUTHOR("Artur Rojek <contact@artur-rojek.eu>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/input/keyboard/adc-keys.c b/drivers/input/keyboard/adc-keys.c index f1753207429d..d687459a0c80 100644 --- a/drivers/input/keyboard/adc-keys.c +++ b/drivers/input/keyboard/adc-keys.c @@ -202,3 +202,4 @@ module_platform_driver(adc_keys_driver); MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>"); MODULE_DESCRIPTION("Input driver for resistor ladder connected on ADC"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/input/touchscreen/colibri-vf50-ts.c b/drivers/input/touchscreen/colibri-vf50-ts.c index 98d5b2ba63fb..89c4d7b2b89e 100644 --- a/drivers/input/touchscreen/colibri-vf50-ts.c +++ b/drivers/input/touchscreen/colibri-vf50-ts.c @@ -372,3 +372,4 @@ module_platform_driver(vf50_touch_driver); MODULE_AUTHOR("Sanchayan Maity"); MODULE_DESCRIPTION("Colibri VF50 Touchscreen driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/input/touchscreen/resistive-adc-touch.c b/drivers/input/touchscreen/resistive-adc-touch.c index 68f7e2e28f37..c89edc1280fe 100644 --- a/drivers/input/touchscreen/resistive-adc-touch.c +++ b/drivers/input/touchscreen/resistive-adc-touch.c @@ -300,3 +300,4 @@ module_platform_driver(grts_driver); MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>"); MODULE_DESCRIPTION("Generic ADC Resistive Touch Driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c index 7cb020dd3423..9591672b0511 100644 --- a/drivers/phy/motorola/phy-cpcap-usb.c +++ b/drivers/phy/motorola/phy-cpcap-usb.c @@ -717,3 +717,4 @@ MODULE_ALIAS("platform:cpcap_usb"); MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>"); MODULE_DESCRIPTION("CPCAP usb phy driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c index 032140bd6682..90a61d9db72c 100644 --- a/drivers/power/supply/ab8500_btemp.c +++ b/drivers/power/supply/ab8500_btemp.c @@ -826,3 +826,4 @@ MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Johan Palsson, Karl Komierowski, Arun R Murthy"); MODULE_ALIAS("platform:ab8500-btemp"); MODULE_DESCRIPTION("AB8500 battery temperature driver"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index bc6c070a564d..ff38254d06ef 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -3748,3 +3748,4 @@ MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Johan Palsson, Karl Komierowski, Arun R Murthy"); MODULE_ALIAS("platform:ab8500-charger"); MODULE_DESCRIPTION("AB8500 charger management driver"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index f8f392592193..d50ed216c7f4 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -3250,3 +3250,4 @@ MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Johan Palsson, Karl Komierowski"); MODULE_ALIAS("platform:ab8500-fg"); MODULE_DESCRIPTION("AB8500 Fuel Gauge driver"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/axp20x_ac_power.c b/drivers/power/supply/axp20x_ac_power.c index 474661ba7cf2..d9892b351621 100644 --- a/drivers/power/supply/axp20x_ac_power.c +++ b/drivers/power/supply/axp20x_ac_power.c @@ -418,3 +418,4 @@ module_platform_driver(axp20x_ac_power_driver); MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>"); MODULE_DESCRIPTION("AXP20X and AXP22X PMICs' AC power supply driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/axp20x_battery.c b/drivers/power/supply/axp20x_battery.c index 50ca8e110085..ee8701a6e907 100644 --- a/drivers/power/supply/axp20x_battery.c +++ b/drivers/power/supply/axp20x_battery.c @@ -1155,3 +1155,4 @@ module_platform_driver(axp20x_batt_driver); MODULE_DESCRIPTION("Battery power supply driver for AXP20X and AXP22X PMICs"); MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c index 29f105f9212d..e951b2b64b25 100644 --- a/drivers/power/supply/axp20x_usb_power.c +++ b/drivers/power/supply/axp20x_usb_power.c @@ -1077,3 +1077,4 @@ module_platform_driver(axp20x_usb_power_driver); MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); MODULE_DESCRIPTION("AXP20x PMIC USB power supply status driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/axp288_fuel_gauge.c b/drivers/power/supply/axp288_fuel_gauge.c index aa04c54ff97e..68dabaf7a4f8 100644 --- a/drivers/power/supply/axp288_fuel_gauge.c +++ b/drivers/power/supply/axp288_fuel_gauge.c @@ -817,3 +817,4 @@ MODULE_AUTHOR("Ramakrishna Pallala <ramakrishna.pallala@intel.com>"); MODULE_AUTHOR("Todd Brandt <todd.e.brandt@linux.intel.com>"); MODULE_DESCRIPTION("Xpower AXP288 Fuel Gauge Driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c index 1d2b8bb08564..808714c6ce95 100644 --- a/drivers/power/supply/cpcap-battery.c +++ b/drivers/power/supply/cpcap-battery.c @@ -1202,3 +1202,4 @@ module_platform_driver(cpcap_battery_driver); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>"); MODULE_DESCRIPTION("CPCAP PMIC Battery Driver"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/cpcap-charger.c b/drivers/power/supply/cpcap-charger.c index 76e2d2e3f5f5..34a57dd5c3cf 100644 --- a/drivers/power/supply/cpcap-charger.c +++ b/drivers/power/supply/cpcap-charger.c @@ -973,3 +973,4 @@ MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>"); MODULE_DESCRIPTION("CPCAP Battery Charger Interface driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:cpcap-charger"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/da9150-charger.c b/drivers/power/supply/da9150-charger.c index 27f36ef5b88d..58449df6068c 100644 --- a/drivers/power/supply/da9150-charger.c +++ b/drivers/power/supply/da9150-charger.c @@ -644,3 +644,4 @@ module_platform_driver(da9150_charger_driver); MODULE_DESCRIPTION("Charger Driver for DA9150"); MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/generic-adc-battery.c b/drivers/power/supply/generic-adc-battery.c index 6913179ebb84..185f55d2fd70 100644 --- a/drivers/power/supply/generic-adc-battery.c +++ b/drivers/power/supply/generic-adc-battery.c @@ -298,3 +298,4 @@ module_platform_driver(gab_driver); MODULE_AUTHOR("anish kumar <yesanishhere@gmail.com>"); MODULE_DESCRIPTION("generic battery driver using IIO"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/ingenic-battery.c b/drivers/power/supply/ingenic-battery.c index b111c7ce2be3..5be269f17bff 100644 --- a/drivers/power/supply/ingenic-battery.c +++ b/drivers/power/supply/ingenic-battery.c @@ -190,3 +190,4 @@ module_platform_driver(ingenic_battery_driver); MODULE_DESCRIPTION("Battery driver for Ingenic JZ47xx SoCs"); MODULE_AUTHOR("Artur Rojek <contact@artur-rojek.eu>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/intel_dc_ti_battery.c b/drivers/power/supply/intel_dc_ti_battery.c index 67a75281b0ac..cb6fa8d88b43 100644 --- a/drivers/power/supply/intel_dc_ti_battery.c +++ b/drivers/power/supply/intel_dc_ti_battery.c @@ -389,3 +389,4 @@ MODULE_ALIAS("platform:" DEV_NAME); MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>"); MODULE_DESCRIPTION("Intel Dollar Cove (TI) battery driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/lego_ev3_battery.c b/drivers/power/supply/lego_ev3_battery.c index 582644f4e8b3..1e53f11a8e2b 100644 --- a/drivers/power/supply/lego_ev3_battery.c +++ b/drivers/power/supply/lego_ev3_battery.c @@ -230,3 +230,4 @@ module_platform_driver(lego_ev3_battery_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Lechner <david@lechnology.com>"); MODULE_DESCRIPTION("LEGO MINDSTORMS EV3 Battery Driver"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/lp8788-charger.c b/drivers/power/supply/lp8788-charger.c index f0a680c155c4..8c6ec98362d0 100644 --- a/drivers/power/supply/lp8788-charger.c +++ b/drivers/power/supply/lp8788-charger.c @@ -727,3 +727,4 @@ MODULE_DESCRIPTION("TI LP8788 Charger Driver"); MODULE_AUTHOR("Milo Kim"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:lp8788-charger"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c index 03ac569e185c..7bfd50fb6836 100644 --- a/drivers/power/supply/max17040_battery.c +++ b/drivers/power/supply/max17040_battery.c @@ -643,3 +643,4 @@ module_i2c_driver(max17040_i2c_driver); MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>"); MODULE_DESCRIPTION("MAX17040 Fuel Gauge"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/mp2629_charger.c b/drivers/power/supply/mp2629_charger.c index 04294359ed7d..0aace0040259 100644 --- a/drivers/power/supply/mp2629_charger.c +++ b/drivers/power/supply/mp2629_charger.c @@ -657,3 +657,4 @@ module_platform_driver(mp2629_charger_driver); MODULE_AUTHOR("Saravanan Sekar <sravanhome@gmail.com>"); MODULE_DESCRIPTION("MP2629 Charger driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/mt6370-charger.c b/drivers/power/supply/mt6370-charger.c index 9d388bc53098..29ce34fd3804 100644 --- a/drivers/power/supply/mt6370-charger.c +++ b/drivers/power/supply/mt6370-charger.c @@ -928,3 +928,4 @@ module_platform_driver(mt6370_chg_driver); MODULE_AUTHOR("ChiaEn Wu <chiaen_wu@richtek.com>"); MODULE_DESCRIPTION("MediaTek MT6370 Charger Driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/qcom_smbx.c b/drivers/power/supply/qcom_smbx.c index 7bda5cd77a75..67fdb4335338 100644 --- a/drivers/power/supply/qcom_smbx.c +++ b/drivers/power/supply/qcom_smbx.c @@ -1056,3 +1056,4 @@ module_platform_driver(qcom_spmi_smb); MODULE_AUTHOR("Casey Connolly <casey.connolly@linaro.org>"); MODULE_DESCRIPTION("Qualcomm SMB2 Charger Driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/rn5t618_power.c b/drivers/power/supply/rn5t618_power.c index 5963a55341ee..84b9d6248489 100644 --- a/drivers/power/supply/rn5t618_power.c +++ b/drivers/power/supply/rn5t618_power.c @@ -818,3 +818,4 @@ module_platform_driver(rn5t618_power_driver); MODULE_ALIAS("platform:rn5t618-power"); MODULE_DESCRIPTION("Power supply driver for RICOH RN5T618"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/rx51_battery.c b/drivers/power/supply/rx51_battery.c index b0220ec2d926..57266921dc8e 100644 --- a/drivers/power/supply/rx51_battery.c +++ b/drivers/power/supply/rx51_battery.c @@ -246,3 +246,4 @@ MODULE_ALIAS("platform:rx51-battery"); MODULE_AUTHOR("Pali Rohár <pali@kernel.org>"); MODULE_DESCRIPTION("Nokia RX-51 battery driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c index 9af0017fa88e..0999fc5bc662 100644 --- a/drivers/power/supply/sc27xx_fuel_gauge.c +++ b/drivers/power/supply/sc27xx_fuel_gauge.c @@ -1346,3 +1346,4 @@ module_platform_driver(sc27xx_fgu_driver); MODULE_DESCRIPTION("Spreadtrum SC27XX PMICs Fual Gauge Unit Driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/twl4030_charger.c b/drivers/power/supply/twl4030_charger.c index c46b22ab8d99..e6c9b2b1ffce 100644 --- a/drivers/power/supply/twl4030_charger.c +++ b/drivers/power/supply/twl4030_charger.c @@ -1146,3 +1146,4 @@ MODULE_AUTHOR("Gražvydas Ignotas"); MODULE_DESCRIPTION("TWL4030 Battery Charger Interface driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:twl4030_bci"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/twl4030_madc_battery.c b/drivers/power/supply/twl4030_madc_battery.c index a99b3ff26929..5e04b4f0a135 100644 --- a/drivers/power/supply/twl4030_madc_battery.c +++ b/drivers/power/supply/twl4030_madc_battery.c @@ -235,3 +235,4 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Lukas Märdian <lukas@goldelico.com>"); MODULE_DESCRIPTION("twl4030_madc battery driver"); MODULE_ALIAS("platform:twl4030_madc_battery"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/power/supply/twl6030_charger.c b/drivers/power/supply/twl6030_charger.c index 020512d0e306..e8ef221fa0f3 100644 --- a/drivers/power/supply/twl6030_charger.c +++ b/drivers/power/supply/twl6030_charger.c @@ -577,3 +577,4 @@ module_platform_driver(twl6030_charger_driver); MODULE_DESCRIPTION("TWL6030 Battery Charger Interface driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c index 0e32a2295990..30644d2d7c54 100644 --- a/drivers/staging/iio/adc/ad7816.c +++ b/drivers/staging/iio/adc/ad7816.c @@ -426,9 +426,9 @@ static const struct of_device_id ad7816_of_match[] = { MODULE_DEVICE_TABLE(of, ad7816_of_match); static const struct spi_device_id ad7816_id[] = { - { "ad7816", ID_AD7816 }, - { "ad7817", ID_AD7817 }, - { "ad7818", ID_AD7818 }, + { .name = "ad7816", .driver_data = ID_AD7816 }, + { .name = "ad7817", .driver_data = ID_AD7817 }, + { .name = "ad7818", .driver_data = ID_AD7818 }, { } }; diff --git a/drivers/staging/iio/addac/adt7316-spi.c b/drivers/staging/iio/addac/adt7316-spi.c index 1debcc36c1af..459dd7416b1d 100644 --- a/drivers/staging/iio/addac/adt7316-spi.c +++ b/drivers/staging/iio/addac/adt7316-spi.c @@ -126,15 +126,14 @@ static int adt7316_spi_probe(struct spi_device *spi_dev) } static const struct spi_device_id adt7316_spi_id[] = { - { "adt7316", 0 }, - { "adt7317", 0 }, - { "adt7318", 0 }, - { "adt7516", 0 }, - { "adt7517", 0 }, - { "adt7519", 0 }, + { .name = "adt7316" }, + { .name = "adt7317" }, + { .name = "adt7318" }, + { .name = "adt7516" }, + { .name = "adt7517" }, + { .name = "adt7519" }, { } }; - MODULE_DEVICE_TABLE(spi, adt7316_spi_id); static const struct of_device_id adt7316_of_spi_match[] = { diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index 59fb3bd26bc1..20f6052cc7fb 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -1814,11 +1814,8 @@ static int adt7316_setup_irq(struct iio_dev *indio_dev) NULL, adt7316_event_handler, irq_type | IRQF_ONESHOT, indio_dev->name, indio_dev); - if (ret) { - dev_err(&indio_dev->dev, "failed to request irq %d\n", - chip->bus.irq); + if (ret) return ret; - } if (irq_type & IRQF_TRIGGER_HIGH) chip->config1 |= ADT7316_INT_POLARITY; diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c index 60c33e10c46f..a78249812b26 100644 --- a/drivers/staging/iio/frequency/ad9832.c +++ b/drivers/staging/iio/frequency/ad9832.c @@ -252,22 +252,22 @@ error_ret: * see dds.h for further information */ -static IIO_DEV_ATTR_FREQ(0, 0, 0200, NULL, ad9832_write, AD9832_FREQ0HM); -static IIO_DEV_ATTR_FREQ(0, 1, 0200, NULL, ad9832_write, AD9832_FREQ1HM); -static IIO_DEV_ATTR_FREQSYMBOL(0, 0200, NULL, ad9832_write, AD9832_FREQ_SYM); +static IIO_DEV_ATTR_FREQ(0200, 0, 0, NULL, ad9832_write, AD9832_FREQ0HM); +static IIO_DEV_ATTR_FREQ(0200, 0, 1, NULL, ad9832_write, AD9832_FREQ1HM); +static IIO_DEV_ATTR_FREQSYMBOL(0200, 0, NULL, ad9832_write, AD9832_FREQ_SYM); static IIO_CONST_ATTR_FREQ_SCALE(0, "1"); /* 1Hz */ -static IIO_DEV_ATTR_PHASE(0, 0, 0200, NULL, ad9832_write, AD9832_PHASE0H); -static IIO_DEV_ATTR_PHASE(0, 1, 0200, NULL, ad9832_write, AD9832_PHASE1H); -static IIO_DEV_ATTR_PHASE(0, 2, 0200, NULL, ad9832_write, AD9832_PHASE2H); -static IIO_DEV_ATTR_PHASE(0, 3, 0200, NULL, ad9832_write, AD9832_PHASE3H); -static IIO_DEV_ATTR_PHASESYMBOL(0, 0200, NULL, +static IIO_DEV_ATTR_PHASE(0200, 0, 0, NULL, ad9832_write, AD9832_PHASE0H); +static IIO_DEV_ATTR_PHASE(0200, 0, 1, NULL, ad9832_write, AD9832_PHASE1H); +static IIO_DEV_ATTR_PHASE(0200, 0, 2, NULL, ad9832_write, AD9832_PHASE2H); +static IIO_DEV_ATTR_PHASE(0200, 0, 3, NULL, ad9832_write, AD9832_PHASE3H); +static IIO_DEV_ATTR_PHASESYMBOL(0200, 0, NULL, ad9832_write, AD9832_PHASE_SYM); static IIO_CONST_ATTR_PHASE_SCALE(0, "0.0015339808"); /* 2PI/2^12 rad*/ -static IIO_DEV_ATTR_PINCONTROL_EN(0, 0200, NULL, +static IIO_DEV_ATTR_PINCONTROL_EN(0200, 0, NULL, ad9832_write, AD9832_PINCTRL_EN); -static IIO_DEV_ATTR_OUT_ENABLE(0, 0200, NULL, +static IIO_DEV_ATTR_OUT_ENABLE(0200, 0, NULL, ad9832_write, AD9832_OUTPUT_EN); static struct attribute *ad9832_attributes[] = { @@ -380,8 +380,8 @@ static const struct of_device_id ad9832_of_match[] = { MODULE_DEVICE_TABLE(of, ad9832_of_match); static const struct spi_device_id ad9832_id[] = { - {"ad9832", 0}, - {"ad9835", 0}, + { .name = "ad9832" }, + { .name = "ad9835" }, { } }; MODULE_DEVICE_TABLE(spi, ad9832_id); diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index 33dfd723923c..0d20f796e0f0 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -314,21 +314,21 @@ static IIO_DEVICE_ATTR(out_altvoltage0_out1_wavetype_available, 0444, * see dds.h for further information */ -static IIO_DEV_ATTR_FREQ(0, 0, 0200, NULL, ad9834_write, AD9834_REG_FREQ0); -static IIO_DEV_ATTR_FREQ(0, 1, 0200, NULL, ad9834_write, AD9834_REG_FREQ1); -static IIO_DEV_ATTR_FREQSYMBOL(0, 0200, NULL, ad9834_write, AD9834_FSEL); +static IIO_DEV_ATTR_FREQ(0200, 0, 0, NULL, ad9834_write, AD9834_REG_FREQ0); +static IIO_DEV_ATTR_FREQ(0200, 0, 1, NULL, ad9834_write, AD9834_REG_FREQ1); +static IIO_DEV_ATTR_FREQSYMBOL(0200, 0, NULL, ad9834_write, AD9834_FSEL); static IIO_CONST_ATTR_FREQ_SCALE(0, "1"); /* 1Hz */ -static IIO_DEV_ATTR_PHASE(0, 0, 0200, NULL, ad9834_write, AD9834_REG_PHASE0); -static IIO_DEV_ATTR_PHASE(0, 1, 0200, NULL, ad9834_write, AD9834_REG_PHASE1); -static IIO_DEV_ATTR_PHASESYMBOL(0, 0200, NULL, ad9834_write, AD9834_PSEL); +static IIO_DEV_ATTR_PHASE(0200, 0, 0, NULL, ad9834_write, AD9834_REG_PHASE0); +static IIO_DEV_ATTR_PHASE(0200, 0, 1, NULL, ad9834_write, AD9834_REG_PHASE1); +static IIO_DEV_ATTR_PHASESYMBOL(0200, 0, NULL, ad9834_write, AD9834_PSEL); static IIO_CONST_ATTR_PHASE_SCALE(0, "0.0015339808"); /* 2PI/2^12 rad*/ -static IIO_DEV_ATTR_PINCONTROL_EN(0, 0200, NULL, ad9834_write, AD9834_PIN_SW); -static IIO_DEV_ATTR_OUT_ENABLE(0, 0200, NULL, ad9834_write, AD9834_RESET); -static IIO_DEV_ATTR_OUTY_ENABLE(0, 1, 0200, NULL, ad9834_write, AD9834_OPBITEN); -static IIO_DEV_ATTR_OUT_WAVETYPE(0, 0, ad9834_store_wavetype, 0); -static IIO_DEV_ATTR_OUT_WAVETYPE(0, 1, ad9834_store_wavetype, 1); +static IIO_DEV_ATTR_PINCONTROL_EN(0200, 0, NULL, ad9834_write, AD9834_PIN_SW); +static IIO_DEV_ATTR_OUT_ENABLE(0200, 0, NULL, ad9834_write, AD9834_RESET); +static IIO_DEV_ATTR_OUTY_ENABLE(0200, 0, 1, NULL, ad9834_write, AD9834_OPBITEN); +static IIO_DEV_ATTR_OUT_WAVETYPE(0200, 0, 0, ad9834_store_wavetype, 0); +static IIO_DEV_ATTR_OUT_WAVETYPE(0200, 0, 1, ad9834_store_wavetype, 1); static struct attribute *ad9834_attributes[] = { &iio_dev_attr_out_altvoltage0_frequency0.dev_attr.attr, @@ -464,10 +464,10 @@ static int ad9834_probe(struct spi_device *spi) } static const struct spi_device_id ad9834_id[] = { - {"ad9833", ID_AD9833}, - {"ad9834", ID_AD9834}, - {"ad9837", ID_AD9837}, - {"ad9838", ID_AD9838}, + { .name = "ad9833", .driver_data = ID_AD9833 }, + { .name = "ad9834", .driver_data = ID_AD9834 }, + { .name = "ad9837", .driver_data = ID_AD9837 }, + { .name = "ad9838", .driver_data = ID_AD9838 }, { } }; MODULE_DEVICE_TABLE(spi, ad9834_id); diff --git a/drivers/staging/iio/frequency/dds.h b/drivers/staging/iio/frequency/dds.h index 2ebe68eb7398..d5f0139b79f0 100644 --- a/drivers/staging/iio/frequency/dds.h +++ b/drivers/staging/iio/frequency/dds.h @@ -7,102 +7,102 @@ #ifndef IIO_DDS_H_ #define IIO_DDS_H_ -/** +/* * /sys/bus/iio/devices/.../out_altvoltageX_frequencyY */ -#define IIO_DEV_ATTR_FREQ(_channel, _num, _mode, _show, _store, _addr) \ +#define IIO_DEV_ATTR_FREQ(_mode, _channel, _num, _show, _store, _addr) \ IIO_DEVICE_ATTR(out_altvoltage##_channel##_frequency##_num, \ _mode, _show, _store, _addr) -/** +/* * /sys/bus/iio/devices/.../out_altvoltageX_frequencyY_scale */ #define IIO_CONST_ATTR_FREQ_SCALE(_channel, _string) \ IIO_CONST_ATTR(out_altvoltage##_channel##_frequency_scale, _string) -/** +/* * /sys/bus/iio/devices/.../out_altvoltageX_frequencysymbol */ -#define IIO_DEV_ATTR_FREQSYMBOL(_channel, _mode, _show, _store, _addr) \ +#define IIO_DEV_ATTR_FREQSYMBOL(_mode, _channel, _show, _store, _addr) \ IIO_DEVICE_ATTR(out_altvoltage##_channel##_frequencysymbol, \ _mode, _show, _store, _addr) -/** +/* * /sys/bus/iio/devices/.../out_altvoltageX_phaseY */ -#define IIO_DEV_ATTR_PHASE(_channel, _num, _mode, _show, _store, _addr) \ +#define IIO_DEV_ATTR_PHASE(_mode, _channel, _num, _show, _store, _addr) \ IIO_DEVICE_ATTR(out_altvoltage##_channel##_phase##_num, \ _mode, _show, _store, _addr) -/** +/* * /sys/bus/iio/devices/.../out_altvoltageX_phaseY_scale */ #define IIO_CONST_ATTR_PHASE_SCALE(_channel, _string) \ IIO_CONST_ATTR(out_altvoltage##_channel##_phase_scale, _string) -/** +/* * /sys/bus/iio/devices/.../out_altvoltageX_phasesymbol */ -#define IIO_DEV_ATTR_PHASESYMBOL(_channel, _mode, _show, _store, _addr) \ +#define IIO_DEV_ATTR_PHASESYMBOL(_mode, _channel, _show, _store, _addr) \ IIO_DEVICE_ATTR(out_altvoltage##_channel##_phasesymbol, \ _mode, _show, _store, _addr) -/** +/* * /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_en */ -#define IIO_DEV_ATTR_PINCONTROL_EN(_channel, _mode, _show, _store, _addr)\ +#define IIO_DEV_ATTR_PINCONTROL_EN(_mode, _channel, _show, _store, _addr)\ IIO_DEVICE_ATTR(out_altvoltage##_channel##_pincontrol_en, \ _mode, _show, _store, _addr) -/** +/* * /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_frequency_en */ -#define IIO_DEV_ATTR_PINCONTROL_FREQ_EN(_channel, _mode, _show, _store, _addr)\ +#define IIO_DEV_ATTR_PINCONTROL_FREQ_EN(_mode, _channel, _show, _store, _addr)\ IIO_DEVICE_ATTR(out_altvoltage##_channel##_pincontrol_frequency_en,\ _mode, _show, _store, _addr) -/** +/* * /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_phase_en */ -#define IIO_DEV_ATTR_PINCONTROL_PHASE_EN(_channel, _mode, _show, _store, _addr)\ +#define IIO_DEV_ATTR_PINCONTROL_PHASE_EN(_mode, _channel, _show, _store, _addr)\ IIO_DEVICE_ATTR(out_altvoltage##_channel##_pincontrol_phase_en, \ _mode, _show, _store, _addr) -/** +/* * /sys/bus/iio/devices/.../out_altvoltageX_out_enable */ -#define IIO_DEV_ATTR_OUT_ENABLE(_channel, _mode, _show, _store, _addr) \ +#define IIO_DEV_ATTR_OUT_ENABLE(_mode, _channel, _show, _store, _addr) \ IIO_DEVICE_ATTR(out_altvoltage##_channel##_out_enable, \ _mode, _show, _store, _addr) -/** +/* * /sys/bus/iio/devices/.../out_altvoltageX_outY_enable */ -#define IIO_DEV_ATTR_OUTY_ENABLE(_channel, _output, \ - _mode, _show, _store, _addr) \ +#define IIO_DEV_ATTR_OUTY_ENABLE(_mode, _channel, _output, \ + _show, _store, _addr) \ IIO_DEVICE_ATTR(out_altvoltage##_channel##_out##_output##_enable,\ _mode, _show, _store, _addr) -/** +/* * /sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype */ -#define IIO_DEV_ATTR_OUT_WAVETYPE(_channel, _output, _store, _addr) \ +#define IIO_DEV_ATTR_OUT_WAVETYPE(_mode, _channel, _output, _store, _addr)\ IIO_DEVICE_ATTR(out_altvoltage##_channel##_out##_output##_wavetype,\ - 0200, NULL, _store, _addr) + _mode, NULL, _store, _addr) -/** +/* * /sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype_available */ diff --git a/drivers/thermal/qcom/qcom-spmi-adc-tm5.c b/drivers/thermal/qcom/qcom-spmi-adc-tm5.c index d7f2e6ca92c2..bb6222c8cc5f 100644 --- a/drivers/thermal/qcom/qcom-spmi-adc-tm5.c +++ b/drivers/thermal/qcom/qcom-spmi-adc-tm5.c @@ -1069,3 +1069,4 @@ module_platform_driver(adc_tm5_driver); MODULE_DESCRIPTION("SPMI PMIC Thermal Monitor ADC driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/thermal/qcom/qcom-spmi-temp-alarm.c b/drivers/thermal/qcom/qcom-spmi-temp-alarm.c index f39ca0ddd17b..fb003ca96454 100644 --- a/drivers/thermal/qcom/qcom-spmi-temp-alarm.c +++ b/drivers/thermal/qcom/qcom-spmi-temp-alarm.c @@ -904,3 +904,4 @@ module_platform_driver(qpnp_tm_driver); MODULE_ALIAS("platform:spmi-temp-alarm"); MODULE_DESCRIPTION("QPNP PMIC Temperature Alarm driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/thermal/renesas/rzg3s_thermal.c b/drivers/thermal/renesas/rzg3s_thermal.c index e25e36c99a88..7ced8f76a0ec 100644 --- a/drivers/thermal/renesas/rzg3s_thermal.c +++ b/drivers/thermal/renesas/rzg3s_thermal.c @@ -270,3 +270,4 @@ module_platform_driver(rzg3s_thermal_driver); MODULE_DESCRIPTION("Renesas RZ/G3S Thermal Sensor Unit Driver"); MODULE_AUTHOR("Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/thermal/thermal-generic-adc.c b/drivers/thermal/thermal-generic-adc.c index 7c844589b153..cfdb8e674dd2 100644 --- a/drivers/thermal/thermal-generic-adc.c +++ b/drivers/thermal/thermal-generic-adc.c @@ -228,3 +228,4 @@ module_platform_driver(gadc_thermal_driver); MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); MODULE_DESCRIPTION("Generic ADC thermal driver using IIO framework with DT"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/include/dt-bindings/iio/adc/mediatek,mt6323-auxadc.h b/include/dt-bindings/iio/adc/mediatek,mt6323-auxadc.h new file mode 100644 index 000000000000..6ee9a9ecffc1 --- /dev/null +++ b/include/dt-bindings/iio/adc/mediatek,mt6323-auxadc.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ + +#ifndef _DT_BINDINGS_MEDIATEK_MT6323_AUXADC_H +#define _DT_BINDINGS_MEDIATEK_MT6323_AUXADC_H + +#define MT6323_AUXADC_BATON2 0 +#define MT6323_AUXADC_CH6 1 +#define MT6323_AUXADC_BAT_TEMP 2 +#define MT6323_AUXADC_CHIP_TEMP 3 +#define MT6323_AUXADC_VCDT 4 +#define MT6323_AUXADC_BATON1 5 +#define MT6323_AUXADC_ISENSE 6 +#define MT6323_AUXADC_BATSNS 7 +#define MT6323_AUXADC_ACCDET 8 +#define MT6323_AUXADC_AUDIO0 9 +#define MT6323_AUXADC_AUDIO1 10 +#define MT6323_AUXADC_AUDIO2 11 +#define MT6323_AUXADC_AUDIO3 12 +#define MT6323_AUXADC_AUDIO4 13 +#define MT6323_AUXADC_AUDIO5 14 +#define MT6323_AUXADC_AUDIO6 15 +#define MT6323_AUXADC_AUDIO7 16 + +#endif diff --git a/include/linux/iio/common/inv_sensors_timestamp.h b/include/linux/iio/common/inv_sensors_timestamp.h index 8d506f1e9df2..4f08204ede3b 100644 --- a/include/linux/iio/common/inv_sensors_timestamp.h +++ b/include/linux/iio/common/inv_sensors_timestamp.h @@ -13,9 +13,9 @@ * @init_period: chip initial period at reset in ns */ struct inv_sensors_timestamp_chip { - uint32_t clock_period; - uint32_t jitter; - uint32_t init_period; + u32 clock_period; + u32 jitter; + u32 init_period; }; /** @@ -24,8 +24,8 @@ struct inv_sensors_timestamp_chip { * @up: interval upper bound */ struct inv_sensors_timestamp_interval { - int64_t lo; - int64_t up; + s64 lo; + s64 up; }; /** @@ -35,9 +35,9 @@ struct inv_sensors_timestamp_interval { * @values: table of all measured values, use for computing the mean */ struct inv_sensors_timestamp_acc { - uint32_t val; + u32 val; size_t idx; - uint32_t values[32]; + u32 values[32]; }; /** @@ -46,6 +46,8 @@ struct inv_sensors_timestamp_acc { * @min_period: minimal acceptable clock period * @max_period: maximal acceptable clock period * @it: interrupts interval timestamps + * @delta: interval timestamps between several interrupts + * @delta_counter: number of data samples in the delta interval * @timestamp: store last timestamp for computing next data timestamp * @mult: current internal period multiplier * @new_mult: new set internal period multiplier (not yet effective) @@ -54,13 +56,15 @@ struct inv_sensors_timestamp_acc { */ struct inv_sensors_timestamp { struct inv_sensors_timestamp_chip chip; - uint32_t min_period; - uint32_t max_period; + u32 min_period; + u32 max_period; struct inv_sensors_timestamp_interval it; - int64_t timestamp; - uint32_t mult; - uint32_t new_mult; - uint32_t period; + struct inv_sensors_timestamp_interval delta; + u32 delta_counter; + s64 timestamp; + u32 mult; + u32 new_mult; + u32 period; struct inv_sensors_timestamp_acc chip_period; }; @@ -68,19 +72,19 @@ void inv_sensors_timestamp_init(struct inv_sensors_timestamp *ts, const struct inv_sensors_timestamp_chip *chip); int inv_sensors_timestamp_update_odr(struct inv_sensors_timestamp *ts, - uint32_t period, bool fifo); + u32 period, bool fifo); void inv_sensors_timestamp_interrupt(struct inv_sensors_timestamp *ts, - size_t sample_nb, int64_t timestamp); + size_t sample_nb, s64 timestamp); -static inline int64_t inv_sensors_timestamp_pop(struct inv_sensors_timestamp *ts) +static inline s64 inv_sensors_timestamp_pop(struct inv_sensors_timestamp *ts) { ts->timestamp += ts->period; return ts->timestamp; } void inv_sensors_timestamp_apply_odr(struct inv_sensors_timestamp *ts, - uint32_t fifo_period, size_t fifo_nb, + u32 fifo_period, size_t fifo_nb, unsigned int fifo_no); static inline void inv_sensors_timestamp_reset(struct inv_sensors_timestamp *ts) @@ -88,6 +92,8 @@ static inline void inv_sensors_timestamp_reset(struct inv_sensors_timestamp *ts) const struct inv_sensors_timestamp_interval interval_init = {0LL, 0LL}; ts->it = interval_init; + ts->delta = interval_init; + ts->delta_counter = 0; ts->timestamp = 0; } diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index 4e3099defc1d..924ac9dc6893 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h @@ -7,6 +7,9 @@ #ifndef _IIO_TYPES_H_ #define _IIO_TYPES_H_ +#include <linux/types.h> +#include <linux/wordpart.h> + #include <uapi/linux/iio/types.h> enum iio_event_info { @@ -34,6 +37,23 @@ enum iio_event_info { #define IIO_VAL_FRACTIONAL_LOG2 11 #define IIO_VAL_CHAR 12 +#define IIO_VAL_DECIMAL64_BASE 32 +#define IIO_VAL_DECIMAL64_MILLI (IIO_VAL_DECIMAL64_BASE + 3) +#define IIO_VAL_DECIMAL64_MICRO (IIO_VAL_DECIMAL64_BASE + 6) +#define IIO_VAL_DECIMAL64_NANO (IIO_VAL_DECIMAL64_BASE + 9) +#define IIO_VAL_DECIMAL64_PICO (IIO_VAL_DECIMAL64_BASE + 12) + +static inline s64 iio_val_s64_compose(s32 val0, s32 val1) +{ + return (s64)(((u64)val1 << 32) | (u32)val0); +} + +static inline void iio_val_s64_decompose(s64 dec64, s32 *val0, s32 *val1) +{ + *val0 = lower_32_bits(dec64); + *val1 = upper_32_bits(dec64); +} + enum iio_available_type { IIO_AVAIL_LIST, IIO_AVAIL_RANGE, diff --git a/include/linux/kstrtox.h b/include/linux/kstrtox.h index 6c9282866770..b41b9736886f 100644 --- a/include/linux/kstrtox.h +++ b/include/linux/kstrtox.h @@ -97,6 +97,9 @@ int __must_check kstrtou8(const char *s, unsigned int base, u8 *res); int __must_check kstrtos8(const char *s, unsigned int base, s8 *res); int __must_check kstrtobool(const char *s, bool *res); +int __must_check kstrtoudec64(const char *s, unsigned int scale, u64 *res); +int __must_check kstrtodec64(const char *s, unsigned int scale, s64 *res); + int __must_check kstrtoull_from_user(const char __user *s, size_t count, unsigned int base, unsigned long long *res); int __must_check kstrtoll_from_user(const char __user *s, size_t count, unsigned int base, long long *res); int __must_check kstrtoul_from_user(const char __user *s, size_t count, unsigned int base, unsigned long *res); diff --git a/include/linux/math64.h b/include/linux/math64.h index cc305206d89f..99189410d4bb 100644 --- a/include/linux/math64.h +++ b/include/linux/math64.h @@ -58,6 +58,20 @@ static inline u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder) } /** + * div64_s64_rem - signed 64bit divide with 64bit divisor and remainder + * @dividend: signed 64bit dividend + * @divisor: signed 64bit divisor + * @remainder: pointer to signed 64bit remainder + * + * Return: sets ``*remainder``, then returns dividend / divisor + */ +static inline s64 div64_s64_rem(s64 dividend, s64 divisor, s64 *remainder) +{ + *remainder = dividend % divisor; + return dividend / divisor; +} + +/** * div64_u64 - unsigned 64bit divide with 64bit divisor * @dividend: unsigned 64bit dividend * @divisor: unsigned 64bit divisor @@ -102,6 +116,10 @@ extern s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder); extern u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder); #endif +#ifndef div64_s64_rem +extern s64 div64_s64_rem(s64 dividend, s64 divisor, s64 *remainder); +#endif + #ifndef div64_u64 extern u64 div64_u64(u64 dividend, u64 divisor); #endif diff --git a/lib/kstrtox.c b/lib/kstrtox.c index edc4eb7c1bca..bac1c057e1b0 100644 --- a/lib/kstrtox.c +++ b/lib/kstrtox.c @@ -17,6 +17,7 @@ #include <linux/export.h> #include <linux/kstrtox.h> #include <linux/math64.h> +#include <linux/overflow.h> #include <linux/types.h> #include <linux/uaccess.h> @@ -45,6 +46,7 @@ const char *_parse_integer_fixup_radix(const char *s, unsigned int *base) * @base: Radix * @p: Where to store result * @max_chars: Maximum amount of characters to convert + * @init: Initial value of the multiply-accumulate result * * Convert non-negative integer string representation in explicitly given * radix to an integer. If overflow occurs, value at @p is set to ULLONG_MAX. @@ -56,12 +58,12 @@ const char *_parse_integer_fixup_radix(const char *s, unsigned int *base) */ noinline unsigned int _parse_integer_limit(const char *s, unsigned int base, unsigned long long *p, - size_t max_chars) + size_t max_chars, unsigned long long init) { unsigned int rv, overflow = 0; unsigned long long res; - res = 0; + res = init; for (rv = 0; rv < max_chars; rv++, s++) { unsigned int c = *s; unsigned int lc = _tolower(c); @@ -94,12 +96,6 @@ unsigned int _parse_integer_limit(const char *s, unsigned int base, unsigned lon return rv | overflow; } -noinline -unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *p) -{ - return _parse_integer_limit(s, base, p, INT_MAX); -} - static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res) { unsigned long long _res; @@ -399,6 +395,109 @@ int kstrtobool(const char *s, bool *res) } EXPORT_SYMBOL(kstrtobool); +static int _kstrtoudec64(const char *s, unsigned int scale, u64 *res) +{ + unsigned int rv_int, rv_frac; + u64 _res = 0; + + rv_int = _parse_integer(s, 10, &_res); + if (rv_int & KSTRTOX_OVERFLOW) + return -ERANGE; + s += rv_int; + + if (*s == '.') + s++; /* skip decimal point */ + + rv_frac = _parse_integer(s, 10, &_res, scale, _res); + if (rv_frac & KSTRTOX_OVERFLOW) + return -ERANGE; + s += rv_frac; + + /* + * Check input beyond rv_int and rv_frac to cover cases like ".5" with + * scale 0, which is considered a valid input, being parsed as 0. + */ + if (!rv_int && !rv_frac && !isdigit(*s)) + return -EINVAL; + + while (isdigit(*s)) /* truncate digits */ + s++; + + if (*s == '\n') + s++; + if (*s) + return -EINVAL; + + if (_res && ((scale - rv_frac) > 19 /* log10(2^64) = 19.26 */ || + check_mul_overflow(_res, int_pow(10, scale - rv_frac), &_res))) + return -ERANGE; + + *res = _res; + return 0; +} + +/** + * kstrtoudec64() - Convert a string to an unsigned 64-bit scaled decimal value. + * @s: The start of the string. The string must be null-terminated, and may also + * include a single newline before its terminating null. The first character + * may also be a plus sign, but not a minus sign. + * @scale: The number of digits to the right of the decimal point. + * @res: Where to write the result of the conversion on success. + * + * For example, a scale of 3 with input "123.45" results in 123450. Note that + * trailing zeros in the fractional part input to match the scale are not + * required. Also, digits beyond the specified scale are ignored. + * + * Return: 0 on success, -ERANGE on overflow and -EINVAL on parsing error. + */ +noinline +int kstrtoudec64(const char *s, unsigned int scale, u64 *res) +{ + if (s[0] == '+') + s++; + return _kstrtoudec64(s, scale, res); +} +EXPORT_SYMBOL(kstrtoudec64); + +/** + * kstrtodec64() - Convert a string to a signed 64-bit scaled decimal value. + * @s: The start of the string. The string must be null-terminated, and may also + * include a single newline before its terminating null. The first character + * may also be a plus sign or a minus sign. + * @scale: The number of digits to the right of the decimal point. + * @res: Where to write the result of the conversion on success. + * + * For example, a scale of 4 with input "-3.141592" results in -31415. Note + * that digits beyond the specified scale are ignored. Also, trailing zeros in + * the fractional part input to match the scale are not required. + * + * Return: 0 on success, -ERANGE on overflow and -EINVAL on parsing error. + */ +noinline +int kstrtodec64(const char *s, unsigned int scale, s64 *res) +{ + u64 tmp; + int rv; + + if (s[0] == '-') { + rv = _kstrtoudec64(s + 1, scale, &tmp); + if (rv < 0) + return rv; + if ((s64)-tmp > 0) + return -ERANGE; + *res = -tmp; + } else { + rv = kstrtoudec64(s, scale, &tmp); + if (rv < 0) + return rv; + if ((s64)tmp < 0) + return -ERANGE; + *res = tmp; + } + return 0; +} +EXPORT_SYMBOL(kstrtodec64); + /* * Since "base" would be a nonsense argument, this open-codes the * _from_user helper instead of using the helper macro below. diff --git a/lib/kstrtox.h b/lib/kstrtox.h index 158c400ca865..73dee79fd8ed 100644 --- a/lib/kstrtox.h +++ b/lib/kstrtox.h @@ -2,10 +2,23 @@ #ifndef _LIB_KSTRTOX_H #define _LIB_KSTRTOX_H +#include <linux/args.h> + #define KSTRTOX_OVERFLOW (1U << 31) const char *_parse_integer_fixup_radix(const char *s, unsigned int *base); unsigned int _parse_integer_limit(const char *s, unsigned int base, unsigned long long *res, - size_t max_chars); -unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *res); + size_t max_chars, unsigned long long init); + +#define _parse_integer0(s, base, res, ...) \ + _parse_integer_limit(s, base, res, INT_MAX, 0) + +#define _parse_integer1(s, base, res, max_chars, ...) \ + _parse_integer_limit(s, base, res, max_chars, 0) + +#define _parse_integer2(s, base, res, max_chars, init, ...) \ + _parse_integer_limit(s, base, res, max_chars, init) + +#define _parse_integer(s, base, res, ...) \ + CONCATENATE(_parse_integer, COUNT_ARGS(__VA_ARGS__))(s, base, res, __VA_ARGS__) #endif diff --git a/lib/math/div64.c b/lib/math/div64.c index d1e92ea24fce..0b10ded09a9b 100644 --- a/lib/math/div64.c +++ b/lib/math/div64.c @@ -158,6 +158,21 @@ u64 div64_u64(u64 dividend, u64 divisor) EXPORT_SYMBOL(div64_u64); #endif +#ifndef div64_s64_rem +s64 div64_s64_rem(s64 dividend, s64 divisor, s64 *remainder) +{ + s64 quot, t, rem; + + quot = div64_u64_rem(abs(dividend), abs(divisor), (u64 *)&rem); + t = dividend >> 63; + *remainder = (rem ^ t) - t; + t = (dividend ^ divisor) >> 63; + + return (quot ^ t) - t; +} +EXPORT_SYMBOL(div64_s64_rem); +#endif + #ifndef div64_s64 s64 div64_s64(s64 dividend, s64 divisor) { diff --git a/lib/math/test_mul_u64_u64_div_u64.c b/lib/math/test_mul_u64_u64_div_u64.c index 338d014f0c73..d12dc05938fb 100644 --- a/lib/math/test_mul_u64_u64_div_u64.c +++ b/lib/math/test_mul_u64_u64_div_u64.c @@ -157,6 +157,7 @@ static void __exit test_exit(void) #define __div64_32 __div64_32 #define div_s64_rem div_s64_rem #define div64_u64_rem div64_u64_rem +#define div64_s64_rem div64_s64_rem #define div64_u64 div64_u64 #define div64_s64 div64_s64 #define iter_div_u64_rem iter_div_u64_rem diff --git a/lib/test-kstrtox.c b/lib/test-kstrtox.c index 811128d0df16..9255234752db 100644 --- a/lib/test-kstrtox.c +++ b/lib/test-kstrtox.c @@ -709,6 +709,182 @@ static void __init test_kstrtos8_fail(void) TEST_FAIL(kstrtos8, s8, "%hhd", test_s8_fail); } +static void __init test_kstrtoudec64_ok(void) +{ + DECLARE_TEST_OK(u64, struct test_udec64); + static DEFINE_TEST_OK(struct test_udec64, test_udec64_ok) = { + /* basic: integer.fraction, exact digits */ + {"0.0", 1, 0}, + {"1.5", 1, 15}, + {"1.234", 3, 1234}, + {"42.0", 1, 420}, + /* zero */ + {"0.0", 1, 0}, + {"0.000", 3, 0}, + /* integer only */ + {"0", 1, 0}, + {"42", 3, 42000}, + {"123.", 2, 12300}, + {"1", 1, 10}, + /* fractional only (leading dot) */ + {".5", 1, 5}, + {".5", 0, 0}, + {".123", 3, 123}, + {".001", 3, 1}, + /* zero padding: fewer fractional digits than scale */ + {"1.2", 3, 1200}, + {"1.2", 6, 1200000}, + {"0.01", 3, 10}, + {"0.1", 9, 100000000ULL}, + {"0.01", 9, 10000000}, + /* truncation: more fractional digits than scale */ + {"1.23456", 3, 1234}, + {"3.1415926535", 6, 3141592}, + {"0.999999999", 3, 999}, + {"1.99", 1, 19}, + {"1.234", 0, 1}, + /* trailing newline */ + {"1.5\n", 1, 15}, + {"42\n", 3, 42000}, + /* plus sign */ + {"+1.5", 1, 15}, + {"+.5", 1, 5}, + /* scale progression */ + {"1.", 0, 1}, + {"1.0", 1, 10}, + {"1.00", 2, 100}, + {"1.000", 3, 1000}, + {"1.000000", 6, 1000000}, + {"1.000000000", 9, 1000000000ULL}, + /* max limit check */ + {"18446744073.709551615", 9, ULLONG_MAX}, + {"18446744073709.551615", 6, ULLONG_MAX}, + {"0.18446744073709551615", 20, ULLONG_MAX}, + /* scale > 19: representable when integer part is small */ + {"0.00000000000000000001", 20, 1}, + {"0.1", 20, 10000000000000000000ULL}, + {"0.00000000000000000000001", 23, 1}, + /* truncation with scale > 19 */ + {"0.0000000000000000000012345", 23, 123}, + /* truncation with many excess digits */ + {"0.00000000000000000000000000000000423", 34, 42}, + {"1.99999999999999999999999999999999999", 3, 1999}, + }; + TEST_OK(kstrtoudec64, u64, "%llu", test_udec64_ok); +} + +static void __init test_kstrtoudec64_fail(void) +{ + static DEFINE_TEST_FAIL(test_udec64_fail) = { + /* empty / whitespace */ + {"", 3}, + {"\n", 3}, + /* minus sign (unsigned) */ + {"-1.5", 1}, + {"-0.5", 1}, + /* only a decimal point */ + {".", 3}, + {".", 0}, + /* only a sign */ + {"+", 3}, + /* non-digit characters */ + {"abc", 3}, + {"1.2x", 3}, + /* leading/trailing space */ + {" 1.5", 1}, + {"1.5 ", 1}, + /* overflow */ + {"18446744073710.551615", 6}, + {"99999999999999999999", 1}, + /* overflow with scale > 19 */ + {"1.0", 21}, + {"0.2", 20}, + {"0.18446744073709551616", 20}, + {"1", 20}, + }; + TEST_FAIL(kstrtoudec64, u64, "%llu", test_udec64_fail); +} + +static void __init test_kstrtodec64_ok(void) +{ + DECLARE_TEST_OK(s64, struct test_dec64); + static DEFINE_TEST_OK(struct test_dec64, test_dec64_ok) = { + /* basic positive */ + {"0.0", 1, 0}, + {"1.5", 1, 15}, + {"1.234", 3, 1234}, + /* basic negative */ + {"-1.5", 1, -15}, + {"-1.234", 3, -1234}, + {"-0.5", 1, -5}, + {"-0.001", 3, -1}, + /* zero (signed) */ + {"-0", 1, 0}, + {"-0.0", 1, 0}, + {"0.000", 3, 0}, + /* integer only */ + {"42", 3, 42000}, + {"-42", 3, -42000}, + /* fractional only */ + {".5", 1, 5}, + {"-.5", 1, -5}, + /* zero padding */ + {"1.2", 3, 1200}, + {"-1.2", 3, -1200}, + {"0.01", 3, 10}, + {"-0.01", 3, -10}, + /* truncation */ + {"1.23456", 3, 1234}, + {"-1.23456", 3, -1234}, + {"0.999999999", 3, 999}, + {"-0.999999999", 3, -999}, + /* trailing newline */ + {"1.5\n", 1, 15}, + {"-1.5\n", 1, -15}, + /* plus sign */ + {"+1.5", 1, 15}, + /* limits */ + {"9223372036.854775807", 9, LLONG_MAX}, + {"-9223372036.854775808", 9, LLONG_MIN}, + /* scale > 19 */ + {"0.0", 20, 0}, + {"-0.0", 20, 0}, + {"0.00000000000000000001", 20, 1}, + {"-0.00000000000000000001", 20, -1}, + {"0.009223372036854775807", 21, LLONG_MAX}, + {"-0.009223372036854775808", 21, LLONG_MIN}, + }; + TEST_OK(kstrtodec64, s64, "%lld", test_dec64_ok); +} + +static void __init test_kstrtodec64_fail(void) +{ + static DEFINE_TEST_FAIL(test_dec64_fail) = { + /* empty / whitespace */ + {"", 3}, + {"\n", 3}, + /* no digits after dot */ + {".", 3}, + {"-.", 3}, + /* no digits at all */ + {"+", 3}, + {"-", 3}, + /* non-digit characters */ + {"abc", 3}, + {"-1.2x", 3}, + /* signed overflow */ + {"9223372036.854775808", 9}, + {"-9223372036.854775809", 9}, + {"99999999999999999999", 1}, + /* signed overflow with scale > 19 */ + {"0.1", 20}, + {"-0.1", 20}, + {"0.09223372036854775808", 20}, + {"-0.09223372036854775809", 20}, + }; + TEST_FAIL(kstrtodec64, s64, "%lld", test_dec64_fail); +} + static int __init test_kstrtox_init(void) { test_kstrtoull_ok(); @@ -735,6 +911,12 @@ static int __init test_kstrtox_init(void) test_kstrtou8_fail(); test_kstrtos8_ok(); test_kstrtos8_fail(); + + test_kstrtoudec64_ok(); + test_kstrtoudec64_fail(); + test_kstrtodec64_ok(); + test_kstrtodec64_fail(); + return -EINVAL; } module_init(test_kstrtox_init); diff --git a/lib/vsprintf.c b/lib/vsprintf.c index e285e8bc4712..1d95ab9314bf 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -86,7 +86,7 @@ static unsigned long long simple_strntoull(const char *startp, char **endp, unsi cp = _parse_integer_fixup_radix(startp, &base); prefix_chars = cp - startp; if (prefix_chars < max_chars) { - rv = _parse_integer_limit(cp, base, &result, max_chars - prefix_chars); + rv = _parse_integer(cp, base, &result, max_chars - prefix_chars); /* FIXME */ cp += (rv & ~KSTRTOX_OVERFLOW); } else { diff --git a/sound/soc/codecs/audio-iio-aux.c b/sound/soc/codecs/audio-iio-aux.c index 964b9a5b2990..eef0af63e3d6 100644 --- a/sound/soc/codecs/audio-iio-aux.c +++ b/sound/soc/codecs/audio-iio-aux.c @@ -311,3 +311,4 @@ module_platform_driver(audio_iio_aux_driver); MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>"); MODULE_DESCRIPTION("IIO ALSA SoC aux driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/sound/soc/samsung/aries_wm8994.c b/sound/soc/samsung/aries_wm8994.c index 6db91b73f25c..d8659973540f 100644 --- a/sound/soc/samsung/aries_wm8994.c +++ b/sound/soc/samsung/aries_wm8994.c @@ -701,3 +701,4 @@ module_platform_driver(aries_audio_driver); MODULE_DESCRIPTION("ALSA SoC ARIES WM8994"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:aries-audio-wm8994"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c index bc34dbbb50c9..d43af5069baf 100644 --- a/sound/soc/samsung/midas_wm1811.c +++ b/sound/soc/samsung/midas_wm1811.c @@ -773,3 +773,4 @@ module_platform_driver(midas_driver); MODULE_AUTHOR("Simon Shields <simon@lineageos.org>"); MODULE_DESCRIPTION("ASoC support for Midas"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c index 66efb9a0acb9..c8022f6efd8a 100644 --- a/sound/soc/stm/stm32_adfsdm.c +++ b/sound/soc/stm/stm32_adfsdm.c @@ -392,3 +392,4 @@ MODULE_DESCRIPTION("stm32 DFSDM DAI driver"); MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:" STM32_ADFSDM_DRV_NAME); +MODULE_IMPORT_NS("IIO_CONSUMER"); |
