diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-04-04 22:25:29 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-04-04 22:25:29 +0200 |
commit | 932f98922f6fca9f8c45274346b49058dd50d51a (patch) | |
tree | 75635c62cfbaa0397d7169a69e132c0a2a235ade | |
parent | 44b8ef17c435ecc1a2a505e39e8556f26c0da4ef (diff) | |
parent | df1d80aee963480c5c2938c64ec0ac3e4a0df2e0 (diff) | |
download | lwn-932f98922f6fca9f8c45274346b49058dd50d51a.tar.gz lwn-932f98922f6fca9f8c45274346b49058dd50d51a.zip |
Merge tag 'iio-for-5.2a-2' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next
Jonathan writes:
First set of new device support, features and fixes for IIO in the 5.2 cycle
Staging graduations
* ad7780
- Move this ADC driver out of staging. Included adding some new features
along the way (see below). Also added DT bindings.
New device support
* adis16480
- Support the ADIS16495 and ADIS16497 IMU devices making
heavy use of refactoring of various aspects of the driver in precursor
patches.
* lsm6dsx
- Support for the ASM330LHH 6-axis (accelerometer + gyro) sensor.
- Support for the LSM6DS0X
* matbotix mb1232
- New driver for this ultrasound ranging device family. Including bindings.
- Supports mb1202, mb1212, mb1222, mb1232, mb1242, mb7040 and mb7137.
* max31856
- New driver for this thermocouple temperature sensor.
* meson saradc
- Support the Meson-G12A (ID addition only).
* stmpe-adc
- New driver supporting generic ADC alongside touchscreen support which
previously existed. Includes DT bindings.
* vcnl4000
- Support for the vcln4040 proximity and light sensor, including adding
DT bindings for this and parts previously supported.
Features
* core
- Allow reading of mount matrices from ACPI in addition to DT.
- Common binding for theromcouple types.
* ad5933
- Add ABI docs as there are a few 'unsual' elements about this
device - perhaps because it's our only impedance analyser.
* ad7780
- Add gain and filter gpio support + readback of current gain and filter.
* adis16480
- Allow selection fo the dataready pin to be used.
- Device tree ID table and binding documentation.
- Support external clock modes, including new bindings.
* bma180
- Mount matrix support.
* bmc150
- Mount matrix support.
* bmg160
- Mount matrix support.
- DT id table and bindings doc.
* bmp280
- Put calibration data into the entropy pool.
* hmc5843
- Mount matrix support.
* itg3200
- Mount matrix support.
* kxcjk1013
- Device tree id table, and binding docs.
* lpc32xx
- Add scale when regulator specified including DT docs for regulator.
* pms7003
- Add device IDs for all supported parts to driver and binding.
* stm32-dfsdm
- Enable hw consumer support, scan mode control and a complex set of
triggered buffer modes.
- Power management.
* stm32-lptimer-counter
- power management.
- Document the pinctrl sleep state binding.
* ti-ads7950
- GPIO pin support.
Cleanups, minor fixes
* core
- Use bitmap_zalloc to make it explicit that is what we are doing.
- Tidy up all the Kconfig files (which had slowly gotten messy)
- Fix a forwards definition missing issue in iio/driver.h
* ad sigma delta core
- Improve handling of SPI bus locking vs CS assertion. This has been
wrong a long time so not rushing this in.
* ad5064
- Mlock to local lock.
* ad5933 (staging cleanup)
- Multiline comment fixes.
- Include ordering.
- SPDX.
- Tidy up Kconfig help which was a bit missleading.
- Change some non standard attributes to ABI defined ones.
* ad7124
- White space fix.
* ad7192
- White space.
- Use DT clock binding.
- Improve error reporting.
- Platform data to DT conversion.
- Use read_avail callback, mostly to avoid the endless series of
patches from new contributors trying to falsely put spaces around
the negative sign.
* ad7280a
- Add brackets to macros to avoid potential precedence isseus.
- Add temp vars for event codes to reduce indent and improved readability.
- Clean out som CamelCase notation.
- White space.
* ad7606
- Fix broken file naming in MAINTAINERS.
* ad7780
- Missing switch defaults to supress warnings and harden the code slightly.
- Set pattern masks more directly.
- Add ID values and masks for all supported chips.
- SPDX + add Renato as a copyright holder as he has done a lot of work on
this driver.
- Add brackets to macros to avoid potential precedence issues.
* ad7923
- White space fixes.
- Use BIT macro to improve readability.
- Add brackets to macros to avoid potential precedence issues.
- Tidy up a null comparisom.
* ad9523
- Fix a typo in naming of variables.
* adis16400
- Combine trigger file into main code as no advantage in separate files.
Rename core file to just adis16400.
- Squash the header into the c file now there is only one file.
- Generalize burst mode to support new variants.
* ak8975
- Local variable to improve readability around mount matrix support.
* as3935
- Avoid potential race by ensuring remove does exact opposite of
probe rather than a slightly different order.
* cross_ec
- Drop some unnecessary includes.
- Fix some warning and the slightly 'unusual' code.
- Add some docs for non obvious function.
- SPDX
* hmc5843
- Potential unhandled error case.
* iio trigger core
- Print an error if there is no available irq due to max consumers per
trigger being set to low.
* iio loop trigger
- Drop an unlikely on IS_ERR as IS_ERR already has the annotation.
* ingenic-adc
- Drop a redundant dev_err call as devm_ioremap_resource reports the same
internally.
* lmp91000
- Drop some unncessary parentheses and white space tidy up.
- Invert and if statement to improve readability.
- Fix a wrong error message.
* lpc32xx
- Header sorting + drop some unused ones.
* mma8542
- Mark a switch fallthrough.
* mpu6050
- Add a local variable to improve code readability around mount matrix
support.
* mxs-lradc-adc
- Handle devm_iio_trigger_alloc failure.
* sps30
- Fix up a kernel version in the ABI docs.
* srf04
- DT binding doc converted to yaml.
* ssp_sensors
- Supress a clang build warning due to lack of visibility of conditional
within a iio_push_to_buffers_with_timestamp. (reasonable false warning!)
* st_accel
- Drop pointless less than 0 comparisom of unsigned int.
* stm32-dfsdm
- Improve accuracy of spi_master_frequency calculation.
- Improve calculation fo sampling frequency.
- Rework various internals to simplify adding triggered buffer support.
- Claim direct mode to avoid racing around read_raw and being in buffered
mode.
* stmpe
- Fix a clang false positive warning.
* ti-ads7950
- Use local lock rather than using the core mlock when not locking around
the device mode.
* vcnl4000
- Use word writes instead of byte writes. It seems byte writes are fine
for some parts (undocument) but not others that the driver will shortly
support.
Other
* mailmap
- Add email address change for Sean Nyekjaer. Update in relevant drivers
* tag 'iio-for-5.2a-2' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (129 commits)
iio: ad_sigma_delta: Properly handle SPI bus locking vs CS assertion
iio: adc: stm32-dfsdm: add PM support
iio: adc: stm32-dfsdm: improve sampling frequency accuracy
staging: iio: adc: ad7280a: Tab alignment
MAINTAINERS: Fix the link to ad7606 dt-bindings
iio:temperature: Add MAX31856 thermocouple support
iio:temperature:max31856:Add device tree bind info
dt-bindings: iio/temperature: Add thermocouple types (and doc)
devantech-srf04.yaml: transform DT binding to YAML
iio: frequency: ad9523: Fix typo in ad9523_platform_data
iio: Make possible to include driver.h first
dt-bindings: iio: add Bosch BMG160 gyroscope sensor
iio: gyro: bmg160: add device tree compatibility table
staging: iio: adc: ad7192: Use read_avail for available attributes
dt-bindings: iio: light: add vcnl4040 devicetree bindings
iio: light: vcnl4000 add support for the VCNL4040 proximity and light sensor
dt-bindings: iio: light: add vcnl4000 devicetree bindings
iio: light: vcnl4000 add devicetree hooks
iio: light: vcnl4000 use word writes instead of byte writes
iio: adc: stm32-dfsdm: claim direct mode for raw read and settings
...
113 files changed, 3775 insertions, 1268 deletions
@@ -187,6 +187,7 @@ Santosh Shilimkar <ssantosh@kernel.org> Santosh Shilimkar <santosh.shilimkar@oracle.org> Sascha Hauer <s.hauer@pengutronix.de> S.Çağlar Onur <caglar@pardus.org.tr> +Sean Nyekjaer <sean@geanix.com> <sean.nyekjaer@prevas.dk> Sebastian Reichel <sre@kernel.org> <sre@debian.org> Sebastian Reichel <sre@kernel.org> <sebastian.reichel@collabora.co.uk> Shiraz Hashim <shiraz.linux.kernel@gmail.com> <shiraz.hashim@st.com> diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-impedance-analyzer-ad5933 b/Documentation/ABI/testing/sysfs-bus-iio-impedance-analyzer-ad5933 index 79c7e88c64cd..0e86747c67f8 100644 --- a/drivers/staging/iio/Documentation/sysfs-bus-iio-impedance-analyzer-ad5933 +++ b/Documentation/ABI/testing/sysfs-bus-iio-impedance-analyzer-ad5933 @@ -1,26 +1,31 @@ -What: /sys/bus/iio/devices/iio:deviceX/outY_freq_start +What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_frequency_start +Date: March 2019 KernelVersion: 3.1.0 Contact: linux-iio@vger.kernel.org Description: Frequency sweep start frequency in Hz. -What: /sys/bus/iio/devices/iio:deviceX/outY_freq_increment +What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_frequency_increment +Date: March 2019 KernelVersion: 3.1.0 Contact: linux-iio@vger.kernel.org Description: Frequency increment in Hz (step size) between consecutive frequency points along the sweep. -What: /sys/bus/iio/devices/iio:deviceX/outY_freq_points +What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_frequency_points +Date: March 2019 KernelVersion: 3.1.0 Contact: linux-iio@vger.kernel.org Description: Number of frequency points (steps) in the frequency sweep. - This value, in conjunction with the outY_freq_start and the - outY_freq_increment, determines the frequency sweep range - for the sweep operation. + This value, in conjunction with the + out_altvoltageY_frequency_start and the + out_altvoltageY_frequency_increment, determines the frequency + sweep range for the sweep operation. -What: /sys/bus/iio/devices/iio:deviceX/outY_settling_cycles +What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_settling_cycles +Date: March 2019 KernelVersion: 3.1.0 Contact: linux-iio@vger.kernel.org Description: diff --git a/Documentation/ABI/testing/sysfs-bus-iio-sps30 b/Documentation/ABI/testing/sysfs-bus-iio-sps30 index 143df8e89d08..06e1c272537b 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-sps30 +++ b/Documentation/ABI/testing/sysfs-bus-iio-sps30 @@ -1,6 +1,6 @@ What: /sys/bus/iio/devices/iio:deviceX/start_cleaning Date: December 2018 -KernelVersion: 4.22 +KernelVersion: 5.0 Contact: linux-iio@vger.kernel.org Description: Writing 1 starts sensor self cleaning. Internal fan accelerates diff --git a/Documentation/ABI/testing/sysfs-bus-iio-temperature-max31856 b/Documentation/ABI/testing/sysfs-bus-iio-temperature-max31856 new file mode 100644 index 000000000000..3b3509a3ef2f --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-temperature-max31856 @@ -0,0 +1,24 @@ +What: /sys/bus/iio/devices/iio:deviceX/fault_oc +KernelVersion: 5.1 +Contact: linux-iio@vger.kernel.org +Description: + Open-circuit fault. The detection of open-circuit faults, + such as those caused by broken thermocouple wires. + Reading returns either '1' or '0'. + '1' = An open circuit such as broken thermocouple wires + has been detected. + '0' = No open circuit or broken thermocouple wires are detected + +What: /sys/bus/iio/devices/iio:deviceX/fault_ovuv +KernelVersion: 5.1 +Contact: linux-iio@vger.kernel.org +Description: + Overvoltage or Undervoltage Input Fault. The internal circuitry + is protected from excessive voltages applied to the thermocouple + cables by integrated MOSFETs at the T+ and T- inputs, and the + BIAS output. These MOSFETs turn off when the input voltage is + negative or greater than VDD. + Reading returns either '1' or '0'. + '1' = The input voltage is negative or greater than VDD. + '0' = The input voltage is positive and less than VDD (normal + state). diff --git a/Documentation/devicetree/bindings/iio/accel/kionix,kxcjk1013.txt b/Documentation/devicetree/bindings/iio/accel/kionix,kxcjk1013.txt new file mode 100644 index 000000000000..eb76a02e2a82 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/accel/kionix,kxcjk1013.txt @@ -0,0 +1,17 @@ +Kionix KXCJK-1013 Accelerometer device tree bindings + +Required properties: + +- compatible: Must be one of: + "kionix,kxcjk1013" + "kionix,kxcj91008" + "kionix,kxtj21009" + "kionix,kxtf9" + - reg: i2c slave address + +Example: + +kxtf9@f { + compatible = "kionix,kxtf9"; + reg = <0x0F>; +}; diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7780.txt b/Documentation/devicetree/bindings/iio/adc/adi,ad7780.txt new file mode 100644 index 000000000000..440e52555349 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7780.txt @@ -0,0 +1,48 @@ +* Analog Devices AD7170/AD7171/AD7780/AD7781 + +Data sheets: + +- AD7170: + * https://www.analog.com/media/en/technical-documentation/data-sheets/AD7170.pdf +- AD7171: + * https://www.analog.com/media/en/technical-documentation/data-sheets/AD7171.pdf +- AD7780: + * https://www.analog.com/media/en/technical-documentation/data-sheets/ad7780.pdf +- AD7781: + * https://www.analog.com/media/en/technical-documentation/data-sheets/AD7781.pdf + +Required properties: + +- compatible: should be one of + * "adi,ad7170" + * "adi,ad7171" + * "adi,ad7780" + * "adi,ad7781" +- reg: spi chip select number for the device +- vref-supply: the regulator supply for the ADC reference voltage + +Optional properties: + +- powerdown-gpios: must be the device tree identifier of the PDRST pin. If + specified, it will be asserted during driver probe. As the + line is active high, it should be marked GPIO_ACTIVE_HIGH. +- adi,gain-gpios: must be the device tree identifier of the GAIN pin. Only for + the ad778x chips. If specified, it will be asserted during + driver probe. As the line is active low, it should be marked + GPIO_ACTIVE_LOW. +- adi,filter-gpios: must be the device tree identifier of the FILTER pin. Only + for the ad778x chips. If specified, it will be asserted + during driver probe. As the line is active low, it should be + marked GPIO_ACTIVE_LOW. + +Example: + +adc@0 { + compatible = "adi,ad7780"; + reg = <0>; + vref-supply = <&vdd_supply> + + powerdown-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>; + adi,gain-gpios = <&gpio 5 GPIO_ACTIVE_LOW>; + adi,filter-gpios = <&gpio 15 GPIO_ACTIVE_LOW>; +}; diff --git a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt index 75c775954102..d57e9df25f4f 100644 --- a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt +++ b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt @@ -9,6 +9,7 @@ Required properties: - "amlogic,meson-gxl-saradc" for GXL - "amlogic,meson-gxm-saradc" for GXM - "amlogic,meson-axg-saradc" for AXG + - "amlogic,meson-g12a-saradc" for AXG along with the generic "amlogic,meson-saradc" - reg: the physical base address and length of the registers - interrupts: the interrupt indicating end of sampling diff --git a/Documentation/devicetree/bindings/iio/adc/lpc32xx-adc.txt b/Documentation/devicetree/bindings/iio/adc/lpc32xx-adc.txt index b3629d3a9adf..3a1bc669bd51 100644 --- a/Documentation/devicetree/bindings/iio/adc/lpc32xx-adc.txt +++ b/Documentation/devicetree/bindings/iio/adc/lpc32xx-adc.txt @@ -6,6 +6,10 @@ Required properties: region. - interrupts: The ADC interrupt +Optional: + - vref-supply: The regulator supply ADC reference voltage, optional + for legacy reason, but highly encouraging to us in new device tree + Example: adc@40048000 { @@ -13,4 +17,5 @@ Example: reg = <0x40048000 0x1000>; interrupt-parent = <&mic>; interrupts = <39 0>; + vref-supply = <&vcc>; }; diff --git a/Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.txt b/Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.txt index 7b5f06f324c8..c52ea2126eaa 100644 --- a/Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.txt +++ b/Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.txt @@ -1,7 +1,13 @@ * Plantower PMS7003 particulate matter sensor Required properties: -- compatible: must be "plantower,pms7003" +- compatible: must one of: + "plantower,pms1003" + "plantower,pms3003" + "plantower,pms5003" + "plantower,pms6003" + "plantower,pms7003" + "plantower,pmsa003" - vcc-supply: phandle to the regulator that provides power to the sensor Optional properties: diff --git a/Documentation/devicetree/bindings/iio/counter/stm32-lptimer-cnt.txt b/Documentation/devicetree/bindings/iio/counter/stm32-lptimer-cnt.txt index a04aa5c04103..e90bc47f752a 100644 --- a/Documentation/devicetree/bindings/iio/counter/stm32-lptimer-cnt.txt +++ b/Documentation/devicetree/bindings/iio/counter/stm32-lptimer-cnt.txt @@ -10,8 +10,9 @@ See ../mfd/stm32-lptimer.txt for details about the parent node. Required properties: - compatible: Must be "st,stm32-lptimer-counter". -- pinctrl-names: Set to "default". -- pinctrl-0: List of phandles pointing to pin configuration nodes, +- pinctrl-names: Set to "default". An additional "sleep" state can be + defined to set pins in sleep state. +- pinctrl-n: List of phandles pointing to pin configuration nodes, to set IN1/IN2 pins in mode of operation for Low-Power Timer input on external pin. @@ -21,7 +22,8 @@ Example: ... counter { compatible = "st,stm32-lptimer-counter"; - pinctrl-names = "default"; + pinctrl-names = "default", "sleep"; pinctrl-0 = <&lptim1_in_pins>; + pinctrl-1 = <&lptim1_sleep_in_pins>; }; }; diff --git a/Documentation/devicetree/bindings/iio/gyroscope/bmg160.txt b/Documentation/devicetree/bindings/iio/gyroscope/bmg160.txt new file mode 100644 index 000000000000..78e18a1e9c1d --- /dev/null +++ b/Documentation/devicetree/bindings/iio/gyroscope/bmg160.txt @@ -0,0 +1,20 @@ +* Bosch BMG160 triaxial rotation sensor (gyroscope) + +Required properties: + + - compatible : should be "bosch,bmg160" or "bosch,bmi055_gyro" + - reg : the I2C address of the sensor (0x69) + +Optional properties: + + - interrupts : interrupt mapping for GPIO IRQ, it should by configured with + flags IRQ_TYPE_EDGE_RISING + +Example: + +bmg160@69 { + compatible = "bosch,bmg160"; + reg = <0x69>; + interrupt-parent = <&gpio6>; + interrupts = <18 (IRQ_TYPE_EDGE_RISING)>; +}; diff --git a/Documentation/devicetree/bindings/iio/imu/adi,adis16480.txt b/Documentation/devicetree/bindings/iio/imu/adi,adis16480.txt new file mode 100644 index 000000000000..ed7783f45233 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16480.txt @@ -0,0 +1,85 @@ + +Analog Devices ADIS16480 and similar IMUs + +Required properties for the ADIS16480: + +- compatible: Must be one of + * "adi,adis16375" + * "adi,adis16480" + * "adi,adis16485" + * "adi,adis16488" + * "adi,adis16495-1" + * "adi,adis16495-2" + * "adi,adis16495-3" + * "adi,adis16497-1" + * "adi,adis16497-2" + * "adi,adis16497-3" +- reg: SPI chip select number for the device +- spi-max-frequency: Max SPI frequency to use + see: Documentation/devicetree/bindings/spi/spi-bus.txt +- spi-cpha: See Documentation/devicetree/bindings/spi/spi-bus.txt +- spi-cpol: See Documentation/devicetree/bindings/spi/spi-bus.txt +- interrupts: interrupt mapping for IRQ, accepted values are: + * IRQF_TRIGGER_RISING + * IRQF_TRIGGER_FALLING + +Optional properties: + +- interrupt-names: Data ready line selection. Valid values are: + * DIO1 + * DIO2 + * DIO3 + * DIO4 + If this field is left empty, DIO1 is assigned as default data ready + signal. +- reset-gpios: must be the device tree identifier of the RESET pin. As the line + is active low, it should be marked GPIO_ACTIVE_LOW. +- clocks: phandle to the external clock. Should be set according to + "clock-names". + If this field is left empty together with the "clock-names" field, then + the internal clock is used. +- clock-names: The name of the external clock to be used. Valid values are: + * sync: In sync mode, the internal clock is disabled and the frequency + of the external clock signal establishes therate of data + collection and processing. See Fig 14 and 15 in the datasheet. + The clock-frequency must be: + * 3000 to 4500 Hz for adis1649x devices. + * 700 to 2400 Hz for adis1648x devices. + * pps: In Pulse Per Second (PPS) Mode, the rate of data collection and + production is equal to the product of the external clock + frequency and the scale factor in the SYNC_SCALE register, see + Table 154 in the datasheet. + The clock-frequency must be: + * 1 to 128 Hz for adis1649x devices. + * This mode is not supported by adis1648x devices. + If this field is left empty together with the "clocks" field, then the + internal clock is used. +- adi,ext-clk-pin: The DIOx line to be used as an external clock input. + Valid values are: + * DIO1 + * DIO2 + * DIO3 + * DIO4 + Each DIOx pin supports only one function at a time (data ready line + selection or external clock input). When a single pin has two + two assignments, the enable bit for the lower priority function + automatically resets to zero (disabling the lower priority function). + Data ready has highest priority. + If this field is left empty, DIO2 is assigned as default external clock + input pin. + +Example: + + imu@0 { + compatible = "adi,adis16495-1"; + reg = <0>; + spi-max-frequency = <3200000>; + spi-cpol; + spi-cpha; + interrupts = <25 IRQF_TRIGGER_FALLING>; + interrupt-parent = <&gpio>; + interrupt-names = "DIO2"; + clocks = <&adis16495_sync>; + clock-names = "sync"; + adi,ext-clk-pin = "DIO1"; + }; diff --git a/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt b/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt index 69d53d98d0f0..4640a012c17a 100644 --- a/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt +++ b/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt @@ -8,6 +8,8 @@ Required properties: "st,lsm6dsm" "st,ism330dlc" "st,lsm6dso" + "st,asm330lhh" + "st,lsm6dsox" - reg: i2c address of the sensor / spi cs line Optional properties: diff --git a/Documentation/devicetree/bindings/iio/light/vcnl4000.txt b/Documentation/devicetree/bindings/iio/light/vcnl4000.txt new file mode 100644 index 000000000000..955af4555c90 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/light/vcnl4000.txt @@ -0,0 +1,24 @@ +VISHAY VCNL4000 - Ambient Light and proximity sensor + +This driver supports the VCNL4000/10/20/40 and VCNL4200 chips + +Required properties: + + -compatible: must be one of : + vishay,vcnl4000 + vishay,vcnl4010 + vishay,vcnl4020 + vishay,vcnl4040 + vishay,vcnl4200 + + -reg: I2C address of the sensor, should be one from below based on the model: + 0x13 + 0x51 + 0x60 + +Example: + +light-sensor@51 { + compatible = "vishay,vcnl4200"; + reg = <0x51>; +}; diff --git a/Documentation/devicetree/bindings/iio/proximity/devantech-srf04.txt b/Documentation/devicetree/bindings/iio/proximity/devantech-srf04.txt deleted file mode 100644 index d4dc7a227e2e..000000000000 --- a/Documentation/devicetree/bindings/iio/proximity/devantech-srf04.txt +++ /dev/null @@ -1,28 +0,0 @@ -* Devantech SRF04 ultrasonic range finder - Bit-banging driver using two GPIOs - -Required properties: - - compatible: Should be "devantech,srf04" - - - trig-gpios: Definition of the GPIO for the triggering (output) - This GPIO is set for about 10 us by the driver to tell the - device it should initiate the measurement cycle. - - - echo-gpios: Definition of the GPIO for the echo (input) - This GPIO is set by the device as soon as an ultrasonic - burst is sent out and reset when the first echo is - received. - Thus this GPIO is set while the ultrasonic waves are doing - one round trip. - It needs to be an GPIO which is able to deliver an - interrupt because the time between two interrupts is - measured in the driver. - See Documentation/devicetree/bindings/gpio/gpio.txt for - information on how to specify a consumer gpio. - -Example: -srf04@0 { - compatible = "devantech,srf04"; - trig-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>; - echo-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>; -}; diff --git a/Documentation/devicetree/bindings/iio/proximity/devantech-srf04.yaml b/Documentation/devicetree/bindings/iio/proximity/devantech-srf04.yaml new file mode 100644 index 000000000000..e7aab785c97d --- /dev/null +++ b/Documentation/devicetree/bindings/iio/proximity/devantech-srf04.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/proximity/devantech-srf04.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Devantech SRF04 ultrasonic range finder + +maintainers: + - Andreas Klinger <ak@it-klinger.de> + +description: | + Bit-banging driver using two GPIOs: + - trigger-gpio is raised by the driver to start sending out an ultrasonic + burst + - echo-gpio is held high by the sensor after sending ultrasonic burst + until it is received once again + + Specifications about the driver can be found at: + http://www.robot-electronics.co.uk/htm/srf04tech.htm + +properties: + compatible: + items: + - const: devantech,srf04 + + trig-gpios: + description: + Definition of the GPIO for the triggering (output) This GPIO is set + for about 10 us by the driver to tell the device it should initiate + the measurement cycle. + maxItems: 1 + + echo-gpios: + description: + Definition of the GPIO for the echo (input) + This GPIO is set by the device as soon as an ultrasonic burst is sent + out and reset when the first echo is received. + Thus this GPIO is set while the ultrasonic waves are doing one round + trip. + It needs to be an GPIO which is able to deliver an interrupt because + the time between two interrupts is measured in the driver. + See Documentation/devicetree/bindings/gpio/gpio.txt for information + on how to specify a consumer gpio. + maxItems: 1 + +required: + - compatible + - trig-gpios + - echo-gpios + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + proximity { + compatible = "devantech,srf04"; + trig-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>; + echo-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>; + }; diff --git a/Documentation/devicetree/bindings/iio/proximity/maxbotix,mb1232.txt b/Documentation/devicetree/bindings/iio/proximity/maxbotix,mb1232.txt new file mode 100644 index 000000000000..dd1058fbe9c3 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/proximity/maxbotix,mb1232.txt @@ -0,0 +1,29 @@ +* MaxBotix I2CXL-MaxSonar ultrasonic distance sensor of type mb1202, + mb1212, mb1222, mb1232, mb1242, mb7040 or mb7137 using the i2c interface + for ranging + +Required properties: + - compatible: "maxbotix,mb1202", + "maxbotix,mb1212", + "maxbotix,mb1222", + "maxbotix,mb1232", + "maxbotix,mb1242", + "maxbotix,mb7040" or + "maxbotix,mb7137" + + - reg: i2c address of the device, see also i2c/i2c.txt + +Optional properties: + - interrupts: Interrupt used to announce the preceding reading + request has finished and that data is available. + If no interrupt is specified the device driver + falls back to wait a fixed amount of time until + data can be retrieved. + +Example: +proximity@70 { + compatible = "maxbotix,mb1232"; + reg = <0x70>; + interrupt-parent = <&gpio2>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>; +}; diff --git a/Documentation/devicetree/bindings/iio/temperature/max31856.txt b/Documentation/devicetree/bindings/iio/temperature/max31856.txt new file mode 100644 index 000000000000..06ab43bb4de8 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/temperature/max31856.txt @@ -0,0 +1,24 @@ +Maxim MAX31856 thermocouple support + +https://datasheets.maximintegrated.com/en/ds/MAX31856.pdf + +Optional property: + - thermocouple-type: Type of thermocouple (THERMOCOUPLE_TYPE_K if + omitted). Supported types are B, E, J, K, N, R, S, T. + +Required properties: + - compatible: must be "maxim,max31856" + - reg: SPI chip select number for the device + - spi-max-frequency: As per datasheet max. supported freq is 5000000 + - spi-cpha: must be defined for max31856 to enable SPI mode 1 + + Refer to spi/spi-bus.txt for generic SPI slave bindings. + + Example: + temp-sensor@0 { + compatible = "maxim,max31856"; + reg = <0>; + spi-max-frequency = <5000000>; + spi-cpha; + thermocouple-type = <THERMOCOUPLE_TYPE_K>; + }; diff --git a/Documentation/devicetree/bindings/iio/temperature/temperature-bindings.txt b/Documentation/devicetree/bindings/iio/temperature/temperature-bindings.txt new file mode 100644 index 000000000000..8f339cab74ae --- /dev/null +++ b/Documentation/devicetree/bindings/iio/temperature/temperature-bindings.txt @@ -0,0 +1,7 @@ +If the temperature sensor device can be configured to use some specific +thermocouple type, you can use the defined types provided in the file +"include/dt-bindings/iio/temperature/thermocouple.h". + +Property: +thermocouple-type: A single cell representing the type of the thermocouple + used by the device. diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 8162b0eb4b50..93753f447c20 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -210,6 +210,7 @@ kiebackpeter Kieback & Peter GmbH kinetic Kinetic Technologies kingdisplay King & Display Technology Co., Ltd. kingnovel Kingnovel Technology Co., Ltd. +kionix Kionix, Inc. koe Kaohsiung Opto-Electronics Inc. kosagi Sutajio Ko-Usagi PTE Ltd. kyo Kyocera Corporation @@ -233,6 +234,7 @@ lsi LSI Corp. (LSI Logic) lwn Liebherr-Werk Nenzing GmbH macnica Macnica Americas marvell Marvell Technology Group Ltd. +maxbotix MaxBotix Inc. maxim Maxim Integrated Products mbvl Mobiveil Inc. mcube mCube diff --git a/MAINTAINERS b/MAINTAINERS index 43b36dbed48e..e74f65ab540b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -868,7 +868,7 @@ L: linux-iio@vger.kernel.org W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/iio/adc/ad7606.c -F: Documentation/devicetree/bindings/iio/adc/ad7606.txt +F: Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt ANALOG DEVICES INC AD7768-1 DRIVER M: Stefan Popa <stefan.popa@analog.com> @@ -950,6 +950,7 @@ F: drivers/dma/dma-axi-dmac.c ANALOG DEVICES INC IIO DRIVERS M: Lars-Peter Clausen <lars@metafoo.de> M: Michael Hennerich <Michael.Hennerich@analog.com> +M: Stefan Popa <stefan.popa@analog.com> W: http://wiki.analog.com/ W: http://ez.analog.com/community/linux-device-drivers S: Supported @@ -9406,6 +9407,13 @@ S: Maintained F: Documentation/devicetree/bindings/sound/max9860.txt F: sound/soc/codecs/max9860.* +MAXBOTIX ULTRASONIC RANGER IIO DRIVER +M: Andreas Klinger <ak@it-klinger.de> +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/proximity/maxbotix,mb1232.txt +F: drivers/iio/proximity/mb1232.c + MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER M: Javier Martinez Canillas <javier@dowhile0.org> L: linux-kernel@vger.kernel.org diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index d08aeb41cd07..014006d1cbb6 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -39,28 +39,28 @@ config IIO_TRIGGER data now' interrupt. config IIO_CONSUMERS_PER_TRIGGER - int "Maximum number of consumers per trigger" - depends on IIO_TRIGGER - default "2" - help - This value controls the maximum number of consumers that a - given trigger may handle. Default is 2. + int "Maximum number of consumers per trigger" + depends on IIO_TRIGGER + default "2" + help + This value controls the maximum number of consumers that a + given trigger may handle. Default is 2. config IIO_SW_DEVICE tristate "Enable software IIO device support" select IIO_CONFIGFS help - Provides IIO core support for software devices. A software - device can be created via configfs or directly by a driver - using the API provided. + Provides IIO core support for software devices. A software + device can be created via configfs or directly by a driver + using the API provided. config IIO_SW_TRIGGER tristate "Enable software triggers support" select IIO_CONFIGFS help - Provides IIO core support for software triggers. A software - trigger can be created via configfs or directly by a driver - using the API provided. + Provides IIO core support for software triggers. A software + trigger can be created via configfs or directly by a driver + using the API provided. config IIO_TRIGGERED_EVENT tristate diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 898839ca164a..4a1f133538ba 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -6,28 +6,28 @@ menu "Accelerometers" config ADIS16201 - tristate "Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer" - depends on SPI - select IIO_ADIS_LIB - select IIO_ADIS_LIB_BUFFER if IIO_BUFFER - help - Say Y here to build support for Analog Devices adis16201 dual-axis - digital inclinometer and accelerometer. + tristate "Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer" + depends on SPI + select IIO_ADIS_LIB + select IIO_ADIS_LIB_BUFFER if IIO_BUFFER + help + Say Y here to build support for Analog Devices adis16201 dual-axis + digital inclinometer and accelerometer. - To compile this driver as a module, say M here: the module will - be called adis16201. + To compile this driver as a module, say M here: the module will + be called adis16201. config ADIS16209 - tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer" - depends on SPI - select IIO_ADIS_LIB - select IIO_ADIS_LIB_BUFFER if IIO_BUFFER - help - Say Y here to build support for Analog Devices adis16209 dual-axis digital inclinometer - and accelerometer. + tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer" + depends on SPI + select IIO_ADIS_LIB + select IIO_ADIS_LIB_BUFFER if IIO_BUFFER + help + Say Y here to build support for Analog Devices adis16209 dual-axis digital inclinometer + and accelerometer. - To compile this driver as a module, say M here: the module will be - called adis16209. + To compile this driver as a module, say M here: the module will be + called adis16209. config ADXL345 tristate @@ -100,16 +100,16 @@ config BMA180 module will be called bma180. config BMA220 - tristate "Bosch BMA220 3-Axis Accelerometer Driver" + tristate "Bosch BMA220 3-Axis Accelerometer Driver" depends on SPI select IIO_BUFFER select IIO_TRIGGERED_BUFFER - help - Say yes here to add support for the Bosch BMA220 triaxial - acceleration sensor. + help + Say yes here to add support for the Bosch BMA220 triaxial + acceleration sensor. - To compile this driver as a module, choose M here: the - module will be called bma220_spi. + To compile this driver as a module, choose M here: the + module will be called bma220_spi. config BMC150_ACCEL tristate "Bosch BMC150 Accelerometer Driver" diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index cb9765a3de60..f9720a1e8a7c 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -116,6 +116,7 @@ struct bma180_data { struct i2c_client *client; struct iio_trigger *trig; const struct bma180_part_info *part_info; + struct iio_mount_matrix orientation; struct mutex mutex; bool sleep_state; int scale; @@ -561,6 +562,15 @@ static int bma180_set_power_mode(struct iio_dev *indio_dev, return ret; } +static const struct iio_mount_matrix * +bma180_accel_get_mount_matrix(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct bma180_data *data = iio_priv(indio_dev); + + return &data->orientation; +} + static const struct iio_enum bma180_power_mode_enum = { .items = bma180_power_modes, .num_items = ARRAY_SIZE(bma180_power_modes), @@ -571,7 +581,8 @@ static const struct iio_enum bma180_power_mode_enum = { static const struct iio_chan_spec_ext_info bma180_ext_info[] = { IIO_ENUM("power_mode", true, &bma180_power_mode_enum), IIO_ENUM_AVAILABLE("power_mode", &bma180_power_mode_enum), - { }, + IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bma180_accel_get_mount_matrix), + { } }; #define BMA180_ACC_CHANNEL(_axis, _bits) { \ @@ -722,6 +733,11 @@ static int bma180_probe(struct i2c_client *client, chip = id->driver_data; data->part_info = &bma180_part_info[chip]; + ret = iio_read_mount_matrix(&client->dev, "mount-matrix", + &data->orientation); + if (ret) + return ret; + ret = data->part_info->chip_config(data); if (ret < 0) goto err_chip_disable; diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index 383c802eb5b8..b4e2d9b04e1d 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -204,6 +204,7 @@ struct bmc150_accel_data { int ev_enable_state; int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */ const struct bmc150_accel_chip_info *chip_info; + struct iio_mount_matrix orientation; }; static const struct { @@ -796,6 +797,20 @@ static ssize_t bmc150_accel_get_fifo_state(struct device *dev, return sprintf(buf, "%d\n", state); } +static const struct iio_mount_matrix * +bmc150_accel_get_mount_matrix(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct bmc150_accel_data *data = iio_priv(indio_dev); + + return &data->orientation; +} + +static const struct iio_chan_spec_ext_info bmc150_accel_ext_info[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bmc150_accel_get_mount_matrix), + { } +}; + static IIO_CONST_ATTR(hwfifo_watermark_min, "1"); static IIO_CONST_ATTR(hwfifo_watermark_max, __stringify(BMC150_ACCEL_FIFO_LENGTH)); @@ -978,6 +993,7 @@ static const struct iio_event_spec bmc150_accel_event = { .shift = 16 - (bits), \ .endianness = IIO_LE, \ }, \ + .ext_info = bmc150_accel_ext_info, \ .event_spec = &bmc150_accel_event, \ .num_event_specs = 1 \ } @@ -1555,6 +1571,11 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, data->regmap = regmap; + ret = iio_read_mount_matrix(dev, "mount-matrix", + &data->orientation); + if (ret) + return ret; + ret = bmc150_accel_chip_init(data); if (ret < 0) return ret; diff --git a/drivers/iio/accel/cros_ec_accel_legacy.c b/drivers/iio/accel/cros_ec_accel_legacy.c index 063e89eff791..46bb2e421bb9 100644 --- a/drivers/iio/accel/cros_ec_accel_legacy.c +++ b/drivers/iio/accel/cros_ec_accel_legacy.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Driver for older Chrome OS EC accelerometer * * Copyright 2017 Google, Inc * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * * This driver uses the memory mapper cros-ec interface to communicate * with the Chrome OS EC about accelerometer data. * Accelerometer access is presented through iio sysfs. @@ -29,7 +21,6 @@ #include <linux/mfd/cros_ec_commands.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/sysfs.h> #include <linux/platform_device.h> #define DRV_NAME "cros-ec-accel-legacy" @@ -353,7 +344,7 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev) struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev); struct iio_dev *indio_dev; struct cros_ec_accel_legacy_state *state; - int ret, i; + int ret; if (!ec || !ec->ec_dev) { dev_warn(&pdev->dev, "No EC device found.\n"); @@ -381,20 +372,17 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev) * Present the channel using HTML5 standard: * need to invert X and Y and invert some lid axis. */ - for (i = X ; i < MAX_AXIS; i++) { - switch (i) { - case X: - ec_accel_channels[X].scan_index = Y; - case Y: - ec_accel_channels[Y].scan_index = X; - case Z: - ec_accel_channels[Z].scan_index = Z; - } - if (state->sensor_num == MOTIONSENSE_LOC_LID && i != Y) - state->sign[i] = -1; - else - state->sign[i] = 1; - } + ec_accel_channels[X].scan_index = Y; + ec_accel_channels[Y].scan_index = X; + ec_accel_channels[Z].scan_index = Z; + + state->sign[Y] = 1; + + if (state->sensor_num == MOTIONSENSE_LOC_LID) + state->sign[X] = state->sign[Z] = -1; + else + state->sign[X] = state->sign[Z] = 1; + indio_dev->num_channels = ARRAY_SIZE(ec_accel_channels); indio_dev->dev.parent = &pdev->dev; indio_dev->info = &cros_ec_accel_legacy_info; @@ -419,5 +407,5 @@ module_platform_driver(cros_ec_accel_platform_driver); MODULE_DESCRIPTION("ChromeOS EC legacy accelerometer driver"); MODULE_AUTHOR("Gwendal Grignou <gwendal@chromium.org>"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 7096e577b23f..a9e98fdb8b23 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -1510,10 +1510,20 @@ static const struct i2c_device_id kxcjk1013_id[] = { MODULE_DEVICE_TABLE(i2c, kxcjk1013_id); +static const struct of_device_id kxcjk1013_of_match[] = { + { .compatible = "kionix,kxcjk1013", }, + { .compatible = "kionix,kxcj91008", }, + { .compatible = "kionix,kxtj21009", }, + { .compatible = "kionix,kxtf9", }, + { } +}; +MODULE_DEVICE_TABLE(of, kxcjk1013_of_match); + static struct i2c_driver kxcjk1013_driver = { .driver = { .name = KXCJK1013_DRV_NAME, .acpi_match_table = ACPI_PTR(kx_acpi_match), + .of_match_table = kxcjk1013_of_match, .pm = &kxcjk1013_pm_ops, }, .probe = kxcjk1013_probe, diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c index 0c0df4fce420..70c60db62247 100644 --- a/drivers/iio/accel/kxsd9.c +++ b/drivers/iio/accel/kxsd9.c @@ -420,9 +420,7 @@ int kxsd9_common_probe(struct device *dev, indio_dev->available_scan_masks = kxsd9_scan_masks; /* Read the mounting matrix, if present */ - ret = of_iio_read_mount_matrix(dev, - "mount-matrix", - &st->orientation); + ret = iio_read_mount_matrix(dev, "mount-matrix", &st->orientation); if (ret) return ret; diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 302781126bc6..00e100fc845a 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -1580,7 +1580,7 @@ static int mma8452_probe(struct i2c_client *client, case FXLS8471_DEVICE_ID: if (ret == data->chip_info->chip_id) break; - /* else: fall through */ + /* fall through */ default: ret = -ENODEV; goto disable_regulators; diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index a3c0916479fa..9930edf423bf 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -992,7 +992,7 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev, goto out; val = elements[i].integer.value; - if (val < 0 || val > 2) + if (val > 2) goto out; /* Avoiding full matrix multiplication, we simply reorder the diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 76db6e5cc296..846c7ace4b96 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -124,6 +124,18 @@ config AD7768_1 To compile this driver as a module, choose M here: the module will be called ad7768-1. +config AD7780 + tristate "Analog Devices AD7780 and similar ADCs driver" + depends on SPI + depends on GPIOLIB || COMPILE_TEST + select AD_SIGMA_DELTA + help + Say yes here to build support for Analog Devices AD7170, AD7171, + AD7780 and AD7781 SPI analog to digital converters (ADC). + + To compile this driver as a module, choose M here: the + module will be called ad7780. + config AD7791 tristate "Analog Devices AD7791 ADC driver" depends on SPI @@ -390,7 +402,7 @@ config HX711 This driver uses two GPIOs, one acts as the clock and controls the channel selection and gain, the other one is used for the measurement - data + data Currently the raw value is read from the chip and delivered. To get an actual weight one needs to subtract the @@ -585,17 +597,17 @@ config MCP3911 called mcp3911. config MEDIATEK_MT6577_AUXADC - tristate "MediaTek AUXADC driver" - depends on ARCH_MEDIATEK || COMPILE_TEST - depends on HAS_IOMEM - help - Say yes here to enable support for MediaTek mt65xx AUXADC. + tristate "MediaTek AUXADC driver" + depends on ARCH_MEDIATEK || COMPILE_TEST + depends on HAS_IOMEM + help + Say yes here to enable support for MediaTek mt65xx AUXADC. - The driver supports immediate mode operation to read from one of sixteen - channels (external or internal). + The driver supports immediate mode operation to read from one of sixteen + channels (external or internal). - This driver can also be built as a module. If so, the module will be - called mt6577_auxadc. + This driver can also be built as a module. If so, the module will be + called mt6577_auxadc. config MEN_Z188_ADC tristate "MEN 16z188 ADC IP Core support" diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 6fcebd167524..085a7512f8df 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o obj-$(CONFIG_AD7606) += ad7606.o obj-$(CONFIG_AD7766) += ad7766.o obj-$(CONFIG_AD7768_1) += ad7768-1.o +obj-$(CONFIG_AD7780) += ad7780.o obj-$(CONFIG_AD7791) += ad7791.o obj-$(CONFIG_AD7793) += ad7793.o obj-$(CONFIG_AD7887) += ad7887.o diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index 7d5e5311d8de..659ef37d5fe8 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -411,7 +411,7 @@ static int ad7124_init_channel_vref(struct ad7124_state *st, dev_err(&st->sd.spi->dev, "Error, trying to use external voltage reference without a %s regulator.\n", ad7124_ref_names[refsel]); - return PTR_ERR(st->vref[refsel]); + return PTR_ERR(st->vref[refsel]); } st->channel_config[channel_number].vref_mv = regulator_get_voltage(st->vref[refsel]); diff --git a/drivers/staging/iio/adc/ad7780.c b/drivers/iio/adc/ad7780.c index c15389f562b2..217a5a5c3c6d 100644 --- a/drivers/staging/iio/adc/ad7780.c +++ b/drivers/iio/adc/ad7780.c @@ -3,6 +3,7 @@ * AD7170/AD7171 and AD7780/AD7781 SPI ADC driver * * Copyright 2011 Analog Devices Inc. + * Copyright 2019 Renato Lui Geh */ #include <linux/interrupt.h> @@ -16,6 +17,7 @@ #include <linux/sched.h> #include <linux/gpio/consumer.h> #include <linux/module.h> +#include <linux/bits.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -27,16 +29,25 @@ #define AD7780_ID1 BIT(4) #define AD7780_ID0 BIT(3) #define AD7780_GAIN BIT(2) -#define AD7780_PAT1 BIT(1) -#define AD7780_PAT0 BIT(0) -#define AD7780_PATTERN (AD7780_PAT0) -#define AD7780_PATTERN_MASK (AD7780_PAT0 | AD7780_PAT1) +#define AD7170_ID 0 +#define AD7171_ID 1 +#define AD7780_ID 1 +#define AD7781_ID 0 -#define AD7170_PAT2 BIT(2) +#define AD7780_ID_MASK (AD7780_ID0 | AD7780_ID1) -#define AD7170_PATTERN (AD7780_PAT0 | AD7170_PAT2) -#define AD7170_PATTERN_MASK (AD7780_PAT0 | AD7780_PAT1 | AD7170_PAT2) +#define AD7780_PATTERN_GOOD 1 +#define AD7780_PATTERN_MASK GENMASK(1, 0) + +#define AD7170_PATTERN_GOOD 5 +#define AD7170_PATTERN_MASK GENMASK(2, 0) + +#define AD7780_GAIN_MIDPOINT 64 +#define AD7780_FILTER_MIDPOINT 13350 + +static const unsigned int ad778x_gain[2] = { 1, 128 }; +static const unsigned int ad778x_odr_avail[2] = { 10000, 16700 }; struct ad7780_chip_info { struct iio_chan_spec channel; @@ -49,7 +60,11 @@ struct ad7780_state { const struct ad7780_chip_info *chip_info; struct regulator *reg; struct gpio_desc *powerdown_gpio; - unsigned int gain; + struct gpio_desc *gain_gpio; + struct gpio_desc *filter_gpio; + unsigned int gain; + unsigned int odr; + unsigned int int_vref_mv; struct ad_sigma_delta sd; }; @@ -103,17 +118,69 @@ static int ad7780_read_raw(struct iio_dev *indio_dev, voltage_uv = regulator_get_voltage(st->reg); if (voltage_uv < 0) return voltage_uv; - *val = (voltage_uv / 1000) * st->gain; + voltage_uv /= 1000; + *val = voltage_uv * st->gain; *val2 = chan->scan_type.realbits - 1; + st->int_vref_mv = voltage_uv; return IIO_VAL_FRACTIONAL_LOG2; case IIO_CHAN_INFO_OFFSET: *val = -(1 << (chan->scan_type.realbits - 1)); return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = st->odr; + return IIO_VAL_INT; + default: + break; } return -EINVAL; } +static int ad7780_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long m) +{ + struct ad7780_state *st = iio_priv(indio_dev); + const struct ad7780_chip_info *chip_info = st->chip_info; + unsigned long long vref; + unsigned int full_scale, gain; + + if (!chip_info->is_ad778x) + return -EINVAL; + + switch (m) { + case IIO_CHAN_INFO_SCALE: + if (val != 0) + return -EINVAL; + + vref = st->int_vref_mv * 1000000LL; + full_scale = 1 << (chip_info->channel.scan_type.realbits - 1); + gain = DIV_ROUND_CLOSEST_ULL(vref, full_scale); + gain = DIV_ROUND_CLOSEST(gain, val2); + st->gain = gain; + if (gain < AD7780_GAIN_MIDPOINT) + gain = 0; + else + gain = 1; + gpiod_set_value(st->gain_gpio, gain); + break; + case IIO_CHAN_INFO_SAMP_FREQ: + if (1000*val + val2/1000 < AD7780_FILTER_MIDPOINT) + val = 0; + else + val = 1; + st->odr = ad778x_odr_avail[val]; + gpiod_set_value(st->filter_gpio, val); + break; + default: + break; + } + + return 0; +} + static int ad7780_postprocess_sample(struct ad_sigma_delta *sigma_delta, unsigned int raw_sample) { @@ -125,10 +192,8 @@ static int ad7780_postprocess_sample(struct ad_sigma_delta *sigma_delta, return -EIO; if (chip_info->is_ad778x) { - if (raw_sample & AD7780_GAIN) - st->gain = 1; - else - st->gain = 128; + st->gain = ad778x_gain[raw_sample & AD7780_GAIN]; + st->odr = ad778x_odr_avail[raw_sample & AD7780_FILTER]; } return 0; @@ -141,30 +206,32 @@ static const struct ad_sigma_delta_info ad7780_sigma_delta_info = { }; #define AD7780_CHANNEL(bits, wordsize) \ - AD_SD_CHANNEL_NO_SAMP_FREQ(1, 0, 0, bits, 32, wordsize - bits) + AD_SD_CHANNEL(1, 0, 0, bits, 32, (wordsize) - (bits)) +#define AD7170_CHANNEL(bits, wordsize) \ + AD_SD_CHANNEL_NO_SAMP_FREQ(1, 0, 0, bits, 32, (wordsize) - (bits)) static const struct ad7780_chip_info ad7780_chip_info_tbl[] = { [ID_AD7170] = { - .channel = AD7780_CHANNEL(12, 24), - .pattern = AD7170_PATTERN, + .channel = AD7170_CHANNEL(12, 24), + .pattern = AD7170_PATTERN_GOOD, .pattern_mask = AD7170_PATTERN_MASK, .is_ad778x = false, }, [ID_AD7171] = { - .channel = AD7780_CHANNEL(16, 24), - .pattern = AD7170_PATTERN, + .channel = AD7170_CHANNEL(16, 24), + .pattern = AD7170_PATTERN_GOOD, .pattern_mask = AD7170_PATTERN_MASK, .is_ad778x = false, }, [ID_AD7780] = { .channel = AD7780_CHANNEL(24, 32), - .pattern = AD7780_PATTERN, + .pattern = AD7780_PATTERN_GOOD, .pattern_mask = AD7780_PATTERN_MASK, .is_ad778x = true, }, [ID_AD7781] = { .channel = AD7780_CHANNEL(20, 32), - .pattern = AD7780_PATTERN, + .pattern = AD7780_PATTERN_GOOD, .pattern_mask = AD7780_PATTERN_MASK, .is_ad778x = true, }, @@ -172,8 +239,47 @@ static const struct ad7780_chip_info ad7780_chip_info_tbl[] = { static const struct iio_info ad7780_info = { .read_raw = ad7780_read_raw, + .write_raw = ad7780_write_raw, }; +static int ad7780_init_gpios(struct device *dev, struct ad7780_state *st) +{ + int ret; + + st->powerdown_gpio = devm_gpiod_get_optional(dev, + "powerdown", + GPIOD_OUT_LOW); + if (IS_ERR(st->powerdown_gpio)) { + ret = PTR_ERR(st->powerdown_gpio); + dev_err(dev, "Failed to request powerdown GPIO: %d\n", ret); + return ret; + } + + if (!st->chip_info->is_ad778x) + return 0; + + + st->gain_gpio = devm_gpiod_get_optional(dev, + "adi,gain", + GPIOD_OUT_HIGH); + if (IS_ERR(st->gain_gpio)) { + ret = PTR_ERR(st->gain_gpio); + dev_err(dev, "Failed to request gain GPIO: %d\n", ret); + return ret; + } + + st->filter_gpio = devm_gpiod_get_optional(dev, + "adi,filter", + GPIOD_OUT_HIGH); + if (IS_ERR(st->filter_gpio)) { + ret = PTR_ERR(st->filter_gpio); + dev_err(dev, "Failed to request filter GPIO: %d\n", ret); + return ret; + } + + return 0; +} + static int ad7780_probe(struct spi_device *spi) { struct ad7780_state *st; @@ -189,16 +295,6 @@ static int ad7780_probe(struct spi_device *spi) ad_sd_init(&st->sd, indio_dev, spi, &ad7780_sigma_delta_info); - st->reg = devm_regulator_get(&spi->dev, "avdd"); - if (IS_ERR(st->reg)) - return PTR_ERR(st->reg); - - ret = regulator_enable(st->reg); - if (ret) { - dev_err(&spi->dev, "Failed to enable specified AVdd supply\n"); - return ret; - } - st->chip_info = &ad7780_chip_info_tbl[spi_get_device_id(spi)->driver_data]; @@ -211,14 +307,18 @@ static int ad7780_probe(struct spi_device *spi) indio_dev->num_channels = 1; indio_dev->info = &ad7780_info; - st->powerdown_gpio = devm_gpiod_get_optional(&spi->dev, - "powerdown", - GPIOD_OUT_LOW); - if (IS_ERR(st->powerdown_gpio)) { - ret = PTR_ERR(st->powerdown_gpio); - dev_err(&spi->dev, "Failed to request powerdown GPIO: %d\n", - ret); - goto error_disable_reg; + ret = ad7780_init_gpios(&spi->dev, st); + if (ret) + goto error_cleanup_buffer_and_trigger; + + st->reg = devm_regulator_get(&spi->dev, "avdd"); + if (IS_ERR(st->reg)) + return PTR_ERR(st->reg); + + ret = regulator_enable(st->reg); + if (ret) { + dev_err(&spi->dev, "Failed to enable specified AVdd supply\n"); + return ret; } ret = ad_sd_setup_buffer_and_trigger(indio_dev); diff --git a/drivers/iio/adc/ad7923.c b/drivers/iio/adc/ad7923.c index d62dbb62be45..cb7b854df00c 100644 --- a/drivers/iio/adc/ad7923.c +++ b/drivers/iio/adc/ad7923.c @@ -24,9 +24,9 @@ #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> -#define AD7923_WRITE_CR (1 << 11) /* write control register */ -#define AD7923_RANGE (1 << 1) /* range to REFin */ -#define AD7923_CODING (1 << 0) /* coding is straight binary */ +#define AD7923_WRITE_CR BIT(11) /* write control register */ +#define AD7923_RANGE BIT(1) /* range to REFin */ +#define AD7923_CODING BIT(0) /* coding is straight binary */ #define AD7923_PM_MODE_AS (1) /* auto shutdown */ #define AD7923_PM_MODE_FS (2) /* full shutdown */ #define AD7923_PM_MODE_OPS (3) /* normal operation */ @@ -40,16 +40,16 @@ #define AD7923_MAX_CHAN 4 -#define AD7923_PM_MODE_WRITE(mode) (mode << 4) /* write mode */ -#define AD7923_CHANNEL_WRITE(channel) (channel << 6) /* write channel */ -#define AD7923_SEQUENCE_WRITE(sequence) (((sequence & 1) << 3) \ - + ((sequence & 2) << 9)) +#define AD7923_PM_MODE_WRITE(mode) ((mode) << 4) /* write mode */ +#define AD7923_CHANNEL_WRITE(channel) ((channel) << 6) /* write channel */ +#define AD7923_SEQUENCE_WRITE(sequence) ((((sequence) & 1) << 3) \ + + (((sequence) & 2) << 9)) /* write sequence fonction */ /* left shift for CR : bit 11 transmit in first */ #define AD7923_SHIFT_REGISTER 4 /* val = value, dec = left shift, bits = number of bits of the mask */ -#define EXTRACT(val, dec, bits) ((val >> dec) & ((1 << bits) - 1)) +#define EXTRACT(val, dec, bits) (((val) >> (dec)) & ((1 << (bits)) - 1)) struct ad7923_state { struct spi_device *spi; @@ -130,7 +130,7 @@ static const struct ad7923_chip_info ad7923_chip_info[] = { * ad7923_update_scan_mode() setup the spi transfer buffer for the new scan mask **/ static int ad7923_update_scan_mode(struct iio_dev *indio_dev, - const unsigned long *active_scan_mask) + const unsigned long *active_scan_mask) { struct ad7923_state *st = iio_priv(indio_dev); int i, cmd, len; @@ -181,7 +181,7 @@ static irqreturn_t ad7923_trigger_handler(int irq, void *p) goto done; iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, - iio_get_time_ns(indio_dev)); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); @@ -272,7 +272,7 @@ static int ad7923_probe(struct spi_device *spi) int ret; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (indio_dev == NULL) + if (!indio_dev) return -ENOMEM; st = iio_priv(indio_dev); @@ -314,7 +314,7 @@ static int ad7923_probe(struct spi_device *spi) return ret; ret = iio_triggered_buffer_setup(indio_dev, NULL, - &ad7923_trigger_handler, NULL); + &ad7923_trigger_handler, NULL); if (ret) goto error_disable_reg; diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index ff5f2da2e1b1..af6cbc683214 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -62,7 +62,7 @@ int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg, struct spi_transfer t = { .tx_buf = data, .len = size + 1, - .cs_change = sigma_delta->bus_locked, + .cs_change = sigma_delta->keep_cs_asserted, }; struct spi_message m; int ret; @@ -217,6 +217,7 @@ static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, spi_bus_lock(sigma_delta->spi->master); sigma_delta->bus_locked = true; + sigma_delta->keep_cs_asserted = true; reinit_completion(&sigma_delta->completion); ret = ad_sigma_delta_set_mode(sigma_delta, mode); @@ -234,9 +235,10 @@ static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, ret = 0; } out: + sigma_delta->keep_cs_asserted = false; + ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); sigma_delta->bus_locked = false; spi_bus_unlock(sigma_delta->spi->master); - ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); return ret; } @@ -289,6 +291,7 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev, spi_bus_lock(sigma_delta->spi->master); sigma_delta->bus_locked = true; + sigma_delta->keep_cs_asserted = true; reinit_completion(&sigma_delta->completion); ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE); @@ -298,9 +301,6 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev, ret = wait_for_completion_interruptible_timeout( &sigma_delta->completion, HZ); - sigma_delta->bus_locked = false; - spi_bus_unlock(sigma_delta->spi->master); - if (ret == 0) ret = -EIO; if (ret < 0) @@ -321,7 +321,10 @@ out: sigma_delta->irq_dis = true; } + sigma_delta->keep_cs_asserted = false; ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); + sigma_delta->bus_locked = false; + spi_bus_unlock(sigma_delta->spi->master); mutex_unlock(&indio_dev->mlock); if (ret) @@ -358,6 +361,8 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev) spi_bus_lock(sigma_delta->spi->master); sigma_delta->bus_locked = true; + sigma_delta->keep_cs_asserted = true; + ret = ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_CONTINUOUS); if (ret) goto err_unlock; @@ -386,6 +391,7 @@ static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev) sigma_delta->irq_dis = true; } + sigma_delta->keep_cs_asserted = false; ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); sigma_delta->bus_locked = false; diff --git a/drivers/iio/adc/ingenic-adc.c b/drivers/iio/adc/ingenic-adc.c index 6ee1673deb0d..92b1d5037ac9 100644 --- a/drivers/iio/adc/ingenic-adc.c +++ b/drivers/iio/adc/ingenic-adc.c @@ -302,10 +302,8 @@ static int ingenic_adc_probe(struct platform_device *pdev) mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); adc->base = devm_ioremap_resource(dev, mem_base); - if (IS_ERR(adc->base)) { - dev_err(dev, "Unable to ioremap mmio resource\n"); + if (IS_ERR(adc->base)) return PTR_ERR(adc->base); - } adc->clk = devm_clk_get(dev, "adc"); if (IS_ERR(adc->clk)) { diff --git a/drivers/iio/adc/lpc32xx_adc.c b/drivers/iio/adc/lpc32xx_adc.c index e361c1532a75..a6ee1c3a9064 100644 --- a/drivers/iio/adc/lpc32xx_adc.c +++ b/drivers/iio/adc/lpc32xx_adc.c @@ -7,20 +7,15 @@ * Copyright (C) 2011, 2012 Roland Stigge <stigge@antcom.de> */ -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/device.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/io.h> #include <linux/clk.h> -#include <linux/err.h> #include <linux/completion.h> -#include <linux/of.h> - +#include <linux/err.h> #include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> /* * LPC32XX registers definitions @@ -52,6 +47,7 @@ struct lpc32xx_adc_state { void __iomem *adc_base; struct clk *clk; struct completion completion; + struct regulator *vref; u32 value; }; @@ -64,7 +60,9 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev, { struct lpc32xx_adc_state *st = iio_priv(indio_dev); int ret; - if (mask == IIO_CHAN_INFO_RAW) { + + switch (mask) { + case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); ret = clk_prepare_enable(st->clk); if (ret) { @@ -84,22 +82,36 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev, mutex_unlock(&indio_dev->mlock); return IIO_VAL_INT; - } - return -EINVAL; + case IIO_CHAN_INFO_SCALE: + *val = regulator_get_voltage(st->vref) / 1000; + *val2 = 10; + + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } } static const struct iio_info lpc32xx_adc_iio_info = { .read_raw = &lpc32xx_read_raw, }; -#define LPC32XX_ADC_CHANNEL(_index) { \ +#define LPC32XX_ADC_CHANNEL_BASE(_index) \ .type = IIO_VOLTAGE, \ .indexed = 1, \ .channel = _index, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .address = LPC32XXAD_IN * _index, \ - .scan_index = _index, \ + .scan_index = _index, + +#define LPC32XX_ADC_CHANNEL(_index) { \ + LPC32XX_ADC_CHANNEL_BASE(_index) \ +} + +#define LPC32XX_ADC_SCALE_CHANNEL(_index) { \ + LPC32XX_ADC_CHANNEL_BASE(_index) \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ } static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = { @@ -108,6 +120,12 @@ static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = { LPC32XX_ADC_CHANNEL(2), }; +static const struct iio_chan_spec lpc32xx_adc_iio_scale_channels[] = { + LPC32XX_ADC_SCALE_CHANNEL(0), + LPC32XX_ADC_SCALE_CHANNEL(1), + LPC32XX_ADC_SCALE_CHANNEL(2), +}; + static irqreturn_t lpc32xx_adc_isr(int irq, void *dev_id) { struct lpc32xx_adc_state *st = dev_id; @@ -166,6 +184,15 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) return retval; } + st->vref = devm_regulator_get(&pdev->dev, "vref"); + if (IS_ERR(st->vref)) { + iodev->channels = lpc32xx_adc_iio_channels; + dev_info(&pdev->dev, + "Missing vref regulator: No scaling available\n"); + } else { + iodev->channels = lpc32xx_adc_iio_scale_channels; + } + platform_set_drvdata(pdev, iodev); init_completion(&st->completion); @@ -174,7 +201,6 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) iodev->dev.parent = &pdev->dev; iodev->info = &lpc32xx_adc_iio_info; iodev->modes = INDIO_DIRECT_MODE; - iodev->channels = lpc32xx_adc_iio_channels; iodev->num_channels = ARRAY_SIZE(lpc32xx_adc_iio_channels); retval = devm_iio_device_register(&pdev->dev, iodev); diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index f8600fbcdfe3..510d8b7ef3a0 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -1150,6 +1150,11 @@ static const struct meson_sar_adc_data meson_sar_adc_axg_data = { .name = "meson-axg-saradc", }; +static const struct meson_sar_adc_data meson_sar_adc_g12a_data = { + .param = &meson_sar_adc_gxl_param, + .name = "meson-g12a-saradc", +}; + static const struct of_device_id meson_sar_adc_of_match[] = { { .compatible = "amlogic,meson8-saradc", @@ -1175,6 +1180,9 @@ static const struct of_device_id meson_sar_adc_of_match[] = { }, { .compatible = "amlogic,meson-axg-saradc", .data = &meson_sar_adc_axg_data, + }, { + .compatible = "amlogic,meson-g12a-saradc", + .data = &meson_sar_adc_g12a_data, }, {}, }; diff --git a/drivers/iio/adc/mxs-lradc-adc.c b/drivers/iio/adc/mxs-lradc-adc.c index c627513d9f0f..5384472b6c4d 100644 --- a/drivers/iio/adc/mxs-lradc-adc.c +++ b/drivers/iio/adc/mxs-lradc-adc.c @@ -465,6 +465,8 @@ static int mxs_lradc_adc_trigger_init(struct iio_dev *iio) trig = devm_iio_trigger_alloc(&iio->dev, "%s-dev%i", iio->name, iio->id); + if (!trig) + return -ENOMEM; trig->dev.parent = adc->dev; iio_trigger_set_drvdata(trig, iio); diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index fcd4a1c00ca0..19adc2b23472 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -12,6 +12,11 @@ #include <linux/iio/buffer.h> #include <linux/iio/hw-consumer.h> #include <linux/iio/sysfs.h> +#include <linux/iio/timer/stm32-lptim-trigger.h> +#include <linux/iio/timer/stm32-timer-trigger.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> #include <linux/interrupt.h> #include <linux/module.h> #include <linux/of_device.h> @@ -38,6 +43,11 @@ #define DFSDM_MAX_RES BIT(31) #define DFSDM_DATA_RES BIT(23) +/* Filter configuration */ +#define DFSDM_CR1_CFG_MASK (DFSDM_CR1_RCH_MASK | DFSDM_CR1_RCONT_MASK | \ + DFSDM_CR1_RSYNC_MASK | DFSDM_CR1_JSYNC_MASK | \ + DFSDM_CR1_JSCAN_MASK) + enum sd_converter_type { DFSDM_AUDIO, DFSDM_IIO, @@ -54,6 +64,8 @@ struct stm32_dfsdm_adc { struct stm32_dfsdm *dfsdm; const struct stm32_dfsdm_dev_data *dev_data; unsigned int fl_id; + unsigned int nconv; + unsigned long smask; /* ADC specific */ unsigned int oversamp; @@ -114,6 +126,61 @@ static int stm32_dfsdm_str2val(const char *str, return -EINVAL; } +/** + * struct stm32_dfsdm_trig_info - DFSDM trigger info + * @name: name of the trigger, corresponding to its source + * @jextsel: trigger signal selection + */ +struct stm32_dfsdm_trig_info { + const char *name; + unsigned int jextsel; +}; + +/* hardware injected trigger enable, edge selection */ +enum stm32_dfsdm_jexten { + STM32_DFSDM_JEXTEN_DISABLED, + STM32_DFSDM_JEXTEN_RISING_EDGE, + STM32_DFSDM_JEXTEN_FALLING_EDGE, + STM32_DFSDM_EXTEN_BOTH_EDGES, +}; + +static const struct stm32_dfsdm_trig_info stm32_dfsdm_trigs[] = { + { TIM1_TRGO, 0 }, + { TIM1_TRGO2, 1 }, + { TIM8_TRGO, 2 }, + { TIM8_TRGO2, 3 }, + { TIM3_TRGO, 4 }, + { TIM4_TRGO, 5 }, + { TIM16_OC1, 6 }, + { TIM6_TRGO, 7 }, + { TIM7_TRGO, 8 }, + { LPTIM1_OUT, 26 }, + { LPTIM2_OUT, 27 }, + { LPTIM3_OUT, 28 }, + {}, +}; + +static int stm32_dfsdm_get_jextsel(struct iio_dev *indio_dev, + struct iio_trigger *trig) +{ + int i; + + /* lookup triggers registered by stm32 timer trigger driver */ + for (i = 0; stm32_dfsdm_trigs[i].name; i++) { + /** + * Checking both stm32 timer trigger type and trig name + * should be safe against arbitrary trigger names. + */ + if ((is_stm32_timer_trigger(trig) || + is_stm32_lptim_trigger(trig)) && + !strcmp(stm32_dfsdm_trigs[i].name, trig->name)) { + return stm32_dfsdm_trigs[i].jextsel; + } + } + + return -EINVAL; +} + static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl, unsigned int fast, unsigned int oversamp) { @@ -200,19 +267,39 @@ static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl, return 0; } -static int stm32_dfsdm_start_channel(struct stm32_dfsdm *dfsdm, - unsigned int ch_id) +static int stm32_dfsdm_start_channel(struct stm32_dfsdm_adc *adc) { - return regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(ch_id), - DFSDM_CHCFGR1_CHEN_MASK, - DFSDM_CHCFGR1_CHEN(1)); + struct iio_dev *indio_dev = iio_priv_to_dev(adc); + struct regmap *regmap = adc->dfsdm->regmap; + const struct iio_chan_spec *chan; + unsigned int bit; + int ret; + + for_each_set_bit(bit, &adc->smask, sizeof(adc->smask) * BITS_PER_BYTE) { + chan = indio_dev->channels + bit; + ret = regmap_update_bits(regmap, DFSDM_CHCFGR1(chan->channel), + DFSDM_CHCFGR1_CHEN_MASK, + DFSDM_CHCFGR1_CHEN(1)); + if (ret < 0) + return ret; + } + + return 0; } -static void stm32_dfsdm_stop_channel(struct stm32_dfsdm *dfsdm, - unsigned int ch_id) +static void stm32_dfsdm_stop_channel(struct stm32_dfsdm_adc *adc) { - regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(ch_id), - DFSDM_CHCFGR1_CHEN_MASK, DFSDM_CHCFGR1_CHEN(0)); + struct iio_dev *indio_dev = iio_priv_to_dev(adc); + struct regmap *regmap = adc->dfsdm->regmap; + const struct iio_chan_spec *chan; + unsigned int bit; + + for_each_set_bit(bit, &adc->smask, sizeof(adc->smask) * BITS_PER_BYTE) { + chan = indio_dev->channels + bit; + regmap_update_bits(regmap, DFSDM_CHCFGR1(chan->channel), + DFSDM_CHCFGR1_CHEN_MASK, + DFSDM_CHCFGR1_CHEN(0)); + } } static int stm32_dfsdm_chan_configure(struct stm32_dfsdm *dfsdm, @@ -237,9 +324,11 @@ static int stm32_dfsdm_chan_configure(struct stm32_dfsdm *dfsdm, DFSDM_CHCFGR1_CHINSEL(ch->alt_si)); } -static int stm32_dfsdm_start_filter(struct stm32_dfsdm *dfsdm, - unsigned int fl_id) +static int stm32_dfsdm_start_filter(struct stm32_dfsdm_adc *adc, + unsigned int fl_id, + struct iio_trigger *trig) { + struct stm32_dfsdm *dfsdm = adc->dfsdm; int ret; /* Enable filter */ @@ -248,7 +337,11 @@ static int stm32_dfsdm_start_filter(struct stm32_dfsdm *dfsdm, if (ret < 0) return ret; - /* Start conversion */ + /* Nothing more to do for injected (scan mode/triggered) conversions */ + if (adc->nconv > 1 || trig) + return 0; + + /* Software start (single or continuous) regular conversion */ return regmap_update_bits(dfsdm->regmap, DFSDM_CR1(fl_id), DFSDM_CR1_RSWSTART_MASK, DFSDM_CR1_RSWSTART(1)); @@ -262,11 +355,45 @@ static void stm32_dfsdm_stop_filter(struct stm32_dfsdm *dfsdm, DFSDM_CR1_DFEN_MASK, DFSDM_CR1_DFEN(0)); } -static int stm32_dfsdm_filter_configure(struct stm32_dfsdm *dfsdm, - unsigned int fl_id, unsigned int ch_id) +static int stm32_dfsdm_filter_set_trig(struct stm32_dfsdm_adc *adc, + unsigned int fl_id, + struct iio_trigger *trig) { - struct regmap *regmap = dfsdm->regmap; - struct stm32_dfsdm_filter *fl = &dfsdm->fl_list[fl_id]; + struct iio_dev *indio_dev = iio_priv_to_dev(adc); + struct regmap *regmap = adc->dfsdm->regmap; + u32 jextsel = 0, jexten = STM32_DFSDM_JEXTEN_DISABLED; + int ret; + + if (trig) { + ret = stm32_dfsdm_get_jextsel(indio_dev, trig); + if (ret < 0) + return ret; + + /* set trigger source and polarity (default to rising edge) */ + jextsel = ret; + jexten = STM32_DFSDM_JEXTEN_RISING_EDGE; + } + + ret = regmap_update_bits(regmap, DFSDM_CR1(fl_id), + DFSDM_CR1_JEXTSEL_MASK | DFSDM_CR1_JEXTEN_MASK, + DFSDM_CR1_JEXTSEL(jextsel) | + DFSDM_CR1_JEXTEN(jexten)); + if (ret < 0) + return ret; + + return 0; +} + +static int stm32_dfsdm_filter_configure(struct stm32_dfsdm_adc *adc, + unsigned int fl_id, + struct iio_trigger *trig) +{ + struct iio_dev *indio_dev = iio_priv_to_dev(adc); + struct regmap *regmap = adc->dfsdm->regmap; + struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[fl_id]; + u32 cr1; + const struct iio_chan_spec *chan; + unsigned int bit, jchg = 0; int ret; /* Average integrator oversampling */ @@ -286,15 +413,68 @@ static int stm32_dfsdm_filter_configure(struct stm32_dfsdm *dfsdm, if (ret) return ret; - /* No scan mode supported for the moment */ - ret = regmap_update_bits(regmap, DFSDM_CR1(fl_id), DFSDM_CR1_RCH_MASK, - DFSDM_CR1_RCH(ch_id)); + ret = stm32_dfsdm_filter_set_trig(adc, fl_id, trig); if (ret) return ret; - return regmap_update_bits(regmap, DFSDM_CR1(fl_id), - DFSDM_CR1_RSYNC_MASK, - DFSDM_CR1_RSYNC(fl->sync_mode)); + /* + * DFSDM modes configuration W.R.T audio/iio type modes + * ---------------------------------------------------------------- + * Modes | regular | regular | injected | injected | + * | | continuous | | + scan | + * --------------|---------|--------------|----------|------------| + * single conv | x | | | | + * (1 chan) | | | | | + * --------------|---------|--------------|----------|------------| + * 1 Audio chan | | sample freq | | | + * | | or sync_mode | | | + * --------------|---------|--------------|----------|------------| + * 1 IIO chan | | sample freq | trigger | | + * | | or sync_mode | | | + * --------------|---------|--------------|----------|------------| + * 2+ IIO chans | | | | trigger or | + * | | | | sync_mode | + * ---------------------------------------------------------------- + */ + if (adc->nconv == 1 && !trig) { + bit = __ffs(adc->smask); + chan = indio_dev->channels + bit; + + /* Use regular conversion for single channel without trigger */ + cr1 = DFSDM_CR1_RCH(chan->channel); + + /* Continuous conversions triggered by SPI clk in buffer mode */ + if (indio_dev->currentmode & INDIO_BUFFER_SOFTWARE) + cr1 |= DFSDM_CR1_RCONT(1); + + cr1 |= DFSDM_CR1_RSYNC(fl->sync_mode); + } else { + /* Use injected conversion for multiple channels */ + for_each_set_bit(bit, &adc->smask, + sizeof(adc->smask) * BITS_PER_BYTE) { + chan = indio_dev->channels + bit; + jchg |= BIT(chan->channel); + } + ret = regmap_write(regmap, DFSDM_JCHGR(fl_id), jchg); + if (ret < 0) + return ret; + + /* Use scan mode for multiple channels */ + cr1 = DFSDM_CR1_JSCAN((adc->nconv > 1) ? 1 : 0); + + /* + * Continuous conversions not supported in injected mode, + * either use: + * - conversions in sync with filter 0 + * - triggered conversions + */ + if (!fl->sync_mode && !trig) + return -EINVAL; + cr1 |= DFSDM_CR1_JSYNC(fl->sync_mode); + } + + return regmap_update_bits(regmap, DFSDM_CR1(fl_id), DFSDM_CR1_CFG_MASK, + cr1); } static int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm, @@ -378,13 +558,38 @@ static ssize_t dfsdm_adc_audio_get_spiclk(struct iio_dev *indio_dev, return snprintf(buf, PAGE_SIZE, "%d\n", adc->spi_freq); } +static int dfsdm_adc_set_samp_freq(struct iio_dev *indio_dev, + unsigned int sample_freq, + unsigned int spi_freq) +{ + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; + unsigned int oversamp; + int ret; + + oversamp = DIV_ROUND_CLOSEST(spi_freq, sample_freq); + if (spi_freq % sample_freq) + dev_dbg(&indio_dev->dev, + "Rate not accurate. requested (%u), actual (%u)\n", + sample_freq, spi_freq / oversamp); + + ret = stm32_dfsdm_set_osrs(fl, 0, oversamp); + if (ret < 0) { + dev_err(&indio_dev->dev, "No filter parameters that match!\n"); + return ret; + } + adc->sample_freq = spi_freq / oversamp; + adc->oversamp = oversamp; + + return 0; +} + static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, uintptr_t priv, const struct iio_chan_spec *chan, const char *buf, size_t len) { struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); - struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[chan->channel]; unsigned int sample_freq = adc->sample_freq; unsigned int spi_freq; @@ -403,17 +608,9 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, return -EINVAL; if (sample_freq) { - if (spi_freq % sample_freq) - dev_warn(&indio_dev->dev, - "Sampling rate not accurate (%d)\n", - spi_freq / (spi_freq / sample_freq)); - - ret = stm32_dfsdm_set_osrs(fl, 0, (spi_freq / sample_freq)); - if (ret < 0) { - dev_err(&indio_dev->dev, - "No filter parameters that match!\n"); + ret = dfsdm_adc_set_samp_freq(indio_dev, sample_freq, spi_freq); + if (ret < 0) return ret; - } } adc->spi_freq = spi_freq; @@ -421,72 +618,44 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, } static int stm32_dfsdm_start_conv(struct stm32_dfsdm_adc *adc, - const struct iio_chan_spec *chan, - bool dma) + struct iio_trigger *trig) { struct regmap *regmap = adc->dfsdm->regmap; int ret; - unsigned int dma_en = 0, cont_en = 0; - ret = stm32_dfsdm_start_channel(adc->dfsdm, chan->channel); + ret = stm32_dfsdm_start_channel(adc); if (ret < 0) return ret; - ret = stm32_dfsdm_filter_configure(adc->dfsdm, adc->fl_id, - chan->channel); + ret = stm32_dfsdm_filter_configure(adc, adc->fl_id, trig); if (ret < 0) goto stop_channels; - if (dma) { - /* Enable DMA transfer*/ - dma_en = DFSDM_CR1_RDMAEN(1); - /* Enable conversion triggered by SPI clock*/ - cont_en = DFSDM_CR1_RCONT(1); - } - /* Enable DMA transfer*/ - ret = regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), - DFSDM_CR1_RDMAEN_MASK, dma_en); + ret = stm32_dfsdm_start_filter(adc, adc->fl_id, trig); if (ret < 0) - goto stop_channels; - - /* Enable conversion triggered by SPI clock*/ - ret = regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), - DFSDM_CR1_RCONT_MASK, cont_en); - if (ret < 0) - goto stop_channels; - - ret = stm32_dfsdm_start_filter(adc->dfsdm, adc->fl_id); - if (ret < 0) - goto stop_channels; + goto filter_unconfigure; return 0; -stop_channels: - regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), - DFSDM_CR1_RDMAEN_MASK, 0); - +filter_unconfigure: regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), - DFSDM_CR1_RCONT_MASK, 0); - stm32_dfsdm_stop_channel(adc->dfsdm, chan->channel); + DFSDM_CR1_CFG_MASK, 0); +stop_channels: + stm32_dfsdm_stop_channel(adc); return ret; } -static void stm32_dfsdm_stop_conv(struct stm32_dfsdm_adc *adc, - const struct iio_chan_spec *chan) +static void stm32_dfsdm_stop_conv(struct stm32_dfsdm_adc *adc) { struct regmap *regmap = adc->dfsdm->regmap; stm32_dfsdm_stop_filter(adc->dfsdm, adc->fl_id); - /* Clean conversion options */ - regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), - DFSDM_CR1_RDMAEN_MASK, 0); - regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), - DFSDM_CR1_RCONT_MASK, 0); + DFSDM_CR1_CFG_MASK, 0); - stm32_dfsdm_stop_channel(adc->dfsdm, chan->channel); + stm32_dfsdm_stop_channel(adc); } static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev, @@ -494,6 +663,7 @@ static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev, { struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); unsigned int watermark = DFSDM_DMA_BUFFER_SIZE / 2; + unsigned int rx_buf_sz = DFSDM_DMA_BUFFER_SIZE; /* * DMA cyclic transfers are used, buffer is split into two periods. @@ -502,7 +672,7 @@ static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev, * - one buffer (period) driver pushed to ASoC side. */ watermark = min(watermark, val * (unsigned int)(sizeof(u32))); - adc->buf_sz = watermark * 2; + adc->buf_sz = min(rx_buf_sz, watermark * 2 * adc->nconv); return 0; } @@ -532,13 +702,41 @@ static unsigned int stm32_dfsdm_adc_dma_residue(struct stm32_dfsdm_adc *adc) return 0; } -static void stm32_dfsdm_audio_dma_buffer_done(void *data) +static irqreturn_t stm32_dfsdm_adc_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + int available = stm32_dfsdm_adc_dma_residue(adc); + + while (available >= indio_dev->scan_bytes) { + u32 *buffer = (u32 *)&adc->rx_buf[adc->bufi]; + + iio_push_to_buffers_with_timestamp(indio_dev, buffer, + pf->timestamp); + available -= indio_dev->scan_bytes; + adc->bufi += indio_dev->scan_bytes; + if (adc->bufi >= adc->buf_sz) + adc->bufi = 0; + } + + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static void stm32_dfsdm_dma_buffer_done(void *data) { struct iio_dev *indio_dev = data; struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); int available = stm32_dfsdm_adc_dma_residue(adc); size_t old_pos; + if (indio_dev->currentmode & INDIO_BUFFER_TRIGGERED) { + iio_trigger_poll_chained(indio_dev->trig); + return; + } + /* * FIXME: In Kernel interface does not support cyclic DMA buffer,and * offers only an interface to push data samples per samples. @@ -566,6 +764,9 @@ static void stm32_dfsdm_audio_dma_buffer_done(void *data) adc->bufi = 0; old_pos = 0; } + /* regular iio buffer without trigger */ + if (adc->dev_data->type == DFSDM_IIO) + iio_push_to_buffers(indio_dev, buffer); } if (adc->cb) adc->cb(&adc->rx_buf[old_pos], adc->bufi - old_pos, @@ -575,6 +776,10 @@ static void stm32_dfsdm_audio_dma_buffer_done(void *data) static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) { struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + struct dma_slave_config config = { + .src_addr = (dma_addr_t)adc->dfsdm->phys_base, + .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, + }; struct dma_async_tx_descriptor *desc; dma_cookie_t cookie; int ret; @@ -585,6 +790,14 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) dev_dbg(&indio_dev->dev, "%s size=%d watermark=%d\n", __func__, adc->buf_sz, adc->buf_sz / 2); + if (adc->nconv == 1 && !indio_dev->trig) + config.src_addr += DFSDM_RDATAR(adc->fl_id); + else + config.src_addr += DFSDM_JDATAR(adc->fl_id); + ret = dmaengine_slave_config(adc->dma_chan, &config); + if (ret) + return ret; + /* Prepare a DMA cyclic transaction */ desc = dmaengine_prep_dma_cyclic(adc->dma_chan, adc->dma_buf, @@ -594,71 +807,154 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) if (!desc) return -EBUSY; - desc->callback = stm32_dfsdm_audio_dma_buffer_done; + desc->callback = stm32_dfsdm_dma_buffer_done; desc->callback_param = indio_dev; cookie = dmaengine_submit(desc); ret = dma_submit_error(cookie); - if (ret) { - dmaengine_terminate_all(adc->dma_chan); - return ret; - } + if (ret) + goto err_stop_dma; /* Issue pending DMA requests */ dma_async_issue_pending(adc->dma_chan); + if (adc->nconv == 1 && !indio_dev->trig) { + /* Enable regular DMA transfer*/ + ret = regmap_update_bits(adc->dfsdm->regmap, + DFSDM_CR1(adc->fl_id), + DFSDM_CR1_RDMAEN_MASK, + DFSDM_CR1_RDMAEN_MASK); + } else { + /* Enable injected DMA transfer*/ + ret = regmap_update_bits(adc->dfsdm->regmap, + DFSDM_CR1(adc->fl_id), + DFSDM_CR1_JDMAEN_MASK, + DFSDM_CR1_JDMAEN_MASK); + } + + if (ret < 0) + goto err_stop_dma; + return 0; + +err_stop_dma: + dmaengine_terminate_all(adc->dma_chan); + + return ret; } -static int stm32_dfsdm_postenable(struct iio_dev *indio_dev) +static void stm32_dfsdm_adc_dma_stop(struct iio_dev *indio_dev) +{ + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + + if (!adc->dma_chan) + return; + + regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR1(adc->fl_id), + DFSDM_CR1_RDMAEN_MASK | DFSDM_CR1_JDMAEN_MASK, 0); + dmaengine_terminate_all(adc->dma_chan); +} + +static int stm32_dfsdm_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + + adc->nconv = bitmap_weight(scan_mask, indio_dev->masklength); + adc->smask = *scan_mask; + + dev_dbg(&indio_dev->dev, "nconv=%d mask=%lx\n", adc->nconv, *scan_mask); + + return 0; +} + +static int __stm32_dfsdm_postenable(struct iio_dev *indio_dev) { struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); - const struct iio_chan_spec *chan = &indio_dev->channels[0]; int ret; /* Reset adc buffer index */ adc->bufi = 0; + if (adc->hwc) { + ret = iio_hw_consumer_enable(adc->hwc); + if (ret < 0) + return ret; + } + ret = stm32_dfsdm_start_dfsdm(adc->dfsdm); if (ret < 0) - return ret; + goto err_stop_hwc; - ret = stm32_dfsdm_start_conv(adc, chan, true); + ret = stm32_dfsdm_adc_dma_start(indio_dev); if (ret) { - dev_err(&indio_dev->dev, "Can't start conversion\n"); + dev_err(&indio_dev->dev, "Can't start DMA\n"); goto stop_dfsdm; } - if (adc->dma_chan) { - ret = stm32_dfsdm_adc_dma_start(indio_dev); - if (ret) { - dev_err(&indio_dev->dev, "Can't start DMA\n"); - goto err_stop_conv; - } + ret = stm32_dfsdm_start_conv(adc, indio_dev->trig); + if (ret) { + dev_err(&indio_dev->dev, "Can't start conversion\n"); + goto err_stop_dma; } return 0; -err_stop_conv: - stm32_dfsdm_stop_conv(adc, chan); +err_stop_dma: + stm32_dfsdm_adc_dma_stop(indio_dev); stop_dfsdm: stm32_dfsdm_stop_dfsdm(adc->dfsdm); +err_stop_hwc: + if (adc->hwc) + iio_hw_consumer_disable(adc->hwc); return ret; } -static int stm32_dfsdm_predisable(struct iio_dev *indio_dev) +static int stm32_dfsdm_postenable(struct iio_dev *indio_dev) +{ + int ret; + + if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { + ret = iio_triggered_buffer_postenable(indio_dev); + if (ret < 0) + return ret; + } + + ret = __stm32_dfsdm_postenable(indio_dev); + if (ret < 0) + goto err_predisable; + + return 0; + +err_predisable: + if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) + iio_triggered_buffer_predisable(indio_dev); + + return ret; +} + +static void __stm32_dfsdm_predisable(struct iio_dev *indio_dev) { struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); - const struct iio_chan_spec *chan = &indio_dev->channels[0]; - if (adc->dma_chan) - dmaengine_terminate_all(adc->dma_chan); + stm32_dfsdm_stop_conv(adc); - stm32_dfsdm_stop_conv(adc, chan); + stm32_dfsdm_adc_dma_stop(indio_dev); stm32_dfsdm_stop_dfsdm(adc->dfsdm); + if (adc->hwc) + iio_hw_consumer_disable(adc->hwc); +} + +static int stm32_dfsdm_predisable(struct iio_dev *indio_dev) +{ + __stm32_dfsdm_predisable(indio_dev); + + if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) + iio_triggered_buffer_predisable(indio_dev); + return 0; } @@ -736,7 +1032,9 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev, if (ret < 0) goto stop_dfsdm; - ret = stm32_dfsdm_start_conv(adc, chan, false); + adc->nconv = 1; + adc->smask = BIT(chan->scan_index); + ret = stm32_dfsdm_start_conv(adc, NULL); if (ret < 0) { regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR2(adc->fl_id), DFSDM_CR2_REOCIE_MASK, DFSDM_CR2_REOCIE(0)); @@ -757,7 +1055,7 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev, else ret = IIO_VAL_INT; - stm32_dfsdm_stop_conv(adc, chan); + stm32_dfsdm_stop_conv(adc); stop_dfsdm: stm32_dfsdm_stop_dfsdm(adc->dfsdm); @@ -777,16 +1075,23 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; ret = stm32_dfsdm_set_osrs(fl, 0, val); if (!ret) adc->oversamp = val; - + iio_device_release_direct_mode(indio_dev); return ret; case IIO_CHAN_INFO_SAMP_FREQ: if (!val) return -EINVAL; + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + switch (ch->src) { case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL: spi_freq = adc->dfsdm->spi_master_freq; @@ -799,20 +1104,9 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev, spi_freq = adc->spi_freq; } - if (spi_freq % val) - dev_warn(&indio_dev->dev, - "Sampling rate not accurate (%d)\n", - spi_freq / (spi_freq / val)); - - ret = stm32_dfsdm_set_osrs(fl, 0, (spi_freq / val)); - if (ret < 0) { - dev_err(&indio_dev->dev, - "Not able to find parameter that match!\n"); - return ret; - } - adc->sample_freq = val; - - return 0; + ret = dfsdm_adc_set_samp_freq(indio_dev, val, spi_freq); + iio_device_release_direct_mode(indio_dev); + return ret; } return -EINVAL; @@ -827,11 +1121,15 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; ret = iio_hw_consumer_enable(adc->hwc); if (ret < 0) { dev_err(&indio_dev->dev, "%s: IIO enable failed (channel %d)\n", __func__, chan->channel); + iio_device_release_direct_mode(indio_dev); return ret; } ret = stm32_dfsdm_single_conv(indio_dev, chan, val); @@ -840,8 +1138,10 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, dev_err(&indio_dev->dev, "%s: Conversion failed (channel %d)\n", __func__, chan->channel); + iio_device_release_direct_mode(indio_dev); return ret; } + iio_device_release_direct_mode(indio_dev); return IIO_VAL_INT; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: @@ -858,15 +1158,25 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, return -EINVAL; } +static int stm32_dfsdm_validate_trigger(struct iio_dev *indio_dev, + struct iio_trigger *trig) +{ + return stm32_dfsdm_get_jextsel(indio_dev, trig) < 0 ? -EINVAL : 0; +} + static const struct iio_info stm32_dfsdm_info_audio = { .hwfifo_set_watermark = stm32_dfsdm_set_watermark, .read_raw = stm32_dfsdm_read_raw, .write_raw = stm32_dfsdm_write_raw, + .update_scan_mode = stm32_dfsdm_update_scan_mode, }; static const struct iio_info stm32_dfsdm_info_adc = { + .hwfifo_set_watermark = stm32_dfsdm_set_watermark, .read_raw = stm32_dfsdm_read_raw, .write_raw = stm32_dfsdm_write_raw, + .update_scan_mode = stm32_dfsdm_update_scan_mode, + .validate_trigger = stm32_dfsdm_validate_trigger, }; static irqreturn_t stm32_dfsdm_irq(int irq, void *arg) @@ -926,12 +1236,6 @@ static void stm32_dfsdm_dma_release(struct iio_dev *indio_dev) static int stm32_dfsdm_dma_request(struct iio_dev *indio_dev) { struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); - struct dma_slave_config config = { - .src_addr = (dma_addr_t)adc->dfsdm->phys_base + - DFSDM_RDATAR(adc->fl_id), - .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, - }; - int ret; adc->dma_chan = dma_request_slave_channel(&indio_dev->dev, "rx"); if (!adc->dma_chan) @@ -941,23 +1245,14 @@ static int stm32_dfsdm_dma_request(struct iio_dev *indio_dev) DFSDM_DMA_BUFFER_SIZE, &adc->dma_buf, GFP_KERNEL); if (!adc->rx_buf) { - ret = -ENOMEM; - goto err_release; + dma_release_channel(adc->dma_chan); + return -ENOMEM; } - ret = dmaengine_slave_config(adc->dma_chan, &config); - if (ret) - goto err_free; + indio_dev->modes |= INDIO_BUFFER_SOFTWARE; + indio_dev->setup_ops = &stm32_dfsdm_buffer_setup_ops; return 0; - -err_free: - dma_free_coherent(adc->dma_chan->device->dev, DFSDM_DMA_BUFFER_SIZE, - adc->rx_buf, adc->dma_buf); -err_release: - dma_release_channel(adc->dma_chan); - - return ret; } static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, @@ -978,7 +1273,8 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, * IIO_CHAN_INFO_OVERSAMPLING_RATIO: used to set oversampling */ ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); - ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO); + ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) | + BIT(IIO_CHAN_INFO_SAMP_FREQ); if (adc->dev_data->type == DFSDM_AUDIO) { ch->scan_type.sign = 's'; @@ -1000,9 +1296,6 @@ static int stm32_dfsdm_audio_init(struct iio_dev *indio_dev) struct stm32_dfsdm_channel *d_ch; int ret; - indio_dev->modes |= INDIO_BUFFER_SOFTWARE; - indio_dev->setup_ops = &stm32_dfsdm_buffer_setup_ops; - ch = devm_kzalloc(&indio_dev->dev, sizeof(*ch), GFP_KERNEL); if (!ch) return -ENOMEM; @@ -1070,6 +1363,25 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) init_completion(&adc->completion); + /* Optionally request DMA */ + if (stm32_dfsdm_dma_request(indio_dev)) { + dev_dbg(&indio_dev->dev, "No DMA support\n"); + return 0; + } + + ret = iio_triggered_buffer_setup(indio_dev, + &iio_pollfunc_store_time, + &stm32_dfsdm_adc_trigger_handler, + &stm32_dfsdm_buffer_setup_ops); + if (ret) { + stm32_dfsdm_dma_release(indio_dev); + dev_err(&indio_dev->dev, "buffer setup failed\n"); + return ret; + } + + /* lptimer/timer hardware triggers */ + indio_dev->modes |= INDIO_HARDWARE_TRIGGERED; + return 0; } @@ -1117,7 +1429,7 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) iio->dev.parent = dev; iio->dev.of_node = np; - iio->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; + iio->modes = INDIO_DIRECT_MODE; platform_set_drvdata(pdev, adc); @@ -1203,10 +1515,48 @@ static int stm32_dfsdm_adc_remove(struct platform_device *pdev) return 0; } +static int __maybe_unused stm32_dfsdm_adc_suspend(struct device *dev) +{ + struct stm32_dfsdm_adc *adc = dev_get_drvdata(dev); + struct iio_dev *indio_dev = iio_priv_to_dev(adc); + + if (iio_buffer_enabled(indio_dev)) + __stm32_dfsdm_predisable(indio_dev); + + return 0; +} + +static int __maybe_unused stm32_dfsdm_adc_resume(struct device *dev) +{ + struct stm32_dfsdm_adc *adc = dev_get_drvdata(dev); + struct iio_dev *indio_dev = iio_priv_to_dev(adc); + const struct iio_chan_spec *chan; + struct stm32_dfsdm_channel *ch; + int i, ret; + + /* restore channels configuration */ + for (i = 0; i < indio_dev->num_channels; i++) { + chan = indio_dev->channels + i; + ch = &adc->dfsdm->ch_list[chan->channel]; + ret = stm32_dfsdm_chan_configure(adc->dfsdm, ch); + if (ret) + return ret; + } + + if (iio_buffer_enabled(indio_dev)) + __stm32_dfsdm_postenable(indio_dev); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(stm32_dfsdm_adc_pm_ops, + stm32_dfsdm_adc_suspend, stm32_dfsdm_adc_resume); + static struct platform_driver stm32_dfsdm_adc_driver = { .driver = { .name = "stm32-dfsdm-adc", .of_match_table = stm32_dfsdm_adc_match, + .pm = &stm32_dfsdm_adc_pm_ops, }, .probe = stm32_dfsdm_adc_probe, .remove = stm32_dfsdm_adc_remove, diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c index bf089f5d6225..0a4d3746d21c 100644 --- a/drivers/iio/adc/stm32-dfsdm-core.c +++ b/drivers/iio/adc/stm32-dfsdm-core.c @@ -12,6 +12,8 @@ #include <linux/interrupt.h> #include <linux/module.h> #include <linux/of_device.h> +#include <linux/pinctrl/consumer.h> +#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/slab.h> @@ -90,6 +92,36 @@ struct dfsdm_priv { struct clk *aclk; /* audio clock */ }; +static inline struct dfsdm_priv *to_stm32_dfsdm_priv(struct stm32_dfsdm *dfsdm) +{ + return container_of(dfsdm, struct dfsdm_priv, dfsdm); +} + +static int stm32_dfsdm_clk_prepare_enable(struct stm32_dfsdm *dfsdm) +{ + struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); + int ret; + + ret = clk_prepare_enable(priv->clk); + if (ret || !priv->aclk) + return ret; + + ret = clk_prepare_enable(priv->aclk); + if (ret) + clk_disable_unprepare(priv->clk); + + return ret; +} + +static void stm32_dfsdm_clk_disable_unprepare(struct stm32_dfsdm *dfsdm) +{ + struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); + + if (priv->aclk) + clk_disable_unprepare(priv->aclk); + clk_disable_unprepare(priv->clk); +} + /** * stm32_dfsdm_start_dfsdm - start global dfsdm interface. * @@ -98,24 +130,17 @@ struct dfsdm_priv { */ int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm) { - struct dfsdm_priv *priv = container_of(dfsdm, struct dfsdm_priv, dfsdm); + struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); struct device *dev = &priv->pdev->dev; unsigned int clk_div = priv->spi_clk_out_div, clk_src; int ret; if (atomic_inc_return(&priv->n_active_ch) == 1) { - ret = clk_prepare_enable(priv->clk); + ret = pm_runtime_get_sync(dev); if (ret < 0) { - dev_err(dev, "Failed to start clock\n"); + pm_runtime_put_noidle(dev); goto error_ret; } - if (priv->aclk) { - ret = clk_prepare_enable(priv->aclk); - if (ret < 0) { - dev_err(dev, "Failed to start audio clock\n"); - goto disable_clk; - } - } /* select clock source, e.g. 0 for "dfsdm" or 1 for "audio" */ clk_src = priv->aclk ? 1 : 0; @@ -123,21 +148,21 @@ int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm) DFSDM_CHCFGR1_CKOUTSRC_MASK, DFSDM_CHCFGR1_CKOUTSRC(clk_src)); if (ret < 0) - goto disable_aclk; + goto pm_put; /* Output the SPI CLKOUT (if clk_div == 0 clock if OFF) */ ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), DFSDM_CHCFGR1_CKOUTDIV_MASK, DFSDM_CHCFGR1_CKOUTDIV(clk_div)); if (ret < 0) - goto disable_aclk; + goto pm_put; /* Global enable of DFSDM interface */ ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), DFSDM_CHCFGR1_DFSDMEN_MASK, DFSDM_CHCFGR1_DFSDMEN(1)); if (ret < 0) - goto disable_aclk; + goto pm_put; } dev_dbg(dev, "%s: n_active_ch %d\n", __func__, @@ -145,11 +170,8 @@ int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm) return 0; -disable_aclk: - clk_disable_unprepare(priv->aclk); -disable_clk: - clk_disable_unprepare(priv->clk); - +pm_put: + pm_runtime_put_sync(dev); error_ret: atomic_dec(&priv->n_active_ch); @@ -165,7 +187,7 @@ EXPORT_SYMBOL_GPL(stm32_dfsdm_start_dfsdm); */ int stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm) { - struct dfsdm_priv *priv = container_of(dfsdm, struct dfsdm_priv, dfsdm); + struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); int ret; if (atomic_dec_and_test(&priv->n_active_ch)) { @@ -183,9 +205,7 @@ int stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm) if (ret < 0) return ret; - clk_disable_unprepare(priv->clk); - if (priv->aclk) - clk_disable_unprepare(priv->aclk); + pm_runtime_put_sync(&priv->pdev->dev); } dev_dbg(&priv->pdev->dev, "%s: n_active_ch %d\n", __func__, atomic_read(&priv->n_active_ch)); @@ -199,7 +219,7 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev, { struct device_node *node = pdev->dev.of_node; struct resource *res; - unsigned long clk_freq; + unsigned long clk_freq, divider; unsigned int spi_freq, rem; int ret; @@ -243,13 +263,20 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev, return 0; } - priv->spi_clk_out_div = div_u64_rem(clk_freq, spi_freq, &rem) - 1; - if (!priv->spi_clk_out_div) { - /* spi_clk_out_div == 0 means ckout is OFF */ + divider = div_u64_rem(clk_freq, spi_freq, &rem); + /* Round up divider when ckout isn't precise, not to exceed spi_freq */ + if (rem) + divider++; + + /* programmable divider is in range of [2:256] */ + if (divider < 2 || divider > 256) { dev_err(&pdev->dev, "spi-max-frequency not achievable\n"); return -EINVAL; } - priv->dfsdm.spi_master_freq = spi_freq; + + /* SPI clock output divider is: divider = CKOUTDIV + 1 */ + priv->spi_clk_out_div = divider - 1; + priv->dfsdm.spi_master_freq = clk_freq / (priv->spi_clk_out_div + 1); if (rem) { dev_warn(&pdev->dev, "SPI clock not accurate\n"); @@ -318,14 +345,111 @@ static int stm32_dfsdm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dfsdm); - return devm_of_platform_populate(&pdev->dev); + ret = stm32_dfsdm_clk_prepare_enable(dfsdm); + if (ret) { + dev_err(&pdev->dev, "Failed to start clock\n"); + return ret; + } + + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + if (ret) + goto pm_put; + + pm_runtime_put(&pdev->dev); + + return 0; + +pm_put: + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + stm32_dfsdm_clk_disable_unprepare(dfsdm); + + return ret; +} + +static int stm32_dfsdm_core_remove(struct platform_device *pdev) +{ + struct stm32_dfsdm *dfsdm = platform_get_drvdata(pdev); + + pm_runtime_get_sync(&pdev->dev); + of_platform_depopulate(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + stm32_dfsdm_clk_disable_unprepare(dfsdm); + + return 0; +} + +static int __maybe_unused stm32_dfsdm_core_suspend(struct device *dev) +{ + struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); + struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); + int ret; + + ret = pm_runtime_force_suspend(dev); + if (ret) + return ret; + + /* Balance devm_regmap_init_mmio_clk() clk_prepare() */ + clk_unprepare(priv->clk); + + return pinctrl_pm_select_sleep_state(dev); } +static int __maybe_unused stm32_dfsdm_core_resume(struct device *dev) +{ + struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); + struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); + int ret; + + ret = pinctrl_pm_select_default_state(dev); + if (ret) + return ret; + + ret = clk_prepare(priv->clk); + if (ret) + return ret; + + return pm_runtime_force_resume(dev); +} + +static int __maybe_unused stm32_dfsdm_core_runtime_suspend(struct device *dev) +{ + struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); + + stm32_dfsdm_clk_disable_unprepare(dfsdm); + + return 0; +} + +static int __maybe_unused stm32_dfsdm_core_runtime_resume(struct device *dev) +{ + struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); + + return stm32_dfsdm_clk_prepare_enable(dfsdm); +} + +static const struct dev_pm_ops stm32_dfsdm_core_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(stm32_dfsdm_core_suspend, + stm32_dfsdm_core_resume) + SET_RUNTIME_PM_OPS(stm32_dfsdm_core_runtime_suspend, + stm32_dfsdm_core_runtime_resume, + NULL) +}; + static struct platform_driver stm32_dfsdm_driver = { .probe = stm32_dfsdm_probe, + .remove = stm32_dfsdm_core_remove, .driver = { .name = "stm32-dfsdm", .of_match_table = stm32_dfsdm_of_match, + .pm = &stm32_dfsdm_core_pm_ops, }, }; diff --git a/drivers/iio/adc/stmpe-adc.c b/drivers/iio/adc/stmpe-adc.c index 37f4b74a5d32..7921f827c6ec 100644 --- a/drivers/iio/adc/stmpe-adc.c +++ b/drivers/iio/adc/stmpe-adc.c @@ -184,9 +184,6 @@ static irqreturn_t stmpe_adc_isr(int irq, void *dev_id) struct stmpe_adc *info = (struct stmpe_adc *)dev_id; u16 data; - if (info->channel > STMPE_TEMP_CHANNEL) - return IRQ_NONE; - if (info->channel <= STMPE_ADC_LAST_NR) { int int_sta; @@ -205,6 +202,8 @@ static irqreturn_t stmpe_adc_isr(int irq, void *dev_id) /* Read value */ stmpe_block_read(info->stmpe, STMPE_REG_TEMP_DATA, 2, (u8 *) &data); + } else { + return IRQ_NONE; } info->value = (u32) be16_to_cpu(data); diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c index 0ad63592cc3c..2e66e4d586ff 100644 --- a/drivers/iio/adc/ti-ads7950.c +++ b/drivers/iio/adc/ti-ads7950.c @@ -17,6 +17,7 @@ #include <linux/bitops.h> #include <linux/device.h> #include <linux/err.h> +#include <linux/gpio/driver.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> @@ -36,12 +37,15 @@ */ #define TI_ADS7950_VA_MV_ACPI_DEFAULT 5000 +#define TI_ADS7950_CR_GPIO BIT(14) #define TI_ADS7950_CR_MANUAL BIT(12) #define TI_ADS7950_CR_WRITE BIT(11) #define TI_ADS7950_CR_CHAN(ch) ((ch) << 7) #define TI_ADS7950_CR_RANGE_5V BIT(6) +#define TI_ADS7950_CR_GPIO_DATA BIT(4) #define TI_ADS7950_MAX_CHAN 16 +#define TI_ADS7950_NUM_GPIOS 4 #define TI_ADS7950_TIMESTAMP_SIZE (sizeof(int64_t) / sizeof(__be16)) @@ -49,6 +53,16 @@ #define TI_ADS7950_EXTRACT(val, dec, bits) \ (((val) >> (dec)) & ((1 << (bits)) - 1)) +#define TI_ADS7950_MAN_CMD(cmd) (TI_ADS7950_CR_MANUAL | (cmd)) +#define TI_ADS7950_GPIO_CMD(cmd) (TI_ADS7950_CR_GPIO | (cmd)) + +/* Manual mode configuration */ +#define TI_ADS7950_MAN_CMD_SETTINGS(st) \ + (TI_ADS7950_MAN_CMD(TI_ADS7950_CR_WRITE | st->cmd_settings_bitmask)) +/* GPIO mode configuration */ +#define TI_ADS7950_GPIO_CMD_SETTINGS(st) \ + (TI_ADS7950_GPIO_CMD(st->gpio_cmd_settings_bitmask)) + struct ti_ads7950_state { struct spi_device *spi; struct spi_transfer ring_xfer; @@ -56,10 +70,36 @@ struct ti_ads7950_state { struct spi_message ring_msg; struct spi_message scan_single_msg; + /* Lock to protect the spi xfer buffers */ + struct mutex slock; + struct gpio_chip chip; + struct regulator *reg; unsigned int vref_mv; - unsigned int settings; + /* + * Bitmask of lower 7 bits used for configuration + * These bits only can be written when TI_ADS7950_CR_WRITE + * is set, otherwise it retains its original state. + * [0-3] GPIO signal + * [4] Set following frame to return GPIO signal values + * [5] Powers down device + * [6] Sets Vref range1(2.5v) or range2(5v) + * + * Bits present on Manual/Auto1/Auto2 commands + */ + unsigned int cmd_settings_bitmask; + + /* + * Bitmask of GPIO command + * [0-3] GPIO direction + * [4-6] Different GPIO alarm mode configurations + * [7] GPIO 2 as device range input + * [8] GPIO 3 as device power down input + * [9] Reset all registers + * [10-11] N/A + */ + unsigned int gpio_cmd_settings_bitmask; /* * DMA (thus cache coherency maintenance) requires the @@ -248,7 +288,7 @@ static int ti_ads7950_update_scan_mode(struct iio_dev *indio_dev, len = 0; for_each_set_bit(i, active_scan_mask, indio_dev->num_channels) { - cmd = TI_ADS7950_CR_WRITE | TI_ADS7950_CR_CHAN(i) | st->settings; + cmd = TI_ADS7950_MAN_CMD(TI_ADS7950_CR_CHAN(i)); st->tx_buf[len++] = cmd; } @@ -268,6 +308,7 @@ static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p) struct ti_ads7950_state *st = iio_priv(indio_dev); int ret; + mutex_lock(&st->slock); ret = spi_sync(st->spi, &st->ring_msg); if (ret < 0) goto out; @@ -276,6 +317,7 @@ static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p) iio_get_time_ns(indio_dev)); out: + mutex_unlock(&st->slock); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; @@ -286,9 +328,8 @@ static int ti_ads7950_scan_direct(struct iio_dev *indio_dev, unsigned int ch) struct ti_ads7950_state *st = iio_priv(indio_dev); int ret, cmd; - mutex_lock(&indio_dev->mlock); - - cmd = TI_ADS7950_CR_WRITE | TI_ADS7950_CR_CHAN(ch) | st->settings; + mutex_lock(&st->slock); + cmd = TI_ADS7950_MAN_CMD(TI_ADS7950_CR_CHAN(ch)); st->single_tx = cmd; ret = spi_sync(st->spi, &st->scan_single_msg); @@ -298,7 +339,7 @@ static int ti_ads7950_scan_direct(struct iio_dev *indio_dev, unsigned int ch) ret = st->single_rx; out: - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&st->slock); return ret; } @@ -317,7 +358,7 @@ static int ti_ads7950_get_range(struct ti_ads7950_state *st) vref /= 1000; } - if (st->settings & TI_ADS7950_CR_RANGE_5V) + if (st->cmd_settings_bitmask & TI_ADS7950_CR_RANGE_5V) vref *= 2; return vref; @@ -362,6 +403,132 @@ static const struct iio_info ti_ads7950_info = { .update_scan_mode = ti_ads7950_update_scan_mode, }; +static void ti_ads7950_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct ti_ads7950_state *st = gpiochip_get_data(chip); + + mutex_lock(&st->slock); + + if (value) + st->cmd_settings_bitmask |= BIT(offset); + else + st->cmd_settings_bitmask &= ~BIT(offset); + + st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st); + spi_sync(st->spi, &st->scan_single_msg); + + mutex_unlock(&st->slock); +} + +static int ti_ads7950_get(struct gpio_chip *chip, unsigned int offset) +{ + struct ti_ads7950_state *st = gpiochip_get_data(chip); + int ret; + + mutex_lock(&st->slock); + + /* If set as output, return the output */ + if (st->gpio_cmd_settings_bitmask & BIT(offset)) { + ret = st->cmd_settings_bitmask & BIT(offset); + goto out; + } + + /* GPIO data bit sets SDO bits 12-15 to GPIO input */ + st->cmd_settings_bitmask |= TI_ADS7950_CR_GPIO_DATA; + st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st); + ret = spi_sync(st->spi, &st->scan_single_msg); + if (ret) + goto out; + + ret = ((st->single_rx >> 12) & BIT(offset)) ? 1 : 0; + + /* Revert back to original settings */ + st->cmd_settings_bitmask &= ~TI_ADS7950_CR_GPIO_DATA; + st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st); + ret = spi_sync(st->spi, &st->scan_single_msg); + if (ret) + goto out; + +out: + mutex_unlock(&st->slock); + + return ret; +} + +static int ti_ads7950_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + struct ti_ads7950_state *st = gpiochip_get_data(chip); + + /* Bitmask is inverted from GPIO framework 0=input/1=output */ + return !(st->gpio_cmd_settings_bitmask & BIT(offset)); +} + +static int _ti_ads7950_set_direction(struct gpio_chip *chip, int offset, + int input) +{ + struct ti_ads7950_state *st = gpiochip_get_data(chip); + int ret = 0; + + mutex_lock(&st->slock); + + /* Only change direction if needed */ + if (input && (st->gpio_cmd_settings_bitmask & BIT(offset))) + st->gpio_cmd_settings_bitmask &= ~BIT(offset); + else if (!input && !(st->gpio_cmd_settings_bitmask & BIT(offset))) + st->gpio_cmd_settings_bitmask |= BIT(offset); + else + goto out; + + st->single_tx = TI_ADS7950_GPIO_CMD_SETTINGS(st); + ret = spi_sync(st->spi, &st->scan_single_msg); + +out: + mutex_unlock(&st->slock); + + return ret; +} + +static int ti_ads7950_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + return _ti_ads7950_set_direction(chip, offset, 1); +} + +static int ti_ads7950_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + ti_ads7950_set(chip, offset, value); + + return _ti_ads7950_set_direction(chip, offset, 0); +} + +static int ti_ads7950_init_hw(struct ti_ads7950_state *st) +{ + int ret = 0; + + mutex_lock(&st->slock); + + /* Settings for Manual/Auto1/Auto2 commands */ + /* Default to 5v ref */ + st->cmd_settings_bitmask = TI_ADS7950_CR_RANGE_5V; + st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st); + ret = spi_sync(st->spi, &st->scan_single_msg); + if (ret) + goto out; + + /* Settings for GPIO command */ + st->gpio_cmd_settings_bitmask = 0x0; + st->single_tx = TI_ADS7950_GPIO_CMD_SETTINGS(st); + ret = spi_sync(st->spi, &st->scan_single_msg); + +out: + mutex_unlock(&st->slock); + + return ret; +} + static int ti_ads7950_probe(struct spi_device *spi) { struct ti_ads7950_state *st; @@ -386,7 +553,6 @@ static int ti_ads7950_probe(struct spi_device *spi) spi_set_drvdata(spi, indio_dev); st->spi = spi; - st->settings = TI_ADS7950_CR_MANUAL | TI_ADS7950_CR_RANGE_5V; info = &ti_ads7950_chip_info[spi_get_device_id(spi)->driver_data]; @@ -432,16 +598,19 @@ static int ti_ads7950_probe(struct spi_device *spi) if (ACPI_COMPANION(&spi->dev)) st->vref_mv = TI_ADS7950_VA_MV_ACPI_DEFAULT; + mutex_init(&st->slock); + st->reg = devm_regulator_get(&spi->dev, "vref"); if (IS_ERR(st->reg)) { dev_err(&spi->dev, "Failed get get regulator \"vref\"\n"); - return PTR_ERR(st->reg); + ret = PTR_ERR(st->reg); + goto error_destroy_mutex; } ret = regulator_enable(st->reg); if (ret) { dev_err(&spi->dev, "Failed to enable regulator \"vref\"\n"); - return ret; + goto error_destroy_mutex; } ret = iio_triggered_buffer_setup(indio_dev, NULL, @@ -451,18 +620,46 @@ static int ti_ads7950_probe(struct spi_device *spi) goto error_disable_reg; } + ret = ti_ads7950_init_hw(st); + if (ret) { + dev_err(&spi->dev, "Failed to init adc chip\n"); + goto error_cleanup_ring; + } + ret = iio_device_register(indio_dev); if (ret) { dev_err(&spi->dev, "Failed to register iio device\n"); goto error_cleanup_ring; } + /* Add GPIO chip */ + st->chip.label = dev_name(&st->spi->dev); + st->chip.parent = &st->spi->dev; + st->chip.owner = THIS_MODULE; + st->chip.base = -1; + st->chip.ngpio = TI_ADS7950_NUM_GPIOS; + st->chip.get_direction = ti_ads7950_get_direction; + st->chip.direction_input = ti_ads7950_direction_input; + st->chip.direction_output = ti_ads7950_direction_output; + st->chip.get = ti_ads7950_get; + st->chip.set = ti_ads7950_set; + + ret = gpiochip_add_data(&st->chip, st); + if (ret) { + dev_err(&spi->dev, "Failed to init GPIOs\n"); + goto error_iio_device; + } + return 0; +error_iio_device: + iio_device_unregister(indio_dev); error_cleanup_ring: iio_triggered_buffer_cleanup(indio_dev); error_disable_reg: regulator_disable(st->reg); +error_destroy_mutex: + mutex_destroy(&st->slock); return ret; } @@ -472,9 +669,11 @@ static int ti_ads7950_remove(struct spi_device *spi) struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ti_ads7950_state *st = iio_priv(indio_dev); + gpiochip_remove(&st->chip); iio_device_unregister(indio_dev); iio_triggered_buffer_cleanup(indio_dev); regulator_disable(st->reg); + mutex_destroy(&st->slock); return 0; } diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c index 8b4568edd5cb..f9461070a74a 100644 --- a/drivers/iio/adc/ti-ads8688.c +++ b/drivers/iio/adc/ti-ads8688.c @@ -523,6 +523,6 @@ static struct spi_driver ads8688_driver = { }; module_spi_driver(ads8688_driver); -MODULE_AUTHOR("Sean Nyekjaer <sean.nyekjaer@prevas.dk>"); +MODULE_AUTHOR("Sean Nyekjaer <sean@geanix.dk>"); MODULE_DESCRIPTION("Texas Instruments ADS8688 driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/buffer/industrialio-buffer-cb.c b/drivers/iio/buffer/industrialio-buffer-cb.c index ea63c838eeae..df21e7dbec40 100644 --- a/drivers/iio/buffer/industrialio-buffer-cb.c +++ b/drivers/iio/buffer/industrialio-buffer-cb.c @@ -36,7 +36,8 @@ static int iio_buffer_cb_store_to(struct iio_buffer *buffer, const void *data) static void iio_buffer_cb_release(struct iio_buffer *buffer) { struct iio_cb_buffer *cb_buff = buffer_to_cb_buffer(buffer); - kfree(cb_buff->buffer.scan_mask); + + bitmap_free(cb_buff->buffer.scan_mask); kfree(cb_buff); } @@ -74,9 +75,8 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev, } cb_buff->indio_dev = cb_buff->channels[0].indio_dev; - cb_buff->buffer.scan_mask - = kcalloc(BITS_TO_LONGS(cb_buff->indio_dev->masklength), - sizeof(long), GFP_KERNEL); + cb_buff->buffer.scan_mask = bitmap_zalloc(cb_buff->indio_dev->masklength, + GFP_KERNEL); if (cb_buff->buffer.scan_mask == NULL) { ret = -ENOMEM; goto error_release_channels; @@ -95,7 +95,7 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev, return cb_buff; error_free_scan_mask: - kfree(cb_buff->buffer.scan_mask); + bitmap_free(cb_buff->buffer.scan_mask); error_release_channels: iio_channel_release_all(cb_buff->channels); error_free_cb_buff: diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig index d5d146e9e372..d5fb436f5ae6 100644 --- a/drivers/iio/chemical/Kconfig +++ b/drivers/iio/chemical/Kconfig @@ -12,14 +12,14 @@ config ATLAS_PH_SENSOR select IIO_TRIGGERED_BUFFER select IRQ_WORK help - Say Y here to build I2C interface support for the following - Atlas Scientific OEM SM sensors: + Say Y here to build I2C interface support for the following + Atlas Scientific OEM SM sensors: * pH SM sensor * EC SM sensor * ORP SM sensor - To compile this driver as module, choose M here: the - module will be called atlas-ph-sensor. + To compile this driver as module, choose M here: the + module will be called atlas-ph-sensor. config BME680 tristate "Bosch Sensortec BME680 sensor driver" @@ -47,8 +47,8 @@ config BME680_SPI config CCS811 tristate "AMS CCS811 VOC sensor" depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help Say Y here to build I2C interface support for the AMS CCS811 VOC (Volatile Organic Compounds) sensor diff --git a/drivers/iio/chemical/pms7003.c b/drivers/iio/chemical/pms7003.c index db8e7b2327b3..23c9ab252470 100644 --- a/drivers/iio/chemical/pms7003.c +++ b/drivers/iio/chemical/pms7003.c @@ -321,7 +321,12 @@ static int pms7003_probe(struct serdev_device *serdev) } static const struct of_device_id pms7003_of_match[] = { + { .compatible = "plantower,pms1003" }, + { .compatible = "plantower,pms3003" }, + { .compatible = "plantower,pms5003" }, + { .compatible = "plantower,pms6003" }, { .compatible = "plantower,pms7003" }, + { .compatible = "plantower,pmsa003" }, { } }; MODULE_DEVICE_TABLE(of, pms7003_of_match); diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c index 89cb0066a6e0..2dafe49aeafd 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c @@ -1,22 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 /* * cros_ec_sensors - Driver for Chrome OS Embedded Controller sensors. * * Copyright (C) 2016 Google, Inc * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * * This driver uses the cros-ec interface to communicate with the Chrome OS * EC about sensors data. Data access is presented through iio sysfs. */ -#include <linux/delay.h> #include <linux/device.h> #include <linux/iio/buffer.h> #include <linux/iio/common/cros_ec_sensors_core.h> @@ -30,7 +21,6 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> -#include <linux/sysfs.h> #define CROS_EC_SENSORS_MAX_CHANNELS 4 diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c index 414cc43c287e..719a0df5aeeb 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * cros_ec_sensors_core - Common function for Chrome OS EC sensor driver. * * Copyright (C) 2016 Google, Inc - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/delay.h> @@ -25,7 +17,6 @@ #include <linux/mfd/cros_ec_commands.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/sysfs.h> #include <linux/platform_device.h> static char *cros_ec_loc[] = { @@ -269,6 +260,17 @@ static int cros_ec_sensors_read_data_unsafe(struct iio_dev *indio_dev, return 0; } +/** + * cros_ec_sensors_read_lpc() - read acceleration data from EC shared memory. + * @indio_dev: pointer to IIO device. + * @scan_mask: bitmap of the sensor indices to scan. + * @data: location to store data. + * + * Note: this is the safe function for reading the EC data. It guarantees + * that the data sampled was not modified by the EC while being read. + * + * Return: 0 on success, -errno on failure. + */ int cros_ec_sensors_read_lpc(struct iio_dev *indio_dev, unsigned long scan_mask, s16 *data) { diff --git a/drivers/iio/common/ms_sensors/Kconfig b/drivers/iio/common/ms_sensors/Kconfig index b28a92b97cf9..89398d0afc0d 100644 --- a/drivers/iio/common/ms_sensors/Kconfig +++ b/drivers/iio/common/ms_sensors/Kconfig @@ -3,4 +3,4 @@ # config IIO_MS_SENSORS_I2C - tristate + tristate diff --git a/drivers/iio/common/ssp_sensors/ssp_iio.c b/drivers/iio/common/ssp_sensors/ssp_iio.c index 645f2e3975db..e38f704d88b7 100644 --- a/drivers/iio/common/ssp_sensors/ssp_iio.c +++ b/drivers/iio/common/ssp_sensors/ssp_iio.c @@ -81,7 +81,7 @@ int ssp_common_process_data(struct iio_dev *indio_dev, void *buf, unsigned int len, int64_t timestamp) { __le32 time; - int64_t calculated_time; + int64_t calculated_time = 0; struct ssp_sensor_data *spd = iio_priv(indio_dev); if (indio_dev->scan_bytes == 0) diff --git a/drivers/iio/counter/stm32-lptimer-cnt.c b/drivers/iio/counter/stm32-lptimer-cnt.c index 42fb8ba67090..2a49cce0edb4 100644 --- a/drivers/iio/counter/stm32-lptimer-cnt.c +++ b/drivers/iio/counter/stm32-lptimer-cnt.c @@ -14,6 +14,7 @@ #include <linux/iio/iio.h> #include <linux/mfd/stm32-lptimer.h> #include <linux/module.h> +#include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> struct stm32_lptim_cnt { @@ -23,6 +24,7 @@ struct stm32_lptim_cnt { u32 preset; u32 polarity; u32 quadrature_mode; + bool enabled; }; static int stm32_lptim_is_enabled(struct stm32_lptim_cnt *priv) @@ -50,6 +52,7 @@ static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv, if (!enable) { clk_disable(priv->clk); + priv->enabled = false; return 0; } @@ -79,6 +82,7 @@ static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv, regmap_write(priv->regmap, STM32_LPTIM_CR, 0); return ret; } + priv->enabled = true; /* Start LP timer in continuous mode */ return regmap_update_bits(priv->regmap, STM32_LPTIM_CR, @@ -361,6 +365,56 @@ static int stm32_lptim_cnt_probe(struct platform_device *pdev) return devm_iio_device_register(&pdev->dev, indio_dev); } +#ifdef CONFIG_PM_SLEEP +static int stm32_lptim_cnt_suspend(struct device *dev) +{ + struct stm32_lptim_cnt *priv = dev_get_drvdata(dev); + int ret; + + /* Only take care of enabled counter: don't disturb other MFD child */ + if (priv->enabled) { + ret = stm32_lptim_setup(priv, 0); + if (ret) + return ret; + + ret = stm32_lptim_set_enable_state(priv, 0); + if (ret) + return ret; + + /* Force enable state for later resume */ + priv->enabled = true; + } + + return pinctrl_pm_select_sleep_state(dev); +} + +static int stm32_lptim_cnt_resume(struct device *dev) +{ + struct stm32_lptim_cnt *priv = dev_get_drvdata(dev); + int ret; + + ret = pinctrl_pm_select_default_state(dev); + if (ret) + return ret; + + if (priv->enabled) { + priv->enabled = false; + ret = stm32_lptim_setup(priv, 1); + if (ret) + return ret; + + ret = stm32_lptim_set_enable_state(priv, 1); + if (ret) + return ret; + } + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(stm32_lptim_cnt_pm_ops, stm32_lptim_cnt_suspend, + stm32_lptim_cnt_resume); + static const struct of_device_id stm32_lptim_cnt_of_match[] = { { .compatible = "st,stm32-lptimer-counter", }, {}, @@ -372,6 +426,7 @@ static struct platform_driver stm32_lptim_cnt_driver = { .driver = { .name = "stm32-lptimer-counter", .of_match_table = stm32_lptim_cnt_of_match, + .pm = &stm32_lptim_cnt_pm_ops, }, }; module_platform_driver(stm32_lptim_cnt_driver); diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c index 2f98cb2a3b96..6c3ba143839b 100644 --- a/drivers/iio/dac/ad5064.c +++ b/drivers/iio/dac/ad5064.c @@ -112,6 +112,8 @@ struct ad5064_state { bool use_internal_vref; ad5064_write_func write; + /* Lock used to maintain consistency between cached and dev state */ + struct mutex lock; /* * DMA (thus cache coherency maintenance) requires the @@ -248,11 +250,11 @@ static int ad5064_set_powerdown_mode(struct iio_dev *indio_dev, struct ad5064_state *st = iio_priv(indio_dev); int ret; - mutex_lock(&indio_dev->mlock); + mutex_lock(&st->lock); st->pwr_down_mode[chan->channel] = mode + 1; ret = ad5064_sync_powerdown_mode(st, chan); - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&st->lock); return ret; } @@ -291,11 +293,11 @@ static ssize_t ad5064_write_dac_powerdown(struct iio_dev *indio_dev, if (ret) return ret; - mutex_lock(&indio_dev->mlock); + mutex_lock(&st->lock); st->pwr_down[chan->channel] = pwr_down; ret = ad5064_sync_powerdown_mode(st, chan); - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&st->lock); return ret ? ret : len; } @@ -349,12 +351,12 @@ static int ad5064_write_raw(struct iio_dev *indio_dev, if (val >= (1 << chan->scan_type.realbits) || val < 0) return -EINVAL; - mutex_lock(&indio_dev->mlock); + mutex_lock(&st->lock); ret = ad5064_write(st, AD5064_CMD_WRITE_INPUT_N_UPDATE_N, chan->address, val, chan->scan_type.shift); if (ret == 0) st->dac_cache[chan->channel] = val; - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&st->lock); break; default: ret = -EINVAL; @@ -856,6 +858,7 @@ static int ad5064_probe(struct device *dev, enum ad5064_type type, return -ENOMEM; st = iio_priv(indio_dev); + mutex_init(&st->lock); dev_set_drvdata(dev, indio_dev); st->chip_info = &ad5064_chip_info_tbl[type]; diff --git a/drivers/iio/dac/ti-dac5571.c b/drivers/iio/dac/ti-dac5571.c index f6dcd8bce2b0..891e9cac019e 100644 --- a/drivers/iio/dac/ti-dac5571.c +++ b/drivers/iio/dac/ti-dac5571.c @@ -429,6 +429,6 @@ static struct i2c_driver dac5571_driver = { }; module_i2c_driver(dac5571_driver); -MODULE_AUTHOR("Sean Nyekjaer <sean.nyekjaer@prevas.dk>"); +MODULE_AUTHOR("Sean Nyekjaer <sean@geanix.dk>"); MODULE_DESCRIPTION("Texas Instruments 8/10/12-bit 1/4-channel DAC driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c index 3f9be69499ec..9b9eee27176c 100644 --- a/drivers/iio/frequency/ad9523.c +++ b/drivers/iio/frequency/ad9523.c @@ -872,22 +872,22 @@ static int ad9523_setup(struct iio_dev *indio_dev) return ret; ret = ad9523_write(indio_dev, AD9523_PLL2_VCO_DIVIDER, - AD9523_PLL2_VCO_DIV_M1(pdata->pll2_vco_diff_m1) | - AD9523_PLL2_VCO_DIV_M2(pdata->pll2_vco_diff_m2) | - AD_IFE(pll2_vco_diff_m1, 0, + AD9523_PLL2_VCO_DIV_M1(pdata->pll2_vco_div_m1) | + AD9523_PLL2_VCO_DIV_M2(pdata->pll2_vco_div_m2) | + AD_IFE(pll2_vco_div_m1, 0, AD9523_PLL2_VCO_DIV_M1_PWR_DOWN_EN) | - AD_IFE(pll2_vco_diff_m2, 0, + AD_IFE(pll2_vco_div_m2, 0, AD9523_PLL2_VCO_DIV_M2_PWR_DOWN_EN)); if (ret < 0) return ret; - if (pdata->pll2_vco_diff_m1) + if (pdata->pll2_vco_div_m1) st->vco_out_freq[AD9523_VCO1] = - st->vco_freq / pdata->pll2_vco_diff_m1; + st->vco_freq / pdata->pll2_vco_div_m1; - if (pdata->pll2_vco_diff_m2) + if (pdata->pll2_vco_div_m2) st->vco_out_freq[AD9523_VCO2] = - st->vco_freq / pdata->pll2_vco_diff_m2; + st->vco_freq / pdata->pll2_vco_div_m2; st->vco_out_freq[AD9523_VCXO] = pdata->vcxo_freq; diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c index 63ca31628a93..e7b38adee39a 100644 --- a/drivers/iio/gyro/bmg160_core.c +++ b/drivers/iio/gyro/bmg160_core.c @@ -102,6 +102,7 @@ struct bmg160_data { struct regmap *regmap; struct iio_trigger *dready_trig; struct iio_trigger *motion_trig; + struct iio_mount_matrix orientation; struct mutex mutex; s16 buffer[8]; u32 dps_range; @@ -794,6 +795,20 @@ static int bmg160_write_event_config(struct iio_dev *indio_dev, return 0; } +static const struct iio_mount_matrix * +bmg160_get_mount_matrix(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct bmg160_data *data = iio_priv(indio_dev); + + return &data->orientation; +} + +static const struct iio_chan_spec_ext_info bmg160_ext_info[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bmg160_get_mount_matrix), + { } +}; + static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("100 200 400 1000 2000"); static IIO_CONST_ATTR(in_anglvel_scale_available, @@ -831,6 +846,7 @@ static const struct iio_event_spec bmg160_event = { .storagebits = 16, \ .endianness = IIO_LE, \ }, \ + .ext_info = bmg160_ext_info, \ .event_spec = &bmg160_event, \ .num_event_specs = 1 \ } @@ -1075,6 +1091,11 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq, data->irq = irq; data->regmap = regmap; + ret = iio_read_mount_matrix(dev, "mount-matrix", + &data->orientation); + if (ret) + return ret; + ret = bmg160_chip_init(data); if (ret < 0) return ret; diff --git a/drivers/iio/gyro/bmg160_i2c.c b/drivers/iio/gyro/bmg160_i2c.c index 90126a5a7663..934a092134f0 100644 --- a/drivers/iio/gyro/bmg160_i2c.c +++ b/drivers/iio/gyro/bmg160_i2c.c @@ -54,10 +54,19 @@ static const struct i2c_device_id bmg160_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, bmg160_i2c_id); +static const struct of_device_id bmg160_of_match[] = { + { .compatible = "bosch,bmg160" }, + { .compatible = "bosch,bmi055_gyro" }, + { } +}; + +MODULE_DEVICE_TABLE(of, bmg160_of_match); + static struct i2c_driver bmg160_i2c_driver = { .driver = { .name = "bmg160_i2c", .acpi_match_table = ACPI_PTR(bmg160_acpi_match), + .of_match_table = bmg160_of_match, .pm = &bmg160_pm_ops, }, .probe = bmg160_i2c_probe, diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c index 7adecb562c81..203a6be33b70 100644 --- a/drivers/iio/gyro/itg3200_core.c +++ b/drivers/iio/gyro/itg3200_core.c @@ -242,6 +242,20 @@ err_ret: return ret; } +static const struct iio_mount_matrix * +itg3200_get_mount_matrix(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct itg3200 *data = iio_priv(indio_dev); + + return &data->orientation; +} + +static const struct iio_chan_spec_ext_info itg3200_ext_info[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, itg3200_get_mount_matrix), + { } +}; + #define ITG3200_ST \ { .sign = 's', .realbits = 16, .storagebits = 16, .endianness = IIO_BE } @@ -255,6 +269,7 @@ err_ret: .address = ITG3200_REG_GYRO_ ## _mod ## OUT_H, \ .scan_index = ITG3200_SCAN_GYRO_ ## _mod, \ .scan_type = ITG3200_ST, \ + .ext_info = itg3200_ext_info, \ } static const struct iio_chan_spec itg3200_channels[] = { @@ -297,6 +312,11 @@ static int itg3200_probe(struct i2c_client *client, st = iio_priv(indio_dev); + ret = iio_read_mount_matrix(&client->dev, "mount-matrix", + &st->orientation); + if (ret) + return ret; + i2c_set_clientdata(client, indio_dev); st->i2c = client; diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c index 77fac81a3adc..8200e48f561b 100644 --- a/drivers/iio/gyro/mpu3050-core.c +++ b/drivers/iio/gyro/mpu3050-core.c @@ -1149,8 +1149,7 @@ int mpu3050_common_probe(struct device *dev, mpu3050->divisor = 99; /* Read the mounting matrix, if present */ - ret = of_iio_read_mount_matrix(dev, "mount-matrix", - &mpu3050->orientation); + ret = iio_read_mount_matrix(dev, "mount-matrix", &mpu3050->orientation); if (ret) return ret; diff --git a/drivers/iio/humidity/Kconfig b/drivers/iio/humidity/Kconfig index 1a0d458e4f4e..f1a8ec9d637b 100644 --- a/drivers/iio/humidity/Kconfig +++ b/drivers/iio/humidity/Kconfig @@ -4,16 +4,16 @@ menu "Humidity sensors" config AM2315 - tristate "Aosong AM2315 relative humidity and temperature sensor" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - If you say yes here you get support for the Aosong AM2315 - relative humidity and ambient temperature sensor. + tristate "Aosong AM2315 relative humidity and temperature sensor" + depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + If you say yes here you get support for the Aosong AM2315 + relative humidity and ambient temperature sensor. - This driver can also be built as a module. If so, the module will - be called am2315. + This driver can also be built as a module. If so, the module will + be called am2315. config DHT11 tristate "DHT11 (and compatible sensors) driver" @@ -78,7 +78,7 @@ config HTS221_SPI config HTU21 tristate "Measurement Specialties HTU21 humidity & temperature sensor" depends on I2C - select IIO_MS_SENSORS_I2C + select IIO_MS_SENSORS_I2C help If you say yes here you get support for the Measurement Specialties HTU21 humidity and temperature sensor. diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index 68629c68b19b..9e452fce1aaf 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -4,8 +4,6 @@ # # When adding new entries keep the list in alphabetical order -adis16400-y := adis16400_core.o -adis16400-$(CONFIG_IIO_BUFFER) += adis16400_buffer.o obj-$(CONFIG_ADIS16400) += adis16400.o obj-$(CONFIG_ADIS16480) += adis16480.o diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400.c index 46a569005a13..beb6919e7180 100644 --- a/drivers/iio/imu/adis16400_core.c +++ b/drivers/iio/imu/adis16400.c @@ -31,8 +31,183 @@ #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/imu/adis.h> + +#define ADIS16400_STARTUP_DELAY 290 /* ms */ +#define ADIS16400_MTEST_DELAY 90 /* ms */ + +#define ADIS16400_FLASH_CNT 0x00 /* Flash memory write count */ +#define ADIS16400_SUPPLY_OUT 0x02 /* Power supply measurement */ +#define ADIS16400_XGYRO_OUT 0x04 /* X-axis gyroscope output */ +#define ADIS16400_YGYRO_OUT 0x06 /* Y-axis gyroscope output */ +#define ADIS16400_ZGYRO_OUT 0x08 /* Z-axis gyroscope output */ +#define ADIS16400_XACCL_OUT 0x0A /* X-axis accelerometer output */ +#define ADIS16400_YACCL_OUT 0x0C /* Y-axis accelerometer output */ +#define ADIS16400_ZACCL_OUT 0x0E /* Z-axis accelerometer output */ +#define ADIS16400_XMAGN_OUT 0x10 /* X-axis magnetometer measurement */ +#define ADIS16400_YMAGN_OUT 0x12 /* Y-axis magnetometer measurement */ +#define ADIS16400_ZMAGN_OUT 0x14 /* Z-axis magnetometer measurement */ +#define ADIS16400_TEMP_OUT 0x16 /* Temperature output */ +#define ADIS16400_AUX_ADC 0x18 /* Auxiliary ADC measurement */ + +#define ADIS16350_XTEMP_OUT 0x10 /* X-axis gyroscope temperature measurement */ +#define ADIS16350_YTEMP_OUT 0x12 /* Y-axis gyroscope temperature measurement */ +#define ADIS16350_ZTEMP_OUT 0x14 /* Z-axis gyroscope temperature measurement */ + +#define ADIS16300_PITCH_OUT 0x12 /* X axis inclinometer output measurement */ +#define ADIS16300_ROLL_OUT 0x14 /* Y axis inclinometer output measurement */ +#define ADIS16300_AUX_ADC 0x16 /* Auxiliary ADC measurement */ + +#define ADIS16448_BARO_OUT 0x16 /* Barometric pressure output */ +#define ADIS16448_TEMP_OUT 0x18 /* Temperature output */ + +/* Calibration parameters */ +#define ADIS16400_XGYRO_OFF 0x1A /* X-axis gyroscope bias offset factor */ +#define ADIS16400_YGYRO_OFF 0x1C /* Y-axis gyroscope bias offset factor */ +#define ADIS16400_ZGYRO_OFF 0x1E /* Z-axis gyroscope bias offset factor */ +#define ADIS16400_XACCL_OFF 0x20 /* X-axis acceleration bias offset factor */ +#define ADIS16400_YACCL_OFF 0x22 /* Y-axis acceleration bias offset factor */ +#define ADIS16400_ZACCL_OFF 0x24 /* Z-axis acceleration bias offset factor */ +#define ADIS16400_XMAGN_HIF 0x26 /* X-axis magnetometer, hard-iron factor */ +#define ADIS16400_YMAGN_HIF 0x28 /* Y-axis magnetometer, hard-iron factor */ +#define ADIS16400_ZMAGN_HIF 0x2A /* Z-axis magnetometer, hard-iron factor */ +#define ADIS16400_XMAGN_SIF 0x2C /* X-axis magnetometer, soft-iron factor */ +#define ADIS16400_YMAGN_SIF 0x2E /* Y-axis magnetometer, soft-iron factor */ +#define ADIS16400_ZMAGN_SIF 0x30 /* Z-axis magnetometer, soft-iron factor */ + +#define ADIS16400_GPIO_CTRL 0x32 /* Auxiliary digital input/output control */ +#define ADIS16400_MSC_CTRL 0x34 /* Miscellaneous control */ +#define ADIS16400_SMPL_PRD 0x36 /* Internal sample period (rate) control */ +#define ADIS16400_SENS_AVG 0x38 /* Dynamic range and digital filter control */ +#define ADIS16400_SLP_CNT 0x3A /* Sleep mode control */ +#define ADIS16400_DIAG_STAT 0x3C /* System status */ + +/* Alarm functions */ +#define ADIS16400_GLOB_CMD 0x3E /* System command */ +#define ADIS16400_ALM_MAG1 0x40 /* Alarm 1 amplitude threshold */ +#define ADIS16400_ALM_MAG2 0x42 /* Alarm 2 amplitude threshold */ +#define ADIS16400_ALM_SMPL1 0x44 /* Alarm 1 sample size */ +#define ADIS16400_ALM_SMPL2 0x46 /* Alarm 2 sample size */ +#define ADIS16400_ALM_CTRL 0x48 /* Alarm control */ +#define ADIS16400_AUX_DAC 0x4A /* Auxiliary DAC data */ + +#define ADIS16334_LOT_ID1 0x52 /* Lot identification code 1 */ +#define ADIS16334_LOT_ID2 0x54 /* Lot identification code 2 */ +#define ADIS16400_PRODUCT_ID 0x56 /* Product identifier */ +#define ADIS16334_SERIAL_NUMBER 0x58 /* Serial number, lot specific */ + +#define ADIS16400_ERROR_ACTIVE (1<<14) +#define ADIS16400_NEW_DATA (1<<14) + +/* MSC_CTRL */ +#define ADIS16400_MSC_CTRL_MEM_TEST (1<<11) +#define ADIS16400_MSC_CTRL_INT_SELF_TEST (1<<10) +#define ADIS16400_MSC_CTRL_NEG_SELF_TEST (1<<9) +#define ADIS16400_MSC_CTRL_POS_SELF_TEST (1<<8) +#define ADIS16400_MSC_CTRL_GYRO_BIAS (1<<7) +#define ADIS16400_MSC_CTRL_ACCL_ALIGN (1<<6) +#define ADIS16400_MSC_CTRL_DATA_RDY_EN (1<<2) +#define ADIS16400_MSC_CTRL_DATA_RDY_POL_HIGH (1<<1) +#define ADIS16400_MSC_CTRL_DATA_RDY_DIO2 (1<<0) + +/* SMPL_PRD */ +#define ADIS16400_SMPL_PRD_TIME_BASE (1<<7) +#define ADIS16400_SMPL_PRD_DIV_MASK 0x7F + +/* DIAG_STAT */ +#define ADIS16400_DIAG_STAT_ZACCL_FAIL 15 +#define ADIS16400_DIAG_STAT_YACCL_FAIL 14 +#define ADIS16400_DIAG_STAT_XACCL_FAIL 13 +#define ADIS16400_DIAG_STAT_XGYRO_FAIL 12 +#define ADIS16400_DIAG_STAT_YGYRO_FAIL 11 +#define ADIS16400_DIAG_STAT_ZGYRO_FAIL 10 +#define ADIS16400_DIAG_STAT_ALARM2 9 +#define ADIS16400_DIAG_STAT_ALARM1 8 +#define ADIS16400_DIAG_STAT_FLASH_CHK 6 +#define ADIS16400_DIAG_STAT_SELF_TEST 5 +#define ADIS16400_DIAG_STAT_OVERFLOW 4 +#define ADIS16400_DIAG_STAT_SPI_FAIL 3 +#define ADIS16400_DIAG_STAT_FLASH_UPT 2 +#define ADIS16400_DIAG_STAT_POWER_HIGH 1 +#define ADIS16400_DIAG_STAT_POWER_LOW 0 + +/* GLOB_CMD */ +#define ADIS16400_GLOB_CMD_SW_RESET (1<<7) +#define ADIS16400_GLOB_CMD_P_AUTO_NULL (1<<4) +#define ADIS16400_GLOB_CMD_FLASH_UPD (1<<3) +#define ADIS16400_GLOB_CMD_DAC_LATCH (1<<2) +#define ADIS16400_GLOB_CMD_FAC_CALIB (1<<1) +#define ADIS16400_GLOB_CMD_AUTO_NULL (1<<0) + +/* SLP_CNT */ +#define ADIS16400_SLP_CNT_POWER_OFF (1<<8) + +#define ADIS16334_RATE_DIV_SHIFT 8 +#define ADIS16334_RATE_INT_CLK BIT(0) + +#define ADIS16400_SPI_SLOW (u32)(300 * 1000) +#define ADIS16400_SPI_BURST (u32)(1000 * 1000) +#define ADIS16400_SPI_FAST (u32)(2000 * 1000) + +#define ADIS16400_HAS_PROD_ID BIT(0) +#define ADIS16400_NO_BURST BIT(1) +#define ADIS16400_HAS_SLOW_MODE BIT(2) +#define ADIS16400_HAS_SERIAL_NUMBER BIT(3) +#define ADIS16400_BURST_DIAG_STAT BIT(4) + +struct adis16400_state; + +struct adis16400_chip_info { + const struct iio_chan_spec *channels; + const int num_channels; + const long flags; + unsigned int gyro_scale_micro; + unsigned int accel_scale_micro; + int temp_scale_nano; + int temp_offset; + int (*set_freq)(struct adis16400_state *st, unsigned int freq); + int (*get_freq)(struct adis16400_state *st); +}; + +/** + * struct adis16400_state - device instance specific data + * @variant: chip variant info + * @filt_int: integer part of requested filter frequency + * @adis: adis device + **/ +struct adis16400_state { + struct adis16400_chip_info *variant; + int filt_int; + + struct adis adis; + unsigned long avail_scan_mask[2]; +}; -#include "adis16400.h" +/* At the moment triggers are only used for ring buffer + * filling. This may change! + */ + +enum { + ADIS16400_SCAN_SUPPLY, + ADIS16400_SCAN_GYRO_X, + ADIS16400_SCAN_GYRO_Y, + ADIS16400_SCAN_GYRO_Z, + ADIS16400_SCAN_ACC_X, + ADIS16400_SCAN_ACC_Y, + ADIS16400_SCAN_ACC_Z, + ADIS16400_SCAN_MAGN_X, + ADIS16400_SCAN_MAGN_Y, + ADIS16400_SCAN_MAGN_Z, + ADIS16400_SCAN_BARO, + ADIS16350_SCAN_TEMP_X, + ADIS16350_SCAN_TEMP_Y, + ADIS16350_SCAN_TEMP_Z, + ADIS16300_SCAN_INCLI_X, + ADIS16300_SCAN_INCLI_Y, + ADIS16400_SCAN_ADC, + ADIS16400_SCAN_TIMESTAMP, +}; #ifdef CONFIG_DEBUG_FS @@ -145,6 +320,11 @@ enum adis16400_chip_variant { ADIS16448, }; +static struct adis_burst adis16400_burst = { + .en = true, + .reg_cmd = ADIS16400_GLOB_CMD, +}; + static int adis16334_get_freq(struct adis16400_state *st) { int ret; @@ -465,6 +645,51 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, } } +#if IS_ENABLED(CONFIG_IIO_BUFFER) +static irqreturn_t adis16400_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct adis16400_state *st = iio_priv(indio_dev); + struct adis *adis = &st->adis; + u32 old_speed_hz = st->adis.spi->max_speed_hz; + void *buffer; + int ret; + + if (!adis->buffer) + return -ENOMEM; + + if (!(st->variant->flags & ADIS16400_NO_BURST) && + st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) { + st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST; + spi_setup(st->adis.spi); + } + + ret = spi_sync(adis->spi, &adis->msg); + if (ret) + dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret); + + if (!(st->variant->flags & ADIS16400_NO_BURST)) { + st->adis.spi->max_speed_hz = old_speed_hz; + spi_setup(st->adis.spi); + } + + if (st->variant->flags & ADIS16400_BURST_DIAG_STAT) + buffer = adis->buffer + sizeof(u16); + else + buffer = adis->buffer; + + iio_push_to_buffers_with_timestamp(indio_dev, buffer, + pf->timestamp); + + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} +#else +#define adis16400_trigger_handler NULL +#endif /* IS_ENABLED(CONFIG_IIO_BUFFER) */ + #define ADIS16400_VOLTAGE_CHAN(addr, bits, name, si, chn) { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ @@ -835,7 +1060,7 @@ static struct adis16400_chip_info adis16400_chips[] = { static const struct iio_info adis16400_info = { .read_raw = &adis16400_read_raw, .write_raw = &adis16400_write_raw, - .update_scan_mode = adis16400_update_scan_mode, + .update_scan_mode = adis_update_scan_mode, .debugfs_reg_access = adis_debugfs_reg_access, }; @@ -926,6 +1151,9 @@ static int adis16400_probe(struct spi_device *spi) if (!(st->variant->flags & ADIS16400_NO_BURST)) { adis16400_setup_chan_mask(st); indio_dev->available_scan_masks = st->avail_scan_mask; + st->adis.burst = &adis16400_burst; + if (st->variant->flags & ADIS16400_BURST_DIAG_STAT) + st->adis.burst->extra_len = sizeof(u16); } ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data); diff --git a/drivers/iio/imu/adis16400.h b/drivers/iio/imu/adis16400.h deleted file mode 100644 index 73b189c1c0fb..000000000000 --- a/drivers/iio/imu/adis16400.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - * adis16400.h support Analog Devices ADIS16400 - * 3d 18g accelerometers, - * 3d gyroscopes, - * 3d 2.5gauss magnetometers via SPI - * - * Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de> - * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org> - * - * Loosely based upon lis3l02dq.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef SPI_ADIS16400_H_ -#define SPI_ADIS16400_H_ - -#include <linux/iio/imu/adis.h> - -#define ADIS16400_STARTUP_DELAY 290 /* ms */ -#define ADIS16400_MTEST_DELAY 90 /* ms */ - -#define ADIS16400_FLASH_CNT 0x00 /* Flash memory write count */ -#define ADIS16400_SUPPLY_OUT 0x02 /* Power supply measurement */ -#define ADIS16400_XGYRO_OUT 0x04 /* X-axis gyroscope output */ -#define ADIS16400_YGYRO_OUT 0x06 /* Y-axis gyroscope output */ -#define ADIS16400_ZGYRO_OUT 0x08 /* Z-axis gyroscope output */ -#define ADIS16400_XACCL_OUT 0x0A /* X-axis accelerometer output */ -#define ADIS16400_YACCL_OUT 0x0C /* Y-axis accelerometer output */ -#define ADIS16400_ZACCL_OUT 0x0E /* Z-axis accelerometer output */ -#define ADIS16400_XMAGN_OUT 0x10 /* X-axis magnetometer measurement */ -#define ADIS16400_YMAGN_OUT 0x12 /* Y-axis magnetometer measurement */ -#define ADIS16400_ZMAGN_OUT 0x14 /* Z-axis magnetometer measurement */ -#define ADIS16400_TEMP_OUT 0x16 /* Temperature output */ -#define ADIS16400_AUX_ADC 0x18 /* Auxiliary ADC measurement */ - -#define ADIS16350_XTEMP_OUT 0x10 /* X-axis gyroscope temperature measurement */ -#define ADIS16350_YTEMP_OUT 0x12 /* Y-axis gyroscope temperature measurement */ -#define ADIS16350_ZTEMP_OUT 0x14 /* Z-axis gyroscope temperature measurement */ - -#define ADIS16300_PITCH_OUT 0x12 /* X axis inclinometer output measurement */ -#define ADIS16300_ROLL_OUT 0x14 /* Y axis inclinometer output measurement */ -#define ADIS16300_AUX_ADC 0x16 /* Auxiliary ADC measurement */ - -#define ADIS16448_BARO_OUT 0x16 /* Barometric pressure output */ -#define ADIS16448_TEMP_OUT 0x18 /* Temperature output */ - -/* Calibration parameters */ -#define ADIS16400_XGYRO_OFF 0x1A /* X-axis gyroscope bias offset factor */ -#define ADIS16400_YGYRO_OFF 0x1C /* Y-axis gyroscope bias offset factor */ -#define ADIS16400_ZGYRO_OFF 0x1E /* Z-axis gyroscope bias offset factor */ -#define ADIS16400_XACCL_OFF 0x20 /* X-axis acceleration bias offset factor */ -#define ADIS16400_YACCL_OFF 0x22 /* Y-axis acceleration bias offset factor */ -#define ADIS16400_ZACCL_OFF 0x24 /* Z-axis acceleration bias offset factor */ -#define ADIS16400_XMAGN_HIF 0x26 /* X-axis magnetometer, hard-iron factor */ -#define ADIS16400_YMAGN_HIF 0x28 /* Y-axis magnetometer, hard-iron factor */ -#define ADIS16400_ZMAGN_HIF 0x2A /* Z-axis magnetometer, hard-iron factor */ -#define ADIS16400_XMAGN_SIF 0x2C /* X-axis magnetometer, soft-iron factor */ -#define ADIS16400_YMAGN_SIF 0x2E /* Y-axis magnetometer, soft-iron factor */ -#define ADIS16400_ZMAGN_SIF 0x30 /* Z-axis magnetometer, soft-iron factor */ - -#define ADIS16400_GPIO_CTRL 0x32 /* Auxiliary digital input/output control */ -#define ADIS16400_MSC_CTRL 0x34 /* Miscellaneous control */ -#define ADIS16400_SMPL_PRD 0x36 /* Internal sample period (rate) control */ -#define ADIS16400_SENS_AVG 0x38 /* Dynamic range and digital filter control */ -#define ADIS16400_SLP_CNT 0x3A /* Sleep mode control */ -#define ADIS16400_DIAG_STAT 0x3C /* System status */ - -/* Alarm functions */ -#define ADIS16400_GLOB_CMD 0x3E /* System command */ -#define ADIS16400_ALM_MAG1 0x40 /* Alarm 1 amplitude threshold */ -#define ADIS16400_ALM_MAG2 0x42 /* Alarm 2 amplitude threshold */ -#define ADIS16400_ALM_SMPL1 0x44 /* Alarm 1 sample size */ -#define ADIS16400_ALM_SMPL2 0x46 /* Alarm 2 sample size */ -#define ADIS16400_ALM_CTRL 0x48 /* Alarm control */ -#define ADIS16400_AUX_DAC 0x4A /* Auxiliary DAC data */ - -#define ADIS16334_LOT_ID1 0x52 /* Lot identification code 1 */ -#define ADIS16334_LOT_ID2 0x54 /* Lot identification code 2 */ -#define ADIS16400_PRODUCT_ID 0x56 /* Product identifier */ -#define ADIS16334_SERIAL_NUMBER 0x58 /* Serial number, lot specific */ - -#define ADIS16400_ERROR_ACTIVE (1<<14) -#define ADIS16400_NEW_DATA (1<<14) - -/* MSC_CTRL */ -#define ADIS16400_MSC_CTRL_MEM_TEST (1<<11) -#define ADIS16400_MSC_CTRL_INT_SELF_TEST (1<<10) -#define ADIS16400_MSC_CTRL_NEG_SELF_TEST (1<<9) -#define ADIS16400_MSC_CTRL_POS_SELF_TEST (1<<8) -#define ADIS16400_MSC_CTRL_GYRO_BIAS (1<<7) -#define ADIS16400_MSC_CTRL_ACCL_ALIGN (1<<6) -#define ADIS16400_MSC_CTRL_DATA_RDY_EN (1<<2) -#define ADIS16400_MSC_CTRL_DATA_RDY_POL_HIGH (1<<1) -#define ADIS16400_MSC_CTRL_DATA_RDY_DIO2 (1<<0) - -/* SMPL_PRD */ -#define ADIS16400_SMPL_PRD_TIME_BASE (1<<7) -#define ADIS16400_SMPL_PRD_DIV_MASK 0x7F - -/* DIAG_STAT */ -#define ADIS16400_DIAG_STAT_ZACCL_FAIL 15 -#define ADIS16400_DIAG_STAT_YACCL_FAIL 14 -#define ADIS16400_DIAG_STAT_XACCL_FAIL 13 -#define ADIS16400_DIAG_STAT_XGYRO_FAIL 12 -#define ADIS16400_DIAG_STAT_YGYRO_FAIL 11 -#define ADIS16400_DIAG_STAT_ZGYRO_FAIL 10 -#define ADIS16400_DIAG_STAT_ALARM2 9 -#define ADIS16400_DIAG_STAT_ALARM1 8 -#define ADIS16400_DIAG_STAT_FLASH_CHK 6 -#define ADIS16400_DIAG_STAT_SELF_TEST 5 -#define ADIS16400_DIAG_STAT_OVERFLOW 4 -#define ADIS16400_DIAG_STAT_SPI_FAIL 3 -#define ADIS16400_DIAG_STAT_FLASH_UPT 2 -#define ADIS16400_DIAG_STAT_POWER_HIGH 1 -#define ADIS16400_DIAG_STAT_POWER_LOW 0 - -/* GLOB_CMD */ -#define ADIS16400_GLOB_CMD_SW_RESET (1<<7) -#define ADIS16400_GLOB_CMD_P_AUTO_NULL (1<<4) -#define ADIS16400_GLOB_CMD_FLASH_UPD (1<<3) -#define ADIS16400_GLOB_CMD_DAC_LATCH (1<<2) -#define ADIS16400_GLOB_CMD_FAC_CALIB (1<<1) -#define ADIS16400_GLOB_CMD_AUTO_NULL (1<<0) - -/* SLP_CNT */ -#define ADIS16400_SLP_CNT_POWER_OFF (1<<8) - -#define ADIS16334_RATE_DIV_SHIFT 8 -#define ADIS16334_RATE_INT_CLK BIT(0) - -#define ADIS16400_SPI_SLOW (u32)(300 * 1000) -#define ADIS16400_SPI_BURST (u32)(1000 * 1000) -#define ADIS16400_SPI_FAST (u32)(2000 * 1000) - -#define ADIS16400_HAS_PROD_ID BIT(0) -#define ADIS16400_NO_BURST BIT(1) -#define ADIS16400_HAS_SLOW_MODE BIT(2) -#define ADIS16400_HAS_SERIAL_NUMBER BIT(3) -#define ADIS16400_BURST_DIAG_STAT BIT(4) - -struct adis16400_state; - -struct adis16400_chip_info { - const struct iio_chan_spec *channels; - const int num_channels; - const long flags; - unsigned int gyro_scale_micro; - unsigned int accel_scale_micro; - int temp_scale_nano; - int temp_offset; - int (*set_freq)(struct adis16400_state *st, unsigned int freq); - int (*get_freq)(struct adis16400_state *st); -}; - -/** - * struct adis16400_state - device instance specific data - * @variant: chip variant info - * @filt_int: integer part of requested filter frequency - * @adis: adis device - **/ -struct adis16400_state { - struct adis16400_chip_info *variant; - int filt_int; - - struct adis adis; - unsigned long avail_scan_mask[2]; -}; - -/* At the moment triggers are only used for ring buffer - * filling. This may change! - */ - -enum { - ADIS16400_SCAN_SUPPLY, - ADIS16400_SCAN_GYRO_X, - ADIS16400_SCAN_GYRO_Y, - ADIS16400_SCAN_GYRO_Z, - ADIS16400_SCAN_ACC_X, - ADIS16400_SCAN_ACC_Y, - ADIS16400_SCAN_ACC_Z, - ADIS16400_SCAN_MAGN_X, - ADIS16400_SCAN_MAGN_Y, - ADIS16400_SCAN_MAGN_Z, - ADIS16400_SCAN_BARO, - ADIS16350_SCAN_TEMP_X, - ADIS16350_SCAN_TEMP_Y, - ADIS16350_SCAN_TEMP_Z, - ADIS16300_SCAN_INCLI_X, - ADIS16300_SCAN_INCLI_Y, - ADIS16400_SCAN_ADC, - ADIS16400_SCAN_TIMESTAMP, -}; - -#ifdef CONFIG_IIO_BUFFER - -ssize_t adis16400_read_data_from_ring(struct device *dev, - struct device_attribute *attr, - char *buf); - - -int adis16400_update_scan_mode(struct iio_dev *indio_dev, - const unsigned long *scan_mask); -irqreturn_t adis16400_trigger_handler(int irq, void *p); - -#else /* CONFIG_IIO_BUFFER */ - -#define adis16400_update_scan_mode NULL -#define adis16400_trigger_handler NULL - -#endif /* CONFIG_IIO_BUFFER */ - -#endif /* SPI_ADIS16400_H_ */ diff --git a/drivers/iio/imu/adis16400_buffer.c b/drivers/iio/imu/adis16400_buffer.c deleted file mode 100644 index e70a5339acb1..000000000000 --- a/drivers/iio/imu/adis16400_buffer.c +++ /dev/null @@ -1,101 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <linux/interrupt.h> -#include <linux/mutex.h> -#include <linux/kernel.h> -#include <linux/spi/spi.h> -#include <linux/slab.h> -#include <linux/bitops.h> -#include <linux/export.h> - -#include <linux/iio/iio.h> -#include <linux/iio/buffer.h> -#include <linux/iio/triggered_buffer.h> -#include <linux/iio/trigger_consumer.h> - -#include "adis16400.h" - -int adis16400_update_scan_mode(struct iio_dev *indio_dev, - const unsigned long *scan_mask) -{ - struct adis16400_state *st = iio_priv(indio_dev); - struct adis *adis = &st->adis; - unsigned int burst_length; - u8 *tx; - - if (st->variant->flags & ADIS16400_NO_BURST) - return adis_update_scan_mode(indio_dev, scan_mask); - - kfree(adis->xfer); - kfree(adis->buffer); - - /* All but the timestamp channel */ - burst_length = (indio_dev->num_channels - 1) * sizeof(u16); - if (st->variant->flags & ADIS16400_BURST_DIAG_STAT) - burst_length += sizeof(u16); - - adis->xfer = kcalloc(2, sizeof(*adis->xfer), GFP_KERNEL); - if (!adis->xfer) - return -ENOMEM; - - adis->buffer = kzalloc(burst_length + sizeof(u16), GFP_KERNEL); - if (!adis->buffer) - return -ENOMEM; - - tx = adis->buffer + burst_length; - tx[0] = ADIS_READ_REG(ADIS16400_GLOB_CMD); - tx[1] = 0; - - adis->xfer[0].tx_buf = tx; - adis->xfer[0].bits_per_word = 8; - adis->xfer[0].len = 2; - adis->xfer[1].rx_buf = adis->buffer; - adis->xfer[1].bits_per_word = 8; - adis->xfer[1].len = burst_length; - - spi_message_init(&adis->msg); - spi_message_add_tail(&adis->xfer[0], &adis->msg); - spi_message_add_tail(&adis->xfer[1], &adis->msg); - - return 0; -} - -irqreturn_t adis16400_trigger_handler(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct adis16400_state *st = iio_priv(indio_dev); - struct adis *adis = &st->adis; - u32 old_speed_hz = st->adis.spi->max_speed_hz; - void *buffer; - int ret; - - if (!adis->buffer) - return -ENOMEM; - - if (!(st->variant->flags & ADIS16400_NO_BURST) && - st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) { - st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST; - spi_setup(st->adis.spi); - } - - ret = spi_sync(adis->spi, &adis->msg); - if (ret) - dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret); - - if (!(st->variant->flags & ADIS16400_NO_BURST)) { - st->adis.spi->max_speed_hz = old_speed_hz; - spi_setup(st->adis.spi); - } - - if (st->variant->flags & ADIS16400_BURST_DIAG_STAT) - buffer = adis->buffer + sizeof(u16); - else - buffer = adis->buffer; - - iio_push_to_buffers_with_timestamp(indio_dev, buffer, - pf->timestamp); - - iio_trigger_notify_done(indio_dev->trig); - - return IRQ_HANDLED; -} diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index a27fe208f3ae..ab137c1bbe7b 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -9,6 +9,9 @@ * */ +#include <linux/clk.h> +#include <linux/bitfield.h> +#include <linux/of_irq.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/mutex.h> @@ -97,6 +100,12 @@ #define ADIS16480_REG_FIRM_DM ADIS16480_REG(0x03, 0x7A) #define ADIS16480_REG_FIRM_Y ADIS16480_REG(0x03, 0x7C) +/* + * External clock scaling in PPS mode. + * Available only for ADIS1649x devices + */ +#define ADIS16495_REG_SYNC_SCALE ADIS16480_REG(0x03, 0x10) + #define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20) /* Each filter coefficent bank spans two pages */ @@ -107,6 +116,20 @@ #define ADIS16480_FIR_COEF_C(x) ADIS16480_FIR_COEF(0x09, (x)) #define ADIS16480_FIR_COEF_D(x) ADIS16480_FIR_COEF(0x0B, (x)) +/* ADIS16480_REG_FNCTIO_CTRL */ +#define ADIS16480_DRDY_SEL_MSK GENMASK(1, 0) +#define ADIS16480_DRDY_SEL(x) FIELD_PREP(ADIS16480_DRDY_SEL_MSK, x) +#define ADIS16480_DRDY_POL_MSK BIT(2) +#define ADIS16480_DRDY_POL(x) FIELD_PREP(ADIS16480_DRDY_POL_MSK, x) +#define ADIS16480_DRDY_EN_MSK BIT(3) +#define ADIS16480_DRDY_EN(x) FIELD_PREP(ADIS16480_DRDY_EN_MSK, x) +#define ADIS16480_SYNC_SEL_MSK GENMASK(5, 4) +#define ADIS16480_SYNC_SEL(x) FIELD_PREP(ADIS16480_SYNC_SEL_MSK, x) +#define ADIS16480_SYNC_EN_MSK BIT(7) +#define ADIS16480_SYNC_EN(x) FIELD_PREP(ADIS16480_SYNC_EN_MSK, x) +#define ADIS16480_SYNC_MODE_MSK BIT(8) +#define ADIS16480_SYNC_MODE(x) FIELD_PREP(ADIS16480_SYNC_MODE_MSK, x) + struct adis16480_chip_info { unsigned int num_channels; const struct iio_chan_spec *channels; @@ -114,12 +137,40 @@ struct adis16480_chip_info { unsigned int gyro_max_scale; unsigned int accel_max_val; unsigned int accel_max_scale; + unsigned int temp_scale; + unsigned int int_clk; + unsigned int max_dec_rate; + const unsigned int *filter_freqs; + bool has_pps_clk_mode; +}; + +enum adis16480_int_pin { + ADIS16480_PIN_DIO1, + ADIS16480_PIN_DIO2, + ADIS16480_PIN_DIO3, + ADIS16480_PIN_DIO4 +}; + +enum adis16480_clock_mode { + ADIS16480_CLK_SYNC, + ADIS16480_CLK_PPS, + ADIS16480_CLK_INT }; struct adis16480 { const struct adis16480_chip_info *chip_info; struct adis adis; + struct clk *ext_clk; + enum adis16480_clock_mode clk_mode; + unsigned int clk_freq; +}; + +static const char * const adis16480_int_pin_names[4] = { + [ADIS16480_PIN_DIO1] = "DIO1", + [ADIS16480_PIN_DIO2] = "DIO2", + [ADIS16480_PIN_DIO3] = "DIO3", + [ADIS16480_PIN_DIO4] = "DIO4", }; #ifdef CONFIG_DEBUG_FS @@ -268,20 +319,34 @@ static int adis16480_debugfs_init(struct iio_dev *indio_dev) static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2) { struct adis16480 *st = iio_priv(indio_dev); - unsigned int t; + unsigned int t, reg; t = val * 1000 + val2 / 1000; if (t <= 0) return -EINVAL; - t = 2460000 / t; - if (t > 2048) - t = 2048; + /* + * When using PPS mode, the rate of data collection is equal to the + * product of the external clock frequency and the scale factor in the + * SYNC_SCALE register. + * When using sync mode, or internal clock, the output data rate is + * equal with the clock frequency divided by DEC_RATE + 1. + */ + if (st->clk_mode == ADIS16480_CLK_PPS) { + t = t / st->clk_freq; + reg = ADIS16495_REG_SYNC_SCALE; + } else { + t = st->clk_freq / t; + reg = ADIS16480_REG_DEC_RATE; + } + + if (t > st->chip_info->max_dec_rate) + t = st->chip_info->max_dec_rate; - if (t != 0) + if ((t != 0) && (st->clk_mode != ADIS16480_CLK_PPS)) t--; - return adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t); + return adis_write_reg_16(&st->adis, reg, t); } static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) @@ -290,12 +355,29 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) uint16_t t; int ret; unsigned freq; + unsigned int reg; - ret = adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t); + if (st->clk_mode == ADIS16480_CLK_PPS) + reg = ADIS16495_REG_SYNC_SCALE; + else + reg = ADIS16480_REG_DEC_RATE; + + ret = adis_read_reg_16(&st->adis, reg, &t); if (ret < 0) return ret; - freq = 2460000 / (t + 1); + /* + * When using PPS mode, the rate of data collection is equal to the + * product of the external clock frequency and the scale factor in the + * SYNC_SCALE register. + * When using sync mode, or internal clock, the output data rate is + * equal with the clock frequency divided by DEC_RATE + 1. + */ + if (st->clk_mode == ADIS16480_CLK_PPS) + freq = st->clk_freq * t; + else + freq = st->clk_freq / (t + 1); + *val = freq / 1000; *val2 = (freq % 1000) * 1000; @@ -425,6 +507,13 @@ static const unsigned int adis16480_def_filter_freqs[] = { 63, }; +static const unsigned int adis16495_def_filter_freqs[] = { + 300, + 100, + 300, + 100, +}; + static const unsigned int ad16480_filter_data[][2] = { [ADIS16480_SCAN_GYRO_X] = { ADIS16480_REG_FILTER_BNK0, 0 }, [ADIS16480_SCAN_GYRO_Y] = { ADIS16480_REG_FILTER_BNK0, 3 }, @@ -456,7 +545,7 @@ static int adis16480_get_filter_freq(struct iio_dev *indio_dev, if (!(val & enable_mask)) *freq = 0; else - *freq = adis16480_def_filter_freqs[(val >> offset) & 0x3]; + *freq = st->chip_info->filter_freqs[(val >> offset) & 0x3]; return IIO_VAL_INT; } @@ -483,10 +572,10 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev, val &= ~enable_mask; } else { best_freq = 0; - best_diff = 310; + best_diff = st->chip_info->filter_freqs[0]; for (i = 0; i < ARRAY_SIZE(adis16480_def_filter_freqs); i++) { - if (adis16480_def_filter_freqs[i] >= freq) { - diff = adis16480_def_filter_freqs[i] - freq; + if (st->chip_info->filter_freqs[i] >= freq) { + diff = st->chip_info->filter_freqs[i] - freq; if (diff < best_diff) { best_diff = diff; best_freq = i; @@ -506,6 +595,7 @@ static int adis16480_read_raw(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, int *val, int *val2, long info) { struct adis16480 *st = iio_priv(indio_dev); + unsigned int temp; switch (info) { case IIO_CHAN_INFO_RAW: @@ -525,8 +615,13 @@ static int adis16480_read_raw(struct iio_dev *indio_dev, *val2 = 100; /* 0.0001 gauss */ return IIO_VAL_INT_PLUS_MICRO; case IIO_TEMP: - *val = 5; - *val2 = 650000; /* 5.65 milli degree Celsius */ + /* + * +85 degrees Celsius = temp_max_scale + * +25 degrees Celsius = 0 + * LSB, 25 degrees Celsius = 60 / temp_max_scale + */ + *val = st->chip_info->temp_scale / 1000; + *val2 = (st->chip_info->temp_scale % 1000) * 1000; return IIO_VAL_INT_PLUS_MICRO; case IIO_PRESSURE: *val = 0; @@ -537,7 +632,8 @@ static int adis16480_read_raw(struct iio_dev *indio_dev, } case IIO_CHAN_INFO_OFFSET: /* Only the temperature channel has a offset */ - *val = 4425; /* 25 degree Celsius = 0x0000 */ + temp = 25 * 1000000LL; /* 25 degree Celsius = 0x0000 */ + *val = DIV_ROUND_CLOSEST_ULL(temp, st->chip_info->temp_scale); return IIO_VAL_INT; case IIO_CHAN_INFO_CALIBBIAS: return adis16480_get_calibbias(indio_dev, chan, val); @@ -678,6 +774,12 @@ enum adis16480_variant { ADIS16480, ADIS16485, ADIS16488, + ADIS16495_1, + ADIS16495_2, + ADIS16495_3, + ADIS16497_1, + ADIS16497_2, + ADIS16497_3, }; static const struct adis16480_chip_info adis16480_chip_info[] = { @@ -693,6 +795,10 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .gyro_max_scale = 300, .accel_max_val = IIO_M_S_2_TO_G(21973), .accel_max_scale = 18, + .temp_scale = 5650, /* 5.65 milli degree Celsius */ + .int_clk = 2460000, + .max_dec_rate = 2048, + .filter_freqs = adis16480_def_filter_freqs, }, [ADIS16480] = { .channels = adis16480_channels, @@ -701,6 +807,10 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .gyro_max_scale = 450, .accel_max_val = IIO_M_S_2_TO_G(12500), .accel_max_scale = 10, + .temp_scale = 5650, /* 5.65 milli degree Celsius */ + .int_clk = 2460000, + .max_dec_rate = 2048, + .filter_freqs = adis16480_def_filter_freqs, }, [ADIS16485] = { .channels = adis16485_channels, @@ -709,6 +819,10 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .gyro_max_scale = 450, .accel_max_val = IIO_M_S_2_TO_G(20000), .accel_max_scale = 5, + .temp_scale = 5650, /* 5.65 milli degree Celsius */ + .int_clk = 2460000, + .max_dec_rate = 2048, + .filter_freqs = adis16480_def_filter_freqs, }, [ADIS16488] = { .channels = adis16480_channels, @@ -717,6 +831,88 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .gyro_max_scale = 450, .accel_max_val = IIO_M_S_2_TO_G(22500), .accel_max_scale = 18, + .temp_scale = 5650, /* 5.65 milli degree Celsius */ + .int_clk = 2460000, + .max_dec_rate = 2048, + .filter_freqs = adis16480_def_filter_freqs, + }, + [ADIS16495_1] = { + .channels = adis16485_channels, + .num_channels = ARRAY_SIZE(adis16485_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(20000), + .gyro_max_scale = 125, + .accel_max_val = IIO_M_S_2_TO_G(32000), + .accel_max_scale = 8, + .temp_scale = 12500, /* 12.5 milli degree Celsius */ + .int_clk = 4250000, + .max_dec_rate = 4250, + .filter_freqs = adis16495_def_filter_freqs, + .has_pps_clk_mode = true, + }, + [ADIS16495_2] = { + .channels = adis16485_channels, + .num_channels = ARRAY_SIZE(adis16485_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(18000), + .gyro_max_scale = 450, + .accel_max_val = IIO_M_S_2_TO_G(32000), + .accel_max_scale = 8, + .temp_scale = 12500, /* 12.5 milli degree Celsius */ + .int_clk = 4250000, + .max_dec_rate = 4250, + .filter_freqs = adis16495_def_filter_freqs, + .has_pps_clk_mode = true, + }, + [ADIS16495_3] = { + .channels = adis16485_channels, + .num_channels = ARRAY_SIZE(adis16485_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(20000), + .gyro_max_scale = 2000, + .accel_max_val = IIO_M_S_2_TO_G(32000), + .accel_max_scale = 8, + .temp_scale = 12500, /* 12.5 milli degree Celsius */ + .int_clk = 4250000, + .max_dec_rate = 4250, + .filter_freqs = adis16495_def_filter_freqs, + .has_pps_clk_mode = true, + }, + [ADIS16497_1] = { + .channels = adis16485_channels, + .num_channels = ARRAY_SIZE(adis16485_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(20000), + .gyro_max_scale = 125, + .accel_max_val = IIO_M_S_2_TO_G(32000), + .accel_max_scale = 40, + .temp_scale = 12500, /* 12.5 milli degree Celsius */ + .int_clk = 4250000, + .max_dec_rate = 4250, + .filter_freqs = adis16495_def_filter_freqs, + .has_pps_clk_mode = true, + }, + [ADIS16497_2] = { + .channels = adis16485_channels, + .num_channels = ARRAY_SIZE(adis16485_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(18000), + .gyro_max_scale = 450, + .accel_max_val = IIO_M_S_2_TO_G(32000), + .accel_max_scale = 40, + .temp_scale = 12500, /* 12.5 milli degree Celsius */ + .int_clk = 4250000, + .max_dec_rate = 4250, + .filter_freqs = adis16495_def_filter_freqs, + .has_pps_clk_mode = true, + }, + [ADIS16497_3] = { + .channels = adis16485_channels, + .num_channels = ARRAY_SIZE(adis16485_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(20000), + .gyro_max_scale = 2000, + .accel_max_val = IIO_M_S_2_TO_G(32000), + .accel_max_scale = 40, + .temp_scale = 12500, /* 12.5 milli degree Celsius */ + .int_clk = 4250000, + .max_dec_rate = 4250, + .filter_freqs = adis16495_def_filter_freqs, + .has_pps_clk_mode = true, }, }; @@ -741,8 +937,17 @@ static int adis16480_stop_device(struct iio_dev *indio_dev) static int adis16480_enable_irq(struct adis *adis, bool enable) { - return adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, - enable ? BIT(3) : 0); + uint16_t val; + int ret; + + ret = adis_read_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, &val); + if (ret < 0) + return ret; + + val &= ~ADIS16480_DRDY_EN_MSK; + val |= ADIS16480_DRDY_EN(enable); + + return adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, val); } static int adis16480_initial_setup(struct iio_dev *indio_dev) @@ -826,6 +1031,156 @@ static const struct adis_data adis16480_data = { .enable_irq = adis16480_enable_irq, }; +static int adis16480_config_irq_pin(struct device_node *of_node, + struct adis16480 *st) +{ + struct irq_data *desc; + enum adis16480_int_pin pin; + unsigned int irq_type; + uint16_t val; + int i, irq = 0; + + desc = irq_get_irq_data(st->adis.spi->irq); + if (!desc) { + dev_err(&st->adis.spi->dev, "Could not find IRQ %d\n", irq); + return -EINVAL; + } + + /* Disable data ready since the default after reset is on */ + val = ADIS16480_DRDY_EN(0); + + /* + * Get the interrupt from the devicetre by reading the interrupt-names + * property. If it is not specified, use DIO1 pin as default. + * According to the datasheet, the factory default assigns DIO2 as data + * ready signal. However, in the previous versions of the driver, DIO1 + * pin was used. So, we should leave it as is since some devices might + * be expecting the interrupt on the wrong physical pin. + */ + pin = ADIS16480_PIN_DIO1; + for (i = 0; i < ARRAY_SIZE(adis16480_int_pin_names); i++) { + irq = of_irq_get_byname(of_node, adis16480_int_pin_names[i]); + if (irq > 0) { + pin = i; + break; + } + } + + val |= ADIS16480_DRDY_SEL(pin); + + /* + * Get the interrupt line behaviour. The data ready polarity can be + * configured as positive or negative, corresponding to + * IRQF_TRIGGER_RISING or IRQF_TRIGGER_FALLING respectively. + */ + irq_type = irqd_get_trigger_type(desc); + if (irq_type == IRQF_TRIGGER_RISING) { /* Default */ + val |= ADIS16480_DRDY_POL(1); + } else if (irq_type == IRQF_TRIGGER_FALLING) { + val |= ADIS16480_DRDY_POL(0); + } else { + dev_err(&st->adis.spi->dev, + "Invalid interrupt type 0x%x specified\n", irq_type); + return -EINVAL; + } + /* Write the data ready configuration to the FNCTIO_CTRL register */ + return adis_write_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, val); +} + +static int adis16480_of_get_ext_clk_pin(struct adis16480 *st, + struct device_node *of_node) +{ + const char *ext_clk_pin; + enum adis16480_int_pin pin; + int i; + + pin = ADIS16480_PIN_DIO2; + if (of_property_read_string(of_node, "adi,ext-clk-pin", &ext_clk_pin)) + goto clk_input_not_found; + + for (i = 0; i < ARRAY_SIZE(adis16480_int_pin_names); i++) { + if (strcasecmp(ext_clk_pin, adis16480_int_pin_names[i]) == 0) + return i; + } + +clk_input_not_found: + dev_info(&st->adis.spi->dev, + "clk input line not specified, using DIO2\n"); + return pin; +} + +static int adis16480_ext_clk_config(struct adis16480 *st, + struct device_node *of_node, + bool enable) +{ + unsigned int mode, mask; + enum adis16480_int_pin pin; + uint16_t val; + int ret; + + ret = adis_read_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, &val); + if (ret < 0) + return ret; + + pin = adis16480_of_get_ext_clk_pin(st, of_node); + /* + * Each DIOx pin supports only one function at a time. When a single pin + * has two assignments, the enable bit for a lower priority function + * automatically resets to zero (disabling the lower priority function). + */ + if (pin == ADIS16480_DRDY_SEL(val)) + dev_warn(&st->adis.spi->dev, + "DIO%x pin supports only one function at a time\n", + pin + 1); + + mode = ADIS16480_SYNC_EN(enable) | ADIS16480_SYNC_SEL(pin); + mask = ADIS16480_SYNC_EN_MSK | ADIS16480_SYNC_SEL_MSK; + /* Only ADIS1649x devices support pps ext clock mode */ + if (st->chip_info->has_pps_clk_mode) { + mode |= ADIS16480_SYNC_MODE(st->clk_mode); + mask |= ADIS16480_SYNC_MODE_MSK; + } + + val &= ~mask; + val |= mode; + + ret = adis_write_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, val); + if (ret < 0) + return ret; + + return clk_prepare_enable(st->ext_clk); +} + +static int adis16480_get_ext_clocks(struct adis16480 *st) +{ + st->clk_mode = ADIS16480_CLK_INT; + st->ext_clk = devm_clk_get(&st->adis.spi->dev, "sync"); + if (!IS_ERR_OR_NULL(st->ext_clk)) { + st->clk_mode = ADIS16480_CLK_SYNC; + return 0; + } + + if (PTR_ERR(st->ext_clk) != -ENOENT) { + dev_err(&st->adis.spi->dev, "failed to get ext clk\n"); + return PTR_ERR(st->ext_clk); + } + + if (st->chip_info->has_pps_clk_mode) { + st->ext_clk = devm_clk_get(&st->adis.spi->dev, "pps"); + if (!IS_ERR_OR_NULL(st->ext_clk)) { + st->clk_mode = ADIS16480_CLK_PPS; + return 0; + } + + if (PTR_ERR(st->ext_clk) != -ENOENT) { + dev_err(&st->adis.spi->dev, "failed to get ext clk\n"); + return PTR_ERR(st->ext_clk); + } + } + + return 0; +} + static int adis16480_probe(struct spi_device *spi) { const struct spi_device_id *id = spi_get_device_id(spi); @@ -853,10 +1208,29 @@ static int adis16480_probe(struct spi_device *spi) if (ret) return ret; - ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL); + ret = adis16480_config_irq_pin(spi->dev.of_node, st); + if (ret) + return ret; + + ret = adis16480_get_ext_clocks(st); if (ret) return ret; + if (!IS_ERR_OR_NULL(st->ext_clk)) { + ret = adis16480_ext_clk_config(st, spi->dev.of_node, true); + if (ret) + return ret; + + st->clk_freq = clk_get_rate(st->ext_clk); + st->clk_freq *= 1000; /* micro */ + } else { + st->clk_freq = st->chip_info->int_clk; + } + + ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL); + if (ret) + goto error_clk_disable_unprepare; + ret = adis16480_initial_setup(indio_dev); if (ret) goto error_cleanup_buffer; @@ -873,6 +1247,8 @@ error_stop_device: adis16480_stop_device(indio_dev); error_cleanup_buffer: adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); +error_clk_disable_unprepare: + clk_disable_unprepare(st->ext_clk); return ret; } @@ -885,6 +1261,7 @@ static int adis16480_remove(struct spi_device *spi) adis16480_stop_device(indio_dev); adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); + clk_disable_unprepare(st->ext_clk); return 0; } @@ -894,13 +1271,35 @@ static const struct spi_device_id adis16480_ids[] = { { "adis16480", ADIS16480 }, { "adis16485", ADIS16485 }, { "adis16488", ADIS16488 }, + { "adis16495-1", ADIS16495_1 }, + { "adis16495-2", ADIS16495_2 }, + { "adis16495-3", ADIS16495_3 }, + { "adis16497-1", ADIS16497_1 }, + { "adis16497-2", ADIS16497_2 }, + { "adis16497-3", ADIS16497_3 }, { } }; MODULE_DEVICE_TABLE(spi, adis16480_ids); +static const struct of_device_id adis16480_of_match[] = { + { .compatible = "adi,adis16375" }, + { .compatible = "adi,adis16480" }, + { .compatible = "adi,adis16485" }, + { .compatible = "adi,adis16488" }, + { .compatible = "adi,adis16495-1" }, + { .compatible = "adi,adis16495-2" }, + { .compatible = "adi,adis16495-3" }, + { .compatible = "adi,adis16497-1" }, + { .compatible = "adi,adis16497-2" }, + { .compatible = "adi,adis16497-3" }, + { }, +}; +MODULE_DEVICE_TABLE(of, adis16480_of_match); + static struct spi_driver adis16480_driver = { .driver = { .name = "adis16480", + .of_match_table = adis16480_of_match, }, .id_table = adis16480_ids, .probe = adis16480_probe, diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index 76643c5571aa..3a7c970568dc 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -20,6 +20,43 @@ #include <linux/iio/triggered_buffer.h> #include <linux/iio/imu/adis.h> +static int adis_update_scan_mode_burst(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct adis *adis = iio_device_get_drvdata(indio_dev); + unsigned int burst_length; + u8 *tx; + + /* All but the timestamp channel */ + burst_length = (indio_dev->num_channels - 1) * sizeof(u16); + burst_length += adis->burst->extra_len; + + adis->xfer = kcalloc(2, sizeof(*adis->xfer), GFP_KERNEL); + if (!adis->xfer) + return -ENOMEM; + + adis->buffer = kzalloc(burst_length + sizeof(u16), GFP_KERNEL); + if (!adis->buffer) + return -ENOMEM; + + tx = adis->buffer + burst_length; + tx[0] = ADIS_READ_REG(adis->burst->reg_cmd); + tx[1] = 0; + + adis->xfer[0].tx_buf = tx; + adis->xfer[0].bits_per_word = 8; + adis->xfer[0].len = 2; + adis->xfer[1].rx_buf = adis->buffer; + adis->xfer[1].bits_per_word = 8; + adis->xfer[1].len = burst_length; + + spi_message_init(&adis->msg); + spi_message_add_tail(&adis->xfer[0], &adis->msg); + spi_message_add_tail(&adis->xfer[1], &adis->msg); + + return 0; +} + int adis_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *scan_mask) { @@ -32,6 +69,9 @@ int adis_update_scan_mode(struct iio_dev *indio_dev, kfree(adis->xfer); kfree(adis->buffer); + if (adis->burst && adis->burst->en) + return adis_update_scan_mode_burst(indio_dev, scan_mask); + scan_count = indio_dev->scan_bytes / 2; adis->xfer = kcalloc(scan_count + 1, sizeof(*adis->xfer), GFP_KERNEL); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 650de0fefb7b..6138a6d86afb 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -796,12 +796,14 @@ static const struct iio_mount_matrix * inv_get_mount_matrix(const struct iio_dev *indio_dev, const struct iio_chan_spec *chan) { - return &((struct inv_mpu6050_state *)iio_priv(indio_dev))->orientation; + struct inv_mpu6050_state *data = iio_priv(indio_dev); + + return &data->orientation; } static const struct iio_chan_spec_ext_info inv_ext_info[] = { IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, inv_get_mount_matrix), - { }, + { } }; #define INV_MPU6050_CHAN(_type, _channel2, _index) \ @@ -1021,8 +1023,8 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, pdata = dev_get_platdata(dev); if (!pdata) { - result = of_iio_read_mount_matrix(dev, "mount-matrix", - &st->orientation); + result = iio_read_mount_matrix(dev, "mount-matrix", + &st->orientation); if (result) { dev_err(dev, "Failed to retrieve mounting matrix %d\n", result); diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig index 094fd006b63d..8dcf5137b8da 100644 --- a/drivers/iio/imu/st_lsm6dsx/Kconfig +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig @@ -9,7 +9,7 @@ config IIO_ST_LSM6DSX help Say yes here to build support for STMicroelectronics LSM6DSx imu sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, - ism330dlc, lsm6dso + ism330dlc, lsm6dso, lsm6dsox, asm330lhh To compile this driver as a module, choose M here: the module will be called st_lsm6dsx. diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index d1d8d07a0714..0a0c56c1701d 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -20,6 +20,8 @@ #define ST_LSM6DSM_DEV_NAME "lsm6dsm" #define ST_ISM330DLC_DEV_NAME "ism330dlc" #define ST_LSM6DSO_DEV_NAME "lsm6dso" +#define ST_ASM330LHH_DEV_NAME "asm330lhh" +#define ST_LSM6DSOX_DEV_NAME "lsm6dsox" enum st_lsm6dsx_hw_id { ST_LSM6DS3_ID, @@ -28,6 +30,8 @@ enum st_lsm6dsx_hw_id { ST_LSM6DSM_ID, ST_ISM330DLC_ID, ST_LSM6DSO_ID, + ST_ASM330LHH_ID, + ST_LSM6DSOX_ID, ST_LSM6DSX_MAX_ID, }; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index 2c0d3763405a..2da8c5ff699a 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -13,9 +13,9 @@ * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the * value of the decimation factor and ODR set for each FIFO data set. * - * LSM6DSO: The FIFO buffer can be configured to store data from gyroscope and - * accelerometer. Each sample is queued with a tag (1B) indicating data source - * (gyroscope, accelerometer, hw timer). + * LSM6DSO/LSM6DSOX/ASM330LHH: The FIFO buffer can be configured to store data + * from gyroscope and accelerometer. Each sample is queued with a tag (1B) + * indicating data source (gyroscope, accelerometer, hw timer). * * FIFO supported modes: * - BYPASS: FIFO disabled @@ -506,7 +506,7 @@ st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw *hw, u8 tag, } /** - * st_lsm6dsx_read_tagged_fifo() - LSM6DSO read FIFO routine + * st_lsm6dsx_read_tagged_fifo() - LSM6DSO/LSM6DSOX/ASM330LHH read FIFO routine * @hw: Pointer to instance of struct st_lsm6dsx_hw. * * Read samples from the hw FIFO and push them to IIO buffers. diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 12e29dda9b98..c167ae2c21ab 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -23,7 +23,7 @@ * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - FIFO size: 4KB * - * - LSM6DSO + * - LSM6DSO/LSM6DSOX/ASM330LHH * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 @@ -287,6 +287,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .max_fifo_size = 512, .id = { [0] = ST_LSM6DSO_ID, + [1] = ST_LSM6DSOX_ID, }, .batch = { [ST_LSM6DSX_ID_ACC] = { @@ -347,6 +348,45 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .batch_en = BIT(3), } }, + { + .wai = 0x6b, + .max_fifo_size = 512, + .id = { + [0] = ST_ASM330LHH_ID, + }, + .batch = { + [ST_LSM6DSX_ID_ACC] = { + .addr = 0x09, + .mask = GENMASK(3, 0), + }, + [ST_LSM6DSX_ID_GYRO] = { + .addr = 0x09, + .mask = GENMASK(7, 4), + }, + }, + .fifo_ops = { + .read_fifo = st_lsm6dsx_read_tagged_fifo, + .fifo_th = { + .addr = 0x07, + .mask = GENMASK(8, 0), + }, + .fifo_diff = { + .addr = 0x3a, + .mask = GENMASK(8, 0), + }, + .th_wl = 1, + }, + .ts_settings = { + .timer_en = { + .addr = 0x19, + .mask = BIT(5), + }, + .decimator = { + .addr = 0x0a, + .mask = GENMASK(7, 6), + }, + }, + }, }; static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = { diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c index 448b7bc1e578..0bfc66d2d772 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c @@ -65,6 +65,14 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = { .compatible = "st,lsm6dso", .data = (void *)ST_LSM6DSO_ID, }, + { + .compatible = "st,asm330lhh", + .data = (void *)ST_ASM330LHH_ID, + }, + { + .compatible = "st,lsm6dsox", + .data = (void *)ST_LSM6DSOX_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); @@ -76,6 +84,8 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = { { 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 }, {}, }; MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c index b1df8a6973e6..9f46d4ce9fc1 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c @@ -65,6 +65,14 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = { .compatible = "st,lsm6dso", .data = (void *)ST_LSM6DSO_ID, }, + { + .compatible = "st,asm330lhh", + .data = (void *)ST_ASM330LHH_ID, + }, + { + .compatible = "st,lsm6dsox", + .data = (void *)ST_LSM6DSOX_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match); @@ -76,6 +84,8 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = { { 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 }, {}, }; MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table); diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index cd5bfe39591b..3c7e7380d1c3 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -320,9 +320,7 @@ static int iio_scan_mask_set(struct iio_dev *indio_dev, const unsigned long *mask; unsigned long *trialmask; - trialmask = kmalloc_array(BITS_TO_LONGS(indio_dev->masklength), - sizeof(*trialmask), - GFP_KERNEL); + trialmask = bitmap_alloc(indio_dev->masklength, GFP_KERNEL); if (trialmask == NULL) return -ENOMEM; if (!indio_dev->masklength) { @@ -344,12 +342,12 @@ static int iio_scan_mask_set(struct iio_dev *indio_dev, } bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength); - kfree(trialmask); + bitmap_free(trialmask); return 0; err_invalid_mask: - kfree(trialmask); + bitmap_free(trialmask); return -EINVAL; } @@ -666,7 +664,7 @@ static void iio_free_scan_mask(struct iio_dev *indio_dev, { /* If the mask is dynamically allocated free it, otherwise do nothing */ if (!indio_dev->available_scan_masks) - kfree(mask); + bitmap_free(mask); } struct iio_device_config { @@ -736,8 +734,7 @@ static int iio_verify_update(struct iio_dev *indio_dev, } /* What scan mask do we actually have? */ - compound_mask = kcalloc(BITS_TO_LONGS(indio_dev->masklength), - sizeof(long), GFP_KERNEL); + compound_mask = bitmap_zalloc(indio_dev->masklength, GFP_KERNEL); if (compound_mask == NULL) return -ENOMEM; @@ -762,7 +759,7 @@ static int iio_verify_update(struct iio_dev *indio_dev, indio_dev->masklength, compound_mask, strict_scanmask); - kfree(compound_mask); + bitmap_free(compound_mask); if (scan_mask == NULL) return -EINVAL; } else { @@ -1303,9 +1300,8 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) channels[i].scan_index; } if (indio_dev->masklength && buffer->scan_mask == NULL) { - buffer->scan_mask = kcalloc(BITS_TO_LONGS(indio_dev->masklength), - sizeof(*buffer->scan_mask), - GFP_KERNEL); + buffer->scan_mask = bitmap_zalloc(indio_dev->masklength, + GFP_KERNEL); if (buffer->scan_mask == NULL) { ret = -ENOMEM; goto error_cleanup_dynamic; @@ -1334,7 +1330,7 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) return 0; error_free_scan_mask: - kfree(buffer->scan_mask); + bitmap_free(buffer->scan_mask); error_cleanup_dynamic: iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list); kfree(indio_dev->buffer->buffer_group.attrs); @@ -1347,7 +1343,7 @@ void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev) if (!indio_dev->buffer) return; - kfree(indio_dev->buffer->scan_mask); + bitmap_free(indio_dev->buffer->scan_mask); kfree(indio_dev->buffer->buffer_group.attrs); kfree(indio_dev->buffer->scan_el_group.attrs); iio_free_chan_devattr_list(&indio_dev->buffer->scan_el_dev_attr_list); diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 4700fd5d8c90..f2ebca65f964 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -19,6 +19,7 @@ #include <linux/device.h> #include <linux/fs.h> #include <linux/poll.h> +#include <linux/property.h> #include <linux/sched.h> #include <linux/wait.h> #include <linux/cdev.h> @@ -530,8 +531,8 @@ ssize_t iio_show_mount_matrix(struct iio_dev *indio_dev, uintptr_t priv, EXPORT_SYMBOL_GPL(iio_show_mount_matrix); /** - * of_iio_read_mount_matrix() - retrieve iio device mounting matrix from - * device-tree "mount-matrix" property + * iio_read_mount_matrix() - retrieve iio device mounting matrix from + * device "mount-matrix" property * @dev: device the mounting matrix property is assigned to * @propname: device specific mounting matrix property name * @matrix: where to store retrieved matrix @@ -541,40 +542,29 @@ EXPORT_SYMBOL_GPL(iio_show_mount_matrix); * * Return: 0 if success, or a negative error code on failure. */ -#ifdef CONFIG_OF -int of_iio_read_mount_matrix(const struct device *dev, - const char *propname, - struct iio_mount_matrix *matrix) +int iio_read_mount_matrix(struct device *dev, const char *propname, + struct iio_mount_matrix *matrix) { - if (dev->of_node) { - int err = of_property_read_string_array(dev->of_node, - propname, matrix->rotation, - ARRAY_SIZE(iio_mount_idmatrix.rotation)); + size_t len = ARRAY_SIZE(iio_mount_idmatrix.rotation); + int err; - if (err == ARRAY_SIZE(iio_mount_idmatrix.rotation)) - return 0; + err = device_property_read_string_array(dev, propname, + matrix->rotation, len); + if (err == len) + return 0; - if (err >= 0) - /* Invalid number of matrix entries. */ - return -EINVAL; + if (err >= 0) + /* Invalid number of matrix entries. */ + return -EINVAL; - if (err != -EINVAL) - /* Invalid matrix declaration format. */ - return err; - } + if (err != -EINVAL) + /* Invalid matrix declaration format. */ + return err; /* Matrix was not declared at all: fallback to identity. */ return iio_setup_mount_idmatrix(dev, matrix); } -#else -int of_iio_read_mount_matrix(const struct device *dev, - const char *propname, - struct iio_mount_matrix *matrix) -{ - return iio_setup_mount_idmatrix(dev, matrix); -} -#endif -EXPORT_SYMBOL(of_iio_read_mount_matrix); +EXPORT_SYMBOL(iio_read_mount_matrix); static ssize_t __iio_format_value(char *buf, size_t len, unsigned int type, int size, const int *vals) diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index ce66699c7fcc..e5b538379ed1 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -254,8 +254,11 @@ static int iio_trigger_attach_poll_func(struct iio_trigger *trig, /* Get irq number */ pf->irq = iio_trigger_get_irq(trig); - if (pf->irq < 0) + if (pf->irq < 0) { + pr_err("Could not find an available irq for trigger %s, CONFIG_IIO_CONSUMERS_PER_TRIGGER=%d limit might be exceeded\n", + trig->name, CONFIG_IIO_CONSUMERS_PER_TRIGGER); goto out_put_module; + } /* Request irq */ ret = request_threaded_irq(pf->irq, pf->h, pf->thread, diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 5190eacfeb0a..954c958cfc43 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -13,11 +13,11 @@ config ACPI_ALS select IIO_TRIGGERED_BUFFER select IIO_KFIFO_BUF help - Say Y here if you want to build a driver for the ACPI0008 - Ambient Light Sensor. + Say Y here if you want to build a driver for the ACPI0008 + Ambient Light Sensor. - To compile this driver as a module, choose M here: the module will - be called acpi-als. + To compile this driver as a module, choose M here: the module will + be called acpi-als. config ADJD_S311 tristate "ADJD-S311-CR999 digital color sensor" @@ -25,31 +25,31 @@ config ADJD_S311 select IIO_TRIGGERED_BUFFER depends on I2C help - If you say yes here you get support for the Avago ADJD-S311-CR999 - digital color light sensor. + If you say yes here you get support for the Avago ADJD-S311-CR999 + digital color light sensor. - This driver can also be built as a module. If so, the module - will be called adjd_s311. + This driver can also be built as a module. If so, the module + will be called adjd_s311. config AL3320A tristate "AL3320A ambient light sensor" depends on I2C help - Say Y here if you want to build a driver for the Dyna Image AL3320A - ambient light sensor. + Say Y here if you want to build a driver for the Dyna Image AL3320A + ambient light sensor. - To compile this driver as a module, choose M here: the - module will be called al3320a. + To compile this driver as a module, choose M here: the + module will be called al3320a. config APDS9300 tristate "APDS9300 ambient light sensor" depends on I2C help - Say Y here if you want to build a driver for the Avago APDS9300 - ambient light sensor. + Say Y here if you want to build a driver for the Avago APDS9300 + ambient light sensor. - To compile this driver as a module, choose M here: the - module will be called apds9300. + To compile this driver as a module, choose M here: the + module will be called apds9300. config APDS9960 tristate "Avago APDS9960 gesture/RGB/ALS/proximity sensor" @@ -68,74 +68,74 @@ config BH1750 tristate "ROHM BH1750 ambient light sensor" depends on I2C help - Say Y here to build support for the ROHM BH1710, BH1715, BH1721, - BH1750, BH1751 ambient light sensors. + Say Y here to build support for the ROHM BH1710, BH1715, BH1721, + BH1750, BH1751 ambient light sensors. - To compile this driver as a module, choose M here: the module will - be called bh1750. + To compile this driver as a module, choose M here: the module will + be called bh1750. config BH1780 tristate "ROHM BH1780 ambient light sensor" depends on I2C help - Say Y here to build support for the ROHM BH1780GLI ambient - light sensor. + Say Y here to build support for the ROHM BH1780GLI ambient + light sensor. - To compile this driver as a module, choose M here: the module will - be called bh1780. + To compile this driver as a module, choose M here: the module will + be called bh1780. config CM32181 depends on I2C tristate "CM32181 driver" help - Say Y here if you use cm32181. - This option enables ambient light sensor using - Capella cm32181 device driver. + Say Y here if you use cm32181. + This option enables ambient light sensor using + Capella cm32181 device driver. - To compile this driver as a module, choose M here: - the module will be called cm32181. + To compile this driver as a module, choose M here: + the module will be called cm32181. config CM3232 depends on I2C tristate "CM3232 ambient light sensor" help - Say Y here if you use cm3232. - This option enables ambient light sensor using - Capella Microsystems cm3232 device driver. + Say Y here if you use cm3232. + This option enables ambient light sensor using + Capella Microsystems cm3232 device driver. - To compile this driver as a module, choose M here: - the module will be called cm3232. + To compile this driver as a module, choose M here: + the module will be called cm3232. config CM3323 depends on I2C tristate "Capella CM3323 color light sensor" help - Say Y here if you want to build a driver for Capella CM3323 - color sensor. + Say Y here if you want to build a driver for Capella CM3323 + color sensor. - To compile this driver as a module, choose M here: the module will - be called cm3323. + To compile this driver as a module, choose M here: the module will + be called cm3323. config CM3605 tristate "Capella CM3605 ambient light and proximity sensor" depends on OF help - Say Y here if you want to build a driver for Capella CM3605 - ambient light and short range proximity sensor. + Say Y here if you want to build a driver for Capella CM3605 + ambient light and short range proximity sensor. - To compile this driver as a module, choose M here: the module will - be called cm3605. + To compile this driver as a module, choose M here: the module will + be called cm3605. config CM36651 depends on I2C tristate "CM36651 driver" help - Say Y here if you use cm36651. - This option enables proximity & RGB sensor using - Capella cm36651 device driver. + Say Y here if you use cm36651. + This option enables proximity & RGB sensor using + Capella cm36651 device driver. - To compile this driver as a module, choose M here: - the module will be called cm36651. + To compile this driver as a module, choose M here: + the module will be called cm36651. config IIO_CROS_EC_LIGHT_PROX tristate "ChromeOS EC Light and Proximity Sensors" @@ -167,21 +167,21 @@ config SENSORS_ISL29018 select REGMAP_I2C default n help - If you say yes here you get support for ambient light sensing and - proximity infrared sensing from Intersil ISL29018. - This driver will provide the measurements of ambient light intensity - in lux, proximity infrared sensing and normal infrared sensing. - Data from sensor is accessible via sysfs. + If you say yes here you get support for ambient light sensing and + proximity infrared sensing from Intersil ISL29018. + This driver will provide the measurements of ambient light intensity + in lux, proximity infrared sensing and normal infrared sensing. + Data from sensor is accessible via sysfs. config SENSORS_ISL29028 tristate "Intersil ISL29028 Concurrent Light and Proximity Sensor" depends on I2C select REGMAP_I2C help - Provides driver for the Intersil's ISL29028 device. - This driver supports the sysfs interface to get the ALS, IR intensity, - Proximity value via iio. The ISL29028 provides the concurrent sensing - of ambient light and proximity. + Provides driver for the Intersil's ISL29028 device. + This driver supports the sysfs interface to get the ALS, IR intensity, + Proximity value via iio. The ISL29028 provides the concurrent sensing + of ambient light and proximity. config ISL29125 tristate "Intersil ISL29125 digital color light sensor" @@ -228,22 +228,22 @@ config JSA1212 depends on I2C select REGMAP_I2C help - Say Y here if you want to build a IIO driver for JSA1212 - proximity & ALS sensor device. + Say Y here if you want to build a IIO driver for JSA1212 + proximity & ALS sensor device. - To compile this driver as a module, choose M here: - the module will be called jsa1212. + To compile this driver as a module, choose M here: + the module will be called jsa1212. config RPR0521 tristate "ROHM RPR0521 ALS and proximity sensor driver" depends on I2C select REGMAP_I2C help - Say Y here if you want to build support for ROHM's RPR0521 - ambient light and proximity sensor device. + Say Y here if you want to build support for ROHM's RPR0521 + ambient light and proximity sensor device. - To compile this driver as a module, choose M here: - the module will be called rpr0521. + To compile this driver as a module, choose M here: + the module will be called rpr0521. config SENSORS_LM3533 tristate "LM3533 ambient light sensor" @@ -269,22 +269,22 @@ config LTR501 select IIO_BUFFER select IIO_TRIGGERED_BUFFER help - If you say yes here you get support for the Lite-On LTR-501ALS-01 - ambient light and proximity sensor. This driver also supports LTR-559 - ALS/PS or LTR-301 ALS sensors. + If you say yes here you get support for the Lite-On LTR-501ALS-01 + ambient light and proximity sensor. This driver also supports LTR-559 + ALS/PS or LTR-301 ALS sensors. - This driver can also be built as a module. If so, the module - will be called ltr501. + This driver can also be built as a module. If so, the module + will be called ltr501. config LV0104CS tristate "LV0104CS Ambient Light Sensor" depends on I2C help - Say Y here if you want to build support for the On Semiconductor - LV0104CS ambient light sensor. + Say Y here if you want to build support for the On Semiconductor + LV0104CS ambient light sensor. - To compile this driver as a module, choose M here: - the module will be called lv0104cs. + To compile this driver as a module, choose M here: + the module will be called lv0104cs. config MAX44000 tristate "MAX44000 Ambient and Infrared Proximity Sensor" @@ -293,11 +293,11 @@ config MAX44000 select IIO_BUFFER select IIO_TRIGGERED_BUFFER help - Say Y here if you want to build support for Maxim Integrated's - MAX44000 ambient and infrared proximity sensor device. + Say Y here if you want to build support for Maxim Integrated's + MAX44000 ambient and infrared proximity sensor device. - To compile this driver as a module, choose M here: - the module will be called max44000. + To compile this driver as a module, choose M here: + the module will be called max44000. config MAX44009 tristate "MAX44009 Ambient Light Sensor" @@ -320,15 +320,15 @@ config OPT3001 opt3001. config PA12203001 - tristate "TXC PA12203001 light and proximity sensor" - depends on I2C - select REGMAP_I2C - help - If you say yes here you get support for the TXC PA12203001 - ambient light and proximity sensor. + tristate "TXC PA12203001 light and proximity sensor" + depends on I2C + select REGMAP_I2C + help + If you say yes here you get support for the TXC PA12203001 + ambient light and proximity sensor. - This driver can also be built as a module. If so, the module - will be called pa12203001. + This driver can also be built as a module. If so, the module + will be called pa12203001. config SI1133 tristate "SI1133 UV Index Sensor and Ambient Light Sensor" @@ -359,12 +359,12 @@ config STK3310 depends on I2C select REGMAP_I2C help - Say yes here to get support for the Sensortek STK3310 ambient light - and proximity sensor. The STK3311 model is also supported by this - driver. + Say yes here to get support for the Sensortek STK3310 ambient light + and proximity sensor. The STK3311 model is also supported by this + driver. - Choosing M will build the driver as a module. If so, the module - will be called stk3310. + Choosing M will build the driver as a module. If so, the module + will be called stk3310. config ST_UVIS25 tristate "STMicroelectronics UVIS25 sensor driver" @@ -396,11 +396,11 @@ config TCS3414 select IIO_BUFFER select IIO_TRIGGERED_BUFFER help - If you say yes here you get support for the TAOS TCS3414 - family of digital color sensors. + If you say yes here you get support for the TAOS TCS3414 + family of digital color sensors. - This driver can also be built as a module. If so, the module - will be called tcs3414. + This driver can also be built as a module. If so, the module + will be called tcs3414. config TCS3472 tristate "TAOS TCS3472 color light-to-digital converter" @@ -408,67 +408,67 @@ config TCS3472 select IIO_BUFFER select IIO_TRIGGERED_BUFFER help - If you say yes here you get support for the TAOS TCS3472 - family of color light-to-digital converters with IR filter. + If you say yes here you get support for the TAOS TCS3472 + family of color light-to-digital converters with IR filter. - This driver can also be built as a module. If so, the module - will be called tcs3472. + This driver can also be built as a module. If so, the module + will be called tcs3472. config SENSORS_TSL2563 tristate "TAOS TSL2560, TSL2561, TSL2562 and TSL2563 ambient light sensors" depends on I2C help - If you say yes here you get support for the Taos TSL2560, - TSL2561, TSL2562 and TSL2563 ambient light sensors. + If you say yes here you get support for the Taos TSL2560, + TSL2561, TSL2562 and TSL2563 ambient light sensors. - This driver can also be built as a module. If so, the module - will be called tsl2563. + This driver can also be built as a module. If so, the module + will be called tsl2563. config TSL2583 tristate "TAOS TSL2580, TSL2581 and TSL2583 light-to-digital converters" depends on I2C help - Provides support for the TAOS tsl2580, tsl2581 and tsl2583 devices. - Access ALS data via iio, sysfs. + Provides support for the TAOS tsl2580, tsl2581 and tsl2583 devices. + Access ALS data via iio, sysfs. config TSL2772 tristate "TAOS TSL/TMD2x71 and TSL/TMD2x72 Family of light and proximity sensors" depends on I2C help - Support for: tsl2571, tsl2671, tmd2671, tsl2771, tmd2771, tsl2572, tsl2672, - tmd2672, tsl2772, tmd2772 devices. - Provides iio_events and direct access via sysfs. + Support for: tsl2571, tsl2671, tmd2671, tsl2771, tmd2771, tsl2572, tsl2672, + tmd2672, tsl2772, tmd2772 devices. + Provides iio_events and direct access via sysfs. config TSL4531 tristate "TAOS TSL4531 ambient light sensors" depends on I2C help - Say Y here if you want to build a driver for the TAOS TSL4531 family - of ambient light sensors with direct lux output. + Say Y here if you want to build a driver for the TAOS TSL4531 family + of ambient light sensors with direct lux output. - To compile this driver as a module, choose M here: the - module will be called tsl4531. + To compile this driver as a module, choose M here: the + module will be called tsl4531. config US5182D tristate "UPISEMI light and proximity sensor" depends on I2C help - If you say yes here you get support for the UPISEMI US5182D - ambient light and proximity sensor. + If you say yes here you get support for the UPISEMI US5182D + ambient light and proximity sensor. - This driver can also be built as a module. If so, the module - will be called us5182d. + This driver can also be built as a module. If so, the module + will be called us5182d. config VCNL4000 tristate "VCNL4000/4010/4020/4200 combined ALS and proximity sensor" depends on I2C help - Say Y here if you want to build a driver for the Vishay VCNL4000, - VCNL4010, VCNL4020, VCNL4200 combined ambient light and proximity - sensor. + Say Y here if you want to build a driver for the Vishay VCNL4000, + VCNL4010, VCNL4020, VCNL4200 combined ambient light and proximity + sensor. - To compile this driver as a module, choose M here: the - module will be called vcnl4000. + To compile this driver as a module, choose M here: the + module will be called vcnl4000. config VCNL4035 tristate "VCNL4035 combined ALS and proximity sensor" @@ -476,41 +476,41 @@ config VCNL4035 select REGMAP_I2C depends on I2C help - Say Y here if you want to build a driver for the Vishay VCNL4035, - combined ambient light (ALS) and proximity sensor. Currently only ALS - function is available. + Say Y here if you want to build a driver for the Vishay VCNL4035, + combined ambient light (ALS) and proximity sensor. Currently only ALS + function is available. - To compile this driver as a module, choose M here: the - module will be called vcnl4035. + To compile this driver as a module, choose M here: the + module will be called vcnl4035. config VEML6070 tristate "VEML6070 UV A light sensor" depends on I2C help - Say Y here if you want to build a driver for the Vishay VEML6070 UV A - light sensor. + Say Y here if you want to build a driver for the Vishay VEML6070 UV A + light sensor. - To compile this driver as a module, choose M here: the - module will be called veml6070. + To compile this driver as a module, choose M here: the + module will be called veml6070. config VL6180 tristate "VL6180 ALS, range and proximity sensor" depends on I2C help - Say Y here if you want to build a driver for the STMicroelectronics - VL6180 combined ambient light, range and proximity sensor. + Say Y here if you want to build a driver for the STMicroelectronics + VL6180 combined ambient light, range and proximity sensor. - To compile this driver as a module, choose M here: the - module will be called vl6180. + To compile this driver as a module, choose M here: the + module will be called vl6180. config ZOPT2201 tristate "ZOPT2201 ALS and UV B sensor" depends on I2C help - Say Y here if you want to build a driver for the IDT - ZOPT2201 ambient light and UV B sensor. + Say Y here if you want to build a driver for the IDT + ZOPT2201 ambient light and UV B sensor. - To compile this driver as a module, choose M here: the - module will be called zopt2201. + To compile this driver as a module, choose M here: the + module will be called zopt2201. endmenu diff --git a/drivers/iio/light/cros_ec_light_prox.c b/drivers/iio/light/cros_ec_light_prox.c index fd1609e975ab..308ee6ff2e22 100644 --- a/drivers/iio/light/cros_ec_light_prox.c +++ b/drivers/iio/light/cros_ec_light_prox.c @@ -1,19 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * cros_ec_light_prox - Driver for light and prox sensors behing CrosEC. * * Copyright (C) 2017 Google, Inc - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ -#include <linux/delay.h> #include <linux/device.h> #include <linux/iio/buffer.h> #include <linux/iio/common/cros_ec_sensors_core.h> @@ -28,7 +19,6 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> -#include <linux/sysfs.h> /* * We only represent one entry for light or proximity. EC is merging different diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index 04fd0d4b6f19..b19e6559b980 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -1,8 +1,9 @@ /* - * vcnl4000.c - Support for Vishay VCNL4000/4010/4020/4200 combined ambient + * vcnl4000.c - Support for Vishay VCNL4000/4010/4020/4040/4200 combined ambient * light and proximity sensor * * Copyright 2012 Peter Meerwald <pmeerw@pmeerw.net> + * Copyright 2019 Pursim SPC * * This file is subject to the terms and conditions of version 2 of * the GNU General Public License. See the file COPYING in the main @@ -10,13 +11,14 @@ * * IIO driver for: * VCNL4000/10/20 (7-bit I2C slave address 0x13) + * VCNL4040 (7-bit I2C slave address 0x60) * VCNL4200 (7-bit I2C slave address 0x51) * * TODO: * allow to adjust IR current * proximity threshold and event handling * periodic ALS/proximity measurement (VCNL4010/20) - * interrupts (VCNL4010/20, VCNL4200) + * interrupts (VCNL4010/20/40, VCNL4200) */ #include <linux/module.h> @@ -30,6 +32,7 @@ #define VCNL4000_DRV_NAME "vcnl4000" #define VCNL4000_PROD_ID 0x01 #define VCNL4010_PROD_ID 0x02 /* for VCNL4020, VCNL4010 */ +#define VCNL4040_PROD_ID 0x86 #define VCNL4200_PROD_ID 0x58 #define VCNL4000_COMMAND 0x80 /* Command register */ @@ -49,6 +52,8 @@ #define VCNL4200_AL_DATA 0x09 /* Ambient light data */ #define VCNL4200_DEV_ID 0x0e /* Device ID, slave address and version */ +#define VCNL4040_DEV_ID 0x0c /* Device ID and version */ + /* Bit masks for COMMAND register */ #define VCNL4000_AL_RDY BIT(6) /* ALS data ready? */ #define VCNL4000_PS_RDY BIT(5) /* proximity data ready? */ @@ -58,6 +63,7 @@ enum vcnl4000_device_ids { VCNL4000, VCNL4010, + VCNL4040, VCNL4200, }; @@ -90,6 +96,7 @@ static const struct i2c_device_id vcnl4000_id[] = { { "vcnl4000", VCNL4000 }, { "vcnl4010", VCNL4010 }, { "vcnl4020", VCNL4010 }, + { "vcnl4040", VCNL4040 }, { "vcnl4200", VCNL4200 }, { } }; @@ -128,31 +135,53 @@ static int vcnl4000_init(struct vcnl4000_data *data) static int vcnl4200_init(struct vcnl4000_data *data) { - int ret; + int ret, id; ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID); if (ret < 0) return ret; - if ((ret & 0xff) != VCNL4200_PROD_ID) - return -ENODEV; + id = ret & 0xff; + + if (id != VCNL4200_PROD_ID) { + ret = i2c_smbus_read_word_data(data->client, VCNL4040_DEV_ID); + if (ret < 0) + return ret; + + id = ret & 0xff; + + if (id != VCNL4040_PROD_ID) + return -ENODEV; + } + + dev_dbg(&data->client->dev, "device id 0x%x", id); data->rev = (ret >> 8) & 0xf; /* Set defaults and enable both channels */ - ret = i2c_smbus_write_byte_data(data->client, VCNL4200_AL_CONF, 0x00); + ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, 0); if (ret < 0) return ret; - ret = i2c_smbus_write_byte_data(data->client, VCNL4200_PS_CONF1, 0x00); + ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, 0); if (ret < 0) return ret; data->al_scale = 24000; data->vcnl4200_al.reg = VCNL4200_AL_DATA; data->vcnl4200_ps.reg = VCNL4200_PS_DATA; - /* Integration time is 50ms, but the experiments show 54ms in total. */ - data->vcnl4200_al.sampling_rate = ktime_set(0, 54000 * 1000); - data->vcnl4200_ps.sampling_rate = ktime_set(0, 4200 * 1000); + switch (id) { + case VCNL4200_PROD_ID: + /* Integration time is 50ms, but the experiments */ + /* show 54ms in total. */ + data->vcnl4200_al.sampling_rate = ktime_set(0, 54000 * 1000); + data->vcnl4200_ps.sampling_rate = ktime_set(0, 4200 * 1000); + break; + case VCNL4040_PROD_ID: + /* Integration time is 80ms, add 10ms. */ + data->vcnl4200_al.sampling_rate = ktime_set(0, 100000 * 1000); + data->vcnl4200_ps.sampling_rate = ktime_set(0, 100000 * 1000); + break; + } data->vcnl4200_al.last_measurement = ktime_set(0, 0); data->vcnl4200_ps.last_measurement = ktime_set(0, 0); mutex_init(&data->vcnl4200_al.lock); @@ -271,6 +300,12 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = { .measure_light = vcnl4000_measure_light, .measure_proximity = vcnl4000_measure_proximity, }, + [VCNL4040] = { + .prod = "VCNL4040", + .init = vcnl4200_init, + .measure_light = vcnl4200_measure_light, + .measure_proximity = vcnl4200_measure_proximity, + }, [VCNL4200] = { .prod = "VCNL4200", .init = vcnl4200_init, @@ -363,9 +398,31 @@ static int vcnl4000_probe(struct i2c_client *client, return devm_iio_device_register(&client->dev, indio_dev); } +static const struct of_device_id vcnl_4000_of_match[] = { + { + .compatible = "vishay,vcnl4000", + .data = "VCNL4000", + }, + { + .compatible = "vishay,vcnl4010", + .data = "VCNL4010", + }, + { + .compatible = "vishay,vcnl4010", + .data = "VCNL4020", + }, + { + .compatible = "vishay,vcnl4200", + .data = "VCNL4200", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, vcnl_4000_of_match); + static struct i2c_driver vcnl4000_driver = { .driver = { .name = VCNL4000_DRV_NAME, + .of_match_table = vcnl_4000_of_match, }, .probe = vcnl4000_probe, .id_table = vcnl4000_id, diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c index 93be1f4c0f27..f4d0a6c0fde7 100644 --- a/drivers/iio/magnetometer/ak8974.c +++ b/drivers/iio/magnetometer/ak8974.c @@ -733,9 +733,8 @@ static int ak8974_probe(struct i2c_client *i2c, ak8974->i2c = i2c; mutex_init(&ak8974->lock); - ret = of_iio_read_mount_matrix(&i2c->dev, - "mount-matrix", - &ak8974->orientation); + ret = iio_read_mount_matrix(&i2c->dev, "mount-matrix", + &ak8974->orientation); if (ret) return ret; diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index d430b80808ef..43d08c089792 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -746,12 +746,14 @@ static const struct iio_mount_matrix * ak8975_get_mount_matrix(const struct iio_dev *indio_dev, const struct iio_chan_spec *chan) { - return &((struct ak8975_data *)iio_priv(indio_dev))->orientation; + struct ak8975_data *data = iio_priv(indio_dev); + + return &data->orientation; } static const struct iio_chan_spec_ext_info ak8975_ext_info[] = { IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, ak8975_get_mount_matrix), - { }, + { } }; #define AK8975_CHANNEL(axis, index) \ @@ -792,7 +794,7 @@ static const struct acpi_device_id ak_acpi_match[] = { {"AK09911", AK09911}, {"AKM9911", AK09911}, {"AK09912", AK09912}, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, ak_acpi_match); #endif @@ -911,9 +913,8 @@ static int ak8975_probe(struct i2c_client *client, data->eoc_irq = 0; if (!pdata) { - err = of_iio_read_mount_matrix(&client->dev, - "mount-matrix", - &data->orientation); + err = iio_read_mount_matrix(&client->dev, "mount-matrix", + &data->orientation); if (err) return err; } else diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index d91cb845e3d6..b0d8b036d9bb 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -143,6 +143,7 @@ struct bmc150_magn_data { */ struct mutex mutex; struct regmap *regmap; + struct iio_mount_matrix orientation; /* 4 x 32 bits for x, y z, 4 bytes align, 64 bits timestamp */ s32 buffer[6]; struct iio_trigger *dready_trig; @@ -612,6 +613,20 @@ static ssize_t bmc150_magn_show_samp_freq_avail(struct device *dev, return len; } +static const struct iio_mount_matrix * +bmc150_magn_get_mount_matrix(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct bmc150_magn_data *data = iio_priv(indio_dev); + + return &data->orientation; +} + +static const struct iio_chan_spec_ext_info bmc150_magn_ext_info[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bmc150_magn_get_mount_matrix), + { } +}; + static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(bmc150_magn_show_samp_freq_avail); static struct attribute *bmc150_magn_attributes[] = { @@ -638,6 +653,7 @@ static const struct attribute_group bmc150_magn_attrs_group = { .storagebits = 32, \ .endianness = IIO_LE \ }, \ + .ext_info = bmc150_magn_ext_info, \ } static const struct iio_chan_spec bmc150_magn_channels[] = { @@ -861,6 +877,11 @@ int bmc150_magn_probe(struct device *dev, struct regmap *regmap, data->irq = irq; data->dev = dev; + ret = iio_read_mount_matrix(dev, "mount-matrix", + &data->orientation); + if (ret) + return ret; + if (!name && ACPI_HANDLE(dev)) name = bmc150_magn_match_acpi_device(dev); diff --git a/drivers/iio/magnetometer/hmc5843.h b/drivers/iio/magnetometer/hmc5843.h index a75224cf99df..e3e22d2508d3 100644 --- a/drivers/iio/magnetometer/hmc5843.h +++ b/drivers/iio/magnetometer/hmc5843.h @@ -43,6 +43,7 @@ struct hmc5843_data { struct mutex lock; struct regmap *regmap; const struct hmc5843_chip_info *variant; + struct iio_mount_matrix orientation; __be16 buffer[8]; }; diff --git a/drivers/iio/magnetometer/hmc5843_core.c b/drivers/iio/magnetometer/hmc5843_core.c index ada142fb7aa3..05629ec56d80 100644 --- a/drivers/iio/magnetometer/hmc5843_core.c +++ b/drivers/iio/magnetometer/hmc5843_core.c @@ -237,6 +237,15 @@ int hmc5843_set_measurement_configuration(struct iio_dev *indio_dev, return hmc5843_set_meas_conf(data, meas_conf); } +static const struct iio_mount_matrix * +hmc5843_get_mount_matrix(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct hmc5843_data *data = iio_priv(indio_dev); + + return &data->orientation; +} + static const struct iio_enum hmc5843_meas_conf_enum = { .items = hmc5843_meas_conf_modes, .num_items = ARRAY_SIZE(hmc5843_meas_conf_modes), @@ -247,7 +256,8 @@ static const struct iio_enum hmc5843_meas_conf_enum = { static const struct iio_chan_spec_ext_info hmc5843_ext_info[] = { IIO_ENUM("meas_conf", true, &hmc5843_meas_conf_enum), IIO_ENUM_AVAILABLE("meas_conf", &hmc5843_meas_conf_enum), - { }, + IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, hmc5843_get_mount_matrix), + { } }; static const struct iio_enum hmc5983_meas_conf_enum = { @@ -260,7 +270,8 @@ static const struct iio_enum hmc5983_meas_conf_enum = { static const struct iio_chan_spec_ext_info hmc5983_ext_info[] = { IIO_ENUM("meas_conf", true, &hmc5983_meas_conf_enum), IIO_ENUM_AVAILABLE("meas_conf", &hmc5983_meas_conf_enum), - { }, + IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, hmc5843_get_mount_matrix), + { } }; static @@ -635,6 +646,11 @@ int hmc5843_common_probe(struct device *dev, struct regmap *regmap, data->variant = &hmc5843_chip_info_tbl[id]; mutex_init(&data->lock); + ret = iio_read_mount_matrix(dev, "mount-matrix", + &data->orientation); + if (ret) + return ret; + indio_dev->dev.parent = dev; indio_dev->name = name; indio_dev->info = &hmc5843_info; diff --git a/drivers/iio/magnetometer/hmc5843_i2c.c b/drivers/iio/magnetometer/hmc5843_i2c.c index 3de7f4426ac4..86abba5827a2 100644 --- a/drivers/iio/magnetometer/hmc5843_i2c.c +++ b/drivers/iio/magnetometer/hmc5843_i2c.c @@ -58,8 +58,13 @@ static const struct regmap_config hmc5843_i2c_regmap_config = { static int hmc5843_i2c_probe(struct i2c_client *cli, const struct i2c_device_id *id) { + struct regmap *regmap = devm_regmap_init_i2c(cli, + &hmc5843_i2c_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + return hmc5843_common_probe(&cli->dev, - devm_regmap_init_i2c(cli, &hmc5843_i2c_regmap_config), + regmap, id->driver_data, id->name); } diff --git a/drivers/iio/magnetometer/hmc5843_spi.c b/drivers/iio/magnetometer/hmc5843_spi.c index 535f03a70d63..79b2b707f90e 100644 --- a/drivers/iio/magnetometer/hmc5843_spi.c +++ b/drivers/iio/magnetometer/hmc5843_spi.c @@ -58,6 +58,7 @@ static const struct regmap_config hmc5843_spi_regmap_config = { 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; @@ -67,8 +68,12 @@ static int hmc5843_spi_probe(struct spi_device *spi) if (ret) return ret; + regmap = devm_regmap_init_spi(spi, &hmc5843_spi_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + return hmc5843_common_probe(&spi->dev, - devm_regmap_init_spi(spi, &hmc5843_spi_regmap_config), + regmap, id->driver_data, id->name); } diff --git a/drivers/iio/potentiometer/Kconfig b/drivers/iio/potentiometer/Kconfig index 6303cbe79903..a81a3a1b4dc8 100644 --- a/drivers/iio/potentiometer/Kconfig +++ b/drivers/iio/potentiometer/Kconfig @@ -26,26 +26,26 @@ config DS1803 module will be called ds1803. config MAX5481 - tristate "Maxim MAX5481-MAX5484 Digital Potentiometer driver" - depends on SPI - help - Say yes here to build support for the Maxim - MAX5481, MAX5482, MAX5483, MAX5484 digital potentiometer - chips. + tristate "Maxim MAX5481-MAX5484 Digital Potentiometer driver" + depends on SPI + help + Say yes here to build support for the Maxim + MAX5481, MAX5482, MAX5483, MAX5484 digital potentiometer + chips. - To compile this driver as a module, choose M here: the - module will be called max5481. + To compile this driver as a module, choose M here: the + module will be called max5481. config MAX5487 - tristate "Maxim MAX5487/MAX5488/MAX5489 Digital Potentiometer driver" - depends on SPI - help - Say yes here to build support for the Maxim - MAX5487, MAX5488, MAX5489 digital potentiometer - chips. - - To compile this driver as a module, choose M here: the - module will be called max5487. + tristate "Maxim MAX5487/MAX5488/MAX5489 Digital Potentiometer driver" + depends on SPI + help + Say yes here to build support for the Maxim + MAX5487, MAX5488, MAX5489 digital potentiometer + chips. + + To compile this driver as a module, choose M here: the + module will be called max5487. config MCP4018 tristate "Microchip MCP4017/18/19 Digital Potentiometer driver" diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c index 90e895adf997..a0e5f530faa9 100644 --- a/drivers/iio/potentiostat/lmp91000.c +++ b/drivers/iio/potentiostat/lmp91000.c @@ -113,7 +113,7 @@ static int lmp91000_read(struct lmp91000_data *data, int channel, int *val) return -EINVAL; /* delay till first temperature reading is complete */ - if ((state != channel) && (channel == LMP91000_REG_MODECN_TEMP)) + if (state != channel && channel == LMP91000_REG_MODECN_TEMP) usleep_range(3000, 4000); data->chan_select = channel != LMP91000_REG_MODECN_3LEAD; @@ -211,12 +211,11 @@ static int lmp91000_read_config(struct lmp91000_data *data) ret = of_property_read_u32(np, "ti,tia-gain-ohm", &val); if (ret) { - if (of_property_read_bool(np, "ti,external-tia-resistor")) - val = 0; - else { - dev_err(dev, "no ti,tia-gain-ohm defined"); + if (!of_property_read_bool(np, "ti,external-tia-resistor")) { + dev_err(dev, "no ti,tia-gain-ohm defined and external resistor not specified\n"); return ret; } + val = 0; } ret = -EINVAL; @@ -255,8 +254,8 @@ static int lmp91000_read_config(struct lmp91000_data *data) regmap_write(data->regmap, LMP91000_REG_LOCK, 0); regmap_write(data->regmap, LMP91000_REG_TIACN, reg); - regmap_write(data->regmap, LMP91000_REG_REFCN, LMP91000_REG_REFCN_EXT_REF - | LMP91000_REG_REFCN_50_ZERO); + regmap_write(data->regmap, LMP91000_REG_REFCN, + LMP91000_REG_REFCN_EXT_REF | LMP91000_REG_REFCN_50_ZERO); regmap_write(data->regmap, LMP91000_REG_LOCK, 1); return 0; @@ -276,7 +275,6 @@ static int lmp91000_buffer_cb(const void *val, void *private) static const struct iio_trigger_ops lmp91000_trigger_ops = { }; - static int lmp91000_buffer_preenable(struct iio_dev *indio_dev) { struct lmp91000_data *data = iio_priv(indio_dev); diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index fe87d27779d9..3329d740c86c 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -164,6 +164,9 @@ static int bmp280_read_calib(struct bmp280_data *data, return ret; } + /* Toss the temperature calibration data into the entropy pool */ + add_device_randomness(t_buf, sizeof(t_buf)); + calib->T1 = le16_to_cpu(t_buf[T1]); calib->T2 = le16_to_cpu(t_buf[T2]); calib->T3 = le16_to_cpu(t_buf[T3]); @@ -177,6 +180,9 @@ static int bmp280_read_calib(struct bmp280_data *data, return ret; } + /* Toss the pressure calibration data into the entropy pool */ + add_device_randomness(p_buf, sizeof(p_buf)); + calib->P1 = le16_to_cpu(p_buf[P1]); calib->P2 = le16_to_cpu(p_buf[P2]); calib->P3 = le16_to_cpu(p_buf[P3]); diff --git a/drivers/iio/pressure/cros_ec_baro.c b/drivers/iio/pressure/cros_ec_baro.c index 87c07af9181f..034ce98d6e97 100644 --- a/drivers/iio/pressure/cros_ec_baro.c +++ b/drivers/iio/pressure/cros_ec_baro.c @@ -1,19 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * cros_ec_baro - Driver for barometer sensor behind CrosEC. * * Copyright (C) 2017 Google, Inc - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ -#include <linux/delay.h> #include <linux/device.h> #include <linux/iio/buffer.h> #include <linux/iio/common/cros_ec_sensors_core.h> diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig index b99367a89f81..12a3d3d40a91 100644 --- a/drivers/iio/proximity/Kconfig +++ b/drivers/iio/proximity/Kconfig @@ -45,6 +45,18 @@ config LIDAR_LITE_V2 To compile this driver as a module, choose M here: the module will be called pulsedlight-lite-v2 +config MB1232 + tristate "MaxSonar I2CXL family ultrasonic sensors" + depends on I2C + help + Say Y to build a driver for the ultrasonic sensors I2CXL of + MaxBotix which have an i2c interface. It can be used to measure + the distance of objects. Supported types are mb1202, mb1212, + mb1222, mb1232, mb1242, mb7040, mb7137 + + To compile this driver as a module, choose M here: the + module will be called mb1232. + config RFD77402 tristate "RFD77402 ToF sensor" depends on I2C diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile index 6d031f903c4c..0bb5f9de13d6 100644 --- a/drivers/iio/proximity/Makefile +++ b/drivers/iio/proximity/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_AS3935) += as3935.o obj-$(CONFIG_ISL29501) += isl29501.o obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o +obj-$(CONFIG_MB1232) += mb1232.o obj-$(CONFIG_RFD77402) += rfd77402.o obj-$(CONFIG_SRF04) += srf04.o obj-$(CONFIG_SRF08) += srf08.o diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index f130388a16a0..b591c63bd6c4 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -345,6 +345,14 @@ static SIMPLE_DEV_PM_OPS(as3935_pm_ops, as3935_suspend, as3935_resume); #define AS3935_PM_OPS NULL #endif +static void as3935_stop_work(void *data) +{ + struct iio_dev *indio_dev = data; + struct as3935_state *st = iio_priv(indio_dev); + + cancel_delayed_work_sync(&st->work); +} + static int as3935_probe(struct spi_device *spi) { struct iio_dev *indio_dev; @@ -368,7 +376,6 @@ static int as3935_probe(struct spi_device *spi) spi_set_drvdata(spi, indio_dev); mutex_init(&st->lock); - INIT_DELAYED_WORK(&st->work, as3935_event_work); ret = of_property_read_u32(np, "ams,tuning-capacitor-pf", &st->tune_cap); @@ -414,22 +421,28 @@ static int as3935_probe(struct spi_device *spi) iio_trigger_set_drvdata(trig, indio_dev); trig->ops = &iio_interrupt_trigger_ops; - ret = iio_trigger_register(trig); + ret = devm_iio_trigger_register(&spi->dev, trig); if (ret) { dev_err(&spi->dev, "failed to register trigger\n"); return ret; } - ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time, - &as3935_trigger_handler, NULL); + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, + iio_pollfunc_store_time, + as3935_trigger_handler, NULL); if (ret) { dev_err(&spi->dev, "cannot setup iio trigger\n"); - goto unregister_trigger; + return ret; } calibrate_as3935(st); + INIT_DELAYED_WORK(&st->work, as3935_event_work); + ret = devm_add_action(&spi->dev, as3935_stop_work, indio_dev); + if (ret) + return ret; + ret = devm_request_irq(&spi->dev, spi->irq, &as3935_interrupt_handler, IRQF_TRIGGER_RISING, @@ -438,35 +451,15 @@ static int as3935_probe(struct spi_device *spi) if (ret) { dev_err(&spi->dev, "unable to request irq\n"); - goto unregister_buffer; + return ret; } - ret = iio_device_register(indio_dev); + ret = devm_iio_device_register(&spi->dev, indio_dev); if (ret < 0) { dev_err(&spi->dev, "unable to register device\n"); - goto unregister_buffer; + return ret; } return 0; - -unregister_buffer: - iio_triggered_buffer_cleanup(indio_dev); - -unregister_trigger: - iio_trigger_unregister(st->trig); - - return ret; -} - -static int as3935_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct as3935_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - iio_trigger_unregister(st->trig); - - return 0; } static const struct of_device_id as3935_of_match[] = { @@ -488,7 +481,6 @@ static struct spi_driver as3935_driver = { .pm = AS3935_PM_OPS, }, .probe = as3935_probe, - .remove = as3935_remove, .id_table = as3935_id, }; module_spi_driver(as3935_driver); diff --git a/drivers/iio/proximity/mb1232.c b/drivers/iio/proximity/mb1232.c new file mode 100644 index 000000000000..166b3e6d7db8 --- /dev/null +++ b/drivers/iio/proximity/mb1232.c @@ -0,0 +1,272 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * mb1232.c - Support for MaxBotix I2CXL-MaxSonar-EZ series ultrasonic + * ranger with i2c interface + * actually tested with mb1232 type + * + * Copyright (c) 2019 Andreas Klinger <ak@it-klinger.de> + * + * For details about the device see: + * https://www.maxbotix.com/documents/I2CXL-MaxSonar-EZ_Datasheet.pdf + */ + +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/of_irq.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/bitops.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +/* registers of MaxSonar device */ +#define MB1232_RANGE_COMMAND 0x51 /* Command for reading range */ +#define MB1232_ADDR_UNLOCK_1 0xAA /* Command 1 for changing address */ +#define MB1232_ADDR_UNLOCK_2 0xA5 /* Command 2 for changing address */ + +struct mb1232_data { + struct i2c_client *client; + + struct mutex lock; + + /* + * optionally a gpio can be used to announce when ranging has + * finished + * since we are just using the falling trigger of it we request + * only the interrupt for announcing when data is ready to be read + */ + struct completion ranging; + int irqnr; +}; + +static irqreturn_t mb1232_handle_irq(int irq, void *dev_id) +{ + struct iio_dev *indio_dev = dev_id; + struct mb1232_data *data = iio_priv(indio_dev); + + complete(&data->ranging); + + return IRQ_HANDLED; +} + +static s16 mb1232_read_distance(struct mb1232_data *data) +{ + struct i2c_client *client = data->client; + int ret; + s16 distance; + __be16 buf; + + mutex_lock(&data->lock); + + reinit_completion(&data->ranging); + + ret = i2c_smbus_write_byte(client, MB1232_RANGE_COMMAND); + if (ret < 0) { + dev_err(&client->dev, "write command - err: %d\n", ret); + goto error_unlock; + } + + if (data->irqnr >= 0) { + /* it cannot take more than 100 ms */ + ret = wait_for_completion_killable_timeout(&data->ranging, + HZ/10); + if (ret < 0) + goto error_unlock; + else if (ret == 0) { + ret = -ETIMEDOUT; + goto error_unlock; + } + } else { + /* use simple sleep if announce irq is not connected */ + msleep(15); + } + + ret = i2c_master_recv(client, (char *)&buf, sizeof(buf)); + if (ret < 0) { + dev_err(&client->dev, "i2c_master_recv: ret=%d\n", ret); + goto error_unlock; + } + + distance = __be16_to_cpu(buf); + /* check for not returning misleading error codes */ + if (distance < 0) { + dev_err(&client->dev, "distance=%d\n", distance); + ret = -EINVAL; + goto error_unlock; + } + + mutex_unlock(&data->lock); + + return distance; + +error_unlock: + mutex_unlock(&data->lock); + + return ret; +} + +static irqreturn_t mb1232_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct mb1232_data *data = iio_priv(indio_dev); + /* + * triggered buffer + * 16-bit channel + 48-bit padding + 64-bit timestamp + */ + s16 buffer[8] = { 0 }; + + buffer[0] = mb1232_read_distance(data); + if (buffer[0] < 0) + goto err; + + iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp); + +err: + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} + +static int mb1232_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, int *val, + int *val2, long mask) +{ + struct mb1232_data *data = iio_priv(indio_dev); + int ret; + + if (channel->type != IIO_DISTANCE) + return -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = mb1232_read_distance(data); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + /* 1 LSB is 1 cm */ + *val = 0; + *val2 = 10000; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static const struct iio_chan_spec mb1232_channels[] = { + { + .type = IIO_DISTANCE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .scan_index = 0, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_CPU, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static const struct iio_info mb1232_info = { + .read_raw = mb1232_read_raw, +}; + +static int mb1232_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct iio_dev *indio_dev; + struct mb1232_data *data; + int ret; + struct device *dev = &client->dev; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_BYTE | + I2C_FUNC_SMBUS_WRITE_BYTE)) + return -ENODEV; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + + indio_dev->info = &mb1232_info; + indio_dev->name = id->name; + indio_dev->dev.parent = dev; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = mb1232_channels; + indio_dev->num_channels = ARRAY_SIZE(mb1232_channels); + + mutex_init(&data->lock); + + init_completion(&data->ranging); + + data->irqnr = irq_of_parse_and_map(dev->of_node, 0); + if (data->irqnr <= 0) { + /* usage of interrupt is optional */ + data->irqnr = -1; + } else { + ret = devm_request_irq(dev, data->irqnr, mb1232_handle_irq, + IRQF_TRIGGER_FALLING, id->name, indio_dev); + if (ret < 0) { + dev_err(dev, "request_irq: %d\n", ret); + return ret; + } + } + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, mb1232_trigger_handler, NULL); + if (ret < 0) { + dev_err(dev, "setup of iio triggered buffer failed\n"); + return ret; + } + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id of_mb1232_match[] = { + { .compatible = "maxbotix,mb1202", }, + { .compatible = "maxbotix,mb1212", }, + { .compatible = "maxbotix,mb1222", }, + { .compatible = "maxbotix,mb1232", }, + { .compatible = "maxbotix,mb1242", }, + { .compatible = "maxbotix,mb7040", }, + { .compatible = "maxbotix,mb7137", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, of_mb1232_match); + +static const struct i2c_device_id mb1232_id[] = { + { "maxbotix-mb1202", }, + { "maxbotix-mb1212", }, + { "maxbotix-mb1222", }, + { "maxbotix-mb1232", }, + { "maxbotix-mb1242", }, + { "maxbotix-mb7040", }, + { "maxbotix-mb7137", }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mb1232_id); + +static struct i2c_driver mb1232_driver = { + .driver = { + .name = "maxbotix-mb1232", + .of_match_table = of_mb1232_match, + }, + .probe = mb1232_probe, + .id_table = mb1232_id, +}; +module_i2c_driver(mb1232_driver); + +MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>"); +MODULE_DESCRIPTION("Maxbotix I2CXL-MaxSonar i2c ultrasonic ranger driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig index 82e4a62745e2..c185cbee25c7 100644 --- a/drivers/iio/temperature/Kconfig +++ b/drivers/iio/temperature/Kconfig @@ -66,14 +66,14 @@ config TMP006 be called tmp006. config TMP007 - tristate "TMP007 infrared thermopile sensor with Integrated Math Engine" - depends on I2C - help - If you say yes here you get support for the Texas Instruments - TMP007 infrared thermopile sensor with Integrated Math Engine. + tristate "TMP007 infrared thermopile sensor with Integrated Math Engine" + depends on I2C + help + If you say yes here you get support for the Texas Instruments + TMP007 infrared thermopile sensor with Integrated Math Engine. - This driver can also be built as a module. If so, the module will - be called tmp007. + This driver can also be built as a module. If so, the module will + be called tmp007. config TSYS01 tristate "Measurement Specialties TSYS01 temperature sensor using I2C bus connection" @@ -97,4 +97,14 @@ config TSYS02D This driver can also be built as a module. If so, the module will be called tsys02d. +config MAX31856 + tristate "MAX31856 thermocouple sensor" + depends on SPI + help + If you say yes here you get support for MAX31856 + thermocouple sensor chip connected via SPI. + + This driver can also be built as a module. If so, the module + will be called max31856. + endmenu diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile index 34a31db0bb63..baca4776ca0d 100644 --- a/drivers/iio/temperature/Makefile +++ b/drivers/iio/temperature/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_HID_SENSOR_TEMP) += hid-sensor-temperature.o obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o +obj-$(CONFIG_MAX31856) += max31856.o obj-$(CONFIG_MLX90614) += mlx90614.o obj-$(CONFIG_MLX90632) += mlx90632.o obj-$(CONFIG_TMP006) += tmp006.o diff --git a/drivers/iio/temperature/max31856.c b/drivers/iio/temperature/max31856.c new file mode 100644 index 000000000000..6b67d6b95cf9 --- /dev/null +++ b/drivers/iio/temperature/max31856.c @@ -0,0 +1,353 @@ +// SPDX-License-Identifier: GPL-2.0 +/* max31856.c + * + * Maxim MAX31856 thermocouple sensor driver + * + * Copyright (C) 2018-2019 Rockwell Collins + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/spi/spi.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <dt-bindings/iio/temperature/thermocouple.h> +/* + * The MSB of the register value determines whether the following byte will + * be written or read. If it is 0, one or more byte reads will follow. + */ +#define MAX31856_RD_WR_BIT BIT(7) + +#define MAX31856_CR0_AUTOCONVERT BIT(7) +#define MAX31856_CR0_1SHOT BIT(6) +#define MAX31856_CR0_OCFAULT BIT(4) +#define MAX31856_CR0_OCFAULT_MASK GENMASK(5, 4) +#define MAX31856_TC_TYPE_MASK GENMASK(3, 0) +#define MAX31856_FAULT_OVUV BIT(1) +#define MAX31856_FAULT_OPEN BIT(0) + +/* The MAX31856 registers */ +#define MAX31856_CR0_REG 0x00 +#define MAX31856_CR1_REG 0x01 +#define MAX31856_MASK_REG 0x02 +#define MAX31856_CJHF_REG 0x03 +#define MAX31856_CJLF_REG 0x04 +#define MAX31856_LTHFTH_REG 0x05 +#define MAX31856_LTHFTL_REG 0x06 +#define MAX31856_LTLFTH_REG 0x07 +#define MAX31856_LTLFTL_REG 0x08 +#define MAX31856_CJTO_REG 0x09 +#define MAX31856_CJTH_REG 0x0A +#define MAX31856_CJTL_REG 0x0B +#define MAX31856_LTCBH_REG 0x0C +#define MAX31856_LTCBM_REG 0x0D +#define MAX31856_LTCBL_REG 0x0E +#define MAX31856_SR_REG 0x0F + +static const struct iio_chan_spec max31856_channels[] = { + { /* Thermocouple Temperature */ + .type = IIO_TEMP, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + }, + { /* Cold Junction Temperature */ + .type = IIO_TEMP, + .channel2 = IIO_MOD_TEMP_AMBIENT, + .modified = 1, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + }, +}; + +struct max31856_data { + struct spi_device *spi; + u32 thermocouple_type; +}; + +static int max31856_read(struct max31856_data *data, u8 reg, + u8 val[], unsigned int read_size) +{ + return spi_write_then_read(data->spi, ®, 1, val, read_size); +} + +static int max31856_write(struct max31856_data *data, u8 reg, + unsigned int val) +{ + u8 buf[2]; + + buf[0] = reg | (MAX31856_RD_WR_BIT); + buf[1] = val; + + return spi_write(data->spi, buf, 2); +} + +static int max31856_init(struct max31856_data *data) +{ + int ret; + u8 reg_cr0_val, reg_cr1_val; + + /* Start by changing to Off mode before making changes as + * some settings are recommended to be set only when the device + * is off + */ + ret = max31856_read(data, MAX31856_CR0_REG, ®_cr0_val, 1); + if (ret) + return ret; + + reg_cr0_val &= ~MAX31856_CR0_AUTOCONVERT; + ret = max31856_write(data, MAX31856_CR0_REG, reg_cr0_val); + if (ret) + return ret; + + /* Set thermocouple type based on dts property */ + ret = max31856_read(data, MAX31856_CR1_REG, ®_cr1_val, 1); + if (ret) + return ret; + + reg_cr1_val &= ~MAX31856_TC_TYPE_MASK; + reg_cr1_val |= data->thermocouple_type; + ret = max31856_write(data, MAX31856_CR1_REG, reg_cr1_val); + if (ret) + return ret; + + /* + * Enable Open circuit fault detection + * Read datasheet for more information: Table 4. + * Value 01 means : Enabled (Once every 16 conversions) + */ + reg_cr0_val &= ~MAX31856_CR0_OCFAULT_MASK; + reg_cr0_val |= MAX31856_CR0_OCFAULT; + + /* Set Auto Conversion Mode */ + reg_cr0_val &= ~MAX31856_CR0_1SHOT; + reg_cr0_val |= MAX31856_CR0_AUTOCONVERT; + + return max31856_write(data, MAX31856_CR0_REG, reg_cr0_val); +} + +static int max31856_thermocouple_read(struct max31856_data *data, + struct iio_chan_spec const *chan, + int *val) +{ + int ret, offset_cjto; + u8 reg_val[3]; + + switch (chan->channel2) { + case IIO_NO_MOD: + /* + * Multibyte Read + * MAX31856_LTCBH_REG, MAX31856_LTCBM_REG, MAX31856_LTCBL_REG + */ + ret = max31856_read(data, MAX31856_LTCBH_REG, reg_val, 3); + if (ret) + return ret; + /* Skip last 5 dead bits of LTCBL */ + *val = (reg_val[0] << 16 | reg_val[1] << 8 | reg_val[2]) >> 5; + /* Check 7th bit of LTCBH reg. value for sign*/ + if (reg_val[0] & 0x80) + *val -= 0x80000; + break; + + case IIO_MOD_TEMP_AMBIENT: + /* + * Multibyte Read + * MAX31856_CJTO_REG, MAX31856_CJTH_REG, MAX31856_CJTL_REG + */ + ret = max31856_read(data, MAX31856_CJTO_REG, reg_val, 3); + if (ret) + return ret; + /* Get Cold Junction Temp. offset register value */ + offset_cjto = reg_val[0]; + /* Get CJTH and CJTL value and skip last 2 dead bits of CJTL */ + *val = (reg_val[1] << 8 | reg_val[2]) >> 2; + /* As per datasheet add offset into CJTH and CJTL */ + *val += offset_cjto; + /* Check 7th bit of CJTH reg. value for sign */ + if (reg_val[1] & 0x80) + *val -= 0x4000; + break; + + default: + return -EINVAL; + } + + ret = max31856_read(data, MAX31856_SR_REG, reg_val, 1); + if (ret) + return ret; + /* Check for over/under voltage or open circuit fault */ + if (reg_val[0] & (MAX31856_FAULT_OVUV | MAX31856_FAULT_OPEN)) + return -EIO; + + return ret; +} + +static int max31856_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct max31856_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = max31856_thermocouple_read(data, chan, val); + if (ret) + return ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + switch (chan->channel2) { + case IIO_MOD_TEMP_AMBIENT: + /* Cold junction Temp. Data resolution is 0.015625 */ + *val = 15; + *val2 = 625000; /* 1000 * 0.015625 */ + ret = IIO_VAL_INT_PLUS_MICRO; + break; + default: + /* Thermocouple Temp. Data resolution is 0.0078125 */ + *val = 7; + *val2 = 812500; /* 1000 * 0.0078125) */ + return IIO_VAL_INT_PLUS_MICRO; + } + break; + } + + return ret; +} + +static ssize_t show_fault(struct device *dev, u8 faultbit, char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct max31856_data *data = iio_priv(indio_dev); + u8 reg_val; + int ret; + bool fault; + + ret = max31856_read(data, MAX31856_SR_REG, ®_val, 1); + if (ret) + return ret; + + fault = reg_val & faultbit; + + return sprintf(buf, "%d\n", fault); +} + +static ssize_t show_fault_ovuv(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return show_fault(dev, MAX31856_FAULT_OVUV, buf); +} + +static ssize_t show_fault_oc(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return show_fault(dev, MAX31856_FAULT_OPEN, buf); +} + +static IIO_DEVICE_ATTR(fault_ovuv, 0444, show_fault_ovuv, NULL, 0); +static IIO_DEVICE_ATTR(fault_oc, 0444, show_fault_oc, NULL, 0); + +static struct attribute *max31856_attributes[] = { + &iio_dev_attr_fault_ovuv.dev_attr.attr, + &iio_dev_attr_fault_oc.dev_attr.attr, + NULL, +}; + +static const struct attribute_group max31856_group = { + .attrs = max31856_attributes, +}; + +static const struct iio_info max31856_info = { + .read_raw = max31856_read_raw, + .attrs = &max31856_group, +}; + +static int max31856_probe(struct spi_device *spi) +{ + const struct spi_device_id *id = spi_get_device_id(spi); + struct iio_dev *indio_dev; + struct max31856_data *data; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->spi = spi; + + spi_set_drvdata(spi, indio_dev); + + indio_dev->info = &max31856_info; + indio_dev->name = id->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = max31856_channels; + indio_dev->num_channels = ARRAY_SIZE(max31856_channels); + + ret = of_property_read_u32(spi->dev.of_node, "thermocouple-type", + &data->thermocouple_type); + + if (ret) { + dev_info(&spi->dev, + "Could not read thermocouple type DT property, configuring as a K-Type\n"); + data->thermocouple_type = THERMOCOUPLE_TYPE_K; + } + + /* + * no need to translate values as the supported types + * have the same value as the #defines + */ + switch (data->thermocouple_type) { + case THERMOCOUPLE_TYPE_B: + case THERMOCOUPLE_TYPE_E: + case THERMOCOUPLE_TYPE_J: + case THERMOCOUPLE_TYPE_K: + case THERMOCOUPLE_TYPE_N: + case THERMOCOUPLE_TYPE_R: + case THERMOCOUPLE_TYPE_S: + case THERMOCOUPLE_TYPE_T: + break; + default: + dev_err(&spi->dev, + "error: thermocouple-type %u not supported by max31856\n" + , data->thermocouple_type); + return -EINVAL; + } + + ret = max31856_init(data); + if (ret) { + dev_err(&spi->dev, "error: Failed to configure max31856\n"); + return ret; + } + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct spi_device_id max31856_id[] = { + { "max31856", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, max31856_id); + +static const struct of_device_id max31856_of_match[] = { + { .compatible = "maxim,max31856" }, + { } +}; +MODULE_DEVICE_TABLE(of, max31856_of_match); + +static struct spi_driver max31856_driver = { + .driver = { + .name = "max31856", + .of_match_table = max31856_of_match, + }, + .probe = max31856_probe, + .id_table = max31856_id, +}; +module_spi_driver(max31856_driver); + +MODULE_AUTHOR("Paresh Chaudhary <paresh.chaudhary@rockwellcollins.com>"); +MODULE_AUTHOR("Patrick Havelange <patrick.havelange@essensium.com>"); +MODULE_DESCRIPTION("Maxim MAX31856 thermocouple sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/trigger/iio-trig-loop.c b/drivers/iio/trigger/iio-trig-loop.c index 94a90e0a3fdb..9258d3cf149b 100644 --- a/drivers/iio/trigger/iio-trig-loop.c +++ b/drivers/iio/trigger/iio-trig-loop.c @@ -60,7 +60,7 @@ static int iio_loop_trigger_set_state(struct iio_trigger *trig, bool state) if (state) { loop_trig->task = kthread_run(iio_loop_thread, trig, trig->name); - if (unlikely(IS_ERR(loop_trig->task))) { + if (IS_ERR(loop_trig->task)) { dev_err(&trig->dev, "failed to create trigger loop thread\n"); return PTR_ERR(loop_trig->task); diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index 94ad59fefb0e..23d9a655a520 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -4,19 +4,6 @@ # menu "Analog to digital converters" -config AD7780 - tristate "Analog Devices AD7780 and similar ADCs driver" - depends on SPI - depends on GPIOLIB || COMPILE_TEST - select AD_SIGMA_DELTA - help - Say yes here to build support for Analog Devices AD7170, AD7171, - AD7780 and AD7781 SPI analog to digital converters (ADC). - If unsure, say N (but it's safe to say "Y"). - - To compile this driver as a module, choose M here: the - module will be called ad7780. - config AD7816 tristate "Analog Devices AD7816/7/8 temperature sensor and ADC driver" depends on SPI diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index 7a421088ff82..4b76769b32bc 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -3,7 +3,6 @@ # Makefile for industrial I/O ADC drivers # -obj-$(CONFIG_AD7780) += ad7780.o obj-$(CONFIG_AD7816) += ad7816.o obj-$(CONFIG_AD7192) += ad7192.o obj-$(CONFIG_AD7280) += ad7280a.o diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c index dfb79fbf63f4..2d86167aeeed 100644 --- a/drivers/staging/iio/adc/ad7192.c +++ b/drivers/staging/iio/adc/ad7192.c @@ -6,6 +6,7 @@ */ #include <linux/interrupt.h> +#include <linux/clk.h> #include <linux/device.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -155,14 +156,16 @@ struct ad7192_state { struct regulator *avdd; struct regulator *dvdd; + struct clk *mclk; u16 int_vref_mv; - u32 mclk; + u32 fclk; u32 f_order; u32 mode; u32 conf; u32 scale_avail[8][2]; u8 gpocon; u8 devid; + u8 clock_sel; struct mutex lock; /* protect sensor state */ struct ad_sigma_delta sd; @@ -215,8 +218,8 @@ static const struct ad_sd_calib_data ad7192_calib_arr[8] = { static int ad7192_calibrate_all(struct ad7192_state *st) { - return ad_sd_calibrate_all(&st->sd, ad7192_calib_arr, - ARRAY_SIZE(ad7192_calib_arr)); + return ad_sd_calibrate_all(&st->sd, ad7192_calib_arr, + ARRAY_SIZE(ad7192_calib_arr)); } static inline bool ad7192_valid_external_frequency(u32 freq) @@ -225,23 +228,45 @@ static inline bool ad7192_valid_external_frequency(u32 freq) freq <= AD7192_EXT_FREQ_MHZ_MAX); } -static int ad7192_setup(struct ad7192_state *st, - const struct ad7192_platform_data *pdata) +static int ad7192_of_clock_select(struct ad7192_state *st) +{ + struct device_node *np = st->sd.spi->dev.of_node; + unsigned int clock_sel; + + clock_sel = AD7192_CLK_INT; + + /* use internal clock */ + if (PTR_ERR(st->mclk) == -ENOENT) { + if (of_property_read_bool(np, "adi,int-clock-output-enable")) + clock_sel = AD7192_CLK_INT_CO; + } else { + if (of_property_read_bool(np, "adi,clock-xtal")) + clock_sel = AD7192_CLK_EXT_MCLK1_2; + else + clock_sel = AD7192_CLK_EXT_MCLK2; + } + + return clock_sel; +} + +static int ad7192_setup(struct ad7192_state *st, struct device_node *np) { struct iio_dev *indio_dev = spi_get_drvdata(st->sd.spi); + bool rej60_en, sinc3_en, refin2_en, chop_en; + bool buf_en, bipolar, burnout_curr_en; unsigned long long scale_uv; int i, ret, id; /* reset the serial interface */ ret = ad_sd_reset(&st->sd, 48); if (ret < 0) - goto out; + return ret; usleep_range(500, 1000); /* Wait for at least 500us */ /* write/read test for device presence */ ret = ad_sd_read_reg(&st->sd, AD7192_REG_ID, 1, &id); if (ret) - goto out; + return ret; id &= AD7192_ID_MASK; @@ -249,44 +274,28 @@ static int ad7192_setup(struct ad7192_state *st, dev_warn(&st->sd.spi->dev, "device ID query failed (0x%X)\n", id); - switch (pdata->clock_source_sel) { - case AD7192_CLK_INT: - case AD7192_CLK_INT_CO: - st->mclk = AD7192_INT_FREQ_MHZ; - break; - case AD7192_CLK_EXT_MCLK1_2: - case AD7192_CLK_EXT_MCLK2: - if (ad7192_valid_external_frequency(pdata->ext_clk_hz)) { - st->mclk = pdata->ext_clk_hz; - break; - } - dev_err(&st->sd.spi->dev, "Invalid frequency setting %u\n", - pdata->ext_clk_hz); - ret = -EINVAL; - goto out; - default: - ret = -EINVAL; - goto out; - } - st->mode = AD7192_MODE_SEL(AD7192_MODE_IDLE) | - AD7192_MODE_CLKSRC(pdata->clock_source_sel) | + AD7192_MODE_CLKSRC(st->clock_sel) | AD7192_MODE_RATE(480); st->conf = AD7192_CONF_GAIN(0); - if (pdata->rej60_en) + rej60_en = of_property_read_bool(np, "adi,rejection-60-Hz-enable"); + if (rej60_en) st->mode |= AD7192_MODE_REJ60; - if (pdata->sinc3_en) + sinc3_en = of_property_read_bool(np, "adi,sinc3-filter-enable"); + if (sinc3_en) st->mode |= AD7192_MODE_SINC3; - if (pdata->refin2_en && st->devid != ID_AD7195) + refin2_en = of_property_read_bool(np, "adi,refin2-pins-enable"); + if (refin2_en && st->devid != ID_AD7195) st->conf |= AD7192_CONF_REFSEL; - if (pdata->chop_en) { + chop_en = of_property_read_bool(np, "adi,chop-enable"); + if (chop_en) { st->conf |= AD7192_CONF_CHOP; - if (pdata->sinc3_en) + if (sinc3_en) st->f_order = 3; /* SINC 3rd order */ else st->f_order = 4; /* SINC 4th order */ @@ -294,30 +303,34 @@ static int ad7192_setup(struct ad7192_state *st, st->f_order = 1; } - if (pdata->buf_en) + buf_en = of_property_read_bool(np, "adi,buffer-enable"); + if (buf_en) st->conf |= AD7192_CONF_BUF; - if (pdata->unipolar_en) + bipolar = of_property_read_bool(np, "bipolar"); + if (!bipolar) st->conf |= AD7192_CONF_UNIPOLAR; - if (pdata->burnout_curr_en && pdata->buf_en && !pdata->chop_en) { + burnout_curr_en = of_property_read_bool(np, + "adi,burnout-currents-enable"); + if (burnout_curr_en && buf_en && !chop_en) { st->conf |= AD7192_CONF_BURN; - } else if (pdata->burnout_curr_en) { + } else if (burnout_curr_en) { dev_warn(&st->sd.spi->dev, "Can't enable burnout currents: see CHOP or buffer\n"); } ret = ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode); if (ret) - goto out; + return ret; ret = ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, st->conf); if (ret) - goto out; + return ret; ret = ad7192_calibrate_all(st); if (ret) - goto out; + return ret; /* Populate available ADC input ranges */ for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) { @@ -331,35 +344,8 @@ static int ad7192_setup(struct ad7192_state *st, } return 0; -out: - dev_err(&st->sd.spi->dev, "setup failed\n"); - return ret; } -static ssize_t -ad7192_show_scale_available(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7192_state *st = iio_priv(indio_dev); - int i, len = 0; - - for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) - len += sprintf(buf + len, "%d.%09u ", st->scale_avail[i][0], - st->scale_avail[i][1]); - - len += sprintf(buf + len, "\n"); - - return len; -} - -static IIO_DEVICE_ATTR_NAMED(in_v_m_v_scale_available, - in_voltage-voltage_scale_available, - 0444, ad7192_show_scale_available, NULL, 0); - -static IIO_DEVICE_ATTR(in_voltage_scale_available, 0444, - ad7192_show_scale_available, NULL, 0); - static ssize_t ad7192_show_ac_excitation(struct device *dev, struct device_attribute *attr, char *buf) @@ -434,8 +420,6 @@ static IIO_DEVICE_ATTR(ac_excitation_en, 0644, AD7192_REG_MODE); static struct attribute *ad7192_attributes[] = { - &iio_dev_attr_in_v_m_v_scale_available.dev_attr.attr, - &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, &iio_dev_attr_bridge_switch_en.dev_attr.attr, &iio_dev_attr_ac_excitation_en.dev_attr.attr, NULL @@ -446,8 +430,6 @@ static const struct attribute_group ad7192_attribute_group = { }; static struct attribute *ad7195_attributes[] = { - &iio_dev_attr_in_v_m_v_scale_available.dev_attr.attr, - &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, &iio_dev_attr_bridge_switch_en.dev_attr.attr, NULL }; @@ -498,7 +480,7 @@ static int ad7192_read_raw(struct iio_dev *indio_dev, *val -= 273 * ad7192_get_temp_scale(unipolar); return IIO_VAL_INT; case IIO_CHAN_INFO_SAMP_FREQ: - *val = st->mclk / + *val = st->fclk / (st->f_order * 1024 * AD7192_MODE_RATE(st->mode)); return IIO_VAL_INT; } @@ -545,7 +527,7 @@ static int ad7192_write_raw(struct iio_dev *indio_dev, break; } - div = st->mclk / (val * st->f_order * 1024); + div = st->fclk / (val * st->f_order * 1024); if (div < 1 || div > 1023) { ret = -EINVAL; break; @@ -578,10 +560,31 @@ static int ad7192_write_raw_get_fmt(struct iio_dev *indio_dev, } } +static int ad7192_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct ad7192_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + *vals = (int *)st->scale_avail; + *type = IIO_VAL_INT_PLUS_NANO; + /* Values are stored in a 2D matrix */ + *length = ARRAY_SIZE(st->scale_avail) * 2; + + return IIO_AVAIL_LIST; + } + + return -EINVAL; +} + static const struct iio_info ad7192_info = { .read_raw = ad7192_read_raw, .write_raw = ad7192_write_raw, .write_raw_get_fmt = ad7192_write_raw_get_fmt, + .read_avail = ad7192_read_avail, .attrs = &ad7192_attribute_group, .validate_trigger = ad_sd_validate_trigger, }; @@ -590,6 +593,7 @@ static const struct iio_info ad7195_info = { .read_raw = ad7192_read_raw, .write_raw = ad7192_write_raw, .write_raw_get_fmt = ad7192_write_raw_get_fmt, + .read_avail = ad7192_read_avail, .attrs = &ad7195_attribute_group, .validate_trigger = ad_sd_validate_trigger, }; @@ -624,6 +628,42 @@ static const struct iio_chan_spec ad7193_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(14), }; +static int ad7192_channels_config(struct iio_dev *indio_dev) +{ + struct ad7192_state *st = iio_priv(indio_dev); + const struct iio_chan_spec *channels; + struct iio_chan_spec *chan; + int i; + + switch (st->devid) { + case ID_AD7193: + channels = ad7193_channels; + indio_dev->num_channels = ARRAY_SIZE(ad7193_channels); + break; + default: + channels = ad7192_channels; + indio_dev->num_channels = ARRAY_SIZE(ad7192_channels); + break; + } + + chan = devm_kcalloc(indio_dev->dev.parent, indio_dev->num_channels, + sizeof(*chan), GFP_KERNEL); + if (!chan) + return -ENOMEM; + + indio_dev->channels = chan; + + for (i = 0; i < indio_dev->num_channels; i++) { + *chan = channels[i]; + if (chan->type != IIO_TEMP) + chan->info_mask_shared_by_type_available |= + BIT(IIO_CHAN_INFO_SCALE); + chan++; + } + + return 0; +} + static int ad7192_probe(struct spi_device *spi) { const struct ad7192_platform_data *pdata = dev_get_platdata(&spi->dev); @@ -686,16 +726,9 @@ static int ad7192_probe(struct spi_device *spi) indio_dev->name = spi_get_device_id(spi)->name; indio_dev->modes = INDIO_DIRECT_MODE; - switch (st->devid) { - case ID_AD7193: - indio_dev->channels = ad7193_channels; - indio_dev->num_channels = ARRAY_SIZE(ad7193_channels); - break; - default: - indio_dev->channels = ad7192_channels; - indio_dev->num_channels = ARRAY_SIZE(ad7192_channels); - break; - } + ret = ad7192_channels_config(indio_dev); + if (ret < 0) + goto error_disable_dvdd; if (st->devid == ID_AD7195) indio_dev->info = &ad7195_info; @@ -708,15 +741,42 @@ static int ad7192_probe(struct spi_device *spi) if (ret) goto error_disable_dvdd; - ret = ad7192_setup(st, pdata); - if (ret) + st->fclk = AD7192_INT_FREQ_MHZ; + + st->mclk = devm_clk_get(&st->sd.spi->dev, "mclk"); + if (IS_ERR(st->mclk) && PTR_ERR(st->mclk) != -ENOENT) { + ret = PTR_ERR(st->mclk); goto error_remove_trigger; + } + + st->clock_sel = ad7192_of_clock_select(st); + + if (st->clock_sel == AD7192_CLK_EXT_MCLK1_2 || + st->clock_sel == AD7192_CLK_EXT_MCLK2) { + ret = clk_prepare_enable(st->mclk); + if (ret < 0) + goto error_remove_trigger; + + st->fclk = clk_get_rate(st->mclk); + if (!ad7192_valid_external_frequency(st->fclk)) { + ret = -EINVAL; + dev_err(&spi->dev, + "External clock frequency out of bounds\n"); + goto error_disable_clk; + } + } + + ret = ad7192_setup(st, spi->dev.of_node); + if (ret) + goto error_disable_clk; ret = iio_device_register(indio_dev); if (ret < 0) - goto error_remove_trigger; + goto error_disable_clk; return 0; +error_disable_clk: + clk_disable_unprepare(st->mclk); error_remove_trigger: ad_sd_cleanup_buffer_and_trigger(indio_dev); error_disable_dvdd: @@ -733,6 +793,7 @@ static int ad7192_remove(struct spi_device *spi) struct ad7192_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); + clk_disable_unprepare(st->mclk); ad_sd_cleanup_buffer_and_trigger(indio_dev); regulator_disable(st->dvdd); diff --git a/drivers/staging/iio/adc/ad7192.h b/drivers/staging/iio/adc/ad7192.h index e382b22c460b..f3669e1df084 100644 --- a/drivers/staging/iio/adc/ad7192.h +++ b/drivers/staging/iio/adc/ad7192.h @@ -32,15 +32,6 @@ struct ad7192_platform_data { u16 vref_mv; - u8 clock_source_sel; - u32 ext_clk_hz; - bool refin2_en; - bool rej60_en; - bool sinc3_en; - bool chop_en; - bool buf_en; - bool unipolar_en; - bool burnout_curr_en; }; #endif /* IIO_ADC_AD7192_H_ */ diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index 47cfe920b2ae..19a5f244dcae 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -96,9 +96,10 @@ #define AD7280A_NUM_CH (AD7280A_AUX_ADC_6 - \ AD7280A_CELL_VOLTAGE_1 + 1) -#define AD7280A_CALC_VOLTAGE_CHAN_NUM(d, c) ((d * AD7280A_CELLS_PER_DEV) + c) -#define AD7280A_CALC_TEMP_CHAN_NUM(d, c) ((d * AD7280A_CELLS_PER_DEV) + \ - c - AD7280A_CELLS_PER_DEV) +#define AD7280A_CALC_VOLTAGE_CHAN_NUM(d, c) (((d) * AD7280A_CELLS_PER_DEV) + \ + (c)) +#define AD7280A_CALC_TEMP_CHAN_NUM(d, c) (((d) * AD7280A_CELLS_PER_DEV) + \ + (c) - AD7280A_CELLS_PER_DEV) #define AD7280A_DEVADDR_MASTER 0 #define AD7280A_DEVADDR_ALL 0x1F @@ -782,43 +783,38 @@ static irqreturn_t ad7280_event_handler(int irq, void *private) for (i = 0; i < st->scan_cnt; i++) { if (((channels[i] >> 23) & 0xF) <= AD7280A_CELL_VOLTAGE_6) { if (((channels[i] >> 11) & 0xFFF) >= - st->cell_threshhigh) - iio_push_event(indio_dev, - IIO_EVENT_CODE(IIO_VOLTAGE, - 1, - 0, - IIO_EV_DIR_RISING, - IIO_EV_TYPE_THRESH, - 0, 0, 0), + st->cell_threshhigh) { + u64 tmp = IIO_EVENT_CODE(IIO_VOLTAGE, 1, 0, + IIO_EV_DIR_RISING, + IIO_EV_TYPE_THRESH, + 0, 0, 0); + iio_push_event(indio_dev, tmp, iio_get_time_ns(indio_dev)); - else if (((channels[i] >> 11) & 0xFFF) <= - st->cell_threshlow) - iio_push_event(indio_dev, - IIO_EVENT_CODE(IIO_VOLTAGE, - 1, - 0, - IIO_EV_DIR_FALLING, - IIO_EV_TYPE_THRESH, - 0, 0, 0), + } else if (((channels[i] >> 11) & 0xFFF) <= + st->cell_threshlow) { + u64 tmp = IIO_EVENT_CODE(IIO_VOLTAGE, 1, 0, + IIO_EV_DIR_FALLING, + IIO_EV_TYPE_THRESH, + 0, 0, 0); + iio_push_event(indio_dev, tmp, iio_get_time_ns(indio_dev)); + } } else { - if (((channels[i] >> 11) & 0xFFF) >= st->aux_threshhigh) - iio_push_event(indio_dev, - IIO_UNMOD_EVENT_CODE( - IIO_TEMP, - 0, + if (((channels[i] >> 11) & 0xFFF) >= + st->aux_threshhigh) { + u64 tmp = IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0, IIO_EV_TYPE_THRESH, - IIO_EV_DIR_RISING), + IIO_EV_DIR_RISING); + iio_push_event(indio_dev, tmp, iio_get_time_ns(indio_dev)); - else if (((channels[i] >> 11) & 0xFFF) <= - st->aux_threshlow) - iio_push_event(indio_dev, - IIO_UNMOD_EVENT_CODE( - IIO_TEMP, - 0, + } else if (((channels[i] >> 11) & 0xFFF) <= + st->aux_threshlow) { + u64 tmp = IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0, IIO_EV_TYPE_THRESH, - IIO_EV_DIR_FALLING), + IIO_EV_DIR_FALLING); + iio_push_event(indio_dev, tmp, iio_get_time_ns(indio_dev)); + } } } @@ -829,30 +825,30 @@ out: } static IIO_DEVICE_ATTR_NAMED(in_thresh_low_value, - in_voltage-voltage_thresh_low_value, - 0644, - ad7280_read_channel_config, - ad7280_write_channel_config, - AD7280A_CELL_UNDERVOLTAGE); + in_voltage-voltage_thresh_low_value, + 0644, + ad7280_read_channel_config, + ad7280_write_channel_config, + AD7280A_CELL_UNDERVOLTAGE); static IIO_DEVICE_ATTR_NAMED(in_thresh_high_value, - in_voltage-voltage_thresh_high_value, - 0644, - ad7280_read_channel_config, - ad7280_write_channel_config, - AD7280A_CELL_OVERVOLTAGE); + in_voltage-voltage_thresh_high_value, + 0644, + ad7280_read_channel_config, + ad7280_write_channel_config, + AD7280A_CELL_OVERVOLTAGE); static IIO_DEVICE_ATTR(in_temp_thresh_low_value, - 0644, - ad7280_read_channel_config, - ad7280_write_channel_config, - AD7280A_AUX_ADC_UNDERVOLTAGE); + 0644, + ad7280_read_channel_config, + ad7280_write_channel_config, + AD7280A_AUX_ADC_UNDERVOLTAGE); static IIO_DEVICE_ATTR(in_temp_thresh_high_value, - 0644, - ad7280_read_channel_config, - ad7280_write_channel_config, - AD7280A_AUX_ADC_OVERVOLTAGE); + 0644, + ad7280_read_channel_config, + ad7280_write_channel_config, + AD7280A_AUX_ADC_OVERVOLTAGE); static struct attribute *ad7280_event_attributes[] = { &iio_dev_attr_in_thresh_low_value.dev_attr.attr, @@ -920,8 +916,8 @@ static int ad7280_probe(struct spi_device *spi) const struct ad7280_platform_data *pdata = dev_get_platdata(&spi->dev); struct ad7280_state *st; int ret; - const unsigned short tACQ_ns[4] = {465, 1010, 1460, 1890}; - const unsigned short nAVG[4] = {1, 2, 4, 8}; + const unsigned short t_acq_ns[4] = {465, 1010, 1460, 1890}; + const unsigned short n_avg[4] = {1, 2, 4, 8}; struct iio_dev *indio_dev; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); @@ -969,10 +965,9 @@ static int ad7280_probe(struct spi_device *spi) */ st->readback_delay_us = - ((tACQ_ns[pdata->acquisition_time & 0x3] + 695) * - (AD7280A_NUM_CH * nAVG[pdata->conversion_averaging & 0x3])) - - tACQ_ns[pdata->acquisition_time & 0x3] + - st->slave_num * 250; + ((t_acq_ns[pdata->acquisition_time & 0x3] + 695) * + (AD7280A_NUM_CH * n_avg[pdata->conversion_averaging & 0x3])) - + t_acq_ns[pdata->acquisition_time & 0x3] + st->slave_num * 250; /* Convert to usecs */ st->readback_delay_us = DIV_ROUND_UP(st->readback_delay_us, 1000); diff --git a/drivers/staging/iio/impedance-analyzer/Kconfig b/drivers/staging/iio/impedance-analyzer/Kconfig index a5b3ee8b02cb..841648847edf 100644 --- a/drivers/staging/iio/impedance-analyzer/Kconfig +++ b/drivers/staging/iio/impedance-analyzer/Kconfig @@ -11,7 +11,7 @@ config AD5933 select IIO_KFIFO_BUF help Say yes here to build support for Analog Devices Impedance Converter, - Network Analyzer, AD5933/4, provides direct access via sysfs. + Network Analyzer, AD5933/4. To compile this driver as a module, choose M here: the module will be called ad5933. diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index d69904899112..af0bcf95ee8a 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -5,22 +5,22 @@ * Copyright 2011 Analog Devices Inc. */ -#include <linux/interrupt.h> +#include <linux/clk.h> +#include <linux/delay.h> #include <linux/device.h> -#include <linux/kernel.h> -#include <linux/sysfs.h> +#include <linux/err.h> #include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> #include <linux/regulator/consumer.h> +#include <linux/sysfs.h> #include <linux/types.h> -#include <linux/err.h> -#include <linux/delay.h> -#include <linux/module.h> -#include <linux/clk.h> -#include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> #include <linux/iio/buffer.h> +#include <linux/iio/iio.h> #include <linux/iio/kfifo_buf.h> +#include <linux/iio/sysfs.h> /* AD5933/AD5934 Registers */ #define AD5933_REG_CONTROL_HB 0x80 /* R/W, 1 byte */ @@ -315,12 +315,12 @@ static ssize_t ad5933_store_frequency(struct device *dev, return ret ? ret : len; } -static IIO_DEVICE_ATTR(out_voltage0_freq_start, 0644, +static IIO_DEVICE_ATTR(out_altvoltage0_frequency_start, 0644, ad5933_show_frequency, ad5933_store_frequency, AD5933_REG_FREQ_START); -static IIO_DEVICE_ATTR(out_voltage0_freq_increment, 0644, +static IIO_DEVICE_ATTR(out_altvoltage0_frequency_increment, 0644, ad5933_show_frequency, ad5933_store_frequency, AD5933_REG_FREQ_INC); @@ -443,12 +443,12 @@ static ssize_t ad5933_store(struct device *dev, return ret ? ret : len; } -static IIO_DEVICE_ATTR(out_voltage0_scale, 0644, +static IIO_DEVICE_ATTR(out_altvoltage0_raw, 0644, ad5933_show, ad5933_store, AD5933_OUT_RANGE); -static IIO_DEVICE_ATTR(out_voltage0_scale_available, 0444, +static IIO_DEVICE_ATTR(out_altvoltage0_scale_available, 0444, ad5933_show, NULL, AD5933_OUT_RANGE_AVAIL); @@ -463,28 +463,29 @@ static IIO_DEVICE_ATTR(in_voltage0_scale_available, 0444, NULL, AD5933_IN_PGA_GAIN_AVAIL); -static IIO_DEVICE_ATTR(out_voltage0_freq_points, 0644, +static IIO_DEVICE_ATTR(out_altvoltage0_frequency_points, 0644, ad5933_show, ad5933_store, AD5933_FREQ_POINTS); -static IIO_DEVICE_ATTR(out_voltage0_settling_cycles, 0644, +static IIO_DEVICE_ATTR(out_altvoltage0_settling_cycles, 0644, ad5933_show, ad5933_store, AD5933_OUT_SETTLING_CYCLES); -/* note: +/* + * note: * ideally we would handle the scale attributes via the iio_info * (read|write)_raw methods, however this part is a untypical since we * don't create dedicated sysfs channel attributes for out0 and in0. */ static struct attribute *ad5933_attributes[] = { - &iio_dev_attr_out_voltage0_scale.dev_attr.attr, - &iio_dev_attr_out_voltage0_scale_available.dev_attr.attr, - &iio_dev_attr_out_voltage0_freq_start.dev_attr.attr, - &iio_dev_attr_out_voltage0_freq_increment.dev_attr.attr, - &iio_dev_attr_out_voltage0_freq_points.dev_attr.attr, - &iio_dev_attr_out_voltage0_settling_cycles.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_raw.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_scale_available.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_frequency_start.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_frequency_increment.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_frequency_points.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_settling_cycles.dev_attr.attr, &iio_dev_attr_in_voltage0_scale.dev_attr.attr, &iio_dev_attr_in_voltage0_scale_available.dev_attr.attr, NULL @@ -571,7 +572,8 @@ static int ad5933_ring_postenable(struct iio_dev *indio_dev) { struct ad5933_state *st = iio_priv(indio_dev); - /* AD5933_CTRL_INIT_START_FREQ: + /* + * AD5933_CTRL_INIT_START_FREQ: * High Q complex circuits require a long time to reach steady state. * To facilitate the measurement of such impedances, this mode allows * the user full control of the settling time requirement before @@ -662,7 +664,8 @@ static void ad5933_work(struct work_struct *work) } if (status & AD5933_STAT_SWEEP_DONE) { - /* last sample received - power down do + /* + * last sample received - power down do * nothing until the ring enable is toggled */ ad5933_cmd(st, AD5933_CTRL_POWER_DOWN); diff --git a/include/dt-bindings/iio/temperature/thermocouple.h b/include/dt-bindings/iio/temperature/thermocouple.h new file mode 100644 index 000000000000..ce037f5238ac --- /dev/null +++ b/include/dt-bindings/iio/temperature/thermocouple.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _DT_BINDINGS_TEMPERATURE_THERMOCOUPLE_H +#define _DT_BINDINGS_TEMPERATURE_THERMOCOUPLE_H + + +#define THERMOCOUPLE_TYPE_B 0x00 +#define THERMOCOUPLE_TYPE_E 0x01 +#define THERMOCOUPLE_TYPE_J 0x02 +#define THERMOCOUPLE_TYPE_K 0x03 +#define THERMOCOUPLE_TYPE_N 0x04 +#define THERMOCOUPLE_TYPE_R 0x05 +#define THERMOCOUPLE_TYPE_S 0x06 +#define THERMOCOUPLE_TYPE_T 0x07 + +#endif /* _DT_BINDINGS_TEMPERATURE_THERMOCOUPLE_H */ diff --git a/include/linux/iio/adc/ad_sigma_delta.h b/include/linux/iio/adc/ad_sigma_delta.h index 7e84351fa2c0..6e9fb1932dde 100644 --- a/include/linux/iio/adc/ad_sigma_delta.h +++ b/include/linux/iio/adc/ad_sigma_delta.h @@ -69,6 +69,7 @@ struct ad_sigma_delta { bool irq_dis; bool bus_locked; + bool keep_cs_asserted; uint8_t comm; diff --git a/include/linux/iio/driver.h b/include/linux/iio/driver.h index 7dfb10ee2669..f54a7bcdefe3 100644 --- a/include/linux/iio/driver.h +++ b/include/linux/iio/driver.h @@ -11,6 +11,7 @@ #ifndef _IIO_INKERN_H_ #define _IIO_INKERN_H_ +struct iio_dev; struct iio_map; /** diff --git a/include/linux/iio/frequency/ad9523.h b/include/linux/iio/frequency/ad9523.h index 12ce3ee427fd..621b93c0bcf9 100644 --- a/include/linux/iio/frequency/ad9523.h +++ b/include/linux/iio/frequency/ad9523.h @@ -129,8 +129,8 @@ enum cpole1_capacitor { * @pll2_ndiv_b_cnt: PLL2 Feedback N-divider, B Counter, range 0..63. * @pll2_freq_doubler_en: PLL2 frequency doubler enable. * @pll2_r2_div: PLL2 R2 divider, range 0..31. - * @pll2_vco_diff_m1: VCO1 divider, range 3..5. - * @pll2_vco_diff_m2: VCO2 divider, range 3..5. + * @pll2_vco_div_m1: VCO1 divider, range 3..5. + * @pll2_vco_div_m2: VCO2 divider, range 3..5. * @rpole2: PLL2 loop filter Rpole resistor value. * @rzero: PLL2 loop filter Rzero resistor value. * @cpole1: PLL2 loop filter Cpole capacitor value. @@ -176,8 +176,8 @@ struct ad9523_platform_data { unsigned char pll2_ndiv_b_cnt; bool pll2_freq_doubler_en; unsigned char pll2_r2_div; - unsigned char pll2_vco_diff_m1; /* 3..5 */ - unsigned char pll2_vco_diff_m2; /* 3..5 */ + unsigned char pll2_vco_div_m1; /* 3..5 */ + unsigned char pll2_vco_div_m2; /* 3..5 */ /* Loop Filter PLL2 */ enum rpole2_resistor rpole2; diff --git a/include/linux/iio/gyro/itg3200.h b/include/linux/iio/gyro/itg3200.h index 2a820850f284..0a30fddccfb3 100644 --- a/include/linux/iio/gyro/itg3200.h +++ b/include/linux/iio/gyro/itg3200.h @@ -104,6 +104,7 @@ struct itg3200 { struct i2c_client *i2c; struct iio_trigger *trig; + struct iio_mount_matrix orientation; }; enum ITG3200_SCAN_INDEX { diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index a74cb177dc6f..bb10c1bee301 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -130,8 +130,8 @@ struct iio_mount_matrix { ssize_t iio_show_mount_matrix(struct iio_dev *indio_dev, uintptr_t priv, const struct iio_chan_spec *chan, char *buf); -int of_iio_read_mount_matrix(const struct device *dev, const char *propname, - struct iio_mount_matrix *matrix); +int iio_read_mount_matrix(struct device *dev, const char *propname, + struct iio_mount_matrix *matrix); typedef const struct iio_mount_matrix * (iio_get_mount_matrix_t)(const struct iio_dev *indio_dev, diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h index 360da7d18a3d..469a493f7ae0 100644 --- a/include/linux/iio/imu/adis.h +++ b/include/linux/iio/imu/adis.h @@ -21,6 +21,7 @@ #define ADIS_REG_PAGE_ID 0x00 struct adis; +struct adis_burst; /** * struct adis_data - ADIS chip variant specific data @@ -57,6 +58,7 @@ struct adis { struct iio_trigger *trig; const struct adis_data *data; + struct adis_burst *burst; struct mutex txrx_lock; struct spi_message msg; @@ -232,6 +234,18 @@ int adis_single_conversion(struct iio_dev *indio_dev, #ifdef CONFIG_IIO_ADIS_LIB_BUFFER +/** + * struct adis_burst - ADIS data for burst transfers + * @en burst mode enabled + * @reg_cmd register command that triggers burst + * @extra_len extra length to account in the SPI RX buffer + */ +struct adis_burst { + bool en; + unsigned int reg_cmd; + unsigned int extra_len; +}; + int adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev, irqreturn_t (*trigger_handler)(int, void *)); void adis_cleanup_buffer_and_trigger(struct adis *adis, |