]> Git Repo - linux.git/commitdiff
Merge tag 'iio-for-5.18a' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23...
authorGreg Kroah-Hartman <[email protected]>
Fri, 18 Mar 2022 11:41:32 +0000 (12:41 +0100)
committerGreg Kroah-Hartman <[email protected]>
Fri, 18 Mar 2022 11:41:32 +0000 (12:41 +0100)
Jonathan writes:

First set of new device support, fixes, cleanups and features for IIO in 5.18

This cycle we had quite a few series that applied similar changes
to lots of drivers. To keep this description manageable I have
called those out in their own section rather than per driver.

Particularly pleased to see the long running AFE precision series
going in this cycle.

Series includes some late breaking fixes.

New device support
* adi,ada4250 amplifier
  - New driver and dt bindings for this programmable gain amplifier.
* adi,admv1014 microwave down-converter
  - New driver, dt bindings and some device specific ABI that
    may be generalized as more drivers for devices similar to this
    are added.
* adi,admv4420 K Band down-converter.
  - New driver and dt bindings.
* adi,adxl367 accelerometer driver.
  - New driver, dt-bindings + some new IIO ABI definitions to support
    reference magnitude events where an estimate of the acceleration
    due to gravity has been removed.
  - A few fixes as follow up patches.
* adi,ltc2688 DAC with toggle and dither modes.
  - New driver and bindings. Includes some new driver specific (for now)
    ABI for handling toggle mode and the addition of a dither waveform to
    the DAC output.
* AFE (analog front end) add support for additional types of analog device
  in front of an ADC.
  - RTD temperature sensors with dt bindings.
  - Temperature transducers wit dt bindings.
  - Related cleanup and features listed in other sections below.
* maxim,ds3502 potentiometer.
  - Add support to ds1803 driver which required significant rework.
* mediatek,mt2701-auxadc driver
  - Add mediatek,mt8186-auxadc - id table and chip specific info only.
* semtech,sx9324, semtech,ax9360
  - Substantial refactoring of sx9310 to extract core logic for reuse
    into a separate module
  - New driver using this supporting sx9324 proximity sensors.
  - New driver using this supporting sx9360 proximity sensors.
* silan,sc7a20
  - Compatible with the st,lis2dh (or nearly anyway) so add ID and
    chip specific info to enable support. Also silan vendor ID added
    for dt-bindings.

Staging graduation
* adi,ad7280a monitoring ADC for stacked lithium-ion batteries in
  electric cars and similar.
  - Substantial rework of driver required to bring inline with current
    IIO best practice. An unusual device in IIO so some interesting features
    we may see more of in future.

Multiple driver/core cleanup
- Use sysfs_emit() in simple locations where there is no path to change
  to various core created attributes.
- Trivial white space fixes around inconsistency between space after { and
  before } in id tables.
- Introduce new handling for fractional types to avoid repeated similar
  implementations. Use this in 3 drivers. Note this is also targeted
  at future use in the AFE driver and was motivated by discussions
  around the precision related work on that driver.
- of related header cleanups - drop of*.h and add mod_devicetable.h as
  appropriate.
- Move a number of symbol exports into IIO_* namespaces.  Two categories,
  1) Library used by multiple drivers e.g. st_sensors
  2) Core driver module exporting functions used by bus specific modules.
  A few related cleanups in this set.
- Switch from CONFIG_PM_* guards to new DEFINE_SIMPLE_DEV_PM_OPS() and
  similar to simplify drivers and take advantage of these new macros
  allowing the compiler to do the job or removing unused code without
  the need for __maybe_unused markings. Conversion of other drivers to
  these new macros ongoing.

Features
* adi,adf4350
  - Switch from of specific to generic device properties enabling use with
    other firmware types.
* adi,adx345
  - Switch from of specific to generic device properties.
  - Add ACPI ID ADS0345
  - Related driver cleanup.
* adi,hmc425a
  - Switch from of specific to generic device properties.
* afe analog rescaler driver
  - Wider range of types supported for scale.
  - Support offset.
  - Kunit tests.
* atlas,ezo-sensor
  - Convert from of to device properties.
* fsl,mma8452
  - Support mount matrix.
* infineon,dps310:
  - Add ACPI ID IFX3100.
* invensense,mpu6050
  - Convert to generic device properties.
* maxim,ds1803
  - Add out_raw_available before supporting more devices.
  - Convert from of specific to device properties.
* samsung,ssp_sensors
  - Convert from of specific to device properties.
* st,stm32-timer trigger
  - Convert from of specific to device properties.
* ti,hdc101x
  - Add ACPI ID TXNW1010.
* ti,tsc2046:
  - Add read_raw support to enable use of iio_hwmon and similar.

Fixes / cleanup.
* mailmap
  - Update for Cai Huoqing
* MAINTAINERS
  - Fix Analog Devices related links.
  - Add entry for ADRF6780
  - Add entry for ADMV1013
  - Add entry for AD7293
  - Add entry for ADMV8818
  - Update files listed for adis-lib
* iio core:
  - Fix wrong comment about current_mode being something a driver should
    ever access.
  - Use struct_size() rather than open coding in industrialio-hw-consumer
* adi,axl355
  - Use units.h definitions instead of local versions.
* adi,adis-lib
  - Simplify *updated_bits() macro
  - Whitespace cleanup.
* afe - Note many of these fixes only apply to particular configurations
  so the problems have probably not been seen in the wild, but will be
  visible with new usecases enabled this cycle.
  - Fix application of consumer scale for IIO_VAL_INT.
  - Apply a scale of 1 when no scale is provided.
  - Make best effort to establish a valid offset value for fractional
    cases.
  - Use s64 for scale calculations where parameters may be signed.
  - Tidy up include order.
  - Improve accuracy for small fractional sales
  - Reduce risk of integer overflow.
* ams,as3935
  - Use devm_delayed_work_autocancel() to replace open coded equivalent.
* aspeed,adc
  - Fix wrong use of divider flag.
* atmel,sama5d2-adc
  - Relax atmel,trigger-edge-type to optional.
  - Drop Ludovic Desroches from listed maintainers of the dt-binding
    inline with previous MAINTAINERS entry update.
* fsl,mma8452
  - Fix probing when i2c_device_id used.
  - dev_get_drvdata() on the iio_dev->dev, no longer returns iio_dev.
    Use dev_to_iio_dev() instead. Note the original path in here
    worked more by luck than design.
* invensense,mpu6050
  - Drop ACPI_PTR() protection to avoid an unused warning.
  - Use fact ACPI_COMPANION() returns null when ACPI_HANDLE() does to
    simplify handling.
* motorola,cpcap-adc
  - Drop unused assignment.
* qcom,spmi-adc
  - Fix wrong example of 'reg' in binding document.
* renesas,rzg2l-adc
  - Trivial typo fix.
* semtech,sx9360
  - Fix wrong register handling for event generation.
* st_sensors
  - Allow manual disabling of I2C or SPI module if not needed for a particular
    board. Default is still to enable the bus specific module if
    appropriate bus is supported.
* st,lsm6dsx
  - dev_get_drvdata() on the iio_dev->dev, no longer returns iio_dev.
    Use dev_to_iio_dev() instead.
* ti,palmas-gpadc
  - Split the interrupt fields in the dt-binding example
* ti,tsc2046
  - Rework state machine to improve readability after recent debugging of
    an issue fixed elsewhere.
  - Add a sanity check to avoid very large memory allocations if a crazy
    delay is specified.
* ti,twl6030
  - Add error handling if devm_request_threaded_irq() fails.
* xilinx,ams
  - Use devm_delayed_work_autocancel() instead of open coding equivalent.
  - Fix missing required clock entry in dt-binding.
  - Fix miss counting of channels resulting in ps channels not
    being enabled.
  - Fix incorrect values written to sequencer registers.
  - Fix sequence for single channel reading.

* tag 'iio-for-5.18a' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (245 commits)
  iio: adc: xilinx-ams: Fix single channel switching sequence
  iio: adc: xilinx-ams: Fixed wrong sequencer register settings
  iio: adc: xilinx-ams: Fixed missing PS channels
  dt-bindings: iio: adc: zynqmp_ams: Add clock entry
  iio: accel: mma8452: use the correct logic to get mma8452_data
  iio: adc: aspeed: Add divider flag to fix incorrect voltage reading.
  iio: imu: st_lsm6dsx: use dev_to_iio_dev() to get iio_dev struct
  dt-bindings: iio: Add ltc2688 documentation
  iio: ABI: add ABI file for the LTC2688 DAC
  iio: dac: add support for ltc2688
  dt-bindings: iio: afe: add bindings for temperature transducers
  dt-bindings: iio: afe: add bindings for temperature-sense-rtd
  iio: afe: rescale: add temperature transducers
  iio: afe: rescale: add RTD temperature sensor support
  iio: test: add basic tests for the iio-rescale driver
  iio: afe: rescale: reduce risk of integer overflow
  iio: afe: rescale: fix accuracy for small fractional scales
  iio: afe: rescale: add offset support
  iio: afe: rescale: add INT_PLUS_{MICRO,NANO} support
  iio: afe: rescale: expose scale processing function
  ...

298 files changed:
.mailmap
Documentation/ABI/testing/sysfs-bus-iio
Documentation/ABI/testing/sysfs-bus-iio-adc-ad7280a [new file with mode: 0644]
Documentation/ABI/testing/sysfs-bus-iio-dac-ltc2688 [new file with mode: 0644]
Documentation/ABI/testing/sysfs-bus-iio-frequency-admv1014 [new file with mode: 0644]
Documentation/ABI/testing/sysfs-bus-iio-sx9324 [new file with mode: 0644]
Documentation/devicetree/bindings/iio/accel/adi,adxl367.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/adi,ad7280a.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml
Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml
Documentation/devicetree/bindings/iio/adc/microchip,mcp3201.yaml
Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml
Documentation/devicetree/bindings/iio/adc/ti,palmas-gpadc.yaml
Documentation/devicetree/bindings/iio/adc/xlnx,zynqmp-ams.yaml
Documentation/devicetree/bindings/iio/afe/temperature-sense-rtd.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/afe/temperature-transducer.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/amplifiers/adi,ada4250.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/dac/adi,ltc2688.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/frequency/adi,admv1014.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/frequency/adi,admv4420.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/proximity/semtech,sx9324.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/proximity/semtech,sx9360.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/st,st-sensors.yaml
Documentation/devicetree/bindings/trivial-devices.yaml
Documentation/devicetree/bindings/vendor-prefixes.yaml
MAINTAINERS
drivers/iio/accel/Kconfig
drivers/iio/accel/Makefile
drivers/iio/accel/adis16201.c
drivers/iio/accel/adis16209.c
drivers/iio/accel/adxl313_core.c
drivers/iio/accel/adxl313_i2c.c
drivers/iio/accel/adxl313_spi.c
drivers/iio/accel/adxl345.h
drivers/iio/accel/adxl345_core.c
drivers/iio/accel/adxl345_i2c.c
drivers/iio/accel/adxl345_spi.c
drivers/iio/accel/adxl355_core.c
drivers/iio/accel/adxl355_i2c.c
drivers/iio/accel/adxl355_spi.c
drivers/iio/accel/adxl367.c [new file with mode: 0644]
drivers/iio/accel/adxl367.h [new file with mode: 0644]
drivers/iio/accel/adxl367_i2c.c [new file with mode: 0644]
drivers/iio/accel/adxl367_spi.c [new file with mode: 0644]
drivers/iio/accel/adxl372.c
drivers/iio/accel/adxl372_i2c.c
drivers/iio/accel/adxl372_spi.c
drivers/iio/accel/bma180.c
drivers/iio/accel/bma400_core.c
drivers/iio/accel/bma400_i2c.c
drivers/iio/accel/bma400_spi.c
drivers/iio/accel/bmc150-accel-core.c
drivers/iio/accel/bmc150-accel-i2c.c
drivers/iio/accel/bmc150-accel-spi.c
drivers/iio/accel/bmi088-accel-core.c
drivers/iio/accel/bmi088-accel-spi.c
drivers/iio/accel/da280.c
drivers/iio/accel/da311.c
drivers/iio/accel/dmard06.c
drivers/iio/accel/dmard09.c
drivers/iio/accel/dmard10.c
drivers/iio/accel/fxls8962af-core.c
drivers/iio/accel/fxls8962af-i2c.c
drivers/iio/accel/fxls8962af-spi.c
drivers/iio/accel/kxsd9-i2c.c
drivers/iio/accel/kxsd9-spi.c
drivers/iio/accel/kxsd9.c
drivers/iio/accel/mc3230.c
drivers/iio/accel/mma7455_core.c
drivers/iio/accel/mma7455_i2c.c
drivers/iio/accel/mma7455_spi.c
drivers/iio/accel/mma7660.c
drivers/iio/accel/mma8452.c
drivers/iio/accel/mma9551.c
drivers/iio/accel/mma9551_core.c
drivers/iio/accel/mma9553.c
drivers/iio/accel/ssp_accel_sensor.c
drivers/iio/accel/st_accel.h
drivers/iio/accel/st_accel_buffer.c
drivers/iio/accel/st_accel_core.c
drivers/iio/accel/st_accel_i2c.c
drivers/iio/accel/st_accel_spi.c
drivers/iio/accel/stk8312.c
drivers/iio/accel/stk8ba50.c
drivers/iio/adc/Kconfig
drivers/iio/adc/Makefile
drivers/iio/adc/ab8500-gpadc.c
drivers/iio/adc/ad7091r-base.c
drivers/iio/adc/ad7091r5.c
drivers/iio/adc/ad7124.c
drivers/iio/adc/ad7192.c
drivers/iio/adc/ad7280a.c [new file with mode: 0644]
drivers/iio/adc/ad7606.c
drivers/iio/adc/ad7606_par.c
drivers/iio/adc/ad7606_spi.c
drivers/iio/adc/ad7780.c
drivers/iio/adc/ad7791.c
drivers/iio/adc/ad7793.c
drivers/iio/adc/ad_sigma_delta.c
drivers/iio/adc/aspeed_adc.c
drivers/iio/adc/at91_adc.c
drivers/iio/adc/cpcap-adc.c
drivers/iio/adc/exynos_adc.c
drivers/iio/adc/hi8435.c
drivers/iio/adc/ina2xx-adc.c
drivers/iio/adc/max9611.c
drivers/iio/adc/mt6577_auxadc.c
drivers/iio/adc/palmas_gpadc.c
drivers/iio/adc/qcom-pm8xxx-xoadc.c
drivers/iio/adc/qcom-spmi-vadc.c
drivers/iio/adc/qcom-vadc-common.c
drivers/iio/adc/rcar-gyroadc.c
drivers/iio/adc/rn5t618-adc.c
drivers/iio/adc/rockchip_saradc.c
drivers/iio/adc/rzg2l_adc.c
drivers/iio/adc/stm32-adc-core.c
drivers/iio/adc/stm32-adc.c
drivers/iio/adc/stm32-dfsdm-adc.c
drivers/iio/adc/stm32-dfsdm-core.c
drivers/iio/adc/ti-adc084s021.c
drivers/iio/adc/ti-tsc2046.c
drivers/iio/adc/twl4030-madc.c
drivers/iio/adc/twl6030-gpadc.c
drivers/iio/adc/vf610_adc.c
drivers/iio/adc/xilinx-ams.c
drivers/iio/afe/iio-rescale.c
drivers/iio/amplifiers/Kconfig
drivers/iio/amplifiers/Makefile
drivers/iio/amplifiers/ada4250.c [new file with mode: 0644]
drivers/iio/amplifiers/hmc425a.c
drivers/iio/buffer/industrialio-buffer-dmaengine.c
drivers/iio/buffer/industrialio-hw-consumer.c
drivers/iio/chemical/atlas-ezo-sensor.c
drivers/iio/chemical/atlas-sensor.c
drivers/iio/chemical/bme680_core.c
drivers/iio/chemical/bme680_i2c.c
drivers/iio/chemical/bme680_spi.c
drivers/iio/chemical/scd4x.c
drivers/iio/chemical/sps30.c
drivers/iio/common/ms_sensors/ms_sensors_i2c.c
drivers/iio/common/ssp_sensors/ssp_dev.c
drivers/iio/common/ssp_sensors/ssp_iio.c
drivers/iio/common/st_sensors/Kconfig
drivers/iio/common/st_sensors/st_sensors_buffer.c
drivers/iio/common/st_sensors/st_sensors_core.c
drivers/iio/common/st_sensors/st_sensors_i2c.c
drivers/iio/common/st_sensors/st_sensors_spi.c
drivers/iio/common/st_sensors/st_sensors_trigger.c
drivers/iio/dac/Kconfig
drivers/iio/dac/Makefile
drivers/iio/dac/ad5592r-base.c
drivers/iio/dac/ad5592r.c
drivers/iio/dac/ad5593r.c
drivers/iio/dac/ad5686-spi.c
drivers/iio/dac/ad5686.c
drivers/iio/dac/ad5696-i2c.c
drivers/iio/dac/ltc2688.c [new file with mode: 0644]
drivers/iio/dac/m62332.c
drivers/iio/dac/stm32-dac-core.c
drivers/iio/dac/stm32-dac.c
drivers/iio/dac/vf610_dac.c
drivers/iio/frequency/Kconfig
drivers/iio/frequency/Makefile
drivers/iio/frequency/ad9523.c
drivers/iio/frequency/adf4350.c
drivers/iio/frequency/admv1013.c
drivers/iio/frequency/admv1014.c [new file with mode: 0644]
drivers/iio/frequency/admv4420.c [new file with mode: 0644]
drivers/iio/gyro/Kconfig
drivers/iio/gyro/adis16136.c
drivers/iio/gyro/adis16260.c
drivers/iio/gyro/ssp_gyro_sensor.c
drivers/iio/gyro/st_gyro_buffer.c
drivers/iio/gyro/st_gyro_core.c
drivers/iio/gyro/st_gyro_i2c.c
drivers/iio/gyro/st_gyro_spi.c
drivers/iio/humidity/dht11.c
drivers/iio/humidity/hdc100x.c
drivers/iio/humidity/htu21.c
drivers/iio/imu/adis.c
drivers/iio/imu/adis16400.c
drivers/iio/imu/adis16460.c
drivers/iio/imu/adis16475.c
drivers/iio/imu/adis16480.c
drivers/iio/imu/adis_buffer.c
drivers/iio/imu/adis_trigger.c
drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
drivers/iio/imu/kmx61.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
drivers/iio/imu/st_lsm9ds0/Kconfig
drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c
drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c
drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c
drivers/iio/industrialio-buffer.c
drivers/iio/industrialio-core.c
drivers/iio/industrialio-event.c
drivers/iio/inkern.c
drivers/iio/light/apds9300.c
drivers/iio/light/bh1780.c
drivers/iio/light/cm3232.c
drivers/iio/light/isl29018.c
drivers/iio/light/isl29125.c
drivers/iio/light/jsa1212.c
drivers/iio/light/lm3533-als.c
drivers/iio/light/ltr501.c
drivers/iio/light/pa12203001.c
drivers/iio/light/rpr0521.c
drivers/iio/light/st_uvis25_core.c
drivers/iio/light/st_uvis25_i2c.c
drivers/iio/light/st_uvis25_spi.c
drivers/iio/light/stk3310.c
drivers/iio/light/tcs3414.c
drivers/iio/light/tcs3472.c
drivers/iio/light/tsl2563.c
drivers/iio/light/tsl2772.c
drivers/iio/light/tsl4531.c
drivers/iio/light/us5182d.c
drivers/iio/light/vcnl4035.c
drivers/iio/magnetometer/Kconfig
drivers/iio/magnetometer/ak8975.c
drivers/iio/magnetometer/bmc150_magn.c
drivers/iio/magnetometer/bmc150_magn_i2c.c
drivers/iio/magnetometer/bmc150_magn_spi.c
drivers/iio/magnetometer/hmc5843_core.c
drivers/iio/magnetometer/hmc5843_i2c.c
drivers/iio/magnetometer/hmc5843_spi.c
drivers/iio/magnetometer/mag3110.c
drivers/iio/magnetometer/mmc35240.c
drivers/iio/magnetometer/rm3100-core.c
drivers/iio/magnetometer/rm3100-i2c.c
drivers/iio/magnetometer/rm3100-spi.c
drivers/iio/magnetometer/st_magn_buffer.c
drivers/iio/magnetometer/st_magn_core.c
drivers/iio/magnetometer/st_magn_i2c.c
drivers/iio/magnetometer/st_magn_spi.c
drivers/iio/potentiometer/Kconfig
drivers/iio/potentiometer/ds1803.c
drivers/iio/pressure/Kconfig
drivers/iio/pressure/dps310.c
drivers/iio/pressure/mpl115.c
drivers/iio/pressure/mpl115_i2c.c
drivers/iio/pressure/mpl115_spi.c
drivers/iio/pressure/mpl3115.c
drivers/iio/pressure/ms5611_core.c
drivers/iio/pressure/ms5611_i2c.c
drivers/iio/pressure/ms5611_spi.c
drivers/iio/pressure/ms5637.c
drivers/iio/pressure/st_pressure_buffer.c
drivers/iio/pressure/st_pressure_core.c
drivers/iio/pressure/st_pressure_i2c.c
drivers/iio/pressure/st_pressure_spi.c
drivers/iio/pressure/zpa2326.c
drivers/iio/pressure/zpa2326_i2c.c
drivers/iio/pressure/zpa2326_spi.c
drivers/iio/proximity/Kconfig
drivers/iio/proximity/Makefile
drivers/iio/proximity/as3935.c
drivers/iio/proximity/ping.c
drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
drivers/iio/proximity/rfd77402.c
drivers/iio/proximity/srf04.c
drivers/iio/proximity/srf08.c
drivers/iio/proximity/sx9310.c
drivers/iio/proximity/sx9324.c [new file with mode: 0644]
drivers/iio/proximity/sx9360.c [new file with mode: 0644]
drivers/iio/proximity/sx9500.c
drivers/iio/proximity/sx_common.c [new file with mode: 0644]
drivers/iio/proximity/sx_common.h [new file with mode: 0644]
drivers/iio/proximity/vl53l0x-i2c.c
drivers/iio/temperature/max31856.c
drivers/iio/temperature/max31865.c
drivers/iio/temperature/maxim_thermocouple.c
drivers/iio/temperature/mlx90614.c
drivers/iio/temperature/mlx90632.c
drivers/iio/temperature/tmp006.c
drivers/iio/temperature/tmp007.c
drivers/iio/temperature/tsys01.c
drivers/iio/temperature/tsys02d.c
drivers/iio/test/Kconfig
drivers/iio/test/Makefile
drivers/iio/test/iio-test-rescale.c [new file with mode: 0644]
drivers/iio/trigger/Kconfig
drivers/iio/trigger/stm32-timer-trigger.c
drivers/staging/iio/accel/adis16203.c
drivers/staging/iio/accel/adis16240.c
drivers/staging/iio/adc/Kconfig
drivers/staging/iio/adc/Makefile
drivers/staging/iio/adc/ad7280a.c [deleted file]
drivers/staging/iio/adc/ad7280a.h [deleted file]
include/linux/iio/adc/qcom-vadc-common.h
include/linux/iio/afe/rescale.h [new file with mode: 0644]
include/linux/iio/iio.h
include/linux/iio/imu/adis.h
include/linux/math.h
include/uapi/linux/iio/types.h
tools/iio/iio_event_monitor.c

index 10ee1103c823b31564494db6f8e3b2e59c92b633..29a45c106dfb6d7c5907db3e015e43b143ef8ef0 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -71,6 +71,7 @@ Boris Brezillon <[email protected]> <[email protected]>
 Brian Avery <[email protected]>
 Brian King <[email protected]>
 Brian Silverman <[email protected]> <[email protected]>
index c551301b33f1790a19bcda87594e6dc35915bfb3..d4ccc68fdcf052834243642972fdacc4d086c504 100644 (file)
@@ -476,6 +476,7 @@ What:               /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_calibscale
 What:          /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_calibscale
 What:          /sys/bus/iio/devices/iio:deviceX/in_voltage_i_calibscale
 What:          /sys/bus/iio/devices/iio:deviceX/in_voltage_q_calibscale
+What:          /sys/bus/iio/devices/iio:deviceX/in_altvoltage_calibscale
 What:          /sys/bus/iio/devices/iio:deviceX/in_voltage_calibscale
 What:          /sys/bus/iio/devices/iio:deviceX/in_accel_x_calibscale
 What:          /sys/bus/iio/devices/iio:deviceX/in_accel_y_calibscale
@@ -1213,6 +1214,32 @@ Description:
                number or direction is not specified, applies to all channels of
                this type.
 
+What:          /sys/.../iio:deviceX/events/in_accel_mag_referenced_en
+What:          /sys/.../iio:deviceX/events/in_accel_mag_referenced_rising_en
+What:          /sys/.../iio:deviceX/events/in_accel_mag_referenced_falling_en
+What:          /sys/.../iio:deviceX/events/in_accel_y_mag_referenced_en
+What:          /sys/.../iio:deviceX/events/in_accel_y_mag_referenced_rising_en
+What:          /sys/.../iio:deviceX/events/in_accel_y_mag_referenced_falling_en
+KernelVersion: 5.18
+Contact:       [email protected]
+Description:
+               Similar to in_accel_mag[_y][_rising|_falling]_en, but the event
+               value is relative to a reference magnitude. The reference magnitude
+               includes the graviational acceleration.
+
+What:          /sys/.../iio:deviceX/events/in_accel_mag_referenced_value
+What:          /sys/.../iio:deviceX/events/in_accel_mag_referenced_rising_value
+What:          /sys/.../iio:deviceX/events/in_accel_mag_referenced_falling_value
+What:          /sys/.../iio:deviceX/events/in_accel_y_mag_referenced_value
+What:          /sys/.../iio:deviceX/events/in_accel_y_mag_referenced_rising_value
+What:          /sys/.../iio:deviceX/events/in_accel_y_mag_referenced_falling_value
+KernelVersion: 5.18
+Contact:       [email protected]
+Description:
+               The value to which the reference magnitude of the channel is
+               compared. If the axis is not specified, it applies to all channels
+               of this type.
+
 What:          /sys/.../events/in_steps_change_en
 KernelVersion: 4.0
 Contact:       [email protected]
@@ -1252,6 +1279,10 @@ Description:
                Actually start the buffer capture up.  Will start trigger
                if first device and appropriate.
 
+               Note that it might be impossible to configure other attributes,
+               (e.g.: events, scale, sampling rate) if they impact the currently
+               active buffer capture session.
+
 What:          /sys/bus/iio/devices/iio:deviceX/bufferY
 KernelVersion: 5.11
 Contact:       [email protected]
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-adc-ad7280a b/Documentation/ABI/testing/sysfs-bus-iio-adc-ad7280a
new file mode 100644 (file)
index 0000000..83b7efe
--- /dev/null
@@ -0,0 +1,13 @@
+What:          /sys/bus/iio/devices/iio:deviceX/in_voltageY-voltageZ_balance_switch_en
+KernelVersion: 5.14
+Contact:       [email protected]
+Description:
+               Used to enable an output for balancing cells for time
+               controlled via in_voltage_Y-voltageZ_balance_switch_timer.
+
+What:          /sys/bus/iio/devices/iio:deviceX/in_voltageY-voltageZ_balance_switch_timer
+KernelVersion: 5.14
+Contact:       [email protected]
+Description:
+               Time in seconds for which balance switch will be turned on.
+               Multiple of 71.5 seconds.
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-dac-ltc2688 b/Documentation/ABI/testing/sysfs-bus-iio-dac-ltc2688
new file mode 100644 (file)
index 0000000..1c35971
--- /dev/null
@@ -0,0 +1,86 @@
+What:          /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_en
+KernelVersion: 5.18
+Contact:       [email protected]
+Description:
+               Dither enable. Write 1 to enable dither or 0 to disable it. This is useful
+               for changing the dither parameters. They way it should be done is:
+
+               - disable dither operation;
+               - change dither parameters (eg: frequency, phase...);
+               - enabled dither operation
+
+What:          /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_raw
+KernelVersion: 5.18
+Contact:       [email protected]
+Description:
+               This raw, unscaled value refers to the dither signal amplitude.
+               The same scale as in out_voltageY_raw applies. However, the
+               offset might be different as it's always 0 for this attribute.
+
+What:          /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_raw_available
+KernelVersion: 5.18
+Contact:       [email protected]
+Description:
+               Available range for dither raw amplitude values.
+
+What:          /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_offset
+KernelVersion: 5.18
+Contact:       [email protected]
+Description:
+               Offset applied to out_voltageY_dither_raw. Read only attribute
+               always set to 0.
+
+What:          /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_frequency
+KernelVersion: 5.18
+Contact:       [email protected]
+Description:
+               Sets the dither signal frequency. Units are in Hz.
+
+What:          /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_frequency_available
+KernelVersion: 5.18
+Contact:       [email protected]
+Description:
+               Returns the available values for the dither frequency.
+
+What:          /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_phase
+KernelVersion: 5.18
+Contact:       [email protected]
+Description:
+               Sets the dither signal phase. Units are in Radians.
+
+What:          /sys/bus/iio/devices/iio:deviceX/out_voltageY_dither_phase_available
+KernelVersion: 5.18
+Contact:       [email protected]
+Description:
+               Returns the available values for the dither phase.
+
+What:          /sys/bus/iio/devices/iio:deviceX/out_voltageY_toggle_en
+KernelVersion: 5.18
+Contact:       [email protected]
+Description:
+               Toggle enable. Write 1 to enable toggle or 0 to disable it. This is
+               useful when one wants to change the DAC output codes. The way it should
+               be done is:
+
+               - disable toggle operation;
+               - change out_voltageY_raw0 and out_voltageY_raw1;
+               - enable toggle operation.
+
+What:          /sys/bus/iio/devices/iio:deviceX/out_voltageY_raw0
+What:          /sys/bus/iio/devices/iio:deviceX/out_voltageY_raw1
+KernelVersion: 5.18
+Contact:       [email protected]
+Description:
+               It has the same meaning as out_voltageY_raw. This attribute is
+               specific to toggle enabled channels and refers to the DAC output
+               code in INPUT_A (_raw0) and INPUT_B (_raw1). The same scale and offset
+               as in out_voltageY_raw applies.
+
+What:          /sys/bus/iio/devices/iio:deviceX/out_voltageY_symbol
+KernelVersion: 5.18
+Contact:       [email protected]
+Description:
+               Performs a SW toggle. This attribute is specific to toggle
+               enabled channels and allows to toggle between out_voltageY_raw0
+               and out_voltageY_raw1 through software. Writing 0 will select
+               out_voltageY_raw0 while 1 selects out_voltageY_raw1.
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-frequency-admv1014 b/Documentation/ABI/testing/sysfs-bus-iio-frequency-admv1014
new file mode 100644 (file)
index 0000000..395010a
--- /dev/null
@@ -0,0 +1,23 @@
+What:          /sys/bus/iio/devices/iio:deviceX/in_altvoltage0_i_calibscale_coarse
+KernelVersion: 5.18
+Contact:       [email protected]
+Description:
+               Read/write value for the digital attenuator gain (IF_I) with coarse steps.
+
+What:          /sys/bus/iio/devices/iio:deviceX/in_altvoltage0_q_calibscale_coarse
+KernelVersion: 5.18
+Contact:       [email protected]
+Description:
+               Read/write value for the digital attenuator gain (IF_Q) with coarse steps.
+
+What:          /sys/bus/iio/devices/iio:deviceX/in_altvoltage0_i_calibscale_fine
+KernelVersion: 5.18
+Contact:       [email protected]
+Description:
+               Read/write value for the digital attenuator gain (IF_I) with fine steps.
+
+What:          /sys/bus/iio/devices/iio:deviceX/in_altvoltage0_q_calibscale_fine
+KernelVersion: 5.18
+Contact:       [email protected]
+Description:
+               Read/write value for the digital attenuator gain (IF_Q) with fine steps.
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-sx9324 b/Documentation/ABI/testing/sysfs-bus-iio-sx9324
new file mode 100644 (file)
index 0000000..632e332
--- /dev/null
@@ -0,0 +1,28 @@
+What:          /sys/bus/iio/devices/iio:deviceX/in_proximity<id>_setup
+Date:          November 2021
+KernelVersion: 5.17
+Contact:       Gwendal Grignou <[email protected]>
+Description:
+               SX9324 has 3 inputs, CS0, CS1 and CS2. Hardware layout
+               defines if the input is
+               + not connected (HZ),
+               + grounded (GD),
+               + connected to an antenna where it can act as a base
+                 (DS - data shield), or measured input (MI).
+
+               The sensor rotates measurement across 4 phases
+               (PH0, PH1, PH2, PH3), where the inputs are configured
+               and then measured.
+
+               By default,  during the first phase, [PH0], CS0 is measured,
+               while CS1 and CS2 are used as shields.
+               `cat in_proximity0_setup` returns "MI,DS,DS".
+               [PH1], CS1 is measured, CS0 and CS2 are shield:
+               `cat in_proximity1_setup` returns "DS,MI,DS".
+               [PH2], CS2 is measured, CS0 and CS1 are shield:
+               `cat in_proximity1_setup` returns "DS,DS,MI".
+               [PH3], CS1 and CS2 are measured (combo mode):
+               `cat in_proximity1_setup` returns "DS,MI,MI".
+
+               Note, these are the chip default. Hardware layout will most
+               likely dictate different output. The entry is read-only.
diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adxl367.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adxl367.yaml
new file mode 100644 (file)
index 0000000..d259e79
--- /dev/null
@@ -0,0 +1,79 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/accel/adi,adxl367.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices ADXL367 3-Axis Digital Accelerometer
+
+maintainers:
+  - Cosmin Tanislav <[email protected]>
+
+description: |
+  The ADXL367 is an ultralow power, 3-axis MEMS accelerometer.
+
+  The ADXL367 does not alias input signals by to achieve ultralow power
+  consumption, it samples the full bandwidth of the sensor at all
+  data rates. Measurement ranges of +-2g, +-4g, and +-8g are available,
+  with a resolution of 0.25mg/LSB on the +-2 g range.
+
+  In addition to its ultralow power consumption, the ADXL367
+  has many features to enable true system level power reduction.
+  It includes a deep multimode output FIFO, a built-in micropower
+  temperature sensor, and an internal ADC for synchronous conversion
+  of an additional analog input.
+    https://www.analog.com/en/products/adxl367.html
+
+properties:
+  compatible:
+    enum:
+      - adi,adxl367
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  spi-max-frequency: true
+
+  vdd-supply: true
+  vddio-supply: true
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      accelerometer@53 {
+        compatible = "adi,adxl367";
+        reg = <0x53>;
+        interrupt-parent = <&gpio>;
+        interrupts = <25 IRQ_TYPE_EDGE_RISING>;
+      };
+    };
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    spi {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      accelerometer@0 {
+        compatible = "adi,adxl367";
+        reg = <0>;
+        spi-max-frequency = <1000000>;
+        interrupt-parent = <&gpio>;
+        interrupts = <25 IRQ_TYPE_EDGE_RISING>;
+      };
+    };
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7280a.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7280a.yaml
new file mode 100644 (file)
index 0000000..a694d57
--- /dev/null
@@ -0,0 +1,77 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/adi,ad7280a.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD7280a Lithium Ion Battery Monitoring System
+
+maintainers:
+  - Michael Hennerich <[email protected]>
+  - Jonathan Cameron <[email protected]>
+
+description: |
+  Bindings for the Analog Devices AD7280a Battery Monitoring System.
+  Used in devices such as hybrid electric cars, battery backup and power tools.
+  Multiple chips can be daisy chained and accessed via a single SPI interface.
+  Data sheet found here:
+    https://www.analog.com/media/en/technical-documentation/data-sheets/AD7280A.pdf
+
+properties:
+  compatible:
+    const: adi,ad7280a
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    description: IRQ line for the ADC
+    maxItems: 1
+
+  spi-max-frequency: true
+
+  adi,voltage-alert-last-chan:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Allows limiting of scope of which channels are considered for voltage
+      alerts, typically because not all are wired to anything. Only applies to
+      last device in the daisy chain.
+    default: 5
+    enum: [3, 4, 5]
+
+  adi,acquisition-time-ns:
+    description:
+      Additional time may be needed to charge the sampling capacitors depending
+      on external writing.
+    default: 400
+    enum: [400, 800, 1200, 1600]
+
+  adi,thermistor-termination:
+    type: boolean
+    description:
+      Enable the thermistor termination function.
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    spi {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      adc@0 {
+        compatible = "adi,ad7280a";
+        reg = <0>;
+        spi-max-frequency = <700000>;
+        interrupt-parent = <&gpio>;
+        interrupts = <25 2>;
+        adi,thermistor-termination;
+        adi,acquisition-time-ns = <800>;
+        adi,voltage-alert-last-chan = <5>;
+      };
+    };
+...
index efed361215b4bd6bf3bea0dc96cf8fa549ba184f..31f840d59303a0c95ff0a911c480d8b89771b05d 100644 (file)
@@ -7,7 +7,6 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: AT91 SAMA5D2 Analog to Digital Converter (ADC)
 
 maintainers:
-  - Ludovic Desroches <[email protected]>
   - Eugen Hristev <[email protected]>
 
 properties:
@@ -72,7 +71,6 @@ required:
   - atmel,min-sample-rate-hz
   - atmel,max-sample-rate-hz
   - atmel,startup-time-ms
-  - atmel,trigger-edge-type
 
 examples:
   - |
index b939f9652e3a0f4d1db386d99e9c99c23a19c770..65581ad4b8162b98e0420ab420ed98ba1ba26e3a 100644 (file)
@@ -34,6 +34,7 @@ properties:
       - items:
           - enum:
               - mediatek,mt8183-auxadc
+              - mediatek,mt8186-auxadc
               - mediatek,mt8195-auxadc
               - mediatek,mt8516-auxadc
           - const: mediatek,mt8173-auxadc
index cbbac4ce56d6a0c655e8ad305b05010900cd5357..fcc1ba53b20d3ed4da508db521370a95eb3b2e95 100644 (file)
@@ -10,7 +10,7 @@ maintainers:
   - Oskar Andero <[email protected]>
 
 description: |
-   Family of simple ADCs with an I2C inteface.
+   Family of simple ADCs with a SPI interface.
 
 properties:
   compatible:
index 27e3108661c073f5e6f46d1157ed0bab27abadf2..2a94db6888308379f0d0b61305a9e6a1ad210585 100644 (file)
@@ -51,7 +51,7 @@ examples:
         #size-cells = <0>;
         pmic_iadc: adc@3600 {
             compatible = "qcom,spmi-iadc";
-            reg = <0x3600 0x100>;
+            reg = <0x3600>;
             interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>;
             qcom,external-resistor-micro-ohms = <10000>;
             #io-channel-cells  = <1>;
index 7b895784e00853a13abc6630b453549be6b9d744..57a31356082ef780edce1f47bc7eee821d224cc8 100644 (file)
@@ -74,9 +74,9 @@ examples:
         compatible = "ti,twl6035-pmic", "ti,palmas-pmic";
         adc {
             compatible = "ti,palmas-gpadc";
-            interrupts = <18 0
-                          16 0
-                          17 0>;
+            interrupts = <18 0>,
+                         <16 0>,
+                         <17 0>;
             #io-channel-cells = <1>;
             ti,channel0-current-microamp = <5>;
             ti,channel3-current-microamp = <10>;
index 87992db389b282b5d4b86ff9d4b36fef77796f03..3698b4b0900f5ad2df202a6d2b5692faee60e69a 100644 (file)
@@ -92,6 +92,10 @@ properties:
     description: AMS Controller register space
     maxItems: 1
 
+  clocks:
+    items:
+      - description: AMS reference clock
+
   ranges:
     description:
       Maps the child address space for PS and/or PL.
@@ -181,12 +185,15 @@ properties:
 required:
   - compatible
   - reg
+  - clocks
   - ranges
 
 additionalProperties: false
 
 examples:
   - |
+    #include <dt-bindings/clock/xlnx-zynqmp-clk.h>
+
     bus {
         #address-cells = <2>;
         #size-cells = <2>;
@@ -196,6 +203,7 @@ examples:
             interrupt-parent = <&gic>;
             interrupts = <0 56 4>;
             reg = <0x0 0xffa50000 0x0 0x800>;
+            clocks = <&zynqmp_clk AMS_REF>;
             #address-cells = <1>;
             #size-cells = <1>;
             #io-channel-cells = <1>;
diff --git a/Documentation/devicetree/bindings/iio/afe/temperature-sense-rtd.yaml b/Documentation/devicetree/bindings/iio/afe/temperature-sense-rtd.yaml
new file mode 100644 (file)
index 0000000..336ce96
--- /dev/null
@@ -0,0 +1,101 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/afe/temperature-sense-rtd.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Temperature Sense RTD
+
+maintainers:
+  - Liam Beguin <[email protected]>
+
+description: |
+  RTDs (Resistance Temperature Detectors) are a kind of temperature sensors
+  used to get a linear voltage to temperature reading within a give range
+  (usually 0 to 100 degrees Celsius).
+
+  When an io-channel measures the output voltage across an RTD such as a
+  PT1000, the interesting measurement is almost always the corresponding
+  temperature, not the voltage output. This binding describes such a circuit.
+
+  The general transfer function here is (using SI units)
+
+    V = R(T) * iexc
+    R(T) = r0 * (1 + alpha * T)
+    T = 1 / (alpha * r0 * iexc) * (V - r0 * iexc)
+
+  The following circuit matches what's in the examples section.
+
+           5V0
+          -----
+            |
+        +---+----+
+        |  R 5k  |
+        +---+----+
+            |
+            V 1mA
+            |
+            +---- Vout
+            |
+        +---+----+
+        | PT1000 |
+        +---+----+
+            |
+          -----
+           GND
+
+properties:
+  compatible:
+    const: temperature-sense-rtd
+
+  io-channels:
+    maxItems: 1
+    description: |
+      Channel node of a voltage io-channel.
+
+  '#io-channel-cells':
+    const: 0
+
+  excitation-current-microamp:
+    description: The current fed through the RTD sensor.
+
+  alpha-ppm-per-celsius:
+    description: |
+      alpha can also be expressed in micro-ohms per ohm Celsius. It's a linear
+      approximation of the resistance versus temperature relationship
+      between 0 and 100 degrees Celsius.
+
+      alpha = (R_100 - R_0) / (100 * R_0)
+
+      Where, R_100 is the resistance of the sensor at 100 degrees Celsius, and
+      R_0 (or r-naught-ohms) is the resistance of the sensor at 0 degrees
+      Celsius.
+
+      Pure platinum has an alpha of 3925. Industry standards such as IEC60751
+      and ASTM E-1137 specify an alpha of 3850.
+
+  r-naught-ohms:
+    description: |
+      Resistance of the sensor at 0 degrees Celsius.
+      Common values are 100 for PT100, 500 for PT500, and 1000 for PT1000
+
+additionalProperties: false
+required:
+  - compatible
+  - io-channels
+  - excitation-current-microamp
+  - alpha-ppm-per-celsius
+  - r-naught-ohms
+
+examples:
+  - |
+    pt1000_1: temperature-sensor0 {
+        compatible = "temperature-sense-rtd";
+        #io-channel-cells = <0>;
+        io-channels = <&temp_adc1 0>;
+
+        excitation-current-microamp = <1000>; /* i = U/R = 5 / 5000 */
+        alpha-ppm-per-celsius = <3908>;
+        r-naught-ohms = <1000>;
+    };
+...
diff --git a/Documentation/devicetree/bindings/iio/afe/temperature-transducer.yaml b/Documentation/devicetree/bindings/iio/afe/temperature-transducer.yaml
new file mode 100644 (file)
index 0000000..cfbf535
--- /dev/null
@@ -0,0 +1,114 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/afe/temperature-transducer.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Temperature Transducer
+
+maintainers:
+  - Liam Beguin <[email protected]>
+
+description: |
+  A temperature transducer is a device that converts a thermal quantity
+  into any other physical quantity. This binding applies to temperature to
+  voltage (like the LTC2997), and temperature to current (like the AD590)
+  linear transducers.
+  In both cases these are assumed to be connected to a voltage ADC.
+
+  When an io-channel measures the output voltage of a temperature analog front
+  end such as a temperature transducer, the interesting measurement is almost
+  always the corresponding temperature, not the voltage output. This binding
+  describes such a circuit.
+
+  The general transfer function here is (using SI units)
+    V(T) = Rsense * Isense(T)
+    T = (Isense(T) / alpha) + offset
+    T = 1 / (Rsense * alpha) * (V + offset * Rsense * alpha)
+
+  When using a temperature to voltage transducer, Rsense is set to 1.
+
+  The following circuits show a temperature to current and a temperature to
+  voltage transducer that can be used with this binding.
+
+           VCC
+          -----
+            |
+        +---+---+
+        | AD590 |                               VCC
+        +---+---+                              -----
+            |                                    |
+            V proportional to T             +----+----+
+            |                          D+ --+         |
+            +---- Vout                      | LTC2997 +--- Vout
+            |                          D- --+         |
+        +---+----+                          +---------+
+        | Rsense |                               |
+        +---+----+                             -----
+            |                                   GND
+          -----
+           GND
+
+properties:
+  compatible:
+    const: temperature-transducer
+
+  io-channels:
+    maxItems: 1
+    description: |
+      Channel node of a voltage io-channel.
+
+  '#io-channel-cells':
+    const: 0
+
+  sense-offset-millicelsius:
+    description: |
+      Temperature offset.
+      This offset is commonly used to convert from Kelvins to degrees Celsius.
+      In that case, sense-offset-millicelsius would be set to <(-273150)>.
+    default: 0
+
+  sense-resistor-ohms:
+    description: |
+      The sense resistor.
+      By default sense-resistor-ohms cancels out the resistor making the
+      circuit behave like a temperature transducer.
+    default: 1
+
+  alpha-ppm-per-celsius:
+    description: |
+      Sometimes referred to as output gain, slope, or temperature coefficient.
+
+      alpha is expressed in parts per million which can be micro-amps per
+      degrees Celsius or micro-volts per degrees Celsius. The is the main
+      characteristic of a temperature transducer and should be stated in the
+      datasheet.
+
+additionalProperties: false
+
+required:
+  - compatible
+  - io-channels
+  - alpha-ppm-per-celsius
+
+examples:
+  - |
+    ad950: temperature-sensor-0 {
+        compatible = "temperature-transducer";
+        #io-channel-cells = <0>;
+        io-channels = <&temp_adc 3>;
+
+        sense-offset-millicelsius = <(-273150)>; /* Kelvin to degrees Celsius */
+        sense-resistor-ohms = <8060>;
+        alpha-ppm-per-celsius = <1>; /* 1 uA/K */
+    };
+  - |
+    znq_tmp: temperature-sensor-1 {
+        compatible = "temperature-transducer";
+        #io-channel-cells = <0>;
+        io-channels = <&temp_adc 2>;
+
+        sense-offset-millicelsius = <(-273150)>; /* Kelvin to degrees Celsius */
+        alpha-ppm-per-celsius = <4000>; /* 4 mV/K */
+    };
+...
diff --git a/Documentation/devicetree/bindings/iio/amplifiers/adi,ada4250.yaml b/Documentation/devicetree/bindings/iio/amplifiers/adi,ada4250.yaml
new file mode 100644 (file)
index 0000000..5277479
--- /dev/null
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/amplifiers/adi,ada4250.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ADA4250 Programmable Gain Instrumentation Amplifier
+
+maintainers:
+  - Antoniu Miclaus <[email protected]>
+
+description: |
+  Precision Low Power, 110kHz, 26uA, Programmable Gain Instrumentation Amplifier.
+
+properties:
+  compatible:
+    enum:
+      - adi,ada4250
+
+  reg:
+    maxItems: 1
+
+  avdd-supply: true
+
+  adi,refbuf-enable:
+    description:
+      Enable internal buffer to drive the reference pin.
+    type: boolean
+
+  spi-max-frequency: true
+
+required:
+  - compatible
+  - reg
+  - avdd-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    spi {
+      #address-cells = <1>;
+      #size-cells = <0>;
+      amplifier@0 {
+        compatible = "adi,ada4250";
+        reg = <0>;
+        avdd-supply = <&avdd>;
+      };
+    };
+...
diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ltc2688.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ltc2688.yaml
new file mode 100644 (file)
index 0000000..48f9e7d
--- /dev/null
@@ -0,0 +1,146 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/dac/adi,ltc2688.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices LTC2688 DAC
+
+maintainers:
+  - Nuno Sá <[email protected]>
+
+description: |
+  Analog Devices LTC2688 16 channel, 16 bit, +-15V DAC
+  https://www.analog.com/media/en/technical-documentation/data-sheets/ltc2688.pdf
+
+properties:
+  compatible:
+    enum:
+      - adi,ltc2688
+
+  reg:
+    maxItems: 1
+
+  vcc-supply:
+    description: Analog Supply Voltage Input.
+
+  iovcc-supply:
+    description: Digital Input/Output Supply Voltage.
+
+  vref-supply:
+    description:
+      Reference Input/Output. The voltage at the REF pin sets the full-scale
+      range of all channels. If not provided the internal reference is used and
+      also provided on the VREF pin".
+
+  clr-gpios:
+    description:
+      If specified, it will be asserted during driver probe. As the line is
+      active low, it should be marked GPIO_ACTIVE_LOW.
+    maxItems: 1
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+patternProperties:
+  "^channel@([0-9]|1[0-5])$":
+    type: object
+
+    properties:
+      reg:
+        description: The channel number representing the DAC output channel.
+        maximum: 15
+
+      adi,toggle-mode:
+        description:
+          Set the channel as a toggle enabled channel. Toggle operation enables
+          fast switching of a DAC output between two different DAC codes without
+          any SPI transaction.
+        type: boolean
+
+      adi,output-range-microvolt:
+        description: Specify the channel output full scale range.
+        oneOf:
+          - items:
+              - const: 0
+              - enum: [5000000, 10000000]
+          - items:
+              - const: -5000000
+              - const: 5000000
+          - items:
+              - const: -10000000
+              - const: 10000000
+          - items:
+              - const: -15000000
+              - const: 15000000
+
+      adi,overrange:
+        description: Enable 5% overrange over the selected full scale range.
+        type: boolean
+
+      clocks:
+        maxItems: 1
+
+      adi,toggle-dither-input:
+        description:
+          Selects the TGPx pin to be associated with this channel. This setting
+          only makes sense for toggle or dither enabled channels. If
+          @adi,toggle-mode is not set and this property is given, the channel is
+          assumed to be a dither capable channel. Note that multiple channels
+          can be mapped to the same pin. If this setting is given, the
+          respective @clock must also be provided. Mappings between this and
+          input pins
+            0 - TGP1
+            1 - TGP2
+            2 - TGP3
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [0, 1, 2]
+
+    dependencies:
+      adi,toggle-dither-input: [ clocks ]
+
+    required:
+      - reg
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+
+    spi {
+          #address-cells = <1>;
+          #size-cells = <0>;
+          ltc2688: ltc2688@0 {
+                  compatible = "adi,ltc2688";
+                  reg = <0>;
+
+                  vcc-supply = <&vcc>;
+                  iovcc-supply = <&vcc>;
+                  vref-supply = <&vref>;
+
+                  #address-cells = <1>;
+                  #size-cells = <0>;
+                  channel@0 {
+                          reg = <0>;
+                          adi,toggle-mode;
+                          adi,overrange;
+                  };
+
+                  channel@1 {
+                          reg = <1>;
+                          adi,output-range-microvolt = <0 10000000>;
+
+                          clocks = <&clock_tgp3>;
+                          adi,toggle-dither-input = <2>;
+                  };
+          };
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/iio/frequency/adi,admv1014.yaml b/Documentation/devicetree/bindings/iio/frequency/adi,admv1014.yaml
new file mode 100644 (file)
index 0000000..2716c1e
--- /dev/null
@@ -0,0 +1,134 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/frequency/adi,admv1014.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ADMV1014 Microwave Downconverter
+
+maintainers:
+  - Antoniu Miclaus <[email protected]>
+
+description: |
+   Wideband, microwave downconverter optimized for point to point microwave
+   radio designs operating in the 24 GHz to 44 GHz frequency range.
+
+   https://www.analog.com/en/products/admv1014.html
+
+properties:
+  compatible:
+    enum:
+      - adi,admv1014
+
+  reg:
+    maxItems: 1
+
+  spi-max-frequency:
+    maximum: 1000000
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: lo_in
+    description:
+      External clock that provides the Local Oscilator input.
+
+  vcm-supply:
+    description:
+      Common-mode voltage regulator.
+
+  vcc-if-bb-supply:
+    description:
+      BB and IF supply voltage regulator.
+
+  vcc-vga-supply:
+    description:
+      RF Amplifier supply voltage regulator.
+
+  vcc-vva-supply:
+    description:
+      VVA Control Circuit supply voltage regulator.
+
+  vcc-lna-3p3-supply:
+    description:
+      Low Noise Amplifier 3.3V supply voltage regulator.
+
+  vcc-lna-1p5-supply:
+    description:
+      Low Noise Amplifier 1.5V supply voltage regulator.
+
+  vcc-bg-supply:
+    description:
+      Band Gap Circuit supply voltage regulator.
+
+  vcc-quad-supply:
+    description:
+      Quadruple supply voltage regulator.
+
+  vcc-mixer-supply:
+    description:
+      Mixer supply voltage regulator.
+
+  adi,input-mode:
+    description:
+      Select the input mode.
+      iq - in-phase quadrature (I/Q) input
+      if - complex intermediate frequency (IF) input
+    enum: [iq, if]
+
+  adi,detector-enable:
+    description:
+      Digital Rx Detector Enable. The Square Law Detector output is
+      available at output pin VDET.
+    type: boolean
+
+  adi,p1db-compensation-enable:
+    description:
+      Turn on bits to optimize P1dB.
+    type: boolean
+
+  adi,quad-se-mode:
+    description:
+      Switch the LO path from differential to single-ended operation.
+      se-neg - Single-Ended Mode, Negative Side Disabled.
+      se-pos - Single-Ended Mode, Positive Side Disabled.
+      diff - Differential Mode.
+    enum: [se-neg, se-pos, diff]
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - vcm-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    spi {
+      #address-cells = <1>;
+      #size-cells = <0>;
+      converter@0 {
+        compatible = "adi,admv1014";
+        reg = <0>;
+        spi-max-frequency = <1000000>;
+        clocks = <&admv1014_lo>;
+        clock-names = "lo_in";
+        vcm-supply = <&vcm>;
+        vcc-if-bb-supply = <&vcc_if_bb>;
+        vcc-vga-supply = <&vcc_vga>;
+        vcc-vva-supply = <&vcc_vva>;
+        vcc-lna-3p3-supply = <&vcc_lna_3p3>;
+        vcc-lna-1p5-supply = <&vcc_lna_1p5>;
+        vcc-bg-supply = <&vcc_bg>;
+        vcc-quad-supply = <&vcc_quad>;
+        vcc-mixer-supply = <&vcc_mixer>;
+        adi,quad-se-mode = "diff";
+        adi,detector-enable;
+        adi,p1db-compensation-enable;
+      };
+    };
+...
diff --git a/Documentation/devicetree/bindings/iio/frequency/adi,admv4420.yaml b/Documentation/devicetree/bindings/iio/frequency/adi,admv4420.yaml
new file mode 100644 (file)
index 0000000..da7fe85
--- /dev/null
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/frequency/adi,admv4420.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ADMV4420 K Band Downconverter
+
+maintainers:
+  - Cristian Pop <[email protected]>
+
+description:
+  The ADMV4420 is a highly integrated, double balanced, active
+  mixer with an integrated fractional-N synthesizer, ideally suited
+  for next generation K band satellite communications
+
+properties:
+  compatible:
+    enum:
+      - adi,admv4420
+
+  reg:
+    maxItems: 1
+
+  spi-max-frequency:
+    maximum: 1000000
+
+  adi,lo-freq-khz:
+    description: LO Frequency
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  adi,ref-ext-single-ended-en:
+    description: External reference selected.
+    type: boolean
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    spi {
+      #address-cells = <1>;
+      #size-cells = <0>;
+      mixer@0 {
+        compatible = "adi,admv4420";
+        reg = <0>;
+        spi-max-frequency = <1000000>;
+        adi,lo-freq-khz = <16750000>;
+        adi,ref-ext-single-ended-en;
+      };
+    };
+...
diff --git a/Documentation/devicetree/bindings/iio/proximity/semtech,sx9324.yaml b/Documentation/devicetree/bindings/iio/proximity/semtech,sx9324.yaml
new file mode 100644 (file)
index 0000000..b8a6ee1
--- /dev/null
@@ -0,0 +1,161 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/proximity/semtech,sx9324.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Semtech's SX9324 capacitive proximity sensor
+
+maintainers:
+  - Gwendal Grignou <[email protected]>
+  - Daniel Campello <[email protected]>
+
+description: |
+  Semtech's SX9324 proximity sensor.
+
+properties:
+  compatible:
+    const: semtech,sx9324
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    description:
+      Generated by device to announce preceding read request has finished
+      and data is available or that a close/far proximity event has happened.
+    maxItems: 1
+
+  vdd-supply:
+    description: Main power supply
+
+  svdd-supply:
+    description: Host interface power supply
+
+  "#io-channel-cells":
+    const: 1
+
+  semtech,ph0-pin:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description: |
+      Array of 3 entries. Index represent the id of the CS pin.
+      Value indicates how each CS pin is used during phase 0.
+      Each of the 3 pins have the following value -
+      0 : unused (high impedance)
+      1 : measured input
+      2 : dynamic shield
+      3 : grounded.
+      For instance, CS0 measured, CS1 shield and CS2 ground is [1, 2, 3]
+    items:
+      enum: [ 0, 1, 2, 3 ]
+    minItems: 3
+    maxItems: 3
+
+  semtech,ph1-pin:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description: Same as ph0-pin for phase 1.
+    items:
+      enum: [ 0, 1, 2, 3 ]
+    minItems: 3
+    maxItems: 3
+
+  semtech,ph2-pin:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description: Same as ph0-pin for phase 2.
+    items:
+      enum: [ 0, 1, 2, 3 ]
+    minItems: 3
+    maxItems: 3
+
+  semtech,ph3-pin:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description: Same as ph0-pin for phase 3.
+    items:
+      enum: [ 0, 1, 2, 3 ]
+    minItems: 3
+    maxItems: 3
+
+
+  semtech,ph01-resolution:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [8, 16, 32, 64, 128, 256, 512, 1024]
+    description:
+      Capacitance measurement resolution. For phase 0 and 1.
+      Higher the number, higher the resolution.
+    default: 128
+
+  semtech,ph23-resolution:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [8, 16, 32, 64, 128, 256, 512, 1024]
+    description:
+      Capacitance measurement resolution. For phase 2 and 3
+    default: 128
+
+  semtech,startup-sensor:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [0, 1, 2, 3]
+    default: 0
+    description: |
+      Phase used for start-up proximity detection.
+      It is used when we enable a phase to remove static offset and measure
+      only capacitance changes introduced by the user.
+
+  semtech,ph01-proxraw-strength:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 0
+    maximum: 7
+    default: 1
+    description:
+      PROXRAW filter strength for phase 0 and 1. A value of 0 represents off,
+      and other values represent 1-1/2^N.
+
+  semtech,ph23-proxraw-strength:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 0
+    maximum: 7
+    default: 1
+    description:
+      Same as proxraw-strength01, for phase 2 and 3.
+
+  semtech,avg-pos-strength:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [0, 16, 64, 128, 256, 512, 1024, 4294967295]
+    default: 16
+    description: |
+      Average positive filter strength. A value of 0 represents off and
+      UINT_MAX (4294967295) represents infinite. Other values
+      represent 1-1/N.
+
+required:
+  - compatible
+  - reg
+  - "#io-channel-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+      proximity@28 {
+        compatible = "semtech,sx9324";
+        reg = <0x28>;
+        interrupt-parent = <&pio>;
+        interrupts = <5 IRQ_TYPE_LEVEL_LOW 5>;
+        vdd-supply = <&pp3300_a>;
+        svdd-supply = <&pp1800_prox>;
+        #io-channel-cells = <1>;
+        semtech,ph0-pin = <1 2 3>;
+        semtech,ph1-pin = <3 2 1>;
+        semtech,ph2-pin = <1 2 3>;
+        semtech,ph3-pin = <3 2 1>;
+        semtech,ph01-resolution = <256>;
+        semtech,ph23-resolution = <256>;
+        semtech,startup-sensor = <1>;
+        semtech,ph01-proxraw-strength = <2>;
+        semtech,ph23-proxraw-strength = <2>;
+        semtech,avg-pos-strength = <64>;
+      };
+    };
diff --git a/Documentation/devicetree/bindings/iio/proximity/semtech,sx9360.yaml b/Documentation/devicetree/bindings/iio/proximity/semtech,sx9360.yaml
new file mode 100644 (file)
index 0000000..63e1a1f
--- /dev/null
@@ -0,0 +1,89 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/proximity/semtech,sx9360.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Semtech's SX9360 capacitive proximity sensor
+
+maintainers:
+  - Gwendal Grignou <[email protected]>
+  - Daniel Campello <[email protected]>
+
+description: |
+  Semtech's SX9360 proximity sensor.
+
+properties:
+  compatible:
+    const: semtech,sx9360
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    description:
+      Generated by device to announce preceding read request has finished
+      and data is available or that a close/far proximity event has happened.
+    maxItems: 1
+
+  vdd-supply:
+    description: Main power supply
+
+  svdd-supply:
+    description: Host interface power supply
+
+  "#io-channel-cells":
+    const: 1
+
+  semtech,resolution:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    enum: [8, 16, 32, 64, 128, 256, 512, 1024]
+    description:
+      Capacitance measurement resolution. For both phases, "reference" and
+      "measurement". Higher the number, higher the resolution.
+    default: 128
+
+  semtech,proxraw-strength:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 0
+    maximum: 7
+    default: 1
+    description:
+      PROXRAW filter strength for both phases. A value of 0 represents off,
+      and other values represent 1-1/2^N.
+
+  semtech,avg-pos-strength:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [0, 16, 64, 128, 256, 512, 1024, 4294967295]
+    default: 16
+    description: |
+      Average positive filter strength. A value of 0 represents off and
+      UINT_MAX (4294967295) represents infinite. Other values
+      represent 1-1/N.
+
+required:
+  - compatible
+  - reg
+  - "#io-channel-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+      proximity@28 {
+        compatible = "semtech,sx9360";
+        reg = <0x28>;
+        interrupt-parent = <&pio>;
+        interrupts = <5 IRQ_TYPE_LEVEL_LOW 5>;
+        vdd-supply = <&pp3300_a>;
+        svdd-supply = <&pp1800_prox>;
+        #io-channel-cells = <1>;
+        semtech,resolution = <256>;
+        semtech,proxraw-strength = <2>;
+        semtech,avg-pos-strength = <64>;
+      };
+    };
index 71de5631ebaef276b07cb853e40037b22781ba32..9735a204825539a267f911ba508bb3d7f77e5090 100644 (file)
@@ -46,6 +46,9 @@ properties:
           - st,lsm330d-accel
           - st,lsm330dl-accel
           - st,lsm330dlc-accel
+      - description: Silan Accelerometers
+        enum:
+          - silan,sc7a20
       - description: STMicroelectronics Gyroscopes
         enum:
           - st,l3g4200d-gyro
index d53a4b2f81aab91987f9998f58930de822ace1dc..fe5401c17c2d59ab3904fe565650969d51702689 100644 (file)
@@ -157,6 +157,8 @@ properties:
           - maxim,ds1803-050
             # 100 kOhm digital potentiometer with I2C interface
           - maxim,ds1803-100
+            # 10 kOhm digital potentiometer with I2C interface
+          - maxim,ds3502
             # Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs
           - maxim,max1237
             # Temperature Sensor, I2C interface
index 294093d45a2308fb51b6453e9ca791210ed125df..b923be2c817209da76063afebedeabed171fd2d8 100644 (file)
@@ -1082,6 +1082,8 @@ patternProperties:
     description: Silicon Image
   "^silabs,.*":
     description: Silicon Laboratories
+  "^silan,.*":
+    description: Hangzhou Silan Microelectronics Co., Ltd.
   "^silead,.*":
     description: Silead Inc.
   "^silergy,.*":
index 412d5dae0deda0a8ff60af3923621b284a32f7cc..329554cc468bdf7b6b5fc259f866cf2d4c724319 100644 (file)
@@ -461,35 +461,35 @@ AD525X ANALOG DEVICES DIGITAL POTENTIOMETERS DRIVER
 M:     Michael Hennerich <[email protected]>
 S:     Supported
 W:     http://wiki.analog.com/AD5254
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     drivers/misc/ad525x_dpot.c
 
 AD5398 CURRENT REGULATOR DRIVER (AD5398/AD5821)
 M:     Michael Hennerich <[email protected]>
 S:     Supported
 W:     http://wiki.analog.com/AD5398
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     drivers/regulator/ad5398.c
 
 AD714X CAPACITANCE TOUCH SENSOR DRIVER (AD7142/3/7/8/7A)
 M:     Michael Hennerich <[email protected]>
 S:     Supported
 W:     http://wiki.analog.com/AD7142
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     drivers/input/misc/ad714x.c
 
 AD7877 TOUCHSCREEN DRIVER
 M:     Michael Hennerich <[email protected]>
 S:     Supported
 W:     http://wiki.analog.com/AD7877
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     drivers/input/touchscreen/ad7877.c
 
 AD7879 TOUCHSCREEN DRIVER (AD7879/AD7889)
 M:     Michael Hennerich <[email protected]>
 S:     Supported
 W:     http://wiki.analog.com/AD7879
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     drivers/input/touchscreen/ad7879.c
 
 ADDRESS SPACE LAYOUT RANDOMIZATION (ASLR)
@@ -501,7 +501,7 @@ M:  Michael Hennerich <[email protected]>
 L:     [email protected]
 S:     Supported
 W:     https://wiki.analog.com/ADF7242
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
 F:     drivers/net/ieee802154/adf7242.c
 
@@ -535,7 +535,7 @@ ADP5520 BACKLIGHT DRIVER WITH IO EXPANDER (ADP5520/ADP5501)
 M:     Michael Hennerich <[email protected]>
 S:     Supported
 W:     http://wiki.analog.com/ADP5520
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     drivers/gpio/gpio-adp5520.c
 F:     drivers/input/keyboard/adp5520-keys.c
 F:     drivers/leds/leds-adp5520.c
@@ -546,7 +546,7 @@ ADP5588 QWERTY KEYPAD AND IO EXPANDER DRIVER (ADP5588/ADP5587)
 M:     Michael Hennerich <[email protected]>
 S:     Supported
 W:     http://wiki.analog.com/ADP5588
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     drivers/gpio/gpio-adp5588.c
 F:     drivers/input/keyboard/adp5588-keys.c
 
@@ -554,7 +554,7 @@ ADP8860 BACKLIGHT DRIVER (ADP8860/ADP8861/ADP8863)
 M:     Michael Hennerich <[email protected]>
 S:     Supported
 W:     http://wiki.analog.com/ADP8860
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     drivers/video/backlight/adp8860_bl.c
 
 ADT746X FAN DRIVER
@@ -593,7 +593,7 @@ ADXL34X THREE-AXIS DIGITAL ACCELEROMETER DRIVER (ADXL345/ADXL346)
 M:     Michael Hennerich <[email protected]>
 S:     Supported
 W:     http://wiki.analog.com/ADXL345
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml
 F:     drivers/input/misc/adxl34x.c
 
@@ -607,10 +607,18 @@ F:        drivers/iio/accel/adxl355_core.c
 F:     drivers/iio/accel/adxl355_i2c.c
 F:     drivers/iio/accel/adxl355_spi.c
 
+ADXL367 THREE-AXIS DIGITAL ACCELEROMETER DRIVER
+M:     Cosmin Tanislav <[email protected]>
+L:     [email protected]
+S:     Supported
+W:     http://ez.analog.com/community/linux-device-drivers
+F:     Documentation/devicetree/bindings/iio/accel/adi,adxl367.yaml
+F:     drivers/iio/accel/adxl367*
+
 ADXL372 THREE-AXIS DIGITAL ACCELEROMETER DRIVER
 M:     Michael Hennerich <[email protected]>
 S:     Supported
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml
 F:     drivers/iio/accel/adxl372.c
 F:     drivers/iio/accel/adxl372_i2c.c
@@ -1050,7 +1058,7 @@ ANALOG DEVICES INC AD7192 DRIVER
 M:     Alexandru Tachici <[email protected]>
 L:     [email protected]
 S:     Supported
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml
 F:     drivers/iio/adc/ad7192.c
 
@@ -1058,15 +1066,23 @@ ANALOG DEVICES INC AD7292 DRIVER
 M:     Marcelo Schmitt <[email protected]>
 L:     [email protected]
 S:     Supported
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml
 F:     drivers/iio/adc/ad7292.c
 
+ANALOG DEVICES INC AD7293 DRIVER
+M:     Antoniu Miclaus <[email protected]>
+L:     [email protected]
+S:     Supported
+W:     https://ez.analog.com/linux-software-drivers
+F:     Documentation/devicetree/bindings/iio/dac/adi,ad7293.yaml
+F:     drivers/iio/dac/ad7293.c
+
 ANALOG DEVICES INC AD7768-1 DRIVER
 M:     Michael Hennerich <[email protected]>
 L:     [email protected]
 S:     Supported
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml
 F:     drivers/iio/adc/ad7768-1.c
 
@@ -1075,7 +1091,7 @@ M:        Michael Hennerich <[email protected]>
 M:     Renato Lui Geh <[email protected]>
 L:     [email protected]
 S:     Supported
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml
 F:     drivers/iio/adc/ad7780.c
 
@@ -1094,6 +1110,14 @@ L:       [email protected]
 S:     Maintained
 F:     drivers/media/i2c/ad9389b*
 
+ANALOG DEVICES INC ADA4250 DRIVER
+M:     Antoniu Miclaus <[email protected]>
+L:     [email protected]
+S:     Supported
+W:     https://ez.analog.com/linux-software-drivers
+F:     Documentation/devicetree/bindings/iio/amplifiers/adi,ada4250.yaml
+F:     drivers/iio/amplifiers/ada4250.c
+
 ANALOG DEVICES INC ADGS1408 DRIVER
 M:     Mircea Caprioru <[email protected]>
 S:     Supported
@@ -1104,7 +1128,7 @@ ANALOG DEVICES INC ADIN DRIVER
 M:     Michael Hennerich <[email protected]>
 L:     [email protected]
 S:     Supported
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     Documentation/devicetree/bindings/net/adi,adin.yaml
 F:     drivers/net/phy/adin.c
 
@@ -1113,20 +1137,22 @@ M:      Nuno Sa <[email protected]>
 L:     [email protected]
 S:     Supported
 F:     drivers/iio/imu/adis.c
+F:     drivers/iio/imu/adis_buffer.c
+F:     drivers/iio/imu/adis_trigger.c
 F:     include/linux/iio/imu/adis.h
 
 ANALOG DEVICES INC ADIS16460 DRIVER
 M:     Dragos Bogdan <[email protected]>
 L:     [email protected]
 S:     Supported
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml
 F:     drivers/iio/imu/adis16460.c
 
 ANALOG DEVICES INC ADIS16475 DRIVER
 M:     Nuno Sa <[email protected]>
 L:     [email protected]
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 S:     Supported
 F:     drivers/iio/imu/adis16475.c
 F:     Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
@@ -1135,22 +1161,54 @@ ANALOG DEVICES INC ADM1177 DRIVER
 M:     Michael Hennerich <[email protected]>
 L:     [email protected]
 S:     Supported
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     Documentation/devicetree/bindings/hwmon/adi,adm1177.yaml
 F:     drivers/hwmon/adm1177.c
 
+ANALOG DEVICES INC ADMV1013 DRIVER
+M:     Antoniu Miclaus <[email protected]>
+L:     [email protected]
+S:     Supported
+W:     https://ez.analog.com/linux-software-drivers
+F:     Documentation/devicetree/bindings/iio/frequency/adi,admv1013.yaml
+F:     drivers/iio/frequency/admv1013.c
+
+ANALOG DEVICES INC ADMV8818 DRIVER
+M:     Antoniu Miclaus <[email protected]>
+L:     [email protected]
+S:     Supported
+W:     https://ez.analog.com/linux-software-drivers
+F:     Documentation/devicetree/bindings/iio/filter/adi,admv8818.yaml
+F:     drivers/iio/filter/admv8818.c
+
+ANALOG DEVICES INC ADMV1014 DRIVER
+M:     Antoniu Miclaus <[email protected]>
+L:     [email protected]
+S:     Supported
+W:     https://ez.analog.com/linux-software-drivers
+F:     Documentation/devicetree/bindings/iio/frequency/adi,admv1014.yaml
+F:     drivers/iio/frequency/admv1014.c
+
 ANALOG DEVICES INC ADP5061 DRIVER
 M:     Michael Hennerich <[email protected]>
 L:     [email protected]
 S:     Supported
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     drivers/power/supply/adp5061.c
 
+ANALOG DEVICES INC ADRF6780 DRIVER
+M:     Antoniu Miclaus <[email protected]>
+L:     [email protected]
+S:     Supported
+W:     https://ez.analog.com/linux-software-drivers
+F:     Documentation/devicetree/bindings/iio/frequency/adi,adrf6780.yaml
+F:     drivers/iio/frequency/adrf6780.c
+
 ANALOG DEVICES INC ADV7180 DRIVER
 M:     Lars-Peter Clausen <[email protected]>
 L:     [email protected]
 S:     Supported
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     drivers/media/i2c/adv7180.c
 F:     Documentation/devicetree/bindings/media/i2c/adv7180.yaml
 
@@ -1193,7 +1251,7 @@ M:        Nuno Sá <[email protected]>
 L:     [email protected] (moderated for non-subscribers)
 S:     Supported
 W:     http://wiki.analog.com/
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     sound/soc/codecs/ad1*
 F:     sound/soc/codecs/ad7*
 F:     sound/soc/codecs/adau*
@@ -1204,7 +1262,7 @@ F:        sound/soc/codecs/ssm*
 ANALOG DEVICES INC DMA DRIVERS
 M:     Lars-Peter Clausen <[email protected]>
 S:     Supported
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     drivers/dma/dma-axi-dmac.c
 
 ANALOG DEVICES INC IIO DRIVERS
@@ -1212,7 +1270,7 @@ M:        Lars-Peter Clausen <[email protected]>
 M:     Michael Hennerich <[email protected]>
 S:     Supported
 W:     http://wiki.analog.com/
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9523
 F:     Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350
 F:     Documentation/devicetree/bindings/iio/*/adi,*
@@ -3286,7 +3344,7 @@ AXI-FAN-CONTROL HARDWARE MONITOR DRIVER
 M:     Nuno Sá <[email protected]>
 L:     [email protected]
 S:     Supported
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     Documentation/devicetree/bindings/hwmon/adi,axi-fan-control.yaml
 F:     drivers/hwmon/axi-fan-control.c
 
@@ -11300,11 +11358,20 @@ S:    Maintained
 F:     Documentation/devicetree/bindings/iio/dac/lltc,ltc1660.yaml
 F:     drivers/iio/dac/ltc1660.c
 
+LTC2688 IIO DAC DRIVER
+M:     Nuno Sá <[email protected]>
+L:     [email protected]
+S:     Supported
+W:     http://ez.analog.com/community/linux-device-drivers
+F:     Documentation/ABI/testing/sysfs-bus-iio-dac-ltc2688
+F:     Documentation/devicetree/bindings/iio/dac/adi,ltc2688.yaml
+F:     drivers/iio/dac/ltc2688.c
+
 LTC2947 HARDWARE MONITOR DRIVER
 M:     Nuno Sá <[email protected]>
 L:     [email protected]
 S:     Supported
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     Documentation/devicetree/bindings/hwmon/adi,ltc2947.yaml
 F:     drivers/hwmon/ltc2947-core.c
 F:     drivers/hwmon/ltc2947-i2c.c
@@ -11315,7 +11382,7 @@ LTC2983 IIO TEMPERATURE DRIVER
 M:     Nuno Sá <[email protected]>
 L:     [email protected]
 S:     Supported
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml
 F:     drivers/iio/temperature/ltc2983.c
 
@@ -11330,7 +11397,7 @@ LTC4306 I2C MULTIPLEXER DRIVER
 M:     Michael Hennerich <[email protected]>
 L:     [email protected]
 S:     Supported
-W:     http://ez.analog.com/community/linux-device-drivers
+W:     https://ez.analog.com/linux-software-drivers
 F:     Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt
 F:     drivers/i2c/muxes/i2c-mux-ltc4306.c
 
index 49587c992a6d0b3307fa1ef1eda19fef53d8e5d8..eac3f02662ae0dbeb6eb10205ecf5588fe22ff73 100644 (file)
@@ -123,6 +123,33 @@ config ADXL355_SPI
          will be called adxl355_spi and you will also get adxl355_core
          for the core module.
 
+config ADXL367
+       tristate
+       select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
+
+config ADXL367_SPI
+       tristate "Analog Devices ADXL367 3-Axis Accelerometer SPI Driver"
+       depends on SPI
+       select ADXL367
+       select REGMAP_SPI
+       help
+         Say yes here to add support for the Analog Devices ADXL367 triaxial
+         acceleration sensor.
+         To compile this driver as a module, choose M here: the
+         module will be called adxl367_spi.
+
+config ADXL367_I2C
+       tristate "Analog Devices ADXL367 3-Axis Accelerometer I2C Driver"
+       depends on I2C
+       select ADXL367
+       select REGMAP_I2C
+       help
+         Say yes here to add support for the Analog Devices ADXL367 triaxial
+         acceleration sensor.
+         To compile this driver as a module, choose M here: the
+         module will be called adxl367_i2c.
+
 config ADXL372
        tristate
        select IIO_BUFFER
@@ -349,8 +376,6 @@ config IIO_ST_ACCEL_3AXIS
        depends on !SENSORS_LIS3_I2C
        depends on !SENSORS_LIS3_SPI
        select IIO_ST_SENSORS_CORE
-       select IIO_ST_ACCEL_I2C_3AXIS if (I2C)
-       select IIO_ST_ACCEL_SPI_3AXIS if (SPI_MASTER)
        select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
        help
          Say yes here to build support for STMicroelectronics accelerometers:
@@ -358,23 +383,30 @@ config IIO_ST_ACCEL_3AXIS
          LIS331DLH, LSM303DL, LSM303DLM, LSM330, LIS2DH12, H3LIS331DL,
          LNG2DM, LIS3DE, LIS2DE12, LIS2HH12
 
-         This driver can also be built as a module. If so, these modules
-         will be created:
-         - st_accel (core functions for the driver [it is mandatory]);
-         - st_accel_i2c (necessary for the I2C devices [optional*]);
-         - st_accel_spi (necessary for the SPI devices [optional*]);
-
-         (*) one of these is necessary to do something.
+         Also need to enable at least one of I2C and SPI interface drivers
+         below.
 
 config IIO_ST_ACCEL_I2C_3AXIS
-       tristate
-       depends on IIO_ST_ACCEL_3AXIS
-       depends on IIO_ST_SENSORS_I2C
+       tristate "STMicroelectronics accelerometers 3-Axis I2C Interface"
+       depends on I2C && IIO_ST_ACCEL_3AXIS
+       default I2C && IIO_ST_ACCEL_3AXIS
+       select IIO_ST_SENSORS_I2C
+       help
+         Build support for STMicroelectronics accelerometers I2C interface.
+
+         To compile this driver as a module, choose M here. The module
+         will be called st_accel_i2c.
 
 config IIO_ST_ACCEL_SPI_3AXIS
-       tristate
-       depends on IIO_ST_ACCEL_3AXIS
-       depends on IIO_ST_SENSORS_SPI
+       tristate "STMicroelectronics accelerometers 3-Axis SPI Interface"
+       depends on SPI_MASTER && IIO_ST_ACCEL_3AXIS
+       default SPI_MASTER && IIO_ST_ACCEL_3AXIS
+       select IIO_ST_SENSORS_SPI
+       help
+         Build support for STMicroelectronics accelerometers SPI interface.
+
+         To compile this driver as a module, choose M here. The module
+         will be called st_accel_spi.
 
 config KXSD9
        tristate "Kionix KXSD9 Accelerometer Driver"
index d03e2f6bba08253639742948c3ef03dc81e66779..4d87926688385a4662d546e1d69ddb29d49b9703 100644 (file)
@@ -15,6 +15,9 @@ obj-$(CONFIG_ADXL345_SPI) += adxl345_spi.o
 obj-$(CONFIG_ADXL355) += adxl355_core.o
 obj-$(CONFIG_ADXL355_I2C) += adxl355_i2c.o
 obj-$(CONFIG_ADXL355_SPI) += adxl355_spi.o
+obj-$(CONFIG_ADXL367) += adxl367.o
+obj-$(CONFIG_ADXL367_I2C) += adxl367_i2c.o
+obj-$(CONFIG_ADXL367_SPI) += adxl367_spi.o
 obj-$(CONFIG_ADXL372) += adxl372.o
 obj-$(CONFIG_ADXL372_I2C) += adxl372_i2c.o
 obj-$(CONFIG_ADXL372_SPI) += adxl372_spi.o
index 7a434e2884d43da776c31d89470cbff2f9de5e32..dfb8e2e5bdf58dc089b4e5e37653e8d17fe17eb6 100644 (file)
@@ -300,3 +300,4 @@ MODULE_AUTHOR("Barry Song <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("spi:adis16201");
+MODULE_IMPORT_NS(IIO_ADISLIB);
index ac08e866d6128bfecfaa03381e2aebaf2ae52012..5a9c6e2296f1db5eb5153cb95d246210414eda07 100644 (file)
@@ -310,3 +310,4 @@ MODULE_AUTHOR("Barry Song <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("spi:adis16209");
+MODULE_IMPORT_NS(IIO_ADISLIB);
index 0d243341f1a757da7469e00ea53af8e56b1d03fb..9e4193e64765f8f411876ae8e85dc477df6b29d9 100644 (file)
@@ -26,7 +26,7 @@ const struct regmap_access_table adxl313_readable_regs_table = {
        .yes_ranges = adxl313_readable_reg_range,
        .n_yes_ranges = ARRAY_SIZE(adxl313_readable_reg_range),
 };
-EXPORT_SYMBOL_GPL(adxl313_readable_regs_table);
+EXPORT_SYMBOL_NS_GPL(adxl313_readable_regs_table, IIO_ADXL313);
 
 static const struct regmap_range adxl313_writable_reg_range[] = {
        regmap_reg_range(ADXL313_REG_SOFT_RESET, ADXL313_REG_SOFT_RESET),
@@ -41,7 +41,7 @@ const struct regmap_access_table adxl313_writable_regs_table = {
        .yes_ranges = adxl313_writable_reg_range,
        .n_yes_ranges = ARRAY_SIZE(adxl313_writable_reg_range),
 };
-EXPORT_SYMBOL_GPL(adxl313_writable_regs_table);
+EXPORT_SYMBOL_NS_GPL(adxl313_writable_regs_table, IIO_ADXL313);
 
 struct adxl313_data {
        struct regmap   *regmap;
@@ -325,7 +325,7 @@ int adxl313_core_probe(struct device *dev,
 
        return devm_iio_device_register(dev, indio_dev);
 }
-EXPORT_SYMBOL_GPL(adxl313_core_probe);
+EXPORT_SYMBOL_NS_GPL(adxl313_core_probe, IIO_ADXL313);
 
 MODULE_AUTHOR("Lucas Stankus <[email protected]>");
 MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer core driver");
index 82e9fb2db1e6dc5d98021d8d72302845ce0094ba..c329765dbf60f00ae0b9835b4efe3f0d426c4b24 100644 (file)
@@ -64,3 +64,4 @@ module_i2c_driver(adxl313_i2c_driver);
 MODULE_AUTHOR("Lucas Stankus <[email protected]>");
 MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer I2C driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ADXL313);
index a6162f36ef52ef94ea018cddb7dcdf6a6dfefbde..a3c6d553462d8867eb13e6bada77205d434b067a 100644 (file)
@@ -90,3 +90,4 @@ module_spi_driver(adxl313_spi_driver);
 MODULE_AUTHOR("Lucas Stankus <[email protected]>");
 MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer SPI driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ADXL313);
index af0fdd02c4f260cf0cd841f6860cdf58e77c3634..d7e67cb08538324fcca18b0ce85b7fac4e08d298 100644 (file)
@@ -9,11 +9,10 @@
 #define _ADXL345_H_
 
 enum adxl345_device_type {
-       ADXL345,
-       ADXL375,
+       ADXL345 = 1,
+       ADXL375 = 2,
 };
 
-int adxl345_core_probe(struct device *dev, struct regmap *regmap,
-                      enum adxl345_device_type type, const char *name);
+int adxl345_core_probe(struct device *dev, struct regmap *regmap);
 
 #endif /* _ADXL345_H_ */
index 4b275051ef61c5330731c7d67455b954aed9553e..370bfec1275a156301b7f7ae172b6281dd5bd2aa 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/property.h>
 #include <linux/regmap.h>
 
 #include <linux/iio/iio.h>
@@ -194,7 +195,7 @@ static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
 
 static struct attribute *adxl345_attrs[] = {
        &iio_const_attr_sampling_frequency_available.dev_attr.attr,
-       NULL,
+       NULL
 };
 
 static const struct attribute_group adxl345_attrs_group = {
@@ -208,30 +209,44 @@ static const struct iio_info adxl345_info = {
        .write_raw_get_fmt      = adxl345_write_raw_get_fmt,
 };
 
+static int adxl345_powerup(void *regmap)
+{
+       return regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_MEASURE);
+}
+
 static void adxl345_powerdown(void *regmap)
 {
        regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_STANDBY);
 }
 
-int adxl345_core_probe(struct device *dev, struct regmap *regmap,
-                      enum adxl345_device_type type, const char *name)
+int adxl345_core_probe(struct device *dev, struct regmap *regmap)
 {
+       enum adxl345_device_type type;
        struct adxl345_data *data;
        struct iio_dev *indio_dev;
+       const char *name;
        u32 regval;
        int ret;
 
-       ret = regmap_read(regmap, ADXL345_REG_DEVID, &regval);
-       if (ret < 0) {
-               dev_err(dev, "Error reading device ID: %d\n", ret);
-               return ret;
+       type = (uintptr_t)device_get_match_data(dev);
+       switch (type) {
+       case ADXL345:
+               name = "adxl345";
+               break;
+       case ADXL375:
+               name = "adxl375";
+               break;
+       default:
+               return -EINVAL;
        }
 
-       if (regval != ADXL345_DEVID) {
-               dev_err(dev, "Invalid device ID: %x, expected %x\n",
-                       regval, ADXL345_DEVID);
-               return -ENODEV;
-       }
+       ret = regmap_read(regmap, ADXL345_REG_DEVID, &regval);
+       if (ret < 0)
+               return dev_err_probe(dev, ret, "Error reading device ID\n");
+
+       if (regval != ADXL345_DEVID)
+               return dev_err_probe(dev, -ENODEV, "Invalid device ID: %x, expected %x\n",
+                                    regval, ADXL345_DEVID);
 
        indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
        if (!indio_dev)
@@ -245,10 +260,8 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
 
        ret = regmap_write(data->regmap, ADXL345_REG_DATA_FORMAT,
                           data->data_range);
-       if (ret < 0) {
-               dev_err(dev, "Failed to set data range: %d\n", ret);
-               return ret;
-       }
+       if (ret < 0)
+               return dev_err_probe(dev, ret, "Failed to set data range\n");
 
        indio_dev->name = name;
        indio_dev->info = &adxl345_info;
@@ -257,12 +270,9 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
        indio_dev->num_channels = ARRAY_SIZE(adxl345_channels);
 
        /* Enable measurement mode */
-       ret = regmap_write(data->regmap, ADXL345_REG_POWER_CTL,
-                          ADXL345_POWER_CTL_MEASURE);
-       if (ret < 0) {
-               dev_err(dev, "Failed to enable measurement mode: %d\n", ret);
-               return ret;
-       }
+       ret = adxl345_powerup(data->regmap);
+       if (ret < 0)
+               return dev_err_probe(dev, ret, "Failed to enable measurement mode\n");
 
        ret = devm_add_action_or_reset(dev, adxl345_powerdown, data->regmap);
        if (ret < 0)
@@ -270,7 +280,7 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
 
        return devm_iio_device_register(dev, indio_dev);
 }
-EXPORT_SYMBOL_GPL(adxl345_core_probe);
+EXPORT_SYMBOL_NS_GPL(adxl345_core_probe, IIO_ADXL345);
 
 MODULE_AUTHOR("Eva Rachel Retuya <[email protected]>");
 MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer core driver");
index a431cba216e692fc5b01ca25ec33d88a9d11d9a1..098cd83f95b219463f581ce71827abac74fddaa7 100644 (file)
@@ -19,23 +19,15 @@ static const struct regmap_config adxl345_i2c_regmap_config = {
        .val_bits = 8,
 };
 
-static int adxl345_i2c_probe(struct i2c_client *client,
-                            const struct i2c_device_id *id)
+static int adxl345_i2c_probe(struct i2c_client *client)
 {
        struct regmap *regmap;
 
-       if (!id)
-               return -ENODEV;
-
        regmap = devm_regmap_init_i2c(client, &adxl345_i2c_regmap_config);
-       if (IS_ERR(regmap)) {
-               dev_err(&client->dev, "Error initializing i2c regmap: %ld\n",
-                       PTR_ERR(regmap));
-               return PTR_ERR(regmap);
-       }
+       if (IS_ERR(regmap))
+               return dev_err_probe(&client->dev, PTR_ERR(regmap), "Error initializing regmap\n");
 
-       return adxl345_core_probe(&client->dev, regmap, id->driver_data,
-                                 id->name);
+       return adxl345_core_probe(&client->dev, regmap);
 }
 
 static const struct i2c_device_id adxl345_i2c_id[] = {
@@ -43,28 +35,33 @@ static const struct i2c_device_id adxl345_i2c_id[] = {
        { "adxl375", ADXL375 },
        { }
 };
-
 MODULE_DEVICE_TABLE(i2c, adxl345_i2c_id);
 
 static const struct of_device_id adxl345_of_match[] = {
-       { .compatible = "adi,adxl345" },
-       { .compatible = "adi,adxl375" },
-       { },
+       { .compatible = "adi,adxl345", .data = (const void *)ADXL345 },
+       { .compatible = "adi,adxl375", .data = (const void *)ADXL375 },
+       { }
 };
-
 MODULE_DEVICE_TABLE(of, adxl345_of_match);
 
+static const struct acpi_device_id adxl345_acpi_match[] = {
+       { "ADS0345", ADXL345 },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, adxl345_acpi_match);
+
 static struct i2c_driver adxl345_i2c_driver = {
        .driver = {
                .name   = "adxl345_i2c",
                .of_match_table = adxl345_of_match,
+               .acpi_match_table = adxl345_acpi_match,
        },
-       .probe          = adxl345_i2c_probe,
+       .probe_new      = adxl345_i2c_probe,
        .id_table       = adxl345_i2c_id,
 };
-
 module_i2c_driver(adxl345_i2c_driver);
 
 MODULE_AUTHOR("Eva Rachel Retuya <[email protected]>");
 MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer I2C driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ADXL345);
index ea559ac2e87d43eada532f52184d31e04063e094..aaade5808657ae9baeb286289b33550abeb216e9 100644 (file)
@@ -22,24 +22,18 @@ static const struct regmap_config adxl345_spi_regmap_config = {
 
 static int adxl345_spi_probe(struct spi_device *spi)
 {
-       const struct spi_device_id *id = spi_get_device_id(spi);
        struct regmap *regmap;
 
        /* Bail out if max_speed_hz exceeds 5 MHz */
-       if (spi->max_speed_hz > ADXL345_MAX_SPI_FREQ_HZ) {
-               dev_err(&spi->dev, "SPI CLK, %d Hz exceeds 5 MHz\n",
-                       spi->max_speed_hz);
-               return -EINVAL;
-       }
+       if (spi->max_speed_hz > ADXL345_MAX_SPI_FREQ_HZ)
+               return dev_err_probe(&spi->dev, -EINVAL, "SPI CLK, %d Hz exceeds 5 MHz\n",
+                                    spi->max_speed_hz);
 
        regmap = devm_regmap_init_spi(spi, &adxl345_spi_regmap_config);
-       if (IS_ERR(regmap)) {
-               dev_err(&spi->dev, "Error initializing spi regmap: %ld\n",
-                       PTR_ERR(regmap));
-               return PTR_ERR(regmap);
-       }
+       if (IS_ERR(regmap))
+               return dev_err_probe(&spi->dev, PTR_ERR(regmap), "Error initializing regmap\n");
 
-       return adxl345_core_probe(&spi->dev, regmap, id->driver_data, id->name);
+       return adxl345_core_probe(&spi->dev, regmap);
 }
 
 static const struct spi_device_id adxl345_spi_id[] = {
@@ -47,28 +41,33 @@ static const struct spi_device_id adxl345_spi_id[] = {
        { "adxl375", ADXL375 },
        { }
 };
-
 MODULE_DEVICE_TABLE(spi, adxl345_spi_id);
 
 static const struct of_device_id adxl345_of_match[] = {
-       { .compatible = "adi,adxl345" },
-       { .compatible = "adi,adxl375" },
-       { },
+       { .compatible = "adi,adxl345", .data = (const void *)ADXL345 },
+       { .compatible = "adi,adxl375", .data = (const void *)ADXL375 },
+       { }
 };
-
 MODULE_DEVICE_TABLE(of, adxl345_of_match);
 
+static const struct acpi_device_id adxl345_acpi_match[] = {
+       { "ADS0345", ADXL345 },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, adxl345_acpi_match);
+
 static struct spi_driver adxl345_spi_driver = {
        .driver = {
                .name   = "adxl345_spi",
                .of_match_table = adxl345_of_match,
+               .acpi_match_table = adxl345_acpi_match,
        },
        .probe          = adxl345_spi_probe,
        .id_table       = adxl345_spi_id,
 };
-
 module_spi_driver(adxl345_spi_driver);
 
 MODULE_AUTHOR("Eva Rachel Retuya <[email protected]>");
 MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer SPI driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ADXL345);
index 4f485909f4598d61af83707e86ca10e68e7c225a..e9c10c8c32f094286770db3f4ee4c287f6f76621 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/mod_devicetable.h>
 #include <linux/of_irq.h>
 #include <linux/regmap.h>
+#include <linux/units.h>
+
 #include <asm/unaligned.h>
 
 #include "adxl355.h"
@@ -60,9 +62,6 @@
 #define ADXL355_PARTID_VAL             0xED
 #define ADXL355_RESET_CODE             0x52
 
-#define MEGA 1000000UL
-#define TERA 1000000000000ULL
-
 static const struct regmap_range adxl355_read_reg_range[] = {
        regmap_reg_range(ADXL355_DEVID_AD_REG, ADXL355_FIFO_DATA_REG),
        regmap_reg_range(ADXL355_OFFSET_X_H_REG, ADXL355_SELF_TEST_REG),
@@ -72,7 +71,7 @@ const struct regmap_access_table adxl355_readable_regs_tbl = {
        .yes_ranges = adxl355_read_reg_range,
        .n_yes_ranges = ARRAY_SIZE(adxl355_read_reg_range),
 };
-EXPORT_SYMBOL_GPL(adxl355_readable_regs_tbl);
+EXPORT_SYMBOL_NS_GPL(adxl355_readable_regs_tbl, IIO_ADXL355);
 
 static const struct regmap_range adxl355_write_reg_range[] = {
        regmap_reg_range(ADXL355_OFFSET_X_H_REG, ADXL355_RESET_REG),
@@ -82,7 +81,7 @@ const struct regmap_access_table adxl355_writeable_regs_tbl = {
        .yes_ranges = adxl355_write_reg_range,
        .n_yes_ranges = ARRAY_SIZE(adxl355_write_reg_range),
 };
-EXPORT_SYMBOL_GPL(adxl355_writeable_regs_tbl);
+EXPORT_SYMBOL_NS_GPL(adxl355_writeable_regs_tbl, IIO_ADXL355);
 
 enum adxl355_op_mode {
        ADXL355_MEASUREMENT,
@@ -758,7 +757,7 @@ int adxl355_core_probe(struct device *dev, struct regmap *regmap,
 
        return devm_iio_device_register(dev, indio_dev);
 }
-EXPORT_SYMBOL_GPL(adxl355_core_probe);
+EXPORT_SYMBOL_NS_GPL(adxl355_core_probe, IIO_ADXL355);
 
 MODULE_AUTHOR("Puranjay Mohan <[email protected]>");
 MODULE_DESCRIPTION("ADXL355 3-Axis Digital Accelerometer core driver");
index 5a987bda9060638578b0f49c0d0d71b9f2b7bdfa..f67d57921c81bc6fceda775a5c7e1fef0d073f29 100644 (file)
@@ -60,3 +60,4 @@ module_i2c_driver(adxl355_i2c_driver);
 MODULE_AUTHOR("Puranjay Mohan <[email protected]>");
 MODULE_DESCRIPTION("ADXL355 3-Axis Digital Accelerometer I2C driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ADXL355);
index fb225aeb56e3134c2f38748d491278f02c679490..5fe986ae03f63d11e1153b8f5081e8e2da96c075 100644 (file)
@@ -63,3 +63,4 @@ module_spi_driver(adxl355_spi_driver);
 MODULE_AUTHOR("Puranjay Mohan <[email protected]>");
 MODULE_DESCRIPTION("ADXL355 3-Axis Digital Accelerometer SPI driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ADXL355);
diff --git a/drivers/iio/accel/adxl367.c b/drivers/iio/accel/adxl367.c
new file mode 100644 (file)
index 0000000..6296013
--- /dev/null
@@ -0,0 +1,1588 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021 Analog Devices, Inc.
+ * Author: Cosmin Tanislav <[email protected]>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/sysfs.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <asm/unaligned.h>
+
+#include "adxl367.h"
+
+#define ADXL367_REG_DEVID              0x00
+#define ADXL367_DEVID_AD               0xAD
+
+#define ADXL367_REG_STATUS             0x0B
+#define ADXL367_STATUS_INACT_MASK      BIT(5)
+#define ADXL367_STATUS_ACT_MASK                BIT(4)
+#define ADXL367_STATUS_FIFO_FULL_MASK  BIT(2)
+
+#define ADXL367_FIFO_ENT_H_MASK                GENMASK(1, 0)
+
+#define ADXL367_REG_X_DATA_H           0x0E
+#define ADXL367_REG_Y_DATA_H           0x10
+#define ADXL367_REG_Z_DATA_H           0x12
+#define ADXL367_REG_TEMP_DATA_H                0x14
+#define ADXL367_REG_EX_ADC_DATA_H      0x16
+#define ADXL367_DATA_MASK              GENMASK(15, 2)
+
+#define ADXL367_TEMP_25C               165
+#define ADXL367_TEMP_PER_C             54
+
+#define ADXL367_VOLTAGE_OFFSET         8192
+#define ADXL367_VOLTAGE_MAX_MV         1000
+#define ADXL367_VOLTAGE_MAX_RAW                GENMASK(13, 0)
+
+#define ADXL367_REG_RESET              0x1F
+#define ADXL367_RESET_CODE             0x52
+
+#define ADXL367_REG_THRESH_ACT_H       0x20
+#define ADXL367_REG_THRESH_INACT_H     0x23
+#define ADXL367_THRESH_MAX             GENMASK(12, 0)
+#define ADXL367_THRESH_VAL_H_MASK      GENMASK(12, 6)
+#define ADXL367_THRESH_H_MASK          GENMASK(6, 0)
+#define ADXL367_THRESH_VAL_L_MASK      GENMASK(5, 0)
+#define ADXL367_THRESH_L_MASK          GENMASK(7, 2)
+
+#define ADXL367_REG_TIME_ACT           0x22
+#define ADXL367_REG_TIME_INACT_H       0x25
+#define ADXL367_TIME_ACT_MAX           GENMASK(7, 0)
+#define ADXL367_TIME_INACT_MAX         GENMASK(15, 0)
+#define ADXL367_TIME_INACT_VAL_H_MASK  GENMASK(15, 8)
+#define ADXL367_TIME_INACT_H_MASK      GENMASK(7, 0)
+#define ADXL367_TIME_INACT_VAL_L_MASK  GENMASK(7, 0)
+#define ADXL367_TIME_INACT_L_MASK      GENMASK(7, 0)
+
+#define ADXL367_REG_ACT_INACT_CTL      0x27
+#define ADXL367_ACT_EN_MASK            GENMASK(1, 0)
+#define ADXL367_ACT_LINKLOOP_MASK      GENMASK(5, 4)
+
+#define ADXL367_REG_FIFO_CTL           0x28
+#define ADXL367_FIFO_CTL_FORMAT_MASK   GENMASK(6, 3)
+#define ADXL367_FIFO_CTL_MODE_MASK     GENMASK(1, 0)
+
+#define ADXL367_REG_FIFO_SAMPLES       0x29
+#define ADXL367_FIFO_SIZE              512
+#define ADXL367_FIFO_MAX_WATERMARK     511
+
+#define ADXL367_SAMPLES_VAL_H_MASK     BIT(8)
+#define ADXL367_SAMPLES_H_MASK         BIT(2)
+#define ADXL367_SAMPLES_VAL_L_MASK     GENMASK(7, 0)
+#define ADXL367_SAMPLES_L_MASK         GENMASK(7, 0)
+
+#define ADXL367_REG_INT1_MAP           0x2A
+#define ADXL367_INT_INACT_MASK         BIT(5)
+#define ADXL367_INT_ACT_MASK           BIT(4)
+#define ADXL367_INT_FIFO_WATERMARK_MASK        BIT(2)
+
+#define ADXL367_REG_FILTER_CTL         0x2C
+#define ADXL367_FILTER_CTL_RANGE_MASK  GENMASK(7, 6)
+#define ADXL367_2G_RANGE_1G            4095
+#define ADXL367_2G_RANGE_100MG         409
+#define ADXL367_FILTER_CTL_ODR_MASK    GENMASK(2, 0)
+
+#define ADXL367_REG_POWER_CTL          0x2D
+#define ADXL367_POWER_CTL_MODE_MASK    GENMASK(1, 0)
+
+#define ADXL367_REG_ADC_CTL            0x3C
+#define ADXL367_REG_TEMP_CTL           0x3D
+#define ADXL367_ADC_EN_MASK            BIT(0)
+
+enum adxl367_range {
+       ADXL367_2G_RANGE,
+       ADXL367_4G_RANGE,
+       ADXL367_8G_RANGE,
+};
+
+enum adxl367_fifo_mode {
+       ADXL367_FIFO_MODE_DISABLED = 0b00,
+       ADXL367_FIFO_MODE_STREAM = 0b10,
+};
+
+enum adxl367_fifo_format {
+       ADXL367_FIFO_FORMAT_XYZ,
+       ADXL367_FIFO_FORMAT_X,
+       ADXL367_FIFO_FORMAT_Y,
+       ADXL367_FIFO_FORMAT_Z,
+       ADXL367_FIFO_FORMAT_XYZT,
+       ADXL367_FIFO_FORMAT_XT,
+       ADXL367_FIFO_FORMAT_YT,
+       ADXL367_FIFO_FORMAT_ZT,
+       ADXL367_FIFO_FORMAT_XYZA,
+       ADXL367_FIFO_FORMAT_XA,
+       ADXL367_FIFO_FORMAT_YA,
+       ADXL367_FIFO_FORMAT_ZA,
+};
+
+enum adxl367_op_mode {
+       ADXL367_OP_STANDBY = 0b00,
+       ADXL367_OP_MEASURE = 0b10,
+};
+
+enum adxl367_act_proc_mode {
+       ADXL367_LOOPED = 0b11,
+};
+
+enum adxl367_act_en_mode {
+       ADXL367_ACT_DISABLED = 0b00,
+       ADCL367_ACT_REF_ENABLED = 0b11,
+};
+
+enum adxl367_activity_type {
+       ADXL367_ACTIVITY,
+       ADXL367_INACTIVITY,
+};
+
+enum adxl367_odr {
+       ADXL367_ODR_12P5HZ,
+       ADXL367_ODR_25HZ,
+       ADXL367_ODR_50HZ,
+       ADXL367_ODR_100HZ,
+       ADXL367_ODR_200HZ,
+       ADXL367_ODR_400HZ,
+};
+
+struct adxl367_state {
+       const struct adxl367_ops        *ops;
+       void                            *context;
+
+       struct device                   *dev;
+       struct regmap                   *regmap;
+
+       struct regulator_bulk_data      regulators[2];
+
+       /*
+        * Synchronize access to members of driver state, and ensure atomicity
+        * of consecutive regmap operations.
+        */
+       struct mutex            lock;
+
+       enum adxl367_odr        odr;
+       enum adxl367_range      range;
+
+       unsigned int    act_threshold;
+       unsigned int    act_time_ms;
+       unsigned int    inact_threshold;
+       unsigned int    inact_time_ms;
+
+       unsigned int    fifo_set_size;
+       unsigned int    fifo_watermark;
+
+       __be16          fifo_buf[ADXL367_FIFO_SIZE] ____cacheline_aligned;
+       __be16          sample_buf;
+       u8              act_threshold_buf[2];
+       u8              inact_time_buf[2];
+       u8              status_buf[3];
+};
+
+static const unsigned int adxl367_threshold_h_reg_tbl[] = {
+       [ADXL367_ACTIVITY]   = ADXL367_REG_THRESH_ACT_H,
+       [ADXL367_INACTIVITY] = ADXL367_REG_THRESH_INACT_H,
+};
+
+static const unsigned int adxl367_act_en_shift_tbl[] = {
+       [ADXL367_ACTIVITY]   = 0,
+       [ADXL367_INACTIVITY] = 2,
+};
+
+static const unsigned int adxl367_act_int_mask_tbl[] = {
+       [ADXL367_ACTIVITY]   = ADXL367_INT_ACT_MASK,
+       [ADXL367_INACTIVITY] = ADXL367_INT_INACT_MASK,
+};
+
+static const int adxl367_samp_freq_tbl[][2] = {
+       [ADXL367_ODR_12P5HZ] = {12, 500000},
+       [ADXL367_ODR_25HZ]   = {25, 0},
+       [ADXL367_ODR_50HZ]   = {50, 0},
+       [ADXL367_ODR_100HZ]  = {100, 0},
+       [ADXL367_ODR_200HZ]  = {200, 0},
+       [ADXL367_ODR_400HZ]  = {400, 0},
+};
+
+/* (g * 2) * 9.80665 * 1000000 / (2^14 - 1) */
+static const int adxl367_range_scale_tbl[][2] = {
+       [ADXL367_2G_RANGE] = {0, 2394347},
+       [ADXL367_4G_RANGE] = {0, 4788695},
+       [ADXL367_8G_RANGE] = {0, 9577391},
+};
+
+static const int adxl367_range_scale_factor_tbl[] = {
+       [ADXL367_2G_RANGE] = 1,
+       [ADXL367_4G_RANGE] = 2,
+       [ADXL367_8G_RANGE] = 4,
+};
+
+enum {
+       ADXL367_X_CHANNEL_INDEX,
+       ADXL367_Y_CHANNEL_INDEX,
+       ADXL367_Z_CHANNEL_INDEX,
+       ADXL367_TEMP_CHANNEL_INDEX,
+       ADXL367_EX_ADC_CHANNEL_INDEX
+};
+
+#define ADXL367_X_CHANNEL_MASK         BIT(ADXL367_X_CHANNEL_INDEX)
+#define ADXL367_Y_CHANNEL_MASK         BIT(ADXL367_Y_CHANNEL_INDEX)
+#define ADXL367_Z_CHANNEL_MASK         BIT(ADXL367_Z_CHANNEL_INDEX)
+#define ADXL367_TEMP_CHANNEL_MASK      BIT(ADXL367_TEMP_CHANNEL_INDEX)
+#define ADXL367_EX_ADC_CHANNEL_MASK    BIT(ADXL367_EX_ADC_CHANNEL_INDEX)
+
+static const enum adxl367_fifo_format adxl367_fifo_formats[] = {
+       ADXL367_FIFO_FORMAT_X,
+       ADXL367_FIFO_FORMAT_Y,
+       ADXL367_FIFO_FORMAT_Z,
+       ADXL367_FIFO_FORMAT_XT,
+       ADXL367_FIFO_FORMAT_YT,
+       ADXL367_FIFO_FORMAT_ZT,
+       ADXL367_FIFO_FORMAT_XA,
+       ADXL367_FIFO_FORMAT_YA,
+       ADXL367_FIFO_FORMAT_ZA,
+       ADXL367_FIFO_FORMAT_XYZ,
+       ADXL367_FIFO_FORMAT_XYZT,
+       ADXL367_FIFO_FORMAT_XYZA,
+};
+
+static const unsigned long adxl367_channel_masks[] = {
+       ADXL367_X_CHANNEL_MASK,
+       ADXL367_Y_CHANNEL_MASK,
+       ADXL367_Z_CHANNEL_MASK,
+       ADXL367_X_CHANNEL_MASK | ADXL367_TEMP_CHANNEL_MASK,
+       ADXL367_Y_CHANNEL_MASK | ADXL367_TEMP_CHANNEL_MASK,
+       ADXL367_Z_CHANNEL_MASK | ADXL367_TEMP_CHANNEL_MASK,
+       ADXL367_X_CHANNEL_MASK | ADXL367_EX_ADC_CHANNEL_MASK,
+       ADXL367_Y_CHANNEL_MASK | ADXL367_EX_ADC_CHANNEL_MASK,
+       ADXL367_Z_CHANNEL_MASK | ADXL367_EX_ADC_CHANNEL_MASK,
+       ADXL367_X_CHANNEL_MASK | ADXL367_Y_CHANNEL_MASK | ADXL367_Z_CHANNEL_MASK,
+       ADXL367_X_CHANNEL_MASK | ADXL367_Y_CHANNEL_MASK | ADXL367_Z_CHANNEL_MASK |
+               ADXL367_TEMP_CHANNEL_MASK,
+       ADXL367_X_CHANNEL_MASK | ADXL367_Y_CHANNEL_MASK | ADXL367_Z_CHANNEL_MASK |
+               ADXL367_EX_ADC_CHANNEL_MASK,
+       0,
+};
+
+static int adxl367_set_measure_en(struct adxl367_state *st, bool en)
+{
+       enum adxl367_op_mode op_mode = en ? ADXL367_OP_MEASURE
+                                         : ADXL367_OP_STANDBY;
+       int ret;
+
+       ret = regmap_update_bits(st->regmap, ADXL367_REG_POWER_CTL,
+                                ADXL367_POWER_CTL_MODE_MASK,
+                                FIELD_PREP(ADXL367_POWER_CTL_MODE_MASK,
+                                           op_mode));
+       if (ret)
+               return ret;
+
+       /*
+        * Wait for acceleration output to settle after entering
+        * measure mode.
+        */
+       if (en)
+               msleep(100);
+
+       return 0;
+}
+
+static void adxl367_scale_act_thresholds(struct adxl367_state *st,
+                                        enum adxl367_range old_range,
+                                        enum adxl367_range new_range)
+{
+       st->act_threshold = st->act_threshold
+                           * adxl367_range_scale_factor_tbl[old_range]
+                           / adxl367_range_scale_factor_tbl[new_range];
+       st->inact_threshold = st->inact_threshold
+                             * adxl367_range_scale_factor_tbl[old_range]
+                             / adxl367_range_scale_factor_tbl[new_range];
+}
+
+static int _adxl367_set_act_threshold(struct adxl367_state *st,
+                                     enum adxl367_activity_type act,
+                                     unsigned int threshold)
+{
+       u8 reg = adxl367_threshold_h_reg_tbl[act];
+       int ret;
+
+       if (threshold > ADXL367_THRESH_MAX)
+               return -EINVAL;
+
+       st->act_threshold_buf[0] = FIELD_PREP(ADXL367_THRESH_H_MASK,
+                                             FIELD_GET(ADXL367_THRESH_VAL_H_MASK,
+                                                       threshold));
+       st->act_threshold_buf[1] = FIELD_PREP(ADXL367_THRESH_L_MASK,
+                                             FIELD_GET(ADXL367_THRESH_VAL_L_MASK,
+                                                       threshold));
+
+       ret = regmap_bulk_write(st->regmap, reg, st->act_threshold_buf,
+                               sizeof(st->act_threshold_buf));
+       if (ret)
+               return ret;
+
+       if (act == ADXL367_ACTIVITY)
+               st->act_threshold = threshold;
+       else
+               st->inact_threshold = threshold;
+
+       return 0;
+}
+
+static int adxl367_set_act_threshold(struct adxl367_state *st,
+                                    enum adxl367_activity_type act,
+                                    unsigned int threshold)
+{
+       int ret;
+
+       mutex_lock(&st->lock);
+
+       ret = adxl367_set_measure_en(st, false);
+       if (ret)
+               goto out;
+
+       ret = _adxl367_set_act_threshold(st, act, threshold);
+       if (ret)
+               goto out;
+
+       ret = adxl367_set_measure_en(st, true);
+
+out:
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static int adxl367_set_act_proc_mode(struct adxl367_state *st,
+                                    enum adxl367_act_proc_mode mode)
+{
+       return regmap_update_bits(st->regmap, ADXL367_REG_ACT_INACT_CTL,
+                                 ADXL367_ACT_LINKLOOP_MASK,
+                                 FIELD_PREP(ADXL367_ACT_LINKLOOP_MASK,
+                                            mode));
+}
+
+static int adxl367_set_act_interrupt_en(struct adxl367_state *st,
+                                       enum adxl367_activity_type act,
+                                       bool en)
+{
+       unsigned int mask = adxl367_act_int_mask_tbl[act];
+
+       return regmap_update_bits(st->regmap, ADXL367_REG_INT1_MAP,
+                                 mask, en ? mask : 0);
+}
+
+static int adxl367_get_act_interrupt_en(struct adxl367_state *st,
+                                       enum adxl367_activity_type act,
+                                       bool *en)
+{
+       unsigned int mask = adxl367_act_int_mask_tbl[act];
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(st->regmap, ADXL367_REG_INT1_MAP, &val);
+       if (ret)
+               return ret;
+
+       *en = !!(val & mask);
+
+       return 0;
+}
+
+static int adxl367_set_act_en(struct adxl367_state *st,
+                             enum adxl367_activity_type act,
+                             enum adxl367_act_en_mode en)
+{
+       unsigned int ctl_shift = adxl367_act_en_shift_tbl[act];
+
+       return regmap_update_bits(st->regmap, ADXL367_REG_ACT_INACT_CTL,
+                                 ADXL367_ACT_EN_MASK << ctl_shift,
+                                 en << ctl_shift);
+}
+
+static int adxl367_set_fifo_watermark_interrupt_en(struct adxl367_state *st,
+                                                  bool en)
+{
+       return regmap_update_bits(st->regmap, ADXL367_REG_INT1_MAP,
+                                 ADXL367_INT_FIFO_WATERMARK_MASK,
+                                 en ? ADXL367_INT_FIFO_WATERMARK_MASK : 0);
+}
+
+static int adxl367_get_fifo_mode(struct adxl367_state *st,
+                                enum adxl367_fifo_mode *fifo_mode)
+{
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(st->regmap, ADXL367_REG_FIFO_CTL, &val);
+       if (ret)
+               return ret;
+
+       *fifo_mode = FIELD_GET(ADXL367_FIFO_CTL_MODE_MASK, val);
+
+       return 0;
+}
+
+static int adxl367_set_fifo_mode(struct adxl367_state *st,
+                                enum adxl367_fifo_mode fifo_mode)
+{
+       return regmap_update_bits(st->regmap, ADXL367_REG_FIFO_CTL,
+                                 ADXL367_FIFO_CTL_MODE_MASK,
+                                 FIELD_PREP(ADXL367_FIFO_CTL_MODE_MASK,
+                                            fifo_mode));
+}
+
+static int adxl367_set_fifo_format(struct adxl367_state *st,
+                                  enum adxl367_fifo_format fifo_format)
+{
+       return regmap_update_bits(st->regmap, ADXL367_REG_FIFO_CTL,
+                                 ADXL367_FIFO_CTL_FORMAT_MASK,
+                                 FIELD_PREP(ADXL367_FIFO_CTL_FORMAT_MASK,
+                                            fifo_format));
+}
+
+static int adxl367_set_fifo_samples(struct adxl367_state *st,
+                                   unsigned int fifo_watermark,
+                                   unsigned int fifo_set_size)
+{
+       unsigned int fifo_samples = fifo_watermark * fifo_set_size;
+       unsigned int fifo_samples_h, fifo_samples_l;
+       int ret;
+
+       if (fifo_samples > ADXL367_FIFO_MAX_WATERMARK)
+               fifo_samples = ADXL367_FIFO_MAX_WATERMARK;
+
+       if (fifo_set_size == 0)
+               return 0;
+
+       fifo_samples /= fifo_set_size;
+
+       fifo_samples_h = FIELD_PREP(ADXL367_SAMPLES_H_MASK,
+                                   FIELD_GET(ADXL367_SAMPLES_VAL_H_MASK,
+                                             fifo_samples));
+       fifo_samples_l = FIELD_PREP(ADXL367_SAMPLES_L_MASK,
+                                   FIELD_GET(ADXL367_SAMPLES_VAL_L_MASK,
+                                             fifo_samples));
+
+       ret = regmap_update_bits(st->regmap, ADXL367_REG_FIFO_CTL,
+                                ADXL367_SAMPLES_H_MASK, fifo_samples_h);
+       if (ret)
+               return ret;
+
+       return regmap_update_bits(st->regmap, ADXL367_REG_FIFO_SAMPLES,
+                                 ADXL367_SAMPLES_L_MASK, fifo_samples_l);
+}
+
+static int adxl367_set_fifo_set_size(struct adxl367_state *st,
+                                    unsigned int fifo_set_size)
+{
+       int ret;
+
+       ret = adxl367_set_fifo_samples(st, st->fifo_watermark, fifo_set_size);
+       if (ret)
+               return ret;
+
+       st->fifo_set_size = fifo_set_size;
+
+       return 0;
+}
+
+static int adxl367_set_fifo_watermark(struct adxl367_state *st,
+                                     unsigned int fifo_watermark)
+{
+       int ret;
+
+       ret = adxl367_set_fifo_samples(st, fifo_watermark, st->fifo_set_size);
+       if (ret)
+               return ret;
+
+       st->fifo_watermark = fifo_watermark;
+
+       return 0;
+}
+
+static int adxl367_set_range(struct iio_dev *indio_dev,
+                            enum adxl367_range range)
+{
+       struct adxl367_state *st = iio_priv(indio_dev);
+       int ret;
+
+       ret = iio_device_claim_direct_mode(indio_dev);
+       if (ret)
+               return ret;
+
+       mutex_lock(&st->lock);
+
+       ret = adxl367_set_measure_en(st, false);
+       if (ret)
+               goto out;
+
+       ret = regmap_update_bits(st->regmap, ADXL367_REG_FILTER_CTL,
+                                ADXL367_FILTER_CTL_RANGE_MASK,
+                                FIELD_PREP(ADXL367_FILTER_CTL_RANGE_MASK,
+                                           range));
+       if (ret)
+               goto out;
+
+       adxl367_scale_act_thresholds(st, st->range, range);
+
+       /* Activity thresholds depend on range */
+       ret = _adxl367_set_act_threshold(st, ADXL367_ACTIVITY,
+                                        st->act_threshold);
+       if (ret)
+               goto out;
+
+       ret = _adxl367_set_act_threshold(st, ADXL367_INACTIVITY,
+                                        st->inact_threshold);
+       if (ret)
+               goto out;
+
+       ret = adxl367_set_measure_en(st, true);
+       if (ret)
+               goto out;
+
+       st->range = range;
+
+out:
+       mutex_unlock(&st->lock);
+
+       iio_device_release_direct_mode(indio_dev);
+
+       return ret;
+}
+
+static int adxl367_time_ms_to_samples(struct adxl367_state *st, unsigned int ms)
+{
+       int freq_hz = adxl367_samp_freq_tbl[st->odr][0];
+       int freq_microhz = adxl367_samp_freq_tbl[st->odr][1];
+       /* Scale to decihertz to prevent precision loss in 12.5Hz case. */
+       int freq_dhz = freq_hz * 10 + freq_microhz / 100000;
+
+       return DIV_ROUND_CLOSEST(ms * freq_dhz, 10000);
+}
+
+static int _adxl367_set_act_time_ms(struct adxl367_state *st, unsigned int ms)
+{
+       unsigned int val = adxl367_time_ms_to_samples(st, ms);
+       int ret;
+
+       if (val > ADXL367_TIME_ACT_MAX)
+               val = ADXL367_TIME_ACT_MAX;
+
+       ret = regmap_write(st->regmap, ADXL367_REG_TIME_ACT, val);
+       if (ret)
+               return ret;
+
+       st->act_time_ms = ms;
+
+       return 0;
+}
+
+static int _adxl367_set_inact_time_ms(struct adxl367_state *st, unsigned int ms)
+{
+       unsigned int val = adxl367_time_ms_to_samples(st, ms);
+       int ret;
+
+       if (val > ADXL367_TIME_INACT_MAX)
+               val = ADXL367_TIME_INACT_MAX;
+
+       st->inact_time_buf[0] = FIELD_PREP(ADXL367_TIME_INACT_H_MASK,
+                                          FIELD_GET(ADXL367_TIME_INACT_VAL_H_MASK,
+                                                    val));
+       st->inact_time_buf[1] = FIELD_PREP(ADXL367_TIME_INACT_L_MASK,
+                                          FIELD_GET(ADXL367_TIME_INACT_VAL_L_MASK,
+                                                    val));
+
+       ret = regmap_bulk_write(st->regmap, ADXL367_REG_TIME_INACT_H,
+                               st->inact_time_buf, sizeof(st->inact_time_buf));
+       if (ret)
+               return ret;
+
+       st->inact_time_ms = ms;
+
+       return 0;
+}
+
+static int adxl367_set_act_time_ms(struct adxl367_state *st,
+                                  enum adxl367_activity_type act,
+                                  unsigned int ms)
+{
+       int ret;
+
+       mutex_lock(&st->lock);
+
+       ret = adxl367_set_measure_en(st, false);
+       if (ret)
+               goto out;
+
+       if (act == ADXL367_ACTIVITY)
+               ret = _adxl367_set_act_time_ms(st, ms);
+       else
+               ret = _adxl367_set_inact_time_ms(st, ms);
+
+       if (ret)
+               goto out;
+
+       ret = adxl367_set_measure_en(st, true);
+
+out:
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static int _adxl367_set_odr(struct adxl367_state *st, enum adxl367_odr odr)
+{
+       int ret;
+
+       ret = regmap_update_bits(st->regmap, ADXL367_REG_FILTER_CTL,
+                                ADXL367_FILTER_CTL_ODR_MASK,
+                                FIELD_PREP(ADXL367_FILTER_CTL_ODR_MASK,
+                                           odr));
+       if (ret)
+               return ret;
+
+       /* Activity timers depend on ODR */
+       ret = _adxl367_set_act_time_ms(st, st->act_time_ms);
+       if (ret)
+               return ret;
+
+       ret = _adxl367_set_inact_time_ms(st, st->inact_time_ms);
+       if (ret)
+               return ret;
+
+       st->odr = odr;
+
+       return 0;
+}
+
+static int adxl367_set_odr(struct iio_dev *indio_dev, enum adxl367_odr odr)
+{
+       struct adxl367_state *st = iio_priv(indio_dev);
+       int ret;
+
+       ret = iio_device_claim_direct_mode(indio_dev);
+       if (ret)
+               return ret;
+
+       mutex_lock(&st->lock);
+
+       ret = adxl367_set_measure_en(st, false);
+       if (ret)
+               goto out;
+
+       ret = _adxl367_set_odr(st, odr);
+       if (ret)
+               goto out;
+
+       ret = adxl367_set_measure_en(st, true);
+
+out:
+       mutex_unlock(&st->lock);
+
+       iio_device_release_direct_mode(indio_dev);
+
+       return ret;
+}
+
+static int adxl367_set_temp_adc_en(struct adxl367_state *st, unsigned int reg,
+                                  bool en)
+{
+       return regmap_update_bits(st->regmap, reg, ADXL367_ADC_EN_MASK,
+                                 en ? ADXL367_ADC_EN_MASK : 0);
+}
+
+static int adxl367_set_temp_adc_reg_en(struct adxl367_state *st,
+                                      unsigned int reg, bool en)
+{
+       int ret;
+
+       switch (reg) {
+       case ADXL367_REG_TEMP_DATA_H:
+               ret = adxl367_set_temp_adc_en(st, ADXL367_REG_TEMP_CTL, en);
+               break;
+       case ADXL367_REG_EX_ADC_DATA_H:
+               ret = adxl367_set_temp_adc_en(st, ADXL367_REG_ADC_CTL, en);
+               break;
+       default:
+               return 0;
+       }
+
+       if (ret)
+               return ret;
+
+       if (en)
+               msleep(100);
+
+       return 0;
+}
+
+static int adxl367_set_temp_adc_mask_en(struct adxl367_state *st,
+                                       const unsigned long *active_scan_mask,
+                                       bool en)
+{
+       if (*active_scan_mask & ADXL367_TEMP_CHANNEL_MASK)
+               return adxl367_set_temp_adc_en(st, ADXL367_REG_TEMP_CTL, en);
+       else if (*active_scan_mask & ADXL367_EX_ADC_CHANNEL_MASK)
+               return adxl367_set_temp_adc_en(st, ADXL367_REG_ADC_CTL, en);
+
+       return 0;
+}
+
+static int adxl367_find_odr(struct adxl367_state *st, int val, int val2,
+                           enum adxl367_odr *odr)
+{
+       size_t size = ARRAY_SIZE(adxl367_samp_freq_tbl);
+       int i;
+
+       for (i = 0; i < size; i++)
+               if (val == adxl367_samp_freq_tbl[i][0] &&
+                   val2 == adxl367_samp_freq_tbl[i][1])
+                       break;
+
+       if (i == size)
+               return -EINVAL;
+
+       *odr = i;
+
+       return 0;
+}
+
+static int adxl367_find_range(struct adxl367_state *st, int val, int val2,
+                             enum adxl367_range *range)
+{
+       size_t size = ARRAY_SIZE(adxl367_range_scale_tbl);
+       int i;
+
+       for (i = 0; i < size; i++)
+               if (val == adxl367_range_scale_tbl[i][0] &&
+                   val2 == adxl367_range_scale_tbl[i][1])
+                       break;
+
+       if (i == size)
+               return -EINVAL;
+
+       *range = i;
+
+       return 0;
+}
+
+static int adxl367_read_sample(struct iio_dev *indio_dev,
+                              struct iio_chan_spec const *chan,
+                              int *val)
+{
+       struct adxl367_state *st = iio_priv(indio_dev);
+       u16 sample;
+       int ret;
+
+       ret = iio_device_claim_direct_mode(indio_dev);
+       if (ret)
+               return ret;
+
+       mutex_lock(&st->lock);
+
+       ret = adxl367_set_temp_adc_reg_en(st, chan->address, true);
+       if (ret)
+               goto out;
+
+       ret = regmap_bulk_read(st->regmap, chan->address, &st->sample_buf,
+                              sizeof(st->sample_buf));
+       if (ret)
+               goto out;
+
+       sample = FIELD_GET(ADXL367_DATA_MASK, be16_to_cpu(st->sample_buf));
+       *val = sign_extend32(sample, chan->scan_type.realbits - 1);
+
+       ret = adxl367_set_temp_adc_reg_en(st, chan->address, false);
+
+out:
+       mutex_unlock(&st->lock);
+
+       iio_device_release_direct_mode(indio_dev);
+
+       return ret ?: IIO_VAL_INT;
+}
+
+static int adxl367_get_status(struct adxl367_state *st, u8 *status,
+                             u16 *fifo_entries)
+{
+       int ret;
+
+       /* Read STATUS, FIFO_ENT_L and FIFO_ENT_H */
+       ret = regmap_bulk_read(st->regmap, ADXL367_REG_STATUS,
+                              st->status_buf, sizeof(st->status_buf));
+       if (ret)
+               return ret;
+
+       st->status_buf[2] &= ADXL367_FIFO_ENT_H_MASK;
+
+       *status = st->status_buf[0];
+       *fifo_entries = get_unaligned_le16(&st->status_buf[1]);
+
+       return 0;
+}
+
+static bool adxl367_push_event(struct iio_dev *indio_dev, u8 status)
+{
+       unsigned int ev_dir;
+
+       if (FIELD_GET(ADXL367_STATUS_ACT_MASK, status))
+               ev_dir = IIO_EV_DIR_RISING;
+       else if (FIELD_GET(ADXL367_STATUS_INACT_MASK, status))
+               ev_dir = IIO_EV_DIR_FALLING;
+       else
+               return false;
+
+       iio_push_event(indio_dev,
+                      IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z,
+                                         IIO_EV_TYPE_THRESH, ev_dir),
+                      iio_get_time_ns(indio_dev));
+
+       return true;
+}
+
+static bool adxl367_push_fifo_data(struct iio_dev *indio_dev, u8 status,
+                                  u16 fifo_entries)
+{
+       struct adxl367_state *st = iio_priv(indio_dev);
+       int ret;
+       int i;
+
+       if (!FIELD_GET(ADXL367_STATUS_FIFO_FULL_MASK, status))
+               return false;
+
+       fifo_entries -= fifo_entries % st->fifo_set_size;
+
+       ret = st->ops->read_fifo(st->context, st->fifo_buf, fifo_entries);
+       if (ret) {
+               dev_err(st->dev, "Failed to read FIFO: %d\n", ret);
+               return true;
+       }
+
+       for (i = 0; i < fifo_entries; i += st->fifo_set_size)
+               iio_push_to_buffers(indio_dev, &st->fifo_buf[i]);
+
+       return true;
+}
+
+static irqreturn_t adxl367_irq_handler(int irq, void *private)
+{
+       struct iio_dev *indio_dev = private;
+       struct adxl367_state *st = iio_priv(indio_dev);
+       u16 fifo_entries;
+       bool handled;
+       u8 status;
+       int ret;
+
+       ret = adxl367_get_status(st, &status, &fifo_entries);
+       if (ret)
+               return IRQ_NONE;
+
+       handled = adxl367_push_event(indio_dev, status);
+       handled |= adxl367_push_fifo_data(indio_dev, status, fifo_entries);
+
+       return handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int adxl367_reg_access(struct iio_dev *indio_dev,
+                             unsigned int reg,
+                             unsigned int writeval,
+                             unsigned int *readval)
+{
+       struct adxl367_state *st = iio_priv(indio_dev);
+
+       if (readval)
+               return regmap_read(st->regmap, reg, readval);
+       else
+               return regmap_write(st->regmap, reg, writeval);
+}
+
+static int adxl367_read_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int *val, int *val2, long info)
+{
+       struct adxl367_state *st = iio_priv(indio_dev);
+
+       switch (info) {
+       case IIO_CHAN_INFO_RAW:
+               return adxl367_read_sample(indio_dev, chan, val);
+       case IIO_CHAN_INFO_SCALE:
+               switch (chan->type) {
+               case IIO_ACCEL:
+                       mutex_lock(&st->lock);
+                       *val = adxl367_range_scale_tbl[st->range][0];
+                       *val2 = adxl367_range_scale_tbl[st->range][1];
+                       mutex_unlock(&st->lock);
+                       return IIO_VAL_INT_PLUS_NANO;
+               case IIO_TEMP:
+                       *val = 1000;
+                       *val2 = ADXL367_TEMP_PER_C;
+                       return IIO_VAL_FRACTIONAL;
+               case IIO_VOLTAGE:
+                       *val = ADXL367_VOLTAGE_MAX_MV;
+                       *val2 = ADXL367_VOLTAGE_MAX_RAW;
+                       return IIO_VAL_FRACTIONAL;
+               default:
+                       return -EINVAL;
+               }
+       case IIO_CHAN_INFO_OFFSET:
+               switch (chan->type) {
+               case IIO_TEMP:
+                       *val = 25 * ADXL367_TEMP_PER_C - ADXL367_TEMP_25C;
+                       return IIO_VAL_INT;
+               case IIO_VOLTAGE:
+                       *val = ADXL367_VOLTAGE_OFFSET;
+                       return IIO_VAL_INT;
+               default:
+                       return -EINVAL;
+               }
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               mutex_lock(&st->lock);
+               *val = adxl367_samp_freq_tbl[st->odr][0];
+               *val2 = adxl367_samp_freq_tbl[st->odr][1];
+               mutex_unlock(&st->lock);
+               return IIO_VAL_INT_PLUS_MICRO;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int adxl367_write_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            int val, int val2, long info)
+{
+       struct adxl367_state *st = iio_priv(indio_dev);
+       int ret;
+
+       switch (info) {
+       case IIO_CHAN_INFO_SAMP_FREQ: {
+               enum adxl367_odr odr;
+
+               ret = adxl367_find_odr(st, val, val2, &odr);
+               if (ret)
+                       return ret;
+
+               return adxl367_set_odr(indio_dev, odr);
+       }
+       case IIO_CHAN_INFO_SCALE: {
+               enum adxl367_range range;
+
+               ret = adxl367_find_range(st, val, val2, &range);
+               if (ret)
+                       return ret;
+
+               return adxl367_set_range(indio_dev, range);
+       }
+       default:
+               return -EINVAL;
+       }
+}
+
+static int adxl367_write_raw_get_fmt(struct iio_dev *indio_dev,
+                                    struct iio_chan_spec const *chan,
+                                    long info)
+{
+       switch (info) {
+       case IIO_CHAN_INFO_SCALE:
+               if (chan->type != IIO_ACCEL)
+                       return -EINVAL;
+
+               return IIO_VAL_INT_PLUS_NANO;
+       default:
+               return IIO_VAL_INT_PLUS_MICRO;
+       }
+}
+
+static int adxl367_read_avail(struct iio_dev *indio_dev,
+                             struct iio_chan_spec const *chan,
+                             const int **vals, int *type, int *length,
+                             long info)
+{
+       switch (info) {
+       case IIO_CHAN_INFO_SCALE:
+               if (chan->type != IIO_ACCEL)
+                       return -EINVAL;
+
+               *vals = (int *)adxl367_range_scale_tbl;
+               *type = IIO_VAL_INT_PLUS_NANO;
+               *length = ARRAY_SIZE(adxl367_range_scale_tbl) * 2;
+               return IIO_AVAIL_LIST;
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               *vals = (int *)adxl367_samp_freq_tbl;
+               *type = IIO_VAL_INT_PLUS_MICRO;
+               *length = ARRAY_SIZE(adxl367_samp_freq_tbl) * 2;
+               return IIO_AVAIL_LIST;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int adxl367_read_event_value(struct iio_dev *indio_dev,
+                                   const struct iio_chan_spec *chan,
+                                   enum iio_event_type type,
+                                   enum iio_event_direction dir,
+                                   enum iio_event_info info,
+                                   int *val, int *val2)
+{
+       struct adxl367_state *st = iio_priv(indio_dev);
+
+       switch (info) {
+       case IIO_EV_INFO_VALUE: {
+               switch (dir) {
+               case IIO_EV_DIR_RISING:
+                       mutex_lock(&st->lock);
+                       *val = st->act_threshold;
+                       mutex_unlock(&st->lock);
+                       return IIO_VAL_INT;
+               case IIO_EV_DIR_FALLING:
+                       mutex_lock(&st->lock);
+                       *val = st->inact_threshold;
+                       mutex_unlock(&st->lock);
+                       return IIO_VAL_INT;
+               default:
+                       return -EINVAL;
+               }
+       }
+       case IIO_EV_INFO_PERIOD:
+               switch (dir) {
+               case IIO_EV_DIR_RISING:
+                       mutex_lock(&st->lock);
+                       *val = st->act_time_ms;
+                       mutex_unlock(&st->lock);
+                       *val2 = 1000;
+                       return IIO_VAL_FRACTIONAL;
+               case IIO_EV_DIR_FALLING:
+                       mutex_lock(&st->lock);
+                       *val = st->inact_time_ms;
+                       mutex_unlock(&st->lock);
+                       *val2 = 1000;
+                       return IIO_VAL_FRACTIONAL;
+               default:
+                       return -EINVAL;
+               }
+       default:
+               return -EINVAL;
+       }
+}
+
+static int adxl367_write_event_value(struct iio_dev *indio_dev,
+                                    const struct iio_chan_spec *chan,
+                                    enum iio_event_type type,
+                                    enum iio_event_direction dir,
+                                    enum iio_event_info info,
+                                    int val, int val2)
+{
+       struct adxl367_state *st = iio_priv(indio_dev);
+
+       switch (info) {
+       case IIO_EV_INFO_VALUE:
+               if (val < 0)
+                       return -EINVAL;
+
+               switch (dir) {
+               case IIO_EV_DIR_RISING:
+                       return adxl367_set_act_threshold(st, ADXL367_ACTIVITY, val);
+               case IIO_EV_DIR_FALLING:
+                       return adxl367_set_act_threshold(st, ADXL367_INACTIVITY, val);
+               default:
+                       return -EINVAL;
+               }
+       case IIO_EV_INFO_PERIOD:
+               if (val < 0)
+                       return -EINVAL;
+
+               val = val * 1000 + DIV_ROUND_UP(val2, 1000);
+               switch (dir) {
+               case IIO_EV_DIR_RISING:
+                       return adxl367_set_act_time_ms(st, ADXL367_ACTIVITY, val);
+               case IIO_EV_DIR_FALLING:
+                       return adxl367_set_act_time_ms(st, ADXL367_INACTIVITY, val);
+               default:
+                       return -EINVAL;
+               }
+       default:
+               return -EINVAL;
+       }
+}
+
+static int adxl367_read_event_config(struct iio_dev *indio_dev,
+                                    const struct iio_chan_spec *chan,
+                                    enum iio_event_type type,
+                                    enum iio_event_direction dir)
+{
+       struct adxl367_state *st = iio_priv(indio_dev);
+       bool en;
+       int ret;
+
+       switch (dir) {
+       case IIO_EV_DIR_RISING:
+               ret = adxl367_get_act_interrupt_en(st, ADXL367_ACTIVITY, &en);
+               return ret ?: en;
+       case IIO_EV_DIR_FALLING:
+               ret = adxl367_get_act_interrupt_en(st, ADXL367_INACTIVITY, &en);
+               return ret ?: en;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int adxl367_write_event_config(struct iio_dev *indio_dev,
+                                     const struct iio_chan_spec *chan,
+                                     enum iio_event_type type,
+                                     enum iio_event_direction dir,
+                                     int state)
+{
+       struct adxl367_state *st = iio_priv(indio_dev);
+       enum adxl367_activity_type act;
+       int ret;
+
+       switch (dir) {
+       case IIO_EV_DIR_RISING:
+               act = ADXL367_ACTIVITY;
+               break;
+       case IIO_EV_DIR_FALLING:
+               act = ADXL367_INACTIVITY;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = iio_device_claim_direct_mode(indio_dev);
+       if (ret)
+               return ret;
+
+       mutex_lock(&st->lock);
+
+       ret = adxl367_set_measure_en(st, false);
+       if (ret)
+               goto out;
+
+       ret = adxl367_set_act_interrupt_en(st, act, state);
+       if (ret)
+               goto out;
+
+       ret = adxl367_set_act_en(st, act, state ? ADCL367_ACT_REF_ENABLED
+                                               : ADXL367_ACT_DISABLED);
+       if (ret)
+               goto out;
+
+       ret = adxl367_set_measure_en(st, true);
+
+out:
+       mutex_unlock(&st->lock);
+
+       iio_device_release_direct_mode(indio_dev);
+
+       return ret;
+}
+
+static ssize_t adxl367_get_fifo_enabled(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct adxl367_state *st = iio_priv(dev_to_iio_dev(dev));
+       enum adxl367_fifo_mode fifo_mode;
+       int ret;
+
+       ret = adxl367_get_fifo_mode(st, &fifo_mode);
+       if (ret)
+               return ret;
+
+       return sysfs_emit(buf, "%d\n", fifo_mode != ADXL367_FIFO_MODE_DISABLED);
+}
+
+static ssize_t adxl367_get_fifo_watermark(struct device *dev,
+                                         struct device_attribute *attr,
+                                         char *buf)
+{
+       struct adxl367_state *st = iio_priv(dev_to_iio_dev(dev));
+       unsigned int fifo_watermark;
+
+       mutex_lock(&st->lock);
+       fifo_watermark = st->fifo_watermark;
+       mutex_unlock(&st->lock);
+
+       return sysfs_emit(buf, "%d\n", fifo_watermark);
+}
+
+static IIO_CONST_ATTR(hwfifo_watermark_min, "1");
+static IIO_CONST_ATTR(hwfifo_watermark_max,
+                     __stringify(ADXL367_FIFO_MAX_WATERMARK));
+static IIO_DEVICE_ATTR(hwfifo_watermark, 0444,
+                      adxl367_get_fifo_watermark, NULL, 0);
+static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
+                      adxl367_get_fifo_enabled, NULL, 0);
+
+static const struct attribute *adxl367_fifo_attributes[] = {
+       &iio_const_attr_hwfifo_watermark_min.dev_attr.attr,
+       &iio_const_attr_hwfifo_watermark_max.dev_attr.attr,
+       &iio_dev_attr_hwfifo_watermark.dev_attr.attr,
+       &iio_dev_attr_hwfifo_enabled.dev_attr.attr,
+       NULL,
+};
+
+static int adxl367_set_watermark(struct iio_dev *indio_dev, unsigned int val)
+{
+       struct adxl367_state *st  = iio_priv(indio_dev);
+       int ret;
+
+       if (val > ADXL367_FIFO_MAX_WATERMARK)
+               return -EINVAL;
+
+       mutex_lock(&st->lock);
+
+       ret = adxl367_set_measure_en(st, false);
+       if (ret)
+               goto out;
+
+       ret = adxl367_set_fifo_watermark(st, val);
+       if (ret)
+               goto out;
+
+       ret = adxl367_set_measure_en(st, true);
+
+out:
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static bool adxl367_find_mask_fifo_format(const unsigned long *scan_mask,
+                                         enum adxl367_fifo_format *fifo_format)
+{
+       size_t size = ARRAY_SIZE(adxl367_fifo_formats);
+       int i;
+
+       for (i = 0; i < size; i++)
+               if (*scan_mask == adxl367_channel_masks[i])
+                       break;
+
+       if (i == size)
+               return false;
+
+       *fifo_format = adxl367_fifo_formats[i];
+
+       return true;
+}
+
+static int adxl367_update_scan_mode(struct iio_dev *indio_dev,
+                                   const unsigned long *active_scan_mask)
+{
+       struct adxl367_state *st  = iio_priv(indio_dev);
+       enum adxl367_fifo_format fifo_format;
+       unsigned int fifo_set_size;
+       int ret;
+
+       if (!adxl367_find_mask_fifo_format(active_scan_mask, &fifo_format))
+               return -EINVAL;
+
+       fifo_set_size = bitmap_weight(active_scan_mask, indio_dev->masklength);
+
+       mutex_lock(&st->lock);
+
+       ret = adxl367_set_measure_en(st, false);
+       if (ret)
+               goto out;
+
+       ret = adxl367_set_fifo_format(st, fifo_format);
+       if (ret)
+               goto out;
+
+       ret = adxl367_set_fifo_set_size(st, fifo_set_size);
+       if (ret)
+               goto out;
+
+       ret = adxl367_set_measure_en(st, true);
+
+out:
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static int adxl367_buffer_postenable(struct iio_dev *indio_dev)
+{
+       struct adxl367_state *st = iio_priv(indio_dev);
+       int ret;
+
+       mutex_lock(&st->lock);
+
+       ret = adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask,
+                                          true);
+       if (ret)
+               goto out;
+
+       ret = adxl367_set_measure_en(st, false);
+       if (ret)
+               goto out;
+
+       ret = adxl367_set_fifo_watermark_interrupt_en(st, true);
+       if (ret)
+               goto out;
+
+       ret = adxl367_set_fifo_mode(st, ADXL367_FIFO_MODE_STREAM);
+       if (ret)
+               goto out;
+
+       ret = adxl367_set_measure_en(st, true);
+
+out:
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static int adxl367_buffer_predisable(struct iio_dev *indio_dev)
+{
+       struct adxl367_state *st = iio_priv(indio_dev);
+       int ret;
+
+       mutex_lock(&st->lock);
+
+       ret = adxl367_set_measure_en(st, false);
+       if (ret)
+               goto out;
+
+       ret = adxl367_set_fifo_mode(st, ADXL367_FIFO_MODE_DISABLED);
+       if (ret)
+               goto out;
+
+       ret = adxl367_set_fifo_watermark_interrupt_en(st, false);
+       if (ret)
+               goto out;
+
+       ret = adxl367_set_measure_en(st, true);
+       if (ret)
+               goto out;
+
+       ret = adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask,
+                                          false);
+
+out:
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static const struct iio_buffer_setup_ops adxl367_buffer_ops = {
+       .postenable = adxl367_buffer_postenable,
+       .predisable = adxl367_buffer_predisable,
+};
+
+static const struct iio_info adxl367_info = {
+       .read_raw = adxl367_read_raw,
+       .write_raw = adxl367_write_raw,
+       .write_raw_get_fmt = adxl367_write_raw_get_fmt,
+       .read_avail = adxl367_read_avail,
+       .read_event_config = adxl367_read_event_config,
+       .write_event_config = adxl367_write_event_config,
+       .read_event_value = adxl367_read_event_value,
+       .write_event_value = adxl367_write_event_value,
+       .debugfs_reg_access = adxl367_reg_access,
+       .hwfifo_set_watermark = adxl367_set_watermark,
+       .update_scan_mode = adxl367_update_scan_mode,
+};
+
+static const struct iio_event_spec adxl367_events[] = {
+       {
+               .type = IIO_EV_TYPE_MAG_REFERENCED,
+               .dir = IIO_EV_DIR_RISING,
+               .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) |
+                                      BIT(IIO_EV_INFO_PERIOD) |
+                                      BIT(IIO_EV_INFO_VALUE),
+       },
+       {
+               .type = IIO_EV_TYPE_MAG_REFERENCED,
+               .dir = IIO_EV_DIR_FALLING,
+               .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) |
+                                      BIT(IIO_EV_INFO_PERIOD) |
+                                      BIT(IIO_EV_INFO_VALUE),
+       },
+};
+
+#define ADXL367_ACCEL_CHANNEL(index, reg, axis) {                      \
+       .type = IIO_ACCEL,                                              \
+       .address = (reg),                                               \
+       .modified = 1,                                                  \
+       .channel2 = IIO_MOD_##axis,                                     \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),                   \
+       .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),           \
+       .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \
+       .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),        \
+       .info_mask_shared_by_all_available =                            \
+                       BIT(IIO_CHAN_INFO_SAMP_FREQ),                   \
+       .event_spec = adxl367_events,                                   \
+       .num_event_specs = ARRAY_SIZE(adxl367_events),                  \
+       .scan_index = (index),                                          \
+       .scan_type = {                                                  \
+               .sign = 's',                                            \
+               .realbits = 14,                                         \
+               .storagebits = 16,                                      \
+               .endianness = IIO_BE,                                   \
+       },                                                              \
+}
+
+#define ADXL367_CHANNEL(index, reg, _type) {                           \
+       .type = (_type),                                                \
+       .address = (reg),                                               \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |                  \
+                             BIT(IIO_CHAN_INFO_OFFSET) |               \
+                             BIT(IIO_CHAN_INFO_SCALE),                 \
+       .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),        \
+       .scan_index = (index),                                          \
+       .scan_type = {                                                  \
+               .sign = 's',                                            \
+               .realbits = 14,                                         \
+               .storagebits = 16,                                      \
+               .endianness = IIO_BE,                                   \
+       },                                                              \
+}
+
+static const struct iio_chan_spec adxl367_channels[] = {
+       ADXL367_ACCEL_CHANNEL(ADXL367_X_CHANNEL_INDEX, ADXL367_REG_X_DATA_H, X),
+       ADXL367_ACCEL_CHANNEL(ADXL367_Y_CHANNEL_INDEX, ADXL367_REG_Y_DATA_H, Y),
+       ADXL367_ACCEL_CHANNEL(ADXL367_Z_CHANNEL_INDEX, ADXL367_REG_Z_DATA_H, Z),
+       ADXL367_CHANNEL(ADXL367_TEMP_CHANNEL_INDEX, ADXL367_REG_TEMP_DATA_H,
+                       IIO_TEMP),
+       ADXL367_CHANNEL(ADXL367_EX_ADC_CHANNEL_INDEX, ADXL367_REG_EX_ADC_DATA_H,
+                       IIO_VOLTAGE),
+};
+
+static int adxl367_verify_devid(struct adxl367_state *st)
+{
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read_poll_timeout(st->regmap, ADXL367_REG_DEVID, val,
+                                      val == ADXL367_DEVID_AD, 1000, 10000);
+       if (ret)
+               return dev_err_probe(st->dev, -ENODEV,
+                                    "Invalid dev id 0x%02X, expected 0x%02X\n",
+                                    val, ADXL367_DEVID_AD);
+
+       return 0;
+}
+
+static int adxl367_setup(struct adxl367_state *st)
+{
+       int ret;
+
+       ret = _adxl367_set_act_threshold(st, ADXL367_ACTIVITY,
+                                        ADXL367_2G_RANGE_1G);
+       if (ret)
+               return ret;
+
+       ret = _adxl367_set_act_threshold(st, ADXL367_INACTIVITY,
+                                        ADXL367_2G_RANGE_100MG);
+       if (ret)
+               return ret;
+
+       ret = adxl367_set_act_proc_mode(st, ADXL367_LOOPED);
+       if (ret)
+               return ret;
+
+       ret = _adxl367_set_odr(st, ADXL367_ODR_400HZ);
+       if (ret)
+               return ret;
+
+       ret = _adxl367_set_act_time_ms(st, 10);
+       if (ret)
+               return ret;
+
+       ret = _adxl367_set_inact_time_ms(st, 10000);
+       if (ret)
+               return ret;
+
+       return adxl367_set_measure_en(st, true);
+}
+
+static void adxl367_disable_regulators(void *data)
+{
+       struct adxl367_state *st = data;
+
+       regulator_bulk_disable(ARRAY_SIZE(st->regulators), st->regulators);
+}
+
+int adxl367_probe(struct device *dev, const struct adxl367_ops *ops,
+                 void *context, struct regmap *regmap, int irq)
+{
+       struct iio_dev *indio_dev;
+       struct adxl367_state *st;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       st = iio_priv(indio_dev);
+       st->dev = dev;
+       st->regmap = regmap;
+       st->context = context;
+       st->ops = ops;
+
+       mutex_init(&st->lock);
+
+       indio_dev->channels = adxl367_channels;
+       indio_dev->num_channels = ARRAY_SIZE(adxl367_channels);
+       indio_dev->available_scan_masks = adxl367_channel_masks;
+       indio_dev->name = "adxl367";
+       indio_dev->info = &adxl367_info;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+
+       st->regulators[0].supply = "vdd";
+       st->regulators[1].supply = "vddio";
+
+       ret = devm_regulator_bulk_get(st->dev, ARRAY_SIZE(st->regulators),
+                                     st->regulators);
+       if (ret)
+               return dev_err_probe(st->dev, ret,
+                                    "Failed to get regulators\n");
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(st->regulators), st->regulators);
+       if (ret)
+               return dev_err_probe(st->dev, ret,
+                                    "Failed to enable regulators\n");
+
+       ret = devm_add_action_or_reset(st->dev, adxl367_disable_regulators, st);
+       if (ret)
+               return dev_err_probe(st->dev, ret,
+                                    "Failed to add regulators disable action\n");
+
+       ret = regmap_write(st->regmap, ADXL367_REG_RESET, ADXL367_RESET_CODE);
+       if (ret)
+               return ret;
+
+       ret = adxl367_verify_devid(st);
+       if (ret)
+               return ret;
+
+       ret = adxl367_setup(st);
+       if (ret)
+               return ret;
+
+       ret = devm_iio_kfifo_buffer_setup_ext(st->dev, indio_dev,
+                                             INDIO_BUFFER_SOFTWARE,
+                                             &adxl367_buffer_ops,
+                                             adxl367_fifo_attributes);
+       if (ret)
+               return ret;
+
+       ret = devm_request_threaded_irq(st->dev, irq, NULL,
+                                       adxl367_irq_handler, IRQF_ONESHOT,
+                                       indio_dev->name, indio_dev);
+       if (ret)
+               return dev_err_probe(st->dev, ret, "Failed to request irq\n");
+
+       return devm_iio_device_register(dev, indio_dev);
+}
+EXPORT_SYMBOL_NS_GPL(adxl367_probe, IIO_ADXL367);
+
+MODULE_AUTHOR("Cosmin Tanislav <[email protected]>");
+MODULE_DESCRIPTION("Analog Devices ADXL367 3-axis accelerometer driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/accel/adxl367.h b/drivers/iio/accel/adxl367.h
new file mode 100644 (file)
index 0000000..4a42622
--- /dev/null
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2021 Analog Devices, Inc.
+ * Author: Cosmin Tanislav <[email protected]>
+ */
+
+#ifndef _ADXL367_H_
+#define _ADXL367_H_
+
+#include <linux/types.h>
+
+struct device;
+struct regmap;
+
+struct adxl367_ops {
+       int (*read_fifo)(void *context, __be16 *fifo_buf,
+                        unsigned int fifo_entries);
+};
+
+int adxl367_probe(struct device *dev, const struct adxl367_ops *ops,
+                 void *context, struct regmap *regmap, int irq);
+
+#endif /* _ADXL367_H_ */
diff --git a/drivers/iio/accel/adxl367_i2c.c b/drivers/iio/accel/adxl367_i2c.c
new file mode 100644 (file)
index 0000000..3606efa
--- /dev/null
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021 Analog Devices, Inc.
+ * Author: Cosmin Tanislav <[email protected]>
+ */
+
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "adxl367.h"
+
+#define ADXL367_I2C_FIFO_DATA  0x42
+
+struct adxl367_i2c_state {
+       struct regmap *regmap;
+};
+
+static bool adxl367_readable_noinc_reg(struct device *dev, unsigned int reg)
+{
+       return reg == ADXL367_I2C_FIFO_DATA;
+}
+
+static int adxl367_i2c_read_fifo(void *context, __be16 *fifo_buf,
+                                unsigned int fifo_entries)
+{
+       struct adxl367_i2c_state *st = context;
+
+       return regmap_noinc_read(st->regmap, ADXL367_I2C_FIFO_DATA, fifo_buf,
+                                fifo_entries * sizeof(*fifo_buf));
+}
+
+static const struct regmap_config adxl367_i2c_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .readable_noinc_reg = adxl367_readable_noinc_reg,
+};
+
+static const struct adxl367_ops adxl367_i2c_ops = {
+       .read_fifo = adxl367_i2c_read_fifo,
+};
+
+static int adxl367_i2c_probe(struct i2c_client *client,
+                            const struct i2c_device_id *id)
+{
+       struct adxl367_i2c_state *st;
+       struct regmap *regmap;
+
+       st = devm_kzalloc(&client->dev, sizeof(*st), GFP_KERNEL);
+       if (!st)
+               return -ENOMEM;
+
+       regmap = devm_regmap_init_i2c(client, &adxl367_i2c_regmap_config);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       st->regmap = regmap;
+
+       return adxl367_probe(&client->dev, &adxl367_i2c_ops, st, regmap,
+                            client->irq);
+}
+
+static const struct i2c_device_id adxl367_i2c_id[] = {
+       { "adxl367", 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, adxl367_i2c_id);
+
+static const struct of_device_id adxl367_of_match[] = {
+       { .compatible = "adi,adxl367" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, adxl367_of_match);
+
+static struct i2c_driver adxl367_i2c_driver = {
+       .driver = {
+               .name = "adxl367_i2c",
+               .of_match_table = adxl367_of_match,
+       },
+       .probe = adxl367_i2c_probe,
+       .id_table = adxl367_i2c_id,
+};
+
+module_i2c_driver(adxl367_i2c_driver);
+
+MODULE_IMPORT_NS(IIO_ADXL367);
+MODULE_AUTHOR("Cosmin Tanislav <[email protected]>");
+MODULE_DESCRIPTION("Analog Devices ADXL367 3-axis accelerometer I2C driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/accel/adxl367_spi.c b/drivers/iio/accel/adxl367_spi.c
new file mode 100644 (file)
index 0000000..26dfc82
--- /dev/null
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021 Analog Devices, Inc.
+ * Author: Cosmin Tanislav <[email protected]>
+ */
+
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "adxl367.h"
+
+#define ADXL367_SPI_WRITE_COMMAND      0x0A
+#define ADXL367_SPI_READ_COMMAND       0x0B
+#define ADXL367_SPI_FIFO_COMMAND       0x0D
+
+struct adxl367_spi_state {
+       struct spi_device       *spi;
+
+       struct spi_message      reg_write_msg;
+       struct spi_transfer     reg_write_xfer[2];
+
+       struct spi_message      reg_read_msg;
+       struct spi_transfer     reg_read_xfer[2];
+
+       struct spi_message      fifo_msg;
+       struct spi_transfer     fifo_xfer[2];
+
+       /*
+        * DMA (thus cache coherency maintenance) requires the
+        * transfer buffers to live in their own cache lines.
+        */
+       u8                      reg_write_tx_buf[1] ____cacheline_aligned;
+       u8                      reg_read_tx_buf[2];
+       u8                      fifo_tx_buf[1];
+};
+
+static int adxl367_read_fifo(void *context, __be16 *fifo_buf,
+                            unsigned int fifo_entries)
+{
+       struct adxl367_spi_state *st = context;
+
+       st->fifo_xfer[1].rx_buf = fifo_buf;
+       st->fifo_xfer[1].len = fifo_entries * sizeof(*fifo_buf);
+
+       return spi_sync(st->spi, &st->fifo_msg);
+}
+
+static int adxl367_read(void *context, const void *reg_buf, size_t reg_size,
+                       void *val_buf, size_t val_size)
+{
+       struct adxl367_spi_state *st = context;
+       u8 reg = ((const u8 *)reg_buf)[0];
+
+       st->reg_read_tx_buf[1] = reg;
+       st->reg_read_xfer[1].rx_buf = val_buf;
+       st->reg_read_xfer[1].len = val_size;
+
+       return spi_sync(st->spi, &st->reg_read_msg);
+}
+
+static int adxl367_write(void *context, const void *val_buf, size_t val_size)
+{
+       struct adxl367_spi_state *st = context;
+
+       st->reg_write_xfer[1].tx_buf = val_buf;
+       st->reg_write_xfer[1].len = val_size;
+
+       return spi_sync(st->spi, &st->reg_write_msg);
+}
+
+static struct regmap_bus adxl367_spi_regmap_bus = {
+       .read = adxl367_read,
+       .write = adxl367_write,
+};
+
+static const struct regmap_config adxl367_spi_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+};
+
+static const struct adxl367_ops adxl367_spi_ops = {
+       .read_fifo = adxl367_read_fifo,
+};
+
+static int adxl367_spi_probe(struct spi_device *spi)
+{
+       struct adxl367_spi_state *st;
+       struct regmap *regmap;
+
+       st = devm_kzalloc(&spi->dev, sizeof(*st), GFP_KERNEL);
+       if (!st)
+               return -ENOMEM;
+
+       st->spi = spi;
+
+       /*
+        * Xfer:   [XFR1] [           XFR2           ]
+        * Master:  0x0A   ADDR DATA0 DATA1 ... DATAN
+        * Slave:   ....   ..........................
+        */
+       st->reg_write_tx_buf[0] = ADXL367_SPI_WRITE_COMMAND;
+       st->reg_write_xfer[0].tx_buf = st->reg_write_tx_buf;
+       st->reg_write_xfer[0].len = sizeof(st->reg_write_tx_buf);
+       spi_message_init_with_transfers(&st->reg_write_msg,
+                                       st->reg_write_xfer, 2);
+
+       /*
+        * Xfer:   [   XFR1  ] [         XFR2        ]
+        * Master:  0x0B ADDR   .....................
+        * Slave:   .........   DATA0 DATA1 ... DATAN
+        */
+       st->reg_read_tx_buf[0] = ADXL367_SPI_READ_COMMAND;
+       st->reg_read_xfer[0].tx_buf = st->reg_read_tx_buf;
+       st->reg_read_xfer[0].len = sizeof(st->reg_read_tx_buf);
+       spi_message_init_with_transfers(&st->reg_read_msg,
+                                       st->reg_read_xfer, 2);
+
+       /*
+        * Xfer:   [XFR1] [         XFR2        ]
+        * Master:  0x0D   .....................
+        * Slave:   ....   DATA0 DATA1 ... DATAN
+        */
+       st->fifo_tx_buf[0] = ADXL367_SPI_FIFO_COMMAND;
+       st->fifo_xfer[0].tx_buf = st->fifo_tx_buf;
+       st->fifo_xfer[0].len = sizeof(st->fifo_tx_buf);
+       spi_message_init_with_transfers(&st->fifo_msg, st->fifo_xfer, 2);
+
+       regmap = devm_regmap_init(&spi->dev, &adxl367_spi_regmap_bus, st,
+                                 &adxl367_spi_regmap_config);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       return adxl367_probe(&spi->dev, &adxl367_spi_ops, st, regmap, spi->irq);
+}
+
+static const struct spi_device_id adxl367_spi_id[] = {
+       { "adxl367", 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(spi, adxl367_spi_id);
+
+static const struct of_device_id adxl367_of_match[] = {
+       { .compatible = "adi,adxl367" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, adxl367_of_match);
+
+static struct spi_driver adxl367_spi_driver = {
+       .driver = {
+               .name = "adxl367_spi",
+               .of_match_table = adxl367_of_match,
+       },
+       .probe = adxl367_spi_probe,
+       .id_table = adxl367_spi_id,
+};
+
+module_spi_driver(adxl367_spi_driver);
+
+MODULE_IMPORT_NS(IIO_ADXL367);
+MODULE_AUTHOR("Cosmin Tanislav <[email protected]>");
+MODULE_DESCRIPTION("Analog Devices ADXL367 3-axis accelerometer SPI driver");
+MODULE_LICENSE("GPL");
index 758952584f8cfd6eef7132e8d583980651d043ad..e3ecbaee61f704797d3df8eedb5b9da113ebcfe1 100644 (file)
@@ -1176,7 +1176,7 @@ bool adxl372_readable_noinc_reg(struct device *dev, unsigned int reg)
 {
        return (reg == ADXL372_FIFO_DATA);
 }
-EXPORT_SYMBOL_GPL(adxl372_readable_noinc_reg);
+EXPORT_SYMBOL_NS_GPL(adxl372_readable_noinc_reg, IIO_ADXL372);
 
 int adxl372_probe(struct device *dev, struct regmap *regmap,
                  int irq, const char *name)
@@ -1260,7 +1260,7 @@ int adxl372_probe(struct device *dev, struct regmap *regmap,
 
        return devm_iio_device_register(dev, indio_dev);
 }
-EXPORT_SYMBOL_GPL(adxl372_probe);
+EXPORT_SYMBOL_NS_GPL(adxl372_probe, IIO_ADXL372);
 
 MODULE_AUTHOR("Stefan Popa <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer driver");
index 9a07ab3d151af405815199c5512990fa0f013c5c..4efb70a5fe40546a406c08d47276ca3bc30391c5 100644 (file)
@@ -67,3 +67,4 @@ module_i2c_driver(adxl372_i2c_driver);
 MODULE_AUTHOR("Stefan Popa <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer I2C driver");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_ADXL372);
index 1f1352fee99a3de150a840752fea4fea811083da..2bd267a22f296f8912b1b03babd51a7a44f19293 100644 (file)
@@ -59,3 +59,4 @@ module_spi_driver(adxl372_spi_driver);
 MODULE_AUTHOR("Stefan Popa <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer SPI driver");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_ADXL372);
index d8a454c266d5f59bea189687fa59f55a984902cb..4f73bc827eecb18d4f1348e73486633b7a8e9a48 100644 (file)
@@ -1065,7 +1065,6 @@ static int bma180_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int bma180_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
@@ -1092,11 +1091,7 @@ static int bma180_resume(struct device *dev)
        return ret;
 }
 
-static SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume);
-#define BMA180_PM_OPS (&bma180_pm_ops)
-#else
-#define BMA180_PM_OPS NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume);
 
 static const struct i2c_device_id bma180_ids[] = {
        { "bma023", BMA023 },
@@ -1137,7 +1132,7 @@ MODULE_DEVICE_TABLE(of, bma180_of_match);
 static struct i2c_driver bma180_driver = {
        .driver = {
                .name   = "bma180",
-               .pm     = BMA180_PM_OPS,
+               .pm     = pm_sleep_ptr(&bma180_pm_ops),
                .of_match_table = bma180_of_match,
        },
        .probe          = bma180_probe,
index fd2647b728d3d052f769e6e42c71d20cd8652015..043002fe6f6337d976aaceab3c0e38198ad9ba5f 100644 (file)
@@ -136,7 +136,7 @@ const struct regmap_config bma400_regmap_config = {
        .writeable_reg = bma400_is_writable_reg,
        .volatile_reg = bma400_is_volatile_reg,
 };
-EXPORT_SYMBOL(bma400_regmap_config);
+EXPORT_SYMBOL_NS(bma400_regmap_config, IIO_BMA400);
 
 static const struct iio_mount_matrix *
 bma400_accel_get_mount_matrix(const struct iio_dev *indio_dev,
@@ -826,7 +826,7 @@ int bma400_probe(struct device *dev, struct regmap *regmap, const char *name)
 
        return iio_device_register(indio_dev);
 }
-EXPORT_SYMBOL(bma400_probe);
+EXPORT_SYMBOL_NS(bma400_probe, IIO_BMA400);
 
 void bma400_remove(struct device *dev)
 {
@@ -846,7 +846,7 @@ void bma400_remove(struct device *dev)
 
        iio_device_unregister(indio_dev);
 }
-EXPORT_SYMBOL(bma400_remove);
+EXPORT_SYMBOL_NS(bma400_remove, IIO_BMA400);
 
 MODULE_AUTHOR("Dan Robertson <[email protected]>");
 MODULE_DESCRIPTION("Bosch BMA400 triaxial acceleration sensor core");
index f50df5310bebf5c6e8a94cf7280d6ca9819af111..da104ffd3fe076e081cad48a5d1bf27cc40cf491 100644 (file)
@@ -61,3 +61,4 @@ module_i2c_driver(bma400_i2c_driver);
 MODULE_AUTHOR("Dan Robertson <[email protected]>");
 MODULE_DESCRIPTION("Bosch BMA400 triaxial acceleration sensor (I2C)");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_BMA400);
index 9f622e37477b4a22da9321f3539086082675066b..23f3a8ab30bda9c7477927d0cd54ab0ac1eaa346 100644 (file)
@@ -120,3 +120,4 @@ module_spi_driver(bma400_spi_driver);
 MODULE_AUTHOR("Dan Robertson <[email protected]>");
 MODULE_DESCRIPTION("Bosch BMA400 triaxial acceleration sensor (SPI)");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_BMA400);
index d11f668016a6aa8ea5a1a5500f63b94b8ebba0fd..7516d7dde1af477649d4b7afff575621bb278c73 100644 (file)
@@ -203,7 +203,7 @@ const struct regmap_config bmc150_regmap_conf = {
        .val_bits = 8,
        .max_register = 0x3f,
 };
-EXPORT_SYMBOL_GPL(bmc150_regmap_conf);
+EXPORT_SYMBOL_NS_GPL(bmc150_regmap_conf, IIO_BMC150);
 
 static int bmc150_accel_set_mode(struct bmc150_accel_data *data,
                                 enum bmc150_power_modes mode,
@@ -1801,7 +1801,7 @@ err_disable_regulators:
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(bmc150_accel_core_probe);
+EXPORT_SYMBOL_NS_GPL(bmc150_accel_core_probe, IIO_BMC150);
 
 void bmc150_accel_core_remove(struct device *dev)
 {
@@ -1824,7 +1824,7 @@ void bmc150_accel_core_remove(struct device *dev)
        regulator_bulk_disable(ARRAY_SIZE(data->regulators),
                               data->regulators);
 }
-EXPORT_SYMBOL_GPL(bmc150_accel_core_remove);
+EXPORT_SYMBOL_NS_GPL(bmc150_accel_core_remove, IIO_BMC150);
 
 #ifdef CONFIG_PM_SLEEP
 static int bmc150_accel_suspend(struct device *dev)
@@ -1899,7 +1899,7 @@ const struct dev_pm_ops bmc150_accel_pm_ops = {
        SET_RUNTIME_PM_OPS(bmc150_accel_runtime_suspend,
                           bmc150_accel_runtime_resume, NULL)
 };
-EXPORT_SYMBOL_GPL(bmc150_accel_pm_ops);
+EXPORT_SYMBOL_NS_GPL(bmc150_accel_pm_ops, IIO_BMC150);
 
 MODULE_AUTHOR("Srinivas Pandruvada <[email protected]>");
 MODULE_LICENSE("GPL v2");
index 9e52df9a8f07795694d0f392d23207049a3fd0fa..dff4d7dd101c678f9f0fc4f8399fde07f30fdf14 100644 (file)
@@ -280,3 +280,4 @@ module_i2c_driver(bmc150_accel_driver);
 MODULE_AUTHOR("Srinivas Pandruvada <[email protected]>");
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("BMC150 I2C accelerometer driver");
+MODULE_IMPORT_NS(IIO_BMC150);
index 11559567cb398dcfaee86e05ff6a1f0eba2c4218..000632c52800cd83c42b24d4dd28fec74a7f38ea 100644 (file)
@@ -84,3 +84,4 @@ module_spi_driver(bmc150_accel_driver);
 MODULE_AUTHOR("Markus Pargmann <[email protected]>");
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("BMC150 SPI accelerometer driver");
+MODULE_IMPORT_NS(IIO_BMC150);
index d74465214feb85e33ecc88539945a6506ac45500..8b2728bbcaded937ee2e1d55ecb7c6c565463551 100644 (file)
@@ -146,7 +146,7 @@ const struct regmap_config bmi088_regmap_conf = {
        .volatile_table = &bmi088_volatile_table,
        .cache_type = REGCACHE_RBTREE,
 };
-EXPORT_SYMBOL_GPL(bmi088_regmap_conf);
+EXPORT_SYMBOL_NS_GPL(bmi088_regmap_conf, IIO_BMI088);
 
 static int bmi088_accel_power_up(struct bmi088_accel_data *data)
 {
@@ -533,7 +533,7 @@ int bmi088_accel_core_probe(struct device *dev, struct regmap *regmap,
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(bmi088_accel_core_probe);
+EXPORT_SYMBOL_NS_GPL(bmi088_accel_core_probe, IIO_BMI088);
 
 
 void bmi088_accel_core_remove(struct device *dev)
@@ -547,7 +547,7 @@ void bmi088_accel_core_remove(struct device *dev)
        pm_runtime_set_suspended(dev);
        bmi088_accel_power_down(data);
 }
-EXPORT_SYMBOL_GPL(bmi088_accel_core_remove);
+EXPORT_SYMBOL_NS_GPL(bmi088_accel_core_remove, IIO_BMI088);
 
 static int __maybe_unused bmi088_accel_runtime_suspend(struct device *dev)
 {
@@ -571,7 +571,7 @@ const struct dev_pm_ops bmi088_accel_pm_ops = {
        SET_RUNTIME_PM_OPS(bmi088_accel_runtime_suspend,
                           bmi088_accel_runtime_resume, NULL)
 };
-EXPORT_SYMBOL_GPL(bmi088_accel_pm_ops);
+EXPORT_SYMBOL_NS_GPL(bmi088_accel_pm_ops, IIO_BMI088);
 
 MODULE_AUTHOR("Niek van Agt <[email protected]>");
 MODULE_LICENSE("GPL v2");
index 758ad2f128962b37de2027669b0ae2c1ecacdd96..961e87a927c450aeb97400ecc0889a879b9b0d06 100644 (file)
@@ -83,3 +83,4 @@ module_spi_driver(bmi088_accel_driver);
 MODULE_AUTHOR("Niek van Agt <[email protected]>");
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("BMI088 accelerometer driver (SPI)");
+MODULE_IMPORT_NS(IIO_BMI088);
index 9633bdae5fd43f08b780c625ebe021e131723ae5..04e9c567896474bc89f95f95e442c54526695ea0 100644 (file)
@@ -153,7 +153,6 @@ static int da280_probe(struct i2c_client *client,
        return devm_iio_device_register(&client->dev, indio_dev);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int da280_suspend(struct device *dev)
 {
        return da280_enable(to_i2c_client(dev), false);
@@ -163,9 +162,8 @@ static int da280_resume(struct device *dev)
 {
        return da280_enable(to_i2c_client(dev), true);
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(da280_pm_ops, da280_suspend, da280_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(da280_pm_ops, da280_suspend, da280_resume);
 
 static const struct acpi_device_id da280_acpi_match[] = {
        {"MIRAACC", da280},
@@ -184,7 +182,7 @@ static struct i2c_driver da280_driver = {
        .driver = {
                .name = "da280",
                .acpi_match_table = ACPI_PTR(da280_acpi_match),
-               .pm = &da280_pm_ops,
+               .pm = pm_sleep_ptr(&da280_pm_ops),
        },
        .probe          = da280_probe,
        .id_table       = da280_i2c_id,
index 04e13487e706ff9ff9bd8a8b5c31b26175f57652..ec4e29d260f7ec61b6cd1b9ae473239cf5ee6bed 100644 (file)
@@ -256,7 +256,6 @@ static int da311_probe(struct i2c_client *client,
        return devm_iio_device_register(&client->dev, indio_dev);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int da311_suspend(struct device *dev)
 {
        return da311_enable(to_i2c_client(dev), false);
@@ -266,9 +265,8 @@ static int da311_resume(struct device *dev)
 {
        return da311_enable(to_i2c_client(dev), true);
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(da311_pm_ops, da311_suspend, da311_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(da311_pm_ops, da311_suspend, da311_resume);
 
 static const struct i2c_device_id da311_i2c_id[] = {
        {"da311", 0},
@@ -279,7 +277,7 @@ MODULE_DEVICE_TABLE(i2c, da311_i2c_id);
 static struct i2c_driver da311_driver = {
        .driver = {
                .name = "da311",
-               .pm = &da311_pm_ops,
+               .pm = pm_sleep_ptr(&da311_pm_ops),
        },
        .probe          = da311_probe,
        .id_table       = da311_i2c_id,
index de2868c28d954c97ea31e37689ac7e75bda72e1e..4b69c8530f5e615559cc0205069e27467a7c9aa6 100644 (file)
@@ -170,7 +170,6 @@ static int dmard06_probe(struct i2c_client *client,
        return devm_iio_device_register(&client->dev, indio_dev);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int dmard06_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
@@ -199,11 +198,8 @@ static int dmard06_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(dmard06_pm_ops, dmard06_suspend, dmard06_resume);
-#define DMARD06_PM_OPS (&dmard06_pm_ops)
-#else
-#define DMARD06_PM_OPS NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(dmard06_pm_ops, dmard06_suspend,
+                               dmard06_resume);
 
 static const struct i2c_device_id dmard06_id[] = {
        { "dmard05", 0 },
@@ -227,7 +223,7 @@ static struct i2c_driver dmard06_driver = {
        .driver = {
                .name = DMARD06_DRV_NAME,
                .of_match_table = dmard06_of_match,
-               .pm = DMARD06_PM_OPS,
+               .pm = pm_sleep_ptr(&dmard06_pm_ops),
        },
 };
 module_i2c_driver(dmard06_driver);
index e6e28c9647776e97012b6a7cf053857a1bad5251..53ab6078cb7f5f88b6b8debdbb3b67d66eb6543f 100644 (file)
@@ -126,7 +126,7 @@ static int dmard09_probe(struct i2c_client *client,
 }
 
 static const struct i2c_device_id dmard09_id[] = {
-       { "dmard09", 0},
+       { "dmard09", 0 },
        { },
 };
 
index f9f173eec2022ce9584b67f753ee8c1c88a602a3..8ac62ec0a04a435996ddba0195ad19be6657b6b1 100644 (file)
@@ -218,7 +218,6 @@ static int dmard10_probe(struct i2c_client *client,
        return devm_iio_device_register(&client->dev, indio_dev);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int dmard10_suspend(struct device *dev)
 {
        return dmard10_shutdown(to_i2c_client(dev));
@@ -228,9 +227,9 @@ static int dmard10_resume(struct device *dev)
 {
        return dmard10_reset(to_i2c_client(dev));
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(dmard10_pm_ops, dmard10_suspend, dmard10_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(dmard10_pm_ops, dmard10_suspend,
+                               dmard10_resume);
 
 static const struct i2c_device_id dmard10_i2c_id[] = {
        {"dmard10", 0},
@@ -241,7 +240,7 @@ MODULE_DEVICE_TABLE(i2c, dmard10_i2c_id);
 static struct i2c_driver dmard10_driver = {
        .driver = {
                .name = "dmard10",
-               .pm = &dmard10_pm_ops,
+               .pm = pm_sleep_ptr(&dmard10_pm_ops),
        },
        .probe          = dmard10_probe,
        .id_table       = dmard10_i2c_id,
index f7fd9e046588bd50feef1dd9a7ac346cbd80eb37..a9d2f10d5d4581735d198ca93ca592a93f6a456b 100644 (file)
@@ -178,7 +178,7 @@ const struct regmap_config fxls8962af_i2c_regmap_conf = {
        .val_bits = 8,
        .max_register = FXLS8962AF_MAX_REG,
 };
-EXPORT_SYMBOL_GPL(fxls8962af_i2c_regmap_conf);
+EXPORT_SYMBOL_NS_GPL(fxls8962af_i2c_regmap_conf, IIO_FXLS8962AF);
 
 const struct regmap_config fxls8962af_spi_regmap_conf = {
        .reg_bits = 8,
@@ -186,7 +186,7 @@ const struct regmap_config fxls8962af_spi_regmap_conf = {
        .val_bits = 8,
        .max_register = FXLS8962AF_MAX_REG,
 };
-EXPORT_SYMBOL_GPL(fxls8962af_spi_regmap_conf);
+EXPORT_SYMBOL_NS_GPL(fxls8962af_spi_regmap_conf, IIO_FXLS8962AF);
 
 enum {
        fxls8962af_idx_x,
@@ -1240,7 +1240,7 @@ int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq)
 
        return devm_iio_device_register(dev, indio_dev);
 }
-EXPORT_SYMBOL_GPL(fxls8962af_core_probe);
+EXPORT_SYMBOL_NS_GPL(fxls8962af_core_probe, IIO_FXLS8962AF);
 
 static int __maybe_unused fxls8962af_runtime_suspend(struct device *dev)
 {
@@ -1306,7 +1306,7 @@ const struct dev_pm_ops fxls8962af_pm_ops = {
        SET_RUNTIME_PM_OPS(fxls8962af_runtime_suspend,
                           fxls8962af_runtime_resume, NULL)
 };
-EXPORT_SYMBOL_GPL(fxls8962af_pm_ops);
+EXPORT_SYMBOL_NS_GPL(fxls8962af_pm_ops, IIO_FXLS8962AF);
 
 MODULE_AUTHOR("Sean Nyekjaer <[email protected]>");
 MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer driver");
index 6bde9891effbf16ca4991b08b7d287ddf76b4e4c..8fbadfea1620ba6ad8a5a8b9bb918cc89f1f7591 100644 (file)
@@ -55,3 +55,4 @@ module_i2c_driver(fxls8962af_driver);
 MODULE_AUTHOR("Sean Nyekjaer <[email protected]>");
 MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer i2c driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_FXLS8962AF);
index 6f4dff3238d3c215de7a0b7fecc8a0135b262702..885b3ab7fcb58f2794df26631c2e58d637d774e9 100644 (file)
@@ -55,3 +55,4 @@ module_spi_driver(fxls8962af_driver);
 MODULE_AUTHOR("Sean Nyekjaer <[email protected]>");
 MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer spi driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_FXLS8962AF);
index 274b41a6e603115dab39cd5ad5615c5f91942ddf..c8dc52f110373eda9ac21b3b27f35fe1a09f4848 100644 (file)
@@ -65,3 +65,4 @@ module_i2c_driver(kxsd9_i2c_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("KXSD9 accelerometer I2C interface");
+MODULE_IMPORT_NS(IIO_KXSD9);
index 441e6b764281c3e2c5c54188309a20e992bd9b9c..a06a3a273de715fd1852a6479571c0b25f4ade79 100644 (file)
@@ -66,3 +66,4 @@ module_spi_driver(kxsd9_spi_driver);
 MODULE_AUTHOR("Jonathan Cameron <[email protected]>");
 MODULE_DESCRIPTION("Kionix KXSD9 SPI driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_KXSD9);
index 552eba5e8b4fda35799ebcae61e9b91e6f15ecff..3975860331a65182c43ae3f20c293fded2874a81 100644 (file)
@@ -476,7 +476,7 @@ err_power_down:
 
        return ret;
 }
-EXPORT_SYMBOL(kxsd9_common_probe);
+EXPORT_SYMBOL_NS(kxsd9_common_probe, IIO_KXSD9);
 
 void kxsd9_common_remove(struct device *dev)
 {
@@ -490,7 +490,7 @@ void kxsd9_common_remove(struct device *dev)
        pm_runtime_disable(dev);
        kxsd9_power_down(st);
 }
-EXPORT_SYMBOL(kxsd9_common_remove);
+EXPORT_SYMBOL_NS(kxsd9_common_remove, IIO_KXSD9);
 
 #ifdef CONFIG_PM
 static int kxsd9_runtime_suspend(struct device *dev)
@@ -516,7 +516,7 @@ const struct dev_pm_ops kxsd9_dev_pm_ops = {
        SET_RUNTIME_PM_OPS(kxsd9_runtime_suspend,
                           kxsd9_runtime_resume, NULL)
 };
-EXPORT_SYMBOL(kxsd9_dev_pm_ops);
+EXPORT_SYMBOL_NS(kxsd9_dev_pm_ops, IIO_KXSD9);
 
 MODULE_AUTHOR("Jonathan Cameron <[email protected]>");
 MODULE_DESCRIPTION("Kionix KXSD9 driver");
index 735002b716f329f272272b5f632e7a3be95f214c..679e69cd7657a4923a4a81fbe95646660a1cf826 100644 (file)
@@ -160,7 +160,6 @@ static int mc3230_remove(struct i2c_client *client)
        return mc3230_set_opcon(iio_priv(indio_dev), MC3230_MODE_OPCON_STANDBY);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int mc3230_suspend(struct device *dev)
 {
        struct mc3230_data *data;
@@ -178,9 +177,8 @@ static int mc3230_resume(struct device *dev)
 
        return mc3230_set_opcon(data, MC3230_MODE_OPCON_WAKE);
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(mc3230_pm_ops, mc3230_suspend, mc3230_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(mc3230_pm_ops, mc3230_suspend, mc3230_resume);
 
 static const struct i2c_device_id mc3230_i2c_id[] = {
        {"mc3230", 0},
@@ -191,7 +189,7 @@ MODULE_DEVICE_TABLE(i2c, mc3230_i2c_id);
 static struct i2c_driver mc3230_driver = {
        .driver = {
                .name = "mc3230",
-               .pm = &mc3230_pm_ops,
+               .pm = pm_sleep_ptr(&mc3230_pm_ops),
        },
        .probe          = mc3230_probe,
        .remove         = mc3230_remove,
index e6739ba74edfacadf5667b663255332b57f4df1d..a34195b3215ddb883eaa8340b4ab045923669019 100644 (file)
@@ -238,7 +238,7 @@ const struct regmap_config mma7455_core_regmap = {
        .val_bits = 8,
        .max_register = MMA7455_REG_TW,
 };
-EXPORT_SYMBOL_GPL(mma7455_core_regmap);
+EXPORT_SYMBOL_NS_GPL(mma7455_core_regmap, IIO_MMA7455);
 
 int mma7455_core_probe(struct device *dev, struct regmap *regmap,
                       const char *name)
@@ -293,7 +293,7 @@ int mma7455_core_probe(struct device *dev, struct regmap *regmap,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(mma7455_core_probe);
+EXPORT_SYMBOL_NS_GPL(mma7455_core_probe, IIO_MMA7455);
 
 void mma7455_core_remove(struct device *dev)
 {
@@ -306,7 +306,7 @@ void mma7455_core_remove(struct device *dev)
        regmap_write(mma7455->regmap, MMA7455_REG_MCTL,
                     MMA7455_MCTL_MODE_STANDBY);
 }
-EXPORT_SYMBOL_GPL(mma7455_core_remove);
+EXPORT_SYMBOL_NS_GPL(mma7455_core_remove, IIO_MMA7455);
 
 MODULE_AUTHOR("Joachim Eastwood <[email protected]>");
 MODULE_DESCRIPTION("Freescale MMA7455L core accelerometer driver");
index 8a5256516f9fd508f7af5594c2984fa187c3c905..a3b84e8a3ea8515912c9b39fbc6b21d6daa85820 100644 (file)
@@ -61,3 +61,4 @@ module_i2c_driver(mma7455_i2c_driver);
 MODULE_AUTHOR("Joachim Eastwood <[email protected]>");
 MODULE_DESCRIPTION("Freescale MMA7455L I2C accelerometer driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_MMA7455);
index ecf690692dcc85c83d8023f3d0282e06032d8b70..564a0e12cebec335944f7cb867d24201389efd88 100644 (file)
@@ -49,3 +49,4 @@ module_spi_driver(mma7455_spi_driver);
 MODULE_AUTHOR("Joachim Eastwood <[email protected]>");
 MODULE_DESCRIPTION("Freescale MMA7455L SPI accelerometer driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_MMA7455);
index 24b83ccdb950714b6a132e0a6b43a282e9e2f49c..112a5a33c29f70f7c3d92f67dffdcb78fa13d845 100644 (file)
@@ -222,7 +222,6 @@ static int mma7660_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int mma7660_suspend(struct device *dev)
 {
        struct mma7660_data *data;
@@ -241,12 +240,8 @@ static int mma7660_resume(struct device *dev)
        return mma7660_set_mode(data, MMA7660_MODE_ACTIVE);
 }
 
-static SIMPLE_DEV_PM_OPS(mma7660_pm_ops, mma7660_suspend, mma7660_resume);
-
-#define MMA7660_PM_OPS (&mma7660_pm_ops)
-#else
-#define MMA7660_PM_OPS NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(mma7660_pm_ops, mma7660_suspend,
+                               mma7660_resume);
 
 static const struct i2c_device_id mma7660_i2c_id[] = {
        {"mma7660", 0},
@@ -270,7 +265,7 @@ MODULE_DEVICE_TABLE(acpi, mma7660_acpi_id);
 static struct i2c_driver mma7660_driver = {
        .driver = {
                .name = "mma7660",
-               .pm = MMA7660_PM_OPS,
+               .pm = pm_sleep_ptr(&mma7660_pm_ops),
                .of_match_table = mma7660_of_match,
                .acpi_match_table = ACPI_PTR(mma7660_acpi_id),
        },
index 64b82b4503adab5912d799784557ae5c939c269b..9c02c681c84c3e8cea447d3176ccb5fed72f5ff0 100644 (file)
 struct mma8452_data {
        struct i2c_client *client;
        struct mutex lock;
+       struct iio_mount_matrix orientation;
        u8 ctrl_reg1;
        u8 data_cfg;
        const struct mma_chip_info *chip_info;
@@ -176,6 +177,7 @@ static const struct mma8452_event_regs trans_ev_regs = {
  * @enabled_events:            event flags enabled and handled by this driver
  */
 struct mma_chip_info {
+       const char *name;
        u8 chip_id;
        const struct iio_chan_spec *channels;
        int num_channels;
@@ -379,8 +381,8 @@ static ssize_t mma8452_show_scale_avail(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf)
 {
-       struct mma8452_data *data = iio_priv(i2c_get_clientdata(
-                                            to_i2c_client(dev)));
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct mma8452_data *data = iio_priv(indio_dev);
 
        return mma8452_show_int_plus_micros(buf, data->chip_info->mma_scales,
                ARRAY_SIZE(data->chip_info->mma_scales));
@@ -1189,6 +1191,20 @@ static const struct attribute_group mma8452_event_attribute_group = {
        .attrs = mma8452_event_attributes,
 };
 
+static const struct iio_mount_matrix *
+mma8452_get_mount_matrix(const struct iio_dev *indio_dev,
+                          const struct iio_chan_spec *chan)
+{
+       struct mma8452_data *data = iio_priv(indio_dev);
+
+       return &data->orientation;
+}
+
+static const struct iio_chan_spec_ext_info mma8452_ext_info[] = {
+       IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, mma8452_get_mount_matrix),
+       { }
+};
+
 #define MMA8452_FREEFALL_CHANNEL(modifier) { \
        .type = IIO_ACCEL, \
        .modified = 1, \
@@ -1227,6 +1243,7 @@ static const struct attribute_group mma8452_event_attribute_group = {
        }, \
        .event_spec = mma8452_transient_event, \
        .num_event_specs = ARRAY_SIZE(mma8452_transient_event), \
+       .ext_info = mma8452_ext_info, \
 }
 
 #define MMA8652_CHANNEL(axis, idx, bits) { \
@@ -1248,6 +1265,7 @@ static const struct attribute_group mma8452_event_attribute_group = {
        }, \
        .event_spec = mma8452_motion_event, \
        .num_event_specs = ARRAY_SIZE(mma8452_motion_event), \
+       .ext_info = mma8452_ext_info, \
 }
 
 static const struct iio_chan_spec mma8451_channels[] = {
@@ -1301,6 +1319,7 @@ enum {
 
 static const struct mma_chip_info mma_chip_info_table[] = {
        [mma8451] = {
+               .name = "mma8451",
                .chip_id = MMA8451_DEVICE_ID,
                .channels = mma8451_channels,
                .num_channels = ARRAY_SIZE(mma8451_channels),
@@ -1325,6 +1344,7 @@ static const struct mma_chip_info mma_chip_info_table[] = {
                                        MMA8452_INT_FF_MT,
        },
        [mma8452] = {
+               .name = "mma8452",
                .chip_id = MMA8452_DEVICE_ID,
                .channels = mma8452_channels,
                .num_channels = ARRAY_SIZE(mma8452_channels),
@@ -1341,6 +1361,7 @@ static const struct mma_chip_info mma_chip_info_table[] = {
                                        MMA8452_INT_FF_MT,
        },
        [mma8453] = {
+               .name = "mma8453",
                .chip_id = MMA8453_DEVICE_ID,
                .channels = mma8453_channels,
                .num_channels = ARRAY_SIZE(mma8453_channels),
@@ -1357,6 +1378,7 @@ static const struct mma_chip_info mma_chip_info_table[] = {
                                        MMA8452_INT_FF_MT,
        },
        [mma8652] = {
+               .name = "mma8652",
                .chip_id = MMA8652_DEVICE_ID,
                .channels = mma8652_channels,
                .num_channels = ARRAY_SIZE(mma8652_channels),
@@ -1366,6 +1388,7 @@ static const struct mma_chip_info mma_chip_info_table[] = {
                .enabled_events = MMA8452_INT_FF_MT,
        },
        [mma8653] = {
+               .name = "mma8653",
                .chip_id = MMA8653_DEVICE_ID,
                .channels = mma8653_channels,
                .num_channels = ARRAY_SIZE(mma8653_channels),
@@ -1380,6 +1403,7 @@ static const struct mma_chip_info mma_chip_info_table[] = {
                .enabled_events = MMA8452_INT_FF_MT,
        },
        [fxls8471] = {
+               .name = "fxls8471",
                .chip_id = FXLS8471_DEVICE_ID,
                .channels = mma8451_channels,
                .num_channels = ARRAY_SIZE(mma8451_channels),
@@ -1522,13 +1546,6 @@ static int mma8452_probe(struct i2c_client *client,
        struct mma8452_data *data;
        struct iio_dev *indio_dev;
        int ret;
-       const struct of_device_id *match;
-
-       match = of_match_device(mma8452_dt_ids, &client->dev);
-       if (!match) {
-               dev_err(&client->dev, "unknown device model\n");
-               return -ENODEV;
-       }
 
        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
        if (!indio_dev)
@@ -1537,7 +1554,18 @@ static int mma8452_probe(struct i2c_client *client,
        data = iio_priv(indio_dev);
        data->client = client;
        mutex_init(&data->lock);
-       data->chip_info = match->data;
+
+       data->chip_info = device_get_match_data(&client->dev);
+       if (!data->chip_info && id) {
+               data->chip_info = &mma_chip_info_table[id->driver_data];
+       } else {
+               dev_err(&client->dev, "unknown device model\n");
+               return -ENODEV;
+       }
+
+       ret = iio_read_mount_matrix(&client->dev, &data->orientation);
+       if (ret)
+               return ret;
 
        data->vdd_reg = devm_regulator_get(&client->dev, "vdd");
        if (IS_ERR(data->vdd_reg))
@@ -1581,11 +1609,11 @@ static int mma8452_probe(struct i2c_client *client,
        }
 
        dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n",
-                match->compatible, data->chip_info->chip_id);
+                data->chip_info->name, data->chip_info->chip_id);
 
        i2c_set_clientdata(client, indio_dev);
        indio_dev->info = &mma8452_info;
-       indio_dev->name = id->name;
+       indio_dev->name = data->chip_info->name;
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->channels = data->chip_info->channels;
        indio_dev->num_channels = data->chip_info->num_channels;
@@ -1810,7 +1838,7 @@ MODULE_DEVICE_TABLE(i2c, mma8452_id);
 static struct i2c_driver mma8452_driver = {
        .driver = {
                .name   = "mma8452",
-               .of_match_table = of_match_ptr(mma8452_dt_ids),
+               .of_match_table = mma8452_dt_ids,
                .pm     = &mma8452_pm_ops,
        },
        .probe = mma8452_probe,
index c53a3398b14c4a719ff7f1cc6f231fc80f16e027..123cdbbb265c167ec77badbf462a32c92d0b527e 100644 (file)
@@ -526,7 +526,6 @@ static int mma9551_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
 static int mma9551_runtime_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
@@ -558,9 +557,7 @@ static int mma9551_runtime_resume(struct device *dev)
 
        return 0;
 }
-#endif
 
-#ifdef CONFIG_PM_SLEEP
 static int mma9551_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
@@ -586,12 +583,10 @@ static int mma9551_resume(struct device *dev)
 
        return ret;
 }
-#endif
 
 static const struct dev_pm_ops mma9551_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(mma9551_suspend, mma9551_resume)
-       SET_RUNTIME_PM_OPS(mma9551_runtime_suspend,
-                          mma9551_runtime_resume, NULL)
+       SYSTEM_SLEEP_PM_OPS(mma9551_suspend, mma9551_resume)
+       RUNTIME_PM_OPS(mma9551_runtime_suspend, mma9551_runtime_resume, NULL)
 };
 
 static const struct acpi_device_id mma9551_acpi_match[] = {
@@ -612,7 +607,7 @@ static struct i2c_driver mma9551_driver = {
        .driver = {
                   .name = MMA9551_DRV_NAME,
                   .acpi_match_table = ACPI_PTR(mma9551_acpi_match),
-                  .pm = &mma9551_pm_ops,
+                  .pm = pm_ptr(&mma9551_pm_ops),
                   },
        .probe = mma9551_probe,
        .remove = mma9551_remove,
@@ -625,3 +620,4 @@ MODULE_AUTHOR("Irina Tirdea <[email protected]>");
 MODULE_AUTHOR("Vlad Dogaru <[email protected]>");
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("MMA9551L motion-sensing platform driver");
+MODULE_IMPORT_NS(IIO_MMA9551);
index fbf2e2c45678b2412b2ed9845b5c8bed8ef5a67c..64ca7d7a9673d0bd54910f8ab124a0d42780666b 100644 (file)
@@ -219,7 +219,7 @@ int mma9551_read_config_byte(struct i2c_client *client, u8 app_id,
        return mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
                                reg, NULL, 0, val, 1);
 }
-EXPORT_SYMBOL(mma9551_read_config_byte);
+EXPORT_SYMBOL_NS(mma9551_read_config_byte, IIO_MMA9551);
 
 /**
  * mma9551_write_config_byte() - write 1 configuration byte
@@ -244,7 +244,7 @@ int mma9551_write_config_byte(struct i2c_client *client, u8 app_id,
        return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg,
                                &val, 1, NULL, 0);
 }
-EXPORT_SYMBOL(mma9551_write_config_byte);
+EXPORT_SYMBOL_NS(mma9551_write_config_byte, IIO_MMA9551);
 
 /**
  * mma9551_read_status_byte() - read 1 status byte
@@ -269,7 +269,7 @@ int mma9551_read_status_byte(struct i2c_client *client, u8 app_id,
        return mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
                                reg, NULL, 0, val, 1);
 }
-EXPORT_SYMBOL(mma9551_read_status_byte);
+EXPORT_SYMBOL_NS(mma9551_read_status_byte, IIO_MMA9551);
 
 /**
  * mma9551_read_config_word() - read 1 config word
@@ -300,7 +300,7 @@ int mma9551_read_config_word(struct i2c_client *client, u8 app_id,
 
        return ret;
 }
-EXPORT_SYMBOL(mma9551_read_config_word);
+EXPORT_SYMBOL_NS(mma9551_read_config_word, IIO_MMA9551);
 
 /**
  * mma9551_write_config_word() - write 1 config word
@@ -327,7 +327,7 @@ int mma9551_write_config_word(struct i2c_client *client, u8 app_id,
        return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg,
                                (u8 *)&v, 2, NULL, 0);
 }
-EXPORT_SYMBOL(mma9551_write_config_word);
+EXPORT_SYMBOL_NS(mma9551_write_config_word, IIO_MMA9551);
 
 /**
  * mma9551_read_status_word() - read 1 status word
@@ -358,7 +358,7 @@ int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
 
        return ret;
 }
-EXPORT_SYMBOL(mma9551_read_status_word);
+EXPORT_SYMBOL_NS(mma9551_read_status_word, IIO_MMA9551);
 
 /**
  * mma9551_read_config_words() - read multiple config words
@@ -397,7 +397,7 @@ int mma9551_read_config_words(struct i2c_client *client, u8 app_id,
 
        return 0;
 }
-EXPORT_SYMBOL(mma9551_read_config_words);
+EXPORT_SYMBOL_NS(mma9551_read_config_words, IIO_MMA9551);
 
 /**
  * mma9551_read_status_words() - read multiple status words
@@ -436,7 +436,7 @@ int mma9551_read_status_words(struct i2c_client *client, u8 app_id,
 
        return 0;
 }
-EXPORT_SYMBOL(mma9551_read_status_words);
+EXPORT_SYMBOL_NS(mma9551_read_status_words, IIO_MMA9551);
 
 /**
  * mma9551_write_config_words() - write multiple config words
@@ -471,7 +471,7 @@ int mma9551_write_config_words(struct i2c_client *client, u8 app_id,
        return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG,
                                reg, (u8 *)be_buf, len * sizeof(u16), NULL, 0);
 }
-EXPORT_SYMBOL(mma9551_write_config_words);
+EXPORT_SYMBOL_NS(mma9551_write_config_words, IIO_MMA9551);
 
 /**
  * mma9551_update_config_bits() - update bits in register
@@ -507,7 +507,7 @@ int mma9551_update_config_bits(struct i2c_client *client, u8 app_id,
 
        return mma9551_write_config_byte(client, app_id, reg, tmp);
 }
-EXPORT_SYMBOL(mma9551_update_config_bits);
+EXPORT_SYMBOL_NS(mma9551_update_config_bits, IIO_MMA9551);
 
 /**
  * mma9551_gpio_config() - configure gpio
@@ -586,7 +586,7 @@ int mma9551_gpio_config(struct i2c_client *client, enum mma9551_gpio_pin pin,
 
        return ret;
 }
-EXPORT_SYMBOL(mma9551_gpio_config);
+EXPORT_SYMBOL_NS(mma9551_gpio_config, IIO_MMA9551);
 
 /**
  * mma9551_read_version() - read device version information
@@ -616,7 +616,7 @@ int mma9551_read_version(struct i2c_client *client)
 
        return 0;
 }
-EXPORT_SYMBOL(mma9551_read_version);
+EXPORT_SYMBOL_NS(mma9551_read_version, IIO_MMA9551);
 
 /**
  * mma9551_set_device_state() - sets HW power mode
@@ -646,7 +646,7 @@ int mma9551_set_device_state(struct i2c_client *client, bool enable)
                                          MMA9551_SLEEP_CFG_FLEEN :
                                          MMA9551_SLEEP_CFG_SNCEN);
 }
-EXPORT_SYMBOL(mma9551_set_device_state);
+EXPORT_SYMBOL_NS(mma9551_set_device_state, IIO_MMA9551);
 
 /**
  * mma9551_set_power_state() - sets runtime PM state
@@ -680,7 +680,7 @@ int mma9551_set_power_state(struct i2c_client *client, bool on)
 
        return 0;
 }
-EXPORT_SYMBOL(mma9551_set_power_state);
+EXPORT_SYMBOL_NS(mma9551_set_power_state, IIO_MMA9551);
 
 /**
  * mma9551_sleep() - sleep
@@ -699,7 +699,7 @@ void mma9551_sleep(int freq)
        else
                msleep_interruptible(sleep_val);
 }
-EXPORT_SYMBOL(mma9551_sleep);
+EXPORT_SYMBOL_NS(mma9551_sleep, IIO_MMA9551);
 
 /**
  * mma9551_read_accel_chan() - read accelerometer channel
@@ -755,7 +755,7 @@ out_poweroff:
        mma9551_set_power_state(client, false);
        return ret;
 }
-EXPORT_SYMBOL(mma9551_read_accel_chan);
+EXPORT_SYMBOL_NS(mma9551_read_accel_chan, IIO_MMA9551);
 
 /**
  * mma9551_read_accel_scale() - read accelerometer scale
@@ -773,7 +773,7 @@ int mma9551_read_accel_scale(int *val, int *val2)
 
        return IIO_VAL_INT_PLUS_MICRO;
 }
-EXPORT_SYMBOL(mma9551_read_accel_scale);
+EXPORT_SYMBOL_NS(mma9551_read_accel_scale, IIO_MMA9551);
 
 /**
  * mma9551_app_reset() - reset application
@@ -792,7 +792,7 @@ int mma9551_app_reset(struct i2c_client *client, u32 app_mask)
                                         MMA9551_RSC_OFFSET(app_mask),
                                         MMA9551_RSC_VAL(app_mask));
 }
-EXPORT_SYMBOL(mma9551_app_reset);
+EXPORT_SYMBOL_NS(mma9551_app_reset, IIO_MMA9551);
 
 MODULE_AUTHOR("Irina Tirdea <[email protected]>");
 MODULE_AUTHOR("Vlad Dogaru <[email protected]>");
index 5ff6bc70708b649e5cb213c62b79f345d0fa89e2..09df58d4be331e5af50a02a57c392ee49d50d648 100644 (file)
@@ -1165,7 +1165,6 @@ static int mma9553_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
 static int mma9553_runtime_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
@@ -1197,9 +1196,7 @@ static int mma9553_runtime_resume(struct device *dev)
 
        return 0;
 }
-#endif
 
-#ifdef CONFIG_PM_SLEEP
 static int mma9553_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
@@ -1225,12 +1222,10 @@ static int mma9553_resume(struct device *dev)
 
        return ret;
 }
-#endif
 
 static const struct dev_pm_ops mma9553_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(mma9553_suspend, mma9553_resume)
-       SET_RUNTIME_PM_OPS(mma9553_runtime_suspend,
-                          mma9553_runtime_resume, NULL)
+       SYSTEM_SLEEP_PM_OPS(mma9553_suspend, mma9553_resume)
+       RUNTIME_PM_OPS(mma9553_runtime_suspend, mma9553_runtime_resume, NULL)
 };
 
 static const struct acpi_device_id mma9553_acpi_match[] = {
@@ -1251,7 +1246,7 @@ static struct i2c_driver mma9553_driver = {
        .driver = {
                   .name = MMA9553_DRV_NAME,
                   .acpi_match_table = ACPI_PTR(mma9553_acpi_match),
-                  .pm = &mma9553_pm_ops,
+                  .pm = pm_ptr(&mma9553_pm_ops),
                   },
        .probe = mma9553_probe,
        .remove = mma9553_remove,
@@ -1263,3 +1258,4 @@ module_i2c_driver(mma9553_driver);
 MODULE_AUTHOR("Irina Tirdea <[email protected]>");
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("MMA9553L pedometer platform driver");
+MODULE_IMPORT_NS(IIO_MMA9551);
index 04dcb2b657ee6258fbd6be3d8ffd8caba9786995..a1164b439f412e645a61b29f6a20e0b6f524f2e9 100644 (file)
@@ -142,3 +142,4 @@ module_platform_driver(ssp_accel_driver);
 MODULE_AUTHOR("Karol Wrona <[email protected]>");
 MODULE_DESCRIPTION("Samsung sensorhub accelerometers driver");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_SSP_SENSORS);
index 8750dea56fcbdfda45a456650d67acbf6da1dff5..00e056c21bfcaa5a8994b162cc9aaed323c14bac 100644 (file)
@@ -36,6 +36,7 @@ enum st_accel_type {
        LIS3DHH,
        LIS2DE12,
        LIS2HH12,
+       SC7A20,
        ST_ACCEL_MAX,
 };
 
@@ -61,6 +62,7 @@ enum st_accel_type {
 #define LIS3DE_ACCEL_DEV_NAME          "lis3de"
 #define LIS2DE12_ACCEL_DEV_NAME                "lis2de12"
 #define LIS2HH12_ACCEL_DEV_NAME                "lis2hh12"
+#define SC7A20_ACCEL_DEV_NAME          "sc7a20"
 
 #ifdef CONFIG_IIO_BUFFER
 int st_accel_allocate_ring(struct iio_dev *indio_dev);
index fc82fa83f1fb7bf0fdd78e31e6d1dae8de0df216..b2977ae19b695ff84536ec08b306d4a2ce07756c 100644 (file)
@@ -7,7 +7,6 @@
  * Denis Ciocca <[email protected]>
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/buffer.h>
@@ -65,7 +64,3 @@ int st_accel_allocate_ring(struct iio_dev *indio_dev)
        return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev,
                NULL, &st_sensors_trigger_handler, &st_accel_buffer_setup_ops);
 }
-
-MODULE_AUTHOR("Denis Ciocca <[email protected]>");
-MODULE_DESCRIPTION("STMicroelectronics accelerometers buffer");
-MODULE_LICENSE("GPL v2");
index 31ea19d0ba71c35d2453b4cedc80885ee82c5402..5c5da6fdb49029b0f1b34d0b4f9f54cd056f093e 100644 (file)
@@ -1087,6 +1087,89 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
                .multi_read_bit = true,
                .bootime = 2,
        },
+       {
+               /*
+                * Not an ST part. Register-compatible with the LIS2DH, even
+                * though the WAI value is different.
+                */
+               .wai = 0x11,
+               .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
+               .sensors_supported = {
+                       [0] = SC7A20_ACCEL_DEV_NAME,
+               },
+               .ch = (struct iio_chan_spec *)st_accel_12bit_channels,
+               .odr = {
+                       .addr = 0x20,
+                       .mask = 0xf0,
+                       .odr_avl = {
+                               { .hz = 1, .value = 0x01, },
+                               { .hz = 10, .value = 0x02, },
+                               { .hz = 25, .value = 0x03, },
+                               { .hz = 50, .value = 0x04, },
+                               { .hz = 100, .value = 0x05, },
+                               { .hz = 200, .value = 0x06, },
+                               { .hz = 400, .value = 0x07, },
+                               { .hz = 1600, .value = 0x08, },
+                       },
+               },
+               .pw = {
+                       .addr = 0x20,
+                       .mask = 0xf0,
+                       .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
+               },
+               .enable_axis = {
+                       .addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
+                       .mask = ST_SENSORS_DEFAULT_AXIS_MASK,
+               },
+               .fs = {
+                       .addr = 0x23,
+                       .mask = 0x30,
+                       .fs_avl = {
+                               [0] = {
+                                       .num = ST_ACCEL_FS_AVL_2G,
+                                       .value = 0x00,
+                                       .gain = IIO_G_TO_M_S_2(1000),
+                               },
+                               [1] = {
+                                       .num = ST_ACCEL_FS_AVL_4G,
+                                       .value = 0x01,
+                                       .gain = IIO_G_TO_M_S_2(2000),
+                               },
+                               [2] = {
+                                       .num = ST_ACCEL_FS_AVL_8G,
+                                       .value = 0x02,
+                                       .gain = IIO_G_TO_M_S_2(4000),
+                               },
+                               [3] = {
+                                       .num = ST_ACCEL_FS_AVL_16G,
+                                       .value = 0x03,
+                                       .gain = IIO_G_TO_M_S_2(12000),
+                               },
+                       },
+               },
+               .bdu = {
+                       .addr = 0x23,
+                       .mask = 0x80,
+               },
+               .drdy_irq = {
+                       .int1 = {
+                               .addr = 0x22,
+                               .mask = 0x10,
+                       },
+                       .addr_ihl = 0x25,
+                       .mask_ihl = 0x02,
+                       .stat_drdy = {
+                               .addr = ST_SENSORS_DEFAULT_STAT_ADDR,
+                               .mask = 0x07,
+                       },
+               },
+               .sim = {
+                       .addr = 0x23,
+                       .value = BIT(0),
+               },
+               .multi_read_bit = true,
+               .bootime = 2,
+       },
 };
 
 /* Default accel DRDY is available on INT1 pin */
@@ -1329,7 +1412,7 @@ const struct st_sensor_settings *st_accel_get_settings(const char *name)
 
        return &st_accel_sensors_settings[index];
 }
-EXPORT_SYMBOL(st_accel_get_settings);
+EXPORT_SYMBOL_NS(st_accel_get_settings, IIO_ST_SENSORS);
 
 int st_accel_common_probe(struct iio_dev *indio_dev)
 {
@@ -1383,8 +1466,9 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
 
        return devm_iio_device_register(parent, indio_dev);
 }
-EXPORT_SYMBOL(st_accel_common_probe);
+EXPORT_SYMBOL_NS(st_accel_common_probe, IIO_ST_SENSORS);
 
 MODULE_AUTHOR("Denis Ciocca <[email protected]>");
 MODULE_DESCRIPTION("STMicroelectronics accelerometers driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ST_SENSORS);
index c0ce78eebad9f765a2ac448fc5ad2e576d097779..96adc4344f4a555ac162e6da02eb7a2235f3208a 100644 (file)
@@ -107,6 +107,10 @@ static const struct of_device_id st_accel_of_match[] = {
                .compatible = "st,lis2hh12",
                .data = LIS2HH12_ACCEL_DEV_NAME,
        },
+       {
+               .compatible = "silan,sc7a20",
+               .data = SC7A20_ACCEL_DEV_NAME,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, st_accel_of_match);
@@ -142,6 +146,7 @@ static const struct i2c_device_id st_accel_id_table[] = {
        { LIS3DE_ACCEL_DEV_NAME },
        { LIS2DE12_ACCEL_DEV_NAME },
        { LIS2HH12_ACCEL_DEV_NAME },
+       { SC7A20_ACCEL_DEV_NAME },
        {},
 };
 MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
@@ -194,3 +199,4 @@ module_i2c_driver(st_accel_driver);
 MODULE_AUTHOR("Denis Ciocca <[email protected]>");
 MODULE_DESCRIPTION("STMicroelectronics accelerometers i2c driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ST_SENSORS);
index b74a1c6d03de7074f780d2db5c0c2cb7974d405d..108b63d0146c5501cc4cfbab6b84b8375b6eff6d 100644 (file)
@@ -164,3 +164,4 @@ module_spi_driver(st_accel_driver);
 MODULE_AUTHOR("Denis Ciocca <[email protected]>");
 MODULE_DESCRIPTION("STMicroelectronics accelerometers spi driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ST_SENSORS);
index de0cdf8c1f94c5b0dca98fa8b1634212a275d8d3..a71dfff3ca4aa64f536aacf569bd4d0605b23a5d 100644 (file)
@@ -611,7 +611,6 @@ static int stk8312_remove(struct i2c_client *client)
        return stk8312_set_mode(data, STK8312_MODE_STANDBY);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int stk8312_suspend(struct device *dev)
 {
        struct stk8312_data *data;
@@ -630,12 +629,8 @@ static int stk8312_resume(struct device *dev)
        return stk8312_set_mode(data, data->mode | STK8312_MODE_ACTIVE);
 }
 
-static SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend, stk8312_resume);
-
-#define STK8312_PM_OPS (&stk8312_pm_ops)
-#else
-#define STK8312_PM_OPS NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend,
+                               stk8312_resume);
 
 static const struct i2c_device_id stk8312_i2c_id[] = {
        /* Deprecated in favour of lowercase form */
@@ -648,7 +643,7 @@ MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id);
 static struct i2c_driver stk8312_driver = {
        .driver = {
                .name = STK8312_DRIVER_NAME,
-               .pm = STK8312_PM_OPS,
+               .pm = pm_sleep_ptr(&stk8312_pm_ops),
        },
        .probe =            stk8312_probe,
        .remove =           stk8312_remove,
index 517c57ed9e9494f6cf423894ad85c2dd56e06ce0..0067ec5cbae8a7e96951bdc4681e0ccbd645ed08 100644 (file)
@@ -504,7 +504,6 @@ static int stk8ba50_remove(struct i2c_client *client)
        return stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int stk8ba50_suspend(struct device *dev)
 {
        struct stk8ba50_data *data;
@@ -523,12 +522,8 @@ static int stk8ba50_resume(struct device *dev)
        return stk8ba50_set_power(data, STK8BA50_MODE_NORMAL);
 }
 
-static SIMPLE_DEV_PM_OPS(stk8ba50_pm_ops, stk8ba50_suspend, stk8ba50_resume);
-
-#define STK8BA50_PM_OPS (&stk8ba50_pm_ops)
-#else
-#define STK8BA50_PM_OPS NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(stk8ba50_pm_ops, stk8ba50_suspend,
+                               stk8ba50_resume);
 
 static const struct i2c_device_id stk8ba50_i2c_id[] = {
        {"stk8ba50", 0},
@@ -546,7 +541,7 @@ MODULE_DEVICE_TABLE(acpi, stk8ba50_acpi_id);
 static struct i2c_driver stk8ba50_driver = {
        .driver = {
                .name = "stk8ba50",
-               .pm = STK8BA50_PM_OPS,
+               .pm = pm_sleep_ptr(&stk8ba50_pm_ops),
                .acpi_match_table = ACPI_PTR(stk8ba50_acpi_id),
        },
        .probe =            stk8ba50_probe,
index 4fdc8bfbb407fa1a30025de5071de8140f10f9aa..71ab0a06aa821620b98b649388b4064a06885e2d 100644 (file)
@@ -64,6 +64,17 @@ config AD7266
          To compile this driver as a module, choose M here: the module will be
          called ad7266.
 
+config AD7280
+       tristate "Analog Devices AD7280A Lithium Ion Battery Monitoring System"
+       depends on SPI
+       select CRC8
+       help
+         Say yes here to build support for Analog Devices AD7280A
+         Lithium Ion Battery Monitoring System.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ad7280a
+
 config AD7291
        tristate "Analog Devices AD7291 ADC driver"
        depends on I2C
index 4a8f1833993bd737e339fd15af4122f987877f01..39d806f6d457831778b3dcf09cb2e67c1d3003a0 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_AD7091R5) += ad7091r5.o ad7091r-base.o
 obj-$(CONFIG_AD7124) += ad7124.o
 obj-$(CONFIG_AD7192) += ad7192.o
 obj-$(CONFIG_AD7266) += ad7266.o
+obj-$(CONFIG_AD7280) += ad7280a.o
 obj-$(CONFIG_AD7291) += ad7291.o
 obj-$(CONFIG_AD7292) += ad7292.o
 obj-$(CONFIG_AD7298) += ad7298.o
index 4c46a201d4ef7e459432ec17f3c2f46fc951cc12..930ce96e6ff5d8b0688419786d9f2fc3bf4c993c 100644 (file)
@@ -942,7 +942,6 @@ static const struct iio_info ab8500_gpadc_info = {
        .read_raw = ab8500_gpadc_read_raw,
 };
 
-#ifdef CONFIG_PM
 static int ab8500_gpadc_runtime_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
@@ -965,7 +964,6 @@ static int ab8500_gpadc_runtime_resume(struct device *dev)
 
        return ret;
 }
-#endif
 
 /**
  * ab8500_gpadc_parse_channel() - process devicetree channel configuration
@@ -1199,20 +1197,16 @@ static int ab8500_gpadc_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const struct dev_pm_ops ab8500_gpadc_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-                               pm_runtime_force_resume)
-       SET_RUNTIME_PM_OPS(ab8500_gpadc_runtime_suspend,
-                          ab8500_gpadc_runtime_resume,
-                          NULL)
-};
+static DEFINE_RUNTIME_DEV_PM_OPS(ab8500_gpadc_pm_ops,
+                                ab8500_gpadc_runtime_suspend,
+                                ab8500_gpadc_runtime_resume, NULL);
 
 static struct platform_driver ab8500_gpadc_driver = {
        .probe = ab8500_gpadc_probe,
        .remove = ab8500_gpadc_remove,
        .driver = {
                .name = "ab8500-gpadc",
-               .pm = &ab8500_gpadc_pm_ops,
+               .pm = pm_ptr(&ab8500_gpadc_pm_ops),
        },
 };
 builtin_platform_driver(ab8500_gpadc_driver);
index 63b4d6ea4566a022f780a31e7480a11670887bad..8e252cde735b999c6877308fcdaf3f2084f768ce 100644 (file)
@@ -260,7 +260,7 @@ int ad7091r_probe(struct device *dev, const char *name,
 
        return devm_iio_device_register(dev, iio_dev);
 }
-EXPORT_SYMBOL_GPL(ad7091r_probe);
+EXPORT_SYMBOL_NS_GPL(ad7091r_probe, IIO_AD7091R);
 
 static bool ad7091r_writeable_reg(struct device *dev, unsigned int reg)
 {
@@ -290,7 +290,7 @@ const struct regmap_config ad7091r_regmap_config = {
        .writeable_reg = ad7091r_writeable_reg,
        .volatile_reg = ad7091r_volatile_reg,
 };
-EXPORT_SYMBOL_GPL(ad7091r_regmap_config);
+EXPORT_SYMBOL_NS_GPL(ad7091r_regmap_config, IIO_AD7091R);
 
 MODULE_AUTHOR("Beniamin Bia <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices AD7091Rx multi-channel converters");
index 9665679c3ea6dfbf9cb1c038f525d212b908b698..47f5763023a403c727bb5c512b60576a07ca3443 100644 (file)
@@ -111,3 +111,4 @@ module_i2c_driver(ad7091r5_driver);
 MODULE_AUTHOR("Beniamin Bia <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices AD7091R5 multi-channel ADC driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_AD7091R);
index b400bbe291aa4868f7c5155169ebac0f176beaeb..c47ead15f6e5ac10d0ec64cdc71a3f2083469e47 100644 (file)
@@ -970,3 +970,4 @@ module_spi_driver(ad71124_driver);
 MODULE_AUTHOR("Stefan Popa <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices AD7124 SPI driver");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA);
index cc990205f306149b20795f9392454ad12fc1fb24..770b4e59238fe4ec9fcb74a9d18ee9125d656620 100644 (file)
@@ -433,7 +433,7 @@ static ssize_t ad7192_show_ac_excitation(struct device *dev,
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        struct ad7192_state *st = iio_priv(indio_dev);
 
-       return sprintf(buf, "%d\n", !!(st->mode & AD7192_MODE_ACX));
+       return sysfs_emit(buf, "%d\n", !!(st->mode & AD7192_MODE_ACX));
 }
 
 static ssize_t ad7192_show_bridge_switch(struct device *dev,
@@ -443,7 +443,7 @@ static ssize_t ad7192_show_bridge_switch(struct device *dev,
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        struct ad7192_state *st = iio_priv(indio_dev);
 
-       return sprintf(buf, "%d\n", !!(st->gpocon & AD7192_GPOCON_BPDSW));
+       return sysfs_emit(buf, "%d\n", !!(st->gpocon & AD7192_GPOCON_BPDSW));
 }
 
 static ssize_t ad7192_set(struct device *dev,
@@ -1048,3 +1048,4 @@ module_spi_driver(ad7192_driver);
 MODULE_AUTHOR("Michael Hennerich <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices AD7190, AD7192, AD7193, AD7195 ADC");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA);
diff --git a/drivers/iio/adc/ad7280a.c b/drivers/iio/adc/ad7280a.c
new file mode 100644 (file)
index 0000000..ef9d277
--- /dev/null
@@ -0,0 +1,1111 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AD7280A Lithium Ion Battery Monitoring System
+ *
+ * Copyright 2011 Analog Devices Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/crc8.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+
+/* Registers */
+
+#define AD7280A_CELL_VOLTAGE_1_REG             0x0  /* D11 to D0, Read only */
+#define AD7280A_CELL_VOLTAGE_2_REG             0x1  /* D11 to D0, Read only */
+#define AD7280A_CELL_VOLTAGE_3_REG             0x2  /* D11 to D0, Read only */
+#define AD7280A_CELL_VOLTAGE_4_REG             0x3  /* D11 to D0, Read only */
+#define AD7280A_CELL_VOLTAGE_5_REG             0x4  /* D11 to D0, Read only */
+#define AD7280A_CELL_VOLTAGE_6_REG             0x5  /* D11 to D0, Read only */
+#define AD7280A_AUX_ADC_1_REG                  0x6  /* D11 to D0, Read only */
+#define AD7280A_AUX_ADC_2_REG                  0x7  /* D11 to D0, Read only */
+#define AD7280A_AUX_ADC_3_REG                  0x8  /* D11 to D0, Read only */
+#define AD7280A_AUX_ADC_4_REG                  0x9  /* D11 to D0, Read only */
+#define AD7280A_AUX_ADC_5_REG                  0xA  /* D11 to D0, Read only */
+#define AD7280A_AUX_ADC_6_REG                  0xB  /* D11 to D0, Read only */
+#define AD7280A_SELF_TEST_REG                  0xC  /* D11 to D0, Read only */
+
+#define AD7280A_CTRL_HB_REG                    0xD  /* D15 to D8, Read/write */
+#define   AD7280A_CTRL_HB_CONV_INPUT_MSK               GENMASK(7, 6)
+#define     AD7280A_CTRL_HB_CONV_INPUT_ALL                     0
+#define     AD7280A_CTRL_HB_CONV_INPUT_6CELL_AUX1_3_5          1
+#define     AD7280A_CTRL_HB_CONV_INPUT_6CELL                   2
+#define     AD7280A_CTRL_HB_CONV_INPUT_SELF_TEST               3
+#define   AD7280A_CTRL_HB_CONV_RREAD_MSK               GENMASK(5, 4)
+#define     AD7280A_CTRL_HB_CONV_RREAD_ALL                     0
+#define     AD7280A_CTRL_HB_CONV_RREAD_6CELL_AUX1_3_5          1
+#define     AD7280A_CTRL_HB_CONV_RREAD_6CELL                   2
+#define     AD7280A_CTRL_HB_CONV_RREAD_NO                      3
+#define   AD7280A_CTRL_HB_CONV_START_MSK               BIT(3)
+#define     AD7280A_CTRL_HB_CONV_START_CNVST                   0
+#define     AD7280A_CTRL_HB_CONV_START_CS                      1
+#define   AD7280A_CTRL_HB_CONV_AVG_MSK                 GENMASK(2, 1)
+#define     AD7280A_CTRL_HB_CONV_AVG_DIS                       0
+#define     AD7280A_CTRL_HB_CONV_AVG_2                         1
+#define     AD7280A_CTRL_HB_CONV_AVG_4                         2
+#define     AD7280A_CTRL_HB_CONV_AVG_8                         3
+#define   AD7280A_CTRL_HB_PWRDN_SW                     BIT(0)
+
+#define AD7280A_CTRL_LB_REG                    0xE  /* D7 to D0, Read/write */
+#define   AD7280A_CTRL_LB_SWRST_MSK                    BIT(7)
+#define   AD7280A_CTRL_LB_ACQ_TIME_MSK                 GENMASK(6, 5)
+#define     AD7280A_CTRL_LB_ACQ_TIME_400ns                     0
+#define     AD7280A_CTRL_LB_ACQ_TIME_800ns                     1
+#define     AD7280A_CTRL_LB_ACQ_TIME_1200ns                    2
+#define     AD7280A_CTRL_LB_ACQ_TIME_1600ns                    3
+#define   AD7280A_CTRL_LB_MUST_SET                     BIT(4)
+#define   AD7280A_CTRL_LB_THERMISTOR_MSK               BIT(3)
+#define   AD7280A_CTRL_LB_LOCK_DEV_ADDR_MSK            BIT(2)
+#define   AD7280A_CTRL_LB_INC_DEV_ADDR_MSK             BIT(1)
+#define   AD7280A_CTRL_LB_DAISY_CHAIN_RB_MSK           BIT(0)
+
+#define AD7280A_CELL_OVERVOLTAGE_REG           0xF  /* D7 to D0, Read/write */
+#define AD7280A_CELL_UNDERVOLTAGE_REG          0x10 /* D7 to D0, Read/write */
+#define AD7280A_AUX_ADC_OVERVOLTAGE_REG                0x11 /* D7 to D0, Read/write */
+#define AD7280A_AUX_ADC_UNDERVOLTAGE_REG       0x12 /* D7 to D0, Read/write */
+
+#define AD7280A_ALERT_REG                      0x13 /* D7 to D0, Read/write */
+#define   AD7280A_ALERT_REMOVE_MSK                     GENMASK(3, 0)
+#define     AD7280A_ALERT_REMOVE_AUX5                  BIT(0)
+#define     AD7280A_ALERT_REMOVE_AUX3_AUX5             BIT(1)
+#define     AD7280A_ALERT_REMOVE_VIN5                  BIT(2)
+#define     AD7280A_ALERT_REMOVE_VIN4_VIN5             BIT(3)
+#define   AD7280A_ALERT_GEN_STATIC_HIGH                        BIT(6)
+#define   AD7280A_ALERT_RELAY_SIG_CHAIN_DOWN           (BIT(7) | BIT(6))
+
+#define AD7280A_CELL_BALANCE_REG               0x14 /* D7 to D0, Read/write */
+#define  AD7280A_CELL_BALANCE_CHAN_BITMAP_MSK          GENMASK(7, 2)
+#define AD7280A_CB1_TIMER_REG                  0x15 /* D7 to D0, Read/write */
+#define  AD7280A_CB_TIMER_VAL_MSK                      GENMASK(7, 3)
+#define AD7280A_CB2_TIMER_REG                  0x16 /* D7 to D0, Read/write */
+#define AD7280A_CB3_TIMER_REG                  0x17 /* D7 to D0, Read/write */
+#define AD7280A_CB4_TIMER_REG                  0x18 /* D7 to D0, Read/write */
+#define AD7280A_CB5_TIMER_REG                  0x19 /* D7 to D0, Read/write */
+#define AD7280A_CB6_TIMER_REG                  0x1A /* D7 to D0, Read/write */
+#define AD7280A_PD_TIMER_REG                   0x1B /* D7 to D0, Read/write */
+#define AD7280A_READ_REG                       0x1C /* D7 to D0, Read/write */
+#define   AD7280A_READ_ADDR_MSK                                GENMASK(7, 2)
+#define AD7280A_CNVST_CTRL_REG                 0x1D /* D7 to D0, Read/write */
+
+/* Transfer fields */
+#define AD7280A_TRANS_WRITE_DEVADDR_MSK                GENMASK(31, 27)
+#define AD7280A_TRANS_WRITE_ADDR_MSK           GENMASK(26, 21)
+#define AD7280A_TRANS_WRITE_VAL_MSK            GENMASK(20, 13)
+#define AD7280A_TRANS_WRITE_ALL_MSK            BIT(12)
+#define AD7280A_TRANS_WRITE_CRC_MSK            GENMASK(10, 3)
+#define AD7280A_TRANS_WRITE_RES_PATTERN                0x2
+
+/* Layouts differ for channel vs other registers */
+#define AD7280A_TRANS_READ_DEVADDR_MSK         GENMASK(31, 27)
+#define AD7280A_TRANS_READ_CONV_CHANADDR_MSK   GENMASK(26, 23)
+#define AD7280A_TRANS_READ_CONV_DATA_MSK       GENMASK(22, 11)
+#define AD7280A_TRANS_READ_REG_REGADDR_MSK     GENMASK(26, 21)
+#define AD7280A_TRANS_READ_REG_DATA_MSK                GENMASK(20, 13)
+#define AD7280A_TRANS_READ_WRITE_ACK_MSK       BIT(10)
+#define AD7280A_TRANS_READ_CRC_MSK             GENMASK(9, 2)
+
+/* Magic value used to indicate this special case */
+#define AD7280A_ALL_CELLS                              (0xAD << 16)
+
+#define AD7280A_MAX_SPI_CLK_HZ         700000 /* < 1MHz */
+#define AD7280A_MAX_CHAIN              8
+#define AD7280A_CELLS_PER_DEV          6
+#define AD7280A_BITS                   12
+#define AD7280A_NUM_CH                 (AD7280A_AUX_ADC_6_REG - \
+                                       AD7280A_CELL_VOLTAGE_1_REG + 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_DEVADDR_MASTER         0
+#define AD7280A_DEVADDR_ALL            0x1F
+
+static const unsigned short ad7280a_n_avg[4] = {1, 2, 4, 8};
+static const unsigned short ad7280a_t_acq_ns[4] = {470, 1030, 1510, 1945};
+
+/* 5-bit device address is sent LSB first */
+static unsigned int ad7280a_devaddr(unsigned int addr)
+{
+       return ((addr & 0x1) << 4) |
+              ((addr & 0x2) << 2) |
+              (addr & 0x4) |
+              ((addr & 0x8) >> 2) |
+              ((addr & 0x10) >> 4);
+}
+
+/*
+ * During a read a valid write is mandatory.
+ * So writing to the highest available address (Address 0x1F) and setting the
+ * address all parts bit to 0 is recommended.
+ * So the TXVAL is AD7280A_DEVADDR_ALL + CRC
+ */
+#define AD7280A_READ_TXVAL     0xF800030A
+
+/*
+ * AD7280 CRC
+ *
+ * P(x) = x^8 + x^5 + x^3 + x^2 + x^1 + x^0 = 0b100101111 => 0x2F
+ */
+#define POLYNOM                0x2F
+
+struct ad7280_state {
+       struct spi_device               *spi;
+       struct iio_chan_spec            *channels;
+       unsigned int                    chain_last_alert_ignore;
+       bool                            thermistor_term_en;
+       int                             slave_num;
+       int                             scan_cnt;
+       int                             readback_delay_us;
+       unsigned char                   crc_tab[CRC8_TABLE_SIZE];
+       u8                              oversampling_ratio;
+       u8                              acquisition_time;
+       unsigned char                   ctrl_lb;
+       unsigned char                   cell_threshhigh;
+       unsigned char                   cell_threshlow;
+       unsigned char                   aux_threshhigh;
+       unsigned char                   aux_threshlow;
+       unsigned char                   cb_mask[AD7280A_MAX_CHAIN];
+       struct mutex                    lock; /* protect sensor state */
+
+       __be32                          tx ____cacheline_aligned;
+       __be32                          rx;
+};
+
+static unsigned char ad7280_calc_crc8(unsigned char *crc_tab, unsigned int val)
+{
+       unsigned char crc;
+
+       crc = crc_tab[val >> 16 & 0xFF];
+       crc = crc_tab[crc ^ (val >> 8 & 0xFF)];
+
+       return crc ^ (val & 0xFF);
+}
+
+static int ad7280_check_crc(struct ad7280_state *st, unsigned int val)
+{
+       unsigned char crc = ad7280_calc_crc8(st->crc_tab, val >> 10);
+
+       if (crc != ((val >> 2) & 0xFF))
+               return -EIO;
+
+       return 0;
+}
+
+/*
+ * After initiating a conversion sequence we need to wait until the conversion
+ * is done. The delay is typically in the range of 15..30us however depending on
+ * the number of devices in the daisy chain, the number of averages taken,
+ * conversion delays and acquisition time options it may take up to 250us, in
+ * this case we better sleep instead of busy wait.
+ */
+
+static void ad7280_delay(struct ad7280_state *st)
+{
+       if (st->readback_delay_us < 50)
+               udelay(st->readback_delay_us);
+       else
+               usleep_range(250, 500);
+}
+
+static int __ad7280_read32(struct ad7280_state *st, unsigned int *val)
+{
+       int ret;
+       struct spi_transfer t = {
+               .tx_buf = &st->tx,
+               .rx_buf = &st->rx,
+               .len = sizeof(st->tx),
+       };
+
+       st->tx = cpu_to_be32(AD7280A_READ_TXVAL);
+
+       ret = spi_sync_transfer(st->spi, &t, 1);
+       if (ret)
+               return ret;
+
+       *val = be32_to_cpu(st->rx);
+
+       return 0;
+}
+
+static int ad7280_write(struct ad7280_state *st, unsigned int devaddr,
+                       unsigned int addr, bool all, unsigned int val)
+{
+       unsigned int reg = FIELD_PREP(AD7280A_TRANS_WRITE_DEVADDR_MSK, devaddr) |
+               FIELD_PREP(AD7280A_TRANS_WRITE_ADDR_MSK, addr) |
+               FIELD_PREP(AD7280A_TRANS_WRITE_VAL_MSK, val) |
+               FIELD_PREP(AD7280A_TRANS_WRITE_ALL_MSK, all);
+
+       reg |= FIELD_PREP(AD7280A_TRANS_WRITE_CRC_MSK,
+                       ad7280_calc_crc8(st->crc_tab, reg >> 11));
+       /* Reserved b010 pattern not included crc calc */
+       reg |= AD7280A_TRANS_WRITE_RES_PATTERN;
+
+       st->tx = cpu_to_be32(reg);
+
+       return spi_write(st->spi, &st->tx, sizeof(st->tx));
+}
+
+static int ad7280_read_reg(struct ad7280_state *st, unsigned int devaddr,
+                          unsigned int addr)
+{
+       int ret;
+       unsigned int tmp;
+
+       /* turns off the read operation on all parts */
+       ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1,
+                          FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK,
+                                     AD7280A_CTRL_HB_CONV_INPUT_ALL) |
+                          FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK,
+                                     AD7280A_CTRL_HB_CONV_RREAD_NO) |
+                          FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK,
+                                     st->oversampling_ratio));
+       if (ret)
+               return ret;
+
+       /* turns on the read operation on the addressed part */
+       ret = ad7280_write(st, devaddr, AD7280A_CTRL_HB_REG, 0,
+                          FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK,
+                                     AD7280A_CTRL_HB_CONV_INPUT_ALL) |
+                          FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK,
+                                     AD7280A_CTRL_HB_CONV_RREAD_ALL) |
+                          FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK,
+                                     st->oversampling_ratio));
+       if (ret)
+               return ret;
+
+       /* Set register address on the part to be read from */
+       ret = ad7280_write(st, devaddr, AD7280A_READ_REG, 0,
+                          FIELD_PREP(AD7280A_READ_ADDR_MSK, addr));
+       if (ret)
+               return ret;
+
+       ret = __ad7280_read32(st, &tmp);
+       if (ret)
+               return ret;
+
+       if (ad7280_check_crc(st, tmp))
+               return -EIO;
+
+       if ((FIELD_GET(AD7280A_TRANS_READ_DEVADDR_MSK, tmp) != devaddr) ||
+           (FIELD_GET(AD7280A_TRANS_READ_REG_REGADDR_MSK, tmp) != addr))
+               return -EFAULT;
+
+       return FIELD_GET(AD7280A_TRANS_READ_REG_DATA_MSK, tmp);
+}
+
+static int ad7280_read_channel(struct ad7280_state *st, unsigned int devaddr,
+                              unsigned int addr)
+{
+       int ret;
+       unsigned int tmp;
+
+       ret = ad7280_write(st, devaddr, AD7280A_READ_REG, 0,
+                          FIELD_PREP(AD7280A_READ_ADDR_MSK, addr));
+       if (ret)
+               return ret;
+
+       ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1,
+                          FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK,
+                                     AD7280A_CTRL_HB_CONV_INPUT_ALL) |
+                          FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK,
+                                     AD7280A_CTRL_HB_CONV_RREAD_NO) |
+                          FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK,
+                                     st->oversampling_ratio));
+       if (ret)
+               return ret;
+
+       ret = ad7280_write(st, devaddr, AD7280A_CTRL_HB_REG, 0,
+                          FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK,
+                                     AD7280A_CTRL_HB_CONV_INPUT_ALL) |
+                          FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK,
+                                     AD7280A_CTRL_HB_CONV_RREAD_ALL) |
+                          FIELD_PREP(AD7280A_CTRL_HB_CONV_START_MSK,
+                                     AD7280A_CTRL_HB_CONV_START_CS) |
+                          FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK,
+                                     st->oversampling_ratio));
+       if (ret)
+               return ret;
+
+       ad7280_delay(st);
+
+       ret = __ad7280_read32(st, &tmp);
+       if (ret)
+               return ret;
+
+       if (ad7280_check_crc(st, tmp))
+               return -EIO;
+
+       if ((FIELD_GET(AD7280A_TRANS_READ_DEVADDR_MSK, tmp) != devaddr) ||
+           (FIELD_GET(AD7280A_TRANS_READ_CONV_CHANADDR_MSK, tmp) != addr))
+               return -EFAULT;
+
+       return FIELD_GET(AD7280A_TRANS_READ_CONV_DATA_MSK, tmp);
+}
+
+static int ad7280_read_all_channels(struct ad7280_state *st, unsigned int cnt,
+                                   unsigned int *array)
+{
+       int i, ret;
+       unsigned int tmp, sum = 0;
+
+       ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_READ_REG, 1,
+                          AD7280A_CELL_VOLTAGE_1_REG << 2);
+       if (ret)
+               return ret;
+
+       ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1,
+                          FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK,
+                                     AD7280A_CTRL_HB_CONV_INPUT_ALL) |
+                          FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK,
+                                     AD7280A_CTRL_HB_CONV_RREAD_ALL) |
+                          FIELD_PREP(AD7280A_CTRL_HB_CONV_START_MSK,
+                                     AD7280A_CTRL_HB_CONV_START_CS) |
+                          FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK,
+                                     st->oversampling_ratio));
+       if (ret)
+               return ret;
+
+       ad7280_delay(st);
+
+       for (i = 0; i < cnt; i++) {
+               ret = __ad7280_read32(st, &tmp);
+               if (ret)
+                       return ret;
+
+               if (ad7280_check_crc(st, tmp))
+                       return -EIO;
+
+               if (array)
+                       array[i] = tmp;
+               /* only sum cell voltages */
+               if (FIELD_GET(AD7280A_TRANS_READ_CONV_CHANADDR_MSK, tmp) <=
+                   AD7280A_CELL_VOLTAGE_6_REG)
+                       sum += FIELD_GET(AD7280A_TRANS_READ_CONV_DATA_MSK, tmp);
+       }
+
+       return sum;
+}
+
+static void ad7280_sw_power_down(void *data)
+{
+       struct ad7280_state *st = data;
+
+       ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1,
+                    AD7280A_CTRL_HB_PWRDN_SW |
+                    FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, st->oversampling_ratio));
+}
+
+static int ad7280_chain_setup(struct ad7280_state *st)
+{
+       unsigned int val, n;
+       int ret;
+
+       ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_LB_REG, 1,
+                          FIELD_PREP(AD7280A_CTRL_LB_DAISY_CHAIN_RB_MSK, 1) |
+                          FIELD_PREP(AD7280A_CTRL_LB_LOCK_DEV_ADDR_MSK, 1) |
+                          AD7280A_CTRL_LB_MUST_SET |
+                          FIELD_PREP(AD7280A_CTRL_LB_SWRST_MSK, 1) |
+                          st->ctrl_lb);
+       if (ret)
+               return ret;
+
+       ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_LB_REG, 1,
+                          FIELD_PREP(AD7280A_CTRL_LB_DAISY_CHAIN_RB_MSK, 1) |
+                          FIELD_PREP(AD7280A_CTRL_LB_LOCK_DEV_ADDR_MSK, 1) |
+                          AD7280A_CTRL_LB_MUST_SET |
+                          FIELD_PREP(AD7280A_CTRL_LB_SWRST_MSK, 0) |
+                          st->ctrl_lb);
+       if (ret)
+               goto error_power_down;
+
+       ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_READ_REG, 1,
+                          FIELD_PREP(AD7280A_READ_ADDR_MSK, AD7280A_CTRL_LB_REG));
+       if (ret)
+               goto error_power_down;
+
+       for (n = 0; n <= AD7280A_MAX_CHAIN; n++) {
+               ret = __ad7280_read32(st, &val);
+               if (ret)
+                       goto error_power_down;
+
+               if (val == 0)
+                       return n - 1;
+
+               if (ad7280_check_crc(st, val)) {
+                       ret = -EIO;
+                       goto error_power_down;
+               }
+
+               if (n != ad7280a_devaddr(FIELD_GET(AD7280A_TRANS_READ_DEVADDR_MSK, val))) {
+                       ret = -EIO;
+                       goto error_power_down;
+               }
+       }
+       ret = -EFAULT;
+
+error_power_down:
+       ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1,
+                    AD7280A_CTRL_HB_PWRDN_SW |
+                    FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, st->oversampling_ratio));
+
+       return ret;
+}
+
+static ssize_t ad7280_show_balance_sw(struct iio_dev *indio_dev,
+                                     uintptr_t private,
+                                     const struct iio_chan_spec *chan, char *buf)
+{
+       struct ad7280_state *st = iio_priv(indio_dev);
+
+       return sysfs_emit(buf, "%d\n",
+                         !!(st->cb_mask[chan->address >> 8] &
+                            BIT(chan->address & 0xFF)));
+}
+
+static ssize_t ad7280_store_balance_sw(struct iio_dev *indio_dev,
+                                      uintptr_t private,
+                                      const struct iio_chan_spec *chan,
+                                      const char *buf, size_t len)
+{
+       struct ad7280_state *st = iio_priv(indio_dev);
+       unsigned int devaddr, ch;
+       bool readin;
+       int ret;
+
+       ret = strtobool(buf, &readin);
+       if (ret)
+               return ret;
+
+       devaddr = chan->address >> 8;
+       ch = chan->address & 0xFF;
+
+       mutex_lock(&st->lock);
+       if (readin)
+               st->cb_mask[devaddr] |= BIT(ch);
+       else
+               st->cb_mask[devaddr] &= ~BIT(ch);
+
+       ret = ad7280_write(st, devaddr, AD7280A_CELL_BALANCE_REG, 0,
+                          FIELD_PREP(AD7280A_CELL_BALANCE_CHAN_BITMAP_MSK,
+                                     st->cb_mask[devaddr]));
+       mutex_unlock(&st->lock);
+
+       return ret ? ret : len;
+}
+
+static ssize_t ad7280_show_balance_timer(struct iio_dev *indio_dev,
+                                        uintptr_t private,
+                                        const struct iio_chan_spec *chan,
+                                        char *buf)
+{
+       struct ad7280_state *st = iio_priv(indio_dev);
+       unsigned int msecs;
+       int ret;
+
+       mutex_lock(&st->lock);
+       ret = ad7280_read_reg(st, chan->address >> 8,
+                             (chan->address & 0xFF) + AD7280A_CB1_TIMER_REG);
+       mutex_unlock(&st->lock);
+
+       if (ret < 0)
+               return ret;
+
+       msecs = FIELD_GET(AD7280A_CB_TIMER_VAL_MSK, ret) * 71500;
+
+       return sysfs_emit(buf, "%u.%u\n", msecs / 1000, msecs % 1000);
+}
+
+static ssize_t ad7280_store_balance_timer(struct iio_dev *indio_dev,
+                                         uintptr_t private,
+                                         const struct iio_chan_spec *chan,
+                                         const char *buf, size_t len)
+{
+       struct ad7280_state *st = iio_priv(indio_dev);
+       int val, val2;
+       int ret;
+
+       ret = iio_str_to_fixpoint(buf, 1000, &val, &val2);
+       if (ret)
+               return ret;
+
+       val = val * 1000 + val2;
+       val /= 71500;
+
+       if (val > 31)
+               return -EINVAL;
+
+       mutex_lock(&st->lock);
+       ret = ad7280_write(st, chan->address >> 8,
+                          (chan->address & 0xFF) + AD7280A_CB1_TIMER_REG, 0,
+                          FIELD_PREP(AD7280A_CB_TIMER_VAL_MSK, val));
+       mutex_unlock(&st->lock);
+
+       return ret ? ret : len;
+}
+
+static const struct iio_chan_spec_ext_info ad7280_cell_ext_info[] = {
+       {
+               .name = "balance_switch_en",
+               .read = ad7280_show_balance_sw,
+               .write = ad7280_store_balance_sw,
+               .shared = IIO_SEPARATE,
+       }, {
+               .name = "balance_switch_timer",
+               .read = ad7280_show_balance_timer,
+               .write = ad7280_store_balance_timer,
+               .shared = IIO_SEPARATE,
+       },
+       {}
+};
+
+static const struct iio_event_spec ad7280_events[] = {
+       {
+               .type = IIO_EV_TYPE_THRESH,
+               .dir = IIO_EV_DIR_RISING,
+               .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE),
+       }, {
+               .type = IIO_EV_TYPE_THRESH,
+               .dir = IIO_EV_DIR_FALLING,
+               .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE),
+       },
+};
+
+static void ad7280_voltage_channel_init(struct iio_chan_spec *chan, int i,
+                                       bool irq_present)
+{
+       chan->type = IIO_VOLTAGE;
+       chan->differential = 1;
+       chan->channel = i;
+       chan->channel2 = chan->channel + 1;
+       if (irq_present) {
+               chan->event_spec = ad7280_events;
+               chan->num_event_specs = ARRAY_SIZE(ad7280_events);
+       }
+       chan->ext_info = ad7280_cell_ext_info;
+}
+
+static void ad7280_temp_channel_init(struct iio_chan_spec *chan, int i,
+                                    bool irq_present)
+{
+       chan->type = IIO_TEMP;
+       chan->channel = i;
+       if (irq_present) {
+               chan->event_spec = ad7280_events;
+               chan->num_event_specs = ARRAY_SIZE(ad7280_events);
+       }
+}
+
+static void ad7280_common_fields_init(struct iio_chan_spec *chan, int addr,
+                                     int cnt)
+{
+       chan->indexed = 1;
+       chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
+       chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
+       chan->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
+       chan->address = addr;
+       chan->scan_index = cnt;
+       chan->scan_type.sign = 'u';
+       chan->scan_type.realbits = 12;
+       chan->scan_type.storagebits = 32;
+}
+
+static void ad7280_total_voltage_channel_init(struct iio_chan_spec *chan,
+                                             int cnt, int dev)
+{
+       chan->type = IIO_VOLTAGE;
+       chan->differential = 1;
+       chan->channel = 0;
+       chan->channel2 = dev * AD7280A_CELLS_PER_DEV;
+       chan->address = AD7280A_ALL_CELLS;
+       chan->indexed = 1;
+       chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
+       chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
+       chan->scan_index = cnt;
+       chan->scan_type.sign = 'u';
+       chan->scan_type.realbits = 32;
+       chan->scan_type.storagebits = 32;
+}
+
+static void ad7280_init_dev_channels(struct ad7280_state *st, int dev, int *cnt,
+                                    bool irq_present)
+{
+       int addr, ch, i;
+       struct iio_chan_spec *chan;
+
+       for (ch = AD7280A_CELL_VOLTAGE_1_REG; ch <= AD7280A_AUX_ADC_6_REG; ch++) {
+               chan = &st->channels[*cnt];
+
+               if (ch < AD7280A_AUX_ADC_1_REG) {
+                       i = AD7280A_CALC_VOLTAGE_CHAN_NUM(dev, ch);
+                       ad7280_voltage_channel_init(chan, i, irq_present);
+               } else {
+                       i = AD7280A_CALC_TEMP_CHAN_NUM(dev, ch);
+                       ad7280_temp_channel_init(chan, i, irq_present);
+               }
+
+               addr = ad7280a_devaddr(dev) << 8 | ch;
+               ad7280_common_fields_init(chan, addr, *cnt);
+
+               (*cnt)++;
+       }
+}
+
+static int ad7280_channel_init(struct ad7280_state *st, bool irq_present)
+{
+       int dev, cnt = 0;
+
+       st->channels = devm_kcalloc(&st->spi->dev, (st->slave_num + 1) * 12 + 1,
+                                   sizeof(*st->channels), GFP_KERNEL);
+       if (!st->channels)
+               return -ENOMEM;
+
+       for (dev = 0; dev <= st->slave_num; dev++)
+               ad7280_init_dev_channels(st, dev, &cnt, irq_present);
+
+       ad7280_total_voltage_channel_init(&st->channels[cnt], cnt, dev);
+
+       return cnt + 1;
+}
+
+static int ad7280a_read_thresh(struct iio_dev *indio_dev,
+                              const struct iio_chan_spec *chan,
+                              enum iio_event_type type,
+                              enum iio_event_direction dir,
+                              enum iio_event_info info, int *val, int *val2)
+{
+       struct ad7280_state *st = iio_priv(indio_dev);
+
+       switch (chan->type) {
+       case IIO_VOLTAGE:
+               switch (dir) {
+               case IIO_EV_DIR_RISING:
+                       *val = 1000 + (st->cell_threshhigh * 1568L) / 100;
+                       return IIO_VAL_INT;
+               case IIO_EV_DIR_FALLING:
+                       *val = 1000 + (st->cell_threshlow * 1568L) / 100;
+                       return IIO_VAL_INT;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case IIO_TEMP:
+               switch (dir) {
+               case IIO_EV_DIR_RISING:
+                       *val = ((st->aux_threshhigh) * 196L) / 10;
+                       return IIO_VAL_INT;
+               case IIO_EV_DIR_FALLING:
+                       *val = (st->aux_threshlow * 196L) / 10;
+                       return IIO_VAL_INT;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ad7280a_write_thresh(struct iio_dev *indio_dev,
+                               const struct iio_chan_spec *chan,
+                               enum iio_event_type type,
+                               enum iio_event_direction dir,
+                               enum iio_event_info info,
+                               int val, int val2)
+{
+       struct ad7280_state *st = iio_priv(indio_dev);
+       unsigned int addr;
+       long value;
+       int ret;
+
+       if (val2 != 0)
+               return -EINVAL;
+
+       mutex_lock(&st->lock);
+       switch (chan->type) {
+       case IIO_VOLTAGE:
+               value = ((val - 1000) * 100) / 1568; /* LSB 15.68mV */
+               value = clamp(value, 0L, 0xFFL);
+               switch (dir) {
+               case IIO_EV_DIR_RISING:
+                       addr = AD7280A_CELL_OVERVOLTAGE_REG;
+                       ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr,
+                                          1, val);
+                       if (ret)
+                               break;
+                       st->cell_threshhigh = value;
+                       break;
+               case IIO_EV_DIR_FALLING:
+                       addr = AD7280A_CELL_UNDERVOLTAGE_REG;
+                       ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr,
+                                          1, val);
+                       if (ret)
+                               break;
+                       st->cell_threshlow = value;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       goto err_unlock;
+               }
+               break;
+       case IIO_TEMP:
+               value = (val * 10) / 196; /* LSB 19.6mV */
+               value = clamp(value, 0L, 0xFFL);
+               switch (dir) {
+               case IIO_EV_DIR_RISING:
+                       addr = AD7280A_AUX_ADC_OVERVOLTAGE_REG;
+                       ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr,
+                                          1, val);
+                       if (ret)
+                               break;
+                       st->aux_threshhigh = val;
+                       break;
+               case IIO_EV_DIR_FALLING:
+                       addr = AD7280A_AUX_ADC_UNDERVOLTAGE_REG;
+                       ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr,
+                                          1, val);
+                       if (ret)
+                               break;
+                       st->aux_threshlow = val;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       goto err_unlock;
+               }
+               break;
+       default:
+               ret = -EINVAL;
+               goto err_unlock;
+       }
+
+err_unlock:
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static irqreturn_t ad7280_event_handler(int irq, void *private)
+{
+       struct iio_dev *indio_dev = private;
+       struct ad7280_state *st = iio_priv(indio_dev);
+       unsigned int *channels;
+       int i, ret;
+
+       channels = kcalloc(st->scan_cnt, sizeof(*channels), GFP_KERNEL);
+       if (!channels)
+               return IRQ_HANDLED;
+
+       ret = ad7280_read_all_channels(st, st->scan_cnt, channels);
+       if (ret < 0)
+               goto out;
+
+       for (i = 0; i < st->scan_cnt; i++) {
+               unsigned int val;
+
+               val = FIELD_GET(AD7280A_TRANS_READ_CONV_DATA_MSK, channels[i]);
+               if (FIELD_GET(AD7280A_TRANS_READ_CONV_CHANADDR_MSK, channels[i]) <=
+                   AD7280A_CELL_VOLTAGE_6_REG) {
+                       if (val >= 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 (val <= 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 (val >= st->aux_threshhigh) {
+                               u64 tmp = IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0,
+                                                       IIO_EV_TYPE_THRESH,
+                                                       IIO_EV_DIR_RISING);
+                               iio_push_event(indio_dev, tmp,
+                                              iio_get_time_ns(indio_dev));
+                       } else if (val <= st->aux_threshlow) {
+                               u64 tmp = IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0,
+                                                       IIO_EV_TYPE_THRESH,
+                                                       IIO_EV_DIR_FALLING);
+                               iio_push_event(indio_dev, tmp,
+                                              iio_get_time_ns(indio_dev));
+                       }
+               }
+       }
+
+out:
+       kfree(channels);
+
+       return IRQ_HANDLED;
+}
+
+static void ad7280_update_delay(struct ad7280_state *st)
+{
+       /*
+        * Total Conversion Time = ((tACQ + tCONV) *
+        *                         (Number of Conversions per Part)) âˆ’
+        *                         tACQ + ((N - 1) * tDELAY)
+        *
+        * Readback Delay = Total Conversion Time + tWAIT
+        */
+
+       st->readback_delay_us =
+               ((ad7280a_t_acq_ns[st->acquisition_time & 0x3] + 720) *
+                       (AD7280A_NUM_CH * ad7280a_n_avg[st->oversampling_ratio & 0x3])) -
+               ad7280a_t_acq_ns[st->acquisition_time & 0x3] + st->slave_num * 250;
+
+       /* Convert to usecs */
+       st->readback_delay_us = DIV_ROUND_UP(st->readback_delay_us, 1000);
+       st->readback_delay_us += 5; /* Add tWAIT */
+}
+
+static int ad7280_read_raw(struct iio_dev *indio_dev,
+                          struct iio_chan_spec const *chan,
+                          int *val,
+                          int *val2,
+                          long m)
+{
+       struct ad7280_state *st = iio_priv(indio_dev);
+       int ret;
+
+       switch (m) {
+       case IIO_CHAN_INFO_RAW:
+               mutex_lock(&st->lock);
+               if (chan->address == AD7280A_ALL_CELLS)
+                       ret = ad7280_read_all_channels(st, st->scan_cnt, NULL);
+               else
+                       ret = ad7280_read_channel(st, chan->address >> 8,
+                                                 chan->address & 0xFF);
+               mutex_unlock(&st->lock);
+
+               if (ret < 0)
+                       return ret;
+
+               *val = ret;
+
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               if ((chan->address & 0xFF) <= AD7280A_CELL_VOLTAGE_6_REG)
+                       *val = 4000;
+               else
+                       *val = 5000;
+
+               *val2 = AD7280A_BITS;
+               return IIO_VAL_FRACTIONAL_LOG2;
+       case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+               *val = ad7280a_n_avg[st->oversampling_ratio];
+               return IIO_VAL_INT;
+       }
+       return -EINVAL;
+}
+
+static int ad7280_write_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int val, int val2, long mask)
+{
+       struct ad7280_state *st = iio_priv(indio_dev);
+       int i;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+               if (val2 != 0)
+                       return -EINVAL;
+               for (i = 0; i < ARRAY_SIZE(ad7280a_n_avg); i++) {
+                       if (val == ad7280a_n_avg[i]) {
+                               st->oversampling_ratio = i;
+                               ad7280_update_delay(st);
+                               return 0;
+                       }
+               }
+               return -EINVAL;
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct iio_info ad7280_info = {
+       .read_raw = ad7280_read_raw,
+       .write_raw = ad7280_write_raw,
+       .read_event_value = &ad7280a_read_thresh,
+       .write_event_value = &ad7280a_write_thresh,
+};
+
+static const struct iio_info ad7280_info_no_irq = {
+       .read_raw = ad7280_read_raw,
+       .write_raw = ad7280_write_raw,
+};
+
+static int ad7280_probe(struct spi_device *spi)
+{
+       struct device *dev = &spi->dev;
+       struct ad7280_state *st;
+       int ret;
+       struct iio_dev *indio_dev;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       st = iio_priv(indio_dev);
+       spi_set_drvdata(spi, indio_dev);
+       st->spi = spi;
+       mutex_init(&st->lock);
+
+       st->thermistor_term_en =
+               device_property_read_bool(dev, "adi,thermistor-termination");
+
+       if (device_property_present(dev, "adi,acquisition-time-ns")) {
+               u32 val;
+
+               ret = device_property_read_u32(dev, "adi,acquisition-time-ns", &val);
+               if (ret)
+                       return ret;
+
+               switch (val) {
+               case 400:
+                       st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_400ns;
+                       break;
+               case 800:
+                       st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_800ns;
+                       break;
+               case 1200:
+                       st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_1200ns;
+                       break;
+               case 1600:
+                       st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_1600ns;
+                       break;
+               default:
+                       dev_err(dev, "Firmware provided acquisition time is invalid\n");
+                       return -EINVAL;
+               }
+       } else {
+               st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_400ns;
+       }
+
+       /* Alert masks are intended for when particular inputs are not wired up */
+       if (device_property_present(dev, "adi,voltage-alert-last-chan")) {
+               u32 val;
+
+               ret = device_property_read_u32(dev, "adi,voltage-alert-last-chan", &val);
+               if (ret)
+                       return ret;
+
+               switch (val) {
+               case 3:
+                       st->chain_last_alert_ignore |= AD7280A_ALERT_REMOVE_VIN4_VIN5;
+                       break;
+               case 4:
+                       st->chain_last_alert_ignore |= AD7280A_ALERT_REMOVE_VIN5;
+                       break;
+               case 5:
+                       break;
+               default:
+                       dev_err(dev,
+                               "Firmware provided last voltage alert channel invalid\n");
+                       break;
+               }
+       }
+       crc8_populate_msb(st->crc_tab, POLYNOM);
+
+       st->spi->max_speed_hz = AD7280A_MAX_SPI_CLK_HZ;
+       st->spi->mode = SPI_MODE_1;
+       spi_setup(st->spi);
+
+       st->ctrl_lb = FIELD_PREP(AD7280A_CTRL_LB_ACQ_TIME_MSK, st->acquisition_time) |
+               FIELD_PREP(AD7280A_CTRL_LB_THERMISTOR_MSK, st->thermistor_term_en);
+       st->oversampling_ratio = 0; /* No oversampling */
+
+       ret = ad7280_chain_setup(st);
+       if (ret < 0)
+               return ret;
+
+       st->slave_num = ret;
+       st->scan_cnt = (st->slave_num + 1) * AD7280A_NUM_CH;
+       st->cell_threshhigh = 0xFF;
+       st->aux_threshhigh = 0xFF;
+
+       ret = devm_add_action_or_reset(dev, ad7280_sw_power_down, st);
+       if (ret)
+               return ret;
+
+       ad7280_update_delay(st);
+
+       indio_dev->name = spi_get_device_id(spi)->name;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = ad7280_channel_init(st, spi->irq > 0);
+       if (ret < 0)
+               return ret;
+
+       indio_dev->num_channels = ret;
+       indio_dev->channels = st->channels;
+       if (spi->irq > 0) {
+               ret = ad7280_write(st, AD7280A_DEVADDR_MASTER,
+                                  AD7280A_ALERT_REG, 1,
+                                  AD7280A_ALERT_RELAY_SIG_CHAIN_DOWN);
+               if (ret)
+                       return ret;
+
+               ret = ad7280_write(st, ad7280a_devaddr(st->slave_num),
+                                  AD7280A_ALERT_REG, 0,
+                                  AD7280A_ALERT_GEN_STATIC_HIGH |
+                                  FIELD_PREP(AD7280A_ALERT_REMOVE_MSK,
+                                             st->chain_last_alert_ignore));
+               if (ret)
+                       return ret;
+
+               ret = devm_request_threaded_irq(dev, spi->irq,
+                                               NULL,
+                                               ad7280_event_handler,
+                                               IRQF_TRIGGER_FALLING |
+                                               IRQF_ONESHOT,
+                                               indio_dev->name,
+                                               indio_dev);
+               if (ret)
+                       return ret;
+
+               indio_dev->info = &ad7280_info;
+       } else {
+               indio_dev->info = &ad7280_info_no_irq;
+       }
+
+       return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct spi_device_id ad7280_id[] = {
+       {"ad7280a", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(spi, ad7280_id);
+
+static struct spi_driver ad7280_driver = {
+       .driver = {
+               .name   = "ad7280",
+       },
+       .probe          = ad7280_probe,
+       .id_table       = ad7280_id,
+};
+module_spi_driver(ad7280_driver);
+
+MODULE_AUTHOR("Michael Hennerich <[email protected]>");
+MODULE_DESCRIPTION("Analog Devices AD7280A");
+MODULE_LICENSE("GPL v2");
index 0a60ecc69d38e12dfcf828a057004cdb8b5294c2..3b193dc26438b4809342e1617f1acab1d7018126 100644 (file)
@@ -693,7 +693,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
 
        return devm_iio_device_register(dev, indio_dev);
 }
-EXPORT_SYMBOL_GPL(ad7606_probe);
+EXPORT_SYMBOL_NS_GPL(ad7606_probe, IIO_AD7606);
 
 #ifdef CONFIG_PM_SLEEP
 
@@ -725,7 +725,7 @@ static int ad7606_resume(struct device *dev)
 }
 
 SIMPLE_DEV_PM_OPS(ad7606_pm_ops, ad7606_suspend, ad7606_resume);
-EXPORT_SYMBOL_GPL(ad7606_pm_ops);
+EXPORT_SYMBOL_NS_GPL(ad7606_pm_ops, IIO_AD7606);
 
 #endif
 
index f732b3ac78785444de9ed38b09ad4bd6a5b87b91..8888e56b5e90e6e91c649fbe1e5e9c948c561f16 100644 (file)
@@ -101,3 +101,4 @@ module_platform_driver(ad7606_driver);
 MODULE_AUTHOR("Michael Hennerich <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_AD7606);
index 29945ad07dca89bcb364c60e4ce1d2687cbeabb1..263a778bcf2539a3b6a6ce6f44b386367a1895d2 100644 (file)
@@ -362,3 +362,4 @@ module_spi_driver(ad7606_driver);
 MODULE_AUTHOR("Michael Hennerich <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_AD7606);
index b6e8c8abf6f4cdac9d357c78630a9186b68f8cb8..a813fe04787c6009c6b2eb5ad327d27319fc9e5b 100644 (file)
@@ -375,3 +375,4 @@ module_spi_driver(ad7780_driver);
 MODULE_AUTHOR("Michael Hennerich <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices AD7780 and similar ADCs");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA);
index cb579aa89f39c8443c9cec7c9d9fae61650ff002..fee8d129a5f0806530a98b8ab9e6681006337797 100644 (file)
@@ -474,3 +474,4 @@ module_spi_driver(ad7791_driver);
 MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices AD7787/AD7788/AD7789/AD7790/AD7791 ADC driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA);
index 0e7ab3fb072a961ecb6a0aaa60f36fa6110f4045..5f8cb9aaac705977dddf1d7cc00f7398fa605669 100644 (file)
@@ -867,3 +867,4 @@ module_spi_driver(ad7793_driver);
 MODULE_AUTHOR("Michael Hennerich <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices AD7793 and similar ADCs");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA);
index cd418bd8bd87df86f7d1f80351ef63ff3c7545b0..ebcd52526cac7c24080901f9517157580f040a1b 100644 (file)
@@ -42,7 +42,7 @@ void ad_sd_set_comm(struct ad_sigma_delta *sigma_delta, uint8_t comm)
         * to select the channel */
        sigma_delta->comm = comm & AD_SD_COMM_CHAN_MASK;
 }
-EXPORT_SYMBOL_GPL(ad_sd_set_comm);
+EXPORT_SYMBOL_NS_GPL(ad_sd_set_comm, IIO_AD_SIGMA_DELTA);
 
 /**
  * ad_sd_write_reg() - Write a register
@@ -94,7 +94,7 @@ int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(ad_sd_write_reg);
+EXPORT_SYMBOL_NS_GPL(ad_sd_write_reg, IIO_AD_SIGMA_DELTA);
 
 static int ad_sd_read_reg_raw(struct ad_sigma_delta *sigma_delta,
        unsigned int reg, unsigned int size, uint8_t *val)
@@ -171,7 +171,7 @@ int ad_sd_read_reg(struct ad_sigma_delta *sigma_delta,
 out:
        return ret;
 }
-EXPORT_SYMBOL_GPL(ad_sd_read_reg);
+EXPORT_SYMBOL_NS_GPL(ad_sd_read_reg, IIO_AD_SIGMA_DELTA);
 
 /**
  * ad_sd_reset() - Reset the serial interface
@@ -199,7 +199,7 @@ int ad_sd_reset(struct ad_sigma_delta *sigma_delta,
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(ad_sd_reset);
+EXPORT_SYMBOL_NS_GPL(ad_sd_reset, IIO_AD_SIGMA_DELTA);
 
 int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
        unsigned int mode, unsigned int channel)
@@ -238,7 +238,7 @@ out:
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(ad_sd_calibrate);
+EXPORT_SYMBOL_NS_GPL(ad_sd_calibrate, IIO_AD_SIGMA_DELTA);
 
 /**
  * ad_sd_calibrate_all() - Performs channel calibration
@@ -262,7 +262,7 @@ int ad_sd_calibrate_all(struct ad_sigma_delta *sigma_delta,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(ad_sd_calibrate_all);
+EXPORT_SYMBOL_NS_GPL(ad_sd_calibrate_all, IIO_AD_SIGMA_DELTA);
 
 /**
  * ad_sigma_delta_single_conversion() - Performs a single data conversion
@@ -337,7 +337,7 @@ out:
 
        return IIO_VAL_INT;
 }
-EXPORT_SYMBOL_GPL(ad_sigma_delta_single_conversion);
+EXPORT_SYMBOL_NS_GPL(ad_sigma_delta_single_conversion, IIO_AD_SIGMA_DELTA);
 
 static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
 {
@@ -465,7 +465,7 @@ int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(ad_sd_validate_trigger);
+EXPORT_SYMBOL_NS_GPL(ad_sd_validate_trigger, IIO_AD_SIGMA_DELTA);
 
 static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_dev)
 {
@@ -524,7 +524,7 @@ int devm_ad_sd_setup_buffer_and_trigger(struct device *dev, struct iio_dev *indi
 
        return devm_ad_sd_probe_trigger(dev, indio_dev);
 }
-EXPORT_SYMBOL_GPL(devm_ad_sd_setup_buffer_and_trigger);
+EXPORT_SYMBOL_NS_GPL(devm_ad_sd_setup_buffer_and_trigger, IIO_AD_SIGMA_DELTA);
 
 /**
  * ad_sd_init() - Initializes a ad_sigma_delta struct
@@ -545,7 +545,7 @@ int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(ad_sd_init);
+EXPORT_SYMBOL_NS_GPL(ad_sd_init, IIO_AD_SIGMA_DELTA);
 
 MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices Sigma-Delta ADCs");
index e939b84cbb561473303f68ed8525dbfeeb53b29d..0793d2474cdcfb6fc064d74ad38ee3d0460fdba5 100644 (file)
@@ -539,7 +539,9 @@ static int aspeed_adc_probe(struct platform_device *pdev)
        data->clk_scaler = devm_clk_hw_register_divider(
                &pdev->dev, clk_name, clk_parent_name, scaler_flags,
                data->base + ASPEED_REG_CLOCK_CONTROL, 0,
-               data->model_data->scaler_bit_width, 0, &data->clk_lock);
+               data->model_data->scaler_bit_width,
+               data->model_data->need_prescaler ? CLK_DIVIDER_ONE_BASED : 0,
+               &data->clk_lock);
        if (IS_ERR(data->clk_scaler))
                return PTR_ERR(data->clk_scaler);
 
index 5a7d3a3a5fa82f12a5f18ad7bb36cf9394273ca6..532daaa6f943ccf07e4c8dc88c4c3f39aff41bc2 100644 (file)
@@ -1234,7 +1234,6 @@ static int at91_adc_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int at91_adc_suspend(struct device *dev)
 {
        struct iio_dev *idev = dev_get_drvdata(dev);
@@ -1256,9 +1255,9 @@ static int at91_adc_resume(struct device *dev)
 
        return 0;
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(at91_adc_pm_ops, at91_adc_suspend, at91_adc_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(at91_adc_pm_ops, at91_adc_suspend,
+                               at91_adc_resume);
 
 static const struct at91_adc_trigger at91sam9260_triggers[] = {
        { .name = "timer-counter-0", .value = 0x1 },
@@ -1386,7 +1385,7 @@ static struct platform_driver at91_adc_driver = {
        .driver = {
                   .name = DRIVER_NAME,
                   .of_match_table = at91_adc_dt_ids,
-                  .pm = &at91_adc_pm_ops,
+                  .pm = pm_sleep_ptr(&at91_adc_pm_ops),
        },
 };
 
index 40e59f4c95bcdd32199e4984485e629c5cc6bd5a..b6c4ef70484ea01097824948bd098497132e9488 100644 (file)
@@ -474,7 +474,7 @@ static int cpcap_adc_calibrate_one(struct cpcap_adc *ddata,
        for (i = 0; i < CPCAP_ADC_MAX_RETRIES; i++) {
                calibration_data[0]  = 0;
                calibration_data[1]  = 0;
-               cal_data_diff = 0;
+
                cpcap_adc_setup_calibrate(ddata, channel);
                error = regmap_read(ddata->reg, calibration_register,
                                    &calibration_data[0]);
index 3b3868aa2533087f79c24d3c79b225403b4f4757..cff1ba57fb16a7f6a29d77eb759f1a4e522febff 100644 (file)
@@ -968,7 +968,6 @@ static int exynos_adc_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int exynos_adc_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
@@ -1001,11 +1000,9 @@ static int exynos_adc_resume(struct device *dev)
 
        return 0;
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(exynos_adc_pm_ops,
-                       exynos_adc_suspend,
-                       exynos_adc_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(exynos_adc_pm_ops, exynos_adc_suspend,
+                               exynos_adc_resume);
 
 static struct platform_driver exynos_adc_driver = {
        .probe          = exynos_adc_probe,
@@ -1013,7 +1010,7 @@ static struct platform_driver exynos_adc_driver = {
        .driver         = {
                .name   = "exynos-adc",
                .of_match_table = exynos_adc_match,
-               .pm     = &exynos_adc_pm_ops,
+               .pm     = pm_sleep_ptr(&exynos_adc_pm_ops),
        },
 };
 
index e665e14c6e546a05cdd8e9017de9e7fd8e5ee47e..8eb0140df133af3afef4e4395321392f4e80f350 100644 (file)
@@ -529,7 +529,7 @@ static const struct of_device_id hi8435_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, hi8435_dt_ids);
 
 static const struct spi_device_id hi8435_id[] = {
-       { "hi8435", 0},
+       { "hi8435", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(spi, hi8435_id);
index 4f9992a51e6452b0c1e4afae708ad3605d0b35eb..8d902a32a0fdb0546727b61068db0657c5b0ad16 100644 (file)
@@ -539,7 +539,7 @@ static ssize_t ina2xx_allow_async_readout_show(struct device *dev,
 {
        struct ina2xx_chip_info *chip = iio_priv(dev_to_iio_dev(dev));
 
-       return sprintf(buf, "%d\n", chip->allow_async_readout);
+       return sysfs_emit(buf, "%d\n", chip->allow_async_readout);
 }
 
 static ssize_t ina2xx_allow_async_readout_store(struct device *dev,
index 01a4275e9c46b858f8bcdf9e93fdefe1f063b677..f982f00303dc0fcae333396207a239a4d6cf66c2 100644 (file)
@@ -429,7 +429,7 @@ static ssize_t max9611_shunt_resistor_show(struct device *dev,
        i = max9611->shunt_resistor_uohm / 1000000;
        r = max9611->shunt_resistor_uohm % 1000000;
 
-       return sprintf(buf, "%u.%06u\n", i, r);
+       return sysfs_emit(buf, "%u.%06u\n", i, r);
 }
 
 static IIO_DEVICE_ATTR(in_power_shunt_resistor, 0444,
index d4fccd52ef08ba147a3fe3844ea2e31fa4f6fb0a..e78c96a185dbb78a8c7c0145c86fc4263ed2394b 100644 (file)
@@ -46,6 +46,11 @@ struct mt6577_auxadc_device {
        const struct mtk_auxadc_compatible *dev_comp;
 };
 
+static const struct mtk_auxadc_compatible mt8186_compat = {
+       .sample_data_cali = false,
+       .check_global_idle = false,
+};
+
 static const struct mtk_auxadc_compatible mt8173_compat = {
        .sample_data_cali = false,
        .check_global_idle = true,
@@ -330,11 +335,12 @@ static SIMPLE_DEV_PM_OPS(mt6577_auxadc_pm_ops,
                         mt6577_auxadc_resume);
 
 static const struct of_device_id mt6577_auxadc_of_match[] = {
-       { .compatible = "mediatek,mt2701-auxadc", .data = &mt8173_compat},
-       { .compatible = "mediatek,mt2712-auxadc", .data = &mt8173_compat},
-       { .compatible = "mediatek,mt7622-auxadc", .data = &mt8173_compat},
-       { .compatible = "mediatek,mt8173-auxadc", .data = &mt8173_compat},
-       { .compatible = "mediatek,mt6765-auxadc", .data = &mt6765_compat},
+       { .compatible = "mediatek,mt2701-auxadc", .data = &mt8173_compat },
+       { .compatible = "mediatek,mt2712-auxadc", .data = &mt8173_compat },
+       { .compatible = "mediatek,mt7622-auxadc", .data = &mt8173_compat },
+       { .compatible = "mediatek,mt8173-auxadc", .data = &mt8173_compat },
+       { .compatible = "mediatek,mt8186-auxadc", .data = &mt8186_compat },
+       { .compatible = "mediatek,mt6765-auxadc", .data = &mt6765_compat },
        { }
 };
 MODULE_DEVICE_TABLE(of, mt6577_auxadc_of_match);
index f9c8385c72d3d924792f55def5a470f8f9751494..61e80bf3d05e462d3c44fd3cd1bc5c8f3c5fad33 100644 (file)
@@ -653,7 +653,6 @@ static int palmas_gpadc_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int palmas_adc_wakeup_configure(struct palmas_gpadc *adc)
 {
        int adc_period, conv;
@@ -822,12 +821,9 @@ static int palmas_gpadc_resume(struct device *dev)
 
        return 0;
 };
-#endif
 
-static const struct dev_pm_ops palmas_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(palmas_gpadc_suspend,
-                               palmas_gpadc_resume)
-};
+static DEFINE_SIMPLE_DEV_PM_OPS(palmas_pm_ops, palmas_gpadc_suspend,
+                               palmas_gpadc_resume);
 
 static const struct of_device_id of_palmas_gpadc_match_tbl[] = {
        { .compatible = "ti,palmas-gpadc", },
@@ -840,7 +836,7 @@ static struct platform_driver palmas_gpadc_driver = {
        .remove = palmas_gpadc_remove,
        .driver = {
                .name = MOD_NAME,
-               .pm = &palmas_pm_ops,
+               .pm = pm_sleep_ptr(&palmas_pm_ops),
                .of_match_table = of_palmas_gpadc_match_tbl,
        },
 };
index 21d7eff645c337aa239781086fe9a5b0b08b64a9..5e9e5682107524e561ecaa7d4bbdda9f99ec23a0 100644 (file)
@@ -175,7 +175,7 @@ struct xoadc_channel {
        const char *datasheet_name;
        u8 pre_scale_mux:2;
        u8 amux_channel:4;
-       const struct vadc_prescale_ratio prescale;
+       const struct u32_fract prescale;
        enum iio_chan_type type;
        enum vadc_scale_fn_type scale_fn_type;
        u8 amux_ip_rsv:3;
@@ -218,7 +218,9 @@ struct xoadc_variant {
                .datasheet_name = __stringify(_dname),                  \
                .pre_scale_mux = _presmux,                              \
                .amux_channel = _amux,                                  \
-               .prescale = { .num = _prenum, .den = _preden },         \
+               .prescale = {                                           \
+                       .numerator = _prenum, .denominator = _preden,   \
+               },                                                      \
                .type = _type,                                          \
                .scale_fn_type = _scale,                                \
                .amux_ip_rsv = _amip,                                   \
@@ -809,12 +811,11 @@ static int pm8xxx_xoadc_parse_channel(struct device *dev,
                BIT(IIO_CHAN_INFO_PROCESSED);
        iio_chan->indexed = 1;
 
-       dev_dbg(dev, "channel [PRESCALE/MUX: %02x AMUX: %02x] \"%s\" "
-               "ref voltage: %d, decimation %d "
-               "prescale %d/%d, scale function %d\n",
+       dev_dbg(dev,
+               "channel [PRESCALE/MUX: %02x AMUX: %02x] \"%s\" ref voltage: %d, decimation %d prescale %d/%d, scale function %d\n",
                hwchan->pre_scale_mux, hwchan->amux_channel, ch->name,
-               ch->amux_ip_rsv, ch->decimation, hwchan->prescale.num,
-               hwchan->prescale.den, hwchan->scale_fn_type);
+               ch->amux_ip_rsv, ch->decimation, hwchan->prescale.numerator,
+               hwchan->prescale.denominator, hwchan->scale_fn_type);
 
        return 0;
 }
index 07b1a99381d977b3dce9bcd107a3fb9dce9e02b1..34202ba52469928c9fa13b13dd6cdace7fc6a8cb 100644 (file)
@@ -122,15 +122,15 @@ struct vadc_priv {
        struct mutex             lock;
 };
 
-static const struct vadc_prescale_ratio vadc_prescale_ratios[] = {
-       {.num =  1, .den =  1},
-       {.num =  1, .den =  3},
-       {.num =  1, .den =  4},
-       {.num =  1, .den =  6},
-       {.num =  1, .den = 20},
-       {.num =  1, .den =  8},
-       {.num = 10, .den = 81},
-       {.num =  1, .den = 10}
+static const struct u32_fract vadc_prescale_ratios[] = {
+       { .numerator =  1, .denominator =  1 },
+       { .numerator =  1, .denominator =  3 },
+       { .numerator =  1, .denominator =  4 },
+       { .numerator =  1, .denominator =  6 },
+       { .numerator =  1, .denominator = 20 },
+       { .numerator =  1, .denominator =  8 },
+       { .numerator = 10, .denominator = 81 },
+       { .numerator =  1, .denominator = 10 },
 };
 
 static int vadc_read(struct vadc_priv *vadc, u16 offset, u8 *data)
@@ -404,13 +404,13 @@ err:
        return ret;
 }
 
-static int vadc_prescaling_from_dt(u32 num, u32 den)
+static int vadc_prescaling_from_dt(u32 numerator, u32 denominator)
 {
        unsigned int pre;
 
        for (pre = 0; pre < ARRAY_SIZE(vadc_prescale_ratios); pre++)
-               if (vadc_prescale_ratios[pre].num == num &&
-                   vadc_prescale_ratios[pre].den == den)
+               if (vadc_prescale_ratios[pre].numerator == numerator &&
+                   vadc_prescale_ratios[pre].denominator == denominator)
                        break;
 
        if (pre == ARRAY_SIZE(vadc_prescale_ratios))
index 14723896aab2b4782fb7210a5c333f2e3c705ba8..6c6aec848f989baf287829236889283651103466 100644 (file)
@@ -289,44 +289,44 @@ static const struct vadc_map_pt adcmap7_100k[] = {
        { 2420, 130048 }
 };
 
-static const struct vadc_prescale_ratio adc5_prescale_ratios[] = {
-       {.num =  1, .den =  1},
-       {.num =  1, .den =  3},
-       {.num =  1, .den =  4},
-       {.num =  1, .den =  6},
-       {.num =  1, .den = 20},
-       {.num =  1, .den =  8},
-       {.num = 10, .den = 81},
-       {.num =  1, .den = 10},
-       {.num =  1, .den = 16}
+static const struct u32_fract adc5_prescale_ratios[] = {
+       { .numerator =  1, .denominator =  1 },
+       { .numerator =  1, .denominator =  3 },
+       { .numerator =  1, .denominator =  4 },
+       { .numerator =  1, .denominator =  6 },
+       { .numerator =  1, .denominator = 20 },
+       { .numerator =  1, .denominator =  8 },
+       { .numerator = 10, .denominator = 81 },
+       { .numerator =  1, .denominator = 10 },
+       { .numerator =  1, .denominator = 16 },
 };
 
 static int qcom_vadc_scale_hw_calib_volt(
-                               const struct vadc_prescale_ratio *prescale,
+                               const struct u32_fract *prescale,
                                const struct adc5_data *data,
                                u16 adc_code, int *result_uv);
 static int qcom_vadc_scale_hw_calib_therm(
-                               const struct vadc_prescale_ratio *prescale,
+                               const struct u32_fract *prescale,
                                const struct adc5_data *data,
                                u16 adc_code, int *result_mdec);
 static int qcom_vadc7_scale_hw_calib_therm(
-                               const struct vadc_prescale_ratio *prescale,
+                               const struct u32_fract *prescale,
                                const struct adc5_data *data,
                                u16 adc_code, int *result_mdec);
 static int qcom_vadc_scale_hw_smb_temp(
-                               const struct vadc_prescale_ratio *prescale,
+                               const struct u32_fract *prescale,
                                const struct adc5_data *data,
                                u16 adc_code, int *result_mdec);
 static int qcom_vadc_scale_hw_chg5_temp(
-                               const struct vadc_prescale_ratio *prescale,
+                               const struct u32_fract *prescale,
                                const struct adc5_data *data,
                                u16 adc_code, int *result_mdec);
 static int qcom_vadc_scale_hw_calib_die_temp(
-                               const struct vadc_prescale_ratio *prescale,
+                               const struct u32_fract *prescale,
                                const struct adc5_data *data,
                                u16 adc_code, int *result_mdec);
 static int qcom_vadc7_scale_hw_calib_die_temp(
-                               const struct vadc_prescale_ratio *prescale,
+                               const struct u32_fract *prescale,
                                const struct adc5_data *data,
                                u16 adc_code, int *result_mdec);
 
@@ -406,7 +406,7 @@ static void qcom_vadc_scale_calib(const struct vadc_linear_graph *calib_graph,
 }
 
 static int qcom_vadc_scale_volt(const struct vadc_linear_graph *calib_graph,
-                               const struct vadc_prescale_ratio *prescale,
+                               const struct u32_fract *prescale,
                                bool absolute, u16 adc_code,
                                int *result_uv)
 {
@@ -414,15 +414,15 @@ static int qcom_vadc_scale_volt(const struct vadc_linear_graph *calib_graph,
 
        qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
 
-       voltage = voltage * prescale->den;
-       result = div64_s64(voltage, prescale->num);
+       voltage *= prescale->denominator;
+       result = div64_s64(voltage, prescale->numerator);
        *result_uv = result;
 
        return 0;
 }
 
 static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph,
-                                const struct vadc_prescale_ratio *prescale,
+                                const struct u32_fract *prescale,
                                 bool absolute, u16 adc_code,
                                 int *result_mdec)
 {
@@ -444,7 +444,7 @@ static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph,
 }
 
 static int qcom_vadc_scale_die_temp(const struct vadc_linear_graph *calib_graph,
-                                   const struct vadc_prescale_ratio *prescale,
+                                   const struct u32_fract *prescale,
                                    bool absolute,
                                    u16 adc_code, int *result_mdec)
 {
@@ -454,8 +454,8 @@ static int qcom_vadc_scale_die_temp(const struct vadc_linear_graph *calib_graph,
        qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
 
        if (voltage > 0) {
-               temp = voltage * prescale->den;
-               do_div(temp, prescale->num * 2);
+               temp = voltage * prescale->denominator;
+               do_div(temp, prescale->numerator * 2);
                voltage = temp;
        } else {
                voltage = 0;
@@ -467,7 +467,7 @@ static int qcom_vadc_scale_die_temp(const struct vadc_linear_graph *calib_graph,
 }
 
 static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph *calib_graph,
-                                   const struct vadc_prescale_ratio *prescale,
+                                   const struct u32_fract *prescale,
                                    bool absolute,
                                    u16 adc_code, int *result_mdec)
 {
@@ -475,8 +475,8 @@ static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph *calib_graph,
 
        qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
 
-       voltage = voltage * prescale->den;
-       voltage = div64_s64(voltage, prescale->num);
+       voltage *= prescale->denominator;
+       voltage = div64_s64(voltage, prescale->numerator);
        voltage = ((PMI_CHG_SCALE_1) * (voltage * 2));
        voltage = (voltage + PMI_CHG_SCALE_2);
        result =  div64_s64(voltage, 1000000);
@@ -487,21 +487,21 @@ static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph *calib_graph,
 
 /* convert voltage to ADC code, using 1.875V reference */
 static u16 qcom_vadc_scale_voltage_code(s32 voltage,
-                                       const struct vadc_prescale_ratio *prescale,
+                                       const struct u32_fract *prescale,
                                        const u32 full_scale_code_volt,
                                        unsigned int factor)
 {
        s64 volt = voltage;
        s64 adc_vdd_ref_mv = 1875; /* reference voltage */
 
-       volt *= prescale->num * factor * full_scale_code_volt;
-       volt = div64_s64(volt, (s64)prescale->den * adc_vdd_ref_mv * 1000);
+       volt *= prescale->numerator * factor * full_scale_code_volt;
+       volt = div64_s64(volt, (s64)prescale->denominator * adc_vdd_ref_mv * 1000);
 
        return volt;
 }
 
 static int qcom_vadc_scale_code_voltage_factor(u16 adc_code,
-                               const struct vadc_prescale_ratio *prescale,
+                               const struct u32_fract *prescale,
                                const struct adc5_data *data,
                                unsigned int factor)
 {
@@ -520,8 +520,8 @@ static int qcom_vadc_scale_code_voltage_factor(u16 adc_code,
        voltage = (s64) adc_code * adc_vdd_ref_mv * 1000;
        voltage = div64_s64(voltage, data->full_scale_code_volt);
        if (voltage > 0) {
-               voltage *= prescale->den;
-               temp = prescale->num * factor;
+               voltage *= prescale->denominator;
+               temp = prescale->numerator * factor;
                voltage = div64_s64(voltage, temp);
        } else {
                voltage = 0;
@@ -531,7 +531,7 @@ static int qcom_vadc_scale_code_voltage_factor(u16 adc_code,
 }
 
 static int qcom_vadc7_scale_hw_calib_therm(
-                               const struct vadc_prescale_ratio *prescale,
+                               const struct u32_fract *prescale,
                                const struct adc5_data *data,
                                u16 adc_code, int *result_mdec)
 {
@@ -557,7 +557,7 @@ static int qcom_vadc7_scale_hw_calib_therm(
 }
 
 static int qcom_vadc_scale_hw_calib_volt(
-                               const struct vadc_prescale_ratio *prescale,
+                               const struct u32_fract *prescale,
                                const struct adc5_data *data,
                                u16 adc_code, int *result_uv)
 {
@@ -568,7 +568,7 @@ static int qcom_vadc_scale_hw_calib_volt(
 }
 
 static int qcom_vadc_scale_hw_calib_therm(
-                               const struct vadc_prescale_ratio *prescale,
+                               const struct u32_fract *prescale,
                                const struct adc5_data *data,
                                u16 adc_code, int *result_mdec)
 {
@@ -584,7 +584,7 @@ static int qcom_vadc_scale_hw_calib_therm(
 }
 
 static int qcom_vadc_scale_hw_calib_die_temp(
-                               const struct vadc_prescale_ratio *prescale,
+                               const struct u32_fract *prescale,
                                const struct adc5_data *data,
                                u16 adc_code, int *result_mdec)
 {
@@ -596,7 +596,7 @@ static int qcom_vadc_scale_hw_calib_die_temp(
 }
 
 static int qcom_vadc7_scale_hw_calib_die_temp(
-                               const struct vadc_prescale_ratio *prescale,
+                               const struct u32_fract *prescale,
                                const struct adc5_data *data,
                                u16 adc_code, int *result_mdec)
 {
@@ -611,7 +611,7 @@ static int qcom_vadc7_scale_hw_calib_die_temp(
 }
 
 static int qcom_vadc_scale_hw_smb_temp(
-                               const struct vadc_prescale_ratio *prescale,
+                               const struct u32_fract *prescale,
                                const struct adc5_data *data,
                                u16 adc_code, int *result_mdec)
 {
@@ -623,7 +623,7 @@ static int qcom_vadc_scale_hw_smb_temp(
 }
 
 static int qcom_vadc_scale_hw_chg5_temp(
-                               const struct vadc_prescale_ratio *prescale,
+                               const struct u32_fract *prescale,
                                const struct adc5_data *data,
                                u16 adc_code, int *result_mdec)
 {
@@ -636,7 +636,7 @@ static int qcom_vadc_scale_hw_chg5_temp(
 
 int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
                    const struct vadc_linear_graph *calib_graph,
-                   const struct vadc_prescale_ratio *prescale,
+                   const struct u32_fract *prescale,
                    bool absolute,
                    u16 adc_code, int *result)
 {
@@ -667,7 +667,7 @@ EXPORT_SYMBOL(qcom_vadc_scale);
 u16 qcom_adc_tm5_temp_volt_scale(unsigned int prescale_ratio,
                                 u32 full_scale_code_volt, int temp)
 {
-       const struct vadc_prescale_ratio *prescale = &adc5_prescale_ratios[prescale_ratio];
+       const struct u32_fract *prescale = &adc5_prescale_ratios[prescale_ratio];
        s32 voltage;
 
        voltage = qcom_vadc_map_temp_voltage(adcmap_100k_104ef_104fb_1875_vref,
@@ -682,7 +682,7 @@ int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype,
                    const struct adc5_data *data,
                    u16 adc_code, int *result)
 {
-       const struct vadc_prescale_ratio *prescale = &adc5_prescale_ratios[prescale_ratio];
+       const struct u32_fract *prescale = &adc5_prescale_ratios[prescale_ratio];
 
        if (!(scaletype >= SCALE_HW_CALIB_DEFAULT &&
                scaletype < SCALE_HW_CALIB_INVALID)) {
@@ -695,13 +695,13 @@ int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype,
 }
 EXPORT_SYMBOL(qcom_adc5_hw_scale);
 
-int qcom_adc5_prescaling_from_dt(u32 num, u32 den)
+int qcom_adc5_prescaling_from_dt(u32 numerator, u32 denominator)
 {
        unsigned int pre;
 
        for (pre = 0; pre < ARRAY_SIZE(adc5_prescale_ratios); pre++)
-               if (adc5_prescale_ratios[pre].num == num &&
-                   adc5_prescale_ratios[pre].den == den)
+               if (adc5_prescale_ratios[pre].numerator == numerator &&
+                   adc5_prescale_ratios[pre].denominator == denominator)
                        break;
 
        if (pre == ARRAY_SIZE(adc5_prescale_ratios))
index 727ea6c6804917edae28dbbcd05b477ba588f147..27d9e147b4b7b8015d66e549cc1a22eac7cbec89 100644 (file)
@@ -577,7 +577,6 @@ static int rcar_gyroadc_remove(struct platform_device *pdev)
        return 0;
 }
 
-#if defined(CONFIG_PM)
 static int rcar_gyroadc_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
@@ -597,10 +596,9 @@ static int rcar_gyroadc_resume(struct device *dev)
 
        return 0;
 }
-#endif
 
 static const struct dev_pm_ops rcar_gyroadc_pm_ops = {
-       SET_RUNTIME_PM_OPS(rcar_gyroadc_suspend, rcar_gyroadc_resume, NULL)
+       RUNTIME_PM_OPS(rcar_gyroadc_suspend, rcar_gyroadc_resume, NULL)
 };
 
 static struct platform_driver rcar_gyroadc_driver = {
@@ -609,7 +607,7 @@ static struct platform_driver rcar_gyroadc_driver = {
        .driver         = {
                .name           = DRIVER_NAME,
                .of_match_table = rcar_gyroadc_match,
-               .pm             = &rcar_gyroadc_pm_ops,
+               .pm             = pm_ptr(&rcar_gyroadc_pm_ops),
        },
 };
 
index 7d891b4ea4616ed4144e564831cb539a72336c74..6bf32907f01dcc3c74e2f0ff63c7eb60e53b2ae0 100644 (file)
@@ -42,11 +42,6 @@ struct rn5t618_adc_data {
        int irq;
 };
 
-struct rn5t618_channel_ratios {
-       u16 numerator;
-       u16 denominator;
-};
-
 enum rn5t618_channels {
        LIMMON = 0,
        VBAT,
@@ -58,7 +53,7 @@ enum rn5t618_channels {
        AIN0
 };
 
-static const struct rn5t618_channel_ratios rn5t618_ratios[8] = {
+static const struct u16_fract rn5t618_ratios[8] = {
        [LIMMON] = {50, 32}, /* measured across 20mOhm, amplified by 32 */
        [VBAT] = {2, 1},
        [VADP] = {3, 1},
index 14b8df4ca9c879852dd2a3b392c9982d41a2be59..b87ea7148b5869692a01158325022cb3dfebb360 100644 (file)
@@ -481,7 +481,6 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
        return devm_iio_device_register(&pdev->dev, indio_dev);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int rockchip_saradc_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
@@ -514,17 +513,17 @@ static int rockchip_saradc_resume(struct device *dev)
 
        return ret;
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(rockchip_saradc_pm_ops,
-                        rockchip_saradc_suspend, rockchip_saradc_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(rockchip_saradc_pm_ops,
+                               rockchip_saradc_suspend,
+                               rockchip_saradc_resume);
 
 static struct platform_driver rockchip_saradc_driver = {
        .probe          = rockchip_saradc_probe,
        .driver         = {
                .name   = "rockchip-saradc",
                .of_match_table = rockchip_saradc_match,
-               .pm     = &rockchip_saradc_pm_ops,
+               .pm     = pm_sleep_ptr(&rockchip_saradc_pm_ops),
        },
 };
 
index 9d5be52bd948b1772e32132105339dadbfbefb6e..7585144b9715b5b76d107fed1a03623662467bc2 100644 (file)
@@ -55,7 +55,7 @@
 #define RZG2L_ADCR(n)                  (0x30 + ((n) * 0x4))
 #define RZG2L_ADCR_AD_MASK             GENMASK(11, 0)
 
-#define RZG2L_ADSMP_DEFUALT_SAMPLING   0x578
+#define RZG2L_ADSMP_DEFAULT_SAMPLING   0x578
 
 #define RZG2L_ADC_MAX_CHANNELS         8
 #define RZG2L_ADC_CHN_MASK             0x7
@@ -395,7 +395,7 @@ static int rzg2l_adc_hw_init(struct rzg2l_adc *adc)
        reg &= ~RZG2L_ADM3_ADIL_MASK;
        reg &= ~RZG2L_ADM3_ADCMP_MASK;
        reg &= ~RZG2L_ADM3_ADSMP_MASK;
-       reg |= (RZG2L_ADM3_ADCMP_E | RZG2L_ADSMP_DEFUALT_SAMPLING);
+       reg |= (RZG2L_ADM3_ADCMP_E | RZG2L_ADSMP_DEFAULT_SAMPLING);
        rzg2l_adc_writel(adc, RZG2L_ADM(3), reg);
 
 exit_hw_init:
index b6e18eb101f7350efc6558a6ef944ab323813ea9..1426562321575081ac63ecfc2649ebd52e24574c 100644 (file)
@@ -763,7 +763,6 @@ static int stm32_adc_remove(struct platform_device *pdev)
        return 0;
 }
 
-#if defined(CONFIG_PM)
 static int stm32_adc_core_runtime_suspend(struct device *dev)
 {
        stm32_adc_core_hw_stop(dev);
@@ -782,15 +781,11 @@ static int stm32_adc_core_runtime_idle(struct device *dev)
 
        return 0;
 }
-#endif
-
-static const struct dev_pm_ops stm32_adc_core_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-                               pm_runtime_force_resume)
-       SET_RUNTIME_PM_OPS(stm32_adc_core_runtime_suspend,
-                          stm32_adc_core_runtime_resume,
-                          stm32_adc_core_runtime_idle)
-};
+
+static DEFINE_RUNTIME_DEV_PM_OPS(stm32_adc_core_pm_ops,
+                               stm32_adc_core_runtime_suspend,
+                               stm32_adc_core_runtime_resume,
+                               stm32_adc_core_runtime_idle);
 
 static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = {
        .regs = &stm32f4_adc_common_regs,
@@ -836,7 +831,7 @@ static struct platform_driver stm32_adc_driver = {
        .driver = {
                .name = "stm32-adc-core",
                .of_match_table = stm32_adc_of_match,
-               .pm = &stm32_adc_core_pm_ops,
+               .pm = pm_ptr(&stm32_adc_core_pm_ops),
        },
 };
 module_platform_driver(stm32_adc_driver);
index 897166d9e45ce7162c0a6abf3cbe9c4ab6cda8a6..a68ecbda6480b298b3561a4fd414c5ab7a3b349f 100644 (file)
@@ -2352,7 +2352,6 @@ static int stm32_adc_remove(struct platform_device *pdev)
        return 0;
 }
 
-#if defined(CONFIG_PM_SLEEP)
 static int stm32_adc_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
@@ -2382,9 +2381,7 @@ static int stm32_adc_resume(struct device *dev)
 
        return stm32_adc_buffer_postenable(indio_dev);
 }
-#endif
 
-#if defined(CONFIG_PM)
 static int stm32_adc_runtime_suspend(struct device *dev)
 {
        return stm32_adc_hw_stop(dev);
@@ -2394,12 +2391,11 @@ static int stm32_adc_runtime_resume(struct device *dev)
 {
        return stm32_adc_hw_start(dev);
 }
-#endif
 
 static const struct dev_pm_ops stm32_adc_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(stm32_adc_suspend, stm32_adc_resume)
-       SET_RUNTIME_PM_OPS(stm32_adc_runtime_suspend, stm32_adc_runtime_resume,
-                          NULL)
+       SYSTEM_SLEEP_PM_OPS(stm32_adc_suspend, stm32_adc_resume)
+       RUNTIME_PM_OPS(stm32_adc_runtime_suspend, stm32_adc_runtime_resume,
+                      NULL)
 };
 
 static const struct stm32_adc_cfg stm32f4_adc_cfg = {
@@ -2453,7 +2449,7 @@ static struct platform_driver stm32_adc_driver = {
        .driver = {
                .name = "stm32-adc",
                .of_match_table = stm32_adc_of_match,
-               .pm = &stm32_adc_pm_ops,
+               .pm = pm_ptr(&stm32_adc_pm_ops),
        },
 };
 module_platform_driver(stm32_adc_driver);
index 1cfefb3b5e56cd44018332cda266288e8e62c973..9704cf0b97531c07e368bab8377322f5ea73eca9 100644 (file)
@@ -1632,7 +1632,7 @@ static int stm32_dfsdm_adc_remove(struct platform_device *pdev)
        return 0;
 }
 
-static int __maybe_unused stm32_dfsdm_adc_suspend(struct device *dev)
+static int stm32_dfsdm_adc_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
@@ -1642,7 +1642,7 @@ static int __maybe_unused stm32_dfsdm_adc_suspend(struct device *dev)
        return 0;
 }
 
-static int __maybe_unused stm32_dfsdm_adc_resume(struct device *dev)
+static int stm32_dfsdm_adc_resume(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
@@ -1665,14 +1665,15 @@ static int __maybe_unused stm32_dfsdm_adc_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(stm32_dfsdm_adc_pm_ops,
-                        stm32_dfsdm_adc_suspend, stm32_dfsdm_adc_resume);
+static DEFINE_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,
+               .pm = pm_sleep_ptr(&stm32_dfsdm_adc_pm_ops),
        },
        .probe = stm32_dfsdm_adc_probe,
        .remove = stm32_dfsdm_adc_remove,
index a627af9a825e7f6b7ba438267ea83ca5ecc5a2c9..a3d4de6ba4c2b588c8ab4c35a0b5ec6e17deef09 100644 (file)
@@ -381,7 +381,7 @@ static int stm32_dfsdm_core_remove(struct platform_device *pdev)
        return 0;
 }
 
-static int __maybe_unused stm32_dfsdm_core_suspend(struct device *dev)
+static int stm32_dfsdm_core_suspend(struct device *dev)
 {
        struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev);
        struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm);
@@ -397,7 +397,7 @@ static int __maybe_unused stm32_dfsdm_core_suspend(struct device *dev)
        return pinctrl_pm_select_sleep_state(dev);
 }
 
-static int __maybe_unused stm32_dfsdm_core_resume(struct device *dev)
+static int stm32_dfsdm_core_resume(struct device *dev)
 {
        struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev);
        struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm);
@@ -414,7 +414,7 @@ static int __maybe_unused stm32_dfsdm_core_resume(struct device *dev)
        return pm_runtime_force_resume(dev);
 }
 
-static int __maybe_unused stm32_dfsdm_core_runtime_suspend(struct device *dev)
+static int stm32_dfsdm_core_runtime_suspend(struct device *dev)
 {
        struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev);
 
@@ -423,7 +423,7 @@ static int __maybe_unused stm32_dfsdm_core_runtime_suspend(struct device *dev)
        return 0;
 }
 
-static int __maybe_unused stm32_dfsdm_core_runtime_resume(struct device *dev)
+static int stm32_dfsdm_core_runtime_resume(struct device *dev)
 {
        struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev);
 
@@ -431,11 +431,10 @@ static int __maybe_unused stm32_dfsdm_core_runtime_resume(struct device *dev)
 }
 
 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)
+       SYSTEM_SLEEP_PM_OPS(stm32_dfsdm_core_suspend, stm32_dfsdm_core_resume)
+       RUNTIME_PM_OPS(stm32_dfsdm_core_runtime_suspend,
+                      stm32_dfsdm_core_runtime_resume,
+                      NULL)
 };
 
 static struct platform_driver stm32_dfsdm_driver = {
@@ -444,7 +443,7 @@ static struct platform_driver stm32_dfsdm_driver = {
        .driver = {
                .name = "stm32-dfsdm",
                .of_match_table = stm32_dfsdm_of_match,
-               .pm = &stm32_dfsdm_core_pm_ops,
+               .pm = pm_ptr(&stm32_dfsdm_core_pm_ops),
        },
 };
 
index ce3f5a3814f9027aa88d41d8e67bd7cb04ceb8d2..c9b5d9aec3dc407b843aaf11563502184c4af287 100644 (file)
@@ -248,7 +248,7 @@ static const struct of_device_id adc084s021_of_match[] = {
 MODULE_DEVICE_TABLE(of, adc084s021_of_match);
 
 static const struct spi_device_id adc084s021_id[] = {
-       { ADC084S021_DRIVER_NAME, 0},
+       { ADC084S021_DRIVER_NAME, 0 },
        {}
 };
 MODULE_DEVICE_TABLE(spi, adc084s021_id);
index e8fc4d01f30b65cfa32fdbf9de2f190c0b4b7a87..55b35570ad8bceed02db6b7b0701310304713e81 100644 (file)
 #define TI_TSC2046_DATA_12BIT                  GENMASK(14, 3)
 
 #define TI_TSC2046_MAX_CHAN                    8
+#define TI_TSC2046_MIN_POLL_CNT                        3
+#define TI_TSC2046_EXT_POLL_CNT                        3
+#define TI_TSC2046_POLL_CNT \
+       (TI_TSC2046_MIN_POLL_CNT + TI_TSC2046_EXT_POLL_CNT)
+#define TI_TSC2046_INT_VREF                    2500
 
 /* Represents a HW sample */
 struct tsc2046_adc_atom {
@@ -123,14 +128,23 @@ struct tsc2046_adc_ch_cfg {
        unsigned int oversampling_ratio;
 };
 
+enum tsc2046_state {
+       TSC2046_STATE_SHUTDOWN,
+       TSC2046_STATE_STANDBY,
+       TSC2046_STATE_POLL,
+       TSC2046_STATE_POLL_IRQ_DISABLE,
+       TSC2046_STATE_ENABLE_IRQ,
+};
+
 struct tsc2046_adc_priv {
        struct spi_device *spi;
        const struct tsc2046_adc_dcfg *dcfg;
 
        struct iio_trigger *trig;
        struct hrtimer trig_timer;
-       spinlock_t trig_lock;
-       unsigned int trig_more_count;
+       enum tsc2046_state state;
+       int poll_cnt;
+       spinlock_t state_lock;
 
        struct spi_transfer xfer;
        struct spi_message msg;
@@ -153,9 +167,6 @@ struct tsc2046_adc_priv {
        struct tsc2046_adc_atom *rx;
        struct tsc2046_adc_atom *tx;
 
-       struct tsc2046_adc_atom *rx_one;
-       struct tsc2046_adc_atom *tx_one;
-
        unsigned int count;
        unsigned int groups;
        u32 effective_speed_hz;
@@ -171,6 +182,8 @@ struct tsc2046_adc_priv {
        .type = IIO_VOLTAGE,                                    \
        .indexed = 1,                                           \
        .channel = index,                                       \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),           \
+       .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),   \
        .datasheet_name = "#name",                              \
        .scan_index = index,                                    \
        .scan_type = {                                          \
@@ -234,6 +247,14 @@ static u8 tsc2046_adc_get_cmd(struct tsc2046_adc_priv *priv, int ch_idx,
        else
                pd = 0;
 
+       switch (ch_idx) {
+       case TI_TSC2046_ADDR_TEMP1:
+       case TI_TSC2046_ADDR_AUX:
+       case TI_TSC2046_ADDR_VBAT:
+       case TI_TSC2046_ADDR_TEMP0:
+               pd |= TI_TSC2046_SER | TI_TSC2046_PD1_VREF_ON;
+       }
+
        return TI_TSC2046_START | FIELD_PREP(TI_TSC2046_ADDR, ch_idx) | pd;
 }
 
@@ -245,16 +266,50 @@ static u16 tsc2046_adc_get_value(struct tsc2046_adc_atom *buf)
 static int tsc2046_adc_read_one(struct tsc2046_adc_priv *priv, int ch_idx,
                                u32 *effective_speed_hz)
 {
+       struct tsc2046_adc_ch_cfg *ch = &priv->ch_cfg[ch_idx];
+       struct tsc2046_adc_atom *rx_buf, *tx_buf;
+       unsigned int val, val_normalized = 0;
+       int ret, i, count_skip = 0, max_count;
        struct spi_transfer xfer;
        struct spi_message msg;
-       int ret;
+       u8 cmd;
+
+       if (!effective_speed_hz) {
+               count_skip = tsc2046_adc_time_to_count(priv, ch->settling_time_us);
+               max_count = count_skip + ch->oversampling_ratio;
+       } else {
+               max_count = 1;
+       }
+
+       if (sizeof(*tx_buf) * max_count > PAGE_SIZE)
+               return -ENOSPC;
+
+       tx_buf = kcalloc(max_count, sizeof(*tx_buf), GFP_KERNEL);
+       if (!tx_buf)
+               return -ENOMEM;
+
+       rx_buf = kcalloc(max_count, sizeof(*rx_buf), GFP_KERNEL);
+       if (!rx_buf) {
+               ret = -ENOMEM;
+               goto free_tx;
+       }
+
+       /*
+        * Do not enable automatic power down on working samples. Otherwise the
+        * plates will never be completely charged.
+        */
+       cmd = tsc2046_adc_get_cmd(priv, ch_idx, true);
+
+       for (i = 0; i < max_count - 1; i++)
+               tx_buf[i].cmd = cmd;
+
+       /* automatically power down on last sample */
+       tx_buf[i].cmd = tsc2046_adc_get_cmd(priv, ch_idx, false);
 
        memset(&xfer, 0, sizeof(xfer));
-       priv->tx_one->cmd = tsc2046_adc_get_cmd(priv, ch_idx, false);
-       priv->tx_one->data = 0;
-       xfer.tx_buf = priv->tx_one;
-       xfer.rx_buf = priv->rx_one;
-       xfer.len = sizeof(*priv->tx_one);
+       xfer.tx_buf = tx_buf;
+       xfer.rx_buf = rx_buf;
+       xfer.len = sizeof(*tx_buf) * max_count;
        spi_message_init_with_transfers(&msg, &xfer, 1);
 
        /*
@@ -265,13 +320,25 @@ static int tsc2046_adc_read_one(struct tsc2046_adc_priv *priv, int ch_idx,
        if (ret) {
                dev_err_ratelimited(&priv->spi->dev, "SPI transfer failed %pe\n",
                                    ERR_PTR(ret));
-               return ret;
+               goto free_bufs;
        }
 
        if (effective_speed_hz)
                *effective_speed_hz = xfer.effective_speed_hz;
 
-       return tsc2046_adc_get_value(priv->rx_one);
+       for (i = 0; i < max_count - count_skip; i++) {
+               val = tsc2046_adc_get_value(&rx_buf[count_skip + i]);
+               val_normalized += val;
+       }
+
+       ret = DIV_ROUND_UP(val_normalized, max_count - count_skip);
+
+free_bufs:
+       kfree(rx_buf);
+free_tx:
+       kfree(tx_buf);
+
+       return ret;
 }
 
 static size_t tsc2046_adc_group_set_layout(struct tsc2046_adc_priv *priv,
@@ -378,6 +445,37 @@ static irqreturn_t tsc2046_adc_trigger_handler(int irq, void *p)
        return IRQ_HANDLED;
 }
 
+static int tsc2046_adc_read_raw(struct iio_dev *indio_dev,
+                               struct iio_chan_spec const *chan,
+                               int *val, int *val2, long m)
+{
+       struct tsc2046_adc_priv *priv = iio_priv(indio_dev);
+       int ret;
+
+       switch (m) {
+       case IIO_CHAN_INFO_RAW:
+               ret = tsc2046_adc_read_one(priv, chan->channel, NULL);
+               if (ret < 0)
+                       return ret;
+
+               *val = ret;
+
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               /*
+                * Note: the TSC2046 has internal voltage divider on the VBAT
+                * line. This divider can be influenced by external divider.
+                * So, it is better to use external voltage-divider driver
+                * instead, which is calculating complete chain.
+                */
+               *val = TI_TSC2046_INT_VREF;
+               *val2 = chan->scan_type.realbits;
+               return IIO_VAL_FRACTIONAL_LOG2;
+       }
+
+       return -EINVAL;
+}
+
 static int tsc2046_adc_update_scan_mode(struct iio_dev *indio_dev,
                                        const unsigned long *active_scan_mask)
 {
@@ -408,24 +506,67 @@ static int tsc2046_adc_update_scan_mode(struct iio_dev *indio_dev,
 }
 
 static const struct iio_info tsc2046_adc_info = {
+       .read_raw         = tsc2046_adc_read_raw,
        .update_scan_mode = tsc2046_adc_update_scan_mode,
 };
 
-static enum hrtimer_restart tsc2046_adc_trig_more(struct hrtimer *hrtimer)
+static enum hrtimer_restart tsc2046_adc_timer(struct hrtimer *hrtimer)
 {
        struct tsc2046_adc_priv *priv = container_of(hrtimer,
                                                     struct tsc2046_adc_priv,
                                                     trig_timer);
        unsigned long flags;
 
-       spin_lock_irqsave(&priv->trig_lock, flags);
-
-       disable_irq_nosync(priv->spi->irq);
-
-       priv->trig_more_count++;
-       iio_trigger_poll(priv->trig);
+       /*
+        * This state machine should address following challenges :
+        * - the interrupt source is based on level shifter attached to the X
+        *   channel of ADC. It will change the state every time we switch
+        *   between channels. So, we need to disable IRQ if we do
+        *   iio_trigger_poll().
+        * - we should do iio_trigger_poll() at some reduced sample rate
+        * - we should still trigger for some amount of time after last
+        *   interrupt with enabled IRQ was processed.
+        */
 
-       spin_unlock_irqrestore(&priv->trig_lock, flags);
+       spin_lock_irqsave(&priv->state_lock, flags);
+       switch (priv->state) {
+       case TSC2046_STATE_ENABLE_IRQ:
+               if (priv->poll_cnt < TI_TSC2046_POLL_CNT) {
+                       priv->poll_cnt++;
+                       hrtimer_start(&priv->trig_timer,
+                                     ns_to_ktime(priv->scan_interval_us *
+                                                 NSEC_PER_USEC),
+                                     HRTIMER_MODE_REL_SOFT);
+
+                       if (priv->poll_cnt >= TI_TSC2046_MIN_POLL_CNT) {
+                               priv->state = TSC2046_STATE_POLL_IRQ_DISABLE;
+                               enable_irq(priv->spi->irq);
+                       } else {
+                               priv->state = TSC2046_STATE_POLL;
+                       }
+               } else {
+                       priv->state = TSC2046_STATE_STANDBY;
+                       enable_irq(priv->spi->irq);
+               }
+               break;
+       case TSC2046_STATE_POLL_IRQ_DISABLE:
+               disable_irq_nosync(priv->spi->irq);
+               fallthrough;
+       case TSC2046_STATE_POLL:
+               priv->state = TSC2046_STATE_ENABLE_IRQ;
+               /* iio_trigger_poll() starts hrtimer */
+               iio_trigger_poll(priv->trig);
+               break;
+       case TSC2046_STATE_SHUTDOWN:
+               break;
+       case TSC2046_STATE_STANDBY:
+               fallthrough;
+       default:
+               dev_warn(&priv->spi->dev, "Got unexpected state: %i\n",
+                        priv->state);
+               break;
+       }
+       spin_unlock_irqrestore(&priv->state_lock, flags);
 
        return HRTIMER_NORESTART;
 }
@@ -434,16 +575,20 @@ static irqreturn_t tsc2046_adc_irq(int irq, void *dev_id)
 {
        struct iio_dev *indio_dev = dev_id;
        struct tsc2046_adc_priv *priv = iio_priv(indio_dev);
-
-       spin_lock(&priv->trig_lock);
+       unsigned long flags;
 
        hrtimer_try_to_cancel(&priv->trig_timer);
 
-       priv->trig_more_count = 0;
-       disable_irq_nosync(priv->spi->irq);
-       iio_trigger_poll(priv->trig);
+       spin_lock_irqsave(&priv->state_lock, flags);
+       if (priv->state != TSC2046_STATE_SHUTDOWN) {
+               priv->state = TSC2046_STATE_ENABLE_IRQ;
+               priv->poll_cnt = 0;
 
-       spin_unlock(&priv->trig_lock);
+               /* iio_trigger_poll() starts hrtimer */
+               disable_irq_nosync(priv->spi->irq);
+               iio_trigger_poll(priv->trig);
+       }
+       spin_unlock_irqrestore(&priv->state_lock, flags);
 
        return IRQ_HANDLED;
 }
@@ -452,49 +597,42 @@ static void tsc2046_adc_reenable_trigger(struct iio_trigger *trig)
 {
        struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
        struct tsc2046_adc_priv *priv = iio_priv(indio_dev);
-       unsigned long flags;
-       int delta;
+       ktime_t tim;
 
        /*
         * We can sample it as fast as we can, but usually we do not need so
         * many samples. Reduce the sample rate for default (touchscreen) use
         * case.
-        * Currently we do not need a highly precise sample rate. It is enough
-        * to have calculated numbers.
-        */
-       delta = priv->scan_interval_us - priv->time_per_scan_us;
-       if (delta > 0)
-               fsleep(delta);
-
-       spin_lock_irqsave(&priv->trig_lock, flags);
-
-       /*
-        * We need to trigger at least one extra sample to detect state
-        * difference on ADC side.
         */
-       if (!priv->trig_more_count) {
-               int timeout_ms = DIV_ROUND_UP(priv->scan_interval_us,
-                                             USEC_PER_MSEC);
-
-               hrtimer_start(&priv->trig_timer, ms_to_ktime(timeout_ms),
-                             HRTIMER_MODE_REL_SOFT);
-       }
-
-       enable_irq(priv->spi->irq);
-
-       spin_unlock_irqrestore(&priv->trig_lock, flags);
+       tim = ns_to_ktime((priv->scan_interval_us - priv->time_per_scan_us) *
+                         NSEC_PER_USEC);
+       hrtimer_start(&priv->trig_timer, tim, HRTIMER_MODE_REL_SOFT);
 }
 
 static int tsc2046_adc_set_trigger_state(struct iio_trigger *trig, bool enable)
 {
        struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
        struct tsc2046_adc_priv *priv = iio_priv(indio_dev);
+       unsigned long flags;
 
        if (enable) {
-               enable_irq(priv->spi->irq);
+               spin_lock_irqsave(&priv->state_lock, flags);
+               if (priv->state == TSC2046_STATE_SHUTDOWN) {
+                       priv->state = TSC2046_STATE_STANDBY;
+                       enable_irq(priv->spi->irq);
+               }
+               spin_unlock_irqrestore(&priv->state_lock, flags);
        } else {
-               disable_irq(priv->spi->irq);
-               hrtimer_try_to_cancel(&priv->trig_timer);
+               spin_lock_irqsave(&priv->state_lock, flags);
+
+               if (priv->state == TSC2046_STATE_STANDBY ||
+                   priv->state == TSC2046_STATE_POLL_IRQ_DISABLE)
+                       disable_irq_nosync(priv->spi->irq);
+
+               priv->state = TSC2046_STATE_SHUTDOWN;
+               spin_unlock_irqrestore(&priv->state_lock, flags);
+
+               hrtimer_cancel(&priv->trig_timer);
        }
 
        return 0;
@@ -511,16 +649,6 @@ static int tsc2046_adc_setup_spi_msg(struct tsc2046_adc_priv *priv)
        size_t size;
        int ret;
 
-       priv->tx_one = devm_kzalloc(&priv->spi->dev, sizeof(*priv->tx_one),
-                                   GFP_KERNEL);
-       if (!priv->tx_one)
-               return -ENOMEM;
-
-       priv->rx_one = devm_kzalloc(&priv->spi->dev, sizeof(*priv->rx_one),
-                                   GFP_KERNEL);
-       if (!priv->rx_one)
-               return -ENOMEM;
-
        /*
         * Make dummy read to set initial power state and get real SPI clock
         * freq. It seems to be not important which channel is used for this
@@ -551,6 +679,12 @@ static int tsc2046_adc_setup_spi_msg(struct tsc2046_adc_priv *priv)
        for (ch_idx = 0; ch_idx < ARRAY_SIZE(priv->l); ch_idx++)
                size += tsc2046_adc_group_set_layout(priv, ch_idx, ch_idx);
 
+       if (size > PAGE_SIZE) {
+               dev_err(&priv->spi->dev,
+                       "Calculated scan buffer is too big. Try to reduce spi-max-frequency, settling-time-us or oversampling-ratio\n");
+               return -ENOSPC;
+       }
+
        priv->tx = devm_kzalloc(&priv->spi->dev, size, GFP_KERNEL);
        if (!priv->tx)
                return -ENOMEM;
@@ -668,10 +802,11 @@ static int tsc2046_adc_probe(struct spi_device *spi)
        iio_trigger_set_drvdata(trig, indio_dev);
        trig->ops = &tsc2046_adc_trigger_ops;
 
-       spin_lock_init(&priv->trig_lock);
+       spin_lock_init(&priv->state_lock);
+       priv->state = TSC2046_STATE_SHUTDOWN;
        hrtimer_init(&priv->trig_timer, CLOCK_MONOTONIC,
                     HRTIMER_MODE_REL_SOFT);
-       priv->trig_timer.function = tsc2046_adc_trig_more;
+       priv->trig_timer.function = tsc2046_adc_timer;
 
        ret = devm_iio_trigger_register(dev, trig);
        if (ret) {
index 6ce40cc4568a2d75561177ec079eaccdce2fc8cb..f8f8aea15612af435c1e75aeab39e69e5e4a9324 100644 (file)
@@ -231,13 +231,7 @@ static const struct iio_chan_spec twl4030_madc_iio_channels[] = {
 
 static struct twl4030_madc_data *twl4030_madc;
 
-struct twl4030_prescale_divider_ratios {
-       s16 numerator;
-       s16 denominator;
-};
-
-static const struct twl4030_prescale_divider_ratios
-twl4030_divider_ratios[16] = {
+static const struct s16_fract twl4030_divider_ratios[16] = {
        {1, 1},         /* CHANNEL 0 No Prescaler */
        {1, 1},         /* CHANNEL 1 No Prescaler */
        {6, 10},        /* CHANNEL 2 */
@@ -256,7 +250,6 @@ twl4030_divider_ratios[16] = {
        {5, 11},        /* CHANNEL 15 */
 };
 
-
 /* Conversion table from -3 to 55 degrees Celcius */
 static int twl4030_therm_tbl[] = {
        30800,  29500,  28300,  27100,
index afdb59e0b5267395b2fa7c8b3af0a6aa2b052e2a..f53e8558b560c7e04e7e41fd22eddfecf0c3c38c 100644 (file)
@@ -911,6 +911,8 @@ static int twl6030_gpadc_probe(struct platform_device *pdev)
        ret = devm_request_threaded_irq(dev, irq, NULL,
                                twl6030_gpadc_irq_handler,
                                IRQF_ONESHOT, "twl6030_gpadc", indio_dev);
+       if (ret)
+               return ret;
 
        ret = twl6030_gpadc_enable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK);
        if (ret < 0) {
@@ -944,7 +946,6 @@ static int twl6030_gpadc_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int twl6030_gpadc_suspend(struct device *pdev)
 {
        int ret;
@@ -968,17 +969,16 @@ static int twl6030_gpadc_resume(struct device *pdev)
 
        return 0;
 };
-#endif
 
-static SIMPLE_DEV_PM_OPS(twl6030_gpadc_pm_ops, twl6030_gpadc_suspend,
-                                       twl6030_gpadc_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(twl6030_gpadc_pm_ops, twl6030_gpadc_suspend,
+                               twl6030_gpadc_resume);
 
 static struct platform_driver twl6030_gpadc_driver = {
        .probe          = twl6030_gpadc_probe,
        .remove         = twl6030_gpadc_remove,
        .driver         = {
                .name   = DRIVER_NAME,
-               .pm     = &twl6030_gpadc_pm_ops,
+               .pm     = pm_sleep_ptr(&twl6030_gpadc_pm_ops),
                .of_match_table = of_twl6030_match_tbl,
        },
 };
index fd57fc43e8e5c636e588df0817d69c70c6801716..c84293efc129c3f6bae8002ca0dba54bfd30bf84 100644 (file)
@@ -912,7 +912,6 @@ static int vf610_adc_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int vf610_adc_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
@@ -952,9 +951,9 @@ disable_reg:
        regulator_disable(info->vref);
        return ret;
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops, vf610_adc_suspend, vf610_adc_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops, vf610_adc_suspend,
+                               vf610_adc_resume);
 
 static struct platform_driver vf610_adc_driver = {
        .probe          = vf610_adc_probe,
@@ -962,7 +961,7 @@ static struct platform_driver vf610_adc_driver = {
        .driver         = {
                .name   = DRIVER_NAME,
                .of_match_table = vf610_adc_match,
-               .pm     = &vf610_adc_pm_ops,
+               .pm     = pm_sleep_ptr(&vf610_adc_pm_ops),
        },
 };
 
index 8343c5f74121ec7f9baf6524a6268908894c80cd..a55396c1f8b28f2e3c51539ff6751136e62025ba 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/devm-helpers.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
@@ -91,8 +92,8 @@
 
 #define AMS_CONF1_SEQ_MASK             GENMASK(15, 12)
 #define AMS_CONF1_SEQ_DEFAULT          FIELD_PREP(AMS_CONF1_SEQ_MASK, 0)
-#define AMS_CONF1_SEQ_CONTINUOUS       FIELD_PREP(AMS_CONF1_SEQ_MASK, 1)
-#define AMS_CONF1_SEQ_SINGLE_CHANNEL   FIELD_PREP(AMS_CONF1_SEQ_MASK, 2)
+#define AMS_CONF1_SEQ_CONTINUOUS       FIELD_PREP(AMS_CONF1_SEQ_MASK, 2)
+#define AMS_CONF1_SEQ_SINGLE_CHANNEL   FIELD_PREP(AMS_CONF1_SEQ_MASK, 3)
 
 #define AMS_REG_SEQ0_MASK              GENMASK(15, 0)
 #define AMS_REG_SEQ2_MASK              GENMASK(21, 16)
@@ -530,14 +531,18 @@ static int ams_enable_single_channel(struct ams *ams, unsigned int offset)
                return -EINVAL;
        }
 
-       /* set single channel, sequencer off mode */
+       /* put sysmon in a soft reset to change the sequence */
        ams_ps_update_reg(ams, AMS_REG_CONFIG1, AMS_CONF1_SEQ_MASK,
-                         AMS_CONF1_SEQ_SINGLE_CHANNEL);
+                         AMS_CONF1_SEQ_DEFAULT);
 
        /* write the channel number */
        ams_ps_update_reg(ams, AMS_REG_CONFIG0, AMS_CONF0_CHANNEL_NUM_MASK,
                          channel_num);
 
+       /* set single channel, sequencer off mode */
+       ams_ps_update_reg(ams, AMS_REG_CONFIG1, AMS_CONF1_SEQ_MASK,
+                         AMS_CONF1_SEQ_SINGLE_CHANNEL);
+
        return 0;
 }
 
@@ -551,6 +556,8 @@ static int ams_read_vcc_reg(struct ams *ams, unsigned int offset, u32 *data)
        if (ret)
                return ret;
 
+       /* clear end-of-conversion flag, wait for next conversion to complete */
+       writel(expect, ams->base + AMS_ISR_1);
        ret = readl_poll_timeout(ams->base + AMS_ISR_1, reg, (reg & expect),
                                 AMS_INIT_POLL_TIME_US, AMS_INIT_TIMEOUT_US);
        if (ret)
@@ -1224,6 +1231,7 @@ static int ams_init_module(struct iio_dev *indio_dev,
 
                /* add PS channels to iio device channels */
                memcpy(channels, ams_ps_channels, sizeof(ams_ps_channels));
+               num_channels = ARRAY_SIZE(ams_ps_channels);
        } else if (fwnode_property_match_string(fwnode, "compatible",
                                                "xlnx,zynqmp-ams-pl") == 0) {
                ams->pl_base = fwnode_iomap(fwnode, 0);
@@ -1348,11 +1356,6 @@ static void ams_clk_disable_unprepare(void *data)
        clk_disable_unprepare(data);
 }
 
-static void ams_cancel_delayed_work(void *data)
-{
-       cancel_delayed_work(data);
-}
-
 static int ams_probe(struct platform_device *pdev)
 {
        struct iio_dev *indio_dev;
@@ -1389,9 +1392,8 @@ static int ams_probe(struct platform_device *pdev)
        if (ret < 0)
                return ret;
 
-       INIT_DELAYED_WORK(&ams->ams_unmask_work, ams_unmask_worker);
-       ret = devm_add_action_or_reset(&pdev->dev, ams_cancel_delayed_work,
-                                      &ams->ams_unmask_work);
+       ret = devm_delayed_work_autocancel(&pdev->dev, &ams->ams_unmask_work,
+                                          ams_unmask_worker);
        if (ret < 0)
                return ret;
 
index 774eb3044edd8278d2a4cdd7360ca21410b3a07d..7e511293d6d1237cb1d958d80682a44fd212d9b9 100644 (file)
  * IIO rescale driver
  *
  * Copyright (C) 2018 Axentia Technologies AB
+ * Copyright (C) 2022 Liam Beguin <[email protected]>
  *
  * Author: Peter Rosin <[email protected]>
  */
 
 #include <linux/err.h>
 #include <linux/gcd.h>
-#include <linux/iio/consumer.h>
-#include <linux/iio/iio.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/property.h>
 
-struct rescale;
+#include <linux/iio/afe/rescale.h>
+#include <linux/iio/consumer.h>
+#include <linux/iio/iio.h>
 
-struct rescale_cfg {
-       enum iio_chan_type type;
-       int (*props)(struct device *dev, struct rescale *rescale);
-};
+int rescale_process_scale(struct rescale *rescale, int scale_type,
+                         int *val, int *val2)
+{
+       s64 tmp;
+       int _val, _val2;
+       s32 rem, rem2;
+       u32 mult;
+       u32 neg;
+
+       switch (scale_type) {
+       case IIO_VAL_INT:
+               *val *= rescale->numerator;
+               if (rescale->denominator == 1)
+                       return scale_type;
+               *val2 = rescale->denominator;
+               return IIO_VAL_FRACTIONAL;
+       case IIO_VAL_FRACTIONAL:
+               /*
+                * When the product of both scales doesn't overflow, avoid
+                * potential accuracy loss (for in kernel consumers) by
+                * keeping a fractional representation.
+                */
+               if (!check_mul_overflow(*val, rescale->numerator, &_val) &&
+                   !check_mul_overflow(*val2, rescale->denominator, &_val2)) {
+                       *val = _val;
+                       *val2 = _val2;
+                       return IIO_VAL_FRACTIONAL;
+               }
+               fallthrough;
+       case IIO_VAL_FRACTIONAL_LOG2:
+               tmp = (s64)*val * 1000000000LL;
+               tmp = div_s64(tmp, rescale->denominator);
+               tmp *= rescale->numerator;
 
-struct rescale {
-       const struct rescale_cfg *cfg;
-       struct iio_channel *source;
-       struct iio_chan_spec chan;
-       struct iio_chan_spec_ext_info *ext_info;
-       bool chan_processed;
-       s32 numerator;
-       s32 denominator;
-};
+               tmp = div_s64_rem(tmp, 1000000000LL, &rem);
+               *val = tmp;
+
+               if (!rem)
+                       return scale_type;
+
+               if (scale_type == IIO_VAL_FRACTIONAL)
+                       tmp = *val2;
+               else
+                       tmp = ULL(1) << *val2;
+
+               rem2 = *val % (int)tmp;
+               *val = *val / (int)tmp;
+
+               *val2 = rem / (int)tmp;
+               if (rem2)
+                       *val2 += div_s64((s64)rem2 * 1000000000LL, tmp);
+
+               return IIO_VAL_INT_PLUS_NANO;
+       case IIO_VAL_INT_PLUS_NANO:
+       case IIO_VAL_INT_PLUS_MICRO:
+               mult = scale_type == IIO_VAL_INT_PLUS_NANO ? 1000000000L : 1000000L;
+
+               /*
+                * For IIO_VAL_INT_PLUS_{MICRO,NANO} scale types if either *val
+                * OR *val2 is negative the schan scale is negative, i.e.
+                * *val = 1 and *val2 = -0.5 yields -1.5 not -0.5.
+                */
+               neg = *val < 0 || *val2 < 0;
+
+               tmp = (s64)abs(*val) * abs(rescale->numerator);
+               *val = div_s64_rem(tmp, abs(rescale->denominator), &rem);
+
+               tmp = (s64)rem * mult + (s64)abs(*val2) * abs(rescale->numerator);
+               tmp = div_s64(tmp, abs(rescale->denominator));
+
+               *val += div_s64_rem(tmp, mult, val2);
+
+               /*
+                * If only one of the rescaler elements or the schan scale is
+                * negative, the combined scale is negative.
+                */
+               if (neg ^ ((rescale->numerator < 0) ^ (rescale->denominator < 0))) {
+                       if (*val)
+                               *val = -*val;
+                       else
+                               *val2 = -*val2;
+               }
+
+               return scale_type;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+int rescale_process_offset(struct rescale *rescale, int scale_type,
+                          int scale, int scale2, int schan_off,
+                          int *val, int *val2)
+{
+       s64 tmp, tmp2;
+
+       switch (scale_type) {
+       case IIO_VAL_FRACTIONAL:
+               tmp = (s64)rescale->offset * scale2;
+               *val = div_s64(tmp, scale) + schan_off;
+               return IIO_VAL_INT;
+       case IIO_VAL_INT:
+               *val = div_s64(rescale->offset, scale) + schan_off;
+               return IIO_VAL_INT;
+       case IIO_VAL_FRACTIONAL_LOG2:
+               tmp = (s64)rescale->offset * (1 << scale2);
+               *val = div_s64(tmp, scale) + schan_off;
+               return IIO_VAL_INT;
+       case IIO_VAL_INT_PLUS_NANO:
+               tmp = (s64)rescale->offset * 1000000000LL;
+               tmp2 = ((s64)scale * 1000000000LL) + scale2;
+               *val = div64_s64(tmp, tmp2) + schan_off;
+               return IIO_VAL_INT;
+       case IIO_VAL_INT_PLUS_MICRO:
+               tmp = (s64)rescale->offset * 1000000LL;
+               tmp2 = ((s64)scale * 1000000LL) + scale2;
+               *val = div64_s64(tmp, tmp2) + schan_off;
+               return IIO_VAL_INT;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
 
 static int rescale_read_raw(struct iio_dev *indio_dev,
                            struct iio_chan_spec const *chan,
                            int *val, int *val2, long mask)
 {
        struct rescale *rescale = iio_priv(indio_dev);
-       unsigned long long tmp;
+       int scale, scale2;
+       int schan_off = 0;
        int ret;
 
        switch (mask) {
@@ -65,27 +174,48 @@ static int rescale_read_raw(struct iio_dev *indio_dev,
                } else {
                        ret = iio_read_channel_scale(rescale->source, val, val2);
                }
-               switch (ret) {
-               case IIO_VAL_FRACTIONAL:
-                       *val *= rescale->numerator;
-                       *val2 *= rescale->denominator;
-                       return ret;
-               case IIO_VAL_INT:
-                       *val *= rescale->numerator;
-                       if (rescale->denominator == 1)
-                               return ret;
-                       *val2 = rescale->denominator;
-                       return IIO_VAL_FRACTIONAL;
-               case IIO_VAL_FRACTIONAL_LOG2:
-                       tmp = *val * 1000000000LL;
-                       do_div(tmp, rescale->denominator);
-                       tmp *= rescale->numerator;
-                       do_div(tmp, 1000000000LL);
-                       *val = tmp;
-                       return ret;
-               default:
-                       return -EOPNOTSUPP;
+               return rescale_process_scale(rescale, ret, val, val2);
+       case IIO_CHAN_INFO_OFFSET:
+               /*
+                * Processed channels are scaled 1-to-1 and source offset is
+                * already taken into account.
+                *
+                * In other cases, real world measurement are expressed as:
+                *
+                *      schan_scale * (raw + schan_offset)
+                *
+                * Given that the rescaler parameters are applied recursively:
+                *
+                *      rescaler_scale * (schan_scale * (raw + schan_offset) +
+                *              rescaler_offset)
+                *
+                * Or,
+                *
+                *      (rescaler_scale * schan_scale) * (raw +
+                *              (schan_offset + rescaler_offset / schan_scale)
+                *
+                * Thus, reusing the original expression the parameters exposed
+                * to userspace are:
+                *
+                *      scale = schan_scale * rescaler_scale
+                *      offset = schan_offset + rescaler_offset / schan_scale
+                */
+               if (rescale->chan_processed) {
+                       *val = rescale->offset;
+                       return IIO_VAL_INT;
                }
+
+               if (iio_channel_has_info(rescale->source->channel,
+                                        IIO_CHAN_INFO_OFFSET)) {
+                       ret = iio_read_channel_offset(rescale->source,
+                                                     &schan_off, NULL);
+                       if (ret != IIO_VAL_INT)
+                               return ret < 0 ? ret : -EOPNOTSUPP;
+               }
+
+               ret = iio_read_channel_scale(rescale->source, &scale, &scale2);
+               return rescale_process_offset(rescale, ret, scale, scale2,
+                                             schan_off, val, val2);
        default:
                return -EINVAL;
        }
@@ -162,6 +292,9 @@ static int rescale_configure_channel(struct device *dev,
        chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
                BIT(IIO_CHAN_INFO_SCALE);
 
+       if (rescale->offset)
+               chan->info_mask_separate |= BIT(IIO_CHAN_INFO_OFFSET);
+
        /*
         * Using .read_avail() is fringe to begin with and makes no sense
         * whatsoever for processed channels, so we make sure that this cannot
@@ -261,10 +394,78 @@ static int rescale_voltage_divider_props(struct device *dev,
        return 0;
 }
 
+static int rescale_temp_sense_rtd_props(struct device *dev,
+                                       struct rescale *rescale)
+{
+       u32 factor;
+       u32 alpha;
+       u32 iexc;
+       u32 tmp;
+       int ret;
+       u32 r0;
+
+       ret = device_property_read_u32(dev, "excitation-current-microamp",
+                                      &iexc);
+       if (ret) {
+               dev_err(dev, "failed to read excitation-current-microamp: %d\n",
+                       ret);
+               return ret;
+       }
+
+       ret = device_property_read_u32(dev, "alpha-ppm-per-celsius", &alpha);
+       if (ret) {
+               dev_err(dev, "failed to read alpha-ppm-per-celsius: %d\n",
+                       ret);
+               return ret;
+       }
+
+       ret = device_property_read_u32(dev, "r-naught-ohms", &r0);
+       if (ret) {
+               dev_err(dev, "failed to read r-naught-ohms: %d\n", ret);
+               return ret;
+       }
+
+       tmp = r0 * iexc * alpha / 1000000;
+       factor = gcd(tmp, 1000000);
+       rescale->numerator = 1000000 / factor;
+       rescale->denominator = tmp / factor;
+
+       rescale->offset = -1 * ((r0 * iexc) / 1000);
+
+       return 0;
+}
+
+static int rescale_temp_transducer_props(struct device *dev,
+                                        struct rescale *rescale)
+{
+       s32 offset = 0;
+       s32 sense = 1;
+       s32 alpha;
+       int ret;
+
+       device_property_read_u32(dev, "sense-offset-millicelsius", &offset);
+       device_property_read_u32(dev, "sense-resistor-ohms", &sense);
+       ret = device_property_read_u32(dev, "alpha-ppm-per-celsius", &alpha);
+       if (ret) {
+               dev_err(dev, "failed to read alpha-ppm-per-celsius: %d\n", ret);
+               return ret;
+       }
+
+       rescale->numerator = 1000000;
+       rescale->denominator = alpha * sense;
+
+       rescale->offset = div_s64((s64)offset * rescale->denominator,
+                                 rescale->numerator);
+
+       return 0;
+}
+
 enum rescale_variant {
        CURRENT_SENSE_AMPLIFIER,
        CURRENT_SENSE_SHUNT,
        VOLTAGE_DIVIDER,
+       TEMP_SENSE_RTD,
+       TEMP_TRANSDUCER,
 };
 
 static const struct rescale_cfg rescale_cfg[] = {
@@ -280,6 +481,14 @@ static const struct rescale_cfg rescale_cfg[] = {
                .type = IIO_VOLTAGE,
                .props = rescale_voltage_divider_props,
        },
+       [TEMP_SENSE_RTD] = {
+               .type = IIO_TEMP,
+               .props = rescale_temp_sense_rtd_props,
+       },
+       [TEMP_TRANSDUCER] = {
+               .type = IIO_TEMP,
+               .props = rescale_temp_transducer_props,
+       },
 };
 
 static const struct of_device_id rescale_match[] = {
@@ -289,6 +498,10 @@ static const struct of_device_id rescale_match[] = {
          .data = &rescale_cfg[CURRENT_SENSE_SHUNT], },
        { .compatible = "voltage-divider",
          .data = &rescale_cfg[VOLTAGE_DIVIDER], },
+       { .compatible = "temperature-sense-rtd",
+         .data = &rescale_cfg[TEMP_SENSE_RTD], },
+       { .compatible = "temperature-transducer",
+         .data = &rescale_cfg[TEMP_TRANSDUCER], },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, rescale_match);
@@ -326,6 +539,7 @@ static int rescale_probe(struct platform_device *pdev)
        rescale->cfg = of_device_get_match_data(dev);
        rescale->numerator = 1;
        rescale->denominator = 1;
+       rescale->offset = 0;
 
        ret = rescale->cfg->props(dev, rescale);
        if (ret)
index 5eb1357a9c788f980d6a49aed82c3c0cfd7614f7..f217a2a1e9586c15d7c7528f5e7e9b1f38470507 100644 (file)
@@ -23,6 +23,17 @@ config AD8366
          To compile this driver as a module, choose M here: the
          module will be called ad8366.
 
+config ADA4250
+       tristate "Analog Devices ADA4250 Instrumentation Amplifier"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices ADA4250
+         SPI Amplifier's support. The driver provides direct access via
+         sysfs.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ada4250.
+
 config HMC425
        tristate "Analog Devices HMC425A and similar GPIO Gain Amplifiers"
        depends on GPIOLIB
index cb551d82f56b89cf0d1cdfced996603f784a710b..2126331129cf6e3ebdaa388830d73bb48abcbd73 100644 (file)
@@ -5,4 +5,5 @@
 
 # When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_AD8366) += ad8366.o
+obj-$(CONFIG_ADA4250) += ada4250.o
 obj-$(CONFIG_HMC425) += hmc425a.o
diff --git a/drivers/iio/amplifiers/ada4250.c b/drivers/iio/amplifiers/ada4250.c
new file mode 100644 (file)
index 0000000..4b32d35
--- /dev/null
@@ -0,0 +1,403 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ADA4250 driver
+ *
+ * Copyright 2022 Analog Devices Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#include <asm/unaligned.h>
+
+/* ADA4250 Register Map */
+#define ADA4250_REG_GAIN_MUX        0x00
+#define ADA4250_REG_REFBUF_EN       0x01
+#define ADA4250_REG_RESET           0x02
+#define ADA4250_REG_SNSR_CAL_VAL    0x04
+#define ADA4250_REG_SNSR_CAL_CNFG   0x05
+#define ADA4250_REG_DIE_REV         0x18
+#define ADA4250_REG_CHIP_ID         0x19
+
+/* ADA4250_REG_GAIN_MUX Map */
+#define ADA4250_GAIN_MUX_MSK        GENMASK(2, 0)
+
+/* ADA4250_REG_REFBUF Map */
+#define ADA4250_REFBUF_MSK          BIT(0)
+
+/* ADA4250_REG_RESET Map */
+#define ADA4250_RESET_MSK           BIT(0)
+
+/* ADA4250_REG_SNSR_CAL_VAL Map */
+#define ADA4250_CAL_CFG_BIAS_MSK    GENMASK(7, 0)
+
+/* ADA4250_REG_SNSR_CAL_CNFG Bit Definition */
+#define ADA4250_BIAS_SET_MSK        GENMASK(3, 2)
+#define ADA4250_RANGE_SET_MSK       GENMASK(1, 0)
+
+/* Miscellaneous definitions */
+#define ADA4250_CHIP_ID             0x4250
+#define ADA4250_RANGE1              0
+#define        ADA4250_RANGE4              3
+
+/* ADA4250 current bias set */
+enum ada4250_current_bias {
+       ADA4250_BIAS_DISABLED,
+       ADA4250_BIAS_BANDGAP,
+       ADA4250_BIAS_AVDD,
+};
+
+struct ada4250_state {
+       struct spi_device       *spi;
+       struct regmap           *regmap;
+       struct regulator        *reg;
+       /* Protect against concurrent accesses to the device and data content */
+       struct mutex            lock;
+       u8                      bias;
+       u8                      gain;
+       int                     offset_uv;
+       bool                    refbuf_en;
+};
+
+/* ADA4250 Current Bias Source Settings: Disabled, Bandgap Reference, AVDD */
+static const int calibbias_table[] = {0, 1, 2};
+
+/* ADA4250 Gain (V/V) values: 1, 2, 4, 8, 16, 32, 64, 128 */
+static const int hwgain_table[] = {1, 2, 4, 8, 16, 32, 64, 128};
+
+static const struct regmap_config ada4250_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .read_flag_mask = BIT(7),
+       .max_register = 0x1A,
+};
+
+static int ada4250_set_offset_uv(struct iio_dev *indio_dev,
+                                const struct iio_chan_spec *chan,
+                                int offset_uv)
+{
+       struct ada4250_state *st = iio_priv(indio_dev);
+
+       int i, ret, x[8], max_vos, min_vos, voltage_v, vlsb = 0;
+       u8 offset_raw, range = ADA4250_RANGE1;
+       u32 lsb_coeff[6] = {1333, 2301, 4283, 8289, 16311, 31599};
+
+       if (st->bias == 0 || st->bias == 3)
+               return -EINVAL;
+
+       voltage_v = regulator_get_voltage(st->reg);
+       voltage_v = DIV_ROUND_CLOSEST(voltage_v, 1000000);
+
+       if (st->bias == ADA4250_BIAS_AVDD)
+               x[0] = voltage_v;
+       else
+               x[0] = 5;
+
+       x[1] = 126 * (x[0] - 1);
+
+       for (i = 0; i < 6; i++)
+               x[i + 2] = DIV_ROUND_CLOSEST(x[1] * 1000, lsb_coeff[i]);
+
+       if (st->gain == 0)
+               return -EINVAL;
+
+       /*
+        * Compute Range and Voltage per LSB for the Sensor Offset Calibration
+        * Example of computation for Range 1 and Range 2 (Curren Bias Set = AVDD):
+        *                     Range 1                            Range 2
+        *   Gain   | Max Vos(mV) |   LSB(mV)        |  Max Vos(mV)  | LSB(mV) |
+        *    2     |    X1*127   | X1=0.126(AVDD-1) |   X1*3*127    |  X1*3   |
+        *    4     |    X2*127   | X2=X1/1.3333     |   X2*3*127    |  X2*3   |
+        *    8     |    X3*127   | X3=X1/2.301      |   X3*3*127    |  X3*3   |
+        *    16    |    X4*127   | X4=X1/4.283      |   X4*3*127    |  X4*3   |
+        *    32    |    X5*127   | X5=X1/8.289      |   X5*3*127    |  X5*3   |
+        *    64    |    X6*127   | X6=X1/16.311     |   X6*3*127    |  X6*3   |
+        *    128   |    X7*127   | X7=X1/31.599     |   X7*3*127    |  X7*3   |
+        */
+       for (i = ADA4250_RANGE1; i <= ADA4250_RANGE4; i++) {
+               max_vos = x[st->gain] *  127 * ((1 << (i + 1)) - 1);
+               min_vos = -1 * max_vos;
+               if (offset_uv > min_vos && offset_uv < max_vos) {
+                       range = i;
+                       vlsb = x[st->gain] * ((1 << (i + 1)) - 1);
+                       break;
+               }
+       }
+
+       if (vlsb <= 0)
+               return -EINVAL;
+
+       offset_raw = DIV_ROUND_CLOSEST(abs(offset_uv), vlsb);
+
+       mutex_lock(&st->lock);
+       ret = regmap_update_bits(st->regmap, ADA4250_REG_SNSR_CAL_CNFG,
+                                ADA4250_RANGE_SET_MSK,
+                                FIELD_PREP(ADA4250_RANGE_SET_MSK, range));
+       if (ret)
+               goto exit;
+
+       st->offset_uv = offset_raw * vlsb;
+
+       /*
+        * To set the offset calibration value, use bits [6:0] and bit 7 as the
+        * polarity bit (set to "0" for a negative offset and "1" for a positive
+        * offset).
+        */
+       if (offset_uv < 0) {
+               offset_raw |= BIT(7);
+               st->offset_uv *= (-1);
+       }
+
+       ret = regmap_write(st->regmap, ADA4250_REG_SNSR_CAL_VAL, offset_raw);
+
+exit:
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static int ada4250_read_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int *val, int *val2, long info)
+{
+       struct ada4250_state *st = iio_priv(indio_dev);
+       int ret;
+
+       switch (info) {
+       case IIO_CHAN_INFO_HARDWAREGAIN:
+               ret = regmap_read(st->regmap, ADA4250_REG_GAIN_MUX, val);
+               if (ret)
+                       return ret;
+
+               *val = BIT(*val);
+
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_OFFSET:
+               *val = st->offset_uv;
+
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_CALIBBIAS:
+               ret = regmap_read(st->regmap, ADA4250_REG_SNSR_CAL_CNFG, val);
+               if (ret)
+                       return ret;
+
+               *val = FIELD_GET(ADA4250_BIAS_SET_MSK, *val);
+
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               *val = 1;
+               *val2 = 1000000;
+
+               return IIO_VAL_FRACTIONAL;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ada4250_write_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            int val, int val2, long info)
+{
+       struct ada4250_state *st = iio_priv(indio_dev);
+       int ret;
+
+       switch (info) {
+       case IIO_CHAN_INFO_HARDWAREGAIN:
+               ret = regmap_write(st->regmap, ADA4250_REG_GAIN_MUX,
+                                  FIELD_PREP(ADA4250_GAIN_MUX_MSK, ilog2(val)));
+               if (ret)
+                       return ret;
+
+               st->gain = ilog2(val);
+
+               return ret;
+       case IIO_CHAN_INFO_OFFSET:
+               return ada4250_set_offset_uv(indio_dev, chan, val);
+       case IIO_CHAN_INFO_CALIBBIAS:
+               ret = regmap_update_bits(st->regmap, ADA4250_REG_SNSR_CAL_CNFG,
+                                        ADA4250_BIAS_SET_MSK,
+                                        FIELD_PREP(ADA4250_BIAS_SET_MSK, val));
+               if (ret)
+                       return ret;
+
+               st->bias = val;
+
+               return ret;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ada4250_read_avail(struct iio_dev *indio_dev,
+                             struct iio_chan_spec const *chan,
+                             const int **vals, int *type, int *length,
+                             long mask)
+{
+       switch (mask) {
+       case IIO_CHAN_INFO_CALIBBIAS:
+               *vals = calibbias_table;
+               *type = IIO_VAL_INT;
+               *length = ARRAY_SIZE(calibbias_table);
+
+               return IIO_AVAIL_LIST;
+       case IIO_CHAN_INFO_HARDWAREGAIN:
+               *vals = hwgain_table;
+               *type = IIO_VAL_INT;
+               *length = ARRAY_SIZE(hwgain_table);
+
+               return IIO_AVAIL_LIST;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ada4250_reg_access(struct iio_dev *indio_dev,
+                             unsigned int reg,
+                             unsigned int write_val,
+                             unsigned int *read_val)
+{
+       struct ada4250_state *st = iio_priv(indio_dev);
+
+       if (read_val)
+               return regmap_read(st->regmap, reg, read_val);
+       else
+               return regmap_write(st->regmap, reg, write_val);
+}
+
+static const struct iio_info ada4250_info = {
+       .read_raw = ada4250_read_raw,
+       .write_raw = ada4250_write_raw,
+       .read_avail = &ada4250_read_avail,
+       .debugfs_reg_access = &ada4250_reg_access,
+};
+
+static const struct iio_chan_spec ada4250_channels[] = {
+       {
+               .type = IIO_VOLTAGE,
+               .output = 1,
+               .indexed = 1,
+               .channel = 0,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN) |
+                               BIT(IIO_CHAN_INFO_OFFSET) |
+                               BIT(IIO_CHAN_INFO_CALIBBIAS) |
+                               BIT(IIO_CHAN_INFO_SCALE),
+               .info_mask_separate_available = BIT(IIO_CHAN_INFO_CALIBBIAS) |
+                                               BIT(IIO_CHAN_INFO_HARDWAREGAIN),
+       }
+};
+
+static void ada4250_reg_disable(void *data)
+{
+       regulator_disable(data);
+}
+
+static int ada4250_init(struct ada4250_state *st)
+{
+       int ret;
+       u16 chip_id;
+       u8 data[2] __aligned(8) = {};
+       struct spi_device *spi = st->spi;
+
+       st->refbuf_en = device_property_read_bool(&spi->dev, "adi,refbuf-enable");
+
+       st->reg = devm_regulator_get(&spi->dev, "avdd");
+       if (IS_ERR(st->reg))
+               return dev_err_probe(&spi->dev, PTR_ERR(st->reg),
+                                    "failed to get the AVDD voltage\n");
+
+       ret = regulator_enable(st->reg);
+       if (ret) {
+               dev_err(&spi->dev, "Failed to enable specified AVDD supply\n");
+               return ret;
+       }
+
+       ret = devm_add_action_or_reset(&spi->dev, ada4250_reg_disable, st->reg);
+       if (ret)
+               return ret;
+
+       ret = regmap_write(st->regmap, ADA4250_REG_RESET,
+                          FIELD_PREP(ADA4250_RESET_MSK, 1));
+       if (ret)
+               return ret;
+
+       ret = regmap_bulk_read(st->regmap, ADA4250_REG_CHIP_ID, data, 2);
+       if (ret)
+               return ret;
+
+       chip_id = get_unaligned_le16(data);
+
+       if (chip_id != ADA4250_CHIP_ID) {
+               dev_err(&spi->dev, "Invalid chip ID.\n");
+               return -EINVAL;
+       }
+
+       return regmap_write(st->regmap, ADA4250_REG_REFBUF_EN,
+                           FIELD_PREP(ADA4250_REFBUF_MSK, st->refbuf_en));
+}
+
+static int ada4250_probe(struct spi_device *spi)
+{
+       struct iio_dev *indio_dev;
+       struct regmap *regmap;
+       struct ada4250_state *st;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       regmap = devm_regmap_init_spi(spi, &ada4250_regmap_config);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       st = iio_priv(indio_dev);
+       st->regmap = regmap;
+       st->spi = spi;
+
+       indio_dev->info = &ada4250_info;
+       indio_dev->name = "ada4250";
+       indio_dev->channels = ada4250_channels;
+       indio_dev->num_channels = ARRAY_SIZE(ada4250_channels);
+
+       mutex_init(&st->lock);
+
+       ret = ada4250_init(st);
+       if (ret) {
+               dev_err(&spi->dev, "ADA4250 init failed\n");
+               return ret;
+       }
+
+       return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct spi_device_id ada4250_id[] = {
+       { "ada4250", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(spi, ada4250_id);
+
+static const struct of_device_id ada4250_of_match[] = {
+       { .compatible = "adi,ada4250" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ada4250_of_match);
+
+static struct spi_driver ada4250_driver = {
+       .driver = {
+                       .name = "ada4250",
+                       .of_match_table = ada4250_of_match,
+               },
+       .probe = ada4250_probe,
+       .id_table = ada4250_id,
+};
+module_spi_driver(ada4250_driver);
+
+MODULE_AUTHOR("Antoniu Miclaus <[email protected]");
+MODULE_DESCRIPTION("Analog Devices ADA4250");
+MODULE_LICENSE("GPL v2");
index 16c0a77f6a1c1fb8dbf8a9625374b39ff3e4ee93..ce80e0c916f4a0db8c8704733bf58188c66857e7 100644 (file)
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 #include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
 #include <linux/platform_device.h>
+#include <linux/property.h>
 #include <linux/slab.h>
 #include <linux/regulator/consumer.h>
 #include <linux/sysfs.h>
@@ -192,7 +192,7 @@ static int hmc425a_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        st = iio_priv(indio_dev);
-       st->type = (uintptr_t)of_device_get_match_data(&pdev->dev);
+       st->type = (uintptr_t)device_get_match_data(&pdev->dev);
 
        st->chip_info = &hmc425a_chip_info_tbl[st->type];
        indio_dev->num_channels = st->chip_info->num_channels;
index f8ce26a24c57aee6d1578d030dce3c0c3532f8be..f744b62a636ad5ef526cd9e6b981b2a729fbe288 100644 (file)
@@ -136,7 +136,7 @@ static ssize_t iio_dmaengine_buffer_get_length_align(struct device *dev,
        struct dmaengine_buffer *dmaengine_buffer =
                iio_buffer_to_dmaengine_buffer(buffer);
 
-       return sprintf(buf, "%zu\n", dmaengine_buffer->align);
+       return sysfs_emit(buf, "%zu\n", dmaengine_buffer->align);
 }
 
 static IIO_DEVICE_ATTR(length_align_bytes, 0444,
index 87d9aabd20c7c55636742cb45916f0a34cc4aa67..fb58f599a80b19bd4e31d314af66396f7a288be0 100644 (file)
@@ -52,7 +52,6 @@ static const struct iio_buffer_access_funcs iio_hw_buf_access = {
 static struct hw_consumer_buffer *iio_hw_consumer_get_buffer(
        struct iio_hw_consumer *hwc, struct iio_dev *indio_dev)
 {
-       size_t mask_size = BITS_TO_LONGS(indio_dev->masklength) * sizeof(long);
        struct hw_consumer_buffer *buf;
 
        list_for_each_entry(buf, &hwc->buffers, head) {
@@ -60,7 +59,8 @@ static struct hw_consumer_buffer *iio_hw_consumer_get_buffer(
                        return buf;
        }
 
-       buf = kzalloc(sizeof(*buf) + mask_size, GFP_KERNEL);
+       buf = kzalloc(struct_size(buf, scan_mask, BITS_TO_LONGS(indio_dev->masklength)),
+                     GFP_KERNEL);
        if (!buf)
                return NULL;
 
index b1bacfe3c3ce0bd93d51c75dcb69c0c29275dc0d..bbcf5a59c1f4e8ef79a6c027b07e32bdeaee1856 100644 (file)
@@ -6,13 +6,15 @@
  * Author: Matt Ranostay <[email protected]>
  */
 
-#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/property.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
-#include <linux/of_device.h>
+
 #include <linux/iio/iio.h>
 
 #define ATLAS_EZO_DRV_NAME             "atlas-ezo-sensor"
@@ -33,7 +35,7 @@ struct atlas_ezo_device {
 
 struct atlas_ezo_data {
        struct i2c_client *client;
-       struct atlas_ezo_device *chip;
+       const struct atlas_ezo_device *chip;
 
        /* lock to avoid multiple concurrent read calls */
        struct mutex lock;
@@ -184,17 +186,17 @@ static const struct iio_info atlas_info = {
 };
 
 static const struct i2c_device_id atlas_ezo_id[] = {
-       { "atlas-co2-ezo", ATLAS_CO2_EZO },
-       { "atlas-o2-ezo", ATLAS_O2_EZO },
-       { "atlas-hum-ezo", ATLAS_HUM_EZO },
+       { "atlas-co2-ezo", (kernel_ulong_t)&atlas_ezo_devices[ATLAS_CO2_EZO] },
+       { "atlas-o2-ezo", (kernel_ulong_t)&atlas_ezo_devices[ATLAS_O2_EZO] },
+       { "atlas-hum-ezo", (kernel_ulong_t)&atlas_ezo_devices[ATLAS_HUM_EZO] },
        {}
 };
 MODULE_DEVICE_TABLE(i2c, atlas_ezo_id);
 
 static const struct of_device_id atlas_ezo_dt_ids[] = {
-       { .compatible = "atlas,co2-ezo", .data = (void *)ATLAS_CO2_EZO, },
-       { .compatible = "atlas,o2-ezo", .data = (void *)ATLAS_O2_EZO, },
-       { .compatible = "atlas,hum-ezo", .data = (void *)ATLAS_HUM_EZO, },
+       { .compatible = "atlas,co2-ezo", .data = &atlas_ezo_devices[ATLAS_CO2_EZO], },
+       { .compatible = "atlas,o2-ezo", .data = &atlas_ezo_devices[ATLAS_O2_EZO], },
+       { .compatible = "atlas,hum-ezo", .data = &atlas_ezo_devices[ATLAS_HUM_EZO], },
        {}
 };
 MODULE_DEVICE_TABLE(of, atlas_ezo_dt_ids);
@@ -202,20 +204,20 @@ MODULE_DEVICE_TABLE(of, atlas_ezo_dt_ids);
 static int atlas_ezo_probe(struct i2c_client *client,
                       const struct i2c_device_id *id)
 {
+       const struct atlas_ezo_device *chip;
        struct atlas_ezo_data *data;
-       struct atlas_ezo_device *chip;
-       const struct of_device_id *of_id;
        struct iio_dev *indio_dev;
 
        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
        if (!indio_dev)
                return -ENOMEM;
 
-       of_id = of_match_device(atlas_ezo_dt_ids, &client->dev);
-       if (!of_id)
-               chip = &atlas_ezo_devices[id->driver_data];
+       if (dev_fwnode(&client->dev))
+               chip = device_get_match_data(&client->dev);
        else
-               chip = &atlas_ezo_devices[(unsigned long)of_id->data];
+               chip = (const struct atlas_ezo_device *)id->driver_data;
+       if (!chip)
+               return -EINVAL;
 
        indio_dev->info = &atlas_info;
        indio_dev->name = ATLAS_EZO_DRV_NAME;
index 04b44a327614f781dc9ea9ebdf2ab0316aba1377..56dea9734c8de13ba5d0d4ee11677f7f6884f63a 100644 (file)
@@ -589,11 +589,11 @@ static const struct iio_info atlas_info = {
 };
 
 static const struct i2c_device_id atlas_id[] = {
-       { "atlas-ph-sm", ATLAS_PH_SM},
-       { "atlas-ec-sm", ATLAS_EC_SM},
-       { "atlas-orp-sm", ATLAS_ORP_SM},
-       { "atlas-do-sm", ATLAS_DO_SM},
-       { "atlas-rtd-sm", ATLAS_RTD_SM},
+       { "atlas-ph-sm", ATLAS_PH_SM },
+       { "atlas-ec-sm", ATLAS_EC_SM },
+       { "atlas-orp-sm", ATLAS_ORP_SM },
+       { "atlas-do-sm", ATLAS_DO_SM },
+       { "atlas-rtd-sm", ATLAS_RTD_SM },
        {}
 };
 MODULE_DEVICE_TABLE(i2c, atlas_id);
@@ -737,7 +737,6 @@ static int atlas_remove(struct i2c_client *client)
        return atlas_set_powermode(data, 0);
 }
 
-#ifdef CONFIG_PM
 static int atlas_runtime_suspend(struct device *dev)
 {
        struct atlas_data *data =
@@ -753,18 +752,16 @@ static int atlas_runtime_resume(struct device *dev)
 
        return atlas_set_powermode(data, 1);
 }
-#endif
 
 static const struct dev_pm_ops atlas_pm_ops = {
-       SET_RUNTIME_PM_OPS(atlas_runtime_suspend,
-                          atlas_runtime_resume, NULL)
+       RUNTIME_PM_OPS(atlas_runtime_suspend, atlas_runtime_resume, NULL)
 };
 
 static struct i2c_driver atlas_driver = {
        .driver = {
                .name   = ATLAS_DRV_NAME,
                .of_match_table = atlas_dt_ids,
-               .pm     = &atlas_pm_ops,
+               .pm     = pm_ptr(&atlas_pm_ops),
        },
        .probe          = atlas_probe,
        .remove         = atlas_remove,
index bf23cc7eb99eaea9f353f048eb8c8a54d5775da8..16ff7a98c9f020c5688e72eb3e568646299a12d1 100644 (file)
@@ -81,7 +81,7 @@ const struct regmap_config bme680_regmap_config = {
        .volatile_table = &bme680_volatile_table,
        .cache_type = REGCACHE_RBTREE,
 };
-EXPORT_SYMBOL(bme680_regmap_config);
+EXPORT_SYMBOL_NS(bme680_regmap_config, IIO_BME680);
 
 static const struct iio_chan_spec bme680_channels[] = {
        {
@@ -957,7 +957,7 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap,
 
        return devm_iio_device_register(dev, indio_dev);
 }
-EXPORT_SYMBOL_GPL(bme680_core_probe);
+EXPORT_SYMBOL_NS_GPL(bme680_core_probe, IIO_BME680);
 
 MODULE_AUTHOR("Himanshu Jha <[email protected]>");
 MODULE_DESCRIPTION("Bosch BME680 Driver");
index 74cf89c82c0afba7f94f842e9a0b744d879cfb80..20f2c20b6b022b131b2f21985cfe3958669bfcf4 100644 (file)
@@ -60,3 +60,4 @@ module_i2c_driver(bme680_i2c_driver);
 MODULE_AUTHOR("Himanshu Jha <[email protected]>");
 MODULE_DESCRIPTION("BME680 I2C driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_BME680);
index cc579a7ac5ce59b7eab1fc11f83cf2361182907b..4404d42ae5ec4d4fce851a186e416fb9c23efdd3 100644 (file)
@@ -4,8 +4,8 @@
  *
  * Copyright (C) 2018 Himanshu Jha <[email protected]>
  */
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
-#include <linux/of.h>
 #include <linux/regmap.h>
 #include <linux/spi/spi.h>
 
@@ -163,3 +163,4 @@ module_spi_driver(bme680_spi_driver);
 MODULE_AUTHOR("Himanshu Jha <[email protected]>");
 MODULE_DESCRIPTION("Bosch BME680 SPI driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_BME680);
index 267bc3c053380b30375a53cc2c9680726e278fc4..20d4e7584e923297cce16f91e22b44fbbb622621 100644 (file)
@@ -423,7 +423,7 @@ static ssize_t calibration_auto_enable_show(struct device *dev,
 
        val = (be16_to_cpu(bval) & SCD4X_READY_MASK) ? 1 : 0;
 
-       return sprintf(buf, "%d\n", val);
+       return sysfs_emit(buf, "%d\n", val);
 }
 
 static ssize_t calibration_auto_enable_store(struct device *dev,
index d51314505115e24799c64bc665226e95e6488ea9..abd67559e451547b5620bcec40d0f10a2968c646 100644 (file)
@@ -221,7 +221,7 @@ static ssize_t cleaning_period_show(struct device *dev,
        if (ret)
                return ret;
 
-       return sprintf(buf, "%d\n", be32_to_cpu(val));
+       return sysfs_emit(buf, "%d\n", be32_to_cpu(val));
 }
 
 static ssize_t cleaning_period_store(struct device *dev, struct device_attribute *attr,
index 16ea697e945c111e8388e1070cf5f73709fedd53..6633b35a94e69affb80c06851f300da68ed7ccaa 100644 (file)
@@ -58,7 +58,7 @@ int ms_sensors_reset(void *cli, u8 cmd, unsigned int delay)
 
        return 0;
 }
-EXPORT_SYMBOL(ms_sensors_reset);
+EXPORT_SYMBOL_NS(ms_sensors_reset, IIO_MEAS_SPEC_SENSORS);
 
 /**
  * ms_sensors_read_prom_word() - PROM word read function
@@ -84,7 +84,7 @@ int ms_sensors_read_prom_word(void *cli, int cmd, u16 *word)
 
        return 0;
 }
-EXPORT_SYMBOL(ms_sensors_read_prom_word);
+EXPORT_SYMBOL_NS(ms_sensors_read_prom_word, IIO_MEAS_SPEC_SENSORS);
 
 /**
  * ms_sensors_convert_and_read() - ADC conversion & read function
@@ -130,7 +130,7 @@ err:
        dev_err(&client->dev, "Unable to make sensor adc conversion\n");
        return ret;
 }
-EXPORT_SYMBOL(ms_sensors_convert_and_read);
+EXPORT_SYMBOL_NS(ms_sensors_convert_and_read, IIO_MEAS_SPEC_SENSORS);
 
 /**
  * ms_sensors_crc_valid() - CRC check function
@@ -248,7 +248,7 @@ int ms_sensors_read_serial(struct i2c_client *client, u64 *sn)
 
        return 0;
 }
-EXPORT_SYMBOL(ms_sensors_read_serial);
+EXPORT_SYMBOL_NS(ms_sensors_read_serial, IIO_MEAS_SPEC_SENSORS);
 
 static int ms_sensors_read_config_reg(struct i2c_client *client,
                                      u8 *config_reg)
@@ -299,7 +299,7 @@ ssize_t ms_sensors_write_resolution(struct ms_ht_dev *dev_data,
                                         MS_SENSORS_CONFIG_REG_WRITE,
                                         config_reg);
 }
-EXPORT_SYMBOL(ms_sensors_write_resolution);
+EXPORT_SYMBOL_NS(ms_sensors_write_resolution, IIO_MEAS_SPEC_SENSORS);
 
 /**
  * ms_sensors_show_battery_low() - Show device battery low indicator
@@ -324,9 +324,9 @@ ssize_t ms_sensors_show_battery_low(struct ms_ht_dev *dev_data,
        if (ret)
                return ret;
 
-       return sprintf(buf, "%d\n", (config_reg & 0x40) >> 6);
+       return sysfs_emit(buf, "%d\n", (config_reg & 0x40) >> 6);
 }
-EXPORT_SYMBOL(ms_sensors_show_battery_low);
+EXPORT_SYMBOL_NS(ms_sensors_show_battery_low, IIO_MEAS_SPEC_SENSORS);
 
 /**
  * ms_sensors_show_heater() - Show device heater
@@ -351,9 +351,9 @@ ssize_t ms_sensors_show_heater(struct ms_ht_dev *dev_data,
        if (ret)
                return ret;
 
-       return sprintf(buf, "%d\n", (config_reg & 0x4) >> 2);
+       return sysfs_emit(buf, "%d\n", (config_reg & 0x4) >> 2);
 }
-EXPORT_SYMBOL(ms_sensors_show_heater);
+EXPORT_SYMBOL_NS(ms_sensors_show_heater, IIO_MEAS_SPEC_SENSORS);
 
 /**
  * ms_sensors_write_heater() - Write device heater
@@ -401,7 +401,7 @@ ssize_t ms_sensors_write_heater(struct ms_ht_dev *dev_data,
 
        return len;
 }
-EXPORT_SYMBOL(ms_sensors_write_heater);
+EXPORT_SYMBOL_NS(ms_sensors_write_heater, IIO_MEAS_SPEC_SENSORS);
 
 /**
  * ms_sensors_ht_read_temperature() - Read temperature
@@ -442,7 +442,7 @@ int ms_sensors_ht_read_temperature(struct ms_ht_dev *dev_data,
 
        return 0;
 }
-EXPORT_SYMBOL(ms_sensors_ht_read_temperature);
+EXPORT_SYMBOL_NS(ms_sensors_ht_read_temperature, IIO_MEAS_SPEC_SENSORS);
 
 /**
  * ms_sensors_ht_read_humidity() - Read humidity
@@ -485,7 +485,7 @@ int ms_sensors_ht_read_humidity(struct ms_ht_dev *dev_data,
 
        return 0;
 }
-EXPORT_SYMBOL(ms_sensors_ht_read_humidity);
+EXPORT_SYMBOL_NS(ms_sensors_ht_read_humidity, IIO_MEAS_SPEC_SENSORS);
 
 /**
  * ms_sensors_tp_crc4() - Calculate PROM CRC for
@@ -602,7 +602,7 @@ int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data)
 
        return 0;
 }
-EXPORT_SYMBOL(ms_sensors_tp_read_prom);
+EXPORT_SYMBOL_NS(ms_sensors_tp_read_prom, IIO_MEAS_SPEC_SENSORS);
 
 /**
  * ms_sensors_read_temp_and_pressure() - read temp and pressure
@@ -688,7 +688,7 @@ int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
 
        return 0;
 }
-EXPORT_SYMBOL(ms_sensors_read_temp_and_pressure);
+EXPORT_SYMBOL_NS(ms_sensors_read_temp_and_pressure, IIO_MEAS_SPEC_SENSORS);
 
 MODULE_DESCRIPTION("Measurement-Specialties common i2c driver");
 MODULE_AUTHOR("William Markezana <[email protected]>");
index 1aee87100038172b1cb973f874065c86c77b4417..a3783ea3117ab2e70c81af5d698a1d3efb3f6079 100644 (file)
@@ -7,9 +7,10 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/mfd/core.h>
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
+#include <linux/property.h>
+
 #include "ssp.h"
 
 #define SSP_WDT_TIME                   10000
@@ -204,7 +205,7 @@ u32 ssp_get_sensor_delay(struct ssp_data *data, enum ssp_sensor_type type)
 {
        return data->delay_buf[type];
 }
-EXPORT_SYMBOL(ssp_get_sensor_delay);
+EXPORT_SYMBOL_NS(ssp_get_sensor_delay, IIO_SSP_SENSORS);
 
 /**
  * ssp_enable_sensor() - enables data acquisition for sensor
@@ -266,7 +267,7 @@ int ssp_enable_sensor(struct ssp_data *data, enum ssp_sensor_type type,
 derror:
        return ret;
 }
-EXPORT_SYMBOL(ssp_enable_sensor);
+EXPORT_SYMBOL_NS(ssp_enable_sensor, IIO_SSP_SENSORS);
 
 /**
  * ssp_change_delay() - changes data acquisition for sensor
@@ -297,7 +298,7 @@ int ssp_change_delay(struct ssp_data *data, enum ssp_sensor_type type,
 
        return 0;
 }
-EXPORT_SYMBOL(ssp_change_delay);
+EXPORT_SYMBOL_NS(ssp_change_delay, IIO_SSP_SENSORS);
 
 /**
  * ssp_disable_sensor() - disables sensor
@@ -334,7 +335,7 @@ int ssp_disable_sensor(struct ssp_data *data, enum ssp_sensor_type type)
 
        return 0;
 }
-EXPORT_SYMBOL(ssp_disable_sensor);
+EXPORT_SYMBOL_NS(ssp_disable_sensor, IIO_SSP_SENSORS);
 
 static irqreturn_t ssp_irq_thread_fn(int irq, void *dev_id)
 {
@@ -425,7 +426,6 @@ int ssp_queue_ssp_refresh_task(struct ssp_data *data, unsigned int delay)
                                  msecs_to_jiffies(delay));
 }
 
-#ifdef CONFIG_OF
 static const struct of_device_id ssp_of_match[] = {
        {
                .compatible     = "samsung,sensorhub-rinato",
@@ -441,8 +441,6 @@ MODULE_DEVICE_TABLE(of, ssp_of_match);
 static struct ssp_data *ssp_parse_dt(struct device *dev)
 {
        struct ssp_data *data;
-       struct device_node *node = dev->of_node;
-       const struct of_device_id *match;
 
        data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
        if (!data)
@@ -461,22 +459,12 @@ static struct ssp_data *ssp_parse_dt(struct device *dev)
        if (IS_ERR(data->mcu_reset_gpiod))
                return NULL;
 
-       match = of_match_node(ssp_of_match, node);
-       if (!match)
-               return NULL;
-
-       data->sensorhub_info = match->data;
+       data->sensorhub_info = device_get_match_data(dev);
 
        dev_set_drvdata(dev, data);
 
        return data;
 }
-#else
-static struct ssp_data *ssp_parse_dt(struct device *pdev)
-{
-       return NULL;
-}
-#endif
 
 /**
  * ssp_register_consumer() - registers iio consumer in ssp framework
@@ -490,7 +478,7 @@ void ssp_register_consumer(struct iio_dev *indio_dev, enum ssp_sensor_type type)
 
        data->sensor_devs[type] = indio_dev;
 }
-EXPORT_SYMBOL(ssp_register_consumer);
+EXPORT_SYMBOL_NS(ssp_register_consumer, IIO_SSP_SENSORS);
 
 static int ssp_probe(struct spi_device *spi)
 {
@@ -612,7 +600,6 @@ static int ssp_remove(struct spi_device *spi)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int ssp_suspend(struct device *dev)
 {
        int ret;
@@ -661,18 +648,15 @@ static int ssp_resume(struct device *dev)
 
        return 0;
 }
-#endif /* CONFIG_PM_SLEEP */
 
-static const struct dev_pm_ops ssp_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(ssp_suspend, ssp_resume)
-};
+static DEFINE_SIMPLE_DEV_PM_OPS(ssp_pm_ops, ssp_suspend, ssp_resume);
 
 static struct spi_driver ssp_driver = {
        .probe = ssp_probe,
        .remove = ssp_remove,
        .driver = {
-               .pm = &ssp_pm_ops,
-               .of_match_table = of_match_ptr(ssp_of_match),
+               .pm = pm_sleep_ptr(&ssp_pm_ops),
+               .of_match_table = ssp_of_match,
                .name = "sensorhub"
        },
 };
index 5336db81ba0a5ec2b442c17aa3d94526150ec63d..88b8b56bfa51b654a5036b6a251d3963f75871c0 100644 (file)
@@ -32,7 +32,7 @@ int ssp_common_buffer_postenable(struct iio_dev *indio_dev)
        return ssp_enable_sensor(data, spd->type,
                                 ssp_get_sensor_delay(data, spd->type));
 }
-EXPORT_SYMBOL(ssp_common_buffer_postenable);
+EXPORT_SYMBOL_NS(ssp_common_buffer_postenable, IIO_SSP_SENSORS);
 
 /**
  * ssp_common_buffer_postdisable() - generic postdisable callback for ssp buffer
@@ -55,7 +55,7 @@ int ssp_common_buffer_postdisable(struct iio_dev *indio_dev)
 
        return ret;
 }
-EXPORT_SYMBOL(ssp_common_buffer_postdisable);
+EXPORT_SYMBOL_NS(ssp_common_buffer_postdisable, IIO_SSP_SENSORS);
 
 /**
  * ssp_common_process_data() - Common process data callback for ssp sensors
@@ -91,8 +91,9 @@ int ssp_common_process_data(struct iio_dev *indio_dev, void *buf,
        return iio_push_to_buffers_with_timestamp(indio_dev, spd->buffer,
                                                  calculated_time);
 }
-EXPORT_SYMBOL(ssp_common_process_data);
+EXPORT_SYMBOL_NS(ssp_common_process_data, IIO_SSP_SENSORS);
 
 MODULE_AUTHOR("Karol Wrona <[email protected]>");
 MODULE_DESCRIPTION("Samsung sensorhub commons");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_SSP_SENSORS);
index 9364ec7a811fd0769afc00327c38b90b69ed8f48..eda8f347fda50a817f4a79ee0cd05a5f5ef23db9 100644 (file)
@@ -13,5 +13,3 @@ config IIO_ST_SENSORS_SPI
 
 config IIO_ST_SENSORS_CORE
        tristate
-       select IIO_ST_SENSORS_I2C if I2C
-       select IIO_ST_SENSORS_SPI if SPI_MASTER
index dccc471e79da8ed596ce483eb266d71f8d8c91c0..e2f108ca949ccd8d1474c4155f31dcd2077f97a9 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/trigger.h>
 #include <linux/interrupt.h>
@@ -77,8 +76,4 @@ st_sensors_get_buffer_element_error:
 
        return IRQ_HANDLED;
 }
-EXPORT_SYMBOL(st_sensors_trigger_handler);
-
-MODULE_AUTHOR("Denis Ciocca <[email protected]>");
-MODULE_DESCRIPTION("STMicroelectronics ST-sensors buffer");
-MODULE_LICENSE("GPL v2");
+EXPORT_SYMBOL_NS(st_sensors_trigger_handler, IIO_ST_SENSORS);
index eb452d0c423c887f65dd0182a40048b47ae7de60..fa9bcdf0d19000b3b717a9fdbf750a0d755639fc 100644 (file)
@@ -46,7 +46,7 @@ int st_sensors_debugfs_reg_access(struct iio_dev *indio_dev,
 
        return 0;
 }
-EXPORT_SYMBOL(st_sensors_debugfs_reg_access);
+EXPORT_SYMBOL_NS(st_sensors_debugfs_reg_access, IIO_ST_SENSORS);
 
 static int st_sensors_match_odr(struct st_sensor_settings *sensor_settings,
                        unsigned int odr, struct st_sensor_odr_avl *odr_out)
@@ -106,7 +106,7 @@ int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr)
 st_sensors_match_odr_error:
        return err;
 }
-EXPORT_SYMBOL(st_sensors_set_odr);
+EXPORT_SYMBOL_NS(st_sensors_set_odr, IIO_ST_SENSORS);
 
 static int st_sensors_match_fs(struct st_sensor_settings *sensor_settings,
                                        unsigned int fs, int *index_fs_avl)
@@ -199,7 +199,7 @@ int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
 set_enable_error:
        return err;
 }
-EXPORT_SYMBOL(st_sensors_set_enable);
+EXPORT_SYMBOL_NS(st_sensors_set_enable, IIO_ST_SENSORS);
 
 int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
 {
@@ -213,7 +213,7 @@ int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
                                axis_enable);
        return err;
 }
-EXPORT_SYMBOL(st_sensors_set_axis_enable);
+EXPORT_SYMBOL_NS(st_sensors_set_axis_enable, IIO_ST_SENSORS);
 
 static void st_reg_disable(void *reg)
 {
@@ -257,7 +257,7 @@ int st_sensors_power_enable(struct iio_dev *indio_dev)
 
        return devm_add_action_or_reset(parent, st_reg_disable, pdata->vdd_io);
 }
-EXPORT_SYMBOL(st_sensors_power_enable);
+EXPORT_SYMBOL_NS(st_sensors_power_enable, IIO_ST_SENSORS);
 
 static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
                                        struct st_sensors_platform_data *pdata)
@@ -352,7 +352,7 @@ void st_sensors_dev_name_probe(struct device *dev, char *name, int len)
        /* The name from the match takes precedence if present */
        strlcpy(name, match, len);
 }
-EXPORT_SYMBOL(st_sensors_dev_name_probe);
+EXPORT_SYMBOL_NS(st_sensors_dev_name_probe, IIO_ST_SENSORS);
 
 int st_sensors_init_sensor(struct iio_dev *indio_dev,
                                        struct st_sensors_platform_data *pdata)
@@ -437,7 +437,7 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev,
 
        return err;
 }
-EXPORT_SYMBOL(st_sensors_init_sensor);
+EXPORT_SYMBOL_NS(st_sensors_init_sensor, IIO_ST_SENSORS);
 
 int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
 {
@@ -486,7 +486,7 @@ int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
 st_accel_set_dataready_irq_error:
        return err;
 }
-EXPORT_SYMBOL(st_sensors_set_dataready_irq);
+EXPORT_SYMBOL_NS(st_sensors_set_dataready_irq, IIO_ST_SENSORS);
 
 int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale)
 {
@@ -509,7 +509,7 @@ int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale)
 st_sensors_match_scale_error:
        return err;
 }
-EXPORT_SYMBOL(st_sensors_set_fullscale_by_gain);
+EXPORT_SYMBOL_NS(st_sensors_set_fullscale_by_gain, IIO_ST_SENSORS);
 
 static int st_sensors_read_axis_data(struct iio_dev *indio_dev,
                                     struct iio_chan_spec const *ch, int *data)
@@ -572,7 +572,7 @@ out:
 
        return err;
 }
-EXPORT_SYMBOL(st_sensors_read_info_raw);
+EXPORT_SYMBOL_NS(st_sensors_read_info_raw, IIO_ST_SENSORS);
 
 /*
  * st_sensors_get_settings_index() - get index of the sensor settings for a
@@ -599,7 +599,7 @@ int st_sensors_get_settings_index(const char *name,
 
        return -ENODEV;
 }
-EXPORT_SYMBOL(st_sensors_get_settings_index);
+EXPORT_SYMBOL_NS(st_sensors_get_settings_index, IIO_ST_SENSORS);
 
 /*
  * st_sensors_verify_id() - verify sensor ID (WhoAmI) is matching with the
@@ -632,7 +632,7 @@ int st_sensors_verify_id(struct iio_dev *indio_dev)
 
        return 0;
 }
-EXPORT_SYMBOL(st_sensors_verify_id);
+EXPORT_SYMBOL_NS(st_sensors_verify_id, IIO_ST_SENSORS);
 
 ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
                                struct device_attribute *attr, char *buf)
@@ -654,7 +654,7 @@ ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
 
        return len;
 }
-EXPORT_SYMBOL(st_sensors_sysfs_sampling_frequency_avail);
+EXPORT_SYMBOL_NS(st_sensors_sysfs_sampling_frequency_avail, IIO_ST_SENSORS);
 
 ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
                                struct device_attribute *attr, char *buf)
@@ -678,7 +678,7 @@ ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
 
        return len;
 }
-EXPORT_SYMBOL(st_sensors_sysfs_scale_avail);
+EXPORT_SYMBOL_NS(st_sensors_sysfs_scale_avail, IIO_ST_SENSORS);
 
 MODULE_AUTHOR("Denis Ciocca <[email protected]>");
 MODULE_DESCRIPTION("STMicroelectronics ST-sensors core");
index 18bd3c3d99bcd11c1971b3015bc79cc5eb118db3..ee95082c741062d6d7dfe9071ddab3e96d0b0fd5 100644 (file)
@@ -61,7 +61,7 @@ int st_sensors_i2c_configure(struct iio_dev *indio_dev,
 
        return 0;
 }
-EXPORT_SYMBOL(st_sensors_i2c_configure);
+EXPORT_SYMBOL_NS(st_sensors_i2c_configure, IIO_ST_SENSORS);
 
 MODULE_AUTHOR("Denis Ciocca <[email protected]>");
 MODULE_DESCRIPTION("STMicroelectronics ST-sensors i2c driver");
index 7c60050e90dc32e37de429f1de2898128395c6e9..63e302c3fbaa1bc229c3bbfa4c65411a087f71b0 100644 (file)
@@ -113,7 +113,7 @@ int st_sensors_spi_configure(struct iio_dev *indio_dev,
 
        return 0;
 }
-EXPORT_SYMBOL(st_sensors_spi_configure);
+EXPORT_SYMBOL_NS(st_sensors_spi_configure, IIO_ST_SENSORS);
 
 MODULE_AUTHOR("Denis Ciocca <[email protected]>");
 MODULE_DESCRIPTION("STMicroelectronics ST-sensors spi driver");
index 392d74449886ec49c891eacd770aa060cb23fe25..899b640c0a70c92066eb958792899b0ccd24d76a 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/trigger.h>
 #include <linux/interrupt.h>
@@ -228,7 +227,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
 
        return 0;
 }
-EXPORT_SYMBOL(st_sensors_allocate_trigger);
+EXPORT_SYMBOL_NS(st_sensors_allocate_trigger, IIO_ST_SENSORS);
 
 int st_sensors_validate_device(struct iio_trigger *trig,
                               struct iio_dev *indio_dev)
@@ -240,8 +239,4 @@ int st_sensors_validate_device(struct iio_trigger *trig,
 
        return 0;
 }
-EXPORT_SYMBOL(st_sensors_validate_device);
-
-MODULE_AUTHOR("Denis Ciocca <[email protected]>");
-MODULE_DESCRIPTION("STMicroelectronics ST-sensors trigger");
-MODULE_LICENSE("GPL v2");
+EXPORT_SYMBOL_NS(st_sensors_validate_device, IIO_ST_SENSORS);
index bfcf7568de329297ba9b98ce2bd9d1cf0851636c..c0bf0d84197f0dd5f0ad47dd82099bc55f022660 100644 (file)
@@ -131,6 +131,17 @@ config AD5624R_SPI
          Say yes here to build support for Analog Devices AD5624R, AD5644R and
          AD5664R converters (DAC). This driver uses the common SPI interface.
 
+config LTC2688
+       tristate "Analog Devices LTC2688 DAC spi driver"
+       depends on SPI
+       select REGMAP
+       help
+         Say yes here to build support for Analog Devices
+         LTC2688 converters (DAC).
+
+         To compile this driver as a module, choose M here: the
+         module will be called ltc2688.
+
 config AD5686
        tristate
 
index 01a50131572f8d2d11fd0f5630bd49533ea5a72f..ec3e42713f0008febc4e5084522af6e83b58afc3 100644 (file)
@@ -35,6 +35,7 @@ obj-$(CONFIG_DS4424) += ds4424.o
 obj-$(CONFIG_LPC18XX_DAC) += lpc18xx_dac.o
 obj-$(CONFIG_LTC1660) += ltc1660.o
 obj-$(CONFIG_LTC2632) += ltc2632.o
+obj-$(CONFIG_LTC2688) += ltc2688.o
 obj-$(CONFIG_M62332) += m62332.o
 obj-$(CONFIG_MAX517) += max517.o
 obj-$(CONFIG_MAX5821) += max5821.o
index 2fcc59728fd6b0a2da2d371b43076dea0275ef2e..a424b7220b61aacdc146f74f349e58c24fdb2090 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/iio/iio.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
-#include <linux/of.h>
 #include <linux/regulator/consumer.h>
 #include <linux/gpio/consumer.h>
 #include <linux/gpio/driver.h>
@@ -661,7 +660,7 @@ error_disable_reg:
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(ad5592r_probe);
+EXPORT_SYMBOL_NS_GPL(ad5592r_probe, IIO_AD5592R);
 
 void ad5592r_remove(struct device *dev)
 {
@@ -675,7 +674,7 @@ void ad5592r_remove(struct device *dev)
        if (st->reg)
                regulator_disable(st->reg);
 }
-EXPORT_SYMBOL_GPL(ad5592r_remove);
+EXPORT_SYMBOL_NS_GPL(ad5592r_remove, IIO_AD5592R);
 
 MODULE_AUTHOR("Paul Cercueil <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters");
index 6bfd7951e18caa45e9e6c2490a984a7c028dd582..1572279b04bb3d7e87bf282df969f8026be3801e 100644 (file)
@@ -170,3 +170,4 @@ module_spi_driver(ad5592r_spi_driver);
 MODULE_AUTHOR("Paul Cercueil <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_AD5592R);
index 64dd7a0bddf764d952a626f05eaa04d5dd0e5dfa..34e1319a971262645ed1153be497c6092b5f62b9 100644 (file)
@@ -137,3 +137,4 @@ module_i2c_driver(ad5593r_driver);
 MODULE_AUTHOR("Paul Cercueil <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices AD5593R multi-channel converters");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_AD5592R);
index 2628810fdbb1ffc9f8ff7e825b0a51d8b4da87b3..75b54c5ba39f74a49e522046ddd3f1a57738cb60 100644 (file)
@@ -137,3 +137,4 @@ module_spi_driver(ad5686_spi_driver);
 MODULE_AUTHOR("Stefan Popa <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices AD5686 and similar multi-channel DACs");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_AD5686);
index e592a995f404cbe61a22f25c61b03709d781845d..f78dd3f33199ee652a828e6504403f305b49db35 100644 (file)
@@ -536,7 +536,7 @@ error_disable_reg:
                regulator_disable(st->reg);
        return ret;
 }
-EXPORT_SYMBOL_GPL(ad5686_probe);
+EXPORT_SYMBOL_NS_GPL(ad5686_probe, IIO_AD5686);
 
 void ad5686_remove(struct device *dev)
 {
@@ -547,7 +547,7 @@ void ad5686_remove(struct device *dev)
        if (!IS_ERR(st->reg))
                regulator_disable(st->reg);
 }
-EXPORT_SYMBOL_GPL(ad5686_remove);
+EXPORT_SYMBOL_NS_GPL(ad5686_remove, IIO_AD5686);
 
 MODULE_AUTHOR("Michael Hennerich <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC");
index 93f0e0e66c22794fee790c1f1205591cef39b608..762503c1901bedd081f1d806e9a2787ee6570df6 100644 (file)
@@ -125,3 +125,4 @@ module_i2c_driver(ad5686_i2c_driver);
 MODULE_AUTHOR("Stefan Popa <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices AD5686 and similar multi-channel DACs");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_AD5686);
diff --git a/drivers/iio/dac/ltc2688.c b/drivers/iio/dac/ltc2688.c
new file mode 100644 (file)
index 0000000..e41861d
--- /dev/null
@@ -0,0 +1,1071 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * LTC2688 16 channel, 16 bit Voltage Output SoftSpan DAC driver
+ *
+ * Copyright 2022 Analog Devices Inc.
+ */
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/limits.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#define LTC2688_DAC_CHANNELS                   16
+
+#define LTC2688_CMD_CH_CODE(x)                 (0x00 + (x))
+#define LTC2688_CMD_CH_SETTING(x)              (0x10 + (x))
+#define LTC2688_CMD_CH_OFFSET(x)               (0X20 + (x))
+#define LTC2688_CMD_CH_GAIN(x)                 (0x30 + (x))
+#define LTC2688_CMD_CH_CODE_UPDATE(x)          (0x40 + (x))
+
+#define LTC2688_CMD_CONFIG                     0x70
+#define LTC2688_CMD_POWERDOWN                  0x71
+#define LTC2688_CMD_A_B_SELECT                 0x72
+#define LTC2688_CMD_SW_TOGGLE                  0x73
+#define LTC2688_CMD_TOGGLE_DITHER_EN           0x74
+#define LTC2688_CMD_THERMAL_STAT               0x77
+#define LTC2688_CMD_UPDATE_ALL                 0x7C
+#define LTC2688_CMD_NOOP                       0xFF
+
+#define LTC2688_READ_OPERATION                 0x80
+
+/* Channel Settings */
+#define LTC2688_CH_SPAN_MSK                    GENMASK(2, 0)
+#define LTC2688_CH_OVERRANGE_MSK               BIT(3)
+#define LTC2688_CH_TD_SEL_MSK                  GENMASK(5, 4)
+#define LTC2688_CH_TGP_MAX                     3
+#define LTC2688_CH_DIT_PER_MSK                 GENMASK(8, 6)
+#define LTC2688_CH_DIT_PH_MSK                  GENMASK(10, 9)
+#define LTC2688_CH_MODE_MSK                    BIT(11)
+
+#define LTC2688_DITHER_RAW_MASK                        GENMASK(15, 2)
+#define LTC2688_CH_CALIBBIAS_MASK              GENMASK(15, 2)
+#define LTC2688_DITHER_RAW_MAX_VAL             (BIT(14) - 1)
+#define LTC2688_CH_CALIBBIAS_MAX_VAL           (BIT(14) - 1)
+
+/* Configuration register */
+#define LTC2688_CONFIG_RST                     BIT(15)
+#define LTC2688_CONFIG_EXT_REF                 BIT(1)
+
+#define LTC2688_DITHER_FREQ_AVAIL_N            5
+
+enum {
+       LTC2688_SPAN_RANGE_0V_5V,
+       LTC2688_SPAN_RANGE_0V_10V,
+       LTC2688_SPAN_RANGE_M5V_5V,
+       LTC2688_SPAN_RANGE_M10V_10V,
+       LTC2688_SPAN_RANGE_M15V_15V,
+       LTC2688_SPAN_RANGE_MAX
+};
+
+enum {
+       LTC2688_MODE_DEFAULT,
+       LTC2688_MODE_DITHER_TOGGLE,
+};
+
+struct ltc2688_chan {
+       long dither_frequency[LTC2688_DITHER_FREQ_AVAIL_N];
+       bool overrange;
+       bool toggle_chan;
+       u8 mode;
+};
+
+struct ltc2688_state {
+       struct spi_device *spi;
+       struct regmap *regmap;
+       struct regulator_bulk_data regulators[2];
+       struct ltc2688_chan channels[LTC2688_DAC_CHANNELS];
+       struct iio_chan_spec *iio_chan;
+       /* lock to protect against multiple access to the device and shared data */
+       struct mutex lock;
+       int vref;
+       /*
+        * DMA (thus cache coherency maintenance) requires the
+        * transfer buffers to live in their own cache lines.
+        */
+       u8 tx_data[6] ____cacheline_aligned;
+       u8 rx_data[3];
+};
+
+static int ltc2688_spi_read(void *context, const void *reg, size_t reg_size,
+                           void *val, size_t val_size)
+{
+       struct ltc2688_state *st = context;
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx_data,
+                       .bits_per_word = 8,
+                       .len = reg_size + val_size,
+                       .cs_change = 1,
+               }, {
+                       .tx_buf = st->tx_data + 3,
+                       .rx_buf = st->rx_data,
+                       .bits_per_word = 8,
+                       .len = reg_size + val_size,
+               },
+       };
+       int ret;
+
+       memcpy(st->tx_data, reg, reg_size);
+
+       ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
+       if (ret)
+               return ret;
+
+       memcpy(val, &st->rx_data[1], val_size);
+
+       return 0;
+}
+
+static int ltc2688_spi_write(void *context, const void *data, size_t count)
+{
+       struct ltc2688_state *st = context;
+
+       return spi_write(st->spi, data, count);
+}
+
+static int ltc2688_span_get(const struct ltc2688_state *st, int c)
+{
+       int ret, reg, span;
+
+       ret = regmap_read(st->regmap, LTC2688_CMD_CH_SETTING(c), &reg);
+       if (ret)
+               return ret;
+
+       span = FIELD_GET(LTC2688_CH_SPAN_MSK, reg);
+       /* sanity check to make sure we don't get any weird value from the HW */
+       if (span >= LTC2688_SPAN_RANGE_MAX)
+               return -EIO;
+
+       return span;
+}
+
+static const int ltc2688_span_helper[LTC2688_SPAN_RANGE_MAX][2] = {
+       {0, 5000}, {0, 10000}, {-5000, 5000}, {-10000, 10000}, {-15000, 15000},
+};
+
+static int ltc2688_scale_get(const struct ltc2688_state *st, int c, int *val)
+{
+       const struct ltc2688_chan *chan = &st->channels[c];
+       int span, fs;
+
+       span = ltc2688_span_get(st, c);
+       if (span < 0)
+               return span;
+
+       fs = ltc2688_span_helper[span][1] - ltc2688_span_helper[span][0];
+       if (chan->overrange)
+               fs = mult_frac(fs, 105, 100);
+
+       *val = DIV_ROUND_CLOSEST(fs * st->vref, 4096);
+
+       return 0;
+}
+
+static int ltc2688_offset_get(const struct ltc2688_state *st, int c, int *val)
+{
+       int span;
+
+       span = ltc2688_span_get(st, c);
+       if (span < 0)
+               return span;
+
+       if (ltc2688_span_helper[span][0] < 0)
+               *val = -32768;
+       else
+               *val = 0;
+
+       return 0;
+}
+
+enum {
+       LTC2688_INPUT_A,
+       LTC2688_INPUT_B,
+       LTC2688_INPUT_B_AVAIL,
+       LTC2688_DITHER_OFF,
+       LTC2688_DITHER_FREQ_AVAIL,
+};
+
+static int ltc2688_dac_code_write(struct ltc2688_state *st, u32 chan, u32 input,
+                                 u16 code)
+{
+       struct ltc2688_chan *c = &st->channels[chan];
+       int ret, reg;
+
+       /* 2 LSBs set to 0 if writing dither amplitude */
+       if (!c->toggle_chan && input == LTC2688_INPUT_B) {
+               if (code > LTC2688_DITHER_RAW_MAX_VAL)
+                       return -EINVAL;
+
+               code = FIELD_PREP(LTC2688_DITHER_RAW_MASK, code);
+       }
+
+       mutex_lock(&st->lock);
+       /* select the correct input register to read from */
+       ret = regmap_update_bits(st->regmap, LTC2688_CMD_A_B_SELECT, BIT(chan),
+                                input << chan);
+       if (ret)
+               goto out_unlock;
+
+       /*
+        * If in dither/toggle mode the dac should be updated by an
+        * external signal (or sw toggle) and not here.
+        */
+       if (c->mode == LTC2688_MODE_DEFAULT)
+               reg = LTC2688_CMD_CH_CODE_UPDATE(chan);
+       else
+               reg = LTC2688_CMD_CH_CODE(chan);
+
+       ret = regmap_write(st->regmap, reg, code);
+out_unlock:
+       mutex_unlock(&st->lock);
+       return ret;
+}
+
+static int ltc2688_dac_code_read(struct ltc2688_state *st, u32 chan, u32 input,
+                                u32 *code)
+{
+       struct ltc2688_chan *c = &st->channels[chan];
+       int ret;
+
+       mutex_lock(&st->lock);
+       ret = regmap_update_bits(st->regmap, LTC2688_CMD_A_B_SELECT, BIT(chan),
+                                input << chan);
+       if (ret)
+               goto out_unlock;
+
+       ret = regmap_read(st->regmap, LTC2688_CMD_CH_CODE(chan), code);
+out_unlock:
+       mutex_unlock(&st->lock);
+
+       if (!c->toggle_chan && input == LTC2688_INPUT_B)
+               *code = FIELD_GET(LTC2688_DITHER_RAW_MASK, *code);
+
+       return ret;
+}
+
+static const int ltc2688_raw_range[] = {0, 1, U16_MAX};
+
+static int ltc2688_read_avail(struct iio_dev *indio_dev,
+                             struct iio_chan_spec const *chan,
+                             const int **vals, int *type, int *length,
+                             long info)
+{
+       switch (info) {
+       case IIO_CHAN_INFO_RAW:
+               *vals = ltc2688_raw_range;
+               *type = IIO_VAL_INT;
+               return IIO_AVAIL_RANGE;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ltc2688_read_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan, int *val,
+                           int *val2, long info)
+{
+       struct ltc2688_state *st = iio_priv(indio_dev);
+       int ret;
+
+       switch (info) {
+       case IIO_CHAN_INFO_RAW:
+               ret = ltc2688_dac_code_read(st, chan->channel, LTC2688_INPUT_A,
+                                           val);
+               if (ret)
+                       return ret;
+
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_OFFSET:
+               ret = ltc2688_offset_get(st, chan->channel, val);
+               if (ret)
+                       return ret;
+
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               ret = ltc2688_scale_get(st, chan->channel, val);
+               if (ret)
+                       return ret;
+
+               *val = 16;
+               return IIO_VAL_FRACTIONAL_LOG2;
+       case IIO_CHAN_INFO_CALIBBIAS:
+               ret = regmap_read(st->regmap,
+                                 LTC2688_CMD_CH_OFFSET(chan->channel), val);
+               if (ret)
+                       return ret;
+
+               *val = FIELD_GET(LTC2688_CH_CALIBBIAS_MASK, *val);
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_CALIBSCALE:
+               ret = regmap_read(st->regmap,
+                                 LTC2688_CMD_CH_GAIN(chan->channel), val);
+               if (ret)
+                       return ret;
+
+               return IIO_VAL_INT;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ltc2688_write_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan, int val,
+                            int val2, long info)
+{
+       struct ltc2688_state *st = iio_priv(indio_dev);
+
+       switch (info) {
+       case IIO_CHAN_INFO_RAW:
+               if (val > U16_MAX || val < 0)
+                       return -EINVAL;
+
+               return ltc2688_dac_code_write(st, chan->channel,
+                                             LTC2688_INPUT_A, val);
+       case IIO_CHAN_INFO_CALIBBIAS:
+               if (val > LTC2688_CH_CALIBBIAS_MAX_VAL)
+                       return -EINVAL;
+
+               return regmap_write(st->regmap,
+                                   LTC2688_CMD_CH_OFFSET(chan->channel),
+                                   FIELD_PREP(LTC2688_CH_CALIBBIAS_MASK, val));
+       case IIO_CHAN_INFO_CALIBSCALE:
+               return regmap_write(st->regmap,
+                                   LTC2688_CMD_CH_GAIN(chan->channel), val);
+       default:
+               return -EINVAL;
+       }
+}
+
+static ssize_t ltc2688_dither_toggle_set(struct iio_dev *indio_dev,
+                                        uintptr_t private,
+                                        const struct iio_chan_spec *chan,
+                                        const char *buf, size_t len)
+{
+       struct ltc2688_state *st = iio_priv(indio_dev);
+       struct ltc2688_chan *c = &st->channels[chan->channel];
+       int ret;
+       bool en;
+
+       ret = kstrtobool(buf, &en);
+       if (ret)
+               return ret;
+
+       mutex_lock(&st->lock);
+       ret = regmap_update_bits(st->regmap, LTC2688_CMD_TOGGLE_DITHER_EN,
+                                BIT(chan->channel), en << chan->channel);
+       if (ret)
+               goto out_unlock;
+
+       c->mode = en ? LTC2688_MODE_DITHER_TOGGLE : LTC2688_MODE_DEFAULT;
+out_unlock:
+       mutex_unlock(&st->lock);
+
+       return ret ?: len;
+}
+
+static ssize_t ltc2688_reg_bool_get(struct iio_dev *indio_dev,
+                                   uintptr_t private,
+                                   const struct iio_chan_spec *chan,
+                                   char *buf)
+{
+       const struct ltc2688_state *st = iio_priv(indio_dev);
+       int ret;
+       u32 val;
+
+       ret = regmap_read(st->regmap, private, &val);
+       if (ret)
+               return ret;
+
+       return sysfs_emit(buf, "%u\n", !!(val & BIT(chan->channel)));
+}
+
+static ssize_t ltc2688_reg_bool_set(struct iio_dev *indio_dev,
+                                   uintptr_t private,
+                                   const struct iio_chan_spec *chan,
+                                   const char *buf, size_t len)
+{
+       const struct ltc2688_state *st = iio_priv(indio_dev);
+       int ret;
+       bool en;
+
+       ret = kstrtobool(buf, &en);
+       if (ret)
+               return ret;
+
+       ret = regmap_update_bits(st->regmap, private, BIT(chan->channel),
+                                en << chan->channel);
+       if (ret)
+               return ret;
+
+       return len;
+}
+
+static ssize_t ltc2688_dither_freq_avail(const struct ltc2688_state *st,
+                                        const struct ltc2688_chan *chan,
+                                        char *buf)
+{
+       int sz = 0;
+       u32 f;
+
+       for (f = 0; f < ARRAY_SIZE(chan->dither_frequency); f++)
+               sz += sysfs_emit_at(buf, sz, "%ld ", chan->dither_frequency[f]);
+
+       buf[sz - 1] = '\n';
+
+       return sz;
+}
+
+static ssize_t ltc2688_dither_freq_get(struct iio_dev *indio_dev,
+                                      uintptr_t private,
+                                      const struct iio_chan_spec *chan,
+                                      char *buf)
+{
+       const struct ltc2688_state *st = iio_priv(indio_dev);
+       const struct ltc2688_chan *c = &st->channels[chan->channel];
+       u32 reg, freq;
+       int ret;
+
+       if (private == LTC2688_DITHER_FREQ_AVAIL)
+               return ltc2688_dither_freq_avail(st, c, buf);
+
+       ret = regmap_read(st->regmap, LTC2688_CMD_CH_SETTING(chan->channel),
+                         &reg);
+       if (ret)
+               return ret;
+
+       freq = FIELD_GET(LTC2688_CH_DIT_PER_MSK, reg);
+       if (freq >= ARRAY_SIZE(c->dither_frequency))
+               return -EIO;
+
+       return sysfs_emit(buf, "%ld\n", c->dither_frequency[freq]);
+}
+
+static ssize_t ltc2688_dither_freq_set(struct iio_dev *indio_dev,
+                                      uintptr_t private,
+                                      const struct iio_chan_spec *chan,
+                                      const char *buf, size_t len)
+{
+       const struct ltc2688_state *st = iio_priv(indio_dev);
+       const struct ltc2688_chan *c = &st->channels[chan->channel];
+       long val;
+       u32 freq;
+       int ret;
+
+       if (private == LTC2688_DITHER_FREQ_AVAIL)
+               return -EINVAL;
+
+       ret = kstrtol(buf, 10, &val);
+       if (ret)
+               return ret;
+
+       for (freq = 0; freq < ARRAY_SIZE(c->dither_frequency); freq++) {
+               if (val == c->dither_frequency[freq])
+                       break;
+       }
+
+       if (freq == ARRAY_SIZE(c->dither_frequency))
+               return -EINVAL;
+
+       ret = regmap_update_bits(st->regmap,
+                                LTC2688_CMD_CH_SETTING(chan->channel),
+                                LTC2688_CH_DIT_PER_MSK,
+                                FIELD_PREP(LTC2688_CH_DIT_PER_MSK, freq));
+       if (ret)
+               return ret;
+
+       return len;
+}
+
+static ssize_t ltc2688_dac_input_read(struct iio_dev *indio_dev,
+                                     uintptr_t private,
+                                     const struct iio_chan_spec *chan,
+                                     char *buf)
+{
+       struct ltc2688_state *st = iio_priv(indio_dev);
+       int ret;
+       u32 val;
+
+       if (private == LTC2688_INPUT_B_AVAIL)
+               return sysfs_emit(buf, "[%u %u %u]\n", ltc2688_raw_range[0],
+                                 ltc2688_raw_range[1],
+                                 ltc2688_raw_range[2] / 4);
+
+       if (private == LTC2688_DITHER_OFF)
+               return sysfs_emit(buf, "0\n");
+
+       ret = ltc2688_dac_code_read(st, chan->channel, private, &val);
+       if (ret)
+               return ret;
+
+       return sysfs_emit(buf, "%u\n", val);
+}
+
+static ssize_t ltc2688_dac_input_write(struct iio_dev *indio_dev,
+                                      uintptr_t private,
+                                      const struct iio_chan_spec *chan,
+                                      const char *buf, size_t len)
+{
+       struct ltc2688_state *st = iio_priv(indio_dev);
+       int ret;
+       u16 val;
+
+       if (private == LTC2688_INPUT_B_AVAIL || private == LTC2688_DITHER_OFF)
+               return -EINVAL;
+
+       ret = kstrtou16(buf, 10, &val);
+       if (ret)
+               return ret;
+
+       ret = ltc2688_dac_code_write(st, chan->channel, private, val);
+       if (ret)
+               return ret;
+
+       return len;
+}
+
+static int ltc2688_get_dither_phase(struct iio_dev *dev,
+                                   const struct iio_chan_spec *chan)
+{
+       struct ltc2688_state *st = iio_priv(dev);
+       int ret, regval;
+
+       ret = regmap_read(st->regmap, LTC2688_CMD_CH_SETTING(chan->channel),
+                         &regval);
+       if (ret)
+               return ret;
+
+       return FIELD_GET(LTC2688_CH_DIT_PH_MSK, regval);
+}
+
+static int ltc2688_set_dither_phase(struct iio_dev *dev,
+                                   const struct iio_chan_spec *chan,
+                                   unsigned int phase)
+{
+       struct ltc2688_state *st = iio_priv(dev);
+
+       return regmap_update_bits(st->regmap,
+                                 LTC2688_CMD_CH_SETTING(chan->channel),
+                                 LTC2688_CH_DIT_PH_MSK,
+                                 FIELD_PREP(LTC2688_CH_DIT_PH_MSK, phase));
+}
+
+static int ltc2688_reg_access(struct iio_dev *indio_dev,
+                             unsigned int reg,
+                             unsigned int writeval,
+                             unsigned int *readval)
+{
+       struct ltc2688_state *st = iio_priv(indio_dev);
+
+       if (readval)
+               return regmap_read(st->regmap, reg, readval);
+
+       return regmap_write(st->regmap, reg, writeval);
+}
+
+static const char * const ltc2688_dither_phase[] = {
+       "0", "1.5708", "3.14159", "4.71239",
+};
+
+static const struct iio_enum ltc2688_dither_phase_enum = {
+       .items = ltc2688_dither_phase,
+       .num_items = ARRAY_SIZE(ltc2688_dither_phase),
+       .set = ltc2688_set_dither_phase,
+       .get = ltc2688_get_dither_phase,
+};
+
+#define LTC2688_CHAN_EXT_INFO(_name, _what, _shared, _read, _write) {  \
+       .name = _name,                                                  \
+       .read = (_read),                                                \
+       .write = (_write),                                              \
+       .private = (_what),                                             \
+       .shared = (_shared),                                            \
+}
+
+/*
+ * For toggle mode we only expose the symbol attr (sw_toggle) in case a TGPx is
+ * not provided in dts.
+ */
+static const struct iio_chan_spec_ext_info ltc2688_toggle_sym_ext_info[] = {
+       LTC2688_CHAN_EXT_INFO("raw0", LTC2688_INPUT_A, IIO_SEPARATE,
+                             ltc2688_dac_input_read, ltc2688_dac_input_write),
+       LTC2688_CHAN_EXT_INFO("raw1", LTC2688_INPUT_B, IIO_SEPARATE,
+                             ltc2688_dac_input_read, ltc2688_dac_input_write),
+       LTC2688_CHAN_EXT_INFO("toggle_en", LTC2688_CMD_TOGGLE_DITHER_EN,
+                             IIO_SEPARATE, ltc2688_reg_bool_get,
+                             ltc2688_dither_toggle_set),
+       LTC2688_CHAN_EXT_INFO("powerdown", LTC2688_CMD_POWERDOWN, IIO_SEPARATE,
+                             ltc2688_reg_bool_get, ltc2688_reg_bool_set),
+       LTC2688_CHAN_EXT_INFO("symbol", LTC2688_CMD_SW_TOGGLE, IIO_SEPARATE,
+                             ltc2688_reg_bool_get, ltc2688_reg_bool_set),
+       {}
+};
+
+static const struct iio_chan_spec_ext_info ltc2688_toggle_ext_info[] = {
+       LTC2688_CHAN_EXT_INFO("raw0", LTC2688_INPUT_A, IIO_SEPARATE,
+                             ltc2688_dac_input_read, ltc2688_dac_input_write),
+       LTC2688_CHAN_EXT_INFO("raw1", LTC2688_INPUT_B, IIO_SEPARATE,
+                             ltc2688_dac_input_read, ltc2688_dac_input_write),
+       LTC2688_CHAN_EXT_INFO("toggle_en", LTC2688_CMD_TOGGLE_DITHER_EN,
+                             IIO_SEPARATE, ltc2688_reg_bool_get,
+                             ltc2688_dither_toggle_set),
+       LTC2688_CHAN_EXT_INFO("powerdown", LTC2688_CMD_POWERDOWN, IIO_SEPARATE,
+                             ltc2688_reg_bool_get, ltc2688_reg_bool_set),
+       {}
+};
+
+static struct iio_chan_spec_ext_info ltc2688_dither_ext_info[] = {
+       LTC2688_CHAN_EXT_INFO("dither_raw", LTC2688_INPUT_B, IIO_SEPARATE,
+                             ltc2688_dac_input_read, ltc2688_dac_input_write),
+       LTC2688_CHAN_EXT_INFO("dither_raw_available", LTC2688_INPUT_B_AVAIL,
+                             IIO_SEPARATE, ltc2688_dac_input_read,
+                             ltc2688_dac_input_write),
+       LTC2688_CHAN_EXT_INFO("dither_offset", LTC2688_DITHER_OFF, IIO_SEPARATE,
+                             ltc2688_dac_input_read, ltc2688_dac_input_write),
+       /*
+        * Not IIO_ENUM because the available freq needs to be computed at
+        * probe. We could still use it, but it didn't felt much right.
+        */
+       LTC2688_CHAN_EXT_INFO("dither_frequency", 0, IIO_SEPARATE,
+                             ltc2688_dither_freq_get, ltc2688_dither_freq_set),
+       LTC2688_CHAN_EXT_INFO("dither_frequency_available",
+                             LTC2688_DITHER_FREQ_AVAIL, IIO_SEPARATE,
+                             ltc2688_dither_freq_get, ltc2688_dither_freq_set),
+       IIO_ENUM("dither_phase", IIO_SEPARATE, &ltc2688_dither_phase_enum),
+       IIO_ENUM_AVAILABLE("dither_phase", IIO_SEPARATE,
+                          &ltc2688_dither_phase_enum),
+       LTC2688_CHAN_EXT_INFO("dither_en", LTC2688_CMD_TOGGLE_DITHER_EN,
+                             IIO_SEPARATE, ltc2688_reg_bool_get,
+                             ltc2688_dither_toggle_set),
+       LTC2688_CHAN_EXT_INFO("powerdown", LTC2688_CMD_POWERDOWN, IIO_SEPARATE,
+                             ltc2688_reg_bool_get, ltc2688_reg_bool_set),
+       {}
+};
+
+static const struct iio_chan_spec_ext_info ltc2688_ext_info[] = {
+       LTC2688_CHAN_EXT_INFO("powerdown", LTC2688_CMD_POWERDOWN, IIO_SEPARATE,
+                             ltc2688_reg_bool_get, ltc2688_reg_bool_set),
+       {}
+};
+
+#define LTC2688_CHANNEL(_chan) {                                       \
+       .type = IIO_VOLTAGE,                                            \
+       .indexed = 1,                                                   \
+       .output = 1,                                                    \
+       .channel = (_chan),                                             \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_CALIBSCALE) |           \
+               BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET) |  \
+               BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_RAW),  \
+       .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW),         \
+       .ext_info = ltc2688_ext_info,                                   \
+}
+
+static const struct iio_chan_spec ltc2688_channels[] = {
+       LTC2688_CHANNEL(0),
+       LTC2688_CHANNEL(1),
+       LTC2688_CHANNEL(2),
+       LTC2688_CHANNEL(3),
+       LTC2688_CHANNEL(4),
+       LTC2688_CHANNEL(5),
+       LTC2688_CHANNEL(6),
+       LTC2688_CHANNEL(7),
+       LTC2688_CHANNEL(8),
+       LTC2688_CHANNEL(9),
+       LTC2688_CHANNEL(10),
+       LTC2688_CHANNEL(11),
+       LTC2688_CHANNEL(12),
+       LTC2688_CHANNEL(13),
+       LTC2688_CHANNEL(14),
+       LTC2688_CHANNEL(15),
+};
+
+static void ltc2688_clk_disable(void *clk)
+{
+       clk_disable_unprepare(clk);
+}
+
+static const int ltc2688_period[LTC2688_DITHER_FREQ_AVAIL_N] = {
+       4, 8, 16, 32, 64,
+};
+
+static int ltc2688_tgp_clk_setup(struct ltc2688_state *st,
+                                struct ltc2688_chan *chan,
+                                struct fwnode_handle *node, int tgp)
+{
+       unsigned long rate;
+       struct clk *clk;
+       int ret, f;
+
+       clk = devm_get_clk_from_child(&st->spi->dev, to_of_node(node), NULL);
+       if (IS_ERR(clk))
+               return dev_err_probe(&st->spi->dev, PTR_ERR(clk),
+                                    "failed to get tgp clk.\n");
+
+       ret = clk_prepare_enable(clk);
+       if (ret)
+               return dev_err_probe(&st->spi->dev, ret,
+                                    "failed to enable tgp clk.\n");
+
+       ret = devm_add_action_or_reset(&st->spi->dev, ltc2688_clk_disable, clk);
+       if (ret)
+               return ret;
+
+       if (chan->toggle_chan)
+               return 0;
+
+       /* calculate available dither frequencies */
+       rate = clk_get_rate(clk);
+       for (f = 0; f < ARRAY_SIZE(chan->dither_frequency); f++)
+               chan->dither_frequency[f] = DIV_ROUND_CLOSEST(rate, ltc2688_period[f]);
+
+       return 0;
+}
+
+static int ltc2688_span_lookup(const struct ltc2688_state *st, int min, int max)
+{
+       u32 span;
+
+       for (span = 0; span < ARRAY_SIZE(ltc2688_span_helper); span++) {
+               if (min == ltc2688_span_helper[span][0] &&
+                   max == ltc2688_span_helper[span][1])
+                       return span;
+       }
+
+       return -EINVAL;
+}
+
+static int ltc2688_channel_config(struct ltc2688_state *st)
+{
+       struct device *dev = &st->spi->dev;
+       struct fwnode_handle *child;
+       u32 reg, clk_input, val, tmp[2];
+       int ret, span;
+
+       device_for_each_child_node(dev, child) {
+               struct ltc2688_chan *chan;
+
+               ret = fwnode_property_read_u32(child, "reg", &reg);
+               if (ret) {
+                       fwnode_handle_put(child);
+                       return dev_err_probe(dev, ret,
+                                            "Failed to get reg property\n");
+               }
+
+               if (reg >= LTC2688_DAC_CHANNELS) {
+                       fwnode_handle_put(child);
+                       return dev_err_probe(dev, -EINVAL,
+                                            "reg bigger than: %d\n",
+                                            LTC2688_DAC_CHANNELS);
+               }
+
+               val = 0;
+               chan = &st->channels[reg];
+               if (fwnode_property_read_bool(child, "adi,toggle-mode")) {
+                       chan->toggle_chan = true;
+                       /* assume sw toggle ABI */
+                       st->iio_chan[reg].ext_info = ltc2688_toggle_sym_ext_info;
+                       /*
+                        * Clear IIO_CHAN_INFO_RAW bit as toggle channels expose
+                        * out_voltage_raw{0|1} files.
+                        */
+                       __clear_bit(IIO_CHAN_INFO_RAW,
+                                   &st->iio_chan[reg].info_mask_separate);
+               }
+
+               ret = fwnode_property_read_u32_array(child, "adi,output-range-microvolt",
+                                                    tmp, ARRAY_SIZE(tmp));
+               if (!ret) {
+                       span = ltc2688_span_lookup(st, (int)tmp[0] / 1000,
+                                                  tmp[1] / 1000);
+                       if (span < 0) {
+                               fwnode_handle_put(child);
+                               return dev_err_probe(dev, -EINVAL,
+                                                    "output range not valid:[%d %d]\n",
+                                                    tmp[0], tmp[1]);
+                       }
+
+                       val |= FIELD_PREP(LTC2688_CH_SPAN_MSK, span);
+               }
+
+               ret = fwnode_property_read_u32(child, "adi,toggle-dither-input",
+                                              &clk_input);
+               if (!ret) {
+                       if (clk_input >= LTC2688_CH_TGP_MAX) {
+                               fwnode_handle_put(child);
+                               return dev_err_probe(dev, -EINVAL,
+                                                    "toggle-dither-input inv value(%d)\n",
+                                                    clk_input);
+                       }
+
+                       ret = ltc2688_tgp_clk_setup(st, chan, child, clk_input);
+                       if (ret) {
+                               fwnode_handle_put(child);
+                               return ret;
+                       }
+
+                       /*
+                        * 0 means software toggle which is the default mode.
+                        * Hence the +1.
+                        */
+                       val |= FIELD_PREP(LTC2688_CH_TD_SEL_MSK, clk_input + 1);
+
+                       /*
+                        * If a TGPx is given, we automatically assume a dither
+                        * capable channel (unless toggle is already enabled).
+                        * On top of this we just set here the dither bit in the
+                        * channel settings. It won't have any effect until the
+                        * global toggle/dither bit is enabled.
+                        */
+                       if (!chan->toggle_chan) {
+                               val |= FIELD_PREP(LTC2688_CH_MODE_MSK, 1);
+                               st->iio_chan[reg].ext_info = ltc2688_dither_ext_info;
+                       } else {
+                               /* wait, no sw toggle after all */
+                               st->iio_chan[reg].ext_info = ltc2688_toggle_ext_info;
+                       }
+               }
+
+               if (fwnode_property_read_bool(child, "adi,overrange")) {
+                       chan->overrange = true;
+                       val |= LTC2688_CH_OVERRANGE_MSK;
+               }
+
+               if (!val)
+                       continue;
+
+               ret = regmap_write(st->regmap, LTC2688_CMD_CH_SETTING(reg),
+                                  val);
+               if (ret) {
+                       fwnode_handle_put(child);
+                       return dev_err_probe(dev, -EINVAL,
+                                            "failed to set chan settings\n");
+               }
+       }
+
+       return 0;
+}
+
+static int ltc2688_setup(struct ltc2688_state *st, struct regulator *vref)
+{
+       struct gpio_desc *gpio;
+       int ret;
+
+       /*
+        * If we have a reset pin, use that to reset the board, If not, use
+        * the reset bit.
+        */
+       gpio = devm_gpiod_get_optional(&st->spi->dev, "clr", GPIOD_OUT_HIGH);
+       if (IS_ERR(gpio))
+               return dev_err_probe(&st->spi->dev, PTR_ERR(gpio),
+                                    "Failed to get reset gpio");
+       if (gpio) {
+               usleep_range(1000, 1200);
+               /* bring device out of reset */
+               gpiod_set_value_cansleep(gpio, 0);
+       } else {
+               ret = regmap_update_bits(st->regmap, LTC2688_CMD_CONFIG,
+                                        LTC2688_CONFIG_RST,
+                                        LTC2688_CONFIG_RST);
+               if (ret)
+                       return ret;
+       }
+
+       usleep_range(10000, 12000);
+
+       /*
+        * Duplicate the default channel configuration as it can change during
+        * @ltc2688_channel_config()
+        */
+       st->iio_chan = devm_kmemdup(&st->spi->dev, ltc2688_channels,
+                                   sizeof(ltc2688_channels), GFP_KERNEL);
+       if (!st->iio_chan)
+               return -ENOMEM;
+
+       ret = ltc2688_channel_config(st);
+       if (ret)
+               return ret;
+
+       if (!vref)
+               return 0;
+
+       return regmap_set_bits(st->regmap, LTC2688_CMD_CONFIG,
+                              LTC2688_CONFIG_EXT_REF);
+}
+
+static void ltc2688_disable_regulators(void *data)
+{
+       struct ltc2688_state *st = data;
+
+       regulator_bulk_disable(ARRAY_SIZE(st->regulators), st->regulators);
+}
+
+static void ltc2688_disable_regulator(void *regulator)
+{
+       regulator_disable(regulator);
+}
+
+static bool ltc2688_reg_readable(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case LTC2688_CMD_CH_CODE(0) ... LTC2688_CMD_CH_GAIN(15):
+               return true;
+       case LTC2688_CMD_CONFIG ... LTC2688_CMD_THERMAL_STAT:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool ltc2688_reg_writable(struct device *dev, unsigned int reg)
+{
+       /*
+        * There's a jump from 0x76 to 0x78 in the write codes and the thermal
+        * status code is 0x77 (which is read only) so that we need to check
+        * that special condition.
+        */
+       if (reg <= LTC2688_CMD_UPDATE_ALL && reg != LTC2688_CMD_THERMAL_STAT)
+               return true;
+
+       return false;
+}
+
+static struct regmap_bus ltc2688_regmap_bus = {
+       .read = ltc2688_spi_read,
+       .write = ltc2688_spi_write,
+       .read_flag_mask = LTC2688_READ_OPERATION,
+       .reg_format_endian_default = REGMAP_ENDIAN_BIG,
+       .val_format_endian_default = REGMAP_ENDIAN_BIG,
+};
+
+static const struct regmap_config ltc2688_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 16,
+       .readable_reg = ltc2688_reg_readable,
+       .writeable_reg = ltc2688_reg_writable,
+       /* ignoring the no op command */
+       .max_register = LTC2688_CMD_UPDATE_ALL,
+};
+
+static const struct iio_info ltc2688_info = {
+       .write_raw = ltc2688_write_raw,
+       .read_raw = ltc2688_read_raw,
+       .read_avail = ltc2688_read_avail,
+       .debugfs_reg_access = ltc2688_reg_access,
+};
+
+static int ltc2688_probe(struct spi_device *spi)
+{
+       struct ltc2688_state *st;
+       struct iio_dev *indio_dev;
+       struct regulator *vref_reg;
+       struct device *dev = &spi->dev;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       st = iio_priv(indio_dev);
+       st->spi = spi;
+
+       /* Just write this once. No need to do it in every regmap read. */
+       st->tx_data[3] = LTC2688_CMD_NOOP;
+       mutex_init(&st->lock);
+
+       st->regmap = devm_regmap_init(dev, &ltc2688_regmap_bus, st,
+                                     &ltc2688_regmap_config);
+       if (IS_ERR(st->regmap))
+               return dev_err_probe(dev, PTR_ERR(st->regmap),
+                                    "Failed to init regmap");
+
+       st->regulators[0].supply = "vcc";
+       st->regulators[1].supply = "iovcc";
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(st->regulators),
+                                     st->regulators);
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to get regulators\n");
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(st->regulators), st->regulators);
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to enable regulators\n");
+
+       ret = devm_add_action_or_reset(dev, ltc2688_disable_regulators, st);
+       if (ret)
+               return ret;
+
+       vref_reg = devm_regulator_get_optional(dev, "vref");
+       if (IS_ERR(vref_reg)) {
+               if (PTR_ERR(vref_reg) != -ENODEV)
+                       return dev_err_probe(dev, PTR_ERR(vref_reg),
+                                            "Failed to get vref regulator");
+
+               vref_reg = NULL;
+               /* internal reference */
+               st->vref = 4096;
+       } else {
+               ret = regulator_enable(vref_reg);
+               if (ret)
+                       return dev_err_probe(dev, ret,
+                                            "Failed to enable vref regulators\n");
+
+               ret = devm_add_action_or_reset(dev, ltc2688_disable_regulator,
+                                              vref_reg);
+               if (ret)
+                       return ret;
+
+               ret = regulator_get_voltage(vref_reg);
+               if (ret < 0)
+                       return dev_err_probe(dev, ret, "Failed to get vref\n");
+
+               st->vref = ret / 1000;
+       }
+
+       ret = ltc2688_setup(st, vref_reg);
+       if (ret)
+               return ret;
+
+       indio_dev->name = "ltc2688";
+       indio_dev->info = &ltc2688_info;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->channels = st->iio_chan;
+       indio_dev->num_channels = ARRAY_SIZE(ltc2688_channels);
+
+       return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id ltc2688_of_id[] = {
+       { .compatible = "adi,ltc2688" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, ltc2688_of_id);
+
+static const struct spi_device_id ltc2688_id[] = {
+       { "ltc2688" },
+       {}
+};
+MODULE_DEVICE_TABLE(spi, ltc2688_id);
+
+static struct spi_driver ltc2688_driver = {
+       .driver = {
+               .name = "ltc2688",
+               .of_match_table = ltc2688_of_id,
+       },
+       .probe = ltc2688_probe,
+       .id_table = ltc2688_id,
+};
+module_spi_driver(ltc2688_driver);
+
+MODULE_AUTHOR("Nuno Sá <[email protected]>");
+MODULE_DESCRIPTION("Analog Devices LTC2688 DAC");
+MODULE_LICENSE("GPL");
index 225b1a374dc130141dac6053add4f4945e21af8e..22b02f50fe411a722423e994b945f0e6f4c5e878 100644 (file)
@@ -25,9 +25,7 @@ struct m62332_data {
        struct regulator        *vcc;
        struct mutex            mutex;
        u8                      raw[M62332_CHANNELS];
-#ifdef CONFIG_PM_SLEEP
        u8                      save[M62332_CHANNELS];
-#endif
 };
 
 static int m62332_set_value(struct iio_dev *indio_dev, u8 val, int channel)
@@ -124,7 +122,6 @@ static int m62332_write_raw(struct iio_dev *indio_dev,
        return -EINVAL;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int m62332_suspend(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
@@ -156,11 +153,7 @@ static int m62332_resume(struct device *dev)
        return m62332_set_value(indio_dev, data->save[1], 1);
 }
 
-static SIMPLE_DEV_PM_OPS(m62332_pm_ops, m62332_suspend, m62332_resume);
-#define M62332_PM_OPS (&m62332_pm_ops)
-#else
-#define M62332_PM_OPS NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(m62332_pm_ops, m62332_suspend, m62332_resume);
 
 static const struct iio_info m62332_info = {
        .read_raw = m62332_read_raw,
@@ -246,7 +239,7 @@ MODULE_DEVICE_TABLE(i2c, m62332_id);
 static struct i2c_driver m62332_driver = {
        .driver = {
                .name   = "m62332",
-               .pm     = M62332_PM_OPS,
+               .pm     = pm_sleep_ptr(&m62332_pm_ops),
        },
        .probe          = m62332_probe,
        .remove         = m62332_remove,
index bd7a3b20e645b570417d747306f9d82973511202..83bf184e3adccb45a7eee3940660d1609604b598 100644 (file)
@@ -195,7 +195,7 @@ static int stm32_dac_remove(struct platform_device *pdev)
        return 0;
 }
 
-static int __maybe_unused stm32_dac_core_resume(struct device *dev)
+static int stm32_dac_core_resume(struct device *dev)
 {
        struct stm32_dac_common *common = dev_get_drvdata(dev);
        struct stm32_dac_priv *priv = to_stm32_dac_priv(common);
@@ -213,23 +213,23 @@ static int __maybe_unused stm32_dac_core_resume(struct device *dev)
        return pm_runtime_force_resume(dev);
 }
 
-static int __maybe_unused stm32_dac_core_runtime_suspend(struct device *dev)
+static int stm32_dac_core_runtime_suspend(struct device *dev)
 {
        stm32_dac_core_hw_stop(dev);
 
        return 0;
 }
 
-static int __maybe_unused stm32_dac_core_runtime_resume(struct device *dev)
+static int stm32_dac_core_runtime_resume(struct device *dev)
 {
        return stm32_dac_core_hw_start(dev);
 }
 
 static const struct dev_pm_ops stm32_dac_core_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, stm32_dac_core_resume)
-       SET_RUNTIME_PM_OPS(stm32_dac_core_runtime_suspend,
-                          stm32_dac_core_runtime_resume,
-                          NULL)
+       SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, stm32_dac_core_resume)
+       RUNTIME_PM_OPS(stm32_dac_core_runtime_suspend,
+                      stm32_dac_core_runtime_resume,
+                      NULL)
 };
 
 static const struct stm32_dac_cfg stm32h7_dac_cfg = {
@@ -253,7 +253,7 @@ static struct platform_driver stm32_dac_driver = {
        .driver = {
                .name = "stm32-dac-core",
                .of_match_table = stm32_dac_of_match,
-               .pm = &stm32_dac_core_pm_ops,
+               .pm = pm_ptr(&stm32_dac_core_pm_ops),
        },
 };
 module_platform_driver(stm32_dac_driver);
index cd71cc4553a73095e92f8dadfe835a75fcc5013b..b20192a071cb42318bd5b2b949b6b8c4f971b74c 100644 (file)
@@ -372,7 +372,7 @@ static int stm32_dac_remove(struct platform_device *pdev)
        return 0;
 }
 
-static int __maybe_unused stm32_dac_suspend(struct device *dev)
+static int stm32_dac_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
        int channel = indio_dev->channels[0].channel;
@@ -386,9 +386,8 @@ static int __maybe_unused stm32_dac_suspend(struct device *dev)
        return pm_runtime_force_suspend(dev);
 }
 
-static const struct dev_pm_ops stm32_dac_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(stm32_dac_suspend, pm_runtime_force_resume)
-};
+static DEFINE_SIMPLE_DEV_PM_OPS(stm32_dac_pm_ops, stm32_dac_suspend,
+                               pm_runtime_force_resume);
 
 static const struct of_device_id stm32_dac_of_match[] = {
        { .compatible = "st,stm32-dac", },
@@ -402,7 +401,7 @@ static struct platform_driver stm32_dac_driver = {
        .driver = {
                .name = "stm32-dac",
                .of_match_table = stm32_dac_of_match,
-               .pm = &stm32_dac_pm_ops,
+               .pm = pm_sleep_ptr(&stm32_dac_pm_ops),
        },
 };
 module_platform_driver(stm32_dac_driver);
index 636b4009f76341970f94de4babaee358643e963c..92429c0d26856a1f7c4960b72bfc47e5e5c212fc 100644 (file)
@@ -242,7 +242,6 @@ static int vf610_dac_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int vf610_dac_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
@@ -268,9 +267,9 @@ static int vf610_dac_resume(struct device *dev)
 
        return 0;
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(vf610_dac_pm_ops, vf610_dac_suspend, vf610_dac_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(vf610_dac_pm_ops, vf610_dac_suspend,
+                               vf610_dac_resume);
 
 static struct platform_driver vf610_dac_driver = {
        .probe          = vf610_dac_probe,
@@ -278,7 +277,7 @@ static struct platform_driver vf610_dac_driver = {
        .driver         = {
                .name   = "vf610-dac",
                .of_match_table = vf610_dac_match,
-               .pm     = &vf610_dac_pm_ops,
+               .pm     = pm_sleep_ptr(&vf610_dac_pm_ops),
        },
 };
 module_platform_driver(vf610_dac_driver);
index b44036f843af7db01bc3a349bf7e8b71562a9ed7..f3702f36436cb85b78cd121fb754d91079f55d1d 100644 (file)
@@ -60,6 +60,26 @@ config ADMV1013
          To compile this driver as a module, choose M here: the
          module will be called admv1013.
 
+config ADMV1014
+       tristate "Analog Devices ADMV1014 Microwave Downconverter"
+       depends on SPI && COMMON_CLK && 64BIT
+       help
+         Say yes here to build support for Analog Devices ADMV1014
+         24 GHz to 44 GHz, Wideband, Microwave Downconverter.
+
+         To compile this driver as a module, choose M here: the
+         module will be called admv1014.
+
+config ADMV4420
+       tristate "Analog Devices ADMV4420 K Band Downconverter"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices K Band
+         Downconverter with integrated Fractional-N PLL and VCO.
+
+         To compile this driver as a module, choose M here: the
+         module will be called admv4420.
+
 config ADRF6780
         tristate "Analog Devices ADRF6780 Microwave Upconverter"
         depends on SPI
index ae6899856c999ce058d1407e696d5f8e18bbb092..48add732f1d3699107f0f558c5778ee14f6588ab 100644 (file)
@@ -8,4 +8,6 @@ obj-$(CONFIG_AD9523) += ad9523.o
 obj-$(CONFIG_ADF4350) += adf4350.o
 obj-$(CONFIG_ADF4371) += adf4371.o
 obj-$(CONFIG_ADMV1013) += admv1013.o
+obj-$(CONFIG_ADMV1014) += admv1014.o
+obj-$(CONFIG_ADMV4420) += admv4420.o
 obj-$(CONFIG_ADRF6780) += adrf6780.o
index bdb0bc3b12dd2c00751aab86f89a99472b6ff099..a0f92c336fc4039e51bd80d0248e1e81ae5012d4 100644 (file)
@@ -551,7 +551,7 @@ static ssize_t ad9523_show(struct device *dev,
        mutex_lock(&st->lock);
        ret = ad9523_read(indio_dev, AD9523_READBACK_0);
        if (ret >= 0) {
-               ret = sprintf(buf, "%d\n", !!(ret & (1 <<
+               ret = sysfs_emit(buf, "%d\n", !!(ret & (1 <<
                        (u32)this_attr->address)));
        }
        mutex_unlock(&st->lock);
index 3d9eba716b69155f525070ff44d3c1b8a0c4f09d..9af20a51540dec1339a82c57c144bfb1af1f5a0a 100644 (file)
@@ -7,17 +7,18 @@
 
 #include <linux/device.h>
 #include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/property.h>
 #include <linux/slab.h>
 #include <linux/sysfs.h>
 #include <linux/spi/spi.h>
 #include <linux/regulator/consumer.h>
 #include <linux/err.h>
-#include <linux/module.h>
 #include <linux/gcd.h>
 #include <linux/gpio/consumer.h>
 #include <asm/div64.h>
 #include <linux/clk.h>
-#include <linux/of.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
@@ -381,10 +382,8 @@ static const struct iio_info adf4350_info = {
        .debugfs_reg_access = &adf4350_reg_access,
 };
 
-#ifdef CONFIG_OF
 static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev)
 {
-       struct device_node *np = dev->of_node;
        struct adf4350_platform_data *pdata;
        unsigned int tmp;
 
@@ -392,101 +391,83 @@ static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev)
        if (!pdata)
                return NULL;
 
-       snprintf(&pdata->name[0], SPI_NAME_SIZE - 1, "%pOFn", np);
+       snprintf(pdata->name, sizeof(pdata->name), "%pfw", dev_fwnode(dev));
 
        tmp = 10000;
-       of_property_read_u32(np, "adi,channel-spacing", &tmp);
+       device_property_read_u32(dev, "adi,channel-spacing", &tmp);
        pdata->channel_spacing = tmp;
 
        tmp = 0;
-       of_property_read_u32(np, "adi,power-up-frequency", &tmp);
+       device_property_read_u32(dev, "adi,power-up-frequency", &tmp);
        pdata->power_up_frequency = tmp;
 
        tmp = 0;
-       of_property_read_u32(np, "adi,reference-div-factor", &tmp);
+       device_property_read_u32(dev, "adi,reference-div-factor", &tmp);
        pdata->ref_div_factor = tmp;
 
-       pdata->ref_doubler_en = of_property_read_bool(np,
-                       "adi,reference-doubler-enable");
-       pdata->ref_div2_en = of_property_read_bool(np,
-                       "adi,reference-div2-enable");
+       pdata->ref_doubler_en = device_property_read_bool(dev, "adi,reference-doubler-enable");
+       pdata->ref_div2_en = device_property_read_bool(dev, "adi,reference-div2-enable");
 
        /* r2_user_settings */
-       pdata->r2_user_settings = of_property_read_bool(np,
-                       "adi,phase-detector-polarity-positive-enable") ?
-                       ADF4350_REG2_PD_POLARITY_POS : 0;
-       pdata->r2_user_settings |= of_property_read_bool(np,
-                       "adi,lock-detect-precision-6ns-enable") ?
-                       ADF4350_REG2_LDP_6ns : 0;
-       pdata->r2_user_settings |= of_property_read_bool(np,
-                       "adi,lock-detect-function-integer-n-enable") ?
-                       ADF4350_REG2_LDF_INT_N : 0;
+       pdata->r2_user_settings = 0;
+       if (device_property_read_bool(dev, "adi,phase-detector-polarity-positive-enable"))
+               pdata->r2_user_settings |= ADF4350_REG2_PD_POLARITY_POS;
+       if (device_property_read_bool(dev, "adi,lock-detect-precision-6ns-enable"))
+               pdata->r2_user_settings |= ADF4350_REG2_LDP_6ns;
+       if (device_property_read_bool(dev, "adi,lock-detect-function-integer-n-enable"))
+               pdata->r2_user_settings |= ADF4350_REG2_LDF_INT_N;
 
        tmp = 2500;
-       of_property_read_u32(np, "adi,charge-pump-current", &tmp);
+       device_property_read_u32(dev, "adi,charge-pump-current", &tmp);
        pdata->r2_user_settings |= ADF4350_REG2_CHARGE_PUMP_CURR_uA(tmp);
 
        tmp = 0;
-       of_property_read_u32(np, "adi,muxout-select", &tmp);
+       device_property_read_u32(dev, "adi,muxout-select", &tmp);
        pdata->r2_user_settings |= ADF4350_REG2_MUXOUT(tmp);
 
-       pdata->r2_user_settings |= of_property_read_bool(np,
-                       "adi,low-spur-mode-enable") ?
-                       ADF4350_REG2_NOISE_MODE(0x3) : 0;
+       if (device_property_read_bool(dev, "adi,low-spur-mode-enable"))
+               pdata->r2_user_settings |= ADF4350_REG2_NOISE_MODE(0x3);
 
        /* r3_user_settings */
 
-       pdata->r3_user_settings = of_property_read_bool(np,
-                       "adi,cycle-slip-reduction-enable") ?
-                       ADF4350_REG3_12BIT_CSR_EN : 0;
-       pdata->r3_user_settings |= of_property_read_bool(np,
-                       "adi,charge-cancellation-enable") ?
-                       ADF4351_REG3_CHARGE_CANCELLATION_EN : 0;
-
-       pdata->r3_user_settings |= of_property_read_bool(np,
-                       "adi,anti-backlash-3ns-enable") ?
-                       ADF4351_REG3_ANTI_BACKLASH_3ns_EN : 0;
-       pdata->r3_user_settings |= of_property_read_bool(np,
-                       "adi,band-select-clock-mode-high-enable") ?
-                       ADF4351_REG3_BAND_SEL_CLOCK_MODE_HIGH : 0;
+       pdata->r3_user_settings = 0;
+       if (device_property_read_bool(dev, "adi,cycle-slip-reduction-enable"))
+               pdata->r3_user_settings |= ADF4350_REG3_12BIT_CSR_EN;
+       if (device_property_read_bool(dev, "adi,charge-cancellation-enable"))
+               pdata->r3_user_settings |= ADF4351_REG3_CHARGE_CANCELLATION_EN;
+       if (device_property_read_bool(dev, "adi,anti-backlash-3ns-enable"))
+               pdata->r3_user_settings |= ADF4351_REG3_ANTI_BACKLASH_3ns_EN;
+       if (device_property_read_bool(dev, "adi,band-select-clock-mode-high-enable"))
+               pdata->r3_user_settings |= ADF4351_REG3_BAND_SEL_CLOCK_MODE_HIGH;
 
        tmp = 0;
-       of_property_read_u32(np, "adi,12bit-clk-divider", &tmp);
+       device_property_read_u32(dev, "adi,12bit-clk-divider", &tmp);
        pdata->r3_user_settings |= ADF4350_REG3_12BIT_CLKDIV(tmp);
 
        tmp = 0;
-       of_property_read_u32(np, "adi,clk-divider-mode", &tmp);
+       device_property_read_u32(dev, "adi,clk-divider-mode", &tmp);
        pdata->r3_user_settings |= ADF4350_REG3_12BIT_CLKDIV_MODE(tmp);
 
        /* r4_user_settings */
 
-       pdata->r4_user_settings = of_property_read_bool(np,
-                       "adi,aux-output-enable") ?
-                       ADF4350_REG4_AUX_OUTPUT_EN : 0;
-       pdata->r4_user_settings |= of_property_read_bool(np,
-                       "adi,aux-output-fundamental-enable") ?
-                       ADF4350_REG4_AUX_OUTPUT_FUND : 0;
-       pdata->r4_user_settings |= of_property_read_bool(np,
-                       "adi,mute-till-lock-enable") ?
-                       ADF4350_REG4_MUTE_TILL_LOCK_EN : 0;
+       pdata->r4_user_settings = 0;
+       if (device_property_read_bool(dev, "adi,aux-output-enable"))
+               pdata->r4_user_settings |= ADF4350_REG4_AUX_OUTPUT_EN;
+       if (device_property_read_bool(dev, "adi,aux-output-fundamental-enable"))
+               pdata->r4_user_settings |= ADF4350_REG4_AUX_OUTPUT_FUND;
+       if (device_property_read_bool(dev, "adi,mute-till-lock-enable"))
+               pdata->r4_user_settings |= ADF4350_REG4_MUTE_TILL_LOCK_EN;
 
        tmp = 0;
-       of_property_read_u32(np, "adi,output-power", &tmp);
+       device_property_read_u32(dev, "adi,output-power", &tmp);
        pdata->r4_user_settings |= ADF4350_REG4_OUTPUT_PWR(tmp);
 
        tmp = 0;
-       of_property_read_u32(np, "adi,aux-output-power", &tmp);
+       device_property_read_u32(dev, "adi,aux-output-power", &tmp);
        pdata->r4_user_settings |= ADF4350_REG4_AUX_OUTPUT_PWR(tmp);
 
        return pdata;
 }
-#else
-static
-struct adf4350_platform_data *adf4350_parse_dt(struct device *dev)
-{
-       return NULL;
-}
-#endif
 
 static int adf4350_probe(struct spi_device *spi)
 {
@@ -496,7 +477,7 @@ static int adf4350_probe(struct spi_device *spi)
        struct clk *clk = NULL;
        int ret;
 
-       if (spi->dev.of_node) {
+       if (dev_fwnode(&spi->dev)) {
                pdata = adf4350_parse_dt(&spi->dev);
                if (pdata == NULL)
                        return -EINVAL;
@@ -625,7 +606,7 @@ MODULE_DEVICE_TABLE(spi, adf4350_id);
 static struct spi_driver adf4350_driver = {
        .driver = {
                .name   = "adf4350",
-               .of_match_table = of_match_ptr(adf4350_of_match),
+               .of_match_table = adf4350_of_match,
        },
        .probe          = adf4350_probe,
        .remove         = adf4350_remove,
index 3f3c478e9baab3041b118b58b48790ae914c2aba..b0e1f6571afbaf84473a6ce4220b961f4dff9c31 100644 (file)
@@ -630,7 +630,7 @@ static int admv1013_probe(struct spi_device *spi)
 }
 
 static const struct spi_device_id admv1013_id[] = {
-       { "admv1013", 0},
+       { "admv1013", 0 },
        {}
 };
 MODULE_DEVICE_TABLE(spi, admv1013_id);
diff --git a/drivers/iio/frequency/admv1014.c b/drivers/iio/frequency/admv1014.c
new file mode 100644 (file)
index 0000000..a7994f8
--- /dev/null
@@ -0,0 +1,823 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ADMV1014 driver
+ *
+ * Copyright 2022 Analog Devices Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/device.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/notifier.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/units.h>
+
+#include <asm/unaligned.h>
+
+/* ADMV1014 Register Map */
+#define ADMV1014_REG_SPI_CONTROL               0x00
+#define ADMV1014_REG_ALARM                     0x01
+#define ADMV1014_REG_ALARM_MASKS               0x02
+#define ADMV1014_REG_ENABLE                    0x03
+#define ADMV1014_REG_QUAD                      0x04
+#define ADMV1014_REG_LO_AMP_PHASE_ADJUST1      0x05
+#define ADMV1014_REG_MIXER                     0x07
+#define ADMV1014_REG_IF_AMP                    0x08
+#define ADMV1014_REG_IF_AMP_BB_AMP             0x09
+#define ADMV1014_REG_BB_AMP_AGC                        0x0A
+#define ADMV1014_REG_VVA_TEMP_COMP             0x0B
+
+/* ADMV1014_REG_SPI_CONTROL Map */
+#define ADMV1014_PARITY_EN_MSK                 BIT(15)
+#define ADMV1014_SPI_SOFT_RESET_MSK            BIT(14)
+#define ADMV1014_CHIP_ID_MSK                   GENMASK(11, 4)
+#define ADMV1014_CHIP_ID                       0x9
+#define ADMV1014_REVISION_ID_MSK               GENMASK(3, 0)
+
+/* ADMV1014_REG_ALARM Map */
+#define ADMV1014_PARITY_ERROR_MSK              BIT(15)
+#define ADMV1014_TOO_FEW_ERRORS_MSK            BIT(14)
+#define ADMV1014_TOO_MANY_ERRORS_MSK           BIT(13)
+#define ADMV1014_ADDRESS_RANGE_ERROR_MSK       BIT(12)
+
+/* ADMV1014_REG_ENABLE Map */
+#define ADMV1014_IBIAS_PD_MSK                  BIT(14)
+#define ADMV1014_P1DB_COMPENSATION_MSK         GENMASK(13, 12)
+#define ADMV1014_IF_AMP_PD_MSK                 BIT(11)
+#define ADMV1014_QUAD_BG_PD_MSK                        BIT(9)
+#define ADMV1014_BB_AMP_PD_MSK                 BIT(8)
+#define ADMV1014_QUAD_IBIAS_PD_MSK             BIT(7)
+#define ADMV1014_DET_EN_MSK                    BIT(6)
+#define ADMV1014_BG_PD_MSK                     BIT(5)
+
+/* ADMV1014_REG_QUAD Map */
+#define ADMV1014_QUAD_SE_MODE_MSK              GENMASK(9, 6)
+#define ADMV1014_QUAD_FILTERS_MSK              GENMASK(3, 0)
+
+/* ADMV1014_REG_LO_AMP_PHASE_ADJUST1 Map */
+#define ADMV1014_LOAMP_PH_ADJ_I_FINE_MSK       GENMASK(15, 9)
+#define ADMV1014_LOAMP_PH_ADJ_Q_FINE_MSK       GENMASK(8, 2)
+
+/* ADMV1014_REG_MIXER Map */
+#define ADMV1014_MIXER_VGATE_MSK               GENMASK(15, 9)
+#define ADMV1014_DET_PROG_MSK                  GENMASK(6, 0)
+
+/* ADMV1014_REG_IF_AMP Map */
+#define ADMV1014_IF_AMP_COARSE_GAIN_I_MSK      GENMASK(11, 8)
+#define ADMV1014_IF_AMP_FINE_GAIN_Q_MSK                GENMASK(7, 4)
+#define ADMV1014_IF_AMP_FINE_GAIN_I_MSK                GENMASK(3, 0)
+
+/* ADMV1014_REG_IF_AMP_BB_AMP Map */
+#define ADMV1014_IF_AMP_COARSE_GAIN_Q_MSK      GENMASK(15, 12)
+#define ADMV1014_BB_AMP_OFFSET_Q_MSK           GENMASK(9, 5)
+#define ADMV1014_BB_AMP_OFFSET_I_MSK           GENMASK(4, 0)
+
+/* ADMV1014_REG_BB_AMP_AGC Map */
+#define ADMV1014_BB_AMP_REF_GEN_MSK            GENMASK(6, 3)
+#define ADMV1014_BB_AMP_GAIN_CTRL_MSK          GENMASK(2, 1)
+#define ADMV1014_BB_SWITCH_HIGH_LOW_CM_MSK     BIT(0)
+
+/* ADMV1014_REG_VVA_TEMP_COMP Map */
+#define ADMV1014_VVA_TEMP_COMP_MSK             GENMASK(15, 0)
+
+/* ADMV1014 Miscellaneous Defines */
+#define ADMV1014_READ                          BIT(7)
+#define ADMV1014_REG_ADDR_READ_MSK             GENMASK(6, 1)
+#define ADMV1014_REG_ADDR_WRITE_MSK            GENMASK(22, 17)
+#define ADMV1014_REG_DATA_MSK                  GENMASK(16, 1)
+#define ADMV1014_NUM_REGULATORS                        9
+
+enum {
+       ADMV1014_IQ_MODE,
+       ADMV1014_IF_MODE,
+};
+
+enum {
+       ADMV1014_SE_MODE_POS = 6,
+       ADMV1014_SE_MODE_NEG = 9,
+       ADMV1014_SE_MODE_DIFF = 12,
+};
+
+enum {
+       ADMV1014_CALIBSCALE_COARSE,
+       ADMV1014_CALIBSCALE_FINE,
+};
+
+static const int detector_table[] = {0, 1, 2, 4, 8, 16, 32, 64};
+
+static const char * const input_mode_names[] = { "iq", "if" };
+
+static const char * const quad_se_mode_names[] = { "se-pos", "se-neg", "diff" };
+
+struct admv1014_state {
+       struct spi_device               *spi;
+       struct clk                      *clkin;
+       struct notifier_block           nb;
+       /* Protect against concurrent accesses to the device and to data*/
+       struct mutex                    lock;
+       struct regulator_bulk_data      regulators[ADMV1014_NUM_REGULATORS];
+       unsigned int                    input_mode;
+       unsigned int                    quad_se_mode;
+       unsigned int                    p1db_comp;
+       bool                            det_en;
+       u8                              data[3] ____cacheline_aligned;
+};
+
+static const int mixer_vgate_table[] = {106, 107, 108, 110, 111, 112, 113, 114,
+                                       117, 118, 119, 120, 122, 123, 44, 45};
+
+static int __admv1014_spi_read(struct admv1014_state *st, unsigned int reg,
+                              unsigned int *val)
+{
+       struct spi_transfer t = {};
+       int ret;
+
+       st->data[0] = ADMV1014_READ | FIELD_PREP(ADMV1014_REG_ADDR_READ_MSK, reg);
+       st->data[1] = 0;
+       st->data[2] = 0;
+
+       t.rx_buf = &st->data[0];
+       t.tx_buf = &st->data[0];
+       t.len = sizeof(st->data);
+
+       ret = spi_sync_transfer(st->spi, &t, 1);
+       if (ret)
+               return ret;
+
+       *val = FIELD_GET(ADMV1014_REG_DATA_MSK, get_unaligned_be24(&st->data[0]));
+
+       return ret;
+}
+
+static int admv1014_spi_read(struct admv1014_state *st, unsigned int reg,
+                            unsigned int *val)
+{
+       int ret;
+
+       mutex_lock(&st->lock);
+       ret = __admv1014_spi_read(st, reg, val);
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static int __admv1014_spi_write(struct admv1014_state *st,
+                               unsigned int reg,
+                               unsigned int val)
+{
+       put_unaligned_be24(FIELD_PREP(ADMV1014_REG_DATA_MSK, val) |
+                          FIELD_PREP(ADMV1014_REG_ADDR_WRITE_MSK, reg), &st->data[0]);
+
+       return spi_write(st->spi, &st->data[0], 3);
+}
+
+static int admv1014_spi_write(struct admv1014_state *st, unsigned int reg,
+                             unsigned int val)
+{
+       int ret;
+
+       mutex_lock(&st->lock);
+       ret = __admv1014_spi_write(st, reg, val);
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static int __admv1014_spi_update_bits(struct admv1014_state *st, unsigned int reg,
+                                     unsigned int mask, unsigned int val)
+{
+       unsigned int data, temp;
+       int ret;
+
+       ret = __admv1014_spi_read(st, reg, &data);
+       if (ret)
+               return ret;
+
+       temp = (data & ~mask) | (val & mask);
+
+       return __admv1014_spi_write(st, reg, temp);
+}
+
+static int admv1014_spi_update_bits(struct admv1014_state *st, unsigned int reg,
+                                   unsigned int mask, unsigned int val)
+{
+       int ret;
+
+       mutex_lock(&st->lock);
+       ret = __admv1014_spi_update_bits(st, reg, mask, val);
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static int admv1014_update_quad_filters(struct admv1014_state *st)
+{
+       unsigned int filt_raw;
+       u64 rate = clk_get_rate(st->clkin);
+
+       if (rate >= (5400 * HZ_PER_MHZ) && rate <= (7000 * HZ_PER_MHZ))
+               filt_raw = 15;
+       else if (rate > (7000 * HZ_PER_MHZ) && rate <= (8000 * HZ_PER_MHZ))
+               filt_raw = 10;
+       else if (rate > (8000 * HZ_PER_MHZ) && rate <= (9200 * HZ_PER_MHZ))
+               filt_raw = 5;
+       else
+               filt_raw = 0;
+
+       return __admv1014_spi_update_bits(st, ADMV1014_REG_QUAD,
+                                       ADMV1014_QUAD_FILTERS_MSK,
+                                       FIELD_PREP(ADMV1014_QUAD_FILTERS_MSK, filt_raw));
+}
+
+static int admv1014_update_vcm_settings(struct admv1014_state *st)
+{
+       unsigned int i, vcm_mv, vcm_comp, bb_sw_hl_cm;
+       int ret;
+
+       vcm_mv = regulator_get_voltage(st->regulators[0].consumer) / 1000;
+       for (i = 0; i < ARRAY_SIZE(mixer_vgate_table); i++) {
+               vcm_comp = 1050 + mult_frac(i, 450, 8);
+               if (vcm_mv != vcm_comp)
+                       continue;
+
+               ret = __admv1014_spi_update_bits(st, ADMV1014_REG_MIXER,
+                                                ADMV1014_MIXER_VGATE_MSK,
+                                                FIELD_PREP(ADMV1014_MIXER_VGATE_MSK,
+                                                           mixer_vgate_table[i]));
+               if (ret)
+                       return ret;
+
+               bb_sw_hl_cm = ~(i / 8);
+               bb_sw_hl_cm = FIELD_PREP(ADMV1014_BB_SWITCH_HIGH_LOW_CM_MSK, bb_sw_hl_cm);
+
+               return __admv1014_spi_update_bits(st, ADMV1014_REG_BB_AMP_AGC,
+                                                 ADMV1014_BB_AMP_REF_GEN_MSK |
+                                                 ADMV1014_BB_SWITCH_HIGH_LOW_CM_MSK,
+                                                 FIELD_PREP(ADMV1014_BB_AMP_REF_GEN_MSK, i) |
+                                                 bb_sw_hl_cm);
+       }
+
+       return -EINVAL;
+}
+
+static int admv1014_read_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            int *val, int *val2, long info)
+{
+       struct admv1014_state *st = iio_priv(indio_dev);
+       unsigned int data;
+       int ret;
+
+       switch (info) {
+       case IIO_CHAN_INFO_OFFSET:
+               ret = admv1014_spi_read(st, ADMV1014_REG_IF_AMP_BB_AMP, &data);
+               if (ret)
+                       return ret;
+
+               if (chan->channel2 == IIO_MOD_I)
+                       *val = FIELD_GET(ADMV1014_BB_AMP_OFFSET_I_MSK, data);
+               else
+                       *val = FIELD_GET(ADMV1014_BB_AMP_OFFSET_Q_MSK, data);
+
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_PHASE:
+               ret = admv1014_spi_read(st, ADMV1014_REG_LO_AMP_PHASE_ADJUST1, &data);
+               if (ret)
+                       return ret;
+
+               if (chan->channel2 == IIO_MOD_I)
+                       *val = FIELD_GET(ADMV1014_LOAMP_PH_ADJ_I_FINE_MSK, data);
+               else
+                       *val = FIELD_GET(ADMV1014_LOAMP_PH_ADJ_Q_FINE_MSK, data);
+
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               ret = admv1014_spi_read(st, ADMV1014_REG_MIXER, &data);
+               if (ret)
+                       return ret;
+
+               *val = FIELD_GET(ADMV1014_DET_PROG_MSK, data);
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_CALIBSCALE:
+               ret = admv1014_spi_read(st, ADMV1014_REG_BB_AMP_AGC, &data);
+               if (ret)
+                       return ret;
+
+               *val = FIELD_GET(ADMV1014_BB_AMP_GAIN_CTRL_MSK, data);
+               return IIO_VAL_INT;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int admv1014_write_raw(struct iio_dev *indio_dev,
+                             struct iio_chan_spec const *chan,
+                             int val, int val2, long info)
+{
+       int data;
+       unsigned int msk;
+       struct admv1014_state *st = iio_priv(indio_dev);
+
+       switch (info) {
+       case IIO_CHAN_INFO_OFFSET:
+               if (chan->channel2 == IIO_MOD_I) {
+                       msk = ADMV1014_BB_AMP_OFFSET_I_MSK;
+                       data = FIELD_PREP(ADMV1014_BB_AMP_OFFSET_I_MSK, val);
+               } else {
+                       msk = ADMV1014_BB_AMP_OFFSET_Q_MSK;
+                       data = FIELD_PREP(ADMV1014_BB_AMP_OFFSET_Q_MSK, val);
+               }
+
+               return admv1014_spi_update_bits(st, ADMV1014_REG_IF_AMP_BB_AMP, msk, data);
+       case IIO_CHAN_INFO_PHASE:
+               if (chan->channel2 == IIO_MOD_I) {
+                       msk = ADMV1014_LOAMP_PH_ADJ_I_FINE_MSK;
+                       data = FIELD_PREP(ADMV1014_LOAMP_PH_ADJ_I_FINE_MSK, val);
+               } else {
+                       msk = ADMV1014_LOAMP_PH_ADJ_Q_FINE_MSK;
+                       data = FIELD_PREP(ADMV1014_LOAMP_PH_ADJ_Q_FINE_MSK, val);
+               }
+
+               return admv1014_spi_update_bits(st, ADMV1014_REG_LO_AMP_PHASE_ADJUST1, msk, data);
+       case IIO_CHAN_INFO_SCALE:
+               return admv1014_spi_update_bits(st, ADMV1014_REG_MIXER,
+                                               ADMV1014_DET_PROG_MSK,
+                                               FIELD_PREP(ADMV1014_DET_PROG_MSK, val));
+       case IIO_CHAN_INFO_CALIBSCALE:
+               return admv1014_spi_update_bits(st, ADMV1014_REG_BB_AMP_AGC,
+                                               ADMV1014_BB_AMP_GAIN_CTRL_MSK,
+                                               FIELD_PREP(ADMV1014_BB_AMP_GAIN_CTRL_MSK, val));
+       default:
+               return -EINVAL;
+       }
+}
+
+static ssize_t admv1014_read(struct iio_dev *indio_dev,
+                            uintptr_t private,
+                            const struct iio_chan_spec *chan,
+                            char *buf)
+{
+       struct admv1014_state *st = iio_priv(indio_dev);
+       unsigned int data;
+       int ret;
+
+       switch (private) {
+       case ADMV1014_CALIBSCALE_COARSE:
+               if (chan->channel2 == IIO_MOD_I) {
+                       ret = admv1014_spi_read(st, ADMV1014_REG_IF_AMP, &data);
+                       if (ret)
+                               return ret;
+
+                       data = FIELD_GET(ADMV1014_IF_AMP_COARSE_GAIN_I_MSK, data);
+               } else {
+                       ret = admv1014_spi_read(st, ADMV1014_REG_IF_AMP_BB_AMP, &data);
+                       if (ret)
+                               return ret;
+
+                       data = FIELD_GET(ADMV1014_IF_AMP_COARSE_GAIN_Q_MSK, data);
+               }
+               break;
+       case ADMV1014_CALIBSCALE_FINE:
+               ret = admv1014_spi_read(st, ADMV1014_REG_IF_AMP, &data);
+               if (ret)
+                       return ret;
+
+               if (chan->channel2 == IIO_MOD_I)
+                       data = FIELD_GET(ADMV1014_IF_AMP_FINE_GAIN_I_MSK, data);
+               else
+                       data = FIELD_GET(ADMV1014_IF_AMP_FINE_GAIN_Q_MSK, data);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return sysfs_emit(buf, "%u\n", data);
+}
+
+static ssize_t admv1014_write(struct iio_dev *indio_dev,
+                             uintptr_t private,
+                             const struct iio_chan_spec *chan,
+                             const char *buf, size_t len)
+{
+       struct admv1014_state *st = iio_priv(indio_dev);
+       unsigned int data, addr, msk;
+       int ret;
+
+       ret = kstrtouint(buf, 10, &data);
+       if (ret)
+               return ret;
+
+       switch (private) {
+       case ADMV1014_CALIBSCALE_COARSE:
+               if (chan->channel2 == IIO_MOD_I) {
+                       addr = ADMV1014_REG_IF_AMP;
+                       msk = ADMV1014_IF_AMP_COARSE_GAIN_I_MSK;
+                       data = FIELD_PREP(ADMV1014_IF_AMP_COARSE_GAIN_I_MSK, data);
+               } else {
+                       addr = ADMV1014_REG_IF_AMP_BB_AMP;
+                       msk = ADMV1014_IF_AMP_COARSE_GAIN_Q_MSK;
+                       data = FIELD_PREP(ADMV1014_IF_AMP_COARSE_GAIN_Q_MSK, data);
+               }
+               break;
+       case ADMV1014_CALIBSCALE_FINE:
+               addr = ADMV1014_REG_IF_AMP;
+
+               if (chan->channel2 == IIO_MOD_I) {
+                       msk = ADMV1014_IF_AMP_FINE_GAIN_I_MSK;
+                       data = FIELD_PREP(ADMV1014_IF_AMP_FINE_GAIN_I_MSK, data);
+               } else {
+                       msk = ADMV1014_IF_AMP_FINE_GAIN_Q_MSK;
+                       data = FIELD_PREP(ADMV1014_IF_AMP_FINE_GAIN_Q_MSK, data);
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = admv1014_spi_update_bits(st, addr, msk, data);
+
+       return ret ? ret : len;
+}
+
+static int admv1014_read_avail(struct iio_dev *indio_dev,
+                              struct iio_chan_spec const *chan,
+                              const int **vals, int *type, int *length,
+                              long info)
+{
+       switch (info) {
+       case IIO_CHAN_INFO_SCALE:
+               *vals = detector_table;
+               *type = IIO_VAL_INT;
+               *length = ARRAY_SIZE(detector_table);
+
+               return IIO_AVAIL_LIST;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int admv1014_reg_access(struct iio_dev *indio_dev,
+                              unsigned int reg,
+                              unsigned int write_val,
+                              unsigned int *read_val)
+{
+       struct admv1014_state *st = iio_priv(indio_dev);
+
+       if (read_val)
+               return admv1014_spi_read(st, reg, read_val);
+       else
+               return admv1014_spi_write(st, reg, write_val);
+}
+
+static const struct iio_info admv1014_info = {
+       .read_raw = admv1014_read_raw,
+       .write_raw = admv1014_write_raw,
+       .read_avail = &admv1014_read_avail,
+       .debugfs_reg_access = &admv1014_reg_access,
+};
+
+static const char * const admv1014_reg_name[] = {
+        "vcm", "vcc-if-bb", "vcc-vga", "vcc-vva", "vcc-lna-3p3",
+        "vcc-lna-1p5", "vcc-bg", "vcc-quad", "vcc-mixer"
+};
+
+static int admv1014_freq_change(struct notifier_block *nb, unsigned long action, void *data)
+{
+       struct admv1014_state *st = container_of(nb, struct admv1014_state, nb);
+       int ret;
+
+       if (action == POST_RATE_CHANGE) {
+               mutex_lock(&st->lock);
+               ret = notifier_from_errno(admv1014_update_quad_filters(st));
+               mutex_unlock(&st->lock);
+               return ret;
+       }
+
+       return NOTIFY_OK;
+}
+
+#define _ADMV1014_EXT_INFO(_name, _shared, _ident) { \
+               .name = _name, \
+               .read = admv1014_read, \
+               .write = admv1014_write, \
+               .private = _ident, \
+               .shared = _shared, \
+}
+
+static const struct iio_chan_spec_ext_info admv1014_ext_info[] = {
+       _ADMV1014_EXT_INFO("calibscale_coarse", IIO_SEPARATE, ADMV1014_CALIBSCALE_COARSE),
+       _ADMV1014_EXT_INFO("calibscale_fine", IIO_SEPARATE, ADMV1014_CALIBSCALE_FINE),
+       { }
+};
+
+#define ADMV1014_CHAN_IQ(_channel, rf_comp) {                          \
+       .type = IIO_ALTVOLTAGE,                                         \
+       .modified = 1,                                                  \
+       .output = 0,                                                    \
+       .indexed = 1,                                                   \
+       .channel2 = IIO_MOD_##rf_comp,                                  \
+       .channel = _channel,                                            \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_PHASE) |                \
+               BIT(IIO_CHAN_INFO_OFFSET),                              \
+       .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBSCALE),      \
+       }
+
+#define ADMV1014_CHAN_IF(_channel, rf_comp) {                          \
+       .type = IIO_ALTVOLTAGE,                                         \
+       .modified = 1,                                                  \
+       .output = 0,                                                    \
+       .indexed = 1,                                                   \
+       .channel2 = IIO_MOD_##rf_comp,                                  \
+       .channel = _channel,                                            \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_PHASE) |                \
+               BIT(IIO_CHAN_INFO_OFFSET),                              \
+       }
+
+#define ADMV1014_CHAN_POWER(_channel) {                                        \
+       .type = IIO_POWER,                                              \
+       .output = 0,                                                    \
+       .indexed = 1,                                                   \
+       .channel = _channel,                                            \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_SCALE),                 \
+       .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \
+       }
+
+#define ADMV1014_CHAN_CALIBSCALE(_channel, rf_comp, _admv1014_ext_info) {      \
+       .type = IIO_ALTVOLTAGE,                                                 \
+       .modified = 1,                                                          \
+       .output = 0,                                                            \
+       .indexed = 1,                                                           \
+       .channel2 = IIO_MOD_##rf_comp,                                          \
+       .channel = _channel,                                                    \
+       .ext_info = _admv1014_ext_info,                                         \
+       }
+
+static const struct iio_chan_spec admv1014_channels_iq[] = {
+       ADMV1014_CHAN_IQ(0, I),
+       ADMV1014_CHAN_IQ(0, Q),
+       ADMV1014_CHAN_POWER(0),
+};
+
+static const struct iio_chan_spec admv1014_channels_if[] = {
+       ADMV1014_CHAN_IF(0, I),
+       ADMV1014_CHAN_IF(0, Q),
+       ADMV1014_CHAN_CALIBSCALE(0, I, admv1014_ext_info),
+       ADMV1014_CHAN_CALIBSCALE(0, Q, admv1014_ext_info),
+       ADMV1014_CHAN_POWER(0),
+};
+
+static void admv1014_clk_disable(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
+static void admv1014_reg_disable(void *data)
+{
+       regulator_bulk_disable(ADMV1014_NUM_REGULATORS, data);
+}
+
+static void admv1014_powerdown(void *data)
+{
+       unsigned int enable_reg, enable_reg_msk;
+
+       /* Disable all components in the Enable Register */
+       enable_reg_msk = ADMV1014_IBIAS_PD_MSK |
+                       ADMV1014_IF_AMP_PD_MSK |
+                       ADMV1014_QUAD_BG_PD_MSK |
+                       ADMV1014_BB_AMP_PD_MSK |
+                       ADMV1014_QUAD_IBIAS_PD_MSK |
+                       ADMV1014_BG_PD_MSK;
+
+       enable_reg = FIELD_PREP(ADMV1014_IBIAS_PD_MSK, 1) |
+                       FIELD_PREP(ADMV1014_IF_AMP_PD_MSK, 1) |
+                       FIELD_PREP(ADMV1014_QUAD_BG_PD_MSK, 1) |
+                       FIELD_PREP(ADMV1014_BB_AMP_PD_MSK, 1) |
+                       FIELD_PREP(ADMV1014_QUAD_IBIAS_PD_MSK, 1) |
+                       FIELD_PREP(ADMV1014_BG_PD_MSK, 1);
+
+       admv1014_spi_update_bits(data, ADMV1014_REG_ENABLE,
+                                enable_reg_msk, enable_reg);
+}
+
+static int admv1014_init(struct admv1014_state *st)
+{
+       unsigned int chip_id, enable_reg, enable_reg_msk;
+       struct spi_device *spi = st->spi;
+       int ret;
+
+       ret = regulator_bulk_enable(ADMV1014_NUM_REGULATORS, st->regulators);
+       if (ret) {
+               dev_err(&spi->dev, "Failed to enable regulators");
+               return ret;
+       }
+
+       ret = devm_add_action_or_reset(&spi->dev, admv1014_reg_disable, st->regulators);
+       if (ret)
+               return ret;
+
+       ret = clk_prepare_enable(st->clkin);
+       if (ret)
+               return ret;
+
+       ret = devm_add_action_or_reset(&spi->dev, admv1014_clk_disable, st->clkin);
+       if (ret)
+               return ret;
+
+       st->nb.notifier_call = admv1014_freq_change;
+       ret = devm_clk_notifier_register(&spi->dev, st->clkin, &st->nb);
+       if (ret)
+               return ret;
+
+       ret = devm_add_action_or_reset(&spi->dev, admv1014_powerdown, st);
+       if (ret)
+               return ret;
+
+       /* Perform a software reset */
+       ret = __admv1014_spi_update_bits(st, ADMV1014_REG_SPI_CONTROL,
+                                        ADMV1014_SPI_SOFT_RESET_MSK,
+                                        FIELD_PREP(ADMV1014_SPI_SOFT_RESET_MSK, 1));
+       if (ret) {
+               dev_err(&spi->dev, "ADMV1014 SPI software reset failed.\n");
+               return ret;
+       }
+
+       ret = __admv1014_spi_update_bits(st, ADMV1014_REG_SPI_CONTROL,
+                                        ADMV1014_SPI_SOFT_RESET_MSK,
+                                        FIELD_PREP(ADMV1014_SPI_SOFT_RESET_MSK, 0));
+       if (ret) {
+               dev_err(&spi->dev, "ADMV1014 SPI software reset disable failed.\n");
+               return ret;
+       }
+
+       ret = __admv1014_spi_write(st, ADMV1014_REG_VVA_TEMP_COMP, 0x727C);
+       if (ret) {
+               dev_err(&spi->dev, "Writing default Temperature Compensation value failed.\n");
+               return ret;
+       }
+
+       ret = __admv1014_spi_read(st, ADMV1014_REG_SPI_CONTROL, &chip_id);
+       if (ret)
+               return ret;
+
+       chip_id = FIELD_GET(ADMV1014_CHIP_ID_MSK, chip_id);
+       if (chip_id != ADMV1014_CHIP_ID) {
+               dev_err(&spi->dev, "Invalid Chip ID.\n");
+               ret = -EINVAL;
+               return ret;
+       }
+
+       ret = __admv1014_spi_update_bits(st, ADMV1014_REG_QUAD,
+                                        ADMV1014_QUAD_SE_MODE_MSK,
+                                        FIELD_PREP(ADMV1014_QUAD_SE_MODE_MSK,
+                                                   st->quad_se_mode));
+       if (ret) {
+               dev_err(&spi->dev, "Writing Quad SE Mode failed.\n");
+               return ret;
+       }
+
+       ret = admv1014_update_quad_filters(st);
+       if (ret) {
+               dev_err(&spi->dev, "Update Quad Filters failed.\n");
+               return ret;
+       }
+
+       ret = admv1014_update_vcm_settings(st);
+       if (ret) {
+               dev_err(&spi->dev, "Update VCM Settings failed.\n");
+               return ret;
+       }
+
+       enable_reg_msk = ADMV1014_P1DB_COMPENSATION_MSK |
+                        ADMV1014_IF_AMP_PD_MSK |
+                        ADMV1014_BB_AMP_PD_MSK |
+                        ADMV1014_DET_EN_MSK;
+
+       enable_reg = FIELD_PREP(ADMV1014_P1DB_COMPENSATION_MSK, st->p1db_comp ? 3 : 0) |
+                    FIELD_PREP(ADMV1014_IF_AMP_PD_MSK, !(st->input_mode)) |
+                    FIELD_PREP(ADMV1014_BB_AMP_PD_MSK, st->input_mode) |
+                    FIELD_PREP(ADMV1014_DET_EN_MSK, st->det_en);
+
+       return __admv1014_spi_update_bits(st, ADMV1014_REG_ENABLE, enable_reg_msk, enable_reg);
+}
+
+static int admv1014_properties_parse(struct admv1014_state *st)
+{
+       const char *str;
+       unsigned int i;
+       struct spi_device *spi = st->spi;
+       int ret;
+
+       st->det_en = device_property_read_bool(&spi->dev, "adi,detector-enable");
+
+       st->p1db_comp = device_property_read_bool(&spi->dev, "adi,p1db-compensation-enable");
+
+       ret = device_property_read_string(&spi->dev, "adi,input-mode", &str);
+       if (ret) {
+               st->input_mode = ADMV1014_IQ_MODE;
+       } else {
+               ret = match_string(input_mode_names, ARRAY_SIZE(input_mode_names), str);
+               if (ret < 0)
+                       return ret;
+
+               st->input_mode = ret;
+       }
+
+       ret = device_property_read_string(&spi->dev, "adi,quad-se-mode", &str);
+       if (ret) {
+               st->quad_se_mode = ADMV1014_SE_MODE_POS;
+       } else {
+               ret = match_string(quad_se_mode_names, ARRAY_SIZE(quad_se_mode_names), str);
+               if (ret < 0)
+                       return ret;
+
+               st->quad_se_mode = ADMV1014_SE_MODE_POS + (ret * 3);
+       }
+
+       for (i = 0; i < ADMV1014_NUM_REGULATORS; ++i)
+               st->regulators[i].supply = admv1014_reg_name[i];
+
+       ret = devm_regulator_bulk_get(&st->spi->dev, ADMV1014_NUM_REGULATORS,
+                                     st->regulators);
+       if (ret) {
+               dev_err(&spi->dev, "Failed to request regulators");
+               return ret;
+       }
+
+       st->clkin = devm_clk_get(&spi->dev, "lo_in");
+       if (IS_ERR(st->clkin))
+               return dev_err_probe(&spi->dev, PTR_ERR(st->clkin),
+                                    "failed to get the LO input clock\n");
+
+       return 0;
+}
+
+static int admv1014_probe(struct spi_device *spi)
+{
+       struct iio_dev *indio_dev;
+       struct admv1014_state *st;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       st = iio_priv(indio_dev);
+
+       ret = admv1014_properties_parse(st);
+       if (ret)
+               return ret;
+
+       indio_dev->info = &admv1014_info;
+       indio_dev->name = "admv1014";
+
+       if (st->input_mode == ADMV1014_IQ_MODE) {
+               indio_dev->channels = admv1014_channels_iq;
+               indio_dev->num_channels = ARRAY_SIZE(admv1014_channels_iq);
+       } else {
+               indio_dev->channels = admv1014_channels_if;
+               indio_dev->num_channels = ARRAY_SIZE(admv1014_channels_if);
+       }
+
+       st->spi = spi;
+
+       mutex_init(&st->lock);
+
+       ret = admv1014_init(st);
+       if (ret)
+               return ret;
+
+       return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct spi_device_id admv1014_id[] = {
+       { "admv1014", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(spi, admv1014_id);
+
+static const struct of_device_id admv1014_of_match[] = {
+       { .compatible = "adi,admv1014" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, admv1014_of_match);
+
+static struct spi_driver admv1014_driver = {
+       .driver = {
+               .name = "admv1014",
+               .of_match_table = admv1014_of_match,
+       },
+       .probe = admv1014_probe,
+       .id_table = admv1014_id,
+};
+module_spi_driver(admv1014_driver);
+
+MODULE_AUTHOR("Antoniu Miclaus <[email protected]");
+MODULE_DESCRIPTION("Analog Devices ADMV1014");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/frequency/admv4420.c b/drivers/iio/frequency/admv4420.c
new file mode 100644 (file)
index 0000000..51134ae
--- /dev/null
@@ -0,0 +1,398 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * ADMV4420
+ *
+ * Copyright 2021 Analog Devices Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/units.h>
+
+#include <asm/unaligned.h>
+
+/* ADMV4420 Register Map */
+#define ADMV4420_SPI_CONFIG_1                  0x00
+#define ADMV4420_SPI_CONFIG_2                  0x01
+#define ADMV4420_CHIPTYPE                      0x03
+#define ADMV4420_PRODUCT_ID_L                  0x04
+#define ADMV4420_PRODUCT_ID_H                  0x05
+#define ADMV4420_SCRATCHPAD                    0x0A
+#define ADMV4420_SPI_REV                       0x0B
+#define ADMV4420_ENABLES                       0x103
+#define ADMV4420_SDO_LEVEL                     0x108
+#define ADMV4420_INT_L                         0x200
+#define ADMV4420_INT_H                         0x201
+#define ADMV4420_FRAC_L                                0x202
+#define ADMV4420_FRAC_M                                0x203
+#define ADMV4420_FRAC_H                                0x204
+#define ADMV4420_MOD_L                         0x208
+#define ADMV4420_MOD_M                         0x209
+#define ADMV4420_MOD_H                         0x20A
+#define ADMV4420_R_DIV_L                       0x20C
+#define ADMV4420_R_DIV_H                       0x20D
+#define ADMV4420_REFERENCE                     0x20E
+#define ADMV4420_VCO_DATA_READBACK1            0x211
+#define ADMV4420_VCO_DATA_READBACK2            0x212
+#define ADMV4420_PLL_MUX_SEL                   0x213
+#define ADMV4420_LOCK_DETECT                   0x214
+#define ADMV4420_BAND_SELECT                   0x215
+#define ADMV4420_VCO_ALC_TIMEOUT               0x216
+#define ADMV4420_VCO_MANUAL                    0x217
+#define ADMV4420_ALC                           0x219
+#define ADMV4420_VCO_TIMEOUT1                  0x21C
+#define ADMV4420_VCO_TIMEOUT2                  0x21D
+#define ADMV4420_VCO_BAND_DIV                  0x21E
+#define ADMV4420_VCO_READBACK_SEL              0x21F
+#define ADMV4420_AUTOCAL                       0x226
+#define ADMV4420_CP_STATE                      0x22C
+#define ADMV4420_CP_BLEED_EN                   0x22D
+#define ADMV4420_CP_CURRENT                    0x22E
+#define ADMV4420_CP_BLEED                      0x22F
+
+#define ADMV4420_SPI_CONFIG_1_SDOACTIVE                (BIT(4) | BIT(3))
+#define ADMV4420_SPI_CONFIG_1_ENDIAN           (BIT(5) | BIT(2))
+#define ADMV4420_SPI_CONFIG_1_SOFTRESET                (BIT(7) | BIT(1))
+
+#define ADMV4420_REFERENCE_DIVIDE_BY_2_MASK    BIT(0)
+#define ADMV4420_REFERENCE_MODE_MASK           BIT(1)
+#define ADMV4420_REFERENCE_DOUBLER_MASK                BIT(2)
+
+#define ADMV4420_REF_DIVIDER_MAX_VAL           GENMASK(9, 0)
+#define ADMV4420_N_COUNTER_INT_MAX             GENMASK(15, 0)
+#define ADMV4420_N_COUNTER_FRAC_MAX            GENMASK(23, 0)
+#define ADMV4420_N_COUNTER_MOD_MAX             GENMASK(23, 0)
+
+#define ENABLE_PLL                             BIT(6)
+#define ENABLE_LO                              BIT(5)
+#define ENABLE_VCO                             BIT(3)
+#define ENABLE_IFAMP                           BIT(2)
+#define ENABLE_MIXER                           BIT(1)
+#define ENABLE_LNA                             BIT(0)
+
+#define ADMV4420_SCRATCH_PAD_VAL_1              0xAD
+#define ADMV4420_SCRATCH_PAD_VAL_2              0xEA
+
+#define ADMV4420_REF_FREQ_HZ                    50000000
+#define MAX_N_COUNTER                           655360UL
+#define MAX_R_DIVIDER                           1024
+#define ADMV4420_DEFAULT_LO_FREQ_HZ            16750000000ULL
+
+enum admv4420_mux_sel {
+       ADMV4420_LOW = 0,
+       ADMV4420_LOCK_DTCT = 1,
+       ADMV4420_R_COUNTER_PER_2 = 4,
+       ADMV4420_N_CONUTER_PER_2 = 5,
+       ADMV4420_HIGH = 8,
+};
+
+struct admv4420_reference_block {
+       bool doubler_en;
+       bool divide_by_2_en;
+       bool ref_single_ended;
+       u32 divider;
+};
+
+struct admv4420_n_counter {
+       u32 int_val;
+       u32 frac_val;
+       u32 mod_val;
+       u32 n_counter;
+};
+
+struct admv4420_state {
+       struct spi_device               *spi;
+       struct regmap                   *regmap;
+       u64                             vco_freq_hz;
+       u64                             lo_freq_hz;
+       struct admv4420_reference_block ref_block;
+       struct admv4420_n_counter       n_counter;
+       enum admv4420_mux_sel           mux_sel;
+       struct mutex                    lock;
+       u8                              transf_buf[4] ____cacheline_aligned;
+};
+
+static const struct regmap_config admv4420_regmap_config = {
+       .reg_bits = 16,
+       .val_bits = 8,
+       .read_flag_mask = BIT(7),
+};
+
+static int admv4420_reg_access(struct iio_dev *indio_dev,
+                              u32 reg, u32 writeval,
+                              u32 *readval)
+{
+       struct admv4420_state *st = iio_priv(indio_dev);
+
+       if (readval)
+               return regmap_read(st->regmap, reg, readval);
+       else
+               return regmap_write(st->regmap, reg, writeval);
+}
+
+static int admv4420_set_n_counter(struct admv4420_state *st, u32 int_val,
+                                 u32 frac_val, u32 mod_val)
+{
+       int ret;
+
+       put_unaligned_le32(frac_val, st->transf_buf);
+       ret = regmap_bulk_write(st->regmap, ADMV4420_FRAC_L, st->transf_buf, 3);
+       if (ret)
+               return ret;
+
+       put_unaligned_le32(mod_val, st->transf_buf);
+       ret = regmap_bulk_write(st->regmap, ADMV4420_MOD_L, st->transf_buf, 3);
+       if (ret)
+               return ret;
+
+       put_unaligned_le32(int_val, st->transf_buf);
+       return regmap_bulk_write(st->regmap, ADMV4420_INT_L, st->transf_buf, 2);
+}
+
+static int admv4420_read_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            int *val, int *val2, long info)
+{
+       struct admv4420_state *st = iio_priv(indio_dev);
+
+       switch (info) {
+       case IIO_CHAN_INFO_FREQUENCY:
+
+               *val = div_u64_rem(st->lo_freq_hz, MICRO, val2);
+
+               return IIO_VAL_INT_PLUS_MICRO;
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct iio_info admv4420_info = {
+       .read_raw = admv4420_read_raw,
+       .debugfs_reg_access = &admv4420_reg_access,
+};
+
+static const struct iio_chan_spec admv4420_channels[] = {
+       {
+               .type = IIO_ALTVOLTAGE,
+               .output = 0,
+               .indexed = 1,
+               .channel = 0,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_FREQUENCY),
+       },
+};
+
+static void admv4420_fw_parse(struct admv4420_state *st)
+{
+       struct device *dev = &st->spi->dev;
+       u32 tmp;
+       int ret;
+
+       ret = device_property_read_u32(dev, "adi,lo-freq-khz", &tmp);
+       if (!ret)
+               st->lo_freq_hz = (u64)tmp * KILO;
+
+       st->ref_block.ref_single_ended = device_property_read_bool(dev,
+                                                                  "adi,ref-ext-single-ended-en");
+}
+
+static inline uint64_t admv4420_calc_pfd_vco(struct admv4420_state *st)
+{
+       return div_u64(st->vco_freq_hz * 10, st->n_counter.n_counter);
+}
+
+static inline uint32_t admv4420_calc_pfd_ref(struct admv4420_state *st)
+{
+       uint32_t tmp;
+       u8 doubler, divide_by_2;
+
+       doubler = st->ref_block.doubler_en ? 2 : 1;
+       divide_by_2 = st->ref_block.divide_by_2_en ? 2 : 1;
+       tmp = ADMV4420_REF_FREQ_HZ * doubler;
+
+       return (tmp / (st->ref_block.divider * divide_by_2));
+}
+
+static int admv4420_calc_parameters(struct admv4420_state *st)
+{
+       u64 pfd_ref, pfd_vco;
+       bool sol_found = false;
+
+       st->ref_block.doubler_en = false;
+       st->ref_block.divide_by_2_en = false;
+       st->vco_freq_hz = div_u64(st->lo_freq_hz, 2);
+
+       for (st->ref_block.divider = 1; st->ref_block.divider < MAX_R_DIVIDER;
+           st->ref_block.divider++) {
+               pfd_ref = admv4420_calc_pfd_ref(st);
+               for (st->n_counter.n_counter = 1; st->n_counter.n_counter < MAX_N_COUNTER;
+                   st->n_counter.n_counter++) {
+                       pfd_vco = admv4420_calc_pfd_vco(st);
+                       if (pfd_ref == pfd_vco) {
+                               sol_found = true;
+                               break;
+                       }
+               }
+
+               if (sol_found)
+                       break;
+
+               st->n_counter.n_counter = 1;
+       }
+       if (!sol_found)
+               return -1;
+
+       st->n_counter.int_val = div_u64_rem(st->n_counter.n_counter, 10, &st->n_counter.frac_val);
+       st->n_counter.mod_val = 10;
+
+       return 0;
+}
+
+static int admv4420_setup(struct iio_dev *indio_dev)
+{
+       struct admv4420_state *st = iio_priv(indio_dev);
+       struct device *dev = indio_dev->dev.parent;
+       u32 val;
+       int ret;
+
+       ret = regmap_write(st->regmap, ADMV4420_SPI_CONFIG_1,
+                          ADMV4420_SPI_CONFIG_1_SOFTRESET);
+       if (ret)
+               return ret;
+
+       ret = regmap_write(st->regmap, ADMV4420_SPI_CONFIG_1,
+                          ADMV4420_SPI_CONFIG_1_SDOACTIVE |
+                          ADMV4420_SPI_CONFIG_1_ENDIAN);
+       if (ret)
+               return ret;
+
+       ret = regmap_write(st->regmap,
+                          ADMV4420_SCRATCHPAD,
+                          ADMV4420_SCRATCH_PAD_VAL_1);
+       if (ret)
+               return ret;
+
+       ret = regmap_read(st->regmap, ADMV4420_SCRATCHPAD, &val);
+       if (ret)
+               return ret;
+
+       if (val != ADMV4420_SCRATCH_PAD_VAL_1) {
+               dev_err(dev, "Failed ADMV4420 to read/write scratchpad %x ", val);
+               return -EIO;
+       }
+
+       ret = regmap_write(st->regmap,
+                          ADMV4420_SCRATCHPAD,
+                          ADMV4420_SCRATCH_PAD_VAL_2);
+       if (ret)
+               return ret;
+
+       ret = regmap_read(st->regmap, ADMV4420_SCRATCHPAD, &val);
+       if (ret)
+               return ret;
+
+       if (val != ADMV4420_SCRATCH_PAD_VAL_2) {
+               dev_err(dev, "Failed to read/write scratchpad %x ", val);
+               return -EIO;
+       }
+
+       st->mux_sel = ADMV4420_LOCK_DTCT;
+       st->lo_freq_hz = ADMV4420_DEFAULT_LO_FREQ_HZ;
+
+       admv4420_fw_parse(st);
+
+       ret = admv4420_calc_parameters(st);
+       if (ret) {
+               dev_err(dev, "Failed calc parameters for %lld ", st->vco_freq_hz);
+               return ret;
+       }
+
+       ret = regmap_write(st->regmap, ADMV4420_R_DIV_L,
+                          FIELD_GET(0xFF, st->ref_block.divider));
+       if (ret)
+               return ret;
+
+       ret = regmap_write(st->regmap, ADMV4420_R_DIV_H,
+                          FIELD_GET(0xFF00, st->ref_block.divider));
+       if (ret)
+               return ret;
+
+       ret = regmap_write(st->regmap, ADMV4420_REFERENCE,
+                          st->ref_block.divide_by_2_en |
+                          FIELD_PREP(ADMV4420_REFERENCE_MODE_MASK, st->ref_block.ref_single_ended) |
+                          FIELD_PREP(ADMV4420_REFERENCE_DOUBLER_MASK, st->ref_block.doubler_en));
+       if (ret)
+               return ret;
+
+       ret = admv4420_set_n_counter(st, st->n_counter.int_val,
+                                    st->n_counter.frac_val,
+                                    st->n_counter.mod_val);
+       if (ret)
+               return ret;
+
+       ret = regmap_write(st->regmap, ADMV4420_PLL_MUX_SEL, st->mux_sel);
+       if (ret)
+               return ret;
+
+       return regmap_write(st->regmap, ADMV4420_ENABLES,
+                           ENABLE_PLL | ENABLE_LO | ENABLE_VCO |
+                           ENABLE_IFAMP | ENABLE_MIXER | ENABLE_LNA);
+}
+
+static int admv4420_probe(struct spi_device *spi)
+{
+       struct iio_dev *indio_dev;
+       struct admv4420_state *st;
+       struct regmap *regmap;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       regmap = devm_regmap_init_spi(spi, &admv4420_regmap_config);
+       if (IS_ERR(regmap))
+               return dev_err_probe(&spi->dev, PTR_ERR(regmap),
+                                    "Failed to initializing spi regmap\n");
+
+       st = iio_priv(indio_dev);
+       st->spi = spi;
+       st->regmap = regmap;
+
+       indio_dev->name = "admv4420";
+       indio_dev->info = &admv4420_info;
+       indio_dev->channels = admv4420_channels;
+       indio_dev->num_channels = ARRAY_SIZE(admv4420_channels);
+
+       ret = admv4420_setup(indio_dev);
+       if (ret) {
+               dev_err(&spi->dev, "Setup ADMV4420 failed (%d)\n", ret);
+               return ret;
+       }
+
+       return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct of_device_id admv4420_of_match[] = {
+       { .compatible = "adi,admv4420" },
+       { }
+};
+
+MODULE_DEVICE_TABLE(of, admv4420_of_match);
+
+static struct spi_driver admv4420_driver = {
+       .driver = {
+               .name = "admv4420",
+               .of_match_table = admv4420_of_match,
+       },
+       .probe = admv4420_probe,
+};
+
+module_spi_driver(admv4420_driver);
+
+MODULE_AUTHOR("Cristian Pop <[email protected]>");
+MODULE_DESCRIPTION("Analog Devices ADMV44200 K Band Downconverter");
+MODULE_LICENSE("Dual BSD/GPL");
index a672f7d12bbb7c8831f0328d491f0cb6d41384af..97b86c4a53a6190611615d695108a2f30c1ea0d6 100644 (file)
@@ -139,30 +139,37 @@ config IIO_ST_GYRO_3AXIS
        tristate "STMicroelectronics gyroscopes 3-Axis Driver"
        depends on (I2C || SPI_MASTER) && SYSFS
        select IIO_ST_SENSORS_CORE
-       select IIO_ST_GYRO_I2C_3AXIS if (I2C)
-       select IIO_ST_GYRO_SPI_3AXIS if (SPI_MASTER)
        select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
        help
          Say yes here to build support for STMicroelectronics gyroscopes:
          L3G4200D, LSM330DL, L3GD20, LSM330DLC, L3G4IS, LSM330, LSM9DS0.
 
-         This driver can also be built as a module. If so, these modules
-         will be created:
-         - st_gyro (core functions for the driver [it is mandatory]);
-         - st_gyro_i2c (necessary for the I2C devices [optional*]);
-         - st_gyro_spi (necessary for the SPI devices [optional*]);
-
-         (*) one of these is necessary to do something.
+         Also need to enable at least one of I2C and SPI interface drivers
+         below.
 
 config IIO_ST_GYRO_I2C_3AXIS
-       tristate
-       depends on IIO_ST_GYRO_3AXIS
-       depends on IIO_ST_SENSORS_I2C
+       tristate "STMicroelectronics gyroscopes 3-Axis I2C Interface"
+       depends on I2C && IIO_ST_GYRO_3AXIS
+       default I2C && IIO_ST_GYRO_3AXIS
+       select IIO_ST_SENSORS_I2C
+       help
+         Build support for STMicroelectronics gyroscopes I2C interface.
+
+         To compile this driver as a module, choose M here. The module
+         will be called st_gyro_i2c.
+
 
 config IIO_ST_GYRO_SPI_3AXIS
-       tristate
-       depends on IIO_ST_GYRO_3AXIS
-       depends on IIO_ST_SENSORS_SPI
+       tristate "STMicroelectronics gyroscopes 3-Axis SPI Interface"
+       depends on SPI_MASTER && IIO_ST_GYRO_3AXIS
+       default SPI_MASTER && IIO_ST_GYRO_3AXIS
+       select IIO_ST_SENSORS_SPI
+       help
+         Build support for STMicroelectronics gyroscopes SPI interface.
+
+         To compile this driver as a module, choose M here. The module
+         will be called st_gyro_spi.
+
 
 config ITG3200
        tristate "InvenSense ITG3200 Digital 3-Axis Gyroscope I2C driver"
index 36879f01e28ca1a66a5ef1653660edda417262a3..71295709f2b969e32488b0e4648d14e0b0dca5e0 100644 (file)
@@ -591,3 +591,4 @@ module_spi_driver(adis16136_driver);
 MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices ADIS16133/ADIS16135/ADIS16136 gyroscope driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ADISLIB);
index 66b6b7bd5e1bcad6f083e8de683d65037598360f..eaf57bd339edd52ec9b2a470da82a56c97d7dc26 100644 (file)
@@ -433,3 +433,4 @@ module_spi_driver(adis16260_driver);
 MODULE_AUTHOR("Barry Song <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices ADIS16260/5 Digital Gyroscope Sensor");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ADISLIB);
index 46ed12771d2fe84221aa2267e95617f21704ae56..5fd1bf9902ea0d25a307a0b28ed9e6de63a714ba 100644 (file)
@@ -142,3 +142,4 @@ module_platform_driver(ssp_gyro_driver);
 MODULE_AUTHOR("Karol Wrona <[email protected]>");
 MODULE_DESCRIPTION("Samsung sensorhub gyroscopes driver");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_SSP_SENSORS);
index 4ae33ef25b9c8277d0e34c6296f9eb6b5d7c28ee..1ebfe7aa6c967fd6110715452e77feef0de1c751 100644 (file)
@@ -7,7 +7,6 @@
  * Denis Ciocca <[email protected]>
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/buffer.h>
@@ -65,6 +64,3 @@ int st_gyro_allocate_ring(struct iio_dev *indio_dev)
                NULL, &st_sensors_trigger_handler, &st_gyro_buffer_setup_ops);
 }
 
-MODULE_AUTHOR("Denis Ciocca <[email protected]>");
-MODULE_DESCRIPTION("STMicroelectronics gyroscopes buffer");
-MODULE_LICENSE("GPL v2");
index 201050b76fe5935959023d18aaa642573739d5f4..62172e18d0d895496fb3adcaa5dc5720019636ff 100644 (file)
@@ -472,7 +472,7 @@ const struct st_sensor_settings *st_gyro_get_settings(const char *name)
 
        return &st_gyro_sensors_settings[index];
 }
-EXPORT_SYMBOL(st_gyro_get_settings);
+EXPORT_SYMBOL_NS(st_gyro_get_settings, IIO_ST_SENSORS);
 
 int st_gyro_common_probe(struct iio_dev *indio_dev)
 {
@@ -518,8 +518,9 @@ int st_gyro_common_probe(struct iio_dev *indio_dev)
 
        return devm_iio_device_register(parent, indio_dev);
 }
-EXPORT_SYMBOL(st_gyro_common_probe);
+EXPORT_SYMBOL_NS(st_gyro_common_probe, IIO_ST_SENSORS);
 
 MODULE_AUTHOR("Denis Ciocca <[email protected]>");
 MODULE_DESCRIPTION("STMicroelectronics gyroscopes driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ST_SENSORS);
index 163c7ba300c1f2c56e2e09e0ea74bea5b1172602..8c7af42b655874b8f8d662fde4d2a4295cda1301 100644 (file)
@@ -120,3 +120,4 @@ module_i2c_driver(st_gyro_driver);
 MODULE_AUTHOR("Denis Ciocca <[email protected]>");
 MODULE_DESCRIPTION("STMicroelectronics gyroscopes i2c driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ST_SENSORS);
index b0023f9b9771bb4a09125310beaca9802b6e7f35..22aaabe48e4a16d9f76888ebb62d5a5ed3619b24 100644 (file)
@@ -124,3 +124,4 @@ module_spi_driver(st_gyro_driver);
 MODULE_AUTHOR("Denis Ciocca <[email protected]>");
 MODULE_DESCRIPTION("STMicroelectronics gyroscopes spi driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ST_SENSORS);
index 9a7819817488b4a0e3c285b129db385ae6b11065..c97e2544877296b0a5705c3d76262cf68453d490 100644 (file)
 #include <linux/kernel.h>
 #include <linux/printk.h>
 #include <linux/slab.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
 #include <linux/sysfs.h>
 #include <linux/io.h>
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/wait.h>
index 9e0fce917ce4cfdecd34b6e3ea492530fc75ab72..47f8e8ef56d6873a7e4cd4736b88a2610e64ea41 100644 (file)
@@ -417,10 +417,17 @@ static const struct of_device_id hdc100x_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, hdc100x_dt_ids);
 
+static const struct acpi_device_id hdc100x_acpi_match[] = {
+       { "TXNW1010" },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, hdc100x_acpi_match);
+
 static struct i2c_driver hdc100x_driver = {
        .driver = {
                .name   = "hdc100x",
                .of_match_table = hdc100x_dt_ids,
+               .acpi_match_table = hdc100x_acpi_match,
        },
        .probe = hdc100x_probe,
        .id_table = hdc100x_id,
index 36df2a102ca440258a87ead11a264e57eacfd79a..fd9e2565f8a2d8d8bcc69f7aaa2e48a3585067e2 100644 (file)
@@ -258,3 +258,4 @@ MODULE_DESCRIPTION("Measurement-Specialties htu21 temperature and humidity drive
 MODULE_AUTHOR("William Markezana <[email protected]>");
 MODULE_AUTHOR("Ludovic Tancerel <[email protected]>");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_MEAS_SPEC_SENSORS);
index cb0d66bf65613903fecb00cbd81de3d57c3de551..f7fcfd04f659da8cec1138f40203aa5b5960f20d 100644 (file)
@@ -30,8 +30,8 @@
  * @value: The value to write to device (up to 4 bytes)
  * @size: The size of the @value (in bytes)
  */
-int __adis_write_reg(struct adis *adis, unsigned int reg,
-       unsigned int value, unsigned int size)
+int __adis_write_reg(struct adis *adis, unsigned int reg, unsigned int value,
+                    unsigned int size)
 {
        unsigned int page = reg / ADIS_PAGE_SIZE;
        int ret, i;
@@ -114,14 +114,14 @@ int __adis_write_reg(struct adis *adis, unsigned int reg,
        ret = spi_sync(adis->spi, &msg);
        if (ret) {
                dev_err(&adis->spi->dev, "Failed to write register 0x%02X: %d\n",
-                               reg, ret);
+                       reg, ret);
        } else {
                adis->current_page = page;
        }
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(__adis_write_reg);
+EXPORT_SYMBOL_NS_GPL(__adis_write_reg, IIO_ADISLIB);
 
 /**
  * __adis_read_reg() - read N bytes from register (unlocked version)
@@ -130,8 +130,8 @@ EXPORT_SYMBOL_GPL(__adis_write_reg);
  * @val: The value read back from the device
  * @size: The size of the @val buffer
  */
-int __adis_read_reg(struct adis *adis, unsigned int reg,
-       unsigned int *val, unsigned int size)
+int __adis_read_reg(struct adis *adis, unsigned int reg, unsigned int *val,
+                   unsigned int size)
 {
        unsigned int page = reg / ADIS_PAGE_SIZE;
        struct spi_message msg;
@@ -201,12 +201,12 @@ int __adis_read_reg(struct adis *adis, unsigned int reg,
        ret = spi_sync(adis->spi, &msg);
        if (ret) {
                dev_err(&adis->spi->dev, "Failed to read register 0x%02X: %d\n",
-                               reg, ret);
+                       reg, ret);
                return ret;
-       } else {
-               adis->current_page = page;
        }
 
+       adis->current_page = page;
+
        switch (size) {
        case 4:
                *val = get_unaligned_be32(adis->rx);
@@ -218,7 +218,7 @@ int __adis_read_reg(struct adis *adis, unsigned int reg,
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(__adis_read_reg);
+EXPORT_SYMBOL_NS_GPL(__adis_read_reg, IIO_ADISLIB);
 /**
  * __adis_update_bits_base() - ADIS Update bits function - Unlocked version
  * @adis: The adis device
@@ -243,17 +243,17 @@ int __adis_update_bits_base(struct adis *adis, unsigned int reg, const u32 mask,
 
        return __adis_write_reg(adis, reg, __val, size);
 }
-EXPORT_SYMBOL_GPL(__adis_update_bits_base);
+EXPORT_SYMBOL_NS_GPL(__adis_update_bits_base, IIO_ADISLIB);
 
 #ifdef CONFIG_DEBUG_FS
 
-int adis_debugfs_reg_access(struct iio_dev *indio_dev,
-       unsigned int reg, unsigned int writeval, unsigned int *readval)
+int adis_debugfs_reg_access(struct iio_dev *indio_dev, unsigned int reg,
+                           unsigned int writeval, unsigned int *readval)
 {
        struct adis *adis = iio_device_get_drvdata(indio_dev);
 
        if (readval) {
-               uint16_t val16;
+               u16 val16;
                int ret;
 
                ret = adis_read_reg_16(adis, reg, &val16);
@@ -261,11 +261,11 @@ int adis_debugfs_reg_access(struct iio_dev *indio_dev,
                        *readval = val16;
 
                return ret;
-       } else {
-               return adis_write_reg_16(adis, reg, writeval);
        }
+
+       return adis_write_reg_16(adis, reg, writeval);
 }
-EXPORT_SYMBOL(adis_debugfs_reg_access);
+EXPORT_SYMBOL_NS(adis_debugfs_reg_access, IIO_ADISLIB);
 
 #endif
 
@@ -279,14 +279,16 @@ EXPORT_SYMBOL(adis_debugfs_reg_access);
 int adis_enable_irq(struct adis *adis, bool enable)
 {
        int ret = 0;
-       uint16_t msc;
+       u16 msc;
 
        mutex_lock(&adis->state_lock);
 
        if (adis->data->enable_irq) {
                ret = adis->data->enable_irq(adis, enable);
                goto out_unlock;
-       } else if (adis->data->unmasked_drdy) {
+       }
+
+       if (adis->data->unmasked_drdy) {
                if (enable)
                        enable_irq(adis->spi->irq);
                else
@@ -312,7 +314,7 @@ out_unlock:
        mutex_unlock(&adis->state_lock);
        return ret;
 }
-EXPORT_SYMBOL(adis_enable_irq);
+EXPORT_SYMBOL_NS(adis_enable_irq, IIO_ADISLIB);
 
 /**
  * __adis_check_status() - Check the device for error conditions (unlocked)
@@ -322,7 +324,7 @@ EXPORT_SYMBOL(adis_enable_irq);
  */
 int __adis_check_status(struct adis *adis)
 {
-       uint16_t status;
+       u16 status;
        int ret;
        int i;
 
@@ -344,7 +346,7 @@ int __adis_check_status(struct adis *adis)
 
        return -EIO;
 }
-EXPORT_SYMBOL_GPL(__adis_check_status);
+EXPORT_SYMBOL_NS_GPL(__adis_check_status, IIO_ADISLIB);
 
 /**
  * __adis_reset() - Reset the device (unlocked version)
@@ -358,7 +360,7 @@ int __adis_reset(struct adis *adis)
        const struct adis_timeout *timeouts = adis->data->timeouts;
 
        ret = __adis_write_reg_8(adis, adis->data->glob_cmd_reg,
-                       ADIS_GLOB_CMD_SW_RESET);
+                                ADIS_GLOB_CMD_SW_RESET);
        if (ret) {
                dev_err(&adis->spi->dev, "Failed to reset device: %d\n", ret);
                return ret;
@@ -368,7 +370,7 @@ int __adis_reset(struct adis *adis)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(__adis_reset);
+EXPORT_SYMBOL_NS_GPL(__adis_reset, IIO_ADIS_LIB);
 
 static int adis_self_test(struct adis *adis)
 {
@@ -414,7 +416,7 @@ int __adis_initial_startup(struct adis *adis)
 {
        const struct adis_timeout *timeouts = adis->data->timeouts;
        struct gpio_desc *gpio;
-       uint16_t prod_id;
+       u16 prod_id;
        int ret;
 
        /* check if the device has rst pin low */
@@ -423,7 +425,7 @@ int __adis_initial_startup(struct adis *adis)
                return PTR_ERR(gpio);
 
        if (gpio) {
-               msleep(10);
+               usleep_range(10, 12);
                /* bring device out of reset */
                gpiod_set_value_cansleep(gpio, 0);
                msleep(timeouts->reset_ms);
@@ -459,7 +461,7 @@ int __adis_initial_startup(struct adis *adis)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(__adis_initial_startup);
+EXPORT_SYMBOL_NS_GPL(__adis_initial_startup, IIO_ADISLIB);
 
 /**
  * adis_single_conversion() - Performs a single sample conversion
@@ -477,7 +479,8 @@ EXPORT_SYMBOL_GPL(__adis_initial_startup);
  * a error bit in the channels raw value set error_mask to 0.
  */
 int adis_single_conversion(struct iio_dev *indio_dev,
-       const struct iio_chan_spec *chan, unsigned int error_mask, int *val)
+                          const struct iio_chan_spec *chan,
+                          unsigned int error_mask, int *val)
 {
        struct adis *adis = iio_device_get_drvdata(indio_dev);
        unsigned int uval;
@@ -486,7 +489,7 @@ int adis_single_conversion(struct iio_dev *indio_dev,
        mutex_lock(&adis->state_lock);
 
        ret = __adis_read_reg(adis, chan->address, &uval,
-                       chan->scan_type.storagebits / 8);
+                             chan->scan_type.storagebits / 8);
        if (ret)
                goto err_unlock;
 
@@ -506,7 +509,7 @@ err_unlock:
        mutex_unlock(&adis->state_lock);
        return ret;
 }
-EXPORT_SYMBOL_GPL(adis_single_conversion);
+EXPORT_SYMBOL_NS_GPL(adis_single_conversion, IIO_ADISLIB);
 
 /**
  * adis_init() - Initialize adis device structure
@@ -521,7 +524,7 @@ EXPORT_SYMBOL_GPL(adis_single_conversion);
  * called.
  */
 int adis_init(struct adis *adis, struct iio_dev *indio_dev,
-       struct spi_device *spi, const struct adis_data *data)
+             struct spi_device *spi, const struct adis_data *data)
 {
        if (!data || !data->timeouts) {
                dev_err(&spi->dev, "No config data or timeouts not defined!\n");
@@ -543,7 +546,7 @@ int adis_init(struct adis *adis, struct iio_dev *indio_dev,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(adis_init);
+EXPORT_SYMBOL_NS_GPL(adis_init, IIO_ADISLIB);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
index 9fd30e62d6e879dc938cc2b5a7daf63767ccdaae..17bb0c40a1495cb55c677633427c40c8404e2b2b 100644 (file)
@@ -1240,3 +1240,4 @@ module_spi_driver(adis16400_driver);
 MODULE_AUTHOR("Manuel Stahl <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices ADIS16400/5 IMU SPI driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ADISLIB);
index b01988170118fae69b4ab8cca2377d36e0cb2233..69facd72bd7d8aeebf51b706534d3ab36879a983 100644 (file)
@@ -428,3 +428,4 @@ module_spi_driver(adis16460_driver);
 MODULE_AUTHOR("Dragos Bogdan <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices ADIS16460 IMU driver");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_ADISLIB);
index ea91d127077df77562e2ee722ff4a7ba0f83381a..ff2b0fab840a4c4b8d86618d6ca6ba3645438104 100644 (file)
@@ -1365,3 +1365,4 @@ module_spi_driver(adis16475_driver);
 MODULE_AUTHOR("Nuno Sa <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices ADIS16475 IMU driver");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_ADISLIB);
index f9b4540db1f437944b785ded54c5ce809f613c4d..44bbe3d19907376dfbeed90e3ab798e2ed80995e 100644 (file)
@@ -1538,3 +1538,4 @@ module_spi_driver(adis16480_driver);
 MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices ADIS16480 IMU driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ADISLIB);
index 351c303c8a8c05749957cbb8a05782e4ae3d2e68..928933027ae34d87d8da69d39ed71ccacefa104f 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/iio/imu/adis.h>
 
 static int adis_update_scan_mode_burst(struct iio_dev *indio_dev,
-       const unsigned long *scan_mask)
+                                      const unsigned long *scan_mask)
 {
        struct adis *adis = iio_device_get_drvdata(indio_dev);
        unsigned int burst_length, burst_max_length;
@@ -67,7 +67,7 @@ static int adis_update_scan_mode_burst(struct iio_dev *indio_dev,
 }
 
 int adis_update_scan_mode(struct iio_dev *indio_dev,
-       const unsigned long *scan_mask)
+                         const unsigned long *scan_mask)
 {
        struct adis *adis = iio_device_get_drvdata(indio_dev);
        const struct iio_chan_spec *chan;
@@ -124,7 +124,7 @@ int adis_update_scan_mode(struct iio_dev *indio_dev,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(adis_update_scan_mode);
+EXPORT_SYMBOL_NS_GPL(adis_update_scan_mode, IIO_ADISLIB);
 
 static irqreturn_t adis_trigger_handler(int irq, void *p)
 {
@@ -158,7 +158,7 @@ static irqreturn_t adis_trigger_handler(int irq, void *p)
        }
 
        iio_push_to_buffers_with_timestamp(indio_dev, adis->buffer,
-               pf->timestamp);
+                                          pf->timestamp);
 
 irq_done:
        iio_trigger_notify_done(indio_dev->trig);
@@ -212,5 +212,5 @@ devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
        return devm_add_action_or_reset(&adis->spi->dev, adis_buffer_cleanup,
                                        adis);
 }
-EXPORT_SYMBOL_GPL(devm_adis_setup_buffer_and_trigger);
+EXPORT_SYMBOL_NS_GPL(devm_adis_setup_buffer_and_trigger, IIO_ADISLIB);
 
index c461bd1e8e69ebfae73cc1cb1ec1e69c3a63dd8f..f890bf842db86b3614c7ce2da8cdc4a3470fffbb 100644 (file)
@@ -15,8 +15,7 @@
 #include <linux/iio/trigger.h>
 #include <linux/iio/imu/adis.h>
 
-static int adis_data_rdy_trigger_set_state(struct iio_trigger *trig,
-                                               bool state)
+static int adis_data_rdy_trigger_set_state(struct iio_trigger *trig, bool state)
 {
        struct adis *adis = iio_trigger_get_drvdata(trig);
 
@@ -88,5 +87,5 @@ int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
 
        return devm_iio_trigger_register(&adis->spi->dev, adis->trig);
 }
-EXPORT_SYMBOL_GPL(devm_adis_probe_trigger);
+EXPORT_SYMBOL_NS_GPL(devm_adis_probe_trigger, IIO_ADISLIB);
 
index f8f0cf716bc6b233004892dd2891e5be9e88de51..9b4298095d3f0ae39a05bbe6d5ba0eb8e300b3f9 100644 (file)
@@ -127,15 +127,14 @@ static int inv_mpu_process_acpi_config(struct i2c_client *client,
 int inv_mpu_acpi_create_mux_client(struct i2c_client *client)
 {
        struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(&client->dev));
+       struct acpi_device *adev = ACPI_COMPANION(&client->dev);
 
        st->mux_client = NULL;
-       if (ACPI_HANDLE(&client->dev)) {
+       if (adev) {
                struct i2c_board_info info;
                struct i2c_client *mux_client;
-               struct acpi_device *adev;
                int ret = -1;
 
-               adev = ACPI_COMPANION(&client->dev);
                memset(&info, 0, sizeof(info));
 
                dmi_check_system(inv_mpu_dev_list);
index fe03707ec2d3d1070763827102e0e719528ffd31..55cffb5fa1151773b18bdaea4631da7a5ab6b97b 100644 (file)
@@ -3,14 +3,14 @@
 * Copyright (C) 2012 Invensense, Inc.
 */
 
-#include <linux/acpi.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
 #include <linux/iio/iio.h>
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
-#include <linux/of_device.h>
 #include <linux/property.h>
+
 #include "inv_mpu_iio.h"
 
 static const struct regmap_config inv_mpu_regmap_config = {
@@ -51,7 +51,7 @@ static int inv_mpu_i2c_aux_setup(struct iio_dev *indio_dev)
 {
        struct inv_mpu6050_state *st = iio_priv(indio_dev);
        struct device *dev = indio_dev->dev.parent;
-       struct device_node *mux_node;
+       struct fwnode_handle *mux_node;
        int ret;
 
        /*
@@ -65,12 +65,12 @@ static int inv_mpu_i2c_aux_setup(struct iio_dev *indio_dev)
        case INV_MPU9150:
        case INV_MPU9250:
        case INV_MPU9255:
-               mux_node = of_get_child_by_name(dev->of_node, "i2c-gate");
+               mux_node = device_get_named_child_node(dev, "i2c-gate");
                if (mux_node != NULL) {
                        st->magn_disabled = true;
                        dev_warn(dev, "disable internal use of magnetometer\n");
                }
-               of_node_put(mux_node);
+               fwnode_handle_put(mux_node);
                break;
        default:
                break;
@@ -249,11 +249,10 @@ static const struct of_device_id inv_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, inv_of_match);
 
-static const struct acpi_device_id __maybe_unused inv_acpi_match[] = {
+static const struct acpi_device_id inv_acpi_match[] = {
        {"INVN6500", INV_MPU6500},
        { },
 };
-
 MODULE_DEVICE_TABLE(acpi, inv_acpi_match);
 
 static struct i2c_driver inv_mpu_driver = {
@@ -262,7 +261,7 @@ static struct i2c_driver inv_mpu_driver = {
        .id_table       =       inv_mpu_id,
        .driver = {
                .of_match_table = inv_of_match,
-               .acpi_match_table = ACPI_PTR(inv_acpi_match),
+               .acpi_match_table = inv_acpi_match,
                .name   =       "inv-mpu6050-i2c",
                .pm     =       &inv_mpu_pmops,
        },
index 6800356b25fb325e1ae5007d5be61426dc51ce73..26a7c2521dc48323c0cfffa3cf1c741842283832 100644 (file)
@@ -2,9 +2,8 @@
 /*
 * Copyright (C) 2015 Intel Corporation Inc.
 */
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
-#include <linux/acpi.h>
-#include <linux/of.h>
 #include <linux/property.h>
 #include <linux/spi/spi.h>
 #include <linux/regmap.h>
@@ -148,7 +147,7 @@ static struct spi_driver inv_mpu_driver = {
        .id_table       =       inv_mpu_id,
        .driver = {
                .of_match_table = inv_of_match,
-               .acpi_match_table = ACPI_PTR(inv_acpi_match),
+               .acpi_match_table = inv_acpi_match,
                .name   =       "inv-mpu6000-spi",
                .pm     =       &inv_mpu_pmops,
        },
index f89724481df9323ef520a41ed891b60c84134746..ec23b1ee472bd10167f3202fdfe66d01a63b5b99 100644 (file)
@@ -1443,7 +1443,6 @@ static int kmx61_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int kmx61_suspend(struct device *dev)
 {
        int ret;
@@ -1469,9 +1468,7 @@ static int kmx61_resume(struct device *dev)
 
        return kmx61_set_mode(data, stby, KMX61_ACC | KMX61_MAG, true);
 }
-#endif
 
-#ifdef CONFIG_PM
 static int kmx61_runtime_suspend(struct device *dev)
 {
        struct kmx61_data *data = i2c_get_clientdata(to_i2c_client(dev));
@@ -1496,11 +1493,10 @@ static int kmx61_runtime_resume(struct device *dev)
 
        return kmx61_set_mode(data, stby, KMX61_ACC | KMX61_MAG, true);
 }
-#endif
 
 static const struct dev_pm_ops kmx61_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(kmx61_suspend, kmx61_resume)
-       SET_RUNTIME_PM_OPS(kmx61_runtime_suspend, kmx61_runtime_resume, NULL)
+       SYSTEM_SLEEP_PM_OPS(kmx61_suspend, kmx61_resume)
+       RUNTIME_PM_OPS(kmx61_runtime_suspend, kmx61_runtime_resume, NULL)
 };
 
 static const struct acpi_device_id kmx61_acpi_match[] = {
@@ -1521,7 +1517,7 @@ static struct i2c_driver kmx61_driver = {
        .driver = {
                .name = KMX61_DRV_NAME,
                .acpi_match_table = ACPI_PTR(kmx61_acpi_match),
-               .pm = &kmx61_pm_ops,
+               .pm = pm_ptr(&kmx61_pm_ops),
        },
        .probe          = kmx61_probe,
        .remove         = kmx61_remove,
index 93f0c6bce502cd59fab579f059bf4a2aac7f6fc7..b1d8d5a66f01f3e9abe7b489f9a171ae763bd185 100644 (file)
@@ -1633,7 +1633,7 @@ st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev,
                                          struct device_attribute *attr,
                                          char *buf)
 {
-       struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
+       struct st_lsm6dsx_sensor *sensor = iio_priv(dev_to_iio_dev(dev));
        const struct st_lsm6dsx_odr_table_entry *odr_table;
        int i, len = 0;
 
@@ -1651,7 +1651,7 @@ static ssize_t st_lsm6dsx_sysfs_scale_avail(struct device *dev,
                                            struct device_attribute *attr,
                                            char *buf)
 {
-       struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
+       struct st_lsm6dsx_sensor *sensor = iio_priv(dev_to_iio_dev(dev));
        const struct st_lsm6dsx_fs_table_entry *fs_table;
        struct st_lsm6dsx_hw *hw = sensor->hw;
        int i, len = 0;
index 53b7017014f884004914bc2fb5d108253df363cf..d29558edee60414d96797821674f72cc3c5cdffb 100644 (file)
@@ -5,8 +5,6 @@ config IIO_ST_LSM9DS0
        depends on (I2C || SPI_MASTER) && SYSFS
        depends on !SENSORS_LIS3_I2C
        depends on !SENSORS_LIS3_SPI
-       select IIO_ST_LSM9DS0_I2C if I2C
-       select IIO_ST_LSM9DS0_SPI if SPI_MASTER
        select IIO_ST_ACCEL_3AXIS
        select IIO_ST_MAGN_3AXIS
 
@@ -17,12 +15,30 @@ config IIO_ST_LSM9DS0
          To compile this driver as a module, choose M here: the module
          will be called st_lsm9ds0.
 
+         Also need to enable at least one of I2C and SPI interface drivers
+
 config IIO_ST_LSM9DS0_I2C
-       tristate
-       depends on IIO_ST_LSM9DS0
+       tristate "STMicroelectronics LSM9DS0 IMU I2C interface"
+       depends on I2C && IIO_ST_LSM9DS0
+       default I2C && IIO_ST_LSM9DS0
+       select IIO_ST_ACCEL_I2C_3AXIS
+       select IIO_ST_MAGN_I2C_3AXIS
        select REGMAP_I2C
+       help
+         Build support for STMicroelectronics LSM9DS0 IMU I2C interface.
+
+         To compile this driver as a module, choose M here. The module
+         will be called st_lsm9ds0_i2c.
 
 config IIO_ST_LSM9DS0_SPI
-       tristate
-       depends on IIO_ST_LSM9DS0
+       tristate "STMicroelectronics LSM9DS0 IMU SPI interface"
+       depends on SPI_MASTER && IIO_ST_LSM9DS0
+       default SPI_MASTER && IIO_ST_LSM9DS0
+       select IIO_ST_ACCEL_SPI_3AXIS
+       select IIO_ST_MAGN_SPI_3AXIS
        select REGMAP_SPI
+       help
+         Build support for STMicroelectronics LSM9DS0 IMU I2C interface.
+
+         To compile this driver as a module, choose M here. The module
+         will be called st_lsm9ds0_spi.
index 9fb06b7cde3cafe3e36c1f18becb5be0fbd68195..ae7bc815382fb62f4ff6bb6d75c8a55936f4d196 100644 (file)
@@ -142,8 +142,9 @@ int st_lsm9ds0_probe(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap)
        /* Setup magnetometer device */
        return st_lsm9ds0_probe_magn(lsm9ds0, regmap);
 }
-EXPORT_SYMBOL_GPL(st_lsm9ds0_probe);
+EXPORT_SYMBOL_NS_GPL(st_lsm9ds0_probe, IIO_ST_SENSORS);
 
 MODULE_AUTHOR("Andy Shevchenko <[email protected]>");
 MODULE_DESCRIPTION("STMicroelectronics LSM9DS0 IMU core driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ST_SENSORS);
index 8f205c477e6fe4b090df313c42e2cc77b689d3d5..a90138d8b06a86e6cc09d6af8330846267a71d59 100644 (file)
@@ -77,3 +77,4 @@ module_i2c_driver(st_lsm9ds0_driver);
 MODULE_AUTHOR("Andy Shevchenko <[email protected]>");
 MODULE_DESCRIPTION("STMicroelectronics LSM9DS0 IMU I2C driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ST_SENSORS);
index 0ddfa53166af9ae51d05a2228ee6010536434f07..b743bf3546a7f960e88e0865060afa60631dd1be 100644 (file)
@@ -76,3 +76,4 @@ module_spi_driver(st_lsm9ds0_driver);
 MODULE_AUTHOR("Andy Shevchenko <[email protected]>");
 MODULE_DESCRIPTION("STMicroelectronics LSM9DS0 IMU SPI driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ST_SENSORS);
index 208b5193c621096ba4bf4a369270a613cb6bf04a..b078eb2f3c9def8745413b8d41ad711c10a60594 100644 (file)
@@ -1383,9 +1383,9 @@ static ssize_t direction_show(struct device *dev,
 
        switch (buffer->direction) {
        case IIO_BUFFER_DIRECTION_IN:
-               return sprintf(buf, "in\n");
+               return sysfs_emit(buf, "in\n");
        case IIO_BUFFER_DIRECTION_OUT:
-               return sprintf(buf, "out\n");
+               return sysfs_emit(buf, "out\n");
        default:
                return -EINVAL;
        }
index 409c278a4c2c130afd9bb2c052778d03aec16eff..e1ed44dec2abe09dcdadcd8b5854a564cd35ad97 100644 (file)
@@ -747,7 +747,7 @@ static ssize_t iio_read_channel_label(struct device *dev,
                return indio_dev->info->read_label(indio_dev, this_attr->c, buf);
 
        if (this_attr->c->extend_name)
-               return sprintf(buf, "%s\n", this_attr->c->extend_name);
+               return sysfs_emit(buf, "%s\n", this_attr->c->extend_name);
 
        return -EINVAL;
 }
index d0732eac0f0aceefefef3e433da9abaf15dae097..ce8b102ce52fd63ec98c6265286b3d1b94d422cf 100644 (file)
@@ -230,6 +230,7 @@ static const char * const iio_ev_type_text[] = {
        [IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive",
        [IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive",
        [IIO_EV_TYPE_CHANGE] = "change",
+       [IIO_EV_TYPE_MAG_REFERENCED] = "mag_referenced",
 };
 
 static const char * const iio_ev_dir_text[] = {
index 0222885b334c1395f8e5f70347a795462f0785fb..df74765d33dcb50172c89f01c81a20746f52bd2c 100644 (file)
@@ -595,28 +595,50 @@ EXPORT_SYMBOL_GPL(iio_read_channel_average_raw);
 static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
        int raw, int *processed, unsigned int scale)
 {
-       int scale_type, scale_val, scale_val2, offset;
+       int scale_type, scale_val, scale_val2;
+       int offset_type, offset_val, offset_val2;
        s64 raw64 = raw;
-       int ret;
 
-       ret = iio_channel_read(chan, &offset, NULL, IIO_CHAN_INFO_OFFSET);
-       if (ret >= 0)
-               raw64 += offset;
+       offset_type = iio_channel_read(chan, &offset_val, &offset_val2,
+                                      IIO_CHAN_INFO_OFFSET);
+       if (offset_type >= 0) {
+               switch (offset_type) {
+               case IIO_VAL_INT:
+                       break;
+               case IIO_VAL_INT_PLUS_MICRO:
+               case IIO_VAL_INT_PLUS_NANO:
+                       /*
+                        * Both IIO_VAL_INT_PLUS_MICRO and IIO_VAL_INT_PLUS_NANO
+                        * implicitely truncate the offset to it's integer form.
+                        */
+                       break;
+               case IIO_VAL_FRACTIONAL:
+                       offset_val /= offset_val2;
+                       break;
+               case IIO_VAL_FRACTIONAL_LOG2:
+                       offset_val >>= offset_val2;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               raw64 += offset_val;
+       }
 
        scale_type = iio_channel_read(chan, &scale_val, &scale_val2,
                                        IIO_CHAN_INFO_SCALE);
        if (scale_type < 0) {
                /*
-                * Just pass raw values as processed if no scaling is
-                * available.
+                * If no channel scaling is available apply consumer scale to
+                * raw value and return.
                 */
-               *processed = raw;
+               *processed = raw * scale;
                return 0;
        }
 
        switch (scale_type) {
        case IIO_VAL_INT:
-               *processed = raw64 * scale_val;
+               *processed = raw64 * scale_val * scale;
                break;
        case IIO_VAL_INT_PLUS_MICRO:
                if (scale_val2 < 0)
index baaf202dce05659586c7c6712bc4f839163fe2ea..0f9d775989979cfc28864431fd67678ca4129cc7 100644 (file)
@@ -466,7 +466,6 @@ static int apds9300_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int apds9300_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
@@ -493,11 +492,8 @@ static int apds9300_resume(struct device *dev)
        return ret;
 }
 
-static SIMPLE_DEV_PM_OPS(apds9300_pm_ops, apds9300_suspend, apds9300_resume);
-#define APDS9300_PM_OPS (&apds9300_pm_ops)
-#else
-#define APDS9300_PM_OPS NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(apds9300_pm_ops, apds9300_suspend,
+                               apds9300_resume);
 
 static const struct i2c_device_id apds9300_id[] = {
        { APDS9300_DRV_NAME, 0 },
@@ -509,7 +505,7 @@ MODULE_DEVICE_TABLE(i2c, apds9300_id);
 static struct i2c_driver apds9300_driver = {
        .driver = {
                .name   = APDS9300_DRV_NAME,
-               .pm     = APDS9300_PM_OPS,
+               .pm     = pm_sleep_ptr(&apds9300_pm_ops),
        },
        .probe          = apds9300_probe,
        .remove         = apds9300_remove,
index abbf2e662e7dbc345c0ed7ccb7a10a0027eb35ef..790d3d6139796c0b5e65e11a9e50ddde258fea08 100644 (file)
@@ -221,7 +221,6 @@ static int bh1780_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
 static int bh1780_runtime_suspend(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
@@ -256,14 +255,9 @@ static int bh1780_runtime_resume(struct device *dev)
 
        return 0;
 }
-#endif /* CONFIG_PM */
 
-static const struct dev_pm_ops bh1780_dev_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-                               pm_runtime_force_resume)
-       SET_RUNTIME_PM_OPS(bh1780_runtime_suspend,
-                          bh1780_runtime_resume, NULL)
-};
+static DEFINE_RUNTIME_DEV_PM_OPS(bh1780_dev_pm_ops, bh1780_runtime_suspend,
+                               bh1780_runtime_resume, NULL);
 
 static const struct i2c_device_id bh1780_id[] = {
        { "bh1780", 0 },
@@ -284,7 +278,7 @@ static struct i2c_driver bh1780_driver = {
        .id_table       = bh1780_id,
        .driver = {
                .name = "bh1780",
-               .pm = &bh1780_dev_pm_ops,
+               .pm = pm_ptr(&bh1780_dev_pm_ops),
                .of_match_table = of_bh1780_match,
        },
 };
index 18a410340dc563813583718a3165992df889e91f..2c80a0535d2c4855da208959bdf030a0489c08e7 100644 (file)
@@ -374,7 +374,6 @@ static const struct i2c_device_id cm3232_id[] = {
        {}
 };
 
-#ifdef CONFIG_PM_SLEEP
 static int cm3232_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
@@ -403,9 +402,7 @@ static int cm3232_resume(struct device *dev)
        return ret;
 }
 
-static const struct dev_pm_ops cm3232_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(cm3232_suspend, cm3232_resume)};
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(cm3232_pm_ops, cm3232_suspend, cm3232_resume);
 
 MODULE_DEVICE_TABLE(i2c, cm3232_id);
 
@@ -419,9 +416,7 @@ static struct i2c_driver cm3232_driver = {
        .driver = {
                .name   = "cm3232",
                .of_match_table = cm3232_of_match,
-#ifdef CONFIG_PM_SLEEP
-               .pm     = &cm3232_pm_ops,
-#endif
+               .pm     = pm_sleep_ptr(&cm3232_pm_ops),
        },
        .id_table       = cm3232_id,
        .probe          = cm3232_probe,
index 2689867467a8bf049df5ecb7d2fffc688fe507cf..b36f8b7ca68e7c672a3c6f03ba43df03eba6c8e4 100644 (file)
@@ -784,7 +784,6 @@ static int isl29018_probe(struct i2c_client *client,
        return devm_iio_device_register(&client->dev, indio_dev);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int isl29018_suspend(struct device *dev)
 {
        struct isl29018_chip *chip = iio_priv(dev_get_drvdata(dev));
@@ -830,11 +829,8 @@ static int isl29018_resume(struct device *dev)
        return err;
 }
 
-static SIMPLE_DEV_PM_OPS(isl29018_pm_ops, isl29018_suspend, isl29018_resume);
-#define ISL29018_PM_OPS (&isl29018_pm_ops)
-#else
-#define ISL29018_PM_OPS NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(isl29018_pm_ops, isl29018_suspend,
+                               isl29018_resume);
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id isl29018_acpi_match[] = {
@@ -866,7 +862,7 @@ static struct i2c_driver isl29018_driver = {
        .driver  = {
                        .name = "isl29018",
                        .acpi_match_table = ACPI_PTR(isl29018_acpi_match),
-                       .pm = ISL29018_PM_OPS,
+                       .pm = pm_sleep_ptr(&isl29018_pm_ops),
                        .of_match_table = isl29018_of_match,
                    },
        .probe   = isl29018_probe,
index ba53b50d711a15894d4a5d3faa1bfbb8eddc3370..eb68a52aab8242eed331810cefc0f5e2b81ec6b7 100644 (file)
@@ -311,7 +311,6 @@ static int isl29125_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int isl29125_suspend(struct device *dev)
 {
        struct isl29125_data *data = iio_priv(i2c_get_clientdata(
@@ -326,9 +325,9 @@ static int isl29125_resume(struct device *dev)
        return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1,
                data->conf1);
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(isl29125_pm_ops, isl29125_suspend, isl29125_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(isl29125_pm_ops, isl29125_suspend,
+                               isl29125_resume);
 
 static const struct i2c_device_id isl29125_id[] = {
        { "isl29125", 0 },
@@ -339,7 +338,7 @@ MODULE_DEVICE_TABLE(i2c, isl29125_id);
 static struct i2c_driver isl29125_driver = {
        .driver = {
                .name   = ISL29125_DRV_NAME,
-               .pm     = &isl29125_pm_ops,
+               .pm     = pm_sleep_ptr(&isl29125_pm_ops),
        },
        .probe          = isl29125_probe,
        .remove         = isl29125_remove,
index 724a0ec9f35cc76b3cc5404ef6a3e1a060d5e756..a55194263d23b05edf580fd5d8c24845cec55b67 100644 (file)
@@ -383,7 +383,6 @@ static int jsa1212_remove(struct i2c_client *client)
        return jsa1212_power_off(data);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int jsa1212_suspend(struct device *dev)
 {
        struct jsa1212_data *data;
@@ -421,12 +420,8 @@ unlock_and_ret:
        return ret;
 }
 
-static SIMPLE_DEV_PM_OPS(jsa1212_pm_ops, jsa1212_suspend, jsa1212_resume);
-
-#define JSA1212_PM_OPS (&jsa1212_pm_ops)
-#else
-#define JSA1212_PM_OPS NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(jsa1212_pm_ops, jsa1212_suspend,
+                               jsa1212_resume);
 
 static const struct acpi_device_id jsa1212_acpi_match[] = {
        {"JSA1212", 0},
@@ -443,7 +438,7 @@ MODULE_DEVICE_TABLE(i2c, jsa1212_id);
 static struct i2c_driver jsa1212_driver = {
        .driver = {
                .name   = JSA1212_DRIVER_NAME,
-               .pm     = JSA1212_PM_OPS,
+               .pm     = pm_sleep_ptr(&jsa1212_pm_ops),
                .acpi_match_table = ACPI_PTR(jsa1212_acpi_match),
        },
        .probe          = jsa1212_probe,
index 8a621244dd0126fc5bfa345e347137b69851e4d5..827bc25269e9117e67dee1c47efb2afb3c3e3cba 100644 (file)
@@ -417,7 +417,7 @@ static ssize_t show_thresh_either_en(struct device *dev,
                enable = 0;
        }
 
-       return scnprintf(buf, PAGE_SIZE, "%u\n", enable);
+       return sysfs_emit(buf, "%u\n", enable);
 }
 
 static ssize_t store_thresh_either_en(struct device *dev,
@@ -474,7 +474,7 @@ static ssize_t show_zone(struct device *dev,
        if (ret)
                return ret;
 
-       return scnprintf(buf, PAGE_SIZE, "%u\n", zone);
+       return sysfs_emit(buf, "%u\n", zone);
 }
 
 enum lm3533_als_attribute_type {
@@ -530,7 +530,7 @@ static ssize_t show_als_attr(struct device *dev,
        if (ret)
                return ret;
 
-       return scnprintf(buf, PAGE_SIZE, "%u\n", val);
+       return sysfs_emit(buf, "%u\n", val);
 }
 
 static ssize_t store_als_attr(struct device *dev,
index 47d61ec2bb50f08b7af6eb86d59a88c9c3962943..679a1e1086ae839f9a74daf03fb652bc6ef808fb 100644 (file)
@@ -1611,7 +1611,6 @@ static int ltr501_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int ltr501_suspend(struct device *dev)
 {
        struct ltr501_data *data = iio_priv(i2c_get_clientdata(
@@ -1627,23 +1626,22 @@ static int ltr501_resume(struct device *dev)
        return ltr501_write_contr(data, data->als_contr,
                data->ps_contr);
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(ltr501_pm_ops, ltr501_suspend, ltr501_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(ltr501_pm_ops, ltr501_suspend, ltr501_resume);
 
 static const struct acpi_device_id ltr_acpi_match[] = {
-       {"LTER0501", ltr501},
-       {"LTER0559", ltr559},
-       {"LTER0301", ltr301},
+       { "LTER0501", ltr501 },
+       { "LTER0559", ltr559 },
+       { "LTER0301", ltr301 },
        { },
 };
 MODULE_DEVICE_TABLE(acpi, ltr_acpi_match);
 
 static const struct i2c_device_id ltr501_id[] = {
-       { "ltr501", ltr501},
-       { "ltr559", ltr559},
-       { "ltr301", ltr301},
-       { "ltr303", ltr303},
+       { "ltr501", ltr501 },
+       { "ltr559", ltr559 },
+       { "ltr301", ltr301 },
+       { "ltr303", ltr303 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, ltr501_id);
@@ -1661,7 +1659,7 @@ static struct i2c_driver ltr501_driver = {
        .driver = {
                .name   = LTR501_DRV_NAME,
                .of_match_table = ltr501_of_match,
-               .pm     = &ltr501_pm_ops,
+               .pm     = pm_sleep_ptr(&ltr501_pm_ops),
                .acpi_match_table = ACPI_PTR(ltr_acpi_match),
        },
        .probe  = ltr501_probe,
index a52b2c788540268d55051f944ec787d8e9d9c8a6..528fa5dd2b1356aeb78e33dfd21ad533a73575aa 100644 (file)
@@ -452,14 +452,14 @@ static const struct dev_pm_ops pa12203001_pm_ops = {
 };
 
 static const struct acpi_device_id pa12203001_acpi_match[] = {
-       { "TXCPA122", 0},
+       { "TXCPA122", 0 },
        {}
 };
 
 MODULE_DEVICE_TABLE(acpi, pa12203001_acpi_match);
 
 static const struct i2c_device_id pa12203001_id[] = {
-               {"txcpa122", 0},
+               { "txcpa122", 0 },
                {}
 };
 
index c2dd8a3d421752a3784f199e60088767f4ce58b0..dabdd05f0e2cc8b571814d3bb61cce88c8ef6e0e 100644 (file)
@@ -1055,7 +1055,6 @@ static int rpr0521_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
 static int rpr0521_runtime_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
@@ -1101,11 +1100,9 @@ static int rpr0521_runtime_resume(struct device *dev)
 
        return 0;
 }
-#endif
 
 static const struct dev_pm_ops rpr0521_pm_ops = {
-       SET_RUNTIME_PM_OPS(rpr0521_runtime_suspend,
-                          rpr0521_runtime_resume, NULL)
+       RUNTIME_PM_OPS(rpr0521_runtime_suspend, rpr0521_runtime_resume, NULL)
 };
 
 static const struct acpi_device_id rpr0521_acpi_match[] = {
@@ -1124,7 +1121,7 @@ MODULE_DEVICE_TABLE(i2c, rpr0521_id);
 static struct i2c_driver rpr0521_driver = {
        .driver = {
                .name   = RPR0521_DRV_NAME,
-               .pm     = &rpr0521_pm_ops,
+               .pm     = pm_ptr(&rpr0521_pm_ops),
                .acpi_match_table = ACPI_PTR(rpr0521_acpi_match),
        },
        .probe          = rpr0521_probe,
index 41a2ce5a2d53882c807bde64a67d238aa3ce64e2..3d4cc1180b6a77ab3eb453ef91dbe373491671aa 100644 (file)
@@ -323,7 +323,7 @@ int st_uvis25_probe(struct device *dev, int irq, struct regmap *regmap)
 
        return devm_iio_device_register(dev, iio_dev);
 }
-EXPORT_SYMBOL(st_uvis25_probe);
+EXPORT_SYMBOL_NS(st_uvis25_probe, IIO_UVIS25);
 
 static int __maybe_unused st_uvis25_suspend(struct device *dev)
 {
@@ -349,7 +349,7 @@ static int __maybe_unused st_uvis25_resume(struct device *dev)
 const struct dev_pm_ops st_uvis25_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(st_uvis25_suspend, st_uvis25_resume)
 };
-EXPORT_SYMBOL(st_uvis25_pm_ops);
+EXPORT_SYMBOL_NS(st_uvis25_pm_ops, IIO_UVIS25);
 
 MODULE_AUTHOR("Lorenzo Bianconi <[email protected]>");
 MODULE_DESCRIPTION("STMicroelectronics uvis25 sensor driver");
index 98cd49eefe4567e01646598a2322c5a21f914b64..b06d09af28a3579a3540c229c921193bd6110675 100644 (file)
@@ -66,3 +66,4 @@ module_i2c_driver(st_uvis25_driver);
 MODULE_AUTHOR("Lorenzo Bianconi <[email protected]>");
 MODULE_DESCRIPTION("STMicroelectronics uvis25 i2c driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_UVIS25);
index af9d94d1278724b0fea7bed40e99f0632c2b7998..3a4dc6d7180c246da623ce3812c8978cfa20d081 100644 (file)
@@ -66,3 +66,4 @@ module_spi_driver(st_uvis25_driver);
 MODULE_AUTHOR("Lorenzo Bianconi <[email protected]>");
 MODULE_DESCRIPTION("STMicroelectronics uvis25 spi driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_UVIS25);
index fc63856ed54debe80b55e815f43a6e9cfc8ba6e6..1d02dfbc29d1a76e96bd226d9b70cb599b580138 100644 (file)
@@ -632,7 +632,6 @@ static int stk3310_remove(struct i2c_client *client)
        return stk3310_set_state(iio_priv(indio_dev), STK3310_STATE_STANDBY);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int stk3310_suspend(struct device *dev)
 {
        struct stk3310_data *data;
@@ -656,12 +655,8 @@ static int stk3310_resume(struct device *dev)
        return stk3310_set_state(data, state);
 }
 
-static SIMPLE_DEV_PM_OPS(stk3310_pm_ops, stk3310_suspend, stk3310_resume);
-
-#define STK3310_PM_OPS (&stk3310_pm_ops)
-#else
-#define STK3310_PM_OPS NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(stk3310_pm_ops, stk3310_suspend,
+                               stk3310_resume);
 
 static const struct i2c_device_id stk3310_i2c_id[] = {
        {"STK3310", 0},
@@ -692,7 +687,7 @@ static struct i2c_driver stk3310_driver = {
        .driver = {
                .name = "stk3310",
                .of_match_table = stk3310_of_match,
-               .pm = STK3310_PM_OPS,
+               .pm = pm_sleep_ptr(&stk3310_pm_ops),
                .acpi_match_table = ACPI_PTR(stk3310_acpi_id),
        },
        .probe =            stk3310_probe,
index b87222141429a8fe690043f0fd4c71aff35ad829..3951536022b3d78bb0e63a5d618de6985ab14240 100644 (file)
@@ -345,7 +345,6 @@ static int tcs3414_probe(struct i2c_client *client,
        return devm_iio_device_register(&client->dev, indio_dev);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int tcs3414_suspend(struct device *dev)
 {
        struct tcs3414_data *data = iio_priv(i2c_get_clientdata(
@@ -360,9 +359,9 @@ static int tcs3414_resume(struct device *dev)
        return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
                data->control);
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(tcs3414_pm_ops, tcs3414_suspend, tcs3414_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(tcs3414_pm_ops, tcs3414_suspend,
+                               tcs3414_resume);
 
 static const struct i2c_device_id tcs3414_id[] = {
        { "tcs3414", 0 },
@@ -373,7 +372,7 @@ MODULE_DEVICE_TABLE(i2c, tcs3414_id);
 static struct i2c_driver tcs3414_driver = {
        .driver = {
                .name   = TCS3414_DRV_NAME,
-               .pm     = &tcs3414_pm_ops,
+               .pm     = pm_sleep_ptr(&tcs3414_pm_ops),
        },
        .probe          = tcs3414_probe,
        .id_table       = tcs3414_id,
index 371c6a39a16547751dfec2fa7792bbc0dab0fd90..823435f59bb6b7d25723d1954a980b41625b6a18 100644 (file)
@@ -572,7 +572,6 @@ static int tcs3472_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int tcs3472_suspend(struct device *dev)
 {
        struct tcs3472_data *data = iio_priv(i2c_get_clientdata(
@@ -598,9 +597,9 @@ static int tcs3472_resume(struct device *dev)
 
        return ret;
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(tcs3472_pm_ops, tcs3472_suspend, tcs3472_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(tcs3472_pm_ops, tcs3472_suspend,
+                               tcs3472_resume);
 
 static const struct i2c_device_id tcs3472_id[] = {
        { "tcs3472", 0 },
@@ -611,7 +610,7 @@ MODULE_DEVICE_TABLE(i2c, tcs3472_id);
 static struct i2c_driver tcs3472_driver = {
        .driver = {
                .name   = TCS3472_DRV_NAME,
-               .pm     = &tcs3472_pm_ops,
+               .pm     = pm_sleep_ptr(&tcs3472_pm_ops),
        },
        .probe          = tcs3472_probe,
        .remove         = tcs3472_remove,
index 5bf2bfbc5379eb013ef373351ace384afcecb317..0a278eea36ca0b21c2973505b423456d72b2bba2 100644 (file)
@@ -814,7 +814,6 @@ static int tsl2563_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int tsl2563_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
@@ -857,11 +856,8 @@ out:
        return ret;
 }
 
-static SIMPLE_DEV_PM_OPS(tsl2563_pm_ops, tsl2563_suspend, tsl2563_resume);
-#define TSL2563_PM_OPS (&tsl2563_pm_ops)
-#else
-#define TSL2563_PM_OPS NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(tsl2563_pm_ops, tsl2563_suspend,
+                               tsl2563_resume);
 
 static const struct i2c_device_id tsl2563_id[] = {
        { "tsl2560", 0 },
@@ -885,7 +881,7 @@ static struct i2c_driver tsl2563_i2c_driver = {
        .driver = {
                .name    = "tsl2563",
                .of_match_table = tsl2563_of_match,
-               .pm     = TSL2563_PM_OPS,
+               .pm     = pm_sleep_ptr(&tsl2563_pm_ops),
        },
        .probe          = tsl2563_probe,
        .remove         = tsl2563_remove,
index d79205361dfac52cd4405e29e1d77bcea631972d..729f14d9f2a4bb18cc65e311d7450fb9d9485298 100644 (file)
@@ -1902,7 +1902,7 @@ static const struct i2c_device_id tsl2772_idtable[] = {
        { "tmd2672", tmd2672 },
        { "tsl2772", tsl2772 },
        { "tmd2772", tmd2772 },
-       { "apds9930", apds9930},
+       { "apds9930", apds9930 },
        {}
 };
 
index 70505ba6d8586380cb0286beab15b1e80fa2f232..6ae1b27e50b6330e841600827d52836fa2e33a3c 100644 (file)
@@ -215,7 +215,6 @@ static int tsl4531_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int tsl4531_suspend(struct device *dev)
 {
        return tsl4531_powerdown(to_i2c_client(dev));
@@ -227,11 +226,8 @@ static int tsl4531_resume(struct device *dev)
                TSL4531_MODE_NORMAL);
 }
 
-static SIMPLE_DEV_PM_OPS(tsl4531_pm_ops, tsl4531_suspend, tsl4531_resume);
-#define TSL4531_PM_OPS (&tsl4531_pm_ops)
-#else
-#define TSL4531_PM_OPS NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(tsl4531_pm_ops, tsl4531_suspend,
+                               tsl4531_resume);
 
 static const struct i2c_device_id tsl4531_id[] = {
        { "tsl4531", 0 },
@@ -242,7 +238,7 @@ MODULE_DEVICE_TABLE(i2c, tsl4531_id);
 static struct i2c_driver tsl4531_driver = {
        .driver = {
                .name   = TSL4531_DRV_NAME,
-               .pm     = TSL4531_PM_OPS,
+               .pm     = pm_sleep_ptr(&tsl4531_pm_ops),
        },
        .probe  = tsl4531_probe,
        .remove = tsl4531_remove,
index 96e4a66ddf28672f6bdb9afd96564387753e0711..1492aaf8d84cfe55ab93515666bcc696cebb3d8c 100644 (file)
@@ -947,15 +947,15 @@ static const struct dev_pm_ops us5182d_pm_ops = {
 };
 
 static const struct acpi_device_id us5182d_acpi_match[] = {
-       { "USD5182", 0},
+       { "USD5182", 0 },
        {}
 };
 
 MODULE_DEVICE_TABLE(acpi, us5182d_acpi_match);
 
 static const struct i2c_device_id us5182d_id[] = {
-               {"usd5182", 0},
-               {}
+       { "usd5182", 0 },
+       {}
 };
 
 MODULE_DEVICE_TABLE(i2c, us5182d_id);
index 0db306ee910e02e1e397169998220e147225872d..da2bf622a67b5fccf882574dc6f8793a7d159e3b 100644 (file)
@@ -651,7 +651,7 @@ static const struct dev_pm_ops vcnl4035_pm_ops = {
 };
 
 static const struct i2c_device_id vcnl4035_id[] = {
-       { "vcnl4035", 0},
+       { "vcnl4035", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, vcnl4035_id);
index 565ee41ccb3ad6a9df0a4f30d416f6dba85c7590..54445365c4bcfd6c79768950ac0e135238bd7f36 100644 (file)
@@ -117,30 +117,35 @@ config IIO_ST_MAGN_3AXIS
        tristate "STMicroelectronics magnetometers 3-Axis Driver"
        depends on (I2C || SPI_MASTER) && SYSFS
        select IIO_ST_SENSORS_CORE
-       select IIO_ST_MAGN_I2C_3AXIS if (I2C)
-       select IIO_ST_MAGN_SPI_3AXIS if (SPI_MASTER)
        select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
        help
          Say yes here to build support for STMicroelectronics magnetometers:
          LSM303DLHC, LSM303DLM, LIS3MDL.
 
-         This driver can also be built as a module. If so, these modules
-         will be created:
-         - st_magn (core functions for the driver [it is mandatory]);
-         - st_magn_i2c (necessary for the I2C devices [optional*]);
-         - st_magn_spi (necessary for the SPI devices [optional*]);
-
-         (*) one of these is necessary to do something.
+         Also need to enable at least one of I2C and SPI interface drivers
+         below.
 
 config IIO_ST_MAGN_I2C_3AXIS
-       tristate
-       depends on IIO_ST_MAGN_3AXIS
-       depends on IIO_ST_SENSORS_I2C
+       tristate "STMicroelectronics magnetometers 3-Axis I2C Interface"
+       depends on I2C && IIO_ST_MAGN_3AXIS
+       default I2C && IIO_ST_MAGN_3AXIS
+       select IIO_ST_SENSORS_I2C
+       help
+         Build support for STMicroelectronics magnetometers I2C interface.
+
+         To compile this driver as a module, choose M here. The module
+         will be called st_magn_i2c.
 
 config IIO_ST_MAGN_SPI_3AXIS
-       tristate
-       depends on IIO_ST_MAGN_3AXIS
-       depends on IIO_ST_SENSORS_SPI
+       tristate "STMicroelectronics magnetometers 3-Axis SPI Interface"
+       depends on SPI_MASTER && IIO_ST_MAGN_3AXIS
+       default SPI_MASTER && IIO_ST_MAGN_3AXIS
+       select IIO_ST_SENSORS_SPI
+       help
+         Build support for STMicroelectronics magnetometers SPI interface.
+
+         To compile this driver as a module, choose M here. The module
+         will be called st_magn_spi.
 
 config SENSORS_HMC5843
        tristate
index 55879a20ae52eeb000f6c59d01b5c18ad2606a35..088f748b683ebbca7bd088e063ba4cb6c5c035d7 100644 (file)
@@ -1033,7 +1033,6 @@ static int ak8975_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
 static int ak8975_runtime_suspend(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
@@ -1074,14 +1073,9 @@ static int ak8975_runtime_resume(struct device *dev)
 
        return 0;
 }
-#endif /* CONFIG_PM */
 
-static const struct dev_pm_ops ak8975_dev_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-                               pm_runtime_force_resume)
-       SET_RUNTIME_PM_OPS(ak8975_runtime_suspend,
-                          ak8975_runtime_resume, NULL)
-};
+static DEFINE_RUNTIME_DEV_PM_OPS(ak8975_dev_pm_ops, ak8975_runtime_suspend,
+                                ak8975_runtime_resume, NULL);
 
 static const struct i2c_device_id ak8975_id[] = {
        {"ak8975", AK8975},
@@ -1113,7 +1107,7 @@ MODULE_DEVICE_TABLE(of, ak8975_of_match);
 static struct i2c_driver ak8975_driver = {
        .driver = {
                .name   = "ak8975",
-               .pm = &ak8975_dev_pm_ops,
+               .pm = pm_ptr(&ak8975_dev_pm_ops),
                .of_match_table = ak8975_of_match,
                .acpi_match_table = ak_acpi_match,
        },
index 3d4d21f979fab0ffcd570f7b503656bd39e8235d..64e8b04e654b8c93205e6a719c4f0074fbbfec48 100644 (file)
@@ -226,7 +226,7 @@ const struct regmap_config bmc150_magn_regmap_config = {
        .writeable_reg = bmc150_magn_is_writeable_reg,
        .volatile_reg = bmc150_magn_is_volatile_reg,
 };
-EXPORT_SYMBOL(bmc150_magn_regmap_config);
+EXPORT_SYMBOL_NS(bmc150_magn_regmap_config, IIO_BMC150_MAGN);
 
 static int bmc150_magn_set_power_mode(struct bmc150_magn_data *data,
                                      enum bmc150_magn_power_modes mode,
@@ -983,7 +983,7 @@ err_poweroff:
        bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, true);
        return ret;
 }
-EXPORT_SYMBOL(bmc150_magn_probe);
+EXPORT_SYMBOL_NS(bmc150_magn_probe, IIO_BMC150_MAGN);
 
 int bmc150_magn_remove(struct device *dev)
 {
@@ -1010,7 +1010,7 @@ int bmc150_magn_remove(struct device *dev)
        regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
        return 0;
 }
-EXPORT_SYMBOL(bmc150_magn_remove);
+EXPORT_SYMBOL_NS(bmc150_magn_remove, IIO_BMC150_MAGN);
 
 #ifdef CONFIG_PM
 static int bmc150_magn_runtime_suspend(struct device *dev)
@@ -1078,7 +1078,7 @@ const struct dev_pm_ops bmc150_magn_pm_ops = {
        SET_RUNTIME_PM_OPS(bmc150_magn_runtime_suspend,
                           bmc150_magn_runtime_resume, NULL)
 };
-EXPORT_SYMBOL(bmc150_magn_pm_ops);
+EXPORT_SYMBOL_NS(bmc150_magn_pm_ops, IIO_BMC150_MAGN);
 
 MODULE_AUTHOR("Irina Tirdea <[email protected]>");
 MODULE_LICENSE("GPL v2");
index 876e96005e33dc9aa42bee47fdd50138d6cd450a..e39b89661ad1a5869fea715734f14e7df9b61562 100644 (file)
@@ -80,3 +80,4 @@ module_i2c_driver(bmc150_magn_driver);
 MODULE_AUTHOR("Daniel Baluta <[email protected]");
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("BMC150 I2C magnetometer driver");
+MODULE_IMPORT_NS(IIO_BMC150_MAGN);
index c6ed3ea8460ae42156b094f71fbe69fe7a9e7426..0db363ffc462f85a08046df7b08cfddc0b3ee225 100644 (file)
@@ -66,3 +66,4 @@ module_spi_driver(bmc150_magn_spi_driver);
 MODULE_AUTHOR("Daniel Baluta <[email protected]");
 MODULE_DESCRIPTION("BMC150 magnetometer SPI driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_BMC150_MAGN);
index 5a730d9bdbb088a1f4d42e3651dbdb7fa4e3e4ff..92eb2d156ddba6d01bdd3526e4a3fad7974630e1 100644 (file)
@@ -608,14 +608,14 @@ int hmc5843_common_suspend(struct device *dev)
        return hmc5843_set_mode(iio_priv(dev_get_drvdata(dev)),
                                HMC5843_MODE_SLEEP);
 }
-EXPORT_SYMBOL(hmc5843_common_suspend);
+EXPORT_SYMBOL_NS(hmc5843_common_suspend, IIO_HMC5843);
 
 int hmc5843_common_resume(struct device *dev)
 {
        return hmc5843_set_mode(iio_priv(dev_get_drvdata(dev)),
                HMC5843_MODE_CONVERSION_CONTINUOUS);
 }
-EXPORT_SYMBOL(hmc5843_common_resume);
+EXPORT_SYMBOL_NS(hmc5843_common_resume, IIO_HMC5843);
 
 int hmc5843_common_probe(struct device *dev, struct regmap *regmap,
                         enum hmc5843_ids id, const char *name)
@@ -669,7 +669,7 @@ buffer_setup_err:
        hmc5843_set_mode(iio_priv(indio_dev), HMC5843_MODE_SLEEP);
        return ret;
 }
-EXPORT_SYMBOL(hmc5843_common_probe);
+EXPORT_SYMBOL_NS(hmc5843_common_probe, IIO_HMC5843);
 
 void hmc5843_common_remove(struct device *dev)
 {
@@ -681,7 +681,7 @@ void hmc5843_common_remove(struct device *dev)
        /*  sleep mode to save power */
        hmc5843_set_mode(iio_priv(indio_dev), HMC5843_MODE_SLEEP);
 }
-EXPORT_SYMBOL(hmc5843_common_remove);
+EXPORT_SYMBOL_NS(hmc5843_common_remove, IIO_HMC5843);
 
 MODULE_AUTHOR("Shubhrajyoti Datta <[email protected]>");
 MODULE_DESCRIPTION("HMC5843/5883/5883L/5983 core driver");
index bc6e12f1d5213d289537307ef2385a632e4b7630..8d2ff8fc204de9e150ab8a38eaa1914c3c5fdd27 100644 (file)
@@ -105,3 +105,4 @@ module_i2c_driver(hmc5843_driver);
 MODULE_AUTHOR("Josef Gajdusek <[email protected]>");
 MODULE_DESCRIPTION("HMC5843/5883/5883L/5983 i2c driver");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_HMC5843);
index 89cf59a62c289d2294c0cf5ec387bad7de3e0a8e..f2a8e98d8eb579a0a5e0d3dedd2c2a09606fdf23 100644 (file)
@@ -102,3 +102,4 @@ module_spi_driver(hmc5843_driver);
 MODULE_AUTHOR("Josef Gajdusek <[email protected]>");
 MODULE_DESCRIPTION("HMC5983 SPI driver");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_HMC5843);
index 17c62d806218d30c4677c8f1de502dbabc490539..226439d0bfb505b4ffc368fbd25bec19cbb7a9d9 100644 (file)
@@ -573,7 +573,6 @@ static int mag3110_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int mag3110_suspend(struct device *dev)
 {
        struct mag3110_data *data = iio_priv(i2c_get_clientdata(
@@ -623,11 +622,8 @@ static int mag3110_resume(struct device *dev)
                data->ctrl_reg1);
 }
 
-static SIMPLE_DEV_PM_OPS(mag3110_pm_ops, mag3110_suspend, mag3110_resume);
-#define MAG3110_PM_OPS (&mag3110_pm_ops)
-#else
-#define MAG3110_PM_OPS NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(mag3110_pm_ops, mag3110_suspend,
+                               mag3110_resume);
 
 static const struct i2c_device_id mag3110_id[] = {
        { "mag3110", 0 },
@@ -645,7 +641,7 @@ static struct i2c_driver mag3110_driver = {
        .driver = {
                .name   = "mag3110",
                .of_match_table = mag3110_of_match,
-               .pm     = MAG3110_PM_OPS,
+               .pm     = pm_sleep_ptr(&mag3110_pm_ops),
        },
        .probe = mag3110_probe,
        .remove = mag3110_remove,
index 65f3d1ed0d597fb1c16bb1289ebc1dbb185d1d22..186edfcda0b70be56ccfa07abfe3663cc8e584e3 100644 (file)
@@ -521,7 +521,6 @@ static int mmc35240_probe(struct i2c_client *client,
        return devm_iio_device_register(&client->dev, indio_dev);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int mmc35240_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
@@ -548,11 +547,9 @@ static int mmc35240_resume(struct device *dev)
 
        return 0;
 }
-#endif
 
-static const struct dev_pm_ops mmc35240_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(mmc35240_suspend, mmc35240_resume)
-};
+static DEFINE_SIMPLE_DEV_PM_OPS(mmc35240_pm_ops, mmc35240_suspend,
+                               mmc35240_resume);
 
 static const struct of_device_id mmc35240_of_match[] = {
        { .compatible = "memsic,mmc35240", },
@@ -576,7 +573,7 @@ static struct i2c_driver mmc35240_driver = {
        .driver = {
                .name = MMC35240_DRV_NAME,
                .of_match_table = mmc35240_of_match,
-               .pm = &mmc35240_pm_ops,
+               .pm = pm_sleep_ptr(&mmc35240_pm_ops),
                .acpi_match_table = ACPI_PTR(mmc35240_acpi_match),
        },
        .probe          = mmc35240_probe,
index 13914273c9992ebd70269ac99c95850446ddf66f..26195733ea3e0bcf29ff33bad6a561b64fe7f7fc 100644 (file)
@@ -100,7 +100,7 @@ const struct regmap_access_table rm3100_readable_table = {
        .yes_ranges = rm3100_readable_ranges,
        .n_yes_ranges = ARRAY_SIZE(rm3100_readable_ranges),
 };
-EXPORT_SYMBOL_GPL(rm3100_readable_table);
+EXPORT_SYMBOL_NS_GPL(rm3100_readable_table, IIO_RM3100);
 
 static const struct regmap_range rm3100_writable_ranges[] = {
        regmap_reg_range(RM3100_W_REG_START, RM3100_W_REG_END),
@@ -110,7 +110,7 @@ const struct regmap_access_table rm3100_writable_table = {
        .yes_ranges = rm3100_writable_ranges,
        .n_yes_ranges = ARRAY_SIZE(rm3100_writable_ranges),
 };
-EXPORT_SYMBOL_GPL(rm3100_writable_table);
+EXPORT_SYMBOL_NS_GPL(rm3100_writable_table, IIO_RM3100);
 
 static const struct regmap_range rm3100_volatile_ranges[] = {
        regmap_reg_range(RM3100_V_REG_START, RM3100_V_REG_END),
@@ -120,7 +120,7 @@ const struct regmap_access_table rm3100_volatile_table = {
        .yes_ranges = rm3100_volatile_ranges,
        .n_yes_ranges = ARRAY_SIZE(rm3100_volatile_ranges),
 };
-EXPORT_SYMBOL_GPL(rm3100_volatile_table);
+EXPORT_SYMBOL_NS_GPL(rm3100_volatile_table, IIO_RM3100);
 
 static irqreturn_t rm3100_thread_fn(int irq, void *d)
 {
@@ -607,7 +607,7 @@ int rm3100_common_probe(struct device *dev, struct regmap *regmap, int irq)
 
        return devm_iio_device_register(dev, indio_dev);
 }
-EXPORT_SYMBOL_GPL(rm3100_common_probe);
+EXPORT_SYMBOL_NS_GPL(rm3100_common_probe, IIO_RM3100);
 
 MODULE_AUTHOR("Song Qiang <[email protected]>");
 MODULE_DESCRIPTION("PNI RM3100 3-axis magnetometer i2c driver");
index 1ac622c6d6c97a97fce710fda17a629c3b0e4e78..ba669ab7113dbe011c8e02810c67fbd67aa0c0dc 100644 (file)
@@ -52,3 +52,4 @@ module_i2c_driver(rm3100_driver);
 MODULE_AUTHOR("Song Qiang <[email protected]>");
 MODULE_DESCRIPTION("PNI RM3100 3-axis magnetometer i2c driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_RM3100);
index 65d5eb9e4f5e73c6a7f704a1e524bb7e14de434d..76dc9b66cd3c5233acd6df099b39f6efcc1fd501 100644 (file)
@@ -62,3 +62,4 @@ module_spi_driver(rm3100_driver);
 MODULE_AUTHOR("Song Qiang <[email protected]>");
 MODULE_DESCRIPTION("PNI RM3100 3-axis magnetometer spi driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_RM3100);
index cb43ccda808ddd748d45f6190c9ffd3d645049e9..79987f42e8d9e796c3bd426a9258b46246fa653f 100644 (file)
@@ -7,7 +7,6 @@
  * Denis Ciocca <[email protected]>
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/buffer.h>
@@ -45,6 +44,3 @@ int st_magn_allocate_ring(struct iio_dev *indio_dev)
                NULL, &st_sensors_trigger_handler, &st_magn_buffer_setup_ops);
 }
 
-MODULE_AUTHOR("Denis Ciocca <[email protected]>");
-MODULE_DESCRIPTION("STMicroelectronics magnetometers buffer");
-MODULE_LICENSE("GPL v2");
index 0806a1e65ce4d8eee15341212e6fb1777e9b63ee..74435f4a427db247c39f6fb9f0d8a10226f7148d 100644 (file)
@@ -606,7 +606,7 @@ const struct st_sensor_settings *st_magn_get_settings(const char *name)
 
        return &st_magn_sensors_settings[index];
 }
-EXPORT_SYMBOL(st_magn_get_settings);
+EXPORT_SYMBOL_NS(st_magn_get_settings, IIO_ST_SENSORS);
 
 int st_magn_common_probe(struct iio_dev *indio_dev)
 {
@@ -653,8 +653,9 @@ int st_magn_common_probe(struct iio_dev *indio_dev)
 
        return devm_iio_device_register(parent, indio_dev);
 }
-EXPORT_SYMBOL(st_magn_common_probe);
+EXPORT_SYMBOL_NS(st_magn_common_probe, IIO_ST_SENSORS);
 
 MODULE_AUTHOR("Denis Ciocca <[email protected]>");
 MODULE_DESCRIPTION("STMicroelectronics magnetometers driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ST_SENSORS);
index 7237711fc09b35cf49045e4929a6191dc1f5cf1d..c5d8c303db4ef46ecd555e3c4f99eb79a2a8b143 100644 (file)
@@ -115,3 +115,4 @@ module_i2c_driver(st_magn_driver);
 MODULE_AUTHOR("Denis Ciocca <[email protected]>");
 MODULE_DESCRIPTION("STMicroelectronics magnetometers i2c driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ST_SENSORS);
index 489d4462862f8ea58c7ebb69012472b427e9d08c..6ddc4318564a4bcfeacad30c92a756d87f4f26e4 100644 (file)
@@ -106,3 +106,4 @@ module_spi_driver(st_magn_driver);
 MODULE_AUTHOR("Denis Ciocca <[email protected]>");
 MODULE_DESCRIPTION("STMicroelectronics magnetometers spi driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ST_SENSORS);
index 832df8da2bc6639b5ccd02f4fb8be7afbc2e4c43..01dd3f858d99cb78df9b5dadbaa2b1bf53125cf6 100644 (file)
@@ -27,11 +27,11 @@ config AD5272
          module will be called ad5272.
 
 config DS1803
-       tristate "Maxim Integrated DS1803 Digital Potentiometer driver"
+       tristate "Maxim Integrated DS1803 and similar Digital Potentiometer driver"
        depends on I2C
        help
-         Say yes here to build support for the Maxim Integrated DS1803
-         digital potentiometer chip.
+         Say yes here to build support for the Maxim Integrated DS1803 and
+         DS3502 digital potentiometer chip.
 
          To compile this driver as a module, choose M here: the
          module will be called ds1803.
index 20b45407eaaca3dc8762dd3fd39381ed08b61dc5..5c212ed7a93133de40c129e9f766b4c4eb490aa6 100644 (file)
@@ -1,12 +1,15 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Maxim Integrated DS1803 digital potentiometer driver
+ * Maxim Integrated DS1803 and similar digital potentiometer driver
  * Copyright (c) 2016 Slawomir Stepien
+ * Copyright (c) 2022 Jagath Jog J
  *
  * Datasheet: https://datasheets.maximintegrated.com/en/ds/DS1803.pdf
+ * Datasheet: https://datasheets.maximintegrated.com/en/ds/DS3502.pdf
  *
  * DEVID       #Wipers #Positions      Resistor Opts (kOhm)    i2c address
  * ds1803      2       256             10, 50, 100             0101xxx
+ * ds3502      1       128             10                      01010xx
  */
 
 #include <linux/err.h>
 #include <linux/iio/iio.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
+#include <linux/property.h>
 
-#define DS1803_MAX_POS         255
-#define DS1803_WRITE(chan)     (0xa8 | ((chan) + 1))
+#define DS1803_WIPER_0         0xA9
+#define DS1803_WIPER_1         0xAA
+#define DS3502_WR_IVR          0x00
 
 enum ds1803_type {
        DS1803_010,
        DS1803_050,
        DS1803_100,
+       DS3502,
 };
 
 struct ds1803_cfg {
+       int wipers;
+       int avail[3];
        int kohms;
-};
-
-static const struct ds1803_cfg ds1803_cfg[] = {
-       [DS1803_010] = { .kohms =  10, },
-       [DS1803_050] = { .kohms =  50, },
-       [DS1803_100] = { .kohms = 100, },
+       const struct iio_chan_spec *channels;
+       u8 num_channels;
+       int (*read)(struct iio_dev *indio_dev,
+                   struct iio_chan_spec const *chan, int *val);
 };
 
 struct ds1803_data {
@@ -40,42 +46,110 @@ struct ds1803_data {
        const struct ds1803_cfg *cfg;
 };
 
-#define DS1803_CHANNEL(ch) {                                   \
-       .type = IIO_RESISTANCE,                                 \
-       .indexed = 1,                                           \
-       .output = 1,                                            \
-       .channel = (ch),                                        \
-       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),           \
-       .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),   \
+#define DS1803_CHANNEL(ch, addr) {                                     \
+       .type = IIO_RESISTANCE,                                         \
+       .indexed = 1,                                                   \
+       .output = 1,                                                    \
+       .channel = (ch),                                                \
+       .address = (addr),                                              \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),                   \
+       .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),           \
+       .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_RAW),   \
 }
 
 static const struct iio_chan_spec ds1803_channels[] = {
-       DS1803_CHANNEL(0),
-       DS1803_CHANNEL(1),
+       DS1803_CHANNEL(0, DS1803_WIPER_0),
+       DS1803_CHANNEL(1, DS1803_WIPER_1),
 };
 
-static int ds1803_read_raw(struct iio_dev *indio_dev,
-                           struct iio_chan_spec const *chan,
-                           int *val, int *val2, long mask)
+static const struct iio_chan_spec ds3502_channels[] = {
+       DS1803_CHANNEL(0, DS3502_WR_IVR),
+};
+
+static int ds1803_read(struct iio_dev *indio_dev,
+                      struct iio_chan_spec const *chan,
+                      int *val)
 {
        struct ds1803_data *data = iio_priv(indio_dev);
-       int pot = chan->channel;
        int ret;
        u8 result[ARRAY_SIZE(ds1803_channels)];
 
+       ret = i2c_master_recv(data->client, result, indio_dev->num_channels);
+       if (ret < 0)
+               return ret;
+
+       *val = result[chan->channel];
+       return ret;
+}
+
+static int ds3502_read(struct iio_dev *indio_dev,
+                      struct iio_chan_spec const *chan,
+                      int *val)
+{
+       struct ds1803_data *data = iio_priv(indio_dev);
+       int ret;
+
+       ret = i2c_smbus_read_byte_data(data->client, chan->address);
+       if (ret < 0)
+               return ret;
+
+       *val = ret;
+       return ret;
+}
+
+static const struct ds1803_cfg ds1803_cfg[] = {
+       [DS1803_010] = {
+               .wipers = 2,
+               .avail = { 0, 1, 255 },
+               .kohms =  10,
+               .channels = ds1803_channels,
+               .num_channels = ARRAY_SIZE(ds1803_channels),
+               .read = ds1803_read,
+       },
+       [DS1803_050] = {
+               .wipers = 2,
+               .avail = { 0, 1, 255 },
+               .kohms =  50,
+               .channels = ds1803_channels,
+               .num_channels = ARRAY_SIZE(ds1803_channels),
+               .read = ds1803_read,
+       },
+       [DS1803_100] = {
+               .wipers = 2,
+               .avail = { 0, 1, 255 },
+               .kohms = 100,
+               .channels = ds1803_channels,
+               .num_channels = ARRAY_SIZE(ds1803_channels),
+               .read = ds1803_read,
+       },
+       [DS3502] = {
+         .wipers = 1,
+         .avail = { 0, 1, 127 },
+         .kohms =  10,
+         .channels = ds3502_channels,
+         .num_channels = ARRAY_SIZE(ds3502_channels),
+         .read = ds3502_read,
+       },
+};
+
+static int ds1803_read_raw(struct iio_dev *indio_dev,
+                          struct iio_chan_spec const *chan,
+                          int *val, int *val2, long mask)
+{
+       struct ds1803_data *data = iio_priv(indio_dev);
+       int ret;
+
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
-               ret = i2c_master_recv(data->client, result,
-                               indio_dev->num_channels);
+               ret = data->cfg->read(indio_dev, chan, val);
                if (ret < 0)
                        return ret;
 
-               *val = result[pot];
                return IIO_VAL_INT;
 
        case IIO_CHAN_INFO_SCALE:
                *val = 1000 * data->cfg->kohms;
-               *val2 = DS1803_MAX_POS;
+               *val2 = data->cfg->avail[2]; /* Max wiper position */
                return IIO_VAL_FRACTIONAL;
        }
 
@@ -83,34 +157,52 @@ static int ds1803_read_raw(struct iio_dev *indio_dev,
 }
 
 static int ds1803_write_raw(struct iio_dev *indio_dev,
-                            struct iio_chan_spec const *chan,
-                            int val, int val2, long mask)
+                           struct iio_chan_spec const *chan,
+                           int val, int val2, long mask)
 {
        struct ds1803_data *data = iio_priv(indio_dev);
-       int pot = chan->channel;
+       u8 addr = chan->address;
+       int max_pos = data->cfg->avail[2];
 
        if (val2 != 0)
                return -EINVAL;
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
-               if (val > DS1803_MAX_POS || val < 0)
+               if (val > max_pos || val < 0)
                        return -EINVAL;
                break;
        default:
                return -EINVAL;
        }
 
-       return i2c_smbus_write_byte_data(data->client, DS1803_WRITE(pot), val);
+       return i2c_smbus_write_byte_data(data->client, addr, val);
+}
+
+static int ds1803_read_avail(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            const int **vals, int *type,
+                            int *length, long mask)
+{
+       struct ds1803_data *data = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               *vals = data->cfg->avail;
+               *length = ARRAY_SIZE(data->cfg->avail);
+               *type = IIO_VAL_INT;
+               return IIO_AVAIL_RANGE;
+       }
+       return -EINVAL;
 }
 
 static const struct iio_info ds1803_info = {
        .read_raw = ds1803_read_raw,
        .write_raw = ds1803_write_raw,
+       .read_avail = ds1803_read_avail,
 };
 
-static int ds1803_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int ds1803_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
        struct device *dev = &client->dev;
        struct ds1803_data *data;
@@ -124,11 +216,13 @@ static int ds1803_probe(struct i2c_client *client,
 
        data = iio_priv(indio_dev);
        data->client = client;
-       data->cfg = &ds1803_cfg[id->driver_data];
+       data->cfg = device_get_match_data(dev);
+       if (!data->cfg)
+               data->cfg = &ds1803_cfg[id->driver_data];
 
        indio_dev->info = &ds1803_info;
-       indio_dev->channels = ds1803_channels;
-       indio_dev->num_channels = ARRAY_SIZE(ds1803_channels);
+       indio_dev->channels = data->cfg->channels;
+       indio_dev->num_channels = data->cfg->num_channels;
        indio_dev->name = client->name;
 
        return devm_iio_device_register(dev, indio_dev);
@@ -138,6 +232,7 @@ static const struct of_device_id ds1803_dt_ids[] = {
        { .compatible = "maxim,ds1803-010", .data = &ds1803_cfg[DS1803_010] },
        { .compatible = "maxim,ds1803-050", .data = &ds1803_cfg[DS1803_050] },
        { .compatible = "maxim,ds1803-100", .data = &ds1803_cfg[DS1803_100] },
+       { .compatible = "maxim,ds3502", .data = &ds1803_cfg[DS3502] },
        {}
 };
 MODULE_DEVICE_TABLE(of, ds1803_dt_ids);
@@ -146,6 +241,7 @@ static const struct i2c_device_id ds1803_id[] = {
        { "ds1803-010", DS1803_010 },
        { "ds1803-050", DS1803_050 },
        { "ds1803-100", DS1803_100 },
+       { "ds3502", DS3502 },
        {}
 };
 MODULE_DEVICE_TABLE(i2c, ds1803_id);
@@ -162,5 +258,6 @@ static struct i2c_driver ds1803_driver = {
 module_i2c_driver(ds1803_driver);
 
 MODULE_AUTHOR("Slawomir Stepien <[email protected]>");
+MODULE_AUTHOR("Jagath Jog J <[email protected]>");
 MODULE_DESCRIPTION("DS1803 digital potentiometer");
 MODULE_LICENSE("GPL v2");
index fc0d3cfca4186bd9a32130dfb6bbad6b275679f0..0ff756cea63ab63d38d5d8d91e537fee00b384c9 100644 (file)
@@ -194,30 +194,35 @@ config IIO_ST_PRESS
        tristate "STMicroelectronics pressure sensor Driver"
        depends on (I2C || SPI_MASTER) && SYSFS
        select IIO_ST_SENSORS_CORE
-       select IIO_ST_PRESS_I2C if (I2C)
-       select IIO_ST_PRESS_SPI if (SPI_MASTER)
        select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
        help
          Say yes here to build support for STMicroelectronics pressure
          sensors: LPS001WP, LPS25H, LPS331AP, LPS22HB, LPS22HH.
 
-         This driver can also be built as a module. If so, these modules
-         will be created:
-         - st_pressure (core functions for the driver [it is mandatory]);
-         - st_pressure_i2c (necessary for the I2C devices [optional*]);
-         - st_pressure_spi (necessary for the SPI devices [optional*]);
-
-         (*) one of these is necessary to do something.
+         Also need to enable at least one of I2C and SPI interface drivers
+         below.
 
 config IIO_ST_PRESS_I2C
-       tristate
-       depends on IIO_ST_PRESS
-       depends on IIO_ST_SENSORS_I2C
+       tristate "STMicroelectronics pressure sensor I2C Interface"
+       depends on I2C && IIO_ST_PRESS
+       default I2C && IIO_ST_PRESS
+       select IIO_ST_SENSORS_I2C
+       help
+         Build support for STMicroelectronics pressure sensor I2C interface.
+
+         To compile this driver as a module, choose M here. The module
+         will be called st_pressure_i2c.
 
 config IIO_ST_PRESS_SPI
-       tristate
-       depends on IIO_ST_PRESS
-       depends on IIO_ST_SENSORS_SPI
+       tristate "STMicroelectronics pressure sensor SPI Interface"
+       depends on SPI_MASTER && IIO_ST_PRESS
+       default SPI_MASTER && IIO_ST_PRESS
+       select IIO_ST_SENSORS_SPI
+       help
+         Build support for STMicroelectronics pressure sensor SPI interface.
+
+         To compile this driver as a module, choose M here. The module
+         will be called st_pressure_spi.
 
 config T5403
        tristate "EPCOS T5403 digital barometric pressure sensor driver"
index 0730380ceb692e92d8d109972ff2ccfc097b4adf..36fb7ae0d0a9d99f81aaea6cf53f06a31c1ab16a 100644 (file)
@@ -812,9 +812,16 @@ static const struct i2c_device_id dps310_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, dps310_id);
 
+static const struct acpi_device_id dps310_acpi_match[] = {
+       { "IFX3100" },
+       {}
+};
+MODULE_DEVICE_TABLE(acpi, dps310_acpi_match);
+
 static struct i2c_driver dps310_driver = {
        .driver = {
                .name = DPS310_DEV_NAME,
+               .acpi_match_table = dps310_acpi_match,
        },
        .probe = dps310_probe,
        .id_table = dps310_id,
index 81f288312a28ded53b3ee5cca0534854df83fdfc..5bf5b9abe6f1a4e6161da0978fdf92ebf545ee96 100644 (file)
@@ -187,7 +187,7 @@ int mpl115_probe(struct device *dev, const char *name,
 
        return devm_iio_device_register(dev, indio_dev);
 }
-EXPORT_SYMBOL_GPL(mpl115_probe);
+EXPORT_SYMBOL_NS_GPL(mpl115_probe, IIO_MPL115);
 
 MODULE_AUTHOR("Peter Meerwald <[email protected]>");
 MODULE_DESCRIPTION("Freescale MPL115 pressure/temperature driver");
index ac1f12bcb65e9f9da21f8fd179198badaed97503..099ab1c6832c5d2b0a4039d7ee720925b497ac33 100644 (file)
@@ -62,3 +62,4 @@ module_i2c_driver(mpl115_i2c_driver);
 MODULE_AUTHOR("Peter Meerwald <[email protected]>");
 MODULE_DESCRIPTION("Freescale MPL115A2 pressure/temperature driver");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_MPL115);
index 4d064f98f56a18c3f3e92d5d70e5e817bd6be5ba..7feec87e2704ef590000be5c24061f8113d46311 100644 (file)
@@ -101,3 +101,4 @@ module_spi_driver(mpl115_spi_driver);
 MODULE_AUTHOR("Akinobu Mita <[email protected]>");
 MODULE_DESCRIPTION("Freescale MPL115A1 pressure/temperature driver");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_MPL115);
index e95b9a5475b4ef616cd123eb68a3992472cc547f..d4f89e4babed4d9ac103efce6364171ae8d5f4ac 100644 (file)
@@ -301,7 +301,6 @@ static int mpl3115_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int mpl3115_suspend(struct device *dev)
 {
        return mpl3115_standby(iio_priv(i2c_get_clientdata(
@@ -317,11 +316,8 @@ static int mpl3115_resume(struct device *dev)
                data->ctrl_reg1);
 }
 
-static SIMPLE_DEV_PM_OPS(mpl3115_pm_ops, mpl3115_suspend, mpl3115_resume);
-#define MPL3115_PM_OPS (&mpl3115_pm_ops)
-#else
-#define MPL3115_PM_OPS NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(mpl3115_pm_ops, mpl3115_suspend,
+                               mpl3115_resume);
 
 static const struct i2c_device_id mpl3115_id[] = {
        { "mpl3115", 0 },
@@ -339,7 +335,7 @@ static struct i2c_driver mpl3115_driver = {
        .driver = {
                .name   = "mpl3115",
                .of_match_table = mpl3115_of_match,
-               .pm     = MPL3115_PM_OPS,
+               .pm     = pm_sleep_ptr(&mpl3115_pm_ops),
        },
        .probe = mpl3115_probe,
        .remove = mpl3115_remove,
index a4d0b54cde9b1be5ec91b88b91338c5365f01a37..717521de66c47a4071f6c34799d44c20b901a079 100644 (file)
@@ -471,7 +471,7 @@ err_fini:
        ms5611_fini(indio_dev);
        return ret;
 }
-EXPORT_SYMBOL(ms5611_probe);
+EXPORT_SYMBOL_NS(ms5611_probe, IIO_MS5611);
 
 void ms5611_remove(struct iio_dev *indio_dev)
 {
@@ -479,7 +479,7 @@ void ms5611_remove(struct iio_dev *indio_dev)
        iio_triggered_buffer_cleanup(indio_dev);
        ms5611_fini(indio_dev);
 }
-EXPORT_SYMBOL(ms5611_remove);
+EXPORT_SYMBOL_NS(ms5611_remove, IIO_MS5611);
 
 MODULE_AUTHOR("Tomasz Duszynski <[email protected]>");
 MODULE_DESCRIPTION("MS5611 core driver");
index 1047a85527a998b420b0362f830a1aee881ae806..3b1de71e0d15cfdd89074ae628d0ac23e0a25b2d 100644 (file)
@@ -140,3 +140,4 @@ module_i2c_driver(ms5611_driver);
 MODULE_AUTHOR("Tomasz Duszynski <[email protected]>");
 MODULE_DESCRIPTION("MS5611 i2c driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_MS5611);
index 9fa2dcd71760bff2b8084589ef6baaa86c8e2e5d..281b0839872025146a683207442f33953ce41e93 100644 (file)
@@ -142,3 +142,4 @@ module_spi_driver(ms5611_driver);
 MODULE_AUTHOR("Tomasz Duszynski <[email protected]>");
 MODULE_DESCRIPTION("MS5611 spi driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_MS5611);
index 81f683321b23182b4a647128116fab29239392a2..70c70019142ae1badc73f6cc37d3d92c19ff7164 100644 (file)
@@ -252,3 +252,4 @@ MODULE_DESCRIPTION("Measurement-Specialties ms5637 temperature & pressure driver
 MODULE_AUTHOR("William Markezana <[email protected]>");
 MODULE_AUTHOR("Ludovic Tancerel <[email protected]>");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_MEAS_SPEC_SENSORS);
index 25dbd5476b2643fb5806cf3da2ebdd3646f113e6..0dbf357c2c22b9e04247f477b56f08492fceb890 100644 (file)
@@ -7,7 +7,6 @@
  * Denis Ciocca <[email protected]>
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/buffer.h>
@@ -44,7 +43,3 @@ int st_press_allocate_ring(struct iio_dev *indio_dev)
        return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev,
                NULL, &st_sensors_trigger_handler, &st_press_buffer_setup_ops);
 }
-
-MODULE_AUTHOR("Denis Ciocca <[email protected]>");
-MODULE_DESCRIPTION("STMicroelectronics pressures buffer");
-MODULE_LICENSE("GPL v2");
index 26a1ee43d56e71d713d654b26134f8b99949490e..5b93933a2e27154bca3e03220b65a54f52e680f6 100644 (file)
@@ -672,7 +672,7 @@ const struct st_sensor_settings *st_press_get_settings(const char *name)
 
        return &st_press_sensors_settings[index];
 }
-EXPORT_SYMBOL(st_press_get_settings);
+EXPORT_SYMBOL_NS(st_press_get_settings, IIO_ST_SENSORS);
 
 int st_press_common_probe(struct iio_dev *indio_dev)
 {
@@ -724,8 +724,9 @@ int st_press_common_probe(struct iio_dev *indio_dev)
 
        return devm_iio_device_register(parent, indio_dev);
 }
-EXPORT_SYMBOL(st_press_common_probe);
+EXPORT_SYMBOL_NS(st_press_common_probe, IIO_ST_SENSORS);
 
 MODULE_AUTHOR("Denis Ciocca <[email protected]>");
 MODULE_DESCRIPTION("STMicroelectronics pressures driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ST_SENSORS);
index 1939e999a427dca0f892d84887183e4f93f7428b..7035777fd9887342249ee76336de4f0fac0a9a5e 100644 (file)
@@ -120,3 +120,4 @@ module_i2c_driver(st_press_driver);
 MODULE_AUTHOR("Denis Ciocca <[email protected]>");
 MODULE_DESCRIPTION("STMicroelectronics pressures i2c driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ST_SENSORS);
index d6fc954e28f8ba49da784da4d058a8bc009ad81f..bfab8e7fb0619acd80e4fcf3ddeadc7c8a3a270b 100644 (file)
@@ -118,3 +118,4 @@ module_spi_driver(st_press_driver);
 MODULE_AUTHOR("Denis Ciocca <[email protected]>");
 MODULE_DESCRIPTION("STMicroelectronics pressures spi driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ST_SENSORS);
index 89295c90f8018e5ba2163a2ba24b0182f4f3d026..67119a9b95fcc375df342b7813581e61077999b5 100644 (file)
@@ -162,7 +162,7 @@ bool zpa2326_isreg_writeable(struct device *dev, unsigned int reg)
                return false;
        }
 }
-EXPORT_SYMBOL_GPL(zpa2326_isreg_writeable);
+EXPORT_SYMBOL_NS_GPL(zpa2326_isreg_writeable, IIO_ZPA2326);
 
 bool zpa2326_isreg_readable(struct device *dev, unsigned int reg)
 {
@@ -191,7 +191,7 @@ bool zpa2326_isreg_readable(struct device *dev, unsigned int reg)
                return false;
        }
 }
-EXPORT_SYMBOL_GPL(zpa2326_isreg_readable);
+EXPORT_SYMBOL_NS_GPL(zpa2326_isreg_readable, IIO_ZPA2326);
 
 bool zpa2326_isreg_precious(struct device *dev, unsigned int reg)
 {
@@ -204,7 +204,7 @@ bool zpa2326_isreg_precious(struct device *dev, unsigned int reg)
                return false;
        }
 }
-EXPORT_SYMBOL_GPL(zpa2326_isreg_precious);
+EXPORT_SYMBOL_NS_GPL(zpa2326_isreg_precious, IIO_ZPA2326);
 
 /**
  * zpa2326_enable_device() - Enable device, i.e. get out of low power mode.
@@ -649,7 +649,7 @@ const struct dev_pm_ops zpa2326_pm_ops = {
        SET_RUNTIME_PM_OPS(zpa2326_runtime_suspend, zpa2326_runtime_resume,
                           NULL)
 };
-EXPORT_SYMBOL_GPL(zpa2326_pm_ops);
+EXPORT_SYMBOL_NS_GPL(zpa2326_pm_ops, IIO_ZPA2326);
 
 /**
  * zpa2326_resume() - Request the PM layer to power supply the device.
@@ -1698,7 +1698,7 @@ poweroff:
 
        return err;
 }
-EXPORT_SYMBOL_GPL(zpa2326_probe);
+EXPORT_SYMBOL_NS_GPL(zpa2326_probe, IIO_ZPA2326);
 
 void zpa2326_remove(const struct device *parent)
 {
@@ -1709,7 +1709,7 @@ void zpa2326_remove(const struct device *parent)
        zpa2326_sleep(indio_dev);
        zpa2326_power_off(indio_dev, iio_priv(indio_dev));
 }
-EXPORT_SYMBOL_GPL(zpa2326_remove);
+EXPORT_SYMBOL_NS_GPL(zpa2326_remove, IIO_ZPA2326);
 
 MODULE_AUTHOR("Gregor Boirie <[email protected]>");
 MODULE_DESCRIPTION("Core driver for Murata ZPA2326 pressure sensor");
index 95d9739444c4b19224b0e1c6a930d1e9417b4607..0db0860d386ba02ddaf348f46f2fd93f01f88c49 100644 (file)
@@ -87,3 +87,4 @@ module_i2c_driver(zpa2326_i2c_driver);
 MODULE_AUTHOR("Gregor Boirie <[email protected]>");
 MODULE_DESCRIPTION("I2C driver for Murata ZPA2326 pressure sensor");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ZPA2326);
index 85201a4bae44c2e5899f00756a09905b9cd9c224..5fbd2586c4ea455e58d3a1438b61c183f21bd978 100644 (file)
@@ -91,3 +91,4 @@ module_spi_driver(zpa2326_spi_driver);
 MODULE_AUTHOR("Gregor Boirie <[email protected]>");
 MODULE_DESCRIPTION("SPI driver for Murata ZPA2326 pressure sensor");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ZPA2326);
index 7c7203ca3ac63803261ad4ae7aafc690c9ccff89..0e5c17530b8bb432cea4bc417723b03acbe24649 100644 (file)
@@ -112,11 +112,17 @@ config SRF04
          To compile this driver as a module, choose M here: the
          module will be called srf04.
 
+config SX_COMMON
+       tristate
+       help
+         Common Semtech proximity sensor code.
+
 config SX9310
        tristate "SX9310/SX9311 Semtech proximity sensor"
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        select REGMAP_I2C
+       select SX_COMMON
        depends on I2C
        help
          Say Y here to build a driver for Semtech's SX9310/SX9311 capacitive
@@ -125,6 +131,34 @@ config SX9310
          To compile this driver as a module, choose M here: the
          module will be called sx9310.
 
+config SX9324
+       tristate "SX9324 Semtech proximity sensor"
+       select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
+       select REGMAP_I2C
+       select SX_COMMON
+       depends on I2C
+       help
+         Say Y here to build a driver for Semtech's SX9324
+         proximity/button sensor.
+
+         To compile this driver as a module, choose M here: the
+         module will be called sx9324.
+
+config SX9360
+       tristate "SX9360 Semtech proximity sensor"
+       select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
+       select REGMAP_I2C
+       select SX_COMMON
+       depends on I2C
+       help
+         Say Y here to build a driver for Semtech's SX9360
+         proximity/button sensor, a simplified SX9324.
+
+         To compile this driver as a module, choose M here: the
+         module will be called sx9360.
+
 config SX9500
        tristate "SX9500 Semtech proximity sensor"
        select IIO_BUFFER
index cbdac09433eb51379dc8d7d09d8465c84376508d..cc838bb5408a89b88c636ed46f9c2737d291c6b1 100644 (file)
@@ -14,6 +14,9 @@ obj-$(CONFIG_RFD77402)                += rfd77402.o
 obj-$(CONFIG_SRF04)            += srf04.o
 obj-$(CONFIG_SRF08)            += srf08.o
 obj-$(CONFIG_SX9310)           += sx9310.o
+obj-$(CONFIG_SX9324)           += sx9324.o
+obj-$(CONFIG_SX9360)           += sx9360.o
+obj-$(CONFIG_SX_COMMON)        += sx_common.o
 obj-$(CONFIG_SX9500)           += sx9500.o
 obj-$(CONFIG_VCNL3020)         += vcnl3020.o
 obj-$(CONFIG_VL53L0X_I2C)      += vl53l0x-i2c.o
index 51f4f92ae84af9cc7bacc92581af806d3034a054..67891ce2bd0958a6b76194607c62823e3fde425e 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/workqueue.h>
+#include <linux/devm-helpers.h>
 #include <linux/mutex.h>
 #include <linux/err.h>
 #include <linux/irq.h>
@@ -122,7 +123,7 @@ static ssize_t as3935_sensor_sensitivity_show(struct device *dev,
                return ret;
        val = (val & AS3935_AFE_MASK) >> 1;
 
-       return sprintf(buf, "%d\n", val);
+       return sysfs_emit(buf, "%d\n", val);
 }
 
 static ssize_t as3935_sensor_sensitivity_store(struct device *dev,
@@ -153,7 +154,7 @@ static ssize_t as3935_noise_level_tripped_show(struct device *dev,
        int ret;
 
        mutex_lock(&st->lock);
-       ret = sprintf(buf, "%d\n", !time_after(jiffies, st->noise_tripped + HZ));
+       ret = sysfs_emit(buf, "%d\n", !time_after(jiffies, st->noise_tripped + HZ));
        mutex_unlock(&st->lock);
 
        return ret;
@@ -295,7 +296,6 @@ static void calibrate_as3935(struct as3935_state *st)
        as3935_write(st, AS3935_NFLWDTH, st->nflwdth_reg);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int as3935_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
@@ -337,20 +337,7 @@ err_resume:
        return ret;
 }
 
-static SIMPLE_DEV_PM_OPS(as3935_pm_ops, as3935_suspend, as3935_resume);
-#define AS3935_PM_OPS (&as3935_pm_ops)
-
-#else
-#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 DEFINE_SIMPLE_DEV_PM_OPS(as3935_pm_ops, as3935_suspend, as3935_resume);
 
 static int as3935_probe(struct spi_device *spi)
 {
@@ -432,8 +419,7 @@ static int as3935_probe(struct spi_device *spi)
 
        calibrate_as3935(st);
 
-       INIT_DELAYED_WORK(&st->work, as3935_event_work);
-       ret = devm_add_action(dev, as3935_stop_work, indio_dev);
+       ret = devm_delayed_work_autocancel(dev, &st->work, as3935_event_work);
        if (ret)
                return ret;
 
@@ -472,7 +458,7 @@ static struct spi_driver as3935_driver = {
        .driver = {
                .name   = "as3935",
                .of_match_table = as3935_of_match,
-               .pm     = AS3935_PM_OPS,
+               .pm     = pm_sleep_ptr(&as3935_pm_ops),
        },
        .probe          = as3935_probe,
        .id_table       = as3935_id,
index 1283ac1c2e03c47aef699483636597e6942f54c6..24a97d41e115c76295557a7b9aba0c220ed61052 100644 (file)
@@ -267,8 +267,8 @@ static const struct iio_chan_spec ping_chan_spec[] = {
 };
 
 static const struct of_device_id of_ping_match[] = {
-       { .compatible = "parallax,ping", .data = &pa_ping_cfg},
-       { .compatible = "parallax,laserping", .data = &pa_laser_ping_cfg},
+       { .compatible = "parallax,ping", .data = &pa_ping_cfg },
+       { .compatible = "parallax,laserping", .data = &pa_laser_ping_cfg },
        {},
 };
 
index 27026c060ab994f25612c2370e4ff4f050a72c2b..648ae576d6fa8e4b3cf41f845d5500a4213007c8 100644 (file)
@@ -338,7 +338,6 @@ static const struct of_device_id lidar_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, lidar_dt_ids);
 
-#ifdef CONFIG_PM
 static int lidar_pm_runtime_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
@@ -358,18 +357,16 @@ static int lidar_pm_runtime_resume(struct device *dev)
 
        return ret;
 }
-#endif
 
 static const struct dev_pm_ops lidar_pm_ops = {
-       SET_RUNTIME_PM_OPS(lidar_pm_runtime_suspend,
-                          lidar_pm_runtime_resume, NULL)
+       RUNTIME_PM_OPS(lidar_pm_runtime_suspend, lidar_pm_runtime_resume, NULL)
 };
 
 static struct i2c_driver lidar_driver = {
        .driver = {
                .name   = LIDAR_DRV_NAME,
                .of_match_table = lidar_dt_ids,
-               .pm     = &lidar_pm_ops,
+               .pm     = pm_ptr(&lidar_pm_ops),
        },
        .probe          = lidar_probe,
        .remove         = lidar_remove,
index 8c06d02139b62d2f43248cfa96d5934f88c1e42a..cb80b3c9d07351ba1e771264b5bcf78a4f75284c 100644 (file)
@@ -295,7 +295,6 @@ static int rfd77402_probe(struct i2c_client *client,
        return devm_iio_device_register(&client->dev, indio_dev);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int rfd77402_suspend(struct device *dev)
 {
        return rfd77402_powerdown(to_i2c_client(dev));
@@ -305,12 +304,12 @@ static int rfd77402_resume(struct device *dev)
 {
        return rfd77402_init(to_i2c_client(dev));
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(rfd77402_pm_ops, rfd77402_suspend, rfd77402_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(rfd77402_pm_ops, rfd77402_suspend,
+                               rfd77402_resume);
 
 static const struct i2c_device_id rfd77402_id[] = {
-       { "rfd77402", 0},
+       { "rfd77402", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, rfd77402_id);
@@ -318,7 +317,7 @@ MODULE_DEVICE_TABLE(i2c, rfd77402_id);
 static struct i2c_driver rfd77402_driver = {
        .driver = {
                .name   = RFD77402_DRV_NAME,
-               .pm     = &rfd77402_pm_ops,
+               .pm     = pm_sleep_ptr(&rfd77402_pm_ops),
        },
        .probe  = rfd77402_probe,
        .id_table = rfd77402_id,
index fe88b2bb60bc8b81dab9f2a606ebfe99a43a8345..4e6286765f01f5bd50260b12068073174166ff83 100644 (file)
@@ -235,12 +235,12 @@ static const struct iio_chan_spec srf04_chan_spec[] = {
 };
 
 static const struct of_device_id of_srf04_match[] = {
-       { .compatible = "devantech,srf04", .data = &srf04_cfg},
-       { .compatible = "maxbotix,mb1000", .data = &mb_lv_cfg},
-       { .compatible = "maxbotix,mb1010", .data = &mb_lv_cfg},
-       { .compatible = "maxbotix,mb1020", .data = &mb_lv_cfg},
-       { .compatible = "maxbotix,mb1030", .data = &mb_lv_cfg},
-       { .compatible = "maxbotix,mb1040", .data = &mb_lv_cfg},
+       { .compatible = "devantech,srf04", .data = &srf04_cfg },
+       { .compatible = "maxbotix,mb1000", .data = &mb_lv_cfg },
+       { .compatible = "maxbotix,mb1010", .data = &mb_lv_cfg },
+       { .compatible = "maxbotix,mb1020", .data = &mb_lv_cfg },
+       { .compatible = "maxbotix,mb1030", .data = &mb_lv_cfg },
+       { .compatible = "maxbotix,mb1040", .data = &mb_lv_cfg },
        {},
 };
 
index 9b0886760f76de1480b3fbc5c5dc5a72401a107b..ac1ab7e89d4e5d3e0f59f53b1a45d4a3dcb658b7 100644 (file)
@@ -528,9 +528,9 @@ static int srf08_probe(struct i2c_client *client,
 }
 
 static const struct of_device_id of_srf08_match[] = {
-       { .compatible = "devantech,srf02", (void *)SRF02},
-       { .compatible = "devantech,srf08", (void *)SRF08},
-       { .compatible = "devantech,srf10", (void *)SRF10},
+       { .compatible = "devantech,srf02", (void *)SRF02 },
+       { .compatible = "devantech,srf08", (void *)SRF08 },
+       { .compatible = "devantech,srf10", (void *)SRF10 },
        {},
 };
 
index a3fdb59b06d22071ff383af88cf796ddfebad26e..ea7318b508ea008b8f9d9deeb669847ee7625253 100644 (file)
  * and in January 2020 by Daniel Campello <[email protected]>.
  */
 
-#include <linux/acpi.h>
 #include <linux/bitfield.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
-#include <linux/irq.h>
+#include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/log2.h>
 #include <linux/mod_devicetable.h>
 #include <linux/pm.h>
 #include <linux/property.h>
 #include <linux/regmap.h>
-#include <linux/regulator/consumer.h>
-#include <linux/slab.h>
-
-#include <linux/iio/buffer.h>
-#include <linux/iio/events.h>
 #include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include <linux/iio/trigger.h>
-#include <linux/iio/triggered_buffer.h>
-#include <linux/iio/trigger_consumer.h>
+
+#include "sx_common.h"
 
 /* Register definitions. */
-#define SX9310_REG_IRQ_SRC                             0x00
+#define SX9310_REG_IRQ_SRC                             SX_COMMON_REG_IRQ_SRC
 #define SX9310_REG_STAT0                               0x01
 #define SX9310_REG_STAT1                               0x02
 #define SX9310_REG_STAT1_COMPSTAT_MASK                 GENMASK(3, 0)
 #define   SX9310_WHOAMI_VALUE                          0x01
 #define   SX9311_WHOAMI_VALUE                          0x02
 #define SX9310_REG_RESET                               0x7f
-#define   SX9310_SOFT_RESET                            0xde
 
 
 /* 4 hardware channels, as defined in STAT0: COMB, CS2, CS1 and CS0. */
 #define SX9310_NUM_CHANNELS                            4
-static_assert(SX9310_NUM_CHANNELS < BITS_PER_LONG);
-
-struct sx9310_data {
-       /* Serialize access to registers and channel configuration */
-       struct mutex mutex;
-       struct i2c_client *client;
-       struct iio_trigger *trig;
-       struct regmap *regmap;
-       struct regulator_bulk_data supplies[2];
-       /*
-        * Last reading of the proximity status for each channel.
-        * We only send an event to user space when this changes.
-        */
-       unsigned long chan_prox_stat;
-       bool trigger_enabled;
-       /* Ensure correct alignment of timestamp when present. */
-       struct {
-               __be16 channels[SX9310_NUM_CHANNELS];
-               s64 ts __aligned(8);
-       } buffer;
-       /* Remember enabled channels and sample rate during suspend. */
-       unsigned int suspend_ctrl0;
-       struct completion completion;
-       unsigned long chan_read;
-       unsigned long chan_event;
-       unsigned int whoami;
-};
-
-static const struct iio_event_spec sx9310_events[] = {
-       {
-               .type = IIO_EV_TYPE_THRESH,
-               .dir = IIO_EV_DIR_RISING,
-               .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD),
-       },
-       {
-               .type = IIO_EV_TYPE_THRESH,
-               .dir = IIO_EV_DIR_FALLING,
-               .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD),
-       },
-       {
-               .type = IIO_EV_TYPE_THRESH,
-               .dir = IIO_EV_DIR_EITHER,
-               .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
-                                BIT(IIO_EV_INFO_HYSTERESIS) |
-                                BIT(IIO_EV_INFO_VALUE),
-       },
-};
-
-#define SX9310_NAMED_CHANNEL(idx, name)                                         \
-       {                                                                \
-               .type = IIO_PROXIMITY,                                   \
-               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |           \
-                                     BIT(IIO_CHAN_INFO_HARDWAREGAIN),   \
-               .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
-               .info_mask_separate_available =                          \
-                       BIT(IIO_CHAN_INFO_HARDWAREGAIN),                 \
-               .indexed = 1,                                            \
-               .channel = idx,                                          \
-               .extend_name = name,                                     \
-               .address = SX9310_REG_DIFF_MSB,                          \
-               .event_spec = sx9310_events,                             \
-               .num_event_specs = ARRAY_SIZE(sx9310_events),            \
-               .scan_index = idx,                                       \
-               .scan_type = {                                           \
-                       .sign = 's',                                     \
-                       .realbits = 12,                                  \
-                       .storagebits = 16,                               \
-                       .endianness = IIO_BE,                            \
-               },                                                       \
-       }
+static_assert(SX9310_NUM_CHANNELS <= SX_COMMON_MAX_NUM_CHANNELS);
+
+#define SX9310_NAMED_CHANNEL(idx, name)                                 \
+{                                                               \
+       .type = IIO_PROXIMITY,                                   \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |           \
+                             BIT(IIO_CHAN_INFO_HARDWAREGAIN),   \
+       .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+       .info_mask_separate_available =                          \
+               BIT(IIO_CHAN_INFO_HARDWAREGAIN),                 \
+       .info_mask_shared_by_all_available =                     \
+               BIT(IIO_CHAN_INFO_SAMP_FREQ),                    \
+       .indexed = 1,                                            \
+       .channel = idx,                                          \
+       .extend_name = name,                                     \
+       .address = SX9310_REG_DIFF_MSB,                          \
+       .event_spec = sx_common_events,                          \
+       .num_event_specs = ARRAY_SIZE(sx_common_events),         \
+       .scan_index = idx,                                       \
+       .scan_type = {                                           \
+               .sign = 's',                                     \
+               .realbits = 12,                                  \
+               .storagebits = 16,                               \
+               .endianness = IIO_BE,                            \
+       },                                                       \
+}
 #define SX9310_CHANNEL(idx) SX9310_NAMED_CHANNEL(idx, NULL)
 
 static const struct iio_chan_spec sx9310_channels[] = {
@@ -251,22 +198,6 @@ static const unsigned int sx9310_scan_period_table[] = {
        400, 600, 800, 1000, 2000, 3000, 4000, 5000,
 };
 
-static ssize_t sx9310_show_samp_freq_avail(struct device *dev,
-                                          struct device_attribute *attr,
-                                          char *buf)
-{
-       size_t len = 0;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(sx9310_samp_freq_table); i++)
-               len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%d ",
-                                sx9310_samp_freq_table[i].val,
-                                sx9310_samp_freq_table[i].val2);
-       buf[len - 1] = '\n';
-       return len;
-}
-static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(sx9310_show_samp_freq_avail);
-
 static const struct regmap_range sx9310_writable_reg_ranges[] = {
        regmap_reg_range(SX9310_REG_IRQ_MSK, SX9310_REG_IRQ_FUNC),
        regmap_reg_range(SX9310_REG_PROX_CTRL0, SX9310_REG_PROX_CTRL19),
@@ -320,64 +251,7 @@ static const struct regmap_config sx9310_regmap_config = {
        .volatile_table = &sx9310_volatile_regs,
 };
 
-static int sx9310_update_chan_en(struct sx9310_data *data,
-                                unsigned long chan_read,
-                                unsigned long chan_event)
-{
-       int ret;
-       unsigned long channels = chan_read | chan_event;
-
-       if ((data->chan_read | data->chan_event) != channels) {
-               ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL0,
-                                        SX9310_REG_PROX_CTRL0_SENSOREN_MASK,
-                                        channels);
-               if (ret)
-                       return ret;
-       }
-       data->chan_read = chan_read;
-       data->chan_event = chan_event;
-       return 0;
-}
-
-static int sx9310_get_read_channel(struct sx9310_data *data, int channel)
-{
-       return sx9310_update_chan_en(data, data->chan_read | BIT(channel),
-                                    data->chan_event);
-}
-
-static int sx9310_put_read_channel(struct sx9310_data *data, int channel)
-{
-       return sx9310_update_chan_en(data, data->chan_read & ~BIT(channel),
-                                    data->chan_event);
-}
-
-static int sx9310_get_event_channel(struct sx9310_data *data, int channel)
-{
-       return sx9310_update_chan_en(data, data->chan_read,
-                                    data->chan_event | BIT(channel));
-}
-
-static int sx9310_put_event_channel(struct sx9310_data *data, int channel)
-{
-       return sx9310_update_chan_en(data, data->chan_read,
-                                    data->chan_event & ~BIT(channel));
-}
-
-static int sx9310_enable_irq(struct sx9310_data *data, unsigned int irq)
-{
-       if (!data->client->irq)
-               return 0;
-       return regmap_update_bits(data->regmap, SX9310_REG_IRQ_MSK, irq, irq);
-}
-
-static int sx9310_disable_irq(struct sx9310_data *data, unsigned int irq)
-{
-       if (!data->client->irq)
-               return 0;
-       return regmap_update_bits(data->regmap, SX9310_REG_IRQ_MSK, irq, 0);
-}
-
-static int sx9310_read_prox_data(struct sx9310_data *data,
+static int sx9310_read_prox_data(struct sx_common_data *data,
                                 const struct iio_chan_spec *chan, __be16 *val)
 {
        int ret;
@@ -393,7 +267,7 @@ static int sx9310_read_prox_data(struct sx9310_data *data,
  * If we have no interrupt support, we have to wait for a scan period
  * after enabling a channel to get a result.
  */
-static int sx9310_wait_for_sample(struct sx9310_data *data)
+static int sx9310_wait_for_sample(struct sx_common_data *data)
 {
        int ret;
        unsigned int val;
@@ -409,66 +283,7 @@ static int sx9310_wait_for_sample(struct sx9310_data *data)
        return 0;
 }
 
-static int sx9310_read_proximity(struct sx9310_data *data,
-                                const struct iio_chan_spec *chan, int *val)
-{
-       int ret;
-       __be16 rawval;
-
-       mutex_lock(&data->mutex);
-
-       ret = sx9310_get_read_channel(data, chan->channel);
-       if (ret)
-               goto out;
-
-       ret = sx9310_enable_irq(data, SX9310_CONVDONE_IRQ);
-       if (ret)
-               goto out_put_channel;
-
-       mutex_unlock(&data->mutex);
-
-       if (data->client->irq) {
-               ret = wait_for_completion_interruptible(&data->completion);
-               reinit_completion(&data->completion);
-       } else {
-               ret = sx9310_wait_for_sample(data);
-       }
-
-       mutex_lock(&data->mutex);
-
-       if (ret)
-               goto out_disable_irq;
-
-       ret = sx9310_read_prox_data(data, chan, &rawval);
-       if (ret)
-               goto out_disable_irq;
-
-       *val = sign_extend32(be16_to_cpu(rawval),
-                            chan->address == SX9310_REG_DIFF_MSB ? 11 : 15);
-
-       ret = sx9310_disable_irq(data, SX9310_CONVDONE_IRQ);
-       if (ret)
-               goto out_put_channel;
-
-       ret = sx9310_put_read_channel(data, chan->channel);
-       if (ret)
-               goto out;
-
-       mutex_unlock(&data->mutex);
-
-       return IIO_VAL_INT;
-
-out_disable_irq:
-       sx9310_disable_irq(data, SX9310_CONVDONE_IRQ);
-out_put_channel:
-       sx9310_put_read_channel(data, chan->channel);
-out:
-       mutex_unlock(&data->mutex);
-
-       return ret;
-}
-
-static int sx9310_read_gain(struct sx9310_data *data,
+static int sx9310_read_gain(struct sx_common_data *data,
                            const struct iio_chan_spec *chan, int *val)
 {
        unsigned int regval, gain;
@@ -496,7 +311,7 @@ static int sx9310_read_gain(struct sx9310_data *data,
        return IIO_VAL_INT;
 }
 
-static int sx9310_read_samp_freq(struct sx9310_data *data, int *val, int *val2)
+static int sx9310_read_samp_freq(struct sx_common_data *data, int *val, int *val2)
 {
        unsigned int regval;
        int ret;
@@ -516,7 +331,7 @@ static int sx9310_read_raw(struct iio_dev *indio_dev,
                           const struct iio_chan_spec *chan, int *val,
                           int *val2, long mask)
 {
-       struct sx9310_data *data = iio_priv(indio_dev);
+       struct sx_common_data *data = iio_priv(indio_dev);
        int ret;
 
        if (chan->type != IIO_PROXIMITY)
@@ -528,7 +343,7 @@ static int sx9310_read_raw(struct iio_dev *indio_dev,
                if (ret)
                        return ret;
 
-               ret = sx9310_read_proximity(data, chan, val);
+               ret = sx_common_read_proximity(data, chan, val);
                iio_device_release_direct_mode(indio_dev);
                return ret;
        case IIO_CHAN_INFO_HARDWAREGAIN:
@@ -562,9 +377,14 @@ static int sx9310_read_avail(struct iio_dev *indio_dev,
                *length = ARRAY_SIZE(sx9310_gain_vals);
                *vals = sx9310_gain_vals;
                return IIO_AVAIL_LIST;
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               *type = IIO_VAL_INT_PLUS_MICRO;
+               *length = ARRAY_SIZE(sx9310_samp_freq_table) * 2;
+               *vals = (int *)sx9310_samp_freq_table;
+               return IIO_AVAIL_LIST;
+       default:
+               return -EINVAL;
        }
-
-       return -EINVAL;
 }
 
 static const unsigned int sx9310_pthresh_codes[] = {
@@ -581,12 +401,12 @@ static int sx9310_get_thresh_reg(unsigned int channel)
        case 1:
        case 2:
                return SX9310_REG_PROX_CTRL9;
+       default:
+               return -EINVAL;
        }
-
-       return -EINVAL;
 }
 
-static int sx9310_read_thresh(struct sx9310_data *data,
+static int sx9310_read_thresh(struct sx_common_data *data,
                              const struct iio_chan_spec *chan, int *val)
 {
        unsigned int reg;
@@ -609,7 +429,7 @@ static int sx9310_read_thresh(struct sx9310_data *data,
        return IIO_VAL_INT;
 }
 
-static int sx9310_read_hysteresis(struct sx9310_data *data,
+static int sx9310_read_hysteresis(struct sx_common_data *data,
                                  const struct iio_chan_spec *chan, int *val)
 {
        unsigned int regval, pthresh;
@@ -633,7 +453,7 @@ static int sx9310_read_hysteresis(struct sx9310_data *data,
        return IIO_VAL_INT;
 }
 
-static int sx9310_read_far_debounce(struct sx9310_data *data, int *val)
+static int sx9310_read_far_debounce(struct sx_common_data *data, int *val)
 {
        unsigned int regval;
        int ret;
@@ -651,7 +471,7 @@ static int sx9310_read_far_debounce(struct sx9310_data *data, int *val)
        return IIO_VAL_INT;
 }
 
-static int sx9310_read_close_debounce(struct sx9310_data *data, int *val)
+static int sx9310_read_close_debounce(struct sx_common_data *data, int *val)
 {
        unsigned int regval;
        int ret;
@@ -675,7 +495,7 @@ static int sx9310_read_event_val(struct iio_dev *indio_dev,
                                 enum iio_event_direction dir,
                                 enum iio_event_info info, int *val, int *val2)
 {
-       struct sx9310_data *data = iio_priv(indio_dev);
+       struct sx_common_data *data = iio_priv(indio_dev);
 
        if (chan->type != IIO_PROXIMITY)
                return -EINVAL;
@@ -699,7 +519,7 @@ static int sx9310_read_event_val(struct iio_dev *indio_dev,
        }
 }
 
-static int sx9310_write_thresh(struct sx9310_data *data,
+static int sx9310_write_thresh(struct sx_common_data *data,
                               const struct iio_chan_spec *chan, int val)
 {
        unsigned int reg;
@@ -729,7 +549,7 @@ static int sx9310_write_thresh(struct sx9310_data *data,
        return ret;
 }
 
-static int sx9310_write_hysteresis(struct sx9310_data *data,
+static int sx9310_write_hysteresis(struct sx_common_data *data,
                                   const struct iio_chan_spec *chan, int _val)
 {
        unsigned int hyst, val = _val;
@@ -759,7 +579,7 @@ static int sx9310_write_hysteresis(struct sx9310_data *data,
        return ret;
 }
 
-static int sx9310_write_far_debounce(struct sx9310_data *data, int val)
+static int sx9310_write_far_debounce(struct sx_common_data *data, int val)
 {
        int ret;
        unsigned int regval;
@@ -780,7 +600,7 @@ static int sx9310_write_far_debounce(struct sx9310_data *data, int val)
        return ret;
 }
 
-static int sx9310_write_close_debounce(struct sx9310_data *data, int val)
+static int sx9310_write_close_debounce(struct sx_common_data *data, int val)
 {
        int ret;
        unsigned int regval;
@@ -807,7 +627,7 @@ static int sx9310_write_event_val(struct iio_dev *indio_dev,
                                  enum iio_event_direction dir,
                                  enum iio_event_info info, int val, int val2)
 {
-       struct sx9310_data *data = iio_priv(indio_dev);
+       struct sx_common_data *data = iio_priv(indio_dev);
 
        if (chan->type != IIO_PROXIMITY)
                return -EINVAL;
@@ -831,7 +651,7 @@ static int sx9310_write_event_val(struct iio_dev *indio_dev,
        }
 }
 
-static int sx9310_set_samp_freq(struct sx9310_data *data, int val, int val2)
+static int sx9310_set_samp_freq(struct sx_common_data *data, int val, int val2)
 {
        int i, ret;
 
@@ -855,8 +675,8 @@ static int sx9310_set_samp_freq(struct sx9310_data *data, int val, int val2)
        return ret;
 }
 
-static int sx9310_write_gain(struct sx9310_data *data,
-                           const struct iio_chan_spec *chan, int val)
+static int sx9310_write_gain(struct sx_common_data *data,
+                            const struct iio_chan_spec *chan, int val)
 {
        unsigned int gain, mask;
        int ret;
@@ -890,7 +710,7 @@ static int sx9310_write_raw(struct iio_dev *indio_dev,
                            const struct iio_chan_spec *chan, int val, int val2,
                            long mask)
 {
-       struct sx9310_data *data = iio_priv(indio_dev);
+       struct sx_common_data *data = iio_priv(indio_dev);
 
        if (chan->type != IIO_PROXIMITY)
                return -EINVAL;
@@ -900,253 +720,12 @@ static int sx9310_write_raw(struct iio_dev *indio_dev,
                return sx9310_set_samp_freq(data, val, val2);
        case IIO_CHAN_INFO_HARDWAREGAIN:
                return sx9310_write_gain(data, chan, val);
+       default:
+               return -EINVAL;
        }
-
-       return -EINVAL;
-}
-
-static irqreturn_t sx9310_irq_handler(int irq, void *private)
-{
-       struct iio_dev *indio_dev = private;
-       struct sx9310_data *data = iio_priv(indio_dev);
-
-       if (data->trigger_enabled)
-               iio_trigger_poll(data->trig);
-
-       /*
-        * Even if no event is enabled, we need to wake the thread to clear the
-        * interrupt state by reading SX9310_REG_IRQ_SRC.
-        * It is not possible to do that here because regmap_read takes a mutex.
-        */
-       return IRQ_WAKE_THREAD;
-}
-
-static void sx9310_push_events(struct iio_dev *indio_dev)
-{
-       int ret;
-       unsigned int val, chan;
-       struct sx9310_data *data = iio_priv(indio_dev);
-       s64 timestamp = iio_get_time_ns(indio_dev);
-       unsigned long prox_changed;
-
-       /* Read proximity state on all channels */
-       ret = regmap_read(data->regmap, SX9310_REG_STAT0, &val);
-       if (ret) {
-               dev_err(&data->client->dev, "i2c transfer error in irq\n");
-               return;
-       }
-
-       /*
-        * Only iterate over channels with changes on proximity status that have
-        * events enabled.
-        */
-       prox_changed = (data->chan_prox_stat ^ val) & data->chan_event;
-
-       for_each_set_bit(chan, &prox_changed, SX9310_NUM_CHANNELS) {
-               int dir;
-               u64 ev;
-
-               dir = (val & BIT(chan)) ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
-               ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan,
-                                         IIO_EV_TYPE_THRESH, dir);
-
-               iio_push_event(indio_dev, ev, timestamp);
-       }
-       data->chan_prox_stat = val;
-}
-
-static irqreturn_t sx9310_irq_thread_handler(int irq, void *private)
-{
-       struct iio_dev *indio_dev = private;
-       struct sx9310_data *data = iio_priv(indio_dev);
-       int ret;
-       unsigned int val;
-
-       mutex_lock(&data->mutex);
-
-       ret = regmap_read(data->regmap, SX9310_REG_IRQ_SRC, &val);
-       if (ret) {
-               dev_err(&data->client->dev, "i2c transfer error in irq\n");
-               goto out;
-       }
-
-       if (val & (SX9310_FAR_IRQ | SX9310_CLOSE_IRQ))
-               sx9310_push_events(indio_dev);
-
-       if (val & SX9310_CONVDONE_IRQ)
-               complete(&data->completion);
-
-out:
-       mutex_unlock(&data->mutex);
-
-       return IRQ_HANDLED;
-}
-
-static int sx9310_read_event_config(struct iio_dev *indio_dev,
-                                   const struct iio_chan_spec *chan,
-                                   enum iio_event_type type,
-                                   enum iio_event_direction dir)
-{
-       struct sx9310_data *data = iio_priv(indio_dev);
-
-       return !!(data->chan_event & BIT(chan->channel));
-}
-
-static int sx9310_write_event_config(struct iio_dev *indio_dev,
-                                    const struct iio_chan_spec *chan,
-                                    enum iio_event_type type,
-                                    enum iio_event_direction dir, int state)
-{
-       struct sx9310_data *data = iio_priv(indio_dev);
-       unsigned int eventirq = SX9310_FAR_IRQ | SX9310_CLOSE_IRQ;
-       int ret;
-
-       /* If the state hasn't changed, there's nothing to do. */
-       if (!!(data->chan_event & BIT(chan->channel)) == state)
-               return 0;
-
-       mutex_lock(&data->mutex);
-       if (state) {
-               ret = sx9310_get_event_channel(data, chan->channel);
-               if (ret)
-                       goto out_unlock;
-               if (!(data->chan_event & ~BIT(chan->channel))) {
-                       ret = sx9310_enable_irq(data, eventirq);
-                       if (ret)
-                               sx9310_put_event_channel(data, chan->channel);
-               }
-       } else {
-               ret = sx9310_put_event_channel(data, chan->channel);
-               if (ret)
-                       goto out_unlock;
-               if (!data->chan_event) {
-                       ret = sx9310_disable_irq(data, eventirq);
-                       if (ret)
-                               sx9310_get_event_channel(data, chan->channel);
-               }
-       }
-
-out_unlock:
-       mutex_unlock(&data->mutex);
-       return ret;
-}
-
-static struct attribute *sx9310_attributes[] = {
-       &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
-       NULL
-};
-
-static const struct attribute_group sx9310_attribute_group = {
-       .attrs = sx9310_attributes,
-};
-
-static const struct iio_info sx9310_info = {
-       .attrs = &sx9310_attribute_group,
-       .read_raw = sx9310_read_raw,
-       .read_avail = sx9310_read_avail,
-       .read_event_value = sx9310_read_event_val,
-       .write_event_value = sx9310_write_event_val,
-       .write_raw = sx9310_write_raw,
-       .read_event_config = sx9310_read_event_config,
-       .write_event_config = sx9310_write_event_config,
-};
-
-static int sx9310_set_trigger_state(struct iio_trigger *trig, bool state)
-{
-       struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
-       struct sx9310_data *data = iio_priv(indio_dev);
-       int ret = 0;
-
-       mutex_lock(&data->mutex);
-
-       if (state)
-               ret = sx9310_enable_irq(data, SX9310_CONVDONE_IRQ);
-       else if (!data->chan_read)
-               ret = sx9310_disable_irq(data, SX9310_CONVDONE_IRQ);
-       if (ret)
-               goto out;
-
-       data->trigger_enabled = state;
-
-out:
-       mutex_unlock(&data->mutex);
-
-       return ret;
-}
-
-static const struct iio_trigger_ops sx9310_trigger_ops = {
-       .set_trigger_state = sx9310_set_trigger_state,
-};
-
-static irqreturn_t sx9310_trigger_handler(int irq, void *private)
-{
-       struct iio_poll_func *pf = private;
-       struct iio_dev *indio_dev = pf->indio_dev;
-       struct sx9310_data *data = iio_priv(indio_dev);
-       __be16 val;
-       int bit, ret, i = 0;
-
-       mutex_lock(&data->mutex);
-
-       for_each_set_bit(bit, indio_dev->active_scan_mask,
-                        indio_dev->masklength) {
-               ret = sx9310_read_prox_data(data, &indio_dev->channels[bit],
-                                           &val);
-               if (ret)
-                       goto out;
-
-               data->buffer.channels[i++] = val;
-       }
-
-       iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer,
-                                          pf->timestamp);
-
-out:
-       mutex_unlock(&data->mutex);
-
-       iio_trigger_notify_done(indio_dev->trig);
-
-       return IRQ_HANDLED;
-}
-
-static int sx9310_buffer_preenable(struct iio_dev *indio_dev)
-{
-       struct sx9310_data *data = iio_priv(indio_dev);
-       unsigned long channels = 0;
-       int bit, ret;
-
-       mutex_lock(&data->mutex);
-       for_each_set_bit(bit, indio_dev->active_scan_mask,
-                        indio_dev->masklength)
-               __set_bit(indio_dev->channels[bit].channel, &channels);
-
-       ret = sx9310_update_chan_en(data, channels, data->chan_event);
-       mutex_unlock(&data->mutex);
-       return ret;
 }
 
-static int sx9310_buffer_postdisable(struct iio_dev *indio_dev)
-{
-       struct sx9310_data *data = iio_priv(indio_dev);
-       int ret;
-
-       mutex_lock(&data->mutex);
-       ret = sx9310_update_chan_en(data, 0, data->chan_event);
-       mutex_unlock(&data->mutex);
-       return ret;
-}
-
-static const struct iio_buffer_setup_ops sx9310_buffer_setup_ops = {
-       .preenable = sx9310_buffer_preenable,
-       .postdisable = sx9310_buffer_postdisable,
-};
-
-struct sx9310_reg_default {
-       u8 reg;
-       u8 def;
-};
-
-static const struct sx9310_reg_default sx9310_default_regs[] = {
+static const struct sx_common_reg_default sx9310_default_regs[] = {
        { SX9310_REG_IRQ_MSK, 0x00 },
        { SX9310_REG_IRQ_FUNC, 0x00 },
        /*
@@ -1191,7 +770,7 @@ static const struct sx9310_reg_default sx9310_default_regs[] = {
 /* Activate all channels and perform an initial compensation. */
 static int sx9310_init_compensation(struct iio_dev *indio_dev)
 {
-       struct sx9310_data *data = iio_priv(indio_dev);
+       struct sx_common_data *data = iio_priv(indio_dev);
        int ret;
        unsigned int val;
        unsigned int ctrl0;
@@ -1209,21 +788,16 @@ static int sx9310_init_compensation(struct iio_dev *indio_dev)
        ret = regmap_read_poll_timeout(data->regmap, SX9310_REG_STAT1, val,
                                       !(val & SX9310_REG_STAT1_COMPSTAT_MASK),
                                       20000, 2000000);
-       if (ret) {
-               if (ret == -ETIMEDOUT)
-                       dev_err(&data->client->dev,
-                               "initial compensation timed out: 0x%02x\n",
-                               val);
+       if (ret)
                return ret;
-       }
 
        regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, ctrl0);
        return ret;
 }
 
-static const struct sx9310_reg_default *
+static const struct sx_common_reg_default *
 sx9310_get_default_reg(struct device *dev, int idx,
-                      struct sx9310_reg_default *reg_def)
+                      struct sx_common_reg_default *reg_def)
 {
        u32 combined[SX9310_NUM_CHANNELS];
        u32 start = 0, raw = 0, pos = 0;
@@ -1324,47 +898,21 @@ sx9310_get_default_reg(struct device *dev, int idx,
        return reg_def;
 }
 
-static int sx9310_init_device(struct iio_dev *indio_dev)
+static int sx9310_check_whoami(struct device *dev,
+                              struct iio_dev *indio_dev)
 {
-       struct sx9310_data *data = iio_priv(indio_dev);
-       struct sx9310_reg_default tmp;
-       const struct sx9310_reg_default *initval;
+       struct sx_common_data *data = iio_priv(indio_dev);
+       unsigned int long ddata;
+       unsigned int whoami;
        int ret;
-       unsigned int i, val;
-
-       ret = regmap_write(data->regmap, SX9310_REG_RESET, SX9310_SOFT_RESET);
-       if (ret)
-               return ret;
-
-       usleep_range(1000, 2000); /* power-up time is ~1ms. */
 
-       /* Clear reset interrupt state by reading SX9310_REG_IRQ_SRC. */
-       ret = regmap_read(data->regmap, SX9310_REG_IRQ_SRC, &val);
+       ret = regmap_read(data->regmap, SX9310_REG_WHOAMI, &whoami);
        if (ret)
                return ret;
 
-       /* Program some sane defaults. */
-       for (i = 0; i < ARRAY_SIZE(sx9310_default_regs); i++) {
-               initval = sx9310_get_default_reg(&indio_dev->dev, i, &tmp);
-               ret = regmap_write(data->regmap, initval->reg, initval->def);
-               if (ret)
-                       return ret;
-       }
-
-       return sx9310_init_compensation(indio_dev);
-}
-
-static int sx9310_set_indio_dev_name(struct device *dev,
-                                    struct iio_dev *indio_dev,
-                                    unsigned int whoami)
-{
-       unsigned int long ddata;
-
        ddata = (uintptr_t)device_get_match_data(dev);
-       if (ddata != whoami) {
-               dev_err(dev, "WHOAMI does not match device data: %u\n", whoami);
-               return -ENODEV;
-       }
+       if (ddata != whoami)
+               return -EINVAL;
 
        switch (whoami) {
        case SX9310_WHOAMI_VALUE:
@@ -1374,115 +922,52 @@ static int sx9310_set_indio_dev_name(struct device *dev,
                indio_dev->name = "sx9311";
                break;
        default:
-               dev_err(dev, "unexpected WHOAMI response: %u\n", whoami);
                return -ENODEV;
        }
 
        return 0;
 }
 
-static void sx9310_regulator_disable(void *_data)
-{
-       struct sx9310_data *data = _data;
+static const struct sx_common_chip_info sx9310_chip_info = {
+       .reg_stat = SX9310_REG_STAT0,
+       .reg_irq_msk = SX9310_REG_IRQ_MSK,
+       .reg_enable_chan = SX9310_REG_PROX_CTRL0,
+       .reg_reset = SX9310_REG_RESET,
+
+       .mask_enable_chan = SX9310_REG_STAT1_COMPSTAT_MASK,
+       .irq_msk_offset = 3,
+       .num_channels = SX9310_NUM_CHANNELS,
+       .num_default_regs = ARRAY_SIZE(sx9310_default_regs),
+
+       .ops = {
+               .read_prox_data = sx9310_read_prox_data,
+               .check_whoami = sx9310_check_whoami,
+               .init_compensation = sx9310_init_compensation,
+               .wait_for_sample = sx9310_wait_for_sample,
+               .get_default_reg = sx9310_get_default_reg,
+       },
 
-       regulator_bulk_disable(ARRAY_SIZE(data->supplies), data->supplies);
-}
+       .iio_channels = sx9310_channels,
+       .num_iio_channels = ARRAY_SIZE(sx9310_channels),
+       .iio_info =  {
+               .read_raw = sx9310_read_raw,
+               .read_avail = sx9310_read_avail,
+               .read_event_value = sx9310_read_event_val,
+               .write_event_value = sx9310_write_event_val,
+               .write_raw = sx9310_write_raw,
+               .read_event_config = sx_common_read_event_config,
+               .write_event_config = sx_common_write_event_config,
+       },
+};
 
 static int sx9310_probe(struct i2c_client *client)
 {
-       int ret;
-       struct device *dev = &client->dev;
-       struct iio_dev *indio_dev;
-       struct sx9310_data *data;
-
-       indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
-       if (!indio_dev)
-               return -ENOMEM;
-
-       data = iio_priv(indio_dev);
-       data->client = client;
-       data->supplies[0].supply = "vdd";
-       data->supplies[1].supply = "svdd";
-       mutex_init(&data->mutex);
-       init_completion(&data->completion);
-
-       data->regmap = devm_regmap_init_i2c(client, &sx9310_regmap_config);
-       if (IS_ERR(data->regmap))
-               return PTR_ERR(data->regmap);
-
-       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
-                                     data->supplies);
-       if (ret)
-               return ret;
-
-       ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies), data->supplies);
-       if (ret)
-               return ret;
-       /* Must wait for Tpor time after initial power up */
-       usleep_range(1000, 1100);
-
-       ret = devm_add_action_or_reset(dev, sx9310_regulator_disable, data);
-       if (ret)
-               return ret;
-
-       ret = regmap_read(data->regmap, SX9310_REG_WHOAMI, &data->whoami);
-       if (ret) {
-               dev_err(dev, "error in reading WHOAMI register: %d", ret);
-               return ret;
-       }
-
-       ret = sx9310_set_indio_dev_name(dev, indio_dev, data->whoami);
-       if (ret)
-               return ret;
-
-       ACPI_COMPANION_SET(&indio_dev->dev, ACPI_COMPANION(dev));
-       indio_dev->channels = sx9310_channels;
-       indio_dev->num_channels = ARRAY_SIZE(sx9310_channels);
-       indio_dev->info = &sx9310_info;
-       indio_dev->modes = INDIO_DIRECT_MODE;
-       i2c_set_clientdata(client, indio_dev);
-
-       ret = sx9310_init_device(indio_dev);
-       if (ret)
-               return ret;
-
-       if (client->irq) {
-               ret = devm_request_threaded_irq(dev, client->irq,
-                                               sx9310_irq_handler,
-                                               sx9310_irq_thread_handler,
-                                               IRQF_ONESHOT,
-                                               "sx9310_event", indio_dev);
-               if (ret)
-                       return ret;
-
-               data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
-                                                   indio_dev->name,
-                                                   iio_device_id(indio_dev));
-               if (!data->trig)
-                       return -ENOMEM;
-
-               data->trig->ops = &sx9310_trigger_ops;
-               iio_trigger_set_drvdata(data->trig, indio_dev);
-
-               ret = devm_iio_trigger_register(dev, data->trig);
-               if (ret)
-                       return ret;
-       }
-
-       ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
-                                             iio_pollfunc_store_time,
-                                             sx9310_trigger_handler,
-                                             &sx9310_buffer_setup_ops);
-       if (ret)
-               return ret;
-
-       return devm_iio_device_register(dev, indio_dev);
+       return sx_common_probe(client, &sx9310_chip_info, &sx9310_regmap_config);
 }
 
 static int __maybe_unused sx9310_suspend(struct device *dev)
 {
-       struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
-       struct sx9310_data *data = iio_priv(indio_dev);
+       struct sx_common_data *data = iio_priv(dev_get_drvdata(dev));
        u8 ctrl0;
        int ret;
 
@@ -1490,11 +975,11 @@ static int __maybe_unused sx9310_suspend(struct device *dev)
 
        mutex_lock(&data->mutex);
        ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0,
-                         &data->suspend_ctrl0);
+                         &data->suspend_ctrl);
        if (ret)
                goto out;
 
-       ctrl0 = data->suspend_ctrl0 & ~SX9310_REG_PROX_CTRL0_SENSOREN_MASK;
+       ctrl0 = data->suspend_ctrl & ~SX9310_REG_PROX_CTRL0_SENSOREN_MASK;
        ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, ctrl0);
        if (ret)
                goto out;
@@ -1508,8 +993,7 @@ out:
 
 static int __maybe_unused sx9310_resume(struct device *dev)
 {
-       struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
-       struct sx9310_data *data = iio_priv(indio_dev);
+       struct sx_common_data *data = iio_priv(dev_get_drvdata(dev));
        int ret;
 
        mutex_lock(&data->mutex);
@@ -1518,7 +1002,7 @@ static int __maybe_unused sx9310_resume(struct device *dev)
                goto out;
 
        ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0,
-                          data->suspend_ctrl0);
+                          data->suspend_ctrl);
 
 out:
        mutex_unlock(&data->mutex);
@@ -1529,9 +1013,7 @@ out:
        return 0;
 }
 
-static const struct dev_pm_ops sx9310_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(sx9310_suspend, sx9310_resume)
-};
+static SIMPLE_DEV_PM_OPS(sx9310_pm_ops, sx9310_suspend, sx9310_resume);
 
 static const struct acpi_device_id sx9310_acpi_match[] = {
        { "STH9310", SX9310_WHOAMI_VALUE },
@@ -1577,3 +1059,4 @@ MODULE_AUTHOR("Gwendal Grignou <[email protected]>");
 MODULE_AUTHOR("Daniel Campello <[email protected]>");
 MODULE_DESCRIPTION("Driver for Semtech SX9310/SX9311 proximity sensor");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(SEMTECH_PROX);
diff --git a/drivers/iio/proximity/sx9324.c b/drivers/iio/proximity/sx9324.c
new file mode 100644 (file)
index 0000000..0d9bbbb
--- /dev/null
@@ -0,0 +1,1068 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2021 Google LLC.
+ *
+ * Driver for Semtech's SX9324 capacitive proximity/button solution.
+ * Based on SX9324 driver and copy of datasheet at:
+ * https://edit.wpgdadawant.com/uploads/news_file/program/2019/30184/tech_files/program_30184_suggest_other_file.pdf
+ */
+
+#include <linux/acpi.h>
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/log2.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+#include <linux/iio/iio.h>
+
+#include "sx_common.h"
+
+/* Register definitions. */
+#define SX9324_REG_IRQ_SRC             SX_COMMON_REG_IRQ_SRC
+#define SX9324_REG_STAT0               0x01
+#define SX9324_REG_STAT1               0x02
+#define SX9324_REG_STAT2               0x03
+#define SX9324_REG_STAT2_COMPSTAT_MASK GENMASK(3, 0)
+#define SX9324_REG_STAT3               0x04
+#define SX9324_REG_IRQ_MSK             0x05
+#define SX9324_CONVDONE_IRQ            BIT(3)
+#define SX9324_FAR_IRQ                 BIT(5)
+#define SX9324_CLOSE_IRQ               BIT(6)
+#define SX9324_REG_IRQ_CFG0            0x06
+#define SX9324_REG_IRQ_CFG1            0x07
+#define SX9324_REG_IRQ_CFG1_FAILCOND    0x80
+#define SX9324_REG_IRQ_CFG2            0x08
+
+#define SX9324_REG_GNRL_CTRL0          0x10
+#define SX9324_REG_GNRL_CTRL0_SCANPERIOD_MASK GENMASK(4, 0)
+#define SX9324_REG_GNRL_CTRL0_SCANPERIOD_100MS 0x16
+#define SX9324_REG_GNRL_CTRL1          0x11
+#define SX9324_REG_GNRL_CTRL1_PHEN_MASK GENMASK(3, 0)
+#define SX9324_REG_GNRL_CTRL1_PAUSECTRL 0x20
+
+#define SX9324_REG_I2C_ADDR            0x14
+#define SX9324_REG_CLK_SPRD            0x15
+
+#define SX9324_REG_AFE_CTRL0           0x20
+#define SX9324_REG_AFE_CTRL1           0x21
+#define SX9324_REG_AFE_CTRL2           0x22
+#define SX9324_REG_AFE_CTRL3           0x23
+#define SX9324_REG_AFE_CTRL4           0x24
+#define SX9324_REG_AFE_CTRL4_FREQ_83_33HZ 0x40
+#define SX9324_REG_AFE_CTRL4_RESOLUTION_MASK GENMASK(2, 0)
+#define SX9324_REG_AFE_CTRL4_RES_100   0x04
+#define SX9324_REG_AFE_CTRL5           0x25
+#define SX9324_REG_AFE_CTRL6           0x26
+#define SX9324_REG_AFE_CTRL7           0x27
+#define SX9324_REG_AFE_PH0             0x28
+#define SX9324_REG_AFE_PH0_PIN_MASK(_pin) \
+       GENMASK(2 * (_pin) + 1, 2 * (_pin))
+
+#define SX9324_REG_AFE_PH1             0x29
+#define SX9324_REG_AFE_PH2             0x2a
+#define SX9324_REG_AFE_PH3             0x2b
+#define SX9324_REG_AFE_CTRL8           0x2c
+#define SX9324_REG_AFE_CTRL8_RESFILTN_4KOHM 0x02
+#define SX9324_REG_AFE_CTRL9           0x2d
+#define SX9324_REG_AFE_CTRL9_AGAIN_1   0x08
+
+#define SX9324_REG_PROX_CTRL0          0x30
+#define SX9324_REG_PROX_CTRL0_GAIN_MASK        GENMASK(5, 3)
+#define SX9324_REG_PROX_CTRL0_GAIN_1           0x80
+#define SX9324_REG_PROX_CTRL0_RAWFILT_MASK     GENMASK(2, 0)
+#define SX9324_REG_PROX_CTRL0_RAWFILT_1P50     0x01
+#define SX9324_REG_PROX_CTRL1          0x31
+#define SX9324_REG_PROX_CTRL2          0x32
+#define SX9324_REG_PROX_CTRL2_AVGNEG_THRESH_16K 0x20
+#define SX9324_REG_PROX_CTRL3          0x33
+#define SX9324_REG_PROX_CTRL3_AVGDEB_2SAMPLES  0x40
+#define SX9324_REG_PROX_CTRL3_AVGPOS_THRESH_16K 0x20
+#define SX9324_REG_PROX_CTRL4          0x34
+#define SX9324_REG_PROX_CTRL4_AVGNEGFILT_MASK  GENMASK(5, 3)
+#define SX9324_REG_PROX_CTRL4_AVGNEG_FILT_2 0x08
+#define SX9324_REG_PROX_CTRL4_AVGPOSFILT_MASK  GENMASK(2, 0)
+#define SX9324_REG_PROX_CTRL3_AVGPOS_FILT_256 0x04
+#define SX9324_REG_PROX_CTRL5          0x35
+#define SX9324_REG_PROX_CTRL5_HYST_MASK                        GENMASK(5, 4)
+#define SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK      GENMASK(3, 2)
+#define SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK                GENMASK(1, 0)
+#define SX9324_REG_PROX_CTRL6          0x36
+#define SX9324_REG_PROX_CTRL6_PROXTHRESH_32    0x08
+#define SX9324_REG_PROX_CTRL7          0x37
+
+#define SX9324_REG_ADV_CTRL0           0x40
+#define SX9324_REG_ADV_CTRL1           0x41
+#define SX9324_REG_ADV_CTRL2           0x42
+#define SX9324_REG_ADV_CTRL3           0x43
+#define SX9324_REG_ADV_CTRL4           0x44
+#define SX9324_REG_ADV_CTRL5           0x45
+#define SX9324_REG_ADV_CTRL5_STARTUPSENS_MASK GENMASK(3, 2)
+#define SX9324_REG_ADV_CTRL5_STARTUP_SENSOR_1  0x04
+#define SX9324_REG_ADV_CTRL5_STARTUP_METHOD_1  0x01
+#define SX9324_REG_ADV_CTRL6           0x46
+#define SX9324_REG_ADV_CTRL7           0x47
+#define SX9324_REG_ADV_CTRL8           0x48
+#define SX9324_REG_ADV_CTRL9           0x49
+#define SX9324_REG_ADV_CTRL10          0x4a
+#define SX9324_REG_ADV_CTRL11          0x4b
+#define SX9324_REG_ADV_CTRL12          0x4c
+#define SX9324_REG_ADV_CTRL13          0x4d
+#define SX9324_REG_ADV_CTRL14          0x4e
+#define SX9324_REG_ADV_CTRL15          0x4f
+#define SX9324_REG_ADV_CTRL16          0x50
+#define SX9324_REG_ADV_CTRL17          0x51
+#define SX9324_REG_ADV_CTRL18          0x52
+#define SX9324_REG_ADV_CTRL19          0x53
+#define SX9324_REG_ADV_CTRL20          0x54
+#define SX9324_REG_ADV_CTRL19_HIGHT_FAILURE_THRESH_SATURATION 0xf0
+
+#define SX9324_REG_PHASE_SEL           0x60
+
+#define SX9324_REG_USEFUL_MSB          0x61
+#define SX9324_REG_USEFUL_LSB          0x62
+
+#define SX9324_REG_AVG_MSB             0x63
+#define SX9324_REG_AVG_LSB             0x64
+
+#define SX9324_REG_DIFF_MSB            0x65
+#define SX9324_REG_DIFF_LSB            0x66
+
+#define SX9324_REG_OFFSET_MSB          0x67
+#define SX9324_REG_OFFSET_LSB          0x68
+
+#define SX9324_REG_SAR_MSB             0x69
+#define SX9324_REG_SAR_LSB             0x6a
+
+#define SX9324_REG_RESET               0x9f
+/* Write this to REG_RESET to do a soft reset. */
+#define SX9324_SOFT_RESET              0xde
+
+#define SX9324_REG_WHOAMI              0xfa
+#define   SX9324_WHOAMI_VALUE          0x23
+
+#define SX9324_REG_REVISION            0xfe
+
+/* 4 channels, as defined in STAT0: PH0, PH1, PH2 and PH3. */
+#define SX9324_NUM_CHANNELS            4
+/* 3 CS pins: CS0, CS1, CS2. */
+#define SX9324_NUM_PINS                        3
+
+static const char * const sx9324_cs_pin_usage[] = { "HZ", "MI", "DS", "GD" };
+
+static ssize_t sx9324_phase_configuration_show(struct iio_dev *indio_dev,
+                                              uintptr_t private,
+                                              const struct iio_chan_spec *chan,
+                                              char *buf)
+{
+       struct sx_common_data *data = iio_priv(indio_dev);
+       unsigned int val;
+       int i, ret, pin_idx;
+       size_t len = 0;
+
+       ret = regmap_read(data->regmap, SX9324_REG_AFE_PH0 + chan->channel, &val);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < SX9324_NUM_PINS; i++) {
+               pin_idx = (val & SX9324_REG_AFE_PH0_PIN_MASK(i)) >> (2 * i);
+               len += sysfs_emit_at(buf, len, "%s,",
+                                    sx9324_cs_pin_usage[pin_idx]);
+       }
+       buf[len - 1] = '\n';
+       return len;
+}
+
+static const struct iio_chan_spec_ext_info sx9324_channel_ext_info[] = {
+       {
+               .name = "setup",
+               .shared = IIO_SEPARATE,
+               .read = sx9324_phase_configuration_show,
+       },
+       {}
+};
+
+#define SX9324_CHANNEL(idx)                                     \
+{                                                               \
+       .type = IIO_PROXIMITY,                                   \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |           \
+                             BIT(IIO_CHAN_INFO_HARDWAREGAIN),   \
+       .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+       .info_mask_separate_available =                          \
+               BIT(IIO_CHAN_INFO_HARDWAREGAIN),                 \
+       .info_mask_shared_by_all_available =                     \
+               BIT(IIO_CHAN_INFO_SAMP_FREQ),                    \
+       .indexed = 1,                                            \
+       .channel = idx,                                          \
+       .address = SX9324_REG_DIFF_MSB,                          \
+       .event_spec = sx_common_events,                          \
+       .num_event_specs = ARRAY_SIZE(sx_common_events),         \
+       .scan_index = idx,                                       \
+       .scan_type = {                                           \
+               .sign = 's',                                     \
+               .realbits = 12,                                  \
+               .storagebits = 16,                               \
+               .endianness = IIO_BE,                            \
+       },                                                       \
+       .ext_info = sx9324_channel_ext_info,                     \
+}
+
+static const struct iio_chan_spec sx9324_channels[] = {
+       SX9324_CHANNEL(0),                      /* Phase 0 */
+       SX9324_CHANNEL(1),                      /* Phase 1 */
+       SX9324_CHANNEL(2),                      /* Phase 2 */
+       SX9324_CHANNEL(3),                      /* Phase 3 */
+       IIO_CHAN_SOFT_TIMESTAMP(4),
+};
+
+/*
+ * Each entry contains the integer part (val) and the fractional part, in micro
+ * seconds. It conforms to the IIO output IIO_VAL_INT_PLUS_MICRO.
+ */
+static const struct {
+       int val;
+       int val2;
+} sx9324_samp_freq_table[] = {
+       { 1000, 0 },  /* 00000: Min (no idle time) */
+       { 500, 0 },  /* 00001: 2 ms */
+       { 250, 0 },  /* 00010: 4 ms */
+       { 166, 666666 },  /* 00011: 6 ms */
+       { 125, 0 },  /* 00100: 8 ms */
+       { 100, 0 },  /* 00101: 10 ms */
+       { 71, 428571 },  /* 00110: 14 ms */
+       { 55, 555556 },  /* 00111: 18 ms */
+       { 45, 454545 },  /* 01000: 22 ms */
+       { 38, 461538 },  /* 01001: 26 ms */
+       { 33, 333333 },  /* 01010: 30 ms */
+       { 29, 411765 },  /* 01011: 34 ms */
+       { 26, 315789 },  /* 01100: 38 ms */
+       { 23, 809524 },  /* 01101: 42 ms */
+       { 21, 739130 },  /* 01110: 46 ms */
+       { 20, 0 },  /* 01111: 50 ms */
+       { 17, 857143 },  /* 10000: 56 ms */
+       { 16, 129032 },  /* 10001: 62 ms */
+       { 14, 705882 },  /* 10010: 68 ms */
+       { 13, 513514 },  /* 10011: 74 ms */
+       { 12, 500000 },  /* 10100: 80 ms */
+       { 11, 111111 },  /* 10101: 90 ms */
+       { 10, 0 },  /* 10110: 100 ms (Typ.) */
+       { 5, 0 },  /* 10111: 200 ms */
+       { 3, 333333 },  /* 11000: 300 ms */
+       { 2, 500000 },  /* 11001: 400 ms */
+       { 1, 666667 },  /* 11010: 600 ms */
+       { 1, 250000 },  /* 11011: 800 ms */
+       { 1, 0 },  /* 11100: 1 s */
+       { 0, 500000 },  /* 11101: 2 s */
+       { 0, 333333 },  /* 11110: 3 s */
+       { 0, 250000 },  /* 11111: 4 s */
+};
+
+static const unsigned int sx9324_scan_period_table[] = {
+       2,   15,  30,  45,   60,   90,   120,  200,
+       400, 600, 800, 1000, 2000, 3000, 4000, 5000,
+};
+
+static const struct regmap_range sx9324_writable_reg_ranges[] = {
+       /*
+        * To set COMPSTAT for compensation, even if datasheet says register is
+        * RO.
+        */
+       regmap_reg_range(SX9324_REG_STAT2, SX9324_REG_STAT2),
+       regmap_reg_range(SX9324_REG_IRQ_MSK, SX9324_REG_IRQ_CFG2),
+       regmap_reg_range(SX9324_REG_GNRL_CTRL0, SX9324_REG_GNRL_CTRL1),
+       /* Leave i2c and clock spreading as unavailable */
+       regmap_reg_range(SX9324_REG_AFE_CTRL0, SX9324_REG_AFE_CTRL9),
+       regmap_reg_range(SX9324_REG_PROX_CTRL0, SX9324_REG_PROX_CTRL7),
+       regmap_reg_range(SX9324_REG_ADV_CTRL0, SX9324_REG_ADV_CTRL20),
+       regmap_reg_range(SX9324_REG_PHASE_SEL, SX9324_REG_PHASE_SEL),
+       regmap_reg_range(SX9324_REG_OFFSET_MSB, SX9324_REG_OFFSET_LSB),
+       regmap_reg_range(SX9324_REG_RESET, SX9324_REG_RESET),
+};
+
+static const struct regmap_access_table sx9324_writeable_regs = {
+       .yes_ranges = sx9324_writable_reg_ranges,
+       .n_yes_ranges = ARRAY_SIZE(sx9324_writable_reg_ranges),
+};
+
+/*
+ * All allocated registers are readable, so we just list unallocated
+ * ones.
+ */
+static const struct regmap_range sx9324_non_readable_reg_ranges[] = {
+       regmap_reg_range(SX9324_REG_IRQ_CFG2 + 1, SX9324_REG_GNRL_CTRL0 - 1),
+       regmap_reg_range(SX9324_REG_GNRL_CTRL1 + 1, SX9324_REG_AFE_CTRL0 - 1),
+       regmap_reg_range(SX9324_REG_AFE_CTRL9 + 1, SX9324_REG_PROX_CTRL0 - 1),
+       regmap_reg_range(SX9324_REG_PROX_CTRL7 + 1, SX9324_REG_ADV_CTRL0 - 1),
+       regmap_reg_range(SX9324_REG_ADV_CTRL20 + 1, SX9324_REG_PHASE_SEL - 1),
+       regmap_reg_range(SX9324_REG_SAR_LSB + 1, SX9324_REG_RESET - 1),
+       regmap_reg_range(SX9324_REG_RESET + 1, SX9324_REG_WHOAMI - 1),
+       regmap_reg_range(SX9324_REG_WHOAMI + 1, SX9324_REG_REVISION - 1),
+};
+
+static const struct regmap_access_table sx9324_readable_regs = {
+       .no_ranges = sx9324_non_readable_reg_ranges,
+       .n_no_ranges = ARRAY_SIZE(sx9324_non_readable_reg_ranges),
+};
+
+static const struct regmap_range sx9324_volatile_reg_ranges[] = {
+       regmap_reg_range(SX9324_REG_IRQ_SRC, SX9324_REG_STAT3),
+       regmap_reg_range(SX9324_REG_USEFUL_MSB, SX9324_REG_DIFF_LSB),
+       regmap_reg_range(SX9324_REG_SAR_MSB, SX9324_REG_SAR_LSB),
+       regmap_reg_range(SX9324_REG_WHOAMI, SX9324_REG_WHOAMI),
+       regmap_reg_range(SX9324_REG_REVISION, SX9324_REG_REVISION),
+};
+
+static const struct regmap_access_table sx9324_volatile_regs = {
+       .yes_ranges = sx9324_volatile_reg_ranges,
+       .n_yes_ranges = ARRAY_SIZE(sx9324_volatile_reg_ranges),
+};
+
+static const struct regmap_config sx9324_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = SX9324_REG_REVISION,
+       .cache_type = REGCACHE_RBTREE,
+
+       .wr_table = &sx9324_writeable_regs,
+       .rd_table = &sx9324_readable_regs,
+       .volatile_table = &sx9324_volatile_regs,
+};
+
+static int sx9324_read_prox_data(struct sx_common_data *data,
+                                const struct iio_chan_spec *chan,
+                                __be16 *val)
+{
+       int ret;
+
+       ret = regmap_write(data->regmap, SX9324_REG_PHASE_SEL, chan->channel);
+       if (ret < 0)
+               return ret;
+
+       return regmap_bulk_read(data->regmap, chan->address, val, sizeof(*val));
+}
+
+/*
+ * If we have no interrupt support, we have to wait for a scan period
+ * after enabling a channel to get a result.
+ */
+static int sx9324_wait_for_sample(struct sx_common_data *data)
+{
+       int ret;
+       unsigned int val;
+
+       ret = regmap_read(data->regmap, SX9324_REG_GNRL_CTRL0, &val);
+       if (ret < 0)
+               return ret;
+       val = FIELD_GET(SX9324_REG_GNRL_CTRL0_SCANPERIOD_MASK, val);
+
+       msleep(sx9324_scan_period_table[val]);
+
+       return 0;
+}
+
+static int sx9324_read_gain(struct sx_common_data *data,
+                           const struct iio_chan_spec *chan, int *val)
+{
+       unsigned int reg, regval;
+       int ret;
+
+       reg = SX9324_REG_PROX_CTRL0 + chan->channel / 2;
+       ret = regmap_read(data->regmap, reg, &regval);
+       if (ret)
+               return ret;
+
+       *val = 1 << FIELD_GET(SX9324_REG_PROX_CTRL0_GAIN_MASK, regval);
+
+       return IIO_VAL_INT;
+}
+
+static int sx9324_read_samp_freq(struct sx_common_data *data,
+                                int *val, int *val2)
+{
+       int ret;
+       unsigned int regval;
+
+       ret = regmap_read(data->regmap, SX9324_REG_GNRL_CTRL0, &regval);
+       if (ret)
+               return ret;
+
+       regval = FIELD_GET(SX9324_REG_GNRL_CTRL0_SCANPERIOD_MASK, regval);
+       *val = sx9324_samp_freq_table[regval].val;
+       *val2 = sx9324_samp_freq_table[regval].val2;
+
+       return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int sx9324_read_raw(struct iio_dev *indio_dev,
+                          const struct iio_chan_spec *chan,
+                          int *val, int *val2, long mask)
+{
+       struct sx_common_data *data = iio_priv(indio_dev);
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (ret)
+                       return ret;
+
+               ret = sx_common_read_proximity(data, chan, val);
+               iio_device_release_direct_mode(indio_dev);
+               return ret;
+       case IIO_CHAN_INFO_HARDWAREGAIN:
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (ret)
+                       return ret;
+
+               ret = sx9324_read_gain(data, chan, val);
+               iio_device_release_direct_mode(indio_dev);
+               return ret;
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               return sx9324_read_samp_freq(data, val, val2);
+       default:
+               return -EINVAL;
+       }
+}
+
+static const int sx9324_gain_vals[] = { 1, 2, 4, 8 };
+
+static int sx9324_read_avail(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            const int **vals, int *type, int *length,
+                            long mask)
+{
+       if (chan->type != IIO_PROXIMITY)
+               return -EINVAL;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_HARDWAREGAIN:
+               *type = IIO_VAL_INT;
+               *length = ARRAY_SIZE(sx9324_gain_vals);
+               *vals = sx9324_gain_vals;
+               return IIO_AVAIL_LIST;
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               *type = IIO_VAL_INT_PLUS_MICRO;
+               *length = ARRAY_SIZE(sx9324_samp_freq_table) * 2;
+               *vals = (int *)sx9324_samp_freq_table;
+               return IIO_AVAIL_LIST;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int sx9324_set_samp_freq(struct sx_common_data *data,
+                               int val, int val2)
+{
+       int i, ret;
+
+       for (i = 0; i < ARRAY_SIZE(sx9324_samp_freq_table); i++)
+               if (val == sx9324_samp_freq_table[i].val &&
+                   val2 == sx9324_samp_freq_table[i].val2)
+                       break;
+
+       if (i == ARRAY_SIZE(sx9324_samp_freq_table))
+               return -EINVAL;
+
+       mutex_lock(&data->mutex);
+
+       ret = regmap_update_bits(data->regmap,
+                                SX9324_REG_GNRL_CTRL0,
+                                SX9324_REG_GNRL_CTRL0_SCANPERIOD_MASK, i);
+
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static int sx9324_read_thresh(struct sx_common_data *data,
+                             const struct iio_chan_spec *chan, int *val)
+{
+       unsigned int regval;
+       unsigned int reg;
+       int ret;
+
+       /*
+        * TODO(gwendal): Depending on the phase function
+        * (proximity/table/body), retrieve the right threshold.
+        * For now, return the proximity threshold.
+        */
+       reg = SX9324_REG_PROX_CTRL6 + chan->channel / 2;
+       ret = regmap_read(data->regmap, reg, &regval);
+       if (ret)
+               return ret;
+
+       if (regval <= 1)
+               *val = regval;
+       else
+               *val = (regval * regval) / 2;
+
+       return IIO_VAL_INT;
+}
+
+static int sx9324_read_hysteresis(struct sx_common_data *data,
+                                 const struct iio_chan_spec *chan, int *val)
+{
+       unsigned int regval, pthresh;
+       int ret;
+
+       ret = sx9324_read_thresh(data, chan, &pthresh);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_read(data->regmap, SX9324_REG_PROX_CTRL5, &regval);
+       if (ret)
+               return ret;
+
+       regval = FIELD_GET(SX9324_REG_PROX_CTRL5_HYST_MASK, regval);
+       if (!regval)
+               *val = 0;
+       else
+               *val = pthresh >> (5 - regval);
+
+       return IIO_VAL_INT;
+}
+
+static int sx9324_read_far_debounce(struct sx_common_data *data, int *val)
+{
+       unsigned int regval;
+       int ret;
+
+       ret = regmap_read(data->regmap, SX9324_REG_PROX_CTRL5, &regval);
+       if (ret)
+               return ret;
+
+       regval = FIELD_GET(SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK, regval);
+       if (regval)
+               *val = 1 << regval;
+       else
+               *val = 0;
+
+       return IIO_VAL_INT;
+}
+
+static int sx9324_read_close_debounce(struct sx_common_data *data, int *val)
+{
+       unsigned int regval;
+       int ret;
+
+       ret = regmap_read(data->regmap, SX9324_REG_PROX_CTRL5, &regval);
+       if (ret)
+               return ret;
+
+       regval = FIELD_GET(SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK, regval);
+       if (regval)
+               *val = 1 << regval;
+       else
+               *val = 0;
+
+       return IIO_VAL_INT;
+}
+
+static int sx9324_read_event_val(struct iio_dev *indio_dev,
+                                const struct iio_chan_spec *chan,
+                                enum iio_event_type type,
+                                enum iio_event_direction dir,
+                                enum iio_event_info info, int *val, int *val2)
+{
+       struct sx_common_data *data = iio_priv(indio_dev);
+
+       if (chan->type != IIO_PROXIMITY)
+               return -EINVAL;
+
+       switch (info) {
+       case IIO_EV_INFO_VALUE:
+               return sx9324_read_thresh(data, chan, val);
+       case IIO_EV_INFO_PERIOD:
+               switch (dir) {
+               case IIO_EV_DIR_RISING:
+                       return sx9324_read_far_debounce(data, val);
+               case IIO_EV_DIR_FALLING:
+                       return sx9324_read_close_debounce(data, val);
+               default:
+                       return -EINVAL;
+               }
+       case IIO_EV_INFO_HYSTERESIS:
+               return sx9324_read_hysteresis(data, chan, val);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int sx9324_write_thresh(struct sx_common_data *data,
+                              const struct iio_chan_spec *chan, int _val)
+{
+       unsigned int reg, val = _val;
+       int ret;
+
+       reg = SX9324_REG_PROX_CTRL6 + chan->channel / 2;
+
+       if (val >= 1)
+               val = int_sqrt(2 * val);
+
+       if (val > 0xff)
+               return -EINVAL;
+
+       mutex_lock(&data->mutex);
+       ret = regmap_write(data->regmap, reg, val);
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static int sx9324_write_hysteresis(struct sx_common_data *data,
+                                  const struct iio_chan_spec *chan, int _val)
+{
+       unsigned int hyst, val = _val;
+       int ret, pthresh;
+
+       ret = sx9324_read_thresh(data, chan, &pthresh);
+       if (ret < 0)
+               return ret;
+
+       if (val == 0)
+               hyst = 0;
+       else if (val >= pthresh >> 2)
+               hyst = 3;
+       else if (val >= pthresh >> 3)
+               hyst = 2;
+       else if (val >= pthresh >> 4)
+               hyst = 1;
+       else
+               return -EINVAL;
+
+       hyst = FIELD_PREP(SX9324_REG_PROX_CTRL5_HYST_MASK, hyst);
+       mutex_lock(&data->mutex);
+       ret = regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5,
+                                SX9324_REG_PROX_CTRL5_HYST_MASK, hyst);
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static int sx9324_write_far_debounce(struct sx_common_data *data, int _val)
+{
+       unsigned int regval, val = _val;
+       int ret;
+
+       if (val > 0)
+               val = ilog2(val);
+       if (!FIELD_FIT(SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK, val))
+               return -EINVAL;
+
+       regval = FIELD_PREP(SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK, val);
+
+       mutex_lock(&data->mutex);
+       ret = regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5,
+                                SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK,
+                                regval);
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static int sx9324_write_close_debounce(struct sx_common_data *data, int _val)
+{
+       unsigned int regval, val = _val;
+       int ret;
+
+       if (val > 0)
+               val = ilog2(val);
+       if (!FIELD_FIT(SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK, val))
+               return -EINVAL;
+
+       regval = FIELD_PREP(SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK, val);
+
+       mutex_lock(&data->mutex);
+       ret = regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5,
+                                SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK,
+                                regval);
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static int sx9324_write_event_val(struct iio_dev *indio_dev,
+                                 const struct iio_chan_spec *chan,
+                                 enum iio_event_type type,
+                                 enum iio_event_direction dir,
+                                 enum iio_event_info info, int val, int val2)
+{
+       struct sx_common_data *data = iio_priv(indio_dev);
+
+       if (chan->type != IIO_PROXIMITY)
+               return -EINVAL;
+
+       switch (info) {
+       case IIO_EV_INFO_VALUE:
+               return sx9324_write_thresh(data, chan, val);
+       case IIO_EV_INFO_PERIOD:
+               switch (dir) {
+               case IIO_EV_DIR_RISING:
+                       return sx9324_write_far_debounce(data, val);
+               case IIO_EV_DIR_FALLING:
+                       return sx9324_write_close_debounce(data, val);
+               default:
+                       return -EINVAL;
+               }
+       case IIO_EV_INFO_HYSTERESIS:
+               return sx9324_write_hysteresis(data, chan, val);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int sx9324_write_gain(struct sx_common_data *data,
+                            const struct iio_chan_spec *chan, int val)
+{
+       unsigned int gain, reg;
+       int ret;
+
+       gain = ilog2(val);
+       reg = SX9324_REG_PROX_CTRL0 + chan->channel / 2;
+       gain = FIELD_PREP(SX9324_REG_PROX_CTRL0_GAIN_MASK, gain);
+
+       mutex_lock(&data->mutex);
+       ret = regmap_update_bits(data->regmap, reg,
+                                SX9324_REG_PROX_CTRL0_GAIN_MASK,
+                                gain);
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static int sx9324_write_raw(struct iio_dev *indio_dev,
+                           const struct iio_chan_spec *chan, int val, int val2,
+                           long mask)
+{
+       struct sx_common_data *data = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               return sx9324_set_samp_freq(data, val, val2);
+       case IIO_CHAN_INFO_HARDWAREGAIN:
+               return sx9324_write_gain(data, chan, val);
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct sx_common_reg_default sx9324_default_regs[] = {
+       { SX9324_REG_IRQ_MSK, 0x00 },
+       { SX9324_REG_IRQ_CFG0, 0x00 },
+       { SX9324_REG_IRQ_CFG1, SX9324_REG_IRQ_CFG1_FAILCOND },
+       { SX9324_REG_IRQ_CFG2, 0x00 },
+       { SX9324_REG_GNRL_CTRL0, SX9324_REG_GNRL_CTRL0_SCANPERIOD_100MS },
+       /*
+        * The lower 4 bits should not be set as it enable sensors measurements.
+        * Turning the detection on before the configuration values are set to
+        * good values can cause the device to return erroneous readings.
+        */
+       { SX9324_REG_GNRL_CTRL1, SX9324_REG_GNRL_CTRL1_PAUSECTRL },
+
+       { SX9324_REG_AFE_CTRL0, 0x00 },
+       { SX9324_REG_AFE_CTRL3, 0x00 },
+       { SX9324_REG_AFE_CTRL4, SX9324_REG_AFE_CTRL4_FREQ_83_33HZ |
+               SX9324_REG_AFE_CTRL4_RES_100 },
+       { SX9324_REG_AFE_CTRL6, 0x00 },
+       { SX9324_REG_AFE_CTRL7, SX9324_REG_AFE_CTRL4_FREQ_83_33HZ |
+               SX9324_REG_AFE_CTRL4_RES_100 },
+
+       /* TODO(gwendal): PHx use chip default or all grounded? */
+       { SX9324_REG_AFE_PH0, 0x29 },
+       { SX9324_REG_AFE_PH1, 0x26 },
+       { SX9324_REG_AFE_PH2, 0x1a },
+       { SX9324_REG_AFE_PH3, 0x16 },
+
+       { SX9324_REG_AFE_CTRL8, SX9324_REG_AFE_CTRL8_RESFILTN_4KOHM },
+       { SX9324_REG_AFE_CTRL9, SX9324_REG_AFE_CTRL9_AGAIN_1 },
+
+       { SX9324_REG_PROX_CTRL0, SX9324_REG_PROX_CTRL0_GAIN_1 |
+               SX9324_REG_PROX_CTRL0_RAWFILT_1P50 },
+       { SX9324_REG_PROX_CTRL1, SX9324_REG_PROX_CTRL0_GAIN_1 |
+               SX9324_REG_PROX_CTRL0_RAWFILT_1P50 },
+       { SX9324_REG_PROX_CTRL2, SX9324_REG_PROX_CTRL2_AVGNEG_THRESH_16K },
+       { SX9324_REG_PROX_CTRL3, SX9324_REG_PROX_CTRL3_AVGDEB_2SAMPLES |
+               SX9324_REG_PROX_CTRL3_AVGPOS_THRESH_16K },
+       { SX9324_REG_PROX_CTRL4, SX9324_REG_PROX_CTRL4_AVGNEG_FILT_2 |
+               SX9324_REG_PROX_CTRL3_AVGPOS_FILT_256 },
+       { SX9324_REG_PROX_CTRL5, 0x00 },
+       { SX9324_REG_PROX_CTRL6, SX9324_REG_PROX_CTRL6_PROXTHRESH_32 },
+       { SX9324_REG_PROX_CTRL7, SX9324_REG_PROX_CTRL6_PROXTHRESH_32 },
+       { SX9324_REG_ADV_CTRL0, 0x00 },
+       { SX9324_REG_ADV_CTRL1, 0x00 },
+       { SX9324_REG_ADV_CTRL2, 0x00 },
+       { SX9324_REG_ADV_CTRL3, 0x00 },
+       { SX9324_REG_ADV_CTRL4, 0x00 },
+       { SX9324_REG_ADV_CTRL5, SX9324_REG_ADV_CTRL5_STARTUP_SENSOR_1 |
+               SX9324_REG_ADV_CTRL5_STARTUP_METHOD_1 },
+       { SX9324_REG_ADV_CTRL6, 0x00 },
+       { SX9324_REG_ADV_CTRL7, 0x00 },
+       { SX9324_REG_ADV_CTRL8, 0x00 },
+       { SX9324_REG_ADV_CTRL9, 0x00 },
+       /* Body/Table threshold */
+       { SX9324_REG_ADV_CTRL10, 0x00 },
+       { SX9324_REG_ADV_CTRL11, 0x00 },
+       { SX9324_REG_ADV_CTRL12, 0x00 },
+       /* TODO(gwendal): SAR currenly disabled */
+       { SX9324_REG_ADV_CTRL13, 0x00 },
+       { SX9324_REG_ADV_CTRL14, 0x00 },
+       { SX9324_REG_ADV_CTRL15, 0x00 },
+       { SX9324_REG_ADV_CTRL16, 0x00 },
+       { SX9324_REG_ADV_CTRL17, 0x00 },
+       { SX9324_REG_ADV_CTRL18, 0x00 },
+       { SX9324_REG_ADV_CTRL19, SX9324_REG_ADV_CTRL19_HIGHT_FAILURE_THRESH_SATURATION },
+       { SX9324_REG_ADV_CTRL20, SX9324_REG_ADV_CTRL19_HIGHT_FAILURE_THRESH_SATURATION },
+};
+
+/* Activate all channels and perform an initial compensation. */
+static int sx9324_init_compensation(struct iio_dev *indio_dev)
+{
+       struct sx_common_data *data = iio_priv(indio_dev);
+       unsigned int val;
+       int ret;
+
+       /* run the compensation phase on all channels */
+       ret = regmap_update_bits(data->regmap, SX9324_REG_STAT2,
+                                SX9324_REG_STAT2_COMPSTAT_MASK,
+                                SX9324_REG_STAT2_COMPSTAT_MASK);
+       if (ret)
+               return ret;
+
+       return regmap_read_poll_timeout(data->regmap, SX9324_REG_STAT2, val,
+                                       !(val & SX9324_REG_STAT2_COMPSTAT_MASK),
+                                       20000, 2000000);
+}
+
+static const struct sx_common_reg_default *
+sx9324_get_default_reg(struct device *dev, int idx,
+                      struct sx_common_reg_default *reg_def)
+{
+#define SX9324_PIN_DEF "semtech,ph0-pin"
+#define SX9324_RESOLUTION_DEF "semtech,ph01-resolution"
+#define SX9324_PROXRAW_DEF "semtech,ph01-proxraw-strength"
+       unsigned int pin_defs[SX9324_NUM_PINS];
+       char prop[] = SX9324_PROXRAW_DEF;
+       u32 start = 0, raw = 0, pos = 0;
+       int ret, count, ph, pin;
+
+       memcpy(reg_def, &sx9324_default_regs[idx], sizeof(*reg_def));
+       switch (reg_def->reg) {
+       case SX9324_REG_AFE_PH0:
+       case SX9324_REG_AFE_PH1:
+       case SX9324_REG_AFE_PH2:
+       case SX9324_REG_AFE_PH3:
+               ph = reg_def->reg - SX9324_REG_AFE_PH0;
+               scnprintf(prop, ARRAY_SIZE(prop), "semtech,ph%d-pin", ph);
+
+               count = device_property_count_u32(dev, prop);
+               if (count != ARRAY_SIZE(pin_defs))
+                       break;
+               ret = device_property_read_u32_array(dev, prop, pin_defs,
+                                                    ARRAY_SIZE(pin_defs));
+               for (pin = 0; pin < SX9324_NUM_PINS; pin++)
+                       raw |= (pin_defs[pin] << (2 * pin)) &
+                              SX9324_REG_AFE_PH0_PIN_MASK(pin);
+               reg_def->def = raw;
+               break;
+       case SX9324_REG_AFE_CTRL4:
+       case SX9324_REG_AFE_CTRL7:
+               if (reg_def->reg == SX9324_REG_AFE_CTRL4)
+                       strncpy(prop, "semtech,ph01-resolution",
+                               ARRAY_SIZE(prop));
+               else
+                       strncpy(prop, "semtech,ph23-resolution",
+                               ARRAY_SIZE(prop));
+
+               ret = device_property_read_u32(dev, prop, &raw);
+               if (ret)
+                       break;
+
+               raw = ilog2(raw) - 3;
+
+               reg_def->def &= ~SX9324_REG_AFE_CTRL4_RESOLUTION_MASK;
+               reg_def->def |= FIELD_PREP(SX9324_REG_AFE_CTRL4_RESOLUTION_MASK,
+                                          raw);
+               break;
+       case SX9324_REG_ADV_CTRL5:
+               ret = device_property_read_u32(dev, "semtech,startup-sensor",
+                                              &start);
+               if (ret)
+                       break;
+
+               reg_def->def &= ~SX9324_REG_ADV_CTRL5_STARTUPSENS_MASK;
+               reg_def->def |= FIELD_PREP(SX9324_REG_ADV_CTRL5_STARTUPSENS_MASK,
+                                          start);
+               break;
+       case SX9324_REG_PROX_CTRL4:
+               ret = device_property_read_u32(dev, "semtech,avg-pos-strength",
+                                              &pos);
+               if (ret)
+                       break;
+
+               /* Powers of 2, except for a gap between 16 and 64 */
+               raw = clamp(ilog2(pos), 3, 11) - (pos >= 32 ? 4 : 3);
+
+               reg_def->def &= ~SX9324_REG_PROX_CTRL4_AVGPOSFILT_MASK;
+               reg_def->def |= FIELD_PREP(SX9324_REG_PROX_CTRL4_AVGPOSFILT_MASK,
+                                          raw);
+               break;
+       case SX9324_REG_PROX_CTRL0:
+       case SX9324_REG_PROX_CTRL1:
+               if (reg_def->reg == SX9324_REG_PROX_CTRL0)
+                       strncpy(prop, "semtech,ph01-proxraw-strength",
+                               ARRAY_SIZE(prop));
+               else
+                       strncpy(prop, "semtech,ph23-proxraw-strength",
+                               ARRAY_SIZE(prop));
+               ret = device_property_read_u32(dev, prop, &raw);
+               if (ret)
+                       break;
+
+               reg_def->def &= ~SX9324_REG_PROX_CTRL0_RAWFILT_MASK;
+               reg_def->def |= FIELD_PREP(SX9324_REG_PROX_CTRL0_RAWFILT_MASK,
+                                          raw);
+               break;
+       }
+       return reg_def;
+}
+
+static int sx9324_check_whoami(struct device *dev,
+                              struct iio_dev *indio_dev)
+{
+       /*
+        * Only one sensor for this driver. Assuming the device tree
+        * is correct, just set the sensor name.
+        */
+       indio_dev->name = "sx9324";
+       return 0;
+}
+
+static const struct sx_common_chip_info sx9324_chip_info = {
+       .reg_stat = SX9324_REG_STAT0,
+       .reg_irq_msk = SX9324_REG_IRQ_MSK,
+       .reg_enable_chan = SX9324_REG_GNRL_CTRL1,
+       .reg_reset = SX9324_REG_RESET,
+
+       .mask_enable_chan = SX9324_REG_GNRL_CTRL1_PHEN_MASK,
+       .irq_msk_offset = 3,
+       .num_channels = SX9324_NUM_CHANNELS,
+       .num_default_regs = ARRAY_SIZE(sx9324_default_regs),
+
+       .ops = {
+               .read_prox_data = sx9324_read_prox_data,
+               .check_whoami = sx9324_check_whoami,
+               .init_compensation = sx9324_init_compensation,
+               .wait_for_sample = sx9324_wait_for_sample,
+               .get_default_reg = sx9324_get_default_reg,
+       },
+
+       .iio_channels = sx9324_channels,
+       .num_iio_channels = ARRAY_SIZE(sx9324_channels),
+       .iio_info =  {
+               .read_raw = sx9324_read_raw,
+               .read_avail = sx9324_read_avail,
+               .read_event_value = sx9324_read_event_val,
+               .write_event_value = sx9324_write_event_val,
+               .write_raw = sx9324_write_raw,
+               .read_event_config = sx_common_read_event_config,
+               .write_event_config = sx_common_write_event_config,
+       },
+};
+
+static int sx9324_probe(struct i2c_client *client)
+{
+       return sx_common_probe(client, &sx9324_chip_info, &sx9324_regmap_config);
+}
+
+static int __maybe_unused sx9324_suspend(struct device *dev)
+{
+       struct sx_common_data *data = iio_priv(dev_get_drvdata(dev));
+       unsigned int regval;
+       int ret;
+
+       disable_irq_nosync(data->client->irq);
+
+       mutex_lock(&data->mutex);
+       ret = regmap_read(data->regmap, SX9324_REG_GNRL_CTRL1, &regval);
+
+       data->suspend_ctrl =
+               FIELD_GET(SX9324_REG_GNRL_CTRL1_PHEN_MASK, regval);
+
+       if (ret < 0)
+               goto out;
+
+       /* Disable all phases, send the device to sleep. */
+       ret = regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1, 0);
+
+out:
+       mutex_unlock(&data->mutex);
+       return ret;
+}
+
+static int __maybe_unused sx9324_resume(struct device *dev)
+{
+       struct sx_common_data *data = iio_priv(dev_get_drvdata(dev));
+       int ret;
+
+       mutex_lock(&data->mutex);
+       ret = regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1,
+                          data->suspend_ctrl | SX9324_REG_GNRL_CTRL1_PAUSECTRL);
+       mutex_unlock(&data->mutex);
+       if (ret)
+               return ret;
+
+       enable_irq(data->client->irq);
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(sx9324_pm_ops, sx9324_suspend, sx9324_resume);
+
+static const struct acpi_device_id sx9324_acpi_match[] = {
+       { "STH9324", SX9324_WHOAMI_VALUE },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, sx9324_acpi_match);
+
+static const struct of_device_id sx9324_of_match[] = {
+       { .compatible = "semtech,sx9324", (void *)SX9324_WHOAMI_VALUE },
+       { }
+};
+MODULE_DEVICE_TABLE(of, sx9324_of_match);
+
+static const struct i2c_device_id sx9324_id[] = {
+       { "sx9324", SX9324_WHOAMI_VALUE },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, sx9324_id);
+
+static struct i2c_driver sx9324_driver = {
+       .driver = {
+               .name   = "sx9324",
+               .acpi_match_table = sx9324_acpi_match,
+               .of_match_table = sx9324_of_match,
+               .pm = &sx9324_pm_ops,
+
+               /*
+                * Lots of i2c transfers in probe + over 200 ms waiting in
+                * sx9324_init_compensation() mean a slow probe; prefer async
+                * so we don't delay boot if we're builtin to the kernel.
+                */
+               .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+       },
+       .probe_new      = sx9324_probe,
+       .id_table       = sx9324_id,
+};
+module_i2c_driver(sx9324_driver);
+
+MODULE_AUTHOR("Gwendal Grignou <[email protected]>");
+MODULE_DESCRIPTION("Driver for Semtech SX9324 proximity sensor");
+MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(SEMTECH_PROX);
diff --git a/drivers/iio/proximity/sx9360.c b/drivers/iio/proximity/sx9360.c
new file mode 100644 (file)
index 0000000..3ebb30c
--- /dev/null
@@ -0,0 +1,893 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2021 Google LLC.
+ *
+ * Driver for Semtech's SX9360 capacitive proximity/button solution.
+ * Based on SX9360 driver and copy of datasheet at:
+ * https://edit.wpgdadawant.com/uploads/news_file/program/2019/30184/tech_files/program_30184_suggest_other_file.pdf
+ */
+
+#include <linux/acpi.h>
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/log2.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+#include <linux/iio/iio.h>
+
+#include "sx_common.h"
+
+/* Nominal Oscillator Frequency. */
+#define SX9360_FOSC_MHZ                        4
+#define SX9360_FOSC_HZ                 (SX9360_FOSC_MHZ * 1000000)
+
+/* Register definitions. */
+#define SX9360_REG_IRQ_SRC             SX_COMMON_REG_IRQ_SRC
+#define SX9360_REG_STAT                0x01
+#define SX9360_REG_STAT_COMPSTAT_MASK  GENMASK(2, 1)
+#define SX9360_REG_IRQ_MSK             0x02
+#define SX9360_CONVDONE_IRQ            BIT(0)
+#define SX9360_FAR_IRQ                 BIT(2)
+#define SX9360_CLOSE_IRQ               BIT(3)
+#define SX9360_REG_IRQ_CFG             0x03
+
+#define SX9360_REG_GNRL_CTRL0          0x10
+#define SX9360_REG_GNRL_CTRL0_PHEN_MASK GENMASK(1, 0)
+#define SX9360_REG_GNRL_CTRL1          0x11
+#define SX9360_REG_GNRL_CTRL1_SCANPERIOD_MASK GENMASK(2, 0)
+#define SX9360_REG_GNRL_CTRL2          0x12
+#define SX9360_REG_GNRL_CTRL2_PERIOD_102MS     0x32
+#define SX9360_REG_GNRL_REG_2_PERIOD_MS(_r)    \
+       (((_r) * 8192) / (SX9360_FOSC_HZ / 1000))
+#define SX9360_REG_GNRL_FREQ_2_REG(_f)  (((_f) * 8192) / SX9360_FOSC_HZ)
+#define SX9360_REG_GNRL_REG_2_FREQ(_r)  (SX9360_FOSC_HZ / ((_r) * 8192))
+
+#define SX9360_REG_AFE_CTRL1           0x21
+#define SX9360_REG_AFE_PARAM0_PHR      0x22
+#define SX9360_REG_AFE_PARAM1_PHR      0x23
+#define SX9360_REG_AFE_PARAM0_PHM      0x24
+#define SX9360_REG_AFE_PARAM0_RSVD             0x08
+#define SX9360_REG_AFE_PARAM0_RESOLUTION_MASK  GENMASK(2, 0)
+#define SX9360_REG_AFE_PARAM0_RESOLUTION_128   0x02
+#define SX9360_REG_AFE_PARAM1_PHM      0x25
+#define SX9360_REG_AFE_PARAM1_AGAIN_PHM_6PF    0x40
+#define SX9360_REG_AFE_PARAM1_FREQ_83_33HZ     0x06
+
+#define SX9360_REG_PROX_CTRL0_PHR      0x40
+#define SX9360_REG_PROX_CTRL0_PHM      0x41
+#define SX9360_REG_PROX_CTRL0_GAIN_MASK        GENMASK(5, 3)
+#define SX9360_REG_PROX_CTRL0_GAIN_1           0x80
+#define SX9360_REG_PROX_CTRL0_RAWFILT_MASK     GENMASK(2, 0)
+#define SX9360_REG_PROX_CTRL0_RAWFILT_1P50     0x01
+#define SX9360_REG_PROX_CTRL1          0x42
+#define SX9360_REG_PROX_CTRL1_AVGNEG_THRESH_MASK       GENMASK(5, 3)
+#define SX9360_REG_PROX_CTRL1_AVGNEG_THRESH_16K 0x20
+#define SX9360_REG_PROX_CTRL2          0x43
+#define SX9360_REG_PROX_CTRL2_AVGDEB_MASK      GENMASK(7, 6)
+#define SX9360_REG_PROX_CTRL2_AVGDEB_2SAMPLES  0x40
+#define SX9360_REG_PROX_CTRL2_AVGPOS_THRESH_16K        0x20
+#define SX9360_REG_PROX_CTRL3          0x44
+#define SX9360_REG_PROX_CTRL3_AVGNEG_FILT_MASK GENMASK(5, 3)
+#define SX9360_REG_PROX_CTRL3_AVGNEG_FILT_2    0x08
+#define SX9360_REG_PROX_CTRL3_AVGPOS_FILT_MASK GENMASK(2, 0)
+#define SX9360_REG_PROX_CTRL3_AVGPOS_FILT_256  0x04
+#define SX9360_REG_PROX_CTRL4          0x45
+#define SX9360_REG_PROX_CTRL4_HYST_MASK                        GENMASK(5, 4)
+#define SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK      GENMASK(3, 2)
+#define SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK                GENMASK(1, 0)
+#define SX9360_REG_PROX_CTRL5          0x46
+#define SX9360_REG_PROX_CTRL5_PROXTHRESH_32    0x08
+
+#define SX9360_REG_REF_CORR0           0x60
+#define SX9360_REG_REF_CORR1           0x61
+
+#define SX9360_REG_USEFUL_PHR_MSB              0x90
+#define SX9360_REG_USEFUL_PHR_LSB              0x91
+
+#define SX9360_REG_OFFSET_PMR_MSB              0x92
+#define SX9360_REG_OFFSET_PMR_LSB              0x93
+
+#define SX9360_REG_USEFUL_PHM_MSB              0x94
+#define SX9360_REG_USEFUL_PHM_LSB              0x95
+
+#define SX9360_REG_AVG_PHM_MSB         0x96
+#define SX9360_REG_AVG_PHM_LSB         0x97
+
+#define SX9360_REG_DIFF_PHM_MSB                0x98
+#define SX9360_REG_DIFF_PHM_LSB                0x99
+
+#define SX9360_REG_OFFSET_PHM_MSB              0x9a
+#define SX9360_REG_OFFSET_PHM_LSB              0x9b
+
+#define SX9360_REG_USE_FILTER_MSB              0x9a
+#define SX9360_REG_USE_FILTER_LSB              0x9b
+
+#define SX9360_REG_RESET               0xcf
+/* Write this to REG_RESET to do a soft reset. */
+#define SX9360_SOFT_RESET              0xde
+
+#define SX9360_REG_WHOAMI              0xfa
+#define   SX9360_WHOAMI_VALUE                          0x60
+
+#define SX9360_REG_REVISION            0xfe
+
+/* 2 channels, Phase Reference and Measurement. */
+#define SX9360_NUM_CHANNELS            2
+
+static const struct iio_chan_spec sx9360_channels[] = {
+       {
+               .type = IIO_PROXIMITY,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                                     BIT(IIO_CHAN_INFO_HARDWAREGAIN),
+               .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+               .info_mask_separate_available =
+                       BIT(IIO_CHAN_INFO_HARDWAREGAIN),
+               .info_mask_shared_by_all_available =
+                       BIT(IIO_CHAN_INFO_SAMP_FREQ),
+               .indexed = 1,
+               .address = SX9360_REG_USEFUL_PHR_MSB,
+               .channel = 0,
+               .scan_index = 0,
+               .scan_type = {
+                       .sign = 's',
+                       .realbits = 12,
+                       .storagebits = 16,
+                       .endianness = IIO_BE,
+               },
+       },
+       {
+               .type = IIO_PROXIMITY,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                                     BIT(IIO_CHAN_INFO_HARDWAREGAIN),
+               .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+               .info_mask_separate_available =
+                       BIT(IIO_CHAN_INFO_HARDWAREGAIN),
+               .info_mask_shared_by_all_available =
+                       BIT(IIO_CHAN_INFO_SAMP_FREQ),
+               .indexed = 1,
+               .address = SX9360_REG_USEFUL_PHM_MSB,
+               .event_spec = sx_common_events,
+               .num_event_specs = ARRAY_SIZE(sx_common_events),
+               .channel = 1,
+               .scan_index = 1,
+               .scan_type = {
+                       .sign = 's',
+                       .realbits = 12,
+                       .storagebits = 16,
+                       .endianness = IIO_BE,
+               },
+       },
+       IIO_CHAN_SOFT_TIMESTAMP(2),
+};
+
+/*
+ * Each entry contains the integer part (val) and the fractional part, in micro
+ * seconds. It conforms to the IIO output IIO_VAL_INT_PLUS_MICRO.
+ *
+ * The frequency control register holds the period, with a ~2ms increment.
+ * Therefore the smallest frequency is 4MHz / (2047 * 8192),
+ * The fastest is 4MHz / 8192.
+ * The interval is not linear, but given there is 2047 possible value,
+ * Returns the fake increment of (Max-Min)/2047
+ */
+static const struct {
+       int val;
+       int val2;
+} sx9360_samp_freq_interval[] = {
+       { 0, 281250 },  /* 4MHz / (8192 * 2047) */
+       { 0, 281250 },
+       { 448, 281250 },  /* 4MHz / 8192 */
+};
+
+static const struct regmap_range sx9360_writable_reg_ranges[] = {
+       /*
+        * To set COMPSTAT for compensation, even if datasheet says register is
+        * RO.
+        */
+       regmap_reg_range(SX9360_REG_STAT, SX9360_REG_IRQ_CFG),
+       regmap_reg_range(SX9360_REG_GNRL_CTRL0, SX9360_REG_GNRL_CTRL2),
+       regmap_reg_range(SX9360_REG_AFE_CTRL1, SX9360_REG_AFE_PARAM1_PHM),
+       regmap_reg_range(SX9360_REG_PROX_CTRL0_PHR, SX9360_REG_PROX_CTRL5),
+       regmap_reg_range(SX9360_REG_REF_CORR0, SX9360_REG_REF_CORR1),
+       regmap_reg_range(SX9360_REG_OFFSET_PMR_MSB, SX9360_REG_OFFSET_PMR_LSB),
+       regmap_reg_range(SX9360_REG_RESET, SX9360_REG_RESET),
+};
+
+static const struct regmap_access_table sx9360_writeable_regs = {
+       .yes_ranges = sx9360_writable_reg_ranges,
+       .n_yes_ranges = ARRAY_SIZE(sx9360_writable_reg_ranges),
+};
+
+/*
+ * All allocated registers are readable, so we just list unallocated
+ * ones.
+ */
+static const struct regmap_range sx9360_non_readable_reg_ranges[] = {
+       regmap_reg_range(SX9360_REG_IRQ_CFG + 1, SX9360_REG_GNRL_CTRL0 - 1),
+       regmap_reg_range(SX9360_REG_GNRL_CTRL2 + 1, SX9360_REG_AFE_CTRL1 - 1),
+       regmap_reg_range(SX9360_REG_AFE_PARAM1_PHM + 1,
+                        SX9360_REG_PROX_CTRL0_PHR - 1),
+       regmap_reg_range(SX9360_REG_PROX_CTRL5 + 1, SX9360_REG_REF_CORR0 - 1),
+       regmap_reg_range(SX9360_REG_REF_CORR1 + 1,
+                        SX9360_REG_USEFUL_PHR_MSB - 1),
+       regmap_reg_range(SX9360_REG_USE_FILTER_LSB + 1, SX9360_REG_RESET - 1),
+       regmap_reg_range(SX9360_REG_RESET + 1, SX9360_REG_WHOAMI - 1),
+       regmap_reg_range(SX9360_REG_WHOAMI + 1, SX9360_REG_REVISION - 1),
+};
+
+static const struct regmap_access_table sx9360_readable_regs = {
+       .no_ranges = sx9360_non_readable_reg_ranges,
+       .n_no_ranges = ARRAY_SIZE(sx9360_non_readable_reg_ranges),
+};
+
+static const struct regmap_range sx9360_volatile_reg_ranges[] = {
+       regmap_reg_range(SX9360_REG_IRQ_SRC, SX9360_REG_STAT),
+       regmap_reg_range(SX9360_REG_USEFUL_PHR_MSB, SX9360_REG_USE_FILTER_LSB),
+       regmap_reg_range(SX9360_REG_WHOAMI, SX9360_REG_WHOAMI),
+       regmap_reg_range(SX9360_REG_REVISION, SX9360_REG_REVISION),
+};
+
+static const struct regmap_access_table sx9360_volatile_regs = {
+       .yes_ranges = sx9360_volatile_reg_ranges,
+       .n_yes_ranges = ARRAY_SIZE(sx9360_volatile_reg_ranges),
+};
+
+static const struct regmap_config sx9360_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = SX9360_REG_REVISION,
+       .cache_type = REGCACHE_RBTREE,
+
+       .wr_table = &sx9360_writeable_regs,
+       .rd_table = &sx9360_readable_regs,
+       .volatile_table = &sx9360_volatile_regs,
+};
+
+static int sx9360_read_prox_data(struct sx_common_data *data,
+                                const struct iio_chan_spec *chan,
+                                __be16 *val)
+{
+       return regmap_bulk_read(data->regmap, chan->address, val, sizeof(*val));
+}
+
+/*
+ * If we have no interrupt support, we have to wait for a scan period
+ * after enabling a channel to get a result.
+ */
+static int sx9360_wait_for_sample(struct sx_common_data *data)
+{
+       int ret;
+       __be16 buf;
+
+       ret = regmap_bulk_read(data->regmap, SX9360_REG_GNRL_CTRL1,
+                              &buf, sizeof(buf));
+       if (ret < 0)
+               return ret;
+       msleep(SX9360_REG_GNRL_REG_2_PERIOD_MS(be16_to_cpu(buf)));
+
+       return 0;
+}
+
+static int sx9360_read_gain(struct sx_common_data *data,
+                           const struct iio_chan_spec *chan, int *val)
+{
+       unsigned int reg, regval;
+       int ret;
+
+       reg = SX9360_REG_PROX_CTRL0_PHR + chan->channel;
+       ret = regmap_read(data->regmap, reg, &regval);
+       if (ret)
+               return ret;
+
+       *val = 1 << FIELD_GET(SX9360_REG_PROX_CTRL0_GAIN_MASK, regval);
+
+       return IIO_VAL_INT;
+}
+
+static int sx9360_read_samp_freq(struct sx_common_data *data,
+                                int *val, int *val2)
+{
+       int ret, divisor;
+       __be16 buf;
+
+       ret = regmap_bulk_read(data->regmap, SX9360_REG_GNRL_CTRL1,
+                              &buf, sizeof(buf));
+       if (ret < 0)
+               return ret;
+       divisor = be16_to_cpu(buf);
+       if (divisor == 0) {
+               *val = 0;
+               return IIO_VAL_INT;
+       }
+
+       *val = SX9360_FOSC_HZ;
+       *val2 = divisor * 8192;
+
+       return IIO_VAL_FRACTIONAL;
+}
+
+static int sx9360_read_raw(struct iio_dev *indio_dev,
+                          const struct iio_chan_spec *chan,
+                          int *val, int *val2, long mask)
+{
+       struct sx_common_data *data = iio_priv(indio_dev);
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (ret)
+                       return ret;
+
+               ret = sx_common_read_proximity(data, chan, val);
+               iio_device_release_direct_mode(indio_dev);
+               return ret;
+       case IIO_CHAN_INFO_HARDWAREGAIN:
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (ret)
+                       return ret;
+
+               ret = sx9360_read_gain(data, chan, val);
+               iio_device_release_direct_mode(indio_dev);
+               return ret;
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               return sx9360_read_samp_freq(data, val, val2);
+       default:
+               return -EINVAL;
+       }
+}
+
+static const char *sx9360_channel_labels[SX9360_NUM_CHANNELS] = {
+       "reference", "main",
+};
+
+static int sx9360_read_label(struct iio_dev *iio_dev, const struct iio_chan_spec *chan,
+                            char *label)
+{
+       return sysfs_emit(label, "%s\n", sx9360_channel_labels[chan->channel]);
+}
+
+static const int sx9360_gain_vals[] = { 1, 2, 4, 8 };
+
+static int sx9360_read_avail(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            const int **vals, int *type, int *length,
+                            long mask)
+{
+       if (chan->type != IIO_PROXIMITY)
+               return -EINVAL;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_HARDWAREGAIN:
+               *type = IIO_VAL_INT;
+               *length = ARRAY_SIZE(sx9360_gain_vals);
+               *vals = sx9360_gain_vals;
+               return IIO_AVAIL_LIST;
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               *type = IIO_VAL_INT_PLUS_MICRO;
+               *length = ARRAY_SIZE(sx9360_samp_freq_interval) * 2;
+               *vals = (int *)sx9360_samp_freq_interval;
+               return IIO_AVAIL_RANGE;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int sx9360_set_samp_freq(struct sx_common_data *data,
+                               int val, int val2)
+{
+       int ret, reg;
+       __be16 buf;
+
+       reg = val * 8192 / SX9360_FOSC_HZ + val2 * 8192 / (SX9360_FOSC_MHZ);
+       buf = cpu_to_be16(reg);
+       mutex_lock(&data->mutex);
+
+       ret = regmap_bulk_write(data->regmap, SX9360_REG_GNRL_CTRL1, &buf,
+                               sizeof(buf));
+
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static int sx9360_read_thresh(struct sx_common_data *data, int *val)
+{
+       unsigned int regval;
+       int ret;
+
+       ret = regmap_read(data->regmap, SX9360_REG_PROX_CTRL5, &regval);
+       if (ret)
+               return ret;
+
+       if (regval <= 1)
+               *val = regval;
+       else
+               *val = (regval * regval) / 2;
+
+       return IIO_VAL_INT;
+}
+
+static int sx9360_read_hysteresis(struct sx_common_data *data, int *val)
+{
+       unsigned int regval, pthresh;
+       int ret;
+
+       ret = sx9360_read_thresh(data, &pthresh);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_read(data->regmap, SX9360_REG_PROX_CTRL4, &regval);
+       if (ret)
+               return ret;
+
+       regval = FIELD_GET(SX9360_REG_PROX_CTRL4_HYST_MASK, regval);
+       if (!regval)
+               *val = 0;
+       else
+               *val = pthresh >> (5 - regval);
+
+       return IIO_VAL_INT;
+}
+
+static int sx9360_read_far_debounce(struct sx_common_data *data, int *val)
+{
+       unsigned int regval;
+       int ret;
+
+       ret = regmap_read(data->regmap, SX9360_REG_PROX_CTRL4, &regval);
+       if (ret)
+               return ret;
+
+       regval = FIELD_GET(SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK, regval);
+       if (regval)
+               *val = 1 << regval;
+       else
+               *val = 0;
+
+       return IIO_VAL_INT;
+}
+
+static int sx9360_read_close_debounce(struct sx_common_data *data, int *val)
+{
+       unsigned int regval;
+       int ret;
+
+       ret = regmap_read(data->regmap, SX9360_REG_PROX_CTRL4, &regval);
+       if (ret)
+               return ret;
+
+       regval = FIELD_GET(SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK, regval);
+       if (regval)
+               *val = 1 << regval;
+       else
+               *val = 0;
+
+       return IIO_VAL_INT;
+}
+
+static int sx9360_read_event_val(struct iio_dev *indio_dev,
+                                const struct iio_chan_spec *chan,
+                                enum iio_event_type type,
+                                enum iio_event_direction dir,
+                                enum iio_event_info info, int *val, int *val2)
+{
+       struct sx_common_data *data = iio_priv(indio_dev);
+
+       if (chan->type != IIO_PROXIMITY)
+               return -EINVAL;
+
+       switch (info) {
+       case IIO_EV_INFO_VALUE:
+               return sx9360_read_thresh(data, val);
+       case IIO_EV_INFO_PERIOD:
+               switch (dir) {
+               case IIO_EV_DIR_RISING:
+                       return sx9360_read_far_debounce(data, val);
+               case IIO_EV_DIR_FALLING:
+                       return sx9360_read_close_debounce(data, val);
+               default:
+                       return -EINVAL;
+               }
+       case IIO_EV_INFO_HYSTERESIS:
+               return sx9360_read_hysteresis(data, val);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int sx9360_write_thresh(struct sx_common_data *data, int _val)
+{
+       unsigned int val = _val;
+       int ret;
+
+       if (val >= 1)
+               val = int_sqrt(2 * val);
+
+       if (val > 0xff)
+               return -EINVAL;
+
+       mutex_lock(&data->mutex);
+       ret = regmap_write(data->regmap, SX9360_REG_PROX_CTRL5, val);
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static int sx9360_write_hysteresis(struct sx_common_data *data, int _val)
+{
+       unsigned int hyst, val = _val;
+       int ret, pthresh;
+
+       ret = sx9360_read_thresh(data, &pthresh);
+       if (ret < 0)
+               return ret;
+
+       if (val == 0)
+               hyst = 0;
+       else if (val >= pthresh >> 2)
+               hyst = 3;
+       else if (val >= pthresh >> 3)
+               hyst = 2;
+       else if (val >= pthresh >> 4)
+               hyst = 1;
+       else
+               return -EINVAL;
+
+       hyst = FIELD_PREP(SX9360_REG_PROX_CTRL4_HYST_MASK, hyst);
+       mutex_lock(&data->mutex);
+       ret = regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4,
+                                SX9360_REG_PROX_CTRL4_HYST_MASK, hyst);
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static int sx9360_write_far_debounce(struct sx_common_data *data, int _val)
+{
+       unsigned int regval, val = _val;
+       int ret;
+
+       if (val > 0)
+               val = ilog2(val);
+       if (!FIELD_FIT(SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK, val))
+               return -EINVAL;
+
+       regval = FIELD_PREP(SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK, val);
+
+       mutex_lock(&data->mutex);
+       ret = regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4,
+                                SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK,
+                                regval);
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static int sx9360_write_close_debounce(struct sx_common_data *data, int _val)
+{
+       unsigned int regval, val = _val;
+       int ret;
+
+       if (val > 0)
+               val = ilog2(val);
+       if (!FIELD_FIT(SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK, val))
+               return -EINVAL;
+
+       regval = FIELD_PREP(SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK, val);
+
+       mutex_lock(&data->mutex);
+       ret = regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4,
+                                SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK,
+                                regval);
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static int sx9360_write_event_val(struct iio_dev *indio_dev,
+                                 const struct iio_chan_spec *chan,
+                                 enum iio_event_type type,
+                                 enum iio_event_direction dir,
+                                 enum iio_event_info info, int val, int val2)
+{
+       struct sx_common_data *data = iio_priv(indio_dev);
+
+       if (chan->type != IIO_PROXIMITY)
+               return -EINVAL;
+
+       switch (info) {
+       case IIO_EV_INFO_VALUE:
+               return sx9360_write_thresh(data, val);
+       case IIO_EV_INFO_PERIOD:
+               switch (dir) {
+               case IIO_EV_DIR_RISING:
+                       return sx9360_write_far_debounce(data, val);
+               case IIO_EV_DIR_FALLING:
+                       return sx9360_write_close_debounce(data, val);
+               default:
+                       return -EINVAL;
+               }
+       case IIO_EV_INFO_HYSTERESIS:
+               return sx9360_write_hysteresis(data, val);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int sx9360_write_gain(struct sx_common_data *data,
+                            const struct iio_chan_spec *chan, int val)
+{
+       unsigned int gain, reg;
+       int ret;
+
+       gain = ilog2(val);
+       reg = SX9360_REG_PROX_CTRL0_PHR + chan->channel;
+       gain = FIELD_PREP(SX9360_REG_PROX_CTRL0_GAIN_MASK, gain);
+
+       mutex_lock(&data->mutex);
+       ret = regmap_update_bits(data->regmap, reg,
+                                SX9360_REG_PROX_CTRL0_GAIN_MASK,
+                                gain);
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static int sx9360_write_raw(struct iio_dev *indio_dev,
+                           const struct iio_chan_spec *chan, int val, int val2,
+                           long mask)
+{
+       struct sx_common_data *data = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               return sx9360_set_samp_freq(data, val, val2);
+       case IIO_CHAN_INFO_HARDWAREGAIN:
+               return sx9360_write_gain(data, chan, val);
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct sx_common_reg_default sx9360_default_regs[] = {
+       { SX9360_REG_IRQ_MSK, 0x00 },
+       { SX9360_REG_IRQ_CFG, 0x00 },
+       /*
+        * The lower 2 bits should not be set as it enable sensors measurements.
+        * Turning the detection on before the configuration values are set to
+        * good values can cause the device to return erroneous readings.
+        */
+       { SX9360_REG_GNRL_CTRL0, 0x00 },
+       { SX9360_REG_GNRL_CTRL1, 0x00 },
+       { SX9360_REG_GNRL_CTRL2, SX9360_REG_GNRL_CTRL2_PERIOD_102MS },
+
+       { SX9360_REG_AFE_CTRL1, 0x00 },
+       { SX9360_REG_AFE_PARAM0_PHR, SX9360_REG_AFE_PARAM0_RSVD |
+               SX9360_REG_AFE_PARAM0_RESOLUTION_128 },
+       { SX9360_REG_AFE_PARAM1_PHR, SX9360_REG_AFE_PARAM1_AGAIN_PHM_6PF |
+               SX9360_REG_AFE_PARAM1_FREQ_83_33HZ },
+       { SX9360_REG_AFE_PARAM0_PHM, SX9360_REG_AFE_PARAM0_RSVD |
+               SX9360_REG_AFE_PARAM0_RESOLUTION_128 },
+       { SX9360_REG_AFE_PARAM1_PHM, SX9360_REG_AFE_PARAM1_AGAIN_PHM_6PF |
+               SX9360_REG_AFE_PARAM1_FREQ_83_33HZ },
+
+       { SX9360_REG_PROX_CTRL0_PHR, SX9360_REG_PROX_CTRL0_GAIN_1 |
+               SX9360_REG_PROX_CTRL0_RAWFILT_1P50 },
+       { SX9360_REG_PROX_CTRL0_PHM, SX9360_REG_PROX_CTRL0_GAIN_1 |
+               SX9360_REG_PROX_CTRL0_RAWFILT_1P50 },
+       { SX9360_REG_PROX_CTRL1, SX9360_REG_PROX_CTRL1_AVGNEG_THRESH_16K },
+       { SX9360_REG_PROX_CTRL2, SX9360_REG_PROX_CTRL2_AVGDEB_2SAMPLES |
+               SX9360_REG_PROX_CTRL2_AVGPOS_THRESH_16K },
+       { SX9360_REG_PROX_CTRL3, SX9360_REG_PROX_CTRL3_AVGNEG_FILT_2 |
+               SX9360_REG_PROX_CTRL3_AVGPOS_FILT_256 },
+       { SX9360_REG_PROX_CTRL4, 0x00 },
+       { SX9360_REG_PROX_CTRL5, SX9360_REG_PROX_CTRL5_PROXTHRESH_32 },
+};
+
+/* Activate all channels and perform an initial compensation. */
+static int sx9360_init_compensation(struct iio_dev *indio_dev)
+{
+       struct sx_common_data *data = iio_priv(indio_dev);
+       unsigned int val;
+       int ret;
+
+       /* run the compensation phase on all channels */
+       ret = regmap_update_bits(data->regmap, SX9360_REG_STAT,
+                                SX9360_REG_STAT_COMPSTAT_MASK,
+                                SX9360_REG_STAT_COMPSTAT_MASK);
+       if (ret)
+               return ret;
+
+       return regmap_read_poll_timeout(data->regmap, SX9360_REG_STAT, val,
+                                      !(val & SX9360_REG_STAT_COMPSTAT_MASK),
+                                      20000, 2000000);
+}
+
+static const struct sx_common_reg_default *
+sx9360_get_default_reg(struct device *dev, int idx,
+                      struct sx_common_reg_default *reg_def)
+{
+       u32 raw = 0, pos = 0;
+       int ret;
+
+       memcpy(reg_def, &sx9360_default_regs[idx], sizeof(*reg_def));
+       switch (reg_def->reg) {
+       case SX9360_REG_AFE_PARAM0_PHR:
+       case SX9360_REG_AFE_PARAM0_PHM:
+               ret = device_property_read_u32(dev, "semtech,resolution", &raw);
+               if (ret)
+                       break;
+
+               raw = ilog2(raw) - 3;
+
+               reg_def->def &= ~SX9360_REG_AFE_PARAM0_RESOLUTION_MASK;
+               reg_def->def |= FIELD_PREP(SX9360_REG_AFE_PARAM0_RESOLUTION_MASK, raw);
+               break;
+       case SX9360_REG_PROX_CTRL0_PHR:
+       case SX9360_REG_PROX_CTRL0_PHM:
+               ret = device_property_read_u32(dev, "semtech,proxraw-strength", &raw);
+               if (ret)
+                       break;
+
+               reg_def->def &= ~SX9360_REG_PROX_CTRL0_RAWFILT_MASK;
+               reg_def->def |= FIELD_PREP(SX9360_REG_PROX_CTRL0_RAWFILT_MASK, raw);
+               break;
+       case SX9360_REG_PROX_CTRL3:
+               ret = device_property_read_u32(dev, "semtech,avg-pos-strength",
+                                              &pos);
+               if (ret)
+                       break;
+
+               /* Powers of 2, except for a gap between 16 and 64 */
+               raw = clamp(ilog2(pos), 3, 11) - (pos >= 32 ? 4 : 3);
+               reg_def->def &= ~SX9360_REG_PROX_CTRL3_AVGPOS_FILT_MASK;
+               reg_def->def |= FIELD_PREP(SX9360_REG_PROX_CTRL3_AVGPOS_FILT_MASK, raw);
+               break;
+       }
+
+       return reg_def;
+}
+
+static int sx9360_check_whoami(struct device *dev, struct iio_dev *indio_dev)
+{
+       /*
+        * Only one sensor for this driver. Assuming the device tree
+        * is correct, just set the sensor name.
+        */
+       indio_dev->name = "sx9360";
+       return 0;
+}
+
+static const struct sx_common_chip_info sx9360_chip_info = {
+       .reg_stat = SX9360_REG_STAT,
+       .reg_irq_msk = SX9360_REG_IRQ_MSK,
+       .reg_enable_chan = SX9360_REG_GNRL_CTRL0,
+       .reg_reset = SX9360_REG_RESET,
+
+       .mask_enable_chan = SX9360_REG_GNRL_CTRL0_PHEN_MASK,
+       .stat_offset = 2,
+       .num_channels = SX9360_NUM_CHANNELS,
+       .num_default_regs = ARRAY_SIZE(sx9360_default_regs),
+
+       .ops = {
+               .read_prox_data = sx9360_read_prox_data,
+               .check_whoami = sx9360_check_whoami,
+               .init_compensation = sx9360_init_compensation,
+               .wait_for_sample = sx9360_wait_for_sample,
+               .get_default_reg = sx9360_get_default_reg,
+       },
+
+       .iio_channels = sx9360_channels,
+       .num_iio_channels = ARRAY_SIZE(sx9360_channels),
+       .iio_info =  {
+               .read_raw = sx9360_read_raw,
+               .read_avail = sx9360_read_avail,
+               .read_label = sx9360_read_label,
+               .read_event_value = sx9360_read_event_val,
+               .write_event_value = sx9360_write_event_val,
+               .write_raw = sx9360_write_raw,
+               .read_event_config = sx_common_read_event_config,
+               .write_event_config = sx_common_write_event_config,
+       },
+};
+
+static int sx9360_probe(struct i2c_client *client)
+{
+       return sx_common_probe(client, &sx9360_chip_info, &sx9360_regmap_config);
+}
+
+static int __maybe_unused sx9360_suspend(struct device *dev)
+{
+       struct sx_common_data *data = iio_priv(dev_get_drvdata(dev));
+       unsigned int regval;
+       int ret;
+
+       disable_irq_nosync(data->client->irq);
+
+       mutex_lock(&data->mutex);
+       ret = regmap_read(data->regmap, SX9360_REG_GNRL_CTRL0, &regval);
+
+       data->suspend_ctrl =
+               FIELD_GET(SX9360_REG_GNRL_CTRL0_PHEN_MASK, regval);
+
+       if (ret < 0)
+               goto out;
+
+       /* Disable all phases, send the device to sleep. */
+       ret = regmap_write(data->regmap, SX9360_REG_GNRL_CTRL0, 0);
+
+out:
+       mutex_unlock(&data->mutex);
+       return ret;
+}
+
+static int __maybe_unused sx9360_resume(struct device *dev)
+{
+       struct sx_common_data *data = iio_priv(dev_get_drvdata(dev));
+       int ret;
+
+       mutex_lock(&data->mutex);
+       ret = regmap_update_bits(data->regmap, SX9360_REG_GNRL_CTRL0,
+                                SX9360_REG_GNRL_CTRL0_PHEN_MASK,
+                                data->suspend_ctrl);
+       mutex_unlock(&data->mutex);
+       if (ret)
+               return ret;
+
+       enable_irq(data->client->irq);
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(sx9360_pm_ops, sx9360_suspend, sx9360_resume);
+
+static const struct acpi_device_id sx9360_acpi_match[] = {
+       { "STH9360", SX9360_WHOAMI_VALUE },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, sx9360_acpi_match);
+
+static const struct of_device_id sx9360_of_match[] = {
+       { .compatible = "semtech,sx9360", (void *)SX9360_WHOAMI_VALUE },
+       { }
+};
+MODULE_DEVICE_TABLE(of, sx9360_of_match);
+
+static const struct i2c_device_id sx9360_id[] = {
+       {"sx9360", SX9360_WHOAMI_VALUE },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, sx9360_id);
+
+static struct i2c_driver sx9360_driver = {
+       .driver = {
+               .name   = "sx9360",
+               .acpi_match_table = sx9360_acpi_match,
+               .of_match_table = sx9360_of_match,
+               .pm = &sx9360_pm_ops,
+
+               /*
+                * Lots of i2c transfers in probe + over 200 ms waiting in
+                * sx9360_init_compensation() mean a slow probe; prefer async
+                * so we don't delay boot if we're builtin to the kernel.
+                */
+               .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+       },
+       .probe_new      = sx9360_probe,
+       .id_table       = sx9360_id,
+};
+module_i2c_driver(sx9360_driver);
+
+MODULE_AUTHOR("Gwendal Grignou <[email protected]>");
+MODULE_DESCRIPTION("Driver for Semtech SX9360 proximity sensor");
+MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(SEMTECH_PROX);
index 3e4ddb2e8c2bd81245a761d3b852fafe894508d5..42589d6200ad294f2f4e6516f7508e6e82f3e948 100644 (file)
@@ -993,7 +993,6 @@ static int sx9500_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int sx9500_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
@@ -1030,11 +1029,8 @@ static int sx9500_resume(struct device *dev)
 
        return ret;
 }
-#endif /* CONFIG_PM_SLEEP */
 
-static const struct dev_pm_ops sx9500_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(sx9500_suspend, sx9500_resume)
-};
+static DEFINE_SIMPLE_DEV_PM_OPS(sx9500_pm_ops, sx9500_suspend, sx9500_resume);
 
 static const struct acpi_device_id sx9500_acpi_match[] = {
        {"SSX9500", 0},
@@ -1060,7 +1056,7 @@ static struct i2c_driver sx9500_driver = {
                .name   = SX9500_DRIVER_NAME,
                .acpi_match_table = ACPI_PTR(sx9500_acpi_match),
                .of_match_table = of_match_ptr(sx9500_of_match),
-               .pm = &sx9500_pm_ops,
+               .pm = pm_sleep_ptr(&sx9500_pm_ops),
        },
        .probe          = sx9500_probe,
        .remove         = sx9500_remove,
diff --git a/drivers/iio/proximity/sx_common.c b/drivers/iio/proximity/sx_common.c
new file mode 100644 (file)
index 0000000..a7c0731
--- /dev/null
@@ -0,0 +1,572 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2021 Google LLC.
+ *
+ * Common part of most Semtech SAR sensor.
+ */
+
+#include <linux/acpi.h>
+#include <linux/bitops.h>
+#include <linux/byteorder/generic.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/interrupt.h>
+#include <linux/irqreturn.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <vdso/bits.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+
+#include "sx_common.h"
+
+/* All Semtech SAR sensors have IRQ bit in the same order. */
+#define   SX_COMMON_CONVDONE_IRQ                       BIT(0)
+#define   SX_COMMON_FAR_IRQ                            BIT(2)
+#define   SX_COMMON_CLOSE_IRQ                          BIT(3)
+
+const struct iio_event_spec sx_common_events[3] = {
+       {
+               .type = IIO_EV_TYPE_THRESH,
+               .dir = IIO_EV_DIR_RISING,
+               .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD),
+       },
+       {
+               .type = IIO_EV_TYPE_THRESH,
+               .dir = IIO_EV_DIR_FALLING,
+               .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD),
+       },
+       {
+               .type = IIO_EV_TYPE_THRESH,
+               .dir = IIO_EV_DIR_EITHER,
+               .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
+                                BIT(IIO_EV_INFO_HYSTERESIS) |
+                                BIT(IIO_EV_INFO_VALUE),
+       },
+};
+EXPORT_SYMBOL_NS_GPL(sx_common_events, SEMTECH_PROX);
+
+static irqreturn_t sx_common_irq_handler(int irq, void *private)
+{
+       struct iio_dev *indio_dev = private;
+       struct sx_common_data *data = iio_priv(indio_dev);
+
+       if (data->trigger_enabled)
+               iio_trigger_poll(data->trig);
+
+       /*
+        * Even if no event is enabled, we need to wake the thread to clear the
+        * interrupt state by reading SX_COMMON_REG_IRQ_SRC.
+        * It is not possible to do that here because regmap_read takes a mutex.
+        */
+       return IRQ_WAKE_THREAD;
+}
+
+static void sx_common_push_events(struct iio_dev *indio_dev)
+{
+       int ret;
+       unsigned int val, chan;
+       struct sx_common_data *data = iio_priv(indio_dev);
+       s64 timestamp = iio_get_time_ns(indio_dev);
+       unsigned long prox_changed;
+
+       /* Read proximity state on all channels */
+       ret = regmap_read(data->regmap, data->chip_info->reg_stat, &val);
+       if (ret) {
+               dev_err(&data->client->dev, "i2c transfer error in irq\n");
+               return;
+       }
+
+       val >>= data->chip_info->stat_offset;
+
+       /*
+        * Only iterate over channels with changes on proximity status that have
+        * events enabled.
+        */
+       prox_changed = (data->chan_prox_stat ^ val) & data->chan_event;
+
+       for_each_set_bit(chan, &prox_changed, data->chip_info->num_channels) {
+               int dir;
+               u64 ev;
+
+               dir = (val & BIT(chan)) ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
+               ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan,
+                                         IIO_EV_TYPE_THRESH, dir);
+
+               iio_push_event(indio_dev, ev, timestamp);
+       }
+       data->chan_prox_stat = val;
+}
+
+static int sx_common_enable_irq(struct sx_common_data *data, unsigned int irq)
+{
+       if (!data->client->irq)
+               return 0;
+       return regmap_update_bits(data->regmap, data->chip_info->reg_irq_msk,
+                                 irq << data->chip_info->irq_msk_offset,
+                                 irq << data->chip_info->irq_msk_offset);
+}
+
+static int sx_common_disable_irq(struct sx_common_data *data, unsigned int irq)
+{
+       if (!data->client->irq)
+               return 0;
+       return regmap_update_bits(data->regmap, data->chip_info->reg_irq_msk,
+                                 irq << data->chip_info->irq_msk_offset, 0);
+}
+
+static int sx_common_update_chan_en(struct sx_common_data *data,
+                                   unsigned long chan_read,
+                                   unsigned long chan_event)
+{
+       int ret;
+       unsigned long channels = chan_read | chan_event;
+
+       if ((data->chan_read | data->chan_event) != channels) {
+               ret = regmap_update_bits(data->regmap,
+                                        data->chip_info->reg_enable_chan,
+                                        data->chip_info->mask_enable_chan,
+                                        channels);
+               if (ret)
+                       return ret;
+       }
+       data->chan_read = chan_read;
+       data->chan_event = chan_event;
+       return 0;
+}
+
+static int sx_common_get_read_channel(struct sx_common_data *data, int channel)
+{
+       return sx_common_update_chan_en(data, data->chan_read | BIT(channel),
+                                    data->chan_event);
+}
+
+static int sx_common_put_read_channel(struct sx_common_data *data, int channel)
+{
+       return sx_common_update_chan_en(data, data->chan_read & ~BIT(channel),
+                                    data->chan_event);
+}
+
+static int sx_common_get_event_channel(struct sx_common_data *data, int channel)
+{
+       return sx_common_update_chan_en(data, data->chan_read,
+                                    data->chan_event | BIT(channel));
+}
+
+static int sx_common_put_event_channel(struct sx_common_data *data, int channel)
+{
+       return sx_common_update_chan_en(data, data->chan_read,
+                                    data->chan_event & ~BIT(channel));
+}
+
+/**
+ * sx_common_read_proximity() - Read raw proximity value.
+ * @data:      Internal data
+ * @chan:      Channel to read
+ * @val:       pointer to return read value.
+ *
+ * Request a conversion, wait for the sensor to be ready and
+ * return the raw proximity value.
+ */
+int sx_common_read_proximity(struct sx_common_data *data,
+                            const struct iio_chan_spec *chan, int *val)
+{
+       int ret;
+       __be16 rawval;
+
+       mutex_lock(&data->mutex);
+
+       ret = sx_common_get_read_channel(data, chan->channel);
+       if (ret)
+               goto out;
+
+       ret = sx_common_enable_irq(data, SX_COMMON_CONVDONE_IRQ);
+       if (ret)
+               goto out_put_channel;
+
+       mutex_unlock(&data->mutex);
+
+       if (data->client->irq) {
+               ret = wait_for_completion_interruptible(&data->completion);
+               reinit_completion(&data->completion);
+       } else {
+               ret = data->chip_info->ops.wait_for_sample(data);
+       }
+
+       mutex_lock(&data->mutex);
+
+       if (ret)
+               goto out_disable_irq;
+
+       ret = data->chip_info->ops.read_prox_data(data, chan, &rawval);
+       if (ret)
+               goto out_disable_irq;
+
+       *val = sign_extend32(be16_to_cpu(rawval), chan->scan_type.realbits - 1);
+
+       ret = sx_common_disable_irq(data, SX_COMMON_CONVDONE_IRQ);
+       if (ret)
+               goto out_put_channel;
+
+       ret = sx_common_put_read_channel(data, chan->channel);
+       if (ret)
+               goto out;
+
+       mutex_unlock(&data->mutex);
+
+       return IIO_VAL_INT;
+
+out_disable_irq:
+       sx_common_disable_irq(data, SX_COMMON_CONVDONE_IRQ);
+out_put_channel:
+       sx_common_put_read_channel(data, chan->channel);
+out:
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(sx_common_read_proximity, SEMTECH_PROX);
+
+/**
+ * sx_common_read_event_config() - Configure event setting.
+ * @indio_dev: iio device object
+ * @chan:      Channel to read
+ * @type:      Type of event (unused)
+ * @dir:       Direction of event (unused)
+ *
+ * return if the given channel is used for event gathering.
+ */
+int sx_common_read_event_config(struct iio_dev *indio_dev,
+                               const struct iio_chan_spec *chan,
+                               enum iio_event_type type,
+                               enum iio_event_direction dir)
+{
+       struct sx_common_data *data = iio_priv(indio_dev);
+
+       return !!(data->chan_event & BIT(chan->channel));
+}
+EXPORT_SYMBOL_NS_GPL(sx_common_read_event_config, SEMTECH_PROX);
+
+/**
+ * sx_common_write_event_config() - Configure event setting.
+ * @indio_dev: iio device object
+ * @chan:      Channel to enable
+ * @type:      Type of event (unused)
+ * @dir:       Direction of event (unused)
+ * @state:     State of the event.
+ *
+ * Enable/Disable event on a given channel.
+ */
+int sx_common_write_event_config(struct iio_dev *indio_dev,
+                                const struct iio_chan_spec *chan,
+                                enum iio_event_type type,
+                                enum iio_event_direction dir, int state)
+{
+       struct sx_common_data *data = iio_priv(indio_dev);
+       unsigned int eventirq = SX_COMMON_FAR_IRQ | SX_COMMON_CLOSE_IRQ;
+       int ret;
+
+       /* If the state hasn't changed, there's nothing to do. */
+       if (!!(data->chan_event & BIT(chan->channel)) == state)
+               return 0;
+
+       mutex_lock(&data->mutex);
+       if (state) {
+               ret = sx_common_get_event_channel(data, chan->channel);
+               if (ret)
+                       goto out_unlock;
+               if (!(data->chan_event & ~BIT(chan->channel))) {
+                       ret = sx_common_enable_irq(data, eventirq);
+                       if (ret)
+                               sx_common_put_event_channel(data, chan->channel);
+               }
+       } else {
+               ret = sx_common_put_event_channel(data, chan->channel);
+               if (ret)
+                       goto out_unlock;
+               if (!data->chan_event) {
+                       ret = sx_common_disable_irq(data, eventirq);
+                       if (ret)
+                               sx_common_get_event_channel(data, chan->channel);
+               }
+       }
+
+out_unlock:
+       mutex_unlock(&data->mutex);
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(sx_common_write_event_config, SEMTECH_PROX);
+
+static int sx_common_set_trigger_state(struct iio_trigger *trig, bool state)
+{
+       struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+       struct sx_common_data *data = iio_priv(indio_dev);
+       int ret = 0;
+
+       mutex_lock(&data->mutex);
+
+       if (state)
+               ret = sx_common_enable_irq(data, SX_COMMON_CONVDONE_IRQ);
+       else if (!data->chan_read)
+               ret = sx_common_disable_irq(data, SX_COMMON_CONVDONE_IRQ);
+       if (ret)
+               goto out;
+
+       data->trigger_enabled = state;
+
+out:
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static const struct iio_trigger_ops sx_common_trigger_ops = {
+       .set_trigger_state = sx_common_set_trigger_state,
+};
+
+static irqreturn_t sx_common_irq_thread_handler(int irq, void *private)
+{
+       struct iio_dev *indio_dev = private;
+       struct sx_common_data *data = iio_priv(indio_dev);
+       int ret;
+       unsigned int val;
+
+       mutex_lock(&data->mutex);
+
+       ret = regmap_read(data->regmap, SX_COMMON_REG_IRQ_SRC, &val);
+       if (ret) {
+               dev_err(&data->client->dev, "i2c transfer error in irq\n");
+               goto out;
+       }
+
+       if (val & ((SX_COMMON_FAR_IRQ | SX_COMMON_CLOSE_IRQ) << data->chip_info->irq_msk_offset))
+               sx_common_push_events(indio_dev);
+
+       if (val & (SX_COMMON_CONVDONE_IRQ << data->chip_info->irq_msk_offset))
+               complete(&data->completion);
+
+out:
+       mutex_unlock(&data->mutex);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t sx_common_trigger_handler(int irq, void *private)
+{
+       struct iio_poll_func *pf = private;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       struct sx_common_data *data = iio_priv(indio_dev);
+       __be16 val;
+       int bit, ret, i = 0;
+
+       mutex_lock(&data->mutex);
+
+       for_each_set_bit(bit, indio_dev->active_scan_mask,
+                        indio_dev->masklength) {
+               ret = data->chip_info->ops.read_prox_data(data,
+                                                    &indio_dev->channels[bit],
+                                                    &val);
+               if (ret)
+                       goto out;
+
+               data->buffer.channels[i++] = val;
+       }
+
+       iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer,
+                                          pf->timestamp);
+
+out:
+       mutex_unlock(&data->mutex);
+
+       iio_trigger_notify_done(indio_dev->trig);
+
+       return IRQ_HANDLED;
+}
+
+static int sx_common_buffer_preenable(struct iio_dev *indio_dev)
+{
+       struct sx_common_data *data = iio_priv(indio_dev);
+       unsigned long channels = 0;
+       int bit, ret;
+
+       mutex_lock(&data->mutex);
+       for_each_set_bit(bit, indio_dev->active_scan_mask,
+                        indio_dev->masklength)
+               __set_bit(indio_dev->channels[bit].channel, &channels);
+
+       ret = sx_common_update_chan_en(data, channels, data->chan_event);
+       mutex_unlock(&data->mutex);
+       return ret;
+}
+
+static int sx_common_buffer_postdisable(struct iio_dev *indio_dev)
+{
+       struct sx_common_data *data = iio_priv(indio_dev);
+       int ret;
+
+       mutex_lock(&data->mutex);
+       ret = sx_common_update_chan_en(data, 0, data->chan_event);
+       mutex_unlock(&data->mutex);
+       return ret;
+}
+
+static const struct iio_buffer_setup_ops sx_common_buffer_setup_ops = {
+       .preenable = sx_common_buffer_preenable,
+       .postdisable = sx_common_buffer_postdisable,
+};
+
+static void sx_common_regulator_disable(void *_data)
+{
+       struct sx_common_data *data = _data;
+
+       regulator_bulk_disable(ARRAY_SIZE(data->supplies), data->supplies);
+}
+
+#define SX_COMMON_SOFT_RESET                           0xde
+
+static int sx_common_init_device(struct iio_dev *indio_dev)
+{
+       struct sx_common_data *data = iio_priv(indio_dev);
+       struct sx_common_reg_default tmp;
+       const struct sx_common_reg_default *initval;
+       int ret;
+       unsigned int i, val;
+
+       ret = regmap_write(data->regmap, data->chip_info->reg_reset,
+                          SX_COMMON_SOFT_RESET);
+       if (ret)
+               return ret;
+
+       usleep_range(1000, 2000); /* power-up time is ~1ms. */
+
+       /* Clear reset interrupt state by reading SX_COMMON_REG_IRQ_SRC. */
+       ret = regmap_read(data->regmap, SX_COMMON_REG_IRQ_SRC, &val);
+       if (ret)
+               return ret;
+
+       /* Program defaults from constant or BIOS. */
+       for (i = 0; i < data->chip_info->num_default_regs; i++) {
+               initval = data->chip_info->ops.get_default_reg(&indio_dev->dev,
+                                                              i, &tmp);
+               ret = regmap_write(data->regmap, initval->reg, initval->def);
+               if (ret)
+                       return ret;
+       }
+
+       return data->chip_info->ops.init_compensation(indio_dev);
+}
+
+/**
+ * sx_common_probe() - Common setup for Semtech SAR sensor
+ * @client:            I2C client object
+ * @chip_info:         Semtech sensor chip information.
+ * @regmap_config:     Sensor registers map configuration.
+ */
+int sx_common_probe(struct i2c_client *client,
+                   const struct sx_common_chip_info *chip_info,
+                   const struct regmap_config *regmap_config)
+{
+       struct device *dev = &client->dev;
+       struct iio_dev *indio_dev;
+       struct sx_common_data *data;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       data = iio_priv(indio_dev);
+
+       data->chip_info = chip_info;
+       data->client = client;
+       data->supplies[0].supply = "vdd";
+       data->supplies[1].supply = "svdd";
+       mutex_init(&data->mutex);
+       init_completion(&data->completion);
+
+       data->regmap = devm_regmap_init_i2c(client, regmap_config);
+       if (IS_ERR(data->regmap))
+               return dev_err_probe(dev, PTR_ERR(data->regmap),
+                                    "Could init register map\n");
+
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
+                                     data->supplies);
+       if (ret)
+               return dev_err_probe(dev, ret, "Unable to get regulators\n");
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies), data->supplies);
+       if (ret)
+               return dev_err_probe(dev, ret, "Unable to enable regulators\n");
+
+       /* Must wait for Tpor time after initial power up */
+       usleep_range(1000, 1100);
+
+       ret = devm_add_action_or_reset(dev, sx_common_regulator_disable, data);
+       if (ret)
+               return dev_err_probe(dev, ret,
+                                    "Unable to register regulators deleter\n");
+
+       ret = data->chip_info->ops.check_whoami(dev, indio_dev);
+       if (ret)
+               return dev_err_probe(dev, ret, "error reading WHOAMI\n");
+
+       ACPI_COMPANION_SET(&indio_dev->dev, ACPI_COMPANION(dev));
+       indio_dev->modes = INDIO_DIRECT_MODE;
+
+       indio_dev->channels =  data->chip_info->iio_channels;
+       indio_dev->num_channels = data->chip_info->num_iio_channels;
+       indio_dev->info = &data->chip_info->iio_info;
+
+       i2c_set_clientdata(client, indio_dev);
+
+       ret = sx_common_init_device(indio_dev);
+       if (ret)
+               return dev_err_probe(dev, ret, "Unable to initialize sensor\n");
+
+       if (client->irq) {
+               ret = devm_request_threaded_irq(dev, client->irq,
+                                               sx_common_irq_handler,
+                                               sx_common_irq_thread_handler,
+                                               IRQF_ONESHOT,
+                                               "sx_event", indio_dev);
+               if (ret)
+                       return dev_err_probe(dev, ret, "No IRQ\n");
+
+               data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
+                                                   indio_dev->name,
+                                                   iio_device_id(indio_dev));
+               if (!data->trig)
+                       return -ENOMEM;
+
+               data->trig->ops = &sx_common_trigger_ops;
+               iio_trigger_set_drvdata(data->trig, indio_dev);
+
+               ret = devm_iio_trigger_register(dev, data->trig);
+               if (ret)
+                       return ret;
+       }
+
+       ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+                                             iio_pollfunc_store_time,
+                                             sx_common_trigger_handler,
+                                             &sx_common_buffer_setup_ops);
+       if (ret)
+               return ret;
+
+       return devm_iio_device_register(dev, indio_dev);
+}
+EXPORT_SYMBOL_NS_GPL(sx_common_probe, SEMTECH_PROX);
+
+MODULE_AUTHOR("Gwendal Grignou <[email protected]>");
+MODULE_DESCRIPTION("Common functions and structures for Semtech sensor");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/proximity/sx_common.h b/drivers/iio/proximity/sx_common.h
new file mode 100644 (file)
index 0000000..5d3edeb
--- /dev/null
@@ -0,0 +1,157 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2021 Google LLC.
+ *
+ * Code shared between most Semtech SAR sensor driver.
+ */
+
+#ifndef IIO_SX_COMMON_H
+#define IIO_SX_COMMON_H
+
+#include <linux/iio/iio.h>
+#include <linux/iio/types.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+
+struct device;
+struct i2c_client;
+struct regmap_config;
+struct sx_common_data;
+
+#define SX_COMMON_REG_IRQ_SRC                          0x00
+
+#define SX_COMMON_MAX_NUM_CHANNELS     4
+static_assert(SX_COMMON_MAX_NUM_CHANNELS < BITS_PER_LONG);
+
+struct sx_common_reg_default {
+       u8 reg;
+       u8 def;
+};
+
+/**
+ * struct sx_common_ops: function pointers needed by common code
+ *
+ * List functions needed by common code to gather information or configure
+ * the sensor.
+ *
+ * @read_prox_data:    Function to read raw proximity data.
+ * @check_whoami:      Set device name based on whoami register.
+ * @init_compensation: Function to set initial compensation.
+ * @wait_for_sample:   When there are no physical IRQ, function to wait for a
+ *                     sample to be ready.
+ * @get_default_reg:   Populate the initial value for a given register.
+ */
+struct sx_common_ops {
+       int (*read_prox_data)(struct sx_common_data *data,
+                             const struct iio_chan_spec *chan, __be16 *val);
+       int (*check_whoami)(struct device *dev, struct iio_dev *indio_dev);
+       int (*init_compensation)(struct iio_dev *indio_dev);
+       int (*wait_for_sample)(struct sx_common_data *data);
+       const struct sx_common_reg_default  *
+               (*get_default_reg)(struct device *dev, int idx,
+                                  struct sx_common_reg_default *reg_def);
+};
+
+/**
+ * struct sx_common_chip_info: Semtech Sensor private chip information
+ *
+ * @reg_stat:          Main status register address.
+ * @reg_irq_msk:       IRQ mask register address.
+ * @reg_enable_chan:   Address to enable/disable channels.
+ *                     Each phase presented by the sensor is an IIO channel..
+ * @reg_reset:         Reset register address.
+ * @mask_enable_chan:  Mask over the channels bits in the enable channel
+ *                     register.
+ * @stat_offset:       Offset to check phase status.
+ * @irq_msk_offset:    Offset to enable interrupt in the IRQ mask
+ *                     register.
+ * @num_channels:      Number of channels.
+ * @num_default_regs:  Number of internal registers that can be configured.
+ *
+ * @ops:               Private functions pointers.
+ * @iio_channels:      Description of exposed iio channels.
+ * @num_iio_channels:  Number of iio_channels.
+ * @iio_info:          iio_info structure for this driver.
+ */
+struct sx_common_chip_info {
+       unsigned int reg_stat;
+       unsigned int reg_irq_msk;
+       unsigned int reg_enable_chan;
+       unsigned int reg_reset;
+
+       unsigned int mask_enable_chan;
+       unsigned int stat_offset;
+       unsigned int irq_msk_offset;
+       unsigned int num_channels;
+       int num_default_regs;
+
+       struct sx_common_ops ops;
+
+       const struct iio_chan_spec *iio_channels;
+       int num_iio_channels;
+       struct iio_info iio_info;
+};
+
+/**
+ * struct sx_common_data: Semtech Sensor private data structure.
+ *
+ * @chip_info:         Structure defining sensor internals.
+ * @mutex:             Serialize access to registers and channel configuration.
+ * @completion:                completion object to wait for data acquisition.
+ * @client:            I2C client structure.
+ * @trig:              IIO trigger object.
+ * @regmap:            Register map.
+ * @num_default_regs:  Number of default registers to set at init.
+ * @supplies:          Power supplies object.
+ * @chan_prox_stat:    Last reading of the proximity status for each channel.
+ *                     We only send an event to user space when this changes.
+ * @trigger_enabled:   True when the device trigger is enabled.
+ * @buffer:            Buffer to store raw samples.
+ * @suspend_ctrl:      Remember enabled channels and sample rate during suspend.
+ * @chan_read:         Bit field for each raw channel enabled.
+ * @chan_event:                Bit field for each event enabled.
+ */
+struct sx_common_data {
+       const struct sx_common_chip_info *chip_info;
+
+       struct mutex mutex;
+       struct completion completion;
+       struct i2c_client *client;
+       struct iio_trigger *trig;
+       struct regmap *regmap;
+
+       struct regulator_bulk_data supplies[2];
+       unsigned long chan_prox_stat;
+       bool trigger_enabled;
+
+       /* Ensure correct alignment of timestamp when present. */
+       struct {
+               __be16 channels[SX_COMMON_MAX_NUM_CHANNELS];
+               s64 ts __aligned(8);
+       } buffer;
+
+       unsigned int suspend_ctrl;
+       unsigned long chan_read;
+       unsigned long chan_event;
+};
+
+int sx_common_read_proximity(struct sx_common_data *data,
+                            const struct iio_chan_spec *chan, int *val);
+
+int sx_common_read_event_config(struct iio_dev *indio_dev,
+                               const struct iio_chan_spec *chan,
+                               enum iio_event_type type,
+                               enum iio_event_direction dir);
+int sx_common_write_event_config(struct iio_dev *indio_dev,
+                                const struct iio_chan_spec *chan,
+                                enum iio_event_type type,
+                                enum iio_event_direction dir, int state);
+
+int sx_common_probe(struct i2c_client *client,
+                   const struct sx_common_chip_info *chip_info,
+                   const struct regmap_config *regmap_config);
+
+/* 3 is the number of events defined by a single phase. */
+extern const struct iio_event_spec sx_common_events[3];
+
+#endif  /* IIO_SX_COMMON_H */
index cf38144b6f95447bfdb2802debb7ba0b695a6d0c..661a79ea200dd62948405f1871b0637d31726f8e 100644 (file)
@@ -226,7 +226,7 @@ static int vl53l0x_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id vl53l0x_id[] = {
-       { "vl53l0x", 0},
+       { "vl53l0x", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, vl53l0x_id);
index 1954322e43be5540ea39c0972f95fdc656e2ab50..54840881259a433a1ffb53b1f4a40ee82f8ceee6 100644 (file)
@@ -320,7 +320,7 @@ static ssize_t show_fault(struct device *dev, u8 faultbit, char *buf)
 
        fault = reg_val & faultbit;
 
-       return sprintf(buf, "%d\n", fault);
+       return sysfs_emit(buf, "%d\n", fault);
 }
 
 static ssize_t show_fault_ovuv(struct device *dev,
@@ -344,7 +344,7 @@ static ssize_t show_filter(struct device *dev,
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        struct max31856_data *data = iio_priv(indio_dev);
 
-       return sprintf(buf, "%d\n", data->filter_50hz ? 50 : 60);
+       return sysfs_emit(buf, "%d\n", data->filter_50hz ? 50 : 60);
 }
 
 static ssize_t set_filter(struct device *dev,
index 4c8d6e6cf677015877efb1f08945f584b6acb61d..86c3f3509a26ff0b74614e2e88a10f1fa6640bc5 100644 (file)
@@ -208,7 +208,7 @@ static ssize_t show_fault(struct device *dev, u8 faultbit, char *buf)
 
        fault = data->buf[0] & faultbit;
 
-       return sprintf(buf, "%d\n", fault);
+       return sysfs_emit(buf, "%d\n", fault);
 }
 
 static ssize_t show_fault_ovuv(struct device *dev,
@@ -225,7 +225,7 @@ static ssize_t show_filter(struct device *dev,
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        struct max31865_data *data = iio_priv(indio_dev);
 
-       return sprintf(buf, "%d\n", data->filter_50hz ? 50 : 60);
+       return sysfs_emit(buf, "%d\n", data->filter_50hz ? 50 : 60);
 }
 
 static ssize_t set_filter(struct device *dev,
index 0297e215b61a8e2c9cb2efbc4f0247a1bd275685..98c41cddc6f00039524f84fada753846af9bad62 100644 (file)
@@ -6,12 +6,11 @@
  * Author: <[email protected]>
  */
 
-#include <linux/module.h>
 #include <linux/init.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/err.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
 #include <linux/spi/spi.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
index afcb10ea7c443543b758799862ec04db06e8d121..c253a53159881aa8a7ba720c7ec1382a5d82ec96 100644 (file)
@@ -600,7 +600,6 @@ static const struct of_device_id mlx90614_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, mlx90614_of_match);
 
-#ifdef CONFIG_PM_SLEEP
 static int mlx90614_pm_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
@@ -630,9 +629,7 @@ static int mlx90614_pm_resume(struct device *dev)
 
        return 0;
 }
-#endif
 
-#ifdef CONFIG_PM
 static int mlx90614_pm_runtime_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
@@ -648,19 +645,18 @@ static int mlx90614_pm_runtime_resume(struct device *dev)
 
        return mlx90614_wakeup(data);
 }
-#endif
 
 static const struct dev_pm_ops mlx90614_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(mlx90614_pm_suspend, mlx90614_pm_resume)
-       SET_RUNTIME_PM_OPS(mlx90614_pm_runtime_suspend,
-                          mlx90614_pm_runtime_resume, NULL)
+       SYSTEM_SLEEP_PM_OPS(mlx90614_pm_suspend, mlx90614_pm_resume)
+       RUNTIME_PM_OPS(mlx90614_pm_runtime_suspend,
+                      mlx90614_pm_runtime_resume, NULL)
 };
 
 static struct i2c_driver mlx90614_driver = {
        .driver = {
                .name   = "mlx90614",
                .of_match_table = mlx90614_of_match,
-               .pm     = &mlx90614_pm_ops,
+               .pm     = pm_ptr(&mlx90614_pm_ops),
        },
        .probe = mlx90614_probe,
        .remove = mlx90614_remove,
index 608ccb1d8bc82feb28eef57a1a31f58f27b1851a..7ee7ff8047a4309b7ebe2edd44e159963bd2289d 100644 (file)
@@ -13,9 +13,9 @@
 #include <linux/iopoll.h>
 #include <linux/kernel.h>
 #include <linux/limits.h>
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/math64.h>
-#include <linux/of.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 
index e4943a0bc9aa9d84dcc4a9b59fd10f8744f6c1ee..706a760f30b4799ceea1ee194d522e3f53ef2744 100644 (file)
@@ -261,7 +261,6 @@ static int tmp006_probe(struct i2c_client *client,
        return devm_iio_device_register(&client->dev, indio_dev);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int tmp006_suspend(struct device *dev)
 {
        return tmp006_power(dev, false);
@@ -271,9 +270,8 @@ static int tmp006_resume(struct device *dev)
 {
        return tmp006_power(dev, true);
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(tmp006_pm_ops, tmp006_suspend, tmp006_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(tmp006_pm_ops, tmp006_suspend, tmp006_resume);
 
 static const struct i2c_device_id tmp006_id[] = {
        { "tmp006", 0 },
@@ -284,7 +282,7 @@ MODULE_DEVICE_TABLE(i2c, tmp006_id);
 static struct i2c_driver tmp006_driver = {
        .driver = {
                .name   = "tmp006",
-               .pm     = &tmp006_pm_ops,
+               .pm     = pm_sleep_ptr(&tmp006_pm_ops),
        },
        .probe = tmp006_probe,
        .id_table = tmp006_id,
index b422371a46744560fc3e19f6f4f56c0e601df951..f3420d8a0e3594d6513a50b47d00be0748ccdb7a 100644 (file)
@@ -537,7 +537,6 @@ static int tmp007_probe(struct i2c_client *client,
        return devm_iio_device_register(&client->dev, indio_dev);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int tmp007_suspend(struct device *dev)
 {
        struct tmp007_data *data = iio_priv(i2c_get_clientdata(
@@ -554,9 +553,8 @@ static int tmp007_resume(struct device *dev)
        return i2c_smbus_write_word_swapped(data->client, TMP007_CONFIG,
                        data->config | TMP007_CONFIG_CONV_EN);
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(tmp007_pm_ops, tmp007_suspend, tmp007_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(tmp007_pm_ops, tmp007_suspend, tmp007_resume);
 
 static const struct of_device_id tmp007_of_match[] = {
        { .compatible = "ti,tmp007", },
@@ -574,7 +572,7 @@ static struct i2c_driver tmp007_driver = {
        .driver = {
                .name   = "tmp007",
                .of_match_table = tmp007_of_match,
-               .pm     = &tmp007_pm_ops,
+               .pm     = pm_sleep_ptr(&tmp007_pm_ops),
        },
        .probe          = tmp007_probe,
        .id_table       = tmp007_id,
index bbfbad9a87676ba9e1510b7b221638010b3dd627..60d58ec5b063619b9f474e6c019b36813adbc86c 100644 (file)
@@ -233,3 +233,4 @@ MODULE_DESCRIPTION("Measurement-Specialties tsys01 temperature driver");
 MODULE_AUTHOR("William Markezana <[email protected]>");
 MODULE_AUTHOR("Ludovic Tancerel <[email protected]>");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_MEAS_SPEC_SENSORS);
index fc96e5f9d3fc51eb7b1162702c0ee21e523f2f3e..49c275e4f51068852032a7cc87aa76183226704e 100644 (file)
@@ -187,3 +187,4 @@ MODULE_DESCRIPTION("Measurement-Specialties tsys02d temperature driver");
 MODULE_AUTHOR("William Markezana <[email protected]>");
 MODULE_AUTHOR("Ludovic Tancerel <[email protected]>");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_MEAS_SPEC_SENSORS);
index 679a7794af20e6d527d143000ceaf3de663205f0..56ca0ad7e77a259e9d88be9dd46a79bd3c0bc8d9 100644 (file)
@@ -4,6 +4,16 @@
 #
 
 # Keep in alphabetical order
+config IIO_RESCALE_KUNIT_TEST
+       bool "Test IIO rescale conversion functions"
+       depends on KUNIT=y && !IIO_RESCALE
+       default KUNIT_ALL_TESTS
+       help
+         If you want to run tests on the iio-rescale code say Y here.
+
+         This takes advantage of ARCH=um to run tests and should be used by
+         developers to tests their changes to the rescaling logic.
+
 config IIO_TEST_FORMAT
         bool "Test IIO formatting functions"
         depends on KUNIT=y
index 467519a2027e5519ead92730ab91c95473254f9b..f15ae0a6394f70e93d6ad5bc2726431169f5661e 100644 (file)
@@ -4,5 +4,6 @@
 #
 
 # Keep in alphabetical order
+obj-$(CONFIG_IIO_RESCALE_KUNIT_TEST) += iio-test-rescale.o ../afe/iio-rescale.o
 obj-$(CONFIG_IIO_TEST_FORMAT) += iio-test-format.o
 CFLAGS_iio-test-format.o += $(DISABLE_STRUCTLEAK_PLUGIN)
diff --git a/drivers/iio/test/iio-test-rescale.c b/drivers/iio/test/iio-test-rescale.c
new file mode 100644 (file)
index 0000000..0b6699b
--- /dev/null
@@ -0,0 +1,710 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Kunit tests for IIO rescale conversions
+ *
+ * Copyright (c) 2021 Liam Beguin <[email protected]>
+ */
+
+#include <linux/gcd.h>
+#include <linux/overflow.h>
+
+#include <linux/iio/afe/rescale.h>
+#include <linux/iio/iio.h>
+
+#include <kunit/test.h>
+
+struct rescale_tc_data {
+       const char *name;
+
+       const s32 numerator;
+       const s32 denominator;
+       const s32 offset;
+
+       const int schan_val;
+       const int schan_val2;
+       const int schan_off;
+       const int schan_scale_type;
+
+       const char *expected;
+       const char *expected_off;
+};
+
+const struct rescale_tc_data scale_cases[] = {
+       /*
+        * Typical use cases
+        */
+       {
+               .name = "typical IIO_VAL_INT, positive",
+               .numerator = 1000000,
+               .denominator = 8060,
+               .schan_scale_type = IIO_VAL_INT,
+               .schan_val = 42,
+               .expected = "5210.918114143",
+       },
+       {
+               .name = "typical IIO_VAL_INT, negative",
+               .numerator = -1000000,
+               .denominator = 8060,
+               .schan_scale_type = IIO_VAL_INT,
+               .schan_val = 42,
+               .expected = "-5210.918114143",
+       },
+       {
+               .name = "typical IIO_VAL_FRACTIONAL, positive",
+               .numerator = 1000000,
+               .denominator = 8060,
+               .schan_scale_type = IIO_VAL_FRACTIONAL,
+               .schan_val = 42,
+               .schan_val2 = 20,
+               .expected = "260.545905707",
+       },
+       {
+               .name = "typical IIO_VAL_FRACTIONAL, negative",
+               .numerator = -1000000,
+               .denominator = 8060,
+               .schan_scale_type = IIO_VAL_FRACTIONAL,
+               .schan_val = 42,
+               .schan_val2 = 20,
+               .expected = "-260.545905707",
+       },
+       {
+               .name = "typical IIO_VAL_FRACTIONAL_LOG2, positive",
+               .numerator = 42,
+               .denominator = 53,
+               .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
+               .schan_val = 4096,
+               .schan_val2 = 16,
+               .expected = "0.049528301",
+       },
+       {
+               .name = "typical IIO_VAL_FRACTIONAL_LOG2, negative",
+               .numerator = -42,
+               .denominator = 53,
+               .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
+               .schan_val = 4096,
+               .schan_val2 = 16,
+               .expected = "-0.049528301",
+       },
+       {
+               .name = "typical IIO_VAL_INT_PLUS_NANO, positive",
+               .numerator = 1000000,
+               .denominator = 8060,
+               .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
+               .schan_val = 10,
+               .schan_val2 = 123456,
+               .expected = "1240.710106203",
+       },
+       {
+               .name = "typical IIO_VAL_INT_PLUS_NANO, negative",
+               .numerator = -1000000,
+               .denominator = 8060,
+               .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
+               .schan_val = 10,
+               .schan_val2 = 123456,
+               .expected = "-1240.710106203",
+       },
+       {
+               .name = "typical IIO_VAL_INT_PLUS_MICRO, positive",
+               .numerator = 1000000,
+               .denominator = 8060,
+               .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
+               .schan_val = 10,
+               .schan_val2 = 1234,
+               .expected = "1240.84789",
+       },
+       {
+               .name = "typical IIO_VAL_INT_PLUS_MICRO, negative",
+               .numerator = -1000000,
+               .denominator = 8060,
+               .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
+               .schan_val = 10,
+               .schan_val2 = 1234,
+               .expected = "-1240.84789",
+       },
+       /*
+        * Use cases with small scales involving divisions
+        */
+       {
+               .name = "small IIO_VAL_FRACTIONAL, 261/509 scaled by 90/1373754273",
+               .numerator = 261,
+               .denominator = 509,
+               .schan_scale_type = IIO_VAL_FRACTIONAL,
+               .schan_val = 90,
+               .schan_val2 = 1373754273,
+               .expected = "0.000000033594",
+       },
+       {
+               .name = "small IIO_VAL_FRACTIONAL, 90/1373754273 scaled by 261/509",
+               .numerator = 90,
+               .denominator = 1373754273,
+               .schan_scale_type = IIO_VAL_FRACTIONAL,
+               .schan_val = 261,
+               .schan_val2 = 509,
+               .expected = "0.000000033594",
+       },
+       {
+               .name = "small IIO_VAL_FRACTIONAL, 760/1373754273 scaled by 427/2727",
+               .numerator = 760,
+               .denominator = 1373754273,
+               .schan_scale_type = IIO_VAL_FRACTIONAL,
+               .schan_val = 427,
+               .schan_val2 = 2727,
+               .expected = "0.000000086626",
+       },
+       {
+               .name = "small IIO_VAL_FRACTIONAL, 761/1373754273 scaled by 427/2727",
+               .numerator = 761,
+               .denominator = 1373754273,
+               .schan_scale_type = IIO_VAL_FRACTIONAL,
+               .schan_val = 427,
+               .schan_val2 = 2727,
+               .expected = "0.000000086740",
+       },
+       {
+               .name = "small IIO_VAL_FRACTIONAL, 5/32768 scaled by 3/10000",
+               .numerator = 5,
+               .denominator = 32768,
+               .schan_scale_type = IIO_VAL_FRACTIONAL,
+               .schan_val = 3,
+               .schan_val2 = 10000,
+               .expected = "0.0000000457763671875",
+       },
+       {
+               .name = "small IIO_VAL_FRACTIONAL, 0 < scale < 1",
+               .numerator = 6,
+               .denominator = 6,
+               .schan_scale_type = IIO_VAL_FRACTIONAL,
+               .schan_val = 1,
+               .schan_val2 = 3,
+               .expected = "0.3333333333333333",
+       },
+       {
+               .name = "small IIO_VAL_FRACTIONAL, -1 < scale < 0",
+               .numerator = -6,
+               .denominator = 6,
+               .schan_scale_type = IIO_VAL_FRACTIONAL,
+               .schan_val = 1,
+               .schan_val2 = 3,
+               .expected = "-0.3333333333333333",
+       },
+       {
+               .name = "small IIO_VAL_FRACTIONAL, 0 < scale < 2",
+               .numerator = 8,
+               .denominator = 2,
+               .schan_scale_type = IIO_VAL_FRACTIONAL,
+               .schan_val = 1,
+               .schan_val2 = 3,
+               .expected = "1.3333333333333333",
+       },
+       {
+               .name = "small IIO_VAL_FRACTIONAL, -2 < scale < 0",
+               .numerator = -8,
+               .denominator = 2,
+               .schan_scale_type = IIO_VAL_FRACTIONAL,
+               .schan_val = 1,
+               .schan_val2 = 3,
+               .expected = "-1.3333333333333333",
+       },
+       {
+               .name = "small IIO_VAL_FRACTIONAL_LOG2, 760/32768 scaled by 15/22",
+               .numerator = 760,
+               .denominator = 32768,
+               .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
+               .schan_val = 15,
+               .schan_val2 = 22,
+               .expected = "0.000000082946",
+       },
+       {
+               .name = "small IIO_VAL_FRACTIONAL_LOG2, 761/32768 scaled by 15/22",
+               .numerator = 761,
+               .denominator = 32768,
+               .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
+               .schan_val = 15,
+               .schan_val2 = 22,
+               .expected = "0.000000083055",
+       },
+       {
+               .name = "small IIO_VAL_FRACTIONAL_LOG2, 0 < scale < 1",
+               .numerator = 16,
+               .denominator = 3,
+               .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
+               .schan_val = 1,
+               .schan_val2 = 4,
+               .expected = "0.3333333333333333",
+       },
+       {
+               .name = "small IIO_VAL_FRACTIONAL_LOG2, -1 < scale < 0",
+               .numerator = -16,
+               .denominator = 3,
+               .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
+               .schan_val = 1,
+               .schan_val2 = 4,
+               .expected = "-0.3333333333333333",
+       },
+       {
+               .name = "small IIO_VAL_FRACTIONAL_LOG2, 0 < scale < 2",
+               .numerator = 8,
+               .denominator = 3,
+               .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
+               .schan_val = 1,
+               .schan_val2 = 1,
+               .expected = "1.3333333333333333",
+       },
+       {
+               .name = "small IIO_VAL_FRACTIONAL_LOG2, -2 < scale < 0",
+               .numerator = -8,
+               .denominator = 3,
+               .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
+               .schan_val = 1,
+               .schan_val2 = 1,
+               .expected = "-1.3333333333333333",
+       },
+       {
+               .name = "small IIO_VAL_INT_PLUS_MICRO, positive",
+               .numerator = 1,
+               .denominator = 2,
+               .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
+               .schan_val = 5,
+               .schan_val2 = 1234,
+               .expected = "2.500617",
+       },
+       {
+               .name = "small IIO_VAL_INT_PLUS_MICRO, negative",
+               .numerator = -1,
+               .denominator = 2,
+               .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
+               .schan_val = 5,
+               .schan_val2 = 1234,
+               .expected = "-2.500617",
+       },
+       /*
+        * INT_PLUS_{MICRO,NANO} positive/negative corner cases
+        */
+       {
+               .name = "negative IIO_VAL_INT_PLUS_NANO, negative schan",
+               .numerator = 1000000,
+               .denominator = 8060,
+               .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
+               .schan_val = -10,
+               .schan_val2 = 123456,
+               .expected = "-1240.710106203",
+       },
+       {
+               .name = "negative IIO_VAL_INT_PLUS_NANO, both negative",
+               .numerator = -1000000,
+               .denominator = 8060,
+               .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
+               .schan_val = -10,
+               .schan_val2 = 123456,
+               .expected = "1240.710106203",
+       },
+       {
+               .name = "negative IIO_VAL_INT_PLUS_NANO, 3 negative",
+               .numerator = -1000000,
+               .denominator = -8060,
+               .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
+               .schan_val = -10,
+               .schan_val2 = 123456,
+               .expected = "-1240.710106203",
+       },
+       {
+               .name = "negative IIO_VAL_INT_PLUS_NANO, 4 negative",
+               .numerator = -1000000,
+               .denominator = -8060,
+               .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
+               .schan_val = -10,
+               .schan_val2 = -123456,
+               .expected = "-1240.710106203",
+       },
+       {
+               .name = "negative IIO_VAL_INT_PLUS_NANO, negative, *val = 0",
+               .numerator = 1,
+               .denominator = -10,
+               .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
+               .schan_val = 0,
+               .schan_val2 = 123456789,
+               .expected = "-0.012345678",
+       },
+       /*
+        * INT_PLUS_{MICRO,NANO} decimal part overflow
+        */
+       {
+               .name = "decimal overflow IIO_VAL_INT_PLUS_NANO, positive",
+               .numerator = 1000000,
+               .denominator = 8060,
+               .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
+               .schan_val = 10,
+               .schan_val2 = 123456789,
+               .expected = "1256.01200856",
+       },
+       {
+               .name = "decimal overflow IIO_VAL_INT_PLUS_NANO, negative",
+               .numerator = -1000000,
+               .denominator = 8060,
+               .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
+               .schan_val = 10,
+               .schan_val2 = 123456789,
+               .expected = "-1256.01200856",
+       },
+       {
+               .name = "decimal overflow IIO_VAL_INT_PLUS_NANO, negative schan",
+               .numerator = 1000000,
+               .denominator = 8060,
+               .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
+               .schan_val = -10,
+               .schan_val2 = 123456789,
+               .expected = "-1256.01200856",
+       },
+       {
+               .name = "decimal overflow IIO_VAL_INT_PLUS_MICRO, positive",
+               .numerator = 1000000,
+               .denominator = 8060,
+               .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
+               .schan_val = 10,
+               .schan_val2 = 123456789,
+               .expected = "16557.914267",
+       },
+       {
+               .name = "decimal overflow IIO_VAL_INT_PLUS_MICRO, negative",
+               .numerator = -1000000,
+               .denominator = 8060,
+               .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
+               .schan_val = 10,
+               .schan_val2 = 123456789,
+               .expected = "-16557.914267",
+       },
+       {
+               .name = "decimal overflow IIO_VAL_INT_PLUS_MICRO, negative schan",
+               .numerator = 1000000,
+               .denominator = 8060,
+               .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
+               .schan_val = -10,
+               .schan_val2 = 123456789,
+               .expected = "-16557.914267",
+       },
+       /*
+        * 32-bit overflow conditions
+        */
+       {
+               .name = "overflow IIO_VAL_FRACTIONAL, positive",
+               .numerator = 2,
+               .denominator = 20,
+               .schan_scale_type = IIO_VAL_FRACTIONAL,
+               .schan_val = S32_MAX,
+               .schan_val2 = 1,
+               .expected = "214748364.7",
+       },
+       {
+               .name = "overflow IIO_VAL_FRACTIONAL, negative",
+               .numerator = -2,
+               .denominator = 20,
+               .schan_scale_type = IIO_VAL_FRACTIONAL,
+               .schan_val = S32_MAX,
+               .schan_val2 = 1,
+               .expected = "-214748364.7",
+       },
+       {
+               .name = "overflow IIO_VAL_FRACTIONAL_LOG2, positive",
+               .numerator = S32_MAX,
+               .denominator = 4096,
+               .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
+               .schan_val = 4096,
+               .schan_val2 = 16,
+               .expected = "32767.99998474121",
+       },
+       {
+               .name = "overflow IIO_VAL_FRACTIONAL_LOG2, negative",
+               .numerator = S32_MAX,
+               .denominator = 4096,
+               .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
+               .schan_val = -4096,
+               .schan_val2 = 16,
+               .expected = "-32767.99998474121",
+       },
+       {
+               .name = "overflow IIO_VAL_INT_PLUS_NANO, positive",
+               .numerator = 2,
+               .denominator = 20,
+               .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
+               .schan_val = 10,
+               .schan_val2 = S32_MAX,
+               .expected = "1.214748364",
+       },
+       {
+               .name = "overflow IIO_VAL_INT_PLUS_NANO, negative",
+               .numerator = -2,
+               .denominator = 20,
+               .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
+               .schan_val = 10,
+               .schan_val2 = S32_MAX,
+               .expected = "-1.214748364",
+       },
+       {
+               .name = "overflow IIO_VAL_INT_PLUS_NANO, negative schan",
+               .numerator = 2,
+               .denominator = 20,
+               .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
+               .schan_val = -10,
+               .schan_val2 = S32_MAX,
+               .expected = "-1.214748364",
+       },
+       {
+               .name = "overflow IIO_VAL_INT_PLUS_MICRO, positive",
+               .numerator = 2,
+               .denominator = 20,
+               .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
+               .schan_val = 10,
+               .schan_val2 = S32_MAX,
+               .expected = "215.748364",
+       },
+       {
+               .name = "overflow IIO_VAL_INT_PLUS_MICRO, negative",
+               .numerator = -2,
+               .denominator = 20,
+               .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
+               .schan_val = 10,
+               .schan_val2 = S32_MAX,
+               .expected = "-215.748364",
+       },
+       {
+               .name = "overflow IIO_VAL_INT_PLUS_MICRO, negative schan",
+               .numerator = 2,
+               .denominator = 20,
+               .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
+               .schan_val = -10,
+               .schan_val2 = S32_MAX,
+               .expected = "-215.748364",
+       },
+};
+
+const struct rescale_tc_data offset_cases[] = {
+       /*
+        * Typical use cases
+        */
+       {
+               .name = "typical IIO_VAL_INT, positive",
+               .offset = 1234,
+               .schan_scale_type = IIO_VAL_INT,
+               .schan_val = 123,
+               .schan_val2 = 0,
+               .schan_off = 14,
+               .expected_off = "24", /* 23.872 */
+       },
+       {
+               .name = "typical IIO_VAL_INT, negative",
+               .offset = -1234,
+               .schan_scale_type = IIO_VAL_INT,
+               .schan_val = 12,
+               .schan_val2 = 0,
+               .schan_off = 14,
+               .expected_off = "-88", /* -88.83333333333333 */
+       },
+       {
+               .name = "typical IIO_VAL_FRACTIONAL, positive",
+               .offset = 1234,
+               .schan_scale_type = IIO_VAL_FRACTIONAL,
+               .schan_val = 12,
+               .schan_val2 = 34,
+               .schan_off = 14,
+               .expected_off = "3510", /* 3510.333333333333 */
+       },
+       {
+               .name = "typical IIO_VAL_FRACTIONAL, negative",
+               .offset = -1234,
+               .schan_scale_type = IIO_VAL_FRACTIONAL,
+               .schan_val = 12,
+               .schan_val2 = 34,
+               .schan_off = 14,
+               .expected_off = "-3482", /* -3482.333333333333 */
+       },
+       {
+               .name = "typical IIO_VAL_FRACTIONAL_LOG2, positive",
+               .offset = 1234,
+               .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
+               .schan_val = 12,
+               .schan_val2 = 16,
+               .schan_off = 14,
+               .expected_off = "6739299", /* 6739299.333333333 */
+       },
+       {
+               .name = "typical IIO_VAL_FRACTIONAL_LOG2, negative",
+               .offset = -1234,
+               .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
+               .schan_val = 12,
+               .schan_val2 = 16,
+               .schan_off = 14,
+               .expected_off = "-6739271", /* -6739271.333333333 */
+       },
+       {
+               .name = "typical IIO_VAL_INT_PLUS_NANO, positive",
+               .offset = 1234,
+               .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
+               .schan_val = 10,
+               .schan_val2 = 123456789,
+               .schan_off = 14,
+               .expected_off = "135", /* 135.8951219647469 */
+       },
+       {
+               .name = "typical IIO_VAL_INT_PLUS_NANO, negative",
+               .offset = -1234,
+               .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
+               .schan_val = 10,
+               .schan_val2 = 123456789,
+               .schan_off = 14,
+               .expected_off = "-107", /* -107.89512196474689 */
+       },
+       {
+               .name = "typical IIO_VAL_INT_PLUS_MICRO, positive",
+               .offset = 1234,
+               .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
+               .schan_val = 10,
+               .schan_val2 = 123456789,
+               .schan_off = 14,
+               .expected_off = "23", /* 23.246438560723952 */
+       },
+       {
+               .name = "typical IIO_VAL_INT_PLUS_MICRO, negative",
+               .offset = -12345,
+               .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
+               .schan_val = 10,
+               .schan_val2 = 123456789,
+               .schan_off = 14,
+               .expected_off = "-78", /* -78.50185091745313 */
+       },
+};
+
+static void case_to_desc(const struct rescale_tc_data *t, char *desc)
+{
+       strcpy(desc, t->name);
+}
+
+KUNIT_ARRAY_PARAM(iio_rescale_scale, scale_cases, case_to_desc);
+KUNIT_ARRAY_PARAM(iio_rescale_offset, offset_cases, case_to_desc);
+
+/**
+ * iio_str_to_nano() - Parse a fixed-point string to get an
+ *                      IIO_VAL_INT_PLUS_NANO value
+ * @str: The string to parse
+ * @nano: The number as an integer
+ *
+ * Returns 0 on success, or a negative error code if the string cound not be
+ * parsed.
+ */
+static int iio_str_to_nano(const char *str, s64 *nano)
+{
+       int tmp, tmp2;
+       int ret = 0;
+
+       /*
+        * iio_str_to_fixpoint() uses 10^8 here instead of 10^9 as fract_mult is
+        * the multiplier for the first decimal place.
+        */
+       ret = iio_str_to_fixpoint(str, 100000000, &tmp, &tmp2);
+       if (ret < 0)
+               return ret;
+
+       if (tmp < 0)
+               tmp2 *= -1;
+
+       *nano = (s64)tmp * 1000000000UL + tmp2;
+
+       return ret;
+}
+
+/**
+ * iio_test_relative_error_ppm() - Compute relative error (in parts-per-million)
+ *                                 between two fixed-point strings
+ * @real_str: The real value as a string
+ * @exp_str: The expected value as a string
+ *
+ * Returns a negative error code if the strings cound not be parsed, or the
+ * relative error in parts-per-million.
+ */
+static int iio_test_relative_error_ppm(const char *real_str, const char *exp_str)
+{
+       s64 real, exp, err;
+       int ret;
+
+       ret = iio_str_to_nano(real_str, &real);
+       if (ret < 0)
+               return ret;
+
+       ret = iio_str_to_nano(exp_str, &exp);
+       if (ret < 0)
+               return ret;
+
+       if (!exp) {
+               pr_err("Expected value is null, relative error is undefined\n");
+               return -EINVAL;
+       }
+
+       err = 1000000UL * abs(exp - real);
+
+       return (int)div64_u64(err, abs(exp));
+}
+
+static void iio_rescale_test_scale(struct kunit *test)
+{
+       struct rescale_tc_data *t = (struct rescale_tc_data *)test->param_value;
+       char *buff = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL);
+       struct rescale rescale;
+       int values[2];
+       int rel_ppm;
+       int ret;
+
+       rescale.numerator = t->numerator;
+       rescale.denominator = t->denominator;
+       rescale.offset = t->offset;
+       values[0] = t->schan_val;
+       values[1] = t->schan_val2;
+
+       ret = rescale_process_scale(&rescale, t->schan_scale_type,
+                                   &values[0], &values[1]);
+
+       ret = iio_format_value(buff, ret, 2, values);
+       KUNIT_EXPECT_EQ(test, (int)strlen(buff), ret);
+
+       rel_ppm = iio_test_relative_error_ppm(buff, t->expected);
+       KUNIT_EXPECT_GE_MSG(test, rel_ppm, 0, "failed to compute ppm\n");
+
+       KUNIT_EXPECT_EQ_MSG(test, rel_ppm, 0,
+                           "\t    real=%s"
+                           "\texpected=%s\n",
+                           buff, t->expected);
+}
+
+static void iio_rescale_test_offset(struct kunit *test)
+{
+       struct rescale_tc_data *t = (struct rescale_tc_data *)test->param_value;
+       char *buff_off = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL);
+       struct rescale rescale;
+       int values[2];
+       int ret;
+
+       rescale.numerator = t->numerator;
+       rescale.denominator = t->denominator;
+       rescale.offset = t->offset;
+       values[0] = t->schan_val;
+       values[1] = t->schan_val2;
+
+       ret = rescale_process_offset(&rescale, t->schan_scale_type,
+                                    t->schan_val, t->schan_val2, t->schan_off,
+                                    &values[0], &values[1]);
+
+       ret = iio_format_value(buff_off, ret, 2, values);
+       KUNIT_EXPECT_EQ(test, (int)strlen(buff_off), ret);
+
+       KUNIT_EXPECT_STREQ(test, strim(buff_off), t->expected_off);
+}
+
+static struct kunit_case iio_rescale_test_cases[] = {
+       KUNIT_CASE_PARAM(iio_rescale_test_scale, iio_rescale_scale_gen_params),
+       KUNIT_CASE_PARAM(iio_rescale_test_offset, iio_rescale_offset_gen_params),
+       {}
+};
+
+static struct kunit_suite iio_rescale_test_suite = {
+       .name = "iio-rescale",
+       .test_cases = iio_rescale_test_cases,
+};
+kunit_test_suite(iio_rescale_test_suite);
index 8cef2f7452e85eb974df7fad3fe3c34d55e9169e..7ecb69725b1dab67920c6c99515f6639ace9bd46 100644 (file)
@@ -38,7 +38,7 @@ config IIO_STM32_LPTIMER_TRIGGER
 
 config IIO_STM32_TIMER_TRIGGER
        tristate "STM32 Timer Trigger"
-       depends on (ARCH_STM32 && OF && MFD_STM32_TIMERS) || COMPILE_TEST
+       depends on (ARCH_STM32 && MFD_STM32_TIMERS) || COMPILE_TEST
        help
          Select this option to enable STM32 Timer Trigger
 
index 4f9461e1412cb02b955cf0abbea7730ab834d3c3..3643c4afae6783479d53458ddf996096c53c54c7 100644 (file)
 #include <linux/iio/timer/stm32-timer-trigger.h>
 #include <linux/iio/trigger.h>
 #include <linux/mfd/stm32-timers.h>
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/of_device.h>
+#include <linux/property.h>
 
 #define MAX_TRIGGERS 7
 #define MAX_VALIDS 5
@@ -771,11 +772,11 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev)
        unsigned int index;
        int ret;
 
-       if (of_property_read_u32(dev->of_node, "reg", &index))
-               return -EINVAL;
+       ret = device_property_read_u32(dev, "reg", &index);
+       if (ret)
+               return ret;
 
-       cfg = (const struct stm32_timer_trigger_cfg *)
-               of_match_device(dev->driver->of_match_table, dev)->data;
+       cfg = device_get_match_data(dev);
 
        if (index >= ARRAY_SIZE(triggers_table) ||
            index >= cfg->num_valids_table)
@@ -827,7 +828,7 @@ static int stm32_timer_trigger_remove(struct platform_device *pdev)
        return 0;
 }
 
-static int __maybe_unused stm32_timer_trigger_suspend(struct device *dev)
+static int stm32_timer_trigger_suspend(struct device *dev)
 {
        struct stm32_timer_trigger *priv = dev_get_drvdata(dev);
 
@@ -849,7 +850,7 @@ static int __maybe_unused stm32_timer_trigger_suspend(struct device *dev)
        return 0;
 }
 
-static int __maybe_unused stm32_timer_trigger_resume(struct device *dev)
+static int stm32_timer_trigger_resume(struct device *dev)
 {
        struct stm32_timer_trigger *priv = dev_get_drvdata(dev);
        int ret;
@@ -875,9 +876,9 @@ static int __maybe_unused stm32_timer_trigger_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(stm32_timer_trigger_pm_ops,
-                        stm32_timer_trigger_suspend,
-                        stm32_timer_trigger_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(stm32_timer_trigger_pm_ops,
+                               stm32_timer_trigger_suspend,
+                               stm32_timer_trigger_resume);
 
 static const struct stm32_timer_trigger_cfg stm32_timer_trg_cfg = {
        .valids_table = valids_table,
@@ -907,7 +908,7 @@ static struct platform_driver stm32_timer_trigger_driver = {
        .driver = {
                .name = "stm32-timer-trigger",
                .of_match_table = stm32_trig_of_match,
-               .pm = &stm32_timer_trigger_pm_ops,
+               .pm = pm_sleep_ptr(&stm32_timer_trigger_pm_ops),
        },
 };
 module_platform_driver(stm32_timer_trigger_driver);
index 1d3026dae827e25b07b9c7cc858a2a52724535dc..62d5397ff1f98a5809fa96064fac53e135dac3cc 100644 (file)
@@ -312,3 +312,4 @@ MODULE_AUTHOR("Barry Song <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices ADIS16203 Programmable 360 Degrees Inclinometer");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("spi:adis16203");
+MODULE_IMPORT_NS(IIO_ADISLIB);
index 2a8aa83b8d9e60408138b1355f41902c263614d5..bca857eef92e271b200b54ddfd3480f4af37dcad 100644 (file)
@@ -440,3 +440,4 @@ MODULE_AUTHOR("Barry Song <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices Programmable Impact Sensor and Recorder");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("spi:adis16240");
+MODULE_IMPORT_NS(IIO_ADISLIB);
index b25f41053facc5b7045b2246409029fe8b133bde..2f0d6cf048d214303e6efb52675c4d35cd6cd259 100644 (file)
@@ -15,15 +15,4 @@ config AD7816
          To compile this driver as a module, choose M here: the
          module will be called ad7816.
 
-config AD7280
-       tristate "Analog Devices AD7280A Lithium Ion Battery Monitoring System"
-       depends on SPI
-       select CRC8
-       help
-         Say yes here to build support for Analog Devices AD7280A
-         Lithium Ion Battery Monitoring System.
-
-         To compile this driver as a module, choose M here: the
-         module will be called ad7280a
-
 endmenu
index 6436a62b6278ff465ad455358d7e210e196b070f..1e2a94c4db84d86872885ab3ae0d94b7443f8f0c 100644 (file)
@@ -4,4 +4,3 @@
 #
 
 obj-$(CONFIG_AD7816) += ad7816.o
-obj-$(CONFIG_AD7280) += ad7280a.o
diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c
deleted file mode 100644 (file)
index fef0055..0000000
+++ /dev/null
@@ -1,1044 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * AD7280A Lithium Ion Battery Monitoring System
- *
- * Copyright 2011 Analog Devices Inc.
- */
-
-#include <linux/crc8.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/spi/spi.h>
-#include <linux/err.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include <linux/iio/events.h>
-
-#include "ad7280a.h"
-
-/* Registers */
-#define AD7280A_CELL_VOLTAGE_1         0x0  /* D11 to D0, Read only */
-#define AD7280A_CELL_VOLTAGE_2         0x1  /* D11 to D0, Read only */
-#define AD7280A_CELL_VOLTAGE_3         0x2  /* D11 to D0, Read only */
-#define AD7280A_CELL_VOLTAGE_4         0x3  /* D11 to D0, Read only */
-#define AD7280A_CELL_VOLTAGE_5         0x4  /* D11 to D0, Read only */
-#define AD7280A_CELL_VOLTAGE_6         0x5  /* D11 to D0, Read only */
-#define AD7280A_AUX_ADC_1              0x6  /* D11 to D0, Read only */
-#define AD7280A_AUX_ADC_2              0x7  /* D11 to D0, Read only */
-#define AD7280A_AUX_ADC_3              0x8  /* D11 to D0, Read only */
-#define AD7280A_AUX_ADC_4              0x9  /* D11 to D0, Read only */
-#define AD7280A_AUX_ADC_5              0xA  /* D11 to D0, Read only */
-#define AD7280A_AUX_ADC_6              0xB  /* D11 to D0, Read only */
-#define AD7280A_SELF_TEST              0xC  /* D11 to D0, Read only */
-#define AD7280A_CONTROL_HB             0xD  /* D15 to D8, Read/write */
-#define AD7280A_CONTROL_LB             0xE  /* D7 to D0, Read/write */
-#define AD7280A_CELL_OVERVOLTAGE       0xF  /* D7 to D0, Read/write */
-#define AD7280A_CELL_UNDERVOLTAGE      0x10 /* D7 to D0, Read/write */
-#define AD7280A_AUX_ADC_OVERVOLTAGE    0x11 /* D7 to D0, Read/write */
-#define AD7280A_AUX_ADC_UNDERVOLTAGE   0x12 /* D7 to D0, Read/write */
-#define AD7280A_ALERT                  0x13 /* D7 to D0, Read/write */
-#define AD7280A_CELL_BALANCE           0x14 /* D7 to D0, Read/write */
-#define AD7280A_CB1_TIMER              0x15 /* D7 to D0, Read/write */
-#define AD7280A_CB2_TIMER              0x16 /* D7 to D0, Read/write */
-#define AD7280A_CB3_TIMER              0x17 /* D7 to D0, Read/write */
-#define AD7280A_CB4_TIMER              0x18 /* D7 to D0, Read/write */
-#define AD7280A_CB5_TIMER              0x19 /* D7 to D0, Read/write */
-#define AD7280A_CB6_TIMER              0x1A /* D7 to D0, Read/write */
-#define AD7280A_PD_TIMER               0x1B /* D7 to D0, Read/write */
-#define AD7280A_READ                   0x1C /* D7 to D0, Read/write */
-#define AD7280A_CNVST_CONTROL          0x1D /* D7 to D0, Read/write */
-
-/* Bits and Masks */
-#define AD7280A_CTRL_HB_CONV_INPUT_ALL                 0
-#define AD7280A_CTRL_HB_CONV_INPUT_6CELL_AUX1_3_4      BIT(6)
-#define AD7280A_CTRL_HB_CONV_INPUT_6CELL               BIT(7)
-#define AD7280A_CTRL_HB_CONV_INPUT_SELF_TEST           (BIT(7) | BIT(6))
-#define AD7280A_CTRL_HB_CONV_RES_READ_ALL              0
-#define AD7280A_CTRL_HB_CONV_RES_READ_6CELL_AUX1_3_4   BIT(4)
-#define AD7280A_CTRL_HB_CONV_RES_READ_6CELL            BIT(5)
-#define AD7280A_CTRL_HB_CONV_RES_READ_NO               (BIT(5) | BIT(4))
-#define AD7280A_CTRL_HB_CONV_START_CNVST               0
-#define AD7280A_CTRL_HB_CONV_START_CS                  BIT(3)
-#define AD7280A_CTRL_HB_CONV_AVG_DIS                   0
-#define AD7280A_CTRL_HB_CONV_AVG_2                     BIT(1)
-#define AD7280A_CTRL_HB_CONV_AVG_4                     BIT(2)
-#define AD7280A_CTRL_HB_CONV_AVG_8                     (BIT(2) | BIT(1))
-#define AD7280A_CTRL_HB_CONV_AVG(x)                    ((x) << 1)
-#define AD7280A_CTRL_HB_PWRDN_SW                       BIT(0)
-
-#define AD7280A_CTRL_LB_SWRST                          BIT(7)
-#define AD7280A_CTRL_LB_ACQ_TIME_400ns                 0
-#define AD7280A_CTRL_LB_ACQ_TIME_800ns                 BIT(5)
-#define AD7280A_CTRL_LB_ACQ_TIME_1200ns                        BIT(6)
-#define AD7280A_CTRL_LB_ACQ_TIME_1600ns                        (BIT(6) | BIT(5))
-#define AD7280A_CTRL_LB_ACQ_TIME(x)                    ((x) << 5)
-#define AD7280A_CTRL_LB_MUST_SET                       BIT(4)
-#define AD7280A_CTRL_LB_THERMISTOR_EN                  BIT(3)
-#define AD7280A_CTRL_LB_LOCK_DEV_ADDR                  BIT(2)
-#define AD7280A_CTRL_LB_INC_DEV_ADDR                   BIT(1)
-#define AD7280A_CTRL_LB_DAISY_CHAIN_RB_EN              BIT(0)
-
-#define AD7280A_ALERT_GEN_STATIC_HIGH                  BIT(6)
-#define AD7280A_ALERT_RELAY_SIG_CHAIN_DOWN             (BIT(7) | BIT(6))
-
-#define AD7280A_ALL_CELLS                              (0xAD << 16)
-
-#define AD7280A_MAX_SPI_CLK_HZ         700000 /* < 1MHz */
-#define AD7280A_MAX_CHAIN              8
-#define AD7280A_CELLS_PER_DEV          6
-#define AD7280A_BITS                   12
-#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_DEVADDR_MASTER         0
-#define AD7280A_DEVADDR_ALL            0x1F
-/* 5-bit device address is sent LSB first */
-static unsigned int ad7280a_devaddr(unsigned int addr)
-{
-       return ((addr & 0x1) << 4) |
-              ((addr & 0x2) << 3) |
-              (addr & 0x4) |
-              ((addr & 0x8) >> 3) |
-              ((addr & 0x10) >> 4);
-}
-
-/* During a read a valid write is mandatory.
- * So writing to the highest available address (Address 0x1F)
- * and setting the address all parts bit to 0 is recommended
- * So the TXVAL is AD7280A_DEVADDR_ALL + CRC
- */
-#define AD7280A_READ_TXVAL     0xF800030A
-
-/*
- * AD7280 CRC
- *
- * P(x) = x^8 + x^5 + x^3 + x^2 + x^1 + x^0 = 0b100101111 => 0x2F
- */
-#define POLYNOM                0x2F
-
-struct ad7280_state {
-       struct spi_device               *spi;
-       struct iio_chan_spec            *channels;
-       struct iio_dev_attr             *iio_attr;
-       int                             slave_num;
-       int                             scan_cnt;
-       int                             readback_delay_us;
-       unsigned char                   crc_tab[CRC8_TABLE_SIZE];
-       unsigned char                   ctrl_hb;
-       unsigned char                   ctrl_lb;
-       unsigned char                   cell_threshhigh;
-       unsigned char                   cell_threshlow;
-       unsigned char                   aux_threshhigh;
-       unsigned char                   aux_threshlow;
-       unsigned char                   cb_mask[AD7280A_MAX_CHAIN];
-       struct mutex                    lock; /* protect sensor state */
-
-       __be32                          buf[2] ____cacheline_aligned;
-};
-
-static unsigned char ad7280_calc_crc8(unsigned char *crc_tab, unsigned int val)
-{
-       unsigned char crc;
-
-       crc = crc_tab[val >> 16 & 0xFF];
-       crc = crc_tab[crc ^ (val >> 8 & 0xFF)];
-
-       return  crc ^ (val & 0xFF);
-}
-
-static int ad7280_check_crc(struct ad7280_state *st, unsigned int val)
-{
-       unsigned char crc = ad7280_calc_crc8(st->crc_tab, val >> 10);
-
-       if (crc != ((val >> 2) & 0xFF))
-               return -EIO;
-
-       return 0;
-}
-
-/* After initiating a conversion sequence we need to wait until the
- * conversion is done. The delay is typically in the range of 15..30 us
- * however depending an the number of devices in the daisy chain and the
- * number of averages taken, conversion delays and acquisition time options
- * it may take up to 250us, in this case we better sleep instead of busy
- * wait.
- */
-
-static void ad7280_delay(struct ad7280_state *st)
-{
-       if (st->readback_delay_us < 50)
-               udelay(st->readback_delay_us);
-       else
-               usleep_range(250, 500);
-}
-
-static int __ad7280_read32(struct ad7280_state *st, unsigned int *val)
-{
-       int ret;
-       struct spi_transfer t = {
-               .tx_buf = &st->buf[0],
-               .rx_buf = &st->buf[1],
-               .len = 4,
-       };
-
-       st->buf[0] = cpu_to_be32(AD7280A_READ_TXVAL);
-
-       ret = spi_sync_transfer(st->spi, &t, 1);
-       if (ret)
-               return ret;
-
-       *val = be32_to_cpu(st->buf[1]);
-
-       return 0;
-}
-
-static int ad7280_write(struct ad7280_state *st, unsigned int devaddr,
-                       unsigned int addr, bool all, unsigned int val)
-{
-       unsigned int reg = devaddr << 27 | addr << 21 |
-                       (val & 0xFF) << 13 | all << 12;
-
-       reg |= ad7280_calc_crc8(st->crc_tab, reg >> 11) << 3 | 0x2;
-       st->buf[0] = cpu_to_be32(reg);
-
-       return spi_write(st->spi, &st->buf[0], 4);
-}
-
-static int ad7280_read(struct ad7280_state *st, unsigned int devaddr,
-                      unsigned int addr)
-{
-       int ret;
-       unsigned int tmp;
-
-       /* turns off the read operation on all parts */
-       ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, 1,
-                          AD7280A_CTRL_HB_CONV_INPUT_ALL |
-                          AD7280A_CTRL_HB_CONV_RES_READ_NO |
-                          st->ctrl_hb);
-       if (ret)
-               return ret;
-
-       /* turns on the read operation on the addressed part */
-       ret = ad7280_write(st, devaddr, AD7280A_CONTROL_HB, 0,
-                          AD7280A_CTRL_HB_CONV_INPUT_ALL |
-                          AD7280A_CTRL_HB_CONV_RES_READ_ALL |
-                          st->ctrl_hb);
-       if (ret)
-               return ret;
-
-       /* Set register address on the part to be read from */
-       ret = ad7280_write(st, devaddr, AD7280A_READ, 0, addr << 2);
-       if (ret)
-               return ret;
-
-       ret = __ad7280_read32(st, &tmp);
-       if (ret)
-               return ret;
-
-       if (ad7280_check_crc(st, tmp))
-               return -EIO;
-
-       if (((tmp >> 27) != devaddr) || (((tmp >> 21) & 0x3F) != addr))
-               return -EFAULT;
-
-       return (tmp >> 13) & 0xFF;
-}
-
-static int ad7280_read_channel(struct ad7280_state *st, unsigned int devaddr,
-                              unsigned int addr)
-{
-       int ret;
-       unsigned int tmp;
-
-       ret = ad7280_write(st, devaddr, AD7280A_READ, 0, addr << 2);
-       if (ret)
-               return ret;
-
-       ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, 1,
-                          AD7280A_CTRL_HB_CONV_INPUT_ALL |
-                          AD7280A_CTRL_HB_CONV_RES_READ_NO |
-                          st->ctrl_hb);
-       if (ret)
-               return ret;
-
-       ret = ad7280_write(st, devaddr, AD7280A_CONTROL_HB, 0,
-                          AD7280A_CTRL_HB_CONV_INPUT_ALL |
-                          AD7280A_CTRL_HB_CONV_RES_READ_ALL |
-                          AD7280A_CTRL_HB_CONV_START_CS |
-                          st->ctrl_hb);
-       if (ret)
-               return ret;
-
-       ad7280_delay(st);
-
-       ret = __ad7280_read32(st, &tmp);
-       if (ret)
-               return ret;
-
-       if (ad7280_check_crc(st, tmp))
-               return -EIO;
-
-       if (((tmp >> 27) != devaddr) || (((tmp >> 23) & 0xF) != addr))
-               return -EFAULT;
-
-       return (tmp >> 11) & 0xFFF;
-}
-
-static int ad7280_read_all_channels(struct ad7280_state *st, unsigned int cnt,
-                                   unsigned int *array)
-{
-       int i, ret;
-       unsigned int tmp, sum = 0;
-
-       ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_READ, 1,
-                          AD7280A_CELL_VOLTAGE_1 << 2);
-       if (ret)
-               return ret;
-
-       ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, 1,
-                          AD7280A_CTRL_HB_CONV_INPUT_ALL |
-                          AD7280A_CTRL_HB_CONV_RES_READ_ALL |
-                          AD7280A_CTRL_HB_CONV_START_CS |
-                          st->ctrl_hb);
-       if (ret)
-               return ret;
-
-       ad7280_delay(st);
-
-       for (i = 0; i < cnt; i++) {
-               ret = __ad7280_read32(st, &tmp);
-               if (ret)
-                       return ret;
-
-               if (ad7280_check_crc(st, tmp))
-                       return -EIO;
-
-               if (array)
-                       array[i] = tmp;
-               /* only sum cell voltages */
-               if (((tmp >> 23) & 0xF) <= AD7280A_CELL_VOLTAGE_6)
-                       sum += ((tmp >> 11) & 0xFFF);
-       }
-
-       return sum;
-}
-
-static void ad7280_sw_power_down(void *data)
-{
-       struct ad7280_state *st = data;
-
-       ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, 1,
-                    AD7280A_CTRL_HB_PWRDN_SW | st->ctrl_hb);
-}
-
-static int ad7280_chain_setup(struct ad7280_state *st)
-{
-       unsigned int val, n;
-       int ret;
-
-       ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_LB, 1,
-                          AD7280A_CTRL_LB_DAISY_CHAIN_RB_EN |
-                          AD7280A_CTRL_LB_LOCK_DEV_ADDR |
-                          AD7280A_CTRL_LB_MUST_SET |
-                          AD7280A_CTRL_LB_SWRST |
-                          st->ctrl_lb);
-       if (ret)
-               return ret;
-
-       ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_LB, 1,
-                          AD7280A_CTRL_LB_DAISY_CHAIN_RB_EN |
-                          AD7280A_CTRL_LB_LOCK_DEV_ADDR |
-                          AD7280A_CTRL_LB_MUST_SET |
-                          st->ctrl_lb);
-       if (ret)
-               goto error_power_down;
-
-       ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_READ, 1,
-                          AD7280A_CONTROL_LB << 2);
-       if (ret)
-               goto error_power_down;
-
-       for (n = 0; n <= AD7280A_MAX_CHAIN; n++) {
-               ret = __ad7280_read32(st, &val);
-               if (ret)
-                       goto error_power_down;
-
-               if (val == 0)
-                       return n - 1;
-
-               if (ad7280_check_crc(st, val)) {
-                       ret = -EIO;
-                       goto error_power_down;
-               }
-
-               if (n != ad7280a_devaddr(val >> 27)) {
-                       ret = -EIO;
-                       goto error_power_down;
-               }
-       }
-       ret = -EFAULT;
-
-error_power_down:
-       ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, 1,
-                    AD7280A_CTRL_HB_PWRDN_SW | st->ctrl_hb);
-
-       return ret;
-}
-
-static ssize_t ad7280_show_balance_sw(struct device *dev,
-                                     struct device_attribute *attr,
-                                     char *buf)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct ad7280_state *st = iio_priv(indio_dev);
-       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-
-       return sprintf(buf, "%d\n",
-                      !!(st->cb_mask[this_attr->address >> 8] &
-                      (1 << ((this_attr->address & 0xFF) + 2))));
-}
-
-static ssize_t ad7280_store_balance_sw(struct device *dev,
-                                      struct device_attribute *attr,
-                                      const char *buf,
-                                      size_t len)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct ad7280_state *st = iio_priv(indio_dev);
-       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-       bool readin;
-       int ret;
-       unsigned int devaddr, ch;
-
-       ret = strtobool(buf, &readin);
-       if (ret)
-               return ret;
-
-       devaddr = this_attr->address >> 8;
-       ch = this_attr->address & 0xFF;
-
-       mutex_lock(&st->lock);
-       if (readin)
-               st->cb_mask[devaddr] |= 1 << (ch + 2);
-       else
-               st->cb_mask[devaddr] &= ~(1 << (ch + 2));
-
-       ret = ad7280_write(st, devaddr, AD7280A_CELL_BALANCE,
-                          0, st->cb_mask[devaddr]);
-       mutex_unlock(&st->lock);
-
-       return ret ? ret : len;
-}
-
-static ssize_t ad7280_show_balance_timer(struct device *dev,
-                                        struct device_attribute *attr,
-                                        char *buf)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct ad7280_state *st = iio_priv(indio_dev);
-       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-       int ret;
-       unsigned int msecs;
-
-       mutex_lock(&st->lock);
-       ret = ad7280_read(st, this_attr->address >> 8,
-                         this_attr->address & 0xFF);
-       mutex_unlock(&st->lock);
-
-       if (ret < 0)
-               return ret;
-
-       msecs = (ret >> 3) * 71500;
-
-       return sprintf(buf, "%u\n", msecs);
-}
-
-static ssize_t ad7280_store_balance_timer(struct device *dev,
-                                         struct device_attribute *attr,
-                                         const char *buf,
-                                         size_t len)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct ad7280_state *st = iio_priv(indio_dev);
-       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-       unsigned long val;
-       int ret;
-
-       ret = kstrtoul(buf, 10, &val);
-       if (ret)
-               return ret;
-
-       val /= 71500;
-
-       if (val > 31)
-               return -EINVAL;
-
-       mutex_lock(&st->lock);
-       ret = ad7280_write(st, this_attr->address >> 8,
-                          this_attr->address & 0xFF,
-                          0, (val & 0x1F) << 3);
-       mutex_unlock(&st->lock);
-
-       return ret ? ret : len;
-}
-
-static struct attribute *ad7280_attributes[AD7280A_MAX_CHAIN *
-                                          AD7280A_CELLS_PER_DEV * 2 + 1];
-
-static const struct attribute_group ad7280_attrs_group = {
-       .attrs = ad7280_attributes,
-};
-
-static void ad7280_voltage_channel_init(struct iio_chan_spec *chan, int i)
-{
-       chan->type = IIO_VOLTAGE;
-       chan->differential = 1;
-       chan->channel = i;
-       chan->channel2 = chan->channel + 1;
-}
-
-static void ad7280_temp_channel_init(struct iio_chan_spec *chan, int i)
-{
-       chan->type = IIO_TEMP;
-       chan->channel = i;
-}
-
-static void ad7280_common_fields_init(struct iio_chan_spec *chan, int addr,
-                                     int cnt)
-{
-       chan->indexed = 1;
-       chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
-       chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
-       chan->address = addr;
-       chan->scan_index = cnt;
-       chan->scan_type.sign = 'u';
-       chan->scan_type.realbits = 12;
-       chan->scan_type.storagebits = 32;
-}
-
-static void ad7280_total_voltage_channel_init(struct iio_chan_spec *chan,
-                                             int cnt, int dev)
-{
-       chan->type = IIO_VOLTAGE;
-       chan->differential = 1;
-       chan->channel = 0;
-       chan->channel2 = dev * AD7280A_CELLS_PER_DEV;
-       chan->address = AD7280A_ALL_CELLS;
-       chan->indexed = 1;
-       chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
-       chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
-       chan->scan_index = cnt;
-       chan->scan_type.sign = 'u';
-       chan->scan_type.realbits = 32;
-       chan->scan_type.storagebits = 32;
-}
-
-static void ad7280_timestamp_channel_init(struct iio_chan_spec *chan, int cnt)
-{
-       chan->type = IIO_TIMESTAMP;
-       chan->channel = -1;
-       chan->scan_index = cnt;
-       chan->scan_type.sign = 's';
-       chan->scan_type.realbits = 64;
-       chan->scan_type.storagebits = 64;
-}
-
-static void ad7280_init_dev_channels(struct ad7280_state *st, int dev, int *cnt)
-{
-       int addr, ch, i;
-       struct iio_chan_spec *chan;
-
-       for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_AUX_ADC_6; ch++) {
-               chan = &st->channels[*cnt];
-
-               if (ch < AD7280A_AUX_ADC_1) {
-                       i = AD7280A_CALC_VOLTAGE_CHAN_NUM(dev, ch);
-                       ad7280_voltage_channel_init(chan, i);
-               } else {
-                       i = AD7280A_CALC_TEMP_CHAN_NUM(dev, ch);
-                       ad7280_temp_channel_init(chan, i);
-               }
-
-               addr = ad7280a_devaddr(dev) << 8 | ch;
-               ad7280_common_fields_init(chan, addr, *cnt);
-
-               (*cnt)++;
-       }
-}
-
-static int ad7280_channel_init(struct ad7280_state *st)
-{
-       int dev, cnt = 0;
-
-       st->channels = devm_kcalloc(&st->spi->dev, (st->slave_num + 1) * 12 + 2,
-                                   sizeof(*st->channels), GFP_KERNEL);
-       if (!st->channels)
-               return -ENOMEM;
-
-       for (dev = 0; dev <= st->slave_num; dev++)
-               ad7280_init_dev_channels(st, dev, &cnt);
-
-       ad7280_total_voltage_channel_init(&st->channels[cnt], cnt, dev);
-       cnt++;
-       ad7280_timestamp_channel_init(&st->channels[cnt], cnt);
-
-       return cnt + 1;
-}
-
-static int ad7280_balance_switch_attr_init(struct iio_dev_attr *attr,
-                                          struct device *dev, int addr, int i)
-{
-       attr->address = addr;
-       attr->dev_attr.attr.mode = 0644;
-       attr->dev_attr.show = ad7280_show_balance_sw;
-       attr->dev_attr.store = ad7280_store_balance_sw;
-       attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL,
-                                                 "in%d-in%d_balance_switch_en",
-                                                 i, i + 1);
-       if (!attr->dev_attr.attr.name)
-               return -ENOMEM;
-
-       return 0;
-}
-
-static int ad7280_balance_timer_attr_init(struct iio_dev_attr *attr,
-                                         struct device *dev, int addr, int i)
-{
-       attr->address = addr;
-       attr->dev_attr.attr.mode = 0644;
-       attr->dev_attr.show = ad7280_show_balance_timer;
-       attr->dev_attr.store = ad7280_store_balance_timer;
-       attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL,
-                                                 "in%d-in%d_balance_timer",
-                                                 i, i + 1);
-       if (!attr->dev_attr.attr.name)
-               return -ENOMEM;
-
-       return 0;
-}
-
-static int ad7280_init_dev_attrs(struct ad7280_state *st, int dev, int *cnt)
-{
-       int addr, ch, i, ret;
-       struct iio_dev_attr *iio_attr;
-       struct device *sdev = &st->spi->dev;
-
-       for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_CELL_VOLTAGE_6; ch++) {
-               iio_attr = &st->iio_attr[*cnt];
-               addr = ad7280a_devaddr(dev) << 8 | ch;
-               i = dev * AD7280A_CELLS_PER_DEV + ch;
-
-               ret = ad7280_balance_switch_attr_init(iio_attr, sdev, addr, i);
-               if (ret < 0)
-                       return ret;
-
-               ad7280_attributes[*cnt] = &iio_attr->dev_attr.attr;
-
-               (*cnt)++;
-               iio_attr = &st->iio_attr[*cnt];
-               addr = ad7280a_devaddr(dev) << 8 | (AD7280A_CB1_TIMER + ch);
-
-               ret = ad7280_balance_timer_attr_init(iio_attr, sdev, addr, i);
-               if (ret < 0)
-                       return ret;
-
-               ad7280_attributes[*cnt] = &iio_attr->dev_attr.attr;
-               (*cnt)++;
-       }
-
-       ad7280_attributes[*cnt] = NULL;
-
-       return 0;
-}
-
-static int ad7280_attr_init(struct ad7280_state *st)
-{
-       int dev, cnt = 0, ret;
-
-       st->iio_attr = devm_kcalloc(&st->spi->dev, 2, sizeof(*st->iio_attr) *
-                                   (st->slave_num + 1) * AD7280A_CELLS_PER_DEV,
-                                   GFP_KERNEL);
-       if (!st->iio_attr)
-               return -ENOMEM;
-
-       for (dev = 0; dev <= st->slave_num; dev++) {
-               ret = ad7280_init_dev_attrs(st, dev, &cnt);
-               if (ret < 0)
-                       return ret;
-       }
-
-       return 0;
-}
-
-static ssize_t ad7280_read_channel_config(struct device *dev,
-                                         struct device_attribute *attr,
-                                         char *buf)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct ad7280_state *st = iio_priv(indio_dev);
-       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-       unsigned int val;
-
-       switch (this_attr->address) {
-       case AD7280A_CELL_OVERVOLTAGE:
-               val = 1000 + (st->cell_threshhigh * 1568) / 100;
-               break;
-       case AD7280A_CELL_UNDERVOLTAGE:
-               val = 1000 + (st->cell_threshlow * 1568) / 100;
-               break;
-       case AD7280A_AUX_ADC_OVERVOLTAGE:
-               val = (st->aux_threshhigh * 196) / 10;
-               break;
-       case AD7280A_AUX_ADC_UNDERVOLTAGE:
-               val = (st->aux_threshlow * 196) / 10;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return sprintf(buf, "%u\n", val);
-}
-
-static ssize_t ad7280_write_channel_config(struct device *dev,
-                                          struct device_attribute *attr,
-                                          const char *buf,
-                                          size_t len)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct ad7280_state *st = iio_priv(indio_dev);
-       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-
-       long val;
-       int ret;
-
-       ret = kstrtol(buf, 10, &val);
-       if (ret)
-               return ret;
-
-       switch (this_attr->address) {
-       case AD7280A_CELL_OVERVOLTAGE:
-       case AD7280A_CELL_UNDERVOLTAGE:
-               val = ((val - 1000) * 100) / 1568; /* LSB 15.68mV */
-               break;
-       case AD7280A_AUX_ADC_OVERVOLTAGE:
-       case AD7280A_AUX_ADC_UNDERVOLTAGE:
-               val = (val * 10) / 196; /* LSB 19.6mV */
-               break;
-       default:
-               return -EFAULT;
-       }
-
-       val = clamp(val, 0L, 0xFFL);
-
-       mutex_lock(&st->lock);
-       switch (this_attr->address) {
-       case AD7280A_CELL_OVERVOLTAGE:
-               st->cell_threshhigh = val;
-               break;
-       case AD7280A_CELL_UNDERVOLTAGE:
-               st->cell_threshlow = val;
-               break;
-       case AD7280A_AUX_ADC_OVERVOLTAGE:
-               st->aux_threshhigh = val;
-               break;
-       case AD7280A_AUX_ADC_UNDERVOLTAGE:
-               st->aux_threshlow = val;
-               break;
-       }
-
-       ret = ad7280_write(st, AD7280A_DEVADDR_MASTER,
-                          this_attr->address, 1, val);
-
-       mutex_unlock(&st->lock);
-
-       return ret ? ret : len;
-}
-
-static irqreturn_t ad7280_event_handler(int irq, void *private)
-{
-       struct iio_dev *indio_dev = private;
-       struct ad7280_state *st = iio_priv(indio_dev);
-       unsigned int *channels;
-       int i, ret;
-
-       channels = kcalloc(st->scan_cnt, sizeof(*channels), GFP_KERNEL);
-       if (!channels)
-               return IRQ_HANDLED;
-
-       ret = ad7280_read_all_channels(st, st->scan_cnt, channels);
-       if (ret < 0)
-               goto out;
-
-       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) {
-                               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) {
-                               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) {
-                               u64 tmp = IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0,
-                                                       IIO_EV_TYPE_THRESH,
-                                                       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) {
-                               u64 tmp = IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0,
-                                                       IIO_EV_TYPE_THRESH,
-                                                       IIO_EV_DIR_FALLING);
-                               iio_push_event(indio_dev, tmp,
-                                              iio_get_time_ns(indio_dev));
-                       }
-               }
-       }
-
-out:
-       kfree(channels);
-
-       return IRQ_HANDLED;
-}
-
-/* Note: No need to fix checkpatch warning that reads:
- *     CHECK: spaces preferred around that '-' (ctx:VxV)
- * The function argument is stringified and doesn't need a fix
- */
-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);
-
-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);
-
-static IIO_DEVICE_ATTR(in_temp_thresh_low_value,
-                      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);
-
-static struct attribute *ad7280_event_attributes[] = {
-       &iio_dev_attr_in_thresh_low_value.dev_attr.attr,
-       &iio_dev_attr_in_thresh_high_value.dev_attr.attr,
-       &iio_dev_attr_in_temp_thresh_low_value.dev_attr.attr,
-       &iio_dev_attr_in_temp_thresh_high_value.dev_attr.attr,
-       NULL,
-};
-
-static const struct attribute_group ad7280_event_attrs_group = {
-       .attrs = ad7280_event_attributes,
-};
-
-static int ad7280_read_raw(struct iio_dev *indio_dev,
-                          struct iio_chan_spec const *chan,
-                          int *val,
-                          int *val2,
-                          long m)
-{
-       struct ad7280_state *st = iio_priv(indio_dev);
-       int ret;
-
-       switch (m) {
-       case IIO_CHAN_INFO_RAW:
-               mutex_lock(&st->lock);
-               if (chan->address == AD7280A_ALL_CELLS)
-                       ret = ad7280_read_all_channels(st, st->scan_cnt, NULL);
-               else
-                       ret = ad7280_read_channel(st, chan->address >> 8,
-                                                 chan->address & 0xFF);
-               mutex_unlock(&st->lock);
-
-               if (ret < 0)
-                       return ret;
-
-               *val = ret;
-
-               return IIO_VAL_INT;
-       case IIO_CHAN_INFO_SCALE:
-               if ((chan->address & 0xFF) <= AD7280A_CELL_VOLTAGE_6)
-                       *val = 4000;
-               else
-                       *val = 5000;
-
-               *val2 = AD7280A_BITS;
-               return IIO_VAL_FRACTIONAL_LOG2;
-       }
-       return -EINVAL;
-}
-
-static const struct iio_info ad7280_info = {
-       .read_raw = ad7280_read_raw,
-       .event_attrs = &ad7280_event_attrs_group,
-       .attrs = &ad7280_attrs_group,
-};
-
-static const struct ad7280_platform_data ad7793_default_pdata = {
-       .acquisition_time = AD7280A_ACQ_TIME_400ns,
-       .conversion_averaging = AD7280A_CONV_AVG_DIS,
-       .thermistor_term_en = true,
-};
-
-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 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));
-       if (!indio_dev)
-               return -ENOMEM;
-
-       st = iio_priv(indio_dev);
-       spi_set_drvdata(spi, indio_dev);
-       st->spi = spi;
-       mutex_init(&st->lock);
-
-       if (!pdata)
-               pdata = &ad7793_default_pdata;
-
-       crc8_populate_msb(st->crc_tab, POLYNOM);
-
-       st->spi->max_speed_hz = AD7280A_MAX_SPI_CLK_HZ;
-       st->spi->mode = SPI_MODE_1;
-       spi_setup(st->spi);
-
-       st->ctrl_lb = AD7280A_CTRL_LB_ACQ_TIME(pdata->acquisition_time & 0x3);
-       st->ctrl_hb = AD7280A_CTRL_HB_CONV_AVG(pdata->conversion_averaging
-                       & 0x3) | (pdata->thermistor_term_en ?
-                       AD7280A_CTRL_LB_THERMISTOR_EN : 0);
-
-       ret = ad7280_chain_setup(st);
-       if (ret < 0)
-               return ret;
-
-       st->slave_num = ret;
-       st->scan_cnt = (st->slave_num + 1) * AD7280A_NUM_CH;
-       st->cell_threshhigh = 0xFF;
-       st->aux_threshhigh = 0xFF;
-
-       ret = devm_add_action_or_reset(&spi->dev, ad7280_sw_power_down, st);
-       if (ret)
-               return ret;
-
-       /*
-        * Total Conversion Time = ((tACQ + tCONV) *
-        *                         (Number of Conversions per Part)) âˆ’
-        *                         tACQ + ((N - 1) * tDELAY)
-        *
-        * Readback Delay = Total Conversion Time + tWAIT
-        */
-
-       st->readback_delay_us =
-               ((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);
-       st->readback_delay_us += 5; /* Add tWAIT */
-
-       indio_dev->name = spi_get_device_id(spi)->name;
-       indio_dev->modes = INDIO_DIRECT_MODE;
-
-       ret = ad7280_channel_init(st);
-       if (ret < 0)
-               return ret;
-
-       indio_dev->num_channels = ret;
-       indio_dev->channels = st->channels;
-       indio_dev->info = &ad7280_info;
-
-       ret = ad7280_attr_init(st);
-       if (ret < 0)
-               return ret;
-
-       ret = devm_iio_device_register(&spi->dev, indio_dev);
-       if (ret)
-               return ret;
-
-       if (spi->irq > 0) {
-               ret = ad7280_write(st, AD7280A_DEVADDR_MASTER,
-                                  AD7280A_ALERT, 1,
-                                  AD7280A_ALERT_RELAY_SIG_CHAIN_DOWN);
-               if (ret)
-                       return ret;
-
-               ret = ad7280_write(st, ad7280a_devaddr(st->slave_num),
-                                  AD7280A_ALERT, 0,
-                                  AD7280A_ALERT_GEN_STATIC_HIGH |
-                                  (pdata->chain_last_alert_ignore & 0xF));
-               if (ret)
-                       return ret;
-
-               ret = devm_request_threaded_irq(&spi->dev, spi->irq,
-                                               NULL,
-                                               ad7280_event_handler,
-                                               IRQF_TRIGGER_FALLING |
-                                               IRQF_ONESHOT,
-                                               indio_dev->name,
-                                               indio_dev);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-static const struct spi_device_id ad7280_id[] = {
-       {"ad7280a", 0},
-       {}
-};
-MODULE_DEVICE_TABLE(spi, ad7280_id);
-
-static struct spi_driver ad7280_driver = {
-       .driver = {
-               .name   = "ad7280",
-       },
-       .probe          = ad7280_probe,
-       .id_table       = ad7280_id,
-};
-module_spi_driver(ad7280_driver);
-
-MODULE_AUTHOR("Michael Hennerich <[email protected]>");
-MODULE_DESCRIPTION("Analog Devices AD7280A");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/adc/ad7280a.h b/drivers/staging/iio/adc/ad7280a.h
deleted file mode 100644 (file)
index 23f18bb..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * AD7280A Lithium Ion Battery Monitoring System
- *
- * Copyright 2011 Analog Devices Inc.
- */
-
-#ifndef IIO_ADC_AD7280_H_
-#define IIO_ADC_AD7280_H_
-
-/*
- * TODO: struct ad7280_platform_data needs to go into include/linux/iio
- */
-
-#define AD7280A_ACQ_TIME_400ns                 0
-#define AD7280A_ACQ_TIME_800ns                 1
-#define AD7280A_ACQ_TIME_1200ns                        2
-#define AD7280A_ACQ_TIME_1600ns                        3
-
-#define AD7280A_CONV_AVG_DIS                   0
-#define AD7280A_CONV_AVG_2                     1
-#define AD7280A_CONV_AVG_4                     2
-#define AD7280A_CONV_AVG_8                     3
-
-#define AD7280A_ALERT_REMOVE_VIN5              BIT(2)
-#define AD7280A_ALERT_REMOVE_VIN4_VIN5         BIT(3)
-#define AD7280A_ALERT_REMOVE_AUX5              BIT(0)
-#define AD7280A_ALERT_REMOVE_AUX4_AUX5         BIT(1)
-
-struct ad7280_platform_data {
-       unsigned int            acquisition_time;
-       unsigned int            conversion_averaging;
-       unsigned int            chain_last_alert_ignore;
-       bool                    thermistor_term_en;
-};
-
-#endif /* IIO_ADC_AD7280_H_ */
index 33f60f43e1aadbe024484d91db2f0139f4a00018..ce78d4804994baba70cf39f67d1f3bf0f927f4c4 100644 (file)
@@ -6,6 +6,7 @@
 #ifndef QCOM_VADC_COMMON_H
 #define QCOM_VADC_COMMON_H
 
+#include <linux/math.h>
 #include <linux/types.h>
 
 #define VADC_CONV_TIME_MIN_US                  2000
@@ -79,16 +80,6 @@ struct vadc_linear_graph {
        s32 gnd;
 };
 
-/**
- * struct vadc_prescale_ratio - Represent scaling ratio for ADC input.
- * @num: the inverse numerator of the gain applied to the input channel.
- * @den: the inverse denominator of the gain applied to the input channel.
- */
-struct vadc_prescale_ratio {
-       u32 num;
-       u32 den;
-};
-
 /**
  * enum vadc_scale_fn_type - Scaling function to convert ADC code to
  *                             physical scaled units for the channel.
@@ -144,12 +135,12 @@ struct adc5_data {
 
 int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
                    const struct vadc_linear_graph *calib_graph,
-                   const struct vadc_prescale_ratio *prescale,
+                   const struct u32_fract *prescale,
                    bool absolute,
                    u16 adc_code, int *result_mdec);
 
 struct qcom_adc5_scale_type {
-       int (*scale_fn)(const struct vadc_prescale_ratio *prescale,
+       int (*scale_fn)(const struct u32_fract *prescale,
                const struct adc5_data *data, u16 adc_code, int *result);
 };
 
diff --git a/include/linux/iio/afe/rescale.h b/include/linux/iio/afe/rescale.h
new file mode 100644 (file)
index 0000000..6eecb43
--- /dev/null
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2018 Axentia Technologies AB
+ */
+
+#ifndef __IIO_RESCALE_H__
+#define __IIO_RESCALE_H__
+
+#include <linux/types.h>
+#include <linux/iio/iio.h>
+
+struct device;
+struct rescale;
+
+struct rescale_cfg {
+       enum iio_chan_type type;
+       int (*props)(struct device *dev, struct rescale *rescale);
+};
+
+struct rescale {
+       const struct rescale_cfg *cfg;
+       struct iio_channel *source;
+       struct iio_chan_spec chan;
+       struct iio_chan_spec_ext_info *ext_info;
+       bool chan_processed;
+       s32 numerator;
+       s32 denominator;
+       s32 offset;
+};
+
+int rescale_process_scale(struct rescale *rescale, int scale_type,
+                         int *val, int *val2);
+int rescale_process_offset(struct rescale *rescale, int scale_type,
+                          int scale, int scale2, int schan_off,
+                          int *val, int *val2);
+#endif /* __IIO_RESCALE_H__ */
index 07025d6b3de1ad38d234e853cea99902c2b42f39..faf00f2c0be6f910ef335dacf8e7c4720f595aa5 100644 (file)
@@ -489,7 +489,7 @@ struct iio_buffer_setup_ops {
 /**
  * struct iio_dev - industrial I/O device
  * @modes:             [DRIVER] operating modes supported by device
- * @currentmode:       [DRIVER] current operating mode
+ * @currentmode:       [INTERN] current operating mode
  * @dev:               [DRIVER] device structure, should be assigned a parent
  *                     and owner
  * @buffer:            [DRIVER] any buffer present
index 7c02f5292eea7b7905127b5cbb1986774a5284ed..515ca09764fe4ac2f7c2cfbbb48df1aa853b0267 100644 (file)
@@ -32,6 +32,7 @@ struct adis_timeout {
        u16 sw_reset_ms;
        u16 self_test_ms;
 };
+
 /**
  * struct adis_data - ADIS chip variant specific data
  * @read_delay: SPI delay for read operations in us
@@ -45,7 +46,7 @@ struct adis_timeout {
  * @self_test_mask: Bitmask of supported self-test operations
  * @self_test_reg: Register address to request self test command
  * @self_test_no_autoclear: True if device's self-test needs clear of ctrl reg
- * @status_error_msgs: Array of error messgaes
+ * @status_error_msgs: Array of error messages
  * @status_error_mask: Bitmask of errors supported by the device
  * @timeouts: Chip specific delays
  * @enable_irq: Hook for ADIS devices that have a special IRQ enable/disable
@@ -130,12 +131,12 @@ struct adis {
        unsigned long           irq_flag;
        void                    *buffer;
 
-       uint8_t                 tx[10] ____cacheline_aligned;
-       uint8_t                 rx[4];
+       u8                      tx[10] ____cacheline_aligned;
+       u8                      rx[4];
 };
 
 int adis_init(struct adis *adis, struct iio_dev *indio_dev,
-       struct spi_device *spi, const struct adis_data *data);
+             struct spi_device *spi, const struct adis_data *data);
 int __adis_reset(struct adis *adis);
 
 /**
@@ -156,9 +157,9 @@ static inline int adis_reset(struct adis *adis)
 }
 
 int __adis_write_reg(struct adis *adis, unsigned int reg,
-       unsigned int val, unsigned int size);
+                    unsigned int val, unsigned int size);
 int __adis_read_reg(struct adis *adis, unsigned int reg,
-       unsigned int *val, unsigned int size);
+                   unsigned int *val, unsigned int size);
 
 /**
  * __adis_write_reg_8() - Write single byte to a register (unlocked)
@@ -167,7 +168,7 @@ int __adis_read_reg(struct adis *adis, unsigned int reg,
  * @value: The value to write
  */
 static inline int __adis_write_reg_8(struct adis *adis, unsigned int reg,
-       uint8_t val)
+                                    u8 val)
 {
        return __adis_write_reg(adis, reg, val, 1);
 }
@@ -179,7 +180,7 @@ static inline int __adis_write_reg_8(struct adis *adis, unsigned int reg,
  * @value: Value to be written
  */
 static inline int __adis_write_reg_16(struct adis *adis, unsigned int reg,
-       uint16_t val)
+                                     u16 val)
 {
        return __adis_write_reg(adis, reg, val, 2);
 }
@@ -191,7 +192,7 @@ static inline int __adis_write_reg_16(struct adis *adis, unsigned int reg,
  * @value: Value to be written
  */
 static inline int __adis_write_reg_32(struct adis *adis, unsigned int reg,
-       uint32_t val)
+                                     u32 val)
 {
        return __adis_write_reg(adis, reg, val, 4);
 }
@@ -203,7 +204,7 @@ static inline int __adis_write_reg_32(struct adis *adis, unsigned int reg,
  * @val: The value read back from the device
  */
 static inline int __adis_read_reg_16(struct adis *adis, unsigned int reg,
-       uint16_t *val)
+                                    u16 *val)
 {
        unsigned int tmp;
        int ret;
@@ -222,7 +223,7 @@ static inline int __adis_read_reg_16(struct adis *adis, unsigned int reg,
  * @val: The value read back from the device
  */
 static inline int __adis_read_reg_32(struct adis *adis, unsigned int reg,
-       uint32_t *val)
+                                    u32 *val)
 {
        unsigned int tmp;
        int ret;
@@ -242,7 +243,7 @@ static inline int __adis_read_reg_32(struct adis *adis, unsigned int reg,
  * @size: The size of the @value (in bytes)
  */
 static inline int adis_write_reg(struct adis *adis, unsigned int reg,
-       unsigned int val, unsigned int size)
+                                unsigned int val, unsigned int size)
 {
        int ret;
 
@@ -261,7 +262,7 @@ static inline int adis_write_reg(struct adis *adis, unsigned int reg,
  * @size: The size of the @val buffer
  */
 static int adis_read_reg(struct adis *adis, unsigned int reg,
-       unsigned int *val, unsigned int size)
+                        unsigned int *val, unsigned int size)
 {
        int ret;
 
@@ -279,7 +280,7 @@ static int adis_read_reg(struct adis *adis, unsigned int reg,
  * @value: The value to write
  */
 static inline int adis_write_reg_8(struct adis *adis, unsigned int reg,
-       uint8_t val)
+                                  u8 val)
 {
        return adis_write_reg(adis, reg, val, 1);
 }
@@ -291,7 +292,7 @@ static inline int adis_write_reg_8(struct adis *adis, unsigned int reg,
  * @value: Value to be written
  */
 static inline int adis_write_reg_16(struct adis *adis, unsigned int reg,
-       uint16_t val)
+                                   u16 val)
 {
        return adis_write_reg(adis, reg, val, 2);
 }
@@ -303,7 +304,7 @@ static inline int adis_write_reg_16(struct adis *adis, unsigned int reg,
  * @value: Value to be written
  */
 static inline int adis_write_reg_32(struct adis *adis, unsigned int reg,
-       uint32_t val)
+                                   u32 val)
 {
        return adis_write_reg(adis, reg, val, 4);
 }
@@ -315,7 +316,7 @@ static inline int adis_write_reg_32(struct adis *adis, unsigned int reg,
  * @val: The value read back from the device
  */
 static inline int adis_read_reg_16(struct adis *adis, unsigned int reg,
-       uint16_t *val)
+                                  u16 *val)
 {
        unsigned int tmp;
        int ret;
@@ -334,7 +335,7 @@ static inline int adis_read_reg_16(struct adis *adis, unsigned int reg,
  * @val: The value read back from the device
  */
 static inline int adis_read_reg_32(struct adis *adis, unsigned int reg,
-       uint32_t *val)
+                                  u32 *val)
 {
        unsigned int tmp;
        int ret;
@@ -381,10 +382,8 @@ static inline int adis_update_bits_base(struct adis *adis, unsigned int reg,
  * @val can lead to undesired behavior if the register to update is 16bit.
  */
 #define adis_update_bits(adis, reg, mask, val) ({                      \
-       BUILD_BUG_ON(sizeof(val) == 1 || sizeof(val) == 8);             \
-       __builtin_choose_expr(sizeof(val) == 4,                         \
-               adis_update_bits_base(adis, reg, mask, val, 4),         \
-               adis_update_bits_base(adis, reg, mask, val, 2));        \
+       BUILD_BUG_ON(sizeof(val) != 2 && sizeof(val) != 4);             \
+       adis_update_bits_base(adis, reg, mask, val, sizeof(val));       \
 })
 
 /**
@@ -399,10 +398,8 @@ static inline int adis_update_bits_base(struct adis *adis, unsigned int reg,
  * @val can lead to undesired behavior if the register to update is 16bit.
  */
 #define __adis_update_bits(adis, reg, mask, val) ({                    \
-       BUILD_BUG_ON(sizeof(val) == 1 || sizeof(val) == 8);             \
-       __builtin_choose_expr(sizeof(val) == 4,                         \
-               __adis_update_bits_base(adis, reg, mask, val, 4),       \
-               __adis_update_bits_base(adis, reg, mask, val, 2));      \
+       BUILD_BUG_ON(sizeof(val) != 2 && sizeof(val) != 4);             \
+       __adis_update_bits_base(adis, reg, mask, val, sizeof(val));     \
 })
 
 int adis_enable_irq(struct adis *adis, bool enable);
@@ -443,8 +440,8 @@ static inline void adis_dev_unlock(struct adis *adis)
 }
 
 int adis_single_conversion(struct iio_dev *indio_dev,
-       const struct iio_chan_spec *chan, unsigned int error_mask,
-       int *val);
+                          const struct iio_chan_spec *chan,
+                          unsigned int error_mask, int *val);
 
 #define ADIS_VOLTAGE_CHAN(addr, si, chan, name, info_all, bits) { \
        .type = IIO_VOLTAGE, \
@@ -493,7 +490,7 @@ int adis_single_conversion(struct iio_dev *indio_dev,
        .modified = 1, \
        .channel2 = IIO_MOD_ ## mod, \
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
-                info_sep, \
+                (info_sep), \
        .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
        .info_mask_shared_by_all = info_all, \
        .address = (addr), \
@@ -527,7 +524,7 @@ devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
 int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev);
 
 int adis_update_scan_mode(struct iio_dev *indio_dev,
-       const unsigned long *scan_mask);
+                         const unsigned long *scan_mask);
 
 #else /* CONFIG_IIO_BUFFER */
 
@@ -551,7 +548,8 @@ static inline int devm_adis_probe_trigger(struct adis *adis,
 #ifdef CONFIG_DEBUG_FS
 
 int adis_debugfs_reg_access(struct iio_dev *indio_dev,
-       unsigned int reg, unsigned int writeval, unsigned int *readval);
+                           unsigned int reg, unsigned int writeval,
+                           unsigned int *readval);
 
 #else
 
index 53674a327e39b519623ff14b6e563c17e5706541..439b8f0b9ebd3201b48cfe82c134e379d398dc3d 100644 (file)
@@ -2,6 +2,7 @@
 #ifndef _LINUX_MATH_H
 #define _LINUX_MATH_H
 
+#include <linux/types.h>
 #include <asm/div64.h>
 #include <uapi/linux/kernel.h>
 
 }                                                      \
 )
 
+#define __STRUCT_FRACT(type)                           \
+struct type##_fract {                                  \
+       __##type numerator;                             \
+       __##type denominator;                           \
+};
+__STRUCT_FRACT(s16)
+__STRUCT_FRACT(u16)
+__STRUCT_FRACT(s32)
+__STRUCT_FRACT(u32)
+#undef __STRUCT_FRACT
+
 /*
  * Multiplies an integer by a fraction, while avoiding unnecessary
  * overflow or loss of precision.
index 48c13147c0a8707d82d809655ffdc450af982ce3..472cead10d8d63630687d93a49ebdd895add30e6 100644 (file)
@@ -104,6 +104,7 @@ enum iio_event_type {
        IIO_EV_TYPE_THRESH_ADAPTIVE,
        IIO_EV_TYPE_MAG_ADAPTIVE,
        IIO_EV_TYPE_CHANGE,
+       IIO_EV_TYPE_MAG_REFERENCED,
 };
 
 enum iio_event_direction {
index b94a16ba5c6c100ccf0a406f88c116525fdce059..2f4581658859979e82ecac61db23dc0c6b35bab7 100644 (file)
@@ -68,6 +68,7 @@ static const char * const iio_ev_type_text[] = {
        [IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive",
        [IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive",
        [IIO_EV_TYPE_CHANGE] = "change",
+       [IIO_EV_TYPE_MAG_REFERENCED] = "mag_referenced",
 };
 
 static const char * const iio_ev_dir_text[] = {
This page took 0.93824 seconds and 4 git commands to generate.